diff --git a/src/devices/bus/snes/sa1.cpp b/src/devices/bus/snes/sa1.cpp index b650a76c5ea..dffdba37ca8 100644 --- a/src/devices/bus/snes/sa1.cpp +++ b/src/devices/bus/snes/sa1.cpp @@ -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 ever protect either, so it's not implemented for the moment) - almost everything CPU related! + - Bus conflict (also seen: https://github.com/VitorVilela7/SnesSpeedTest) Compatibility: asahishi: plays OK @@ -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(0x800); + m_sa1_timer = timer_alloc(TIMER_SA1); + 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,69 @@ 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? m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + // timer is run parallely with CPUs + m_sa1_timer->adjust(m_sa1->clocks_to_attotime(2), 0, m_sa1->clocks_to_attotime(2)); } +void sns_sa1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SA1: + 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(); + } + } + break; + // Math & DMA timer here? + default: + throw emu_fatalerror("Unknown id in sns_sa1_device::device_timer"); + } +} /*------------------------------------------------- mapper specific handlers @@ -218,31 +288,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); - } } @@ -253,16 +311,16 @@ void sns_sa1_device::recalc_irqs() // handle this separately to avoid accessing recursively the regs? -template -uint8_t sns_sa1_device::var_length_read(uint32_t offset) +u8 sns_sa1_device::var_length_read(offs_t offset) { + // TODO: memory accessing 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 +333,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((m_bwram_snes * 0x2000) + (offset & 0x1fff)); + return read_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff)); if ((offset & 0xf00000) == 0x400000) //$40-4f:0000-ffff - return read_bwram(offset & 0xfffff); + return read_bwram(offset & 0xfffff); if ((offset & 0x40f800) == 0x000000) //$00-3f|80-bf:0000-07ff return read_iram(offset); @@ -295,71 +353,55 @@ void sns_sa1_device::dma_transfer() 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; // 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 accessing + 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((m_bwram_sa1 * 0x2000) + (dma_src & 0x1fff)); - } - if ((dma_src & 0xf00000) == 0x400000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - data = read_bwram(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(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,29 +417,67 @@ 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 -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; + if (!machine().side_effects_disabled()) + { + //latch counters + m_hcr = m_hpos; + m_vcr = m_vpos; + } //then return h-count value = (m_hcr >> 0) & 0xff; break; @@ -415,23 +495,23 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) break; case 0x106: // Math Result bits0-7 - value = (uint64_t)(m_math_res >> 0) & 0xff; + value = (u64)(m_math_res >> 0) & 0xff; break; case 0x107: // Math Result bits8-15 - value = (uint64_t)(m_math_res >> 8) & 0xff; + value = (u64)(m_math_res >> 8) & 0xff; break; case 0x108: // Math Result bits16-23 - value = (uint64_t)(m_math_res >> 16) & 0xff; + value = (u64)(m_math_res >> 16) & 0xff; break; case 0x109: // Math Result bits24-31 - value = (uint64_t)(m_math_res >> 24) & 0xff; + value = (u64)(m_math_res >> 24) & 0xff; break; case 0x10a: // Math Result bits32-39 - value = (uint64_t)(m_math_res >> 32) & 0xff; + value = (u64)(m_math_res >> 32) & 0xff; break; case 0x10b: // Math Overflow (above 40bit result) @@ -440,7 +520,7 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) case 0x10c: // Var-Length Read Port Low { - uint32_t data = (var_length_read(m_vda + 0) << 0) | (var_length_read(m_vda + 1) << 8) | (var_length_read(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,12 +528,12 @@ uint8_t sns_sa1_device::read_regs(uint32_t offset) case 0x10d: // Var-Length Read Port High { - uint32_t data = (var_length_read(m_vda + 0) << 0) | (var_length_read(m_vda + 1) << 8) | (var_length_read(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 m_vbit += m_vlen; @@ -465,9 +545,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 +552,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 @@ -484,33 +561,36 @@ 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: @@ -522,58 +602,109 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) case 0x002: // SNES SIC 00h SNES CPU Int Clear (W) 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; + 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); + 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; + 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); + 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; + 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); + m_sa1_irq_vector &= 0x00ff; + m_sa1_irq_vector |= (data<<8); break; + case 0x020: + // SNES CXB - Super MMC Bank C (W) + 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: + // SNES DXB - Super MMC Bank D (W) + 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: + // SNES EXB - Super MMC Bank E (W) + 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: + // SNES FXB - Super MMC Bank F (W) + 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: // Both CDMA 00h 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; + 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 m_scpu_flags &= ~(SCPU_IRQV_ALT|SCPU_NMIV_ALT); @@ -591,21 +722,17 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) case 0x00b: // SA-1 CIC 00h SA-1 CPU Int Clear (W) 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: @@ -626,9 +753,12 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) break; case 0x010: // SA-1 TMC 00h H/V Timer Control (W) + m_timer_ctrl = data; break; case 0x011: // SA-1 CTR - SA-1 CPU Timer Restart (W) + 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,51 +776,15 @@ 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); - 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; @@ -700,60 +794,14 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) // printf("%02x to SA-1 DMA control\n", data); 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: // Both CDMA 00h 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) @@ -787,9 +835,9 @@ 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(); @@ -820,24 +868,24 @@ void sns_sa1_device::write_regs(uint32_t offset, uint8_t data) // After Math B has been written, we do math 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 cycle 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 cycle 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 cycle 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,7 +900,7 @@ 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 m_vbit += m_vlen; @@ -879,69 +927,115 @@ 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: + // Both CDMA 00h 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 + { +// printf("SA-1: normal DMA to BWRAM\n"); + 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; + 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; - for (uint32_t y = 0; y < 8; y++) + // 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,21 +1045,21 @@ uint8_t sns_sa1_device::read_cconv1_dma(uint32_t offset) } template -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 @@ -982,23 +1076,24 @@ uint8_t sns_sa1_device::read_bwram(uint32_t offset, bool bitmap) } // 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 @@ -1015,7 +1110,7 @@ void sns_sa1_device::write_bwram(uint32_t offset, uint8_t data, bool bitmap) } // 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,91 +1120,61 @@ 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; + u8 ret = 0; // TODO: unverified & unknown value - 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 & 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] + { + const u8 slot = (BIT(offset, 23) << 1) | BIT(offset, 21); + u8 bank; // 256 banks (64 Mbit limited) + + 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 < 0x200000) - { - 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); - - 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 (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(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) @@ -1124,15 +1189,18 @@ 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); // Internal SA-1 RAM (2K) + } if (offset < 0x400000 && address >= 0x6000 && address < 0x8000) write_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff), data); // SA-1 BWRAM @@ -1150,132 +1218,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) { - uint16_t address = offset & 0xffff; + if (bus_conflict_rom()) // bus conflict? + 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()) // bus conflict? + m_sa1->adjust_icount(-2); // wait 2 cycle + return read_iram(offset & 0x7ff); +} + +void sns_sa1_device::sa1_iram_w(offs_t offset, u8 data) +{ + if (bus_conflict_iram()) // bus conflict? + m_sa1->adjust_icount(-2); // wait 2 cycle + + if (BIT(m_iram_write_sa1, BIT(offset, 8, 3))) + write_iram(offset & 0x7ff, data); // Internal SA-1 RAM (2K) +} + +u8 sns_sa1_device::sa1_bwram_r(offs_t offset, bool bitmap) +{ + if (bus_conflict_bwram()) // bus conflict? + m_sa1->adjust_icount(-3); // wait 3 cycle + else + m_sa1->adjust_icount(-1); // wait 1 cycle + + return read_bwram(offset, bitmap); +} + +void sns_sa1_device::sa1_bwram_w(offs_t offset, u8 data, bool bitmap) +{ + if (bus_conflict_bwram()) // bus conflict? + m_sa1->adjust_icount(-3); // wait 3 cycle + 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) +{ + 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); // Internal SA-1 RAM (2K) else if (address >= 0x2200 && address < 0x2400) - return read_regs(offset & 0x1ff); // SA-1 Regs + return read_regs(offset & 0x1ff); // SA-1 Regs else if (address >= 0x3000 && address < 0x3800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); // Internal SA-1 RAM (2K) } else if (address < 0x8000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram((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); // SA-1 BWRAM else - return read_h(offset); // ROM + return sa1_rom_r(offset | 0x800000); // ROM return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) } else - return read_h(offset); // ROM + return sa1_rom_r(offset | 0xc00000); // ROM } -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); // Internal SA-1 RAM (2K) else if (address >= 0x2200 && address < 0x2400) - return read_regs(offset & 0x1ff); // SA-1 Regs + return read_regs(offset & 0x1ff); // SA-1 Regs else if (address >= 0x3000 && address < 0x3800) - return read_iram(offset); // Internal SA-1 RAM (2K) + return sa1_iram_r(offset); // Internal SA-1 RAM (2K) } else if (address < 0x8000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram((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; - } + return sa1_bwram_r((m_bwram_sa1 * 0x2000) + (offset & 0x1fff), m_bwram_sa1_source); // SA-1 BWRAM else - return read_l(offset); // ROM + { + if (bus_conflict_rom()) // bus conflict? + 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); // ROM + } return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) } else if (offset < 0x500000) - { - m_sa1->adjust_icount(-1); // wait 1 cycle - return read_bwram(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(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? } -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); // Internal SA-1 RAM (2K) else if (address >= 0x2200 && address < 0x2400) write_regs(offset & 0x1ff, data); // SA-1 Regs else if (address >= 0x3000 && address < 0x3800) - write_iram(offset, data); // Internal SA-1 RAM (2K) + sa1_iram_w(offset, data); // Internal SA-1 RAM (2K) } 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); // SA-1 BWRAM } } -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); } diff --git a/src/devices/bus/snes/sa1.h b/src/devices/bus/snes/sa1.h index baff8561078..8126e11c247 100644 --- a/src/devices/bus/snes/sa1.h +++ b/src/devices/bus/snes/sa1.h @@ -7,6 +7,7 @@ #include "snes_slot.h" #include "cpu/g65816/g65816.h" +#include // ======================> sns_sa1_device @@ -16,108 +17,169 @@ class sns_sa1_device : public device_t, { public: // construction/destruction - sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: + static const device_timer_id TIMER_SA1 = 0; // SA-1 internal timer (18 bit linear timer or HV timer) + // device-level overrides virtual void device_start() override; virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; // reading and writing - virtual uint8_t read_l(offs_t offset) override; - virtual uint8_t read_h(offs_t offset) override; - virtual void write_l(offs_t offset, uint8_t data) override; - virtual void write_h(offs_t offset, uint8_t data) override; + virtual u8 read_l(offs_t offset) override; + virtual u8 read_h(offs_t offset) override; + virtual void write_l(offs_t offset, u8 data) override; + virtual void write_h(offs_t offset, u8 data) override; // additional reading and writing - virtual uint8_t chip_read(offs_t offset) override; - virtual void chip_write(offs_t offset, uint8_t data) override; + virtual u8 chip_read(offs_t offset) override; + virtual void chip_write(offs_t offset, u8 data) override; private: - template uint8_t var_length_read(uint32_t offset); + u8 var_length_read(offs_t offset); void dma_transfer(); void dma_cctype1_transfer(); void dma_cctype2_transfer(); - template uint8_t read_regs(uint32_t offset); - uint8_t read_iram(uint32_t offset); - template uint8_t read_bwram(uint32_t offset, bool bitmap = false); - uint8_t read_cconv1_dma(uint32_t offset); - void write_regs(uint32_t offset, uint8_t data); - void write_iram(uint32_t offset, uint8_t data); - void write_bwram(uint32_t offset, uint8_t data, bool bitmap = false); + u8 host_r(offs_t offset); + void host_w(offs_t offset, u8 data); + void shared_regs_w(offs_t offset, u8 data); + + u8 read_regs(offs_t offset); + u8 read_iram(offs_t offset); + template u8 read_bwram(offs_t offset, bool bitmap = false); + u8 read_cconv1_dma(offs_t offset); + void write_regs(offs_t offset, u8 data); + void write_iram(offs_t offset, u8 data); + void write_bwram(offs_t offset, u8 data, bool bitmap = false); void recalc_irqs(); - required_device m_sa1; + u8 rom_r(offs_t offset); + u8 sa1_rom_r(offs_t offset); - uint8_t m_internal_ram[0x800]; + u8 sa1_iram_r(offs_t offset); + void sa1_iram_w(offs_t offset, u8 data); + + u8 sa1_bwram_r(offs_t offset, bool bitmap = false); + void sa1_bwram_w(offs_t offset, u8 data, bool bitmap = false); + + required_device m_sa1; + emu_timer *m_sa1_timer; + + std::unique_ptr m_internal_ram; + + // bus conflict related: + // ROM: [00-3f][8000-ffff], [80-bf][8000-ffff], [c0-ff][0000-ffff] + // IRAM: [00-3f][3000-38ff], [80-bf][3000-38ff] + // BWRAM: [00-3f][6000-7fff], [40-4f][0000-ffff], [80-bf][6000-7fff] + inline const bool bus_conflict_rom() { return ((address_r() & 0x408000) == 0x008000) || ((address_r() & 0xc00000) == 0xc00000); } + inline const bool bus_conflict_iram() { return ((address_r() & 0x40f800) == 0x003000); } + inline const bool bus_conflict_bwram() { return ((address_r() & 0x40e000) == 0x006000) || ((address_r() & 0xf00000) == 0x400000); } // register related // $2200 - uint8_t m_sa1_ctrl; + u8 m_sa1_ctrl; + bool m_sa1_reset_flag; + // SA-1 CPU Control (CCNT) + inline const bool CCNT_SA1_CPU_IRQ() { return BIT(m_sa1_ctrl, 7); } // SA-1 CPU IRQ (from SNES CPU) + inline const bool CCNT_SA1_CPU_RDYB() { return BIT(m_sa1_ctrl, 6); } // SA-1 CPU ready + inline const bool CCNT_SA1_CPU_RESB() { return BIT(m_sa1_ctrl, 5); } // SA-1 CPU reset + inline const bool CCNT_SA1_CPU_NMI() { return BIT(m_sa1_ctrl, 4); } // SA-1 CPU NMI (from SNES CPU) + inline const u8 CCNT_SMEG() { return BIT(m_sa1_ctrl, 0, 4); } // Message from SNES CPU to SA-1 CPU + inline const bool sa1_halted() { return (CCNT_SA1_CPU_RDYB() || CCNT_SA1_CPU_RESB()); } // SA-1 is halted? // $2201 - uint8_t m_scpu_sie; + u8 m_scpu_sie; // $2203-$2208 - uint16_t m_sa1_reset, m_sa1_nmi, m_sa1_irq; + u16 m_sa1_reset_vector, m_sa1_nmi_vector, m_sa1_irq_vector; // $2209 - uint8_t m_scpu_ctrl; + u8 m_scpu_ctrl; + // SNES CPU Control (SCNT) + inline const bool SCNT_SNESCPU_IRQ() { return BIT(m_scpu_ctrl, 7); } // IRQ from SA-1 CPU to SNES CPU + inline const bool SCNT_SNESCPU_IVSW() { return BIT(m_scpu_ctrl, 6); } // SNES CPU IRQ vector selection (ROM, IRQ vector register) + inline const bool SCNT_SNESCPU_NVSW() { return BIT(m_scpu_ctrl, 4); } // SNES CPU NMI vector selection (ROM, NMI vector register) + inline const u8 SCNT_CMEG() { return BIT(m_scpu_ctrl, 0, 4); } // Message from SA-1 CPU to SNES CPU // $220a - uint8_t m_sa1_sie; - // $200c-$200d - S-CPU vectors - uint16_t m_irq_vector, m_nmi_vector; - // $2012-$2015 - uint16_t m_hcount, m_vcount; + u8 m_sa1_sie; + // $220c-$220d - S-CPU vectors + u16 m_irq_vector, m_nmi_vector; + // $2210-$2211 + u8 m_timer_ctrl; + // H/V Timer control (TMC) + inline const bool TMC_HVSELB() { return BIT(m_timer_ctrl, 7); } // Select HV timer (HV timer, Linear timer) + inline const bool TMC_VEN() { return BIT(m_timer_ctrl, 1); } // V count enable + inline const bool TMC_HEN() { return BIT(m_timer_ctrl, 0); } // H count enable + // H/V Timer position + u16 m_hpos, m_vpos; + // $2212-$2215 + u16 m_hcount, m_vcount; // $2220-$2223 - int m_bank_c_hi, m_bank_c_rom; - int m_bank_d_hi, m_bank_d_rom; - int m_bank_e_hi, m_bank_e_rom; - int m_bank_f_hi, m_bank_f_rom; + /* + enum super_mmc_t + { + CXB = 0, + DXB = 1, + EXB = 2, + FXB = 3 + }; + */ + bool m_bank_hi[4]; + u8 m_bank_rom[4]; // $2224-$2225 & $223f - uint8_t m_bwram_snes, m_bwram_sa1; - int m_bwram_sa1_source, m_bwram_sa1_format; + u8 m_bwram_snes, m_bwram_sa1; + bool m_bwram_sa1_source, m_bwram_sa1_format; // $2226-$2227 - int m_bwram_write_snes, m_bwram_write_sa1; + bool m_bwram_write_snes, m_bwram_write_sa1; // $2228 - uint32_t m_bwpa_sa1; + u32 m_bwpa_sa1; // $2229-$222a - uint8_t m_iram_write_snes, m_iram_write_sa1; + u8 m_iram_write_snes, m_iram_write_sa1; // $2230-$2231 - uint8_t m_dma_ctrl, m_dma_ccparam; - bool m_dma_cconv_end; - uint8_t m_dma_cconv_size; - uint8_t m_dma_cconv_bits; + u8 m_dma_ctrl, m_dma_ccparam; + u8 m_dma_cconv_size; + u8 m_dma_cconv_bits; + // DMA Control (DCNT) + inline const bool DCNT_DMAEN() { return BIT(m_dma_ctrl, 7); } // DMA Enable control + //inline const bool DCNT_DPRIO() { return BIT(m_dma_ctrl, 6); } // Processing priority between SA-1 CPU and DMA; Not emulated currently + inline const bool DCNT_CDEN() { return BIT(m_dma_ctrl, 5); } // DMA mode selection (Normal/Character conversion) + inline const bool DCNT_CDSEL() { return BIT(m_dma_ctrl, 4); } // Character conversion DMA type + inline const bool DCNT_DD() { return BIT(m_dma_ctrl, 2); } // Destination device (IRAM, BWRAM) + inline const u8 DCNT_SD() { return BIT(m_dma_ctrl, 0, 1); } // Source device (ROM, IRAM, BWRAM) + // Character conversion DMA parameters (CDMA) + inline const bool CDMA_CHDEND() { return BIT(m_dma_ccparam, 7); } // End character conversion 1 + inline const u8 CDMA_SIZE() { return std::min(5, BIT(m_dma_ccparam, 2, 3)); } // Number of virtual VRAM horizontal characters (1 << SIZE) + inline const u8 CDMA_CB() { return std::min(2, BIT(m_dma_ccparam, 0, 2)); } // Character conversion DMA color mode (8bpp, 4bpp, 2bpp) // $2232-$2237 - uint32_t m_src_addr, m_dst_addr; + u32 m_src_addr, m_dst_addr; // $2238-$2239 - uint16_t m_dma_cnt; + u16 m_dma_cnt; // $2240-$224f - uint8_t m_brf_reg[0x10]; + u8 m_brf_reg[0x10]; // $2250-$2254 - uint8_t m_math_ctlr, m_math_overflow; - uint16_t m_math_a, m_math_b; - uint64_t m_math_res; + u8 m_math_ctlr, m_math_overflow; + u16 m_math_a, m_math_b; + u64 m_math_res; // $2258-$225b - uint32_t m_vda; - uint8_t m_vbit, m_vlen; - int m_drm; + u32 m_vda; + u8 m_vbit, m_vlen; + bool m_drm; // $2300-$2301 - uint8_t m_scpu_flags, m_sa1_flags; + u8 m_scpu_flags, m_sa1_flags; // $2302-$2305 - uint16_t m_hcr, m_vcr; + u16 m_hcr, m_vcr; bool m_cconv1_dma_active; - uint32_t m_cconv_bits; + u8 m_cconv2_line; - uint8_t sa1_lo_r(offs_t offset); - uint8_t sa1_hi_r(offs_t offset); - void sa1_lo_w(offs_t offset, uint8_t data); - void sa1_hi_w(offs_t offset, uint8_t data); + u8 sa1_lo_r(offs_t offset); + u8 sa1_hi_r(offs_t offset); + void sa1_lo_w(offs_t offset, u8 data); + void sa1_hi_w(offs_t offset, u8 data); void sa1_map(address_map &map); - - uint8_t dma_cctype1_read(offs_t offset); }; diff --git a/src/devices/bus/snes/snes_slot.cpp b/src/devices/bus/snes/snes_slot.cpp index 5f84ea91683..9cb4a0a0f81 100644 --- a/src/devices/bus/snes/snes_slot.cpp +++ b/src/devices/bus/snes/snes_slot.cpp @@ -188,6 +188,30 @@ uint8_t device_sns_cart_interface::read_open_bus() return 0xff; } +//------------------------------------------------- +// scanlines_r - get motherboard scanline count +//------------------------------------------------- + +int device_sns_cart_interface::scanlines_r() +{ + if (m_slot != nullptr) + return m_slot->scanlines_r(); + + return 0xff; +} + +//------------------------------------------------- +// address_r - get address pin from S-CPU +//------------------------------------------------- + +offs_t device_sns_cart_interface::address_r() +{ + if (m_slot != nullptr) + return m_slot->address_r(); + + return 0xff; +} + //************************************************************************** // LIVE DEVICE //************************************************************************** diff --git a/src/devices/bus/snes/snes_slot.h b/src/devices/bus/snes/snes_slot.h index 6c415a596cc..e4be59b6fc1 100644 --- a/src/devices/bus/snes/snes_slot.h +++ b/src/devices/bus/snes/snes_slot.h @@ -145,6 +145,8 @@ protected: DECLARE_WRITE_LINE_MEMBER(write_irq); uint8_t read_open_bus(); + int scanlines_r(); + offs_t address_r(); // internal state uint8_t *m_rom; @@ -172,6 +174,8 @@ public: // configuration auto irq_callback() { return m_irq_callback.bind(); } auto open_bus_callback() { return m_open_bus_callback.bind(); } + void set_scanlines(int scanlines) { m_scanlines = scanlines; } + void set_address(offs_t address) { m_address = address; } // image-level overrides virtual image_init_result call_load() override; @@ -194,8 +198,14 @@ public: void setup_nvram(); void internal_header_logging(uint8_t *ROM, uint32_t len); - void save_ram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); - if (m_cart && m_cart->get_rtc_ram_size()) m_cart->save_rtc_ram(); } + void save_ram() + { + save_item(NAME(m_address)); + if (m_cart && m_cart->get_nvram_size()) + m_cart->save_nvram(); + if (m_cart && m_cart->get_rtc_ram_size()) + m_cart->save_rtc_ram(); + } // reading and writing uint8_t read_l(offs_t offset); @@ -209,6 +219,8 @@ public: DECLARE_WRITE_LINE_MEMBER(write_irq) { m_irq_callback(state); } uint8_t read_open_bus() { return m_open_bus_callback(); } + int scanlines_r() { return m_scanlines; } + offs_t address_r() { return m_address; } // in order to support legacy dumps + add-on CPU dump appended at the end of the file, we // check if the required data is present and update bank map accordingly @@ -238,6 +250,8 @@ protected: private: devcb_write_line m_irq_callback; devcb_read8 m_open_bus_callback; + int m_scanlines; + offs_t m_address; }; // ======================> sns_cart_slot_device diff --git a/src/mame/drivers/snes.cpp b/src/mame/drivers/snes.cpp index 965377999c5..852a2297eda 100644 --- a/src/mame/drivers/snes.cpp +++ b/src/mame/drivers/snes.cpp @@ -1304,6 +1304,19 @@ void snes_console_state::machine_start() // m_maincpu->set_5a22_map(); break; } + // install memory access taps (send address pin to cartridge slot) + m_maincpu->space(AS_PROGRAM).install_readwrite_tap + ( + 0x000000, 0xffffff, "cartslot_tap", + [this](offs_t offset, u8 &, u8) + { + m_cartslot->set_address(offset); + }, + [this](offs_t offset, u8 &, u8) + { + m_cartslot->set_address(offset); + } + ); m_cartslot->save_ram(); } } @@ -1317,7 +1330,7 @@ void snes_console_state::machine_reset() void snes_console_state::snes(machine_config &config) { /* basic machine hardware */ - _5A22(config, m_maincpu, MCLK_NTSC); /* 2.68 MHz, also 3.58 MHz */ + _5A22(config, m_maincpu, MCLK_NTSC); // Nintendo S-CPU 5A22-0x, 21.477272MHz / (6, 8, 12) = 1.79 MHz, 2.68 MHz, also 3.58 MHz m_maincpu->set_addrmap(AS_PROGRAM, &snes_console_state::snes_map); // runs at 24.576 MHz / 12 = 2.048 MHz @@ -1329,6 +1342,9 @@ void snes_console_state::snes(machine_config &config) //config.set_maximum_quantum(attotime::from_hz(48000)); config.set_perfect_quantum(m_maincpu); + INPUT_MERGER_ANY_HIGH(config, m_scpu_irq); + m_scpu_irq->output_handler().set_inputline(m_maincpu, G65816_LINE_IRQ); + /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(DOTCLK_NTSC * 2, SNES_HTOTAL * 2, 0, SNES_SCR_WIDTH * 2, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC); @@ -1355,8 +1371,9 @@ void snes_console_state::snes(machine_config &config) m_s_dsp->add_route(1, "rspeaker", 1.00); SNS_CART_SLOT(config, m_cartslot, MCLK_NTSC, snes_cart, nullptr); - m_cartslot->irq_callback().set_inputline(m_maincpu, G65816_LINE_IRQ); // FIXME: conflict with video interrupt, it should be ORed + m_cartslot->irq_callback().set(m_scpu_irq, FUNC(input_merger_device::in_w<1>)); // FIXME: conflict with video interrupt, it should be ORed m_cartslot->open_bus_callback().set(FUNC(snes_console_state::snes_open_bus_r)); + m_cartslot->set_scanlines(SNES_VTOTAL_NTSC); SOFTWARE_LIST(config, "cart_list").set_original("snes"); SOFTWARE_LIST(config, "bsx_list").set_original("snes_bspack"); @@ -1372,6 +1389,7 @@ void snes_console_state::snespal(machine_config &config) m_ppu->set_clock(MCLK_PAL); m_cartslot->set_clock(MCLK_PAL); + m_cartslot->set_scanlines(SNES_VTOTAL_PAL); } diff --git a/src/mame/includes/snes.h b/src/mame/includes/snes.h index 13f73509bd7..34c41e0e94b 100644 --- a/src/mame/includes/snes.h +++ b/src/mame/includes/snes.h @@ -5,6 +5,7 @@ #define MAME_INCLUDES_SNES_H #include "cpu/g65816/g65816.h" +#include "machine/input_merger.h" #include "machine/s_smp.h" #include "sound/s_dsp.h" #include "video/snes_ppu.h" @@ -306,6 +307,7 @@ public: m_s_dsp(*this, "s_dsp"), m_ppu(*this, "ppu"), m_screen(*this, "screen"), + m_scpu_irq(*this, "scpu_irq"), m_wram(*this, "wram") { } @@ -395,6 +397,7 @@ protected: required_device m_s_dsp; required_device m_ppu; required_device m_screen; + optional_device m_scpu_irq; required_shared_ptr m_wram; @@ -440,6 +443,7 @@ protected: DECLARE_DEVICE_IMAGE_LOAD_MEMBER(load_snes_cart); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(load_sufami_cart); void snes_init_timers(); + void scpu_irq_refresh(); }; /* Special chips, checked at init and used in memory handlers */ diff --git a/src/mame/machine/snes.cpp b/src/mame/machine/snes.cpp index 5afd2019388..23e474e11ee 100644 --- a/src/mame/machine/snes.cpp +++ b/src/mame/machine/snes.cpp @@ -43,6 +43,15 @@ uint32_t snes_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, Timers *************************************/ +void snes_state::scpu_irq_refresh() +{ + if (m_scpu_irq != nullptr) // multiplexed interrupt? + m_scpu_irq->in_w<0>(SNES_CPU_REG(TIMEUP) & 0x80); + else + m_maincpu->set_input_line(G65816_LINE_IRQ, (SNES_CPU_REG(TIMEUP) & 0x80) ? ASSERT_LINE : CLEAR_LINE); +} + + void snes_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch (id) @@ -89,7 +98,7 @@ void snes_state::hirq_tick() // (don't need to switch to the 65816 context, we don't do anything dependant on it) m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y()); SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */ - m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE); + scpu_irq_refresh(); // don't happen again m_hirq_timer->adjust(attotime::never); @@ -136,7 +145,7 @@ TIMER_CALLBACK_MEMBER(snes_state::snes_scanline_tick) SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */ // IRQ latches the counters, do it now m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y()); - m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE ); + scpu_irq_refresh(); } } /* Horizontal IRQ timer */ @@ -404,8 +413,9 @@ uint8_t snes_state::snes_r_io(offs_t offset) switch (offset) // offset is from 0x000000 { case WMDATA: /* Data to read from WRAM */ - value = m_wram[m_wram_address++]; - m_wram_address &= 0x1ffff; + value = m_wram[m_wram_address]; + if (!machine().side_effects_disabled()) + m_wram_address = (m_wram_address + 1) & 0x1ffff; return value; case OLDJOY1: /* Data for old NES controllers (JOYSER1) */ @@ -416,12 +426,16 @@ uint8_t snes_state::snes_r_io(offs_t offset) case RDNMI: /* NMI flag by v-blank and version number */ value = (SNES_CPU_REG(RDNMI) & 0x80) | (snes_open_bus_r() & 0x70); - SNES_CPU_REG(RDNMI) &= 0x70; /* NMI flag is reset on read */ + if (!machine().side_effects_disabled()) + SNES_CPU_REG(RDNMI) &= 0x70; /* NMI flag is reset on read */ return value | 2; //CPU version number case TIMEUP: /* IRQ flag by H/V count timer */ value = (snes_open_bus_r() & 0x7f) | (SNES_CPU_REG(TIMEUP) & 0x80); - m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); - SNES_CPU_REG(TIMEUP) = 0; // flag is cleared on both read and write + if (!machine().side_effects_disabled()) + { + SNES_CPU_REG(TIMEUP) = 0; // flag is cleared on both read and write + scpu_irq_refresh(); + } return value; case HVBJOY: /* H/V blank and joypad controller enable */ // electronics test says hcounter 272 is start of hblank, which is beampos 363 @@ -500,16 +514,13 @@ void snes_state::snes_w_io(address_space &space, offs_t offset, uint8_t data) m_wram_address &= 0x1ffff; return; case WMADDL: /* Address to read/write to wram (low) */ - m_wram_address = (m_wram_address & 0xffff00) | (data << 0); - m_wram_address &= 0x1ffff; + m_wram_address = (m_wram_address & 0x1ff00) | (data << 0); return; case WMADDM: /* Address to read/write to wram (mid) */ - m_wram_address = (m_wram_address & 0xff00ff) | (data << 8); - m_wram_address &= 0x1ffff; + m_wram_address = (m_wram_address & 0x100ff) | (data << 8); return; case WMADDH: /* Address to read/write to wram (high) */ - m_wram_address = (m_wram_address & 0x00ffff) | (data << 16); - m_wram_address &= 0x1ffff; + m_wram_address = (m_wram_address & 0x0ffff) | ((data & 1) << 16); return; case OLDJOY1: /* Old NES joystick support */ write_joy_latch(data); @@ -521,8 +532,8 @@ void snes_state::snes_w_io(address_space &space, offs_t offset, uint8_t data) case NMITIMEN: /* Flag for v-blank, timer int. and joy read */ if ((data & 0x30) == 0x00) { - m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); SNES_CPU_REG(TIMEUP) = 0; // clear pending IRQ if irq is disabled here, 3x3 Eyes - Seima Korin Den behaves on this + scpu_irq_refresh(); } SNES_CPU_REG(NMITIMEN) = data; return; @@ -531,20 +542,16 @@ void snes_state::snes_w_io(address_space &space, offs_t offset, uint8_t data) SNES_CPU_REG(WRIO) = data; return; case HTIMEL: /* H-Count timer settings (low) */ - m_htime = (m_htime & 0xff00) | (data << 0); - m_htime &= 0x1ff; + m_htime = (m_htime & 0x100) | (data << 0); return; case HTIMEH: /* H-Count timer settings (high) */ - m_htime = (m_htime & 0x00ff) | (data << 8); - m_htime &= 0x1ff; + m_htime = (m_htime & 0x0ff) | ((data & 1) << 8); return; case VTIMEL: /* V-Count timer settings (low) */ - m_vtime = (m_vtime & 0xff00) | (data << 0); - m_vtime &= 0x1ff; + m_vtime = (m_vtime & 0x100) | (data << 0); return; case VTIMEH: /* V-Count timer settings (high) */ - m_vtime = (m_vtime & 0x00ff) | (data << 8); - m_vtime &= 0x1ff; + m_vtime = (m_vtime & 0x0ff) | ((data & 1) << 8); return; case MDMAEN: /* DMA channel designation and trigger */ dma(space, data); @@ -556,8 +563,8 @@ void snes_state::snes_w_io(address_space &space, offs_t offset, uint8_t data) SNES_CPU_REG(HDMAEN) = data; return; case TIMEUP: // IRQ Flag is cleared on both read and write - m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); SNES_CPU_REG(TIMEUP) = 0; + scpu_irq_refresh(); return; /* Following are read-only */ case HVBJOY: /* H/V blank and joypad enable */ @@ -1215,6 +1222,7 @@ inline int snes_state::dma_abus_valid( uint32_t address ) inline uint8_t snes_state::abus_read( address_space &space, uint32_t abus ) { + m_maincpu->adjust_icount(-8); // 8 master cycle per memory access if (!dma_abus_valid(abus)) return 0; @@ -1225,6 +1233,7 @@ inline void snes_state::dma_transfer( address_space &space, uint8_t dma, uint32_ { if (m_dma_channel[dma].dmap & 0x80) /* PPU->CPU */ { + m_maincpu->adjust_icount(-8); // 8 master cycle per memory access if (bbus == 0x2180 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) { //illegal WRAM->WRAM transfer (bus conflict)