From 1f485e69baa95aabcb75e060ed1bdb3664b2fcb9 Mon Sep 17 00:00:00 2001 From: Dirk Best Date: Wed, 14 Aug 2013 09:43:00 +0000 Subject: [PATCH] i8089.c: move execute interface to the main device, the two channels can't really run at the same time --- src/emu/machine/i8089.c | 667 ++++++++++++++++++++-------------------- src/emu/machine/i8089.h | 8 +- 2 files changed, 341 insertions(+), 334 deletions(-) diff --git a/src/emu/machine/i8089.c b/src/emu/machine/i8089.c index 3b8ba65e905..560c432ba95 100644 --- a/src/emu/machine/i8089.c +++ b/src/emu/machine/i8089.c @@ -39,8 +39,7 @@ const device_type I8089_CHANNEL = &device_creator; -class i8089_channel : public device_t, - public device_execute_interface +class i8089_channel : public device_t { public: // construction/destruction @@ -49,9 +48,16 @@ public: template void set_sintr_callback(_sintr sintr) { m_write_sintr.set_callback(sintr); } void set_control_block(offs_t address); + + int execute_run(); void attention(); - bool priority(); - bool bus_load_limit(); + + // channel status + bool executing() { return BIT(m_r[PSW].w, 2); } + bool transferring() { return BIT(m_r[PSW].w, 6); } + bool priority() { return BIT(m_r[PSW].w, 7); } + bool chained() { return CC_CHAIN; } + bool lock() { return CC_LOCK; } DECLARE_WRITE_LINE_MEMBER( ext_w ); DECLARE_WRITE_LINE_MEMBER( drq_w ); @@ -60,9 +66,6 @@ protected: // device-level overrides virtual void device_start(); virtual void device_reset(); - virtual void execute_run(); - - int m_icount; private: @@ -162,6 +165,8 @@ private: i8089_device *m_iop; + int m_icount; + // dma void terminate_dma(int offset); @@ -211,9 +216,8 @@ private: i8089_channel::i8089_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, I8089_CHANNEL, "Intel 8089 I/O Channel", tag, owner, clock, "i8089_channel", __FILE__), - device_execute_interface(mconfig, *this), - m_icount(0), m_write_sintr(*this), + m_icount(0), m_xfer_pending(false), m_dma_value(0), m_dma_state(DMA_IDLE) @@ -225,9 +229,6 @@ void i8089_channel::device_start() // get parent device m_iop = downcast(owner()); - // set our instruction counter - m_icountptr = &m_icount; - // resolve callbacks m_write_sintr.resolve_safe(); @@ -308,332 +309,334 @@ UINT16 i8089_channel::imm16() // adjust task pointer and continue execution void i8089_channel::terminate_dma(int offset) { - logerror("%s('%s'): terminating dma transfer\n", shortname(), tag()); + if (VERBOSE) + logerror("%s('%s'): terminating dma transfer\n", shortname(), tag()); + m_r[TP].w += offset; m_r[PSW].w |= 1 << 2; m_r[PSW].w &= ~(1 << 6); m_dma_state = DMA_IDLE; } -void i8089_channel::execute_run() +int i8089_channel::execute_run() { - do - { - // active transfer? - if (BIT(m_r[PSW].w, 6)) - { - // new transfer? - if (BIT(m_r[PSW].w, 2)) - { - // we are no longer executing task blocks - m_r[PSW].w &= ~(1 << 2); - m_xfer_pending = false; + m_icount = 0; - if (VERBOSE) - { - logerror("%s('%s'): ---- starting dma transfer ----\n", shortname(), tag()); - logerror("%s('%s'): ga = %06x, gb = %06x, gc = %06x\n", shortname(), tag(), m_r[GA].w, m_r[GB].w, m_r[GC].w); - logerror("%s('%s'): bc = %04x, cc = %04x, mc = %04x\n", shortname(), tag(), m_r[BC].w, m_r[CC].w, m_r[MC].w); - } + // active transfer? + if (transferring()) + { + // new transfer? + if (executing()) + { + // we are no longer executing task blocks + m_r[PSW].w &= ~(1 << 2); + m_xfer_pending = false; + + if (VERBOSE) + { + logerror("%s('%s'): ---- starting dma transfer ----\n", shortname(), tag()); + logerror("%s('%s'): ga = %06x, gb = %06x, gc = %06x\n", shortname(), tag(), m_r[GA].w, m_r[GB].w, m_r[GC].w); + logerror("%s('%s'): bc = %04x, cc = %04x, mc = %04x\n", shortname(), tag(), m_r[BC].w, m_r[CC].w, m_r[MC].w); + } + } + + // todo: port transfers + if (CC_FUNC != 0x03) + fatalerror("%s('%s'): port transfer\n", shortname(), tag()); + + switch (m_dma_state) + { + case DMA_IDLE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_IDLE (bc = %04x)\n", shortname(), tag(), m_r[BC].w); + + // synchronize on source? + if (CC_SYNC == 0x01) + m_dma_state = DMA_WAIT_FOR_SOURCE_DRQ; + else + m_dma_state = DMA_FETCH; + break; + + case DMA_WAIT_FOR_SOURCE_DRQ: + fatalerror("%s('%s'): wait for source drq not supported\n", shortname(), tag()); + break; + + case DMA_FETCH: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_FETCH", shortname(), tag()); + + // source is 16-bit? + if (BIT(m_r[PSW].w, 1)) + { + m_dma_value = m_iop->read_word(m_r[GA + CC_SOURCE].w); + m_r[GA + CC_SOURCE].w += 2; + m_r[BC].w -= 2; + } + // destination is 16-bit, byte count is even + else if (BIT(m_r[PSW].w, 0) && !(m_r[BC].w & 1)) + { + m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; + } + // destination is 16-bit, byte count is odd + else if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) + { + m_dma_value |= m_iop->read_byte(m_r[GA + CC_SOURCE].w) << 8; + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; + } + // 8-bit transfer + else + { + m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; } - // todo: port transfers - if (CC_FUNC != 0x03) - fatalerror("%s('%s'): port transfer\n", shortname(), tag()); + if (VERBOSE_DMA) + logerror("[ %04x ]\n", m_dma_value); - switch (m_dma_state) + if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) + m_dma_state = DMA_FETCH; + else if (CC_TRANS) + m_dma_state = DMA_TRANSLATE; + else if (CC_SYNC == 0x02) + m_dma_state = DMA_WAIT_FOR_DEST_DRQ; + else + m_dma_state = DMA_STORE; + + break; + + case DMA_TRANSLATE: + fatalerror("%s('%s'): dma translate requested\n", shortname(), tag()); + break; + + case DMA_WAIT_FOR_DEST_DRQ: + fatalerror("%s('%s'): wait for destination drq not supported\n", shortname(), tag()); + break; + + case DMA_STORE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_STORE", shortname(), tag()); + + // destination is 16-bit? + if (BIT(m_r[PSW].w, 0)) { - case DMA_IDLE: - if (VERBOSE_DMA) - logerror("%s('%s'): entering state: DMA_IDLE (bc = %04x)\n", shortname(), tag(), m_r[BC].w); - - // synchronize on source? - if (CC_SYNC == 0x01) - m_dma_state = DMA_WAIT_FOR_SOURCE_DRQ; - else - m_dma_state = DMA_FETCH; - break; - - case DMA_WAIT_FOR_SOURCE_DRQ: - fatalerror("%s('%s'): wait for source drq not supported\n", shortname(), tag()); - break; - - case DMA_FETCH: - if (VERBOSE_DMA) - logerror("%s('%s'): entering state: DMA_FETCH", shortname(), tag()); - - // source is 16-bit? - if (BIT(m_r[PSW].w, 1)) - { - m_dma_value = m_iop->read_word(m_r[GA + CC_SOURCE].w); - m_r[GA + CC_SOURCE].w += 2; - m_r[BC].w -= 2; - } - // destination is 16-bit, byte count is even - else if (BIT(m_r[PSW].w, 0) && !(m_r[BC].w & 1)) - { - m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); - m_r[GA + CC_SOURCE].w++; - m_r[BC].w--; - } - // destination is 16-bit, byte count is odd - else if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) - { - m_dma_value |= m_iop->read_byte(m_r[GA + CC_SOURCE].w) << 8; - m_r[GA + CC_SOURCE].w++; - m_r[BC].w--; - } - // 8-bit transfer - else - { - m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].w); - m_r[GA + CC_SOURCE].w++; - m_r[BC].w--; - } + m_iop->write_word(m_r[GB - CC_SOURCE].w, m_dma_value); + m_r[GB - CC_SOURCE].w += 2; if (VERBOSE_DMA) logerror("[ %04x ]\n", m_dma_value); - - if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) - m_dma_state = DMA_FETCH; - else if (CC_TRANS) - m_dma_state = DMA_TRANSLATE; - else if (CC_SYNC == 0x02) - m_dma_state = DMA_WAIT_FOR_DEST_DRQ; - else - m_dma_state = DMA_STORE; - - break; - - case DMA_TRANSLATE: - fatalerror("%s('%s'): dma translate requested\n", shortname(), tag()); - break; - - case DMA_WAIT_FOR_DEST_DRQ: - fatalerror("%s('%s'): wait for destination drq not supported\n", shortname(), tag()); - break; - - case DMA_STORE: - if (VERBOSE_DMA) - logerror("%s('%s'): entering state: DMA_STORE", shortname(), tag()); - - // destination is 16-bit? - if (BIT(m_r[PSW].w, 0)) - { - m_iop->write_word(m_r[GB - CC_SOURCE].w, m_dma_value); - m_r[GB - CC_SOURCE].w += 2; - - if (VERBOSE_DMA) - logerror("[ %04x ]\n", m_dma_value); - } - // destination is 8-bit - else - { - m_iop->write_byte(m_r[GB - CC_SOURCE].w, m_dma_value & 0xff); - m_r[GB - CC_SOURCE].w++; - - if (VERBOSE_DMA) - logerror("[ %02x ]\n", m_dma_value & 0xff); - } - - if (CC_TMC & 0x03) - m_dma_state = DMA_COMPARE; - else - m_dma_state = DMA_TERMINATE; - - break; - - case DMA_COMPARE: - fatalerror("%s('%s'): dma compare requested\n", shortname(), tag()); - break; - - case DMA_TERMINATE: - if (VERBOSE_DMA) - logerror("%s('%s'): entering state: DMA_TERMINATE\n", shortname(), tag()); - - // terminate on masked compare? - if (CC_TMC & 0x03) - fatalerror("%s('%s'): terminate on masked compare not supported\n", shortname(), tag()); - - // terminate on byte count? - else if (CC_TBC && m_r[BC].w == 0) - terminate_dma((CC_TBC - 1) * 4); - - // terminate on external signal - else if (CC_TX) - fatalerror("%s('%s'): terminate on external signal not supported\n", shortname(), tag()); - - // terminate on single transfer - else if (CC_TS) - fatalerror("%s('%s'): terminate on single transfer not supported\n", shortname(), tag()); - - // not terminated, continue transfer - else - // do we need to read another byte? - if (BIT(m_r[PSW].w, 1) && !BIT(m_r[PSW].w, 0)) - if (CC_SYNC == 0x02) - m_dma_state = DMA_WAIT_FOR_DEST_DRQ; - else - m_dma_state = DMA_STORE_BYTE_HIGH; - - // transfer done - else - m_dma_state = DMA_IDLE; - - break; - - case DMA_STORE_BYTE_HIGH: - if (VERBOSE_DMA) - logerror("%s('%s'): entering state: DMA_STORE_BYTE_HIGH[ %02x ]\n", shortname(), tag(), (m_dma_value >> 8) & 0xff); - - m_iop->write_byte(m_r[GB - CC_SOURCE].w, (m_dma_value >> 8) & 0xff); + } + // destination is 8-bit + else + { + m_iop->write_byte(m_r[GB - CC_SOURCE].w, m_dma_value & 0xff); m_r[GB - CC_SOURCE].w++; + + if (VERBOSE_DMA) + logerror("[ %02x ]\n", m_dma_value & 0xff); + } + + if (CC_TMC & 0x03) + m_dma_state = DMA_COMPARE; + else m_dma_state = DMA_TERMINATE; - break; - } + break; - m_icount--; + case DMA_COMPARE: + fatalerror("%s('%s'): dma compare requested\n", shortname(), tag()); + break; + + case DMA_TERMINATE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_TERMINATE\n", shortname(), tag()); + + // terminate on masked compare? + if (CC_TMC & 0x03) + fatalerror("%s('%s'): terminate on masked compare not supported\n", shortname(), tag()); + + // terminate on byte count? + else if (CC_TBC && m_r[BC].w == 0) + terminate_dma((CC_TBC - 1) * 4); + + // terminate on external signal + else if (CC_TX) + fatalerror("%s('%s'): terminate on external signal not supported\n", shortname(), tag()); + + // terminate on single transfer + else if (CC_TS) + fatalerror("%s('%s'): terminate on single transfer not supported\n", shortname(), tag()); + + // not terminated, continue transfer + else + // do we need to read another byte? + if (BIT(m_r[PSW].w, 1) && !BIT(m_r[PSW].w, 0)) + if (CC_SYNC == 0x02) + m_dma_state = DMA_WAIT_FOR_DEST_DRQ; + else + m_dma_state = DMA_STORE_BYTE_HIGH; + + // transfer done + else + m_dma_state = DMA_IDLE; + + break; + + case DMA_STORE_BYTE_HIGH: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_STORE_BYTE_HIGH[ %02x ]\n", shortname(), tag(), (m_dma_value >> 8) & 0xff); + + m_iop->write_byte(m_r[GB - CC_SOURCE].w, (m_dma_value >> 8) & 0xff); + m_r[GB - CC_SOURCE].w++; + m_dma_state = DMA_TERMINATE; + + break; } - // executing task block instructions? - else if (BIT(m_r[PSW].w, 2)) - { - // dma transfer pending? - if (m_xfer_pending) - m_r[PSW].w |= 1 << 6; - - // fetch first two instruction bytes - UINT16 op = m_iop->read_word(m_r[TP].w); - m_r[TP].w += 2; - - // extract parameters - UINT8 params = op & 0xff; - UINT8 opcode = (op >> 8) & 0xff; - - int brp = (params >> 5) & 0x07; - int wb = (params >> 3) & 0x03; - int aa = (params >> 1) & 0x03; - int w = (params >> 0) & 0x01; - int opc = (opcode >> 2) & 0x3f; - int mm = (opcode >> 0) & 0x03; - - // fix-up so we can use our register array - if (mm == BC) mm = PP; - - UINT8 o; - UINT16 off, seg; - - logerror("%s('%s'): executing %x %x %x %x %02x %x\n", shortname(), tag(), brp, wb, aa, w, opc, mm); - - switch (opc) - { - case 0x00: // control - switch (brp) - { - case 0: nop(); break; - case 1: invalid(opc); break; - case 2: sintr(); break; - case 3: xfer(); break; - default: wid(BIT(brp, 1), BIT(brp, 0)); - } - break; - - case 0x02: // lpdi - off = imm16(); - seg = imm16(); - lpdi(brp, seg, off); - break; - - case 0x08: // add(b)i r, i - if (w) addi_ri(brp, imm16()); - else addbi_ri(brp, imm8()); - break; - - case 0x0a: // and(b)i r, i - if (w) andi_ri(brp, imm16()); - else andbi_ri(brp, imm8()); - break; - - case 0x0c: // mov(b)i r, i - if (w) movi_ri(brp, imm16()); - else movbi_ri(brp, imm8()); - break; - - case 0x0f: // dec r - dec_r(brp); - break; - - case 0x12: // hlt - if (BIT(brp, 0)) - hlt(); - break; - - case 0x22: // lpd - o = offset(aa); - lpd(brp, mm, o); - break; - - case 0x28: // add(b) r, m - if (w) add_rm(brp, mm, offset(aa)); - else addb_rm(brp, mm, offset(aa)); - break; - - case 0x2a: // and(b) r, m - if (w) and_rm(brp, mm, offset(aa)); - else andb_rm(brp, mm, offset(aa)); - break; - - case 0x27: // call - o = offset(aa); - call(mm, displacement(wb), o); - break; - - case 0x30: // add(b)i m, i - o = offset(aa); - if (w) addi_mi(mm, imm16(), o); - else addbi_mi(mm, imm8(), o); - break; - - case 0x32: // and(b)i m, i - o = offset(aa); - if (w) andi_mi(mm, imm16()); - else andbi_mi(mm, imm8()); - break; - - case 0x34: // add(b) m, r - if (w) add_mr(mm, brp, offset(aa)); - else addb_mr(mm, brp, offset(aa)); - break; - - case 0x36: // and(b) m, r - if (w) and_mr(mm, brp, offset(aa)); - else andb_mr(mm, brp, offset(aa)); - break; - - case 0x3b: // dec(b) m - if (w) dec_m(mm, offset(aa)); - else decb(mm, offset(aa)); - break; - - case 0x3e: // clr - clr(mm, brp, offset(aa)); - break; - - default: - invalid(opc); - } - - m_icount--; - } - - // nothing to do - else - { - m_icount--; - } + m_icount++; } - while (m_icount > 0); + + // executing task block instructions? + else if (executing()) + { + // dma transfer pending? + if (m_xfer_pending) + m_r[PSW].w |= 1 << 6; + + // fetch first two instruction bytes + UINT16 op = m_iop->read_word(m_r[TP].w); + m_r[TP].w += 2; + + // extract parameters + UINT8 params = op & 0xff; + UINT8 opcode = (op >> 8) & 0xff; + + int brp = (params >> 5) & 0x07; + int wb = (params >> 3) & 0x03; + int aa = (params >> 1) & 0x03; + int w = (params >> 0) & 0x01; + int opc = (opcode >> 2) & 0x3f; + int mm = (opcode >> 0) & 0x03; + + // fix-up so we can use our register array + if (mm == BC) mm = PP; + + UINT8 o; + UINT16 off, seg; + + logerror("%s('%s'): executing %x %x %x %x %02x %x\n", shortname(), tag(), brp, wb, aa, w, opc, mm); + + switch (opc) + { + case 0x00: // control + switch (brp) + { + case 0: nop(); break; + case 1: invalid(opc); break; + case 2: sintr(); break; + case 3: xfer(); break; + default: wid(BIT(brp, 1), BIT(brp, 0)); + } + break; + + case 0x02: // lpdi + off = imm16(); + seg = imm16(); + lpdi(brp, seg, off); + break; + + case 0x08: // add(b)i r, i + if (w) addi_ri(brp, imm16()); + else addbi_ri(brp, imm8()); + break; + + case 0x0a: // and(b)i r, i + if (w) andi_ri(brp, imm16()); + else andbi_ri(brp, imm8()); + break; + + case 0x0c: // mov(b)i r, i + if (w) movi_ri(brp, imm16()); + else movbi_ri(brp, imm8()); + break; + + case 0x0f: // dec r + dec_r(brp); + break; + + case 0x12: // hlt + if (BIT(brp, 0)) hlt(); + else invalid(opc); + break; + + case 0x22: // lpd + o = offset(aa); + lpd(brp, mm, o); + break; + + case 0x28: // add(b) r, m + if (w) add_rm(brp, mm, offset(aa)); + else addb_rm(brp, mm, offset(aa)); + break; + + case 0x2a: // and(b) r, m + if (w) and_rm(brp, mm, offset(aa)); + else andb_rm(brp, mm, offset(aa)); + break; + + case 0x27: // call + o = offset(aa); + call(mm, displacement(wb), o); + break; + + case 0x30: // add(b)i m, i + o = offset(aa); + if (w) addi_mi(mm, imm16(), o); + else addbi_mi(mm, imm8(), o); + break; + + case 0x32: // and(b)i m, i + o = offset(aa); + if (w) andi_mi(mm, imm16()); + else andbi_mi(mm, imm8()); + break; + + case 0x34: // add(b) m, r + if (w) add_mr(mm, brp, offset(aa)); + else addb_mr(mm, brp, offset(aa)); + break; + + case 0x36: // and(b) m, r + if (w) and_mr(mm, brp, offset(aa)); + else andb_mr(mm, brp, offset(aa)); + break; + + case 0x3b: // dec(b) m + if (w) dec_m(mm, offset(aa)); + else decb(mm, offset(aa)); + break; + + case 0x3e: // clr + clr(mm, brp, offset(aa)); + break; + + default: + invalid(opc); + } + + m_icount++; + } + + // nothing to do + else + { + m_icount++; + } + + return m_icount; } void i8089_channel::set_control_block(offs_t address) @@ -641,16 +644,6 @@ void i8089_channel::set_control_block(offs_t address) m_r[CP].w = address; } -bool i8089_channel::bus_load_limit() -{ - return BIT(m_r[PSW].w, 5); -} - -bool i8089_channel::priority() -{ - return BIT(m_r[PSW].w, 7); -} - void i8089_channel::examine_ccw(UINT8 ccw) { // priority and bus load limit, bit 7 and 5 @@ -1010,6 +1003,8 @@ const device_type I8089 = &device_creator; i8089_device::i8089_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, I8089, "Intel 8089", tag, owner, clock, "i8089", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), m_ch1(*this, "1"), m_ch2(*this, "2"), m_write_sintr1(*this), @@ -1035,9 +1030,8 @@ void i8089_device::static_set_cputag(device_t &device, const char *tag) void i8089_device::device_start() { - // make sure our channels have been setup first - if (!m_ch1->started() || !m_ch2->started()) - throw device_missing_dependencies(); + // set our instruction counter + m_icountptr = &m_icount; // resolve callbacks m_write_sintr1.resolve_safe(); @@ -1055,10 +1049,6 @@ void i8089_device::device_start() device_t *cpu = machine().device(m_cputag); m_mem = &cpu->memory().space(AS_PROGRAM); m_io = &cpu->memory().space(AS_IO); - - // initialize channel clock - m_ch1->set_unscaled_clock(clock()); - m_ch2->set_unscaled_clock(clock()); } //------------------------------------------------- @@ -1194,6 +1184,17 @@ void i8089_device::write_word(offs_t address, UINT16 data) } } +void i8089_device::execute_run() +{ + do + { + // allocate cycles to the two channels, very very incomplete + m_icount -= m_ch1->execute_run(); + m_icount -= m_ch2->execute_run(); + } + while (m_icount > 0); +} + //************************************************************************** // EXTERNAL INPUTS diff --git a/src/emu/machine/i8089.h b/src/emu/machine/i8089.h index 5f7b2961c44..04f25e1e51c 100644 --- a/src/emu/machine/i8089.h +++ b/src/emu/machine/i8089.h @@ -36,7 +36,8 @@ class i8089_channel; // ======================> i8089_device -class i8089_device : public device_t +class i8089_device : public device_t, + public device_execute_interface { friend class i8089_channel; @@ -68,6 +69,11 @@ protected: virtual void device_start(); virtual void device_reset(); + // device_execute_interface overrides + virtual void execute_run(); + + int m_icount; + // optional information overrides virtual machine_config_constructor device_mconfig_additions() const;