Page 1 of 2
FIXED Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sun Jul 14, 2013 10:12 am
by doctorized
Updated for 5.20+
This code reads Serial Presence Detect (SPD) data from DDR2 and DDR3 RAM memory modules and shows all info included EPP 1.0, EPP 2.0 and XMP memory profiles. No WMI usage, only driver. Test it and tell me how it works.
http://kc2000labs.shadowtavern.com/pb/z ... PD_520.rar
EDIT: The code updated for PB 5.20 and uploaded: 11/30/2013.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sun Jul 14, 2013 12:37 pm
by rsts
It seems to work fine (but I need to open up my PC to be sure)

Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Thu Jul 18, 2013 9:04 pm
by doctorized
I wrote a pdf file explaining the EPP 2.0 memory profiles, as NVidia has a pdf that it is not very helpful (with some errors).
http://kc2000labs.shadowtavern.com/EPP2.0.pdf
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Fri Jul 19, 2013 10:02 am
by Mesa
It doesn't work on Xp32b and purebasic 5.20b6 x86.
In callingprocedures.pb
line: ModuleData(lDimm)\EPP[0]\ProfileType = "Basic"
-> error: "ProfileType" desn't exist.
Mesa.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sat Jul 20, 2013 10:12 am
by doctorized
Tested again on another compurer. Somewhere there is a bug. Let me find it and then try again.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sat Jul 20, 2013 12:32 pm
by doctorized
In some computers works file but in some others it doesn't: it can read the Base Address but it cannot scan it for EEPROM devices. I cannot find out why. Can anyone help?
@Mesa: please download the code and run it again.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sat Jul 20, 2013 7:27 pm
by Helle
Works for Intel Z87-Chip-Set with
Code: Select all
...
Data.i $80868C22, ?ID80868C22
...
;and
...
ID80868C22: Data.s "Intel 8 Series/C220 Series SMBus Controller"
...
But is this necessary? I think, the values for bus=0, device=31 and function=3 are fix for the SM-Bus.
Helle
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sun Jul 21, 2013 10:18 am
by Mesa
Hi,
I've got an another bug, on line 155 of CallingProcedures.pb:
ReDim spd.c(Dimm,255)
-> "only the last dimension of the array can be modified by Redim"
Mesa.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sun Jul 21, 2013 12:14 pm
by doctorized
Helle wrote:But is this necessary? I think, the values for bus=0, device=31 and function=3 are fix for the SM-Bus.
No, it is not fix. For example my ATI/AMD SMBus controller is at: bus=0, device=20 and function=0. A friend's pc with NVIDIA 750 has: bus=0, device=1 and function=1.
@Mesa: As I think that something bad is happening with memory allocation/writing, try to use Purifier. It may help us find what is going on.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Sun Jul 21, 2013 5:53 pm
by Helle
Ah, yes. Please check this:
Code: Select all
;- Scan PCI-Bus for Base-Address SM-Bus. SMB is Class $0C05 in Bus0 (PCI Local Bus Specification Revision 2.3).
;- "Helle" Klaus Helbing, 21.07.2013, PB v5.10 (x64)
;- Use WinRing0.dll/.sys or WinRing0x64.dll/.sys. DLL and SYS must be in this folder (make an EXE!)!
Datas.l
Config_Address.l = $0CF8
Config_Data.l = $0CFC
#PROCESSOR_ARCHITECTURE_AMD64 = $9
SI.SYSTEM_INFO ;Structure System_Info
GetSystemInfo_(@SI)
If SI\wProcessorArchitecture = #PROCESSOR_ARCHITECTURE_AMD64
DLLOK = OpenLibrary(0, "WinRing0x64.dll") ;64-Bit-Version
Else
DLLOK = OpenLibrary(0, "WinRing0.dll") ;32-Bit-Version
EndIf
If DLLOK
Prototype.i ProtoWinRing0_0()
WR0_InitializeOls.ProtoWinRing0_0 = GetFunction(0, "InitializeOls")
WR0_DeinitializeOls.ProtoWinRing0_0 = GetFunction(0, "DeinitializeOls")
Prototype.i ProtoWinRing0_2(V1.l, V2.l)
WR0_ReadIoPortDword.ProtoWinRing0_2 = GetFunction(0, "ReadIoPortDwordEx")
WR0_WriteIoPortDword.ProtoWinRing0_2 = GetFunction(0, "WriteIoPortDwordEx")
If WR0_InitializeOls()
Reg_Address.l = $80000000 ;set Bit31
For Device = 0 To 31
Reg_Address & $FFFFF8FF ;set Functions=0
For Function = 0 To 7
WR0_WriteIoPortDword(Config_Address, Reg_Address + $A) ;$A=Sub Class, $B=Base Class
WR0_ReadIoPortDword(Config_Data, @Datas)
Datas = (Datas >> 16) & $FFFF
If Datas = $0C05 ;SMB is Class $0C05
WR0_WriteIoPortDword(Config_Address, Reg_Address + $20) ;$20=Base Address Register (4) ...
WR0_ReadIoPortDword(Config_Data, @Datas)
Break 2
EndIf
Reg_Address + $100
Next
Next
WR0_DeinitializeOls()
MessageRequester("SMB Base-Address", "$" + Hex(Datas & $FFFFFFFC))
Else
MessageRequester("Error!", "No WinRing0!")
EndIf
EndIf
Notice: I use DLL and SYS from WinRing0!
My result: $F000.
Helle
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Mon Jul 22, 2013 10:34 am
by doctorized
Helle wrote:Ah, yes. Please check this:
YESS! That's what I wanted!! I had forgoten that each device type has its own ClassID. Now I can find SMBus controller without the need of the "ChipsAndBasses.pb" file. The first problem is solved. The second is to find out what is going on with NVidia SMBuses.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Mon Jul 22, 2013 12:08 pm
by Helle
Third

: Don´t work with AMD (e.g. FX8120 with SB950; must be $b00). I will take a look in the AMD-BKDG (BIOS and Kernel Developer’s Guide).
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Mon Jul 22, 2013 12:28 pm
by doctorized
Helle wrote: must be $b00.
What do you get? I have SB750 and I get BaseAddress = $B00. Do you use my way with the chips to find the base address or yours? If you use mine, then SB950 is not in the list. Replace the procedure with this:
Code: Select all
Procedure.l GetSMBusBaseAddress()
OnErrorGoto(?ExitDevs)
bus.l: dev.l: func.l
pci_address.l
id.l
type.b
ClassID.l
For bus = 0 To 255
For dev = 0 To $1F
For func = 0 To 7
pci_address = ((bus & $ff)<<8) | ((dev & $1f)<<3) | (func & 7)
id = PciConfigReadLong(pci_address, $A)
ClassID = id & $ffff
If ClassID = $0C05
lAddress = PciConfigReadLong(pci_address, $20) & $FFF0
If lAddress = 0
lAddress = PciConfigReadLong(pci_address, $24) & $FFF0
If lAddress = 0
lAddress = PciConfigReadLong(pci_address, $90) & $FFF0
If lAddress = 0
lAddress = PciConfigReadLong(pci_address, $94) & $FFF0
EndIf
EndIf
EndIf
If lAddress <> 0
ProcedureReturn lAddress
EndIf
EndIf
type = PciConfigReadChar(pci_address, $0e);
If func =0 And (type & $80) =0 :Break: EndIf
Next
Next
Next
ExitDevs:
ProcedureReturn 0
EndProcedure
I also found this:
http://kc2000labs.shadowtavern.com/Unit1.cpp. It is from a C++ project and I am trying to find out what could I retrieve from it without any luck.
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Mon Jul 22, 2013 2:27 pm
by Helle
With all codes no chance for the SB950. Class $0C05 is found on Device = $14, Function = $0. Vendor = $1002, Device = $4385. This is in your list as "ATI RD600/RS600". The Win7-Device-Manager says for $1002_4385: "ATI I/O-Communicationprocessor SMBus-Controller". A scan in the Reg_Address-Area is without success (for $B00). No second found of $0C05.
Helle
Re: Reading SPD data from DDR2 and DDR3 RAM memory modules
Posted: Mon Jul 22, 2013 2:36 pm
by doctorized
Helle wrote:With all codes no chance for the SB950.
If you take a look at the cpp file I refer above, you will see that it is using a seperate procedure for each vendor: ATI, NVidia, SIS, VIA, INTEL. I tried to use the code for NVidia with no success. I cannot find out what is wrong.
The initial code:
Code: Select all
int Get_NVCK804_SMBUS(BYTE * SPD,WORD BASE_ADDRESS,BYTE Slave_Address)
{
for(int i=0;i<0x80;i++)
{
int error=0;
do
{
outportb(BASE_ADDRESS+0x00,0xFF);
flag=inportb(BASE_ADDRESS+0x00);
error++;
if(error>0x8000)
{
MessageBox(Application->Handle,"Reset Nvidia CK804 SMBUS Error!","nForce CK804",MB_OK|MB_ICONINFORMATION);
return 2;
}
}while((flag&0x9F)!=0);
error=0;
outportb((BASE_ADDRESS+0x02),Slave_Address-1);
outportb((BASE_ADDRESS+0x03),i);
outportb((BASE_ADDRESS+0x00),0x07);
do
{
error++;
if(error>0x100)
{
MessageBox(Application->Handle,"Read Nvidia CK804 SMBUS Error!","nForce CK804",MB_OK|MB_ICONINFORMATION);
return 2;
}
if((inportb(BASE_ADDRESS+0x01)&0x10)==0x10)
{
char buffer[256];
sprintf(buffer,"No Module in channel 0x%02X!",Slave_Address-1);
//MessageBox(Application->Handle,buffer,"nForce CK804",MB_OK|MB_ICONINFORMATION);
return 1;
}
Sleep(1);
}while(inportb(BASE_ADDRESS+0x01)!=0x80);
SPD[i]=inportb(BASE_ADDRESS+0x04);
}
return 0;
//quaere(SPD);
}
and mine:
Code: Select all
Procedure.l smbCallBus(BaseAddr.l, Cmd.b, Slave.b, RW.b)
For i=0 To $80
error.l=0
While (flag & $9F) <> 0
WriteIOPortByte(BaseAddr, $FF)
flag = ReadIOPortByte(BaseAddr)
error + 1
If error > $80
Debug "i = " + Hex(i) + " / Reset Nvidia SMBUS Error!"
ProcedureReturn 2
EndIf
Wend
;Slave = Slave - 1
error = 0
WriteIoPortByte(BaseAddr + 2, Slave -1)
WriteIoPortByte(BaseAddr + 3, i)
WriteIoPortByte(BaseAddr + 0, 7)
Delay(20)
While ReadIOPortByte(BaseAddr + 1) <> $80
error + 1
If error > $100
Debug "i = " + Hex(i) + " / Read Nvidia SMBUS Error!"
ProcedureReturn 3
EndIf
If ReadIOPortByte(BaseAddr + 1) & $10 = $10
Debug "i = " + Hex(i) + " / No Module in channel " + Hex(Slave - 1)
ProcedureReturn 1
EndIf
Delay(20)
Wend
Debug Hex(ReadIOPortByte(BaseAddr + 4))
Next
EndProcedure