mirror of
https://github.com/holub/mame
synced 2025-05-29 00:53:09 +03:00
lr35902.c: Converted LR35902 cpu core to c++. [Wilbert Pol]
This commit is contained in:
parent
d27f8cb525
commit
08d355c02a
@ -41,98 +41,144 @@
|
||||
#include "debugger.h"
|
||||
#include "lr35902.h"
|
||||
|
||||
#define FLAG_Z 0x80
|
||||
#define FLAG_N 0x40
|
||||
#define FLAG_H 0x20
|
||||
#define FLAG_C 0x10
|
||||
|
||||
#define CYCLES_PASSED(X) cpustate->icount -= ((X) / (cpustate->gb_speed)); \
|
||||
if ( cpustate->timer_expired_func ) { \
|
||||
cpustate->timer_expired_func( cpustate->device, X ); \
|
||||
}
|
||||
|
||||
typedef struct _lr35902_state {
|
||||
UINT8 A;
|
||||
UINT8 F;
|
||||
UINT8 B;
|
||||
UINT8 C;
|
||||
UINT8 D;
|
||||
UINT8 E;
|
||||
UINT8 H;
|
||||
UINT8 L;
|
||||
|
||||
UINT16 SP;
|
||||
UINT16 PC;
|
||||
/* Interrupt related */
|
||||
UINT8 IE;
|
||||
UINT8 IF;
|
||||
int irq_state;
|
||||
int ei_delay;
|
||||
device_irq_callback irq_callback;
|
||||
legacy_cpu_device *device;
|
||||
address_space *program;
|
||||
int icount;
|
||||
/* Timer stuff */
|
||||
lr35902_timer_fired_func timer_expired_func;
|
||||
/* Fetch & execute related */
|
||||
int execution_state;
|
||||
UINT8 op;
|
||||
/* Others */
|
||||
int gb_speed;
|
||||
int gb_speed_change_pending;
|
||||
int enable;
|
||||
int doHALTbug;
|
||||
UINT8 features;
|
||||
const lr35902_cpu_core *config;
|
||||
} lr35902_state;
|
||||
|
||||
INLINE lr35902_state *get_safe_token(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == LR35902);
|
||||
return (lr35902_state *)downcast<legacy_cpu_device *>(device)->token();
|
||||
}
|
||||
|
||||
typedef int (*OpcodeEmulator) (lr35902_state *cpustate);
|
||||
|
||||
#define IME 0x01
|
||||
#define HALTED 0x02
|
||||
#define HALTED 0x02
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LR35902 DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
const device_type LR35902 = &device_creator<lr35902_cpu_device>;
|
||||
|
||||
|
||||
lr35902_cpu_device::lr35902_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: cpu_device(mconfig, LR35902, "LR35902", tag, owner, clock),
|
||||
m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0)
|
||||
{
|
||||
c_regs = NULL;
|
||||
c_features = 0;
|
||||
c_timer_expired_func = NULL;
|
||||
}
|
||||
|
||||
|
||||
void lr35902_cpu_device::static_set_config(device_t &device, const lr35902_config &config)
|
||||
{
|
||||
lr35902_cpu_device &conf = downcast<lr35902_cpu_device &>(device);
|
||||
static_cast<lr35902_config &>(conf) = config;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Memory functions */
|
||||
/****************************************************************************/
|
||||
|
||||
#define mem_ReadByte(cs,A) ((UINT8)(cs)->program->read_byte(A)); CYCLES_PASSED(4);
|
||||
#define mem_WriteByte(cs,A,V) ((cs)->program->write_byte(A,V)); CYCLES_PASSED(4);
|
||||
|
||||
INLINE UINT8 mem_ReadOp(lr35902_state *cpustate)
|
||||
inline void lr35902_cpu_device::cycles_passed(UINT8 cycles)
|
||||
{
|
||||
UINT8 r = mem_ReadByte (cpustate, cpustate->PC++);
|
||||
return r;
|
||||
m_icount -= cycles / m_gb_speed;
|
||||
if ( m_timer_expired_func )
|
||||
{
|
||||
m_timer_expired_func( this, cycles );
|
||||
}
|
||||
}
|
||||
|
||||
INLINE UINT16 mem_ReadWord (lr35902_state *cpustate, UINT32 address)
|
||||
|
||||
inline UINT8 lr35902_cpu_device::mem_read_byte( UINT16 addr )
|
||||
{
|
||||
UINT16 value = mem_ReadByte (cpustate, (address + 1) & 0xffff);
|
||||
value <<= 8;
|
||||
value |= mem_ReadByte (cpustate, address);
|
||||
return value;
|
||||
UINT8 data = m_program->read_byte( addr );
|
||||
cycles_passed( 4 );
|
||||
return data;
|
||||
}
|
||||
|
||||
INLINE void mem_WriteWord (lr35902_state *cpustate, UINT32 address, UINT16 value)
|
||||
|
||||
inline void lr35902_cpu_device::mem_write_byte( UINT16 addr, UINT8 data )
|
||||
{
|
||||
mem_WriteByte (cpustate, address, value & 0xFF);
|
||||
mem_WriteByte (cpustate, (address + 1) & 0xffff, value >> 8);
|
||||
m_program->write_byte( addr, data );
|
||||
cycles_passed( 4 );
|
||||
}
|
||||
|
||||
static CPU_INIT( lr35902 )
|
||||
{
|
||||
lr35902_state *cpustate = get_safe_token(device);
|
||||
|
||||
cpustate->config = (const lr35902_cpu_core *) device->static_config();
|
||||
cpustate->irq_callback = irqcallback;
|
||||
cpustate->device = device;
|
||||
cpustate->program = device->space(AS_PROGRAM);
|
||||
inline UINT16 lr35902_cpu_device::mem_read_word( UINT16 addr )
|
||||
{
|
||||
UINT16 data = mem_read_byte( addr );
|
||||
data |= ( mem_read_byte( addr + 1 ) << 8 );
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
inline void lr35902_cpu_device::mem_write_word( UINT16 addr, UINT16 data )
|
||||
{
|
||||
mem_write_byte( addr, data & 0xFF );
|
||||
mem_write_byte( addr + 1, data >> 8 );
|
||||
}
|
||||
|
||||
|
||||
void lr35902_cpu_device::device_start()
|
||||
{
|
||||
m_device = this;
|
||||
m_program = this->space(AS_PROGRAM);
|
||||
|
||||
save_item(NAME(m_A));
|
||||
save_item(NAME(m_F));
|
||||
save_item(NAME(m_B));
|
||||
save_item(NAME(m_C));
|
||||
save_item(NAME(m_D));
|
||||
save_item(NAME(m_E));
|
||||
save_item(NAME(m_H));
|
||||
save_item(NAME(m_L));
|
||||
save_item(NAME(m_PC));
|
||||
save_item(NAME(m_SP));
|
||||
save_item(NAME(m_IE));
|
||||
save_item(NAME(m_IF));
|
||||
save_item(NAME(m_irq_state));
|
||||
save_item(NAME(m_ei_delay));
|
||||
save_item(NAME(m_execution_state));
|
||||
save_item(NAME(m_op));
|
||||
save_item(NAME(m_gb_speed));
|
||||
save_item(NAME(m_gb_speed_change_pending));
|
||||
save_item(NAME(m_enable));
|
||||
save_item(NAME(m_doHALTbug));
|
||||
|
||||
// Register state for debugger
|
||||
state_add( LR35902_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X");
|
||||
state_add( LR35902_SP, "SP", m_SP ).callimport().callexport().formatstr("%04X");
|
||||
state_add( LR35902_A, "A", m_A ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_F, "F", m_F ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_B, "B", m_B ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_C, "C", m_C ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_D, "D", m_D ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_E, "E", m_E ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_H, "H", m_H ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_L, "L", m_L ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_IRQ_STATE, "IRQ", m_enable ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_IE, "IE", m_IE ).callimport().callexport().formatstr("%02X");
|
||||
state_add( LR35902_IF, "IF", m_IF ).callimport().callexport().formatstr("%02X");
|
||||
|
||||
state_add(STATE_GENPC, "curpc", m_PC).callimport().callexport().formatstr("%8s").noshow();
|
||||
state_add(STATE_GENFLAGS, "GENFLAGS", m_F).mask(0xf0).formatstr("%8s").noshow();
|
||||
|
||||
m_icountptr = &m_icount;
|
||||
}
|
||||
|
||||
|
||||
void lr35902_cpu_device::state_string_export(const device_state_entry &entry, astring &string)
|
||||
{
|
||||
switch (entry.index())
|
||||
{
|
||||
case LR35902_SPEED:
|
||||
string.printf("%02X", 0x7E | ( ( m_gb_speed - 1 ) << 7 ) | m_gb_speed_change_pending );
|
||||
break;
|
||||
|
||||
case STATE_GENFLAGS:
|
||||
string.printf("%c%c%c%c",
|
||||
m_F & FLAG_Z ? 'Z' : '.',
|
||||
m_F & FLAG_N ? 'N' : '.',
|
||||
m_F & FLAG_H ? 'H' : '.',
|
||||
m_F & FLAG_C ? 'C' : '.'
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*** Reset lr353902 registers: ******************************/
|
||||
@ -140,64 +186,68 @@ static CPU_INIT( lr35902 )
|
||||
/*** file before starting execution with lr35902_execute(cpustate)***/
|
||||
/*** It sets the registers to their initial values. ***/
|
||||
/************************************************************/
|
||||
static CPU_RESET( lr35902 )
|
||||
void lr35902_cpu_device::device_reset()
|
||||
{
|
||||
lr35902_state *cpustate = get_safe_token(device);
|
||||
|
||||
cpustate->A = 0x00;
|
||||
cpustate->F = 0x00;
|
||||
cpustate->B = 0x00;
|
||||
cpustate->C = 0x00;
|
||||
cpustate->D = 0x00;
|
||||
cpustate->E = 0x00;
|
||||
cpustate->H = 0x00;
|
||||
cpustate->L = 0x00;
|
||||
cpustate->SP = 0x0000;
|
||||
cpustate->PC = 0x0000;
|
||||
cpustate->timer_expired_func = NULL;
|
||||
cpustate->features = LR35902_FEATURE_HALT_BUG;
|
||||
if (cpustate->config)
|
||||
{
|
||||
if ( cpustate->config->regs ) {
|
||||
cpustate->A = cpustate->config->regs[0] >> 8;
|
||||
cpustate->F = cpustate->config->regs[0] & 0xFF;
|
||||
cpustate->B = cpustate->config->regs[1] >> 8;
|
||||
cpustate->C = cpustate->config->regs[1] & 0xFF;
|
||||
cpustate->D = cpustate->config->regs[2] >> 8;
|
||||
cpustate->E = cpustate->config->regs[2] & 0xFF;
|
||||
cpustate->H = cpustate->config->regs[3] >> 8;
|
||||
cpustate->L = cpustate->config->regs[3] & 0xFF;
|
||||
cpustate->SP = cpustate->config->regs[4];
|
||||
cpustate->PC = cpustate->config->regs[5];
|
||||
}
|
||||
cpustate->timer_expired_func = cpustate->config->timer_expired_func;
|
||||
cpustate->features = cpustate->config->features;
|
||||
m_A = 0x00;
|
||||
m_F = 0x00;
|
||||
m_B = 0x00;
|
||||
m_C = 0x00;
|
||||
m_D = 0x00;
|
||||
m_E = 0x00;
|
||||
m_H = 0x00;
|
||||
m_L = 0x00;
|
||||
m_SP = 0x0000;
|
||||
m_PC = 0x0000;
|
||||
m_timer_expired_func = NULL;
|
||||
m_features = LR35902_FEATURE_HALT_BUG;
|
||||
if ( c_regs ) {
|
||||
m_A = c_regs[0] >> 8;
|
||||
m_F = c_regs[0] & 0xFF;
|
||||
m_B = c_regs[1] >> 8;
|
||||
m_C = c_regs[1] & 0xFF;
|
||||
m_D = c_regs[2] >> 8;
|
||||
m_E = c_regs[2] & 0xFF;
|
||||
m_H = c_regs[3] >> 8;
|
||||
m_L = c_regs[3] & 0xFF;
|
||||
m_SP = c_regs[4];
|
||||
m_PC = c_regs[5];
|
||||
}
|
||||
cpustate->enable = 0;
|
||||
cpustate->IE = 0;
|
||||
cpustate->IF = 0;
|
||||
m_timer_expired_func = c_timer_expired_func;
|
||||
m_features = c_features;
|
||||
|
||||
cpustate->execution_state = 0;
|
||||
cpustate->doHALTbug = 0;
|
||||
cpustate->ei_delay = 0;
|
||||
cpustate->gb_speed_change_pending = 0;
|
||||
cpustate->gb_speed = 1;
|
||||
m_enable = 0;
|
||||
m_IE = 0;
|
||||
m_IF = 0;
|
||||
|
||||
m_execution_state = 0;
|
||||
m_doHALTbug = 0;
|
||||
m_ei_delay = 0;
|
||||
m_gb_speed_change_pending = 0;
|
||||
m_gb_speed = 1;
|
||||
}
|
||||
|
||||
INLINE void lr35902_ProcessInterrupts (lr35902_state *cpustate)
|
||||
|
||||
offs_t lr35902_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
|
||||
{
|
||||
UINT8 irq = cpustate->IE & cpustate->IF;
|
||||
extern CPU_DISASSEMBLE( lr35902 );
|
||||
return CPU_DISASSEMBLE_NAME( lr35902 )(NULL, buffer, pc, oprom, opram, 0);
|
||||
}
|
||||
|
||||
|
||||
void lr35902_cpu_device::check_interrupts()
|
||||
{
|
||||
UINT8 irq = m_IE & m_IF;
|
||||
|
||||
/* Interrupts should be taken after the first instruction after an EI instruction */
|
||||
if (cpustate->ei_delay) {
|
||||
cpustate->ei_delay = 0;
|
||||
if (m_ei_delay) {
|
||||
m_ei_delay = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
logerror("Attempting to process LR35902 Interrupt IRQ $%02X\n", irq);
|
||||
logerror("Attempting to process LR35902 Interrupt IE $%02X\n", cpustate->IE);
|
||||
logerror("Attempting to process LR35902 Interrupt IF $%02X\n", cpustate->IF);
|
||||
logerror("Attempting to process LR35902 Interrupt IE $%02X\n", m_IE);
|
||||
logerror("Attempting to process LR35902 Interrupt IF $%02X\n", m_IF);
|
||||
*/
|
||||
if (irq)
|
||||
{
|
||||
@ -210,34 +260,32 @@ INLINE void lr35902_ProcessInterrupts (lr35902_state *cpustate)
|
||||
{
|
||||
if( irq & (1<<irqline) )
|
||||
{
|
||||
if (cpustate->enable & HALTED)
|
||||
if (m_enable & HALTED)
|
||||
{
|
||||
cpustate->enable &= ~HALTED;
|
||||
cpustate->PC++;
|
||||
if ( cpustate->features & LR35902_FEATURE_HALT_BUG ) {
|
||||
if ( ! ( cpustate->enable & IME ) ) {
|
||||
m_enable &= ~HALTED;
|
||||
m_PC++;
|
||||
if ( m_features & LR35902_FEATURE_HALT_BUG ) {
|
||||
if ( ! ( m_enable & IME ) ) {
|
||||
/* Old cpu core (dmg/mgb/sgb) */
|
||||
cpustate->doHALTbug = 1;
|
||||
m_doHALTbug = 1;
|
||||
}
|
||||
} else {
|
||||
/* New cpu core (cgb/agb/ags) */
|
||||
/* Adjust for internal syncing with video core */
|
||||
/* This feature needs more investigation */
|
||||
if ( irqline < 2 ) {
|
||||
CYCLES_PASSED( 4 );
|
||||
cycles_passed( 4 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( cpustate->enable & IME ) {
|
||||
if ( cpustate->irq_callback )
|
||||
(*cpustate->irq_callback)(cpustate->device, irqline);
|
||||
cpustate->enable &= ~IME;
|
||||
cpustate->IF &= ~(1 << irqline);
|
||||
CYCLES_PASSED( 12 );
|
||||
cpustate->SP -= 2;
|
||||
mem_WriteWord (cpustate, cpustate->SP, cpustate->PC);
|
||||
cpustate->PC = 0x40 + irqline * 8;
|
||||
/*logerror("LR35902 Interrupt PC $%04X\n", cpustate->PC );*/
|
||||
if ( m_enable & IME ) {
|
||||
m_enable &= ~IME;
|
||||
m_IF &= ~(1 << irqline);
|
||||
cycles_passed( 12 );
|
||||
m_SP -= 2;
|
||||
mem_write_word( m_SP, m_PC );
|
||||
m_PC = 0x40 + irqline * 8;
|
||||
/*logerror("LR35902 Interrupt PC $%04X\n", m_PC );*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -245,198 +293,63 @@ INLINE void lr35902_ProcessInterrupts (lr35902_state *cpustate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/*** Execute lr35902 code for cycles cycles, return nr of ***/
|
||||
/*** cycles actually executed. ***/
|
||||
/************************************************************/
|
||||
static CPU_EXECUTE( lr35902 )
|
||||
void lr35902_cpu_device::execute_run()
|
||||
{
|
||||
lr35902_state *cpustate = get_safe_token(device);
|
||||
|
||||
do
|
||||
{
|
||||
if ( cpustate->execution_state ) {
|
||||
if ( m_execution_state ) {
|
||||
UINT8 x;
|
||||
/* Execute instruction */
|
||||
switch( cpustate->op ) {
|
||||
switch( m_op ) {
|
||||
#include "opc_main.h"
|
||||
}
|
||||
} else {
|
||||
/* Fetch and count cycles */
|
||||
lr35902_ProcessInterrupts (cpustate);
|
||||
debugger_instruction_hook(device, cpustate->PC);
|
||||
if ( cpustate->enable & HALTED ) {
|
||||
CYCLES_PASSED( 4 );
|
||||
cpustate->execution_state = 1;
|
||||
check_interrupts();
|
||||
debugger_instruction_hook(this, m_PC);
|
||||
if ( m_enable & HALTED ) {
|
||||
cycles_passed( 4 );
|
||||
m_execution_state = 1;
|
||||
} else {
|
||||
cpustate->op = mem_ReadOp (cpustate);
|
||||
if ( cpustate->doHALTbug ) {
|
||||
cpustate->PC--;
|
||||
cpustate->doHALTbug = 0;
|
||||
m_op = mem_read_byte( m_PC++ );
|
||||
if ( m_doHALTbug ) {
|
||||
m_PC--;
|
||||
m_doHALTbug = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
cpustate->execution_state ^= 1;
|
||||
} while (cpustate->icount > 0);
|
||||
m_execution_state ^= 1;
|
||||
} while (m_icount > 0);
|
||||
}
|
||||
|
||||
static CPU_BURN( lr35902 )
|
||||
|
||||
void lr35902_cpu_device::execute_set_input( int inptnum, int state )
|
||||
{
|
||||
lr35902_state *cpustate = get_safe_token(device);
|
||||
|
||||
if( cycles > 0 )
|
||||
{
|
||||
/* NOP takes 4 cycles per instruction */
|
||||
int n = (cycles + 3) / 4;
|
||||
cpustate->icount -= 4 * n;
|
||||
}
|
||||
}
|
||||
|
||||
static void lr35902_set_irq_line (lr35902_state *cpustate, int irqline, int state)
|
||||
{
|
||||
/*logerror("setting irq line 0x%02x state 0x%08x\n", irqline, state);*/
|
||||
//if( cpustate->irq_state == state )
|
||||
// return;
|
||||
|
||||
cpustate->irq_state = state;
|
||||
m_irq_state = state;
|
||||
if( state == ASSERT_LINE )
|
||||
{
|
||||
|
||||
cpustate->IF |= (0x01 << irqline);
|
||||
/*logerror("LR35902 assert irq line %d ($%02X)\n", irqline, cpustate->IF);*/
|
||||
|
||||
m_IF |= (0x01 << inptnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
cpustate->IF &= ~(0x01 << irqline);
|
||||
/*logerror("LR35902 clear irq line %d ($%02X)\n", irqline, cpustate->IF);*/
|
||||
|
||||
m_IF &= ~(0x01 << inptnum);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNUSED_FUNCTION
|
||||
static void lr35902_clear_pending_interrupts (lr35902_state *cpustate)
|
||||
|
||||
UINT8 lr35902_cpu_device::get_speed()
|
||||
{
|
||||
cpustate->IF = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static CPU_SET_INFO( lr35902 )
|
||||
{
|
||||
lr35902_state *cpustate = get_safe_token(device);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
/* --- the following bits of info are set as 64-bit signed integers --- */
|
||||
case CPUINFO_INT_INPUT_STATE + 0:
|
||||
case CPUINFO_INT_INPUT_STATE + 1:
|
||||
case CPUINFO_INT_INPUT_STATE + 2:
|
||||
case CPUINFO_INT_INPUT_STATE + 3:
|
||||
case CPUINFO_INT_INPUT_STATE + 4: lr35902_set_irq_line(cpustate, state-CPUINFO_INT_INPUT_STATE, info->i); break;
|
||||
|
||||
case CPUINFO_INT_SP: cpustate->SP = info->i; break;
|
||||
case CPUINFO_INT_PC: cpustate->PC = info->i; break;
|
||||
|
||||
case CPUINFO_INT_REGISTER + LR35902_PC: cpustate->PC = info->i; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_SP: cpustate->SP = info->i; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_AF: cpustate->A = info->i >> 8; cpustate->F = info->i & 0xFF; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_BC: cpustate->B = info->i >> 8; cpustate->C = info->i & 0xFF; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_DE: cpustate->D = info->i >> 8; cpustate->E = info->i & 0xFF; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_HL: cpustate->H = info->i >> 8; cpustate->L = info->i & 0xFF; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_IE: cpustate->IE = info->i; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_IF: cpustate->IF = info->i; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_SPEED: cpustate->gb_speed_change_pending = info->i & 0x01; break;
|
||||
}
|
||||
return 0x7E | ( ( m_gb_speed - 1 ) << 7 ) | m_gb_speed_change_pending;
|
||||
}
|
||||
|
||||
CPU_GET_INFO( lr35902 )
|
||||
|
||||
void lr35902_cpu_device::set_speed( UINT8 speed_request )
|
||||
{
|
||||
lr35902_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(lr35902_state); break;
|
||||
case CPUINFO_INT_INPUT_LINES: info->i = 5; break;
|
||||
case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0xff; 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 = 1; break;
|
||||
case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 1; break;
|
||||
case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
|
||||
case CPUINFO_INT_MIN_CYCLES: info->i = 1; /* right? */ break;
|
||||
case CPUINFO_INT_MAX_CYCLES: info->i = 16; /* right? */ break;
|
||||
|
||||
case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break;
|
||||
case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16; break;
|
||||
case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break;
|
||||
case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
|
||||
case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
|
||||
case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
|
||||
case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break;
|
||||
case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 16; break;
|
||||
case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
|
||||
|
||||
case CPUINFO_INT_SP: info->i = cpustate->SP; break;
|
||||
case CPUINFO_INT_PC: info->i = cpustate->PC; break;
|
||||
case CPUINFO_INT_PREVIOUSPC: info->i = 0; /* TODO??? */ break;
|
||||
|
||||
case CPUINFO_INT_INPUT_STATE + 0:
|
||||
case CPUINFO_INT_INPUT_STATE + 1:
|
||||
case CPUINFO_INT_INPUT_STATE + 2:
|
||||
case CPUINFO_INT_INPUT_STATE + 3:
|
||||
case CPUINFO_INT_INPUT_STATE + 4: info->i = cpustate->IF & (1 << (state-CPUINFO_INT_INPUT_STATE)); break;
|
||||
|
||||
case CPUINFO_INT_REGISTER + LR35902_PC: info->i = cpustate->PC; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_SP: info->i = cpustate->SP; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_AF: info->i = ( cpustate->A << 8 ) | cpustate->F; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_BC: info->i = ( cpustate->B << 8 ) | cpustate->C; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_DE: info->i = ( cpustate->D << 8 ) | cpustate->E; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_HL: info->i = ( cpustate->H << 8 ) | cpustate->L; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_IE: info->i = cpustate->IE; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_IF: info->i = cpustate->IF; break;
|
||||
case CPUINFO_INT_REGISTER + LR35902_SPEED: info->i = 0x7E | ( ( cpustate->gb_speed - 1 ) << 7 ) | cpustate->gb_speed_change_pending; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(lr35902); break;
|
||||
case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(lr35902); break;
|
||||
case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(lr35902); break;
|
||||
case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(lr35902); break;
|
||||
case CPUINFO_FCT_BURN: info->burn = CPU_BURN_NAME(lr35902); break;
|
||||
case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(lr35902); break;
|
||||
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, "LR35902"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Sharp LR35902"); break;
|
||||
case DEVINFO_STR_VERSION: strcpy(info->s, "1.4"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright The MESS Team."); break;
|
||||
|
||||
case CPUINFO_STR_FLAGS:
|
||||
sprintf(info->s, "%c%c%c%c%c%c%c%c",
|
||||
cpustate->F & 0x80 ? 'Z':'.',
|
||||
cpustate->F & 0x40 ? 'N':'.',
|
||||
cpustate->F & 0x20 ? 'H':'.',
|
||||
cpustate->F & 0x10 ? 'C':'.',
|
||||
cpustate->F & 0x08 ? '3':'.',
|
||||
cpustate->F & 0x04 ? '2':'.',
|
||||
cpustate->F & 0x02 ? '1':'.',
|
||||
cpustate->F & 0x01 ? '0':'.');
|
||||
break;
|
||||
|
||||
case CPUINFO_STR_REGISTER + LR35902_PC: sprintf(info->s, "PC:%04X", cpustate->PC); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_SP: sprintf(info->s, "SP:%04X", cpustate->SP); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_AF: sprintf(info->s, "AF:%02X%02X", cpustate->A, cpustate->F); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_BC: sprintf(info->s, "BC:%02X%02X", cpustate->B, cpustate->C); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_DE: sprintf(info->s, "DE:%02X%02X", cpustate->D, cpustate->E); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_HL: sprintf(info->s, "HL:%02X%02X", cpustate->H, cpustate->L); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_IRQ_STATE: sprintf(info->s, "IRQ:%X", cpustate->enable & IME ); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_IE: sprintf(info->s, "IE:%02X", cpustate->IE); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_IF: sprintf(info->s, "IF:%02X", cpustate->IF); break;
|
||||
case CPUINFO_STR_REGISTER + LR35902_SPEED: sprintf(info->s, "SPD:%02x", 0x7E | ( ( cpustate->gb_speed - 1 ) << 7 ) | cpustate->gb_speed_change_pending ); break;
|
||||
}
|
||||
m_gb_speed_change_pending = speed_request & 0x01;
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_CPU_DEVICE(LR35902, lr35902);
|
||||
|
@ -4,19 +4,24 @@
|
||||
#define __LR35902_H__
|
||||
|
||||
|
||||
typedef void (*lr35902_timer_fired_func)(device_t *device, int cycles);
|
||||
#define MCFG_LR35902_CONFIG(_config) \
|
||||
lr35902_cpu_device::static_set_config(*device, _config);
|
||||
|
||||
typedef struct _lr35902_cpu_core lr35902_cpu_core;
|
||||
struct _lr35902_cpu_core
|
||||
class lr35902_cpu_device;
|
||||
|
||||
// Perhaps replace this with a standard device callback
|
||||
typedef void (*lr35902_timer_fired_func)(lr35902_cpu_device *device, int cycles);
|
||||
|
||||
struct lr35902_config
|
||||
{
|
||||
const UINT16 *regs;
|
||||
UINT8 features;
|
||||
lr35902_timer_fired_func timer_expired_func;
|
||||
const UINT16 *c_regs;
|
||||
UINT8 c_features;
|
||||
lr35902_timer_fired_func c_timer_expired_func;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LR35902_PC=1, LR35902_SP, LR35902_AF, LR35902_BC, LR35902_DE, LR35902_HL,
|
||||
LR35902_PC=1, LR35902_SP, LR35902_A, LR35902_F, LR35902_B, LR35902_C, LR35902_D, LR35902_E, LR35902_H, LR35902_L,
|
||||
LR35902_IRQ_STATE,
|
||||
/* Pseudo registers to keep track of the interrupt statuses */
|
||||
LR35902_IE, LR35902_IF,
|
||||
@ -24,13 +29,100 @@ enum
|
||||
LR35902_SPEED,
|
||||
};
|
||||
|
||||
// This and the features configuration could be removed if we introduce proper subclasses
|
||||
#define LR35902_FEATURE_HALT_BUG 0x01
|
||||
|
||||
/****************************************************************************/
|
||||
/* Return register contents */
|
||||
/****************************************************************************/
|
||||
DECLARE_LEGACY_CPU_DEVICE(LR35902, lr35902);
|
||||
|
||||
extern CPU_DISASSEMBLE( lr35902 );
|
||||
class lr35902_cpu_device : public cpu_device,
|
||||
public lr35902_config
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
lr35902_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock);
|
||||
|
||||
static void static_set_config(device_t &device, const lr35902_config &config);
|
||||
|
||||
UINT8 get_speed();
|
||||
void set_speed( UINT8 speed_request );
|
||||
|
||||
UINT8 get_ie() { return m_IE; }
|
||||
void set_ie( UINT8 data ) { m_IE = data; }
|
||||
|
||||
UINT8 get_if() { return m_IF; }
|
||||
void set_if( UINT8 data ) { m_IF = data; }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// device_execute_interface overrides
|
||||
virtual UINT32 execute_min_cycles() const { return 1; }
|
||||
virtual UINT32 execute_max_cycles() const { return 16; }
|
||||
virtual UINT32 execute_input_lines() const { return 5; }
|
||||
virtual void execute_run();
|
||||
virtual void execute_set_input(int inputnum, int state);
|
||||
|
||||
// device_memory_interface overrides
|
||||
virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; }
|
||||
|
||||
// device_state_interface overrides
|
||||
void state_string_export(const device_state_entry &entry, astring &string);
|
||||
|
||||
// device_disasm_interface overrides
|
||||
virtual UINT32 disasm_min_opcode_bytes() const { return 1; }
|
||||
virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
|
||||
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
||||
|
||||
inline void cycles_passed(UINT8 cycles);
|
||||
inline UINT8 mem_read_byte(UINT16 addr);
|
||||
inline void mem_write_byte(UINT16 addr, UINT8 data);
|
||||
inline UINT16 mem_read_word(UINT16 addr);
|
||||
inline void mem_write_word(UINT16 addr, UINT16 data);
|
||||
inline void check_interrupts();
|
||||
|
||||
protected:
|
||||
address_space_config m_program_config;
|
||||
|
||||
UINT8 m_A;
|
||||
UINT8 m_F;
|
||||
UINT8 m_B;
|
||||
UINT8 m_C;
|
||||
UINT8 m_D;
|
||||
UINT8 m_E;
|
||||
UINT8 m_H;
|
||||
UINT8 m_L;
|
||||
|
||||
UINT16 m_SP;
|
||||
UINT16 m_PC;
|
||||
/* Interrupt related */
|
||||
UINT8 m_IE;
|
||||
UINT8 m_IF;
|
||||
int m_irq_state;
|
||||
int m_ei_delay;
|
||||
lr35902_cpu_device *m_device;
|
||||
address_space *m_program;
|
||||
int m_icount;
|
||||
/* Timer stuff */
|
||||
lr35902_timer_fired_func m_timer_expired_func;
|
||||
/* Fetch & execute related */
|
||||
int m_execution_state;
|
||||
UINT8 m_op;
|
||||
/* Others */
|
||||
int m_gb_speed;
|
||||
int m_gb_speed_change_pending;
|
||||
int m_enable;
|
||||
int m_doHALTbug;
|
||||
UINT8 m_features;
|
||||
const struct lr35902_config *m_config;
|
||||
|
||||
/* Flag bit definitions */
|
||||
static const UINT8 FLAG_Z = 0x80;
|
||||
static const UINT8 FLAG_N = 0x40;
|
||||
static const UINT8 FLAG_H = 0x20;
|
||||
static const UINT8 FLAG_C = 0x10;
|
||||
};
|
||||
|
||||
extern const device_type LR35902;
|
||||
|
||||
#endif /* __LR35902_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user