summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/h8/h8_dma.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/h8/h8_dma.cpp')
-rw-r--r--src/devices/cpu/h8/h8_dma.cpp123
1 files changed, 119 insertions, 4 deletions
diff --git a/src/devices/cpu/h8/h8_dma.cpp b/src/devices/cpu/h8/h8_dma.cpp
index af27444c64c..28e245e43c4 100644
--- a/src/devices/cpu/h8/h8_dma.cpp
+++ b/src/devices/cpu/h8/h8_dma.cpp
@@ -21,6 +21,7 @@ void h8_dma_device::device_reset()
{
dmabcr = 0x0000;
dmawer = 0x00;
+ dreq[0] = dreq[1] = false;
}
bool h8_dma_device::trigger_dma(int vector)
@@ -32,6 +33,14 @@ bool h8_dma_device::trigger_dma(int vector)
return start0 || start1;
}
+void h8_dma_device::count_last(int id)
+{
+ if(id & 2)
+ dmach1->count_last(id & 1);
+ else
+ dmach0->count_last(id & 1);
+}
+
void h8_dma_device::count_done(int id)
{
if(id & 2)
@@ -45,6 +54,26 @@ void h8_dma_device::clear_dte(int id)
dmabcr &= ~(0x0010 << id);
}
+void h8_dma_device::set_input(int inputnum, int state)
+{
+ if(inputnum == H8_INPUT_LINE_DREQ0) {
+ if(state == ASSERT_LINE) {
+ dmach0->start_test(h8_dma_channel_device::DREQ_LEVEL);
+ if(!dreq[0])
+ dmach0->start_test(h8_dma_channel_device::DREQ_EDGE);
+ }
+ dreq[0] = (state == ASSERT_LINE);
+ } else if(inputnum == H8_INPUT_LINE_DREQ1) {
+ if(state == ASSERT_LINE) {
+ dmach1->start_test(h8_dma_channel_device::DREQ_LEVEL);
+ if(!dreq[1])
+ dmach1->start_test(h8_dma_channel_device::DREQ_EDGE);
+ }
+ dreq[1] = (state == ASSERT_LINE);
+ } else
+ logerror("input line %d not supported for h8_dma_device\n", inputnum);
+}
+
READ8_MEMBER(h8_dma_device::dmawer_r)
{
logerror("dmawer_r %02x\n", dmawer);
@@ -133,7 +162,6 @@ void h8_dma_channel_device::set_id(int id)
{
state[0].id = id;
state[1].id = id | 1;
-
}
READ16_MEMBER(h8_dma_channel_device::marah_r)
@@ -247,6 +275,75 @@ WRITE16_MEMBER(h8_dma_channel_device::dmacr_w)
start_test(-1);
}
+// H8H DMA
+READ8_MEMBER(h8_dma_channel_device::dtcra_r)
+{
+ logerror("dtcra_r %02x\n", dtcr[0]);
+ return dtcr[0];
+}
+
+WRITE8_MEMBER(h8_dma_channel_device::dtcra_w)
+{
+ dtcr[0] = data;
+ logerror("dtcra_w %02x\n", dtcr[0]);
+ if((dtcr[0] & 0x80) && (dtcr[1] & 0x80)) { // if both DTME and DTE are set, start DMA
+ h8h_sync();
+ }
+}
+
+READ8_MEMBER(h8_dma_channel_device::dtcrb_r)
+{
+ logerror("dtcrb_r %02x\n", dtcr[1]);
+ return dtcr[1];
+}
+
+WRITE8_MEMBER(h8_dma_channel_device::dtcrb_w)
+{
+ dtcr[1] = data;
+ logerror("dtcrb_w %02x\n", dtcr[1]);
+ if((dtcr[0] & 0x80) && (dtcr[1] & 0x80)) { // if both DTME and DTE are set, start DMA
+ h8h_sync();
+ }
+}
+
+void h8_dma_channel_device::h8h_sync()
+{
+ // update DMACR
+ dmacr = 0;
+ if(BIT(dtcr[0], 6)) dmacr |= 1 << 15; // DTSZ
+ dmacr |= ((dtcr[0] & 0b110000) >> 4) << 13; // SAID, SAIDE
+ if(BIT(dtcr[0], 0)) dmacr |= 1 << 11; // BLKE
+ if(BIT(dtcr[1], 3)) dmacr |= 1 << 12; // BLKDIR (TMS)
+ dmacr |= ((dtcr[1] & 0b110000) >> 4) << 5; // DAID, DAIDE
+ if(BIT(dmacr, 11)) {
+ // Block Transfer Mode
+ switch(dtcr[1] & 0b111) { // DTS
+ case 0b000: dmacr |= 0b1000; break; // ITU channel 0
+ case 0b001: dmacr |= 0b1001; break; // ITU channel 1
+ case 0b010: dmacr |= 0b1010; break; // ITU channel 2
+ case 0b011: dmacr |= 0b1011; break; // ITU channel 3
+ case 0b110: dmacr |= 0b1000; break; // DREQ falling edge
+ }
+ } else {
+ // Normal Mode
+ switch(dtcr[1] & 0b111) { // DTS
+ case 0b000: dmacr |= 0b0111; break; // Auto-request (burst mode)
+ case 0b010: dmacr |= 0b0110; break; // Auto-request (cycle-steal mode)
+ case 0b110: dmacr |= 0b0010; break; // DREQ falling edge
+ case 0b111: dmacr |= 0b0011; break; // DREQ low-level
+ }
+ }
+
+ // set_bcr
+ bool _fae = (dtcr[0] & 0b110) == 0b110; // A channel operates in full address mode when DTS2A and DTS1A are both set to 1.
+ uint8_t _dta = 0; // don't support
+ uint8_t _dte = BIT(dtcr[0], 7) ? 0b11 : 0b00;
+ uint8_t _dtie = BIT(dtcr[0], 3) ? 0b11 : 0b00;
+ set_bcr(_fae, !_fae, _dta, _dte, _dtie);
+
+ start_test(-1);
+}
+
void h8_dma_channel_device::set_bcr(bool _fae, bool _sae, uint8_t _dta, uint8_t _dte, uint8_t _dtie)
{
fae = _fae;
@@ -267,11 +364,18 @@ bool h8_dma_channel_device::start_test(int vector)
if(dmacr & 0x0800)
throw emu_fatalerror("%s: DMA startup test in full address/block mode unimplemented.\n", tag());
else {
- if((dmacr & 0x0006) == 0x0006) {
+ // Normal Mode
+ if(vector == -1) {
start(0);
return true;
- } else
- throw emu_fatalerror("%s: DMA startup test in full address/normal mode/dreq unimplemented.\n", tag());
+ } else {
+ // DREQ trigger
+ if(((dmacr & 0b111) == 0b0010 && vector == DREQ_EDGE) || ((dmacr & 0b111) == 0b0011 && vector == DREQ_LEVEL)) {
+ state[0].suspended = false;
+ return true;
+ }
+ }
+ return false;
}
} else {
if(dte == 0)
@@ -291,6 +395,8 @@ void h8_dma_channel_device::start(int submodule)
state[submodule].dest = mar[1];
state[submodule].count = etcr[0] ? etcr[0] : 0x10000;
state[submodule].mode_16 = dmacr & 0x8000;
+ state[submodule].autoreq = (dmacr & 6) == 6;
+ state[submodule].suspended = !state[submodule].autoreq; // non-auto-request transfers start suspended
int32_t step = state[submodule].mode_16 ? 2 : 1;
state[submodule].incs = dmacr & 0x2000 ? dmacr & 0x4000 ? -step : step : 0;
state[submodule].incd = dmacr & 0x0020 ? dmacr & 0x0040 ? -step : step : 0;
@@ -301,16 +407,25 @@ void h8_dma_channel_device::start(int submodule)
}
}
+void h8_dma_channel_device::count_last(int submodule)
+{
+ logerror("count last on %d\n", submodule);
+ if(!state[submodule].autoreq) // "The TEND signal goes low during the last write cycle."
+ cpu->set_input_line(H8_INPUT_LINE_TEND0 + (state[submodule].id >> 1), ASSERT_LINE);
+}
void h8_dma_channel_device::count_done(int submodule)
{
logerror("count done on %d\n", submodule);
+ if(!state[submodule].autoreq)
+ cpu->set_input_line(H8_INPUT_LINE_TEND0 + (state[submodule].id >> 1), CLEAR_LINE);
if(fae) {
if(dmacr & 0x0800)
throw emu_fatalerror("%s: DMA count done full address/block mode unimplemented.\n", tag());
else {
dte &= ~1;
dmac->clear_dte(state[0].id);
+ dtcr[0] &= ~0x80; // clear DTE (for H8H)
if(dtie & 1)
throw emu_fatalerror("%s: DMA end-of-transfer interrupt in full address/normal mode unimplemented.\n", tag());
}