root/lm-sensors/trunk/prog/eeprom/decode-dimms.pl @ 3305

Revision 3305, 41.0 KB (checked in by khali, 7 years ago)

Fix latencies decoding (SDRAM).
Fix CAS latency decoding (DDR SDRAM).
Decode latencies, timings and module height (DDR SDRAM).

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl -w
2#
3# Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
4# modified by Christian Zuckschwerdt <zany@triq.net>
5# modified by Burkart Lingner <burkart@bollchen.de>
6#
7#    This program is free software; you can redistribute it and/or modify
8#    it under the terms of the GNU General Public License as published by
9#    the Free Software Foundation; either version 2 of the License, or
10#    (at your option) any later version.
11#
12#    This program is distributed in the hope that it will be useful,
13#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#    GNU General Public License for more details.
16#
17#    You should have received a copy of the GNU General Public License
18#    along with this program; if not, write to the Free Software
19#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
21# Version 0.4  1999  Philip Edelbrock <phil@netroedge.com>
22# Version 0.5  2000-03-30  Christian Zuckschwerdt <zany@triq.net>
23#  html output (selectable by commandline switches)
24# Version 0.6  2000-09-16  Christian Zuckschwerdt <zany@triq.net>
25#  updated according to SPD Spec Rev 1.2B
26#  see http://developer.intel.com/technology/memory/pc133sdram/spec/Spdsd12b.htm
27# Version 0.7  2002-11-08  Jean Delvare <khali@linux-fr.org>
28#  pass -w and use strict
29#  valid HTML 3.2 output (--format mode)
30#  miscellaneous formatting enhancements and bug fixes
31#  clearer HTML output (original patch by Nick Kurshev <nickols_k@mail.ru>)
32#  stop decoding on checksum error by default (--checksum option forces)
33# Version 0.8  2005-06-20  Burkart Lingner <burkart@bollchen.de>
34#  adapted to Kernel 2.6's /sys filesystem
35# Version 0.9  2005-07-15  Jean Delvare <khali@linux-fr.org>
36#  fix perl warning
37#  fix typo
38#  refactor some code
39# Version 1.0  2005-09-18  Jean Delvare <khali@linux-fr.org>
40#  add large lookup tables for manufacturer names, based on data
41#  provided by Rudolf Marek, taken from:
42#  http://www.jedec.org/download/search/JEP106r.pdf
43# Version 1.1  2006-01-22  Jean Delvare <khali@linux-fr.org>
44#  improve the text output, making it hopefully clearer
45#  read eeprom by 64-byte blocks, this allows some code cleanups
46#  use sysopen/sysread instead of open/read for better performance
47#  verify checksum before decoding anything
48# Version 1.2  2006-05-15  Jean Delvare <khali@linux-fr.org>
49#  implement per-memory-type decoding
50#  don't decode revision code, manufacturing date and assembly serial
51#  number where not set
52#  decode the manufacturing date to an ISO8601 date
53# Version 1.3  2006-05-21  Jean Delvare <khali@linux-fr.org>
54#  detect undefined manufacturer code and handle it properly
55#  round up timing data
56#  minor display adjustments
57#  group cycle and access times, display the CAS value for each (SDRAM)
58#  refactor some bitfield tests into loops (SDRAM)
59#  display latencies and burst length on a single line (SDRAM)
60#  don't display manufacturing location when undefined
61#  check that the manufacturing date is proper BCD, else fall back to
62#  hexadecimal display
63# Version 1.4  2006-05-26  Jean Delvare <khali@linux-fr.org>
64#  fix latencies decoding (SDRAM)
65#  fix CAS latency decoding (DDR SDRAM)
66#  decode latencies, timings and module height (DDR SDRAM)
67#
68#
69# EEPROM data decoding for SDRAM DIMM modules.
70#
71# Two assumptions: lm_sensors-2.x installed,
72# and Perl is at /usr/bin/perl
73#
74# use the following command line switches
75#  -f, --format            print nice html output
76#  -b, --bodyonly          don't print html header
77#                          (useful for postprocessing the output)
78#  -c, --checksum          decode completely even if checksum fails
79#  -h, --help              display this usage summary
80#
81# References:
82# PC SDRAM Serial Presence
83# Detect (SPD) Specification, Intel,
84# 1997,1999, Rev 1.2B
85#
86# Jedec Standards 4.1.x & 4.5.x
87# http://www.jedec.org
88#
89
90require 5.004;
91
92use strict;
93use POSIX;
94use Fcntl qw(:DEFAULT :seek);
95use vars qw($opt_html $opt_body $opt_bodyonly $opt_igncheck $use_sysfs
96            @vendors %decode_callback);
97
98@vendors = (
99["AMD", "AMI", "Fairchild", "Fujitsu",
100 "GTE", "Harris", "Hitachi", "Inmos",
101 "Intel", "I.T.T.", "Intersil", "Monolithic Memories",
102 "Mostek", "Freescale (formerly Motorola)", "National", "NEC",
103 "RCA", "Raytheon", "Conexant (Rockwell)", "Seeq",
104 "Philips Semi. (Signetics)", "Synertek", "Texas Instruments", "Toshiba",
105 "Xicor", "Zilog", "Eurotechnique", "Mitsubishi",
106 "Lucent (AT&T)", "Exel", "Atmel", "SGS/Thomson",
107 "Lattice Semi.", "NCR", "Wafer Scale Integration", "IBM",
108 "Tristar", "Visic", "Intl. CMOS Technology", "SSSI",
109 "MicrochipTechnology", "Ricoh Ltd.", "VLSI", "Micron Technology",
110 "Hyundai Electronics", "OKI Semiconductor", "ACTEL", "Sharp",
111 "Catalyst", "Panasonic", "IDT", "Cypress",
112 "DEC", "LSI Logic", "Zarlink (formerly Plessey)", "UTMC",
113 "Thinking Machine", "Thomson CSF", "Integrated CMOS (Vertex)", "Honeywell",
114 "Tektronix", "Sun Microsystems", "SST", "ProMos/Mosel Vitelic",
115 "Infineon (formerly Siemens)", "Macronix", "Xerox", "Plus Logic",
116 "SunDisk", "Elan Circuit Tech.", "European Silicon Str.", "Apple Computer",
117 "Xilinx", "Compaq", "Protocol Engines", "SCI",
118 "Seiko Instruments", "Samsung", "I3 Design System", "Klic",
119 "Crosspoint Solutions", "Alliance Semiconductor", "Tandem", "Hewlett-Packard",
120 "Intg. Silicon Solutions", "Brooktree", "New Media", "MHS Electronic",
121 "Performance Semi.", "Winbond Electronic", "Kawasaki Steel", "Bright Micro",
122 "TECMAR", "Exar", "PCMCIA", "LG Semi (formerly Goldstar)",
123 "Northern Telecom", "Sanyo", "Array Microsystems", "Crystal Semiconductor",
124 "Analog Devices", "PMC-Sierra", "Asparix", "Convex Computer",
125 "Quality Semiconductor", "Nimbus Technology", "Transwitch", "Micronas (ITT Intermetall)",
126 "Cannon", "Altera", "NEXCOM", "QUALCOMM",
127 "Sony", "Cray Research", "AMS(Austria Micro)", "Vitesse",
128 "Aster Electronics", "Bay Networks (Synoptic)", "Zentrum or ZMD", "TRW",
129 "Thesys", "Solbourne Computer", "Allied-Signal", "Dialog",
130 "Media Vision", "Level One Communication"],
131["Cirrus Logic", "National Instruments", "ILC Data Device", "Alcatel Mietec",
132 "Micro Linear", "Univ. of NC", "JTAG Technologies", "Loral",
133 "Nchip", "Galileo Tech", "Bestlink Systems", "Graychip",
134 "GENNUM", "VideoLogic", "Robert Bosch", "Chip Express",
135 "DATARAM", "United Microelec Corp.", "TCSI", "Smart Modular",
136 "Hughes Aircraft", "Lanstar Semiconductor", "Qlogic", "Kingston",
137 "Music Semi", "Ericsson Components", "SpaSE", "Eon Silicon Devices",
138 "Programmable Micro Corp", "DoD", "Integ. Memories Tech.", "Corollary Inc.",
139 "Dallas Semiconductor", "Omnivision", "EIV(Switzerland)", "Novatel Wireless",
140 "Zarlink (formerly Mitel)", "Clearpoint", "Cabletron", "Silicon Technology",
141 "Vanguard", "Hagiwara Sys-Com", "Vantis", "Celestica",
142 "Century", "Hal Computers", "Rohm Company Ltd.", "Juniper Networks",
143 "Libit Signal Processing", "Mushkin Enhanced Memory", "Tundra Semiconductor", "Adaptec Inc.",
144 "LightSpeed Semi.", "ZSP Corp.", "AMIC Technology", "Adobe Systems",
145 "Dynachip", "PNY Electronics", "Newport Digital", "MMC Networks",
146 "T Square", "Seiko Epson", "Broadcom", "Viking Components",
147 "V3 Semiconductor", "Flextronics (formerly Orbit)", "Suwa Electronics", "Transmeta",
148 "Micron CMS", "American Computer & Digital Components Inc", "Enhance 3000 Inc", "Tower Semiconductor",
149 "CPU Design", "Price Point", "Maxim Integrated Product", "Tellabs",
150 "Centaur Technology", "Unigen Corporation", "Transcend Information", "Memory Card Technology",
151 "CKD Corporation Ltd.", "Capital Instruments, Inc.", "Aica Kogyo, Ltd.", "Linvex Technology",
152 "MSC Vertriebs GmbH", "AKM Company, Ltd.", "Dynamem, Inc.", "NERA ASA",
153 "GSI Technology", "Dane-Elec (C Memory)", "Acorn Computers", "Lara Technology",
154 "Oak Technology, Inc.", "Itec Memory", "Tanisys Technology", "Truevision",
155 "Wintec Industries", "Super PC Memory", "MGV Memory", "Galvantech",
156 "Gadzoox Nteworks", "Multi Dimensional Cons.", "GateField", "Integrated Memory System",
157 "Triscend", "XaQti", "Goldenram", "Clear Logic",
158 "Cimaron Communications", "Nippon Steel Semi. Corp.", "Advantage Memory", "AMCC",
159 "LeCroy", "Yamaha Corporation", "Digital Microwave", "NetLogic Microsystems",
160 "MIMOS Semiconductor", "Advanced Fibre", "BF Goodrich Data.", "Epigram",
161 "Acbel Polytech Inc.", "Apacer Technology", "Admor Memory", "FOXCONN",
162 "Quadratics Superconductor", "3COM"],
163["Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated",
164 "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies",
165 "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG",
166 "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", "Power General",
167 "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", "Delkin Devices",
168 "Symagery Microsystems", "C-Port Corporation", "SiberCore Technologies", "Southland Microsystems",
169 "Malleable Technologies", "Kendin Communications", "Great Technology Microcomputer", "Sanmina Corporation",
170 "HADCO Corporation", "Corsair", "Actrans System Inc.", "ALPHA Technologies",
171 "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", "Align Manufacturing", "Peregrine Semiconductor",
172 "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", "Chrysalis ITS",
173 "ADTEC Corporation", "Kentron Technologies", "Win Technologies", "Tachyon Semiconductor (formerly ASIC Designs Inc.)",
174 "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", "Sarnoff Corporation",
175 "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)", "Legend",
176 "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", "SwitchOn Networks",
177 "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", "Virata Corporation",
178 "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", "Newport Communications",
179 "Chip2Chip Incorporated", "Phobos Corporation", "Intellitech Corporation", "Nordic VLSI ASA",
180 "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", "Agilent Technologies",
181 "Centillium Communications", "W.L. Gore", "HanBit Electronics", "GlobeSpan",
182 "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
183 "MetaLink Technologies", "Feiya Technology", "I & C Technology", "Shikatronics",
184 "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
185 "Hyperchip", "Gemstone Communications", "Anadigm (formerly Anadyne)", "3ParData",
186 "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
187 "Skyup Technology", "HiNT Corporation", "Chiaro", "MCI Computer GMBH",
188 "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", "Legerity",
189 "Jasmine Networks", "Caspian Networks", "nCUBE", "Silicon Access Networks",
190 "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", "BRECIS",
191 "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
192 "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
193 "eSilicon", "Morphics Technology", "Accelerant Networks", "Silicon Wave",
194 "SandCraft", "Elpida"],
195["Solectron", "Optosys Technologies", "Buffalo (Formerly Melco)", "TriMedia Technologies",
196 "Cyan Technologies", "Global Locate", "Optillion", "Terago Communications",
197 "Ikanos Communications", "Princeton Technology", "Nanya Technology", "Elite Flash Storage",
198 "Mysticom", "LightSand Communications", "ATI Technologies", "Agere Systems",
199 "NeoMagic", "AuroraNetics", "Golden Empire", "Mushkin",
200 "Tioga Technologies", "Netlist", "TeraLogic", "Cicada Semiconductor",
201 "Centon Electronics", "Tyco Electronics", "Magis Works", "Zettacom",
202 "Cogency Semiconductor", "Chipcon AS", "Aspex Technology", "F5 Networks",
203 "Programmable Silicon Solutions", "ChipWrights", "Acorn Networks", "Quicklogic",
204 "Kingmax Semiconductor", "BOPS", "Flasys", "BitBlitz Communications",
205 "eMemory Technology", "Procket Networks", "Purple Ray", "Trebia Networks",
206 "Delta Electronics", "Onex Communications", "Ample Communications", "Memory Experts Intl",
207 "Astute Networks", "Azanda Network Devices", "Dibcom", "Tekmos",
208 "API NetWorks", "Bay Microsystems", "Firecron Ltd", "Resonext Communications",
209 "Tachys Technologies", "Equator Technology", "Concept Computer", "SILCOM",
210 "3Dlabs", "c't Magazine", "Sanera Systems", "Silicon Packets",
211 "Viasystems Group", "Simtek", "Semicon Devices Singapore", "Satron Handelsges",
212 "Improv Systems", "INDUSYS GmbH", "Corrent", "Infrant Technologies",
213 "Ritek Corp", "empowerTel Networks", "Hypertec", "Cavium Networks",
214 "PLX Technology", "Massana Design", "Intrinsity", "Valence Semiconductor",
215 "Terawave Communications", "IceFyre Semiconductor", "Primarion", "Picochip Designs Ltd",
216 "Silverback Systems", "Jade Star Technologies", "Pijnenburg Securealink", "MemorySolutioN",
217 "Cambridge Silicon Radio", "Swissbit", "Nazomi Communications", "eWave System",
218 "Rockwell Collins", "Picocel Co., Ltd.", "Alphamosaic Ltd", "Sandburst",
219 "SiCon Video", "NanoAmp Solutions", "Ericsson Technology", "PrairieComm",
220 "Mitac International", "Layer N Networks", "MtekVision", "Allegro Networks",
221 "Marvell Semiconductors", "Netergy Microelectronic", "NVIDIA", "Internet Machines",
222 "Peak Electronics", "Litchfield Communication", "Accton Technology", "Teradiant Networks",
223 "Europe Technologies", "Cortina Systems", "RAM Components", "Raqia Networks",
224 "ClearSpeed", "Matsushita Battery", "Xelerated", "SimpleTech",
225 "Utron Technology", "Astec International", "AVM gmbH", "Redux Communications",
226 "Dot Hill Systems", "TeraChip"],
227["T-RAM Incorporated", "Innovics Wireless", "Teknovus", "KeyEye Communications",
228 "Runcom Technologies", "RedSwitch", "Dotcast", "Silicon Mountain Memory",
229 "Signia Technologies", "Pixim", "Galazar Networks", "White Electronic Designs",
230 "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", "Europe Technologies",
231 "Potentia Power Systems", "C-guys Incorporated", "Digital Communications Technology Incorporated", "Silicon-Based Technology",
232 "Fulcrum Microsystems", "Positivo Informatica Ltd", "XIOtech Corporation", "PortalPlayer",
233 "Zhiying Software", "Direct2Data", "Phonex Broadband", "Skyworks Solutions",
234 "Entropic Communications", "Pacific Force Technology", "Zensys A/S", "Legend Silicon Corp.",
235 "sci-worx GmbH", "Oasis Silicon Systems", "Renesas Technology", "Raza Microelectronics",
236 "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
237 "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
238 "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
239 "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
240 "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
241 "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
242 "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", "Bandspeed",
243 "LeWiz Communications", "CPU Technology", "Ramaxel Technology", "DSP Group",
244 "Axis Communications", "Legacy Electronics", "Chrontel", "Powerchip Semiconductor",
245 "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", "VirtualDigm",
246 "G Skill Intl", "Quanta Computer", "Yield Microelectronics", "Afa Technologies",
247 "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", "Advance Modules",
248 "Microsoft", "Open-Silicon", "Goal Semiconductor", "ARC International",
249 "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
250 "Adimos", "SiGe Semiconductor", "Fodus Communications", "Credence Systems Corp.",
251 "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", "GateChange Technologies",
252 "High Density Devices AS", "Synopsys", "Gigaram", "Enigma Semiconductor Inc.",
253 "Century Micro Inc.", "Icera Semiconductor", "Mediaworks Integrated Systems", "O'Neil Product Development",
254 "Supreme Top Technology Ltd.", "MicroDisplay Corporation", "Team Group Inc.", "Sinett Corporation",
255 "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
256 "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", "Wisair Ltd.",
257 "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", "Eudar Technology Inc.",
258 "Focus Enhancements", "Xyratex"],
259["Specular Networks", "Patriot Memory", "U-Chip Technology Corp.", "Silicon Optix",
260 "Greenfield Networks", "CompuRAM GmbH", "Stargen, Inc.", "NetCell Corporation",
261 "Excalibrus Technologies Ltd", "SCM Microsystems", "Xsigo Systems, Inc.", "CHIPS & Systems Inc",
262 "Tier 1 Multichip Solutions", "CWRL Labs", "Teradici", "Gigaram, Inc.",
263 "g2 Microsystems", "PowerFlash Semiconductor", "P.A. Semi, Inc.", "NovaTech Solutions, S.A.",
264 "c2 Microsystems, Inc.", "Level5 Networks", "COS Memory AG", "Innovasic Semiconductor",
265 "02IC Co. Ltd", "Tabula, Inc.", "Crucial Technology", "Chelsio Communications",
266 "Solarflare Communications", "Xambala Inc.", "EADS Astrium", "ATO Semicon Co. Ltd.",
267 "Imaging Works, Inc.", "Astute Networks, Inc.", "Tzero", "Emulex",
268 "Power-One", "Pulse~LINK Inc.", "Hon Hai Precision Industry", "White Rock Networks Inc.",
269 "Telegent Systems USA, Inc.", "Atrua Technologies, Inc.", "Acbel Polytech Inc.",
270 "eRide Inc.","ULi Electronics Inc.", "Magnum Semiconductor Inc.", "neoOne Technology, Inc.",
271 "Connex Technology, Inc.", "Stream Processors, Inc.", "Focus Enhancements", "Telecis Wireless, Inc.",
272 "uNav Microelectronics", "Tarari, Inc.", "Ambric, Inc.", "Newport Media, Inc.", "VMTS",
273 "Enuclia Semiconductor, Inc.", "Virtium Technology Inc.", "Solid State System Co., Ltd.", "Kian Tech LLC",
274 "Artimi", "Power Quotient International", "Avago Technologies", "ADTechnology", "Sigma Designs",
275 "SiCortex, Inc.", "Ventura Technology Group", "eASIC", "M.H.S. SAS", "Micro Star International", 
276 "Rapport Inc.", "Makway International", "Broad Reach Engineering Co.", 
277 "Semiconductor Mfg Intl Corp", "SiConnect", "FCI USA Inc.", "Validity Sensors", 
278 "Coney Technology Co. Ltd.", "Spans Logic", "Neterion Inc."]);
279
280$use_sysfs = -d '/sys/bus';
281
282# We consider that no data was written to this area of the SPD EEPROM if
283# all bytes read 0x00 or all bytes read 0xff
284sub spd_written(@)
285{
286        my $all_00 = 1;
287        my $all_ff = 1;
288       
289        foreach my $b (@_) {
290                $all_00 = 0 unless $b == 0x00;
291                $all_ff = 0 unless $b == 0xff;
292                return 1 unless $all_00 or $all_ff;
293        }
294
295        return 0;
296}
297
298sub parity($)
299{
300        my $n = shift;
301        my $parity = 0;
302
303        while ($n) {
304                $parity++ if ($n & 1);
305                $n >>= 1;
306        }
307
308        return ($parity & 1);
309}
310
311sub manufacturer(@)
312{
313        my @bytes = @_;
314        my $ai = 0;
315        my $first;
316
317        return ("Undefined", []) unless spd_written(@bytes);
318       
319        while (defined($first = shift(@bytes)) && $first == 0x7F) {
320                $ai++;
321        }
322
323        return ("Invalid", []) unless defined $first;
324        return ("Invalid", [$first, @bytes]) if parity($first) != 1;
325        return ("Unknown", \@bytes) unless (($first & 0x7F) - 1 <= $vendors[$ai]);
326
327        return ($vendors[$ai][($first & 0x7F) - 1], \@bytes);
328}
329
330sub manufacturer_data(@)
331{
332        my $hex = "";
333        my $asc = "";
334
335        return unless spd_written(@_);
336
337        foreach my $byte (@_) {
338                $hex .= sprintf("\%02X ", $byte);
339                $asc .= ($byte >= 32 && $byte < 127) ? chr($byte) : '?';
340        }
341
342        return "$hex(\"$asc\")";
343}
344
345sub part_number(@)
346{
347        my $asc = "";
348        my $byte;
349
350        while (defined ($byte = shift) && $byte >= 32 && $byte < 127) {
351                $asc .= chr($byte);
352        }
353
354        return ($asc eq "") ? "Undefined" : $asc;
355}
356
357sub printl ($$) # print a line w/ label and value
358{
359        my ($label, $value) = @_;
360        if ($opt_html) {
361                $label =~ s/</\&lt;/sg;
362                $label =~ s/>/\&gt;/sg;
363                $label =~ s/\n/<br>\n/sg;
364                $value =~ s/</\&lt;/sg;
365                $value =~ s/>/\&gt;/sg;
366                $value =~ s/\n/<br>\n/sg;
367                print "<tr><td valign=top>$label</td><td>$value</td></tr>\n";
368        } else {
369                my @values = split /\n/, $value;
370                printf "%-47s %-32s\n", $label, shift @values;
371                printf "%-47s %-32s\n", "", $_ foreach (@values);
372        }
373}
374
375sub printl2 ($$) # print a line w/ label and value (outside a table)
376{
377        my ($label, $value) = @_;
378        if ($opt_html) {
379                $label =~ s/</\&lt;/sg;
380                $label =~ s/>/\&gt;/sg;
381                $label =~ s/\n/<br>\n/sg;
382                $value =~ s/</\&lt;/sg;
383                $value =~ s/>/\&gt;/sg;
384                $value =~ s/\n/<br>\n/sg;
385        }
386        print "$label: $value\n";
387}
388
389sub prints ($) # print seperator w/ given text
390{
391        my ($label) = @_;
392        if ($opt_html) {
393                $label =~ s/</\&lt;/sg;
394                $label =~ s/>/\&gt;/sg;
395                $label =~ s/\n/<br>\n/sg;
396                print "<tr><td align=center colspan=2><b>$label</b></td></tr>\n";
397        } else {
398                print "\n---=== $label ===---\n";
399        }
400}
401
402sub printh ($) # print header w/ given text
403{
404        my ($label) = @_;
405        if ($opt_html) {
406                $label =~ s/</\&lt;/sg;
407                $label =~ s/>/\&gt;/sg;
408                $label =~ s/\n/<br>\n/sg;
409                print "<h1>$label</h1>\n";
410        } else {
411                print "\n$label\n";
412        }
413}
414
415# Parameter: bytes 0-63
416sub decode_sdr_sdram($)
417{
418        my $bytes = shift;
419        my ($l, $temp);
420
421#size computation
422
423        my $a = $bytes->[3];
424        my $b = $bytes->[4];
425        my $c = $bytes->[5];
426        my $d = $bytes->[17];
427        my $k=0;
428        my $ii=0;
429       
430        $ii = (($a) & 0x0f) + (( $b) & 0x0f) - 17;
431        if (( $c <= 8) && ( $d <= 8)) {
432                 $k = ( $c) * ( $d);
433        }
434       
435        if($ii > 0 && $ii <= 12 && $k > 0) {
436                printl "Size", ((1 << $ii) * $k) . " MB"; }
437        else { 
438                printl "INVALID SIZE", $a . "," . $b . "," . $c . "," . $d;
439        }
440
441        my @cas;
442        for ($ii = 0; $ii < 7; $ii++) {
443                push(@cas, $ii + 1) if ($bytes->[18] & (1 << $ii));
444        }
445
446        my $trcd;
447        my $trp;
448        my $tras;
449        my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
450
451        $trcd =$bytes->[29];
452        $trp =$bytes->[27];;
453        $tras =$bytes->[30];
454
455        printl "tCL-tRCD-tRP-tRAS",
456                $cas[$#cas] . "-" .
457                ceil($trcd/$ctime) . "-" .
458                ceil($trp/$ctime) . "-" .
459                ceil($tras/$ctime);
460
461        $l = "Number of Row Address Bits";
462        if ($bytes->[3] == 0) { printl $l, "Undefined!"; }
463        elsif ($bytes->[3] == 1) { printl $l, "1/16"; }
464        elsif ($bytes->[3] == 2) { printl $l, "2/17"; }
465        elsif ($bytes->[3] == 3) { printl $l, "3/18"; }
466        else { printl $l, $bytes->[3]; }
467
468        $l = "Number of Col Address Bits";
469        if ($bytes->[4] == 0) { printl $l, "Undefined!"; }
470        elsif ($bytes->[4] == 1) { printl $l, "1/16"; }
471        elsif ($bytes->[4] == 2) { printl $l, "2/17"; }
472        elsif ($bytes->[4] == 3) { printl $l, "3/18"; }
473        else { printl $l, $bytes->[4]; }
474
475        $l = "Number of Module Rows";
476        if ($bytes->[5] == 0 ) { printl $l, "Undefined!"; }
477        else { printl $l, $bytes->[5]; }
478
479        $l = "Data Width";
480        if ($bytes->[7] > 1) {
481                printl $l, "Undefined!"
482        } else {
483                $temp = ($bytes->[7] * 256) + $bytes->[6];
484                printl $l, $temp;
485        }
486
487        $l = "Module Interface Signal Levels";
488        if ($bytes->[8] == 0) { printl $l, "5.0 Volt/TTL"; }
489        elsif ($bytes->[8] == 1) { printl $l, "LVTTL"; }
490        elsif ($bytes->[8] == 2) { printl $l, "HSTL 1.5"; }
491        elsif ($bytes->[8] == 3) { printl $l, "SSTL 3.3"; }
492        elsif ($bytes->[8] == 4) { printl $l, "SSTL 2.5"; }
493        elsif ($bytes->[8] == 255) { printl $l, "New Table"; }
494        else { printl $l, "Undefined!"; }
495
496        $l = "Module Configuration Type";
497        if ($bytes->[11] == 0) { printl $l, "No Parity"; }
498        elsif ($bytes->[11] == 1) { printl $l, "Parity"; }
499        elsif ($bytes->[11] == 2) { printl $l, "ECC"; }
500        else { printl $l, "Undefined!"; }
501
502        $l = "Refresh Type";
503        if ($bytes->[12] > 126) { printl $l, "Self Refreshing"; }
504        else { printl $l, "Not Self Refreshing"; }
505
506        $l = "Refresh Rate";
507        $temp = $bytes->[12] & 0x7f;
508        if ($temp == 0) { printl $l, "Normal (15.625 us)"; }
509        elsif ($temp == 1) { printl $l, "Reduced (3.9 us)"; }
510        elsif ($temp == 2) { printl $l, "Reduced (7.8 us)"; }
511        elsif ($temp == 3) { printl $l, "Extended (31.3 us)"; }
512        elsif ($temp == 4) { printl $l, "Extended (62.5 us)"; }
513        elsif ($temp == 5) { printl $l, "Extended (125 us)"; }
514        else { printl $l, "Undefined!"; }
515
516        $l = "Primary SDRAM Component Bank Config";
517        if ($bytes->[13] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
518        else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
519
520        $l = "Primary SDRAM Component Widths";
521        $temp = $bytes->[13] & 0x7f;
522        if ($temp == 0) { printl $l, "Undefined!\n"; }
523        else { printl $l, $temp; }
524
525        $l = "Error Checking SDRAM Component Bank Config";
526        if ($bytes->[14] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
527        else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
528
529        $l = "Error Checking SDRAM Component Widths";
530        $temp = $bytes->[14] & 0x7f;
531        if ($temp == 0) { printl $l, "Undefined!"; }
532        else { printl $l, $temp; }
533
534        $l = "Min Clock Delay for Back to Back Random Access";
535        if ($bytes->[15] == 0) { printl $l, "Undefined!"; }
536        else { printl $l, $bytes->[15]; }
537
538        prints "The Following Apply to SDRAM DIMMs ONLY";
539
540        $l = "Burst lengths supported";
541        my @array;
542        for ($ii = 0; $ii < 4; $ii++) {
543                push(@array, 1 << $ii) if ($bytes->[16] & (1 << $ii));
544        }
545        push(@array, "Page") if ($bytes->[16] & 128);
546        if (@array) { $temp = join ', ', @array; }
547        else { $temp = "None"; }
548        printl $l, $temp;
549
550        $l = "Number of Device Banks";
551        if ($bytes->[17] == 0) { printl $l, "Undefined/Reserved!"; }
552        else { printl $l, $bytes->[17]; }
553
554        $l = "Supported CAS Latencies";
555        if (@cas) { $temp = join ', ', @cas; }
556        else { $temp = "None"; }
557        printl $l, $temp;
558
559        $l = "Supported CS Latencies";
560        @array = ();
561        for ($ii = 0; $ii < 7; $ii++) {
562                push(@array, $ii) if ($bytes->[19] & (1 << $ii));
563        }
564        if (@array) { $temp = join ', ', @array; }
565        else { $temp = "None"; }
566        printl $l, $temp;
567
568        $l = "Supported WE Latencies";
569        @array = ();
570        for ($ii = 0; $ii < 7; $ii++) {
571                push(@array, $ii) if ($bytes->[20] & (1 << $ii));
572        }
573        if (@array) { $temp = join ', ', @array; }
574        else { $temp = "None"; }
575        printl $l, $temp;
576
577        if (@cas >= 1) {
578                $l = "Cycle Time (CAS ".$cas[$#cas].")";
579                $temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
580                printl $l, "$temp ns";
581
582                $l = "Access Time (CAS ".$cas[$#cas].")";
583                $temp = ($bytes->[10] >> 4) + ($bytes->[10] & 0xf) * 0.1;
584                printl $l, "$temp ns";
585        }
586
587        if (@cas >= 2 && spd_written(@$bytes[23..24])) {
588                $l = "Cycle Time (CAS ".$cas[$#cas-1].")";
589                $temp = $bytes->[23] >> 4;
590                if ($temp == 0) { printl $l, "Undefined!"; }
591                else {
592                        if ($temp < 4 ) { $temp=$temp + 15; }
593                        printl $l, $temp + (($bytes->[23] & 0xf) * 0.1) . " ns";
594                }
595
596                $l = "Access Time (CAS ".$cas[$#cas-1].")";
597                $temp = $bytes->[24] >> 4;
598                if ($temp == 0) { printl $l, "Undefined!"; }
599                else {
600                        if ($temp < 4 ) { $temp=$temp + 15; }
601                        printl $l, $temp + (($bytes->[24] & 0xf) * 0.1) . " ns";
602                }
603        }
604
605        if (@cas >= 3 && spd_written(@$bytes[25..26])) {
606                $l = "Cycle Time (CAS ".$cas[$#cas-2].")";
607                $temp = $bytes->[25] >> 2;
608                if ($temp == 0) { printl $l, "Undefined!"; }
609                else { printl $l, $temp + ($bytes->[25] & 0x3) * 0.25 . " ns"; }
610
611                $l = "Access Time (CAS ".$cas[$#cas-2].")";
612                $temp = $bytes->[26] >> 2;
613                if ($temp == 0) { printl $l, "Undefined!"; }
614                else { printl $l, $temp + ($bytes->[26] & 0x3) * 0.25 . " ns"; }
615        }
616
617        $l = "SDRAM Module Attributes";
618        $temp = "";
619        if ($bytes->[21] & 1) { $temp .= "Buffered Address/Control Inputs\n"; }
620        if ($bytes->[21] & 2) { $temp .= "Registered Address/Control Inputs\n"; }
621        if ($bytes->[21] & 4) { $temp .= "On card PLL (clock)\n"; }
622        if ($bytes->[21] & 8) { $temp .= "Buffered DQMB Inputs\n"; }
623        if ($bytes->[21] & 16) { $temp .= "Registered DQMB Inputs\n"; }
624        if ($bytes->[21] & 32) { $temp .= "Differential Clock Input\n"; }
625        if ($bytes->[21] & 64) { $temp .= "Redundant Row Address\n"; }
626        if ($bytes->[21] & 128) { $temp .= "Undefined (bit 7)\n"; }
627        if ($bytes->[21] == 0) { $temp .= "(None Reported)\n"; }
628        printl $l, $temp;
629
630        $l = "SDRAM Device Attributes (General)";
631        $temp = "";
632        if ($bytes->[22] & 1) { $temp .= "Supports Early RAS# Recharge\n"; }
633        if ($bytes->[22] & 2) { $temp .= "Supports Auto-Precharge\n"; }
634        if ($bytes->[22] & 4) { $temp .= "Supports Precharge All\n"; }
635        if ($bytes->[22] & 8) { $temp .= "Supports Write1/Read Burst\n"; }
636        if ($bytes->[22] & 16) { $temp .= "Lower VCC Tolerance: 5%\n"; }
637        else { $temp .= "Lower VCC Tolerance: 10%\n"; }
638        if ($bytes->[22] & 32) { $temp .= "Upper VCC Tolerance: 5%\n"; }
639        else { $temp .= "Upper VCC Tolerance: 10%\n"; }
640        if ($bytes->[22] & 64) { $temp .= "Undefined (bit 6)\n"; }
641        if ($bytes->[22] & 128) { $temp .= "Undefined (bit 7)\n"; }
642        printl $l, $temp;
643
644        prints "The Following are Required (for SDRAMs)";
645
646        $l = "Minimum Row Precharge Time";
647        if ($bytes->[27] == 0) { printl $l, "Undefined!"; }
648        else { printl $l, "$bytes->[27] ns"; }
649
650        $l = "Row Active to Row Active Min";
651        if ($bytes->[28] == 0) { printl $l, "Undefined!"; }
652        else { printl $l, "$bytes->[28] ns"; }
653
654        $l = "RAS to CAS Delay";
655        if ($bytes->[29] == 0) { printl $l, "Undefined!"; }
656        else { printl $l, "$bytes->[29] ns"; }
657
658        $l = "Min RAS Pulse Width";
659        if ($bytes->[30] == 0) { printl $l, "Undefined!"; }
660        else { printl $l, "$bytes->[30] ns"; }
661
662        prints "The Following are Required and Apply to ALL DIMMs";
663
664        $l = "Row Densities";
665        $temp = "";
666        if ($bytes->[31] & 1) { $temp .= "4 MByte\n"; }
667        if ($bytes->[31] & 2) { $temp .= "8 MByte\n"; }
668        if ($bytes->[31] & 4) { $temp .= "16 MByte\n"; }
669        if ($bytes->[31] & 8) { $temp .= "32 MByte\n"; }
670        if ($bytes->[31] & 16) { $temp .= "64 MByte\n"; }
671        if ($bytes->[31] & 32) { $temp .= "128 MByte\n"; }
672        if ($bytes->[31] & 64) { $temp .= "256 MByte\n"; }
673        if ($bytes->[31] & 128) { $temp .= "512 MByte\n"; }
674        if ($bytes->[31] == 0) { $temp .= "(Undefined! -- None Reported!)\n"; }
675        printl $l, $temp;
676
677        prints "The Following are Proposed and Apply to SDRAM DIMMs";
678
679        $l = "Command and Address Signal Setup Time";
680        $temp = (($bytes->[32] & 0x7f) >> 4) + ($bytes->[32] & 0xf) * 0.1;
681        printl $l, (($bytes->[32] >> 7) ? -$temp : $temp) . " ns";
682
683        $l = "Command and Address Signal Hold Time";
684        $temp = (($bytes->[33] & 0x7f) >> 4) + ($bytes->[33] & 0xf) * 0.1;
685        printl $l, (($bytes->[33] >> 7) ? -$temp : $temp) . " ns";
686
687        $l = "Data Signal Setup Time";
688        $temp = (($bytes->[34] & 0x7f) >> 4) + ($bytes->[34] & 0xf) * 0.1;
689        printl $l, (($bytes->[34] >> 7) ? -$temp : $temp) . " ns";
690
691        $l = "Data Signal Hold Time";
692        $temp = (($bytes->[35] & 0x7f) >> 4) + ($bytes->[35] & 0xf) * 0.1;
693        printl $l, (($bytes->[35] >> 7) ? -$temp : $temp) . " ns";
694}
695
696# Parameter: bytes 0-63
697sub decode_ddr_sdram($)
698{
699        my $bytes = shift;
700        my ($l, $temp);
701
702        $l = "Maximum module speed";
703        $temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
704        my $ddrclk = 2 * (1000 / $temp);
705        my $tbits = ($bytes->[7] * 256) + $bytes->[6];
706        if (($bytes->[11] == 2) || ($bytes->[11] == 1)) { $tbits = $tbits - 8; }
707        my $pcclk = int ($ddrclk * $tbits / 8);
708        $pcclk += 100 if ($pcclk % 100) >= 50; # Round properly
709        $pcclk = $pcclk - ($pcclk % 100);
710        $ddrclk = int ($ddrclk);
711        printl $l, "${ddrclk}MHz (PC${pcclk})";
712
713#size computation
714
715        my $k=0;
716        my $ii=0;
717       
718        $ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
719        if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) {
720                 $k = $bytes->[5] * $bytes->[17];
721        }
722       
723        if($ii > 0 && $ii <= 12 && $k > 0) {
724                printl "Size", ((1 << $ii) * $k) . " MB"; }
725        else { 
726                printl "INVALID SIZE", $bytes->[3] . ", " . $bytes->[4] . ", " .
727                                       $bytes->[5] . ", " . $bytes->[17];
728        }
729
730        my $highestCAS = 0;
731        my %cas;
732        for ($ii = 0; $ii < 7; $ii++) {
733                if ($bytes->[18] & (1 << $ii)) {
734                        $highestCAS = 1+$ii*0.5;
735                        $cas{$highestCAS}++;
736                }
737        }
738
739        my $trcd;
740        my $trp;
741        my $tras;
742        my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
743
744        $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25);
745        $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25);
746        $tras = $bytes->[30];
747
748        printl "tCL-tRCD-tRP-tRAS",
749                $highestCAS . "-" .
750                ceil($trcd/$ctime) . "-" .
751                ceil($trp/$ctime) . "-" .
752                ceil($tras/$ctime);
753
754# latencies
755        if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; }
756        else { $temp = "None"; }
757        printl "Supported CAS Latencies", $temp;
758
759        my @array;
760        for ($ii = 0; $ii < 7; $ii++) {
761                push(@array, $ii) if ($bytes->[19] & (1 << $ii));
762        }
763        if (@array) { $temp = join ', ', @array; }
764        else { $temp = "None"; }
765        printl "Supported CS Latencies", $temp;
766
767        @array = ();
768        for ($ii = 0; $ii < 7; $ii++) {
769                push(@array, $ii) if ($bytes->[20] & (1 << $ii));
770        }
771        if (@array) { $temp = join ', ', @array; }
772        else { $temp = "None"; }
773        printl "Supported WE Latencies", $temp;
774
775# timings
776        if (exists $cas{$highestCAS}) {
777                printl "Minimum Cycle Time (CAS $highestCAS)",
778                       "$ctime ns";
779
780                printl "Maximum Access Time (CAS $highestCAS)",
781                       (($bytes->[10] >> 4) * 0.1 + ($bytes->[10] & 0xf) * 0.01) . " ns";
782        }
783
784        if (exists $cas{$highestCAS-0.5} && spd_written(@$bytes[23..24])) {
785                printl "Minimum Cycle Time (CAS ".($highestCAS-0.5).")",
786                       (($bytes->[23] >> 4) + ($bytes->[23] & 0xf) * 0.1) . " ns";
787
788                printl "Maximum Access Time (CAS ".($highestCAS-0.5).")",
789                       (($bytes->[24] >> 4) * 0.1 + ($bytes->[24] & 0xf) * 0.01) . " ns";
790        }
791
792        if (exists $cas{$highestCAS-1} && spd_written(@$bytes[25..26])) {
793                printl "Minimum Cycle Time (CAS ".($highestCAS-1).")",
794                       (($bytes->[25] >> 4) + ($bytes->[25] & 0xf) * 0.1) . " ns";
795
796                printl "Maximum Access Time (CAS ".($highestCAS-1).")",
797                       (($bytes->[26] >> 4) * 0.1 + ($bytes->[26] & 0xf) * 0.01) . " ns";
798        }
799
800# module attributes
801        if ($bytes->[47] & 0x03) {
802                if (($bytes->[47] & 0x03) == 0x01) { $temp = "1.125\" to 1.25\""; }
803                elsif (($bytes->[47] & 0x03) == 0x02) { $temp = "1.7\""; }
804                elsif (($bytes->[47] & 0x03) == 0x03) { $temp = "Other"; }
805                printl "Module Height", $temp;
806        }
807}
808
809# Parameter: bytes 0-63
810sub decode_ddr2_sdram($)
811{
812        my $bytes = shift;
813        my ($l, $temp);
814
815        $l = "Maximum module speed";
816        $temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
817        my $ddrclk = 4 * (1000 / $temp);
818        my $tbits = ($bytes->[7] * 256) + $bytes->[6];
819        if (($bytes->[11] == 2) || ($bytes->[11] == 1)) { $tbits = $tbits - 8; }
820        my $pcclk = int ($ddrclk * $tbits / 8);
821        $pcclk += 100 if ($pcclk % 100) >= 50; # Round properly
822        $pcclk = $pcclk - ($pcclk % 100);
823        $ddrclk = int ($ddrclk);
824        printl $l, "${ddrclk}MHz (PC${pcclk})";
825
826#size computation
827        my $a = $bytes->[3];
828        my $b = $bytes->[4];
829        my $c = $bytes->[5];
830        my $d = $bytes->[17];
831        my $k=0;
832        my $ii=0;
833
834        $ii = ($a & 0x0f) + ($b & 0x0f) - 17;
835        $k = (($c & 0x7) + 1) * $d;
836       
837        if($ii > 0 && $ii <= 12 && $k > 0) {
838                printl "Size", ((1 << $ii) * $k) . " MB"; 
839        } else {
840                printl "INVALID SIZE", $a . "," . $b . "," . $c . "," . $d;
841        }
842
843        my $highestCAS = 0;
844        my $trcd;
845        my $trp;
846        my $tras;
847        my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
848
849        if ($bytes->[18] & 4) { $highestCAS = 2; }
850        if ($bytes->[18] & 8) { $highestCAS = 3; }
851        if ($bytes->[18] & 16) { $highestCAS = 4; }
852        if ($bytes->[18] & 32) { $highestCAS = 5; }
853       
854        $trcd =($bytes->[29] >> 2)+(($bytes->[29] & 3)*0.25);
855        $trp =($bytes->[27] >> 2)+(($bytes->[27] & 3)*0.25);
856        $tras =$bytes->[30];
857
858        printl "tCL-tRCD-tRP-tRAS",
859                $highestCAS . "-" .
860                ceil($trcd/$ctime) . "-" .
861                ceil($trp/$ctime) . "-" .
862                ceil($tras/$ctime);
863}
864
865%decode_callback = (
866        "SDR SDRAM"     => \&decode_sdr_sdram,
867        "DDR SDRAM"     => \&decode_ddr_sdram,
868        "DDR2 SDRAM"    => \&decode_ddr2_sdram,
869);
870
871# Parameter: bytes 64-127
872sub decode_intel_spec_freq($)
873{
874        my $bytes = shift;
875        my ($l, $temp);
876
877        $l = "Intel Specification for Frequency";
878        if ($bytes->[62] == 0x66) { $temp = "66MHz\n"; }
879        elsif ($bytes->[62] == 100) { $temp = "100MHz or 133MHz\n"; }
880        elsif ($bytes->[62] == 133) { $temp = "133MHz\n"; }
881        else { $temp = "Undefined!\n"; }
882        printl $l, $temp;
883
884        $l = "Intel Spec Details for 100MHz Support";
885        $temp="";
886        if ($bytes->[63] & 1) { $temp .= "Intel Concurrent Auto-precharge\n"; }
887        if ($bytes->[63] & 2) { $temp .= "CAS Latency = 2\n"; }
888        if ($bytes->[63] & 4) { $temp .= "CAS Latency = 3\n"; }
889        if ($bytes->[63] & 8) { $temp .= "Junction Temp A (100 degrees C)\n"; }
890        else { $temp .= "Junction Temp B (90 degrees C)\n"; }
891        if ($bytes->[63] & 16) { $temp .= "CLK 3 Connected\n"; }
892        if ($bytes->[63] & 32) { $temp .= "CLK 2 Connected\n"; }
893        if ($bytes->[63] & 64) { $temp .= "CLK 1 Connected\n"; }
894        if ($bytes->[63] & 128) { $temp .= "CLK 0 Connected\n"; }
895        if (($bytes->[63] & 192) == 192) { $temp .= "Double-sided DIMM\n"; }
896        elsif (($bytes->[63] & 192) != 0) { $temp .= "Single-sided DIMM\n"; }
897        printl $l, $temp;
898}
899
900sub readspd64 ($$) { # reads 64 bytes from SPD-EEPROM
901        my ($offset, $dimm_i) = @_;
902        my @bytes;
903        if ($use_sysfs) {
904                # Kernel 2.6 with sysfs
905                sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
906                        or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
907                binmode HANDLE;
908                sysseek(HANDLE, $offset, SEEK_SET);
909                sysread(HANDLE, my $eeprom, 64);
910                close HANDLE;
911                @bytes = unpack("C64", $eeprom);
912        } else {
913                # Kernel 2.4 with procfs
914                for my $i (0 .. 3) {
915                        my $hexoff = sprintf('%02x', $offset + $i * 16);
916                        push @bytes, split(" ", `cat /proc/sys/dev/sensors/$dimm_i/$hexoff`);
917                }
918        }
919        return @bytes;
920}
921
922for (@ARGV) {
923    if (/-h/) {
924                print "Usage: $0 [-c] [-f [-b]]\n",
925                        "       $0 -h\n\n",
926                        "  -f, --format            print nice html output\n",
927                        "  -b, --bodyonly          don't print html header\n",
928                        "                          (useful for postprocessing the output)\n",
929                        "  -c, --checksum          decode completely even if checksum fails\n",
930                        "  -h, --help              display this usage summary\n";
931                exit;
932    }
933    $opt_html = 1 if (/-f/);
934    $opt_bodyonly = 1 if (/-b/);
935    $opt_igncheck = 1 if (/-c/);
936}
937$opt_body = $opt_html && ! $opt_bodyonly;
938
939if ($opt_body)
940{
941        print "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
942              "<html><head>\n",
943                  "\t<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n",
944                  "\t<title>PC DIMM Serial Presence Detect Tester/Decoder Output</title>\n",
945                  "</head><body>\n";
946}
947
948printh 'PC DIMM Serial Presence Detect Tester/Decoder
949By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
950Jean Delvare and others
951Version 2.10.1';
952
953
954my $dimm_count=0;
955if ($use_sysfs) { $_=`ls /sys/bus/i2c/drivers/eeprom`; }
956else { $_=`ls /proc/sys/dev/sensors/`; }
957my @dimm_list=split();
958
959for my $i ( 0 .. $#dimm_list ) {
960        $_=$dimm_list[$i];
961        if (($use_sysfs && /^\d+-\d+$/)
962         || (!$use_sysfs && /^eeprom-/)) {
963                print "<b><u>" if $opt_html;
964                printl2 "\n\nDecoding EEPROM", ($use_sysfs ?
965                        "/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
966                        "/proc/sys/dev/sensors/$dimm_list[$i]");
967                print "</u></b>" if $opt_html;
968                print "<table border=1>\n" if $opt_html;
969                if (($use_sysfs && /^[^-]+-([^-]+)$/)
970                 || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
971                        my $dimm_num=$1 - 49;
972                        printl "Guessing DIMM is in", "bank $dimm_num";
973                }
974
975# Decode first 3 bytes (0-2)
976                prints "The Following is Required Data and is Applicable to all DIMM Types";
977
978                my @bytes = readspd64(0, $dimm_list[$i]);
979                my $dimm_checksum = 0;
980                $dimm_checksum += $bytes[$_] foreach (0 .. 62);
981                $dimm_checksum &= 0xff;
982
983                my $l = "EEPROM Checksum of bytes 0-62";
984                printl $l, ($bytes[63] == $dimm_checksum ?
985                        sprintf("OK (0x%.2X)", $bytes[63]):
986                        sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n",
987                                $bytes[63], $dimm_checksum));
988
989                next unless $bytes[63] == $dimm_checksum or $opt_igncheck;
990               
991                $dimm_count++;
992                # Simple heuristic to detect Rambus
993                my $is_rambus = $bytes[0] < 4;
994                my $temp;
995                if ($is_rambus) {
996                        if ($bytes[0] == 1) { $temp = "0.7"; }
997                        elsif ($bytes[0] == 2) { $temp = "1.0"; }
998                        elsif ($bytes[0] == 0 || $bytes[0] == 255) { $temp = "Invalid"; }
999                        else { $temp = "Reserved"; }
1000                        printl "SPD Revision", $temp;
1001                } else {
1002                        printl "# of bytes written to SDRAM EEPROM",
1003                               $bytes[0];
1004                }
1005
1006                $l = "Total number of bytes in EEPROM";
1007                if ($bytes[1] <= 14) {
1008                        printl $l, 2**$bytes[1];
1009                } elsif ($bytes[1] == 0) {
1010                        printl $l, "RFU"; 
1011                } else { printl $l, "ERROR!"; }
1012
1013                $l = "Fundamental Memory type";
1014                my $type = "Unknown";
1015                if ($is_rambus) {
1016                        if ($bytes[2] == 1) { $type = "Direct Rambus"; }
1017                        elsif ($bytes[2] == 17) { $type = "Rambus"; }
1018                } else {
1019                        if ($bytes[2] == 1) { $type = "FPM DRAM"; }
1020                        elsif ($bytes[2] == 2) { $type = "EDO"; }
1021                        elsif ($bytes[2] == 3) { $type = "Pipelined Nibble"; }
1022                        elsif ($bytes[2] == 4) { $type = "SDR SDRAM"; }
1023                        elsif ($bytes[2] == 5) { $type = "Multiplexed ROM"; }
1024                        elsif ($bytes[2] == 6) { $type = "DDR SGRAM"; }
1025                        elsif ($bytes[2] == 7) { $type = "DDR SDRAM"; }
1026                        elsif ($bytes[2] == 8) { $type = "DDR2 SDRAM"; }
1027                }
1028                printl $l, $type;
1029
1030# Decode next 59 bytes (3-61, depend on memory type)
1031                $decode_callback{$type}->(\@bytes)
1032                        if exists $decode_callback{$type};
1033
1034# Decode next 2 bytes (62-63)
1035                printl "SPD Revision code ", sprintf("%x", $bytes[62]);
1036
1037# Decode next 35 bytes (64-98, common to all memory types)
1038                @bytes = readspd64(64, $dimm_list[$i]);
1039               
1040                $l = "Manufacturer";
1041                # $extra is a reference to an array containing up to
1042                # 7 extra bytes from the Manufacturer field. Sometimes
1043                # these bytes are filled with interesting data.
1044                ($temp, my $extra) = manufacturer(@bytes[0..7]);
1045                printl $l, $temp;
1046                $l = "Custom Manufacturer Data";
1047                $temp = manufacturer_data(@{$extra});
1048                printl $l, $temp if defined $temp;
1049               
1050                if (spd_written($bytes[8])) {
1051                        # Try the location code as ASCII first, as earlier specifications
1052                        # suggested this. As newer specifications don't mention it anymore,
1053                        # we still fall back to binary.
1054                        $l = "Manufacturing Location Code";
1055                        $temp = (chr($bytes[8]) =~ m/^[\w\d]$/) ? chr($bytes[8])
1056                              : sprintf("0x%.2X", $bytes[8]);
1057                        printl $l, $temp;
1058                }
1059               
1060                $l = "Part Number";
1061                $temp = part_number(@bytes[9..26]);
1062                printl $l, $temp;
1063               
1064                if (spd_written(@bytes[27..28])) {
1065                        $l = "Revision Code";
1066                        $temp = sprintf("0x%02X%02X\n", @bytes[27..28]);
1067                        printl $l, $temp;
1068                }
1069               
1070                if (spd_written(@bytes[29..30])) {
1071                        $l = "Manufacturing Date";
1072                        # In theory the year and week are in BCD format, but
1073                        # this is not always true in practice :(
1074                        if (($bytes[29] & 0xf0) <= 0x90
1075                         && ($bytes[29] & 0x0f) <= 0x09
1076                         && ($bytes[30] & 0xf0) <= 0x90
1077                         && ($bytes[30] & 0x0f) <= 0x09) {
1078                                # Note that this heuristic will break in year 2080
1079                                $temp = sprintf("%d%02X-W%02X\n",
1080                                                $bytes[29] >= 0x80 ? 19 : 20,
1081                                                @bytes[29..30]);
1082                        } else {
1083                                $temp = sprintf("0x%02X%02X\n",
1084                                                @bytes[29..30]);
1085                        }
1086                        printl $l, $temp;
1087                }
1088               
1089                if (spd_written(@bytes[31..34])) {
1090                        $l = "Assembly Serial Number";
1091                        $temp = sprintf("0x%02X%02X%02X%02X\n",
1092                                        @bytes[31..34]);
1093                        printl $l, $temp;
1094                }
1095
1096# Next 27 bytes (99-125) are manufacturer specific, can't decode
1097
1098# Last 2 bytes (126-127) are reserved, Intel used them as an extension
1099                if ($type eq "SDR SDRAM") {
1100                        decode_intel_spec_freq(\@bytes);
1101                }
1102               
1103                print "</table>\n" if $opt_html;
1104        }
1105}
1106printl2 "\n\nNumber of SDRAM DIMMs detected and decoded", $dimm_count;
1107
1108print "</body></html>\n" if $opt_body;
Note: See TracBrowser for help on using the browser.