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
This commit is contained in:
BartmanAbyss 2017-04-24 22:37:35 +02:00 committed by Olivier Galibert
parent 2a1cc17f33
commit 19823bab94
6 changed files with 233 additions and 15 deletions

View File

@ -145,9 +145,9 @@ void h8_device::set_current_dma(h8_dma_state *state)
if(!state) if(!state)
logerror("DMA done\n"); logerror("DMA done\n");
else else
logerror("New current dma s=%x d=%x is=%d id=%d count=%x m=%d\n", logerror("New current dma s=%x d=%x is=%d id=%d count=%x m=%d autoreq=%d\n",
state->source, state->dest, state->incs, state->incd, state->source, state->dest, state->incs, state->incd,
state->count, state->mode_16 ? 16 : 8); state->count, state->mode_16 ? 16 : 8, state->autoreq);
} }
@ -620,7 +620,7 @@ void h8_device::prefetch_done()
if(requested_state != -1) { if(requested_state != -1) {
inst_state = requested_state; inst_state = requested_state;
requested_state = -1; requested_state = -1;
} else if(current_dma) } else if(current_dma && !current_dma->suspended)
inst_state = STATE_DMA; inst_state = STATE_DMA;
else if(current_dtc) else if(current_dtc)
inst_state = STATE_DTC; inst_state = STATE_DTC;

View File

@ -176,6 +176,8 @@ macro jsr32 %opc %spreg
prefetch_noirq(); prefetch_noirq();
10003 dma 10003 dma
if(current_dma->count == 1)
dma_device->count_last(current_dma->id);
if(current_dma->mode_16) { if(current_dma->mode_16) {
TMP1 = read16(current_dma->source); TMP1 = read16(current_dma->source);
write16(current_dma->dest, TMP1); write16(current_dma->dest, TMP1);
@ -186,6 +188,8 @@ macro jsr32 %opc %spreg
current_dma->source += current_dma->incs; current_dma->source += current_dma->incs;
current_dma->dest += current_dma->incd; current_dma->dest += current_dma->incd;
current_dma->count--; current_dma->count--;
if(!current_dma->autoreq)
current_dma->suspended = true;
if(!current_dma->count) { if(!current_dma->count) {
uint8_t id = current_dma->id; uint8_t id = current_dma->id;
current_dma = nullptr; current_dma = nullptr;
@ -2441,22 +2445,22 @@ macro jsr32 %opc %spreg
prefetch(); prefetch();
7b5c598f ffffffff 0 eepmov.b - - o 7b5c598f ffffffff 0 eepmov.b - - o
while(r8_r(4)) { while(r8_r(4+8)) {
TMP1 = read8(r16_r(5)); TMP1 = read8(r16_r(5));
write8(r16_r(6), TMP1); write8(r16_r(6), TMP1);
r16_w(5, r16_r(5)+1); r16_w(5, r16_r(5)+1);
r16_w(6, r16_r(6)+1); r16_w(6, r16_r(6)+1);
r8_w(4, r8_r(4)-1); r8_w(4+8, r8_r(4+8)-1);
} }
prefetch(); prefetch();
7b5c598f ffffffff 0 eepmov.b - - h 7b5c598f ffffffff 0 eepmov.b - - h
while(r8_r(4)) { while(r8_r(4+8)) {
TMP1 = read8(r32_r(5)); TMP1 = read8(r32_r(5));
write8(r32_r(6), TMP1); write8(r32_r(6), TMP1);
r32_w(5, r32_r(5)+1); r32_w(5, r32_r(5)+1);
r32_w(6, r32_r(6)+1); r32_w(6, r32_r(6)+1);
r8_w(4, r8_r(4)-1); r8_w(4+8, r8_r(4+8)-1);
} }
prefetch(); prefetch();

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Olivier Galibert // copyright-holders:Olivier Galibert
#include "emu.h" #include "emu.h"
#include "h83002.h" #include "h83002.h"
@ -9,6 +9,9 @@ h83002_device::h83002_device(const machine_config &mconfig, const char *tag, dev
h8h_device(mconfig, H83002, "H8/3002", tag, owner, clock, "h83002", __FILE__, address_map_delegate(FUNC(h83002_device::map), this)), h8h_device(mconfig, H83002, "H8/3002", tag, owner, clock, "h83002", __FILE__, address_map_delegate(FUNC(h83002_device::map), this)),
intc(*this, "intc"), intc(*this, "intc"),
adc(*this, "adc"), adc(*this, "adc"),
dma(*this, "dma"),
dma0(*this, "dma:0"),
dma1(*this, "dma:1"),
port4(*this, "port4"), port4(*this, "port4"),
port6(*this, "port6"), port6(*this, "port6"),
port7(*this, "port7"), port7(*this, "port7"),
@ -24,7 +27,9 @@ h83002_device::h83002_device(const machine_config &mconfig, const char *tag, dev
timer16_4(*this, "timer16:4"), timer16_4(*this, "timer16:4"),
sci0(*this, "sci0"), sci0(*this, "sci0"),
sci1(*this, "sci1"), sci1(*this, "sci1"),
watchdog(*this, "watchdog") watchdog(*this, "watchdog"),
tend0_cb(*this),
tend1_cb(*this)
{ {
syscr = 0; syscr = 0;
} }
@ -32,6 +37,10 @@ h83002_device::h83002_device(const machine_config &mconfig, const char *tag, dev
static MACHINE_CONFIG_FRAGMENT(h83002) static MACHINE_CONFIG_FRAGMENT(h83002)
MCFG_H8H_INTC_ADD("intc") MCFG_H8H_INTC_ADD("intc")
MCFG_H8_ADC_3337_ADD("adc", "intc", 60) MCFG_H8_ADC_3337_ADD("adc", "intc", 60)
MCFG_H8_DMA_ADD("dma")
// (H8/2002.pdf) Table 8-11 DMAC Activation Sources
MCFG_H8_DMA_CHANNEL_ADD("dma:0", "intc", 44, h8_dma_channel_device::NONE, 24, h8_dma_channel_device::DREQ_EDGE, h8_dma_channel_device::DREQ_LEVEL, 28, 32, 36, 54, 53, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE)
MCFG_H8_DMA_CHANNEL_ADD("dma:1", "intc", 46, h8_dma_channel_device::NONE, 24, h8_dma_channel_device::DREQ_EDGE, h8_dma_channel_device::DREQ_LEVEL, 28, 32, 36, 54, 53, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE, h8_dma_channel_device::NONE)
MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00)
MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80) MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80)
MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00) MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00)
@ -53,6 +62,24 @@ MACHINE_CONFIG_END
DEVICE_ADDRESS_MAP_START(map, 16, h83002_device) DEVICE_ADDRESS_MAP_START(map, 16, h83002_device)
AM_RANGE(0xfffd10, 0xffff0f) AM_RAM AM_RANGE(0xfffd10, 0xffff0f) AM_RAM
// DMA: only full address mode supported
AM_RANGE(0xffff20, 0xffff21) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, marah_r, marah_w )
AM_RANGE(0xffff22, 0xffff23) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, maral_r, maral_w )
AM_RANGE(0xffff24, 0xffff25) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, etcra_r, etcra_w )
AM_RANGE(0xffff26, 0xffff27) AM_DEVREADWRITE8("dma:0", h8_dma_channel_device, dtcra_r, dtcra_w, 0x00ff )
AM_RANGE(0xffff28, 0xffff29) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, marbh_r, marbh_w )
AM_RANGE(0xffff2a, 0xffff2b) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, marbl_r, marbl_w )
AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE( "dma:0", h8_dma_channel_device, etcrb_r, etcrb_w )
AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("dma:0", h8_dma_channel_device, dtcrb_r, dtcrb_w, 0x00ff )
AM_RANGE(0xffff30, 0xffff31) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, marah_r, marah_w )
AM_RANGE(0xffff32, 0xffff33) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, maral_r, maral_w )
AM_RANGE(0xffff34, 0xffff35) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, etcra_r, etcra_w )
AM_RANGE(0xffff36, 0xffff37) AM_DEVREADWRITE8("dma:1", h8_dma_channel_device, dtcra_r, dtcra_w, 0x00ff )
AM_RANGE(0xffff38, 0xffff39) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, marbh_r, marbh_w )
AM_RANGE(0xffff3a, 0xffff3b) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, marbl_r, marbl_w )
AM_RANGE(0xffff3c, 0xffff3d) AM_DEVREADWRITE( "dma:1", h8_dma_channel_device, etcrb_r, etcrb_w )
AM_RANGE(0xffff3e, 0xffff3f) AM_DEVREADWRITE8("dma:1", h8_dma_channel_device, dtcrb_r, dtcrb_w, 0x00ff )
AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00)
AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff)
AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00) AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00)
@ -94,6 +121,7 @@ DEVICE_ADDRESS_MAP_START(map, 16, h83002_device)
AM_RANGE(0xffffa8, 0xffffa9) AM_DEVREADWRITE( "watchdog", h8_watchdog_device, wd_r, wd_w ) AM_RANGE(0xffffa8, 0xffffa9) AM_DEVREADWRITE( "watchdog", h8_watchdog_device, wd_r, wd_w )
AM_RANGE(0xffffaa, 0xffffab) AM_DEVREADWRITE( "watchdog", h8_watchdog_device, rst_r, rst_w ) AM_RANGE(0xffffaa, 0xffffab) AM_DEVREADWRITE( "watchdog", h8_watchdog_device, rst_r, rst_w )
AM_RANGE(0xffffac, 0xffffad) AM_READWRITE8( rtmcsr_r,rtmcsr_w,0x00ff)
AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00)
AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff)
@ -140,7 +168,14 @@ machine_config_constructor h83002_device::device_mconfig_additions() const
void h83002_device::execute_set_input(int inputnum, int state) void h83002_device::execute_set_input(int inputnum, int state)
{ {
intc->set_input(inputnum, state); if(inputnum == H8_INPUT_LINE_TEND0 && !tend0_cb.isnull())
tend0_cb(state);
else if(inputnum == H8_INPUT_LINE_TEND1 && !tend1_cb.isnull())
tend1_cb(state);
else if(inputnum >= H8_INPUT_LINE_DREQ0 && inputnum <= H8_INPUT_LINE_DREQ3)
dma->set_input(inputnum, state);
else
intc->set_input(inputnum, state);
} }
int h83002_device::trapa_setup() int h83002_device::trapa_setup()
@ -205,6 +240,10 @@ void h83002_device::internal_update(uint64_t current_time)
void h83002_device::device_start() void h83002_device::device_start()
{ {
h8h_device::device_start(); h8h_device::device_start();
dma_device = dma;
tend0_cb.resolve();
tend1_cb.resolve();
} }
void h83002_device::device_reset() void h83002_device::device_reset()
@ -224,3 +263,15 @@ WRITE8_MEMBER(h83002_device::syscr_w)
update_irq_filter(); update_irq_filter();
logerror("syscr = %02x\n", data); logerror("syscr = %02x\n", data);
} }
READ8_MEMBER(h83002_device::rtmcsr_r)
{
// set bit 7 -- Compare Match Flag (CMF): This status flag indicates that the RTCNT and RTCOR values have matched.
return rtmcsr | 0x80;
}
WRITE8_MEMBER(h83002_device::rtmcsr_w)
{
rtmcsr = data;
logerror("rtmcsr = %02x\n", data);
}

View File

@ -16,22 +16,37 @@
#include "h8h.h" #include "h8h.h"
#include "h8_adc.h" #include "h8_adc.h"
#include "h8_dma.h"
#include "h8_port.h" #include "h8_port.h"
#include "h8_intc.h" #include "h8_intc.h"
#include "h8_timer16.h" #include "h8_timer16.h"
#include "h8_sci.h" #include "h8_sci.h"
#include "h8_watchdog.h" #include "h8_watchdog.h"
#define MCFG_H83002_TEND0_CALLBACK(_devcb) \
devcb = &h83002_device::set_tend0_callback(*device, DEVCB_##_devcb);
#define MCFG_H83002_TEND1_CALLBACK(_devcb) \
devcb = &h83002_device::set_tend1_callback(*device, DEVCB_##_devcb);
class h83002_device : public h8h_device { class h83002_device : public h8h_device {
public: public:
h83002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); h83002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
template<class _Object> static devcb_base &set_tend0_callback(device_t &device, _Object object) { return downcast<h83002_device&>(device).tend0_cb.set_callback(object); }
template<class _Object> static devcb_base &set_tend1_callback(device_t &device, _Object object) { return downcast<h83002_device&>(device).tend1_cb.set_callback(object); }
DECLARE_READ8_MEMBER(syscr_r); DECLARE_READ8_MEMBER(syscr_r);
DECLARE_WRITE8_MEMBER(syscr_w); DECLARE_WRITE8_MEMBER(syscr_w);
DECLARE_READ8_MEMBER(rtmcsr_r);
DECLARE_WRITE8_MEMBER(rtmcsr_w);
protected: protected:
required_device<h8h_intc_device> intc; required_device<h8h_intc_device> intc;
required_device<h8_adc_device> adc; required_device<h8_adc_device> adc;
optional_device<h8_dma_device> dma;
optional_device<h8_dma_channel_device> dma0;
optional_device<h8_dma_channel_device> dma1;
required_device<h8_port_device> port4; required_device<h8_port_device> port4;
required_device<h8_port_device> port6; required_device<h8_port_device> port6;
required_device<h8_port_device> port7; required_device<h8_port_device> port7;
@ -50,6 +65,9 @@ protected:
required_device<h8_watchdog_device> watchdog; required_device<h8_watchdog_device> watchdog;
uint8_t syscr; uint8_t syscr;
uint8_t rtmcsr;
devcb_write_line tend0_cb, tend1_cb;
virtual void update_irq_filter() override; virtual void update_irq_filter() override;
virtual void interrupt_taken() override; virtual void interrupt_taken() override;

View File

@ -21,6 +21,7 @@ void h8_dma_device::device_reset()
{ {
dmabcr = 0x0000; dmabcr = 0x0000;
dmawer = 0x00; dmawer = 0x00;
dreq[0] = dreq[1] = false;
} }
bool h8_dma_device::trigger_dma(int vector) bool h8_dma_device::trigger_dma(int vector)
@ -32,6 +33,14 @@ bool h8_dma_device::trigger_dma(int vector)
return start0 || start1; 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) void h8_dma_device::count_done(int id)
{ {
if(id & 2) if(id & 2)
@ -45,6 +54,26 @@ void h8_dma_device::clear_dte(int id)
dmabcr &= ~(0x0010 << 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) READ8_MEMBER(h8_dma_device::dmawer_r)
{ {
logerror("dmawer_r %02x\n", dmawer); logerror("dmawer_r %02x\n", dmawer);
@ -133,7 +162,6 @@ void h8_dma_channel_device::set_id(int id)
{ {
state[0].id = id; state[0].id = id;
state[1].id = id | 1; state[1].id = id | 1;
} }
READ16_MEMBER(h8_dma_channel_device::marah_r) READ16_MEMBER(h8_dma_channel_device::marah_r)
@ -247,6 +275,75 @@ WRITE16_MEMBER(h8_dma_channel_device::dmacr_w)
start_test(-1); 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) void h8_dma_channel_device::set_bcr(bool _fae, bool _sae, uint8_t _dta, uint8_t _dte, uint8_t _dtie)
{ {
fae = _fae; fae = _fae;
@ -267,11 +364,18 @@ bool h8_dma_channel_device::start_test(int vector)
if(dmacr & 0x0800) if(dmacr & 0x0800)
throw emu_fatalerror("%s: DMA startup test in full address/block mode unimplemented.\n", tag()); throw emu_fatalerror("%s: DMA startup test in full address/block mode unimplemented.\n", tag());
else { else {
if((dmacr & 0x0006) == 0x0006) { // Normal Mode
if(vector == -1) {
start(0); start(0);
return true; return true;
} else } else {
throw emu_fatalerror("%s: DMA startup test in full address/normal mode/dreq unimplemented.\n", tag()); // DREQ trigger
if(((dmacr & 0b111) == 0b0010 && vector == DREQ_EDGE) || ((dmacr & 0b111) == 0b0011 && vector == DREQ_LEVEL)) {
state[0].suspended = false;
return true;
}
}
return false;
} }
} else { } else {
if(dte == 0) if(dte == 0)
@ -291,6 +395,8 @@ void h8_dma_channel_device::start(int submodule)
state[submodule].dest = mar[1]; state[submodule].dest = mar[1];
state[submodule].count = etcr[0] ? etcr[0] : 0x10000; state[submodule].count = etcr[0] ? etcr[0] : 0x10000;
state[submodule].mode_16 = dmacr & 0x8000; 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; int32_t step = state[submodule].mode_16 ? 2 : 1;
state[submodule].incs = dmacr & 0x2000 ? dmacr & 0x4000 ? -step : step : 0; state[submodule].incs = dmacr & 0x2000 ? dmacr & 0x4000 ? -step : step : 0;
state[submodule].incd = dmacr & 0x0020 ? dmacr & 0x0040 ? -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) void h8_dma_channel_device::count_done(int submodule)
{ {
logerror("count done on %d\n", 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(fae) {
if(dmacr & 0x0800) if(dmacr & 0x0800)
throw emu_fatalerror("%s: DMA count done full address/block mode unimplemented.\n", tag()); throw emu_fatalerror("%s: DMA count done full address/block mode unimplemented.\n", tag());
else { else {
dte &= ~1; dte &= ~1;
dmac->clear_dte(state[0].id); dmac->clear_dte(state[0].id);
dtcr[0] &= ~0x80; // clear DTE (for H8H)
if(dtie & 1) if(dtie & 1)
throw emu_fatalerror("%s: DMA end-of-transfer interrupt in full address/normal mode unimplemented.\n", tag()); throw emu_fatalerror("%s: DMA end-of-transfer interrupt in full address/normal mode unimplemented.\n", tag());
} }

View File

@ -19,6 +19,8 @@ struct h8_dma_state {
int32_t incs, incd; int32_t incs, incd;
uint32_t count; uint32_t count;
int id; int id;
bool autoreq; // activate by auto-request
bool suspended;
bool mode_16; bool mode_16;
}; };
@ -31,6 +33,19 @@ struct h8_dma_state {
class h8_dma_channel_device; class h8_dma_channel_device;
enum {
// mind the order, all DREQ, TEND need to be sequential
H8_INPUT_LINE_DREQ0 = INPUT_LINE_IRQ9 + 1,
H8_INPUT_LINE_DREQ1,
H8_INPUT_LINE_DREQ2,
H8_INPUT_LINE_DREQ3,
H8_INPUT_LINE_TEND0,
H8_INPUT_LINE_TEND1,
H8_INPUT_LINE_TEND2,
H8_INPUT_LINE_TEND3,
};
class h8_dma_device : public device_t { class h8_dma_device : public device_t {
public: public:
h8_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); h8_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@ -43,15 +58,20 @@ public:
DECLARE_WRITE16_MEMBER(dmabcr_w); DECLARE_WRITE16_MEMBER(dmabcr_w);
bool trigger_dma(int vector); bool trigger_dma(int vector);
void count_last(int id);
void count_done(int id); void count_done(int id);
void clear_dte(int id); void clear_dte(int id);
void set_input(int inputnum, int state);
protected: protected:
required_device<h8_dma_channel_device> dmach0, dmach1; required_device<h8_dma_channel_device> dmach0, dmach1;
virtual void device_start() override; virtual void device_start() override;
virtual void device_reset() override; virtual void device_reset() override;
bool dreq[2];
uint8_t dmawer, dmatcr; uint8_t dmawer, dmatcr;
uint16_t dmabcr; uint16_t dmabcr;
}; };
@ -96,9 +116,16 @@ public:
DECLARE_READ16_MEMBER(dmacr_r); DECLARE_READ16_MEMBER(dmacr_r);
DECLARE_WRITE16_MEMBER(dmacr_w); DECLARE_WRITE16_MEMBER(dmacr_w);
// H8H DMA
DECLARE_READ8_MEMBER(dtcra_r);
DECLARE_WRITE8_MEMBER(dtcra_w);
DECLARE_READ8_MEMBER(dtcrb_r);
DECLARE_WRITE8_MEMBER(dtcrb_w);
void set_id(int id); void set_id(int id);
void set_bcr(bool fae, bool sae, uint8_t dta, uint8_t dte, uint8_t dtie); void set_bcr(bool fae, bool sae, uint8_t dta, uint8_t dte, uint8_t dtie);
bool start_test(int vector); bool start_test(int vector);
void count_last(int submodule);
void count_done(int submodule); void count_done(int submodule);
protected: protected:
required_device<h8_dma_device> dmac; required_device<h8_dma_device> dmac;
@ -112,12 +139,15 @@ protected:
uint32_t mar[2]; uint32_t mar[2];
uint16_t ioar[2], etcr[2], dmacr; uint16_t ioar[2], etcr[2], dmacr;
uint8_t dtcr[2]; // H8H
uint8_t dta, dte, dtie; uint8_t dta, dte, dtie;
bool fae, sae; bool fae; // Full-Address Mode
bool sae; // Short-Address Mode
virtual void device_start() override; virtual void device_start() override;
virtual void device_reset() override; virtual void device_reset() override;
void h8h_sync(); // call set_bcr with contents from DTCR
void start(int submodule); void start(int submodule);
}; };