From d0728c8ade148a811ba042323294e1b476e1798a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Tue, 10 Apr 2018 13:56:37 +0200 Subject: [PATCH 01/14] Emulate invalid instructions. Treat them as NOPs of different length just as real 65C02. --- src/65c02isa.csv | 88 ++++++++++++++++++++++++------------------------ src/emulation.c | 12 +++++++ src/rk65c02.c | 19 +++-------- 3 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/65c02isa.csv b/src/65c02isa.csv index 3f8643e..b81a750 100644 --- a/src/65c02isa.csv +++ b/src/65c02isa.csv @@ -1,8 +1,8 @@ opcode_id,mnemonic,addressing,size,emulation,modify_pc OP_BRK,"brk",IMPLIED,2,emul_brk,true OP_ORA_IZPX,"ora",IZPX,2,emul_ora,false -OP_NOPI_3,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_4,"invalid",IMPLIED,1,NULL,false +OP_NOPI_3,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_4,"invalid",IMPLIED,1,emul_invalid,false OP_TSB_ZP,"tsb",ZP,2,emul_tsb,false OP_ORA_ZP,"ora",ZP,2,emul_ora,false OP_ASL_ZP,"asl",ZP,2,emul_asl,false @@ -10,7 +10,7 @@ OP_RMB0_ZP,"rmb0",ZP,2,emul_rmb0,false OP_PHP,"php",IMPLIED,1,emul_php,false OP_ORA_IMM,"ora",IMMEDIATE,2,emul_ora,false OP_ASL,"asl",ACCUMULATOR,1,emul_asl,false -OP_NOPI_C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_C,"invalid",IMPLIED,1,emul_invalid,false OP_TSB_ABS,"tsb",ABSOLUTE,3,emul_tsb,false OP_ORA_ABS,"ora",ABSOLUTE,3,emul_ora,false OP_ASL_ABS,"asl",ABSOLUTE,3,emul_asl,false @@ -18,7 +18,7 @@ OP_BBR0_REL,"bbr0",ZPR,2,emul_bbr0,true OP_BPL_REL,"bpl",RELATIVE,2,emul_bpl,true OP_ORA_IZPY,"ora",IZPY,2,emul_ora,false OP_ORA_IZP,"ora",IZP,2,emul_ora,false -OP_NOPI_14,"invalid",IMPLIED,1,NULL,false +OP_NOPI_14,"invalid",IMPLIED,1,emul_invalid,false OP_TRB_ZP,"trb",ZP,2,emul_trb,false OP_ORA_ZPX,"ora",ZPX,2,emul_ora,false OP_ASL_ZPX,"asl",ZPX,2,emul_asl,false @@ -26,15 +26,15 @@ OP_RMB1_ZP,"rmb1",ZP,2,emul_rmb1,false OP_CLC,"clc",IMPLIED,1,emul_clc,false OP_ORA_ABSY,"ora",ABSOLUTEY,3,emul_ora,false OP_INC,"inc",ACCUMULATOR,1,emul_inc,false -OP_NOPI_1C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_1C,"invalid",IMPLIED,1,emul_invalid,false OP_TRB_ABS,"trb",ABSOLUTE,3,emul_trb,false OP_ORA_ABSX,"ora",ABSOLUTEX,3,emul_ora,false OP_ASL_ABSX,"asl",ABSOLUTEX,3,emul_asl,false OP_BBR1_REL,"bbr1",ZPR,2,emul_bbr1,true OP_JSR,"jsr",ABSOLUTE,3,emul_jsr,true OP_AND_IZPX,"and",IZPX,2,emul_and,false -OP_NOPI_23,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_24,"invalid",IMPLIED,1,NULL,false +OP_NOPI_23,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_24,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ZP,"bit",ZP,2,emul_bit,false OP_AND_ZP,"and",ZP,2,emul_and,false OP_ROL_ZP,"rol",ZP,2,emul_rol,false @@ -42,7 +42,7 @@ OP_RMB2_ZP,"rmb2",ZP,2,emul_rmb2,false OP_PLP,"plp",IMPLIED,1,emul_plp,false OP_AND_IMM,"and",IMMEDIATE,2,emul_and,false OP_ROL,"rol",ACCUMULATOR,1,emul_rol,false -OP_NOPI_2C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_2C,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ABS,"bit",ABSOLUTE,3,emul_bit,false OP_AND_ABS,"and",ABSOLUTE,3,emul_and,false OP_ROL_ABS,"rol",ABSOLUTE,3,emul_rol,false @@ -50,7 +50,7 @@ OP_BBR2_REL,"bbr2",ZPR,2,emul_bbr2,true OP_BMI_REL,"bmi",RELATIVE,2,emul_bmi,true OP_AND_IZPY,"and",IZPY,2,emul_and,false OP_AND_IZP,"and",IZP,2,emul_and,false -OP_NOPI_34,"invalid",IMPLIED,1,NULL,false +OP_NOPI_34,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ZPX,"bit",ZPX,2,emul_bit,false OP_AND_ZPX,"and",ZPX,2,emul_and,false OP_ROL_ZPX,"rol",ZPX,2,emul_rol,false @@ -58,23 +58,23 @@ OP_RMB3_ZP,"rmb3",ZP,2,emul_rmb3,false OP_SEC,"sec",IMPLIED,1,emul_sec,false OP_AND_ABSY,"and",ABSOLUTEY,3,emul_and,false OP_DEC,"dec",ACCUMULATOR,1,emul_dec,false -OP_NOPI_3C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_3C,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ABSX,"bit",ABSOLUTEX,3,emul_bit,false OP_AND_ABSX,"and",ABSOLUTEX,3,emul_and,false OP_ROL_ABSX,"rol",ABSOLUTEX,3,emul_rol,false OP_BBR3_REL,"bbr3",ZPR,2,emul_bbr3,true OP_RTI,"rti",IMPLIED,1,emul_rti,true OP_EOR_IZPX,"eor",IZPX,2,emul_eor,false -OP_NOPI_43,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_44,"invalid",IMPLIED,1,NULL,false -OP_NOPI_45,"invalid",ZP,2,NULL,false +OP_NOPI_43,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_44,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_45,"invalid",ZP,2,emul_invalid,false OP_EOR_ZP,"eor",ZP,2,emul_eor,false OP_LSR_ZP,"lsr",ZP,2,emul_lsr,false OP_RMB4_ZP,"rmb4",ZP,2,emul_rmb4,false OP_PHA,"pha",IMPLIED,1,emul_pha,false OP_EOR_IMM,"eor",IMMEDIATE,2,emul_eor,false OP_LSR,"lsr",ACCUMULATOR,1,emul_lsr,false -OP_NOPI_4C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_4C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_ABS,"jmp",ABSOLUTE,3,emul_jmp,true OP_EOR_ABS,"eor",ABSOLUTE,3,emul_eor,false OP_LSR_ABS,"lsr",ABSOLUTE,3,emul_lsr,false @@ -82,23 +82,23 @@ OP_BBR4_REL,"bbr4",ZPR,2,emul_bbr4,true OP_BVC_REL,"bvc",RELATIVE,2,emul_bvc,true OP_EOR_IZPY,"eor",IZPY,2,emul_eor,false OP_EOR_IZP,"eor",IZP,2,emul_eor,false -OP_NOPI_54,"invalid",IMPLIED,1,NULL,false -OP_NOPI_55,"invalid",ZPX,2,NULL,false +OP_NOPI_54,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_55,"invalid",ZPX,2,emul_invalid,false OP_EOR_ZPX,"eor",ZPX,2,emul_eor,false OP_LSR_ZPX,"lsr",ZPX,2,emul_lsr,false OP_RMB5_ZP,"rmb5",ZP,2,emul_rmb5,false OP_CLI,"cli",IMPLIED,1,emul_cli,false OP_EOR_ABSY,"eor",ABSOLUTEY,3,emul_eor,false OP_PHY,"phy",IMPLIED,1,emul_phy,false -OP_NOPI_5C,"invalid",IMPLIED,1,NULL,false -OP_NOPI_5D,"invalid",ABSOLUTE,3,NULL,false +OP_NOPI_5C,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_5D,"invalid",ABSOLUTE,3,emul_invalid,false OP_EOR_ABSX,"eor",ABSOLUTEX,3,emul_eor,false OP_LSR_ABSX,"lsr",ABSOLUTEX,3,emul_lsr,false OP_BBR5_REL,"bbr5",ZPR,2,emul_bbr5,true OP_RTS,"rts",IMPLIED,1,emul_rts,false OP_ADC_IZPX,"adc",IZPX,2,emul_adc,false -OP_NOPI_63,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_64,"invalid",IMPLIED,1,NULL,false +OP_NOPI_63,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_64,"invalid",IMPLIED,1,emul_invalid,false OP_STZ_ZP,"stz",ZP,2,emul_stz,false OP_ADC_ZP,"adc",ZP,2,emul_adc,false OP_ROR_ZP,"ror",ZP,2,emul_ror,false @@ -106,7 +106,7 @@ OP_RMB6_ZP,"rmb6",ZP,2,emul_rmb6,false OP_PLA,"pla",IMPLIED,1,emul_pla,false OP_ADC_IMM,"adc",IMMEDIATE,2,emul_adc,false OP_ROR,"ror",ACCUMULATOR,1,emul_ror,false -OP_NOPI_6C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_6C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_IABS,"jmp",IABSOLUTE,3,emul_jmp,true OP_ADC_ABS,"adc",ABSOLUTE,3,emul_adc,false OP_ROR_ABS,"ror",ABSOLUTE,3,emul_ror,false @@ -114,7 +114,7 @@ OP_BBR6_REL,"bbr6",ZPR,2,emul_bbr6,true OP_BVS_REL,"bvs",RELATIVE,2,emul_bvs,true OP_ADC_IZPY,"adc",IZPY,2,emul_adc,false OP_ADC_IZP,"adc",IZP,2,emul_adc,false -OP_NOPI_74,"invalid",IMPLIED,1,NULL,false +OP_NOPI_74,"invalid",IMPLIED,1,emul_invalid,false OP_STZ_ZPX,"stz",ZPX,2,emul_stz,false OP_ADC_ZPX,"adc",ZPX,2,emul_adc,false OP_ROR_ZPX,"ror",ZPX,2,emul_ror,false @@ -122,15 +122,15 @@ OP_RMB7_ZP,"rmb7",ZP,2,emul_rmb7,false OP_SEI,"sei",IMPLIED,1,emul_sei,false OP_ADC_ABSY,"adc",ABSOLUTEY,3,emul_adc,false OP_PLY,"ply",IMPLIED,1,emul_ply,false -OP_NOPI_7C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_7C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_IABSX,"jmp",IABSOLUTEX,3,emul_jmp,true OP_ADC_ABSX,"adc",ABSOLUTEX,3,emul_adc,false OP_ROR_ABSX,"ror",ABSOLUTEX,3,emul_ror,false OP_BBR7_REL,"bbr7",ZPR,2,emul_bbr7,true OP_BRA_REL,"bra",RELATIVE,2,emul_bra,true OP_STA_IZPX,"sta",IZPX,2,emul_sta,false -OP_NOPI_83,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_84,"invalid",IMPLIED,1,NULL,false +OP_NOPI_83,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_84,"invalid",IMPLIED,1,emul_invalid,false OP_STY_ZP,"sty",ZP,2,emul_sty,false OP_STA_ZP,"sta",ZP,2,emul_sta,false OP_STX_ZP,"stx",ZP,2,emul_stx,false @@ -138,7 +138,7 @@ OP_SMB0_ZP,"smb0",ZP,2,emul_smb0,false OP_DEY,"dey",IMPLIED,1,emul_dey,false OP_BIT_IMM,"bit",IMMEDIATE,2,emul_bit,false OP_TXA,"txa",IMPLIED,1,emul_txa,false -OP_NOPI_8C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_8C,"invalid",IMPLIED,1,emul_invalid,false OP_STY_ABS,"sty",ABSOLUTE,3,emul_sty,false OP_STA_ABS,"sta",ABSOLUTE,3,emul_sta,false OP_STX_ABS,"stx",ABSOLUTE,3,emul_stx,false @@ -146,7 +146,7 @@ OP_BBS0_REL,"bbs0",ZPR,2,emul_bbs0,true OP_BCC_REL,"bcc",RELATIVE,2,emul_bcc,true OP_STA_IZPY,"sta",IZPY,2,emul_sta,false OP_STA_IZP,"sta",IZP,2,emul_sta,false -OP_NOPI_94,"invalid",IMPLIED,1,NULL,false +OP_NOPI_94,"invalid",IMPLIED,1,emul_invalid,false OP_STY_ZPX,"sty",ZPX,2,emul_sty,false OP_STA_ZPX,"sta",ZPX,2,emul_sta,false OP_STX_ZPY,"stx",ZPY,2,emul_stx,false @@ -154,7 +154,7 @@ OP_SMB1_ZP,"smb1",ZP,2,emul_smb1,false OP_TYA,"tya",IMPLIED,1,emul_tya,false OP_STA_ABSY,"sta",ABSOLUTEY,3,emul_sta,false OP_TXS,"txs",IMPLIED,1,emul_txs,false -OP_NOPI_9C,"invalid",IMPLIED,1,NULL,false +OP_NOPI_9C,"invalid",IMPLIED,1,emul_invalid,false OP_STZ_ABS,"stz",ABSOLUTE,3,emul_stz,false OP_STA_ABSX,"sta",ABSOLUTEX,3,emul_sta,false OP_STZ_ABSX,"stz",ABSOLUTEX,3,emul_stz,false @@ -162,7 +162,7 @@ OP_BBS1_REL,"bbs1",ZPR,2,emul_bbs1,true OP_LDY_IMM,"ldy",IMMEDIATE,2,emul_ldy,false OP_LDA_IZPX,"lda",IZPX,2,emul_lda,false OP_LDX_IMM,"ldx",IMMEDIATE,2,emul_ldx,false -OP_NOPI_A4,"invalid",IMPLIED,1,NULL,false +OP_NOPI_A4,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ZP,"ldy",ZP,2,emul_ldy,false OP_LDA_ZP,"lda",ZP,2,emul_lda,false OP_LDX_ZP,"ldx",ZP,2,emul_ldx,false @@ -170,7 +170,7 @@ OP_SMB2_ZP,"smb2",ZP,2,emul_smb2,false OP_TAY,"tay",IMPLIED,1,emul_tay,false OP_LDA_IMM,"lda",IMMEDIATE,2,emul_lda,false OP_TAX,"tax",IMPLIED,1,emul_tax,false -OP_NOPI_AC,"invalid",IMPLIED,1,NULL,false +OP_NOPI_AC,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ABS,"ldy",ABSOLUTE,3,emul_ldy,false OP_LDA_ABS,"lda",ABSOLUTE,3,emul_lda,false OP_LDX_ABS,"ldx",ABSOLUTE,3,emul_ldx,false @@ -178,7 +178,7 @@ OP_BBS2_REL,"bbs2",ZPR,2,emul_bbs2,true OP_BCS_REL,"bcs",RELATIVE,2,emul_bcs,true OP_LDA_IZPY,"lda",IZPY,2,emul_lda,false OP_LDA_IZP,"lda",IZP,2,emul_lda,false -OP_NOPI_B4,"invalid",IMPLIED,1,NULL,false +OP_NOPI_B4,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ZPX,"ldy",ZPX,2,emul_ldy,false OP_LDA_ZPX,"lda",ZPX,2,emul_lda,false OP_LDX_ZPY,"ldx",ZPY,1,emul_ldx,false @@ -186,15 +186,15 @@ OP_SMB3_ZP,"smb3",ZP,2,emul_smb3,false OP_CLV,"clv",IMPLIED,1,emul_clv,false OP_LDA_ABSY,"lda",ABSOLUTEY,3,emul_lda,false OP_TSX,"tsx",IMPLIED,1,emul_tsx,false -OP_NOPI_BC,"invalid",IMPLIED,1,NULL,false +OP_NOPI_BC,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ABSX,"ldy",ABSOLUTEX,3,emul_ldy,false OP_LDA_ABSX,"lda",ABSOLUTEX,3,emul_lda,false OP_LDX_ABSY,"ldx",ABSOLUTEY,3,emul_ldx,false OP_BBS3_REL,"bbs3",ZPR,2,emul_bbs3,true OP_CPY_IMM,"cpy",IMMEDIATE,2,emul_cpy,false OP_CMP_IZPX,"cmp",IZPX,2,emul_cmp,false -OP_NOPI_C3,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_C4,"invalid",IMPLIED,1,NULL,false +OP_NOPI_C3,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_C4,"invalid",IMPLIED,1,emul_invalid,false OP_CPY_ZP,"cpy",ZP,2,emul_cpy,false OP_CMP_ZP,"cmp",ZP,2,emul_cmp,false OP_DEC_ZP,"dec",ZP,2,emul_dec,false @@ -210,8 +210,8 @@ OP_BBS4_REL,"bbs4",ZPR,2,emul_bbs4,true OP_BNE_REL,"bne",RELATIVE,2,emul_bne,true OP_CMP_IZPY,"cmp",IZPY,2,emul_cmp,false OP_CMP_IZP,"cmp",IZP,2,emul_cmp,false -OP_NOPI_D4,"invalid",IMPLIED,1,NULL,false -OP_NOPI_D5,"invalid",ZPX,2,NULL,false +OP_NOPI_D4,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_D5,"invalid",ZPX,2,emul_invalid,false OP_CMP_ZPX,"cmp",ZPX,2,emul_cmp,false OP_DEC_ZPX,"dec",ZPX,2,emul_dec,false OP_SMB5_ZP,"smb5",ZP,2,emul_smb5,false @@ -219,14 +219,14 @@ OP_CLD,"cld",IMPLIED,1,emul_cld,false OP_CMP_ABSY,"cmp",ABSOLUTEY,3,emul_cmp,false OP_PHX,"phx",IMPLIED,1,emul_phx,false OP_STP,"stp",IMPLIED,1,emul_stp,false -OP_NOPI_DD,"invalid",ABSOLUTE,3,NULL,false +OP_NOPI_DD,"invalid",ABSOLUTE,3,emul_invalid,false OP_CMP_ABSX,"cmp",ABSOLUTEX,3,emul_cmp,false OP_DEC_ABSX,"dec",ABSOLUTEX,3,emul_dec,false OP_BBS5_REL,"bbs5",ZPR,2,emul_bbs5,true OP_CPX_IMM,"cpx",IMMEDIATE,2,emul_cpx,false OP_SBC_IZPX,"sbc",IZPX,2,emul_sbc,false -OP_NOPI_E3,"invalid",IMMEDIATE,2,NULL,false -OP_NOPI_E4,"invalid",IMPLIED,1,NULL,false +OP_NOPI_E3,"invalid",IMMEDIATE,2,emul_invalid,false +OP_NOPI_E4,"invalid",IMPLIED,1,emul_invalid,false OP_CPX_ZP,"cpx",ZP,2,emul_cpx,false OP_SBC_ZP,"sbc",ZP,2,emul_sbc,false OP_INC_ZP,"inc",ZP,2,emul_inc,false @@ -234,7 +234,7 @@ OP_SMB6_ZP,"smb6",ZP,2,emul_smb6,false OP_INX,"inx",IMPLIED,1,emul_inx,false OP_SBC_IMM,"sbc",IMMEDIATE,2,emul_sbc,false OP_NOP,"nop",IMPLIED,1,emul_nop,false -OP_NOPI_EC,"invalid",IMPLIED,1,NULL,false +OP_NOPI_EC,"invalid",IMPLIED,1,emul_invalid,false OP_CPX_ABS,"cpx",ABSOLUTE,3,emul_cpx,false OP_SBC_ABS,"sbc",ABSOLUTE,3,emul_sbc,false OP_INC_ABS,"inc",ABSOLUTE,3,emul_inc,false @@ -242,16 +242,16 @@ OP_BBS6_REL,"bbs6",ZPR,2,emul_bbs6,true OP_BEQ_REL,"beq",RELATIVE,2,emul_beq,true OP_SBC_IZPY,"sbc",IZPY,2,emul_sbc,false OP_SBC_IZP,"sbc",IZP,2,emul_sbc,false -OP_NOPI_F4,"invalid",IMPLIED,1,NULL,false -OP_NOPI_F5,"invalid",ZPX,2,NULL,false +OP_NOPI_F4,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_F5,"invalid",ZPX,2,emul_invalid,false OP_SBC_ZPX,"sbc",ZPX,2,emul_sbc,false OP_INC_ZPX,"inc",ZPX,2,emul_inc,false OP_SMB7_ZP,"smb7",ZP,2,emul_smb7,false OP_SED,"sed",IMPLIED,1,emul_sed,false OP_SBC_ABSY,"sbc",ABSOLUTEY,3,emul_sbc,false OP_PLX,"plx",IMPLIED,1,emul_plx,false -OP_NOPI_FC,"invalid",IMPLIED,1,NULL,false -OP_NOPI_FD,"invalid",ABSOLUTE,3,NULL,false +OP_NOPI_FC,"invalid",IMPLIED,1,emul_invalid,false +OP_NOPI_FD,"invalid",ABSOLUTE,3,emul_invalid,false OP_SBC_ABSX,"sbc",ABSOLUTEX,3,emul_sbc,false OP_INC_ABSX,"inc",ABSOLUTEX,3,emul_inc,false OP_BBS7_REL,"bbs7",ZPR,2,emul_bbs7,true diff --git a/src/emulation.c b/src/emulation.c index 2c6092e..232f17f 100644 --- a/src/emulation.c +++ b/src/emulation.c @@ -1,6 +1,8 @@ #include #include +#include "log.h" + #include "emulation.h" /* RMB, SMB, BBR, BBS are handled by these */ @@ -1096,3 +1098,13 @@ emul_wai(rk65c02emu_t *e, void *id, instruction_t *i) e->stopreason = WAI; } +/* emulate invalid opcode (variable-lenght NOP) */ +void +emul_invalid(rk65c02emu_t *e, void *id, instruction_t *i) +{ + /* Essentially do nothing, but log this. */ + + rk65c02_log(LOG_WARN, "Invalid opcode %x at %x", i->opcode, + e->regs.PC); +} + diff --git a/src/rk65c02.c b/src/rk65c02.c index 4294ff7..c7c6434 100644 --- a/src/rk65c02.c +++ b/src/rk65c02.c @@ -127,21 +127,12 @@ rk65c02_exec(rk65c02emu_t *e) i = instruction_fetch(e->bus, e->regs.PC); id = instruction_decode(i.opcode); - if (id.emul != NULL) { - id.emul(e, &id, &i); + assert(id.emul); - if (!instruction_modify_pc(&id)) - program_counter_increment(e, &id); - } else { - /* - * Technically, on a real 65C02, all invalid opcodes - * are NOPs, but until rk65c02 reaches some level of - * maturity, let's catch them here to help iron out the - * bugs. - */ - rk65c02_panic(e, "invalid opcode %X @ %X\n", - i.opcode, e->regs.PC); - } + id.emul(e, &id, &i); + + if (!instruction_modify_pc(&id)) + program_counter_increment(e, &id); if (e->trace) debug_trace_savestate(e, tpc, &id, &i); From 578955e4a145a4f273e40469eca1f35e81caebbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 12 Apr 2018 11:40:33 +0200 Subject: [PATCH 02/14] Add test case for invalid opcode handling. --- test/test_emulation.c | 33 ++++++++++++++++++++++++++++ test/test_emulation_invalid_opcode.s | 11 ++++++++++ 2 files changed, 44 insertions(+) create mode 100644 test/test_emulation_invalid_opcode.s diff --git a/test/test_emulation.c b/test/test_emulation.c index ddbb617..8e2b696 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -1474,6 +1474,37 @@ ATF_TC_BODY(emul_wrap_zpx, tc) } } +ATF_TC_WITHOUT_HEAD(emul_invalid_opcode); +ATF_TC_BODY(emul_invalid_opcode, tc) +{ + rk65c02emu_t e; + bus_t b; + + struct reg_state rorig; + + rk65c02_loglevel_set(LOG_DEBUG); + + b = bus_init_with_default_devs(); + e = rk65c02_init(&b); + + e.runtime_disassembly = true; + rorig = e.regs; + + ATF_REQUIRE(rom_start(&e, "test_emulation_invalid_opcode.rom", tc)); + + ATF_CHECK(e.regs.A == rorig.A); + ATF_CHECK(e.regs.X == rorig.X); + ATF_CHECK(e.regs.Y == rorig.Y); + ATF_CHECK(e.regs.SP == rorig.SP); + ATF_CHECK(e.regs.P == rorig.P); + + ATF_CHECK(e.regs.PC == 0xC007); + + rk65c02_log(LOG_INFO, "PC: %x", e.regs.PC); + +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, emul_and); @@ -1518,6 +1549,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, emul_wrap_zpx); ATF_TP_ADD_TC(tp, emul_wrap_izpx); + ATF_TP_ADD_TC(tp, emul_invalid_opcode); + return (atf_no_error()); } diff --git a/test/test_emulation_invalid_opcode.s b/test/test_emulation_invalid_opcode.s new file mode 100644 index 0000000..fafe31f --- /dev/null +++ b/test/test_emulation_invalid_opcode.s @@ -0,0 +1,11 @@ +.byte 0x42 +.byte 0xFF +.byte 0x43 +.byte 0x44 +.byte 0xFF +.byte 0x4B +.byte 0xFC +.byte 0xFF +.byte 0xFF + stp + From 0ac5932e757b474c2a71a7c0f950e7327d697084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 12 Apr 2018 12:45:05 +0200 Subject: [PATCH 03/14] Doxify more. --- src/log.h | 32 +++++++++++++++++++++++--------- src/rk65c02.h | 48 ++++++++++++++++++++++++++++-------------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/log.h b/src/log.h index 3b50e7f..456e8f3 100644 --- a/src/log.h +++ b/src/log.h @@ -1,15 +1,29 @@ +/** + * @file log.h + * @brief Logging-related functions. + */ #include -#define LOG_TRACE 5 -#define LOG_DEBUG 4 -#define LOG_INFO 3 -#define LOG_WARN 4 -#define LOG_ERROR 2 -#define LOG_CRIT 1 -#define LOG_NOTHING 0 /* At 0 nothing will get logged, can be set as +#define LOG_TRACE 5 /**< Most verbose log level. Used for tracing. */ +#define LOG_DEBUG 4 /**< Debug-level messages. */ +#define LOG_INFO 3 /**< Informational messages. */ +#define LOG_WARN 4 /**< Warning messages. */ +#define LOG_ERROR 2 /**< Errors. */ +#define LOG_CRIT 1 /**< Critical errors. */ +#define LOG_NOTHING 0 /**< At 0 nothing will get logged, can be set as current level, but not when creating new log messages. */ -void rk65c02_loglevel_set(uint8_t); -void rk65c02_log(uint8_t, const char *, ...); +/** + * @brief Set the logging verbosity level. + * @param level Desired log verbosity level. + */ +void rk65c02_loglevel_set(uint8_t level); + +/** + * @brief Send a message to log. + * @param level Log level at which message should be logged. + * @param fmt Message in a printf-like format. + */ +void rk65c02_log(uint8_t level, const char *fmt, ...); diff --git a/src/rk65c02.h b/src/rk65c02.h index 977e9a4..7ed5004 100644 --- a/src/rk65c02.h +++ b/src/rk65c02.h @@ -7,7 +7,7 @@ #include "bus.h" /** - * @brief Current state of the emulator. + * @brief State of the emulator. */ typedef enum { STOPPED, /**< Stopped. */ @@ -29,7 +29,7 @@ typedef enum { } emu_stop_reason_t; /** - * @brief Current state of emulated CPU registers. + * @brief State of the emulated CPU registers. */ struct reg_state { uint8_t A; /**< Accumulator. */ @@ -45,14 +45,10 @@ typedef struct reg_state reg_state_t; #define P_CARRY 0x1 #define P_ZERO 0x2 -/** Status register flag: IRQ disabled */ -#define P_IRQ_DISABLE 0x4 -/** Status register flag: BCD mode */ -#define P_DECIMAL 0x8 -/** Status register flag: BRK was the cause of interrupt */ -#define P_BREAK 0x10 -/** Status register flag: Undefined (always 1) */ -#define P_UNDEFINED 0x20 +#define P_IRQ_DISABLE 0x4 /**< Status register flag: IRQ disabled */ +#define P_DECIMAL 0x8 /**< Status register flag: BCD mode */ +#define P_BREAK 0x10 /**< Status register flag: BRK was the cause of interrupt */ +#define P_UNDEFINED 0x20 /**< Status register flag: Undefined (always 1) */ #define P_SIGN_OVERFLOW 0x40 #define P_NEGATIVE 0x80 @@ -81,10 +77,10 @@ typedef struct trace_t { * @brief Instance of the emulator. */ struct rk65c02emu { - emu_state_t state; - bus_t *bus; - reg_state_t regs; - emu_stop_reason_t stopreason; + emu_state_t state; /**< Current emulator status. */ + bus_t *bus; /**< Bus to which CPU is attached. */ + reg_state_t regs; /**< CPU registers. */ + emu_stop_reason_t stopreason; /**< Reason for stopping emulation. */ bool irq; /**< Interrupt request line state, true is asserted. */ breakpoint_t *bps_head; /**< Pointer to linked list with breakpoints. */ @@ -97,18 +93,23 @@ typedef struct rk65c02emu rk65c02emu_t; /** * @brief Initialize the new emulator instance. Set initial CPU state. + * @param b Bus description. + * @return New emulator instance. */ -rk65c02emu_t rk65c02_init(bus_t *); +rk65c02emu_t rk65c02_init(bus_t *b); /** * @brief Start the emulator. + * @param e Emulator instance. */ -void rk65c02_start(rk65c02emu_t *); +void rk65c02_start(rk65c02emu_t *e); /** * @brief Execute as many instructions as specified in steps argument. + * @param e Emulator instance. + * @param steps Number of instructions to execute. */ -void rk65c02_step(rk65c02emu_t *, uint16_t); +void rk65c02_step(rk65c02emu_t *e, uint16_t steps); char *rk65c02_regs_string_get(reg_state_t); void rk65c02_dump_regs(reg_state_t); @@ -116,15 +117,22 @@ void rk65c02_dump_stack(rk65c02emu_t *, uint8_t); /** * @brief Assert the IRQ line. + * @param e Emulator instance. */ -void rk65c02_assert_irq(rk65c02emu_t *); +void rk65c02_assert_irq(rk65c02emu_t *e); /** * @brief Respond to interrupt and start the interrupt service routine. + * @param e Emulator instance. */ -void rk65c02_irq(rk65c02emu_t *); +void rk65c02_irq(rk65c02emu_t *e); -void rk65c02_panic(rk65c02emu_t *, const char*, ...); +/** + * @brief Handle critical error - send message to log and stop emulation. + * @param e Emulator instance. + * @param fmt Message in printf-like format. + */ +void rk65c02_panic(rk65c02emu_t *e, const char *fmt, ...); /** * @brief Prep the emulator, load code from file, pass bus config optionally. From e5448f50ebbacc67a16085468716e83c546ec91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 12 Apr 2018 15:13:48 +0200 Subject: [PATCH 04/14] Fix expected PC address. --- test/test_emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_emulation.c b/test/test_emulation.c index 8e2b696..9b04af3 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -1498,7 +1498,7 @@ ATF_TC_BODY(emul_invalid_opcode, tc) ATF_CHECK(e.regs.SP == rorig.SP); ATF_CHECK(e.regs.P == rorig.P); - ATF_CHECK(e.regs.PC == 0xC007); + ATF_CHECK(e.regs.PC == 0xC00A); rk65c02_log(LOG_INFO, "PC: %x", e.regs.PC); From fae3445e5827741eba6258addd0c2dc667c2fb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 12 Apr 2018 15:28:47 +0200 Subject: [PATCH 05/14] Add test cases for TRB and TSB. --- test/test_emulation.c | 34 ++++++++++++++++++++++++++++++++++ test/test_emulation_trb.s | 12 ++++++++++++ test/test_emulation_tsb.s | 12 ++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/test_emulation_trb.s create mode 100644 test/test_emulation_tsb.s diff --git a/test/test_emulation.c b/test/test_emulation.c index 9b04af3..435fd20 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -1419,6 +1419,38 @@ ATF_TC_BODY(emul_smb, tc) } } +ATF_TC_WITHOUT_HEAD(emul_trb); +ATF_TC_BODY(emul_trb, tc) +{ + rk65c02emu_t e; + bus_t b; + + b = bus_init_with_default_devs(); + e = rk65c02_init(&b); + + ATF_REQUIRE(rom_start(&e, "test_emulation_trb.rom", tc)); + + ATF_CHECK(bus_read_1(&b, 0x10) == 0x84); + ATF_CHECK(bus_read_1(&b, 0x11) == 0xA6); + +} + +ATF_TC_WITHOUT_HEAD(emul_tsb); +ATF_TC_BODY(emul_tsb, tc) +{ + rk65c02emu_t e; + bus_t b; + + b = bus_init_with_default_devs(); + e = rk65c02_init(&b); + + ATF_REQUIRE(rom_start(&e, "test_emulation_tsb.rom", tc)); + + ATF_CHECK(bus_read_1(&b, 0x10) == 0xB7); + ATF_CHECK(bus_read_1(&b, 0x11) == 0xE7); + +} + ATF_TC_WITHOUT_HEAD(emul_wrap_izpx); ATF_TC_BODY(emul_wrap_izpx, tc) { @@ -1540,6 +1572,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, emul_sbc_bcd); ATF_TP_ADD_TC(tp, emul_rmb); ATF_TP_ADD_TC(tp, emul_smb); + ATF_TP_ADD_TC(tp, emul_trb); + ATF_TP_ADD_TC(tp, emul_tsb); ATF_TP_ADD_TC(tp, emul_sign_overflow_basic); ATF_TP_ADD_TC(tp, emul_sign_overflow_thorough); diff --git a/test/test_emulation_trb.s b/test/test_emulation_trb.s new file mode 100644 index 0000000..c66d60f --- /dev/null +++ b/test/test_emulation_trb.s @@ -0,0 +1,12 @@ +start: lda #0xa6 + sta 0x10 + lda #0x33 + trb 0x10 + + lda #0xa6 + sta 0x11 + lda #0x41 + trb 0x11 + + stp + diff --git a/test/test_emulation_tsb.s b/test/test_emulation_tsb.s new file mode 100644 index 0000000..b61411f --- /dev/null +++ b/test/test_emulation_tsb.s @@ -0,0 +1,12 @@ +start: lda #0xa6 + sta 0x10 + lda #0x33 + tsb 0x10 + + lda #0xa6 + sta 0x11 + lda #0x41 + tsb 0x11 + + stp + From 6d7f0abef06b18ee60eb7afc90c5713c5de9bb7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Fri, 13 Apr 2018 11:25:30 +0200 Subject: [PATCH 06/14] Comment WAI/interrupt behaviour. --- src/rk65c02.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rk65c02.c b/src/rk65c02.c index c7c6434..acfc3a1 100644 --- a/src/rk65c02.c +++ b/src/rk65c02.c @@ -71,6 +71,14 @@ rk65c02_assert_irq(rk65c02emu_t *e) */ e->irq = true; + /* + * If the CPU was put to sleep by executing WAI instruction, resume + * operation. + * + * Whether interrupt will immediately be serviced, or not, depends + * on normal "interrupt disable" flag behaviour, so here we just + * need to start the CPU. + */ if ((e->state == STOPPED) && (e->stopreason == WAI)) rk65c02_start(e); } From 7445c275e621f09ee2bf7982f58c67e8202eeb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Fri, 13 Apr 2018 12:26:06 +0200 Subject: [PATCH 07/14] Add test cases for ROR and ROL. Too old to ROR and to ROL. --- test/test_emulation.c | 64 +++++++++++++++++++++++++++++++++++++++ test/test_emulation_rol.s | 7 +++++ test/test_emulation_ror.s | 7 +++++ 3 files changed, 78 insertions(+) create mode 100644 test/test_emulation_rol.s create mode 100644 test/test_emulation_ror.s diff --git a/test/test_emulation.c b/test/test_emulation.c index 435fd20..fd0b0ab 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -599,6 +599,68 @@ ATF_TC_BODY(emul_lsr, tc) bus_finish(&b); } +ATF_TC_WITHOUT_HEAD(emul_rol); +ATF_TC_BODY(emul_rol, tc) +{ + rk65c02emu_t e; + bus_t b; + + b = bus_init_with_default_devs(); + e = rk65c02_init(&b); + + e.regs.A = 0x55; + e.regs.P |= P_CARRY; + e.regs.X = 0x1; + + bus_write_1(&b, 0x10, 0x55); + bus_write_1(&b, 0x11, 0xFF); + bus_write_1(&b, 0x200, 0xAA); + bus_write_1(&b, 0x201, 0x01); + + ATF_REQUIRE(rom_start(&e, "test_emulation_rol.rom", tc)); + + ATF_CHECK(e.regs.A == 0xAB); + ATF_CHECK(bus_read_1(&b, 0x10) == 0xAA); + ATF_CHECK(bus_read_1(&b, 0x11) == 0xFE); + ATF_CHECK(bus_read_1(&b, 0x200) == 0x55); + ATF_CHECK(bus_read_1(&b, 0x201) == 0x3); + + ATF_CHECK(e.regs.P ^ P_CARRY); + + bus_finish(&b); +} + +ATF_TC_WITHOUT_HEAD(emul_ror); +ATF_TC_BODY(emul_ror, tc) +{ + rk65c02emu_t e; + bus_t b; + + b = bus_init_with_default_devs(); + e = rk65c02_init(&b); + + e.regs.A = 0x55; + e.regs.P |= P_CARRY; + e.regs.X = 0x1; + + bus_write_1(&b, 0x10, 0x55); + bus_write_1(&b, 0x11, 0xFF); + bus_write_1(&b, 0x200, 0xAA); + bus_write_1(&b, 0x201, 0x01); + + ATF_REQUIRE(rom_start(&e, "test_emulation_ror.rom", tc)); + + ATF_CHECK(e.regs.A == 0xAA); + ATF_CHECK(bus_read_1(&b, 0x10) == 0xAA); + ATF_CHECK(bus_read_1(&b, 0x11) == 0xFF); + ATF_CHECK(bus_read_1(&b, 0x200) == 0xD5); + ATF_CHECK(bus_read_1(&b, 0x201) == 0x0); + + ATF_CHECK(e.regs.P & P_CARRY); + + bus_finish(&b); +} + ATF_TC_WITHOUT_HEAD(emul_nop); ATF_TC_BODY(emul_nop, tc) { @@ -1564,6 +1626,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, emul_stz); ATF_TP_ADD_TC(tp, emul_php_plp); ATF_TP_ADD_TC(tp, emul_phx_phy_plx_ply); + ATF_TP_ADD_TC(tp, emul_rol); + ATF_TP_ADD_TC(tp, emul_ror); ATF_TP_ADD_TC(tp, emul_stack); ATF_TP_ADD_TC(tp, emul_txa_tya_tax_tay); ATF_TP_ADD_TC(tp, emul_sta); diff --git a/test/test_emulation_rol.s b/test/test_emulation_rol.s new file mode 100644 index 0000000..c62c215 --- /dev/null +++ b/test/test_emulation_rol.s @@ -0,0 +1,7 @@ +start: rol A + rol 0x10 + rol 0x10,X + rol 0x200 + rol 0x200,X + stp + diff --git a/test/test_emulation_ror.s b/test/test_emulation_ror.s new file mode 100644 index 0000000..a692041 --- /dev/null +++ b/test/test_emulation_ror.s @@ -0,0 +1,7 @@ +start: ror A + ror 0x10 + ror 0x10,X + ror 0x200 + ror 0x200,X + stp + From a2fdb78d2b4c6df5cc06db900adf80b762510403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Mon, 16 Apr 2018 12:14:31 +0200 Subject: [PATCH 08/14] BBR and BBS instructions have 2 operands. --- src/65c02isa.csv | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/65c02isa.csv b/src/65c02isa.csv index b81a750..52b16e4 100644 --- a/src/65c02isa.csv +++ b/src/65c02isa.csv @@ -14,7 +14,7 @@ OP_NOPI_C,"invalid",IMPLIED,1,emul_invalid,false OP_TSB_ABS,"tsb",ABSOLUTE,3,emul_tsb,false OP_ORA_ABS,"ora",ABSOLUTE,3,emul_ora,false OP_ASL_ABS,"asl",ABSOLUTE,3,emul_asl,false -OP_BBR0_REL,"bbr0",ZPR,2,emul_bbr0,true +OP_BBR0_REL,"bbr0",ZPR,3,emul_bbr0,true OP_BPL_REL,"bpl",RELATIVE,2,emul_bpl,true OP_ORA_IZPY,"ora",IZPY,2,emul_ora,false OP_ORA_IZP,"ora",IZP,2,emul_ora,false @@ -30,7 +30,7 @@ OP_NOPI_1C,"invalid",IMPLIED,1,emul_invalid,false OP_TRB_ABS,"trb",ABSOLUTE,3,emul_trb,false OP_ORA_ABSX,"ora",ABSOLUTEX,3,emul_ora,false OP_ASL_ABSX,"asl",ABSOLUTEX,3,emul_asl,false -OP_BBR1_REL,"bbr1",ZPR,2,emul_bbr1,true +OP_BBR1_REL,"bbr1",ZPR,3,emul_bbr1,true OP_JSR,"jsr",ABSOLUTE,3,emul_jsr,true OP_AND_IZPX,"and",IZPX,2,emul_and,false OP_NOPI_23,"invalid",IMMEDIATE,2,emul_invalid,false @@ -46,7 +46,7 @@ OP_NOPI_2C,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ABS,"bit",ABSOLUTE,3,emul_bit,false OP_AND_ABS,"and",ABSOLUTE,3,emul_and,false OP_ROL_ABS,"rol",ABSOLUTE,3,emul_rol,false -OP_BBR2_REL,"bbr2",ZPR,2,emul_bbr2,true +OP_BBR2_REL,"bbr2",ZPR,3,emul_bbr2,true OP_BMI_REL,"bmi",RELATIVE,2,emul_bmi,true OP_AND_IZPY,"and",IZPY,2,emul_and,false OP_AND_IZP,"and",IZP,2,emul_and,false @@ -62,7 +62,7 @@ OP_NOPI_3C,"invalid",IMPLIED,1,emul_invalid,false OP_BIT_ABSX,"bit",ABSOLUTEX,3,emul_bit,false OP_AND_ABSX,"and",ABSOLUTEX,3,emul_and,false OP_ROL_ABSX,"rol",ABSOLUTEX,3,emul_rol,false -OP_BBR3_REL,"bbr3",ZPR,2,emul_bbr3,true +OP_BBR3_REL,"bbr3",ZPR,3,emul_bbr3,true OP_RTI,"rti",IMPLIED,1,emul_rti,true OP_EOR_IZPX,"eor",IZPX,2,emul_eor,false OP_NOPI_43,"invalid",IMMEDIATE,2,emul_invalid,false @@ -78,7 +78,7 @@ OP_NOPI_4C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_ABS,"jmp",ABSOLUTE,3,emul_jmp,true OP_EOR_ABS,"eor",ABSOLUTE,3,emul_eor,false OP_LSR_ABS,"lsr",ABSOLUTE,3,emul_lsr,false -OP_BBR4_REL,"bbr4",ZPR,2,emul_bbr4,true +OP_BBR4_REL,"bbr4",ZPR,3,emul_bbr4,true OP_BVC_REL,"bvc",RELATIVE,2,emul_bvc,true OP_EOR_IZPY,"eor",IZPY,2,emul_eor,false OP_EOR_IZP,"eor",IZP,2,emul_eor,false @@ -94,7 +94,7 @@ OP_NOPI_5C,"invalid",IMPLIED,1,emul_invalid,false OP_NOPI_5D,"invalid",ABSOLUTE,3,emul_invalid,false OP_EOR_ABSX,"eor",ABSOLUTEX,3,emul_eor,false OP_LSR_ABSX,"lsr",ABSOLUTEX,3,emul_lsr,false -OP_BBR5_REL,"bbr5",ZPR,2,emul_bbr5,true +OP_BBR5_REL,"bbr5",ZPR,3,emul_bbr5,true OP_RTS,"rts",IMPLIED,1,emul_rts,false OP_ADC_IZPX,"adc",IZPX,2,emul_adc,false OP_NOPI_63,"invalid",IMMEDIATE,2,emul_invalid,false @@ -110,7 +110,7 @@ OP_NOPI_6C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_IABS,"jmp",IABSOLUTE,3,emul_jmp,true OP_ADC_ABS,"adc",ABSOLUTE,3,emul_adc,false OP_ROR_ABS,"ror",ABSOLUTE,3,emul_ror,false -OP_BBR6_REL,"bbr6",ZPR,2,emul_bbr6,true +OP_BBR6_REL,"bbr6",ZPR,3,emul_bbr6,true OP_BVS_REL,"bvs",RELATIVE,2,emul_bvs,true OP_ADC_IZPY,"adc",IZPY,2,emul_adc,false OP_ADC_IZP,"adc",IZP,2,emul_adc,false @@ -126,7 +126,7 @@ OP_NOPI_7C,"invalid",IMPLIED,1,emul_invalid,false OP_JMP_IABSX,"jmp",IABSOLUTEX,3,emul_jmp,true OP_ADC_ABSX,"adc",ABSOLUTEX,3,emul_adc,false OP_ROR_ABSX,"ror",ABSOLUTEX,3,emul_ror,false -OP_BBR7_REL,"bbr7",ZPR,2,emul_bbr7,true +OP_BBR7_REL,"bbr7",ZPR,3,emul_bbr7,true OP_BRA_REL,"bra",RELATIVE,2,emul_bra,true OP_STA_IZPX,"sta",IZPX,2,emul_sta,false OP_NOPI_83,"invalid",IMMEDIATE,2,emul_invalid,false @@ -142,7 +142,7 @@ OP_NOPI_8C,"invalid",IMPLIED,1,emul_invalid,false OP_STY_ABS,"sty",ABSOLUTE,3,emul_sty,false OP_STA_ABS,"sta",ABSOLUTE,3,emul_sta,false OP_STX_ABS,"stx",ABSOLUTE,3,emul_stx,false -OP_BBS0_REL,"bbs0",ZPR,2,emul_bbs0,true +OP_BBS0_REL,"bbs0",ZPR,3,emul_bbs0,true OP_BCC_REL,"bcc",RELATIVE,2,emul_bcc,true OP_STA_IZPY,"sta",IZPY,2,emul_sta,false OP_STA_IZP,"sta",IZP,2,emul_sta,false @@ -158,7 +158,7 @@ OP_NOPI_9C,"invalid",IMPLIED,1,emul_invalid,false OP_STZ_ABS,"stz",ABSOLUTE,3,emul_stz,false OP_STA_ABSX,"sta",ABSOLUTEX,3,emul_sta,false OP_STZ_ABSX,"stz",ABSOLUTEX,3,emul_stz,false -OP_BBS1_REL,"bbs1",ZPR,2,emul_bbs1,true +OP_BBS1_REL,"bbs1",ZPR,3,emul_bbs1,true OP_LDY_IMM,"ldy",IMMEDIATE,2,emul_ldy,false OP_LDA_IZPX,"lda",IZPX,2,emul_lda,false OP_LDX_IMM,"ldx",IMMEDIATE,2,emul_ldx,false @@ -174,7 +174,7 @@ OP_NOPI_AC,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ABS,"ldy",ABSOLUTE,3,emul_ldy,false OP_LDA_ABS,"lda",ABSOLUTE,3,emul_lda,false OP_LDX_ABS,"ldx",ABSOLUTE,3,emul_ldx,false -OP_BBS2_REL,"bbs2",ZPR,2,emul_bbs2,true +OP_BBS2_REL,"bbs2",ZPR,3,emul_bbs2,true OP_BCS_REL,"bcs",RELATIVE,2,emul_bcs,true OP_LDA_IZPY,"lda",IZPY,2,emul_lda,false OP_LDA_IZP,"lda",IZP,2,emul_lda,false @@ -190,7 +190,7 @@ OP_NOPI_BC,"invalid",IMPLIED,1,emul_invalid,false OP_LDY_ABSX,"ldy",ABSOLUTEX,3,emul_ldy,false OP_LDA_ABSX,"lda",ABSOLUTEX,3,emul_lda,false OP_LDX_ABSY,"ldx",ABSOLUTEY,3,emul_ldx,false -OP_BBS3_REL,"bbs3",ZPR,2,emul_bbs3,true +OP_BBS3_REL,"bbs3",ZPR,3,emul_bbs3,true OP_CPY_IMM,"cpy",IMMEDIATE,2,emul_cpy,false OP_CMP_IZPX,"cmp",IZPX,2,emul_cmp,false OP_NOPI_C3,"invalid",IMMEDIATE,2,emul_invalid,false @@ -206,7 +206,7 @@ OP_WAI,"wai",IMPLIED,1,emul_wai,false OP_CPY_ABS,"cpy",ABSOLUTE,3,emul_cpy,false OP_CMP_ABS,"cmp",ABSOLUTE,3,emul_cmp,false OP_DEC_ABS,"dec",ABSOLUTE,3,emul_dec,false -OP_BBS4_REL,"bbs4",ZPR,2,emul_bbs4,true +OP_BBS4_REL,"bbs4",ZPR,3,emul_bbs4,true OP_BNE_REL,"bne",RELATIVE,2,emul_bne,true OP_CMP_IZPY,"cmp",IZPY,2,emul_cmp,false OP_CMP_IZP,"cmp",IZP,2,emul_cmp,false @@ -222,7 +222,7 @@ OP_STP,"stp",IMPLIED,1,emul_stp,false OP_NOPI_DD,"invalid",ABSOLUTE,3,emul_invalid,false OP_CMP_ABSX,"cmp",ABSOLUTEX,3,emul_cmp,false OP_DEC_ABSX,"dec",ABSOLUTEX,3,emul_dec,false -OP_BBS5_REL,"bbs5",ZPR,2,emul_bbs5,true +OP_BBS5_REL,"bbs5",ZPR,3,emul_bbs5,true OP_CPX_IMM,"cpx",IMMEDIATE,2,emul_cpx,false OP_SBC_IZPX,"sbc",IZPX,2,emul_sbc,false OP_NOPI_E3,"invalid",IMMEDIATE,2,emul_invalid,false @@ -238,7 +238,7 @@ OP_NOPI_EC,"invalid",IMPLIED,1,emul_invalid,false OP_CPX_ABS,"cpx",ABSOLUTE,3,emul_cpx,false OP_SBC_ABS,"sbc",ABSOLUTE,3,emul_sbc,false OP_INC_ABS,"inc",ABSOLUTE,3,emul_inc,false -OP_BBS6_REL,"bbs6",ZPR,2,emul_bbs6,true +OP_BBS6_REL,"bbs6",ZPR,3,emul_bbs6,true OP_BEQ_REL,"beq",RELATIVE,2,emul_beq,true OP_SBC_IZPY,"sbc",IZPY,2,emul_sbc,false OP_SBC_IZP,"sbc",IZP,2,emul_sbc,false @@ -254,4 +254,4 @@ OP_NOPI_FC,"invalid",IMPLIED,1,emul_invalid,false OP_NOPI_FD,"invalid",ABSOLUTE,3,emul_invalid,false OP_SBC_ABSX,"sbc",ABSOLUTEX,3,emul_sbc,false OP_INC_ABSX,"inc",ABSOLUTEX,3,emul_inc,false -OP_BBS7_REL,"bbs7",ZPR,2,emul_bbs7,true +OP_BBS7_REL,"bbs7",ZPR,3,emul_bbs7,true From 4ff3f390db1bdc7bccfc6da839df271ef6f7239a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Mon, 16 Apr 2018 12:26:52 +0200 Subject: [PATCH 09/14] Fix assembling opcode 0xFF (BBS7). --- src/instruction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/instruction.c b/src/instruction.c index 3de98ff..adc9941 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -187,7 +187,7 @@ assemble_single_buf(uint8_t **buf, uint8_t *bsize, const char *mnemonic, address opcode = 0; /* find the opcode for given mnemonic and addressing mode */ - while (opcode < 0xFF) { + while (opcode <= 0xFF) { /* this is stupid */ id = instruction_decode(opcode); if ((strcmp(mnemonic, id.mnemonic) == 0) && (id.mode == mode)) { found = true; From 8ca86735df0620f252300896f381a41607e97769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Mon, 16 Apr 2018 12:27:53 +0200 Subject: [PATCH 10/14] Add tests for BBRx, BBSx. --- test/test_emulation.c | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/test/test_emulation.c b/test/test_emulation.c index fd0b0ab..07517c1 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -1011,6 +1011,88 @@ ATF_TC_BODY(emul_jsr_rts, tc) } +ATF_TC_WITHOUT_HEAD(emul_bbr); +ATF_TC_BODY(emul_bbr, tc) +{ + rk65c02emu_t e; + bus_t b; + assembler_t a; + + uint8_t i, val; + uint16_t opc; + + char instr[] = "bbr "; + + b = bus_init_with_default_devs(); + a = assemble_init(&b, ROM_LOAD_ADDR); + e = rk65c02_init(&b); + + e.regs.PC = ROM_LOAD_ADDR; + + for (i = 0; i < 8; i++) { + val = 0xFF & ~(1 << i); + bus_write_1(&b, 0x10+i, val); + } + + for (i = 0; i < 8; i++) { + instr[3] = '0'+i; + ATF_REQUIRE(assemble_single(&a, instr, ZPR, 0x10+i, 0x70)); + } + + e.runtime_disassembly = true; + + for (i = 0; i < 8; i++) { + opc = e.regs.PC; + rk65c02_step(&e, 1); + ATF_CHECK(e.regs.PC == opc + 2 + 0x70); + rk65c02_dump_regs(e.regs); + e.regs.PC = ROM_LOAD_ADDR + (3 * (i + 1)); + } + + +} + +ATF_TC_WITHOUT_HEAD(emul_bbs); +ATF_TC_BODY(emul_bbs, tc) +{ + rk65c02emu_t e; + bus_t b; + assembler_t a; + + uint8_t i; + uint16_t opc; + + char instr[] = "bbs "; + + b = bus_init_with_default_devs(); + a = assemble_init(&b, ROM_LOAD_ADDR); + e = rk65c02_init(&b); + + e.regs.PC = ROM_LOAD_ADDR; + + for (i = 0; i < 8; i++) { + bus_write_1(&b, 0x10+i, 1 << i); + } + + for (i = 0; i < 8; i++) { + instr[3] = '0'+i; + ATF_REQUIRE(assemble_single(&a, instr, ZPR, 0x10+i, 0x70)); + } + + e.runtime_disassembly = true; + + for (i = 0; i < 8; i++) { + opc = e.regs.PC; + rk65c02_step(&e, 1); + ATF_CHECK(e.regs.PC == opc + 2 + 0x70); + rk65c02_dump_regs(e.regs); + e.regs.PC = ROM_LOAD_ADDR + (3 * (i + 1)); + } + + +} + + ATF_TC_WITHOUT_HEAD(emul_branch); ATF_TC_BODY(emul_branch, tc) { @@ -1607,6 +1689,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, emul_adc_bcd); ATF_TP_ADD_TC(tp, emul_bit); ATF_TP_ADD_TC(tp, emul_branch); + ATF_TP_ADD_TC(tp, emul_bbr); + ATF_TP_ADD_TC(tp, emul_bbs); ATF_TP_ADD_TC(tp, emul_cmp); ATF_TP_ADD_TC(tp, emul_cpx); ATF_TP_ADD_TC(tp, emul_cpy); From e2bf924fa93c898660e9ebb9c907f46e94bafc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 26 Apr 2018 14:16:04 +0200 Subject: [PATCH 11/14] Make sure doff is initialized. --- src/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bus.c b/src/bus.c index 68ebcd4..71bca5b 100644 --- a/src/bus.c +++ b/src/bus.c @@ -64,6 +64,7 @@ bus_access_device(bus_t *t, uint16_t addr, device_t **d, uint16_t *off) device_mapping_t *dm; device_t *dtmp; + doff = 0; *d = NULL; LL_FOREACH(t->dm_head, dm) { From 216450da525a3ae68a548a5c53768076ddc4d11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Thu, 26 Apr 2018 14:16:32 +0200 Subject: [PATCH 12/14] Enable debug-safe optimizations. Also ggdb for tests. --- src/Makefile | 2 +- test/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 17a4d30..c599e38 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,7 +7,7 @@ LIB_STATIC=librk65c02.a LDFLAGS_SO=-shared #LDFLAGS_CLI=-lreadline -CFLAGS=-Wall -fpic -ggdb +CFLAGS=-Wall -fpic -ggdb -Og #CFLAGS=-Wall -fpic -ggdb -I/opt/local/include/uthash 65C02ISA=65c02isa diff --git a/test/Makefile b/test/Makefile index 1c669c7..90856b9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-Wall -I../src -g +CFLAGS=-Wall -I../src -ggdb -Og LDFLAGS=-latf-c -lgc RK6502LIB=../src/librk65c02.a VASM=vasm6502_std From b7986df55391b58d900975515ded04caae526763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Fri, 27 Apr 2018 10:34:48 +0200 Subject: [PATCH 13/14] Split address calculation into separate function. This removes some code duplication for instruction_data_read/write functions. Also this way implementing watchpoints will be far easier. --- src/instruction.c | 115 +++++++++++++++------------------------------- src/instruction.h | 1 + 2 files changed, 39 insertions(+), 77 deletions(-) diff --git a/src/instruction.c b/src/instruction.c index adc9941..ba9ba6b 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -275,110 +275,71 @@ instruction_status_adjust_negative(rk65c02emu_t *e, uint8_t regval) void instruction_data_write_1(rk65c02emu_t *e, instrdef_t *id, instruction_t *i, uint8_t val) { - uint16_t iaddr; - - switch (id->mode) { - case ZP: - case ZPR: - bus_write_1(e->bus, i->op1, val); - break; - case ZPX: - bus_write_1(e->bus, (uint8_t) (i->op1 + e->regs.X), val); - break; - case ZPY: - bus_write_1(e->bus, i->op1 + e->regs.Y, val); - break; - case IZP: - iaddr = bus_read_1(e->bus, i->op1); - iaddr |= (bus_read_1(e->bus, i->op1 + 1) << 8); - bus_write_1(e->bus, iaddr, val); - break; - case ABSOLUTE: - bus_write_1(e->bus, i->op1 + (i->op2 << 8), val); - break; - case IZPX: /* Zero Page Indexed Indirect with X */ - iaddr = bus_read_1(e->bus,(uint8_t) (i->op1 + e->regs.X)); - iaddr |= (bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X + 1)) << 8); - bus_write_1(e->bus, iaddr, val); - break; - case IZPY: /* Zero Page Indirect Indexed with Y */ - iaddr = bus_read_1(e->bus, i->op1); - iaddr |= (bus_read_1(e->bus, i->op1 + 1) << 8); - bus_write_1(e->bus, iaddr + e->regs.Y, val); - break; - case ABSOLUTEX: - bus_write_1(e->bus, (i->op1 + (i->op2 << 8)) + e->regs.X, val); - break; - case ABSOLUTEY: - bus_write_1(e->bus, (i->op1 + (i->op2 << 8)) + e->regs.Y, val); - break; - case ACCUMULATOR: + if (id->mode == ACCUMULATOR) { e->regs.A = val; - break; - case IMMEDIATE: - case RELATIVE: - case IABSOLUTE: - case IABSOLUTEX: - /* - * IABSOLUTE, IABSOLUTEX, RELATIVE are only for branches - * and jumps. They do not read or write anything, only modify - * PC which is handled within emulation of a given opcode. - */ - default: - rk65c02_panic(e, "unhandled addressing mode for opcode %x\n", - i->opcode); - break; + return; } + + if (id->mode == IMMEDIATE) { + rk65c02_panic(e, + "invalid IMMEDIATE addressing mode for opcode %x\n", + i->opcode); + return; + } + + bus_write_1(e->bus, instruction_data_address(e, id, i), val); } uint8_t instruction_data_read_1(rk65c02emu_t *e, instrdef_t *id, instruction_t *i) { - uint8_t rv; /* data read from the bus */ - uint16_t iaddr; /* indirect address */ + if (id->mode == ACCUMULATOR) + return e->regs.A; + else if (id->mode == IMMEDIATE) + return i->op1; - rv = 0; + return bus_read_1(e->bus, instruction_data_address(e, id, i)); +} + +uint16_t +instruction_data_address(rk65c02emu_t *e, instrdef_t *id, instruction_t *i) +{ + uint16_t addr; + + addr = 0; switch (id->mode) { - case ACCUMULATOR: - rv = e->regs.A; - break; - case IMMEDIATE: - rv = i->op1; - break; case ZP: case ZPR: - rv = bus_read_1(e->bus, i->op1); + addr = i->op1; break; case ZPX: - rv = bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X)); + addr = ((uint8_t) (i->op1 + e->regs.X)); break; case ZPY: - rv = bus_read_1(e->bus, i->op1 + e->regs.Y); + addr = i->op1 + e->regs.Y; break; case IZP: - iaddr = bus_read_1(e->bus, i->op1); - iaddr |= (bus_read_1(e->bus, i->op1 + 1) << 8); - rv = bus_read_1(e->bus, iaddr); + addr = bus_read_1(e->bus, i->op1); + addr |= (bus_read_1(e->bus, i->op1 + 1) << 8); break; case IZPX: /* Zero Page Indexed Indirect with X */ - iaddr = bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X)); - iaddr |= (bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X + 1)) << 8); - rv = bus_read_1(e->bus, iaddr); + addr = bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X)); + addr |= (bus_read_1(e->bus, (uint8_t) (i->op1 + e->regs.X + 1)) << 8); break; case IZPY: /* Zero Page Indirect Indexed with Y */ - iaddr = bus_read_1(e->bus, i->op1); - iaddr |= (bus_read_1(e->bus, i->op1 + 1) << 8); - rv = bus_read_1(e->bus, iaddr + e->regs.Y); + addr = bus_read_1(e->bus, i->op1); + addr |= (bus_read_1(e->bus, i->op1 + 1) << 8); + addr += e->regs.Y; break; case ABSOLUTE: - rv = bus_read_1(e->bus, i->op1 + (i->op2 << 8)); + addr = i->op1 + (i->op2 << 8); break; case ABSOLUTEX: - rv = bus_read_1(e->bus, (i->op1 + (i->op2 << 8)) + e->regs.X); + addr = i->op1 + (i->op2 << 8) + e->regs.X; break; case ABSOLUTEY: - rv = bus_read_1(e->bus, (i->op1 + (i->op2 << 8)) + e->regs.Y); + addr = i->op1 + (i->op2 << 8) + e->regs.Y; break; case IABSOLUTE: case IABSOLUTEX: @@ -394,7 +355,7 @@ instruction_data_read_1(rk65c02emu_t *e, instrdef_t *id, instruction_t *i) break; } - return rv; + return addr; } /* put value onto the stack */ diff --git a/src/instruction.h b/src/instruction.h index 98595f0..6504116 100644 --- a/src/instruction.h +++ b/src/instruction.h @@ -55,6 +55,7 @@ char * instruction_string_get(instruction_t *); void disassemble(bus_t *, uint16_t); uint8_t instruction_data_read_1(rk65c02emu_t *, instrdef_t *, instruction_t *); void instruction_data_write_1(rk65c02emu_t *, instrdef_t *, instruction_t *, uint8_t); +uint16_t instruction_data_address(rk65c02emu_t *e, instrdef_t *id, instruction_t *i); void instruction_status_adjust_zero(rk65c02emu_t *, uint8_t); void instruction_status_adjust_negative(rk65c02emu_t *, uint8_t); void stack_push(rk65c02emu_t *, uint8_t); From 1ec075518c3c19edaea7813ed1b5bc5c971b153f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kujawa?= Date: Fri, 27 Apr 2018 14:07:42 +0200 Subject: [PATCH 14/14] Split assembler-related things into separate file. --- src/Makefile | 2 +- src/assembler.c | 104 ++++++++++++++++++++++++++++++++++++++++++ src/assembler.h | 22 +++++++++ src/instruction.c | 87 ----------------------------------- src/instruction.h | 14 ------ test/test_assemble.c | 1 + test/test_debug.c | 1 + test/test_emulation.c | 1 + 8 files changed, 130 insertions(+), 102 deletions(-) create mode 100644 src/assembler.c create mode 100644 src/assembler.h diff --git a/src/Makefile b/src/Makefile index c599e38..f6797f4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ #CLI=rk65c02cli #CLI_OBJS=rk65c02cli.o -LIB_OBJS=rk65c02.o bus.o instruction.o emulation.o debug.o device_ram.o device_fb.o device_serial.o log.o +LIB_OBJS=rk65c02.o bus.o instruction.o emulation.o debug.o device_ram.o device_fb.o device_serial.o log.o assembler.o LIB_SO=librk65c02.so LIB_STATIC=librk65c02.a diff --git a/src/assembler.c b/src/assembler.c new file mode 100644 index 0000000..d3e4e81 --- /dev/null +++ b/src/assembler.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "bus.h" +#include "rk65c02.h" +#include "log.h" +#include "assembler.h" +#include "instruction.h" + +assembler_t +assemble_init(bus_t *b, uint16_t pc) +{ + assembler_t asmblr; + + asmblr.bus = b; + asmblr.pc = pc; + + return asmblr; +} + +bool +assemble_single_implied(assembler_t *a, const char *mnemonic) +{ + return assemble_single(a, mnemonic, IMPLIED, 0, 0); +} + +bool +assemble_single(assembler_t *a, const char *mnemonic, addressing_t mode, uint8_t op1, uint8_t op2) +{ + uint8_t *asmbuf; + uint8_t bsize; + bool rv; + + rv = assemble_single_buf(&asmbuf, &bsize, mnemonic, mode, op1, op2); + if (rv == false) + return rv; + + rv = bus_load_buf(a->bus, a->pc, asmbuf, bsize); + a->pc += bsize; + + return rv; +} + +bool +assemble_single_buf_implied(uint8_t **buf, uint8_t *bsize, const char *mnemonic) +{ + return assemble_single_buf(buf, bsize, mnemonic, IMPLIED, 0, 0); +} + + +bool +assemble_single_buf(uint8_t **buf, uint8_t *bsize, const char *mnemonic, addressing_t mode, uint8_t op1, uint8_t op2) +{ + instrdef_t id; + uint8_t opcode; + bool found; + + found = false; + opcode = 0; + + /* find the opcode for given mnemonic and addressing mode */ + while (opcode <= 0xFF) { /* this is stupid */ + id = instruction_decode(opcode); + if ((strcmp(mnemonic, id.mnemonic) == 0) && (id.mode == mode)) { + found = true; + break; + } + opcode++; + } + + if (!found) { + rk65c02_log(LOG_ERROR, + "Couldn't find opcode for mnemonic %s mode %x.", + mnemonic, mode); + return false; + } + + *bsize = id.size; + *buf = GC_MALLOC(id.size); + if(*buf == NULL) { + rk65c02_log(LOG_ERROR, "Error allocating assembly buffer."); + return false; + } + + /* fill the buffer */ + memset(*buf, 0, id.size); + (*buf)[0] = opcode; + /* XXX */ + if (id.size > 1) + (*buf)[1] = op1; + if (id.size > 2) + (*buf)[2] = op2; + + return found; +} + diff --git a/src/assembler.h b/src/assembler.h new file mode 100644 index 0000000..e12d426 --- /dev/null +++ b/src/assembler.h @@ -0,0 +1,22 @@ +#ifndef _ASSEMBLER_H_ +#define _ASSEMBLER_H_ + +#include "instruction.h" +#include "rk65c02.h" + +struct assembler { + bus_t *bus; + uint16_t pc; +}; + +typedef struct assembler assembler_t; + +bool assemble_single_buf_implied(uint8_t **, uint8_t *, const char *); +bool assemble_single_buf(uint8_t **, uint8_t *, const char *, addressing_t, uint8_t, uint8_t); + +assembler_t assemble_init(bus_t *, uint16_t); +bool assemble_single(assembler_t *, const char *, addressing_t, uint8_t, uint8_t); +bool assemble_single_implied(assembler_t *, const char *); + +#endif /* _ASSEMBLER_H_ */ + diff --git a/src/instruction.c b/src/instruction.c index ba9ba6b..d52f7d7 100644 --- a/src/instruction.c +++ b/src/instruction.c @@ -135,93 +135,6 @@ instruction_string_get(instruction_t *i) return str; } -assembler_t -assemble_init(bus_t *b, uint16_t pc) -{ - assembler_t asmblr; - - asmblr.bus = b; - asmblr.pc = pc; - - return asmblr; -} - -bool -assemble_single_implied(assembler_t *a, const char *mnemonic) -{ - return assemble_single(a, mnemonic, IMPLIED, 0, 0); -} - -bool -assemble_single(assembler_t *a, const char *mnemonic, addressing_t mode, uint8_t op1, uint8_t op2) -{ - uint8_t *asmbuf; - uint8_t bsize; - bool rv; - - rv = assemble_single_buf(&asmbuf, &bsize, mnemonic, mode, op1, op2); - if (rv == false) - return rv; - - rv = bus_load_buf(a->bus, a->pc, asmbuf, bsize); - a->pc += bsize; - - return rv; -} - -bool -assemble_single_buf_implied(uint8_t **buf, uint8_t *bsize, const char *mnemonic) -{ - return assemble_single_buf(buf, bsize, mnemonic, IMPLIED, 0, 0); -} - - -bool -assemble_single_buf(uint8_t **buf, uint8_t *bsize, const char *mnemonic, addressing_t mode, uint8_t op1, uint8_t op2) -{ - instrdef_t id; - uint8_t opcode; - bool found; - - found = false; - opcode = 0; - - /* find the opcode for given mnemonic and addressing mode */ - while (opcode <= 0xFF) { /* this is stupid */ - id = instruction_decode(opcode); - if ((strcmp(mnemonic, id.mnemonic) == 0) && (id.mode == mode)) { - found = true; - break; - } - opcode++; - } - - if (!found) { - rk65c02_log(LOG_ERROR, - "Couldn't find opcode for mnemonic %s mode %x.", - mnemonic, mode); - return false; - } - - *bsize = id.size; - *buf = GC_MALLOC(id.size); - if(*buf == NULL) { - rk65c02_log(LOG_ERROR, "Error allocating assembly buffer."); - return false; - } - - /* fill the buffer */ - memset(*buf, 0, id.size); - (*buf)[0] = opcode; - /* XXX */ - if (id.size > 1) - (*buf)[1] = op1; - if (id.size > 2) - (*buf)[2] = op2; - - return found; -} - void disassemble(bus_t *b, uint16_t addr) { diff --git a/src/instruction.h b/src/instruction.h index 6504116..8b358ba 100644 --- a/src/instruction.h +++ b/src/instruction.h @@ -41,13 +41,6 @@ struct instrdef { typedef struct instrdef instrdef_t; -struct assembler { - bus_t *bus; - uint16_t pc; -}; - -typedef struct assembler assembler_t; - instruction_t instruction_fetch(bus_t *, uint16_t); instrdef_t instruction_decode(uint8_t); void instruction_print(instruction_t *); @@ -64,11 +57,4 @@ void program_counter_increment(rk65c02emu_t *, instrdef_t *); bool instruction_modify_pc(instrdef_t *); void program_counter_branch(rk65c02emu_t *, int8_t); -bool assemble_single_buf_implied(uint8_t **, uint8_t *, const char *); -bool assemble_single_buf(uint8_t **, uint8_t *, const char *, addressing_t, uint8_t, uint8_t); - -assembler_t assemble_init(bus_t *, uint16_t); -bool assemble_single(assembler_t *, const char *, addressing_t, uint8_t, uint8_t); -bool assemble_single_implied(assembler_t *, const char *); - #endif /* _INSTRUCTION_H_ */ diff --git a/test/test_assemble.c b/test/test_assemble.c index 0f18e04..d9315d2 100644 --- a/test/test_assemble.c +++ b/test/test_assemble.c @@ -7,6 +7,7 @@ #include "bus.h" #include "rk65c02.h" +#include "assembler.h" #include "instruction.h" #include "utils.h" diff --git a/test/test_debug.c b/test/test_debug.c index eb93f58..1ae4199 100644 --- a/test/test_debug.c +++ b/test/test_debug.c @@ -9,6 +9,7 @@ #include "bus.h" #include "rk65c02.h" +#include "assembler.h" #include "instruction.h" #include "debug.h" #include "utils.h" diff --git a/test/test_emulation.c b/test/test_emulation.c index 07517c1..fed334a 100644 --- a/test/test_emulation.c +++ b/test/test_emulation.c @@ -6,6 +6,7 @@ #include "bus.h" #include "rk65c02.h" +#include "assembler.h" #include "instruction.h" #include "debug.h" #include "log.h"