diff --git a/src/sim65/6502.c b/src/sim65/6502.c index bfb3f3e9b..1c915e618 100644 --- a/src/sim65/6502.c +++ b/src/sim65/6502.c @@ -35,9 +35,8 @@ /*****************************************************************************/ /* Known bugs and limitations of the 65C02 simulation: - * support currently only on the level of 65SC02: - BBRx, BBSx, RMBx, SMBx, WAI, and STP are unsupported -*/ + * the WAI ($CB) and STP ($DB) instructions are unsupported. + */ #include #include @@ -623,14 +622,14 @@ static unsigned HaveIRQRequest; /* 2 x Read-Modify-Write opcode helpers (illegal opcodes) */ /* Execution cycles for 2 x R-M-W opcodes */ -#define RMW2_CY_ZP 5 -#define RMW2_CY_ZPX 6 +#define RMW2_CY_ZP 5 +#define RMW2_CY_ZPX 6 #define RMW2_CY_ZPY 6 -#define RMW2_CY_ABS 6 -#define RMW2_CY_ABSX 7 -#define RMW2_CY_ABSY 7 -#define RMW2_CY_ZPXIND 8 -#define RMW2_CY_ZPINDY 8 +#define RMW2_CY_ABS 6 +#define RMW2_CY_ABSX 7 +#define RMW2_CY_ABSY 7 +#define RMW2_CY_ZPXIND 8 +#define RMW2_CY_ZPINDY 8 /* zp / zp,x / zp,y / abs / abs,x / abs,y / (zp,x) / (zp),y */ #define ILLx2_OP(mode, op) \ @@ -1112,6 +1111,46 @@ static unsigned HaveIRQRequest; +/* Set/reset a specific bit in a zero-page byte. This macro + * macro is used to implement the 65C02 RMBx and SMBx instructions. + */ +#define ZP_BITOP(bitnr, bitval) \ + do { \ + uint8_t zp_address = MemReadByte (Regs.PC + 1); \ + uint8_t zp_value = MemReadByte (zp_address); \ + if (bitval) { \ + zp_value |= (1 << bitnr); \ + } else { \ + zp_value &= ~(1 << bitnr); \ + } \ + MemWriteByte (zp_address, zp_value); \ + Regs.PC += 2; \ + Cycles = 5; \ + } while (0) + +/* Branch depending on the state of a specific bit of a zero page + * address. This macro is used to implement the 65C02 BBRx and + * BBSx instructions. + */ +#define ZP_BIT_BRANCH(bitnr, bitval) \ + do { \ + uint8_t zp_address = MemReadByte (Regs.PC + 1); \ + uint8_t zp_value = MemReadByte (zp_address); \ + int displacement = (int8_t)MemReadByte (Regs.PC + 2); \ + if (((zp_value & (1 << bitnr)) != 0) == bitval) { \ + Regs.PC += 3; \ + uint8_t OldPCH = PCH; \ + Regs.PC += displacement; \ + Cycles = 6; \ + if (PCH != OldPCH) { \ + Cycles += 1; \ + } \ + } else { \ + Regs.PC += 3; \ + Cycles = 5; \ + } \ + } while (0) + /*****************************************************************************/ /* Opcode handling functions */ /*****************************************************************************/ @@ -1204,6 +1243,14 @@ static void OPC_6502_07 (void) +static void OPC_65C02_07 (void) +/* Opcode $07: RMB0 zp */ +{ + ZP_BITOP(0, 0); +} + + + static void OPC_6502_08 (void) /* Opcode $08: PHP */ { @@ -1283,6 +1330,14 @@ static void OPC_6502_0F (void) +static void OPC_65C02_0F (void) +/* Opcode $0F: BBR0 zp, rel */ +{ + ZP_BIT_BRANCH (0, 0); +} + + + static void OPC_6502_10 (void) /* Opcode $10: BPL */ { @@ -1362,6 +1417,14 @@ static void OPC_6502_17 (void) +static void OPC_65C02_17 (void) +/* Opcode $17: RMB1 zp */ +{ + ZP_BITOP(1, 0); +} + + + static void OPC_6502_18 (void) /* Opcode $18: CLC */ { @@ -1453,6 +1516,15 @@ static void OPC_6502_1F (void) + +static void OPC_65C02_1F (void) +/* Opcode $1F: BBR1 zp, rel */ +{ + ZP_BIT_BRANCH (1, 0); +} + + + static void OPC_6502_20 (void) /* Opcode $20: JSR */ { @@ -1541,6 +1613,14 @@ static void OPC_6502_27 (void) +static void OPC_65C02_27 (void) +/* Opcode $27: RMB2 zp */ +{ + ZP_BITOP(2, 0); +} + + + static void OPC_6502_28 (void) /* Opcode $28: PLP */ { @@ -1604,6 +1684,14 @@ static void OPC_6502_2F (void) +static void OPC_65C02_2F (void) +/* Opcode $2F: BBR2 zp, rel */ +{ + ZP_BIT_BRANCH (2, 0); +} + + + static void OPC_6502_30 (void) /* Opcode $30: BMI */ { @@ -1668,6 +1756,14 @@ static void OPC_6502_37 (void) +static void OPC_65C02_37 (void) +/* Opcode $37: RMB3 zp */ +{ + ZP_BITOP(3, 0); +} + + + static void OPC_6502_38 (void) /* Opcode $38: SEC */ { @@ -1744,6 +1840,14 @@ static void OPC_6502_3F (void) +static void OPC_65C02_3F (void) +/* Opcode $3F: BBR3 zp, rel */ +{ + ZP_BIT_BRANCH (3, 0); +} + + + static void OPC_6502_40 (void) /* Opcode $40: RTI */ { @@ -1797,6 +1901,14 @@ static void OPC_6502_47 (void) +static void OPC_65C02_47 (void) +/* Opcode $47: RMB4 zp */ +{ + ZP_BITOP(4, 0); +} + + + static void OPC_6502_48 (void) /* Opcode $48: PHA */ { @@ -1868,6 +1980,14 @@ static void OPC_6502_4F (void) +static void OPC_65C02_4F (void) +/* Opcode $4F: BBR4 zp, rel */ +{ + ZP_BIT_BRANCH (4, 0); +} + + + static void OPC_6502_50 (void) /* Opcode $50: BVC */ { @@ -1924,6 +2044,14 @@ static void OPC_6502_57 (void) +static void OPC_65C02_57 (void) +/* Opcode $57: RMB5 zp */ +{ + ZP_BITOP(5, 0); +} + + + static void OPC_6502_58 (void) /* Opcode $58: CLI */ { @@ -2001,6 +2129,14 @@ static void OPC_6502_5F (void) +static void OPC_65C02_5F (void) +/* Opcode $5F: BBR5 zp, rel */ +{ + ZP_BIT_BRANCH (5, 0); +} + + + static void OPC_6502_60 (void) /* Opcode $60: RTS */ { @@ -2074,6 +2210,14 @@ static void OPC_6502_67 (void) +static void OPC_65C02_67 (void) +/* Opcode $67: RMB6 zp */ +{ + ZP_BITOP(6, 0); +} + + + static void OPC_6502_68 (void) /* Opcode $68: PLA */ { @@ -2187,6 +2331,14 @@ static void OPC_6502_6F (void) +static void OPC_65C02_6F (void) +/* Opcode $6F: BBR6 zp, rel */ +{ + ZP_BIT_BRANCH (6, 0); +} + + + static void OPC_6502_70 (void) /* Opcode $70: BVS */ { @@ -2265,6 +2417,14 @@ static void OPC_6502_77 (void) +static void OPC_65C02_77 (void) +/* Opcode $77: RMB7 zp */ +{ + ZP_BITOP(7, 0); +} + + + static void OPC_6502_78 (void) /* Opcode $78: SEI */ { @@ -2365,6 +2525,14 @@ static void OPC_6502_7F (void) +static void OPC_65C02_7F (void) +/* Opcode $7F: BBR7 zp, rel */ +{ + ZP_BIT_BRANCH (7, 0); +} + + + /* Aliases of opcode $80 */ #define OPC_6502_82 OPC_6502_80 #define OPC_6502_C2 OPC_6502_80 @@ -2435,6 +2603,14 @@ static void OPC_6502_87 (void) +static void OPC_65C02_87 (void) +/* Opcode $87: SMB0 zp */ +{ + ZP_BITOP(0, 1); +} + + + static void OPC_6502_88 (void) /* Opcode $88: DEY */ { @@ -2507,6 +2683,14 @@ static void OPC_6502_8F (void) +static void OPC_65C02_8F (void) +/* Opcode $8F: BBS0 zp, rel */ +{ + ZP_BIT_BRANCH (0, 1); +} + + + static void OPC_6502_90 (void) /* Opcode $90: BCC */ { @@ -2571,6 +2755,14 @@ static void OPC_6502_97 (void) +static void OPC_65C02_97 (void) +/* Opcode $97: SMB1 zp */ +{ + ZP_BITOP(1, 1); +} + + + static void OPC_6502_98 (void) /* Opcode $98: TYA */ { @@ -2641,6 +2833,14 @@ static void OPC_6502_9E (void) +static void OPC_65SC02_9E (void) +/* Opcode $9E: STZ abs,x */ +{ + STO_OP (ABSX, 0); +} + + + static void OPC_6502_9F (void) /* Opcode $9F: SHA abs,y */ { @@ -2649,10 +2849,10 @@ static void OPC_6502_9F (void) -static void OPC_65SC02_9E (void) -/* Opcode $9E: STZ abs,x */ +static void OPC_65C02_9F (void) +/* Opcode $9F: BBS1 zp, rel */ { - STO_OP (ABSX, 0); + ZP_BIT_BRANCH (1, 1); } @@ -2721,6 +2921,14 @@ static void OPC_6502_A7 (void) +static void OPC_65C02_A7 (void) +/* Opcode $A7: SMB2 zp */ +{ + ZP_BITOP(2, 1); +} + + + static void OPC_6502_A8 (void) /* Opcode $A8: TAY */ { @@ -2793,6 +3001,14 @@ static void OPC_6502_AF (void) +static void OPC_65C02_AF (void) +/* Opcode $AF: BBS2 zp, rel */ +{ + ZP_BIT_BRANCH (2, 1); +} + + + static void OPC_6502_B0 (void) /* Opcode $B0: BCS */ { @@ -2857,6 +3073,14 @@ static void OPC_6502_B7 (void) +static void OPC_65C02_B7 (void) +/* Opcode $B7: SMB3 zp */ +{ + ZP_BITOP(3, 1); +} + + + static void OPC_6502_B8 (void) /* Opcode $B8: CLV */ { @@ -2927,6 +3151,14 @@ static void OPC_6502_BF (void) +static void OPC_65C02_BF (void) +/* Opcode $BF: BBS3 zp, rel */ +{ + ZP_BIT_BRANCH (3, 1); +} + + + static void OPC_6502_C0 (void) /* Opcode $C0: CPY #imm */ { @@ -2983,6 +3215,14 @@ static void OPC_6502_C7 (void) +static void OPC_65C02_C7 (void) +/* Opcode $C7: SMB4 zp */ +{ + ZP_BITOP(4, 1); +} + + + static void OPC_6502_C8 (void) /* Opcode $C8: INY */ { @@ -3051,6 +3291,14 @@ static void OPC_6502_CF (void) +static void OPC_65C02_CF (void) +/* Opcode $CF: BBS4 zp, rel */ +{ + ZP_BIT_BRANCH (4, 1); +} + + + static void OPC_6502_D0 (void) /* Opcode $D0: BNE */ { @@ -3107,6 +3355,14 @@ static void OPC_6502_D7 (void) +static void OPC_65C02_D7 (void) +/* Opcode $D7: SMB5 zp */ +{ + ZP_BITOP(5, 1); +} + + + static void OPC_6502_D8 (void) /* Opcode $D8: CLD */ { @@ -3167,6 +3423,14 @@ static void OPC_6502_DF (void) +static void OPC_65C02_DF (void) +/* Opcode $DF: BBS5 zp, rel */ +{ + ZP_BIT_BRANCH (5, 1); +} + + + static void OPC_6502_E0 (void) /* Opcode $E0: CPX #imm */ { @@ -3237,6 +3501,14 @@ static void OPC_6502_E7 (void) +static void OPC_65C02_E7 (void) +/* Opcode $E7: SMB6 zp */ +{ + ZP_BITOP(6, 1); +} + + + static void OPC_6502_E8 (void) /* Opcode $E8: INX */ { @@ -3357,6 +3629,14 @@ static void OPC_6502_EF (void) +static void OPC_65C02_EF (void) +/* Opcode $EF: BBS6 zp, rel */ +{ + ZP_BIT_BRANCH (6, 1); +} + + + static void OPC_6502_F0 (void) /* Opcode $F0: BEQ */ { @@ -3430,6 +3710,14 @@ static void OPC_6502_F7 (void) +static void OPC_65C02_F7 (void) +/* Opcode $F7: SMB7 zp */ +{ + ZP_BITOP(7, 1); +} + + + static void OPC_6502_F8 (void) /* Opcode $F8: SED */ { @@ -3508,6 +3796,14 @@ static void OPC_6502_FF (void) +static void OPC_65C02_FF (void) +/* Opcode $FF: BBS7 zp, rel */ +{ + ZP_BIT_BRANCH (7, 1); +} + + + /*****************************************************************************/ /* Opcode handler tables */ /*****************************************************************************/ @@ -4047,7 +4343,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_04, OPC_6502_05, OPC_6502_06, - OPC_Illegal, // $07: RMB0 currently unsupported + OPC_65C02_07, OPC_6502_08, OPC_6502_09, OPC_6502_0A, @@ -4055,7 +4351,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_0C, OPC_6502_0D, OPC_6502_0E, - OPC_Illegal, // $0F: BBR0 currently unsupported + OPC_65C02_0F, OPC_6502_10, OPC_6502_11, OPC_65SC02_12, @@ -4063,7 +4359,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_14, OPC_6502_15, OPC_6502_16, - OPC_Illegal, // $17: RMB1 currently unsupported + OPC_65C02_17, OPC_6502_18, OPC_6502_19, OPC_65SC02_1A, @@ -4071,7 +4367,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_1C, OPC_6502_1D, OPC_65C02_1E, - OPC_Illegal, // $1F: BBR1 currently unsupported + OPC_65C02_1F, OPC_6502_20, OPC_6502_21, OPC_65C02_NOP22, // $22 @@ -4079,7 +4375,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_24, OPC_6502_25, OPC_6502_26, - OPC_Illegal, // $27: RMB2 currently unsupported + OPC_65C02_27, OPC_6502_28, OPC_6502_29, OPC_6502_2A, @@ -4087,7 +4383,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_2C, OPC_6502_2D, OPC_6502_2E, - OPC_Illegal, // $2F: BBR2 currently unsupported + OPC_65C02_2F, OPC_6502_30, OPC_6502_31, OPC_65SC02_32, @@ -4095,7 +4391,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_34, OPC_6502_35, OPC_6502_36, - OPC_Illegal, // $37: RMB3 currently unsupported + OPC_65C02_37, OPC_6502_38, OPC_6502_39, OPC_65SC02_3A, @@ -4103,7 +4399,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_3C, OPC_6502_3D, OPC_65C02_3E, - OPC_Illegal, // $3F: BBR3 currently unsupported + OPC_65C02_3F, OPC_6502_40, OPC_6502_41, OPC_65C02_NOP22, // $42 @@ -4111,7 +4407,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_44, // $44 OPC_6502_45, OPC_6502_46, - OPC_Illegal, // $47: RMB4 currently unsupported + OPC_65C02_47, OPC_6502_48, OPC_6502_49, OPC_6502_4A, @@ -4119,7 +4415,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_4C, OPC_6502_4D, OPC_6502_4E, - OPC_Illegal, // $4F: BBR4 currently unsupported + OPC_65C02_4F, OPC_6502_50, OPC_6502_51, OPC_65SC02_52, @@ -4127,7 +4423,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_NOP24, // $54 OPC_6502_55, OPC_6502_56, - OPC_Illegal, // $57: RMB5 currently unsupported + OPC_65C02_57, OPC_6502_58, OPC_6502_59, OPC_65SC02_5A, @@ -4135,7 +4431,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_5C, OPC_6502_5D, OPC_65C02_5E, - OPC_Illegal, // $5F: BBR5 currently unsupported + OPC_65C02_5F, OPC_6502_60, OPC_65C02_61, OPC_65C02_NOP22, // $62 @@ -4143,7 +4439,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_64, OPC_65C02_65, OPC_6502_66, - OPC_Illegal, // $67: RMB6 currently unsupported + OPC_65C02_67, OPC_6502_68, OPC_65C02_69, OPC_6502_6A, @@ -4151,7 +4447,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_6C, OPC_65C02_6D, OPC_6502_6E, - OPC_Illegal, // $6F: BBR6 currently unsupported + OPC_65C02_6F, OPC_6502_70, OPC_65C02_71, OPC_65C02_72, @@ -4159,7 +4455,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_74, OPC_65C02_75, OPC_6502_76, - OPC_Illegal, // $77: RMB7 currently unsupported + OPC_65C02_77, OPC_6502_78, OPC_65C02_79, OPC_65SC02_7A, @@ -4167,7 +4463,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_7C, OPC_65C02_7D, OPC_65C02_7E, - OPC_Illegal, // $7F: BBR7 currently unsupported + OPC_65C02_7F, OPC_65SC02_80, OPC_6502_81, OPC_65C02_NOP22, // $82 @@ -4175,7 +4471,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_84, OPC_6502_85, OPC_6502_86, - OPC_Illegal, // $87: SMB0 currently unsupported + OPC_65C02_87, OPC_6502_88, OPC_65SC02_89, OPC_6502_8A, @@ -4183,7 +4479,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_8C, OPC_6502_8D, OPC_6502_8E, - OPC_Illegal, // $8F: BBS0 currently unsupported + OPC_65C02_8F, OPC_6502_90, OPC_6502_91, OPC_65SC02_92, @@ -4191,7 +4487,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_94, OPC_6502_95, OPC_6502_96, - OPC_Illegal, // $97: SMB1 currently unsupported + OPC_65C02_97, OPC_6502_98, OPC_6502_99, OPC_6502_9A, @@ -4199,7 +4495,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65SC02_9C, OPC_6502_9D, OPC_65SC02_9E, - OPC_Illegal, // $9F: BBS1 currently unsupported + OPC_65C02_9F, OPC_6502_A0, OPC_6502_A1, OPC_6502_A2, @@ -4207,7 +4503,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_A4, OPC_6502_A5, OPC_6502_A6, - OPC_Illegal, // $A7: SMB2 currently unsupported + OPC_65C02_A7, OPC_6502_A8, OPC_6502_A9, OPC_6502_AA, @@ -4215,7 +4511,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_AC, OPC_6502_AD, OPC_6502_AE, - OPC_Illegal, // $AF: BBS2 currently unsupported + OPC_65C02_AF, OPC_6502_B0, OPC_6502_B1, OPC_65SC02_B2, @@ -4223,7 +4519,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_B4, OPC_6502_B5, OPC_6502_B6, - OPC_Illegal, // $B7: SMB3 currently unsupported + OPC_65C02_B7, OPC_6502_B8, OPC_6502_B9, OPC_6502_BA, @@ -4231,7 +4527,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_BC, OPC_6502_BD, OPC_6502_BE, - OPC_Illegal, // $BF: BBS3 currently unsupported + OPC_65C02_BF, OPC_6502_C0, OPC_6502_C1, OPC_65C02_NOP22, // $C2 @@ -4239,7 +4535,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_C4, OPC_6502_C5, OPC_6502_C6, - OPC_Illegal, // $C7: SMB4 currently unsupported + OPC_65C02_C7, OPC_6502_C8, OPC_6502_C9, OPC_6502_CA, @@ -4247,7 +4543,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_CC, OPC_6502_CD, OPC_6502_CE, - OPC_Illegal, // $CF: BBS4 currently unsupported + OPC_65C02_CF, OPC_6502_D0, OPC_6502_D1, OPC_65SC02_D2, @@ -4255,7 +4551,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_NOP24, // $D4 OPC_6502_D5, OPC_6502_D6, - OPC_Illegal, // $D7: SMB5 currently unsupported + OPC_65C02_D7, OPC_6502_D8, OPC_6502_D9, OPC_65SC02_DA, @@ -4263,7 +4559,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_NOP34, // $DC OPC_6502_DD, OPC_6502_DE, - OPC_Illegal, // $DF: BBS5 currently unsupported + OPC_65C02_DF, OPC_6502_E0, OPC_65C02_E1, OPC_65C02_NOP22, // $E2 @@ -4271,7 +4567,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_E4, OPC_65C02_E5, OPC_6502_E6, - OPC_Illegal, // $E7: SMB6 currently unsupported + OPC_65C02_E7, OPC_6502_E8, OPC_65C02_E9, OPC_6502_EA, @@ -4279,7 +4575,7 @@ static const OPFunc OP65C02Table[256] = { OPC_6502_EC, OPC_65C02_ED, OPC_6502_EE, - OPC_Illegal, // $EF: BBS6 currently unsupported + OPC_65C02_EF, OPC_6502_F0, OPC_65C02_F1, OPC_65C02_F2, @@ -4287,7 +4583,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_NOP24, // $F4 OPC_65C02_F5, OPC_6502_F6, - OPC_Illegal, // $F7: SMB7 currently unsupported + OPC_65C02_F7, OPC_6502_F8, OPC_65C02_F9, OPC_65SC02_FA, @@ -4295,7 +4591,7 @@ static const OPFunc OP65C02Table[256] = { OPC_65C02_NOP34, // $FC OPC_65C02_FD, OPC_6502_FE, - OPC_Illegal, // $FF: BBS7 currently unsupported + OPC_65C02_FF };