Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix RDRAM initialization #1111

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/device/rcp/ri/ri_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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] */
}


Expand Down
69 changes: 36 additions & 33 deletions src/device/rdram/rdram.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <string.h>

#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.
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
}
}


Expand Down
2 changes: 2 additions & 0 deletions src/device/rdram/rdram.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct rdram
uint32_t* dram;
size_t dram_size;

uint8_t corrupted_handler;

struct r4300_core* r4300;
};

Expand Down
4 changes: 2 additions & 2 deletions src/main/savestates.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down