diff --git a/.gitattributes b/.gitattributes index eedb25ecb24..5bbf079f240 100644 --- a/.gitattributes +++ b/.gitattributes @@ -512,6 +512,12 @@ src/emu/cpu/i8085/8085dasm.c svneol=native#text/plain src/emu/cpu/i8085/i8085.c svneol=native#text/plain src/emu/cpu/i8085/i8085.h svneol=native#text/plain src/emu/cpu/i8085/i8085cpu.h svneol=native#text/plain +src/emu/cpu/i8089/i8089.c svneol=native#text/plain +src/emu/cpu/i8089/i8089.h svneol=native#text/plain +src/emu/cpu/i8089/i8089_channel.c svneol=native#text/plain +src/emu/cpu/i8089/i8089_channel.h svneol=native#text/plain +src/emu/cpu/i8089/i8089_dasm.c svneol=native#text/plain +src/emu/cpu/i8089/i8089_ops.c svneol=native#text/plain src/emu/cpu/i86/i186.c svneol=native#text/plain src/emu/cpu/i86/i186.h svneol=native#text/plain src/emu/cpu/i86/i286.c svneol=native#text/plain @@ -1254,8 +1260,6 @@ src/emu/machine/generic.c svneol=native#text/plain src/emu/machine/generic.h svneol=native#text/plain src/emu/machine/i2cmem.c svneol=native#text/plain src/emu/machine/i2cmem.h svneol=native#text/plain -src/emu/machine/i8089.c svneol=native#text/plain -src/emu/machine/i8089.h svneol=native#text/plain src/emu/machine/i8155.c svneol=native#text/plain src/emu/machine/i8155.h svneol=native#text/plain src/emu/machine/i8212.c svneol=native#text/plain diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 989ed1ed979..1bd5e7f7d69 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -718,6 +718,25 @@ $(CPUOBJ)/i8085/i8085.o: $(CPUSRC)/i8085/i8085.c \ $(CPUSRC)/i8085/i8085cpu.h +#------------------------------------------------- +# Intel 8089 +#@src/emu/cpu/i8085/i8089.h,CPUS += I8089 +#------------------------------------------------- + +ifneq ($(filter I8089,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/i8089 +CPUOBJS += $(CPUOBJ)/i8089/i8089.o \ + $(CPUOBJ)/i8089/i8089_channel.o \ + $(CPUOBJ)/i8089/i8089_ops.o +DASMOBJS += $(CPUOBJ)/i8089/i8089_dasm.o +endif + +$(CPUOBJ)/i8089/i8089_ops.o: $(CPUSRC)/i8089/i8089_channel.h +$(CPUOBJ)/i8089/i8089_channel.o: $(CPUSRC)/i8089/i8089_channel.h + +$(CPUOBJ)/i8089/i8089.o: $(CPUSRC)/i8089/i8089.c \ + $(CPUSRC)/i8089/i8089.h + #------------------------------------------------- # Intel MCS-48 (8039 and derivatives) diff --git a/src/emu/cpu/i8089/i8089.c b/src/emu/cpu/i8089/i8089.c new file mode 100644 index 00000000000..c4ad5e35824 --- /dev/null +++ b/src/emu/cpu/i8089/i8089.c @@ -0,0 +1,348 @@ +/*************************************************************************** + + Intel 8089 I/O Processor + +***************************************************************************/ + +#include "i8089.h" +#include "i8089_channel.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8089 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8089_device - constructor +//------------------------------------------------- + +i8089_device::i8089_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpu_device(mconfig, I8089, "Intel 8089", tag, owner, clock, "i8089", __FILE__), + m_icount(0), + m_ch1(*this, "1"), + m_ch2(*this, "2"), + m_write_sintr1(*this), + m_write_sintr2(*this), + m_16bit_system(false), + m_16bit_remote(false), + m_master(false), + m_request_grant(false), + m_current_tp(0), + m_ca(0), + m_sel(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8089_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_write_sintr1.resolve_safe(); + m_write_sintr2.resolve_safe(); + + // register debugger states + state_add(i8089_channel::GA, "CH1 GA", m_ch1->m_r[i8089_channel::GA].w).mask(0xfffff); + state_add(i8089_channel::GB, "CH1 GB", m_ch1->m_r[i8089_channel::GB].w).mask(0xfffff); + state_add(i8089_channel::GC, "CH1 GC", m_ch1->m_r[i8089_channel::GC].w).mask(0xfffff); + state_add(i8089_channel::TP, "CH1 TP", m_ch1->m_r[i8089_channel::TP].w).mask(0xfffff); + state_add(i8089_channel::BC, "CH1 BC", m_ch1->m_r[i8089_channel::BC].w).mask(0xffff); + state_add(i8089_channel::IX, "CH1 IX", m_ch1->m_r[i8089_channel::IX].w).mask(0xffff); + state_add(i8089_channel::CC, "CH1 CC", m_ch1->m_r[i8089_channel::CC].w).mask(0xffff); + state_add(i8089_channel::MC, "CH1 MC", m_ch1->m_r[i8089_channel::MC].w).mask(0xffff); + state_add(i8089_channel::CP, "CH1 CP", m_ch1->m_r[i8089_channel::CP].w).mask(0xfffff); + state_add(i8089_channel::PP, "CH1 PP", m_ch1->m_r[i8089_channel::PP].w).mask(0xfffff); + state_add(i8089_channel::PSW, "CH1 PSW", m_ch1->m_r[i8089_channel::PSW].w).callimport().callexport().formatstr("%12s"); + + state_add(i8089_channel::GA + i8089_channel::NUM_REGS, "CH2 GA", m_ch2->m_r[i8089_channel::GA].w).mask(0xfffff); + state_add(i8089_channel::GB + i8089_channel::NUM_REGS, "CH2 GB", m_ch2->m_r[i8089_channel::GB].w).mask(0xfffff); + state_add(i8089_channel::GC + i8089_channel::NUM_REGS, "CH2 GC", m_ch2->m_r[i8089_channel::GC].w).mask(0xfffff); + state_add(i8089_channel::TP + i8089_channel::NUM_REGS, "CH2 TP", m_ch2->m_r[i8089_channel::TP].w).mask(0xfffff); + state_add(i8089_channel::BC + i8089_channel::NUM_REGS, "CH2 BC", m_ch2->m_r[i8089_channel::BC].w).mask(0xffff); + state_add(i8089_channel::IX + i8089_channel::NUM_REGS, "CH2 IX", m_ch2->m_r[i8089_channel::IX].w).mask(0xffff); + state_add(i8089_channel::CC + i8089_channel::NUM_REGS, "CH2 CC", m_ch2->m_r[i8089_channel::CC].w).mask(0xffff); + state_add(i8089_channel::MC + i8089_channel::NUM_REGS, "CH2 MC", m_ch2->m_r[i8089_channel::MC].w).mask(0xffff); + state_add(i8089_channel::CP + i8089_channel::NUM_REGS, "CH2 CP", m_ch2->m_r[i8089_channel::CP].w).mask(0xfffff); + state_add(i8089_channel::PP + i8089_channel::NUM_REGS, "CH2 PP", m_ch2->m_r[i8089_channel::PP].w).mask(0xfffff); + state_add(i8089_channel::PSW + i8089_channel::NUM_REGS, "CH2 PSW", m_ch2->m_r[i8089_channel::PSW].w).callimport().callexport().formatstr("%12s"); + + state_add(STATE_GENPC, "GENPC", m_current_tp).mask(0xfffff).noshow(); + + // register for save states + save_item(NAME(m_16bit_system)); + save_item(NAME(m_16bit_remote)); + save_item(NAME(m_master)); + save_item(NAME(m_request_grant)); + save_item(NAME(m_ca)); + save_item(NAME(m_sel)); + + // assign memory spaces + m_mem = &space(AS_PROGRAM); + m_io = &space(AS_IO); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8089_device::device_config_complete() +{ + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, m_databus_width, 20); + m_io_config = address_space_config("io", ENDIANNESS_LITTLE, m_databus_width, 16); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8089_device::device_reset() +{ + m_initialized = false; +} + +//------------------------------------------------- +// memory_space_config - device-specific address +// space configurations +//------------------------------------------------- + +const address_space_config *i8089_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + default: return NULL; + } +} + +//------------------------------------------------- +// disasm_disassemble - disassembler +//------------------------------------------------- + +offs_t i8089_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(i8089); + return CPU_DISASSEMBLE_NAME(i8089)(this, buffer, pc, oprom, opram, options); +} + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void i8089_device::state_string_export(const device_state_entry &entry, astring &string) +{ + switch (entry.index()) + { + case i8089_channel::PSW: + string.printf("%c%s%c%s%s%s%c%c", + BIT(m_ch1->m_r[i8089_channel::PSW].w, 7) ? 'P':'.', + BIT(m_ch1->m_r[i8089_channel::PSW].w, 6) ? "XF":"..", + BIT(m_ch1->m_r[i8089_channel::PSW].w, 5) ? 'B':'.', + BIT(m_ch1->m_r[i8089_channel::PSW].w, 4) ? "IS":"..", + BIT(m_ch1->m_r[i8089_channel::PSW].w, 3) ? "IC":"..", + BIT(m_ch1->m_r[i8089_channel::PSW].w, 2) ? "TB":"..", + BIT(m_ch1->m_r[i8089_channel::PSW].w, 1) ? 'S':'.', + BIT(m_ch1->m_r[i8089_channel::PSW].w, 0) ? 'D':'.'); + break; + + case i8089_channel::PSW + i8089_channel::NUM_REGS: + string.printf("%c%s%c%s%s%s%c%c", + BIT(m_ch2->m_r[i8089_channel::PSW].w, 7) ? 'P':'.', + BIT(m_ch2->m_r[i8089_channel::PSW].w, 6) ? "XF":"..", + BIT(m_ch2->m_r[i8089_channel::PSW].w, 5) ? 'B':'.', + BIT(m_ch2->m_r[i8089_channel::PSW].w, 4) ? "IS":"..", + BIT(m_ch2->m_r[i8089_channel::PSW].w, 3) ? "IC":"..", + BIT(m_ch2->m_r[i8089_channel::PSW].w, 2) ? "TB":"..", + BIT(m_ch2->m_r[i8089_channel::PSW].w, 1) ? 'S':'.', + BIT(m_ch2->m_r[i8089_channel::PSW].w, 0) ? 'D':'.'); + break; + } +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( i8089 ) + MCFG_I8089_CHANNEL_ADD("1") + MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch1_sintr_w)) + MCFG_I8089_CHANNEL_ADD("2") + MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch2_sintr_w)) +MACHINE_CONFIG_END + +machine_config_constructor i8089_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( i8089 ); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +// the i8089 actually executes a program from internal rom here: +// +// MOVB SYSBUS from FFFF6 +// LPD System Configuration Block from FFFF8 +// MOVB SOC from (SCB) +// LPD Control Pointer (CP) from (SCB) + 2 +// MOVBI "00" to CP + 1 (clear busy flag) + +void i8089_device::initialize() +{ + assert(!m_initialized); + + // get system bus width + UINT8 sys_bus = m_mem->read_byte(0xffff6); + m_16bit_system = BIT(sys_bus, 0); + + // get system configuration block address + UINT16 scb_offset = read_word(0xffff8); + UINT16 scb_segment = read_word(0xffffa); + offs_t scb_address = ((scb_segment << 4) + scb_offset) & 0x0fffff; + + // get system operation command + UINT16 soc = read_word(scb_address); + m_16bit_remote = BIT(soc, 0); + m_request_grant = BIT(soc, 1); + m_master = !m_sel; + + // get control block address + UINT16 cb_offset = read_word(scb_address + 2); + UINT16 cb_segment = read_word(scb_address + 4); + offs_t cb_address = ((cb_segment << 4) + cb_offset) & 0x0fffff; + + // initialize channels + m_ch1->set_reg(i8089_channel::CP, cb_address); + m_ch2->set_reg(i8089_channel::CP, cb_address + 8); + + // clear busy + UINT16 ccw = read_word(cb_address); + write_word(cb_address, ccw & 0x00ff); + + // done + m_initialized = true; + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag()); + logerror("%s('%s'): %s system bus\n", shortname(), basetag(), m_16bit_system ? "16-bit" : "8-bit"); + logerror("%s('%s'): system configuration block location: %06x\n", shortname(), basetag(), scb_address); + logerror("%s('%s'): %s remote bus\n", shortname(), basetag(), m_16bit_remote ? "16-bit" : "8-bit"); + logerror("%s('%s'): request/grant: %d\n", shortname(), basetag(), m_request_grant); + logerror("%s('%s'): is %s\n", shortname(), basetag(), m_master ? "master" : "slave"); + logerror("%s('%s'): channel control block location: %06x\n", shortname(), basetag(), cb_address); + } +} + +UINT8 i8089_device::read_byte(offs_t address) +{ + assert(m_initialized); + return m_mem->read_byte(address); +} + +UINT16 i8089_device::read_word(offs_t address) +{ + assert(m_initialized); + + UINT16 data = 0xffff; + + if (m_16bit_system && !(address & 1)) + { + data = m_mem->read_word(address); + } + else + { + data = m_mem->read_byte(address); + data |= m_mem->read_byte(address + 1) << 8; + } + + return data; +} + +void i8089_device::write_byte(offs_t address, UINT8 data) +{ + assert(m_initialized); + m_mem->write_byte(address, data); +} + +void i8089_device::write_word(offs_t address, UINT16 data) +{ + assert(m_initialized); + + if (m_16bit_system && !(address & 1)) + { + m_mem->write_word(address, data); + } + else + { + m_mem->write_byte(address, data & 0xff); + m_mem->write_byte(address + 1, (data >> 8) & 0xff); + } +} + +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 +//************************************************************************** + +WRITE_LINE_MEMBER( i8089_device::ca_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ca_w: %u\n", shortname(), basetag(), state); + + if (m_ca == 1 && state == 0) + { + if (!m_initialized) + initialize(); + else + { + if (m_sel == 0) + m_ch1->attention(); + else + m_ch2->attention(); + } + } + + m_ca = state; +} + +WRITE_LINE_MEMBER( i8089_device::drq1_w ) { m_ch1->drq_w(state); } +WRITE_LINE_MEMBER( i8089_device::drq2_w ) { m_ch2->drq_w(state); } +WRITE_LINE_MEMBER( i8089_device::ext1_w ) { m_ch1->ext_w(state); } +WRITE_LINE_MEMBER( i8089_device::ext2_w ) { m_ch2->ext_w(state); } diff --git a/src/emu/machine/i8089.h b/src/emu/cpu/i8089/i8089.h similarity index 71% rename from src/emu/machine/i8089.h rename to src/emu/cpu/i8089/i8089.h index 04f25e1e51c..c758d9e9f52 100644 --- a/src/emu/machine/i8089.h +++ b/src/emu/cpu/i8089/i8089.h @@ -16,9 +16,8 @@ // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define MCFG_I8089_ADD(_tag, _clock, _cputag) \ - MCFG_DEVICE_ADD(_tag, I8089, _clock) \ - i8089_device::static_set_cputag(*device, _cputag); +#define MCFG_I8089_DATABUS_WIDTH(_databus_width) \ + i8089_device::set_databus_width(*device, _databus_width); #define MCFG_I8089_SINTR1(_sintr1) \ downcast(device)->set_sintr1_callback(DEVCB2_##_sintr1); @@ -36,8 +35,7 @@ class i8089_channel; // ======================> i8089_device -class i8089_device : public device_t, - public device_execute_interface +class i8089_device : public cpu_device { friend class i8089_channel; @@ -49,6 +47,9 @@ public: template void set_sintr1_callback(_sintr1 sintr1) { m_write_sintr1.set_callback(sintr1); } template void set_sintr2_callback(_sintr2 sintr2) { m_write_sintr2.set_callback(sintr2); } + // static configuration helpers + static void set_databus_width(device_t &device, UINT8 databus_width) { downcast(device).m_databus_width = databus_width; } + // input lines DECLARE_WRITE_LINE_MEMBER( ca_w ); DECLARE_WRITE_LINE_MEMBER( sel_w ) { m_sel = state; } @@ -61,12 +62,10 @@ public: DECLARE_WRITE_LINE_MEMBER( ch1_sintr_w ) { m_write_sintr1(state); } DECLARE_WRITE_LINE_MEMBER( ch2_sintr_w ) { m_write_sintr2(state); } - // inline configuration - static void static_set_cputag(device_t &device, const char *tag); - protected: // device-level overrides virtual void device_start(); + virtual void device_config_complete(); virtual void device_reset(); // device_execute_interface overrides @@ -74,6 +73,20 @@ protected: int m_icount; + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + address_space_config m_program_config; + address_space_config m_io_config; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, astring &string); + // optional information overrides virtual machine_config_constructor device_mconfig_additions() const; @@ -91,9 +104,7 @@ private: void initialize(); - // internal state - const char *m_cputag; - + UINT8 m_databus_width; address_space *m_mem; address_space *m_io; @@ -104,6 +115,9 @@ private: bool m_master; bool m_request_grant; + // task pointer for the currently executing channel + offs_t m_current_tp; + // state of input pins int m_ca; int m_sel; diff --git a/src/emu/cpu/i8089/i8089_channel.c b/src/emu/cpu/i8089/i8089_channel.c new file mode 100644 index 00000000000..8e9e2833b46 --- /dev/null +++ b/src/emu/cpu/i8089/i8089_channel.c @@ -0,0 +1,641 @@ +/*************************************************************************** + + Intel 8089 I/O Processor + + I/O channel + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "i8089_channel.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define VERBOSE 1 +#define VERBOSE_DMA 1 + +// channel control register fields +#define CC_TMC ((m_r[CC].w >> 0) & 0x07) // terminate on masked compare +#define CC_TBC ((m_r[CC].w >> 3) & 0x03) // terminate on byte count +#define CC_TX ((m_r[CC].w >> 5) & 0x03) // terminate on external signal +#define CC_TS ((m_r[CC].w >> 7) & 0x01) // terminate on single transfer +#define CC_CHAIN ((m_r[CC].w >> 8) & 0x01) // chaining +#define CC_LOCK ((m_r[CC].w >> 9) & 0x01) // actuate lock +#define CC_SOURCE ((m_r[CC].w >> 10) & 0x01) // source register +#define CC_SYNC ((m_r[CC].w >> 11) & 0x03) // synchronization +#define CC_TRANS ((m_r[CC].w >> 13) & 0x01) // translation +#define CC_FUNC ((m_r[CC].w >> 14) & 0x03) // function + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8089_CHANNEL = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8089_channel - constructor +//------------------------------------------------- + +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__), + m_write_sintr(*this), + m_icount(0), + m_xfer_pending(false), + m_dma_value(0), + m_dma_state(DMA_IDLE) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8089_channel::device_start() +{ + // get parent device + m_iop = downcast(owner()); + + // resolve callbacks + m_write_sintr.resolve_safe(); + + // register for save states + save_item(NAME(m_xfer_pending)); + save_item(NAME(m_dma_value)); + save_item(NAME(m_dma_state)); + + for (int i = 0; i < ARRAY_LENGTH(m_r); i++) + { + save_item(NAME(m_r[i].w), i); + save_item(NAME(m_r[i].t), i); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8089_channel::device_reset() +{ + m_xfer_pending = false; + + // initialize registers + for (int i = 0; i < ARRAY_LENGTH(m_r); i++) + { + m_r[i].w = 0; + m_r[i].t = 0; + } +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void i8089_channel::set_reg(int reg, int value, int tag) +{ + m_r[reg].w = value; + + if (tag != -1) + m_r[reg].t = tag; + + if (reg == TP) + m_iop->m_current_tp = value; +} + +// channel status +bool i8089_channel::executing() { return BIT(m_r[PSW].w, 2); } +bool i8089_channel::transferring() { return BIT(m_r[PSW].w, 6); } +bool i8089_channel::priority() { return BIT(m_r[PSW].w, 7); } +bool i8089_channel::chained() { return CC_CHAIN; } +bool i8089_channel::lock() { return CC_LOCK; } + +UINT16 i8089_channel::displacement(int wb) +{ + UINT16 displacement = 0; + + if (wb == 1) + { + displacement = m_iop->read_byte(m_r[TP].w); + set_reg(TP, m_r[TP].w + 1); + } + else if (wb == 2) + { + displacement = m_iop->read_word(m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + } + + return displacement; +} + +UINT8 i8089_channel::offset(int aa) +{ + UINT8 offset = 0; + + if (aa == 1) + { + offset = m_iop->read_byte(m_r[TP].w); + set_reg(TP, m_r[TP].w + 1); + } + + return offset; +} + +UINT8 i8089_channel::imm8() +{ + UINT8 imm8 = m_iop->read_byte(m_r[TP].w); + set_reg(TP, m_r[TP].w + 1); + return imm8; +} + +UINT16 i8089_channel::imm16() +{ + UINT16 imm16 = m_iop->read_word(m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + return imm16; +} + +// adjust task pointer and continue execution +void i8089_channel::terminate_dma(int offset) +{ + if (VERBOSE) + logerror("%s('%s'): terminating dma transfer\n", shortname(), tag()); + + set_reg(TP, m_r[TP].w + offset); + m_r[PSW].w |= 1 << 2; + m_r[PSW].w &= ~(1 << 6); + m_dma_state = DMA_IDLE; +} + +int i8089_channel::execute_run() +{ + m_icount = 0; + + // 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--; + } + + 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); + m_r[GB - CC_SOURCE].w++; + m_dma_state = DMA_TERMINATE; + + break; + } + + m_icount++; + } + + // executing task block instructions? + else if (executing()) + { + // call debugger + debugger_instruction_hook(m_iop, m_iop->m_current_tp); + + // 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); + set_reg(TP, 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; + + 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(), o); + else andbi_mi(mm, imm8(), o); + 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::examine_ccw(UINT8 ccw) +{ + // priority and bus load limit, bit 7 and 5 + m_r[PSW].w = (m_r[PSW].w & 0x5f) | (ccw & 0xa0); + + // acknowledge interrupt + if (BIT(ccw, 4)) + { + m_write_sintr(0); + m_r[PSW].w &= ~(1 << 5); + } + + // interrupt enable + if (BIT(ccw, 5)) + { + if (BIT(ccw, 4)) + m_r[PSW].w &= ~(1 << 4); + else + m_r[PSW].w |= 1 << 4; + } +} + +void i8089_channel::attention() +{ + // examine control byte + UINT8 ccw = m_iop->read_byte(m_r[CP].w); + + switch (ccw & 0x07) + { + // no channel command + case 0: + if (VERBOSE) + logerror("%s('%s'): command received: update psw\n", shortname(), tag()); + + examine_ccw(ccw); + break; + + // start channel, tb in local space + case 1: + if (VERBOSE) + logerror("%s('%s'): command received: start channel in local space\n", shortname(), tag()); + + examine_ccw(ccw); + + lpd(PP, CP, 2); + movp_pm(TP, PP); + movbi_mi(CP, 0xff, 1); + + m_r[PSW].w |= 1 << 2; + + break; + + // reserved + case 2: + if (VERBOSE) + logerror("%s('%s'): command received: invalid command 010\n", shortname(), tag()); + + break; + + // start channel, tb in system space + case 3: + if (VERBOSE) + logerror("%s('%s'): command received: start channel in system space\n", shortname(), tag()); + + examine_ccw(ccw); + + lpd(PP, CP, 2); + lpd(TP, PP); + movbi_mi(CP, 0xff, 1); + + m_r[PSW].w |= 1 << 2; + + if (VERBOSE) + { + logerror("%s('%s'): ---- starting channel ----\n", shortname(), tag()); + logerror("%s('%s'): parameter block address: %06x\n", shortname(), tag(), m_r[PP].w); + logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); + } + + break; + + case 4: + if (VERBOSE) + logerror("%s('%s'): command received: invalid command 100\n", shortname(), tag()); + + break; + + // continue channel processing + case 5: + if (VERBOSE) + logerror("%s('%s'): command received: continue channel processing\n", shortname(), tag()); + + // restore task pointer and parameter block + movp_pm(TP, PP); + movb_rm(PSW, PP, 3); + movbi_mi(CP, 0xff, 1); + + m_r[PSW].w |= 1 << 2; + + if (VERBOSE) + { + logerror("%s('%s'): ---- continuing channel ----\n", shortname(), tag()); + logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); + } + + break; + + // halt channel, save tp + case 6: + if (VERBOSE) + logerror("%s('%s'): command received: halt channel and save tp\n", shortname(), tag()); + + // save task pointer and psw to parameter block + movp_mp(PP, TP); + movb_mr(PP, PSW, 3); + hlt(); + + break; + + // halt channel, don't save tp + case 7: + if (VERBOSE) + logerror("%s('%s'): command received: halt channel\n", shortname(), tag()); + + hlt(); + + break; + } +} + +WRITE_LINE_MEMBER( i8089_channel::ext_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ext_w: %d\n", shortname(), tag(), state); +} + +WRITE_LINE_MEMBER( i8089_channel::drq_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ext_w: %d\n", shortname(), tag(), state); +} diff --git a/src/emu/cpu/i8089/i8089_channel.h b/src/emu/cpu/i8089/i8089_channel.h new file mode 100644 index 00000000000..5b92cb496a5 --- /dev/null +++ b/src/emu/cpu/i8089/i8089_channel.h @@ -0,0 +1,216 @@ +/*************************************************************************** + + Intel 8089 I/O Processor + + I/O channel + +***************************************************************************/ + +#pragma once + +#ifndef __I8089_CHANNEL_H__ +#define __I8089_CHANNEL_H__ + +#include "emu.h" +#include "i8089.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8089_CHANNEL_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, I8089_CHANNEL, 0) + +#define MCFG_I8089_CHANNEL_SINTR(_sintr) \ + downcast(device)->set_sintr_callback(DEVCB2_##_sintr); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class i8089_channel : public device_t +{ +public: + // construction/destruction + i8089_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_sintr_callback(_sintr sintr) { m_write_sintr.set_callback(sintr); } + + // set register + void set_reg(int reg, int value, int tag = -1); + + int execute_run(); + void attention(); + + // channel status + bool executing(); + bool transferring(); + bool priority(); + bool chained(); + bool lock(); + + DECLARE_WRITE_LINE_MEMBER( ext_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + + // register + enum + { + GA, // 20-bit general purpose address a + GB, // 20-bit general purpose address b + GC, // 20-bit general purpose address c + BC, // byte count + TP, // 20-bit task pointer + IX, // byte count + CC, // mask compare + MC, // channel control + + // internal use register + CP, // 20-bit control block pointer + PP, // 20-bit parameter pointer + PSW, // program status word + + NUM_REGS + }; + + struct + { + int w; // 20-bit address + int t; // tag-bit + } + m_r[11]; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + // opcodes + void add_rm(int r, int m, int o = 0); + void add_mr(int m, int r, int o = 0); + void addb_rm(int r, int m, int o = 0); + void addb_mr(int m, int r, int o = 0); + void addbi_ri(int r, int i); + void addbi_mi(int m, int i, int o = 0); + void addi_ri(int r, int i); + void addi_mi(int m, int i, int o = 0); + void and_rm(int r, int m, int o = 0); + void and_mr(int m, int r, int o = 0); + void andb_rm(int r, int m, int o = 0); + void andb_mr(int m, int r, int o = 0); + void andbi_ri(int r, int i); + void andbi_mi(int m, int i, int o = 0); + void andi_ri(int r, int i); + void andi_mi(int m, int i, int o = 0); + void call(int m, int d, int o = 0); + void clr(int m, int b, int o = 0); + void dec_r(int r); + void dec_m(int m, int o = 0); + void decb(int m, int o = 0); + void hlt(); + void inc_r(int r); + void inc_m(int m, int o = 0); + void incb(int m, int o = 0); + void jbt(int m, int b, int d, int o = 0); + void jmce(int m, int d, int o = 0); + void jmcne(int m, int d, int o = 0); + void jmp(int d); + void jnbt(int m, int b, int d, int o = 0); + void jnz_r(int r, int d); + void jnz_m(int m, int d, int o = 0); + void jnzb(int m, int d, int o = 0); + void jz_r(int r, int d); + void jz_m(int m, int d, int o = 0); + void jzb(int m, int d, int o = 0); + void lcall(int m, int d, int o = 0); + void ljbt(int m, int b, int d, int o = 0); + void ljmce(int m, int d, int o = 0); + void ljmcne(int m, int d, int o = 0); + void ljmp(int d); + void ljnbt(int m, int b, int d, int o = 0); + void ljnz_r(int r, int d); + void ljnz_m(int m, int d, int o = 0); + void ljnzb(int m, int d, int o = 0); + void ljz_r(int r, int d); + void ljz_m(int m, int d, int o = 0); + void ljzb(int m, int d, int o = 0); + void lpd(int p, int m, int o = 0); + void lpdi(int p, int i, int o = 0); + void mov_mr(int m, int r, int o = 0); + void mov_rm(int r, int m, int o = 0); + void mov_mm(int m1, int m2, int o1 = 0, int o2 = 0); + void movb_mr(int m, int r, int o = 0); + void movb_rm(int r, int m, int o = 0); + void movb_mm(int m1, int m2, int o1 = 0, int o2 = 0); + void movbi_ri(int r, int i); + void movbi_mi(int m, int i, int o = 0); + void movi_ri(int r, int i); + void movi_mi(int m, int i, int o = 0); + void movp_mp(int m, int p, int o = 0); + void movp_pm(int p, int m, int o = 0); + void nop(); + void not_r(int r); + void not_m(int m, int o = 0); + void not_rm(int r, int m, int o = 0); + void notb_m(int m, int o = 0); + void notb_rm(int r, int m, int o = 0); + void or_rm(int r, int m, int o = 0); + void or_mr(int m, int r, int o = 0); + void orb_rm(int r, int m, int o = 0); + void orb_mr(int m, int r, int o = 0); + void orbi_ri(int r, int i); + void orbi_mi(int m, int i, int o = 0); + void ori_ri(int r, int i); + void ori_mi(int m, int i, int o = 0); + void setb(int m, int b, int o = 0); + void sintr(); + void tsl(int m, int i, int d, int o = 0); + void wid(int s, int d); + void xfer(); + void invalid(int opc); + + // instruction fetch + UINT16 displacement(int wb); + UINT8 offset(int aa); + UINT8 imm8(); + UINT16 imm16(); + + void examine_ccw(UINT8 ccw); + + devcb2_write_line m_write_sintr; + + i8089_device *m_iop; + + int m_icount; + + // dma + void terminate_dma(int offset); + + bool m_xfer_pending; + UINT16 m_dma_value; + int m_dma_state; + + // dma state + enum + { + DMA_IDLE, + DMA_WAIT_FOR_SOURCE_DRQ, + DMA_FETCH, + DMA_TRANSLATE, + DMA_WAIT_FOR_DEST_DRQ, + DMA_STORE, + DMA_STORE_BYTE_HIGH, + DMA_COMPARE, + DMA_TERMINATE + }; +}; + + +// device type definition +extern const device_type I8089_CHANNEL; + + +#endif /* __I8089_CHANNEL_H__ */ diff --git a/src/emu/cpu/i8089/i8089_dasm.c b/src/emu/cpu/i8089/i8089_dasm.c new file mode 100644 index 00000000000..fde997ab82b --- /dev/null +++ b/src/emu/cpu/i8089/i8089_dasm.c @@ -0,0 +1,174 @@ +/*************************************************************************** + + Intel 8089 I/O Processor + + Disassembler + + Note: Incomplete + +***************************************************************************/ + +#include "emu.h" + +INT16 displacement(offs_t &pc, int wb, const UINT8 *oprom) +{ + INT16 result = 0; + + switch (wb) + { + case 1: + return oprom[2]; + pc += 1; + break; + case 2: + return oprom[2] | (oprom[3] << 8); + pc += 2; + break; + } + + return result; +} + +void offset(char *buffer, offs_t &pc, int aa, int mm, const UINT8 *oprom) +{ + const char *mm_name[] = { "ga", "gb", "gc", "pp" }; + + switch (aa) + { + case 0: sprintf(buffer, "[%s]", mm_name[mm]); break; + case 1: sprintf(buffer, "[%s].%x", mm_name[mm], oprom[2]); pc++; break; + case 2: sprintf(buffer, "[%s+ix]", mm_name[mm]); break; + case 3: sprintf(buffer, "[%s+ix+]", mm_name[mm]); break; + } +} + +UINT8 imm8(offs_t &pc, const UINT8 *oprom) +{ + pc += 1; + return oprom[2]; +} + +UINT16 imm16(offs_t &pc, const UINT8 *oprom) +{ + pc += 2; + return oprom[2] | (oprom[3] << 8); +} + +#define BRP brp_name[brp] +#define SDISP displacement(pc, wb, oprom) +#define OFFSET(x) offset(x, pc, aa, mm, oprom) +#define IMM8 imm8(pc, oprom) +#define IMM16 imm16(pc, oprom) + +CPU_DISASSEMBLE( i8089 ) +{ + const char *brp_name[] = { "ga", "gb", "gc", "bc", "tp", "ix", "cc", "mc" }; + + UINT32 flags = 0; + offs_t ppc = pc; + + // temporary storage + char o[10], o2[10]; + memset(o, 0, sizeof(o)); + memset(o2, 0, sizeof(o2)); + UINT16 off, seg; + + // decode instruction + int brp = (oprom[0] >> 5) & 0x07; + int wb = (oprom[0] >> 3) & 0x03; + int aa = (oprom[0] >> 1) & 0x03; + int w = (oprom[0] >> 0) & 0x01; + int opc = (oprom[1] >> 2) & 0x3f; + int mm = (oprom[1] >> 0) & 0x03; + + pc += 2; + + switch (opc) + { + case 0x00: + switch (brp) + { + case 0: sprintf(buffer, "nop"); break; + case 1: sprintf(buffer, "???"); break; + case 2: sprintf(buffer, "sintr"); break; + case 3: sprintf(buffer, "xfer"); break; + default: sprintf(buffer, "wid %d, %d", BIT(brp, 1) ? 16 : 8, BIT(brp, 0) ? 16 : 8); break; + } + break; + case 0x02: + off = IMM16; + seg = IMM16; + sprintf(buffer, "lpdi %s, %4x %4x", BRP, off, seg); + break; + case 0x08: + if (w) sprintf(buffer, "addi %s, %04x", BRP, IMM16); + else sprintf(buffer, "addbi %s, %02x", BRP, IMM8); + break; + case 0x0a: + if (w) sprintf(buffer, "andi %s, %04x", BRP, IMM16); + else sprintf(buffer, "andbi %s, %02x", BRP, IMM8); + break; + case 0x0c: + if (w) sprintf(buffer, "movi %s, %04x", BRP, IMM16); + else sprintf(buffer, "movbi %s, %02x", BRP, IMM8); + break; + case 0x0f: + sprintf(buffer, "dec %s", BRP); + break; + case 0x12: + sprintf(buffer, "hlt"); + break; + case 0x22: + OFFSET(o); + sprintf(buffer, "lpd %s, %s", BRP, o); + break; + case 0x28: + OFFSET(o); + if (w) sprintf(buffer, "add %s, %s", BRP, o); + else sprintf(buffer, "addb %s, %s", BRP, o); + break; + case 0x2a: + OFFSET(o); + if (w) sprintf(buffer, "and %s, %s", BRP, o); + else sprintf(buffer, "andb %s, %s", BRP, o); + break; + case 0x27: + OFFSET(o); + sprintf(buffer, "call %s, %06x", o, ppc + SDISP); + flags = DASMFLAG_STEP_OVER; + break; + case 0x30: + OFFSET(o); + if (w) sprintf(buffer, "addi %s, %04x", o, IMM16); + else sprintf(buffer, "addbi %s, %02x", o, IMM8); + break; + case 0x32: + OFFSET(o); + if (w) sprintf(buffer, "andi %s, %04x", o, IMM16); + else sprintf(buffer, "andbi %s, %02x", o, IMM8); + break; + case 0x34: + OFFSET(o); + if (w) sprintf(buffer, "add %s, %s", o, BRP); + else sprintf(buffer, "addb %s, %s", o, BRP); + break; + case 0x36: + OFFSET(o); + if (w) sprintf(buffer, "and %s, %s", o, BRP); + else sprintf(buffer, "andb %s, %s", o, BRP); + break; + case 0x3b: + OFFSET(o); + if (w) sprintf(buffer, "dec %s", o); + else sprintf(buffer, "decb %s", o); + break; + case 0x3e: + OFFSET(o); + sprintf(buffer, "clr %s, %d", o, brp); + break; + default: + sprintf(buffer, "???"); + } + + return (pc - ppc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/emu/cpu/i8089/i8089_ops.c b/src/emu/cpu/i8089/i8089_ops.c new file mode 100644 index 00000000000..4ceff35ddc8 --- /dev/null +++ b/src/emu/cpu/i8089/i8089_ops.c @@ -0,0 +1,198 @@ +/*************************************************************************** + + Intel 8089 I/O Processor + + Opcode implementations + +***************************************************************************/ + +#include "emu.h" +#include "i8089_channel.h" + +#define UNIMPLEMENTED logerror("%s('%s'): unimplemented opcode: %s\n", shortname(), tag(), __FUNCTION__); + +void i8089_channel::add_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::add_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::addb_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::addb_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::addbi_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::addbi_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::addi_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::addi_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::and_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::and_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::andb_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::andb_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::andbi_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::andbi_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::andi_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::andi_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::call(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::clr(int m, int b, int o) { UNIMPLEMENTED } +void i8089_channel::dec_r(int r) { UNIMPLEMENTED } +void i8089_channel::dec_m(int m, int o) { UNIMPLEMENTED } +void i8089_channel::decb(int m, int o) { UNIMPLEMENTED } + +// halt +void i8089_channel::hlt() +{ + movbi_mi(CP, 0x00, 1); + m_r[PSW].w &= ~(1 << 2); +} + +void i8089_channel::inc_r(int r) { UNIMPLEMENTED } +void i8089_channel::inc_m(int m, int o) { UNIMPLEMENTED } +void i8089_channel::incb(int m, int o) { UNIMPLEMENTED } +void i8089_channel::jbt(int m, int b, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jmce(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jmcne(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jmp(int d) { UNIMPLEMENTED } +void i8089_channel::jnbt(int m, int b, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jnz_r(int r, int d) { UNIMPLEMENTED } +void i8089_channel::jnz_m(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jnzb(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jz_r(int r, int d) { UNIMPLEMENTED } +void i8089_channel::jz_m(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::jzb(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::lcall(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljbt(int m, int b, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljmce(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljmcne(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljmp(int d) { UNIMPLEMENTED } +void i8089_channel::ljnbt(int m, int b, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljnz_r(int r, int d) { UNIMPLEMENTED } +void i8089_channel::ljnz_m(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljnzb(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljz_r(int r, int d) { UNIMPLEMENTED } +void i8089_channel::ljz_m(int m, int d, int o) { UNIMPLEMENTED } +void i8089_channel::ljzb(int m, int d, int o) { UNIMPLEMENTED } + +// load pointer from memory +void i8089_channel::lpd(int p, int m, int o) +{ + UINT16 offset = m_iop->read_word(m_r[m].w + o); + UINT16 segment = m_iop->read_word(m_r[m].w + o + 2); + + set_reg(p, ((segment << 4) + offset) & 0xfffff, 0); +} + +// load pointer from immediate data +void i8089_channel::lpdi(int p, int i, int o) +{ + set_reg(p, (o << 4) + (i & 0xffff), 0); +} + +void i8089_channel::mov_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::mov_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::mov_mm(int m1, int m2, int o1, int o2) { UNIMPLEMENTED } + +// move register to memory byte +void i8089_channel::movb_mr(int m, int r, int o) +{ + m_iop->write_byte(m_r[m].w + o, m_r[r].w & 0xff); +} + +// move memory byte to register +void i8089_channel::movb_rm(int r, int m, int o) +{ + UINT8 byte = m_iop->read_byte(m_r[m].w + o); + set_reg(r, (BIT(byte, 7) ? 0xfff00 : 0x00000) | byte, 1); +} + +// move memory byte to memory byte +void i8089_channel::movb_mm(int m1, int m2, int o1, int o2) +{ + UINT8 byte = m_iop->read_byte(m_r[m2].w + o2); + m_iop->write_byte(m_r[m1].w + o1, byte); +} + +// move immediate byte to register +void i8089_channel::movbi_ri(int r, int i) +{ + set_reg(r, (BIT(i, 7) ? 0xfff00 : 0x00000) | (i & 0xff), 1); +} + +// move immediate byte to memory byte +void i8089_channel::movbi_mi(int m, int i, int o) +{ + m_iop->write_byte(m_r[m].w + o, i & 0xff); +} + +// move immediate word to register +void i8089_channel::movi_ri(int r, int i) +{ + set_reg(r, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff), 1); +} + +// move immediate word to memory word +void i8089_channel::movi_mi(int m, int i, int o) +{ + m_iop->write_word(m_r[m].w + o, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff)); +} + +// move pointer to memory (store) +void i8089_channel::movp_mp(int m, int p, int o) +{ + m_iop->write_word(m_r[m].w + o, m_r[p].w & 0xffff); + m_iop->write_word(m_r[m].w + o + 2, (m_r[p].w >> 12 & 0xf0) | (m_r[p].t << 3 & 0x01)); +} + +// move memory to pointer (restore) +void i8089_channel::movp_pm(int p, int m, int o) +{ + UINT16 offset = m_iop->read_word(m_r[m].w + o); + UINT16 segment = m_iop->read_word(m_r[m].w + o + 2); + + set_reg(p, ((segment << 4) + offset) & 0xfffff, segment >> 3 & 0x01); +} + +// no operation +void i8089_channel::nop() +{ +} + +void i8089_channel::not_r(int r) { UNIMPLEMENTED } +void i8089_channel::not_m(int m, int o) { UNIMPLEMENTED } +void i8089_channel::not_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::notb_m(int m, int o) { UNIMPLEMENTED } +void i8089_channel::notb_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::or_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::or_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::orb_rm(int r, int m, int o) { UNIMPLEMENTED } +void i8089_channel::orb_mr(int m, int r, int o) { UNIMPLEMENTED } +void i8089_channel::orbi_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::orbi_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::ori_ri(int r, int i) { UNIMPLEMENTED } +void i8089_channel::ori_mi(int m, int i, int o) { UNIMPLEMENTED } +void i8089_channel::setb(int m, int b, int o) { UNIMPLEMENTED } + +// set interrupt service flip-flop +void i8089_channel::sintr() +{ + if (BIT(m_r[PSW].w, 4)) + { + m_r[PSW].w |= 1 << 5; + m_write_sintr(1); + } +} + +void i8089_channel::tsl(int m, int i, int d, int o) { UNIMPLEMENTED } + +// set source and destination logical widths +void i8089_channel::wid(int s, int d) +{ + m_r[PSW].w &= 0x3f; + m_r[PSW].w |= d << 0; + m_r[PSW].w |= s << 1; +} + +// enter dma transfer mode after next instruction +void i8089_channel::xfer() +{ + m_xfer_pending = true; +} + +void i8089_channel::invalid(int opc) +{ + logerror("%s('%s'): invalid opcode: %02x\n", shortname(), tag(), opc); +} diff --git a/src/emu/machine/i8089.c b/src/emu/machine/i8089.c deleted file mode 100644 index 560c432ba95..00000000000 --- a/src/emu/machine/i8089.c +++ /dev/null @@ -1,1227 +0,0 @@ -/*************************************************************************** - - Intel 8089 I/O Processor - -***************************************************************************/ - -#include "i8089.h" - - -//************************************************************************** -// MACROS/CONSTANTS -//************************************************************************** - -#define VERBOSE 1 -#define VERBOSE_DMA 1 - -// channel control register fields -#define CC_TMC ((m_r[CC].w >> 0) & 0x07) // terminate on masked compare -#define CC_TBC ((m_r[CC].w >> 3) & 0x03) // terminate on byte count -#define CC_TX ((m_r[CC].w >> 5) & 0x03) // terminate on external signal -#define CC_TS ((m_r[CC].w >> 7) & 0x01) // terminate on single transfer -#define CC_CHAIN ((m_r[CC].w >> 8) & 0x01) // chaining -#define CC_LOCK ((m_r[CC].w >> 9) & 0x01) // actuate lock -#define CC_SOURCE ((m_r[CC].w >> 10) & 0x01) // source register -#define CC_SYNC ((m_r[CC].w >> 11) & 0x03) // synchronization -#define CC_TRANS ((m_r[CC].w >> 13) & 0x01) // translation -#define CC_FUNC ((m_r[CC].w >> 14) & 0x03) // function - - -//************************************************************************** -// I/O CHANNEL -//************************************************************************** - -#define MCFG_I8089_CHANNEL_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, I8089_CHANNEL, 0) - -#define MCFG_I8089_CHANNEL_SINTR(_sintr) \ - downcast(device)->set_sintr_callback(DEVCB2_##_sintr); - -const device_type I8089_CHANNEL = &device_creator; - -class i8089_channel : public device_t -{ -public: - // construction/destruction - i8089_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - 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(); - - // 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 ); - -protected: - // device-level overrides - virtual void device_start(); - virtual void device_reset(); - -private: - - // opcodes - void add_rm(int r, int m, int o = 0); - void add_mr(int m, int r, int o = 0); - void addb_rm(int r, int m, int o = 0); - void addb_mr(int m, int r, int o = 0); - void addbi_ri(int r, int i); - void addbi_mi(int m, int i, int o = 0); - void addi_ri(int r, int i); - void addi_mi(int m, int i, int o = 0); - void and_rm(int r, int m, int o = 0); - void and_mr(int m, int r, int o = 0); - void andb_rm(int r, int m, int o = 0); - void andb_mr(int m, int r, int o = 0); - void andbi_ri(int r, int i); - void andbi_mi(int m, int i, int o = 0); - void andi_ri(int r, int i); - void andi_mi(int m, int i, int o = 0); - void call(int m, int d, int o = 0); - void clr(int m, int b, int o = 0); - void dec_r(int r); - void dec_m(int m, int o = 0); - void decb(int m, int o = 0); - void hlt(); - void inc_r(int r); - void inc_m(int m, int o = 0); - void incb(int m, int o = 0); - void jbt(int m, int b, int d, int o = 0); - void jmce(int m, int d, int o = 0); - void jmcne(int m, int d, int o = 0); - void jmp(int d); - void jnbt(int m, int b, int d, int o = 0); - void jnz_r(int r, int d); - void jnz_m(int m, int d, int o = 0); - void jnzb(int m, int d, int o = 0); - void jz_r(int r, int d); - void jz_m(int m, int d, int o = 0); - void jzb(int m, int d, int o = 0); - void lcall(int m, int d, int o = 0); - void ljbt(int m, int b, int d, int o = 0); - void ljmce(int m, int d, int o = 0); - void ljmcne(int m, int d, int o = 0); - void ljmp(int d); - void ljnbt(int m, int b, int d, int o = 0); - void ljnz_r(int r, int d); - void ljnz_m(int m, int d, int o = 0); - void ljnzb(int m, int d, int o = 0); - void ljz_r(int r, int d); - void ljz_m(int m, int d, int o = 0); - void ljzb(int m, int d, int o = 0); - void lpd(int p, int m, int o = 0); - void lpdi(int p, int i, int o = 0); - void mov_mr(int m, int r, int o = 0); - void mov_rm(int r, int m, int o = 0); - void mov_mm(int m1, int m2, int o1 = 0, int o2 = 0); - void movb_mr(int m, int r, int o = 0); - void movb_rm(int r, int m, int o = 0); - void movb_mm(int m1, int m2, int o1 = 0, int o2 = 0); - void movbi_ri(int r, int i); - void movbi_mi(int m, int i, int o = 0); - void movi_ri(int r, int i); - void movi_mi(int m, int i, int o = 0); - void movp_mp(int m, int p, int o = 0); - void movp_pm(int p, int m, int o = 0); - void nop(); - void not_r(int r); - void not_m(int m, int o = 0); - void not_rm(int r, int m, int o = 0); - void notb_m(int m, int o = 0); - void notb_rm(int r, int m, int o = 0); - void or_rm(int r, int m, int o = 0); - void or_mr(int m, int r, int o = 0); - void orb_rm(int r, int m, int o = 0); - void orb_mr(int m, int r, int o = 0); - void orbi_ri(int r, int i); - void orbi_mi(int m, int i, int o = 0); - void ori_ri(int r, int i); - void ori_mi(int m, int i, int o = 0); - void setb(int m, int b, int o = 0); - void sintr(); - void tsl(int m, int i, int d, int o = 0); - void wid(int s, int d); - void xfer(); - void invalid(int opc); - - // instruction fetch - UINT16 displacement(int wb); - UINT8 offset(int aa); - UINT8 imm8(); - UINT16 imm16(); - - void examine_ccw(UINT8 ccw); - - devcb2_write_line m_write_sintr; - - i8089_device *m_iop; - - int m_icount; - - // dma - void terminate_dma(int offset); - - bool m_xfer_pending; - UINT16 m_dma_value; - int m_dma_state; - - // dma state - enum - { - DMA_IDLE, - DMA_WAIT_FOR_SOURCE_DRQ, - DMA_FETCH, - DMA_TRANSLATE, - DMA_WAIT_FOR_DEST_DRQ, - DMA_STORE, - DMA_STORE_BYTE_HIGH, - DMA_COMPARE, - DMA_TERMINATE - }; - - // register - enum - { - GA, // 20-bit general purpose address a - GB, // 20-bit general purpose address b - GC, // 20-bit general purpose address c - BC, // byte count - TP, // 20-bit task pointer - IX, // byte count - CC, // mask compare - MC, // channel control - - // internal use register - CP, // 20-bit control block pointer - PP, // 20-bit parameter pointer - PSW // program status word - }; - - struct - { - int w; // 20-bit address - int t; // tag-bit - } - m_r[11]; -}; - -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__), - m_write_sintr(*this), - m_icount(0), - m_xfer_pending(false), - m_dma_value(0), - m_dma_state(DMA_IDLE) -{ -} - -void i8089_channel::device_start() -{ - // get parent device - m_iop = downcast(owner()); - - // resolve callbacks - m_write_sintr.resolve_safe(); - - // register for save states - save_item(NAME(m_xfer_pending)); - save_item(NAME(m_dma_value)); - save_item(NAME(m_dma_state)); - - for (int i = 0; i < ARRAY_LENGTH(m_r); i++) - { - save_item(NAME(m_r[i].w), i); - save_item(NAME(m_r[i].t), i); - } -} - -void i8089_channel::device_reset() -{ - m_xfer_pending = false; - - // initialize registers - for (int i = 0; i < ARRAY_LENGTH(m_r); i++) - { - m_r[i].w = 0; - m_r[i].t = 0; - } -} - - -//************************************************************************** -// IMPLEMENTATION -//************************************************************************** - -UINT16 i8089_channel::displacement(int wb) -{ - UINT16 displacement = 0; - - if (wb == 1) - { - displacement = m_iop->read_byte(m_r[TP].w); - m_r[TP].w++; - } - else if (wb == 2) - { - displacement = m_iop->read_word(m_r[TP].w); - m_r[TP].w += 2; - } - - return displacement; -} - -UINT8 i8089_channel::offset(int aa) -{ - UINT8 offset = 0; - - if (aa == 1) - { - offset = m_iop->read_byte(m_r[TP].w); - m_r[TP].w++; - } - - return offset; -} - -UINT8 i8089_channel::imm8() -{ - UINT8 imm8 = m_iop->read_byte(m_r[TP].w); - m_r[TP].w++; - return imm8; -} - -UINT16 i8089_channel::imm16() -{ - UINT16 imm16 = m_iop->read_word(m_r[TP].w); - m_r[TP].w += 2; - return imm16; -} - -// adjust task pointer and continue execution -void i8089_channel::terminate_dma(int offset) -{ - 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; -} - -int i8089_channel::execute_run() -{ - m_icount = 0; - - // 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--; - } - - 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); - m_r[GB - CC_SOURCE].w++; - m_dma_state = DMA_TERMINATE; - - break; - } - - m_icount++; - } - - // 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) -{ - m_r[CP].w = address; -} - -void i8089_channel::examine_ccw(UINT8 ccw) -{ - // priority and bus load limit, bit 7 and 5 - m_r[PSW].w = (m_r[PSW].w & 0x5f) | (ccw & 0xa0); - - // acknowledge interrupt - if (BIT(ccw, 4)) - { - m_write_sintr(0); - m_r[PSW].w &= ~(1 << 5); - } - - // interrupt enable - if (BIT(ccw, 5)) - { - if (BIT(ccw, 4)) - m_r[PSW].w &= ~(1 << 4); - else - m_r[PSW].w |= 1 << 4; - } -} - -void i8089_channel::attention() -{ - // examine control byte - UINT8 ccw = m_iop->read_byte(m_r[CP].w); - - switch (ccw & 0x07) - { - // no channel command - case 0: - if (VERBOSE) - logerror("%s('%s'): command received: update psw\n", shortname(), tag()); - - examine_ccw(ccw); - break; - - // start channel, tb in local space - case 1: - if (VERBOSE) - logerror("%s('%s'): command received: start channel in local space\n", shortname(), tag()); - - examine_ccw(ccw); - - lpd(PP, CP, 2); - movp_pm(TP, PP); - movbi_mi(CP, 0xff, 1); - - m_r[PSW].w |= 1 << 2; - - break; - - // reserved - case 2: - if (VERBOSE) - logerror("%s('%s'): command received: invalid command 010\n", shortname(), tag()); - - break; - - // start channel, tb in system space - case 3: - if (VERBOSE) - logerror("%s('%s'): command received: start channel in system space\n", shortname(), tag()); - - examine_ccw(ccw); - - lpd(PP, CP, 2); - lpd(TP, PP); - movbi_mi(CP, 0xff, 1); - - m_r[PSW].w |= 1 << 2; - - if (VERBOSE) - { - logerror("%s('%s'): ---- starting channel ----\n", shortname(), tag()); - logerror("%s('%s'): parameter block address: %06x\n", shortname(), tag(), m_r[PP].w); - logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); - } - - break; - - case 4: - if (VERBOSE) - logerror("%s('%s'): command received: invalid command 100\n", shortname(), tag()); - - break; - - // continue channel processing - case 5: - if (VERBOSE) - logerror("%s('%s'): command received: continue channel processing\n", shortname(), tag()); - - // restore task pointer and parameter block - movp_pm(TP, PP); - movb_rm(PSW, PP, 3); - movbi_mi(CP, 0xff, 1); - - m_r[PSW].w |= 1 << 2; - - if (VERBOSE) - { - logerror("%s('%s'): ---- continuing channel ----\n", shortname(), tag()); - logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); - } - - break; - - // halt channel, save tp - case 6: - if (VERBOSE) - logerror("%s('%s'): command received: halt channel and save tp\n", shortname(), tag()); - - // save task pointer and psw to parameter block - movp_mp(PP, TP); - movb_mr(PP, PSW, 3); - hlt(); - - break; - - // halt channel, don't save tp - case 7: - if (VERBOSE) - logerror("%s('%s'): command received: halt channel\n", shortname(), tag()); - - hlt(); - - break; - } -} - -WRITE_LINE_MEMBER( i8089_channel::ext_w ) -{ - if (VERBOSE) - logerror("%s('%s'): ext_w: %d\n", shortname(), tag(), state); -} - -WRITE_LINE_MEMBER( i8089_channel::drq_w ) -{ - if (VERBOSE) - logerror("%s('%s'): ext_w: %d\n", shortname(), tag(), state); -} - - -//************************************************************************** -// OPCODES -//************************************************************************** - -#define UNIMPLEMENTED logerror("%s('%s'): unimplemented opcode: %s\n", shortname(), tag(), __FUNCTION__); - -void i8089_channel::add_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::add_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::addb_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::addb_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::addbi_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::addbi_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::addi_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::addi_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::and_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::and_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::andb_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::andb_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::andbi_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::andbi_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::andi_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::andi_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::call(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::clr(int m, int b, int o) { UNIMPLEMENTED } -void i8089_channel::dec_r(int r) { UNIMPLEMENTED } -void i8089_channel::dec_m(int m, int o) { UNIMPLEMENTED } -void i8089_channel::decb(int m, int o) { UNIMPLEMENTED } - -// halt -void i8089_channel::hlt() -{ - movbi_mi(CP, 0x00, 1); - m_r[PSW].w &= ~(1 << 2); -} - -void i8089_channel::inc_r(int r) { UNIMPLEMENTED } -void i8089_channel::inc_m(int m, int o) { UNIMPLEMENTED } -void i8089_channel::incb(int m, int o) { UNIMPLEMENTED } -void i8089_channel::jbt(int m, int b, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jmce(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jmcne(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jmp(int d) { UNIMPLEMENTED } -void i8089_channel::jnbt(int m, int b, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jnz_r(int r, int d) { UNIMPLEMENTED } -void i8089_channel::jnz_m(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jnzb(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jz_r(int r, int d) { UNIMPLEMENTED } -void i8089_channel::jz_m(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::jzb(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::lcall(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljbt(int m, int b, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljmce(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljmcne(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljmp(int d) { UNIMPLEMENTED } -void i8089_channel::ljnbt(int m, int b, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljnz_r(int r, int d) { UNIMPLEMENTED } -void i8089_channel::ljnz_m(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljnzb(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljz_r(int r, int d) { UNIMPLEMENTED } -void i8089_channel::ljz_m(int m, int d, int o) { UNIMPLEMENTED } -void i8089_channel::ljzb(int m, int d, int o) { UNIMPLEMENTED } - -// load pointer from memory -void i8089_channel::lpd(int p, int m, int o) -{ - UINT16 offset = m_iop->read_word(m_r[m].w + o); - UINT16 segment = m_iop->read_word(m_r[m].w + o + 2); - - m_r[p].w = ((segment << 4) + offset) & 0xfffff; - m_r[p].t = 0; -} - -// load pointer from immediate data -void i8089_channel::lpdi(int p, int i, int o) -{ - m_r[p].w = (o << 4) + (i & 0xffff); - m_r[p].t = 0; -} - -void i8089_channel::mov_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::mov_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::mov_mm(int m1, int m2, int o1, int o2) { UNIMPLEMENTED } - -// move register to memory byte -void i8089_channel::movb_mr(int m, int r, int o) -{ - m_iop->write_byte(m_r[m].w + o, m_r[r].w & 0xff); -} - -// move memory byte to register -void i8089_channel::movb_rm(int r, int m, int o) -{ - UINT8 byte = m_iop->read_byte(m_r[m].w + o); - m_r[r].w = (BIT(byte, 7) ? 0xfff00 : 0x00000) | byte; - m_r[r].t = 1; -} - -// move memory byte to memory byte -void i8089_channel::movb_mm(int m1, int m2, int o1, int o2) -{ - UINT8 byte = m_iop->read_byte(m_r[m2].w + o2); - m_iop->write_byte(m_r[m1].w + o1, byte); -} - -// move immediate byte to register -void i8089_channel::movbi_ri(int r, int i) -{ - m_r[r].w = (BIT(i, 7) ? 0xfff00 : 0x00000) | (i & 0xff); - m_r[r].t = 1; -} - -// move immediate byte to memory byte -void i8089_channel::movbi_mi(int m, int i, int o) -{ - m_iop->write_byte(m_r[m].w + o, i & 0xff); -} - -// move immediate word to register -void i8089_channel::movi_ri(int r, int i) -{ - m_r[r].w = (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff); - m_r[r].t = 1; -} - -// move immediate word to memory word -void i8089_channel::movi_mi(int m, int i, int o) -{ - m_iop->write_word(m_r[m].w + o, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff)); -} - -// move pointer to memory (store) -void i8089_channel::movp_mp(int m, int p, int o) -{ - m_iop->write_word(m_r[m].w + o, m_r[p].w & 0xffff); - m_iop->write_word(m_r[m].w + o + 2, (m_r[p].w >> 12 & 0xf0) | (m_r[p].t << 3 & 0x01)); -} - -// move memory to pointer (restore) -void i8089_channel::movp_pm(int p, int m, int o) -{ - UINT16 offset = m_iop->read_word(m_r[m].w + o); - UINT16 segment = m_iop->read_word(m_r[m].w + o + 2); - - m_r[p].w = ((segment << 4) + offset) & 0xfffff; - m_r[p].t = segment >> 3 & 0x01; -} - -// no operation -void i8089_channel::nop() -{ -} - -void i8089_channel::not_r(int r) { UNIMPLEMENTED } -void i8089_channel::not_m(int m, int o) { UNIMPLEMENTED } -void i8089_channel::not_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::notb_m(int m, int o) { UNIMPLEMENTED } -void i8089_channel::notb_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::or_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::or_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::orb_rm(int r, int m, int o) { UNIMPLEMENTED } -void i8089_channel::orb_mr(int m, int r, int o) { UNIMPLEMENTED } -void i8089_channel::orbi_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::orbi_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::ori_ri(int r, int i) { UNIMPLEMENTED } -void i8089_channel::ori_mi(int m, int i, int o) { UNIMPLEMENTED } -void i8089_channel::setb(int m, int b, int o) { UNIMPLEMENTED } - -// set interrupt service flip-flop -void i8089_channel::sintr() -{ - if (BIT(m_r[PSW].w, 4)) - { - m_r[PSW].w |= 1 << 5; - m_write_sintr(1); - } -} - -void i8089_channel::tsl(int m, int i, int d, int o) { UNIMPLEMENTED } - -// set source and destination logical widths -void i8089_channel::wid(int s, int d) -{ - m_r[PSW].w &= 0x3f; - m_r[PSW].w |= d << 0; - m_r[PSW].w |= s << 1; -} - -// enter dma transfer mode after next instruction -void i8089_channel::xfer() -{ - m_xfer_pending = true; -} - -void i8089_channel::invalid(int opc) -{ - logerror("%s('%s'): invalid opcode: %02x\n", shortname(), tag(), opc); -} - - -//************************************************************************** -// DEVICE DEFINITIONS -//************************************************************************** - -const device_type I8089 = &device_creator; - - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// i8089_device - constructor -//------------------------------------------------- - -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), - m_write_sintr2(*this), - m_16bit_system(false), - m_16bit_remote(false), - m_master(false), - m_request_grant(false), - m_ca(0), - m_sel(0) -{ -} - -void i8089_device::static_set_cputag(device_t &device, const char *tag) -{ - i8089_device &i8089 = downcast(device); - i8089.m_cputag = tag; -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void i8089_device::device_start() -{ - // set our instruction counter - m_icountptr = &m_icount; - - // resolve callbacks - m_write_sintr1.resolve_safe(); - m_write_sintr2.resolve_safe(); - - // register for save states - save_item(NAME(m_16bit_system)); - save_item(NAME(m_16bit_remote)); - save_item(NAME(m_master)); - save_item(NAME(m_request_grant)); - save_item(NAME(m_ca)); - save_item(NAME(m_sel)); - - // get pointers to memory - device_t *cpu = machine().device(m_cputag); - m_mem = &cpu->memory().space(AS_PROGRAM); - m_io = &cpu->memory().space(AS_IO); -} - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void i8089_device::device_reset() -{ - m_initialized = false; -} - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -static MACHINE_CONFIG_FRAGMENT( i8089 ) - MCFG_I8089_CHANNEL_ADD("1") - MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch1_sintr_w)) - MCFG_I8089_CHANNEL_ADD("2") - MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch2_sintr_w)) -MACHINE_CONFIG_END - -machine_config_constructor i8089_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( i8089 ); -} - - -//************************************************************************** -// IMPLEMENTATION -//************************************************************************** - -// the i8089 actually executes a program from internal rom here: -// -// MOVB SYSBUS from FFFF6 -// LPD System Configuration Block from FFFF8 -// MOVB SOC from (SCB) -// LPD Control Pointer (CP) from (SCB) + 2 -// MOVBI "00" to CP + 1 (clear busy flag) - -void i8089_device::initialize() -{ - assert(!m_initialized); - - // get system bus width - UINT8 sys_bus = m_mem->read_byte(0xffff6); - m_16bit_system = BIT(sys_bus, 0); - - // get system configuration block address - UINT16 scb_offset = read_word(0xffff8); - UINT16 scb_segment = read_word(0xffffa); - offs_t scb_address = ((scb_segment << 4) + scb_offset) & 0x0fffff; - - // get system operation command - UINT16 soc = read_word(scb_address); - m_16bit_remote = BIT(soc, 0); - m_request_grant = BIT(soc, 1); - m_master = !m_sel; - - // get control block address - UINT16 cb_offset = read_word(scb_address + 2); - UINT16 cb_segment = read_word(scb_address + 4); - offs_t cb_address = ((cb_segment << 4) + cb_offset) & 0x0fffff; - - // initialize channels - m_ch1->set_control_block(cb_address); - m_ch2->set_control_block(cb_address + 8); - - // clear busy - UINT16 ccw = read_word(cb_address); - write_word(cb_address, ccw & 0x00ff); - - // done - m_initialized = true; - - // output some debug info - if (VERBOSE) - { - logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag()); - logerror("%s('%s'): %s system bus\n", shortname(), basetag(), m_16bit_system ? "16-bit" : "8-bit"); - logerror("%s('%s'): system configuration block location: %06x\n", shortname(), basetag(), scb_address); - logerror("%s('%s'): %s remote bus\n", shortname(), basetag(), m_16bit_remote ? "16-bit" : "8-bit"); - logerror("%s('%s'): request/grant: %d\n", shortname(), basetag(), m_request_grant); - logerror("%s('%s'): is %s\n", shortname(), basetag(), m_master ? "master" : "slave"); - logerror("%s('%s'): channel control block location: %06x\n", shortname(), basetag(), cb_address); - } -} - -UINT8 i8089_device::read_byte(offs_t address) -{ - assert(m_initialized); - return m_mem->read_byte(address); -} - -UINT16 i8089_device::read_word(offs_t address) -{ - assert(m_initialized); - - UINT16 data = 0xffff; - - if (m_16bit_system && !(address & 1)) - { - data = m_mem->read_word(address); - } - else - { - data = m_mem->read_byte(address); - data |= m_mem->read_byte(address + 1) << 8; - } - - return data; -} - -void i8089_device::write_byte(offs_t address, UINT8 data) -{ - assert(m_initialized); - m_mem->write_byte(address, data); -} - -void i8089_device::write_word(offs_t address, UINT16 data) -{ - assert(m_initialized); - - if (m_16bit_system && !(address & 1)) - { - m_mem->write_word(address, data); - } - else - { - m_mem->write_byte(address, data & 0xff); - m_mem->write_byte(address + 1, (data >> 8) & 0xff); - } -} - -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 -//************************************************************************** - -WRITE_LINE_MEMBER( i8089_device::ca_w ) -{ - if (VERBOSE) - logerror("%s('%s'): ca_w: %u\n", shortname(), basetag(), state); - - if (m_ca == 1 && state == 0) - { - if (!m_initialized) - initialize(); - else - { - if (m_sel == 0) - m_ch1->attention(); - else - m_ch2->attention(); - } - } - - m_ca = state; -} - -WRITE_LINE_MEMBER( i8089_device::drq1_w ) { m_ch1->drq_w(state); } -WRITE_LINE_MEMBER( i8089_device::drq2_w ) { m_ch2->drq_w(state); } -WRITE_LINE_MEMBER( i8089_device::ext1_w ) { m_ch1->ext_w(state); } -WRITE_LINE_MEMBER( i8089_device::ext2_w ) { m_ch2->ext_w(state); } diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak index 358e9faa82f..f0a4f51ee7c 100644 --- a/src/emu/machine/machine.mak +++ b/src/emu/machine/machine.mak @@ -465,15 +465,6 @@ ifneq ($(filter I2CMEM,$(MACHINES)),) MACHINEOBJS += $(MACHINEOBJ)/i2cmem.o endif -#------------------------------------------------- -# -#@src/emu/machine/i8089.h,MACHINES += I8089 -#------------------------------------------------- - -ifneq ($(filter I8089,$(MACHINES)),) -MACHINEOBJS += $(MACHINEOBJ)/i8089.o -endif - #------------------------------------------------- # #@src/emu/machine/i8155.h,MACHINES += I8155 diff --git a/src/mess/drivers/apricot.c b/src/mess/drivers/apricot.c index b518bebeb36..f5489a38b32 100644 --- a/src/mess/drivers/apricot.c +++ b/src/mess/drivers/apricot.c @@ -2,15 +2,15 @@ ACT Apricot PC/Xi - - Needs Intel 8089 support (I/O processor) + - Error 29 (timer failed) - Dump of the keyboard MCU ROM needed (can be dumped using test mode) ***************************************************************************/ #include "emu.h" #include "cpu/i86/i86.h" +#include "cpu/i8089/i8089.h" #include "machine/ram.h" -#include "machine/i8089.h" #include "machine/pit8253.h" #include "machine/i8255.h" #include "machine/pic8259.h" @@ -24,16 +24,16 @@ #include "formats/apridisk.h" -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** class apricot_state : public driver_device { public: - apricot_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), + apricot_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_cpu(*this, "ic91"), m_ram(*this, RAM_TAG), m_iop(*this, "ic71"), m_sn(*this, "ic7"), @@ -55,7 +55,7 @@ public: m_display_enabled(0) { } - required_device m_maincpu; + required_device m_cpu; required_device m_ram; required_device m_iop; required_device m_sn; @@ -101,9 +101,9 @@ public: }; -/*************************************************************************** - I/O -***************************************************************************/ +//************************************************************************** +// I/O +//************************************************************************** WRITE8_MEMBER( apricot_state::i8089_ca1_w ) { @@ -136,7 +136,7 @@ WRITE8_MEMBER( apricot_state::apricot_sysctrl_w ) if (!BIT(data, 5)) m_fdc->set_floppy(BIT(data, 6) ? m_floppy1->get_device() : m_floppy0->get_device()); - /* switch video modes */ + // switch video modes m_crtc->set_clock( m_video_mode ? XTAL_15MHz / 10 : XTAL_15MHz / 16); m_crtc->set_hpixels_per_column( m_video_mode ? 10 : 16); } @@ -229,9 +229,9 @@ static const centronics_interface apricot_centronics_intf = }; -/*************************************************************************** - FLOPPY -***************************************************************************/ +//************************************************************************** +// FLOPPY +//************************************************************************** void apricot_state::wd2793_intrq_w(bool state) { @@ -250,9 +250,9 @@ static SLOT_INTERFACE_START( apricot_floppies ) SLOT_INTERFACE_END -/*************************************************************************** - VIDEO EMULATION -***************************************************************************/ +//************************************************************************** +// VIDEO EMULATION +//************************************************************************** UINT32 apricot_state::screen_update_apricot(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { @@ -272,7 +272,7 @@ static MC6845_UPDATE_ROW( apricot_update_row ) if (state->m_video_mode) { - /* text mode */ + // text mode for (i = 0; i < x_count; i++) { UINT16 code = state->m_screen_buffer[(ma + i) & 0x7ff]; @@ -280,21 +280,21 @@ static MC6845_UPDATE_ROW( apricot_update_row ) UINT16 data = ram[offset + 1] << 8 | ram[offset]; int fill = 0; - if (BIT(code, 12) && BIT(data, 14)) fill = 1; /* strike-through? */ - if (BIT(code, 13) && BIT(data, 15)) fill = 1; /* underline? */ + if (BIT(code, 12) && BIT(data, 14)) fill = 1; // strike-through? + if (BIT(code, 13) && BIT(data, 15)) fill = 1; // underline? - /* draw 10 pixels of the character */ + // draw 10 pixels of the character for (x = 0; x <= 10; x++) { int color = fill ? 1 : BIT(data, x); - if (BIT(code, 15)) color = !color; /* reverse? */ + if (BIT(code, 15)) color = !color; // reverse? bitmap.pix32(y, x + i*10) = RGB_MONOCHROME_GREEN_HIGHLIGHT[color ? 1 + BIT(code, 14) : 0]; } } } else { - /* graphics mode */ + // graphics mode fatalerror("Graphics mode not implemented!\n"); } } @@ -314,15 +314,20 @@ static MC6845_INTERFACE( apricot_mc6845_intf ) }; -/*************************************************************************** - MACHINE EMULATION -***************************************************************************/ +//************************************************************************** +// MACHINE EMULATION +//************************************************************************** void apricot_state::machine_start() { - m_maincpu->space(AS_PROGRAM).install_ram(0x00000, m_ram->size() - 1, m_ram->pointer()); - m_maincpu->set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(apricot_state::irq_callback), this)); + // install shared memory to the main cpu and the iop + m_cpu->space(AS_PROGRAM).install_ram(0x00000, m_ram->size() - 1, m_ram->pointer()); + m_iop->space(AS_PROGRAM).install_ram(0x00000, m_ram->size() - 1, m_ram->pointer()); + // setup interrupt acknowledge callback for the main cpu + m_cpu->set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(apricot_state::irq_callback), this)); + + // setup floppy disk controller callbacks m_fdc->setup_intrq_cb(wd2793_t::line_cb(FUNC(apricot_state::wd2793_intrq_w), this)); m_fdc->setup_drq_cb(wd2793_t::line_cb(FUNC(apricot_state::wd2793_drq_w), this)); @@ -332,9 +337,9 @@ void apricot_state::machine_start() } -/*************************************************************************** - ADDRESS MAPS -***************************************************************************/ +//************************************************************************** +// ADDRESS MAPS +//************************************************************************** static ADDRESS_MAP_START( apricot_mem, AS_PROGRAM, 16, apricot_state ) // AM_RANGE(0x00000, 0x3ffff) AM_RAMBANK("standard_ram") @@ -354,13 +359,13 @@ static ADDRESS_MAP_START( apricot_io, AS_IO, 16, apricot_state ) AM_RANGE(0x6a, 0x6b) AM_MIRROR(0x04) AM_DEVREADWRITE8("ic30", mc6845_device, register_r, register_w, 0x00ff) AM_RANGE(0x70, 0x71) AM_MIRROR(0x04) AM_WRITE8(i8089_ca1_w, 0x00ff) AM_RANGE(0x72, 0x73) AM_MIRROR(0x04) AM_WRITE8(i8089_ca2_w, 0x00ff) - AM_RANGE(0x78, 0x7f) AM_NOP /* unavailable */ + AM_RANGE(0x78, 0x7f) AM_NOP // unavailable ADDRESS_MAP_END -/*************************************************************************** - MACHINE DRIVERS -***************************************************************************/ +//************************************************************************** +// MACHINE DRIVERS +//************************************************************************** static const sn76496_config psg_intf = { @@ -368,11 +373,16 @@ static const sn76496_config psg_intf = }; static MACHINE_CONFIG_START( apricot, apricot_state ) - MCFG_CPU_ADD("maincpu", I8086, XTAL_15MHz / 3) + // main cpu + MCFG_CPU_ADD("ic91", I8086, XTAL_15MHz / 3) MCFG_CPU_PROGRAM_MAP(apricot_mem) MCFG_CPU_IO_MAP(apricot_io) - MCFG_I8089_ADD("ic71", XTAL_15MHz / 3, "maincpu") + // i/o cpu + MCFG_CPU_ADD("ic71", I8089, XTAL_15MHz / 3) + MCFG_CPU_PROGRAM_MAP(apricot_mem) + MCFG_CPU_IO_MAP(apricot_io) + MCFG_I8089_DATABUS_WIDTH(16) MCFG_I8089_SINTR1(DEVWRITELINE("ic31", pic8259_device, ir0_w)) MCFG_I8089_SINTR2(DEVWRITELINE("ic31", pic8259_device, ir1_w)) @@ -383,6 +393,8 @@ static MACHINE_CONFIG_START( apricot, apricot_state ) MCFG_SCREEN_REFRESH_RATE(72) MCFG_SCREEN_UPDATE_DRIVER(apricot_state, screen_update_apricot) + MCFG_MC6845_ADD("ic30", MC6845, "screen", XTAL_15MHz / 10, apricot_mc6845_intf) + // sound hardware MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("ic7", SN76489, XTAL_4MHz / 2) @@ -392,12 +404,11 @@ static MACHINE_CONFIG_START( apricot, apricot_state ) // internal ram MCFG_RAM_ADD(RAM_TAG) MCFG_RAM_DEFAULT_SIZE("256k") - MCFG_RAM_EXTRA_OPTIONS("384k,512k") /* with 1 or 2 128k expansion boards */ + MCFG_RAM_EXTRA_OPTIONS("384k,512k") // with 1 or 2 128k expansion boards // devices - MCFG_MC6845_ADD("ic30", MC6845, "screen", XTAL_15MHz / 10, apricot_mc6845_intf) MCFG_I8255A_ADD("ic17", apricot_i8255a_intf) - MCFG_PIC8259_ADD("ic31", INPUTLINE("maincpu", 0), VCC, NULL) + MCFG_PIC8259_ADD("ic31", INPUTLINE("ic91", 0), VCC, NULL) MCFG_PIT8253_ADD("ic16", apricot_pit8253_intf) MCFG_Z80SIO0_ADD("ic15", XTAL_15MHz / 6, apricot_z80sio_intf) @@ -417,9 +428,9 @@ static MACHINE_CONFIG_DERIVED( apricotxi, apricot ) MACHINE_CONFIG_END -/*************************************************************************** - ROM DEFINITIONS -***************************************************************************/ +//************************************************************************** +// ROM DEFINITIONS +//************************************************************************** ROM_START( apricot ) ROM_REGION(0x4000, "bootstrap", 0) @@ -429,15 +440,15 @@ ROM_END ROM_START( apricotxi ) ROM_REGION(0x4000, "bootstrap", 0) - ROM_LOAD16_BYTE("lo_ve007.u11", 0x0000, 0x2000, CRC(e74e14d1) SHA1(569133b0266ce3563b21ae36fa5727308797deee)) /* LO Ve007 03.04.84 */ - ROM_LOAD16_BYTE("hi_ve007.u9", 0x0001, 0x2000, CRC(b04fb83e) SHA1(cc2b2392f1b4c04bb6ec8ee26f8122242c02e572)) /* HI Ve007 03.04.84 */ + ROM_LOAD16_BYTE("lo_ve007.u11", 0x0000, 0x2000, CRC(e74e14d1) SHA1(569133b0266ce3563b21ae36fa5727308797deee)) // LO Ve007 03.04.84 + ROM_LOAD16_BYTE("hi_ve007.u9", 0x0001, 0x2000, CRC(b04fb83e) SHA1(cc2b2392f1b4c04bb6ec8ee26f8122242c02e572)) // HI Ve007 03.04.84 ROM_END -/*************************************************************************** - GAME DRIVERS -***************************************************************************/ +//************************************************************************** +// GAME DRIVERS +//************************************************************************** -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS COMP( 1983, apricot, 0, 0, apricot, 0, driver_device, 0, "ACT", "Apricot PC", GAME_NOT_WORKING ) COMP( 1984, apricotxi, apricot, 0, apricotxi, 0, driver_device, 0, "ACT", "Apricot Xi", GAME_NOT_WORKING ) diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 98bb9124fde..1adc0b7fdd7 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -27,6 +27,7 @@ include $(SRC)/mess/messcore.mak CPUS += Z80 CPUS += Z180 CPUS += I8085 +CPUS += I8089 CPUS += M6502 CPUS += H6280 CPUS += I86 diff --git a/src/tools/unidasm.c b/src/tools/unidasm.c index 49380634c4c..30f65c2e2e6 100644 --- a/src/tools/unidasm.c +++ b/src/tools/unidasm.c @@ -131,6 +131,7 @@ CPU_DISASSEMBLE( i8008 ); CPU_DISASSEMBLE( i8051 ); CPU_DISASSEMBLE( i8052 ); CPU_DISASSEMBLE( i8085 ); +CPU_DISASSEMBLE( i8089 ); CPU_DISASSEMBLE( i80c51 ); CPU_DISASSEMBLE( i80c52 ); CPU_DISASSEMBLE( i860 ); @@ -275,6 +276,7 @@ static const dasm_table_entry dasm_table[] = { "i8051", _8bit, 0, CPU_DISASSEMBLE_NAME(i8051) }, { "i8052", _8bit, 0, CPU_DISASSEMBLE_NAME(i8052) }, { "i8085", _8bit, 0, CPU_DISASSEMBLE_NAME(i8085) }, + { "i8089", _8bit, 0, CPU_DISASSEMBLE_NAME(i8089) }, { "i80c51", _8bit, 0, CPU_DISASSEMBLE_NAME(i80c51) }, { "i80c52", _8bit, 0, CPU_DISASSEMBLE_NAME(i80c52) }, { "i860", _64le, 0, CPU_DISASSEMBLE_NAME(i860) },