diff --git a/src/device/rcp/ri/ri_controller.h b/src/device/rcp/ri/ri_controller.h index 940fa80e5..852cb6f94 100644 --- a/src/device/rcp/ri/ri_controller.h +++ b/src/device/rcp/ri/ri_controller.h @@ -54,12 +54,23 @@ static osal_inline uint32_t ri_reg(uint32_t address) return (address & 0xffff) >> 2; } -static osal_inline uint16_t ri_address_to_id_field(uint32_t address) +static osal_inline uint32_t ri_address(uint32_t address) { - /* XXX: pure guessing, need harware test */ - return (uint16_t)(((address >> 20) == 0x03f) - ? (address & 0x0007fc00) >> 10 /* RDRAM registers id_field: [19..10] */ - : (address & 0x00f00000) >> 20); /* RDRAM memory id_field: [23..20] */ + /* https://n64brew.dev/wiki/RDRAM_Interface#Memory_addressing */ + return (((address >> 20) == 0x03f) + ? (((address & 0x3ff))) | /* Adr[10:0] */ + (((address >> 10) & 0x1ff) << 11) | /* Adr[19:11] */ + (((address >> 10) & 0x1ff) << 20) /* Adr[28:20] */ + : (((address & 0x7ff))) | /* Adr[10:0] */ + (((address >> 11) & 0x1ff) << 11) | /* Adr[19:11] */ + (((address >> 20) & 0x03f) << 20)); /* Adr[28:20] */ +} + +static osal_inline uint16_t ri_address_to_id_field(uint32_t address, uint8_t swapfield) +{ + /* https://n64brew.dev/wiki/RDRAM#RDRAM_addressing */ + return (((swapfield & ((address >> 11) & 0x1ff))) + | ((~swapfield & ((address >> 20) & 0x1ff)))); /* AdrS[28:20] */ } diff --git a/src/device/rdram/rdram.c b/src/device/rdram/rdram.c index 28065eaf0..345120c0b 100644 --- a/src/device/rdram/rdram.c +++ b/src/device/rdram/rdram.c @@ -31,7 +31,7 @@ #include #define RDRAM_BCAST_ADDRESS_MASK UINT32_C(0x00080000) - +#define RDRAM_MODE_CE_MASK UINT32_C(0x80000000) /* XXX: deduce # of RDRAM modules from it's total size * Assume only 2Mo RDRAM modules. @@ -59,19 +59,25 @@ static osal_inline uint16_t idfield_value(uint32_t device_id) { return ((((device_id >> 26) & 0x3f) << 0) | (((device_id >> 23) & 0x01) << 6) - | (((device_id >> 16) & 0xff) << 7) + | (((device_id >> 8) & 0xff) << 7) | (((device_id >> 7) & 0x01) << 15)); } +static osal_inline uint8_t swapfield_value(uint32_t address_select) +{ + return ((((address_select >> 25) & 0x7f) << 0) + | (((address_select >> 15) & 0x01) << 7)); +} + static size_t get_module(const struct rdram* rdram, uint32_t address) { size_t module; size_t modules = get_modules_count(rdram); - uint16_t id_field = ri_address_to_id_field(address); - + uint16_t id_field; for (module = 0; module < modules; ++module) { - if (id_field == idfield_value(rdram->regs[module][RDRAM_DEVICE_ID_REG])) { + id_field = ri_address_to_id_field(ri_address(address), swapfield_value(rdram->regs[module][RDRAM_ADDR_SELECT_REG])); + if ((id_field & 0xFFFE) == (idfield_value(rdram->regs[module][RDRAM_DEVICE_ID_REG]) & 0xFFFE)) { return module; } } @@ -87,8 +93,6 @@ static void read_rdram_dram_corrupted(void* opaque, uint32_t address, uint32_t* uint32_t addr = rdram_dram_address(address); size_t module; - *value = rdram->dram[addr]; - module = get_module(rdram, address); if (module == RDRAM_MAX_MODULES_COUNT) { *value = 0; @@ -97,7 +101,14 @@ static void read_rdram_dram_corrupted(void* opaque, uint32_t address, uint32_t* /* corrupt read value if CC value is not calibrated */ uint32_t mode = rdram->regs[module][RDRAM_MODE_REG] ^ UINT32_C(0xc0c0c0c0); - if ((mode & 0x80000000) && (cc_value(mode) == 0)) { + if ((mode & RDRAM_MODE_CE_MASK) && (cc_value(mode) == 0)) { + *value = 0; + return; + } + + if (address < rdram->dram_size) { + *value = rdram->dram[addr]; + } else { *value = 0; } } @@ -107,7 +118,7 @@ static void map_corrupt_rdram(struct rdram* rdram, int corrupt) struct mem_mapping mapping; mapping.begin = MM_RDRAM_DRAM; - mapping.end = MM_RDRAM_DRAM + rdram->dram_size - 1; + mapping.end = MM_RDRAM_DRAM + 0x3efffff; mapping.type = M64P_MEM_RDRAM; mapping.handler.opaque = rdram; mapping.handler.read32 = (corrupt) @@ -131,6 +142,7 @@ void init_rdram(struct rdram* rdram, rdram->dram = dram; rdram->dram_size = dram_size; rdram->r4300 = r4300; + rdram->corrupted_handler = 0; } void poweron_rdram(struct rdram* rdram) @@ -185,33 +197,11 @@ void write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t m { struct rdram* rdram = (struct rdram*)opaque; uint32_t reg = rdram_reg(address); + uint32_t mode; + uint8_t corrupted_handler = 0; size_t module; size_t modules = get_modules_count(rdram); - /* HACK: Detect when current Control calibration is about to start, - * so we can set corrupted rdram_dram handler - */ - if (address & RDRAM_BCAST_ADDRESS_MASK && reg == RDRAM_DELAY_REG) { - map_corrupt_rdram(rdram, 1); - } - - /* HACK: Detect when current Control calibration is over, - * so we can restore the original rdram_dram handler - * and let dynarec have it's fast_memory enabled. - */ - if (address & RDRAM_BCAST_ADDRESS_MASK && reg == RDRAM_MODE_REG) { - map_corrupt_rdram(rdram, 0); - - /* HACK: In the IPL3 procedure, at this point, - * the amount of detected memory can be found in s4 */ - size_t ipl3_rdram_size = r4300_regs(rdram->r4300)[20] & UINT32_C(0x0fffffff); - if (ipl3_rdram_size != rdram->dram_size) { - DebugMessage(M64MSG_WARNING, "IPL3 detected %u MB of RDRAM != %u MB", - (uint32_t) ipl3_rdram_size / (1024*1024), (uint32_t) rdram->dram_size / (1024*1024)); - } - } - - if (address & RDRAM_BCAST_ADDRESS_MASK) { for (module = 0; module < modules; ++module) { masked_write(&rdram->regs[module][reg], value, mask); @@ -223,6 +213,19 @@ void write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t m masked_write(&rdram->regs[module][reg], value, mask); } } + + /* toggle corrupt handler based on CC value for all modules, + * only check values when writing to the mode register */ + if (reg == RDRAM_MODE_REG) { + for (module = 0; module < modules; ++module) { + mode = rdram->regs[module][RDRAM_MODE_REG] ^ UINT32_C(0xc0c0c0c0); + corrupted_handler |= ((mode & RDRAM_MODE_CE_MASK) && (cc_value(mode) == 0)); + } + if (rdram->corrupted_handler != corrupted_handler) { + map_corrupt_rdram(rdram, corrupted_handler); + rdram->corrupted_handler = corrupted_handler; + } + } } diff --git a/src/device/rdram/rdram.h b/src/device/rdram/rdram.h index 3a208b75a..6c30a9c1b 100644 --- a/src/device/rdram/rdram.h +++ b/src/device/rdram/rdram.h @@ -54,6 +54,8 @@ struct rdram uint32_t* dram; size_t dram_size; + uint8_t corrupted_handler; + struct r4300_core* r4300; }; diff --git a/src/main/savestates.c b/src/main/savestates.c index 664edd1c8..959261df0 100644 --- a/src/main/savestates.c +++ b/src/main/savestates.c @@ -932,7 +932,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath) */ for (i = 0; i < RDRAM_MAX_MODULES_COUNT; ++i) { memcpy(dev->rdram.regs[i], dev->rdram.regs[0], RDRAM_REGS_COUNT*sizeof(dev->rdram.regs[0][0])); - dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2; + dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(ri_address(i * 0x200000), 0) << 2; } /* dd state */ @@ -1286,7 +1286,7 @@ static int savestates_load_pj64(struct device* dev, */ for (i = 0; i < (SaveRDRAMSize / 0x200000); ++i) { memcpy(dev->rdram.regs[i], dev->rdram.regs[0], RDRAM_REGS_COUNT*sizeof(dev->rdram.regs[0][0])); - dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2; + dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(ri_address(i * 0x200000), 0) << 2; } /* dd state */