* Re: [PATCH] More DDR2 data for decode-dimms.pl [not found] ` <Pine.LNX.4.58.0802281401020.14140-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org> @ 2008-03-19 13:16 ` Jean Delvare [not found] ` <20080319141609.338c19b1-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 6+ messages in thread From: Jean Delvare @ 2008-03-19 13:16 UTC (permalink / raw) To: Trent Piepho; +Cc: Linux I2C Hi Trent, On Thu, 28 Feb 2008 14:19:02 -0800 (PST), Trent Piepho wrote: > This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms. > Including all the detailed timing parameters with their standard tXXX > names, useful if one is trying to program a DDR memory controller for > example. Thanks for doing this. Review: > Index: decode-dimms.pl > =================================================================== > --- i2c-tools/eeprom/decode-dimms.pl (revision 5132) > +++ i2c-tools/eeprom/decode-dimms.pl (working copy) > @@ -834,6 +834,20 @@ > return $atime; > } > > +sub ddrx_sdram_rtime($$$) > +{ > + my ($t, $b1, $b2) = @_; > + my $rtime = $b1; Please add a blank line here for a better readability. > + if($t == 2) { > + $rtime += ($b2 & 1) * 256; > + my @table = (0, .250, .330, .500, .660, .750); Not sure why you specify 3 decimal places when the last one is always 0? > + $rtime += $table[($b2>>1)&7]; Coding style: spaces around >> and &. Same in many places below. > + } > + return $rtime; > +} I don't understand the point of the first parameter ($t). The function is always called with $t = 2. If you ever needed to ignore $b2, rather than calling this function with $t = 1, you could simply pass $b2 = 0. Or even better, you wouldn't call ddrx_sdram_rtime() at all, as it would return $b1 directly. Please also name this function ddr2_sdram_rtime rather than ddrx_sdram_rtime. "x" in names adds to confusion, as the reader doesn't know what are the "valid values" of "x". > + > +sub tns($) { return sprintf("%3.2f ns", $_[0]); } Please unfold. This function should probably come earlier in the script, as we may want to use it for other memory module types in the future. > + > # Parameter: bytes 0-63 > sub decode_ddr2_sdram($) > { > @@ -875,6 +889,40 @@ > $bytes->[5] . "," . $bytes->[17]; > } > > + printl "Banks x Rows x Columns x Bits", > + join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]); > + printl "Ranks", ($bytes->[5]&7) + 1; > + > + printl "SDRAM Device Width", $bytes->[13]." bits"; > + > + my @heights = ("< 25.4", "25.4", "25.4 - 30.0", "30.0", "30.5", "> 30.5"); > + printl "Module Height", $heights[$bytes->[5]>>5]." mm"; > + my @types = ("RDIMM", "UDIMM", "SO-DIMM", "Micro-DIMM", > + "Mini-RDIMM", "Mini-UDIMM"); > + my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0); > + my @suptypes; > + foreach $ii (0..5) { > + push @suptypes, "$types[$ii] ($widths[$ii] mm)" > + if($bytes->[20] & (1<<$ii)); > + } > + printl "Module Type".(@suptypes>1?'s':''), join(', ', @suptypes); Coding style: doubled space. Maybe this could go to a subfunction for clarity? > + printl "DRAM Package", $bytes->[5]&0x10 ? "Stack" : "Planar"; > + > + my @volts = ("TTL/5V Tolerant", "LVTTL", "HSTL 1.5V", > + "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD"); > + printl "Voltage Interface Level", $volts[$bytes->[8]]; Not sure what sense it makes to have "TBD" in the list. Presumably all the values above 6 are "to be defined", not just 6. > + > + my @refresh = qw(Normal Reduced Reduced Extended Extended Extended); > + my @refresht = (15.625,3.9,7.8,31.3,62.5,125); Coding style: space after commas please, it is unreadable otherwise. > + printl "Refresh Rate", > + "$refresh[$bytes->[12]&0x7f] ($refresht[$bytes->[12]&0x7f] us)". > + ($bytes->[12]&0x80 ? " - Self Refresh" : ""); This too could go to a subfunction? > + > + my @burst; > + push @burst, 4 if ($bytes->[16] & 4); > + push @burst, 8 if ($bytes->[16] & 8); > + printl "Burst lengths supported", join(', ', @burst); Should be "Supported Burst Lengths" to look like the other items. > + > my $highestCAS = 0; > my %cas; > for ($ii = 2; $ii < 7; $ii++) { > @@ -899,31 +947,59 @@ > ceil($tras/$ctime); > > # latencies > - if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; } > + if (keys %cas) { $temp = join ', ', map("${_}T",sort { $b <=> $a } keys %cas); } Coding style: space after comma. Fine with me, but then we should probably do the same for SDR and DDR types (in a later patch), for consistency. > else { $temp = "None"; } > - printl "Supported CAS Latencies", $temp; > + printl "Supported CAS Latencies (tCL)", $temp; > > # timings > if (exists $cas{$highestCAS}) { > - printl "Minimum Cycle Time (CAS $highestCAS)", > - "$ctime ns"; > - printl "Maximum Access Time (CAS $highestCAS)", > - ddr2_sdram_atime($bytes->[10]) . " ns"; > + printl "Minimum Cycle Time @ CAS $highestCAS (tCK min)", > + tns($ctime); > + printl "Maximum Access Time @ CAS $highestCAS (tAC)", > + tns(ddr2_sdram_atime($bytes->[10])); > } s/@/at/ please. This too is a change that should be done for SDR and DDR types as well, for consistency. > > if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) { > - printl "Minimum Cycle Time (CAS ".($highestCAS-1).")", > - ddr2_sdram_ctime($bytes->[23]) . " ns"; > - printl "Maximum Access Time (CAS ".($highestCAS-1).")", > - ddr2_sdram_atime($bytes->[24]) . " ns"; > + printl "Minimum Cycle Time @ CAS ".($highestCAS-1), > + tns(ddr2_sdram_ctime($bytes->[23])); > + printl "Maximum Access Time @ CAS ".($highestCAS-1), > + tns(ddr2_sdram_atime($bytes->[24])); > } > > if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) { > - printl "Minimum Cycle Time (CAS ".($highestCAS-2).")", > - ddr2_sdram_ctime($bytes->[25]) . " ns"; > - printl "Maximum Access Time (CAS ".($highestCAS-2).")", > - ddr2_sdram_atime($bytes->[26]) . " ns"; > + printl "Minimum Cycle Time @ CAS ".($highestCAS-2), > + tns(ddr2_sdram_ctime($bytes->[25])); > + printl "Maximum Access Time @ CAS ".($highestCAS-2), > + tns(ddr2_sdram_atime($bytes->[26])); > } > + printl "Maximim Device Cycle Time (tCK max)", Typo: Maximum. I would also remove "Device" for consistency. > + tns(ddr2_sdram_ctime($bytes->[43])); > + > + # Some timing information > + prints("Timing Parameters"); > + printl "Address/Command Setup Time Before Clock (tIS)", > + tns(ddr2_sdram_atime($bytes->[32])); > + printl "Address/Command Hold Time After Clock (tIH)", > + tns(ddr2_sdram_atime($bytes->[33])); > + printl "Data Input Setup Time Before Strobe (tDS)", > + tns(ddr2_sdram_atime($bytes->[34])); > + printl "Data Input Hold Time After Strobe (tDH)", > + tns(ddr2_sdram_atime($bytes->[35])); > + printl "Minimum Row Precharge Delay (tRP)", tns($trp); > + printl "Minimum Row Active to Row Active Delay (tRRD)", > + tns($bytes->[28]/4); > + printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd); > + printl "Minimum RAS# Pulse Width (tRAS)", tns($tras); > + printl "Write Recovery Time (tWR)", tns($bytes->[36]/4); > + printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4); > + printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4); > + printl "Minimum Active to Auto-refresh Delay (tRC)", > + tns(ddrx_sdram_rtime(2, $bytes->[41], ($bytes->[40]>>3)&0xe)); As far as I can see, the masking isn't needed, as you do it again in ddrx_sdram_rtime(). That being said, it would probably make sense to do all the shifting and masking on the caller's side. Doing half of the shifting outside and the other half inside the function is pretty confusing. > + printl "Minimum Recovery Delay (tRFC)", > + tns(ddrx_sdram_rtime(2, $bytes->[42], $bytes->[40])); > + printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100); > + printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100); > + printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]); > } > > # Parameter: bytes 0-63 Please respin the patch to address my comments, and I'll apply it to i2c-tools SVN. Thanks, -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <20080319141609.338c19b1-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] More DDR2 data for decode-dimms.pl [not found] ` <20080319141609.338c19b1-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-03-20 1:36 ` Trent Piepho [not found] ` <Pine.LNX.4.58.0803191731500.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org> 0 siblings, 1 reply; 6+ messages in thread From: Trent Piepho @ 2008-03-20 1:36 UTC (permalink / raw) To: Jean Delvare; +Cc: Linux I2C On Wed, 19 Mar 2008, Jean Delvare wrote: > I don't understand the point of the first parameter ($t). The function > is always called with $t = 2. If you ever needed to ignore $b2, rather > than calling this function with $t = 1, you could simply pass $b2 = 0. > Or even better, you wouldn't call ddrx_sdram_rtime() at all, as it > would return $b1 directly. The idea was to use the same function for ddr1 and ddr2, hence the name, with $t the type to use. But the specs are different enought that it is probably a bad idea. > > + my @volts = ("TTL/5V Tolerant", "LVTTL", "HSTL 1.5V", > > + "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD"); > > + printl "Voltage Interface Level", $volts[$bytes->[8]]; > > Not sure what sense it makes to have "TBD" in the list. Presumably all > the values above 6 are "to be defined", not just 6. The spec, http://www.jedec.org/download/search/4_01_02_10R14.pdf On page 10, they only list 0-6, with 6 as TBD. I thought maybe they intended to use 6 for something but hadn't decided on the voltage at the time the spec was written, while the rest were intended to be undefined. The spec uses "undefined", "reserved", "TBD", and "-" in various places and not clear what they mean exactly. > > + printl "Minimum Active to Auto-refresh Delay (tRC)", > > + tns(ddrx_sdram_rtime(2, $bytes->[41], ($bytes->[40]>>3)&0xe)); > > + printl "Minimum Recovery Delay (tRFC)", > > + tns(ddrx_sdram_rtime(2, $bytes->[42], $bytes->[40])); > > As far as I can see, the masking isn't needed, as you do it again in > ddrx_sdram_rtime(). That being said, it would probably make sense to do > all the shifting and masking on the caller's side. Doing half of the > shifting outside and the other half inside the function is pretty > confusing. This is better? printl "Minimum Active to Auto-refresh Delay (tRC)", tns(ddr2_sdram_rtime($bytes->[41], ($bytes->[40] >> 4) & 7)); printl "Minimum Recovery Delay (tRFC)", tns(ddr2_sdram_rtime($bytes->[42] + ($bytes->[40] & 1) * 256, ($bytes->[40] >> 1) & 7)); I was trying to do as much as possible on the callee's side. --- This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms. Including all the detailed timing parameters with their standard tXXX names, useful if one is trying to program a DDR memory controller for example. Index: eeprom/decode-dimms.pl =================================================================== --- eeprom/decode-dimms.pl (revision 5151) +++ eeprom/decode-dimms.pl (working copy) @@ -406,6 +406,11 @@ } } +sub tns($) # print a time in ns +{ + return sprintf("%3.2f ns", $_[0]); +} + # Parameter: bytes 0-63 sub decode_sdr_sdram($) { @@ -834,6 +839,39 @@ return $atime; } +sub ddr2_sdram_rtime($$) +{ + my ($rtime, $ext) = @_; + my @table = (0, .25, .33, .50, .66, .75); + + return $time + $table[$ext]; +} + +sub ddr2_module_types($) +{ + my $byte = shift; + my @types = qw(RDIMM UDIMM SO-DIMM Micro-DIMM Mini-RDIMM Mini-UDIMM); + my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0); + my @suptypes; + + foreach $ii (0..5) { + push @suptypes, "$types[$ii] ($widths[$ii] mm)" + if($byte & (1 << $ii)); + } + + return @subtypes; +} + +sub ddr2_refresh_rate($) +{ + my $bytes = shift; + my @refresh = qw(Normal Reduced Reduced Extended Extended Extended); + my @refresht = (15.625, 3.9, 7.8, 31.3, 62.5, 125); + + return "$refresh[$byte & 0x7f] ($refresht[$byte & 0x7f] us)". + ($byte & 0x80 ? " - Self Refresh" : ""); +} + # Parameter: bytes 0-63 sub decode_ddr2_sdram($) { @@ -875,6 +913,31 @@ $bytes->[5] . "," . $bytes->[17]; } + printl "Banks x Rows x Columns x Bits", + join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]); + printl "Ranks", ($bytes->[5]&7) + 1; + + printl "SDRAM Device Width", $bytes->[13]." bits"; + + my @heights = ('< 25.4', '25.4', '25.4 - 30.0', '30.0', '30.5', '> 30.5'); + printl "Module Height", $heights[$bytes->[5] >> 5]." mm"; + + my @suptypes = ddr2_module_types($bytes->[20]); + printl "Module Type".(@suptypes > 1 ? 's' : ''), join(', ', @suptypes); + + printl "DRAM Package", $bytes->[5] & 0x10 ? "Stack" : "Planar"; + + my @volts = ("TTL (5V Tolerant)", "LVTTL", "HSTL 1.5V", + "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD"); + printl "Voltage Interface Level", $volts[$bytes->[8]]; + + printl "Refresh Rate", ddr2_refresh_rate($bytes->[12]); + + my @burst; + push @burst, 4 if ($bytes->[16] & 4); + push @burst, 8 if ($bytes->[16] & 8); + printl "Supported Burst Lengths", join(', ', @burst); + my $highestCAS = 0; my %cas; for ($ii = 2; $ii < 7; $ii++) { @@ -899,31 +962,60 @@ ceil($tras/$ctime); # latencies - if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; } + if (keys %cas) { $temp = join ', ', map("${_}T", sort { $b <=> $a } keys %cas); } else { $temp = "None"; } - printl "Supported CAS Latencies", $temp; + printl "Supported CAS Latencies (tCL)", $temp; # timings if (exists $cas{$highestCAS}) { - printl "Minimum Cycle Time (CAS $highestCAS)", - "$ctime ns"; - printl "Maximum Access Time (CAS $highestCAS)", - ddr2_sdram_atime($bytes->[10]) . " ns"; + printl "Minimum Cycle Time at CAS $highestCAS (tCK min)", + tns($ctime); + printl "Maximum Access Time at CAS $highestCAS (tAC)", + tns(ddr2_sdram_atime($bytes->[10])); } if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-1).")", - ddr2_sdram_ctime($bytes->[23]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-1).")", - ddr2_sdram_atime($bytes->[24]) . " ns"; + printl "Minimum Cycle Time at CAS ".($highestCAS-1), + tns(ddr2_sdram_ctime($bytes->[23])); + printl "Maximum Access Time at CAS ".($highestCAS-1), + tns(ddr2_sdram_atime($bytes->[24])); } if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-2).")", - ddr2_sdram_ctime($bytes->[25]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-2).")", - ddr2_sdram_atime($bytes->[26]) . " ns"; + printl "Minimum Cycle Time at CAS ".($highestCAS-2), + tns(ddr2_sdram_ctime($bytes->[25])); + printl "Maximum Access Time at CAS ".($highestCAS-2), + tns(ddr2_sdram_atime($bytes->[26])); } + printl "Maximum Cycle Time (tCK max)", + tns(ddr2_sdram_ctime($bytes->[43])); + + # Some timing information + prints("Timing Parameters"); + printl "Address/Command Setup Time Before Clock (tIS)", + tns(ddr2_sdram_atime($bytes->[32])); + printl "Address/Command Hold Time After Clock (tIH)", + tns(ddr2_sdram_atime($bytes->[33])); + printl "Data Input Setup Time Before Strobe (tDS)", + tns(ddr2_sdram_atime($bytes->[34])); + printl "Data Input Hold Time After Strobe (tDH)", + tns(ddr2_sdram_atime($bytes->[35])); + printl "Minimum Row Precharge Delay (tRP)", tns($trp); + printl "Minimum Row Active to Row Active Delay (tRRD)", + tns($bytes->[28]/4); + printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd); + printl "Minimum RAS# Pulse Width (tRAS)", tns($tras); + printl "Write Recovery Time (tWR)", tns($bytes->[36]/4); + printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4); + printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4); + printl "Minimum Active to Auto-refresh Delay (tRC)", + tns(ddr2_sdram_rtime($bytes->[41], ($bytes->[40] >> 4) & 7)); + printl "Minimum Recovery Delay (tRFC)", + tns(ddr2_sdram_rtime($bytes->[42] + ($bytes->[40] & 1) * 256, + ($bytes->[40] >> 1) & 7)); + printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100); + printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100); + printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]); } # Parameter: bytes 0-63 _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <Pine.LNX.4.58.0803191731500.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>]
* Re: [PATCH] More DDR2 data for decode-dimms.pl [not found] ` <Pine.LNX.4.58.0803191731500.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org> @ 2008-03-20 11:13 ` Jean Delvare [not found] ` <20080320121336.2109d6d3-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 6+ messages in thread From: Jean Delvare @ 2008-03-20 11:13 UTC (permalink / raw) To: Trent Piepho; +Cc: Linux I2C Hi Trent, On Wed, 19 Mar 2008 18:36:32 -0700 (PDT), Trent Piepho wrote: > On Wed, 19 Mar 2008, Jean Delvare wrote: > > As far as I can see, the masking isn't needed, as you do it again in > > ddrx_sdram_rtime(). That being said, it would probably make sense to do > > all the shifting and masking on the caller's side. Doing half of the > > shifting outside and the other half inside the function is pretty > > confusing. > > This is better? > > printl "Minimum Active to Auto-refresh Delay (tRC)", > tns(ddr2_sdram_rtime($bytes->[41], ($bytes->[40] >> 4) & 7)); > printl "Minimum Recovery Delay (tRFC)", > tns(ddr2_sdram_rtime($bytes->[42] + ($bytes->[40] & 1) * 256, > ($bytes->[40] >> 1) & 7)); > > I was trying to do as much as possible on the callee's side. Yes I think it is better. I understand that putting more on the callee's side performs better and makes the code look better on the caller's side, but the problem is that the helper function then has an interface that is obscure and difficult to understand and validate. I prefer something a bit slower but with a clean interface. If you want to move some more code in the callee, I propose the following: sub ddr2_sdram_rtime($$) { my ($rtime, $ext1, $ext2) = @_; my @table = (0, .25, .33, .50, .66, .75); return $time + ext1 * 256 + $table[$ext2]; } (...) printl "Minimum Active to Auto-refresh Delay (tRC)", tns(ddr2_sdram_rtime($bytes->[41], 0, ($bytes->[40] >> 4) & 7)); printl "Minimum Recovery Delay (tRFC)", tns(ddr2_sdram_rtime($bytes->[42], $bytes->[40] & 1, ($bytes->[40] >> 1) & 7)); That's probably the best trade-off you can get. I'm fine with the rest, with one question though: > + my @burst; > + push @burst, 4 if ($bytes->[16] & 4); > + push @burst, 8 if ($bytes->[16] & 8); > + printl "Supported Burst Lengths", join(', ', @burst); Do DDR2 modules have to support burst at all? The SDR code assumes that the module might not support any burst length and prints "None" in this case. I suspect that we should do the same for DDR2. Thanks, -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <20080320121336.2109d6d3-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] More DDR2 data for decode-dimms.pl [not found] ` <20080320121336.2109d6d3-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2008-03-20 15:47 ` Trent Piepho [not found] ` <Pine.LNX.4.58.0803200822100.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org> 0 siblings, 1 reply; 6+ messages in thread From: Trent Piepho @ 2008-03-20 15:47 UTC (permalink / raw) To: Jean Delvare; +Cc: Linux I2C On Thu, 20 Mar 2008, Jean Delvare wrote: > If you want to move some more code in the callee, I propose the > following: > > sub ddr2_sdram_rtime($$) > { > my ($rtime, $ext1, $ext2) = @_; > my @table = (0, .25, .33, .50, .66, .75); > > return $time + ext1 * 256 + $table[$ext2]; > } > > (...) > printl "Minimum Active to Auto-refresh Delay (tRC)", > tns(ddr2_sdram_rtime($bytes->[41], 0, ($bytes->[40] >> 4) & 7)); > printl "Minimum Recovery Delay (tRFC)", > tns(ddr2_sdram_rtime($bytes->[42], $bytes->[40] & 1, > ($bytes->[40] >> 1) & 7)); Ok, I've changed it to use this method. Thought I would have put the " & 7" inside the function, since it's common to any and all calls to the function. It's one less thing for the person calling it to worry about. > I'm fine with the rest, with one question though: > > > + my @burst; > > + push @burst, 4 if ($bytes->[16] & 4); > > + push @burst, 8 if ($bytes->[16] & 8); > > + printl "Supported Burst Lengths", join(', ', @burst); > > Do DDR2 modules have to support burst at all? The SDR code assumes that > the module might not support any burst length and prints "None" in this > case. I suspect that we should do the same for DDR2. Good question, all my SPD data supports 4 and 8, but I didn't see anything in the spec (which is not very precise about such matters) that said bursts must be supported. I put in a line of code to say "None" if there are no bursts lengths. --------------------------------------------------------------------------- This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms. Included are all the detailed timing parameters with their standard tXXX names, useful if one is trying to program a DDR memory controller for example. Or just to compare against any other SPD dump or memory spec sheet. --- Index: eeprom/decode-dimms.pl =================================================================== --- eeprom/decode-dimms.pl (revision 5151) +++ eeprom/decode-dimms.pl (working copy) @@ -406,6 +406,11 @@ } } +sub tns($) # print a time in ns +{ + return sprintf("%3.2f ns", $_[0]); +} + # Parameter: bytes 0-63 sub decode_sdr_sdram($) { @@ -834,6 +839,40 @@ return $atime; } +# Base, high-bit, 3-bit fraction code +sub ddr2_sdram_rtime($$$) +{ + my ($rtime, $msb, $ext) = @_; + my @table = (0, .25, .33, .50, .66, .75); + + return $rtime + $msb * 256 + $table[$ext]; +} + +sub ddr2_module_types($) +{ + my $byte = shift; + my @types = qw(RDIMM UDIMM SO-DIMM Micro-DIMM Mini-RDIMM Mini-UDIMM); + my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0); + my @suptypes; + + foreach (0..5) { + push @suptypes, "$types[$_] ($widths[$_] mm)" + if($byte & (1 << $_)); + } + + return @suptypes; +} + +sub ddr2_refresh_rate($) +{ + my $byte = shift; + my @refresh = qw(Normal Reduced Reduced Extended Extended Extended); + my @refresht = (15.625, 3.9, 7.8, 31.3, 62.5, 125); + + return "$refresh[$byte & 0x7f] ($refresht[$byte & 0x7f] us)". + ($byte & 0x80 ? " - Self Refresh" : ""); +} + # Parameter: bytes 0-63 sub decode_ddr2_sdram($) { @@ -875,6 +914,32 @@ $bytes->[5] . "," . $bytes->[17]; } + printl "Banks x Rows x Columns x Bits", + join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]); + printl "Ranks", ($bytes->[5]&7) + 1; + + printl "SDRAM Device Width", $bytes->[13]." bits"; + + my @heights = ('< 25.4', '25.4', '25.4 - 30.0', '30.0', '30.5', '> 30.5'); + printl "Module Height", $heights[$bytes->[5] >> 5]." mm"; + + my @suptypes = ddr2_module_types($bytes->[20]); + printl "Module Type".(@suptypes > 1 ? 's' : ''), join(', ', @suptypes); + + printl "DRAM Package", $bytes->[5] & 0x10 ? "Stack" : "Planar"; + + my @volts = ("TTL (5V Tolerant)", "LVTTL", "HSTL 1.5V", + "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD"); + printl "Voltage Interface Level", $volts[$bytes->[8]]; + + printl "Refresh Rate", ddr2_refresh_rate($bytes->[12]); + + my @burst; + push @burst, 4 if ($bytes->[16] & 4); + push @burst, 8 if ($bytes->[16] & 8); + $burst[0] = 'None' if !@burst; + printl "Supported Burst Lengths", join(', ', @burst); + my $highestCAS = 0; my %cas; for ($ii = 2; $ii < 7; $ii++) { @@ -899,31 +964,60 @@ ceil($tras/$ctime); # latencies - if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; } + if (keys %cas) { $temp = join ', ', map("${_}T", sort { $b <=> $a } keys %cas); } else { $temp = "None"; } - printl "Supported CAS Latencies", $temp; + printl "Supported CAS Latencies (tCL)", $temp; # timings if (exists $cas{$highestCAS}) { - printl "Minimum Cycle Time (CAS $highestCAS)", - "$ctime ns"; - printl "Maximum Access Time (CAS $highestCAS)", - ddr2_sdram_atime($bytes->[10]) . " ns"; + printl "Minimum Cycle Time at CAS $highestCAS (tCK min)", + tns($ctime); + printl "Maximum Access Time at CAS $highestCAS (tAC)", + tns(ddr2_sdram_atime($bytes->[10])); } if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-1).")", - ddr2_sdram_ctime($bytes->[23]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-1).")", - ddr2_sdram_atime($bytes->[24]) . " ns"; + printl "Minimum Cycle Time at CAS ".($highestCAS-1), + tns(ddr2_sdram_ctime($bytes->[23])); + printl "Maximum Access Time at CAS ".($highestCAS-1), + tns(ddr2_sdram_atime($bytes->[24])); } if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) { - printl "Minimum Cycle Time (CAS ".($highestCAS-2).")", - ddr2_sdram_ctime($bytes->[25]) . " ns"; - printl "Maximum Access Time (CAS ".($highestCAS-2).")", - ddr2_sdram_atime($bytes->[26]) . " ns"; + printl "Minimum Cycle Time at CAS ".($highestCAS-2), + tns(ddr2_sdram_ctime($bytes->[25])); + printl "Maximum Access Time at CAS ".($highestCAS-2), + tns(ddr2_sdram_atime($bytes->[26])); } + printl "Maximum Cycle Time (tCK max)", + tns(ddr2_sdram_ctime($bytes->[43])); + + # Some timing information + prints("Timing Parameters"); + printl "Address/Command Setup Time Before Clock (tIS)", + tns(ddr2_sdram_atime($bytes->[32])); + printl "Address/Command Hold Time After Clock (tIH)", + tns(ddr2_sdram_atime($bytes->[33])); + printl "Data Input Setup Time Before Strobe (tDS)", + tns(ddr2_sdram_atime($bytes->[34])); + printl "Data Input Hold Time After Strobe (tDH)", + tns(ddr2_sdram_atime($bytes->[35])); + printl "Minimum Row Precharge Delay (tRP)", tns($trp); + printl "Minimum Row Active to Row Active Delay (tRRD)", + tns($bytes->[28]/4); + printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd); + printl "Minimum RAS# Pulse Width (tRAS)", tns($tras); + printl "Write Recovery Time (tWR)", tns($bytes->[36]/4); + printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4); + printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4); + printl "Minimum Active to Auto-refresh Delay (tRC)", + tns(ddr2_sdram_rtime($bytes->[41], 0, ($bytes->[40] >> 4) & 7)); + printl "Minimum Recovery Delay (tRFC)", + tns(ddr2_sdram_rtime($bytes->[42], $bytes->[40] & 1, + ($bytes->[40] >> 1) & 7)); + printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100); + printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100); + printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]); } # Parameter: bytes 0-63 _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <Pine.LNX.4.58.0803200822100.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>]
* Re: [PATCH] More DDR2 data for decode-dimms.pl [not found] ` <Pine.LNX.4.58.0803200822100.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org> @ 2008-03-21 17:47 ` Jean Delvare 0 siblings, 0 replies; 6+ messages in thread From: Jean Delvare @ 2008-03-21 17:47 UTC (permalink / raw) To: Trent Piepho; +Cc: Linux I2C Hi Trent, On Thu, 20 Mar 2008 08:47:20 -0700 (PDT), Trent Piepho wrote: > This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms. > Included are all the detailed timing parameters with their standard tXXX > names, useful if one is trying to program a DDR memory controller for > example. Or just to compare against any other SPD dump or memory spec > sheet. > > --- > Index: eeprom/decode-dimms.pl > =================================================================== > --- eeprom/decode-dimms.pl (revision 5151) > +++ eeprom/decode-dimms.pl (working copy) <snip> Patch applied, thanks. -- Jean Delvare _______________________________________________ i2c mailing list i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org http://lists.lm-sensors.org/mailman/listinfo/i2c ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] More DDR2 data for decode-dimms.pl
@ 2008-02-28 22:19 Trent Piepho
0 siblings, 0 replies; 6+ messages in thread
From: Trent Piepho @ 2008-02-28 22:19 UTC (permalink / raw)
To: lm-sensors-GZX6beZjE8VD60Wz+7aTrA
This lets decode-dimms.pl decode almost all of the SPD data for DDR2 dimms.
Including all the detailed timing parameters with their standard tXXX
names, useful if one is trying to program a DDR memory controller for
example.
Index: decode-dimms.pl
===================================================================
--- i2c-tools/eeprom/decode-dimms.pl (revision 5132)
+++ i2c-tools/eeprom/decode-dimms.pl (working copy)
@@ -834,6 +834,20 @@
return $atime;
}
+sub ddrx_sdram_rtime($$$)
+{
+ my ($t, $b1, $b2) = @_;
+ my $rtime = $b1;
+ if($t == 2) {
+ $rtime += ($b2 & 1) * 256;
+ my @table = (0, .250, .330, .500, .660, .750);
+ $rtime += $table[($b2>>1)&7];
+ }
+ return $rtime;
+}
+
+sub tns($) { return sprintf("%3.2f ns", $_[0]); }
+
# Parameter: bytes 0-63
sub decode_ddr2_sdram($)
{
@@ -875,6 +889,40 @@
$bytes->[5] . "," . $bytes->[17];
}
+ printl "Banks x Rows x Columns x Bits",
+ join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]);
+ printl "Ranks", ($bytes->[5]&7) + 1;
+
+ printl "SDRAM Device Width", $bytes->[13]." bits";
+
+ my @heights = ("< 25.4", "25.4", "25.4 - 30.0", "30.0", "30.5", "> 30.5");
+ printl "Module Height", $heights[$bytes->[5]>>5]." mm";
+ my @types = ("RDIMM", "UDIMM", "SO-DIMM", "Micro-DIMM",
+ "Mini-RDIMM", "Mini-UDIMM");
+ my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0);
+ my @suptypes;
+ foreach $ii (0..5) {
+ push @suptypes, "$types[$ii] ($widths[$ii] mm)"
+ if($bytes->[20] & (1<<$ii));
+ }
+ printl "Module Type".(@suptypes>1?'s':''), join(', ', @suptypes);
+ printl "DRAM Package", $bytes->[5]&0x10 ? "Stack" : "Planar";
+
+ my @volts = ("TTL/5V Tolerant", "LVTTL", "HSTL 1.5V",
+ "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD");
+ printl "Voltage Interface Level", $volts[$bytes->[8]];
+
+ my @refresh = qw(Normal Reduced Reduced Extended Extended Extended);
+ my @refresht = (15.625,3.9,7.8,31.3,62.5,125);
+ printl "Refresh Rate",
+ "$refresh[$bytes->[12]&0x7f] ($refresht[$bytes->[12]&0x7f] us)".
+ ($bytes->[12]&0x80 ? " - Self Refresh" : "");
+
+ my @burst;
+ push @burst, 4 if ($bytes->[16] & 4);
+ push @burst, 8 if ($bytes->[16] & 8);
+ printl "Burst lengths supported", join(', ', @burst);
+
my $highestCAS = 0;
my %cas;
for ($ii = 2; $ii < 7; $ii++) {
@@ -899,31 +947,59 @@
ceil($tras/$ctime);
# latencies
- if (keys %cas) { $temp = join ', ', sort { $b <=> $a } keys %cas; }
+ if (keys %cas) { $temp = join ', ', map("${_}T",sort { $b <=> $a } keys %cas); }
else { $temp = "None"; }
- printl "Supported CAS Latencies", $temp;
+ printl "Supported CAS Latencies (tCL)", $temp;
# timings
if (exists $cas{$highestCAS}) {
- printl "Minimum Cycle Time (CAS $highestCAS)",
- "$ctime ns";
- printl "Maximum Access Time (CAS $highestCAS)",
- ddr2_sdram_atime($bytes->[10]) . " ns";
+ printl "Minimum Cycle Time @ CAS $highestCAS (tCK min)",
+ tns($ctime);
+ printl "Maximum Access Time @ CAS $highestCAS (tAC)",
+ tns(ddr2_sdram_atime($bytes->[10]));
}
if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) {
- printl "Minimum Cycle Time (CAS ".($highestCAS-1).")",
- ddr2_sdram_ctime($bytes->[23]) . " ns";
- printl "Maximum Access Time (CAS ".($highestCAS-1).")",
- ddr2_sdram_atime($bytes->[24]) . " ns";
+ printl "Minimum Cycle Time @ CAS ".($highestCAS-1),
+ tns(ddr2_sdram_ctime($bytes->[23]));
+ printl "Maximum Access Time @ CAS ".($highestCAS-1),
+ tns(ddr2_sdram_atime($bytes->[24]));
}
if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) {
- printl "Minimum Cycle Time (CAS ".($highestCAS-2).")",
- ddr2_sdram_ctime($bytes->[25]) . " ns";
- printl "Maximum Access Time (CAS ".($highestCAS-2).")",
- ddr2_sdram_atime($bytes->[26]) . " ns";
+ printl "Minimum Cycle Time @ CAS ".($highestCAS-2),
+ tns(ddr2_sdram_ctime($bytes->[25]));
+ printl "Maximum Access Time @ CAS ".($highestCAS-2),
+ tns(ddr2_sdram_atime($bytes->[26]));
}
+ printl "Maximim Device Cycle Time (tCK max)",
+ tns(ddr2_sdram_ctime($bytes->[43]));
+
+ # Some timing information
+ prints("Timing Parameters");
+ printl "Address/Command Setup Time Before Clock (tIS)",
+ tns(ddr2_sdram_atime($bytes->[32]));
+ printl "Address/Command Hold Time After Clock (tIH)",
+ tns(ddr2_sdram_atime($bytes->[33]));
+ printl "Data Input Setup Time Before Strobe (tDS)",
+ tns(ddr2_sdram_atime($bytes->[34]));
+ printl "Data Input Hold Time After Strobe (tDH)",
+ tns(ddr2_sdram_atime($bytes->[35]));
+ printl "Minimum Row Precharge Delay (tRP)", tns($trp);
+ printl "Minimum Row Active to Row Active Delay (tRRD)",
+ tns($bytes->[28]/4);
+ printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd);
+ printl "Minimum RAS# Pulse Width (tRAS)", tns($tras);
+ printl "Write Recovery Time (tWR)", tns($bytes->[36]/4);
+ printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4);
+ printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4);
+ printl "Minimum Active to Auto-refresh Delay (tRC)",
+ tns(ddrx_sdram_rtime(2, $bytes->[41], ($bytes->[40]>>3)&0xe));
+ printl "Minimum Recovery Delay (tRFC)",
+ tns(ddrx_sdram_rtime(2, $bytes->[42], $bytes->[40]));
+ printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100);
+ printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100);
+ printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]);
}
# Parameter: bytes 0-63
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 6+ messages in threadend of thread, other threads:[~2008-03-21 17:47 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <Pine.LNX.4.58.0802281401020.14140@shell4.speakeasy.net>
[not found] ` <Pine.LNX.4.58.0802281401020.14140-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-19 13:16 ` [PATCH] More DDR2 data for decode-dimms.pl Jean Delvare
[not found] ` <20080319141609.338c19b1-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-20 1:36 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803191731500.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-20 11:13 ` Jean Delvare
[not found] ` <20080320121336.2109d6d3-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-03-20 15:47 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0803200822100.16142-nuiHJn5p267P3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
2008-03-21 17:47 ` Jean Delvare
2008-02-28 22:19 Trent Piepho
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox