diff --git a/dag/extdeps/memory/micron.dag b/dag/extdeps/memory/micron.dag new file mode 100644 index 00000000000..2da21028a00 --- /dev/null +++ b/dag/extdeps/memory/micron.dag @@ -0,0 +1,202 @@ +module extdeps.memory.micron + +import std.measure { ByteSize, byte_size, bit_width } +import extdeps.memory.types { DramModuleCatalogRow, DimmBuffering, dram_generation_ddr4, MonolithicDie, DualDiePackage } +import extdeps.vendor.micron { micron } +import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef, FactCitation } +import std.decl_ref { DeclarationRef, WholeDeclaration, decl_ref } +import extdeps.uri { Uri, Https } + +// THE ANCHOR IS MICRON'S OWN PART CATALOG, NOT AN ENCYCLOPAEDIA. micron.com serves one +// catalogue record per Micron part number from its product database ("data-source": +// "DATABASE" in the record itself), and that record carries the module's full JEDEC DDR4 SPD +// image plus a details table (density, industry speed, CAS latency, component configuration, +// die count, package, status). The page renders client-side; the record it renders is the +// same origin's _jcr_content.products.json/getproductinfo/-/-/-/en_US/-/ resource under +// the part-detail path, fetched 2026-09-12 with HTTP 200 and no credentials. An SPD image +// published by the manufacturer is the manufacturer's statement of the module's organization +// at byte grain, which is stronger evidence than a marketing table and is what every row in +// this module is read from. +data micron_part_catalog_mta36ads2g72pz_2g1a1: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "www.micron.com/products/obsolete/obsolete-vlp-rdimm/part-catalog/part-detail/mta36ads2g72pz-2g1a1" + } +} + +data micron_part_catalog_mta36asf2g72pz_2g1a2: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "www.micron.com/products/obsolete/obsolete-rdimm/part-catalog/part-detail/mta36asf2g72pz-2g1a2" + } +} + +// Micron "DDR4 Module Part Numbering System", Rev. 05-Dec-2018, © 2016 Micron Technology, +// Inc., the sheet Micron publishes at micron.com/numbering. Micron's asset host answered +// "Request Rejected" to this session (2026-09-12), so the locator is a distributor-hosted copy +// of Micron's PDF, sha256 7d52c2ad719c2aec1ff3298a0c785e82395e503810a07dcf2591abae2da5c6a2; +// re-cite the Micron locator when it is reachable. It is the authority for what the letters +// of a Micron module part number DENOTE, which no catalogue record states. +data micron_ddr4_module_part_numbering_rev_2018_12_05: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "siewert-kau.info/micron/wp-content/uploads/2020/05/Nomenklatur_Micron.pdf" + } +} + +// Micron "288-Pin DDR4 RDIMM Core Product Description", CCM005-341111752-10541, +// ddr4_rdimm_core.pdf Rev. B 12/2021. Same hosting situation as the numbering sheet: Micron's +// own copy sits behind the rejecting asset host, so this is DigiKey's copy of Micron's PDF, +// sha256 ea054b3d5774bffe78814bb670601b3fc919b59706ea84e3b1d2d2e849628abc. It is the family +// specification the per-part addendum supplements, and it carries the two facts a part record +// cannot: the module outlines (Figure 1 RDIMM 31.25 ± 0.15 mm; Figure 2 VLP RDIMM 18.75 ± 0.15 +// mm, both 133.35 mm long) and the DDP-versus-3DS pin semantics quoted at DramDieStacking. +data micron_ddr4_rdimm_core_rev_b_2021_12: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "media.digikey.com/pdf/Data%20Sheets/Micron%20Technology%20Inc%20PDFs/DDR4_SDRAM_RDIMM_Core_RevB_Dec2021.pdf" + } +} + +data extdeps_external_authority_anchor: ExternalAuthority = micron_part_catalog_mta36ads2g72pz_2g1a1 + +data extdeps_model_scope: ExternalModelScope = ExternalModelScope { + subject: ExternalSubjectRef { + declaration: DeclarationRef { + module_path: "extdeps.memory.micron", + decl_name: "mta36ads2g72pz_2g1a1_catalog", + field: WholeDeclaration + } + }, + first_citation: micron_part_catalog_mta36ads2g72pz_2g1a1, + further_citations: [micron_ddr4_module_part_numbering_rev_2018_12_05, micron_ddr4_rdimm_core_rev_b_2021_12] +} + +data stick_capacity_bytes_16g: ByteSize = byte_size(17179869184) + +// MTA36ADS2G72PZ-2G1A1, DECODED FIELD BY FIELD AGAINST THE NUMBERING SHEET, then checked +// against the SPD image Micron publishes for it. Numbering sheet, Rev. 05-Dec-2018: +// MT Micron Technology +// A Product Family: DDR4 SDRAM +// 36 Number of Die +// A Voltage: 1.2V +// DS Module Options: "VLP Dual-Die w/Temp Sensor" +// 2G72 Module Configuration, depth x width: 2 Gig x 72 (G = Gigabits) +// P Module Type: 288-pin RDIMM +// Z Package Code: commercial temp, halogen-free, single-/dual-/quad-/octal-rank DIMM +// -2G1 Module Speed: DDR4-2133, PC4-2133, SPD CL-nRCD-nRP 15-15-15, component mark -093E +// A Die Revision +// 1 Printed Circuit Board Revision +// So the family letters answer the brief's second question outright: the sibling +// MTA36ASF2G72PZ differs ONLY in the module-options field, SF = "FBGA w/Temp Sensor" -- a +// full-height module built from single-die FBGA packages -- where DS is a very-low-profile +// module built from dual-die packages. D is the height, S is the package; the operator's +// reading of the label "2DRx4" as "two ranks, dual-die, x4" is what Micron's own code says. +// +// THE SPD IMAGE AGREES AT EVERY BYTE THE ROW READS (JESD21-C Annex L byte layout; process +// code JG, one of twelve the record lists, which differ only in register-vendor bytes 133-135 +// and the bytes-128..253 CRC and NOT in any organization byte): +// byte 2 = 0x0C DDR4 SDRAM +// byte 3 = 0x01 module type RDIMM +// byte 4 = 0x84 4 Gb per die, 4 bank groups x 4 banks +// byte 5 = 0x21 16 row address bits, 10 column bits +// byte 6 = 0x91 NON-MONOLITHIC, 2 dies, MULTI LOAD STACK -- the dual-die package +// byte 12 = 0x08 2 package ranks, x4 device width, symmetrical +// byte 13 = 0x0B 64-bit primary bus + 8-bit ECC extension +// byte 18 = 0x08 with byte 125 = 0xC2 (-62 ps) tCKmin 938 ps = DDR4-2133 +// byte 24 = 0x6C tAAmin 13.5 ns -> CL 15 at 2133 +// byte 128 = 0x04 module nominal height <= 19 mm (the VLP outline; the ASF sibling reads +// 0x11, <= 32 mm, the full-height outline) +// byte 130 = 0x08 raw card reference design byte differs from the sibling's 0x01 +// bytes 329-349 "36ADS2G72PZ-2G1A1"; bytes 320-321 = 0x80 0x2C, JEP106 Micron +// The catalogue details table says the same in words: Density 16GB, Industry Speed PC4-2133, +// 2133 MT/s, CAS Latency CL = 15, Bus Width x72, ECC True, Component Config "2Gb x4" (that is +// the 8 Gb DUAL-DIE PACKAGE: 2 Gig x 4 = 8 Gbit per package, two 4 Gb dies), Number of +// Components 36 (dies, matching the part-number field), Package FBGA, Part Status Obsolete. +// +// WHAT THE ROW CARRIES AND WHAT IT DOES NOT. rank_count is the module's package-rank +// organization, 2, exactly as for a monolithic 2Rx4 -- byte 12 counts CS-selected ranks and a +// DDP's second die is CS1-selected. dram_module_required_die_density divides 16 GiB by (16 +// data dies x 2 ranks) and lands on 4 Gbit, which byte 4 states independently, so three row +// figures corroborate a fourth the way the Samsung row's do. The 18.75 mm outline is a +// FORM-FACTOR fact the catalogue row type has no field for; it is stated here and in the +// numbering decode, and becomes a typed carrier when a chassis DIMM-clearance consumer exists +// to read it (DESIGN 3c: no dangling height row). +// +// The eBay listing that sold these modules described them as "2Rx4"; the physical label reads +// "2DRx4". The listing is not a source for any field of this row. +// +// INDEPENDENTLY MEASURED, NOT AUTHORED FROM HERE: the Mt. Collins unit-1 host firmware prints +// this part as "RDIMM[2c:80] 16GB 2133 ECC 2R x4 RCD[b3:80] 36ADS2G72PZ-2G1A1" and, when a +// socket also held monolithic modules, "CHANNEL Mismatch Byte 6 SLOT0[00] EXP[91]" -- so the +// module's own SPD reads byte 6 = 0x91 on the board, agreeing with the image Micron publishes. +// That reading is a receipt in the observing layer (hw-first-host, 2026-09-12) and is quoted +// here only as the corroboration; the row cites Micron. +data mta36ads2g72pz_2g1a1_catalog: DramModuleCatalogRow = DramModuleCatalogRow { + part_number: "MTA36ADS2G72PZ-2G1A1", + manufacturer: micron, + generation: dram_generation_ddr4, + capacity_bytes: stick_capacity_bytes_16g, + data_rate_mts: 2133, + ecc: true, + buffering: Registered, + die_stacking: DualDiePackage, + chip_width: bit_width(4), + + rank_count: 2, +} + +data mta36ads2g72pz_2g1a1_catalog_citation: FactCitation = FactCitation { + fact: decl_ref(module_path: "extdeps.memory.micron", decl_name: "mta36ads2g72pz_2g1a1_catalog"), + authority: micron_part_catalog_mta36ads2g72pz_2g1a1, +} + +// The numbering sheet attests the part-number decode above (DS = VLP dual-die, -2G1 = 2133 +// CL15), which the catalogue record confirms but does not explain. Two citations for one row +// because they ground different fields of it, not because either is weak. +data mta36ads2g72pz_2g1a1_numbering_citation: FactCitation = FactCitation { + fact: decl_ref(module_path: "extdeps.memory.micron", decl_name: "mta36ads2g72pz_2g1a1_catalog"), + authority: micron_ddr4_module_part_numbering_rev_2018_12_05, +} + +// MTA36ASF2G72PZ-2G1A2: THE CONTROL, AND THE ONLY AXES ON WHICH IT DIFFERS ARE THE POINT. +// Same numbering decode except SF = "FBGA w/Temp Sensor", same 36 dies, same 2G72, same P, Z, +// -2G1; die revision A, PCB revision 2. Micron's SPD for it (process code KI; catalogue path +// obsolete-rdimm) reads byte 4 = 0x84, byte 5 = 0x21, byte 12 = 0x08, byte 13 = 0x0B, byte +// 18 = 0x08 / byte 125 = 0xC2, byte 24 = 0x6C -- identical to the ADS part at every +// organization and timing byte -- and differs at byte 6 = 0x00 (MONOLITHIC), byte 128 = 0x11 +// (<= 32 mm), byte 130 = 0x01 (raw card), byte 131 = 0x09 versus 0x05. Details table: +// Component Config "1Gb x4" (a 4 Gb monolithic package), Number of Components 36. +// +// So Micron's own data says the two quartets the operator ran share vendor, generation, +// capacity, data rate, CAS latency, ECC, buffering, device width, rank count AND die density. +// What differs is the package construction (dual-die multi-load stack versus monolithic), the +// PCB outline (18.75 mm versus 31.25 mm) and, with it, the raw-card reference design. That is +// the whole of what these two rows can say; which of those three the Mt. Collins training +// outcome tracks is an observation for the observing layer and is not authored here. +// +// THE SUFFIX IS MICRON'S, AND THE LABEL AGREES. -2G1A2 is the MTA36ASF2G72PZ-2G1 SKU Micron's +// catalogue serves a record for. The Mt. Collins unit-1 host firmware reads the trained +// quartet's SPD part-number field as 36ASF2G72PZ-2G1A2II (hw-first-host SOL capture, +// 2026-09-12): the same die/PCB revision pair, followed by II, which is one of the eight +// process codes Micron's record lists for this SKU (KI/KJ/KK/KG/II/IG/IJ/IK). A process code +// selects register-vendor bytes and nothing organizational, so the row's part_number stays at +// the catalogue grain and the process code is a per-module observation. +data mta36asf2g72pz_2g1a2_catalog: DramModuleCatalogRow = DramModuleCatalogRow { + part_number: "MTA36ASF2G72PZ-2G1A2", + manufacturer: micron, + generation: dram_generation_ddr4, + capacity_bytes: stick_capacity_bytes_16g, + data_rate_mts: 2133, + ecc: true, + buffering: Registered, + die_stacking: MonolithicDie, + chip_width: bit_width(4), + + rank_count: 2, +} + +data mta36asf2g72pz_2g1a2_catalog_citation: FactCitation = FactCitation { + fact: decl_ref(module_path: "extdeps.memory.micron", decl_name: "mta36asf2g72pz_2g1a2_catalog"), + authority: micron_part_catalog_mta36asf2g72pz_2g1a2, +} diff --git a/dag/extdeps/memory/samsung.dag b/dag/extdeps/memory/samsung.dag index 67cd2835e85..be5d8fde38b 100644 --- a/dag/extdeps/memory/samsung.dag +++ b/dag/extdeps/memory/samsung.dag @@ -1,7 +1,7 @@ module extdeps.memory.samsung import std.measure { ByteSize, byte_size, bit_width } -import extdeps.memory.types { DramModuleCatalogRow, DimmBuffering, dram_generation_ddr4, MonolithicDie, ThreeDimensionalStacked } +import extdeps.memory.types { DramModuleCatalogRow, DimmBuffering, dram_generation_ddr4, DualDiePackage, ThreeDimensionalStacked } import extdeps.vendor.samsung { samsung } import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } import std.decl_ref { DeclarationRef, WholeDeclaration } @@ -51,6 +51,15 @@ data stick_capacity_bytes_32g: ByteSize = byte_size(34359738368) // ONE PRECISION, since the derived count reads as a package count and is not one: at x4 with // ECC the module carries 18 dies per rank and 72 across four ranks, which this part reaches // as 36 dual-die packages. dram_chips_per_rank counts DIES, the unit that determines density. +// +// die_stacking IS DualDiePackage FOR THE REASON THE SENTENCE ABOVE ALREADY GAVE (2026-09-12). +// Until DramDieStacking had a multi-load-stack arm this row was written MonolithicDie, which +// contradicted its own provenance: 72 dies on 36 packages is a dual-die package per site, the +// JEDEC "multi load stack" class, and not a monolithic device. The value has the same label +// standing as every other field of this row -- it is derived from the stated die and package +// counts, not read from a Samsung datasheet -- and it dissolves with the rest of the row when +// a Samsung document carrying this part lands. No consumer folds this row's stacking today; +// the correction is so the first one that does is not handed a class the part does not belong to. data m386a4g40dm0_cpb_catalog: DramModuleCatalogRow = DramModuleCatalogRow { part_number: "M386A4G40DM0-CPB", manufacturer: samsung, @@ -59,7 +68,7 @@ data m386a4g40dm0_cpb_catalog: DramModuleCatalogRow = DramModuleCatalogRow { data_rate_mts: 2133, ecc: true, buffering: LoadReduced, - die_stacking: MonolithicDie, + die_stacking: DualDiePackage, chip_width: bit_width(4), rank_count: 4, diff --git a/dag/extdeps/memory/types.dag b/dag/extdeps/memory/types.dag index 1f256232800..36fbae4ab22 100644 --- a/dag/extdeps/memory/types.dag +++ b/dag/extdeps/memory/types.dag @@ -76,7 +76,26 @@ type DimmBuffering = Unbuffered | Registered | LoadReduced // 3DS is through-silicon-via die stacking presenting multiple logical ranks behind one physical // package load, which is precisely why a controller can admit it separately from ordinary // registered modules: the electrical load and the rank arithmetic differ. -type DramDieStacking = MonolithicDie | ThreeDimensionalStacked +// +// THE THIRD VALUE IS JEDEC'S, NOT A VENDOR'S (2026-09-12). The DDR4 SPD "SDRAM Package Type" +// byte (JESD21-C Annex L, byte 6) classifies a device as monolithic, a MULTI LOAD STACK, or a +// SINGLE LOAD STACK. 3DS is the single-load stack: one chip-select, one electrical load, chip-ID +// pins address the dies. A dual-die package (DDP, Micron's "Dual-Die") is the multi-load stack: +// two dies in one package, each on its own CS/CKE/ODT, so the package presents two ranks and two +// loads -- the same load count as two monolithic packages, in one footprint. The Micron DDR4 +// RDIMM Core Rev. B 12/2021 states the distinction in its C0-C2 pin description: "Some DDR4 +// modules support a traditional DDP package, which uses CS1_n, CKE1, and ODT1 to control the +// second die. All other stack configurations, such as a 4H or 8H, are assumed to be single-load +// (initiator/target) type configurations where C0, C1, and C2 are used as chip ID selects". +// +// Before this value existed the axis had no honest arm for a DDP module: MonolithicDie was a +// lie about the package and ThreeDimensionalStacked a lie about the load, and the first such row +// (extdeps.memory.micron mta36ads2g72pz_2g1a1_catalog) would have been graded by the Altra +// admission fold against a class it does not belong to. rank_count and +// dram_module_required_die_density are unchanged by the value: a DDP module's ranks are +// CS-selected package ranks exactly like a monolithic two-rank module's, and density stays per +// die, which is the figure JEDEC's ceiling bounds. +type DramDieStacking = MonolithicDie | DualDiePackage | ThreeDimensionalStacked // The module class a controller admits, as the product of the two independent axes. Carried as a // record rather than an enum of named combinations so that a newly admitted pairing is a value, @@ -93,8 +112,9 @@ fn dram_module_class_eq(a: DramModuleClass, b: DramModuleClass) -> Bool { LoadReduced => match b.buffering { LoadReduced => true Unbuffered => false Registered => false } }) && (match a.stacking { - MonolithicDie => match b.stacking { MonolithicDie => true ThreeDimensionalStacked => false } - ThreeDimensionalStacked => match b.stacking { ThreeDimensionalStacked => true MonolithicDie => false } + MonolithicDie => match b.stacking { MonolithicDie => true DualDiePackage => false ThreeDimensionalStacked => false } + DualDiePackage => match b.stacking { DualDiePackage => true MonolithicDie => false ThreeDimensionalStacked => false } + ThreeDimensionalStacked => match b.stacking { ThreeDimensionalStacked => true MonolithicDie => false DualDiePackage => false } }) } diff --git a/dag/extdeps/vendor/micron.dag b/dag/extdeps/vendor/micron.dag new file mode 100644 index 00000000000..414af34b53a --- /dev/null +++ b/dag/extdeps/vendor/micron.dag @@ -0,0 +1,31 @@ +module extdeps.vendor.micron + +import std.decl_ref { DeclarationRef, WholeDeclaration } +import extdeps.vendor { Vendor } +import extdeps.hardware { Hardware } + +import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } +import extdeps.uri { Uri, Https } + +data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "en.wikipedia.org/wiki/Micron_Technology" + } +} + +data extdeps_model_scope: ExternalModelScope = ExternalModelScope { + subject: ExternalSubjectRef { + declaration: DeclarationRef { + module_path: "extdeps.vendor.micron", + decl_name: "micron", + field: WholeDeclaration + } + }, + first_citation: extdeps_external_authority_anchor, + further_citations: [] +} + +// The legal name is the one Micron prints in its own document footers ("© 2019 Micron +// Technology, Inc."), so the row does not depend on the anchor for its spelling. +data micron: Vendor = Vendor { legal_name: "Micron Technology, Inc." } diff --git a/dag/gunbc/extdeps_scope_frontier.dag b/dag/gunbc/extdeps_scope_frontier.dag index b69f1172f27..af7920fc298 100644 --- a/dag/gunbc/extdeps_scope_frontier.dag +++ b/dag/gunbc/extdeps_scope_frontier.dag @@ -384,6 +384,7 @@ data scope_carrier_paths: List = [ "dag/extdeps/vendor/salesforce.dag", "dag/extdeps/vendor/samsung.dag", "dag/extdeps/vendor/sk_hynix.dag", + "dag/extdeps/vendor/micron.dag", "dag/extdeps/vendor/verizon.dag", "dag/extdeps/vendor/western_digital.dag", "dag/extdeps/vendor/atlassian.dag", @@ -412,6 +413,7 @@ data scope_carrier_paths: List = [ "dag/extdeps/probes/provider_interface_acquisition.dag", "dag/extdeps/memory/samsung.dag", "dag/extdeps/memory/sk_hynix.dag", + "dag/extdeps/memory/micron.dag", "dag/extdeps/accounting/encumbrance.dag", "dag/extdeps/ampere/mt_collins_product_brief/platform.dag", "dag/extdeps/boards/supermicro.dag", diff --git a/dag/test/claim/altra_memory_controller_witness_test.dag b/dag/test/claim/altra_memory_controller_witness_test.dag index 7fa4823c50c..ed61f63400f 100644 --- a/dag/test/claim/altra_memory_controller_witness_test.dag +++ b/dag/test/claim/altra_memory_controller_witness_test.dag @@ -12,6 +12,7 @@ import extdeps.memory.types { LoadReduced, DramDieStacking, MonolithicDie, + DualDiePackage, ThreeDimensionalStacked, DramModuleClass, dram_module_class_eq, @@ -84,6 +85,21 @@ test fn w_stacking_is_independent_of_buffering() -> Bool { && !altra_admits_module_class(c: DramModuleClass { buffering: LoadReduced, stacking: ThreeDimensionalStacked }) } +// THE THIRD STACKING VALUE IS NEITHER OF THE OTHER TWO, AND THE DATASHEET NAMES NO CLASS FOR IT. +// A dual-die (multi-load stack) registered module is not the datasheet's "RDIMMs" row as this +// module transcribes it (monolithic) and not its "Stacked (3DS) RDIMMs" row (single-load stack), +// so the fold answers false for it. That is the absence of a listing -- Issue 1.55 §2.10 does not +// mention DDP at all -- and NOT a withdrawal like UDIMM's; the two are kept apart above. The +// control matters because before DualDiePackage existed such a module could only be written as +// monolithic and would have been admitted as a class it does not belong to. +test fn w_a_dual_die_registered_module_is_not_among_the_listed_classes() -> Bool { + let reg_ddp = DramModuleClass { buffering: Registered, stacking: DualDiePackage } + !altra_admits_module_class(c: reg_ddp) + && !dram_module_class_eq(a: reg_ddp, b: DramModuleClass { buffering: Registered, stacking: MonolithicDie }) + && !dram_module_class_eq(a: reg_ddp, b: DramModuleClass { buffering: Registered, stacking: ThreeDimensionalStacked }) + && dram_module_class_eq(a: reg_ddp, b: DramModuleClass { buffering: Registered, stacking: DualDiePackage }) +} + // THE WITHDRAWAL IS THE STANDING, not a missing entry. A board-down proposal must land on the // arm that says the nearest class was taken away, because that routes differently from "nobody // has established it" — one stops the proposal, the other invites a test campaign. diff --git a/dag/test/claim/micron_dram_module_witness_test.dag b/dag/test/claim/micron_dram_module_witness_test.dag new file mode 100644 index 00000000000..8da5d40bec8 --- /dev/null +++ b/dag/test/claim/micron_dram_module_witness_test.dag @@ -0,0 +1,186 @@ +module test.claim.micron_dram_module + +import std.types { Bool, NonEmptyStr, list_length } +import std.measure { bit_width, bit_width_count, byte_size, byte_size_count } +import std.decl_ref { decl_ref, declaration_ref_eq } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import extdeps.memory.types { + DramModuleCatalogRow, + DramModuleClass, + DualDiePackage, + MonolithicDie, + Registered, + ThreeDimensionalStacked, + dram_chips_per_rank, + dram_generation_ddr4, + dram_generation_eq, + dram_module_class_eq, + dram_module_is_realizable, + dram_module_required_die_density, +} +import extdeps.memory.jedec { ddr4_generation_catalog, ddr5_generation_catalog } +import extdeps.memory.micron { + extdeps_model_scope, + micron_ddr4_module_part_numbering_rev_2018_12_05, + micron_ddr4_rdimm_core_rev_b_2021_12, + micron_part_catalog_mta36ads2g72pz_2g1a1, + micron_part_catalog_mta36asf2g72pz_2g1a2, + mta36ads2g72pz_2g1a1_catalog, + mta36ads2g72pz_2g1a1_catalog_citation, + mta36ads2g72pz_2g1a1_numbering_citation, + mta36asf2g72pz_2g1a2_catalog, + mta36asf2g72pz_2g1a2_catalog_citation, +} +import extdeps.vendor.micron { micron } +import extdeps.cpu.ampere_altra_memory_controller { altra_admits_module_class } +import product.installed_bom_reconcile { + DimmPopulationConfirmed, + DimmPopulationRefused, + DimmPopulationUnconfirmed, + DimmObservationHostMismatch, + DimmSlotLocator, + DimmSlotsObserved, + HostDimmExpectation, + ObservedDimmCataloged, + ObservedDimmSlot, + dimm_reconcile_verdict, +} +import gunbc.fleet_intent_network { operator_host_mtcollins1 } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +test fn w_ads_row_axes_match_the_numbering_decode_and_spd() -> Bool { + mta36ads2g72pz_2g1a1_catalog.part_number == ("MTA36ADS2G72PZ-2G1A1" as NonEmptyStr) + && mta36ads2g72pz_2g1a1_catalog.manufacturer == micron + && mta36ads2g72pz_2g1a1_catalog.buffering == Registered + && mta36ads2g72pz_2g1a1_catalog.die_stacking == DualDiePackage + && bit_width_count(b: mta36ads2g72pz_2g1a1_catalog.chip_width) == 4 + && mta36ads2g72pz_2g1a1_catalog.rank_count == 2 + && mta36ads2g72pz_2g1a1_catalog.data_rate_mts == 2133 + && mta36ads2g72pz_2g1a1_catalog.ecc + && byte_size_count(b: mta36ads2g72pz_2g1a1_catalog.capacity_bytes) == 17179869184 + && dram_generation_eq(a: mta36ads2g72pz_2g1a1_catalog.generation, b: dram_generation_ddr4) +} + +// THE TWO SIBLINGS AGREE ON EVERY FIELD BUT ONE, which is the finding the module exists to +// carry: the axis Micron's own data separates them on is package construction, and nothing +// else on the row. A control that let them differ elsewhere would let a wrong transcription of +// either row masquerade as the finding. +test fn w_siblings_differ_only_in_die_stacking() -> Bool { + mta36asf2g72pz_2g1a2_catalog.die_stacking == MonolithicDie + && mta36asf2g72pz_2g1a2_catalog.manufacturer == mta36ads2g72pz_2g1a1_catalog.manufacturer + && byte_size_count(b: mta36asf2g72pz_2g1a2_catalog.capacity_bytes) == byte_size_count(b: mta36ads2g72pz_2g1a1_catalog.capacity_bytes) + && mta36asf2g72pz_2g1a2_catalog.data_rate_mts == mta36ads2g72pz_2g1a1_catalog.data_rate_mts + && mta36asf2g72pz_2g1a2_catalog.ecc == mta36ads2g72pz_2g1a1_catalog.ecc + && mta36asf2g72pz_2g1a2_catalog.buffering == mta36ads2g72pz_2g1a1_catalog.buffering + && bit_width_count(b: mta36asf2g72pz_2g1a2_catalog.chip_width) == bit_width_count(b: mta36ads2g72pz_2g1a1_catalog.chip_width) + && mta36asf2g72pz_2g1a2_catalog.rank_count == mta36ads2g72pz_2g1a1_catalog.rank_count + && mta36asf2g72pz_2g1a2_catalog.part_number != mta36ads2g72pz_2g1a1_catalog.part_number + && !dram_module_class_eq( + a: DramModuleClass { buffering: Registered, stacking: mta36asf2g72pz_2g1a2_catalog.die_stacking }, + b: DramModuleClass { buffering: Registered, stacking: mta36ads2g72pz_2g1a1_catalog.die_stacking }, + ) +} + +// SPD byte 4 says 4 Gb per die; the row's capacity, width and rank count must divide back out +// to it, for BOTH siblings, so the density corroboration does not depend on the stacking value. +test fn w_both_rows_derive_eighteen_dies_per_rank_and_four_gigabit() -> Bool { + dram_chips_per_rank(module: mta36ads2g72pz_2g1a1_catalog) == 18 + && dram_chips_per_rank(module: mta36asf2g72pz_2g1a2_catalog) == 18 + && byte_size_count(b: dram_module_required_die_density(module: mta36ads2g72pz_2g1a1_catalog)) == 536870912 + && byte_size_count(b: dram_module_required_die_density(module: mta36asf2g72pz_2g1a2_catalog)) == 536870912 +} + +test fn w_both_rows_are_realizable_on_ddr4_and_not_ddr5() -> Bool { + dram_module_is_realizable(module: mta36ads2g72pz_2g1a1_catalog, jedec: ddr4_generation_catalog) + && dram_module_is_realizable(module: mta36asf2g72pz_2g1a2_catalog, jedec: ddr4_generation_catalog) + && !dram_module_is_realizable(module: mta36ads2g72pz_2g1a1_catalog, jedec: ddr5_generation_catalog) +} + +// THE ALTRA ADMISSION FOLD NOW ANSWERS DIFFERENTLY FOR THE TWO SIBLINGS, and the answer for the +// DDP part is "not among the classes the Rev A1 datasheet names" -- RDIMM, LRDIMM, 3DS RDIMM -- +// which is the absence of a listing and not a withdrawal (extdeps.cpu.ampere_altra_memory_controller +// keeps those two apart). Before DualDiePackage existed the ADS row could only be written as +// monolithic and this fold would have admitted it as a class it does not belong to. +test fn w_altra_fold_separates_the_siblings_on_the_stacking_axis() -> Bool { + altra_admits_module_class(c: DramModuleClass { buffering: Registered, stacking: mta36asf2g72pz_2g1a2_catalog.die_stacking }) + && !altra_admits_module_class(c: DramModuleClass { buffering: Registered, stacking: mta36ads2g72pz_2g1a1_catalog.die_stacking }) + && altra_admits_module_class(c: DramModuleClass { buffering: Registered, stacking: ThreeDimensionalStacked }) +} + +// THE PURCHASING/INTAKE CONSUMER: an observed Micron part on Mt. Collins unit 1 now resolves to +// a cited catalog row instead of refusing as ObservedDimmUncataloged. One slot, one expectation, +// and the reconciliation CONFIRMS -- which it could not do for any Micron part before this module. +test fn w_observed_micron_part_on_mtcollins1_reconciles_against_a_cited_row() -> Bool { + match dimm_reconcile_verdict( + expectation: HostDimmExpectation { + host: operator_host_mtcollins1, + catalog: mta36ads2g72pz_2g1a1_catalog, + stick_count: 1, + }, + observation: DimmSlotsObserved { + host: operator_host_mtcollins1, + slots: [ + ObservedDimmSlot { + locator: "DIMM_A1" as DimmSlotLocator, + identity: ObservedDimmCataloged { catalog: mta36ads2g72pz_2g1a1_catalog }, + serial: none, + }, + ], + }, + ) { + DimmPopulationConfirmed { host: _, stick_count: n } => n == 1 + DimmPopulationRefused { host: _, discrepancies: _, count: _ } => false + DimmObservationHostMismatch { expectation_host: _, observation_host: _ } => false + DimmPopulationUnconfirmed { host: _, cause: _ } => false + } +} + +// AND THE DISCRIMINATING CONTROL ON THAT CONSUMER: expecting the monolithic sibling and observing +// the dual-die one is a part difference the reconciliation must name, not absorb. If the two rows +// ever collapsed into one identity this would pass Confirmed and the finding would be gone. +test fn w_expecting_the_asf_sibling_and_observing_the_ads_part_refuses() -> Bool { + match dimm_reconcile_verdict( + expectation: HostDimmExpectation { + host: operator_host_mtcollins1, + catalog: mta36asf2g72pz_2g1a2_catalog, + stick_count: 1, + }, + observation: DimmSlotsObserved { + host: operator_host_mtcollins1, + slots: [ + ObservedDimmSlot { + locator: "DIMM_A1" as DimmSlotLocator, + identity: ObservedDimmCataloged { catalog: mta36ads2g72pz_2g1a1_catalog }, + serial: none, + }, + ], + }, + ) { + DimmPopulationRefused { host: _, discrepancies: d, count: _ } => list_length(items: d) == 1 + DimmPopulationConfirmed { host: _, stick_count: _ } => false + DimmObservationHostMismatch { expectation_host: _, observation_host: _ } => false + DimmPopulationUnconfirmed { host: _, cause: _ } => false + } +} + +test fn w_citations_bind_each_row_to_micron_hosted_authorities() -> Bool { + declaration_ref_eq( + a: mta36ads2g72pz_2g1a1_catalog_citation.fact, + b: decl_ref(module_path: "extdeps.memory.micron", decl_name: "mta36ads2g72pz_2g1a1_catalog"), + ) + && mta36ads2g72pz_2g1a1_catalog_citation.authority == micron_part_catalog_mta36ads2g72pz_2g1a1 + && declaration_ref_eq( + a: mta36ads2g72pz_2g1a1_numbering_citation.fact, + b: mta36ads2g72pz_2g1a1_catalog_citation.fact, + ) + && mta36ads2g72pz_2g1a1_numbering_citation.authority == micron_ddr4_module_part_numbering_rev_2018_12_05 + && declaration_ref_eq( + a: mta36asf2g72pz_2g1a2_catalog_citation.fact, + b: decl_ref(module_path: "extdeps.memory.micron", decl_name: "mta36asf2g72pz_2g1a2_catalog"), + ) + && mta36asf2g72pz_2g1a2_catalog_citation.authority == micron_part_catalog_mta36asf2g72pz_2g1a2 + && extdeps_model_scope.first_citation == micron_part_catalog_mta36ads2g72pz_2g1a1 + && list_length(items: extdeps_model_scope.further_citations) == 2 + && extdeps_model_scope.first_citation.uri.locator != micron_ddr4_rdimm_core_rev_b_2021_12.uri.locator +} diff --git a/dag/test/claim/samsung_dram_module_witness_test.dag b/dag/test/claim/samsung_dram_module_witness_test.dag index f401652aaeb..82a57b22dd5 100644 --- a/dag/test/claim/samsung_dram_module_witness_test.dag +++ b/dag/test/claim/samsung_dram_module_witness_test.dag @@ -24,6 +24,7 @@ data control_32g_1rx8: DramModuleCatalogRow = DramModuleCatalogRow { test fn row_axes_match_the_labelled_module_organization() -> Bool { m386a4g40dm0_cpb_catalog.part_number == ("M386A4G40DM0-CPB" as NonEmptyStr) && m386a4g40dm0_cpb_catalog.buffering == LoadReduced + && m386a4g40dm0_cpb_catalog.die_stacking == DualDiePackage && bit_width_count(b: m386a4g40dm0_cpb_catalog.chip_width) == 4 && m386a4g40dm0_cpb_catalog.rank_count == 4 && m386a4g40dm0_cpb_catalog.data_rate_mts == 2133 diff --git a/docs/plans/micron-mta36ads2g72pz-identification.md b/docs/plans/micron-mta36ads2g72pz-identification.md new file mode 100644 index 00000000000..ee15c525fa7 --- /dev/null +++ b/docs/plans/micron-mta36ads2g72pz-identification.md @@ -0,0 +1,209 @@ +# MTA36ADS2G72PZ-2G1A1: what Micron says it is, and what the Ampere documents say about it + +Survey date: 2026-09-12. Lane: clever-heron-234, work item `node://adhoc-677e2a53-ae7`. +Landed authority: `extdeps.memory.micron` (rows `mta36ads2g72pz_2g1a1_catalog`, +`mta36asf2g72pz_2g1a2_catalog`), `extdeps.vendor.micron`, and the third value of +`extdeps.memory.types` `DramDieStacking`. This document carries the reading; the rows carry the +facts. Nothing observed on Mt. Collins unit 1 is authored into `extdeps`. + +## Verdict, in the brief's order + +1. **MTA36ADS2G72PZ-2G1A1 is a 16 GB, 2-rank, x4, DDR4-2133 CL15, ECC, registered, + VERY-LOW-PROFILE (18.75 mm) RDIMM built from 18 DUAL-DIE packages of two 4 Gb dies each.** + Every word of that is Micron's, from two documents (part-numbering decode and the SPD image + Micron publishes for the part), and the two agree at byte grain. Status: obsolete. +2. **ADS versus ASF is `DS` = "VLP Dual-Die w/Temp Sensor" versus `SF` = "FBGA w/Temp + Sensor".** Micron's DDR4 Module Part Numbering System (Rev. 05-Dec-2018) defines the + module-options field as a two-letter code where the first letter is the PCB height class + (`S` standard, `D` VLP, `H` 2U, `L` 4U) and the second the DRAM package (`F` FBGA + single-die, `S` dual-die, `Q` quad-die, `E` octal-die). The letter difference IS the answer: + the ADS part is the VLP dual-die build of the same 36-die, 2 Gig x 72, RDIMM, -2G1 family. +3. **"2DRx4" reads as "2 ranks, dual-die, x4", and that is verified, not adopted.** The + operator's hypothesis was that a VLP module needs dual-die packages to reach 16 GB with x4 + devices in 18.75 mm. Micron's SPD byte 6 for the part is `0x91`: non-monolithic, 2 dies, + MULTI LOAD STACK, i.e. the JEDEC class a DDP belongs to. Byte 128 (`0x04`, nominal height + ≤ 19 mm) confirms the VLP outline. The catalogue's "Component Config: 2Gb x4" names the + 8 Gb dual-die package; "Number of Components: 36" counts dies, matching the `36` in the + part number, whose field the numbering sheet labels "Number of Die". +4. **Ampere publishes nothing that admits or refuses a dual-die (multi-load stack) RDIMM.** + Altra Rev A1 Datasheet Issue 1.55 §2.10 lists "RDIMMs, LRDIMMs, and Stacked (3DS) RDIMMs" + and "8 Gb and 16 Gb DRAM devices"; the words DDP, dual-die, multi-load and 4 Gb do not + appear in the document. Neither does the Mt. Collins GSG, the OCP Mt. Jade spec, or the + AVL say anything about package construction. The OCP Table 3 "Different DRAM DIES" = Yes + cells govern MIXING die types across modules; they do not say a given die construction is + supported, and this survey did not let them. Note also that the datasheet's device list + (8 Gb, 16 Gb) does not name the 4 Gb die that BOTH Micron quartets use, and the monolithic + quartet trained; so "unlisted device density" is a fact about both quartets and cannot be + what separates them. The corpus now models the DDP class as *not among the listed classes* + (`altra_admits_module_class` answers false for Registered × DualDiePackage) and the + controller module's own prose keeps that distinct from a withdrawal such as UDIMM's. +5. **Neither part is on the Ampere Altra Family AVL Issue 1.15 (December 2025).** Table 3's + Micron rows are MTA18ASF2G72PDZ (16 GB 2Rx8), MTA18ASF2G72PZ-2G9E1 (16 GB 1Rx4), + MTA36ASF4G72PZ (32 GB 2Rx4, three suffixes) and MTA36ASF8G72PZ-3G2E1 (64 GB 2Rx4) — all + `SF`, all 8 Gb/16 Gb dies, all 2666 or faster. There is NO 16 GB 2Rx4 row from any vendor + and no 2133 row at all, so the AVL is equally silent about the ADS part and the ASF part + that trained. An AVL omission is not a prohibition and this survey does not read it as one. + +**Firmware corroboration, received from hw-first-host after this survey was drafted (SOL capture +`artifacts/bmc/mtcollins1-sol-dram-training-2026-09-12.txt`, sha256 `e5044f71…8a4c`, on that +lane's branch).** The Altra DRAM-init firmware prints the ADS part as +`RDIMM[2c:80] 16GB 2133 ECC 2R x4 RCD[b3:80] 36ADS2G72PZ-2G1A1` — rank count 2, exactly as +Micron's byte 12 says, the `D` being a package letter and not a rank — and refuses the mixed +socket with `ERR: CHANNEL Mismatch Byte 6 SLOT0[00] EXP[91] @MCU[4]` followed by +`ERROR: Non-identical DIMM mixture NOT supported!`. Two things follow, both about the observing +layer and neither authored into `extdeps`: (a) the module's SPD byte 6 reads `0x91` on the +board, agreeing with Micron's published image; (b) what the firmware enforces on that socket is +**byte-6 agreement across the socket's channels**, i.e. a MIXING rule, so the failure with +4 × ADS + 12 monolithic is a mixed-population refusal and says nothing about a uniform ADS +population, which has not been run. The trained quartet's label reads `36ASF2G72PZ-2G1A2II`, +matching the catalogue SKU carried here plus process code `II`. The firmware's `RCD[b3:80]` / +`RCD[32:86]` per-module variation is the same variation Micron's record carries across process +codes (bytes 133–135), which is why register vendor is not a field of the catalogue row. + +**Which of the three differing axes is operative — read carefully, because three bytes differ +and only one is named.** The refusal quotes byte 6. Bytes 128 (height) and 130 (raw card) +differ between the two parts just as much and are not mentioned. The strongest honest reading: +the axis the firmware is known to compare is package type / die count / signal loading — the +byte `DualDiePackage` is grounded on — and VLP height and raw card are not shown to matter. +What the message does NOT establish is that they are unchecked: a comparator that stops at its +first mismatch would print byte 6 whether or not it also compares 128 or 130 later in its +order. So "VLP is a passenger" is the reading the evidence favours, at inference strength; +proving it needs a population that differs at 128/130 but agrees at 6 (an `SS`/`DF`-coded part +against a monolithic full-height one), which has not been run. + +**What Micron's data leaves as the only differences between the two quartets:** package +construction (dual-die multi-load stack vs monolithic), PCB outline (18.75 vs 31.25 mm) and, with +the outline, the JEDEC raw-card reference design (SPD byte 130 `0x08` vs `0x01`) and the +module-attribute byte 131 (`0x05` vs `0x09`). Everything else — vendor, generation, capacity, +speed bin, CAS latency, ECC, buffering, device width, package-rank count, die density, DRAM +addressing — is byte-identical between the two SPD images. Which of those the Mt. Collins +training outcome tracks is not decided by any document read here; the firmware line above +names byte 6 directly, and that receipt belongs with the lane that ran the crossovers. + +## Documents read + +| Document | Revision | Locator | Digest / standing | What it establishes | +|---|---|---|---|---| +| Micron part catalogue record, MTA36ADS2G72PZ-2G1A1 | database record fetched 2026-09-12 | `www.micron.com/products/obsolete/obsolete-vlp-rdimm/part-catalog/part-detail/mta36ads2g72pz-2g1a1` (renders `…/_jcr_content.products.json/getproductinfo/-/-/-/en_US/-/mta36ads2g72pz-2g1a1`) | HTTP 200, no credentials, `"data-source": "DATABASE"`, `"sub-category": "obsolete-vlp-rdimm"` | Details table and full DDR4 SPD image (12 process codes JG/HK/JJ/JI/HG/HJ/II/HI/IG/IJ/IK/JK; they differ only at register-vendor bytes 133–135 and the bytes-128..253 CRC). | +| Micron part catalogue record, MTA36ASF2G72PZ-2G1A2 | same | `www.micron.com/products/obsolete/obsolete-rdimm/part-catalog/part-detail/mta36asf2g72pz-2g1a2` | HTTP 200 | The control's details table and SPD (process codes KI/KJ/KK/KG/II/IG/IJ/IK). The bare `mta36asf2g72pz-2g1` record answers with no process codes. | +| Micron DDR4 Module Part Numbering System | Rev. 05-Dec-2018 | `siewert-kau.info/micron/wp-content/uploads/2020/05/Nomenklatur_Micron.pdf` (distributor copy; `micron.com/numbering` → `assets.micron.com` answers "Request Rejected" to this session) | sha256 `7d52c2ad…5c6a2` | Field decode: family, die count, voltage, module options (`DS` = VLP Dual-Die w/Temp Sensor, `SF` = FBGA w/Temp Sensor), configuration, module type (`P` = 288-pin RDIMM), package code (`Z`), speed grade (`-2G1` = DDR4-2133, PC4-2133, 15-15-15, component -093E), die and PCB revision. | +| Micron 288-Pin DDR4 RDIMM Core Product Description | Rev. B 12/2021, CCM005-341111752-10541 | `media.digikey.com/pdf/Data%20Sheets/Micron%20Technology%20Inc%20PDFs/DDR4_SDRAM_RDIMM_Core_RevB_Dec2021.pdf` (DigiKey copy of Micron's PDF; Micron's own host rejects) | sha256 `ea054b3d…8abc` | Figure 1 RDIMM 31.25 ± 0.15 mm; Figure 2 VLP RDIMM 18.75 ± 0.15 mm; Table 12 module ↔ component speed grades; C0–C2 pin text distinguishing "a traditional DDP package, which uses CS1_n, CKE1, and ODT1 to control the second die" from single-load 4H/8H stacks. It says the per-part organization lives in the MPN-specific addendum. | +| Micron per-part addendum for MTA36ADS2G72PZ | — | **Not found.** Probed `…/data-sheet/modules/{vlp_rdimm,rdimm,parity_rdimm}/ads36a2gx72pz.pdf` and variants (404); search engines index no addendum for the ADS family; the catalogue page's download resource answers 404. | — | The SPD image is the strongest first-party organization statement reachable; the addendum would add placement and thermal figures, not organization. | +| Ampere Altra Rev A1 Datasheet | Issue 1.55, 2025-04-08 | `extdeps.cpu.ampere` `ampere_altra_rev_a1_datasheet_authority` (v1.55 locator) | 90 pages, read as text | §2.10 feature list; no DDP / dual-die / multi-load / 4 Gb text anywhere in the document. | +| Ampere Altra Family AVL | Issue 1.15, December 2025, AMP 2025-0116 | `extdeps.cpu.ampere` `ampere_altra_avl_authority` | sha256 `6199ae84…8d0d` (matches swift-bat-341's read) | Table 3 Micron rows listed above; no 16 GB 2Rx4 row; no 2133 row; §1.3 test suite is homogeneous 1DPC/2DPC. | +| OCP Mt. Jade Motherboard Spec | Rev 1.0 | `extdeps.ocp.mt_jade.memory_mixing` | already modelled | Table 3 is a MIXING matrix; "Different DRAM DIES" = Yes is not a construction-support statement. | +| swift-bat-341 survey | 2026-09-11 | [altra-cross-channel-rank-mixing-survey.md](altra-cross-channel-rank-mixing-survey.md) | — | Starting point for the AVL and the platform-guide reads; nothing there is contradicted here. | + +### Reading the two SPD images side by side + +| Byte | Meaning (JESD21-C Annex L) | ADS-2G1A1 | ASF-2G1A2 | +|---|---|---|---| +| 2 | DRAM device type | `0C` DDR4 | `0C` | +| 3 | Module type | `01` RDIMM | `01` | +| 4 | Density and banks | `84` 4 Gb/die, 4 BG × 4 banks | `84` | +| 5 | Addressing | `21` 16 rows, 10 columns | `21` | +| **6** | **SDRAM package type** | **`91` non-monolithic, 2 dies, multi-load stack** | **`00` monolithic** | +| 12 | Module organization | `08` 2 package ranks, x4 | `08` | +| 13 | Bus width | `0B` 64 + 8 ECC | `0B` | +| 18 / 125 | tCKmin / fine offset | `08` / `C2` → 938 ps (2133) | same | +| 24 | tAAmin | `6C` 13.5 ns → CL15 | same | +| **128** | **Nominal height** | **`04` ≤ 19 mm** | **`11` ≤ 32 mm** | +| 129 | Max thickness | `11` | `11` | +| **130** | **Raw card** | **`08`** | **`01`** | +| **131** | **RDIMM attributes** | **`05`** | **`09`** | +| 329–349 | Part number | `36ADS2G72PZ-2G1A1` | `36ASF2G72PZ-2G1A2` | + +Raw card letters and bytes 131/133–135 are recorded as bytes, not decoded: the JEDEC raw-card +letter table and the JEP106 register-vendor table are not authorities the corpus carries yet, +and reading them from memory would be exactly the uncited transcription §4d forbids. A JEDEC +SPD authority module (`extdeps.memory.jedec` currently carries only the generation ceilings) is +the named follow-up that would make the decode above typed rather than prose. + +## The OEM SEL family (second half) + +Payloads observed on Mt. Collins unit 1, all manufacturer `3a cd 00`, record type `C0`, raw +bytes preserved exactly as the brief carries them: + +``` +0fde7033ff10 0fde703bff10 2026-08-19, same timestamp, adjacent record IDs +0fde70330102 (x19) 0fde70330502 (x2) +0fde70331102 0fde703b1102 +``` + +### What is public + +The only public serializer of a `3a cd 00` / `C0` OEM SEL record with this byte shape is +Ampere's OpenBMC layer, `meta-ampere/meta-common/recipes-ampere/host/ac01-boot-progress/dimm_train_fail_log.sh` +in `github.com/ampere-openbmc/openbmc` (read at `f68588807957ffbc07371634ed41e534e7b416c2`, +2026-01-22; the script has three commits in its history and was created 2023-04-15 already +carrying the constants below — there is no earlier revision with a different sensor number). +It emits, via `IpmiSelAddOem` with OEM id `0x3a 0xcd 0x00` and SEL type bytes +`0x00 0x00 0x00 0xC0`: + +``` +byte 0 SENSOR_TYPE_SYSTEM_FW_PROGRESS = 0x0F +byte 1 SENSOR_BOOT_PROGRESS = 235 = 0xEB +byte 2 EVENT_DIR_ASSERTION | OEM_SENSOR_SPECIFIC = 0x00 | 0x70 +byte 3 (channel << 4) | (socket << 3) | BOOT_SYNDROME_DATA(=4) +byte 4 syndrome bits 15:8 (the SoC-BMC "Boot Stage Error Syndrome" byte 1) +byte 5 syndrome bits 7:0 (byte 0: [1:0] failure type, [4:2] physical rank, [7:5] syndrome 0) +``` + +The syndrome bytes it copies are defined by the Ampere Altra Family SoC-BMC Interface +Specification, Issue 1.43 (2023-05-30), Table 16 registers `0xB4` (slot select) and `0xB5` +(Boot Stage Error Syndrome): failure type 1 = PHY training, 2 = DIMM training; syndrome 0 for +PHY = setup / write leveling / read gate leveling / read leveling / software training; +syndrome 0 for DIMM = VREFDQ / LRDIMM DB / LRDIMM DB software; byte 1 for write leveling = +slice number and per-nibble "no rising edge" bits. The specification is a `connect-admin` +download that answered HTTP 200 without credentials (sha256 `34ccdcd2…`, 56 pages). The +companion "Altra Family Monitoring Events" v0.60 (2023-06-05, sha256 `23d84c2c…`) is a +Redfish message registry and defines no SEL byte layout. + +### What is not public, and therefore not decoded + +- **Sensor `0xde` (222) is not in any public Ampere source.** `ampere-openbmc/openbmc`, + `ampere-ipmi-oem`, and the Mt. Jade / Mt. Mitchell IPMI sensor YAMLs were searched; 222 and + 235 appear there only as ordinary temperature/current sensor numbers unrelated to boot + progress. Mt. Collins runs AMI MegaRAC (`extdeps.ampere.mt_collins_product_brief.bmc`), not + this OpenBMC layer, and AMI's Ampere port is not published. So the `0xde` serializer is + **not found**. +- **Byte 3's low nibble is `3` where the public schema writes `4`**, and the sensor number + differs, so the OpenBMC layout is a *related* schema and no byte of ours may be read through + it as a decode. Under that layout byte 3 = `0x33` would be channel 3, socket 0; `0x3b` + would be channel 3, socket 1 — which is consistent with the operator's inference that bit 3 + moved with the socket holding the intervened population across the two crossovers, and is + still an inference: the companions moved with it. +- **The tail is ambiguous even under the cousin schema**, and the ambiguity is why it is not + promoted. Reading `11 02` as `[syndrome hi][syndrome lo]` gives failure type 2 (DIMM + training), rank 0, syndrome0 = 0 with byte 1 = `0x11`; reading it as `[lo][hi]` gives failure + type 1 (PHY training), rank 4, syndrome0 = 0, byte 1 = `0x02` (write-leveling slice 2). The + two readings name different training steps and different ranks. Only a decode of register + `0xB5` on this platform, or the AMI serializer, settles it. The `ff 10` pair from 2026-08-19 + reads as failure type 3 (Reserved) under one ordering and failure type 0 (N/A — no failure) + under the other, neither of which is a syndrome a training-failure record should carry, which + is further evidence that the `0xde` family is not simply the `0xeb` family under another + sensor number. + +So the payloads stay raw. `gunbc.host_memory_qualification` `TrainingEvidenceStanding` already +has the right arms for what a receipt may claim: `AssociatedByIdenticalSignature` at best +(signature = the raw six bytes, source = the meta-ampere script as the related schema), never +`DecodedFromPlatformSyndrome`, until `0xB5` is read on the unit. + +## What this lane did not land, and why + +- **No `HostMemoryStanding` or `CausalExperimentReceipt` rows for the eight Mt. Collins + configurations.** The brief summarises them (durations, wattage, temperature, payloads) but + carries no instants, no DIMM masks, no slot locators; authoring receipts from a summary would + fabricate `observed_at` values and put prose in the mask field — the exact defect that module's + own notes record. The rows belong to the lane that holds the raw BMC log; they now have a + catalog row to bind to (`ObservedDimmCataloged { catalog: mta36ads2g72pz_2g1a1_catalog }` + reconciles, exercised by `test.claim.micron_dram_module`). +- **No typed SEL/OEM-record carrier.** One night's payloads under an unpublished schema are + not an upstream authority. A carrier is warranted when either the AMI serializer or a `0xB5` + read exists to ground it. +- **No `form_factor`/height field on `DramModuleCatalogRow`.** The VLP fact is carried in the + row's annotation and here; the field lands with its first consumer (a chassis DIMM-clearance + check), per §3c. +- **The Micron-hosted locators.** Both Micron PDFs are cited through distributor copies with + digests because `assets.micron.com` rejects this session's fetches; re-cite to `micron.com` + when reachable. The catalogue records ARE Micron-hosted.