diff options
author | 2017-04-24 22:37:35 +0200 | |
---|---|---|
committer | 2017-04-24 22:37:35 +0200 | |
commit | 19823bab94efb1283e684ad56ae4eca769ea095c (patch) | |
tree | 0d5b2ea1125ec70651b592bb337faea481a76711 /src/devices/cpu/h8/h8_dma.cpp | |
parent | 2a1cc17f330ee21244ff59a3123b5f6bc28eeab0 (diff) |
Fixed h8 instruction eepmov.b (used r4h instead of r4l) (#2253)
Added support for non-autorequest DMA (DREQ edge, DREQ level) in h8
Added support for H8/300H to h8_dma (previously only H8/300S supported)
Added DMA channels to H8/3002
Added RTMCSR register to H8/3002
Diffstat (limited to 'src/devices/cpu/h8/h8_dma.cpp')
-rw-r--r-- | src/devices/cpu/h8/h8_dma.cpp | 123 |
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()); } |