From 1c56a127d53ad66ba1bb454650e1b37ceadd3da9 Mon Sep 17 00:00:00 2001 From: Curt Coder Date: Fri, 4 Sep 2009 12:40:47 +0000 Subject: [PATCH] Added preliminary Zilog Z8 CPU core for MESS. --- .gitattributes | 4 + src/emu/cpu/cpu.mak | 16 + src/emu/cpu/z8/z8.c | 948 ++++++++++++++++++++++++++++++++++++++++ src/emu/cpu/z8/z8.h | 41 ++ src/emu/cpu/z8/z8dasm.c | 378 ++++++++++++++++ src/emu/cpu/z8/z8ops.c | 746 +++++++++++++++++++++++++++++++ src/mame/mame.mak | 1 + src/tools/unidasm.c | 2 + 8 files changed, 2136 insertions(+) create mode 100644 src/emu/cpu/z8/z8.c create mode 100644 src/emu/cpu/z8/z8.h create mode 100644 src/emu/cpu/z8/z8dasm.c create mode 100644 src/emu/cpu/z8/z8ops.c diff --git a/.gitattributes b/.gitattributes index 73088f2a204..32ca904cc5d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -492,6 +492,10 @@ src/emu/cpu/z180/z180op.c svneol=native#text/plain src/emu/cpu/z180/z180ops.h svneol=native#text/plain src/emu/cpu/z180/z180tbl.h svneol=native#text/plain src/emu/cpu/z180/z180xy.c svneol=native#text/plain +src/emu/cpu/z8/z8.c svneol=native#text/plain +src/emu/cpu/z8/z8.h svneol=native#text/plain +src/emu/cpu/z8/z8dasm.c svneol=native#text/plain +src/emu/cpu/z8/z8ops.c svneol=native#text/plain src/emu/cpu/z80/z80.c svneol=native#text/plain src/emu/cpu/z80/z80.h svneol=native#text/plain src/emu/cpu/z80/z80daisy.c svneol=native#text/plain diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 919b4cee662..8d4980c5f81 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -1577,6 +1577,22 @@ $(CPUOBJ)/z8000/z8000.o: $(CPUSRC)/z8000/z8000.c \ +#------------------------------------------------- +# Zilog Z8 +#------------------------------------------------- + +ifneq ($(filter Z8,$(CPUS)),) +OBJDIRS += $(CPUOBJ)/z8 +CPUOBJS += $(CPUOBJ)/z8/z8.o +DASMOBJS += $(CPUOBJ)/z8/z8dasm.o +endif + +$(CPUOBJ)/z8/z8.o: $(CPUSRC)/z8/z8.c \ + $(CPUSRC)/z8/z8ops.c \ + $(CPUSRC)/z8/z8.h + + + #------------------------------------------------- # Argonaut SuperFX #------------------------------------------------- diff --git a/src/emu/cpu/z8/z8.c b/src/emu/cpu/z8/z8.c new file mode 100644 index 00000000000..052518be668 --- /dev/null +++ b/src/emu/cpu/z8/z8.c @@ -0,0 +1,948 @@ +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + - strobed I/O + - interrupts + - expose register file to disassembler + - decimal adjust instruction + - timer Tin/Tout modes + - serial + - instruction pipeline + +*/ + +#include "driver.h" +#include "debugger.h" +#include "z8.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + Z8_REGISTER_P0 = 0, + Z8_REGISTER_P1, + Z8_REGISTER_P2, + Z8_REGISTER_P3, + Z8_REGISTER_SIO = 0xf0, + Z8_REGISTER_TMR, + Z8_REGISTER_T1, + Z8_REGISTER_PRE1, + Z8_REGISTER_T0, + Z8_REGISTER_PRE0, + Z8_REGISTER_P2M, + Z8_REGISTER_P3M, + Z8_REGISTER_P01M, + Z8_REGISTER_IPR, + Z8_REGISTER_IRQ, + Z8_REGISTER_IMR, + Z8_REGISTER_FLAGS, + Z8_REGISTER_RP, + Z8_REGISTER_SPH, + Z8_REGISTER_SPL +}; + +#define Z8_P3_DAV0 0x04 /* not supported */ +#define Z8_P3_DAV1 0x08 /* not supported */ +#define Z8_P3_DAV2 0x02 /* not supported */ +#define Z8_P3_RDY0 0x20 /* not supported */ +#define Z8_P3_RDY1 0x10 /* not supported */ +#define Z8_P3_RDY2 0x40 /* not supported */ +#define Z8_P3_IRQ0 0x04 /* not supported */ +#define Z8_P3_IRQ1 0x08 /* not supported */ +#define Z8_P3_IRQ2 0x02 /* not supported */ +#define Z8_P3_IRQ3 0x01 /* not supported */ +#define Z8_P3_DI 0x01 /* not supported */ +#define Z8_P3_DO 0x80 /* not supported */ +#define Z8_P3_TIN 0x02 /* not supported */ +#define Z8_P3_TOUT 0x40 /* not supported */ +#define Z8_P3_DM 0x10 /* not supported */ + +#define Z8_PRE0_COUNT_MODULO_N 0x01 + +#define Z8_PRE1_COUNT_MODULO_N 0x01 +#define Z8_PRE1_INTERNAL_CLOCK 0x02 + +#define Z8_TMR_LOAD_T0 0x01 +#define Z8_TMR_ENABLE_T0 0x02 +#define Z8_TMR_LOAD_T1 0x04 +#define Z8_TMR_ENABLE_T1 0x08 +#define Z8_TMR_TIN_MASK 0x30 /* not supported */ +#define Z8_TMR_TIN_EXTERNAL_CLK 0x00 /* not supported */ +#define Z8_TMR_TIN_GATE 0x10 /* not supported */ +#define Z8_TMR_TIN_TRIGGER 0x20 /* not supported */ +#define Z8_TMR_TIN_RETRIGGER 0x30 /* not supported */ +#define Z8_TMR_TOUT_MASK 0xc0 /* not supported */ +#define Z8_TMR_TOUT_OFF 0x00 /* not supported */ +#define Z8_TMR_TOUT_T0 0x40 /* not supported */ +#define Z8_TMR_TOUT_T1 0x80 /* not supported */ +#define Z8_TMR_TOUT_INTERNAL_CLK 0xc0 /* not supported */ + +#define Z8_P01M_P0L_MODE_MASK 0x03 +#define Z8_P01M_P0L_MODE_OUTPUT 0x00 +#define Z8_P01M_P0L_MODE_INPUT 0x01 +#define Z8_P01M_P0L_MODE_A8_A11 0x02 /* not supported */ +#define Z8_P01M_INTERNAL_STACK 0x04 +#define Z8_P01M_P1_MODE_MASK 0x18 +#define Z8_P01M_P1_MODE_OUTPUT 0x00 +#define Z8_P01M_P1_MODE_INPUT 0x08 +#define Z8_P01M_P1_MODE_AD0_AD7 0x10 /* not supported */ +#define Z8_P01M_P1_MODE_HI_Z 0x18 /* not supported */ +#define Z8_P01M_EXTENDED_TIMING 0x20 /* not supported */ +#define Z8_P01M_P0H_MODE_MASK 0xc0 +#define Z8_P01M_P0H_MODE_OUTPUT 0x00 +#define Z8_P01M_P0H_MODE_INPUT 0x40 +#define Z8_P01M_P0H_MODE_A12_A15 0x80 /* not supported */ + +#define Z8_P3M_P2_ACTIVE_PULLUPS 0x01 /* not supported */ +#define Z8_P3M_P0_STROBED 0x04 /* not supported */ +#define Z8_P3M_P33_P34_MASK 0x18 +#define Z8_P3M_P33_P34_INPUT_OUTPUT 0x00 +#define Z8_P3M_P33_P34_INPUT_DM 0x08 /* not supported */ +#define Z8_P3M_P33_P34_INPUT_DM_2 0x10 /* not supported */ +#define Z8_P3M_P33_P34_DAV1_RDY1 0x18 /* not supported */ +#define Z8_P3M_P2_STROBED 0x20 /* not supported */ +#define Z8_P3M_P3_SERIAL 0x40 /* not supported */ +#define Z8_P3M_PARITY 0x80 /* not supported */ + +#define Z8_IMR_ENABLE 0x80 /* not supported */ +#define Z8_IMR_RAM_PROTECT 0x40 /* not supported */ +#define Z8_IMR_ENABLE_IRQ5 0x20 /* not supported */ +#define Z8_IMR_ENABLE_IRQ4 0x10 /* not supported */ +#define Z8_IMR_ENABLE_IRQ3 0x08 /* not supported */ +#define Z8_IMR_ENABLE_IRQ2 0x04 /* not supported */ +#define Z8_IMR_ENABLE_IRQ1 0x02 /* not supported */ +#define Z8_IMR_ENABLE_IRQ0 0x01 /* not supported */ + +#define Z8_FLAGS_F1 0x01 +#define Z8_FLAGS_F2 0x02 +#define Z8_FLAGS_H 0x04 +#define Z8_FLAGS_D 0x08 +#define Z8_FLAGS_V 0x10 +#define Z8_FLAGS_S 0x20 +#define Z8_FLAGS_Z 0x40 +#define Z8_FLAGS_C 0x80 + +enum +{ + CC_F = 0, CC_LT, CC_LE, CC_ULE, CC_OV, CC_MI, CC_Z, CC_C, + CC_T, CC_GE, CC_GT, CC_UGT, CC_NOV, CC_PL, CC_NZ, CC_NC +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define P01M cpustate->r[Z8_REGISTER_P01M] +#define P2M cpustate->r[Z8_REGISTER_P2M] +#define P3M cpustate->r[Z8_REGISTER_P3M] +#define T0 cpustate->r[Z8_REGISTER_T0] +#define T1 cpustate->r[Z8_REGISTER_T1] +#define PRE0 cpustate->r[Z8_REGISTER_PRE0] +#define PRE1 cpustate->r[Z8_REGISTER_PRE1] + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _z8_state z8_state; +struct _z8_state +{ + const address_space *program; + const address_space *data; + const address_space *io; + + /* registers */ + UINT16 pc; /* program counter */ + UINT8 r[256]; /* register file */ + UINT8 input[4]; /* port input latches */ + UINT8 output[4]; /* port output latches */ + UINT8 t0; /* timer 0 current count */ + UINT8 t1; /* timer 1 current count */ + + /* fake registers */ + UINT16 fake_sp; /* fake stack pointer */ + UINT8 fake_r[16]; /* fake working registers */ + + /* interrupts */ + int irq[6]; /* interrupts */ + + /* execution logic */ + int clock; /* clock */ + int icount; /* instruction counter */ + + cpu_state_table state_table; + + /* timers */ + emu_timer *t0_timer; + emu_timer *t1_timer; +}; + +/*************************************************************************** + CPU STATE DESCRIPTION +***************************************************************************/ + +#define Z8_STATE_ENTRY(_name, _format, _member, _datamask, _flags) \ + CPU_STATE_ENTRY(Z8_##_name, #_name, _format, z8_state, _member, _datamask, ~0, _flags) + +static const cpu_state_entry state_array[] = +{ + Z8_STATE_ENTRY(PC, "%04X", pc, 0xffff, 0) + Z8_STATE_ENTRY(GENPC, "%04X", pc, 0xffff, CPUSTATE_NOSHOW) + Z8_STATE_ENTRY(SP, "%04X", fake_sp, 0xffff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(GENSP, "%04X", fake_sp, 0xffff, CPUSTATE_NOSHOW | CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(RP, "%02X", r[Z8_REGISTER_RP], 0xff, 0) + Z8_STATE_ENTRY(T0, "%02X", t0, 0xff, 0) + Z8_STATE_ENTRY(T1, "%02X", t1, 0xff, 0) + + Z8_STATE_ENTRY(R0, "%02X", fake_r[0], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R1, "%02X", fake_r[1], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R2, "%02X", fake_r[2], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R3, "%02X", fake_r[3], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R4, "%02X", fake_r[4], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R5, "%02X", fake_r[5], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R6, "%02X", fake_r[6], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R7, "%02X", fake_r[7], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R8, "%02X", fake_r[8], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R9, "%02X", fake_r[9], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R10, "%02X", fake_r[10], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R11, "%02X", fake_r[11], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R12, "%02X", fake_r[12], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R13, "%02X", fake_r[13], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R14, "%02X", fake_r[14], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) + Z8_STATE_ENTRY(R15, "%02X", fake_r[15], 0xff, CPUSTATE_IMPORT | CPUSTATE_EXPORT) +}; + +static const cpu_state_table state_table_template = +{ + NULL, /* pointer to the base of state (offsets are relative to this) */ + 0, /* subtype this table refers to */ + ARRAY_LENGTH(state_array), /* number of entries */ + state_array /* array of entries */ +}; + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE z8_state *get_safe_token(const device_config *device) +{ + assert(device != NULL); + assert(device->token != NULL); + assert(device->type == CPU); + assert((cpu_get_type(device) == CPU_Z8601) || + (cpu_get_type(device) == CPU_UB8830D) || + (cpu_get_type(device) == CPU_Z8611)); + return (z8_state *)device->token; +} + +INLINE UINT8 fetch(z8_state *cpustate) +{ + UINT8 data = memory_decrypted_read_byte(cpustate->program, cpustate->pc); + + cpustate->pc++; + + return data; +} + +INLINE UINT8 register_read(z8_state *cpustate, UINT8 offset) +{ + UINT8 data = 0xff; + UINT8 mask = 0; + + switch (offset) + { + case Z8_REGISTER_P0: + switch (P01M & Z8_P01M_P0L_MODE_MASK) + { + case Z8_P01M_P0L_MODE_OUTPUT: data = cpustate->output[offset] & 0x0f; break; + case Z8_P01M_P0L_MODE_INPUT: mask = 0x0f; break; + default: /* A8...A11 */ data = 0x0f; break; + } + + switch (P01M & Z8_P01M_P0H_MODE_MASK) + { + case Z8_P01M_P0H_MODE_OUTPUT: data |= cpustate->output[offset] & 0xf0; break; + case Z8_P01M_P0H_MODE_INPUT: mask |= 0xf0; break; + default: /* A12...A15 */ data |= 0xf0; break; + } + + if (!(P3M & Z8_P3M_P0_STROBED)) + { + if (mask) cpustate->input[offset] = memory_read_byte_8be(cpustate->io, offset); + } + + data |= cpustate->input[offset] & mask; + break; + + case Z8_REGISTER_P1: + switch (P01M & Z8_P01M_P1_MODE_MASK) + { + case Z8_P01M_P1_MODE_OUTPUT: data = cpustate->output[offset]; break; + case Z8_P01M_P1_MODE_INPUT: mask = 0xff; break; + default: /* AD0..AD7 */ data = 0xff; break; + } + + if ((P3M & Z8_P3M_P33_P34_MASK) != Z8_P3M_P33_P34_DAV1_RDY1) + { + if (mask) cpustate->input[offset] = memory_read_byte_8be(cpustate->io, offset); + } + + data |= cpustate->input[offset] & mask; + break; + + case Z8_REGISTER_P2: + mask = cpustate->r[Z8_REGISTER_P2M]; + + if (!(P3M & Z8_P3M_P2_STROBED)) + { + if (mask) cpustate->input[offset] = memory_read_byte_8be(cpustate->io, offset); + } + + data = (cpustate->input[offset] & mask) | (cpustate->output[offset] & ~mask); + break; + + case Z8_REGISTER_P3: + // TODO: special port 3 modes + if (!(P3M & 0x7c)) + { + mask = 0x0f; + } + + if (mask) cpustate->input[offset] = memory_read_byte_8be(cpustate->io, offset); + + data = (cpustate->input[offset] & mask) | (cpustate->output[offset] & ~mask); + break; + + case Z8_REGISTER_T0: + data = cpustate->t0; + break; + + case Z8_REGISTER_T1: + data = cpustate->t1; + break; + + case Z8_REGISTER_PRE1: + case Z8_REGISTER_PRE0: + case Z8_REGISTER_P2M: + case Z8_REGISTER_P3M: + case Z8_REGISTER_P01M: + case Z8_REGISTER_IPR: + /* write only */ + break; + + default: + data = cpustate->r[offset]; + break; + } + + return data; +} + +INLINE UINT16 register_pair_read(z8_state *cpustate, UINT8 offset) +{ + return (register_read(cpustate, offset) << 8) | register_read(cpustate, offset + 1); +} + +INLINE void register_write(z8_state *cpustate, UINT8 offset, UINT8 data) +{ + UINT8 mask = 0; + + switch (offset) + { + case Z8_REGISTER_P0: + cpustate->output[offset] = data; + if ((P01M & Z8_P01M_P0L_MODE_MASK) == Z8_P01M_P0L_MODE_OUTPUT) mask |= 0x0f; + if ((P01M & Z8_P01M_P0H_MODE_MASK) == Z8_P01M_P0H_MODE_OUTPUT) mask |= 0xf0; + if (mask) memory_write_byte_8be(cpustate->io, offset, data & mask); + break; + + case Z8_REGISTER_P1: + cpustate->output[offset] = data; + if ((P01M & Z8_P01M_P1_MODE_MASK) == Z8_P01M_P1_MODE_OUTPUT) mask = 0xff; + if (mask) memory_write_byte_8be(cpustate->io, offset, data & mask); + break; + + case Z8_REGISTER_P2: + cpustate->output[offset] = data; + mask = cpustate->r[Z8_REGISTER_P2M] ^ 0xff; + if (mask) memory_write_byte_8be(cpustate->io, offset, data & mask); + break; + + case Z8_REGISTER_P3: + cpustate->output[offset] = data; + + // TODO: special port 3 modes + if (!(P3M & 0x7c)) + { + mask = 0xf0; + } + + if (mask) memory_write_byte_8be(cpustate->io, offset, data & mask); + break; + + case Z8_REGISTER_SIO: + break; + + case Z8_REGISTER_TMR: + if (data & Z8_TMR_LOAD_T0) + { + cpustate->t0 = T0; + timer_adjust_periodic(cpustate->t0_timer, attotime_zero, 0, ATTOTIME_IN_HZ(cpustate->clock / 2 / 4 / ((PRE0 >> 2) + 1))); + } + + timer_enable(cpustate->t0_timer, data & Z8_TMR_ENABLE_T0); + + if (data & Z8_TMR_LOAD_T1) + { + cpustate->t1 = T1; + timer_adjust_periodic(cpustate->t1_timer, attotime_zero, 0, ATTOTIME_IN_HZ(cpustate->clock / 2 / 4 / ((PRE1 >> 2) + 1))); + } + + timer_enable(cpustate->t1_timer, data & Z8_TMR_ENABLE_T1); + break; + + case Z8_REGISTER_P2M: + break; + case Z8_REGISTER_P3M: + break; + case Z8_REGISTER_P01M: + break; + case Z8_REGISTER_IPR: + break; + case Z8_REGISTER_IRQ: + break; + case Z8_REGISTER_IMR: + break; + case Z8_REGISTER_FLAGS: + break; + case Z8_REGISTER_RP: + break; + case Z8_REGISTER_SPH: + break; + case Z8_REGISTER_SPL: + break; + default: + // TODO ignore missing registers + break; + } + + cpustate->r[offset] = data; +} + +INLINE void register_pair_write(z8_state *cpustate, UINT8 offset, UINT16 data) +{ + register_write(cpustate, offset, data >> 8); + register_write(cpustate, offset + 1, data & 0xff); +} + +INLINE UINT8 get_working_register(z8_state *cpustate, int offset) +{ + return (cpustate->r[Z8_REGISTER_RP] & 0xf0) | (offset & 0x0f); +} + +INLINE UINT8 get_register(z8_state *cpustate, UINT8 offset) +{ + if ((offset & 0xf0) == 0xe0) + return get_working_register(cpustate, offset & 0x0f); + else + return offset; +} + +INLINE UINT8 get_intermediate_register(z8_state *cpustate, int offset) +{ + return register_read(cpustate, get_register(cpustate, offset)); +} + +INLINE void stack_push_byte(z8_state *cpustate, UINT8 src) +{ + if (register_read(cpustate, Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP - 1 */ + UINT8 sp = register_read(cpustate, Z8_REGISTER_SPL) - 1; + register_write(cpustate, Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + register_write(cpustate, sp, src); + } + else + { + /* SP <- SP - 1 */ + UINT16 sp = register_pair_read(cpustate, Z8_REGISTER_SPH) - 1; + register_pair_write(cpustate, Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + memory_write_byte(cpustate->data, sp, src); + } +} + +INLINE void stack_push_word(z8_state *cpustate, UINT16 src) +{ + if (register_read(cpustate, Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP - 2 */ + UINT8 sp = register_read(cpustate, Z8_REGISTER_SPL) - 2; + register_write(cpustate, Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + register_pair_write(cpustate, sp, src); + } + else + { + /* SP <- SP - 2 */ + UINT16 sp = register_pair_read(cpustate, Z8_REGISTER_SPH) - 2; + register_pair_write(cpustate, Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + memory_write_word_8le(cpustate->data, sp, src); + } +} + +INLINE UINT8 stack_pop_byte(z8_state *cpustate) +{ + if (register_read(cpustate, Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP + 1 */ + UINT8 sp = register_read(cpustate, Z8_REGISTER_SPL) + 1; + register_write(cpustate, Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + return register_read(cpustate, sp); + } + else + { + /* SP <- SP + 1 */ + UINT16 sp = register_pair_read(cpustate, Z8_REGISTER_SPH) + 1; + register_pair_write(cpustate, Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + return memory_read_byte(cpustate->data, sp); + } +} + +INLINE UINT16 stack_pop_word(z8_state *cpustate) +{ + if (register_read(cpustate, Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP + 2 */ + UINT8 sp = register_read(cpustate, Z8_REGISTER_SPL) + 2; + register_write(cpustate, Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + return register_read(cpustate, sp); + } + else + { + /* SP <- SP + 2 */ + UINT16 sp = register_pair_read(cpustate, Z8_REGISTER_SPH) + 2; + register_pair_write(cpustate, Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + return memory_read_word_8le(cpustate->data, sp); + } +} + +INLINE void set_flag(z8_state *cpustate, UINT8 flag, int state) +{ + if (state) + cpustate->r[Z8_REGISTER_FLAGS] |= flag; + else + cpustate->r[Z8_REGISTER_FLAGS] &= ~flag; +} + +#define set_flag_h(state) set_flag(cpustate, Z8_FLAGS_H, state); +#define set_flag_d(state) set_flag(cpustate, Z8_FLAGS_D, state); +#define set_flag_v(state) set_flag(cpustate, Z8_FLAGS_V, state); +#define set_flag_s(state) set_flag(cpustate, Z8_FLAGS_S, state); +#define set_flag_z(state) set_flag(cpustate, Z8_FLAGS_Z, state); +#define set_flag_c(state) set_flag(cpustate, Z8_FLAGS_C, state); + +/*************************************************************************** + OPCODE HANDLERS +***************************************************************************/ + +#define INSTRUCTION(mnemonic) INLINE void (mnemonic)(z8_state *cpustate, UINT8 opcode, int *cycles) + +INSTRUCTION( illegal ) +{ + logerror("Z8: PC = %04x, Illegal opcode = %02x\n", cpustate->pc - 1, opcode); +} + +#include "z8ops.c" + +/*************************************************************************** + OPCODE TABLES +***************************************************************************/ + +typedef void (*z8_opcode_func) (z8_state *cpustate, UINT8 opcode, int *cycles); + +typedef struct _z8_opcode_map z8_opcode_map; +struct _z8_opcode_map +{ + z8_opcode_func function; + int execution_cycles; + int pipeline_cycles; +}; + +static const z8_opcode_map Z8601_OPCODE_MAP[] = +{ + { dec_R1, 6, 5 }, { dec_IR1, 6, 5 }, { add_r1_r2, 10, 5 }, { add_r1_Ir2, 10, 5 }, { add_R2_R1, 10, 5 }, { add_IR2_R1, 10, 5 }, { add_R1_IM, 10, 5 }, { add_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { rlc_R1, 6, 5 }, { rlc_IR1, 6, 5 }, { adc_r1_r2, 6, 5 }, { adc_r1_Ir2, 6, 5 }, { adc_R2_R1, 10, 5 }, { adc_IR2_R1, 10, 5 }, { adc_R1_IM, 10, 5 }, { adc_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { inc_R1, 6, 5 }, { inc_IR1, 6, 5 }, { sub_r1_r2, 6, 5 }, { sub_r1_Ir2, 6, 5 }, { sub_R2_R1, 10, 5 }, { sub_IR2_R1, 10, 5 }, { sub_R1_IM, 10, 5 }, { sub_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { jp_IRR1, 8, 0 }, { srp_IM, 6, 1 }, { sbc_r1_r2, 6, 5 }, { sbc_r1_Ir2, 6, 5 }, { sbc_R2_R1, 10, 5 }, { sbc_IR2_R1, 10, 5 }, { sbc_R1_IM, 10, 5 }, { sbc_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { da_R1, 8, 5 }, { da_IR1, 8, 5 }, { or_r1_r2, 6, 5 }, { or_r1_Ir2, 6, 5 }, { or_R2_R1, 10, 5 }, { or_IR2_R1, 10, 5 }, { or_R1_IM, 10, 5 }, { or_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { pop_R1, 10, 5 }, { pop_IR1, 10, 5 }, { and_r1_r2, 6, 5 }, { and_r1_Ir2, 6, 5 }, { and_R2_R1, 10, 5 }, { and_IR2_R1, 10, 5 }, { and_R1_IM, 10, 5 }, { and_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { com_R1, 6, 5 }, { com_IR1, 6, 5 }, { tcm_r1_r2, 6, 5 }, { tcm_r1_Ir2, 6, 5 }, { tcm_R2_R1, 10, 5 }, { tcm_IR2_R1, 10, 5 }, { tcm_R1_IM, 10, 5 }, { tcm_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { push_R2, 10, 1 }, { push_IR2, 12, 1 },{ tm_r1_r2, 6, 5 }, { tm_r1_Ir2, 6, 5 }, { tm_R2_R1, 10, 5 }, { tm_IR2_R1, 10, 5 }, { tm_R1_IM, 10, 5 }, { tm_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { illegal, 0, 0 }, + + { decw_RR1, 10, 5 },{ decw_IR1, 10, 5 },{ lde_r1_Irr2, 12, 0 }, { ldei_Ir1_Irr2, 18, 0 },{ illegal, 0, 0 }, { illegal, 0, 0 }, { illegal, 0, 0 }, { illegal, 0, 0 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { di, 6, 1 }, + + { rl_R1, 6, 5 }, { rl_IR1, 6, 5 }, { lde_r2_Irr1, 12, 0 }, { ldei_Ir2_Irr1, 18, 0 },{ illegal, 0, 0 }, { illegal, 0, 0 }, { illegal, 0, 0 }, { illegal, 0, 0 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { ei, 6, 1 }, + + { incw_RR1, 10, 5 },{ incw_IR1, 10, 5 },{ cp_r1_r2, 6, 5 }, { cp_r1_Ir2, 6, 5 }, { cp_R2_R1, 10, 5 }, { cp_IR2_R1, 10, 5 }, { cp_R1_IM, 10, 5 }, { cp_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { ret, 14, 0 }, + + { clr_R1, 6, 5 }, { clr_IR1, 6, 5 }, { xor_r1_r2, 6, 5 }, { xor_r1_Ir2, 6, 5 }, { xor_R2_R1, 10, 5 }, { xor_IR2_R1, 10, 5 }, { xor_R1_IM, 10, 5 }, { xor_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { iret, 16, 0 }, + + { rrc_R1, 6, 5 }, { rrc_IR1, 6, 5 }, { ldc_r1_Irr2, 12, 0 }, { ldci_Ir1_Irr2, 18, 0 },{ illegal, 0, 0 }, { illegal, 0, 0 }, { illegal, 0, 0 }, { ld_r1_x_R2, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { rcf, 6, 5 }, + + { sra_R1, 6, 5 }, { sra_IR1, 6, 5 }, { ldc_r2_Irr1, 12, 0 }, { ldci_Ir2_Irr1, 18, 0 },{ call_IRR1, 20, 0 }, { illegal, 0, 0 }, { call_DA, 20, 0 }, { ld_r2_x_R1, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { scf, 6, 5 }, + + { rr_R1, 6, 5 }, { rr_IR1, 6, 5 }, { illegal, 0, 0 }, { ld_r1_Ir2, 6, 5 }, { ld_R2_R1, 10, 5 }, { ld_IR2_R1, 10, 5 }, { ld_R1_IM, 10, 5 }, { ld_IR1_IM, 10, 5 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { ccf, 6, 5 }, + + { swap_R1, 8, 5 }, { swap_IR1, 8, 5 }, { illegal, 0, 0 }, { ld_Ir1_r2, 6, 5 }, { illegal, 0, 0 }, { ld_R2_IR1, 10, 5 }, { illegal, 0, 0 }, { illegal, 0, 0 }, + { ld_r1_R2, 6, 5 }, { ld_r2_R1, 6, 5 }, { djnz_r1_RA, 10, 5 }, { jr_cc_RA, 10, 0 }, { ld_r1_IM, 6, 5 }, { jp_cc_DA, 10, 0 }, { inc_r1, 6, 5 }, { nop, 6, 0 }, +}; + +/*************************************************************************** + TIMER CALLBACKS +***************************************************************************/ + +static TIMER_CALLBACK( t0_tick ) +{ + z8_state *cpustate = (z8_state *)ptr; + + cpustate->t0--; + + if (cpustate->t0 == 0) + { + cpustate->t0 = T0; + timer_adjust_periodic(cpustate->t0_timer, attotime_zero, 0, ATTOTIME_IN_HZ(cpustate->clock / 2 / 4 / ((PRE0 >> 2) + 1))); + timer_enable(cpustate->t0_timer, PRE0 & Z8_PRE0_COUNT_MODULO_N); + cpustate->irq[4] = ASSERT_LINE; + } +} + +static TIMER_CALLBACK( t1_tick ) +{ + z8_state *cpustate = (z8_state *)ptr; + + cpustate->t1--; + + if (cpustate->t1 == 0) + { + cpustate->t1 = T1; + timer_adjust_periodic(cpustate->t1_timer, attotime_zero, 0, ATTOTIME_IN_HZ(cpustate->clock / 2 / 4 / ((PRE1 >> 2) + 1))); + timer_enable(cpustate->t1_timer, PRE1 & Z8_PRE0_COUNT_MODULO_N); + cpustate->irq[5] = ASSERT_LINE; + } +} + +/*************************************************************************** + INITIALIZATION +***************************************************************************/ + +static CPU_INIT( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + /* set up the state table */ + cpustate->state_table = state_table_template; + cpustate->state_table.baseptr = cpustate; + cpustate->state_table.subtypemask = 1; + + cpustate->clock = device->clock; + + /* find address spaces */ + cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); + cpustate->data = memory_find_address_space(device, ADDRESS_SPACE_DATA); + cpustate->io = memory_find_address_space(device, ADDRESS_SPACE_IO); + + /* allocate timers */ + cpustate->t0_timer = timer_alloc(device->machine, t0_tick, cpustate); + cpustate->t1_timer = timer_alloc(device->machine, t1_tick, cpustate); + + /* register for state saving */ + state_save_register_device_item(device, 0, cpustate->pc); + state_save_register_device_item_array(device, 0, cpustate->r); + state_save_register_device_item_array(device, 0, cpustate->input); + state_save_register_device_item_array(device, 0, cpustate->output); + state_save_register_device_item_array(device, 0, cpustate->irq); +} + +/*************************************************************************** + EXECUTION +***************************************************************************/ + +static CPU_EXECUTE( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + cpustate->icount = cycles; + + do + { + UINT8 opcode; + int cycles; + + debugger_instruction_hook(device, cpustate->pc); + + /* TODO: sample interrupts */ + cpustate->input[3] = memory_read_byte_8be(cpustate->io, 3); + + /* fetch opcode */ + opcode = fetch(cpustate); + cycles = Z8601_OPCODE_MAP[opcode].execution_cycles; + + /* execute instruction */ + (*(Z8601_OPCODE_MAP[opcode].function))(cpustate, opcode, &cycles); + + cpustate->icount -= cycles; + } + while (cpustate->icount > 0); + + return cycles - cpustate->icount; +} + +/*************************************************************************** + RESET +***************************************************************************/ + +static CPU_RESET( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + cpustate->pc = 0x000c; + + register_write(cpustate, Z8_REGISTER_TMR, 0x00); + register_write(cpustate, Z8_REGISTER_PRE1, register_read(cpustate, Z8_REGISTER_PRE1) & 0xfc); + register_write(cpustate, Z8_REGISTER_PRE0, register_read(cpustate, Z8_REGISTER_PRE0) & 0xfe); + register_write(cpustate, Z8_REGISTER_P2M, 0xff); + register_write(cpustate, Z8_REGISTER_P3M, 0x00); + register_write(cpustate, Z8_REGISTER_P01M, 0x4d); + register_write(cpustate, Z8_REGISTER_IRQ, 0x00); + register_write(cpustate, Z8_REGISTER_RP, 0x00); +} + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +static ADDRESS_MAP_START( program_2kb, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x07ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( program_4kb, ADDRESS_SPACE_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x0fff) AM_ROM +ADDRESS_MAP_END + +/************************************************************************** + * STATE IMPORT/EXPORT + **************************************************************************/ + +static CPU_IMPORT_STATE( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + switch (entry->index) + { + case Z8_SP: + case Z8_GENSP: + cpustate->r[Z8_REGISTER_SPH] = cpustate->fake_sp >> 8; + cpustate->r[Z8_REGISTER_SPL] = cpustate->fake_sp & 0xff; + break; + + case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15: + cpustate->r[cpustate->r[Z8_REGISTER_RP] + (entry->index - Z8_R0)] = cpustate->fake_r[entry->index - Z8_R0]; + break; + + default: + fatalerror("CPU_IMPORT_STATE(z8) called for unexpected value\n"); + break; + } +} + +static CPU_EXPORT_STATE( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + switch (entry->index) + { + case Z8_SP: + case Z8_GENSP: + cpustate->fake_sp = (cpustate->r[Z8_REGISTER_SPH] << 8) | cpustate->r[Z8_REGISTER_SPL]; + break; + + case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15: + cpustate->fake_r[entry->index - Z8_R0] = cpustate->r[cpustate->r[Z8_REGISTER_RP] + (entry->index - Z8_R0)]; + break; + + default: + fatalerror("CPU_EXPORT_STATE(z8) called for unexpected value\n"); + break; + } +} + +/*************************************************************************** + GENERAL CONTEXT ACCESS +***************************************************************************/ + +static CPU_SET_INFO( z8 ) +{ + z8_state *cpustate = get_safe_token(device); + + switch (state) + { + case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ0: cpustate->irq[0] = info->i; break; + case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ1: cpustate->irq[1] = info->i; break; + case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ2: cpustate->irq[2] = info->i; break; + case CPUINFO_INT_INPUT_STATE + INPUT_LINE_IRQ3: cpustate->irq[3] = info->i; break; + } +} + +static CPU_GET_INFO( z8 ) +{ + z8_state *cpustate = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; + + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(z8_state); break; + case CPUINFO_INT_INPUT_LINES: info->i = 4; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 2; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 3; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 6; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 20; break; + + case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 16; break; + case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 16; break; + case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 2; break; + case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break; + + /* --- the following bits of info are returned as pointers to functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(z8); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(z8); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(z8); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(z8); break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(z8); break; + case CPUINFO_FCT_IMPORT_STATE: info->import_state = CPU_IMPORT_STATE_NAME(z8); break; + case CPUINFO_FCT_EXPORT_STATE: info->export_state = CPU_EXPORT_STATE_NAME(z8); break; + + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; + case CPUINFO_PTR_STATE_TABLE: info->state_table = &cpustate->state_table; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Z8"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Zilog Z8"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break; + + case CPUINFO_STR_FLAGS: sprintf(info->s, + "%c%c%c%c%c%c", + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_C ? 'C' : '.', + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_Z ? 'Z' : '.', + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_S ? 'S' : '.', + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_V ? 'V' : '.', + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_D ? 'D' : '.', + cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS_H ? 'H' : '.'); break; + } +} + +/*************************************************************************** + CPU-SPECIFIC CONTEXT ACCESS +***************************************************************************/ + +CPU_GET_INFO( z8601 ) +{ + switch (state) + { + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(program_2kb); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Z8601"); break; + + default: CPU_GET_INFO_CALL(z8); break; + } +} + +CPU_GET_INFO( ub8830d ) +{ + switch (state) + { + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(program_2kb); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "UB8830D"); break; + + default: CPU_GET_INFO_CALL(z8); break; + } +} + +CPU_GET_INFO( z8611 ) +{ + switch (state) + { + /* --- the following bits of info are returned as pointers --- */ + case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(program_4kb); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Z8611"); break; + + default: CPU_GET_INFO_CALL(z8); break; + } +} diff --git a/src/emu/cpu/z8/z8.h b/src/emu/cpu/z8/z8.h new file mode 100644 index 00000000000..0f0bc364df6 --- /dev/null +++ b/src/emu/cpu/z8/z8.h @@ -0,0 +1,41 @@ +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#pragma once + +#ifndef __Z8_H__ +#define __Z8_H__ + +#include "cpuintrf.h" + +enum +{ + Z8_PC, Z8_SP, Z8_RP, Z8_T0, Z8_T1, + + Z8_R0, Z8_R1, Z8_R2, Z8_R3, Z8_R4, Z8_R5, Z8_R6, Z8_R7, Z8_R8, Z8_R9, Z8_R10, Z8_R11, Z8_R12, Z8_R13, Z8_R14, Z8_R15, + + Z8_GENPC = REG_GENPC, + Z8_GENSP = REG_GENSP +}; + +/* Zilog Z8601 */ +CPU_GET_INFO( z8601 ); +#define CPU_Z8601 CPU_GET_INFO_NAME( z8601 ) + +/* VEB Mikroelektronik Erfurt UB8830D MME */ +CPU_GET_INFO( ub8830d ); +#define CPU_UB8830D CPU_GET_INFO_NAME( ub8830d ) + +/* Zilog Z8611 */ +CPU_GET_INFO( z8611 ); +#define CPU_Z8611 CPU_GET_INFO_NAME( z8611 ) + +CPU_DISASSEMBLE( z8 ); + +#endif diff --git a/src/emu/cpu/z8/z8dasm.c b/src/emu/cpu/z8/z8dasm.c new file mode 100644 index 00000000000..07aef5bf9b2 --- /dev/null +++ b/src/emu/cpu/z8/z8dasm.c @@ -0,0 +1,378 @@ +#include "cpuintrf.h" +#include "debugger.h" +#include "z8.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +static const char* REGISTER_NAME[256] = +{ + "P0", "P1", "P2", "P3", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "SIO", "TMR", "T1", "PRE1", "T0", "PRE0", "P2M", "P3M", "P01M", "IPR", "IRQ", "IMR", "FLAGS", "RP", "SPH", "SPL" +}; + +static const char* CONDITION_CODE[16] = +{ + "F", "LT", "LE", "ULE", "OV", "MI", "Z", "C", + "", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC" +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define r "R%u" +#define Ir "@R%u" +#define R "%02Xh" +#define RR "%02Xh" +#define IR "@%02Xh" +#define Irr "@RR%u" +#define IRR "@%02Xh" +#define IM "#%02Xh" +#define X "%02Xh(R%u)" +#define DA "%04Xh" +#define RA "%04Xh" + +#define B0 oprom[0] +#define B1 oprom[1] +#define B0H (B0 >> 4) +#define B0L (B0 & 0x0f) +#define OPH (opcode >> 4) + +#define ARG(_formatting, _value) { if (argc) dst += sprintf(dst, ", "); dst += sprintf(dst, _formatting, _value); argc++; } + +#define arg_name(_value) ARG("%s", REGISTER_NAME[_value]) +#define arg_cc ARG("%s", CONDITION_CODE[OPH]) +#define arg_r(_value) ARG(r, _value) +#define arg_Ir(_value) ARG(Ir, _value) +#define arg_Irr(_value) ARG(Irr, _value & 0x0f) +#define arg_R(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else if ((_value < 4) || (_value >= 0xf0)) arg_name(_value) else ARG(R, _value) +#define arg_RR(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else ARG(R, _value) +#define arg_IR(_value) if ((_value & 0xf0) == 0xe0) ARG(Ir, _value & 0x0f) else ARG(IR, _value) +#define arg_IRR(_value) if ((_value & 0xf0) == 0xe0) ARG(Irr, _value & 0x0f) else ARG(IRR, _value) +#define arg_IM(_value) ARG(IM, _value) +#define arg_RA ARG(RA, pc + (INT8)B0 + 2) +#define arg_DA ARG(DA, B0 << 8 | B1) +#define arg_X(_value1, _value2) { if (argc) dst += sprintf(dst, ", "); dst += sprintf(dst, X, _value1, _value2); argc++; } + +#define illegal dst += sprintf(dst, "Illegal") +#define mnemonic(_mnemonic) dst += sprintf(dst, "%-5s", _mnemonic) +#define bytes(_count) oprom += (_count - 1) +#define step_over flags = DASMFLAG_STEP_OVER +#define step_out flags = DASMFLAG_STEP_OUT + +/*************************************************************************** + DISASSEMBLER +***************************************************************************/ + +CPU_DISASSEMBLE( z8 ) +{ + const UINT8 *startrom = oprom; + UINT32 flags = 0; + UINT8 opcode = *oprom++; + char *dst = buffer; + int argc = 0; + + switch (pc) + { + case 0x0000: + case 0x0002: + case 0x0004: + case 0x0006: + case 0x0008: + case 0x000a: + sprintf(buffer, "IRQ%u Vector %04Xh", pc / 2, opcode << 8 | *oprom++); break; + default: + switch (opcode) + { + case 0x00: mnemonic("DEC"); arg_R(B0); bytes(2); break; + case 0x01: mnemonic("DEC"); arg_IR(B0); bytes(2); break; + case 0x02: mnemonic("ADD"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x03: mnemonic("ADD"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x04: mnemonic("ADD"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x05: mnemonic("ADD"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x06: mnemonic("ADD"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x07: mnemonic("ADD"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x08: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x09: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x0a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x0b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x0c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x0d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x0e: mnemonic("INC"); arg_r(OPH); break; + case 0x0f: illegal; break; + + case 0x10: mnemonic("RLC"); arg_R(B0); bytes(2); break; + case 0x11: mnemonic("RLC"); arg_IR(B0); bytes(2); break; + case 0x12: mnemonic("ADC"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x13: mnemonic("ADC"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x14: mnemonic("ADC"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x15: mnemonic("ADC"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x16: mnemonic("ADC"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x17: mnemonic("ADC"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x18: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x19: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x1a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x1b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x1c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x1d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x1e: mnemonic("INC"); arg_r(OPH); break; + case 0x1f: illegal; break; + + case 0x20: mnemonic("INC"); arg_R(B0); bytes(2); break; + case 0x21: mnemonic("INC"); arg_IR(B0); bytes(2); break; + case 0x22: mnemonic("SUB"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x23: mnemonic("SUB"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x24: mnemonic("SUB"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x25: mnemonic("SUB"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x26: mnemonic("SUB"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x27: mnemonic("SUB"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x28: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x29: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x2a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x2b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x2c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x2d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x2e: mnemonic("INC"); arg_r(OPH); break; + case 0x2f: illegal; break; + + case 0x30: mnemonic("JP"); arg_IRR(B0); bytes(2); break; + case 0x31: mnemonic("SRP"); arg_IM(*oprom++); break; + case 0x32: mnemonic("SBC"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x33: mnemonic("SBC"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x34: mnemonic("SBC"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x35: mnemonic("SBC"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x36: mnemonic("SBC"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x37: mnemonic("SBC"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x38: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x39: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x3a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x3b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x3c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x3d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x3e: mnemonic("INC"); arg_r(OPH); break; + case 0x3f: illegal; break; + + case 0x40: mnemonic("DA"); arg_R(B0); bytes(2); break; + case 0x41: mnemonic("DA"); arg_IR(B0); bytes(2); break; + case 0x42: mnemonic("OR"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x43: mnemonic("OR"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x44: mnemonic("OR"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x45: mnemonic("OR"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x46: mnemonic("OR"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x47: mnemonic("OR"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x48: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x49: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x4a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x4b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x4c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x4d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x4e: mnemonic("INC"); arg_r(OPH); break; + case 0x4f: illegal; /* mnemonic("WDH"); */ break; + + case 0x50: mnemonic("POP"); arg_R(B0); bytes(2); break; + case 0x51: mnemonic("POP"); arg_IR(B0); bytes(2); break; + case 0x52: mnemonic("AND"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x53: mnemonic("AND"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x54: mnemonic("AND"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x55: mnemonic("AND"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x56: mnemonic("AND"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x57: mnemonic("AND"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x58: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x59: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x5a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x5b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x5c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x5d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x5e: mnemonic("INC"); arg_r(OPH); break; + case 0x5f: illegal; /* mnemonic("WDT"); */ break; + + case 0x60: mnemonic("COM"); arg_R(B0); bytes(2); break; + case 0x61: mnemonic("COM"); arg_IR(B0); bytes(2); break; + case 0x62: mnemonic("TCM"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x63: mnemonic("TCM"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x64: mnemonic("TCM"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x65: mnemonic("TCM"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x66: mnemonic("TCM"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x67: mnemonic("TCM"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x68: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x69: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x6a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x6b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x6c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x6d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x6e: mnemonic("INC"); arg_r(OPH); break; + case 0x6f: illegal; /* mnemonic("STOP"); */ break; + + case 0x70: mnemonic("PUSH"); arg_R(B0); bytes(2); break; + case 0x71: mnemonic("PUSH"); arg_IR(B0); bytes(2); break; + case 0x72: mnemonic("TM"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x73: mnemonic("TM"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x74: mnemonic("TM"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0x75: mnemonic("TM"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0x76: mnemonic("TM"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x77: mnemonic("TM"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x78: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x79: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x7a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x7b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x7c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x7d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x7e: mnemonic("INC"); arg_r(OPH); break; + case 0x7f: illegal; /* mnemonic("HALT"); */ break; + + case 0x80: mnemonic("DECW"); arg_RR(*oprom++); break; + case 0x81: mnemonic("DECW"); arg_IR(B0); bytes(2); break; + case 0x82: mnemonic("LDE"); arg_r(B0H); arg_Irr(B0L); bytes(2); break; + case 0x83: mnemonic("LDEI"); arg_Ir(B0H); arg_Irr(B0L); bytes(2); break; + case 0x84: illegal; break; + case 0x85: illegal; break; + case 0x86: illegal; break; + case 0x87: illegal; break; + case 0x88: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x89: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x8a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x8b: mnemonic("JR"); arg_RA; bytes(2); break; + case 0x8c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x8d: mnemonic("JP"); arg_DA; bytes(3); break; + case 0x8e: mnemonic("INC"); arg_r(OPH); break; + case 0x8f: mnemonic("DI"); break; + + case 0x90: mnemonic("RL"); arg_R(B0); bytes(2); break; + case 0x91: mnemonic("RL"); arg_IR(B0); bytes(2); break; + case 0x92: mnemonic("LDE"); arg_r(B0L); arg_Irr(B0H); bytes(2); break; + case 0x93: mnemonic("LDEI"); arg_Ir(B0L); arg_Irr(B0H); bytes(2); break; + case 0x94: illegal; break; + case 0x95: illegal; break; + case 0x96: illegal; break; + case 0x97: illegal; break; + case 0x98: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x99: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x9a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x9b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x9c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x9d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x9e: mnemonic("INC"); arg_r(OPH); break; + case 0x9f: mnemonic("EI"); break; + + case 0xa0: mnemonic("INCW"); arg_RR(B0); bytes(2); break; + case 0xa1: mnemonic("INCW"); arg_IR(B0); bytes(2); break; + case 0xa2: mnemonic("CP"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0xa3: mnemonic("CP"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xa4: mnemonic("CP"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0xa5: mnemonic("CP"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0xa6: mnemonic("CP"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xa7: mnemonic("CP"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xa8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xa9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xaa: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xab: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xac: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xad: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xae: mnemonic("INC"); arg_r(OPH); break; + case 0xaf: mnemonic("RET"); step_out; break; + + case 0xb0: mnemonic("CLR"); arg_R(B0); bytes(2); break; + case 0xb1: mnemonic("XOR"); arg_IR(B0); bytes(2); break; + case 0xb2: mnemonic("XOR"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0xb3: mnemonic("XOR"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xb4: mnemonic("XOR"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0xb5: mnemonic("XOR"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0xb6: mnemonic("XOR"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xb7: mnemonic("XOR"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xb8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xb9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xba: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xbb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xbc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xbd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xbe: mnemonic("INC"); arg_r(OPH); break; + case 0xbf: mnemonic("IRET"); step_out; break; + + case 0xc0: mnemonic("RRC"); arg_R(B0); bytes(2); break; + case 0xc1: mnemonic("RRC"); arg_IR(B0); bytes(2); break; + case 0xc2: mnemonic("LDC"); arg_r(B0H); arg_Irr(B0L); bytes(2); break; + case 0xc3: mnemonic("LDCI"); arg_Ir(B0H); arg_Irr(B0L); bytes(2); break; + case 0xc4: illegal; break; + case 0xc5: illegal; break; + case 0xc6: illegal; break; + case 0xc7: mnemonic("LD"); arg_r(B0H); arg_X(B1, B0L); bytes(3); break; + case 0xc8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xc9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xca: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xcb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xcc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xcd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xce: mnemonic("INC"); arg_r(OPH); break; + case 0xcf: mnemonic("RCF"); break; + + case 0xd0: mnemonic("SRA"); arg_R(B0); bytes(2); break; + case 0xd1: mnemonic("SRA"); arg_IR(B0); bytes(2); break; + case 0xd2: mnemonic("LDC"); arg_Irr(B0L); arg_r(B0H); bytes(2); break; + case 0xd3: mnemonic("LDCI"); arg_Irr(B0L); arg_Ir(B0H); bytes(2); break; + case 0xd4: mnemonic("CALL"); arg_IRR(B0); bytes(2); step_over; break; + case 0xd5: illegal; break; + case 0xd6: mnemonic("CALL"); arg_DA; bytes(3); step_over; break; + case 0xd7: mnemonic("LD"); arg_r(B0L); arg_X(B1, B0H); bytes(3); break; + case 0xd8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xd9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xda: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xdb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xdc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xdd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xde: mnemonic("INC"); arg_r(OPH); break; + case 0xdf: mnemonic("SCF"); break; + + case 0xe0: mnemonic("RR"); arg_R(B0); bytes(2); break; + case 0xe1: mnemonic("RR"); arg_IR(B0); bytes(2); break; + case 0xe2: illegal; break; + case 0xe3: mnemonic("LD"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xe4: mnemonic("LD"); arg_R(B0); arg_R(B1); bytes(3); break; + case 0xe5: mnemonic("LD"); arg_R(B0); arg_IR(B1); bytes(3); break; + case 0xe6: mnemonic("LD"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xe7: mnemonic("LD"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xe8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xe9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xea: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xeb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xec: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xed: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xee: mnemonic("INC"); arg_r(OPH); break; + case 0xef: mnemonic("CCF"); break; + + case 0xf0: mnemonic("SWAP"); arg_R(B0); bytes(2); break; + case 0xf1: mnemonic("SWAP"); arg_IR(B0); bytes(2); break; + case 0xf2: illegal; break; + case 0xf3: mnemonic("LD"); arg_Ir(B0H); arg_r(B0L); bytes(2); break; + case 0xf4: illegal; break; + case 0xf5: mnemonic("LD"); arg_IR(B0); arg_R(B1); bytes(3); break; + case 0xf6: illegal; break; + case 0xf7: illegal; break; + case 0xf8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xf9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xfa: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xfb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xfc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xfd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xfe: mnemonic("INC"); arg_r(OPH); break; + case 0xff: mnemonic("NOP"); break; + } + } + + return (oprom - startrom) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/emu/cpu/z8/z8ops.c b/src/emu/cpu/z8/z8ops.c new file mode 100644 index 00000000000..fd9a7467674 --- /dev/null +++ b/src/emu/cpu/z8/z8ops.c @@ -0,0 +1,746 @@ +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define read(_reg) register_read(cpustate, _reg) +#define r(_data) get_working_register(cpustate, _data) +#define Ir(_data) get_intermediate_register(cpustate, get_working_register(cpustate, _data)) +#define R get_register(cpustate, fetch(cpustate)) +#define IR get_intermediate_register(cpustate, get_register(cpustate, fetch(cpustate))) +#define RR get_intermediate_register(cpustate, get_register(cpustate, fetch(cpustate))) +#define IM fetch(cpustate) +#define flag(_flag) ((cpustate->r[Z8_REGISTER_FLAGS] & Z8_FLAGS##_##_flag) ? 1 : 0) + +#define mode_r1_r2(_func) \ + UINT8 dst_src = fetch(cpustate);\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(r(dst_src & 0x0f));\ + _func(cpustate, dst, src); + +#define mode_r1_Ir2(_func) \ + UINT8 dst_src = fetch(cpustate);\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(Ir(dst_src & 0x0f));\ + _func(cpustate, dst, src); + +#define mode_R2_R1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = R;\ + _func(cpustate, dst, src); + +#define mode_IR2_R1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = IR;\ + _func(cpustate, dst, src); + +#define mode_R1_IM(_func) \ + UINT8 dst = R;\ + UINT8 src = IM;\ + _func(cpustate, dst, src); + +#define mode_IR1_IM(_func) \ + UINT8 dst = IR;\ + UINT8 src = IM;\ + _func(cpustate, dst, src); + +#define mode_r1(_func) \ + UINT8 dst = r(opcode >> 4);\ + _func(cpustate, dst); + +#define mode_R1(_func) \ + UINT8 dst = R;\ + _func(cpustate, dst); + +#define mode_RR1(_func) \ + UINT8 dst = R;\ + _func(cpustate, dst); + +#define mode_IR1(_func) \ + UINT8 dst = IR;\ + _func(cpustate, dst); + +#define mode_r1_IM(_func) \ + UINT8 dst = r(opcode >> 4);\ + UINT8 src = IM;\ + _func(cpustate, dst, src); + +#define mode_r1_R2(_func) \ + UINT8 dst = r(opcode >> 4);\ + UINT8 src = read(R);\ + _func(cpustate, dst, src); + +#define mode_r2_R1(_func) \ + UINT8 src = read(r(opcode >> 4));\ + UINT8 dst = R;\ + _func(cpustate, dst, src); + +#define mode_Ir1_r2(_func) \ + UINT8 dst_src = fetch(cpustate);\ + UINT8 dst = Ir(dst_src >> 4);\ + UINT8 src = read(r(dst_src & 0x0f));\ + _func(cpustate, dst, src); + +#define mode_R2_IR1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = IR;\ + _func(cpustate, dst, src); + +#define mode_r1_x_R2(_func) \ + UINT8 dst_src = fetch(cpustate);\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(read(r(dst_src & 0x0f)) + R);\ + _func(cpustate, dst, src); + +#define mode_r2_x_R1(_func) \ + UINT8 dst_src = fetch(cpustate);\ + UINT8 dst = R + read(r(dst_src & 0x0f));\ + UINT8 src = read(r(dst_src >> 4));\ + _func(cpustate, dst, src); + +/*************************************************************************** + LOAD INSTRUCTIONS +***************************************************************************/ + +static void clear(z8_state *cpustate, UINT8 dst) +{ + /* dst <- 0 */ + register_write(cpustate, dst, 0); +} + +INSTRUCTION( clr_R1 ) { mode_R1(clear) } +INSTRUCTION( clr_IR1 ) { mode_IR1(clear) } + +static void load(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- src */ + register_write(cpustate, dst, src); +} + +INSTRUCTION( ld_r1_IM ) { mode_r1_IM(load) } +INSTRUCTION( ld_r1_R2 ) { mode_r1_R2(load) } +INSTRUCTION( ld_r2_R1 ) { mode_r2_R1(load) } +INSTRUCTION( ld_Ir1_r2 ) { mode_Ir1_r2(load) } +INSTRUCTION( ld_R2_IR1 ) { mode_R2_IR1(load) } +INSTRUCTION( ld_r1_x_R2 ) { mode_r1_x_R2(load) } +INSTRUCTION( ld_r2_x_R1 ) { mode_r2_x_R1(load) } + +INSTRUCTION( ld_r1_r2 ) { mode_r1_r2(load) } +INSTRUCTION( ld_r1_Ir2 ) { mode_r1_Ir2(load) } +INSTRUCTION( ld_R2_R1 ) { mode_R2_R1(load) } +INSTRUCTION( ld_IR2_R1 ) { mode_IR2_R1(load) } +INSTRUCTION( ld_R1_IM ) { mode_R1_IM(load) } +INSTRUCTION( ld_IR1_IM ) { mode_IR1_IM(load) } + +static void load_from_memory(z8_state *cpustate, const address_space *space) +{ + UINT8 operands = fetch(cpustate); + UINT8 dst = get_working_register(cpustate, operands >> 4); + UINT8 src = get_working_register(cpustate, operands & 0x0f); + + UINT16 address = register_pair_read(cpustate, src); + UINT8 data = memory_decrypted_read_byte(cpustate->program, address); + + register_write(cpustate, dst, data); +} + +static void load_to_memory(z8_state *cpustate, const address_space *space) +{ + UINT8 operands = fetch(cpustate); + UINT8 src = get_working_register(cpustate, operands >> 4); + UINT8 dst = get_working_register(cpustate, operands & 0x0f); + + UINT16 address = register_pair_read(cpustate, dst); + UINT8 data = register_read(cpustate, src); + + memory_write_byte(cpustate->program, address, data); +} + +static void load_from_memory_autoinc(z8_state *cpustate, const address_space *space) +{ + UINT8 operands = fetch(cpustate); + UINT8 dst = get_working_register(cpustate, operands >> 4); + UINT8 real_dst = get_intermediate_register(cpustate, dst); + UINT8 src = get_working_register(cpustate, operands & 0x0f); + + UINT16 address = register_pair_read(cpustate, src); + UINT8 data = memory_decrypted_read_byte(cpustate->program, address); + + register_write(cpustate, real_dst, data); + + register_write(cpustate, dst, real_dst + 1); + register_pair_write(cpustate, src, address + 1); +} + +static void load_to_memory_autoinc(z8_state *cpustate, const address_space *space) +{ + UINT8 operands = fetch(cpustate); + UINT8 src = get_working_register(cpustate, operands >> 4); + UINT8 dst = get_working_register(cpustate, operands & 0x0f); + UINT8 real_src = get_intermediate_register(cpustate, src); + + UINT16 address = register_pair_read(cpustate, dst); + UINT8 data = register_read(cpustate, real_src); + + memory_write_byte(cpustate->program, address, data); + + register_pair_write(cpustate, dst, address + 1); + register_write(cpustate, src, real_src + 1); +} + +INSTRUCTION( ldc_r1_Irr2 ) { load_from_memory(cpustate, cpustate->program); } +INSTRUCTION( ldc_r2_Irr1 ) { load_to_memory(cpustate, cpustate->program); } +INSTRUCTION( ldci_Ir1_Irr2 ) { load_from_memory_autoinc(cpustate, cpustate->program); } +INSTRUCTION( ldci_Ir2_Irr1 ) { load_to_memory_autoinc(cpustate, cpustate->program); } +INSTRUCTION( lde_r1_Irr2 ) { load_from_memory(cpustate, cpustate->data); } +INSTRUCTION( lde_r2_Irr1 ) { load_to_memory(cpustate, cpustate->data); } +INSTRUCTION( ldei_Ir1_Irr2 ) { load_from_memory_autoinc(cpustate, cpustate->data); } +INSTRUCTION( ldei_Ir2_Irr1 ) { load_to_memory_autoinc(cpustate, cpustate->data); } + +static void pop(z8_state *cpustate, UINT8 dst) +{ + /* dst <- @SP + SP <- SP + 1 */ + register_write(cpustate, dst, stack_pop_byte(cpustate)); +} + +INSTRUCTION( pop_R1 ) { mode_R1(pop) } +INSTRUCTION( pop_IR1 ) { mode_IR1(pop) } + +static void push(z8_state *cpustate, UINT8 src) +{ + /* SP <- SP - 1 + @SP <- src */ + stack_push_byte(cpustate, read(src)); +} + +INSTRUCTION( push_R2 ) { mode_R1(push) } +INSTRUCTION( push_IR2 ) { mode_IR1(push) } + +/*************************************************************************** + ARITHMETIC INSTRUCTIONS +***************************************************************************/ + +static void add_carry(z8_state *cpustate, UINT8 dst, INT8 src) +{ + /* dst <- dst + src + C */ + UINT8 data = register_read(cpustate, dst); + UINT16 new_data = data + src + flag(C); + + set_flag_c(new_data & 0x100); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) == (src & 0x80)) && ((new_data & 0x80) != (src & 0x80))); + set_flag_d(0); + set_flag_h(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10)); + + register_write(cpustate, dst, new_data & 0xff); +} + +INSTRUCTION( adc_r1_r2 ) { mode_r1_r2(add_carry) } +INSTRUCTION( adc_r1_Ir2 ) { mode_r1_Ir2(add_carry) } +INSTRUCTION( adc_R2_R1 ) { mode_R2_R1(add_carry) } +INSTRUCTION( adc_IR2_R1 ) { mode_IR2_R1(add_carry) } +INSTRUCTION( adc_R1_IM ) { mode_R1_IM(add_carry) } +INSTRUCTION( adc_IR1_IM ) { mode_IR1_IM(add_carry) } + +static void add(z8_state *cpustate, UINT8 dst, INT8 src) +{ + /* dst <- dst + src */ + UINT8 data = register_read(cpustate, dst); + UINT16 new_data = data + src; + + set_flag_c(new_data & 0x100); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) == (src & 0x80)) && ((new_data & 0x80) != (src & 0x80))); + set_flag_d(0); + set_flag_h(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10)); + + register_write(cpustate, dst, new_data & 0xff); +} + +INSTRUCTION( add_r1_r2 ) { mode_r1_r2(add) } +INSTRUCTION( add_r1_Ir2 ) { mode_r1_Ir2(add) } +INSTRUCTION( add_R2_R1 ) { mode_R2_R1(add) } +INSTRUCTION( add_IR2_R1 ) { mode_IR2_R1(add) } +INSTRUCTION( add_R1_IM ) { mode_R1_IM(add) } +INSTRUCTION( add_IR1_IM ) { mode_IR1_IM(add) } + +static void compare(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst - src */ + UINT8 data = register_read(cpustate, dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); +} + +INSTRUCTION( cp_r1_r2 ) { mode_r1_r2(compare) } +INSTRUCTION( cp_r1_Ir2 ) { mode_r1_Ir2(compare) } +INSTRUCTION( cp_R2_R1 ) { mode_R2_R1(compare) } +INSTRUCTION( cp_IR2_R1 ) { mode_IR2_R1(compare) } +INSTRUCTION( cp_R1_IM ) { mode_R1_IM(compare) } +INSTRUCTION( cp_IR1_IM ) { mode_IR1_IM(compare) } + +static void decimal_adjust(z8_state *cpustate, UINT8 dst) +{ +} + +INSTRUCTION( da_R1 ) { mode_R1(decimal_adjust) } +INSTRUCTION( da_IR1 ) { mode_IR1(decimal_adjust) } + +static void decrement(z8_state *cpustate, UINT8 dst) +{ + /* dst <- dst - 1 */ + UINT8 data = register_read(cpustate, dst) - 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(data == 0x7f); + + register_write(cpustate, dst, data); +} + +INSTRUCTION( dec_R1 ) { mode_R1(decrement) } +INSTRUCTION( dec_IR1 ) { mode_IR1(decrement) } + +static void decrement_word(z8_state *cpustate, UINT8 dst) +{ + /* dst <- dst - 1 */ + UINT16 data = register_pair_read(cpustate, dst) - 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x8000); + set_flag_v(data == 0x7fff); + + register_pair_write(cpustate, dst, data); +} + +INSTRUCTION( decw_RR1 ) { mode_RR1(decrement_word) } +INSTRUCTION( decw_IR1 ) { mode_IR1(decrement_word) } + +static void increment(z8_state *cpustate, UINT8 dst) +{ + /* dst <- dst + 1 */ + UINT8 data = register_read(cpustate, dst) + 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(data == 0x80); + + register_write(cpustate, dst, data); +} + +INSTRUCTION( inc_r1 ) { mode_r1(increment) } +INSTRUCTION( inc_R1 ) { mode_R1(increment) } +INSTRUCTION( inc_IR1 ) { mode_IR1(increment) } + +static void increment_word(z8_state *cpustate, UINT8 dst) +{ + /* dst <- dst + 1 */ + UINT16 data = register_pair_read(cpustate, dst) + 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x8000); + set_flag_v(data == 0x8000); + + register_pair_write(cpustate, dst, data); +} + +INSTRUCTION( incw_RR1 ) { mode_RR1(increment_word) } +INSTRUCTION( incw_IR1 ) { mode_IR1(increment_word) } + +static void subtract_carry(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- dst - src - C */ + UINT8 data = register_read(cpustate, dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); + set_flag_d(1); + set_flag_h(!(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10))); + + register_write(cpustate, dst, new_data & 0xff); +} + +INSTRUCTION( sbc_r1_r2 ) { mode_r1_r2(subtract_carry) } +INSTRUCTION( sbc_r1_Ir2 ) { mode_r1_Ir2(subtract_carry) } +INSTRUCTION( sbc_R2_R1 ) { mode_R2_R1(subtract_carry) } +INSTRUCTION( sbc_IR2_R1 ) { mode_IR2_R1(subtract_carry) } +INSTRUCTION( sbc_R1_IM ) { mode_R1_IM(subtract_carry) } +INSTRUCTION( sbc_IR1_IM ) { mode_IR1_IM(subtract_carry) } + +static void subtract(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- dst - src */ + UINT8 data = register_read(cpustate, dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); + set_flag_d(1); + set_flag_h(!(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10))); + + register_write(cpustate, dst, new_data & 0xff); +} + +INSTRUCTION( sub_r1_r2 ) { mode_r1_r2(subtract) } +INSTRUCTION( sub_r1_Ir2 ) { mode_r1_Ir2(subtract) } +INSTRUCTION( sub_R2_R1 ) { mode_R2_R1(subtract) } +INSTRUCTION( sub_IR2_R1 ) { mode_IR2_R1(subtract) } +INSTRUCTION( sub_R1_IM ) { mode_R1_IM(subtract) } +INSTRUCTION( sub_IR1_IM ) { mode_IR1_IM(subtract) } + +/*************************************************************************** + LOGICAL INSTRUCTIONS +***************************************************************************/ + +static void and(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- dst AND src */ + UINT8 data = register_read(cpustate, dst) & src; + register_write(cpustate, dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( and_r1_r2 ) { mode_r1_r2(and) } +INSTRUCTION( and_r1_Ir2 ) { mode_r1_Ir2(and) } +INSTRUCTION( and_R2_R1 ) { mode_R2_R1(and) } +INSTRUCTION( and_IR2_R1 ) { mode_IR2_R1(and) } +INSTRUCTION( and_R1_IM ) { mode_R1_IM(and) } +INSTRUCTION( and_IR1_IM ) { mode_IR1_IM(and) } + +static void complement(z8_state *cpustate, UINT8 dst) +{ + /* dst <- NOT dst */ + UINT8 data = register_read(cpustate, dst) ^ 0xff; + register_write(cpustate, dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( com_R1 ) { mode_R1(complement) } +INSTRUCTION( com_IR1 ) { mode_IR1(complement) } + +static void or(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- dst OR src */ + UINT8 data = register_read(cpustate, dst) | src; + register_write(cpustate, dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( or_r1_r2 ) { mode_r1_r2(or) } +INSTRUCTION( or_r1_Ir2 ) { mode_r1_Ir2(or) } +INSTRUCTION( or_R2_R1 ) { mode_R2_R1(or) } +INSTRUCTION( or_IR2_R1 ) { mode_IR2_R1(or) } +INSTRUCTION( or_R1_IM ) { mode_R1_IM(or) } +INSTRUCTION( or_IR1_IM ) { mode_IR1_IM(or) } + +static void xor(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst <- dst XOR src */ + UINT8 data = register_read(cpustate, dst) ^ src; + register_write(cpustate, dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( xor_r1_r2 ) { mode_r1_r2(xor) } +INSTRUCTION( xor_r1_Ir2 ) { mode_r1_Ir2(xor) } +INSTRUCTION( xor_R2_R1 ) { mode_R2_R1(xor) } +INSTRUCTION( xor_IR2_R1 ) { mode_IR2_R1(xor) } +INSTRUCTION( xor_R1_IM ) { mode_R1_IM(xor) } +INSTRUCTION( xor_IR1_IM ) { mode_IR1_IM(xor) } + +/*************************************************************************** + PROGRAM CONTROL INSTRUCTIONS +***************************************************************************/ + +static void call(z8_state *cpustate, UINT16 dst) +{ + stack_push_word(cpustate, cpustate->pc); + cpustate->pc = dst; +} + +INSTRUCTION( call_IRR1 ) { UINT16 dst = register_pair_read(cpustate, get_intermediate_register(cpustate, get_register(cpustate, fetch(cpustate)))); call(cpustate, dst); } +INSTRUCTION( call_DA ) { UINT16 dst = (fetch(cpustate) << 8) | fetch(cpustate); call(cpustate, dst); } + +INSTRUCTION( djnz_r1_RA ) +{ + INT8 ra = (INT8)fetch(cpustate); + + /* r <- r - 1 */ + int r = get_working_register(cpustate, opcode >> 4); + UINT8 data = register_read(cpustate, r) - 1; + register_write(cpustate, r, data); + + /* if r<>0, PC <- PC + dst */ + if (data != 0) + { + cpustate->pc += ra; + *cycles += 2; + } +} + +INSTRUCTION( iret ) +{ + /* FLAGS <- @SP + SP <- SP + 1 */ + register_write(cpustate, Z8_REGISTER_FLAGS, stack_pop_byte(cpustate)); + + /* PC <- @SP + SP <- SP + 2 */ + cpustate->pc = stack_pop_word(cpustate); + + /* IMR (7) <- 1 */ + cpustate->r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; +} + +INSTRUCTION( ret ) +{ + /* PC <- @SP + SP <- SP + 2 */ + cpustate->pc = stack_pop_word(cpustate); +} + +static void jump(z8_state *cpustate, UINT16 dst) +{ + /* PC <- dst */ + cpustate->pc = dst; +} + +INSTRUCTION( jp_IRR1 ) { jump(cpustate, register_pair_read(cpustate, IR)); } + +static int check_condition_code(z8_state *cpustate, int cc) +{ + int truth = 0; + + switch (cc) + { + case CC_F: truth = 0; break; + case CC_LT: truth = flag(S) ^ flag(V); break; + case CC_LE: truth = (flag(Z) | (flag(S) ^ flag(V))); break; + case CC_ULE: truth = flag(C) | flag(Z); break; + case CC_OV: truth = flag(V); break; + case CC_MI: truth = flag(S); break; + case CC_Z: truth = flag(Z); break; + case CC_C: truth = flag(C); break; + case CC_T: truth = 1; break; + case CC_GE: truth = !(flag(S) ^ flag(V)); break; + case CC_GT: truth = !(flag(Z) | (flag(S) ^ flag(V))); break; + case CC_UGT: truth = (!flag(C) & !flag(Z)); break; + case CC_NOV: truth = !flag(V); break; + case CC_PL: truth = !flag(S); break; + case CC_NZ: truth = !flag(Z); break; + case CC_NC: truth = !flag(C); break; + } + + return truth; +} + +INSTRUCTION( jp_cc_DA ) +{ + UINT16 dst = (fetch(cpustate) << 8) | fetch(cpustate); + + /* if cc is true, then PC <- dst */ + if (check_condition_code(cpustate, opcode >> 4)) + { + jump(cpustate, dst); + *cycles += 2; + } +} + +INSTRUCTION( jr_cc_RA ) +{ + INT8 ra = (INT8)fetch(cpustate); + UINT16 dst = cpustate->pc + ra; + + /* if cc is true, then PC <- dst */ + if (check_condition_code(cpustate, opcode >> 4)) + { + jump(cpustate, dst); + *cycles += 2; + } +} + +/*************************************************************************** + BIT MANIPULATION INSTRUCTIONS +***************************************************************************/ + +static void test_complement_under_mask(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* NOT(dst) AND src */ + UINT8 data = (register_read(cpustate, dst) ^ 0xff) & src; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( tcm_r1_r2 ) { mode_r1_r2(test_complement_under_mask) } +INSTRUCTION( tcm_r1_Ir2 ) { mode_r1_Ir2(test_complement_under_mask) } +INSTRUCTION( tcm_R2_R1 ) { mode_R2_R1(test_complement_under_mask) } +INSTRUCTION( tcm_IR2_R1 ) { mode_IR2_R1(test_complement_under_mask) } +INSTRUCTION( tcm_R1_IM ) { mode_R1_IM(test_complement_under_mask) } +INSTRUCTION( tcm_IR1_IM ) { mode_IR1_IM(test_complement_under_mask) } + +static void test_under_mask(z8_state *cpustate, UINT8 dst, UINT8 src) +{ + /* dst AND src */ + UINT8 data = register_read(cpustate, dst) & src; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( tm_r1_r2 ) { mode_r1_r2(test_under_mask) } +INSTRUCTION( tm_r1_Ir2 ) { mode_r1_Ir2(test_under_mask) } +INSTRUCTION( tm_R2_R1 ) { mode_R2_R1(test_under_mask) } +INSTRUCTION( tm_IR2_R1 ) { mode_IR2_R1(test_under_mask) } +INSTRUCTION( tm_R1_IM ) { mode_R1_IM(test_under_mask) } +INSTRUCTION( tm_IR1_IM ) { mode_IR1_IM(test_under_mask) } + +/*************************************************************************** + ROTATE AND SHIFT INSTRUCTIONS +***************************************************************************/ + +static void rotate_left(z8_state *cpustate, UINT8 dst) +{ + /* << */ + UINT8 data = register_read(cpustate, dst); + UINT8 new_data = (data << 1) | BIT(data, 7); + + set_flag_c(data & 0x80); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(cpustate, dst, new_data); +} + +INSTRUCTION( rl_R1 ) { mode_R1(rotate_left) } +INSTRUCTION( rl_IR1 ) { mode_IR1(rotate_left) } + +static void rotate_left_carry(z8_state *cpustate, UINT8 dst) +{ + /* << C */ + UINT8 data = register_read(cpustate, dst); + UINT8 new_data = (data << 1) | flag(C); + + set_flag_c(data & 0x80); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(cpustate, dst, new_data); +} + +INSTRUCTION( rlc_R1 ) { mode_R1(rotate_left_carry) } +INSTRUCTION( rlc_IR1 ) { mode_IR1(rotate_left_carry) } + +static void rotate_right(z8_state *cpustate, UINT8 dst) +{ + /* >> */ + UINT8 data = register_read(cpustate, dst); + UINT8 new_data = ((data & 0x01) << 7) | (data >> 1); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(cpustate, dst, new_data); +} + +INSTRUCTION( rr_R1 ) { mode_R1(rotate_right) } +INSTRUCTION( rr_IR1 ) { mode_IR1(rotate_right) } + +static void rotate_right_carry(z8_state *cpustate, UINT8 dst) +{ + /* >> C */ + UINT8 data = register_read(cpustate, dst); + UINT8 new_data = (flag(C) << 7) | (data >> 1); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(cpustate, dst, new_data); +} + +INSTRUCTION( rrc_R1 ) { mode_R1(rotate_right_carry) } +INSTRUCTION( rrc_IR1 ) { mode_IR1(rotate_right_carry) } + +static void shift_right_arithmetic(z8_state *cpustate, UINT8 dst) +{ + /* */ + UINT8 data = register_read(cpustate, dst); + UINT8 new_data = (data & 0x80) | ((data >> 1) & 0x7f); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(0); + + register_write(cpustate, dst, new_data); +} + +INSTRUCTION( sra_R1 ) { mode_R1(shift_right_arithmetic) } +INSTRUCTION( sra_IR1 ) { mode_IR1(shift_right_arithmetic) } + +static void swap(z8_state *cpustate, UINT8 dst) +{ + /* dst(7-4) <-> dst(3-0) */ + UINT8 data = register_read(cpustate, dst); + data = (data << 4) | (data >> 4); + register_write(cpustate, dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); +// set_flag_v(0); undefined +} + +INSTRUCTION( swap_R1 ) { mode_R1(swap) } +INSTRUCTION( swap_IR1 ) { mode_IR1(swap) } + +/*************************************************************************** + CPU CONTROL INSTRUCTIONS +***************************************************************************/ + +INSTRUCTION( ccf ) { cpustate->r[Z8_REGISTER_FLAGS] ^= Z8_FLAGS_C; } +INSTRUCTION( di ) { cpustate->r[Z8_REGISTER_IMR] &= ~Z8_IMR_ENABLE; } +INSTRUCTION( ei ) { cpustate->r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; } +INSTRUCTION( nop ) { /* no operation */ } +INSTRUCTION( rcf ) { set_flag_c(0); } +INSTRUCTION( scf ) { set_flag_c(1); } +INSTRUCTION( srp_IM ) { cpustate->r[Z8_REGISTER_RP] = fetch(cpustate); } diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 8f33ed021c8..2bcacab3014 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -115,6 +115,7 @@ CPUS += AVR8 CPUS += TMS0980 CPUS += I4004 CPUS += SUPERFX +CPUS += Z8 #------------------------------------------------- diff --git a/src/tools/unidasm.c b/src/tools/unidasm.c index da9a3d8d79a..e24638f5408 100644 --- a/src/tools/unidasm.c +++ b/src/tools/unidasm.c @@ -173,6 +173,7 @@ CPU_DISASSEMBLE( v810 ); CPU_DISASSEMBLE( z180 ); CPU_DISASSEMBLE( z8000 ); CPU_DISASSEMBLE( z80 ); +CPU_DISASSEMBLE( z8 ); static const dasm_table_entry dasm_table[] = @@ -295,6 +296,7 @@ static const dasm_table_entry dasm_table[] = { "z180", _8bit, 0, CPU_DISASSEMBLE_NAME(z180) }, // { "z8000", _16be, 0, CPU_DISASSEMBLE_NAME(z8000) }, { "z80", _8bit, 0, CPU_DISASSEMBLE_NAME(z80) }, + { "z8", _8bit, 0, CPU_DISASSEMBLE_NAME(z8) }, };