Thread: Working on a 6502. Could you tell me if this is efficient?

  1. #1
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266

    Working on a 6502. Could you tell me if this is efficient?

    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
    Code:
    #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
    6502.c
    Code:
    #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);
    }
    main.c
    Code:
    #include "6502.h"
    
    byte Memory[0x10000];
    
    int main(int argc, char *argv[]){
    
        execute();
    
        return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    If all your functions have the same prototype, then you could use a jump table

    Code:
    typedef void (*fn)(reg *);
    fn table[256] = {
        // obviously populated with the right function in the right place!
        and_im,
        and_zp,
    };
    Calling it is a snap, with
    Code:
        for(;;){
            opcode = m_read(r.pc.w++);
            table[opcode](&r);
        }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    Quote Originally Posted by Salem View Post
    If all your functions have the same prototype, then you could use a jump table

    Code:
    typedef void (*fn)(reg *);
    fn table[256] = {
        // obviously populated with the right function in the right place!
        and_im,
        and_zp,
    };
    Calling it is a snap, with
    Code:
        for(;;){
            opcode = m_read(r.pc.w++);
            table[opcode](&r);
        }
    You mean create a table with the elements containing function poiners? All of the opcode functions return void and they all take "reg*" as the only argument. I was tempted to make that global because of this. That is a lot of revision to do but I just might do it. Also, doesn't the compiler optimize this kind of code automatically(large switch statements)?

  4. #4
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Yes, large switch statements with continuous values will probably be optimized to a jump table.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Whilst one might expect (and many compilers do) collapse to a simple jump table, there is no guarantee that this would happen.

    2. A jump table (as posted) is considerably less code space than a big switch (every call needs parameters, a case label and a break).

    3. If you start dealing with the variants, then patching the table to point to the bug-fixed instructions is something you can easily do at run-time.

    4. Not all 256 instructions did anything useful. On the original, nearly all the undocumented opcodes did something, Some s/w protection mechanisms deliberately used these to hamper would-be hackers.
    On the 65C02, all the undocumented opcodes are NOP as I recall.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    Quote Originally Posted by Salem View Post
    Whilst one might expect (and many compilers do) collapse to a simple jump table, there is no guarantee that this would happen.

    2. A jump table (as posted) is considerably less code space than a big switch (every call needs parameters, a case label and a break).

    3. If you start dealing with the variants, then patching the table to point to the bug-fixed instructions is something you can easily do at run-time.

    4. Not all 256 instructions did anything useful. On the original, nearly all the undocumented opcodes did something, Some s/w protection mechanisms deliberately used these to hamper would-be hackers.
    On the 65C02, all the undocumented opcodes are NOP as I recall.
    And how exactly would I place these functions into the right place in the table. That would seem to take a lot of time too

    would it be:
    Code:
    fn Table[256];
    Table[opcode] = void (*func_ptr)(reg*);
    where "func_ptr" equals the name of the function. Would I need to do this for every single one?

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You're worried about efficiency while emulating a chip that is about 5000 times slower than a modern CPU? You're just going to have to slow things down anyway the first time you run a piece of 6502 code that depends on the chip being slow enough...
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by Syscal View Post
    And how exactly would I place these functions into the right place in the table. That would seem to take a lot of time too
    It'd, but the final size of the object module would be much less than having 256 case labels.
    Quote Originally Posted by Syscal View Post
    would it be:
    Code:
    fn Table[256];
    Table[opcode] = void (*func_ptr)(reg*);
    Or something along those lines, where the opcode indexes into the jump table.
    Quote Originally Posted by Syscal View Post
    where "func_ptr" equals the name of the function. Would I need to do this for every single one?
    Yep!

  9. #9
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    Quote Originally Posted by Salem View Post
    Calling it is a snap, with
    Code:
            table[opcode](&r);

    I guess I learn something new everyday. I've never seen that syntax before. I was surprised to see it compile. I guess it makes since. Function pointers used to be icky stuff for me.

  10. #10
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    So I'm working on the jump table and it seems to be taking a long time to create. Just to be sure I am not wasting all of this time. I have placed about 1/4th of the pointers in the table. Is this the general idea?:

    Code:
    typedef void (*func)(reg*);
    func Table[256] = {
        &brk,NULL,NULL,NULL,NULL,&asl_zp,NULL,NULL,NULL,NULL,&asl_a,NULL,NULL,NULL,&asl_abs,NULL, //0   - 15
        &bpl,NULL,NULL,NULL,NULL,NULL,&asl_zp_x,NULL,&clc,NULL,NULL,NULL,NULL,NULL,&asl_abs_x,NULL, //16  - 31
        NULL,&and_ix,NULL,NULL,&bit_zp,&and_zp,NULL,NULL,NULL,NULL,&and_im,NULL,&bit_abs,&and_abs,NULL,NULL, //32  - 47 
        &bmi,&and_iy,NULL,NULL,NULL,&and_zp_x,NULL,NULL,NULL,&and_abs_y,NULL,NULL,NULL,&and_abs_x,NULL,NULL, //48  - 63
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //64  - 79
        &bvc,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&cli,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //80  - 95
        NULL,&adc_ix,NULL,NULL,NULL,&adc_zp,NULL,NULL,NULL,&adc_im,NULL,NULL,NULL,&adc_abs,NULL,NULL, //96  - 111
        &bvs,&adc_iy,NULL,NULL,NULL,&adc_zp_x,NULL,NULL,NULL,&adc_abs_y,NULL,NULL,NULL,&adc_abs_x,NULL,NULL, //112 - 127
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&dey,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //128 - 143
        &bcc,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //144 - 159
        NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //160 - 175
        &bcs,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&clv,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //176 - 191
        &cpy_im,&cmp_ix,NULL,NULL,&cpy_zp,&cmp_zp,&dec_zp,NULL,NULL,&cmp_im,&dex,NULL,&cpy_abs,&cmp_abs,&dec_abs,NULL, //192 - 207
        &bne,&cmp_iy,NULL,NULL,NULL,&cmp_zp_x,&dec_zp_x,NULL,&cld,&cmp_abs_y,NULL,NULL,NULL,&cmp_abs_x,&dec_abs_x,NULL, //208 - 223
        &cpx_im,NULL,NULL,NULL,&cpx_zp,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&cpx_abs,NULL,NULL,NULL, //224 - 239
        &beq,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, //240 - 255
    };

  11. #11
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    If most opcodes are unused, you could do something like.
    Code:
    func Table[256] = { 0 };
    
    Table[0x0] = &brk;
    Table[0x5] = &asl; 
    ...
    etc. So you won't have so many NULLs.

  12. #12
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    Quote Originally Posted by cyberfish View Post
    If most opcodes are unused, you could do something like.
    Code:
    func Table[256] = { 0 };
    
    Table[0x0] = &brk;
    Table[0x5] = &asl; 
    ...
    etc. So you won't have so many NULLs.
    I'm steadily populating the table. There are a lot more to add. Wayy more. Could what NULLs are left be switch to some sort of NOP opcode ptr?

  13. #13
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    That would be a good idea I think.

    This way you can have a handler for illegal instructions.

  14. #14
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    My completed jump table:
    Code:
    #include "6502.h"
    
    typedef void (*func)(reg*);
    
    func Table[256] = {
        &brk,&ora_ix,&nop,&nop,&nop,&ora_zp,&asl_zp,&nop,&php,&ora_im,&asl_a,&nop,&nop,&ora_abs,&asl_abs,&nop, //0   - 15
        &bpl,&ora_iy,&nop,&nop,&nop,&ora_zp_x,&asl_zp_x,&nop,&clc,&ora_abs_y,&nop,&nop,&nop,&ora_abs_x,&asl_abs_x,&nop, //16  - 31
        &jsr,&and_ix,&nop,&nop,&bit_zp,&and_zp,&rol_zp,&nop,&plp,&nop,&and_im,&rol_a,&bit_abs,&and_abs,&rol_abs,&nop, //32  - 47
        &bmi,&and_iy,&nop,&nop,&nop,&and_zp_x,&rol_zp_x,&nop,&sec,&and_abs_y,&nop,&nop,&nop,&and_abs_x,&rol_abs_x,&nop, //48  - 63
        &rti,&eor_ix,&nop,&nop,&nop,&eor_zp,&lsr_zp,&nop,&pha,&eor_im,&lsr_a,&nop,&jmp_abs,&eor_abs,&lsr_abs,&nop, //64  - 79
        &bvc,&eor_iy,&nop,&nop,&nop,&eor_zp_x,&lsr_zp_x,&nop,&cli,&eor_abs_y,&nop,&nop,&nop,&eor_abs_x,&lsr_abs_x,&nop, //80  - 95
        &rts,&adc_ix,&nop,&nop,&nop,&adc_zp,&ror_zp,&nop,&pla,&adc_im,&ror_a,&nop,&jmp_ind,&adc_abs,&ror_abs,&nop, //96  - 111
        &bvs,&adc_iy,&nop,&nop,&nop,&adc_zp_x,ror_zp_x,&nop,&sei,&adc_abs_y,&nop,&nop,&nop,&adc_abs_x,&ror_abs_x,&nop, //112 - 127
        &nop,&sta_ix,&nop,&nop,&sty_zp,&sta_zp,&stx_zp,&nop,&dey,&nop,&txa,&nop,&sty_abs,&sta_abs,&stx_abs,&nop, //128 - 143
        &bcc,&sta_iy,&nop,&nop,&sty_zp_x,&sta_zp_x,&stx_zp_y,&nop,&tya,&sta_abs_y,&txs,&nop,&nop,&sta_abs_x,&nop,&nop, //144 - 159
        &ldy_im,&lda_ix,&ldx_im,&nop,&ldy_zp,&lda_zp,&ldx_zp,&nop,&tay,&lda_im,&tax,&nop,&ldy_abs,&lda_abs,&ldx_abs,&nop, //160 - 175
        &bcs,&lda_iy,&nop,&nop,&ldy_zp_x,&lda_zp_x,&ldx_zp_y,&nop,&clv,&lda_abs_y,&tsx,&nop,&ldy_abs_x,&lda_abs_x,&ldx_abs_y,&nop, //176 - 191
        &cpy_im,&cmp_ix,&nop,&nop,&cpy_zp,&cmp_zp,&dec_zp,&nop,&iny,&cmp_im,&dex,&nop,&cpy_abs,&cmp_abs,&dec_abs,&nop, //192 - 207
        &bne,&cmp_iy,&nop,&nop,&nop,&cmp_zp_x,&dec_zp_x,&nop,&cld,&cmp_abs_y,&nop,&nop,&nop,&cmp_abs_x,&dec_abs_x,&nop, //208 - 223
        &cpx_im,&sbc_ix,&nop,&nop,&cpx_zp,&sbc_zp,&inc_zp,&nop,&inx,&sbc_im,&nop,&nop,&cpx_abs,&sbc_abs,&inc_abs,&nop, //224 - 239
        &beq,&sbc_iy,&nop,&nop,&nop,&sbc_zp_x,&inc_zp_x,&nop,&sed,&sbc_abs_y,&nop,&nop,&nop,&sbc_abs_x,&inc_abs_x,&nop, //240 - 255
    };

  15. #15
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    So I began looking over my code, and I wrote this very simple little function that extracts the addressing mode. This would greatly reduce the amount of functions that I currently have. Is this a practical method for extracting addressing modes? I feel like a newbie, but I am trying to do this all on my own, aside from 6502 documentation that I must consult.


    I only have the printf statements in the cases for proof that it works. I'm really thinking about adding this in and getting the data that way. I would eliminate about 60 functions.
    Code:
    #include <stdio.h>
    
    typedef unsigned char byte;
    
    void getAddrMode(byte opcode){
        switch(opcode & 0x3){
            case 0x00:
                switch((opcode >> 2) & 0x7){
                    case 0x00:printf("Immediate \n"); break;
                    case 0x01:printf("Zero Page \n"); break;
                    case 0x03:printf("Absolute \n"); break;
                    case 0x05:printf("Zero Page X \n"); break;
                    case 0x07:printf("Absolute X \n"); break;
                }
                break;
            case 0x01:
                switch((opcode >> 2) & 0x7){
                    case 0x00:printf("Zero Page X \n"); break;
                    case 0x01:printf("Zero Page \n"); break;
                    case 0x02:printf("Immediate \n"); break;
                    case 0x03:printf("Absolute \n"); break;
                    case 0x04:printf("Zero Page Y \n"); break;
                    case 0x05:printf("Zero Page X \n"); break;
                    case 0x06:printf("Absolute Y \n"); break;
                    case 0x07:printf("Absolute X \n"); break;
                }
                break;
            case 0x02:
                switch((opcode >> 2) & 0x7){
                    case 0x00:printf("Immediate \n"); break;
                    case 0x01:printf("Zero Page \n"); break;
                    case 0x02:printf("Accumulator \n"); break;
                    case 0x03:printf("Absolute \n"); break;
                    case 0x05:printf("Zero Page X \n"); break;
                    case 0x07:printf("Absolute X \n"); break;
                }
                break;
        }
    }
    
    int main(){
    
        byte opcode = 1;
    
        while(opcode){
            scanf("%x",&opcode);
            getAddrMode(opcode);
        }
    
        return 0;
    }

    There woudn't be a need for a whole function for each addr_mode to function.

    so instead of
    Code:
    void adc_im(reg* r);
    void adc_abs(reg* r);
    void adc_zp(reg* r);
    ...
    I could just do:

    Code:
    typedef unsigned char byte;
    
    void adc(reg* r, byte data); 
    
    main...
    
    byte data, addr_mode;
    
    addr_mode = getAddrMode(opcode);
    data = getData(addr_mode);
    
    adc(&r, data);
    Only one adc( ) function is needed this way. And that would go for every opcode.
    Last edited by Syscal; 08-29-2010 at 10:58 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Program Not working Right
    By raven420smoke in forum C++ Programming
    Replies: 2
    Last Post: 09-16-2005, 03:21 AM
  2. Trying to eject D drive using code, but not working... :(
    By snowfrog in forum C++ Programming
    Replies: 3
    Last Post: 05-07-2005, 07:47 PM
  3. Animation class not working
    By VirtualAce in forum Game Programming
    Replies: 5
    Last Post: 03-02-2005, 06:48 AM
  4. x on upper right corner not working
    By caduardo21 in forum Windows Programming
    Replies: 1
    Last Post: 02-20-2005, 08:35 PM
  5. cygwin -> unix , my code not working properly ;(
    By CyC|OpS in forum C Programming
    Replies: 4
    Last Post: 05-18-2002, 04:08 AM