package xCAT::SPD;

#This module provides the ability to decode DIMM SPD data to human readable format
use strict;

#use Data::Dumper;
require Exporter;
our @ISA       = qw/Exporter/;
our @EXPORT_OK = qw/decode_spd/;

sub do_crc16 {
    my @data = @_;
    my $crc  = 0;
    while (@data) {
        my $byte = shift @data;
        $crc = $crc ^ $byte << 8;
        my $loopcount = 8;
        while ($loopcount--) {
            if ($crc & 0x8000) {
                $crc = $crc << 1 ^ 0x1021;
            } else {
                $crc = $crc << 1;
            }
        }
    }
    return $crc & 0xffff;
}



sub decode_manufacturer {
    my $jedec_ids = [
        {
            0x01 => "AMD",
            0x02 => "AMI",
            0x83 => "Fairchild",
            0x04 => "Fujitsu",
            0x85 => "GTE",
            0x86 => "Harris",
            0x07 => "Hitachi",
            0x08 => "Inmos",
            0x89 => "Intel",
            0x8a => "I.T.T.",
            0x0b => "Intersil",
            0x8c => "Monolithic Memories",
            0x0d => "Mostek",
            0x0e => "Motorola",
            0x8f => "National",
            0x10 => "NEC",
            0x91 => "RCA",
            0x92 => "Raytheon",
            0x13 => "Conexant (Rockwell)",
            0x94 => "Seeq",
            0x15 => "Philips Semi. (Signetics)",
            0x16 => "Synertek",
            0x97 => "Texas Instruments",
            0x98 => "Toshiba",
            0x19 => "Xicor",
            0x1a => "Zilog",
            0x9b => "Eurotechnique",
            0x1c => "Mitsubishi",
            0x9d => "Lucent (AT&T)",
            0x9e => "Exel",
            0x1f => "Atmel",
            0x20 => "SGS/Thomson",
            0xa1 => "Lattice Semi.",
            0xa2 => "NCR",
            0x23 => "Wafer Scale Integration",
            0xa4 => "IBM",
            0x25 => "Tristar",
            0x26 => "Visic",
            0xa7 => "Intl. CMOS Technology",
            0xa8 => "SSSI",
            0x29 => "Microchip Technology",
            0x2a => "Ricoh Ltd.",
            0xab => "VLSI",
            0x2c => "Micron Technology",
            0xad => "Hyundai Electronics",
            0xae => "OKI Semiconductor",
            0x2f => "ACTEL",
            0xb0 => "Sharp",
            0x31 => "Catalyst",
            0x32 => "Panasonic",
            0xb3 => "IDT",
            0x34 => "Cypress",
            0xb5 => "DEC",
            0xb6 => "LSI Logic",
            0x37 => "Zarlink",
            0x38 => "UTMC",
            0xb9 => "Thinking Machine",
            0xba => "Thomson CSF",
            0x3b => "Integrated CMOS(Vertex)",
            0xbc => "Honeywell",
            0x3d => "Tektronix",
            0x3e => "Sun Microsystems",
            0xbf => "SST",
            0x40 => "MOSEL",
            0xc1 => "Infineon",
            0xc2 => "Macronix",
            0x43 => "Xerox",
            0xc4 => "Plus Logic",
            0x45 => "SunDisk",
            0x46 => "Elan Circuit Tech.",
            0xc7 => "European Silicon Str.",
            0xc8 => "Apple Computer",
            0xc9 => "Xilinx",
            0x4a => "Compaq",
            0xcb => "Protocol Engines",
            0x4c => "SCI",
            0xcd => "Seiko Instruments",
            0xce => "Samsung",
            0x4f => "I3 Design System",
            0xd0 => "Klic",
            0x51 => "Crosspoint Solutions",
            0x52 => "Alliance Semiconductor",
            0xd3 => "Tandem",
            0x54 => "Hewlett-Packard",
            0xd5 => "Intg. Silicon Solutions",
            0xd6 => "Brooktree",
            0x57 => "New Media",
            0x58 => "MHS Electronic",
            0xd9 => "Performance Semi.",
            0xda => "Winbond Electronic",
            0x5b => "Kawasaki Steel",
            0xdc => "Bright Micro",
            0x5d => "TECMAR",
            0x5e => "Exar",
            0xdf => "PCMCIA",
            0xe0 => "LG Semiconductor",
            0x61 => "Northern Telecom",
            0x62 => "Sanyo",
            0xe3 => "Array Microsystems",
            0x64 => "Crystal Semiconductor",
            0xe5 => "Analog Devices",
            0xe6 => "PMC-Sierra",
            0x67 => "Asparix",
            0x68 => "Convex Computer",
            0xe9 => "Quality Semiconductor",
            0xea => "Nimbus Technology",
            0x6b => "Transwitch",
            0xec => "Micronas (ITT Intermetall)",
            0x6d => "Cannon",
            0x6e => "Altera",
            0xef => "NEXCOM",
            0x70 => "QUALCOMM",
            0xf1 => "Sony",
            0xf2 => "Cray Research",
            0x73 => "AMS (Austria Micro)",
            0xf4 => "Vitesse",
            0x75 => "Aster Electronics",
            0x76 => "Bay Networks (Synoptic)",
            0xf7 => "Zentrum",
            0xf8 => "TRW",
            0x79 => "Thesys",
            0x7a => "Solbourne Computer",
            0xfb => "Allied-Signal",
            0x7c => "Dialog",
            0xfd => "Media Vision",
            0xfe => "Level One Communication",
        },
        {
            0x01 => "Cirrus Logic",
            0x02 => "National Instruments",
            0x83 => "ILC Data Device",
            0x04 => "Alcatel Mietec",
            0x85 => "Micro Linear",
            0x86 => "Univ. of NC",
            0x07 => "JTAG Technologies",
            0x08 => "Loral",
            0x89 => "Nchip",
            0x8A => "Galileo Tech",
            0x0B => "Bestlink Systems",
            0x8C => "Graychip",
            0x0D => "GENNUM",
            0x0E => "VideoLogic",
            0x8F => "Robert Bosch",
            0x10 => "Chip Express",
            0x91 => "DATARAM",
            0x92 => "United Microelec Corp.",
            0x13 => "TCSI",
            0x94 => "Smart Modular",
            0x15 => "Hughes Aircraft",
            0x16 => "Lanstar Semiconductor",
            0x97 => "Qlogic",
            0x98 => "Kingston",
            0x19 => "Music Semi",
            0x1A => "Ericsson Components",
            0x9B => "SpaSE",
            0x1C => "Eon Silicon Devices",
            0x9D => "Programmable Micro Corp",
            0x9E => "DoD",
            0x1F => "Integ. Memories Tech.",
            0x20 => "Corollary Inc.",
            0xA1 => "Dallas Semiconductor",
            0xA2 => "Omnivision",
            0x23 => "EIV(Switzerland)",
            0xA4 => "Novatel Wireless",
            0x25 => "Zarlink (formerly Mitel)",
            0x26 => "Clearpoint",
            0xA7 => "Cabletron",
            0xA8 => "Silicon Technology",
            0x29 => "Vanguard",
            0x2A => "Hagiwara Sys-Com",
            0xAB => "Vantis",
            0x2C => "Celestica",
            0xAD => "Century",
            0xAE => "Hal Computers",
            0x2F => "Rohm Company Ltd.",
            0xB0 => "Juniper Networks",
            0x31 => "Libit Signal Processing",
            0x32 => "Enhanced Memories Inc.",
            0xB3 => "Tundra Semiconductor",
            0x34 => "Adaptec Inc.",
            0xB5 => "LightSpeed Semi.",
            0xB6 => "ZSP Corp.",
            0x37 => "AMIC Technology",
            0x38 => "Adobe Systems",
            0xB9 => "Dynachip",
            0xBA => "PNY Electronics",
            0x3B => "Newport Digital",
            0xBC => "MMC Networks",
            0x3D => "T Square",
            0x3E => "Seiko Epson",
            0xBF => "Broadcom",
            0x40 => "Viking Components",
            0xC1 => "V3 Semiconductor",
            0xC2 => "Flextronics (formerly Orbit)",
            0x43 => "Suwa Electronics",
            0xC4 => "Transmeta",
            0x45 => "Micron CMS",
            0x46 => "American Computer & Digital Components Inc",
            0xC7 => "Enhance 3000 Inc",
            0xC8 => "Tower Semiconductor",
            0x49 => "CPU Design",
            0x4A => "Price Point",
            0xCB => "Maxim Integrated Product",
            0x4C => "Tellabs",
            0xCD => "Centaur Technology",
            0xCE => "Unigen Corporation",
            0x4F => "Transcend Information",
            0xD0 => "Memory Card Technology",
            0x51 => "CKD Corporation Ltd.",
            0x52 => "Capital Instruments, Inc.",
            0xD3 => "Aica Kogyo, Ltd.",
            0x54 => "Linvex Technology",
            0xD5 => "MSC Vertriebs GmbH",
            0xD6 => "AKM Company, Ltd.",
            0x57 => "Dynamem, Inc.",
            0x58 => "NERA ASA",
            0xD9 => "GSI Technology",
            0xDA => "Dane-Elec (C Memory)",
            0x5B => "Acorn Computers",
            0xDC => "Lara Technology",
            0x5D => "Oak Technology, Inc.",
            0x5E => "Itec Memory",
            0xDF => "Tanisys Technology",
            0xE0 => "Truevision",
            0x61 => "Wintec Industries",
            0x62 => "Super PC Memory",
            0xE3 => "MGV Memory",
            0x64 => "Galvantech",
            0xE5 => "Gadzoox Nteworks",
            0xE6 => "Multi Dimensional Cons.",
            0x67 => "GateField",
            0x68 => "Integrated Memory System",
            0xE9 => "Triscend",
            0xEA => "XaQti",
            0x6B => "Goldenram",
            0xEC => "Clear Logic",
            0x6D => "Cimaron Communications",
            0x6E => "Nippon Steel Semi. Corp.",
            0xEF => "Advantage Memory",
            0x70 => "AMCC",
            0xF1 => "LeCroy",
            0xF2 => "Yamaha Corporation",
            0x73 => "Digital Microwave",
            0xF4 => "NetLogic Microsystems",
            0x75 => "MIMOS Semiconductor",
            0x76 => "Advanced Fibre",
            0xF7 => "BF Goodrich Data.",
            0xF8 => "Epigram",
            0x79 => "Acbel Polytech Inc.",
            0x7A => "Apacer Technology",
            0xFB => "Admor Memory",
            0x7C => "FOXCONN",
            0xFD => "Quadratics Superconductor",
            0xFE => "3COM",
        },
        {
            0x01 => "Camintonn Corporation",
            0x02 => "ISOA Incorporated",
            0x83 => "Agate Semiconductor",
            0x04 => "ADMtek Incorporated",
            0x85 => "HYPERTEC",
            0x86 => "Adhoc Technologies",
            0x07 => "MOSAID Technologies",
            0x08 => "Ardent Technologies",
            0x89 => "Switchcore",
            0x8A => "Cisco Systems, Inc.",
            0x0B => "Allayer Technologies",
            0x8C => "WorkX AG",
            0x0D => "Oasis Semiconductor",
            0x0E => "Novanet Semiconductor",
            0x8F => "E-M Solutions",
            0x10 => "Power General",
            0x91 => "Advanced Hardware Arch.",
            0x92 => "Inova Semiconductors GmbH",
            0x13 => "Telocity",
            0x94 => "Delkin Devices",
            0x15 => "Symagery Microsystems",
            0x16 => "C-Port Corporation",
            0x97 => "SiberCore Technologies",
            0x98 => "Southland Microsystems",
            0x19 => "Malleable Technologies",
            0x1A => "Kendin Communications",
            0x9B => "Great Technology Microcomputer",
            0x1C => "Sanmina Corporation",
            0x9D => "HADCO Corporation",
            0x9E => "Corsair",
            0x1F => "Actrans System Inc.",
            0x20 => "ALPHA Technologies",
            0xA1 => "Cygnal Integrated Products Incorporated",
            0xA2 => "Artesyn Technologies",
            0x23 => "Align Manufacturing",
            0xA4 => "Peregrine Semiconductor",
            0x25 => "Chameleon Systems",
            0x26 => "Aplus Flash Technology",
            0xA7 => "MIPS Technologies",
            0xA8 => "Chrysalis ITS",
            0x29 => "ADTEC Corporation",
            0x2A => "Kentron Technologies",
            0xAB => "Win Technologies",
            0x2C => "ASIC Designs Inc",
            0xAD => "Extreme Packet Devices",
            0xAE => "RF Micro Devices",
            0x2F => "Siemens AG",
            0xB0 => "Sarnoff Corporation",
            0x31 => "Itautec Philco SA",
            0x32 => "Radiata Inc.",
            0xB3 => "Benchmark Elect. (AVEX)",
            0x34 => "Legend",
            0xB5 => "SpecTek Incorporated",
            0xB6 => "Hi/fn",
            0x37 => "Enikia Incorporated",
            0x38 => "SwitchOn Networks",
            0xB9 => "AANetcom Incorporated",
            0xBA => "Micro Memory Bank",
            0x3B => "ESS Technology",
            0xBC => "Virata Corporation",
            0x3D => "Excess Bandwidth",
            0x3E => "West Bay Semiconductor",
            0xBF => "DSP Group",
            0x40 => "Newport Communications",
            0xC1 => "Chip2Chip Incorporated",
            0xC2 => "Phobos Corporation",
            0x43 => "Intellitech Corporation",
            0xC4 => "Nordic VLSI ASA",
            0x45 => "Ishoni Networks",
            0x46 => "Silicon Spice",
            0xC7 => "Alchemy Semiconductor",
            0xC8 => "Agilent Technologies",
            0x49 => "Centillium Communications",
            0x4A => "W.L. Gore",
            0xCB => "HanBit Electronics",
            0x4C => "GlobeSpan",
            0xCD => "Element 14",
            0xCE => "Pycon",
            0x4F => "Saifun Semiconductors",
            0xD0 => "Sibyte, Incorporated",
            0x51 => "MetaLink Technologies",
            0x52 => "Feiya Technology",
            0xD3 => "I & C Technology",
            0x54 => "Shikatronics",
            0xD5 => "Elektrobit",
            0xD6 => "Megic",
            0x57 => "Com-Tier",
            0x58 => "Malaysia Micro Solutions",
            0xD9 => "Hyperchip",
            0xDA => "Gemstone Communications",
            0x5B => "Anadyne Microelectronics",
            0xDC => "3ParData",
            0x5D => "Mellanox Technologies",
            0x5E => "Tenx Technologies",
            0xDF => "Helix AG",
            0xE0 => "Domosys",
            0x61 => "Skyup Technology",
            0x62 => "HiNT Corporation",
            0xE3 => "Chiaro",
            0x64 => "MCI Computer GMBH",
            0xE5 => "Exbit Technology A/S",
            0xE6 => "Integrated Technology Express",
            0x67 => "AVED Memory",
            0x68 => "Legerity",
            0xE9 => "Jasmine Networks",
            0xEA => "Caspian Networks",
            0x6B => "nCUBE",
            0xEC => "Silicon Access Networks",
            0x6D => "FDK Corporation",
            0x6E => "High Bandwidth Access",
            0xEF => "MultiLink Technology",
            0x70 => "BRECIS",
            0xF1 => "World Wide Packets",
            0xF2 => "APW",
            0x73 => "Chicory Systems",
            0xF4 => "Xstream Logic",
            0x75 => "Fast-Chip",
            0x76 => "Zucotto Wireless",
            0xF7 => "Realchip",
            0xF8 => "Galaxy Power",
            0x79 => "eSilicon",
            0x7A => "Morphics Technology",
            0xFB => "Accelerant Networks",
            0x7C => "Silicon Wave",
            0xFD => "SandCraft",
            0xFE => "Elpida",
        },
        {
            0x01 => "Solectron",
            0x02 => "Optosys Technologies",
            0x83 => "Buffalo (Formerly Melco)",
            0x04 => "TriMedia Technologies",
            0x85 => "Cyan Technologies",
            0x86 => "Global Locate",
            0x07 => "Optillion",
            0x08 => "Terago Communications",
            0x89 => "Ikanos Communications",
            0x8A => "Princeton Technology",
            0x0B => "Nanya Technology",
            0x8C => "Elite Flash Storage",
            0x0D => "Mysticom",
            0x0E => "LightSand Communications",
            0x8F => "ATI Technologies",
            0x10 => "Agere Systems",
            0x91 => "NeoMagic",
            0x92 => "AuroraNetics",
            0x13 => "Golden Empire",
            0x94 => "Muskin",
            0x15 => "Tioga Technologies",
            0x16 => "Netlist",
            0x97 => "TeraLogic",
            0x98 => "Cicada Semiconductor",
            0x19 => "Centon Electronics",
            0x1A => "Tyco Electronics",
            0x9B => "Magis Works",
            0x1C => "Zettacom",
            0x9D => "Cogency Semiconductor",
            0x9E => "Chipcon AS",
            0x1F => "Aspex Technology",
            0x20 => "F5 Networks",
            0xA1 => "Programmable Silicon Solutions",
            0xA2 => "ChipWrights",
            0x23 => "Acorn Networks",
            0xA4 => "Quicklogic",
            0x25 => "Kingmax Semiconductor",
            0x26 => "BOPS",
            0xA7 => "Flasys",
            0xA8 => "BitBlitz Communications",
            0x29 => "eMemory Technology",
            0x2A => "Procket Networks",
            0xAB => "Purple Ray",
            0x2C => "Trebia Networks",
            0xAD => "Delta Electronics",
            0xAE => "Onex Communications",
            0x2F => "Ample Communications",
            0xB0 => "Memory Experts Intl",
            0x31 => "Astute Networks",
            0x32 => "Azanda Network Devices",
            0xB3 => "Dibcom",
            0x34 => "Tekmos",
            0xB5 => "API NetWorks",
            0xB6 => "Bay Microsystems",
            0x37 => "Firecron Ltd",
            0x38 => "Resonext Communications",
            0xB9 => "Tachys Technologies",
            0xBA => "Equator Technology",
            0x3B => "Concept Computer",
            0xBC => "SILCOM",
            0x3D => "3Dlabs",
            0x3E => "ct Magazine",
            0xBF => "Sanera Systems",
            0x40 => "Silicon Packets",
            0xC1 => "Viasystems Group",
            0xC2 => "Simtek",
            0x43 => "Semicon Devices Singapore",
            0xC4 => "Satron Handelsges",
            0x45 => "Improv Systems",
            0x46 => "INDUSYS GmbH",
            0xC7 => "Corrent",
            0xC8 => "Infrant Technologies",
            0x49 => "Ritek Corp",
            0x4A => "empowerTel Networks",
            0xCB => "Hypertec",
            0x4C => "Cavium Networks",
            0xCD => "PLX Technology",
            0xCE => "Massana Design",
            0x4F => "Intrinsity",
            0xD0 => "Valence Semiconductor",
            0x51 => "Terawave Communications",
            0x52 => "IceFyre Semiconductor",
            0xD3 => "Primarion",
            0x54 => "Picochip Designs Ltd",
            0xD5 => "Silverback Systems",
            0xD6 => "Jade Star Technologies",
            0x57 => "Pijnenburg Securealink",
            0x58 => "MemorySolutioN",
            0xD9 => "Cambridge Silicon Radio",
            0xDA => "Swissbit",
            0x5B => "Nazomi Communications",
            0xDC => "eWave System",
            0x5D => "Rockwell Collins",
            0x5E => "PAION",
            0xDF => "Alphamosaic Ltd",
            0xE0 => "Sandburst",
            0x61 => "SiCon Video",
            0x62 => "NanoAmp Solutions",
            0xE3 => "Ericsson Technology",
            0x64 => "PrairieComm",
            0xE5 => "Mitac International",
            0xE6 => "Layer N Networks",
            0x67 => "Atsana Semiconductor",
            0x68 => "Allegro Networks",
            0xE9 => "Marvell Semiconductors",
            0xEA => "Netergy Microelectronic",
            0x6B => "NVIDIA",
            0xEC => "Internet Machines",
            0x6D => "Peak Electronics",
            0xEF => "Accton Technology",
            0x70 => "Teradiant Networks",
            0xF1 => "Europe Technologies",
            0xF2 => "Cortina Systems",
            0x73 => "RAM Components",
            0xF4 => "Raqia Networks",
            0x75 => "ClearSpeed",
            0x76 => "Matsushita Battery",
            0xF7 => "Xelerated",
            0xF8 => "SimpleTech",
            0x79 => "Utron Technology",
            0x7A => "Astec International",
            0xFB => "AVM gmbH",
            0x7C => "Redux Communications",
            0xFD => "Dot Hill Systems",
            0xFE => "TeraChip",
        },
        {
            0x01 => "T-RAM Incorporated",
            0x02 => "Innovics Wireless",
            0x83 => "Teknovus",
            0x04 => "KeyEye Communications",
            0x85 => "Runcom Technologies",
            0x86 => "RedSwitch",
            0x07 => "Dotcast",
            0x08 => "Silicon Mountain Memory",
            0x89 => "Signia Technologies",
            0x8A => "Pixim",
            0x0B => "Galazar Networks",
            0x8C => "White Electronic Designs",
            0x0D => "Patriot Scientific",
            0x0E => "Neoaxiom Corporation",
            0x8F => "3Y Power Technology",
            0x10 => "Europe Technologies",
            0x91 => "Potentia Power Systems",
            0x92 => "C-guys Incorporated",
            0x13 => "Digital Communications Technology Incorporated",
            0x94 => "Silicon-Based Technology",
            0x15 => "Fulcrum Microsystems",
            0x16 => "Positivo Informatica Ltd",
            0x97 => "XIOtech Corporation",
            0x98 => "PortalPlayer",
            0x19 => "Zhiying Software",
            0x1A => "Direct2Data",
            0x9B => "Phonex Broadband",
            0x1C => "Skyworks Solutions",
            0x9D => "Entropic Communications",
            0x9E => "Pacific Force Technology",
            0x1F => "Zensys A/S",
            0x20 => "Legend Silicon Corp.",
            0xA1 => "sci-worx GmbH",
            0xA2 => "Oasis Silicon Systems",
            0x23 => "Renesas Technology",
            0xA4 => "Raza Microelectronics",
            0x25 => "Phyworks",
            0x26 => "MediaTek",
            0xA7 => "Non-cents Productions",
            0xA8 => "US Modular",
            0x29 => "Wintegra Ltd",
            0x2A => "Mathstar",
            0xAB => "StarCore",
            0x2C => "Oplus Technologies",
            0xAD => "Mindspeed",
            0xAE => "Just Young Computer",
            0x2F => "Radia Communications",
            0xB0 => "OCZ",
            0x31 => "Emuzed",
            0x32 => "LOGIC Devices",
            0xB3 => "Inphi Corporation",
            0x34 => "Quake Technologies",
            0xB5 => "Vixel",
            0xB6 => "SolusTek",
            0x37 => "Kongsberg Maritime",
            0x38 => "Faraday Technology",
            0xB9 => "Altium Ltd.",
            0xBA => "Insyte",
            0x3B => "ARM Ltd.",
            0xBC => "DigiVision",
            0x3D => "Vativ Technologies",
            0x3E => "Endicott Interconnect Technologies",
            0xBF => "Pericom",
            0x40 => "Bandspeed",
            0xC1 => "LeWiz Communications",
            0xC2 => "CPU Technology",
            0x43 => "Ramaxel Technology",
            0xC4 => "DSP Group",
            0x45 => "Axis Communications",
            0x46 => "Legacy Electronics",
            0xC7 => "Chrontel",
            0xC8 => "Powerchip Semiconductor",
            0x49 => "MobilEye Technologies",
            0x4A => "Excel Semiconductor",
            0xCB => "A-DATA Technology",
            0x4C => "VirtualDigm",
        }
    ];
    my $arr_index = shift;
    $arr_index = $arr_index & 0x7f;
    my $code = shift;
    unless ($code) {
        return "Malformed SPD";
    }
    if (defined $jedec_ids->[$arr_index]->{$code}) {
        return $jedec_ids->[$arr_index]->{$code};
    } else {
        return "Unrecognized manufacturer: $arr_index, $code";
    }
}








sub decode_spd {
    my %memtypes = (
        1  => "STD FPM DRAM",
        2  => "EDO",
        3  => "Pipelined Nibble",
        4  => "SDRAM",
        5  => "ROM",
        6  => "DDR SGRAM",
        7  => "DDR SDRAM",
        8  => "DDR2 SDRAM",
        9  => "DDR2 SDRAM FB-DIMM",
        10 => "DDR2 SDRAM FB-DIMM PROBE",
        11 => "DDR3 SDRAM",
        12 => "DDR4 SDRAM",
    );

    my %modtypes = (
        1 => "RDIMM",
        2 => "UDIMM",
        3 => "SODIMM",
        4 => "Micro-DIMM",
        5 => "Mini-RDIMM",
        6 => "Mini-UDIMM",
    );

    my %speedfromclock = (
        800  => 6400,
        1066 => 8500,
        1333 => 10600,
        1600 => 12800,
        1867 => 14900,
        2132 => 17000,
        2133 => 17000,
        2134 => 17000,
    );

    my %ddrmodcap = (
        0 => 256,
        1 => 512,
        2 => 1024,
        3 => 2048,
        4 => 4096,
        5 => 8192,
        6 => 16384,
        7 => 32768,
    );

    my %ddrdevwidth = (
        0 => 4,
        1 => 8,
        2 => 16,
        3 => 32
    );
    my %ddrranks = (
        0 => 1,
        1 => 2,
        2 => 3,
        3 => 4
    );
    my %ddrbuswidth = (
        0 => 8,
        1 => 16,
        2 => 32,
        3 => 64
    );

    my @spd = @_;
    my $rethash;

    #print Dumper(@spd);
    if (($spd[0] & 0xf) > 3) {    #TODO: Remove workaround for buggy SPD
        $rethash->{product}->{extra} = [ { value => 'Malformed SPD (missing leading byte)', encoding => 3 } ];
        unshift @spd, 3;
    }
    $rethash->{product}->{name} = $memtypes{ $spd[2] };
    if ($spd[2] == 11) {          #DDR3 spec applies
        my $ftbdividend = $spd[9] >> 4;
        my $ftbdivisor  = $spd[9] & 0xf;
        my $ftb         = $ftbdividend / $ftbdivisor;
        my $fineoffset  = $spd[34];
        if ($fineoffset & 0b10000000) {

            #negative value, twos complement
            $fineoffset = 0 - (($fineoffset ^ 0xff) + 1);
        }
        $fineoffset = ($ftb * $fineoffset) * 10**-3;
        my $mtb   = $spd[10] / $spd[11];
        my $clock = int(2 / (($mtb * $spd[12] + $fineoffset) * 10**-3));
        my $speed = $speedfromclock{$clock};
        unless ($speed) { $speed = "UNKNOWN"; }
        $rethash->{product}->{name} = "PC3-" . $speed . " ($clock MT/s)";
        if ($spd[8] & 0b11000) {
            $rethash->{product}->{name} .= " ECC";
        }
        $rethash->{product}->{name} .= " " . $modtypes{ $spd[3] & 0x0f };
        my $sdramcap   = $ddrmodcap{ $spd[4] & 0xf };
        my $buswidth   = $ddrbuswidth{ $spd[8] & 0b111 };
        my $sdramwidth = $ddrdevwidth{ $spd[7] & 0b111 };
        my $ranks      = $ddrranks{ ($spd[7] & 0b111000) >> 3 };


        my $capacity = $sdramcap / 8 * $buswidth / $sdramwidth * $ranks;
        if ($capacity < 1024) {
            $capacity = $capacity . "MB";
        } else {
            $capacity = ($capacity / 1024) . "GB";
        }
        $rethash->{product}->{name} = $capacity . " " . $rethash->{product}->{name};

        $rethash->{product}->{manufacturer} = decode_manufacturer($spd[117], $spd[118]);
        $rethash->{product}->{buildlocation} = sprintf("%02x", $spd[119]);
        if ($spd[120] != 0 or $spd[121] != 0) {
            $rethash->{product}->{builddate} = sprintf("Week %x of 20%02x", $spd[121], $spd[120]);
        }
        foreach (@spd[ 128 .. 145 ]) {
            if ($_ & 0b10000000) {
                $rethash->{product}->{model} = "Malformed SPD";
            }
        }
        unless ($rethash->{product}->{model}) {
            $rethash->{product}->{model} = pack("C*", @spd[ 128 .. 145 ]);
        }
        if ($spd[0] & 0b10000000) {    #crc is to exclude 117-125, crc 0 to 116
            unless (do_crc16(@spd[ 0 .. 116 ]) == ($spd[126] + ($spd[127] << 8))) {
                push @{ $rethash->{product}->{extra} }, "SPD CRC Invalid!";
            }
        } else {                       #crc for 0 to 125
            unless (do_crc16(@spd[ 0 .. 125 ]) == ($spd[126] + ($spd[127] << 8))) {
                push @{ $rethash->{product}->{extra} }, "CRC Invalid!";
            }
        }

        #my $rawspd="SPD Dump: ";
        #foreach (@spd) {
        #	$rawspd .= sprintf("%02X ",$_);
        #}
        #push @{$rethash->{product}->{extra}},$rawspd;
    } elsif ($spd[2] == 12) {    #DDR4 spec applies
         # spd[125] spd[18] spd[18is sdram min cycle time .. spd125 is fine offset for min time
         # mtb and ftb are fixed in ddr4 spd spec.. mtb is always 0.125 ns and ftb is always 0.001 ns
        my $speed;
        my $clock;
        if ($spd[17] == 0) {
            my $fineoffset = $spd[125];
            if ($fineoffset & 0b10000000) {

                #negative value, twos complement
                $fineoffset = 0 - (($fineoffset ^ 0xff) + 1);
            }
            $clock = int(2 / ((0.125 * $spd[18] + $fineoffset * 0.001) * 0.001));
            $speed = $speedfromclock{$clock};
            unless ($speed) { $speed = "UNKNOWN"; }
        } else { # this would mean a different MTB and FTB than spec indicated..
            $clock = "UNKNOWN";
            $speed = "UNKNOWN";
        }
        $rethash->{product}->{name} = "PC4-" . $speed . " ($clock MT/s)";
        if ($spd[13] & 0b11000 == 0b1000) {
            $rethash->{product}->{name} .= " ECC";
        }
        $rethash->{product}->{name} .= " " . $modtypes{ $spd[3] & 0x0f };
        my $sdramcap   = $ddrmodcap{ $spd[4] & 0xf };
        my $buswidth   = $ddrbuswidth{ $spd[13] & 0b111 };
        my $sdramwidth = $ddrdevwidth{ $spd[12] & 0b111 };
        my $ranks      = $ddrranks{ ($spd[12] & 0b111000) >> 3 };


        my $capacity = $sdramcap / 8 * $buswidth / $sdramwidth * $ranks;
        if ($capacity < 1024) {
            $capacity = $capacity . "MB";
        } else {
            $capacity = ($capacity / 1024) . "GB";
        }
        $rethash->{product}->{name} = $capacity . " " . $rethash->{product}->{name};

        $rethash->{product}->{manufacturer} = decode_manufacturer($spd[320], $spd[321]);
        $rethash->{product}->{buildlocation} = sprintf("%02x", $spd[322]);
        if ($spd[323] != 0 or $spd[324] != 0) {
            $rethash->{product}->{builddate} = sprintf("Week %x of 20%02x", $spd[323], $spd[324]);
        }
        foreach (@spd[ 329 .. 348 ]) {
            if ($_ > 126 or $_ < 32) {
                $rethash->{product}->{model} = "Malformed SPD";
            }
        }
        unless ($rethash->{product}->{model}) {
            $rethash->{product}->{model} = pack("C*", @spd[ 329 .. 348 ]);
        }

        #my $rawspd="SPD Dump: ";
        #foreach (@spd) {
        #	$rawspd .= sprintf("%02X ",$_);
        #}
        #push @{$rethash->{product}->{extra}},$rawspd;
    } else {
        $rethash->{product}->{model} = "Unrecognized SPD";
    }
    return $rethash;
}

1;
