Compare commits

...

7 Commits

22 changed files with 734 additions and 428 deletions
+9
View File
@@ -12442,6 +12442,7 @@ Transferpak=Yes
GoodName=Pokemon Stadium (E) (V1.0) [f1]
CRC=9DFE20E9 18894032
RefMD5=2859090D78581E0925A3AF8045E81E4B
SiDmaDuration=8192
[31EE2DE8E65E30F5934C450DBAA924F0]
GoodName=Pokemon Stadium (E) (V1.1) [!]
@@ -12449,6 +12450,7 @@ CRC=91C9E05D AD3AAFB9
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[0E85A098D0F0E8A7EB572A69612A6873]
GoodName=Pokemon Stadium (F) [!]
@@ -12456,6 +12458,7 @@ CRC=A23553A3 42BF2D39
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[4688C66F8C13EDA13DD5678176A7FD8A]
GoodName=Pokemon Stadium (F) [f1]
@@ -12468,6 +12471,7 @@ CRC=42011E1B E3552DB5
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[8FAA825507E6CD3F388CC33343FAE547]
GoodName=Pokemon Stadium (G) [f1]
@@ -12480,6 +12484,7 @@ CRC=A53FA82D DAE2C15D
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[D14A499BC4E324974EAE3E42DEC58625]
GoodName=Pokemon Stadium (S) [!]
@@ -12487,6 +12492,7 @@ CRC=B6E549CE DC8134C0
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[8D296A614A47AC99B80D1EDE669E62B3]
GoodName=Pokemon Stadium (S) [f1]
@@ -12499,6 +12505,7 @@ CRC=90F5D9B3 9D0EDCF0
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[C9214988B08511D2F44FAC2FAD2EE67A]
GoodName=Pokemon Stadium (U) (V1.0) [f1]
@@ -12511,6 +12518,7 @@ CRC=1A122D43 C17DAF0F
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[A7087A96A709E4C662A459B4B4159094]
GoodName=Pokemon Stadium (U) (V1.1) [b1]
@@ -12528,6 +12536,7 @@ CRC=9C8FB2FA 9B84A09B
Players=4
SaveType=Flash RAM
Transferpak=Yes
SiDmaDuration=8192
[B1271DB50D6EF8F6B53CC640C3743E4F]
GoodName=Pokemon Stadium 2 (E) [!]
@@ -37,7 +37,7 @@
static uint16_t gb_cart_address(unsigned int bank, uint16_t address)
{
return (address & 0x3fff) | ((bank & 0x3) * 0x4000) ;
return 0x4000 * bank + (address & 0x7fff) - 0x4000;
}
void init_transferpak(struct transferpak* tpk, struct gb_cart* gb_cart)
@@ -49,10 +49,7 @@ void poweron_transferpak(struct transferpak* tpk)
{
tpk->enabled = 0;
tpk->bank = 0;
tpk->access_mode = (tpk->gb_cart == NULL)
? CART_NOT_INSERTED
: CART_ACCESS_MODE_0;
tpk->access_mode_changed = 0x44;
tpk->reset_state = 3;
if (tpk->gb_cart != NULL) {
poweron_gb_cart(tpk->gb_cart);
@@ -68,9 +65,11 @@ void change_gb_cart(struct transferpak* tpk, struct gb_cart* gb_cart)
}
else {
tpk->access_mode = CART_ACCESS_MODE_0;
poweron_gb_cart(gb_cart);
// poweron_gb_cart(gb_cart);
}
tpk->reset_state = 3;
tpk->gb_cart = gb_cart;
}
@@ -84,131 +83,225 @@ static void unplug_transferpak(void* pak)
{
}
static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size)
{
struct transferpak* tpk = (struct transferpak*)pak;
uint8_t value;
DebugMessage(M64MSG_VERBOSE, "tpak read: %04x", address);
switch(address >> 12)
{
case 0x8:
/* get gb cart state (enabled/disabled) */
value = (tpk->enabled)
? 0x84
: 0x00;
DebugMessage(M64MSG_VERBOSE, "tpak get cart state: %02x", value);
memset(data, value, size);
break;
case 0xb:
/* get gb cart access mode */
if (tpk->enabled)
{
DebugMessage(M64MSG_VERBOSE, "tpak get access mode: %02x", tpk->access_mode);
memset(data, tpk->access_mode, size);
if (tpk->access_mode != CART_NOT_INSERTED)
{
data[0] |= tpk->access_mode_changed;
}
tpk->access_mode_changed = 0;
}
break;
case 0xc:
case 0xd:
case 0xe:
case 0xf:
/* read gb cart */
if (tpk->enabled)
{
DebugMessage(M64MSG_VERBOSE, "tpak read cart: %04x", address);
if (tpk->gb_cart != NULL) {
read_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size);
}
}
break;
/* Reads from the Transfer Pak. */
static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size)
{
struct transferpak* tpk = (struct transferpak*)pak;
uint8_t value;
switch (address >> 12)
{
case 0x8:
/*
* 0x8 => read the TPak "enabled" status
* In Rust code: if (enabled) => 0x84 else => 0x00
*/
value = (tpk->enabled) ? 0x84 : 0x00;
DebugMessage(M64MSG_VERBOSE, "TPak returning cart state: %02x", value);
memset(data, value, size);
return;
default:
DebugMessage(M64MSG_WARNING, "Unknown tpak read: %04x", address);
if (!tpk->enabled) {
DebugMessage(M64MSG_VERBOSE, "TPak read ignored because disabled");
return;
}
}
}
static void write_transferpak(void* pak, uint16_t address, const uint8_t* data, size_t size)
{
struct transferpak* tpk = (struct transferpak*)pak;
uint8_t value = data[size-1];
DebugMessage(M64MSG_VERBOSE, "tpak write: %04x <- %02x", address, value);
switch(address >> 12)
switch (address >> 12)
{
case 0x8:
/* enable / disable gb cart */
switch(value)
{
case 0xfe:
tpk->enabled = 0;
DebugMessage(M64MSG_VERBOSE, "tpak disabled");
break;
case 0x84:
tpk->enabled = 1;
DebugMessage(M64MSG_VERBOSE, "tpak enabled");
break;
default:
DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value);
case 0xB:
{
uint8_t val = 0;
if (tpk->gb_cart && tpk->gb_cart->enabled) {
val |= (1 << 0); /* bit0 => cart enabled? */
}
val |= (uint8_t)((tpk->reset_state & 3) << 2);
if (tpk->enabled) {
val |= (1 << 7);
}
/* Simple state machine for reset_state (mirroring Rust logic). */
if ( tpk->gb_cart->enabled && tpk->reset_state == 3) {
tpk->reset_state = 2;
}
else if (!tpk->gb_cart->enabled && tpk->reset_state == 2) {
tpk->reset_state = 1;
}
else if (!tpk->gb_cart->enabled && tpk->reset_state == 1) {
tpk->reset_state = 0;
}
DebugMessage(M64MSG_VERBOSE, "TPak read 0xB => %02x", val);
memset(data, val, size);
break;
}
case 0xC:
case 0xD:
case 0xE:
case 0xF:
/*
* Read from the Game Boy cart.
* The address is computed as bank-based offset
* (0x4000 * bank + ((address & 0x7FFF) - 0x4000)).
*/
if (tpk->gb_cart != NULL)
{
const uint16_t cart_addr = gb_cart_address(tpk->bank, address);
read_gb_cart(tpk->gb_cart, cart_addr, data, size);
//DebugMessage(M64MSG_VERBOSE,
// "TPak reading cart: bank=%d, raw_addr=%04x => gb_addr=%04x -> %02x", tpk->bank, address, cart_addr, data[0]);
/*for(int i = 0; i < size; i++)
{
DebugMessage(M64MSG_VERBOSE, "TPak reading cart: bank=%d, raw_addr=%04x => gb_addr=%04x -> %02x", tpk->bank, address, cart_addr, data[i]);
}*/
}
else
{
DebugMessage(M64MSG_WARNING, "TPak read: no GB cart present");
memset(data, 0x00, size);
}
break;
default:
DebugMessage(M64MSG_WARNING, "Unknown TPak read at %04x", address);
memset(data, 0x00, size);
break;
}
}
/* Writes to the Transfer Pak. */
static void write_transferpak(void* pak, uint16_t address, const uint8_t* buf, size_t size)
{
struct transferpak* tpk = (struct transferpak*)pak;
/* The Rust code always uses the last byte as the "value" for multi-byte writes. */
uint16_t value = buf[size - 1];
DebugMessage(M64MSG_VERBOSE, "TransferPak write: %04x <- %02x", address, value);
switch (address >> 12)
{
case 0x8:
/*
* Matches the Rust approach: 0xFE => disable, 0x84 => enable
*/
switch (value)
{
case 0xFE:
tpk->enabled = 0;
DebugMessage(M64MSG_VERBOSE, "TPak disabled");
return;
case 0x84:
if (!tpk->enabled)
{
tpk->bank = 3;
tpk->reset_state = 0;
if (tpk->gb_cart != NULL)
{
tpk->gb_cart->enabled = 0;
}
}
tpk->enabled = 1;
DebugMessage(M64MSG_VERBOSE, "TPak enabled (0x84)");
return;
default:
DebugMessage(M64MSG_WARNING,
"Unknown write to TPak (0x8 region): %02x", value);
return;
}
return;
default:
/* If TPak not enabled, ignore writes (as in your Rust example). */
if (!tpk->enabled) {
DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled");
return;
}
break;
case 0xA:
if (!tpk->enabled) {
DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled");
return;
}
break;
case 0xa:
/* set gb cart bank */
if (tpk->enabled)
{
tpk->bank = value;
DebugMessage(M64MSG_VERBOSE, "tpak set bank %02x", tpk->bank);
tpk->bank = (uint16_t)value;
if (tpk->bank > 3) {
DebugMessage(M64MSG_WARNING, "TPak: invalid bank %d", tpk->bank);
tpk->bank = 0;
}
DebugMessage(M64MSG_VERBOSE, "TPak set bank => %d", tpk->bank);
break;
case 0xB:
if (value & 1)
{
if (tpk->gb_cart != NULL && !tpk->gb_cart->enabled)
{
/* Reset state to 3, and do any "power-on" type logic on the cart. */
tpk->reset_state = 3;
tpk->gb_cart->enabled = 1;
tpk->gb_cart->rom_bank = 1;
tpk->gb_cart->ram_bank = 0;
tpk->gb_cart->ram_enable = 0;
/* e.g. set cart type if needed:
* tpk->gb_cart->cart_type = get_cart_type(tpk->gb_cart->rom[0x147]);
* (This depends on your real code.)
*/
DebugMessage(M64MSG_VERBOSE, "TPak: cart enabled, reset_state=3");
}
else if (tpk->gb_cart)
{
tpk->gb_cart->enabled = 1;
DebugMessage(M64MSG_VERBOSE, "TPak: cart already enabled");
}
}
else
{
if (tpk->gb_cart) {
tpk->gb_cart->enabled = 0;
}
DebugMessage(M64MSG_VERBOSE, "TPak: cart disabled via write to 0xB");
}
break;
case 0xC:
case 0xD:
case 0xE:
case 0xF:
{
if (!tpk->enabled) {
DebugMessage(M64MSG_VERBOSE, "TPak write ignored because disabled");
return;
}
break;
case 0xb:
/* set gb cart access mode */
if (tpk->enabled)
{
tpk->access_mode_changed = 0x04;
tpk->access_mode = ((value & 1) == 0)
? CART_ACCESS_MODE_0
: CART_ACCESS_MODE_1;
if ((value & 0xfe) != 0)
{
DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value);
}
DebugMessage(M64MSG_VERBOSE, "tpak set access mode %02x", tpk->access_mode);
}
break;
case 0xc:
case 0xd:
case 0xe:
case 0xf:
/* write gb cart */
// if (tpk->enabled)
{
DebugMessage(M64MSG_VERBOSE, "tpak write gb: %04x <- %02x", address, value);
if (tpk->gb_cart != NULL) {
write_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size);
}
}
break;
default:
DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value);
}
}
/* Write to GB cart memory. */
if (tpk->gb_cart != NULL)
{
uint16_t cart_addr = gb_cart_address(tpk->bank, address);
DebugMessage(M64MSG_VERBOSE,
"TPak write to cart: bank=%d, raw_addr=%04x => gb_addr=%04x val=%02x",
tpk->bank, address, cart_addr, value);
write_gb_cart(tpk->gb_cart, cart_addr, buf, size);
}
else
{
DebugMessage(M64MSG_WARNING,
"TPak write to 0xC..0xF, but no GB cart present");
}
break;
};
}
}
/* Transfer pak definition */
const struct pak_interface g_itransferpak =
@@ -219,3 +312,4 @@ const struct pak_interface g_itransferpak =
read_transferpak,
write_transferpak
};
@@ -40,6 +40,7 @@ struct transferpak
unsigned int bank;
unsigned int access_mode;
unsigned int access_mode_changed;
unsigned int reset_state;
struct gb_cart* gb_cart;
};
+2 -1
View File
@@ -129,6 +129,7 @@ void init_device(struct device* dev,
{ &dev->dd, dd_mecha_int_handler }, /* DD MECHA */
{ &dev->dd, dd_bm_int_handler }, /* DD BM */
{ &dev->dd, dd_dv_int_handler }, /* DD DRIVE */
{ &dev->sp, rsp_task_event },
};
#define R(x) read_ ## x
@@ -141,7 +142,7 @@ void init_device(struct device* dev,
/* memory map */
{ A(MM_RDRAM_DRAM, 0x3efffff), M64P_MEM_RDRAM, { &dev->rdram, RW(rdram_dram) } },
{ A(MM_RDRAM_REGS, 0xfffff), M64P_MEM_RDRAMREG, { &dev->rdram, RW(rdram_regs) } },
{ A(MM_RSP_MEM, 0xffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
{ A(MM_RSP_MEM, 0x3ffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
{ A(MM_RSP_REGS, 0xffff), M64P_MEM_RSPREG, { &dev->sp, RW(rsp_regs) } },
{ A(MM_RSP_REGS2, 0xffff), M64P_MEM_RSP, { &dev->sp, RW(rsp_regs2) } },
{ A(MM_DPC_REGS, 0xffff), M64P_MEM_DP, { &dev->dp, RW(dpc_regs) } },
+93 -68
View File
@@ -54,7 +54,7 @@ enum gbcart_extra_devices
/* various helper functions for ram, rom, or MBC uses */
static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint16_t address, uint8_t* data, size_t size)
static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint32_t address, uint8_t* data, size_t size)
{
assert(size > 0);
@@ -68,14 +68,14 @@ static void read_rom(const void* rom_storage, const struct storage_backend_inter
}
static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint16_t address, uint8_t* data, size_t size, uint8_t mask)
static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint32_t address, uint8_t* data, size_t size, uint8_t mask)
{
size_t i;
assert(size > 0);
/* RAM has to be enabled before use */
if (!enabled) {
DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address);
DebugMessage(M64MSG_WARNING, "read_ram Trying to read from non enabled GB RAM %04x", address);
memset(data, 0xff, size);
return;
}
@@ -240,7 +240,7 @@ static int write_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, const u
/* 0x2000-0x3fff: ROM bank select (low 5 bits) */
case (0x2000 >> 13):
bank = value & 0x1f;
gb_cart->rom_bank = (gb_cart->rom_bank & ~UINT8_C(0x1f)) | ((bank == 0) ? 1 : bank);
gb_cart->rom_bank = (gb_cart->rom_bank & ~UINT8_C(0x1f)) | (bank == 0) ? 1 : bank;
DebugMessage(M64MSG_VERBOSE, "MBC1 set rom bank %02x", gb_cart->rom_bank);
break;
@@ -345,25 +345,32 @@ static int write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const u
return 0;
}
static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size)
static int read_gb_cart_mbc3(struct gb_cart* gb_cart,
uint16_t address,
uint8_t* dst,
size_t size)
{
switch(address >> 13)
if (address < 0x4000)
{
/* 0x0000-0x3fff: ROM bank 00 */
case (0x0000 >> 13):
case (0x2000 >> 13):
read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size);
break;
/* Bank 0 (0x0000 - 0x3FFF) */
uint32_t banked_address = address & 0x3FFF; /* same as just address, but & 0x3FFF is explicit */
read_rom(gb_cart->rom_storage, gb_cart->irom_storage, banked_address, dst, size);
/* 0x4000-0x7fff: ROM bank 01-7f */
case (0x4000 >> 13):
case (0x6000 >> 13):
read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size);
break;
/* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */
case (0xa000 >> 13):
//DebugMessage(M64MSG_VERBOSE, "MBC3 read from ROM bank 0: %04x", address);
}
else if (address < 0x8000)
{
/* Switched ROM bank (0x4000 - 0x7FFF) */
size_t banked_address = (size_t)((uint32_t)address - 0x4000)
+ (gb_cart->rom_bank * 0x4000);
read_rom(gb_cart->rom_storage, gb_cart->irom_storage, banked_address, dst, size);
//DebugMessage(M64MSG_VERBOSE, "MBC3 read from ROM bank %02x: %04x", gb_cart->rom_bank, address);
}
else if (address >= 0xA000 && address < 0xC000)
{
switch(gb_cart->ram_bank)
{
/* RAM banks */
@@ -375,8 +382,12 @@ static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t*
case 0x05:
case 0x06:
case 0x07:
read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff));
{
size_t banked_address = (size_t)((uint32_t)address - 0xA000)
+ (gb_cart->ram_bank * 0x2000);
read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, banked_address, dst, size, UINT8_C(0xff));
break;
}
/* RTC registers */
case 0x08:
@@ -387,68 +398,78 @@ static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t*
/* RAM has to be enabled before use */
if (!gb_cart->ram_enable) {
DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address);
memset(data, 0xff, size);
memset(dst, 0xff, size);
break;
}
if (!(gb_cart->extra_devices & GED_RTC)) {
DebugMessage(M64MSG_WARNING, "Trying to read from absent RTC %04x", address);
memset(data, 0xff, size);
memset(dst, 0xff, size);
break;
}
memset(data, read_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08), size);
memset(dst, read_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08), size);
break;
default:
DebugMessage(M64MSG_WARNING, "Unknown device mapped in RAM/RTC space: %04x", address);
}
break;
default:
DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC3): %04x", address);
}
else
{
/* The Rust code does a panic!("Unsupported read address {:x}", address); */
DebugMessage(M64MSG_WARNING, "Unsupported read address %04x", address);
}
return 0;
}
static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size)
static int write_gb_cart_mbc3(struct gb_cart* gb_cart,
uint16_t address,
const uint8_t* src,
size_t size)
{
uint8_t bank;
uint8_t value = data[size-1];
if (size == 0) {
/* Nothing to write, just return */
return 0;
}
switch(address >> 13)
uint8_t value = src[size - 1];
if (address < 0x2000)
{
/* 0x0000-0x1fff: RAM/RTC enable */
case (0x0000 >> 13):
/* Enable or disable RAM */
set_ram_enable(gb_cart, value);
break;
/* 0x2000-0x3fff: ROM bank select */
case (0x2000 >> 13):
bank = value & 0x7f;
gb_cart->rom_bank = (bank == 0) ? 1 : bank;
DebugMessage(M64MSG_VERBOSE, "MBC3 set rom bank %02x", gb_cart->rom_bank);
break;
/* 0x4000-0x5fff: RAM bank / RTC register select */
case (0x4000 >> 13):
gb_cart->ram_bank = value;
}
else if (address < 0x4000)
{
/* Select ROM bank (0x01..0x7F) */
uint8_t bank = value & 0x7F;
gb_cart->rom_bank = bank;
if (gb_cart->rom_bank == 0) {
gb_cart->rom_bank = 1;
}
DebugMessage(M64MSG_VERBOSE, "MBC3 set rom bank %02x addr %04x", gb_cart->rom_bank, address);
}
else if (address < 0x6000)
{
/* Select RAM bank or RTC register */
gb_cart->ram_bank = (value & 0x0F);
DebugMessage(M64MSG_VERBOSE, "MBC3 set ram bank %02x", gb_cart->ram_bank);
break;
/* 0x6000-0x7fff: latch clock registers */
case (0x6000 >> 13):
}
else if (address < 0x8000)
{
/* RTC latch (not implemented here) */
/* The Rust code simply does nothing. */
if (!(gb_cart->extra_devices & GED_RTC)) {
DebugMessage(M64MSG_WARNING, "Trying to latch to absent RTC %04x", address);
break;
}
latch_mbc3_rtc_regs(&gb_cart->rtc, value);
break;
/* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */
case (0xa000 >> 13):
else
latch_mbc3_rtc_regs(&gb_cart->rtc, value);
}
else if (address >= 0xA000 && address < 0xC000)
{
DebugMessage(M64MSG_VERBOSE, "MBC3 write to RAM: %04x <- %02x (bank %02x)", address, value, gb_cart->ram_bank);
switch(gb_cart->ram_bank)
{
/* RAM banks */
@@ -460,7 +481,7 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u
case 0x05:
case 0x06:
case 0x07:
write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff));
write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), src, size, UINT8_C(0xff));
break;
/* RTC registers */
@@ -469,11 +490,11 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u
case 0x0a:
case 0x0b:
case 0x0c:
/* RAM has to be enabled before use */
if (!gb_cart->ram_enable) {
DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address);
break;
}
/* RAM has to be enabled before use */
if (!gb_cart->ram_enable) {
DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address);
break;
}
if (!(gb_cart->extra_devices & GED_RTC)) {
DebugMessage(M64MSG_WARNING, "Trying to write to absent RTC %04x", address);
@@ -486,15 +507,18 @@ static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const u
default:
DebugMessage(M64MSG_WARNING, "Unknwown device mapped in RAM/RTC space: %04x", address);
}
break;
default:
DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC3): %04x", address);
}
else
{
/* The Rust code does panic!("Unsupported write address {:x}", address); */
DebugMessage(M64MSG_WARNING, "Unsupported write address %04x", address);
}
return 0;
}
static int read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size)
{
switch(address >> 13)
@@ -1117,3 +1141,4 @@ int write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data
return gb_cart->write_gb_cart(gb_cart, address, data, size);
}
@@ -56,6 +56,7 @@ struct gb_cart
void* ram_storage;
const struct storage_backend_interface* iram_storage;
unsigned int enabled;
unsigned int rom_bank;
unsigned int ram_bank;
+3 -2
View File
@@ -173,11 +173,12 @@ struct interrupt_handler
void (*callback)(void*);
};
enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 };
enum { CP0_INTERRUPT_HANDLERS_COUNT = 17 };
enum {
INTR_UNSAFE_R4300 = 0x01,
INTR_UNSAFE_RSP = 0x02,
INTR_UNSAFE_RSP = 0x02,
INTR_UNSAFE_RDP = 0x04,
};
struct cp0
@@ -656,6 +656,11 @@ void gen_interrupt(struct r4300_core* r4300)
call_interrupt_handler(&r4300->cp0, 15);
break;
case RSP_TSK_EVT:
remove_interrupt_event(&r4300->cp0);
call_interrupt_handler(&r4300->cp0, 16);
break;
default:
DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", r4300->cp0.q.first->data.type);
remove_interrupt_event(&r4300->cp0);
@@ -69,5 +69,6 @@ void nmi_int_handler(void* opaque);
#define DD_MC_INT 0x1000
#define DD_BM_INT 0x2000
#define DD_DV_INT 0x4000
#define RSP_TSK_EVT 0x8000
#endif /* M64P_DEVICE_R4300_INTERRUPT_H */
@@ -26,6 +26,7 @@
#include "device/memory/memory.h"
#include "device/rcp/mi/mi_controller.h"
#include "device/rcp/rsp/rsp_core.h"
#include "device/r4300/r4300_core.h"
#include "plugin/plugin.h"
static void update_dpc_status(struct rdp_core* dp, uint32_t w)
@@ -40,7 +41,13 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE;
if (dp->do_on_unfreeze & DELAY_DP_INT)
{
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
}
if (dp->do_on_unfreeze & DELAY_UPDATESCREEN)
gfx.updateScreen();
dp->do_on_unfreeze = 0;
@@ -51,6 +58,22 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
if (w & DPC_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH;
if (w & DPC_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH;
if (w & DPC_CLR_TMEM_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_TMEM_BUSY;
dp->dpc_regs[DPC_TMEM_REG] = 0;
}
if (w & DPC_CLR_PIPE_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_PIPE_BUSY;
dp->dpc_regs[DPC_PIPEBUSY_REG] = 0;
}
if (w & DPC_CLR_CMD_CTR)
{
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_CMD_BUSY;
dp->dpc_regs[DPC_BUFBUSY_REG] = 0;
}
/* clear clock counter */
if (w & DPC_CLR_CLOCK_CTR) dp->dpc_regs[DPC_CLOCK_REG] = 0;
}
@@ -73,11 +96,13 @@ void poweron_rdp(struct rdp_core* dp)
{
memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t));
memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t));
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK;
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK | DPC_STATUS_PIPE_BUSY | DPC_STATUS_CBUF_READY;
dp->do_on_unfreeze = 0;
poweron_fb(&dp->fb);
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
}
@@ -106,18 +131,35 @@ void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
return;
}
masked_write(&dp->dpc_regs[reg], value, mask);
switch(reg)
{
case DPC_START_REG:
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
if (!(dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID))
{
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
}
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_VALID;
break;
case DPC_END_REG:
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID)
{
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_START_VALID;
}
unprotect_framebuffers(&dp->fb);
gfx.processRDPList();
protect_framebuffers(&dp->fb);
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
if (dp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
{
dp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
dp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
add_interrupt_event(&dp->mi->r4300->cp0, DP_INT, dp->dpc_regs[DPC_CLOCK_REG]);
}
}
break;
}
}
@@ -149,6 +191,9 @@ void rdp_interrupt_event(void* opaque)
{
struct rdp_core* dp = (struct rdp_core*)opaque;
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
raise_rcp_interrupt(dp->mi, MI_INTR_DP);
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
}
@@ -37,7 +37,11 @@ enum
DPC_STATUS_FREEZE = 0x002,
DPC_STATUS_FLUSH = 0x004,
DPC_STATUS_START_GCLK = 0x008,
DPC_STATUS_TMEM_BUSY = 0x010,
DPC_STATUS_PIPE_BUSY = 0x020,
DPC_STATUS_CMD_BUSY = 0x040,
DPC_STATUS_CBUF_READY = 0x080,
DPC_STATUS_DMA_BUSY = 0x100,
DPC_STATUS_END_VALID = 0x200,
DPC_STATUS_START_VALID = 0x400,
/* DPC status - write */
+119 -104
View File
@@ -76,13 +76,16 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma)
pre_framebuffer_read(&sp->dp->fb, dramaddr);
for(i=0; i<length; i++) {
spmem[(memaddr^S8) & 0xfff] = dram[(dramaddr^S8) & 0x7fffff];
spmem[(memaddr & 0xfff)^S8] = dram[(dramaddr^S8) & 0x7fffff];
memaddr++;
dramaddr++;
}
dramaddr+=skip;
}
sp->regs[SP_MEM_ADDR_REG] = (memaddr & 0xfff) + (dma->memaddr & 0x1000);
sp->regs[SP_DRAM_ADDR_REG] = dramaddr;
sp->regs[SP_MEM_ADDR_REG] = memaddr & 0xfff;
sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff;
sp->regs[SP_RD_LEN_REG] = 0xff8;
@@ -146,69 +149,87 @@ static void fifo_pop(struct rsp_core* sp)
static void update_sp_status(struct rsp_core* sp, uint32_t w)
{
/* clear / set halt */
if ((w & 0x3) == 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
if ((w & 0x3) == 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
if ((w & SP_CLR_HALT) && !(w & SP_SET_HALT))
{
sp->rsp_wait &= ~WAIT_HALTED;
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
}
if ((w & SP_SET_HALT) && !(w & SP_CLR_HALT))
{
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
sp->rsp_status = 0;
sp->first_run = 1;
sp->rsp_wait |= WAIT_HALTED;
sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
}
/* clear broke */
if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
if (w & SP_CLR_BROKE) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
/* clear SP interrupt */
if ((w & 0x18) == 0x8)
if ((w & SP_CLR_INTR) && !(w & SP_SET_INTR))
{
clear_rcp_interrupt(sp->mi, MI_INTR_SP);
}
/* set SP interrupt */
if ((w & 0x18) == 0x10)
if ((w & SP_SET_INTR) && !(w & SP_CLR_INTR))
{
signal_rcp_interrupt(sp->mi, MI_INTR_SP);
}
/* clear / set single step */
if ((w & 0x60) == 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
if ((w & 0x60) == 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
if ((w & SP_CLR_SSTEP) && !(w & SP_SET_SSTEP)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
if ((w & SP_SET_SSTEP) && !(w & SP_CLR_SSTEP)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
/* clear / set interrupt on break */
if ((w & 0x180) == 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
if ((w & 0x180) == 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
if ((w & SP_CLR_INTR_BREAK) && !(w & SP_SET_INTR_BREAK))
{
if (sp->rsp_wait & WAIT_PENDING_SP_INT_BROKE)
{
// If a game clears SP_SET_INTR_BREAK before the interrupt happens,
// that means it would have been cleared before the BREAK command
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
sp->rsp_wait &= ~WAIT_PENDING_SP_INT_BROKE;
sp->regs[SP_STATUS_REG] = sp->rsp_status;
sp->rsp_status = 0;
}
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
}
if ((w & SP_SET_INTR_BREAK) && !(w & SP_CLR_INTR_BREAK)) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
/* clear / set signal 0 */
if ((w & 0x600) == 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
if ((w & 0x600) == 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
if ((w & SP_CLR_SIG0) && !(w & SP_SET_SIG0)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
if ((w & SP_SET_SIG0) && !(w & SP_CLR_SIG0)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
/* clear / set signal 1 */
if ((w & 0x1800) == 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
if ((w & 0x1800) == 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
if ((w & SP_CLR_SIG1) && !(w & SP_SET_SIG1)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
if ((w & SP_SET_SIG1) && !(w & SP_CLR_SIG1)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
/* clear / set signal 2 */
if ((w & 0x6000) == 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
if ((w & 0x6000) == 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
if ((w & SP_CLR_SIG2) && !(w & SP_SET_SIG2)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
if ((w & SP_SET_SIG2) && !(w & SP_CLR_SIG2)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
/* clear / set signal 3 */
if ((w & 0x18000) == 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
if ((w & 0x18000) == 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
if ((w & SP_CLR_SIG3) && !(w & SP_SET_SIG3)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
if ((w & SP_SET_SIG3) && !(w & SP_CLR_SIG3)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
/* clear / set signal 4 */
if ((w & 0x60000) == 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
if ((w & 0x60000) == 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
if ((w & SP_CLR_SIG4) && !(w & SP_SET_SIG4)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
if ((w & SP_SET_SIG4) && !(w & SP_CLR_SIG4)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
/* clear / set signal 5 */
if ((w & 0x180000) == 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
if ((w & 0x180000) == 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
if ((w & SP_CLR_SIG5) && !(w & SP_SET_SIG5)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
if ((w & SP_SET_SIG5) && !(w & SP_CLR_SIG5)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
/* clear / set signal 6 */
if ((w & 0x600000) == 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
if ((w & 0x600000) == 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
if ((w & SP_CLR_SIG6) && !(w & SP_SET_SIG6)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
if ((w & SP_SET_SIG6) && !(w & SP_CLR_SIG6)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
/* clear / set signal 7 */
if ((w & 0x1800000) == 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
if ((w & 0x1800000) == 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
if ((w & SP_CLR_SIG7) && !(w & SP_SET_SIG7)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
if ((w & SP_SET_SIG7) && !(w & SP_CLR_SIG7)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
if (sp->rsp_task_locked && (get_event(&sp->mi->r4300->cp0.q, SP_INT))) return;
if (!((w & 0x3) == 1) && !(w & 0x4) && !sp->rsp_task_locked)
return;
if (!(sp->regs[SP_STATUS_REG] & SP_STATUS_HALT))
do_SP_Task(sp);
do_SP_Task(sp);
}
void init_rsp(struct rsp_core* sp,
@@ -230,7 +251,9 @@ void poweron_rsp(struct rsp_core* sp)
memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t));
memset(sp->fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma));
sp->rsp_task_locked = 0;
sp->rsp_status = 0;
sp->first_run = 1;
sp->rsp_wait = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
sp->regs[SP_STATUS_REG] = 1;
sp->regs[SP_RD_LEN_REG] = 0xff8;
@@ -286,6 +309,12 @@ void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
switch(reg)
{
case SP_MEM_ADDR_REG:
sp->regs[SP_MEM_ADDR_REG] &= 0x1ff8;
break;
case SP_DRAM_ADDR_REG:
sp->regs[SP_DRAM_ADDR_REG] &= 0xfffff8;
break;
case SP_RD_LEN_REG:
fifo_push(sp, SP_DMA_WRITE);
break;
@@ -317,7 +346,10 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
uint32_t reg = rsp_reg2(address);
if (reg == SP_PC_REG)
mask &= 0xffc;
{
masked_write(&sp->regs2[SP_PC_REG], value & 0xffc, mask);
return;
}
if (reg < SP_REGS2_COUNT)
masked_write(&sp->regs2[reg], value, mask);
@@ -325,97 +357,66 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
void do_SP_Task(struct rsp_core* sp)
{
uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff;
if (sp->rsp_wait)
return;
if (get_event(&sp->mi->r4300->cp0.q, RSP_TSK_EVT))
return;
uint32_t sp_delay_time;
uint32_t saved_status = sp->regs[SP_STATUS_REG];
uint32_t sp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_SP;
uint32_t dp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_DP;
if (sp->mem[0xfc0/4] == 1)
uint32_t rsp_cycles = rsp.doRspCycles(sp->first_run) / 2;
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP && !dp_bit_set)
{
unprotect_framebuffers(&sp->dp->fb);
//gfx.processDList();
sp->regs2[SP_PC_REG] &= 0xfff;
#if defined(PROFILE)
timed_section_start(TIMED_SECTION_GFX);
#endif
rsp.doRspCycles(0xffffffff);
#if defined(PROFILE)
timed_section_end(TIMED_SECTION_GFX);
#endif
sp->regs2[SP_PC_REG] |= save_pc;
new_frame();
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
{
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
cp0_update_count(sp->mi->r4300);
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000);
}
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
sp->rsp_wait |= WAIT_PENDING_DP_SYNC;
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
} else {
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, rsp_cycles + sp->dp->dpc_regs[DPC_CLOCK_REG]);
}
sp_delay_time = 1000;
protect_framebuffers(&sp->dp->fb);
}
else if (sp->mem[0xfc0/4] == 2)
{
//audio.processAList();
sp->regs2[SP_PC_REG] &= 0xfff;
#if defined(PROFILE)
timed_section_start(TIMED_SECTION_AUDIO);
#endif
rsp.doRspCycles(0xffffffff);
#if defined(PROFILE)
timed_section_end(TIMED_SECTION_AUDIO);
#endif
sp->regs2[SP_PC_REG] |= save_pc;
sp_delay_time = 4000;
sp->rsp_status = sp->regs[SP_STATUS_REG];
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_HALT) == 0)
{
add_interrupt_event(&sp->mi->r4300->cp0, RSP_TSK_EVT, rsp_cycles);
sp->first_run = 0;
}
else
{
sp->regs2[SP_PC_REG] &= 0xfff;
rsp.doRspCycles(0xffffffff);
sp->regs2[SP_PC_REG] |= save_pc;
sp_delay_time = 0;
sp->rsp_wait |= WAIT_HALTED;
sp->first_run = 1;
}
sp->rsp_task_locked = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
if ((sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)) == 0)
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_BROKE) && (sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK))
{
sp->rsp_task_locked = 1;
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP;
sp->rsp_wait |= WAIT_PENDING_SP_INT_BROKE;
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
sp->regs[SP_STATUS_REG] = saved_status;
}
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP)
else if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP && !sp_bit_set)
{
cp0_update_count(sp->mi->r4300);
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time);
sp->rsp_wait |= WAIT_PENDING_SP_INT;
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
}
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
if (!sp_bit_set)
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP;
}
sp->regs[SP_STATUS_REG] &=
~(SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT);
}
void rsp_interrupt_event(void* opaque)
{
struct rsp_core* sp = (struct rsp_core*)opaque;
if (!sp->rsp_task_locked)
{
sp->regs[SP_STATUS_REG] |=
SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT;
}
sp->regs[SP_STATUS_REG] = sp->rsp_status;
sp->rsp_status = 0;
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK) != 0)
{
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
}
clear_rsp_wait(sp, WAIT_PENDING_SP_INT | WAIT_PENDING_SP_INT_BROKE);
}
void rsp_end_of_dma_event(void* opaque)
@@ -423,3 +424,17 @@ void rsp_end_of_dma_event(void* opaque)
struct rsp_core* sp = (struct rsp_core*)opaque;
fifo_pop(sp);
}
void rsp_task_event(void* opaque)
{
struct rsp_core* sp = (struct rsp_core*)opaque;
do_SP_Task(sp);
}
void clear_rsp_wait(struct rsp_core* sp, uint32_t value)
{
sp->rsp_wait &= ~value;
do_SP_Task(sp);
}
@@ -55,6 +55,36 @@ enum
SP_STATUS_SIG7 = 0x4000,
};
enum
{
/* SP_STATUS - write */
SP_CLR_HALT = 0x0000001,
SP_SET_HALT = 0x0000002,
SP_CLR_BROKE = 0x0000004,
SP_CLR_INTR = 0x0000008,
SP_SET_INTR = 0x0000010,
SP_CLR_SSTEP = 0x0000020,
SP_SET_SSTEP = 0x0000040,
SP_CLR_INTR_BREAK = 0x0000080,
SP_SET_INTR_BREAK = 0x0000100,
SP_CLR_SIG0 = 0x0000200,
SP_SET_SIG0 = 0x0000400,
SP_CLR_SIG1 = 0x0000800,
SP_SET_SIG1 = 0x0001000,
SP_CLR_SIG2 = 0x0002000,
SP_SET_SIG2 = 0x0004000,
SP_CLR_SIG3 = 0x0008000,
SP_SET_SIG3 = 0x0010000,
SP_CLR_SIG4 = 0x0020000,
SP_SET_SIG4 = 0x0040000,
SP_CLR_SIG5 = 0x0080000,
SP_SET_SIG5 = 0x0100000,
SP_CLR_SIG6 = 0x0200000,
SP_SET_SIG6 = 0x0400000,
SP_CLR_SIG7 = 0x0800000,
SP_SET_SIG7 = 0x1000000,
};
enum sp_registers
{
SP_MEM_ADDR_REG,
@@ -81,6 +111,14 @@ enum sp_dma_dir
SP_DMA_WRITE
};
enum sp_rsp_wait
{
WAIT_PENDING_SP_INT_BROKE = 0x1,
WAIT_PENDING_SP_INT = 0x2,
WAIT_PENDING_DP_SYNC = 0x4,
WAIT_HALTED = 0x8
};
enum { SP_DMA_FIFO_SIZE = 2} ;
struct sp_dma
@@ -96,7 +134,9 @@ struct rsp_core
uint32_t* mem;
uint32_t regs[SP_REGS_COUNT];
uint32_t regs2[SP_REGS2_COUNT];
uint32_t rsp_task_locked;
uint32_t rsp_status;
uint32_t first_run;
uint32_t rsp_wait;
struct mi_controller* mi;
struct rdp_core* dp;
@@ -141,4 +181,7 @@ void do_SP_Task(struct rsp_core* sp);
void rsp_interrupt_event(void* opaque);
void rsp_end_of_dma_event(void* opaque);
void rsp_task_event(void* opaque);
void clear_rsp_wait(struct rsp_core* sp, uint32_t value);
#endif
+2 -2
View File
@@ -949,7 +949,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
/* reset fb state */
poweron_fb(&dev->dp.fb);
dev->sp.rsp_task_locked = 0;
//dev->sp.rsp_task_locked = 0;
dev->r4300.cp0.interrupt_unsafe_state = 0;
*r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300);
@@ -1253,7 +1253,7 @@ static int savestates_load_pj64(struct device* dev,
// No flashram info in pj64 savestate.
poweron_flashram(&dev->cart.flashram);
dev->sp.rsp_task_locked = 0;
//dev->sp.rsp_task_locked = 0;
dev->r4300.cp0.interrupt_unsafe_state = 0;
/* extra fb state */
@@ -127,4 +127,3 @@ void dummyvideo_ResizeVideoOutput(int width, int height)
{
}
@@ -41,6 +41,7 @@ extern void dummyvideo_ViWidthChanged(void);
extern void dummyvideo_ReadScreen2(void *dest, int *width, int *height, int front);
extern void dummyvideo_SetRenderingCallback(void (*callback)(int));
extern void dummyvideo_ResizeVideoOutput(int width, int height);
extern void dummyvideo_FullSync(void);
extern void dummyvideo_FBRead(unsigned int addr);
extern void dummyvideo_FBWrite(unsigned int addr, unsigned int size);
+10 -29
View File
@@ -20,8 +20,6 @@ RSP::CPU cpu;
#else
RSP::JIT::CPU cpu;
#endif
short MFC0_count[32];
int SP_STATUS_TIMEOUT;
} // namespace RSP
extern "C"
@@ -53,47 +51,33 @@ extern "C"
EXPORT unsigned int CALL DoRspCycles(unsigned int cycles)
{
if (*RSP::rsp.SP_STATUS_REG & (SP_STATUS_HALT | SP_STATUS_BROKE))
return 0;
// We don't know if Mupen from the outside invalidated our IMEM.
RSP::cpu.invalidate_imem();
if (cycles)
{
RSP::cpu.get_state().last_instruction_type = RSP::VU_INSTRUCTION;
RSP::cpu.get_state().instruction_pipeline = 0;
RSP::cpu.invalidate_imem();
}
// Run CPU until we either break or we need to fire an IRQ.
RSP::cpu.get_state().pc = *RSP::rsp.SP_PC_REG & 0xfff;
RSP::cpu.get_state().instruction_count = 0;
#ifdef INTENSE_DEBUG
fprintf(stderr, "RUN TASK: %u\n", RSP::cpu.get_state().pc);
log_rsp_mem_parallel();
#endif
for (auto &count : RSP::MFC0_count)
count = 0;
while (!(*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT))
{
auto mode = RSP::cpu.run();
if (mode == RSP::MODE_CHECK_FLAGS && (*RSP::cpu.get_state().cp0.irq & 1))
break;
if (mode == RSP::MODE_EXIT)
break;
}
*RSP::rsp.SP_PC_REG = 0x04001000 | (RSP::cpu.get_state().pc & 0xffc);
// From CXD4.
if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_BROKE)
return cycles;
else if (*RSP::cpu.get_state().cp0.irq & 1)
RSP::rsp.CheckInterrupts();
else if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT)
return cycles;
else if (*RSP::rsp.SP_SEMAPHORE_REG != 0) // Semaphore lock fixes.
{
}
else
RSP::SP_STATUS_TIMEOUT = 16; // From now on, wait 16 times, not 0x7fff
// CPU restarts with the correct SIGs.
*RSP::rsp.SP_STATUS_REG &= ~SP_STATUS_HALT;
*RSP::rsp.SP_PC_REG = (RSP::cpu.get_state().pc & 0xffc);
return cycles;
}
@@ -157,9 +141,6 @@ extern "C"
*cr[RSP::CP0_REGISTER_SP_STATUS] = SP_STATUS_HALT;
RSP::cpu.get_state().cp0.irq = RSP::rsp.MI_INTR_REG;
// From CXD4.
RSP::SP_STATUS_TIMEOUT = 0x7fff;
RSP::cpu.set_dmem(reinterpret_cast<uint32_t *>(Rsp_Info.DMEM));
RSP::cpu.set_imem(reinterpret_cast<uint32_t *>(Rsp_Info.IMEM));
RSP::cpu.set_rdram(reinterpret_cast<uint32_t *>(Rsp_Info.RDRAM));
+130 -87
View File
@@ -6,8 +6,6 @@
namespace RSP
{
extern RSP_INFO rsp;
extern short MFC0_count[32];
extern int SP_STATUS_TIMEOUT;
} // namespace RSP
#endif
@@ -28,34 +26,15 @@ extern "C"
rsp->sr[rt] = res;
#ifdef PARALLEL_INTEGRATION
if (rd == CP0_REGISTER_SP_STATUS)
{
// Might be waiting for the CPU to set a signal bit on the STATUS register. Increment timeout
RSP::MFC0_count[rt] += 1;
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
{
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
return MODE_CHECK_FLAGS;
}
}
#endif
#if 0 // FIXME: this is broken with upstream mupen64plus-core
if (rd == CP0_REGISTER_SP_SEMAPHORE)
{
if (*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE])
{
#ifdef PARALLEL_INTEGRATION
RSP::MFC0_count[rt] += 8; // Almost certainly waiting on the CPU. Timeout faster.
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
{
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
return MODE_CHECK_FLAGS;
}
#endif
}
else
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
return MODE_EXIT;
}
// We don't return control to the CPU if the RDP FREEZE bit is set, doing so seems to cause flickering
else if (rd == CP0_REGISTER_SP_STATUS && (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_FREEZE) == 0)
{
return MODE_EXIT;
}
#endif
@@ -65,12 +44,44 @@ extern "C"
return MODE_CONTINUE;
}
#define RSP_HANDLE_STATUS_WRITE(flag) \
switch (rt & (SP_SET_##flag | SP_CLR_##flag)) \
{ \
case SP_SET_##flag: status |= SP_STATUS_##flag; break; \
case SP_CLR_##flag: status &= ~SP_STATUS_##flag; break; \
default: break; \
static inline void rdp_status_write(RSP::CPUState *rsp, uint32_t rt)
{
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_CMD_STATUS];
if (rt & DPC_CLR_XBUS_DMEM_DMA)
status &= ~DPC_STATUS_XBUS_DMEM_DMA;
else if (rt & DPC_SET_XBUS_DMEM_DMA)
status |= DPC_STATUS_XBUS_DMEM_DMA;
if (rt & DPC_CLR_FREEZE)
status &= ~DPC_STATUS_FREEZE;
else if (rt & DPC_SET_FREEZE)
status |= DPC_STATUS_FREEZE;
if (rt & DPC_CLR_FLUSH)
status &= ~DPC_STATUS_FLUSH;
else if (rt & DPC_SET_FLUSH)
status |= DPC_STATUS_FLUSH;
if (rt & DPC_CLR_TMEM_CTR)
{
status &= ~DPC_STATUS_TMEM_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] = 0;
}
if (rt & DPC_CLR_PIPE_CTR)
{
status &= ~DPC_STATUS_PIPE_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_PIPE_BUSY] = 0;
}
if (rt & DPC_CLR_CMD_CTR)
{
status &= ~DPC_STATUS_CMD_BUSY;
*rsp->cp0.cr[CP0_REGISTER_CMD_BUSY] = 0;
}
if (rt & DPC_CLR_CLOCK_CTR)
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] = 0;
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] = status;
}
static inline int rsp_status_write(RSP::CPUState *rsp, uint32_t rt)
@@ -79,28 +90,69 @@ extern "C"
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_SP_STATUS];
RSP_HANDLE_STATUS_WRITE(HALT)
RSP_HANDLE_STATUS_WRITE(SSTEP)
RSP_HANDLE_STATUS_WRITE(INTR_BREAK)
RSP_HANDLE_STATUS_WRITE(SIG0)
RSP_HANDLE_STATUS_WRITE(SIG1)
RSP_HANDLE_STATUS_WRITE(SIG2)
RSP_HANDLE_STATUS_WRITE(SIG3)
RSP_HANDLE_STATUS_WRITE(SIG4)
RSP_HANDLE_STATUS_WRITE(SIG5)
RSP_HANDLE_STATUS_WRITE(SIG6)
RSP_HANDLE_STATUS_WRITE(SIG7)
switch (rt & (SP_SET_INTR | SP_CLR_INTR))
{
case SP_SET_INTR: *rsp->cp0.irq |= 1; break;
case SP_CLR_INTR: *rsp->cp0.irq &= ~1; break;
default: break;
}
if ((rt & SP_CLR_HALT) && !(rt & SP_SET_HALT))
status &= ~SP_STATUS_HALT;
if ((rt & SP_SET_HALT) && !(rt & SP_CLR_HALT))
status |= SP_STATUS_HALT;
if (rt & SP_CLR_BROKE)
status &= ~SP_STATUS_BROKE;
if ((rt & SP_CLR_INTR) && !(rt & SP_SET_INTR))
*rsp->cp0.irq &= ~1;
if ((rt & SP_SET_INTR) && !(rt & SP_CLR_INTR))
*rsp->cp0.irq |= 1;
if ((rt & SP_CLR_SSTEP) && !(rt & SP_SET_SSTEP))
status &= ~SP_STATUS_SSTEP;
if ((rt & SP_SET_SSTEP) && !(rt & SP_CLR_SSTEP))
status |= SP_STATUS_SSTEP;
if ((rt & SP_CLR_INTR_BREAK) && !(rt & SP_SET_INTR_BREAK))
status &= ~SP_STATUS_INTR_BREAK;
if ((rt & SP_SET_INTR_BREAK) && !(rt & SP_CLR_INTR_BREAK))
status |= SP_STATUS_INTR_BREAK;
if ((rt & SP_CLR_SIG0) && !(rt & SP_SET_SIG0))
status &= ~SP_STATUS_SIG0;
if ((rt & SP_SET_SIG0) && !(rt & SP_CLR_SIG0))
status |= SP_STATUS_SIG0;
if ((rt & SP_CLR_SIG1) && !(rt & SP_SET_SIG1))
status &= ~SP_STATUS_SIG1;
if ((rt & SP_SET_SIG1) && !(rt & SP_CLR_SIG1))
status |= SP_STATUS_SIG1;
if ((rt & SP_CLR_SIG2) && !(rt & SP_SET_SIG2))
status &= ~SP_STATUS_SIG2;
if ((rt & SP_SET_SIG2) && !(rt & SP_CLR_SIG2))
status |= SP_STATUS_SIG2;
if ((rt & SP_CLR_SIG3) && !(rt & SP_SET_SIG3))
status &= ~SP_STATUS_SIG3;
if ((rt & SP_SET_SIG3) && !(rt & SP_CLR_SIG3))
status |= SP_STATUS_SIG3;
if ((rt & SP_CLR_SIG4) && !(rt & SP_SET_SIG4))
status &= ~SP_STATUS_SIG4;
if ((rt & SP_SET_SIG4) && !(rt & SP_CLR_SIG4))
status |= SP_STATUS_SIG4;
if ((rt & SP_CLR_SIG5) && !(rt & SP_SET_SIG5))
status &= ~SP_STATUS_SIG5;
if ((rt & SP_SET_SIG5) && !(rt & SP_CLR_SIG5))
status |= SP_STATUS_SIG5;
if ((rt & SP_CLR_SIG6) && !(rt & SP_SET_SIG6))
status &= ~SP_STATUS_SIG6;
if ((rt & SP_SET_SIG6) && !(rt & SP_CLR_SIG6))
status |= SP_STATUS_SIG6;
if ((rt & SP_CLR_SIG7) && !(rt & SP_SET_SIG7))
status &= ~SP_STATUS_SIG7;
if ((rt & SP_SET_SIG7) && !(rt & SP_CLR_SIG7))
status |= SP_STATUS_SIG7;
*rsp->cp0.cr[CP0_REGISTER_SP_STATUS] = status;
return ((*rsp->cp0.irq & 1) || (status & SP_STATUS_HALT)) ? MODE_CHECK_FLAGS : MODE_CONTINUE;
}
@@ -109,14 +161,9 @@ extern "C"
static int rsp_dma_read(RSP::CPUState *rsp)
{
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH];
uint32_t length = (length_reg & 0xFFF) + 1;
uint32_t skip = (length_reg >> 20) & 0xFFF;
unsigned count = (length_reg >> 12) & 0xFF;
// Force alignment.
length = (length + 0x7) & ~0x7;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
uint32_t skip = (length_reg >> 20) & 0xFF8;
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
// Check length.
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
@@ -156,7 +203,7 @@ extern "C"
source += length + skip;
dest += length;
} while (++i <= count);
} while (++i < count);
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = source;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = dest;
@@ -171,14 +218,9 @@ extern "C"
static void rsp_dma_write(RSP::CPUState *rsp)
{
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH];
uint32_t length = (length_reg & 0xFFF) + 1;
uint32_t skip = (length_reg >> 20) & 0xFFF;
unsigned count = (length_reg >> 12) & 0xFF;
// Force alignment.
length = (length + 0x7) & ~0x7;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
uint32_t skip = (length_reg >> 20) & 0xFF8;
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
// Check length.
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
@@ -210,7 +252,7 @@ extern "C"
source += length;
dest += length + skip;
} while (++i <= count);
} while (++i < count);
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = source;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = dest;
@@ -228,11 +270,11 @@ extern "C"
switch (static_cast<CP0Registers>(rd & 15))
{
case CP0_REGISTER_DMA_CACHE:
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1fff;
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1ff8;
break;
case CP0_REGISTER_DMA_DRAM:
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xffffff;
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xfffff8;
break;
case CP0_REGISTER_DMA_READ_LENGTH:
@@ -254,26 +296,34 @@ extern "C"
return rsp_status_write(rsp, val);
case CP0_REGISTER_SP_SEMAPHORE:
// Any write to the semaphore register, regardless of value, sets it to 0 for the next read
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 0;
break;
case CP0_REGISTER_CMD_START:
#ifdef INTENSE_DEBUG
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffffff8u);
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffff8u);
#endif
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = *rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] =
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
if (!(*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID))
{
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = val & 0xfffff8u;
}
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= DPC_STATUS_START_VALID;
break;
case CP0_REGISTER_CMD_END:
#ifdef INTENSE_DEBUG
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffffff8u);
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffff8u);
#endif
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffff8u;
if (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID)
{
*rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] = *rsp->cp0.cr[CP0_REGISTER_CMD_START];
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~DPC_STATUS_START_VALID;
}
#ifdef PARALLEL_INTEGRATION
RSP::rsp.ProcessRdpList();
if (*rsp->cp0.irq & 0x20)
return MODE_EXIT;
#endif
break;
@@ -282,14 +332,7 @@ extern "C"
break;
case CP0_REGISTER_CMD_STATUS:
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x1) << 0);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x2) << 0);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x4) << 1);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x8) << 1);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x10) << 2);
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x20) << 2);
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] &= !(val & 0x40) * -1;
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] &= !(val & 0x200) * -1;
rdp_status_write(rsp, val);
break;
case CP0_REGISTER_CMD_CURRENT:
+1 -2
View File
@@ -1927,14 +1927,13 @@ ReturnMode CPU::run()
{
case MODE_BREAK:
*state.cp0.cr[CP0_REGISTER_SP_STATUS] |= SP_STATUS_BROKE | SP_STATUS_HALT;
if (*state.cp0.cr[CP0_REGISTER_SP_STATUS] & SP_STATUS_INTR_BREAK)
*state.cp0.irq |= 1;
#ifndef PARALLEL_INTEGRATION
print_registers();
#endif
return MODE_BREAK;
case MODE_CHECK_FLAGS:
case MODE_EXIT:
case MODE_DMA_READ:
return static_cast<ReturnMode>(ret);
+36 -1
View File
@@ -48,6 +48,31 @@ enum CP0Registers
CP0_REGISTER_CMD_TMEM_BUSY = 15,
};
// CMD_STATUS read bits.
#define DPC_STATUS_XBUS_DMEM_DMA 0x001
#define DPC_STATUS_FREEZE 0x002
#define DPC_STATUS_FLUSH 0x004
#define DPC_STATUS_START_GCLK 0x008
#define DPC_STATUS_TMEM_BUSY 0x010
#define DPC_STATUS_PIPE_BUSY 0x020
#define DPC_STATUS_CMD_BUSY 0x040
#define DPC_STATUS_CBUF_READY 0x080
#define DPC_STATUS_DMA_BUSY 0x100
#define DPC_STATUS_END_VALID 0x200
#define DPC_STATUS_START_VALID 0x400
// CMD_STATUS write bits.
#define DPC_CLR_XBUS_DMEM_DMA 0x001
#define DPC_SET_XBUS_DMEM_DMA 0x002
#define DPC_CLR_FREEZE 0x004
#define DPC_SET_FREEZE 0x008
#define DPC_CLR_FLUSH 0x010
#define DPC_SET_FLUSH 0x020
#define DPC_CLR_TMEM_CTR 0x040
#define DPC_CLR_PIPE_CTR 0x080
#define DPC_CLR_CMD_CTR 0x100
#define DPC_CLR_CLOCK_CTR 0x200
// SP_STATUS read bits.
#define SP_STATUS_HALT 0x0001
#define SP_STATUS_BROKE 0x0002
@@ -117,6 +142,9 @@ struct alignas(64) CP2
struct CPUState
{
uint32_t pc = 0;
uint32_t instruction_count = 0;
uint32_t last_instruction_type = 0;
uint32_t instruction_pipeline = 0;
uint32_t dirty_blocks = 0;
static_assert(CODE_BLOCKS <= 32, "Code blocks must fit in 32-bit register.");
@@ -138,7 +166,14 @@ enum ReturnMode
MODE_CONTINUE = 1,
MODE_BREAK = 2,
MODE_DMA_READ = 3,
MODE_CHECK_FLAGS = 4
MODE_CHECK_FLAGS = 4,
MODE_EXIT = 5
};
enum InstructionType
{
VU_INSTRUCTION = 0,
SU_INSTRUCTION = 1
};
} // namespace RSP
@@ -38,6 +38,7 @@
#include "m64p_types.h"
#include "m64p_config.h"
#include "m64p_plugin.h"
#include <string.h>
#include <stdint.h>
@@ -440,7 +440,9 @@ void vk_process_commands()
// For synchronous RDP:
if (vk_synchronous)
processor->signal_timeline();
{
processor->wait_for_timeline(processor->signal_timeline());
}
*gfx.MI_INTR_REG |= DP_INTERRUPT;
*GET_GFX_INFO(DPC_STATUS_REG) &= ~(DP_STATUS_PIPE_BUSY | DP_STATUS_START_GCLK);