summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/nec/v25.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/nec/v25.cpp')
-rw-r--r--src/devices/cpu/nec/v25.cpp152
1 files changed, 150 insertions, 2 deletions
diff --git a/src/devices/cpu/nec/v25.cpp b/src/devices/cpu/nec/v25.cpp
index 6d96206f0ed..ee4f1886170 100644
--- a/src/devices/cpu/nec/v25.cpp
+++ b/src/devices/cpu/nec/v25.cpp
@@ -38,6 +38,11 @@
#include "v25.h"
#include "necdasm.h"
+#define LOG_BUSLOCK (1 << 1)
+//#define VERBOSE (...)
+
+#include "logmacro.h"
+
typedef uint8_t BOOLEAN;
typedef uint8_t BYTE;
typedef uint16_t WORD;
@@ -64,6 +69,8 @@ v25_common_device::v25_common_device(const machine_config &mconfig, device_type
, m_p0_out(*this)
, m_p1_out(*this)
, m_p2_out(*this)
+ , m_dma_read(*this, 0xffff)
+ , m_dma_write(*this)
, m_prefetch_size(prefetch_size)
, m_prefetch_cycles(prefetch_cycles)
, m_chip_type(chip_type)
@@ -210,9 +217,20 @@ void v25_common_device::device_reset()
m_intm = 0;
m_halted = 0;
- m_TM0 = m_MD0 = m_TM1 = m_MD1 = 0;
m_TMC0 = m_TMC1 = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ m_scm[i] = 0;
+ m_scc[i] = 0;
+ m_brg[i] = 0;
+ m_sce[i] = 0;
+ }
+
+ m_dmam[0] = m_dmam[1] = 0;
+ m_dma_channel = -1;
+ m_last_dma_channel = 0;
+
m_RAMEN = 1;
m_TB = 20;
m_PCK = 8;
@@ -470,6 +488,111 @@ void v25_common_device::external_int()
}
}
+void v25_common_device::dma_process()
+{
+ uint16_t sar = m_internal_ram[m_dma_channel * 4];
+ uint16_t dar = m_internal_ram[m_dma_channel * 4 + 1];
+ uint16_t sarh_darh = m_internal_ram[m_dma_channel * 4 + 2];
+ uint8_t dmamode = BIT(m_dmam[m_dma_channel], 5, 3);
+ bool w = BIT(m_dmam[m_dma_channel], 4);
+
+ uint32_t saddr = ((uint32_t(sarh_darh) & 0xff00) << 4) + sar;
+ uint32_t daddr = ((uint32_t(sarh_darh) & 0x00ff) << 12) + dar;
+
+ switch (dmamode & 3)
+ {
+ case 0:
+ // Memory to memory transfer
+ if (w)
+ {
+ uint16_t data = v25_read_word(saddr);
+ v25_write_word(daddr, data);
+ }
+ else
+ {
+ uint8_t data = v25_read_byte(saddr);
+ v25_write_byte(daddr, data);
+ }
+ m_icount -= (w && m_program->addr_width() == 8) ? 8 : 4;
+ break;
+
+ case 1:
+ // I/O to memory transfer
+ if (w && m_program->addr_width() == 16)
+ {
+ uint16_t data = m_dma_read[m_dma_channel](daddr);
+ v25_write_word(daddr, data);
+ }
+ else
+ {
+ uint8_t data = m_dma_read[m_dma_channel](daddr);
+ v25_write_byte(daddr, data);
+ if (w)
+ {
+ logerror("Warning: V25 16-bit I/O to memory transfer\n");
+ data = m_dma_read[m_dma_channel](daddr + 1);
+ v25_write_byte(daddr + 1, data);
+ m_icount -= 2;
+ }
+ }
+ m_icount -= 2;
+ break;
+
+ case 2:
+ // Memory to I/O transfer
+ if (w && m_program->addr_width() == 16)
+ {
+ uint16_t data = v25_read_word(saddr);
+ m_dma_write[m_dma_channel](saddr, data);
+ }
+ else
+ {
+ uint8_t data = v25_read_byte(saddr);
+ m_dma_write[m_dma_channel](saddr, data);
+ if (w)
+ {
+ logerror("Warning: V25 16-bit memory to I/O transfer\n");
+ data = v25_read_byte(saddr + 1);
+ m_dma_write[m_dma_channel](saddr + 1, data);
+ m_icount -= 2;
+ }
+ }
+ m_icount -= 2;
+ break;
+
+ default:
+ logerror("Reserved DMA transfer mode\n");
+ m_icount--;
+ break;
+ }
+
+ // Update source and destination based on address control
+ uint8_t dmac = m_dmac[m_dma_channel];
+ if (BIT(dmac, 0, 2) == 1)
+ m_internal_ram[m_dma_channel * 4] = sar + (w ? 2 : 1);
+ else if (BIT(dmac, 0, 2) == 2)
+ m_internal_ram[m_dma_channel * 4] = sar - (w ? 2 : 1);
+ if (BIT(dmac, 4, 2) == 1)
+ m_internal_ram[m_dma_channel * 4 + 1] = dar + (w ? 2 : 1);
+ else if (BIT(dmac, 4, 2) == 2)
+ m_internal_ram[m_dma_channel * 4 + 1] = dar - (w ? 2 : 1);
+
+ // Update TC
+ uint16_t tc = --m_internal_ram[m_dma_channel * 4 + 3];
+ if (tc == 0)
+ {
+ m_dmam[m_dma_channel] &= 0xf0; // disable channel
+ m_pending_irq |= m_dma_channel ? INTD1 : INTD0; // request interrupt
+ }
+
+ if (dmamode == 0 || dmamode > 4 || tc == 0)
+ {
+ // Single step/single transfer modes (or end of burst)
+ m_last_dma_channel = m_dma_channel;
+ m_dma_channel = -1;
+ }
+}
+
/****************************************************************************/
/* OPCODES */
/****************************************************************************/
@@ -557,6 +680,9 @@ void v25_common_device::device_start()
m_EO = 0;
m_E16 = 0;
+ m_TM0 = m_MD0 = m_TM1 = m_MD1 = 0;
+ m_dmac[0] = m_dmac[1] = 0;
+
for (i = 0; i < 4; i++)
m_timers[i] = timer_alloc(FUNC(v25_common_device::v25_timer_callback), this);
@@ -613,6 +739,14 @@ void v25_common_device::device_start()
save_item(NAME(m_MD1));
save_item(NAME(m_TMC0));
save_item(NAME(m_TMC1));
+ save_item(NAME(m_scm));
+ save_item(NAME(m_scc));
+ save_item(NAME(m_brg));
+ save_item(NAME(m_sce));
+ save_item(NAME(m_dmac));
+ save_item(NAME(m_dmam));
+ save_item(NAME(m_dma_channel));
+ save_item(NAME(m_last_dma_channel));
save_item(NAME(m_RAMEN));
save_item(NAME(m_TB));
save_item(NAME(m_PCK));
@@ -767,12 +901,18 @@ void v25_common_device::execute_run()
if (m_halted)
{
+ debugger_wait_hook();
m_icount = 0;
- debugger_instruction_hook((Sreg(PS)<<4) + m_ip);
return;
}
while(m_icount>0) {
+ if (m_dma_channel != -1)
+ {
+ dma_process();
+ continue;
+ }
+
/* Dispatch IRQ */
m_prev_ip = m_ip;
if (m_no_interrupt==0 && (m_pending_irq & m_unmasked_irq))
@@ -791,5 +931,13 @@ void v25_common_device::execute_run()
prev_ICount = m_icount;
(this->*s_nec_instruction[fetchop()])();
do_prefetch(prev_ICount);
+
+ if ((m_dmam[0] & 0x0c) == 0x0c || (m_dmam[1] & 0x0c) == 0x0c)
+ {
+ if ((m_dmam[1 - m_last_dma_channel] & 0x0c) == 0x0c)
+ m_dma_channel = 1 - m_last_dma_channel;
+ else
+ m_dma_channel = m_last_dma_channel;
+ }
}
}