summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author cam900 <dbtlrchl@naver.com>2021-11-20 09:35:56 +0900
committer GitHub <noreply@github.com>2021-11-19 19:35:56 -0500
commitdb40a44d0093bdb2ffa508a9452a81e05750f56e (patch)
tree2be2d06c93adf6986d09954a4d496553824409e7 /src
parent6229ca9544962fa7e69dc8691346bc586482197b (diff)
bus/snes/sa1.cpp: Flesh out some SA1 features, Fix SNES timing, interrupt (#8673)
Diffstat (limited to 'src')
-rw-r--r--src/devices/bus/snes/sa1.cpp1018
-rw-r--r--src/devices/bus/snes/sa1.h174
-rw-r--r--src/devices/bus/snes/snes_slot.cpp24
-rw-r--r--src/devices/bus/snes/snes_slot.h18
-rw-r--r--src/mame/drivers/snes.cpp22
-rw-r--r--src/mame/includes/snes.h4
-rw-r--r--src/mame/machine/snes.cpp55
7 files changed, 772 insertions, 543 deletions
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<u8[]>(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 <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 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<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);
@@ -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<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,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<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;
+ 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<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,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<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
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;
-
- 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,21 +1045,21 @@ 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
@@ -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;
-
- 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)
@@ -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)
+{
+ 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<true>(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)
{
- 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<true>(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<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); // 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<true>(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)
+ 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()) // 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
}
- 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...)
}
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?
}
-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 <algorithm>
// ======================> 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<bool SA1Read> 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<bool SA1Read> uint8_t read_regs(uint32_t offset);
- uint8_t read_iram(uint32_t offset);
- template<bool SA1Read> 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<bool SA1Read> 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();
+ u8 rom_r(offs_t offset);
+ u8 sa1_rom_r(offs_t offset);
+
+ 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<g65816_device> m_sa1;
+ emu_timer *m_sa1_timer;
+
+ std::unique_ptr<u8[]> m_internal_ram;
- uint8_t m_internal_ram[0x800];
+ // 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<u8>(5, BIT(m_dma_ccparam, 2, 3)); } // Number of virtual VRAM horizontal characters (1 << SIZE)
+ inline const u8 CDMA_CB() { return std::min<u8>(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<s_dsp_device> m_s_dsp;
required_device<snes_ppu_device> m_ppu;
required_device<screen_device> m_screen;
+ optional_device<input_merger_device> m_scpu_irq;
required_shared_ptr<u8> 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)