diff --git a/SPDAccessor/SPDAccessor.cpp b/SPDAccessor/SPDAccessor.cpp index 4a6afcd8..1299a8b3 100644 --- a/SPDAccessor/SPDAccessor.cpp +++ b/SPDAccessor/SPDAccessor.cpp @@ -29,11 +29,17 @@ using namespace std::chrono_literals; #define BASIC_MEMORY_TYPE_ADDR (0x02) #define DDR4_JEDEC_ID_ADDR (0x140) +#define DDR4_PART_NR_START (0x149) +#define DDR4_PART_NR_END (0x15C) +#define DDR4_PART_NR_LEN (DDR4_PART_NR_END - DDR4_PART_NR_START + 1) #define DDR4_MANUF_SPECIFIC_START (0x161) #define DDR4_MANUF_SPECIFIC_END (0x17D) #define DDR4_MANUF_SPECIFIC_LEN (DDR4_MANUF_SPECIFIC_END - DDR4_MANUF_SPECIFIC_START + 1) #define DDR5_JEDEC_ID_ADDR (0x200) +#define DDR5_PART_NR_START (0x209) +#define DDR5_PART_NR_END (0x226) +#define DDR5_PART_NR_LEN (DDR5_PART_NR_END - DDR5_PART_NR_START + 1) #define DDR5_MANUF_SPECIFIC_START (0x22B) #define DDR5_MANUF_SPECIFIC_END (0x27F) #define DDR5_MANUF_SPECIFIC_LEN (DDR5_MANUF_SPECIFIC_END - DDR5_MANUF_SPECIFIC_START + 1) @@ -105,6 +111,36 @@ SPDAccessor *SPDAccessor::for_memory_type(SPDMemoryType type, i2c_smbus_interfac return(nullptr); }; +std::string SPDAccessor::read_part_nr_at(uint16_t address, std::size_t len) +{ + std::string part_number; + + for(std::size_t i = 0; i < len; i++) + { + std::size_t spd_addr = address + i; + part_number += (char)this->at(spd_addr); + } + + // Find the true end of string & truncate it to that point. + // Part number should be padded with 0x20 (space) for DDR4 (Source: Wikipedia) + // It may be padded with 0x00 (Source: real-life tests on DDR5 memory) + // Note: To prevent infinite loop, end_of_string_idx MUST be signed. + int end_of_string_idx = part_number.length()-1; + for(; end_of_string_idx >= 0; end_of_string_idx--) + { + if( + part_number[end_of_string_idx] != '\0' && + part_number[end_of_string_idx] != ' ' + ) + { + break; + } + } + part_number = part_number.substr(0, end_of_string_idx + 1); + + return part_number; +} + /*---------------------------------------------------------*\ | Internal implementation for specific memory type. | \*---------------------------------------------------------*/ @@ -128,6 +164,11 @@ uint16_t DDR4Accessor::jedec_id() return((this->at(DDR4_JEDEC_ID_ADDR) << 8) + (this->at(DDR4_JEDEC_ID_ADDR+1) & 0x7f) - 1); } +std::string DDR4Accessor::part_number() +{ + return this->read_part_nr_at(DDR4_PART_NR_START, DDR4_PART_NR_LEN); +} + uint8_t DDR4Accessor::manufacturer_data(uint16_t index) { if(index > DDR4_MANUF_SPECIFIC_LEN-1) @@ -157,6 +198,11 @@ uint16_t DDR5Accessor::jedec_id() return((this->at(DDR5_JEDEC_ID_ADDR) << 8) + (this->at(DDR5_JEDEC_ID_ADDR+1) & 0x7f) - 1); } +std::string DDR5Accessor::part_number() +{ + return this->read_part_nr_at(DDR5_PART_NR_START, DDR5_PART_NR_LEN); +} + uint8_t DDR5Accessor::manufacturer_data(uint16_t index) { if(index > DDR5_MANUF_SPECIFIC_LEN-1) diff --git a/SPDAccessor/SPDAccessor.h b/SPDAccessor/SPDAccessor.h index 13dc3004..5bb453cb 100644 --- a/SPDAccessor/SPDAccessor.h +++ b/SPDAccessor/SPDAccessor.h @@ -11,6 +11,10 @@ #include "SPDCommon.h" +#include +#include +#include + class SPDAccessor { public: @@ -21,6 +25,7 @@ class SPDAccessor virtual SPDMemoryType memory_type() = 0; virtual uint16_t jedec_id() = 0; + virtual std::string part_number() = 0; virtual uint8_t manufacturer_data(uint16_t index) = 0; virtual SPDAccessor *copy() = 0; @@ -30,6 +35,8 @@ class SPDAccessor protected: i2c_smbus_interface *bus; uint8_t address; + + std::string read_part_nr_at(uint16_t address, std::size_t len); }; /*---------------------------------------------------------*\ @@ -43,6 +50,7 @@ class DDR4Accessor : public SPDAccessor virtual ~DDR4Accessor(); virtual SPDMemoryType memory_type(); virtual uint16_t jedec_id(); + virtual std::string part_number(); virtual uint8_t manufacturer_data(uint16_t index); }; @@ -53,5 +61,6 @@ class DDR5Accessor : public SPDAccessor virtual ~DDR5Accessor(); virtual SPDMemoryType memory_type(); virtual uint16_t jedec_id(); + virtual std::string part_number(); virtual uint8_t manufacturer_data(uint16_t index); }; diff --git a/SPDAccessor/SPDWrapper.cpp b/SPDAccessor/SPDWrapper.cpp index e252e0c4..5c4e321a 100644 --- a/SPDAccessor/SPDWrapper.cpp +++ b/SPDAccessor/SPDWrapper.cpp @@ -83,6 +83,15 @@ uint16_t SPDWrapper::jedec_id() return jedec_id_val; } +std::string SPDWrapper::part_number() +{ + if(accessor == nullptr) + { + return std::string(); + } + return accessor->part_number(); +} + uint8_t SPDWrapper::manufacturer_data(uint16_t index) { if(accessor == nullptr) diff --git a/SPDAccessor/SPDWrapper.h b/SPDAccessor/SPDWrapper.h index fe9d6e62..b65c1cff 100644 --- a/SPDAccessor/SPDWrapper.h +++ b/SPDAccessor/SPDWrapper.h @@ -24,6 +24,7 @@ class SPDWrapper SPDMemoryType memory_type(); int index(); uint16_t jedec_id(); + std::string part_number(); uint8_t manufacturer_data(uint16_t index); private: