From 0c619140a00f383cd1e2ae6afc5b1915b7512f0f Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Tue, 14 Jan 2025 23:34:51 +0100 Subject: [PATCH] Fix RDRAM initialization --- src/device/rcp/ri/ri_controller.h | 12 +++++ src/device/rdram/rdram.c | 77 +++++++++++++++++-------------- src/device/rdram/rdram.h | 2 + 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/device/rcp/ri/ri_controller.h b/src/device/rcp/ri/ri_controller.h index 940fa80e5..c410c71ba 100644 --- a/src/device/rcp/ri/ri_controller.h +++ b/src/device/rcp/ri/ri_controller.h @@ -54,6 +54,18 @@ static osal_inline uint32_t ri_reg(uint32_t address) return (address & 0xffff) >> 2; } +static osal_inline uint32_t ri_address(uint32_t address) +{ + /* 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) & 0x3F) << 20)); /* Adr[28:20] */ +} + static osal_inline uint16_t ri_address_to_id_field(uint32_t address) { /* XXX: pure guessing, need harware test */ diff --git a/src/device/rdram/rdram.c b/src/device/rdram/rdram.c index 28065eaf0..76b5be428 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,32 @@ 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 osal_inline uint16_t ri_address_to_idfield(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] */ +} + 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_idfield(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 +100,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 +108,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; } } @@ -122,7 +140,6 @@ static void map_corrupt_rdram(struct rdram* rdram, int corrupt) #endif } - void init_rdram(struct rdram* rdram, uint32_t* dram, size_t dram_size, @@ -131,6 +148,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) @@ -155,7 +173,6 @@ void poweron_rdram(struct rdram* rdram) } } - void read_rdram_regs(void* opaque, uint32_t address, uint32_t* value) { struct rdram* rdram = (struct rdram*)opaque; @@ -181,37 +198,16 @@ void read_rdram_regs(void* opaque, uint32_t address, uint32_t* value) } } +#include void write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { 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 +219,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; };