lr35902.c: Converted LR35902 cpu core to c++. [Wilbert Pol]

This commit is contained in:
Wilbert Pol 2012-02-26 20:36:24 +00:00
parent d27f8cb525
commit 08d355c02a
4 changed files with 1168 additions and 1162 deletions

View File

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

View File

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