mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
i8089: converted to a proper cpu core, added debugger support and disassembler
This commit is contained in:
parent
700b42c396
commit
8085624dc7
8
.gitattributes
vendored
8
.gitattributes
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
348
src/emu/cpu/i8089/i8089.c
Normal file
348
src/emu/cpu/i8089/i8089.c
Normal file
@ -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<i8089_device>;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// 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); }
|
@ -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<i8089_device *>(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<class _sintr1> void set_sintr1_callback(_sintr1 sintr1) { m_write_sintr1.set_callback(sintr1); }
|
||||
template<class _sintr2> 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<i8089_device &>(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;
|
641
src/emu/cpu/i8089/i8089_channel.c
Normal file
641
src/emu/cpu/i8089/i8089_channel.c
Normal file
@ -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<i8089_channel>;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// 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<i8089_device *>(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);
|
||||
}
|
216
src/emu/cpu/i8089/i8089_channel.h
Normal file
216
src/emu/cpu/i8089/i8089_channel.h
Normal file
@ -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<i8089_channel *>(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<class _sintr> 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__ */
|
174
src/emu/cpu/i8089/i8089_dasm.c
Normal file
174
src/emu/cpu/i8089/i8089_dasm.c
Normal file
@ -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;
|
||||
}
|
198
src/emu/cpu/i8089/i8089_ops.c
Normal file
198
src/emu/cpu/i8089/i8089_ops.c
Normal file
@ -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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_cpu;
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<i8089_device> m_iop;
|
||||
required_device<sn76489_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 )
|
||||
|
@ -27,6 +27,7 @@ include $(SRC)/mess/messcore.mak
|
||||
CPUS += Z80
|
||||
CPUS += Z180
|
||||
CPUS += I8085
|
||||
CPUS += I8089
|
||||
CPUS += M6502
|
||||
CPUS += H6280
|
||||
CPUS += I86
|
||||
|
@ -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) },
|
||||
|
Loading…
Reference in New Issue
Block a user