v6502
The MOS 6502 Virtual Machine and Toolchain Infrastructure
cpu.h
Go to the documentation of this file.
1 
4 /*
5  * Copyright (c) 2013 Daniel Loffgren
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to
9  * deal in the Software without restriction, including without limitation the
10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23  * IN THE SOFTWARE.
24  */
25 
26 #ifndef v6502_cpu_h
27 #define v6502_cpu_h
28 
29 #include <stdint.h>
30 
31 #include <v6502/mem.h>
32 
35 typedef struct {
37  uint16_t pc;
39  uint8_t ac;
41  uint8_t x;
43  uint8_t y;
45  uint8_t sr;
47  uint8_t sp;
51  void(*fault_callback)(void *context, const char *reason);
54 } v6502_cpu;
55 
58 typedef enum {
59  // Single Byte Instructions
60  v6502_opcode_brk = 0x00, // BRK - Break
61  v6502_opcode_nop = 0xEA, // NOP - No-op
62  v6502_opcode_clc = 0x18, // CLC - Clear Carry Flag
63  v6502_opcode_cld = 0xD8, // CLD - Clear Decimal Flag
64  v6502_opcode_cli = 0x58, // CLI - Clear Interrupt Flag
65  v6502_opcode_clv = 0xB8, // CLV - Clear Overflow Flag
66  v6502_opcode_sec = 0x38, // SEC - Set Carry Flag
67  v6502_opcode_sed = 0xF8, // SED - Set Decimal Flag
68  v6502_opcode_sei = 0x78, // SEI - Set Interrupt Flag
69  v6502_opcode_dex = 0xCA, // DEX - Decrement X
70  v6502_opcode_dey = 0x88, // DEY - Decrement Y
71  v6502_opcode_tax = 0xAA, // TAX - Transfer Accumulator to X
72  v6502_opcode_tay = 0xA8, // TAY - Transfer Accumulator to Y
73  v6502_opcode_tsx = 0xBA, // TSX - Transfer Status Flags to X
74  v6502_opcode_txa = 0x8A, // TXA - Transfer X to Accumulator
75  v6502_opcode_txs = 0x9A, // TXS - Transfer X to Status Flags
76  v6502_opcode_tya = 0x98, // TYA - Transfer Y to Accumulator
77  v6502_opcode_inx = 0xE8, // INX - Increment X
78  v6502_opcode_iny = 0xC8, // INY - Increment Y
79 
80  // Stack Instructions
81  v6502_opcode_jsr = 0x20, // JSR - Call Subroutine
82  v6502_opcode_rti = 0x40, // RTI - Return from Interrupt
83  v6502_opcode_rts = 0x60, // RTS - Return from Subroutine
84  v6502_opcode_pha = 0x48, // PHA - Push Accumulator to Stack
85  v6502_opcode_php = 0x08, // PHP - Push Program Counter to Stack
86  v6502_opcode_pla = 0x68, // PLA - Pull Accumulator from Stack
87  v6502_opcode_plp = 0x28, // PLP - Pull Program Counter from Stack
88 
89  // Branch Instructions
90  v6502_opcode_bcc = 0x90, // BCC - Branch if Carry Clear
91  v6502_opcode_bcs = 0xB0, // BCS - Branch if Carry Set
92  v6502_opcode_beq = 0xF0, // BEQ - Branch if Equal (Zero Set)
93  v6502_opcode_bne = 0xD0, // BNE - Branch if Not Equal (Zero Clear)
94  v6502_opcode_bmi = 0x30, // BMI - Branch if Minus (Negative Set)
95  v6502_opcode_bpl = 0x10, // BPL - Branch if Plus (Negative Clear)
96  v6502_opcode_bvc = 0x50, // BVC - Branch if Overflow Clear
97  v6502_opcode_bvs = 0x70, // BVS - Branch if Overflow Set
98 
99  // ADC - Add With Carry
100  v6502_opcode_adc_imm = 0x69,
101  v6502_opcode_adc_zpg = 0x65,
102  v6502_opcode_adc_zpgx = 0x75,
103  v6502_opcode_adc_abs = 0x6D,
104  v6502_opcode_adc_absx = 0x7D,
105  v6502_opcode_adc_absy = 0x79,
106  v6502_opcode_adc_indx = 0x61,
107  v6502_opcode_adc_indy = 0x71,
108 
109  // AND - Bitwise And
110  v6502_opcode_and_imm = 0x29,
111  v6502_opcode_and_zpg = 0x25,
112  v6502_opcode_and_zpgx = 0x35,
113  v6502_opcode_and_abs = 0x2D,
114  v6502_opcode_and_absx = 0x3D,
115  v6502_opcode_and_absy = 0x39,
116  v6502_opcode_and_indx = 0x21,
117  v6502_opcode_and_indy = 0x31,
118 
119  // ASL - Arithmetic Shift Left
120  v6502_opcode_asl_acc = 0x0A,
121  v6502_opcode_asl_zpg = 0x06,
122  v6502_opcode_asl_zpgx = 0x16,
123  v6502_opcode_asl_abs = 0x0E,
124  v6502_opcode_asl_absx = 0x1E,
125 
126  // BIT - Bit Test
127  v6502_opcode_bit_zpg = 0x24,
128  v6502_opcode_bit_abs = 0x2C,
129 
130  // CMP - Compare Accumulator
131  v6502_opcode_cmp_imm = 0xC9,
132  v6502_opcode_cmp_zpg = 0xC5,
133  v6502_opcode_cmp_zpgx = 0xD5,
134  v6502_opcode_cmp_abs = 0xCD,
135  v6502_opcode_cmp_absx = 0xDD,
136  v6502_opcode_cmp_absy = 0xD9,
137  v6502_opcode_cmp_indx = 0xC1,
138  v6502_opcode_cmp_indy = 0xD1,
139 
140  // CPX - Compare X
141  v6502_opcode_cpx_imm = 0xE0,
142  v6502_opcode_cpx_zpg = 0xE4,
143  v6502_opcode_cpx_abs = 0xEC,
144 
145  // CPY - Compare Y
146  v6502_opcode_cpy_imm = 0xC0,
147  v6502_opcode_cpy_zpg = 0xC4,
148  v6502_opcode_cpy_abs = 0xCC,
149 
150  // DEC - Decrement Accumulator
151  v6502_opcode_dec_zpg = 0xC6,
152  v6502_opcode_dec_zpgx = 0xD6,
153  v6502_opcode_dec_abs = 0xCE,
154  v6502_opcode_dec_absx = 0xDE,
155 
156  // EOR - Bitwise Exclusive Or
157  v6502_opcode_eor_imm = 0x49,
158  v6502_opcode_eor_zpg = 0x45,
159  v6502_opcode_eor_zpgx = 0x55,
160  v6502_opcode_eor_abs = 0x4D,
161  v6502_opcode_eor_absx = 0x5D,
162  v6502_opcode_eor_absy = 0x59,
163  v6502_opcode_eor_indx = 0x41,
164  v6502_opcode_eor_indy = 0x51,
165 
166  // INC - Increment Accumulator
167  v6502_opcode_inc_zpg = 0xE6,
168  v6502_opcode_inc_zpgx = 0xF6,
169  v6502_opcode_inc_abs = 0xEE,
170  v6502_opcode_inc_absx = 0xFE,
171 
172  // JMP - Unconditional Jump
173  v6502_opcode_jmp_abs = 0x4C,
174  v6502_opcode_jmp_ind = 0x6C,
175 
176  // ORA - Bitwise Or
177  v6502_opcode_ora_imm = 0x09,
178  v6502_opcode_ora_zpg = 0x05,
179  v6502_opcode_ora_zpgx = 0x15,
180  v6502_opcode_ora_abs = 0x0D,
181  v6502_opcode_ora_absx = 0x1D,
182  v6502_opcode_ora_absy = 0x19,
183  v6502_opcode_ora_indx = 0x01,
184  v6502_opcode_ora_indy = 0x11,
185 
186  // LDA - Load Accumulator
187  v6502_opcode_lda_imm = 0xA9,
188  v6502_opcode_lda_zpg = 0xA5,
189  v6502_opcode_lda_zpgx = 0xB5,
190  v6502_opcode_lda_abs = 0xAD,
191  v6502_opcode_lda_absx = 0xBD,
192  v6502_opcode_lda_absy = 0xB9,
193  v6502_opcode_lda_indx = 0xA1,
194  v6502_opcode_lda_indy = 0xB1,
195 
196  // LDX - Load X
197  v6502_opcode_ldx_imm = 0xA2,
198  v6502_opcode_ldx_zpg = 0xA6,
199  v6502_opcode_ldx_zpgy = 0xB6,
200  v6502_opcode_ldx_abs = 0xAE,
201  v6502_opcode_ldx_absy = 0xBE,
202 
203  // LDY - Load Y
204  v6502_opcode_ldy_imm = 0xA0,
205  v6502_opcode_ldy_zpg = 0xA4,
206  v6502_opcode_ldy_zpgx = 0xB4,
207  v6502_opcode_ldy_abs = 0xAC,
208  v6502_opcode_ldy_absx = 0xBC,
209 
210  // LSR - Logical Shift Right
211  v6502_opcode_lsr_acc = 0x4A,
212  v6502_opcode_lsr_zpg = 0x46,
213  v6502_opcode_lsr_zpgx = 0x56,
214  v6502_opcode_lsr_abs = 0x4E,
215  v6502_opcode_lsr_absx = 0x5E,
216 
217  // ROL - Rotate Left
218  v6502_opcode_rol_acc = 0x2A,
219  v6502_opcode_rol_zpg = 0x26,
220  v6502_opcode_rol_zpgx = 0x36,
221  v6502_opcode_rol_abs = 0x2E,
222  v6502_opcode_rol_absx = 0x3E,
223 
224  // ROR - Rotate Right
225  v6502_opcode_ror_acc = 0x6A,
226  v6502_opcode_ror_zpg = 0x66,
227  v6502_opcode_ror_zpgx = 0x76,
228  v6502_opcode_ror_abs = 0x6E,
229  v6502_opcode_ror_absx = 0x7E,
230 
231  // SBC - Subtract with Carry
232  v6502_opcode_sbc_imm = 0xE9,
233  v6502_opcode_sbc_zpg = 0xE5,
234  v6502_opcode_sbc_zpgx = 0xF5,
235  v6502_opcode_sbc_abs = 0xED,
236  v6502_opcode_sbc_absx = 0xFD,
237  v6502_opcode_sbc_absy = 0xF9,
238  v6502_opcode_sbc_indx = 0xE1,
239  v6502_opcode_sbc_indy = 0xF1,
240 
241  // STA - Store Accumulator
242  v6502_opcode_sta_zpg = 0x85,
243  v6502_opcode_sta_zpgx = 0x95,
244  v6502_opcode_sta_abs = 0x8D,
245  v6502_opcode_sta_absx = 0x9D,
246  v6502_opcode_sta_absy = 0x99,
247  v6502_opcode_sta_indx = 0x81,
248  v6502_opcode_sta_indy = 0x91,
249 
250  // STX - Store X
251  v6502_opcode_stx_zpg = 0x86,
252  v6502_opcode_stx_zpgy = 0x96,
253  v6502_opcode_stx_abs = 0x8E,
254 
255  // STY - Store Y
256  v6502_opcode_sty_zpg = 0x84,
257  v6502_opcode_sty_zpgx = 0x94,
258  v6502_opcode_sty_abs = 0x8C,
259 
260  // WAI - Wait
261  v6502_opcode_wai = 0xCB
262 } v6502_opcode;
263 
266 typedef enum {
267  v6502_cpu_status_carry = 1 << 0,
268  v6502_cpu_status_zero = 1 << 1,
269  v6502_cpu_status_interrupt = 1 << 2,
270  v6502_cpu_status_decimal = 1 << 3,
271  v6502_cpu_status_break = 1 << 4,
272  v6502_cpu_status_ignored = 1 << 5,
273  v6502_cpu_status_overflow = 1 << 6,
274  v6502_cpu_status_negative = 1 << 7,
276 
279 typedef enum {
280  v6502_address_mode_symbol = -2, // Added for external code, like assemblers
281  v6502_address_mode_unknown = -1,
282  v6502_address_mode_implied = 0, // Or none
283  v6502_address_mode_accumulator = 1,
284  v6502_address_mode_immediate = 2,
285  v6502_address_mode_absolute = 3,
286  v6502_address_mode_absolute_x = 4,
287  v6502_address_mode_absolute_y = 5,
288  v6502_address_mode_indirect = 6,
289  v6502_address_mode_indirect_x = 7,
290  v6502_address_mode_indirect_y = 8,
291  v6502_address_mode_relative = 9,
292  v6502_address_mode_zeropage = 10,
293  v6502_address_mode_zeropage_x = 11,
294  v6502_address_mode_zeropage_y = 12,
296 
302 void v6502_destroyCPU(v6502_cpu *cpu);
316 void v6502_execute(v6502_cpu *cpu, uint8_t opcode, uint8_t low, uint8_t high);
318 void v6502_step(v6502_cpu *cpu);
320 void v6502_reset(v6502_cpu *cpu);
322 void v6502_nmi(v6502_cpu *cpu);
325 #endif
void v6502_reset(v6502_cpu *cpu)
Hardware reset a v6502_cpu.
Definition: cpu.c:290
v6502_cpu * v6502_createCPU(void)
Create a v6502_cpu.
Definition: cpu.c:156
Virtual Memory.
void v6502_step(v6502_cpu *cpu)
Single step a v6502_cpu.
Definition: cpu.c:300
uint16_t pc
Program counter (16-bit)
Definition: cpu.h:37
v6502_memory * memory
Virtual Memory.
Definition: cpu.h:49
void v6502_nmi(v6502_cpu *cpu)
Send an NMI to a v6502_cpu.
Definition: cpu.c:285
v6502_address_mode
Address Modes.
Definition: cpu.h:279
v6502_address_mode v6502_addressModeForOpcode(v6502_opcode opcode)
Return the v6502_address_mode of an instruction based on the opcode (See: Karnaugh Map Analysis) ...
Definition: cpu.c:196
Virtual CPU Object.
Definition: cpu.h:35
uint8_t y
Y register (8-bit)
Definition: cpu.h:43
void v6502_execute(v6502_cpu *cpu, uint8_t opcode, uint8_t low, uint8_t high)
Execute an instruction on a v6502_cpu.
Definition: cpu.c:316
uint8_t sp
Stack Pointer (8-bit)
Definition: cpu.h:47
void v6502_destroyCPU(v6502_cpu *cpu)
Destroy a v6502_cpu.
Definition: cpu.c:160
void * fault_context
Fault Callback Context.
Definition: cpu.h:53
v6502_opcode
Instruction Set.
Definition: cpu.h:58
uint8_t ac
Accumulator (8-bit)
Definition: cpu.h:39
Virtual Memory Object.
Definition: mem.h:119
int v6502_instructionLengthForOpcode(v6502_opcode opcode)
Return the byte-length of an instruction based on the opcode (See: Karnaugh Map Analysis) ...
Definition: cpu.c:167
v6502_cpu_status
Status Register Flags.
Definition: cpu.h:266
uint8_t sr
Status register (8-bit)
Definition: cpu.h:45
uint8_t x
X register (8-bit)
Definition: cpu.h:41