The core of processor, this file contains instruction decoder and memory structure. Before use, call Reset() to set correct values of registers. Execution of one instruction is done by calling InstrStep().
Known bugs:
Definition in file cpu.c.#include "cpu.h"
Go to the source code of this file.
Flags | |
#define | FN 0x80 |
#define | FV 0x40 |
#define | FB 0x10 |
#define | FD 0x08 |
#define | FI 0x04 |
#define | FZ 0x02 |
#define | FC 0x01 |
Adresses | |
#define | RESETVKT 0xFFFC |
#define | IRQVKT 0xFFFE |
#define | NMIVKT 0xFFFA |
Flag handling defines | |
#define | GETFLAG(X) ((regs.P & (X))!=0) |
#define | SETFLAG(X) regs.P=((regs.P) | (X)) |
#define | CLFLAG(X) (regs.P=regs.P & (~(X))) |
#define | FLAG(BL, FL) if (BL) SETFLAG(FL); else CLFLAG(FL) |
#define | SETNZFLAGS(X) FLAG((X) & 0x80, FN); FLAG(!(X), FZ) |
Other defines | |
#define | ADR(X, Y) (((Y) << PAGESIZE)+(X)) |
#define | M2PC(X) regs.PC=((*memgetb)((X) + 1) << PAGESIZE) + (*memgetb)(X) |
#define | HI(X) ((unsigned char) (((X) >> PAGESIZE) & 0xFF)) |
#define | LO(X) ((unsigned char) ((X) & 0xFF)) |
#define | PCSTEP(X) regs.PC+=(X) |
#define | HEX2DEC(X) ((((X)>>4) & 0x0F)*10 + ((X) & 0x0F)) |
#define | DEC2HEX(X) (((((X)/10) % 10)<<4) + (X) % 10) |
Stack handling defines | |
#define | STACKADD(X) (*memsetb)(regs.S, (X)); regs.S--; if (regs.S<0x100) regs.S=0x1FF |
#define | STACKREMOVE(X) regs.S++; if (regs.S>0x1FF) regs.S=0x100; X=(*memgetb)(regs.S) |
Cycle consumption defines. | |
#define | CONSUME(X) cycles += X |
#define | CONSREL if ((oldpc & 0xFF00) != (regs.PC & 0xFF00)) CONSUME(1) |
#define | CONSABSX |
#define | CONSABSY |
#define | CONSINDY |
Memory reading/writing macros - according to adressing mode | |
#define | IMM regs.PC+1 |
#define | ZP (*memgetb)(regs.PC+1)&0xFF |
#define | ZPX ((*memgetb)(regs.PC+1)+regs.X)&0xFF |
#define | ZPY ((*memgetb)(regs.PC+1)+regs.Y)&0xFF |
#define | ABS ADR((*memgetb)(regs.PC+1), (*memgetb)(regs.PC+2)) |
#define | ABSX ADR((*memgetb)(regs.PC+1), (*memgetb)(regs.PC+2))+regs.X |
#define | ABSY ADR((*memgetb)(regs.PC+1), (*memgetb)(regs.PC+2))+regs.Y |
#define | INDX ADR((*memgetb)(((*memgetb)(regs.PC+1)+regs.X) & 0xFF), (*memgetb)(((*memgetb)(regs.PC+1)+regs.X+1) & 0xFF)) |
#define | INDY ADR((*memgetb)((*memgetb)(regs.PC+1)), (*memgetb)(((*memgetb)(regs.PC+1)+1)) & 0xFF) + regs.Y |
#define | REL regs.PC+1 |
#define | JMPADR ADR((*memgetb)(regs.PC+1), (*memgetb)(regs.PC+2)) |
Instruction defs | |
#define | ADC(MEMREAD, STEP) |
#define | AND(MEMREAD, STEP) |
#define | ASL(MEMREAD, STEP) |
#define | ASLA |
#define | BCC(MEMREAD, STEP) |
#define | BCS(MEMREAD, STEP) |
#define | BEQ(MEMREAD, STEP) |
#define | BNE(MEMREAD, STEP) |
#define | BMI(MEMREAD, STEP) |
#define | BPL(MEMREAD, STEP) |
#define | BVC(MEMREAD, STEP) |
#define | BVS(MEMREAD, STEP) |
#define | BIT(MEMREAD, STEP) |
#define | BRK |
#define | CLC |
#define | CLD |
#define | CLI |
#define | CLV |
#define | CMP(MEMREAD, STEP) |
#define | CPX(MEMREAD, STEP) |
#define | CPY(MEMREAD, STEP) |
#define | DEC(MEMREAD, STEP) |
#define | DEX |
#define | DEY |
#define | EOR(MEMREAD, STEP) |
#define | INC(MEMREAD, STEP) |
#define | INX |
#define | INY |
#define | JMP(MEMREAD) regs.PC=MEMREAD |
#define | JMPIND |
#define | JSR(MEMREAD) |
#define | LDA(MEMREAD, STEP) |
#define | LDX(MEMREAD, STEP) |
#define | LDY(MEMREAD, STEP) |
#define | LSR(MEMREAD, STEP) |
#define | LSRA |
#define | NOP PCSTEP(1) |
#define | ORA(MEMREAD, STEP) |
#define | PHA |
#define | PHP |
#define | PLA |
#define | PLP |
#define | ROL(MEMREAD, STEP) |
#define | ROLA |
#define | ROR(MEMREAD, STEP) |
#define | RORA |
#define | RTI |
#define | RTS |
#define | SBC(MEMREAD, STEP) |
#define | SEC |
#define | SED |
#define | SEI |
#define | STA(MEMREAD, STEP) |
#define | STX(MEMREAD, STEP) |
#define | STY(MEMREAD, STEP) |
#define | TAX |
#define | TXA |
#define | TAY |
#define | TYA |
#define | TSX |
#define | TXS |
Defines | |
#define | TRUE 1 |
#define | FALSE 0 |
#define | PAGESIZE 8 |
Functions | |
UINT | InstrStep () |
Executes one instruction on adress stored in regs.PC. | |
Regs * | GetRegs () |
void | SetRegs (Regs r) |
void | Reset () |
Reset interrupt. | |
void | Irq () |
IRQ interrupt. | |
void | Nmi () |
NMI interrupt. | |
Variables | |
Regs | regs |
|
Absolute adressing mode |
|
Absolute, X adressing mode |
|
Absolute, Y adressing mode |
|
Value: if (regs.P & FD) { \ tmp=HEX2DEC(regs.A)+HEX2DEC((*memgetb)(MEMREAD))+GETFLAG(FC); \ if( tmp > 99 ) { \ tmp=DEC2HEX(tmp); \ SETFLAG(FC); \ if ((tmp & 0x40)==(regs.A & 0x40)) SETFLAG(FV); \ } \ else { \ tmp=DEC2HEX(tmp); \ if (!(tmp & 0x40) && (regs.A & 0x40)) SETFLAG(FV); \ } \ regs.A=tmp; \ } \ else { \ tmp=regs.A+(*memgetb)(MEMREAD)+GETFLAG(FC); \ if(tmp<regs.A) { \ SETFLAG(FC); \ if ((tmp & 0x40)==(regs.A & 0x40)) SETFLAG(FV); \ } \ else { \ if (!(tmp & 0x40) && (regs.A & 0x40)) SETFLAG(FV); \ } \ regs.A=tmp; \ } \ SETNZFLAGS(regs.A); \ PCSTEP(STEP) |
|
Converts 2 bytes to 16-bit adress |
|
Value: AND: [A] & [M] -> [A], sets NZ |
|
Value: tmp=(*memgetb)(MEMREAD); \ FLAG(FC, tmp & 0x80); \ tmp=(tmp << 1); \ (*memsetb)(MEMREAD, tmp); \ SETNZFLAGS(tmp); \ PCSTEP(STEP) |
|
Value: ASL: [C] <- [A] <- 0, left shift, sets NZ |
|
Value: BCC: relative jump, if [C]=0 |
|
Value: BCS: relative jump, if [C]=1 |
|
Value: BEQ: relative jump, if [Z]=1 |
|
Value: BIT: [A] and [M], [M7] -> [N], [M6] -> [V], result sets [Z] |
|
Value: BMI: relative jump, if [N]=1 |
|
Value: BNE: relative jump, if [Z]=0 |
|
Value: BPL: relative jump, if [N]=0 |
|
Value: BRK: Sw interrupt, 1 -> [B], [PC] -> Stack, [P] -> Stack, 1 -> [I] 0 -> [D] (According to Western Design Center W65C02), IRQVKT -> PC |
|
Value: BVC: relative jump, if [V]=0 |
|
Value: BVS: relative jump, if [V]=1 |
|
Value: CLC: 0 -> [C] |
|
Value: CLD: 0 -> [D] |
|
Sets flag X to 0. Affects P register |
|
Value: CLI: 0 -> [I] |
|
Value: CLV: 0 -> [V] |
|
Value: CMP: [A] - [M], result sets NZC |
|
Value: If page boundary is crossed, add 1 cycle |
|
Value: If page boundary is crossed, add 1 cycle |
|
Value: If page boundary is crossed, add 1 cycle |
|
If branch crosses a page boundary, add 1 cycle |
|
Consume X cycles |
|
Value: CPX: [X] - [M], result sets NZC |
|
Value: CPY: [Y] - [M], result sets NZC |
|
Value: tmp=(*memgetb)(MEMREAD); \ tmp--; \ SETNZFLAGS(tmp); \ (*memsetb)(MEMREAD, tmp); \ PCSTEP(STEP) |
|
Converts number in BCD code to std. decimal. Example> $10 hex -> 10 dec |
|
Value: DEX: [X] -1 -> [X], sets NZ |
|
Value: DEY: [Y] - 1 -> [Y], sets NZ |
|
Value: EOR: [A] xor [M] -> [A], sets NZ |
|
BRK flag |
|
Caryy flag |
|
Decimal flag |
|
Interrupt flag |
|
If condition BL is satisfied, flag FL is set to 1 otherwise 0 |
|
Negative flag |
|
Overflow flag |
|
Zero flag |
|
Gets value of flag X, for conditions |
|
Converts number to BCD. Example: 10 dec -> $10 hex |
|
Higher byte of word |
|
Immediate adressing mode |
|
Value: tmp=(*memgetb)(MEMREAD); \ tmp++; \ SETNZFLAGS(tmp); \ (*memsetb)(MEMREAD, tmp); \ PCSTEP(STEP) |
|
Indirect, X adressing mode |
|
Indirect, Y adressing mode |
|
Value: INX: [X] + 1 -> [X], sets NZ |
|
Value: INY: [Y] + 1 -> [Y], sets NZ |
|
IRQ jumps here |
|
JMP: [M] -> [PC] JMP(..) only for ABSOLUTE adressing! Explanation follows |
|
Used only for jmp, should be absolute |
|
Value: Indirect jump must never use adress beginning on 0xXXFF. if so, jump will be done to adress stored in 0xXXFF and 0xXX00 ! (no page overflow) |
|
Value: JSR: [PC] + 2 - 1 -> Stack, [M] -> PC JSR puts adress of next instruction-1 on the stack (rts adds +1) |
|
Value: LDA: [M] -> [A], sets NZ |
|
Value: LDX: [M] -> [X], sets NZ |
|
Value: LDY: [M] -> [Y], sets NZ |
|
Lower byte of word |
|
Value: tmp=(*memgetb)(MEMREAD); \ FLAG(FC, tmp & 0x01); \ tmp=(tmp >> 1); \ (*memsetb)(MEMREAD, tmp); \ SETNZFLAGS(tmp); \ PCSTEP(STEP) |
|
Value: LSR: 0 -> [A] -> [C], right shift, sets: NZC |
|
Sets PC to 2b adress stored in memory from adress X |
|
NOP: Reserved |
|
Value: ORA: [A] or [M] -> [A], sets NZ |
|
Moves execution point |
|
Value: PHA: A -> Stack |
|
Value: PHP: P -> Stack |
|
Value: STACKREMOVE(regs.A); \ SETNZFLAGS(regs.A); \ PCSTEP(1) |
|
Value: PLP: Stack -> P, sets NVBDIZC |
|
Relative adressing mode |
|
Reset interrupt jumps here |
|
Value: ROL: [C_new] <- [M] <- [C_old], left rotation, sets NZC |
|
Value: ROL: [C_new] <- [A] <- [C_old], left rotation, sets NZC |
|
Value: ROR: [C_old] -> [M] -> [C_new], right rotation, sets NZC |
|
Value: ROR A: [C_old] -> [A] -> [C_new], right rotation, sets NZC |
|
Value: STACKREMOVE(regs.P); \ STACKREMOVE(tmp); \ STACKREMOVE(regs.PC); \ regs.PC=(regs.PC << 8) + tmp |
|
Value: STACKREMOVE(tmp); \ STACKREMOVE(regs.PC); \ regs.PC=(regs.PC << 8) + tmp + 1 |
|
Value: if (regs.P & FD) { \ tmp=HEX2DEC(regs.A)-HEX2DEC((*memgetb)(MEMREAD))- (1-GETFLAG(FC)); \ if(tmp<=99) { \ tmp=DEC2HEX(tmp); \ SETFLAG(FC); \ if ((tmp & 0x40) && !(regs.A & 0x40)) SETFLAG(FV); \ } \ else { \ tmp=tmp-156; \ tmp=DEC2HEX(tmp); \ if ((tmp & 0x40)==(regs.A & 0x40)) SETFLAG(FV); \ } \ regs.A=tmp; \ } \ else { \ tmp=regs.A-(*memgetb)(MEMREAD)-(1-GETFLAG(FC)); \ if(tmp<=regs.A) { \ SETFLAG(FC); \ if ((tmp & 0x40) && !(regs.A & 0x40)) SETFLAG(FV); \ } \ else { \ if ((tmp & 0x40)==(regs.A & 0x40)) SETFLAG(FV); \ } \ regs.A=tmp; \ } \ SETNZFLAGS(regs.A); \ PCSTEP(STEP) |
|
Value: SEC: 1 -> [C] |
|
Value: SED: 1 -> [D] |
|
Value: SEI: 1 -> [I] |
|
Sets flag X to 1. Affects P register |
|
Sets N and Z flag according to X |
|
Value: STA: [A] -> [M] |
|
Adds byte X to/from the top of stack |
|
Removes byte X to/from the top of stack |
|
Value: STX: [X] -> [M] |
|
Value: STY: [Y] -> [M] |
|
Value: TAX: [A] -> [X], sets NZ |
|
Value: TAY: [A] -> [Y], sets NZ |
|
Value: TSX: [S] -> [X], sets NZ |
|
Value: TXA: [X] -> [A], sets NZ |
|
Value: TXS: [X] -> [S] |
|
Value: TYA: [Y] -> [A], sets NZ |
|
Zero page adressing mode |
|
Zero page, X adressing mode |
|
Zero page, Y adressing mode |
|
Executes one instruction on adress stored in regs.PC.
Executes one instruction on adress stored in regs.PC; increments (or changes in case of jump) program counter
|
|
IRQ interrupt.
Adds actual position and the P register (flags) to the top of the stack, sets the I (interrupt) flag to 1 and jumps to the IRQVKT, reset initialization routine. |
|
NMI interrupt.
Adds actual position and the P register (flags) to the top of the stack, sets the I (interrupt) flag to 1 and jumps to the NMIVKT, reset initialization routine. |
|
Reset interrupt.
Zeroes A, X, Y registers, resets stack pointer S, initializes P register (zeroes all flags except I, which is set to 1) and jumps to the RESETVKT, reset initialization routine. |
|
Variable containing all registers |