summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/g65816/g65816.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/g65816/g65816.cpp')
-rw-r--r--src/devices/cpu/g65816/g65816.cpp175
1 files changed, 115 insertions, 60 deletions
diff --git a/src/devices/cpu/g65816/g65816.cpp b/src/devices/cpu/g65816/g65816.cpp
index 20995f19a8f..cede980dc57 100644
--- a/src/devices/cpu/g65816/g65816.cpp
+++ b/src/devices/cpu/g65816/g65816.cpp
@@ -100,6 +100,8 @@ TODO general:
#include "emu.h"
#include "g65816.h"
+#include "g65816cm.h"
+
DEFINE_DEVICE_TYPE(G65816, g65816_device, "w65c816", "WDC W65C816")
DEFINE_DEVICE_TYPE(G65802, g65802_device, "w65c802", "WDC W65C802")
@@ -258,10 +260,10 @@ unsigned g65816_device::g65816i_read_8_opcode(unsigned address)
unsigned g65816_device::g65816i_read_8_direct(unsigned address)
{
- if (FLAG_E)
+ if (FLAG_E && !MAKE_UINT_8(REGISTER_D))
{
/* force address into zero page */
- address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D);
+ address = REGISTER_D | MAKE_UINT_8(address);
CLOCKS -= (bus_5A22_cycle_burst(address));
}
else
@@ -290,10 +292,10 @@ void g65816_device::g65816i_write_8_normal(unsigned address, unsigned value)
void g65816_device::g65816i_write_8_direct(unsigned address, unsigned value)
{
- if (FLAG_E)
+ if (FLAG_E && !MAKE_UINT_8(REGISTER_D))
{
/* force address into zero page */
- address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D);
+ address = REGISTER_D | MAKE_UINT_8(address);
CLOCKS -= (bus_5A22_cycle_burst(address));
}
else
@@ -307,58 +309,68 @@ void g65816_device::g65816i_write_8_direct(unsigned address, unsigned value)
unsigned g65816_device::g65816i_read_16_normal(unsigned address)
{
return g65816i_read_8_normal(address) |
- (g65816i_read_8_normal(address+1)<<8);
+ (g65816i_read_8_normal(address + 1) << 8);
}
unsigned g65816_device::g65816i_read_16_immediate(unsigned address)
{
return g65816i_read_8_immediate(address) |
- (g65816i_read_8_immediate(address+1)<<8);
+ (g65816i_read_8_immediate(address + 1) << 8);
}
unsigned g65816_device::g65816i_read_16_direct(unsigned address)
{
return g65816i_read_8_direct(address) |
- (g65816i_read_8_direct(address+1)<<8);
+ (g65816i_read_8_direct(address + 1) << 8);
+}
+
+unsigned g65816_device::g65816i_read_16_direct_x(unsigned address)
+{
+ if (FLAG_E && MAKE_UINT_8(REGISTER_D))
+ {
+ // The (direct,X) addressing mode has a bug in which the high byte is
+ // wrapped within the page if E = 1 and D&0xFF != 0.
+ uint8_t lo = g65816i_read_8_direct(address);
+ uint8_t hi = g65816i_read_8_direct((address & 0xffff00) |
+ MAKE_UINT_8(address + 1));
+ return lo | (hi<<8);
+ }
+ else
+ {
+ return g65816i_read_16_direct(address);
+ }
}
unsigned g65816_device::g65816i_read_16_vector(unsigned address)
{
return g65816i_read_8_vector(address) |
- (g65816i_read_8_vector(address+1)<<8);
+ (g65816i_read_8_vector(address + 1) << 8);
}
void g65816_device::g65816i_write_16_normal(unsigned address, unsigned value)
{
- g65816i_write_8_normal(address, value&0xff);
- g65816i_write_8_normal(address+1, value>>8);
+ g65816i_write_8_normal(address, value & 0xff);
+ g65816i_write_8_normal(address + 1, value >> 8);
}
void g65816_device::g65816i_write_16_direct(unsigned address, unsigned value)
{
- g65816i_write_8_direct(address, value&0xff);
- g65816i_write_8_direct(address+1, value>>8);
+ g65816i_write_8_direct(address, value & 0xff);
+ g65816i_write_8_direct(address + 1, value >> 8);
}
unsigned g65816_device::g65816i_read_24_normal(unsigned address)
{
return g65816i_read_8_normal(address) |
- (g65816i_read_8_normal(address+1)<<8) |
- (g65816i_read_8_normal(address+2)<<16);
+ (g65816i_read_8_normal(address + 1) << 8) |
+ (g65816i_read_8_normal(address + 2) << 16);
}
unsigned g65816_device::g65816i_read_24_immediate(unsigned address)
{
return g65816i_read_8_immediate(address) |
- (g65816i_read_8_immediate(address+1)<<8) |
- (g65816i_read_8_immediate(address+2)<<16);
-}
-
-unsigned g65816_device::g65816i_read_24_direct(unsigned address)
-{
- return g65816i_read_8_direct(address) |
- (g65816i_read_8_direct(address+1)<<8) |
- (g65816i_read_8_direct(address+2)<<16);
+ (g65816i_read_8_immediate(address + 1) << 8) |
+ (g65816i_read_8_immediate(address + 2) << 16);
}
@@ -371,11 +383,11 @@ void g65816_device::g65816i_push_8(unsigned value)
g65816i_write_8_normal(REGISTER_S, value);
if (FLAG_E)
{
- REGISTER_S = MAKE_UINT_8(REGISTER_S-1) | 0x100;
+ REGISTER_S = MAKE_UINT_8(REGISTER_S - 1) | 0x100;
}
else
{
- REGISTER_S = MAKE_UINT_16(REGISTER_S-1);
+ REGISTER_S = MAKE_UINT_16(REGISTER_S - 1);
}
}
@@ -383,19 +395,19 @@ unsigned g65816_device::g65816i_pull_8()
{
if (FLAG_E)
{
- REGISTER_S = MAKE_UINT_8(REGISTER_S+1) | 0x100;
+ REGISTER_S = MAKE_UINT_8(REGISTER_S + 1) | 0x100;
}
else
{
- REGISTER_S = MAKE_UINT_16(REGISTER_S+1);
+ REGISTER_S = MAKE_UINT_16(REGISTER_S + 1);
}
return g65816i_read_8_normal(REGISTER_S);
}
void g65816_device::g65816i_push_16(unsigned value)
{
- g65816i_push_8(value>>8);
- g65816i_push_8(value&0xff);
+ g65816i_push_8(value >> 8);
+ g65816i_push_8(value & 0xff);
}
unsigned g65816_device::g65816i_pull_16()
@@ -406,9 +418,9 @@ unsigned g65816_device::g65816i_pull_16()
void g65816_device::g65816i_push_24(unsigned value)
{
- g65816i_push_8(value>>16);
- g65816i_push_8((value>>8)&0xff);
- g65816i_push_8(value&0xff);
+ g65816i_push_8(value >> 16);
+ g65816i_push_8((value >> 8) & 0xff);
+ g65816i_push_8(value & 0xff);
}
unsigned g65816_device::g65816i_pull_24()
@@ -418,6 +430,51 @@ unsigned g65816_device::g65816i_pull_24()
return ((res + 1) & 0xffff) | (g65816i_pull_8() << 16);
}
+void g65816_device::g65816i_push_8_native(unsigned value)
+{
+ g65816i_write_8_normal(REGISTER_S, value);
+ REGISTER_S = MAKE_UINT_16(REGISTER_S - 1);
+}
+
+unsigned g65816_device::g65816i_pull_8_native()
+{
+ REGISTER_S = MAKE_UINT_16(REGISTER_S + 1);
+ return g65816i_read_8_normal(REGISTER_S);
+}
+
+void g65816_device::g65816i_push_16_native(unsigned value)
+{
+ g65816i_push_8_native(value >> 8);
+ g65816i_push_8_native(value & 0xff);
+}
+
+unsigned g65816_device::g65816i_pull_16_native()
+{
+ unsigned res = g65816i_pull_8_native();
+ return res | (g65816i_pull_8_native() << 8);
+}
+
+void g65816_device::g65816i_push_24_native(unsigned value)
+{
+ g65816i_push_8_native(value >> 16);
+ g65816i_push_8_native((value >> 8) & 0xff);
+ g65816i_push_8_native(value & 0xff);
+}
+
+unsigned g65816_device::g65816i_pull_24_native()
+{
+ unsigned res = g65816i_pull_8_native();
+ res |= g65816i_pull_8_native() << 8;
+ return ((res + 1) & 0xffff) | (g65816i_pull_8_native() << 16);
+}
+
+void g65816_device::g65816i_update_reg_s()
+{
+ if (FLAG_E)
+ {
+ REGISTER_S = MAKE_UINT_8(REGISTER_S) | 0x100;
+ }
+}
/* ======================================================================== */
/* ============================ PROGRAM COUNTER =========================== */
@@ -431,7 +488,7 @@ void g65816_device::g65816i_jump_16(unsigned address)
void g65816_device::g65816i_jump_24(unsigned address)
{
- REGISTER_PB = address&0xff0000;
+ REGISTER_PB = address & 0xff0000;
REGISTER_PC = MAKE_UINT_16(address);
g65816i_jumping(REGISTER_PC);
}
@@ -442,7 +499,7 @@ void g65816_device::g65816i_branch_8(unsigned offset)
{
unsigned old_pc = REGISTER_PC;
REGISTER_PC = MAKE_UINT_16(REGISTER_PC + MAKE_INT_8(offset));
- if((REGISTER_PC^old_pc)&0xff00)
+ if ((REGISTER_PC ^ old_pc) & 0xff00)
CLK(1);
}
else
@@ -467,7 +524,7 @@ void g65816_device::g65816i_set_flag_mx(unsigned value)
{
if (FLAG_M)
{
- if(!(value & FLAGPOS_M))
+ if (!(value & FLAGPOS_M))
{
REGISTER_A |= REGISTER_B;
REGISTER_B = 0;
@@ -476,7 +533,7 @@ void g65816_device::g65816i_set_flag_mx(unsigned value)
}
else
{
- if(value & FLAGPOS_M)
+ if (value & FLAGPOS_M)
{
REGISTER_B = REGISTER_A & 0xff00;
REGISTER_A = MAKE_UINT_8(REGISTER_A);
@@ -485,28 +542,28 @@ void g65816_device::g65816i_set_flag_mx(unsigned value)
}
if (FLAG_X)
{
- if(!(value & FLAGPOS_X))
+ if (!(value & FLAGPOS_X))
{
FLAG_X = XFLAG_CLEAR;
}
}
else
{
- if(value & FLAGPOS_X)
+ if (value & FLAGPOS_X)
{
REGISTER_X = MAKE_UINT_8(REGISTER_X);
REGISTER_Y = MAKE_UINT_8(REGISTER_Y);
FLAG_X = XFLAG_SET;
}
}
- g65816i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4));
+ g65816i_set_execution_mode((FLAG_M >> 4) | (FLAG_X >> 4));
}
void g65816_device::g65816i_set_flag_e(unsigned value)
{
if (FLAG_E)
{
- if(!value)
+ if (!value)
{
FLAG_E = EFLAG_CLEAR;
g65816i_set_execution_mode(EXECUTION_MODE_M1X1);
@@ -549,7 +606,7 @@ void g65816_device::g65816i_set_flag_i(unsigned value)
/* Get the Processor Status Register */
unsigned g65816_device::g65816i_get_reg_p()
{
- return (FLAG_N&0x80) |
+ return (FLAG_N & 0x80) |
((FLAG_V>>1)&0x40) |
FLAG_M |
FLAG_X |
@@ -589,6 +646,7 @@ void g65816_device::g65816i_set_reg_p(unsigned value)
void g65816_device::g65816i_interrupt_hardware(unsigned vector)
{
+ standard_irq_callback(0, g65816_get_pc());
if (FLAG_E)
{
CLK(7);
@@ -598,7 +656,6 @@ void g65816_device::g65816i_interrupt_hardware(unsigned vector)
g65816i_set_flag_i(IFLAG_SET);
REGISTER_PB = 0;
g65816i_jump_16(g65816i_read_16_vector(vector));
- standard_irq_callback(0);
}
else
{
@@ -610,7 +667,6 @@ void g65816_device::g65816i_interrupt_hardware(unsigned vector)
g65816i_set_flag_i(IFLAG_SET);
REGISTER_PB = 0;
g65816i_jump_16(g65816i_read_16_vector(vector));
- standard_irq_callback(0);
}
}
@@ -629,7 +685,7 @@ void g65816_device::g65816i_interrupt_software(unsigned vector)
else
{
CLK(8);
- g65816i_push_8(REGISTER_PB>>16);
+ g65816i_push_8(REGISTER_PB >> 16);
g65816i_push_16(REGISTER_PC);
g65816i_push_8(g65816i_get_reg_p());
FLAG_D = DFLAG_CLEAR;
@@ -641,6 +697,7 @@ void g65816_device::g65816i_interrupt_software(unsigned vector)
void g65816_device::g65816i_interrupt_nmi()
{
+ standard_irq_callback(G65816_LINE_NMI, g65816_get_pc());
if (FLAG_E)
{
CLK(7);
@@ -653,7 +710,7 @@ void g65816_device::g65816i_interrupt_nmi()
else
{
CLK(8);
- g65816i_push_8(REGISTER_PB>>16);
+ g65816i_push_8(REGISTER_PB >> 16);
g65816i_push_16(REGISTER_PC);
g65816i_push_8(g65816i_get_reg_p());
FLAG_D = DFLAG_CLEAR;
@@ -684,17 +741,17 @@ unsigned g65816_device::EA_DX() {return MAKE_UINT_16(REGISTER_D + g65816i_rea
unsigned g65816_device::EA_DY() {return MAKE_UINT_16(REGISTER_D + g65816i_read_8_immediate(EA_IMM8()) + REGISTER_Y);}
unsigned g65816_device::EA_AX() {unsigned tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_X;}
unsigned g65816_device::EA_ALX() {return EA_AL() + REGISTER_X;}
-unsigned g65816_device::EA_AY() {unsigned tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;}
+unsigned g65816_device::EA_AY() {unsigned tmp = EA_A(); if((tmp^(tmp+REGISTER_Y))&0xff00) CLK(1); return tmp + REGISTER_Y;}
unsigned g65816_device::EA_DI() {return REGISTER_DB | g65816i_read_16_direct(EA_D());}
-unsigned g65816_device::EA_DLI() {return g65816i_read_24_direct(EA_D());}
+unsigned g65816_device::EA_DLI() {return g65816i_read_24_normal(EA_D());}
unsigned g65816_device::EA_AI() {return g65816i_read_16_normal(g65816i_read_16_immediate(EA_IMM16()));}
unsigned g65816_device::EA_ALI() {return g65816i_read_24_normal(EA_A());}
-unsigned g65816_device::EA_DXI() {return REGISTER_DB | g65816i_read_16_direct(EA_DX());}
-unsigned g65816_device::EA_DIY() {unsigned tmp = REGISTER_DB | g65816i_read_16_direct(EA_D()); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;}
-unsigned g65816_device::EA_DLIY() {return g65816i_read_24_direct(EA_D()) + REGISTER_Y;}
+unsigned g65816_device::EA_DXI() {return REGISTER_DB | g65816i_read_16_direct_x(EA_DX());}
+unsigned g65816_device::EA_DIY() {unsigned tmp = REGISTER_DB | g65816i_read_16_direct(EA_D()); if((tmp^(tmp+REGISTER_Y))&0xff00) CLK(1); return tmp + REGISTER_Y;}
+unsigned g65816_device::EA_DLIY() {return g65816i_read_24_normal(EA_D()) + REGISTER_Y;}
unsigned g65816_device::EA_AXI() {return g65816i_read_16_normal(MAKE_UINT_16(g65816i_read_16_immediate(EA_IMM16()) + REGISTER_X));}
unsigned g65816_device::EA_S() {return MAKE_UINT_16(REGISTER_S + g65816i_read_8_immediate(EA_IMM8()));}
-unsigned g65816_device::EA_SIY() {return MAKE_UINT_16(g65816i_read_16_normal(REGISTER_S + g65816i_read_8_immediate(EA_IMM8())) + REGISTER_Y) | REGISTER_DB;}
+unsigned g65816_device::EA_SIY() {return (g65816i_read_16_normal(REGISTER_S + g65816i_read_8_immediate(EA_IMM8())) | REGISTER_DB) + REGISTER_Y;}
@@ -767,7 +824,7 @@ unsigned g65816_device::g65816_get_pc()
void g65816_device::g65816_set_pc(unsigned val)
{
REGISTER_PC = MAKE_UINT_16(val);
- REGISTER_PB = (val >> 16) & 0xFF;
+ REGISTER_PB = (val >> 16) & 0xff;
g65816_jumping(REGISTER_PB | REGISTER_PC);
}
@@ -787,7 +844,7 @@ void g65816_device::g65816_set_sp(unsigned val)
unsigned g65816_device::g65816_get_reg(int regnum)
{
/* Set the function tables to emulation mode if the FTABLE is nullptr */
- if( FTABLE_GET_REG == nullptr )
+ if (FTABLE_GET_REG == nullptr)
g65816i_set_execution_mode(EXECUTION_MODE_E);
return (this->*FTABLE_GET_REG)(regnum);
@@ -823,7 +880,7 @@ bool g65816_device::get_x_flag() const
void g65816_device::g65816_restore_state()
{
// restore proper function pointers
- g65816i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4));
+ g65816i_set_execution_mode((FLAG_M >> 4) | (FLAG_X >> 4));
// make sure the memory system can keep up
g65816i_jumping(REGISTER_PB | REGISTER_PC);
@@ -875,8 +932,6 @@ void g65816_device::device_start()
(has_space(AS_OPCODES) ? space(AS_OPCODES) : space(AS_PROGRAM)).cache(m_opcode);
(has_space(AS_DATA) ? space(AS_DATA) : space(AS_PROGRAM)).specific(m_data);
- m_wdm_w.resolve_safe();
-
save_item(NAME(m_a));
save_item(NAME(m_b));
save_item(NAME(m_x));
@@ -986,14 +1041,14 @@ void g65816_device::state_export(const device_state_entry &entry)
m_debugger_temp = m_db>>16;
break;
case G65816_P:
- m_debugger_temp = (m_flag_n&0x80) |
- ((m_flag_v>>1)&0x40) |
+ m_debugger_temp = (m_flag_n & 0x80) |
+ ((m_flag_v >> 1)&0x40) |
m_flag_m |
m_flag_x |
m_flag_d |
m_flag_i |
- ((!m_flag_z)<<1) |
- ((m_flag_c>>8)&1);
+ ((!m_flag_z) << 1) |
+ ((m_flag_c >> 8) & 1);
break;
case G65816_A:
m_debugger_temp = m_a | m_b;