mirror of
https://github.com/holub/mame
synced 2025-10-06 00:54:22 +03:00

timer_adjust_oneshot(t,...) => t->adjust(...) timer_adjust_periodic(t,...) => t->adjust(...) timer_reset(t,...) => t->reset(...) timer_enable(t,...) => t->enable(...) timer_enabled(t) => t->enabled() timer_get_param(t) => t->param() timer_get_ptr(t) => t->ptr() timer_set_param(t,...) => t->set_param(...) timer_set_ptr(t) => t->set_ptr(...) timer_timeelapsed(t) => t->elapsed() timer_timeleft(t) => t->remaining() timer_starttime(t) => t->start() timer_firetime(t) => t->expire() Also remove some stray legacy cpuexec* macros that were lurking in schedule.h): cpuexec_describe_context(m) => m->describe_context() cpuexec_boost_interleave(m,...) => m->scheduler().boot_interleave(...) cpuexec_trigger(m,...) => m->scheduler().trigger(...) cpuexec_triggertime(m,...) => m->scheduler().trigger(...) Specific regex'es used: timer_adjust_oneshot( *)\(( *)([^,;]+), * \3->adjust\1\(\2 timer_adjust_periodic( *)\(( *)([^,;]+), * \3->adjust\1\(\2 (->adjust.*), *0( *)\) \1\2\) timer_reset( *)\(( *)([^,;]+), * \3->reset\1\(\2 (->reset *\(.*)attotime::never \1 timer_enable( *)\(( *)([^,;]+), * \3->enable\1\(\2 timer_enabled( *)\(( *)([^,;)]+)\) \3->enabled\1\(\2\) timer_get_param( *)\(( *)([^,;)]+)\) \3->param\1\(\2\) timer_get_ptr( *)\(( *)([^,;)]+)\) \3->ptr\1\(\2\) timer_timeelapsed( *)\(( *)([^,;)]+)\) \3->elapsed\1\(\2\) timer_timeleft( *)\(( *)([^,;)]+)\) \3->remaining\1\(\2\) timer_starttime( *)\(( *)([^,;)]+)\) \3->start\1\(\2\) timer_firetime( *)\(( *)([^,;)]+)\) \3->expire\1\(\2\) timer_set_param( *)\(( *)([^,;]+), * \3->set_param\1\(\2 timer_set_ptr( *)\(( *)([^,;]+), * \3->set_ptr\1\(\2 cpuexec_describe_context( *)\(( *)([^,;)]+)\) \3->describe_context\1\(\2\) \&m_machine->describe_context m_machine.describe_context cpuexec_boost_interleave( *)\(( *)([^,;]+), * \3->scheduler().boost_interleave\1\(\2 cpuexec_trigger( *)\(( *)([^,;]+), * \3->scheduler().trigger\1\(\2 cpuexec_triggertime( *)\(( *)([^,;]+), * \3->scheduler().trigger\1\(\2
924 lines
32 KiB
C
924 lines
32 KiB
C
/**********************************************************************
|
|
|
|
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 "emu.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
|
|
{
|
|
address_space *program;
|
|
direct_read_data *direct;
|
|
address_space *data;
|
|
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 */
|
|
|
|
/* timers */
|
|
emu_timer *t0_timer;
|
|
emu_timer *t1_timer;
|
|
};
|
|
|
|
/***************************************************************************
|
|
INLINE FUNCTIONS
|
|
***************************************************************************/
|
|
|
|
INLINE z8_state *get_safe_token(device_t *device)
|
|
{
|
|
assert(device != NULL);
|
|
assert((device->type() == Z8601) ||
|
|
(device->type() == UB8830D) ||
|
|
(device->type() == Z8611));
|
|
return (z8_state *)downcast<legacy_cpu_device *>(device)->token();
|
|
}
|
|
|
|
INLINE UINT8 fetch(z8_state *cpustate)
|
|
{
|
|
UINT8 data = cpustate->direct->read_decrypted_byte(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] = cpustate->io->read_byte(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] = cpustate->io->read_byte(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] = cpustate->io->read_byte(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] = cpustate->io->read_byte(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) cpustate->io->write_byte(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) cpustate->io->write_byte(offset, data & mask);
|
|
break;
|
|
|
|
case Z8_REGISTER_P2:
|
|
cpustate->output[offset] = data;
|
|
mask = cpustate->r[Z8_REGISTER_P2M] ^ 0xff;
|
|
if (mask) cpustate->io->write_byte(offset, data & mask);
|
|
break;
|
|
|
|
case Z8_REGISTER_P3:
|
|
cpustate->output[offset] = data;
|
|
|
|
// TODO: special port 3 modes
|
|
if (!(P3M & 0x7c))
|
|
{
|
|
mask = 0xf0;
|
|
}
|
|
|
|
if (mask) cpustate->io->write_byte(offset, data & mask);
|
|
break;
|
|
|
|
case Z8_REGISTER_SIO:
|
|
break;
|
|
|
|
case Z8_REGISTER_TMR:
|
|
if (data & Z8_TMR_LOAD_T0)
|
|
{
|
|
cpustate->t0 = T0;
|
|
cpustate->t0_timer->adjust(attotime::zero, 0, attotime::from_hz(cpustate->clock / 2 / 4 / ((PRE0 >> 2) + 1)));
|
|
}
|
|
|
|
cpustate->t0_timer->enable(data & Z8_TMR_ENABLE_T0);
|
|
|
|
if (data & Z8_TMR_LOAD_T1)
|
|
{
|
|
cpustate->t1 = T1;
|
|
cpustate->t1_timer->adjust(attotime::zero, 0, attotime::from_hz(cpustate->clock / 2 / 4 / ((PRE1 >> 2) + 1)));
|
|
}
|
|
|
|
cpustate->t1_timer->enable(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 */
|
|
cpustate->data->write_byte(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 */
|
|
cpustate->data->write_word(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 cpustate->data->read_byte(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 cpustate->data->read_word(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;
|
|
cpustate->t0_timer->adjust(attotime::zero, 0, attotime::from_hz(cpustate->clock / 2 / 4 / ((PRE0 >> 2) + 1)));
|
|
cpustate->t0_timer->enable(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;
|
|
cpustate->t1_timer->adjust(attotime::zero, 0, attotime::from_hz(cpustate->clock / 2 / 4 / ((PRE1 >> 2) + 1)));
|
|
cpustate->t1_timer->enable(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 */
|
|
{
|
|
device_state_interface *state;
|
|
device->interface(state);
|
|
state->state_add(Z8_PC, "PC", cpustate->pc);
|
|
state->state_add(STATE_GENPC, "GENPC", cpustate->pc).noshow();
|
|
state->state_add(Z8_SP, "SP", cpustate->fake_sp).callimport().callexport();
|
|
state->state_add(STATE_GENSP, "GENSP", cpustate->fake_sp).callimport().callexport().noshow();
|
|
state->state_add(Z8_RP, "RP", cpustate->r[Z8_REGISTER_RP]);
|
|
state->state_add(Z8_T0, "T0", cpustate->t0);
|
|
state->state_add(Z8_T1, "T1", cpustate->t1);
|
|
state->state_add(STATE_GENFLAGS, "GENFLAGS", cpustate->r[Z8_REGISTER_FLAGS]).noshow().formatstr("%6s");
|
|
|
|
astring tempstr;
|
|
for (int regnum = 0; regnum < 16; regnum++)
|
|
state->state_add(Z8_R0 + regnum, tempstr.format("R%d", regnum), cpustate->fake_r[regnum]).callimport().callexport();
|
|
}
|
|
|
|
cpustate->clock = device->clock();
|
|
|
|
/* find address spaces */
|
|
cpustate->program = device->space(AS_PROGRAM);
|
|
cpustate->direct = &cpustate->program->direct();
|
|
cpustate->data = device->space(AS_DATA);
|
|
cpustate->io = device->space(AS_IO);
|
|
|
|
/* allocate timers */
|
|
cpustate->t0_timer = device->machine->scheduler().timer_alloc(FUNC(t0_tick), cpustate);
|
|
cpustate->t1_timer = device->machine->scheduler().timer_alloc(FUNC(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);
|
|
|
|
do
|
|
{
|
|
UINT8 opcode;
|
|
int cycles;
|
|
|
|
debugger_instruction_hook(device, cpustate->pc);
|
|
|
|
/* TODO: sample interrupts */
|
|
cpustate->input[3] = cpustate->io->read_byte(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);
|
|
}
|
|
|
|
/***************************************************************************
|
|
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;
|
|
}
|
|
}
|
|
|
|
static CPU_EXPORT_STRING( z8 )
|
|
{
|
|
z8_state *cpustate = get_safe_token(device);
|
|
|
|
switch (entry.index())
|
|
{
|
|
case STATE_GENFLAGS: string.printf("%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;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
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 DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
|
|
case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break;
|
|
case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
|
|
case DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 8; break;
|
|
case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 16; break;
|
|
case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 8; break;
|
|
case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 2; break;
|
|
case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_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;
|
|
case CPUINFO_FCT_EXPORT_STRING: info->export_string = CPU_EXPORT_STRING_NAME(z8); break;
|
|
|
|
/* --- the following bits of info are returned as pointers --- */
|
|
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; 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;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
CPU-SPECIFIC CONTEXT ACCESS
|
|
***************************************************************************/
|
|
|
|
CPU_GET_INFO( z8601 )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as pointers --- */
|
|
case DEVINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_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 DEVINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_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 DEVINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_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;
|
|
}
|
|
}
|
|
|
|
DEFINE_LEGACY_CPU_DEVICE(Z8601, z8601);
|
|
DEFINE_LEGACY_CPU_DEVICE(UB8830D, ub8830d);
|
|
DEFINE_LEGACY_CPU_DEVICE(Z8611, z8611);
|