mirror of
https://github.com/rkujawa/rk65c02.git
synced 2025-04-12 16:37:18 +00:00
Merge branch 'master' of github.com:rkujawa/rk65c02
This commit is contained in:
commit
6c3e66a9f1
120
src/65c02isa.csv
120
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,15 +10,15 @@ 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
|
||||
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
|
||||
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_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,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,15 +42,15 @@ 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
|
||||
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
|
||||
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,47 +58,47 @@ 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_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,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
|
||||
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
|
||||
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_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,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,15 +106,15 @@ 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
|
||||
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
|
||||
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_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,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,15 +138,15 @@ 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
|
||||
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
|
||||
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,15 +154,15 @@ 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
|
||||
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
|
||||
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,15 +170,15 @@ 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
|
||||
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
|
||||
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_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,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
|
||||
@ -206,12 +206,12 @@ 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
|
||||
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_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,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,24 +234,24 @@ 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
|
||||
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
|
||||
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
|
||||
OP_BBS7_REL,"bbs7",ZPR,3,emul_bbs7,true
|
||||
|
|
@ -1,13 +1,13 @@
|
||||
#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
|
||||
|
||||
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
|
||||
|
104
src/assembler.c
Normal file
104
src/assembler.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gc/gc.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
22
src/assembler.h
Normal file
22
src/assembler.h
Normal file
@ -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_ */
|
||||
|
@ -70,6 +70,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) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
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)
|
||||
{
|
||||
@ -275,110 +188,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 +268,7 @@ instruction_data_read_1(rk65c02emu_t *e, instrdef_t *id, instruction_t *i)
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* put value onto the stack */
|
||||
|
@ -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 *);
|
||||
@ -55,6 +48,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);
|
||||
@ -63,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_ */
|
||||
|
32
src/log.h
32
src/log.h
@ -1,15 +1,29 @@
|
||||
/**
|
||||
* @file log.h
|
||||
* @brief Logging-related functions.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#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, ...);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
@ -127,21 +135,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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "bus.h"
|
||||
#include "rk65c02.h"
|
||||
#include "assembler.h"
|
||||
#include "instruction.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "bus.h"
|
||||
#include "rk65c02.h"
|
||||
#include "assembler.h"
|
||||
#include "instruction.h"
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "bus.h"
|
||||
#include "rk65c02.h"
|
||||
#include "assembler.h"
|
||||
#include "instruction.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
@ -599,6 +600,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)
|
||||
{
|
||||
@ -949,6 +1012,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)
|
||||
{
|
||||
@ -1419,6 +1564,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)
|
||||
{
|
||||
@ -1474,6 +1651,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 == 0xC00A);
|
||||
|
||||
rk65c02_log(LOG_INFO, "PC: %x", e.regs.PC);
|
||||
|
||||
}
|
||||
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, emul_and);
|
||||
@ -1482,6 +1690,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);
|
||||
@ -1501,6 +1711,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);
|
||||
@ -1509,6 +1721,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);
|
||||
@ -1518,6 +1732,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());
|
||||
}
|
||||
|
||||
|
11
test/test_emulation_invalid_opcode.s
Normal file
11
test/test_emulation_invalid_opcode.s
Normal file
@ -0,0 +1,11 @@
|
||||
.byte 0x42
|
||||
.byte 0xFF
|
||||
.byte 0x43
|
||||
.byte 0x44
|
||||
.byte 0xFF
|
||||
.byte 0x4B
|
||||
.byte 0xFC
|
||||
.byte 0xFF
|
||||
.byte 0xFF
|
||||
stp
|
||||
|
7
test/test_emulation_rol.s
Normal file
7
test/test_emulation_rol.s
Normal file
@ -0,0 +1,7 @@
|
||||
start: rol A
|
||||
rol 0x10
|
||||
rol 0x10,X
|
||||
rol 0x200
|
||||
rol 0x200,X
|
||||
stp
|
||||
|
7
test/test_emulation_ror.s
Normal file
7
test/test_emulation_ror.s
Normal file
@ -0,0 +1,7 @@
|
||||
start: ror A
|
||||
ror 0x10
|
||||
ror 0x10,X
|
||||
ror 0x200
|
||||
ror 0x200,X
|
||||
stp
|
||||
|
12
test/test_emulation_trb.s
Normal file
12
test/test_emulation_trb.s
Normal file
@ -0,0 +1,12 @@
|
||||
start: lda #0xa6
|
||||
sta 0x10
|
||||
lda #0x33
|
||||
trb 0x10
|
||||
|
||||
lda #0xa6
|
||||
sta 0x11
|
||||
lda #0x41
|
||||
trb 0x11
|
||||
|
||||
stp
|
||||
|
12
test/test_emulation_tsb.s
Normal file
12
test/test_emulation_tsb.s
Normal file
@ -0,0 +1,12 @@
|
||||
start: lda #0xa6
|
||||
sta 0x10
|
||||
lda #0x33
|
||||
tsb 0x10
|
||||
|
||||
lda #0xa6
|
||||
sta 0x11
|
||||
lda #0x41
|
||||
tsb 0x11
|
||||
|
||||
stp
|
||||
|
Loading…
x
Reference in New Issue
Block a user