diff options
Diffstat (limited to 'src/mame/machine/n64.c')
-rw-r--r-- | src/mame/machine/n64.c | 1752 |
1 files changed, 1752 insertions, 0 deletions
diff --git a/src/mame/machine/n64.c b/src/mame/machine/n64.c new file mode 100644 index 00000000000..e8ee71bd200 --- /dev/null +++ b/src/mame/machine/n64.c @@ -0,0 +1,1752 @@ +/* machine/n64.c - contains N64 hardware emulation shared between MAME and MESS */ + +#include "driver.h" +#include "cpu/mips/mips3.h" +#include "cpu/rsp/rsp.h" +#include "sound/custom.h" +#include "streams.h" +#include "includes/n64.h" +#include "sound/dmadac.h" + +#ifdef LSB_FIRST + #define BYTE_ADDR_XOR 3 + #define WORD_ADDR_XOR 1 +#else + #define BYTE_ADDR_XOR 0 + #define WORD_ADDR_XOR 0 +#endif + +UINT32 *rdram; +UINT32 *rsp_imem; +UINT32 *rsp_dmem; + +//static int first_rsp = 1; + +// MIPS Interface +static UINT32 mi_version; +static UINT32 mi_interrupt = 0; +static UINT32 mi_intr_mask = 0; + +extern int fb_width; + +void signal_rcp_interrupt(int interrupt) +{ + if (mi_intr_mask & interrupt) + { + mi_interrupt |= interrupt; + + cpunum_set_input_line(0, INPUT_LINE_IRQ0, ASSERT_LINE); + } +} + +void clear_rcp_interrupt(int interrupt) +{ + mi_interrupt &= ~interrupt; + + //if (!mi_interrupt) + { + cpunum_set_input_line(0, INPUT_LINE_IRQ0, CLEAR_LINE); + } +} + +READ32_HANDLER( n64_mi_reg_r ) +{ + switch (offset) + { + case 0x04/4: // MI_VERSION_REG + return mi_version; + + case 0x08/4: // MI_INTR_REG + return mi_interrupt; + + case 0x0c/4: // MI_INTR_MASK_REG + return mi_intr_mask; + + default: + logerror("mi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + + return 0; +} + +WRITE32_HANDLER( n64_mi_reg_w ) +{ + switch (offset) + { + case 0x00/4: // MI_INIT_MODE_REG + if (data & 0x0800) + { + clear_rcp_interrupt(DP_INTERRUPT); + } + break; + + case 0x04/4: // MI_VERSION_REG + mi_version = data; + break; + + case 0x0c/4: // MI_INTR_MASK_REG + { + if (data & 0x0001) mi_intr_mask &= ~0x1; // clear SP mask + if (data & 0x0002) mi_intr_mask |= 0x1; // set SP mask + if (data & 0x0004) mi_intr_mask &= ~0x2; // clear SI mask + if (data & 0x0008) mi_intr_mask |= 0x2; // set SI mask + if (data & 0x0010) mi_intr_mask &= ~0x4; // clear AI mask + if (data & 0x0020) mi_intr_mask |= 0x4; // set AI mask + if (data & 0x0040) mi_intr_mask &= ~0x8; // clear VI mask + if (data & 0x0080) mi_intr_mask |= 0x8; // set VI mask + if (data & 0x0100) mi_intr_mask &= ~0x10; // clear PI mask + if (data & 0x0200) mi_intr_mask |= 0x10; // set PI mask + if (data & 0x0400) mi_intr_mask &= ~0x20; // clear DP mask + if (data & 0x0800) mi_intr_mask |= 0x20; // set DP mask + break; + } + + default: + logerror("mi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + + +// RSP Interface + +// #define RSP_STATUS_HALT 0x00000001 + +//static UINT32 rsp_sp_status = 0; +//static UINT32 cpu_sp_status = SP_STATUS_HALT; +static UINT32 sp_mem_addr; +static UINT32 sp_dram_addr; +static int sp_dma_length; +static int sp_dma_count; +static int sp_dma_skip; + +static UINT32 sp_semaphore; + +static void sp_dma(int direction) +{ + UINT8 *src, *dst; + int i; + //int cpu = cpu_getactivecpu(); + + if (sp_dma_length == 0) + { + return; + } + + sp_dma_length++; + + if ((sp_dma_length & 3) != 0) + { + //fatalerror("sp_dma (%s): sp_dma_length unaligned %08X\n", cpu ? "RSP" : "R4300i", sp_dma_length); + sp_dma_length = sp_dma_length & ~3; + //sp_dma_length = (sp_dma_length + 3) & ~3; + + //sp_dma_length &= ~3; + } + + if (sp_mem_addr & 0x3) + { + //sp_mem_addr = (sp_mem_addr + 3) & ~3; + sp_mem_addr = sp_mem_addr & ~3; + // sp_mem_addr &= ~0x3; + // fatalerror("sp_dma (%s): sp_mem_addr unaligned: %08X\n", cpu ? "RSP" : "R4300i", sp_mem_addr); + } + if (sp_dram_addr & 0x3) + { + //sp_dram_addr = (sp_dram_addr + 3) & ~3; + sp_dram_addr = sp_dram_addr & ~3; + // sp_dram_addr &= ~0x3; + // fatalerror("sp_dma (%s): sp_dram_addr unaligned: %08X\n", cpu ? "RSP" : "R4300i", sp_dram_addr); + + // Diddy Kong Racing does unaligned DMA? + //sp_dram_addr &= ~0x3; + //sp_dram_addr = (sp_dram_addr + 3) & ~0x3; + } + + if (sp_dma_count > 0) + { + fatalerror("sp_dma: dma_count = %d\n", sp_dma_count); + } + if (sp_dma_skip > 0) + { + fatalerror("sp_dma: dma_skip = %d\n", sp_dma_skip); + } + + if ((sp_mem_addr & 0xfff) + (sp_dma_length) > 0x1000) + { + fatalerror("sp_dma: dma out of memory area: %08X, %08X\n", sp_mem_addr, sp_dma_length); + } + + if (direction == 0) // RDRAM -> I/DMEM + { + src = (UINT8*)&rdram[sp_dram_addr / 4]; + dst = (sp_mem_addr & 0x1000) ? (UINT8*)&rsp_imem[(sp_mem_addr & 0xfff) / 4] : (UINT8*)&rsp_dmem[(sp_mem_addr & 0xfff) / 4]; + + //mame_printf_debug("sp_dma: %08X to %08X, length %08X\n", sp_dram_addr, sp_mem_addr, sp_dma_length); + + for (i=0; i < sp_dma_length; i++) + { + dst[BYTE4_XOR_BE(i)] = src[BYTE4_XOR_BE(i)]; + } + + /*dst = (sp_mem_addr & 0x1000) ? (UINT8*)rsp_imem : (UINT8*)rsp_dmem; + for (i=0; i <= sp_dma_length; i++) + { + dst[BYTE4_XOR_BE(sp_mem_addr+i) & 0xfff] = src[BYTE4_XOR_BE(i)]; + }*/ + + sp_mem_addr += sp_dma_length; + sp_dram_addr += sp_dma_length; + } + else // I/DMEM -> RDRAM + { + src = (sp_mem_addr & 0x1000) ? (UINT8*)&rsp_imem[(sp_mem_addr & 0xfff) / 4] : (UINT8*)&rsp_dmem[(sp_mem_addr & 0xfff) / 4]; + dst = (UINT8*)&rdram[sp_dram_addr / 4]; + +// mame_printf_debug("sp_dma: %08X to %08X, length %08X\n", sp_mem_addr, sp_dram_addr, sp_dma_length); + + for (i=0; i < sp_dma_length; i++) + { + dst[BYTE4_XOR_BE(i)] = src[BYTE4_XOR_BE(i)]; + } + + /*src = (sp_mem_addr & 0x1000) ? (UINT8*)rsp_imem : (UINT8*)rsp_dmem; + for (i=0; i <= sp_dma_length; i++) + { + dst[BYTE4_XOR_BE(i)] = src[BYTE4_XOR_BE(sp_mem_addr+i) & 0xfff]; + }*/ + + sp_mem_addr += sp_dma_length; + sp_dram_addr += sp_dma_length; + } +} + + + + +void sp_set_status(UINT32 status) +{ + if (status & 0x1) + { + //cpu_trigger(6789); + + cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_HALT); + //rsp_sp_status |= SP_STATUS_HALT; + } + if (status & 0x2) + { + //rsp_sp_status |= SP_STATUS_BROKE; + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_BROKE); + + if (cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & RSP_STATUS_INTR_BREAK) + { + signal_rcp_interrupt(SP_INTERRUPT); + } + } +} + +READ32_HANDLER( n64_sp_reg_r ) +{ + switch (offset) + { + case 0x00/4: // SP_MEM_ADDR_REG + return sp_mem_addr; + + case 0x04/4: // SP_DRAM_ADDR_REG + return sp_dram_addr; + + case 0x08/4: // SP_RD_LEN_REG + return (sp_dma_skip << 20) | (sp_dma_count << 12) | sp_dma_length; + + case 0x10/4: // SP_STATUS_REG + return cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR); + + case 0x14/4: // SP_DMA_FULL_REG + return 0; + + case 0x18/4: // SP_DMA_BUSY_REG + return 0; + + case 0x1c/4: // SP_SEMAPHORE_REG + return sp_semaphore; + + case 0x20/4: // DP_CMD_START + case 0x24/4: // DP_CMD_END + case 0x28/4: // DP_CMD_CURRENT + case 0x2c/4: // DP_CMD_STATUS + case 0x30/4: // DP_CMD_CLOCK + case 0x34/4: // DP_CMD_BUSY + case 0x38/4: // DP_CMD_PIPE_BUSY + case 0x3c/4: // DP_CMD_TMEM_BUSY + return 0; + + case 0x40000/4: // PC + return cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_PC); + + default: + logerror("sp_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + + return 0; +} + +WRITE32_HANDLER( n64_sp_reg_w ) +{ + if ((offset & 0x10000) == 0) + { + switch (offset & 0xffff) + { + case 0x00/4: // SP_MEM_ADDR_REG + sp_mem_addr = data; + break; + + case 0x04/4: // SP_DRAM_ADDR_REG + sp_dram_addr = data & 0xffffff; + break; + + case 0x08/4: // SP_RD_LEN_REG + sp_dma_length = data & 0xfff; + sp_dma_count = (data >> 12) & 0xff; + sp_dma_skip = (data >> 20) & 0xfff; + sp_dma(0); + break; + + case 0x0c/4: // SP_WR_LEN_REG + sp_dma_length = data & 0xfff; + sp_dma_count = (data >> 12) & 0xff; + sp_dma_skip = (data >> 20) & 0xfff; + sp_dma(1); + break; + + case 0x10/4: // RSP_STATUS_REG + { + // printf( "RSP_STATUS_REG Write; %08x\n", data ); + if (data & 0x00000001) // clear halt + { + //if (first_rsp) + //{ + // cpu_spinuntil_trigger(6789); + + // printf( "Clearing RSP_STATUS_HALT\n" ); + cpunum_set_input_line(1, INPUT_LINE_HALT, CLEAR_LINE); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_HALT ); + // RSP_STATUS &= ~RSP_STATUS_HALT; + //} + //else + //{ + // first_rsp = 1; + //} + } + if (data & 0x00000002) // set halt + { + // printf( "Setting RSP_STATUS_HALT\n" ); + cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_HALT ); + // RSP_STATUS |= RSP_STATUS_HALT; + } + if (data & 0x00000004) + { + //printf( "Clearing RSP_STATUS_BROKE\n" ); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_BROKE ); + // RSP_STATUS &= ~RSP_STATUS_BROKE; // clear broke + } + if (data & 0x00000008) // clear interrupt + { + clear_rcp_interrupt(SP_INTERRUPT); + } + if (data & 0x00000010) // set interrupt + { + signal_rcp_interrupt(SP_INTERRUPT); + } + if (data & 0x00000020) + { + // printf( "Clearing RSP_STATUS_SSTEP\n" ); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SSTEP ); + // RSP_STATUS &= ~RSP_STATUS_SSTEP; // clear single step + } + if (data & 0x00000040) + { + //printf( "Setting RSP_STATUS_SSTEP\n" ); + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SSTEP ); + // RSP_STATUS |= RSP_STATUS_SSTEP; // set single step + } + if (data & 0x00000080) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_INTR_BREAK ); + // RSP_STATUS &= ~RSP_STATUS_INTR_BREAK; // clear interrupt on break + } + if (data & 0x00000100) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_INTR_BREAK ); + // RSP_STATUS |= RSP_STATUS_INTR_BREAK; // set interrupt on break + } + if (data & 0x00000200) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL0 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL0; // clear signal 0 + } + if (data & 0x00000400) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL0 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL0; // set signal 0 + } + if (data & 0x00000800) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL1 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL1; // clear signal 1 + } + if (data & 0x00001000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL1 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL1; // set signal 1 + } + if (data & 0x00002000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL2 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL2; // clear signal 2 + } + if (data & 0x00004000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL2 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL2; // set signal 2 + } + if (data & 0x00008000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL3 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL3; // clear signal 3 + } + if (data & 0x00010000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL3 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL3; // set signal 3 + } + if (data & 0x00020000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL4 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL4; // clear signal 4 + } + if (data & 0x00040000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL4 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL4; // set signal 4 + } + if (data & 0x00080000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL5 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL5; // clear signal 5 + } + if (data & 0x00100000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL5 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL5; // set signal 5 + } + if (data & 0x00200000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL6 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL6; // clear signal 6 + } + if (data & 0x00400000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL6 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL6; // set signal 6 + } + if (data & 0x00800000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & ~RSP_STATUS_SIGNAL7 ); + // RSP_STATUS &= ~RSP_STATUS_SIGNAL7; // clear signal 7 + } + if (data & 0x01000000) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_SIGNAL7 ); + // RSP_STATUS |= RSP_STATUS_SIGNAL7; // set signal 7 + } + break; + } + + case 0x1c/4: // SP_SEMAPHORE_REG + sp_semaphore = data; + // mame_printf_debug("sp_semaphore = %08X\n", sp_semaphore); + break; + + default: + logerror("sp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } + } + else + { + switch (offset & 0xffff) + { + case 0x00/4: // SP_PC_REG + //printf( "Setting PC to: %08x\n", 0x04001000 | (data & 0xfff ) ); + if( cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_NEXTPC) != 0xffffffff ) + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_NEXTPC, 0x04001000 | (data & 0xfff)); + } + else + { + cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_PC, 0x04001000 | (data & 0xfff)); + } + break; + + default: + logerror("sp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } + } +} + +UINT32 sp_read_reg(UINT32 reg) +{ + switch (reg) + { + //case 4: return rsp_sp_status; + default: return n64_sp_reg_r(reg, 0x00000000); + } +} + +void sp_write_reg(UINT32 reg, UINT32 data) +{ + switch (reg) + { + default: n64_sp_reg_w(reg, data, 0x00000000); break; + } +} + +// RDP Interface +UINT32 dp_start; +UINT32 dp_end; +UINT32 dp_current; +UINT32 dp_status = 0; + + +void dp_full_sync(void) +{ + signal_rcp_interrupt(DP_INTERRUPT); +} + +READ32_HANDLER( n64_dp_reg_r ) +{ + switch (offset) + { + case 0x00/4: // DP_START_REG + return dp_start; + + case 0x04/4: // DP_END_REG + return dp_end; + + case 0x08/4: // DP_CURRENT_REG + return dp_current; + + case 0x0c/4: // DP_STATUS_REG + return dp_status; + + default: + logerror("dp_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + + return 0; +} + +WRITE32_HANDLER( n64_dp_reg_w ) +{ + switch (offset) + { + case 0x00/4: // DP_START_REG + dp_start = data; + dp_current = dp_start; + break; + + case 0x04/4: // DP_END_REG + dp_end = data; + rdp_process_list(); + break; + + case 0x0c/4: // DP_STATUS_REG + if (data & 0x00000001) dp_status &= ~DP_STATUS_XBUS_DMA; + if (data & 0x00000002) dp_status |= DP_STATUS_XBUS_DMA; + if (data & 0x00000004) dp_status &= ~DP_STATUS_FREEZE; + if (data & 0x00000008) dp_status |= DP_STATUS_FREEZE; + if (data & 0x00000010) dp_status &= ~DP_STATUS_FLUSH; + if (data & 0x00000020) dp_status |= DP_STATUS_FLUSH; + break; + + default: + logerror("dp_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + + + +// Video Interface +static UINT32 vi_width; +UINT32 vi_origin; +UINT32 vi_control; +static UINT32 vi_burst, vi_vsync, vi_hsync, vi_leap, vi_hstart, vi_vstart; +static UINT32 vi_intr, vi_vburst, vi_xscale, vi_yscale; + +READ32_HANDLER( n64_vi_reg_r ) +{ + switch (offset) + { + case 0x04/4: // VI_ORIGIN_REG + return vi_origin; + + case 0x08/4: // VI_WIDTH_REG + return vi_width; + + case 0x0c/4: + return vi_intr; + + case 0x10/4: // VI_CURRENT_REG + return video_screen_get_vpos(0); + + case 0x14/4: // VI_BURST_REG + return vi_burst; + + case 0x18/4: // VI_V_SYNC_REG + return vi_vsync; + + case 0x1c/4: // VI_H_SYNC_REG + return vi_hsync; + + case 0x20/4: // VI_LEAP_REG + return vi_leap; + + case 0x24/4: // VI_H_START_REG + return vi_hstart; + + case 0x28/4: // VI_V_START_REG + return vi_vstart; + + case 0x2c/4: // VI_V_BURST_REG + return vi_vburst; + + case 0x30/4: // VI_X_SCALE_REG + return vi_xscale; + + case 0x34/4: // VI_Y_SCALE_REG + return vi_yscale; + + default: + logerror("vi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + return 0; +} + +WRITE32_HANDLER( n64_vi_reg_w ) +{ + switch (offset) + { + case 0x00/4: // VI_CONTROL_REG + if ((vi_control & 0x40) != (data & 0x40)) + { + screen_state *state = &Machine->screen[0]; + rectangle visarea = state->visarea; + visarea.max_y = (data & 0x40) ? 479 : 239; + video_screen_configure(0, state->width, visarea.max_y + 1, &visarea, Machine->screen[0].refresh); + } + vi_control = data; + break; + + case 0x04/4: // VI_ORIGIN_REG + vi_origin = data & 0xffffff; + break; + + case 0x08/4: // VI_WIDTH_REG + if (vi_width != data && data > 0) + { + screen_state *state = &Machine->screen[0]; + rectangle visarea = state->visarea; + visarea.max_x = data-1; + video_screen_configure(0, visarea.max_x + 1, state->height, &visarea, Machine->screen[0].refresh); + } + vi_width = data; + fb_width = data; + break; + + case 0x0c/4: // VI_INTR_REG + vi_intr = data; + break; + + case 0x10/4: // VI_CURRENT_REG + clear_rcp_interrupt(VI_INTERRUPT); + break; + + case 0x14/4: // VI_BURST_REG + vi_burst = data; + break; + + case 0x18/4: // VI_V_SYNC_REG + vi_vsync = data; + break; + + case 0x1c/4: // VI_H_SYNC_REG + vi_hsync = data; + break; + + case 0x20/4: // VI_LEAP_REG + vi_leap = data; + break; + + case 0x24/4: // VI_H_START_REG + vi_hstart = data; + break; + + case 0x28/4: // VI_V_START_REG + vi_vstart = data; + break; + + case 0x2c/4: // VI_V_BURST_REG + vi_vburst = data; + break; + + case 0x30/4: // VI_X_SCALE_REG + vi_xscale = data; + break; + + case 0x34/4: // VI_Y_SCALE_REG + vi_yscale = data; + break; + + /* + Uncomment this for convenient homebrew debugging + case 0x44/4: // TEMP DEBUG + printf( "E Ping: %08x\n", data ); + break; + */ + + default: + logerror("vi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + + +// Audio Interface +static UINT32 ai_dram_addr; +static UINT32 ai_len; +static UINT32 ai_control = 0; +static int ai_dacrate; +static int ai_bitrate; +static UINT32 ai_status = 0; + +static emu_timer *audio_timer; + +#define SOUNDBUFFER_LENGTH 0x20000 +#define AUDIO_DMA_DEPTH 2 + +typedef struct +{ + UINT32 address; + UINT32 length; +} AUDIO_DMA; + +static AUDIO_DMA audio_fifo[AUDIO_DMA_DEPTH]; +static int audio_fifo_wpos = 0; +static int audio_fifo_rpos = 0; +static int audio_fifo_num = 0; + +static void audio_fifo_push(UINT32 address, UINT32 length) +{ + AUDIO_DMA *current; + attotime period; + + if (audio_fifo_num == AUDIO_DMA_DEPTH) + { + mame_printf_debug("audio_fifo_push: tried to push to full DMA FIFO!!!\n"); + } + +// mame_printf_debug("fifo_push: adr %08x len %08x\n", address, length); + + audio_fifo[audio_fifo_wpos].address = address; + audio_fifo[audio_fifo_wpos].length = length; + current = &audio_fifo[audio_fifo_wpos]; + + audio_fifo_wpos++; + audio_fifo_num++; + + if (audio_fifo_wpos >= AUDIO_DMA_DEPTH) + { + audio_fifo_wpos = 0; + } + + if (audio_fifo_num >= AUDIO_DMA_DEPTH) + { + ai_status |= 0x80000001; // FIFO full + } + + // adjust the timer + period = attotime_mul(ATTOTIME_IN_HZ(DACRATE_NTSC), (ai_dacrate + 1) * (current->length / 4)); + timer_adjust(audio_timer, period, 0, attotime_zero); +} + +static void audio_fifo_pop(void) +{ + audio_fifo_rpos++; + audio_fifo_num--; + + if (audio_fifo_num < 0) + { + fatalerror("audio_fifo_pop: FIFO underflow!\n"); + } + + if (audio_fifo_rpos >= AUDIO_DMA_DEPTH) + { + audio_fifo_rpos = 0; + } + + if (audio_fifo_num < AUDIO_DMA_DEPTH) + { + ai_status &= ~0x80000001; // FIFO not full + } + + ai_len = 0; +} + +static AUDIO_DMA *audio_fifo_get_top(void) +{ + if (audio_fifo_num > 0) + { + return &audio_fifo[audio_fifo_rpos]; + } + else + { + return NULL; + } +} + +static void start_audio_dma(void) +{ + INT16 *ram = (INT16*)rdram; + AUDIO_DMA *current = audio_fifo_get_top(); + + ram = &ram[current->address/2]; + +// mame_printf_debug("DACDMA: %x for %x bytes\n", current->address, current->length); + + dmadac_transfer(0, 2, 2, 2, current->length/4, ram); +} + +static TIMER_CALLBACK( audio_timer_callback ) +{ + audio_fifo_pop(); + + // keep playing if there's another DMA queued + if (audio_fifo_get_top() != NULL) + { + start_audio_dma(); + signal_rcp_interrupt(AI_INTERRUPT); + } +} + +READ32_HANDLER( n64_ai_reg_r ) +{ + switch (offset) + { + case 0x04/4: // AI_LEN_REG + { + return ai_len; + } + + case 0x0c/4: // AI_STATUS_REG + return ai_status; + + default: + logerror("ai_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + + return 0; +} + +WRITE32_HANDLER( n64_ai_reg_w ) +{ +// UINT16 *ram = (UINT16*)rdram; + + switch (offset) + { + case 0x00/4: // AI_DRAM_ADDR_REG +// mame_printf_debug("ai_dram_addr = %08X at %08X\n", data, activecpu_get_pc()); + ai_dram_addr = data & 0xffffff; + break; + + case 0x04/4: // AI_LEN_REG +// mame_printf_debug("ai_len = %08X at %08X\n", data, activecpu_get_pc()); + ai_len = data & 0x3ffff; // Hardware v2.0 has 18 bits, v1.0 has 15 bits + audio_fifo_push(ai_dram_addr, ai_len); + break; + + case 0x08/4: // AI_CONTROL_REG +// mame_printf_debug("ai_control = %08X at %08X\n", data, activecpu_get_pc()); + ai_control = data; + break; + + case 0x0c/4: + clear_rcp_interrupt(AI_INTERRUPT); + break; + + case 0x10/4: // AI_DACRATE_REG + ai_dacrate = data & 0x3fff; + dmadac_set_frequency(0, 2, (double)DACRATE_NTSC / (double)(ai_dacrate+1)); + dmadac_enable(0, 2, 1); + break; + + case 0x14/4: // AI_BITRATE_REG +// mame_printf_debug("ai_bitrate = %08X\n", data); + ai_bitrate = data & 0xf; + break; + + default: + logerror("ai_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + + +// Peripheral Interface + +static UINT32 pi_dram_addr, pi_cart_addr; +static UINT32 pi_first_dma = 1; + +READ32_HANDLER( n64_pi_reg_r ) +{ + switch (offset) + { + case 0x00/4: // PI_DRAM_ADDR_REG + return pi_dram_addr; + + case 0x04/4: // PI_CART_ADDR_REG + return pi_cart_addr; + + case 0x10/4: // PI_STATUS_REG + return 0; + + default: + logerror("pi_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + return 0; +} + +WRITE32_HANDLER( n64_pi_reg_w ) +{ + switch (offset) + { + case 0x00/4: // PI_DRAM_ADDR_REG + { + pi_dram_addr = data; + break; + } + + case 0x04/4: // PI_CART_ADDR_REG + { + pi_cart_addr = data; + break; + } + + case 0x08/4: // PI_RD_LEN_REG + { + int i; + UINT32 dma_length = (data + 1); + + /*if (dma_length & 3) + { + dma_length = (dma_length + 3) & ~3; + }*/ + + //mame_printf_debug("PI DMA: %08X to %08X, length %08X\n", pi_dram_addr, pi_cart_addr, dma_length); + + if (pi_dram_addr != 0xffffffff) + { + for (i=0; i < dma_length; i++) + { + UINT8 b = program_read_byte_32be(pi_dram_addr); + program_write_byte_32be(pi_cart_addr, b); + pi_cart_addr += 1; + pi_dram_addr += 1; + } + } + + signal_rcp_interrupt(PI_INTERRUPT); + break; + } + + case 0x0c/4: // PI_WR_LEN_REG + { + int i; + UINT32 dma_length = (data + 1); + + /*if (dma_length & 3) + { + dma_length = (dma_length + 3) & ~3; + }*/ + + //mame_printf_debug("PI DMA: %08X to %08X, length %08X\n", pi_cart_addr, pi_dram_addr, dma_length); + + if (pi_dram_addr != 0xffffffff) + { + for (i=0; i < dma_length; i++) + { + /*UINT32 d = program_read_dword_32be(pi_cart_addr); + program_write_dword_32be(pi_dram_addr, d); + pi_cart_addr += 4; + pi_dram_addr += 4;*/ + + UINT8 b = program_read_byte_32be(pi_cart_addr); + program_write_byte_32be(pi_dram_addr, b); + pi_cart_addr += 1; + pi_dram_addr += 1; + } + } + signal_rcp_interrupt(PI_INTERRUPT); + + if (pi_first_dma) + { + // TODO: CIC-6105 has different address... + program_write_dword_32be(0x00000318, 0x400000); + program_write_dword_32be(0x000003f0, 0x800000); + pi_first_dma = 0; + } + + break; + } + + case 0x10/4: // PI_STATUS_REG + { + if (data & 0x2) + { + clear_rcp_interrupt(PI_INTERRUPT); + } + break; + } + + default: + logerror("pi_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + +// RDRAM Interface +READ32_HANDLER( n64_ri_reg_r ) +{ + switch (offset) + { + default: + logerror("ri_reg_r: %08X, %08X at %08X\n", offset, mem_mask, activecpu_get_pc()); + break; + } + + return 0; +} + +WRITE32_HANDLER( n64_ri_reg_w ) +{ + switch (offset) + { + default: + logerror("ri_reg_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, activecpu_get_pc()); + break; + } +} + +// Serial Interface +static UINT8 pif_ram[0x40]; +static UINT8 pif_cmd[0x40]; +UINT32 si_dram_addr = 0; +UINT32 si_pif_addr = 0; +UINT32 si_status = 0; + +static UINT8 eeprom[512]; +static UINT8 mempack[0x8000]; + +static UINT8 calc_mempack_crc(UINT8 *buffer, int length) +{ + int i, j; + UINT32 crc = 0; + UINT32 temp2 = 0; + + for (i=0; i <= length; i++) + { + for (j=7; j >= 0; j--) + { + if ((crc & 0x80) != 0) + { + temp2 = 0x85; + } + else + { + temp2 = 0; + } + + crc <<= 1; + + if (i == length) + { + crc &= 0xff; + } + else + { + if ((buffer[i] & (1 << j)) != 0) + { + crc |= 0x1; + } + } + + crc ^= temp2; + } + } + + return crc; +} + +static int pif_channel_handle_command(int channel, int slength, UINT8 *sdata, int rlength, UINT8 *rdata) +{ + int i; + UINT8 command = sdata[0]; + + switch (command) + { + case 0x00: // Read status + { + if (slength != 1 || rlength != 3) + { + // osd_die("handle_pif: read status (bytes to send %d, bytes to receive %d)\n", bytes_to_send, bytes_to_recv); + } + + switch (channel) + { + case 0: + { + rdata[0] = 0x05; + rdata[1] = 0x00; + rdata[2] = 0x02; + return 0; + } + case 1: + case 2: + case 3: + { + // not connected + return 1; + } + case 4: + { + rdata[0] = 0x00; + rdata[1] = 0x80; + rdata[2] = 0x00; + //rdata[0] = 0xff; + //rdata[1] = 0xff; + //rdata[2] = 0xff; + + return 1; + } + case 5: + { + mame_printf_debug("EEPROM2? read status\n"); + return 1; + } + } + + break; + } + + case 0x01: // Read button values + { + UINT16 buttons = 0; + INT8 x = 0, y = 0; + if (slength != 1 || rlength != 4) + { + fatalerror("handle_pif: read button values (bytes to send %d, bytes to receive %d)\n", slength, rlength); + } + + switch (channel) + { + case 0: + { + buttons = readinputport((channel*3) + 0); + x = readinputport((channel*3) + 1) - 128; + y = readinputport((channel*3) + 2) - 128; + + rdata[0] = (buttons >> 8) & 0xff; + rdata[1] = (buttons >> 0) & 0xff; + rdata[2] = (UINT8)(x); + rdata[3] = (UINT8)(y); + return 0; + } + case 1: + case 2: + case 3: + { + // not connected + return 1; + } + } + + break; + } + + case 0x02: + { + UINT32 address, checksum; + + /*mame_printf_debug("Read from mempack, rlength = %d, slength = %d\n", rlength, slength); + for (i=0; i < slength; i++) + { + mame_printf_debug("%02X ", sdata[i]); + } + mame_printf_debug("\n");*/ + + address = (sdata[1] << 8) | (sdata[2]); + checksum = address & 0x1f; + address &= ~0x1f; + + if (address == 0x400) + { + for (i=0; i < rlength-1; i++) + { + rdata[i] = 0x00; + } + + rdata[rlength-1] = calc_mempack_crc(rdata, rlength-1); + // mame_printf_debug("CRC = %02X\n", rdata[rlength-1]); + } + else if (address < 0x7fe0) + { + for (i=0; i < rlength-1; i++) + { + rdata[i] = mempack[address+i]; + } + + rdata[rlength-1] = calc_mempack_crc(rdata, rlength-1); + // mame_printf_debug("CRC = %02X\n", rdata[rlength-1]); + } + return 1; + } + case 0x03: + { + UINT32 address, checksum; + int i; + /*mame_printf_debug("Write to mempack, rlength = %d, slength = %d\n", rlength, slength); + for (i=0; i < slength; i++) + { + mame_printf_debug("%02X ", sdata[i]); + } + mame_printf_debug("\n");*/ + + address = (sdata[1] << 8) | (sdata[2]); + checksum = address & 0x1f; + address &= ~0x1f; + + if (address == 0x8000) + { + + } + else + { + for (i=3; i < slength; i++) + { + mempack[address++] = sdata[i]; + } + } + + rdata[0] = calc_mempack_crc(&sdata[3], slength-3); + + return 1; + } + + case 0x04: // Read from EEPROM + { + UINT8 block_offset; + + if (channel != 4) + { + //fatalerror("Tried to write to EEPROM on channel %d\n", channel); + return 1; + } + + if (slength != 2 || rlength != 8) + { + fatalerror("handle_pif: write EEPROM (bytes to send %d, bytes to receive %d)\n", slength, rlength); + } + + block_offset = sdata[1] * 8; + + for (i=0; i < 8; i++) + { + rdata[i] = eeprom[block_offset+i]; + } + + return 1; + } + + case 0x05: // Write to EEPROM + { + UINT8 block_offset; + + if (channel != 4) + { + //fatalerror("Tried to write to EEPROM on channel %d\n", channel); + return 1; + } + + if (slength != 10 || rlength != 1) + { + fatalerror("handle_pif: write EEPROM (bytes to send %d, bytes to receive %d)\n", slength, rlength); + } + + block_offset = sdata[1] * 8; + //mame_printf_debug("Write EEPROM: offset %02X: ", block_offset); + for (i=0; i < 8; i++) + { + //mame_printf_debug("%02X ", sdata[2+i]); + eeprom[block_offset+i] = sdata[2+i]; + } + //mame_printf_debug("\n"); + + rdata[0] = 0; + + return 1; + } + + case 0xff: // reset + { + rdata[0] = 0xff; + rdata[1] = 0xff; + rdata[2] = 0xff; + return 0; + } + + default: + { + mame_printf_debug("handle_pif: unknown/unimplemented command %02X\n", command); + return 1; + } + } + + return 0; +} + +static void handle_pif(void) +{ + int j; + + /* + { + int i; + for (i=0; i < 8; i++) + { + int j = i * 8; + mame_printf_debug("PIFCMD%d: %02X %02X %02X %02X %02X %02X %02X %02X\n", i, pif_cmd[j], pif_cmd[j+1], pif_cmd[j+2], pif_cmd[j+3], pif_cmd[j+4], pif_cmd[j+5], pif_cmd[j+6], pif_cmd[j+7]); + } + mame_printf_debug("\n"); + } + */ + + if (pif_cmd[0x3f] == 0x1) // only handle the command if the last byte is 1 + { + int channel = 0; + int end = 0; + int cmd_ptr = 0; + + while (cmd_ptr < 0x3f && !end) + { + UINT8 bytes_to_send; + INT8 bytes_to_recv; + + bytes_to_send = pif_cmd[cmd_ptr++]; + + if (bytes_to_send == 0xfe) + { + end = 1; + } + else if (bytes_to_send == 0xff) + { + // do nothing + } + else + { + if (bytes_to_send > 0 && (bytes_to_send & 0xc0) == 0) + { + int res; + UINT8 recv_buffer[0x40]; + UINT8 send_buffer[0x40]; + + bytes_to_recv = pif_cmd[cmd_ptr++]; + + for (j=0; j < bytes_to_send; j++) + { + send_buffer[j] = pif_cmd[cmd_ptr++]; + } + + res = pif_channel_handle_command(channel, bytes_to_send, send_buffer, bytes_to_recv, recv_buffer); + + if (res == 0) + { + if (cmd_ptr + bytes_to_recv > 0x3f) + { + fatalerror("cmd_ptr overflow\n"); + } + for (j=0; j < bytes_to_recv; j++) + { + pif_ram[cmd_ptr++] = recv_buffer[j]; + } + } + else if (res == 1) + { + int offset = 0;//bytes_to_send; + pif_ram[cmd_ptr-offset-2] |= 0x80; + } + } + + channel++; + } + } + + pif_ram[0x3f] = 0; + } + + /* + { + int i; + for (i=0; i < 8; i++) + { + int j = i * 8; + mame_printf_debug("PIFRAM%d: %02X %02X %02X %02X %02X %02X %02X %02X\n", i, pif_ram[j], pif_ram[j+1], pif_ram[j+2], pif_ram[j+3], pif_ram[j+4], pif_ram[j+5], pif_ram[j+6], pif_ram[j+7]); + } + mame_printf_debug("\n"); + } + */ +} + +static void pif_dma(int direction) +{ + int i; + UINT32 *src, *dst; + + if (si_dram_addr & 0x3) + { + fatalerror("pif_dma: si_dram_addr unaligned: %08X\n", si_dram_addr); + } + + if (direction) // RDRAM -> PIF RAM + { + src = (UINT32*)&rdram[(si_dram_addr & 0x1fffffff) / 4]; + + for (i=0; i < 64; i+=4) + { + UINT32 d = *src++; + pif_ram[i+0] = (d >> 24) & 0xff; + pif_ram[i+1] = (d >> 16) & 0xff; + pif_ram[i+2] = (d >> 8) & 0xff; + pif_ram[i+3] = (d >> 0) & 0xff; + } + + memcpy(pif_cmd, pif_ram, 0x40); + } + else // PIF RAM -> RDRAM + { + handle_pif(); + + dst = (UINT32*)&rdram[(si_dram_addr & 0x1fffffff) / 4]; + + for (i=0; i < 64; i+=4) + { + UINT32 d = 0; + d |= pif_ram[i+0] << 24; + d |= pif_ram[i+1] << 16; + d |= pif_ram[i+2] << 8; + d |= pif_ram[i+3] << 0; + + *dst++ = d; + } + } + + si_status |= 0x1000; + signal_rcp_interrupt(SI_INTERRUPT); +} + +READ32_HANDLER( n64_si_reg_r ) +{ + switch (offset) + { + case 0x00/4: // SI_DRAM_ADDR_REG + return si_dram_addr; + + case 0x18/4: // SI_STATUS_REG + return si_status; + } + return 0; +} + +WRITE32_HANDLER( n64_si_reg_w ) +{ + switch (offset) + { + case 0x00/4: // SI_DRAM_ADDR_REG + si_dram_addr = data; + // mame_printf_debug("si_dram_addr = %08X\n", si_dram_addr); + break; + + case 0x04/4: // SI_PIF_ADDR_RD64B_REG + // PIF RAM -> RDRAM + si_pif_addr = data; + pif_dma(0); + break; + + case 0x10/4: // SI_PIF_ADDR_WR64B_REG + // RDRAM -> PIF RAM + si_pif_addr = data; + pif_dma(1); + break; + + case 0x18/4: // SI_STATUS_REG + si_status &= ~0x1000; + clear_rcp_interrupt(SI_INTERRUPT); + break; + + default: + logerror("si_reg_w: %08X, %08X, %08X\n", data, offset, mem_mask); + break; + } +} + +UINT32 cic_status = 0x00000000; + +READ32_HANDLER( n64_pif_ram_r ) +{ + /*mame_printf_debug( "pif_ram_r: %08X, %08X = %08X\n", offset << 2, mem_mask, ( ( pif_ram[offset*4+0] << 24 ) | ( pif_ram[offset*4+1] << 16 ) | ( pif_ram[offset*4+2] << 8 ) | ( pif_ram[offset*4+3] << 0 ) ) & ~mem_mask );*/ + if( offset == ( 0x24 / 4 ) ) + { + cic_status = 0x00000080; + } + if( offset == ( 0x3C / 4 ) ) + { + return cic_status; + } + return ( ( pif_ram[offset*4+0] << 24 ) | ( pif_ram[offset*4+1] << 16 ) | ( pif_ram[offset*4+2] << 8 ) | ( pif_ram[offset*4+3] << 0 ) ) & ~mem_mask; +} + +WRITE32_HANDLER( n64_pif_ram_w ) +{ + /*mame_printf_debug("pif_ram_w: %08X, %08X, %08X\n", data, offset << 4, mem_mask);*/ + /* + if( (~mem_mask) & 0xff000000 ) + { + pif_ram[offset*4+0] = ( data >> 24 ) & 0x000000ff; + } + if( (~mem_mask) & 0x00ff0000 ) + { + pif_ram[offset*4+1] = ( data >> 16 ) & 0x000000ff; + } + if( (~mem_mask) & 0x0000ff00 ) + { + pif_ram[offset*4+2] = ( data >> 8 ) & 0x000000ff; + } + if( (~mem_mask) & 0x000000ff ) + { + pif_ram[offset*4+3] = ( data >> 0 ) & 0x000000ff; + } + */ + + signal_rcp_interrupt(SI_INTERRUPT); +} + +//static UINT16 crc_seed = 0x3f; + +void n64_machine_reset(void) +{ + int i; + //UINT32 *pif_rom = (UINT32*)memory_region(REGION_USER1); + UINT32 *cart = (UINT32*)memory_region(REGION_USER2); + UINT64 boot_checksum; + + cpunum_set_info_int(0, CPUINFO_INT_MIPS3_DRC_OPTIONS, MIPS3DRC_FASTEST_OPTIONS + MIPS3DRC_STRICT_VERIFY); + + /* configure fast RAM regions for DRC */ + cpunum_set_info_int(0, CPUINFO_INT_MIPS3_FASTRAM_SELECT, 0); + cpunum_set_info_int(0, CPUINFO_INT_MIPS3_FASTRAM_START, 0x00000000); + cpunum_set_info_int(0, CPUINFO_INT_MIPS3_FASTRAM_END, 0x007fffff); + cpunum_set_info_ptr(0, CPUINFO_PTR_MIPS3_FASTRAM_BASE, rdram); + cpunum_set_info_int(0, CPUINFO_INT_MIPS3_FASTRAM_READONLY, 0); + + audio_timer = timer_alloc(audio_timer_callback); + timer_adjust(audio_timer, attotime_never, 0, attotime_never); + + cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE); + + // bootcode differs between CIC-chips, so we can use its checksum to detect the CIC-chip + boot_checksum = 0; + for (i=0x40; i < 0x1000; i+=4) + { + boot_checksum += cart[i/4]+i; + } + + if (boot_checksum == U64(0x000000d057e84864)) + { + // CIC-NUS-6101 + mame_printf_debug("CIC-NUS-6101 detected\n"); + // crc_seed = 0x3f; + pif_ram[0x24] = 0x00; + pif_ram[0x25] = 0x04; + pif_ram[0x26] = 0x3f; + pif_ram[0x27] = 0x3f; + } + else if (boot_checksum == U64(0x000000d6499e376b)) + { + // CIC-NUS-6103 + mame_printf_debug("CIC-NUS-6103 detected\n"); + // crc_seed = 0x78; + pif_ram[0x24] = 0x00; + pif_ram[0x25] = 0x04; + pif_ram[0x26] = 0x78; + pif_ram[0x27] = 0x78; + } + else if (boot_checksum == U64(0x0000011a4a1604b6)) + { + // CIC-NUS-6105 + mame_printf_debug("CIC-NUS-6105 detected\n"); + // crc_seed = 0x91; + + // first_rsp = 0; + pif_ram[0x24] = 0x00; + pif_ram[0x25] = 0x04; + pif_ram[0x26] = 0x91; + pif_ram[0x27] = 0x91; + } + else if (boot_checksum == U64(0x000000d6d5de4ba0)) + { + // CIC-NUS-6106 + mame_printf_debug("CIC-NUS-6106 detected\n"); + // crc_seed = 0x85; + pif_ram[0x24] = 0x00; + pif_ram[0x25] = 0x04; + pif_ram[0x26] = 0x85; + pif_ram[0x27] = 0x85; + } + else + { + mame_printf_debug("Unknown BootCode Checksum %08X%08X\n", (UINT32)(boot_checksum>>32),(UINT32)(boot_checksum)); + } + + /* + // bootcode differs between CIC-chips, so we can use its checksum to detect the CIC-chip + boot_checksum = 0; + for (i=0x40; i < 0x1000; i+=4) + { + boot_checksum += cart[i/4]+i; + } + + if (boot_checksum == U64(0x000000d057e84864)) + { + // CIC-NUS-6101 + mame_printf_debug("CIC-NUS-6101 detected\n"); + crc_seed = 0x3f; + } + else if (boot_checksum == U64(0x000000d6499e376b)) + { + // CIC-NUS-6103 + mame_printf_debug("CIC-NUS-6103 detected\n"); + crc_seed = 0x78; + } + else if (boot_checksum == U64(0x0000011a4a1604b6)) + { + // CIC-NUS-6105 + mame_printf_debug("CIC-NUS-6105 detected\n"); + crc_seed = 0x91; + + first_rsp = 0; + } + else if (boot_checksum == U64(0x000000d6d5de4ba0)) + { + // CIC-NUS-6106 + mame_printf_debug("CIC-NUS-6106 detected\n"); + crc_seed = 0x85; + } + else + { + mame_printf_debug("Unknown BootCode Checksum %08X%08X\n", (UINT32)(boot_checksum>>32),(UINT32)(boot_checksum)); + } + + // The PIF Boot ROM is not dumped, the following code simulates it + + // clear all registers + for (i=1; i < 32; i++) + { + *pif_rom++ = 0x00000000 | 0 << 21 | 0 << 16 | i << 11 | 0x20; // ADD ri, r0, r0 + } + + // R20 <- 0x00000001 + *pif_rom++ = 0x34000000 | 20 << 16 | 0x0001; // ORI r20, r0, 0x0001 + + // R22 <- 0x0000003F + *pif_rom++ = 0x34000000 | 22 << 16 | crc_seed; // ORI r22, r0, 0x003f + + // R29 <- 0xA4001FF0 + *pif_rom++ = 0x3c000000 | 29 << 16 | 0xa400; // LUI r29, 0xa400 + *pif_rom++ = 0x34000000 | 29 << 21 | 29 << 16 | 0x1ff0; // ORI r29, r29, 0x1ff0 + + // clear CP0 registers + for (i=0; i < 32; i++) + { + *pif_rom++ = 0x40000000 | 4 << 21 | 0 << 16 | i << 11; // MTC2 cp0ri, r0 + } + + // Random <- 0x0000001F + *pif_rom++ = 0x34000000 | 1 << 16 | 0x001f; + *pif_rom++ = 0x40000000 | 4 << 21 | 1 << 16 | 1 << 11; // MTC2 Random, r1 + + // Status <- 0x70400004 + *pif_rom++ = 0x3c000000 | 1 << 16 | 0x7040; // LUI r1, 0x7040 + *pif_rom++ = 0x34000000 | 1 << 21 | 1 << 16 | 0x0004; // ORI r1, r1, 0x0004 + *pif_rom++ = 0x40000000 | 4 << 21 | 1 << 16 | 12 << 11; // MTC2 Status, r1 + + // PRId <- 0x00000B00 + *pif_rom++ = 0x34000000 | 1 << 16 | 0x0b00; // ORI r1, r0, 0x0b00 + *pif_rom++ = 0x40000000 | 4 << 21 | 1 << 16 | 15 << 11; // MTC2 PRId, r1 + + // Config <- 0x0006E463 + *pif_rom++ = 0x3c000000 | 1 << 16 | 0x0006; // LUI r1, 0x0006 + *pif_rom++ = 0x34000000 | 1 << 21 | 1 << 16 | 0xe463; // ORI r1, r1, 0xe463 + *pif_rom++ = 0x40000000 | 4 << 21 | 1 << 16 | 16 << 11; // MTC2 Config, r1 + + // (0xa4300004) <- 0x01010101 + *pif_rom++ = 0x3c000000 | 1 << 16 | 0x0101; // LUI r1, 0x0101 + *pif_rom++ = 0x34000000 | 1 << 21 | 1 << 16 | 0x0101; // ORI r1, r1, 0x0101 + *pif_rom++ = 0x3c000000 | 3 << 16 | 0xa430; // LUI r3, 0xa430 + *pif_rom++ = 0xac000000 | 3 << 21 | 1 << 16 | 0x0004; // SW r1, 0x0004(r3) + + // Copy 0xb0000000...1fff -> 0xa4000000...1fff + *pif_rom++ = 0x34000000 | 3 << 16 | 0x0400; // ORI r3, r0, 0x0400 + *pif_rom++ = 0x3c000000 | 4 << 16 | 0xb000; // LUI r4, 0xb000 + *pif_rom++ = 0x3c000000 | 5 << 16 | 0xa400; // LUI r5, 0xa400 + *pif_rom++ = 0x8c000000 | 4 << 21 | 1 << 16; // LW r1, 0x0000(r4) + *pif_rom++ = 0xac000000 | 5 << 21 | 1 << 16; // SW r1, 0x0000(r5) + *pif_rom++ = 0x20000000 | 4 << 21 | 4 << 16 | 0x0004; // ADDI r4, r4, 0x0004 + *pif_rom++ = 0x20000000 | 5 << 21 | 5 << 16 | 0x0004; // ADDI r5, r5, 0x0004 + *pif_rom++ = 0x20000000 | 3 << 21 | 3 << 16 | 0xffff; // ADDI r3, r3, -1 + *pif_rom++ = 0x14000000 | 3 << 21 | 0 << 16 | 0xfffa; // BNE r3, r0, -6 + *pif_rom++ = 0x00000000; + + *pif_rom++ = 0x34000000 | 3 << 16 | 0x0000; // ORI r3, r0, 0x0000 + *pif_rom++ = 0x34000000 | 4 << 16 | 0x0000; // ORI r4, r0, 0x0000 + *pif_rom++ = 0x34000000 | 5 << 16 | 0x0000; // ORI r5, r0, 0x0000 + + // Zelda and DK64 need these + *pif_rom++ = 0x3c000000 | 9 << 16 | 0xa400; + *pif_rom++ = 0x34000000 | 9 << 21 | 9 << 16 | 0x1ff0; + *pif_rom++ = 0x3c000000 | 11 << 16 | 0xa400; + *pif_rom++ = 0x3c000000 | 31 << 16 | 0xffff; + *pif_rom++ = 0x34000000 | 31 << 21 | 31 << 16 | 0xffff; + + *pif_rom++ = 0x3c000000 | 1 << 16 | 0xa400; // LUI r1, 0xa400 + *pif_rom++ = 0x34000000 | 1 << 21 | 1 << 16 | 0x0040; // ORI r1, r1, 0x0040 + *pif_rom++ = 0x00000000 | 1 << 21 | 0x8; // JR r1 + */ +} |