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