Added preliminary Zilog Z8 CPU core for MESS.

This commit is contained in:
Curt Coder 2009-09-04 12:40:47 +00:00
parent f09c9059f9
commit 1c56a127d5
8 changed files with 2136 additions and 0 deletions

4
.gitattributes vendored
View File

@ -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

View File

@ -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
#-------------------------------------------------

948
src/emu/cpu/z8/z8.c Normal file
View File

@ -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;
}
}

41
src/emu/cpu/z8/z8.h Normal file
View File

@ -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

378
src/emu/cpu/z8/z8dasm.c Normal file
View File

@ -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;
}

746
src/emu/cpu/z8/z8ops.c Normal file
View File

@ -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); }

View File

@ -115,6 +115,7 @@ CPUS += AVR8
CPUS += TMS0980
CPUS += I4004
CPUS += SUPERFX
CPUS += Z8
#-------------------------------------------------

View File

@ -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) },
};