diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index b4cdc3aef..1f7a29ede 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -60,6 +60,7 @@ typedef struct int type; smram_t *smram_low, *smram_high; void *agpgart; + void (*write_drbs)(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); } i4x0_t; @@ -652,7 +653,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: if ((addr & 0x7) <= dev->max_drb) { - spd_write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); break; } switch (dev->type) { @@ -676,7 +677,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x65: if ((addr & 0x7) <= dev->max_drb) { - spd_write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); break; } switch (dev->type) { @@ -699,7 +700,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x66: if ((addr & 0x7) <= dev->max_drb) { - spd_write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); break; } switch (dev->type) { @@ -713,7 +714,7 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) break; case 0x67: if ((addr & 0x7) <= dev->max_drb) { - spd_write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); break; } switch (dev->type) { @@ -733,8 +734,12 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x68: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: case INTEL_430HX: + case INTEL_430HX: case INTEL_430VX: case INTEL_430TX: regs[0x68] = val; break; @@ -755,8 +760,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x69: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: case INTEL_440BX: case INTEL_440GX: regs[0x69] = val; break; @@ -769,8 +777,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) } break; case 0x6a: case 0x6b: + if (dev->type == INTEL_430NX) { + dev->write_drbs(regs, 0x60, 0x60 + dev->max_drb, dev->drb_unit); + break; + } switch (dev->type) { - case INTEL_430NX: case INTEL_440BX: case INTEL_440GX: regs[addr] = val; break; @@ -1309,6 +1320,8 @@ static void regs[0x00] = 0x86; regs[0x01] = 0x80; /*Intel*/ + dev->write_drbs = spd_write_drbs; + switch (dev->type) { case INTEL_420TX: case INTEL_420ZX: @@ -1360,7 +1373,7 @@ static void regs[0x59] = 0x0f; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02; dev->max_drb = 5; - dev->drb_unit = 4; + dev->drb_unit = 1; dev->drb_default = 0x02; break; case INTEL_430NX: @@ -1381,8 +1394,9 @@ static void regs[0x59] = 0x0f; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = regs[0x64] = regs[0x65] = regs[0x66] = regs[0x67] = 0x02; dev->max_drb = 7; - dev->drb_unit = 4; + dev->drb_unit = 1; dev->drb_default = 0x02; + dev->write_drbs = spd_write_drbs_with_ext; break; case INTEL_430FX: regs[0x02] = 0x2d; regs[0x03] = 0x12; /* SB82437FX-66 */ diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 81216a6f6..0e17d0da3 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -106,6 +106,7 @@ typedef struct { extern void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size); extern void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); +extern void spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); extern void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit); extern void spd_write_drbs_ali1621(uint8_t *regs, uint8_t reg_min, uint8_t reg_max); diff --git a/src/mem/spd.c b/src/mem/spd.c index 2ce97153b..db8f1a806 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -400,6 +400,58 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit } +/* Needed for 430LX. */ +void +spd_write_drbs_with_ext(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) +{ + uint8_t row, dimm, drb; + uint16_t row_val = size, rows[SPD_MAX_SLOTS]; + int shift; + + /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ + if (!spd_present) { + dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2i((machines[machine].max_ram >> 10) / dimm)), 0); + } + + /* Write DRBs for each row. */ + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + for (row = 0; row <= (reg_max - reg_min); row++) { + dimm = (row >> 1); + size = 0; + + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = (row & 1) ? 0 : drb_unit; + else + size = (row & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (rows[dimm] >> 1); + } + + /* Determine the DRB register to write. */ + drb = reg_min + row; + if (apollo && ((drb & 0xf) < 0xa)) + drb = apollo + (drb & 0xf); + + /* Write DRB register, adding the previous DRB's value. */ + if (row == 0) + row_val = 0; + if (size) + row_val += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + regs[drb] = row_val & 0xff; + drb = reg_min + 8 + (row >> 1); + shift = (row & 0x01) << 3; + regs[drb] = (((row_val & 0xfff) >> 8) << shift); + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); + } +} + + /* Used by ALi M1531 and M1541/2. */ void spd_write_drbs_interleaved(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit)