So I started working on a 6502 emulator just to see if I could do it. I've not finished the core so I haven't written an assembler yet. I have this huge switch statement with each opcode. I know there is another method that could greatly reduce that by extracting the addressing modes from the opcode but I opted to go this way. Is this efficient? Keep in mind that I am not some expert which is why I would like to improve and that I'm aware that there is much to be done yet with this core. I haven't even implemented all of the instructions.
6502.h
6502.cCode:#ifndef _6502_H #define _6502_H #include <stdbool.h> #include <stdio.h> #define C_FLAG 0x01 #define Z_FLAG 0x02 #define I_FLAG 0x04 #define D_FLAG 0x08 #define B_FLAG 0x10 #define R_FLAG 0x20 #define V_FLAG 0x40 #define N_FLAG 0x80 typedef unsigned char byte; typedef short word; typedef union{ byte b[2]; word w; }PC; typedef struct{ byte a,x,y,p; word s; PC pc; }reg; typedef PC pair; byte m_read(word); void m_write(word, byte); void set_flag(reg* r, int FLAG); void clr_flag(reg* r, int FLAG); bool chk_flag(const reg* r, int FLAG); //ADDRESS RETURNING FUNCTIONS word mc_abs(reg *r); word mc_abs_x(reg *r); word mc_abs_y(reg *r); word mc_ix(reg *r); word mc_iy(reg *r); byte mc_zp(reg *r); byte mc_zp_x(reg *r); byte mc_zp_y(reg *r); byte mc_im(reg *r); word mc_rel(reg *r); //MEMORY WRITING FUNCTIONS void mw_abs(reg *r); void mw_abs_x(reg *r); void mw_abs_y(reg *r); void mw_ix(reg *r); void mw_iy(reg *r); void mw_im(reg *r); void mw_zp(reg *r); void mw_zp_x(reg *r); void mw_zp_y(reg *r); void mw_rel(reg *r); //MEMORY READING FUNCTIONS byte mr_abs(reg *r); byte mr_abs_x(reg *r); byte mr_abs_y(reg *r); byte mr_zp(reg* r); byte mr_zp_x(reg *r); byte mr_zp_y(reg *r); byte mr_im(reg *r); byte mr_ix(reg *r); byte mr_iy(reg *r); byte mr_rel(reg* r); void execute(); void decode_exec(byte, reg*); //INSTRUCTION FUNCTIONS void and_im(reg *r); void and_zp(reg *r); void and_zp_x(reg* r); void and_abs(reg *r); void and_abs_x(reg *r); void and_abs_y(reg *r); void and_ix(reg *r); void and_iy(reg *r); void asl_a(reg* r); void asl_zp(reg* r); void asl_zp_x(reg* r); void asl_abs(reg* r); void asl_abs_x(reg* r); void bcc(reg* r); void bcs(reg* r); void beq(reg* r); void bmi(reg* r); void bne(reg* r); void bpl(reg* r); void brk(reg* r); void bvc(reg* r); void bvs(reg* r); void clc(reg* r); void cld(reg* r); void cli(reg* r); void clv(reg* r); void cmp_im(reg* r); void cmp_zp(reg* r); void sec(reg *r); void sed(reg *r); void sei(reg *r); void sta_zp(reg *r); void sta_zp_x(reg *r); void sta_abs(reg *r); void sta_abs_x(reg *r); void sta_abs_y(reg *r); void sta_ix(reg *r); void sta_iy(reg *r); void stx_zp(reg* r); void stx_zp_y(reg *r); void stx_abs(reg* r); void sty_zp(reg* r); void sty_zp_x(reg* r); void sty_abs(reg* r); void tax(reg* r); void tay(reg* r); void tsx(reg* r); void txa(reg* r); void txs(reg* r); void tya(reg* r); #endif
main.cCode:#include "6502.h" extern byte Memory[0x10000]; void execute(){ byte opcode; reg r; r.s = 0x01FF; for(;;){ opcode = m_read(r.pc.w++); decode_exec(opcode,&r); } } byte m_read(word addr){ return Memory[addr]; } void m_write(word addr, byte value){ Memory[addr] = value; } void decode_exec(byte opcode, reg* r){ switch(opcode){ case 0x69: /**ADC IMMEDIATE **/ case 0x65: /**ADC ZERO PAGE **/ case 0x75: /**ADC ZERO PAGE X**/ case 0x6D: /**ADC ABSOLUTE **/ case 0x7D: /**ADC ABSOLUTE X **/ case 0x79: /**ADC ABSOLUTE Y **/ case 0x61: /**ADC INDIRECT X **/ case 0x71: /**ADC INDIRECT Y **/ case 0x29: and_im(r); break; /**AND IMMEDIATE **/ case 0x25: and_zp(r); break; /**AND ZERO PAGE **/ case 0x35: and_zp_x(r); break;/**AND ZERO PAGE X**/ case 0x2D: and_abs(r); break;/**AND ABSOLUTE **/ case 0x3D: and_abs_x(r); break; /**AND ABSOLUTE X **/ case 0x39: and_abs_y(r); break;/**AND ASOLUTE Y **/ case 0x21: and_ix(r); break;/**AND INDIRECT X **/ case 0x31: and_iy(r); break;/**AND INDIRECT Y **/ case 0x0A: asl_a(r); break; /**ASL ACCUMULATOR**/ case 0x06: asl_zp(r); break;/**ASL ZERO PAGE **/ case 0x16: asl_zp_x(r); break;/**ASL ZERO PAGE X**/ case 0x0E: asl_abs(r); break;/**ABSOLUTE **/ case 0x1E: asl_abs_x(r); break;/**ABSOLUTE X **//**asl()**/ case 0x90: bcc(r); break;/**BCC RELATIVE **//**bcc(&CPU, RAM, data);**/ case 0xB0: bcs(r); break;/**BCS RELATIVE **//**bcs(&CPU, RAM, data);**/ case 0xF0: beq(r); break;/**BEQ RELATIVE **//**beq(&CPU, RAM, data);**/ case 0x30: bmi(r); break;/**BMI RELATIVE **//**bmi();**/ case 0xD0: bne(r); break;/**BNE RELATIVE **//**bne();**/ case 0x10: bpl(r); break;/**BPL RELATIVE **//**bpl();**/ case 0x00: brk(r); break;/**BRK IMPLIED **//**brk();**/ case 0x50: bvc(r); break;/**BVC RELATIVE **//**bvc();**/ case 0x70: bvs(r); break;/**BVS RELATIVE **//**bvs();**/ case 0x24: /**BIT ZERO PAGE **/ case 0x2C: /**BIT ABSOLUTE **//**bit();**/ case 0x18: clc(r); break;/**CLC IMPLIED **//**clc();**/ case 0xD8: cld(r); break;/**CLD IMPLIED **//**cld();**/ case 0x58: cli(r); break;/**CLI IMPLIED **//**cli();**/ case 0xB8: clv(r); break;/**CLV IMPLIED **//**clv();**/ case 0xC9: cmp_im(r); break;/**CMP IMMEDIATE **/ case 0xC5: cmp_zp(r); break;/**ZERO PAGE **/ case 0xD5: /**ZERO PAGE X **/ case 0xCD: /**ABSOLUTE **/ case 0xDD: /**ABSOLUTE X **/ case 0xD9: /**ABSOLUTE Y **/ case 0xC1: /**INDIRECT X **/ case 0xD1: /**INDIRECT Y **//**cmp();**/ case 0xE0: /**CPX IMMEDIATE **/ case 0xE4: /**ZERO PAGE **/ case 0xEC: /**ABSOLUTE **//**cpx();**/ case 0xC0: /**CPY IMMEDIATE **/ case 0xC4: /**ZERO PAGE **/ case 0xCC: /**ABSOLUTE **//**cpy();**/ case 0xC6: /**DEC ZERO PAGE **/ case 0xD6: /**ZERO PAGE X **/ case 0xCE: /**ABSOLUTE **/ case 0xDE: /**ABSOLUTE X **//**dec();**/ case 0xCA: /**DEX IMPLIED **//**dex();**/ case 0x88: /**DEY IMPLIED **//**dey();**/ case 0x49: /**EOR IMMEDIATE **/ case 0x45: /**ZERO PAGE **/ case 0x55: /**ZERO PAGE X **/ case 0x4D: /**ABSOLUTE **/ case 0x5D: /**ABSOLUTE X **/ case 0x59: /**ABSOLUTE Y **/ case 0x41: /**INDIRECT X **/ case 0x51: /**INDIRECT Y **//**eor();**/ case 0xE6: /**INC ZERO PAGE **/ case 0xF6: /**ZERO PAGE X **/ case 0xEE: /**ABSOLUTE **/ case 0xFE: /**ABSOLUTE X **//**inc();**/ case 0xE8: /**INX IMPLIED **//**inx();**/ case 0xC8: /**INY IMPLIED **//**iny();**/ case 0x4C: /**JMP ABSOLUTE **/ case 0x6C: /**INDIRECT **//**jmp();**/ case 0x20: /**JRS ABSOLUTE **//**jsr();**/ case 0xA9: /**LDA IMMEDIATE **/ case 0xA5: /**ZERO PAGE **/ case 0xB5: /**ZERO PAGE X **/ case 0xAD: /**ABSOLUTE **/ case 0xBD: /**ABSOLUTE X **/ case 0xB9: /**ABSOLUTE Y **/ case 0xA1: /**INDIRECT X **/ case 0xB1: /**INDIRECT Y **//**lda();**/ case 0xA2: /**LDX IMMEDIATE **/ case 0xA6: /**ZERO PAGE **/ case 0xB6: /**ZERO PAGE Y **/ case 0xAE: /**ABSOLUTE **/ case 0xBE: /**ABSOLUTE Y **//**ldx();**/ case 0xA0: /**LDY IMMEDIATE **/ case 0xA4: /**ZERO PAGE **/ case 0xB4: /**ZERO PAGE X **/ case 0xAC: /**ABSOLUTE **/ case 0xBC: /**ABSOLUTE X **//**ldy();**/ case 0x4A: /**LSR ACCUMULATOR**/ case 0x46: /**ZERO PAGE **/ case 0x56: /**ZERO PAGE X **/ case 0x4E: /**ABSOLUTE **/ case 0X5E: /**ABSOLUTE X **//**lsr();**/ case 0xEA: /**NOP **//**nop();**/ case 0x09: /**ORA IMMEDIATE **/ case 0x05: /**ZERO PAGE **/ case 0x15: /**ZERO PAGE X **/ case 0x0D: /**ABSOLUTE **/ case 0x1D: /**ABSOLUTE X **/ case 0x19: /**ABSOLUTE Y **/ case 0x01: /**INDIRECT X **/ case 0x11: /**INDIRECT Y **//**ora();**/ case 0x48: /**PHA IMPLIED **//**pha();**/ case 0x08: /**PHP IMPLIED **//**php();**/ case 0x68: /**PLA IMPLIED **//**pla();**/ case 0x28: /**PLP IMPLIED **//**plp();**/ case 0x2A: /**ROL ACCUMULATOR**/ case 0x26: /**ZERO PAGE **/ case 0x36: /**ZERO PAGE X **/ case 0x2E: /**ABSOLUTE **/ case 0x3E: /**ABSOLUTE X **//**rol();**/ case 0x6A: /**ROR ACCUMULATOR**/ case 0x66: /**ZERO PAGE **/ case 0x76: /**ZERO PAGE X **/ case 0x6E: /**ABSOLUTE **/ case 0x7E: /**ABSOLUTE X **//**ror();**/ case 0x40: /**RTI IMPLIED **//**rti();**/ case 0x60: /**RTS IMPLIED **//**rts();**/ case 0xE9: /**SBC IMMEDIATE **/ case 0xE5: /**ZERO PAGE **/ case 0xF5: /**ZERO PAGE X **/ case 0xED: /**ABSOLUTE **/ case 0xFD: /**ABSOLUTE X **/ case 0xF9: /**ABSOLUTE Y **/ case 0xE1: /**INDIRECT X **/ case 0xF1: /**INDIRECT Y **//**sbc();**/ case 0x38: sec(r); break;/**SEC IMPLIED **//**sec();**/ case 0xF8: sed(r); break; /**SED IMPLIED **//**sed();**/ case 0x78: sei(r); break;/**SEI IMPLIED **//**sei();**/ case 0x85: sta_zp(r); break;/**STA ZERO PAGE **/ case 0x95: sta_zp_x(r); break;/**ZERO PAGE X **/ case 0x8D: sta_abs(r); break;/**ABSOLUTE **/ case 0x9D: sta_abs_x(r); break;/**ABSOLUTE X **/ case 0x99: sta_abs_y(r); break;/**ABSOLUTE Y **/ case 0x81: sta_ix(r); break;/**INDIRECT X **/ case 0x91: sta_iy(r); break;/**INDIRECT Y **//**sta();**/ case 0x86: stx_zp(r); break; /**STX ZERO PAGE **/ case 0x96: stx_zp_y(r); break;/**ZERO PAGE Y **/ case 0x8E: stx_abs(r); break;/**ABSOLUTE **//**stx();**/ case 0x84: sty_zp(r); break; /**STY ZERO PAGE **/ case 0x94: sty_zp_x(r); break; /**ZERO PAGE X **/ case 0X8C: sty_abs(r); break; /**ABSOLUTE **//**sty();**/ case 0xAA: tax(r); break; /**TAX IMPLIED **//**tax();**/ case 0xA8: tay(r); break; /**TAY IMPLIED **//**tay():**/ case 0xBA: tsx(r); break; /**TSX IMPLIED **//**tsx();**/ case 0x8A: txa(r); break; /**TXA IMPLIED **//**txa();**/ case 0x9A: txs(r); break; /**TXS IMPLIED **//**txs();**/ case 0x98: tya(r); break; /**TYA IMPLIED **//**tya();**/ default:break; /**bad op **/ } } void set_flag(reg *r, int FLAG){ r->p |= FLAG; } void clr_flag(reg *r, int FLAG){ r->p &= ~FLAG; } bool chk_flag(const reg *r, int FLAG){ return (r->p & FLAG) != 0; } word mc_abs(reg *r){ pair addr; addr.b[1] = m_read(r->pc.w++); addr.b[0] = m_read(r->pc.w++); return addr.w; } byte mr_abs(reg *r){ return m_read(mc_abs(r)); }; void mw_abs(reg* r){ m_write(mc_abs(r), m_read(r->pc.w++)); } word mc_abs_x(reg *r){ pair addr; addr.b[1] = m_read(r->pc.w++); addr.b[0] = m_read(r->pc.w++); addr.w += r->x; addr.w = m_read(addr.w); return addr.w; } byte mr_abs_x(reg *r){ return m_read(mc_abs_x(r)); } void mw_abs_x(reg *r){ m_write(mc_abs_x(r), m_read(r->pc.w++)); } word mc_abs_y(reg *r){ pair addr; addr.b[1] = m_read(r->pc.w++); addr.b[0] = m_read(r->pc.w++); addr.w += r->y; addr.w = m_read(addr.w); return addr.w; } byte mr_abs_y(reg *r){ return m_read(mc_abs_y(r)); } void mw_abs_y(reg *r){ m_write(mc_abs_y(r), m_read(r->pc.w++)); } byte mc_zp(reg *r){ return m_read(r->pc.w++); } byte mr_zp(reg *r){ return m_read(mc_zp(r)); } void mw_zp(reg* r){ m_write(mc_zp(r), m_read(r->pc.w++)); } byte mc_zp_x(reg *r){ return (byte)m_read(r->pc.w++) + r->x; } void mw_zp_x(reg* r){ m_write(mc_zp_x(r), m_read(r->pc.w++)); } byte mr_zp_x(reg *r){ return m_read(mc_zp_x(r)); } byte mc_zp_y(reg *r){ return (byte)m_read(r->pc.w++) + r->y; } void mw_zp_y(reg* r){ m_write(mc_zp_y(r), m_read(r->pc.w++)); } byte mr_zp_y(reg *r){ return m_read(mc_zp_y(r)); } byte mc_im(reg *r){ return m_read(r->pc.w++); } void mw_im(reg *r){ m_write(mc_im(r), m_read(r->pc.w++)); } byte mr_im(reg* r){ return m_read(r->pc.w++); } word mc_ix(reg *r){ pair addr, ix_addr; addr.b[1] = m_read(r->pc.w++) + r->x; ix_addr.b[1] = m_read(addr.w++); ix_addr.b[0] = m_read(addr.w); return ix_addr.w; } void mw_ix(reg* r){ m_write(mc_ix(r), m_read(r->pc.w++)); } byte mr_ix(reg *r){ return m_read(mc_ix(r)); } word mc_iy(reg *r){ pair addr, iy_addr; addr.w = m_read(r->pc.w++); iy_addr.b[1] = m_read(addr.w++); iy_addr.b[0] = m_read(addr.w); iy_addr.w += r->y; return iy_addr.w; } void mw_iy(reg* r){ m_write(mc_iy(r), m_read(r->pc.w++)); } byte mr_iy(reg *r){ return m_read(mc_iy(r)); } byte mr_rel(reg* r){ return m_read(mc_rel(r)); } word mc_rel(reg* r){ r->pc.w += m_read(r->pc.w++); return r->pc.w; } void mw_rel(reg* r){ int addr = mc_rel(r); m_write(r->pc.w + addr, Memory[addr]); } void and_im(reg *r){ (r->a &= m_read(r->pc.w++)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_zp(reg *r){ r->a &= m_read(mc_zp(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_zp_x(reg* r){ r->a &= m_read(mc_zp_x(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_abs(reg *r){ r->a &= m_read(mc_abs(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_abs_x(reg *r){ r->a &= m_read(mc_abs_x(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_abs_y(reg *r){ r->a &= m_read(mc_abs_y(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_ix(reg *r){ r->a &= m_read(mc_ix(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void and_iy(reg *r){ r->a &= m_read(mc_iy(r)); if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void asl_a(reg* r){ /** NEED TO IMPLEMENT C_FLAG AND N_FLAG SET **/ /** FOR ALL ASL FUNCTIONS **/ r->a <<= 1; } void asl_zp(reg* r){ int addr = mc_zp(r); m_write(addr, Memory[addr] << 1); } void asl_zp_x(reg* r){ int addr = mc_zp_x(r); m_write(addr, Memory[addr] << 1); } void asl_abs(reg* r){ int addr = mc_abs(r); m_write(addr, Memory[addr] << 1); } void asl_abs_x(reg* r){ int addr = mc_abs_x(r); m_write(addr, Memory[addr] << 1); } void bcc(reg* r){ if(!chk_flag(r, C_FLAG)) mc_rel(r); } void bcs(reg* r){ if(chk_flag(r, C_FLAG)) mc_rel(r); } void beq(reg* r){ if(chk_flag(r, Z_FLAG)) mc_rel(r); } void bmi(reg* r){ if(chk_flag(r, N_FLAG)) mc_rel(r); } void bne(reg* r){ if(!chk_flag(r, Z_FLAG)) mc_rel(r); } void bpl(reg* r){ if(!chk_flag(r, N_FLAG)) mc_rel(r); } void brk(reg* r){ /** NEEDS TO BE IMPLEMENTED **/ } void bvc(reg* r){ if(!chk_flag(r, V_FLAG)) mc_rel(r); } void bvs(reg* r){ if(chk_flag(r, V_FLAG)) mc_rel(r); } void clc(reg* r){clr_flag(r, C_FLAG);} void cld(reg* r){clr_flag(r, D_FLAG);} void cli(reg* r){clr_flag(r, I_FLAG);} void clv(reg* r){clr_flag(r, V_FLAG);} void cmp_im(reg* r){ byte rhs = m_read(r->pc.w++); byte value = r->a - rhs; if (r->a > rhs) set_flag(r, C_FLAG); if ((value & 0x80) == 1) set_flag(r, N_FLAG); if (value == 0) set_flag(r, Z_FLAG); } void cmp_zp(reg* r){ } void sec(reg *r){set_flag(r, C_FLAG);} void sed(reg *r){set_flag(r, D_FLAG);} void sei(reg *r){set_flag(r, I_FLAG);} void sta_zp(reg *r){m_write(mc_zp(r), r->a);} void sta_zp_x(reg *r){m_write(mc_zp_x(r), r->a);} void sta_abs(reg *r){m_write(mc_abs(r), r->a);} void sta_abs_x(reg *r){m_write(mc_abs_x(r), r->a);} void sta_abs_y(reg *r){m_write(mc_abs_y(r), r->a);} void sta_ix(reg *r){m_write(mc_ix(r), r->a);} void sta_iy(reg *r){m_write(mc_iy(r), r->a);} void stx_zp(reg* r){m_write(mc_zp(r), r->x);} void stx_zp_y(reg* r){m_write(mc_zp_y(r),r->x);} void stx_abs(reg* r){m_write(mc_abs(r), r->x);} void sty_zp(reg* r){mw_zp(r);} void sty_zp_x(reg* r){mw_zp_x(r);} void sty_abs(reg* r){mw_abs(r);} void tax(reg *r){ r->x = r->a; if(r->x) set_flag(r, Z_FLAG); if((r->x & 0x80) == 1) set_flag(r, N_FLAG); } void tay(reg *r){ r->y = r->a; if(r->y) set_flag(r, Z_FLAG); if((r->y & 0x80) == 1) set_flag(r, N_FLAG); } void tsx(reg *r){ r->x = r->s; if(r->x) set_flag(r, Z_FLAG); if((r->x & 0x80) == 1) set_flag(r, N_FLAG); } void txa(reg *r){ r->a = r->x; if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); } void txs(reg *r){ r->s = r->x; } void tya(reg *r){ r->a = r->y; if(r->a) set_flag(r, Z_FLAG); if((r->a & 0x80) == 1) set_flag(r, N_FLAG); }
Code:#include "6502.h" byte Memory[0x10000]; int main(int argc, char *argv[]){ execute(); return 0; }