diff options
Diffstat (limited to 'src/devices/bus/snes/sa1.cpp')
-rw-r--r-- | src/devices/bus/snes/sa1.cpp | 1131 |
1 files changed, 605 insertions, 526 deletions
diff --git a/src/devices/bus/snes/sa1.cpp b/src/devices/bus/snes/sa1.cpp index b650a76c5ea..65ff3d5b251 100644 --- a/src/devices/bus/snes/sa1.cpp +++ b/src/devices/bus/snes/sa1.cpp @@ -5,17 +5,17 @@ SA-1 add-on chip emulation (for SNES/SFC) Note: - - SA-1 register description below is based on no$cash docs. - - about bankswitch handling: no matter what is ROM size, at loading the ROM is mirrored up to 8MB and a + - SA-1 register description below is based on nocash docs. + - Bankswitch handling: no matter what ROM size is used, at loading the ROM is mirrored up to 8MB and a rom_bank_map[0x100] array is built as a lookup table for 256x32KB banks filling the 8MB accessible ROM - area; this allows to handle any 0-7 value written to CXB/DXB/EXB/FXB SA-1 registers without any masking! - - about BWRAM "bitmap mode": in 2bits mode + area; this allows any value from 0-7 being written to CXB/DXB/EXB/FXB SA-1 registers without any masking. + - about BWRAM "bitmap mode": in 2-bit mode 600000h.Bit0-1 mirrors to 400000h.Bit0-1 600001h.Bit0-1 mirrors to 400000h.Bit2-3 600002h.Bit0-1 mirrors to 400000h.Bit4-5 600003h.Bit0-1 mirrors to 400000h.Bit6-7 ... - in 4bits mode + in 4-bit mode 600000h.Bit0-3 mirrors to 400000h.Bit0-3 600001h.Bit0-3 mirrors to 400000h.Bit4-7 600002h.Bit0-3 mirrors to 400001h.Bit0-3 @@ -24,9 +24,10 @@ to handle the separate modes, bitmap accesses go to offset + 0x100000 TODO: - - test case for BWRAM & IRAM write protect (bsnes does not seem to ever protect either, so it's not implemented + - Test case for BWRAM write protect (bsnes does not seem to protect either, so it's not implemented for the moment) - - almost everything CPU related! + - Almost everything CPU related + - Bus conflicts Compatibility: asahishi: plays OK @@ -60,8 +61,8 @@ sshogi3: plays OK taikyoid: plays OK takemiya: plays OK - [Note: for Igo & Shougi games, "plays OK" means you can get ingame and the CPU replies to your moves... subtle bugs - might indeed exist...] + Note: for Igo & Shougi games, "plays OK" means you can get ingame and the CPU replies to your moves; subtle bugs + might indeed exist. ***********************************************************************************************************/ @@ -85,50 +86,55 @@ DEFINE_DEVICE_TYPE(SNS_LOROM_SA1, sns_sa1_device, "sns_rom_sa1", "SNES Cart + SA-1") -sns_sa1_device::sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +sns_sa1_device::sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, SNS_LOROM_SA1, tag, owner, clock) , device_sns_cart_interface(mconfig, *this) , m_sa1(*this, "sa1cpu") - , m_sa1_ctrl(0), m_scpu_sie(0), m_sa1_reset(0), m_sa1_nmi(0), m_sa1_irq(0), m_scpu_ctrl(0), m_sa1_sie(0) + , m_sa1_timer(nullptr) + , m_sa1_ctrl(0), m_sa1_reset_flag(true), m_scpu_sie(0), m_sa1_reset_vector(0), m_sa1_nmi_vector(0), m_sa1_irq_vector(0), m_scpu_ctrl(0), m_sa1_sie(0) , m_irq_vector(0), m_nmi_vector(0) + , m_timer_ctrl(0) + , m_hpos(0), m_vpos(0) , m_hcount(0), m_vcount(0) - , m_bank_c_hi(0), m_bank_c_rom(0), m_bank_d_hi(0), m_bank_d_rom(0), m_bank_e_hi(0), m_bank_e_rom(0), m_bank_f_hi(0), m_bank_f_rom(0) - , m_bwram_snes(0), m_bwram_sa1(0), m_bwram_sa1_source(0), m_bwram_sa1_format(0), m_bwram_write_snes(0), m_bwram_write_sa1(0), m_bwpa_sa1(0) + , m_bank_hi{false,false,false,false}, m_bank_rom{0,0,0,0} + , m_bwram_snes(0), m_bwram_sa1(0), m_bwram_sa1_source(false), m_bwram_sa1_format(false), m_bwram_write_snes(false), m_bwram_write_sa1(false), m_bwpa_sa1(0) , m_iram_write_snes(0), m_iram_write_sa1(0) , m_dma_ctrl(0), m_dma_ccparam(0), m_src_addr(0), m_dst_addr(0), m_dma_cnt(0) , m_math_ctlr(0), m_math_overflow(0), m_math_a(0), m_math_b(0), m_math_res(0) - , m_vda(0), m_vbit(0), m_vlen(0), m_drm(0), m_scpu_flags(0), m_sa1_flags(0), m_hcr(0), m_vcr(0) + , m_vda(0), m_vbit(0), m_vlen(0), m_drm(false), m_scpu_flags(0), m_sa1_flags(0), m_hcr(0), m_vcr(0) + , m_cconv1_dma_active(false), m_cconv2_line(0) { } void sns_sa1_device::device_start() { + m_internal_ram = make_unique_clear<u8[]>(0x800); + m_sa1_timer = timer_alloc(FUNC(sns_sa1_device::timer_tick), this); + m_scpu_ctrl = 0; m_nmi_vector = 0; - m_bank_c_hi = 0; - m_bank_c_rom = 0; + m_bank_hi[0] = false; + m_bank_rom[0] = 0; - save_item(NAME(m_internal_ram)); + save_pointer(NAME(m_internal_ram), 0x800); save_item(NAME(m_sa1_ctrl)); + save_item(NAME(m_sa1_reset_flag)); save_item(NAME(m_scpu_sie)); - save_item(NAME(m_sa1_reset)); - save_item(NAME(m_sa1_nmi)); - save_item(NAME(m_sa1_irq)); + save_item(NAME(m_sa1_reset_vector)); + save_item(NAME(m_sa1_nmi_vector)); + save_item(NAME(m_sa1_irq_vector)); save_item(NAME(m_scpu_ctrl)); save_item(NAME(m_sa1_sie)); save_item(NAME(m_irq_vector)); save_item(NAME(m_nmi_vector)); + save_item(NAME(m_timer_ctrl)); + save_item(NAME(m_hpos)); + save_item(NAME(m_vpos)); save_item(NAME(m_hcount)); save_item(NAME(m_vcount)); - save_item(NAME(m_bank_c_hi)); - save_item(NAME(m_bank_c_rom)); - save_item(NAME(m_bank_d_hi)); - save_item(NAME(m_bank_d_rom)); - save_item(NAME(m_bank_e_hi)); - save_item(NAME(m_bank_e_rom)); - save_item(NAME(m_bank_f_hi)); - save_item(NAME(m_bank_f_rom)); + save_item(NAME(m_bank_hi)); + save_item(NAME(m_bank_rom)); save_item(NAME(m_bwram_snes)); save_item(NAME(m_bwram_sa1)); save_item(NAME(m_bwram_sa1_source)); @@ -157,38 +163,44 @@ void sns_sa1_device::device_start() save_item(NAME(m_sa1_flags)); save_item(NAME(m_hcr)); save_item(NAME(m_vcr)); + save_item(NAME(m_cconv1_dma_active)); + save_item(NAME(m_cconv2_line)); } void sns_sa1_device::device_reset() { - memset(m_internal_ram, 0, sizeof(m_internal_ram)); + std::fill_n(&m_internal_ram[0], 0x800, 0); m_sa1_ctrl = 0x20; + m_sa1_reset_flag = true; m_scpu_ctrl = 0; m_irq_vector = 0; m_nmi_vector = 0; + m_timer_ctrl = 0; + m_hpos = 0; + m_vpos = 0; m_hcount = 0; m_vcount = 0; - m_bank_c_hi = 0; - m_bank_c_rom = 0; - m_bank_d_hi = 0; - m_bank_d_rom = 1; - m_bank_e_hi = 0; - m_bank_e_rom = 2; - m_bank_f_hi = 0; - m_bank_f_rom = 3; + m_bank_hi[0] = false; + m_bank_hi[1] = false; + m_bank_hi[2] = false; + m_bank_hi[3] = false; + m_bank_rom[0] = 0; + m_bank_rom[1] = 1; + m_bank_rom[2] = 2; + m_bank_rom[3] = 3; m_bwram_snes = 0; m_bwram_sa1 = 0; - m_bwram_sa1_source = 0; - m_bwram_sa1_format = 0; - m_bwram_write_snes = 1; - m_bwram_write_sa1 = 1; - m_bwpa_sa1 = 0x0f; - m_iram_write_snes = 1; - m_iram_write_sa1 = 1; + m_bwram_sa1_source = false; + m_bwram_sa1_format = false; + m_bwram_write_snes = false; + m_bwram_write_sa1 = false; + m_bwpa_sa1 = 0x100 << 0x0f; + m_iram_write_snes = 0; + m_iram_write_sa1 = 0; m_src_addr = 0; m_dst_addr = 0; - memset(m_brf_reg, 0, sizeof(m_brf_reg)); + std::fill(std::begin(m_brf_reg), std::end(m_brf_reg), 0); m_math_ctlr = 0; m_math_overflow = 0; m_math_a = 0; @@ -197,7 +209,7 @@ void sns_sa1_device::device_reset() m_vda = 0; m_vbit = 0; m_vlen = 0; - m_drm = 0; + m_drm = false; m_hcr = 0; m_vcr = 0; m_scpu_sie = m_sa1_sie = 0; @@ -205,11 +217,63 @@ void sns_sa1_device::device_reset() m_dma_ctrl = 0; m_dma_ccparam = 0; m_dma_cnt = 0; + m_cconv1_dma_active = false; + m_cconv2_line = 0; - // sa-1 CPU starts out not running? + // SA-1 CPU starts out not running m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + // Timer is run in sync with the CPU + m_sa1_timer->adjust(m_sa1->clocks_to_attotime(2), 0, m_sa1->clocks_to_attotime(2)); } +TIMER_CALLBACK_MEMBER(sns_sa1_device::timer_tick) +{ + if (TMC_HVSELB()) + { + // 18 bit Linear timer + m_hpos++; + m_vpos += m_hpos >> 9; + m_hpos &= 0x1ff; + m_vpos &= 0x1ff; + } + else + { + // H/V timer + if (++m_hpos >= 341) + { + m_hpos = 0; + if (++m_vpos >= scanlines_r()) + m_vpos = 0; + } + } + // send timer IRQ + if (TMC_HEN() && TMC_VEN()) // both H and V count enabled + { + if ((m_hpos == m_hcount) && (m_vpos == m_vcount)) + { + m_sa1_flags |= SA1_IRQ_TIMER; + recalc_irqs(); + } + } + else if (TMC_HEN()) // H count only + { + if (m_hpos == m_hcount) + { + m_sa1_flags |= SA1_IRQ_TIMER; + recalc_irqs(); + } + } + else if (TMC_VEN()) // V count only + { + if ((m_hpos == 0) && (m_vpos == m_vcount)) + { + m_sa1_flags |= SA1_IRQ_TIMER; + recalc_irqs(); + } + } + + // TODO: Math & DMA timer +} /*------------------------------------------------- mapper specific handlers @@ -218,31 +282,19 @@ void sns_sa1_device::device_reset() void sns_sa1_device::recalc_irqs() { if (m_scpu_flags & m_scpu_sie & (SCPU_IRQ_SA1|SCPU_IRQ_CHARCONV)) - { write_irq(ASSERT_LINE); - } else - { write_irq(CLEAR_LINE); - } - if (m_sa1_flags & m_sa1_sie & (SA1_IRQ_SCPU|SA1_IRQ_TIMER|SA1_IRQ_DMA)) - { + if ((!sa1_halted()) && (m_sa1_flags & m_sa1_sie & (SA1_IRQ_SCPU|SA1_IRQ_TIMER|SA1_IRQ_DMA))) m_sa1->set_input_line(G65816_LINE_IRQ, ASSERT_LINE); - } else - { m_sa1->set_input_line(G65816_LINE_IRQ, CLEAR_LINE); - } - if (m_sa1_flags & m_sa1_sie & SA1_NMI_SCPU) - { + if ((!sa1_halted()) && (m_sa1_flags & m_sa1_sie & SA1_NMI_SCPU)) m_sa1->set_input_line(G65816_LINE_NMI, ASSERT_LINE); - } else - { m_sa1->set_input_line(G65816_LINE_NMI, CLEAR_LINE); - } } @@ -251,18 +303,18 @@ void sns_sa1_device::recalc_irqs() -------------------------------------------------*/ -// handle this separately to avoid accessing recursively the regs? +// TODO: Handle this separately to avoid accessing the regs recursively -template <bool SA1Read> -uint8_t sns_sa1_device::var_length_read(uint32_t offset) +u8 sns_sa1_device::var_length_read(offs_t offset) { + // TODO: memory access cycle // handle 0xffea/0xffeb/0xffee/0xffef if ((offset & 0xffffe0) == 0x00ffe0) { - if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff; - if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff; - if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff; - if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff; + if (offset == 0xffea && SCNT_SNESCPU_NVSW()) return (m_nmi_vector >> 0) & 0xff; + if (offset == 0xffeb && SCNT_SNESCPU_NVSW()) return (m_nmi_vector >> 8) & 0xff; + if (offset == 0xffee && SCNT_SNESCPU_IVSW()) return (m_irq_vector >> 0) & 0xff; + if (offset == 0xffef && SCNT_SNESCPU_IVSW()) return (m_irq_vector >> 8) & 0xff; } if ((offset & 0xc08000) == 0x008000) //$00-3f:8000-ffff @@ -275,10 +327,10 @@ uint8_t sns_sa1_device::var_length_read(uint32_t offset) return read_h(offset & 0x7fffff); if ((offset & 0x40e000) == 0x006000) //$00-3f|80-bf:6000-7fff - return read_bwram<SA1Read>((m_bwram_snes * 0x2000) + (offset & 0x1fff)); + return read_bwram<true>((m_bwram_snes * 0x2000) + (offset & 0x1fff)); if ((offset & 0xf00000) == 0x400000) //$40-4f:0000-ffff - return read_bwram<SA1Read>(offset & 0xfffff); + return read_bwram<true>(offset & 0xfffff); if ((offset & 0x40f800) == 0x000000) //$00-3f|80-bf:0000-07ff return read_iram(offset); @@ -291,75 +343,57 @@ uint8_t sns_sa1_device::var_length_read(uint32_t offset) void sns_sa1_device::dma_transfer() { -// printf("DMA src %08x (%d), dst %08x (%d) cnt %d\n", m_src_addr, m_dma_ctrl & 3, m_dst_addr, m_dma_ctrl & 4, m_dma_cnt); - while (m_dma_cnt--) { - uint8_t data = 0; // open bus? - uint32_t dma_src = m_src_addr++; - uint32_t dma_dst = m_dst_addr++; + u8 data = 0; // TODO: open bus + const u32 dma_src = m_src_addr++; + const u32 dma_dst = m_dst_addr++; // source and destination cannot be the same // source = { 0=ROM, 1=BWRAM, 2=IRAM } // destination = { 0=IRAM, 1=BWRAM } - if ((m_dma_ctrl & 0x03) == 1 && (m_dma_ctrl & 0x04) == 0x04) continue; - if ((m_dma_ctrl & 0x03) == 2 && (m_dma_ctrl & 0x04) == 0x00) continue; + if (((DCNT_SD()) == 1) && (DCNT_DD())) continue; + if (((DCNT_SD()) == 2) && (!(DCNT_DD()))) continue; - m_sa1->adjust_icount(-1); // 1 cycle per memory accessing - switch (m_dma_ctrl & 0x03) + int cycle = 1; // 1 cycle per memory access + switch (DCNT_SD()) { case 0: // ROM - if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x000000) - { - data = read_l(dma_src & 0x7fffff); - } - if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x800000) - { - data = read_h(dma_src & 0x7fffff); - } - if ((dma_src & 0xc00000) == 0xc00000) - { - data = read_h(dma_src & 0x7fffff); - } + if (bus_conflict_rom() && (cycle < 2)) // wait 1 cycle if conflict + cycle = 2; + data = rom_r(dma_src & 0xffffff); break; case 1: // BWRAM - if ((dma_src & 0x40e000) == 0x006000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - data = read_bwram<true>((m_bwram_sa1 * 0x2000) + (dma_src & 0x1fff)); - } - if ((dma_src & 0xf00000) == 0x400000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - data = read_bwram<true>(dma_src & 0xfffff); - } + if (bus_conflict_bwram() && (cycle < 4)) // wait 3 cycle if conflict + cycle = 4; + else if (cycle < 2) + cycle = 2; + data = read_bwram<true>(dma_src & 0xfffff); break; case 2: // IRAM + if (bus_conflict_iram() && (cycle < 3)) // wait 2 cycle if conflict + cycle = 3; data = read_iram(dma_src); break; } - switch (m_dma_ctrl & 0x04) + if (DCNT_DD()) // BWRAM { - case 0x00: // IRAM - write_iram(dma_dst, data); - break; - - case 0x04: // BWRAM - if ((dma_dst & 0x40e000) == 0x006000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - write_bwram((m_bwram_sa1 * 0x2000) + (dma_dst & 0x1fff), data); - } - if ((dma_dst & 0xf00000) == 0x400000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - write_bwram(dma_dst & 0xfffff, data); - } - break; + if (bus_conflict_bwram() && (cycle < 4)) // wait 3 cycle if conflict + cycle = 4; + else if (cycle < 2) + cycle = 2; + write_bwram(dma_dst & 0xfffff, data); } + else // IRAM + { + if (bus_conflict_iram() && (cycle < 3)) // wait 2 cycle if conflict + cycle = 3; + write_iram(dma_dst, data); + } + m_sa1->adjust_icount(-cycle); // progress } m_sa1_flags |= SA1_IRQ_DMA; @@ -375,30 +409,68 @@ void sns_sa1_device::dma_cctype1_transfer() void sns_sa1_device::dma_cctype2_transfer() { + const u8 bank = BIT(m_cconv2_line, 0) << 3; + const u8 bpp = 2 << (2 - m_dma_cconv_bits); + const u32 tx = BIT(m_cconv2_line, 3) << (6 - m_dma_cconv_bits); + const u32 ty = (BIT(m_cconv2_line, 0, 3) << 1); + const u32 dst_addr = (m_dst_addr & ~((1 << (7 - m_dma_cconv_bits)) - 1)) + tx + ty; + + // TODO: memory access/process cycle + for (u8 bit = 0; bit < bpp; bit++) + { + u8 byte = 0; + const offs_t plane = BIT(bit, 0) | (BIT(bit, 1, 2) << 4); + for (u8 x = 0; x < 8; x++) + byte |= BIT(m_brf_reg[bank | x], bit) << (7 - x); + + write_iram(dst_addr + plane, byte); + } + + m_cconv2_line = (m_cconv2_line + 1) & 0xf; } -template<bool SA1Read> -uint8_t sns_sa1_device::read_regs(uint32_t offset) +u8 sns_sa1_device::host_r(offs_t offset) { - uint8_t value = 0xff; + u8 value = read_open_bus(); offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs switch (offset) { case 0x100: // S-CPU Flag Read - value = (m_scpu_ctrl & 0x0f) | m_scpu_flags; + value = SCNT_CMEG() | m_scpu_flags; + break; + case 0x10e: + // SNES VC Version Code Register (R) + // value = read_open_bus(); // verified + break; + default: + logerror("S-CPU Read access to an unmapped reg (%x)", offset); break; + } + return value; +} + +u8 sns_sa1_device::read_regs(offs_t offset) +{ + u8 value = 0xff; // unverified + offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs + + switch (offset) + { case 0x101: // SA-1 Flag Read - value = (m_sa1_ctrl & 0x0f) | m_sa1_flags; + value = CCNT_SMEG() | m_sa1_flags; break; case 0x102: // H-Count Read Low - //latch counters - m_hcr = m_hcount >> 2; - m_vcr = m_vcount; - //then return h-count + if (!machine().side_effects_disabled()) + { + // latch counters + m_hcr = m_hpos; + m_vcr = m_vpos; + } + // return h-count value = (m_hcr >> 0) & 0xff; break; case 0x103: @@ -414,33 +486,33 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) value = (m_vcr >> 8) & 0xff; break; case 0x106: - // Math Result bits0-7 - value = (uint64_t)(m_math_res >> 0) & 0xff; + // Math Result bits 0-7 + value = (u64)(m_math_res >> 0) & 0xff; break; case 0x107: - // Math Result bits8-15 - value = (uint64_t)(m_math_res >> 8) & 0xff; + // Math Result bits 8-15 + value = (u64)(m_math_res >> 8) & 0xff; break; case 0x108: - // Math Result bits16-23 - value = (uint64_t)(m_math_res >> 16) & 0xff; + // Math Result bits 16-23 + value = (u64)(m_math_res >> 16) & 0xff; break; case 0x109: - // Math Result bits24-31 - value = (uint64_t)(m_math_res >> 24) & 0xff; + // Math Result bits 24-31 + value = (u64)(m_math_res >> 24) & 0xff; break; case 0x10a: - // Math Result bits32-39 - value = (uint64_t)(m_math_res >> 32) & 0xff; + // Math Result bits 32-39 + value = (u64)(m_math_res >> 32) & 0xff; break; case 0x10b: - // Math Overflow (above 40bit result) + // Math Overflow (above 40-bit result) value = m_math_overflow; break; case 0x10c: // Var-Length Read Port Low { - uint32_t data = (var_length_read<SA1Read>(m_vda + 0) << 0) | (var_length_read<SA1Read>(m_vda + 1) << 8) | (var_length_read<SA1Read>(m_vda + 2) << 16); + u32 data = (var_length_read(m_vda + 0) << 0) | (var_length_read(m_vda + 1) << 8) | (var_length_read(m_vda + 2) << 16); data >>= m_vbit; value = (data >> 0) & 0xff; } @@ -448,14 +520,14 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) case 0x10d: // Var-Length Read Port High { - uint32_t data = (var_length_read<SA1Read>(m_vda + 0) << 0) | (var_length_read<SA1Read>(m_vda + 1) << 8) | (var_length_read<SA1Read>(m_vda + 2) << 16); + u32 data = (var_length_read(m_vda + 0) << 0) | (var_length_read(m_vda + 1) << 8) | (var_length_read(m_vda + 2) << 16); data >>= m_vbit; if (!machine().side_effects_disabled()) { - if (m_drm == 1) + if (m_drm) { - //auto-increment mode + // auto-increment mode m_vbit += m_vlen; m_vda += (m_vbit >> 3); m_vbit &= 7; @@ -465,9 +537,6 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) value = (data >> 8) & 0xff; } break; - case 0x10e: - // SNES VC Version Code Register (R) - break; default: logerror("SA-1 Read access to an unmapped reg (%x)", offset); break; @@ -475,7 +544,7 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) return value; } -void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) +void sns_sa1_device::host_w(offs_t offset, u8 data) { offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs @@ -483,152 +552,197 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) { case 0x000: // SA-1 control flags -// printf("%02x to SA-1 control\n", data); - if ((BIT(data, 5)) && !(BIT(m_sa1_ctrl, 5))) + if (CCNT_SA1_CPU_RDYB() && BIT(data, 5)) // Pull up reset pin + m_sa1_reset_flag = true; + + if ((BIT(data, 5, 2) != 0) && (BIT(m_sa1_ctrl, 5, 2) == 0)) { -// printf("Engaging SA-1 reset\n"); m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + if (BIT(data, 5)) // Pull up reset pin + m_sa1_reset_flag = true; } - else if (!(BIT(data, 5)) && (BIT(m_sa1_ctrl, 5))) + else if ((BIT(data, 5, 2) == 0) && (BIT(m_sa1_ctrl, 5, 2) != 0)) { -// printf("Releasing SA-1 reset\n"); m_sa1->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); - m_sa1->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); - m_sa1->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + if (m_sa1_reset_flag && (!BIT(data, 5))) + { + m_sa1->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_sa1->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + m_sa1_reset_flag = false; + } } m_sa1_ctrl = data; - // message to S-CPU - m_scpu_ctrl &= 0xf0; - m_scpu_ctrl |= (data & 0x0f); - - if (BIT(m_sa1_ctrl, 7)) - { + if (CCNT_SA1_CPU_IRQ()) m_sa1_flags |= SA1_IRQ_SCPU; - } - if (BIT(m_sa1_ctrl, 4)) - { + + if (CCNT_SA1_CPU_NMI()) m_sa1_flags |= SA1_NMI_SCPU; - } + recalc_irqs(); break; case 0x001: - // SNES SIE 00h SNES CPU Int Enable (W) + // SNES CPU Int Enable m_scpu_sie = data; -// printf("S-CPU IE = %02x\n", data); recalc_irqs(); break; case 0x002: - // SNES SIC 00h SNES CPU Int Clear (W) + // SNES CPU Int Clear if (BIT(data, 7)) // ack IRQ from SA-1 - { m_scpu_flags &= ~SCPU_IRQ_SA1; - } + if (BIT(data, 5)) // ack character conversion IRQ - { m_scpu_flags &= ~SCPU_IRQ_CHARCONV; - } + recalc_irqs(); break; case 0x003: - // SNES CRV - SA-1 CPU Reset Vector Lsb (W) - m_sa1_reset &= 0xff00; - m_sa1_reset |= data; + // SA-1 CPU Reset Vector LSB + m_sa1_reset_vector &= 0xff00; + m_sa1_reset_vector |= data; break; case 0x004: - // SNES CRV - SA-1 CPU Reset Vector Msb (W) - m_sa1_reset &= 0x00ff; - m_sa1_reset |= (data<<8); + // SA-1 CPU Reset Vector MSB + m_sa1_reset_vector &= 0x00ff; + m_sa1_reset_vector |= (data<<8); break; case 0x005: - // SNES CNV - SA-1 CPU NMI Vector Lsb (W) - m_sa1_nmi &= 0xff00; - m_sa1_nmi |= data; + // SA-1 CPU NMI Vector LSB + m_sa1_nmi_vector &= 0xff00; + m_sa1_nmi_vector |= data; break; case 0x006: - // SNES CNV - SA-1 CPU NMI Vector Msb (W) - m_sa1_nmi &= 0x00ff; - m_sa1_nmi |= (data<<8); + // SA-1 CPU NMI Vector MSB + m_sa1_nmi_vector &= 0x00ff; + m_sa1_nmi_vector |= (data<<8); break; case 0x007: - // SNES CIV - SA-1 CPU IRQ Vector Lsb (W) - m_sa1_irq &= 0xff00; - m_sa1_irq |= data; + // SA-1 CPU IRQ Vector LSB + m_sa1_irq_vector &= 0xff00; + m_sa1_irq_vector |= data; break; case 0x008: - // SNES CIV - SA-1 CPU IRQ Vector Msb (W) - m_sa1_irq &= 0x00ff; - m_sa1_irq |= (data<<8); + // SA-1 CPU IRQ Vector MSB + m_sa1_irq_vector &= 0x00ff; + m_sa1_irq_vector |= (data<<8); + break; + case 0x020: + // Super MMC Bank C + m_bank_hi[0] = BIT(data, 7); // [00-1f][8000-ffff] is mirror of [c0-cf][0000-ffff] bank or first 1MB of ROM + m_bank_rom[0] = data & 0x07; // ROM 1MB bank for [c0-cf] + break; + case 0x021: + // Super MMC Bank D + m_bank_hi[1] = BIT(data, 7); // [20-3f][8000-ffff] is mirror of [d0-df][0000-ffff] bank or second 1MB of ROM + m_bank_rom[1] = data & 0x07; // ROM 1MB bank for [d0-df] + break; + case 0x022: + // Super MMC Bank E + m_bank_hi[2] = BIT(data, 7); // [80-9f][8000-ffff] is mirror of [e0-ef][0000-ffff] bank or third 1MB of ROM + m_bank_rom[2] = data & 0x07; // ROM 1MB bank for [e0-ef] + break; + case 0x023: + // Super MMC Bank F + m_bank_hi[3] = BIT(data, 7); // [a0-bf][8000-ffff] is mirror of [e0-ef][0000-ffff] bank or fourth 1MB of ROM + m_bank_rom[3] = data & 0x07; // ROM 1MB bank for [f0-ff] + break; + case 0x024: + // BWRAM bank from SNES side + m_bwram_snes = data & 0x1f; // max 32x8K banks + break; + case 0x026: + // enable writing to BWRAM from SNES + m_bwram_write_snes = BIT(data, 7); break; + case 0x028: + // write protected area at bottom of BWRAM + m_bwpa_sa1 = 0x100 << (data & 0x0f); + break; + case 0x029: + // enable writing to IRAM from SNES (1 bit for each 0x100 chunk) + m_iram_write_snes = data; + break; + case 0x031: // Character Conversion DMA Parameters + case 0x032: // DMA Source Device Start Address Low + case 0x033: // DMA Source Device Start Address Mid + case 0x034: // DMA Source Device Start Address High + case 0x035: // DMA Dest Device Start Address Low + case 0x036: // DMA Dest Device Start Address Mid + case 0x037: // DMA Dest Device Start Address High + shared_regs_w(offset, data); + break; + default: + logerror("S-CPU Write access to an unmapped reg (%x) with data %x", offset, data); + break; + } +} + +void sns_sa1_device::write_regs(offs_t offset, u8 data) +{ + offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs + + switch (offset) + { case 0x009: // S-CPU control flags m_scpu_ctrl = data; - if (m_scpu_ctrl & 0x80) + if (SCNT_SNESCPU_IRQ()) { m_scpu_flags |= SCPU_IRQ_SA1; -// printf("SA-1 cause S-CPU IRQ\n"); } - // message to SA-1 - m_sa1_ctrl &= 0xf0; - m_sa1_ctrl |= (data & 0x0f); - - // clear IRQ/NMI override flags in flags word + // acquire IRQ/NMI override flags from data m_scpu_flags &= ~(SCPU_IRQV_ALT|SCPU_NMIV_ALT); - - // and set them m_scpu_flags |= (data & (SCPU_IRQV_ALT|SCPU_NMIV_ALT)); recalc_irqs(); break; case 0x00a: - // SA-1 CIE 00h SA-1 CPU Int Enable (W) + // SA-1 CPU Int Enable m_sa1_sie = data; -// printf("SA-1 IE = %02x\n", data); recalc_irqs(); break; case 0x00b: - // SA-1 CIC 00h SA-1 CPU Int Clear (W) + // SA-1 CPU Int Clear if (BIT(data, 7)) - { m_sa1_flags &= ~SA1_IRQ_SCPU; - } + if (BIT(data, 6)) - { m_sa1_flags &= ~SA1_IRQ_TIMER; - } + if (BIT(data, 5)) - { m_sa1_flags &= ~SA1_IRQ_DMA; - } + if (BIT(data, 4)) - { m_sa1_flags &= ~SA1_NMI_SCPU; - } + recalc_irqs(); break; case 0x00c: - // NMI Vector Low + // SA-1 NMI Vector Low m_nmi_vector = (m_nmi_vector & 0xff00) | (data << 0); break; case 0x00d: - // NMI Vector High + // SA-1 NMI Vector High m_nmi_vector = (m_nmi_vector & 0x00ff) | (data << 8); break; case 0x00e: - // IRQ Vector Low + // SA-1 IRQ Vector Low m_irq_vector = (m_irq_vector & 0xff00) | (data << 0); break; case 0x00f: - // IRQ Vector High + // SA-1 IRQ Vector High m_irq_vector = (m_irq_vector & 0x00ff) | (data << 8); break; case 0x010: - // SA-1 TMC 00h H/V Timer Control (W) + // H/V Timer Control + m_timer_ctrl = data; break; case 0x011: - // SA-1 CTR - SA-1 CPU Timer Restart (W) + // CPU Timer Restart + m_hpos = m_vpos = 0; + m_sa1_timer->adjust(m_sa1->clocks_to_attotime(2), 0, m_sa1->clocks_to_attotime(2)); break; case 0x012: // H-Count Low @@ -646,128 +760,45 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) // V-Count High m_vcount = (m_vcount & 0x00ff) | (data << 8); break; - case 0x020: - // ROM 1MB bank for [c0-cf] - m_bank_c_hi = BIT(data, 7); - m_bank_c_rom = data & 0x07; - break; - case 0x021: - // ROM 1MB bank for [d0-df] - m_bank_d_hi = BIT(data, 7); - m_bank_d_rom = data & 0x07; - break; - case 0x022: - // ROM 1MB bank for [e0-ef] - m_bank_e_hi = BIT(data, 7); - m_bank_e_rom = data & 0x07; - break; - case 0x023: - // ROM 1MB bank for [f0-ff] - m_bank_f_hi = BIT(data, 7); - m_bank_f_rom = data & 0x07; - break; - case 0x024: - // BWRAM bank from SNES side - m_bwram_snes = data & 0x1f; // max 32x8K banks - break; case 0x025: // BWRAM bank & type from SA-1 side - m_bwram_sa1_source = BIT(data, 7); // 0 = normal, 1 = bitmap? - m_bwram_sa1 = data & 0x7f; // up to 128x8K banks here? - break; - case 0x026: - // enable writing to BWRAM from SNES - m_bwram_write_snes = BIT(data, 7); + m_bwram_sa1_source = BIT(data, 7); // 0 = normal, 1 = bitmap + m_bwram_sa1 = data & 0x7f; // up to 128x8K banks here break; case 0x027: // enable writing to BWRAM from SA-1 m_bwram_write_sa1 = BIT(data, 7); break; - case 0x028: - // write protected area at bottom of BWRAM - m_bwpa_sa1 = 0x100 * (data & 0x0f); - break; - case 0x029: - // enable writing to IRAM from SNES (1 bit for each 0x100 chunk) - m_iram_write_snes = data; - break; case 0x02a: // enable writing to IRAM from SA-1 (1 bit for each 0x100 chunk) m_iram_write_sa1 = data; break; case 0x030: - // SA-1 DCNT 00h DMA Control (W) -// printf("%02x to SA-1 DMA control\n", data); + // DMA Control (W) m_dma_ctrl = data; break; - case 0x031: - // Both CDMA 00h Character Conversion DMA Parameters (W) - m_dma_ccparam = data; - m_dma_cconv_size = (data >> 2) & 7; - if (m_dma_cconv_size > 5) m_dma_cconv_size = 5; - m_dma_cconv_bits = data & 3; - if (m_dma_cconv_bits > 2) m_dma_cconv_bits = 2; - - if (BIT(data, 7)) - m_cconv1_dma_active = false; - break; - case 0x032: - // DMA Source Device Start Address Low - m_src_addr = (m_src_addr & 0xffff00) | (data << 0); - break; - case 0x033: - // DMA Source Device Start Address Mid - m_src_addr = (m_src_addr & 0xff00ff) | (data << 8); - break; - case 0x034: - // DMA Source Device Start Address High - m_src_addr = (m_src_addr & 0x00ffff) | (data << 16); - break; - case 0x035: - // DMA Dest Device Start Address Low - m_dst_addr = (m_dst_addr & 0xffff00) | (data << 0); - break; - case 0x036: - // DMA Dest Device Start Address Mid - m_dst_addr = (m_dst_addr & 0xff00ff) | (data << 8); - if (m_dma_ctrl & 0x80) - { - if (!(m_dma_ctrl & 0x20) && !(m_dma_ctrl & 0x04)) // Normal DMA to IRAM - { - dma_transfer(); - } - - if (m_dma_ctrl & 0x20 && m_dma_ctrl & 0x10) // CC DMA Type 1 - { - dma_cctype1_transfer(); - } - } - break; - case 0x037: - // DMA Dest Device Start Address High - m_dst_addr = (m_dst_addr & 0x00ffff) | (data << 16); - if (m_dma_ctrl & 0x80) - { - if (!(m_dma_ctrl & 0x20) && m_dma_ctrl & 0x04) // Normal DMA to BWRAM - { -// printf("SA-1: normal DMA to BWRAM\n"); - dma_transfer(); - } - } + case 0x031: // Character Conversion DMA Parameters (W) + case 0x032: // DMA Source Device Start Address Low + case 0x033: // DMA Source Device Start Address Mid + case 0x034: // DMA Source Device Start Address High + case 0x035: // DMA Dest Device Start Address Low + case 0x036: // DMA Dest Device Start Address Mid + case 0x037: // DMA Dest Device Start Address High + shared_regs_w(offset, data); break; case 0x038: - // SA-1 DTC - DMA Terminal Counter Lsb (W) + // DMA Terminal Counter LSB m_dma_cnt &= 0xff00; m_dma_cnt |= data; break; case 0x039: - // SA-1 DTC - DMA Terminal Counter Msb (W) + // DMA Terminal Counter MSB m_dma_cnt &= 0x00ff; m_dma_cnt |= (data<<8); break; case 0x03f: // Format for BWRAM when mapped to bitmap - m_bwram_sa1_format = BIT(data, 7); // 0 = 4bit, 1 = 2bit + m_bwram_sa1_format = BIT(data, 7); // 0 = 4-bit, 1 = 2-bit break; case 0x040: case 0x041: @@ -787,11 +818,10 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) case 0x04f: // Bit Map Register File (2240h..224Fh) m_brf_reg[offset & 0x0f] = data; - if ((offset & 0x07) == 7 && m_dma_ctrl & 0x80) + if (((offset & 0x07) == 7) && DCNT_DMAEN()) { - if (m_dma_ctrl & 0x20 && !(m_dma_ctrl & 0x10)) // CC DMA Type 2 + if (DCNT_CDEN() && (!(DCNT_CDSEL()))) // CC DMA Type 2 { -// printf("SA-1: CC DMA type 2\n"); dma_cctype2_transfer(); } } @@ -817,27 +847,27 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) case 0x054: // Math B High m_math_b = (data << 8) | (m_math_b & 0x00ff); - // After Math B has been written, we do math + // After Math B has been written, perform the operation switch (m_math_ctlr) { - case 0: //signed multiplication - m_math_res = (int16_t)m_math_a * (int16_t)m_math_b; + case 0: // signed multiplication (5 cycles required) + m_math_res = (s16)m_math_a * (s16)m_math_b; m_math_b = 0; break; - case 1: //unsigned division + case 1: // unsigned division (5 cycles required) if (m_math_b == 0) m_math_res = 0; else { - int16_t quotient = (int16_t)m_math_a / (uint16_t)m_math_b; - uint16_t remainder = (int16_t)m_math_a % (uint16_t)m_math_b; - m_math_res = (uint64_t)((remainder << 16) | quotient); + s16 quotient = (s16)m_math_a / (u16)m_math_b; + u16 remainder = (s16)m_math_a % (u16)m_math_b; + m_math_res = (u64)((remainder << 16) | quotient); } break; - case 2: //sigma (accumulative multiplication) + case 2: // sigma (accumulative multiplication) (6 cycles required) case 3: - uint64_t acum = (int16_t)m_math_a * (int16_t)m_math_b; - uint64_t mask = 0xffffffffffU; + u64 acum = (s16)m_math_a * (s16)m_math_b; + u64 mask = 0xffffffffffU; m_math_res += acum; m_math_overflow = (m_math_res > mask) ? 0x80 : 0; m_math_res &= mask; @@ -852,9 +882,9 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) if (m_vlen == 0) m_vlen = 16; - if (m_drm == 0) + if (!m_drm) { - //fixed mode + // fixed mode m_vbit += m_vlen; m_vda += (m_vbit >> 3); m_vbit &= 7; @@ -879,69 +909,114 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) } } -uint8_t sns_sa1_device::read_iram(uint32_t offset) +void sns_sa1_device::shared_regs_w(offs_t offset, u8 data) +{ + offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs + + switch (offset) + { + case 0x031: + // Character Conversion DMA Parameters (W) + m_dma_ccparam = data; + m_dma_cconv_size = CDMA_SIZE(); + m_dma_cconv_bits = CDMA_CB(); + if (CDMA_CHDEND()) + m_cconv1_dma_active = false; + break; + case 0x032: + // DMA Source Device Start Address Low + m_src_addr = (m_src_addr & 0xffff00) | (data << 0); + break; + case 0x033: + // DMA Source Device Start Address Mid + m_src_addr = (m_src_addr & 0xff00ff) | (data << 8); + break; + case 0x034: + // DMA Source Device Start Address High + m_src_addr = (m_src_addr & 0x00ffff) | (data << 16); + break; + case 0x035: + // DMA Dest Device Start Address Low + m_dst_addr = (m_dst_addr & 0xffff00) | (data << 0); + break; + case 0x036: + // DMA Dest Device Start Address Mid + m_dst_addr = (m_dst_addr & 0xff00ff) | (data << 8); + if (DCNT_DMAEN()) + { + if ((!(DCNT_CDEN())) && (!(DCNT_DD()))) // Normal DMA to IRAM + dma_transfer(); + + if (DCNT_CDEN() && DCNT_CDSEL()) // CC DMA Type 1 + dma_cctype1_transfer(); + } + break; + case 0x037: + // DMA Dest Device Start Address High + m_dst_addr = (m_dst_addr & 0x00ffff) | (data << 16); + if (DCNT_DMAEN()) + { + if ((!(DCNT_CDEN())) && DCNT_DD()) // Normal DMA to BWRAM + { + dma_transfer(); + } + } + break; + default: + logerror("SA-1 Write access to an unmapped reg (%x) with data %x", offset, data); + break; + } +} + +u8 sns_sa1_device::read_iram(offs_t offset) { return m_internal_ram[offset & 0x7ff]; } -void sns_sa1_device::write_iram(uint32_t offset, uint8_t data) +void sns_sa1_device::write_iram(offs_t offset, u8 data) { m_internal_ram[offset & 0x7ff] = data; } -uint8_t sns_sa1_device::read_cconv1_dma(uint32_t offset) +u8 sns_sa1_device::read_cconv1_dma(offs_t offset) { - uint32_t store_mask = (1 << (6 - m_dma_cconv_bits)) - 1; + const u32 store_mask = (1 << (6 - m_dma_cconv_bits)) - 1; if (!machine().side_effects_disabled()) { if ((offset & store_mask) == 0) { - uint32_t bpp = 2 << (2 - m_dma_cconv_bits); - uint32_t tile_stride = (8 << m_dma_cconv_size) >> m_dma_cconv_bits; - uint32_t bwram_addr_mask = m_nvram.size() - 1; - uint32_t tile = ((offset - m_src_addr) & bwram_addr_mask) >> (6 - m_dma_cconv_bits); - uint32_t ty = (tile >> m_dma_cconv_size); - uint32_t tx = tile & ((1 << m_dma_cconv_size) - 1); - uint32_t bwram_src = m_src_addr + ty * 8 * tile_stride + tx * bpp; - - for (uint32_t y = 0; y < 8; y++) + const u32 bpp = 2 << (2 - m_dma_cconv_bits); + const u32 tile_stride = (8 << m_dma_cconv_size) >> m_dma_cconv_bits; + const u32 bwram_addr_mask = m_nvram.size() - 1; + const u32 tile = ((offset - m_src_addr) & bwram_addr_mask) >> (6 - m_dma_cconv_bits); + const u32 ty = (tile >> m_dma_cconv_size); + const u32 tx = tile & ((1 << m_dma_cconv_size) - 1); + u32 bwram_src = m_src_addr + ty * 8 * tile_stride + tx * bpp; + + // TODO: memory access/process cycle + for (u32 y = 0; y < 8; y++) { - uint64_t raw_pixels = 0; - for (uint64_t bit = 0; bit < bpp; bit++) - { - raw_pixels |= (uint64_t)m_nvram[(bwram_src + bit) & bwram_addr_mask] << (bit << 3); - } + u64 raw_pixels = 0; + for (u64 bit = 0; bit < bpp; bit++) + raw_pixels |= (u64)m_nvram[(bwram_src + bit) & bwram_addr_mask] << (bit << 3); + bwram_src += tile_stride; - uint8_t linear[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - for (uint32_t x = 0; x < 8; x++) + u8 linear[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + for (u8 x = 0; x < 8; x++) { - linear[0] |= BIT(raw_pixels, 0) << (7 - x); - linear[1] |= BIT(raw_pixels, 1) << (7 - x); - if (m_dma_cconv_bits == 2) - { - raw_pixels >>= 2; - continue; - } - linear[2] |= BIT(raw_pixels, 2) << (7 - x); - linear[3] |= BIT(raw_pixels, 3) << (7 - x); - if (m_dma_cconv_bits == 1) - { - raw_pixels >>= 4; - continue; - } - linear[4] |= BIT(raw_pixels, 4) << (7 - x); - linear[5] |= BIT(raw_pixels, 5) << (7 - x); - linear[6] |= BIT(raw_pixels, 6) << (7 - x); - linear[7] |= BIT(raw_pixels, 7) << (7 - x); - raw_pixels >>= 8; + for (u8 bit = 0; bit < bpp; bit++) + linear[bit] |= BIT(raw_pixels, bit) << (7 - x); + + raw_pixels >>= bpp; } - for (uint32_t byte = 0; byte < bpp; byte++) + const u32 dy = (y << 1); + for (u8 byte = 0; byte < bpp; byte++) { - uint32_t dst_addr = m_dst_addr + (y << 1) + ((byte & 6) << 3) + (byte & 1); - write_iram(dst_addr, linear[byte]); + const u32 plane = BIT(byte, 0) | (BIT(byte, 1, 2) << 4); + write_iram(m_dst_addr + dy + plane, linear[byte]); } } } @@ -951,71 +1026,72 @@ uint8_t sns_sa1_device::read_cconv1_dma(uint32_t offset) } template<bool SA1Read> -uint8_t sns_sa1_device::read_bwram(uint32_t offset, bool bitmap) +u8 sns_sa1_device::read_bwram(offs_t offset, bool bitmap) { - int shift; - uint8_t mask; - if (m_nvram.empty()) return 0xff; // this should probably never happen, or are there SA-1 games with no BWRAM? if (m_cconv1_dma_active && !SA1Read) return read_cconv1_dma(offset); + const offs_t bwram_addr_mask = (m_nvram.size() - 1); if (!bitmap) - return m_nvram[offset & (m_nvram.size() - 1)]; + return m_nvram[offset & bwram_addr_mask]; // Bitmap BWRAM + u8 shift, mask; + if (m_bwram_sa1_format) { - // 2bits mode + // 2-bit mode shift = ((offset & 3) << 1); mask = 0x03; offset >>= 2; } else { - // 4bits mode + // 4-bit mode shift = ((offset & 1) << 2); mask = 0x0f; offset >>= 1; } // only return the correct bits - return (m_nvram[offset & (m_nvram.size() - 1)] >> shift) & mask; + return (m_nvram[offset & bwram_addr_mask] >> shift) & mask; } -void sns_sa1_device::write_bwram(uint32_t offset, uint8_t data, bool bitmap) +void sns_sa1_device::write_bwram(offs_t offset, u8 data, bool bitmap) { - uint8_t mask; - if (m_nvram.empty()) return; // this should probably never happen, or are there SA-1 games with no BWRAM? + const offs_t bwram_addr_mask = (m_nvram.size() - 1); if (!bitmap) { - m_nvram[offset & (m_nvram.size() - 1)] = data; + m_nvram[offset & bwram_addr_mask] = data; return; } // Bitmap BWRAM + u8 mask; + if (m_bwram_sa1_format) { - // 2bits mode + // 2-bit mode data = (data & 0x03) << ((offset & 3) << 1); mask = 0x03 << ((offset & 3) << 1); offset >>= 2; } else { - // 4bits mode + // 4-bit mode data = (data & 0x0f) << ((offset & 1) << 2); mask = 0x0f << ((offset & 1) << 2); offset >>= 1; } // only change the correct bits, keeping the rest untouched - m_nvram[offset & (m_nvram.size() - 1)] = (m_nvram[offset & (m_nvram.size() - 1)] & ~mask) | data; + m_nvram[offset & bwram_addr_mask] = (m_nvram[offset & bwram_addr_mask] & ~mask) | data; } @@ -1025,97 +1101,67 @@ void sns_sa1_device::write_bwram(uint32_t offset, uint8_t data, bool bitmap) -------------------------------------------------*/ -uint8_t sns_sa1_device::read_l(offs_t offset) +u8 sns_sa1_device::rom_r(offs_t offset) { - int bank; - - if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff; - if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff; - if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff; - if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff; + u8 ret = 0; // TODO: unverified & unknown value - // ROM is mapped to [00-3f][8000-ffff] only here - if (offset < 0x200000) + if ((offset & 0xc00000) == 0xc00000) // [c0-ff][0000-ffff] + ret = m_rom[(rom_bank_map[(m_bank_rom[BIT(offset, 20, 2)] << 5) | BIT(offset, 15, 5)] << 15) | (offset & 0x7fff)]; + else if ((offset & 0x408000) == 0x008000) // [00-3f][8000-ffff], [80-bf][8000-ffff] { - if (!m_bank_c_hi) // when HiROM mapping is disabled, we always access first 1MB here - bank = (offset / 0x10000) + 0x00; - else // when HiROM mapping is enabled, we mirror [c0-cf][0000-ffff] bank - bank = (offset / 0x10000) + (m_bank_c_rom * 0x20); + const u8 slot = (BIT(offset, 23) << 1) | BIT(offset, 21); + u8 bank; // 256 banks (64 Mbit limited) - bank &= 0xff; - return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; - } - else if (offset < 0x400000) - { - offset -= 0x200000; - if (!m_bank_d_hi) // when HiROM mapping is disabled, we always access second 1MB here - bank = (offset / 0x10000) + 0x20; - else // when HiROM mapping is enabled, we mirror [d0-df][0000-ffff] bank - bank = (offset / 0x10000) + (m_bank_d_rom * 0x20); - - bank &= 0xff; - return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + if (!m_bank_hi[slot]) // when HiROM mapping is disabled, we always access each 1MB here + bank = BIT(offset, 16, 5) | (slot << 5); + else // when HiROM mapping is enabled, we mirror [(cx,dx,ex,fx)][0000-ffff] bank + bank = BIT(offset, 16, 5) | (m_bank_rom[slot] << 5); + + ret = m_rom[(rom_bank_map[bank] << 15) | (offset & 0x7fff)]; } + return ret; +} + +u8 sns_sa1_device::read_l(offs_t offset) +{ + if (offset == 0xffea && SCNT_SNESCPU_NVSW()) return (m_nmi_vector >> 0) & 0xff; + if (offset == 0xffeb && SCNT_SNESCPU_NVSW()) return (m_nmi_vector >> 8) & 0xff; + if (offset == 0xffee && SCNT_SNESCPU_IVSW()) return (m_irq_vector >> 0) & 0xff; + if (offset == 0xffef && SCNT_SNESCPU_IVSW()) return (m_irq_vector >> 8) & 0xff; + + // ROM is mapped to [00-3f][8000-ffff] only here + if (offset < 0x400000) + return rom_r(offset); else return 0; // this should not happen (the driver should only call read_l in the above case) } -uint8_t sns_sa1_device::read_h(offs_t offset) +u8 sns_sa1_device::read_h(offs_t offset) { - int bank; - // ROM is mapped to [80-bf][8000-ffff] & [c0-ff][0000-ffff] - if (offset < 0x200000) - { - if (!m_bank_e_hi) // when HiROM mapping is disabled, we always access third 1MB here - bank = (offset / 0x10000) + 0x40; - else // when HiROM mapping is enabled, we mirror [e0-ef][0000-ffff] bank - bank = (offset / 0x10000) + (m_bank_e_rom * 0x20); - - bank &= 0xff; - return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; - } - else if (offset < 0x400000) - { - offset -= 0x200000; - if (!m_bank_f_hi) // when HiROM mapping is disabled, we always access fourth 1MB here - bank = (offset / 0x10000) + 0x60; - else // when HiROM mapping is enabled, we mirror [f0-ff][0000-ffff] bank - bank = (offset / 0x10000) + (m_bank_f_rom * 0x20); - - bank &= 0xff; - return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; - } - else if (offset < 0x500000) - return m_rom[rom_bank_map[(m_bank_c_rom * 0x20) + ((offset - 0x400000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; - else if (offset < 0x600000) - return m_rom[rom_bank_map[(m_bank_d_rom * 0x20) + ((offset - 0x500000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; - else if (offset < 0x700000) - return m_rom[rom_bank_map[(m_bank_e_rom * 0x20) + ((offset - 0x600000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; - else - return m_rom[rom_bank_map[(m_bank_f_rom * 0x20) + ((offset - 0x700000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; + return rom_r(offset | 0x800000); } -void sns_sa1_device::write_l(offs_t offset, uint8_t data) +void sns_sa1_device::write_l(offs_t offset, u8 data) { } -void sns_sa1_device::write_h(offs_t offset, uint8_t data) +void sns_sa1_device::write_h(offs_t offset, u8 data) { } -uint8_t sns_sa1_device::chip_read(offs_t offset) +u8 sns_sa1_device::chip_read(offs_t offset) { - uint16_t address = offset & 0xffff; + u16 address = offset & 0xffff; if (offset < 0x400000 && address >= 0x2200 && address < 0x2400) - return read_regs<false>(address & 0x1ff); // SA-1 Regs + return host_r(address & 0x1ff); // SA-1 Regs if (offset < 0x400000 && address >= 0x3000 && address < 0x3800) - return read_iram(address & 0x7ff); // Internal SA-1 RAM (2K) + return read_iram(address & 0x7ff); if (offset < 0x400000 && address >= 0x6000 && address < 0x8000) - return read_bwram<false>((m_bwram_snes * 0x2000) + (offset & 0x1fff)); // SA-1 BWRAM + return read_bwram<false>((m_bwram_snes * 0x2000) + (offset & 0x1fff)); if (offset >= 0x400000 && offset < 0x500000) return read_bwram<false>(offset & 0xfffff); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored) @@ -1124,18 +1170,21 @@ uint8_t sns_sa1_device::chip_read(offs_t offset) } -void sns_sa1_device::chip_write(offs_t offset, uint8_t data) +void sns_sa1_device::chip_write(offs_t offset, u8 data) { - uint16_t address = offset & 0xffff; + u16 address = offset & 0xffff; if (offset < 0x400000 && address >= 0x2200 && address < 0x2400) - write_regs(address & 0x1ff, data); // SA-1 Regs + host_w(address & 0x1ff, data); // SA-1 Regs if (offset < 0x400000 && address >= 0x3000 && address < 0x3800) - write_iram(address & 0x7ff, data); // Internal SA-1 RAM (2K) + { + if (BIT(m_iram_write_snes, BIT(address, 8, 3))) + write_iram(address & 0x7ff, data); + } if (offset < 0x400000 && address >= 0x6000 && address < 0x8000) - write_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff), data); // SA-1 BWRAM + write_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff), data); if (offset >= 0x400000 && offset < 0x500000) write_bwram(offset & 0xfffff, data); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored) @@ -1150,132 +1199,162 @@ void sns_sa1_device::chip_write(offs_t offset, uint8_t data) // I/O regs or WRAM, and there are a few additional accesses to IRAM (in [00-3f][0000-07ff]) // and to BWRAM (in [60-6f][0000-ffff], so-called bitmap mode) -uint8_t sns_sa1_device::sa1_hi_r(offs_t offset) +u8 sns_sa1_device::sa1_rom_r(offs_t offset) +{ + if (bus_conflict_rom()) + m_sa1->adjust_icount(-1); // wait 1 cycle + + return rom_r(offset); +} + +u8 sns_sa1_device::sa1_iram_r(offs_t offset) +{ + if (bus_conflict_iram()) + m_sa1->adjust_icount(-2); // wait 2 cycles + return read_iram(offset & 0x7ff); +} + +void sns_sa1_device::sa1_iram_w(offs_t offset, u8 data) +{ + if (bus_conflict_iram()) + m_sa1->adjust_icount(-2); // wait 2 cycles + + if (BIT(m_iram_write_sa1, BIT(offset, 8, 3))) + write_iram(offset & 0x7ff, data); +} + +u8 sns_sa1_device::sa1_bwram_r(offs_t offset, bool bitmap) +{ + if (bus_conflict_bwram()) + m_sa1->adjust_icount(-3); // wait 3 cycles + else + m_sa1->adjust_icount(-1); // wait 1 cycle + + return read_bwram<true>(offset, bitmap); +} + +void sns_sa1_device::sa1_bwram_w(offs_t offset, u8 data, bool bitmap) +{ + if (bus_conflict_bwram()) + m_sa1->adjust_icount(-3); // wait 3 cycles + else + m_sa1->adjust_icount(-1); // wait 1 cycle + + // TODO: write protectable? + write_bwram(offset, data, bitmap); +} + +u8 sns_sa1_device::sa1_hi_r(offs_t offset) { - uint16_t address = offset & 0xffff; + u16 address = offset & 0xffff; if (offset < 0x400000) { if (address < 0x6000) { if (address < 0x0800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); else if (address >= 0x2200 && address < 0x2400) - return read_regs<true>(offset & 0x1ff); // SA-1 Regs + return read_regs(offset & 0x1ff); else if (address >= 0x3000 && address < 0x3800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); } else if (address < 0x8000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram<true>((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), m_bwram_sa1_source); // SA-1 BWRAM - } + return sa1_bwram_r((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), m_bwram_sa1_source); else - return read_h(offset); // ROM + return sa1_rom_r(offset | 0x800000); - return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) + return 0xff; // TOOD: Maybe open bus. Check if same as the main system or different (currently not accessible from carts anyway). } else - return read_h(offset); // ROM + return sa1_rom_r(offset | 0xc00000); } -uint8_t sns_sa1_device::sa1_lo_r(offs_t offset) +u8 sns_sa1_device::sa1_lo_r(offs_t offset) { - uint16_t address = offset & 0xffff; + u16 address = offset & 0xffff; if (offset < 0x400000) { if (address < 0x6000) { if (address < 0x0800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); else if (address >= 0x2200 && address < 0x2400) - return read_regs<true>(offset & 0x1ff); // SA-1 Regs + return read_regs(offset & 0x1ff); else if (address >= 0x3000 && address < 0x3800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); } else if (address < 0x8000) + return sa1_bwram_r((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), m_bwram_sa1_source); // SA-1 BWRAM + else { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram<true>((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), m_bwram_sa1_source); // SA-1 BWRAM - } - else if (offset == 0xffee) - { - return m_sa1_irq & 0xff; - } - else if (offset == 0xffef) - { - return m_sa1_irq>>8; - } - else if (offset == 0xffea) - { - return m_sa1_nmi & 0xff; - } - else if (offset == 0xffeb) - { - return m_sa1_nmi>>8; - } - else if (offset == 0xfffc) - { - return m_sa1_reset & 0xff; - } - else if (offset == 0xfffd) - { - return m_sa1_reset>>8; + if (bus_conflict_rom()) + m_sa1->adjust_icount(-1); // wait 1 cycle + + if (offset == 0xffee) + { + return m_sa1_irq_vector & 0xff; + } + else if (offset == 0xffef) + { + return m_sa1_irq_vector >> 8; + } + else if (offset == 0xffea) + { + return m_sa1_nmi_vector & 0xff; + } + else if (offset == 0xffeb) + { + return m_sa1_nmi_vector >> 8; + } + else if (offset == 0xfffc) + { + return m_sa1_reset_vector & 0xff; + } + else if (offset == 0xfffd) + { + return m_sa1_reset_vector >> 8; + } + else + return rom_r(offset); } - else - return read_l(offset); // ROM - return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) + return 0xff; // TOOD: Maybe open bus. Check if same as the main system or different (currently not accessible from carts anyway). } else if (offset < 0x500000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram<true>(offset & 0xfffff, false); // SA-1 BWRAM (not mirrored above!) - } + return sa1_bwram_r(offset & 0xfffff, false); // SA-1 BWRAM (not mirrored above) else if (offset >= 0x600000 && offset < 0x700000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram<true>(offset & 0xfffff, true); // SA-1 BWRAM Bitmap mode - } + return sa1_bwram_r(offset & 0xfffff, true); // SA-1 BWRAM Bitmap mode else - return 0xff; // nothing should be mapped here, so maybe open bus? + return 0xff; // nothing should be mapped here, so maybe open bus } -void sns_sa1_device::sa1_hi_w(offs_t offset, uint8_t data) +void sns_sa1_device::sa1_hi_w(offs_t offset, u8 data) { - uint16_t address = offset & 0xffff; + u16 address = offset & 0xffff; if (offset < 0x400000) { if (address < 0x6000) { if (address < 0x0800) - write_iram(offset, data); // Internal SA-1 RAM (2K) + sa1_iram_w(offset, data); else if (address >= 0x2200 && address < 0x2400) - write_regs(offset & 0x1ff, data); // SA-1 Regs + write_regs(offset & 0x1ff, data); else if (address >= 0x3000 && address < 0x3800) - write_iram(offset, data); // Internal SA-1 RAM (2K) + sa1_iram_w(offset, data); } else if (address < 0x8000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - write_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), data, m_bwram_sa1_source); // SA-1 BWRAM - } + sa1_bwram_w((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), data, m_bwram_sa1_source); } } -void sns_sa1_device::sa1_lo_w(offs_t offset, uint8_t data) +void sns_sa1_device::sa1_lo_w(offs_t offset, u8 data) { if (offset >= 0x400000 && offset < 0x500000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - write_bwram(offset & 0xfffff, data, false); // SA-1 BWRAM (not mirrored above!) - } + sa1_bwram_w(offset & 0xfffff, data, false); // SA-1 BWRAM (not mirrored above) else if (offset >= 0x600000 && offset < 0x700000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - write_bwram(offset & 0xfffff, data, true); // SA-1 BWRAM Bitmap mode - } + sa1_bwram_w(offset & 0xfffff, data, true); // SA-1 BWRAM Bitmap mode else sa1_hi_w(offset, data); } |