yane/core/cpu.rs
1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4
5use crate::core::StatusRegister;
6
7/// The CPU of the NES.
8///
9/// Contains all registers and is responsible for changing the flags when the values are set/unset.
10#[derive(Clone, Serialize, Deserialize)]
11pub struct Cpu {
12 /// Accumulator
13 pub a: u8,
14 /// X index register
15 pub x: u8,
16 /// Y index register
17 pub y: u8,
18 /// Program counter
19 pub p_c: u16,
20 /// Stack pointer
21 pub s_p: u8,
22 /// Status register
23 pub s_r: StatusRegister,
24}
25
26impl Default for Cpu {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl Cpu {
33 pub fn new() -> Cpu {
34 Cpu {
35 a: 0,
36 x: 0,
37 y: 0,
38 p_c: 0,
39 s_p: 0xFF,
40 s_r: StatusRegister::new(),
41 }
42 }
43 /// Load some value into A.
44 /// ```
45 /// let mut cpu = yane::core::Cpu::new();
46 /// cpu.lda(0x18);
47 /// assert_eq!(cpu.a, 0x18);
48 /// ```
49 pub fn lda(&mut self, value: u8) {
50 self.a = value;
51 self.set_load_flags(self.a);
52 }
53
54 /// Load some value into X.
55 ///
56 /// ```
57 /// let mut cpu = yane::core::Cpu::new();
58 /// cpu.ldx(0x18);
59 /// assert_eq!(cpu.x, 0x18);
60 /// ```
61 pub fn ldx(&mut self, value: u8) {
62 self.x = value;
63 self.set_load_flags(self.x);
64 }
65 /// Load some value into Y.
66 ///
67 /// ```
68 /// let mut cpu = yane::core::Cpu::new();
69 /// cpu.ldy(0x18);
70 /// assert_eq!(cpu.y, 0x18);
71 /// ```
72 pub fn ldy(&mut self, value: u8) {
73 self.y = value;
74 self.set_load_flags(self.y);
75 }
76 /// Add some value with A and the carry bit in the status register.
77 ///
78 /// * Zero is set if A = 0 after the operation
79 /// * Overflow is set if overflow occurs
80 /// * Negative flag is set if the seventh flag is set
81 pub fn adc(&mut self, value: u8) {
82 let i = self.a;
83 self.a = self
84 .a
85 .wrapping_add(value)
86 .wrapping_add(if self.s_r.c { 1 } else { 0 });
87 self.s_r.z = self.a == 0;
88 // Way of checking for (unsigned) overflow
89 self.s_r.c = self.a < i || (self.a == i && value > 0);
90 // Way of checking for (signed) overflow
91 // If I and value are the same sign (i.e. both positive/negative) but the result is a different sign, overflow has occured
92 self.s_r.v = (i & 0x80) == (value & 0x80) && (i & 0x80) != (self.a & 0x80);
93 self.s_r.n = self.a & 0x80 != 0;
94 }
95 /// Perform an AND (`&``) operation between A and some value.
96 ///
97 /// * Z is set if A is 0
98 /// * N is set if A is negative (i.e. the MSB is set)
99 /// ```
100 /// let mut cpu = yane::core::Cpu::new();
101 /// cpu.a = 0xAA;
102 /// cpu.and(0x0F);
103 /// assert_eq!(cpu.a, 0x0A);
104 /// ```
105 pub fn and(&mut self, value: u8) {
106 self.a &= value;
107 self.s_r.z = self.a == 0;
108 self.s_r.n = (self.a & 0x80) != 0;
109 }
110 /// Perform an arithmatic shift left on some value.
111 ///
112 /// Essentially multiply it by 2
113 /// * C is set to the carry bit (i.e. the MSB before the shift).
114 /// * Z is set if `value` is 0 after the shift.
115 /// * N is set if the MSB of `value` is set after the shift.
116 /// ```
117 /// let mut cpu = yane::core::Cpu::new();
118 /// assert_eq!(cpu.asl(0x98), 0x30);
119 /// assert_eq!(cpu.s_r.z, false);
120 /// assert_eq!(cpu.s_r.c, true);
121 /// ```
122 pub fn asl(&mut self, value: u8) -> u8 {
123 self.s_r.z = value & 0x7F == 0;
124 self.s_r.c = value & 0x80 != 0;
125 self.s_r.n = value & 0x40 != 0;
126 value << 1
127 }
128 /// Perform a branch to `value` relatively if `param == true`.
129 ///
130 /// Updates the PC accordingly.
131 /// Return how many cycles are needed by the branching operation.
132 pub fn branch_if(&mut self, param: bool, value: u8) -> i64 {
133 if param {
134 // PC if we don't take the branch
135 let pc = self.p_c.wrapping_add(2);
136 // Value is signed here, so we need to convert to signed values first and then convert back to unsigned
137 self.p_c = (self.p_c as i16).wrapping_add((value as i8) as i16) as u16;
138 // Wrapping add here since we will add 2 bytes after the current instruction
139 return 3 + if (pc & 0xFF00) != (self.p_c.wrapping_add(2) & 0xFF00) {
140 1
141 } else {
142 0
143 };
144 }
145 2
146 }
147 /// Perform a bitwise test by ANDing A with `value`.
148 ///
149 /// Does not store the result, but uses it to set some flags
150 /// * Z is set if the result is 0.
151 /// * V is set to bit 6 of `value`.
152 /// * N is set to bit 7 of `value`.
153 /// ```
154 /// let mut cpu = yane::core::Cpu::new();
155 /// cpu.a = 0x18;
156 /// cpu.bit(0xE0);
157 /// // A is not affected
158 /// assert_eq!(cpu.a, 0x18);
159 /// assert_eq!(cpu.s_r.z, true);
160 /// assert_eq!(cpu.s_r.v, true);
161 /// assert_eq!(cpu.s_r.n, true);
162 /// ```
163 pub fn bit(&mut self, value: u8) {
164 let result = self.a & value;
165 self.s_r.z = result == 0;
166 self.s_r.v = (value & 0x40) != 0;
167 self.s_r.n = (value & 0x80) != 0;
168 }
169 /// Perform an interrupt to the location specified.
170 ///
171 /// Basically just sets the program counter to `location` and sets the interrupt flag.
172 /// Returns an array representing the the program counter and status register, to be pushed to the stack.
173 /// Return array is in the form `[LSB(PC), MSB(PC), SR]`, where:
174 /// * `LSB(PC)` is the least significant byte of the program counter
175 /// * `MSB(PC)` is the most significant byte of the program counter
176 /// * SR is the status register
177 pub fn brk(&mut self, location: u16) -> [u8; 3] {
178 let to_stack: [u8; 3] = [
179 (self.p_c & 0xFF) as u8,
180 (self.p_c >> 8) as u8,
181 self.s_r.to_byte() | 0x10,
182 ];
183 self.s_r.i = true;
184 self.p_c = location;
185 to_stack
186 }
187 /// "Compare" the two values given and set the status register accordingly
188 ///
189 /// * C is set to `u >= v`
190 /// * Z is set to `u == v``
191 /// * N is set to the MSB of `u - v`
192 /// ```
193 /// let mut cpu = yane::core::Cpu::new();
194 /// cpu.compare(0x18, 0x18);
195 /// assert_eq!(cpu.s_r.z, true);
196 /// cpu.compare(0x19, 0x18);
197 /// assert_eq!(cpu.s_r.c, true);
198 /// cpu.compare(0x18, 0x19);
199 /// assert_eq!(cpu.s_r.n, true);
200 /// ```
201 pub fn compare(&mut self, u: u8, v: u8) {
202 self.s_r.c = u >= v;
203 self.s_r.z = u == v;
204 self.s_r.n = (u.wrapping_sub(v) & 0x80) != 0;
205 }
206 /// Compare a value with A.
207 ///
208 /// Shorthand for [Cpu::compare] with [Cpu::a] and `v`.
209 pub fn cmp(&mut self, v: u8) {
210 self.compare(self.a, v);
211 }
212 /// Compare a value with X.
213 ///
214 /// Shorthand for [Cpu::compare] with [Cpu::a] and `v`.
215 pub fn cpx(&mut self, v: u8) {
216 self.compare(self.x, v);
217 }
218 /// Comapre a value with Y.
219 /// Shorthand for `cpu.compare(cpu.y, v)`
220 pub fn cpy(&mut self, v: u8) {
221 self.compare(self.y, v);
222 }
223 /// Decrement some value and set the flags accordingly.
224 ///
225 /// * Z is set if the return value is `0`
226 /// * N is set if the MSB of the return value is set.
227 /// ```
228 /// let mut cpu = yane::core::Cpu::new();
229 /// let a = cpu.dec(0x81);
230 /// assert_eq!(a, 0x80);
231 /// // Result is not zero
232 /// assert_eq!(cpu.s_r.z, false);
233 /// // Result is negative
234 /// assert_eq!(cpu.s_r.n, true);
235 /// ```
236 pub fn dec(&mut self, v: u8) -> u8 {
237 self.s_r.z = v == 1;
238 let r = v.wrapping_sub(1);
239 self.s_r.n = (r & 0x80) != 0;
240 r
241 }
242 /// Perform an exclusive OR on A.
243 ///
244 /// Sets A to the result of A ^ `value`.
245 /// * Z is set to A == 0
246 /// * N is set to the MSB of A
247 ///```
248 /// let mut cpu = yane::core::Cpu::new();
249 /// cpu.a = 0xFF;
250 /// cpu.eor(0x77);
251 /// assert_eq!(cpu.a, 0x88);
252 /// assert_eq!(cpu.s_r.z, false);
253 /// assert_eq!(cpu.s_r.n, true);
254 /// ```
255 pub fn eor(&mut self, value: u8) {
256 self.a ^= value;
257 self.s_r.z = self.a == 0;
258 self.s_r.n = (self.a & 0x80) != 0;
259 }
260 /// Increment the value given and sets flag accordingly.
261 ///
262 /// Return the value after incrementation, wrapping if needed.
263 /// * Z is set if the result is 0
264 /// * N is set if the result is negative
265 pub fn inc(&mut self, value: u8) -> u8 {
266 let v = value.wrapping_add(1);
267 self.s_r.z = v == 0;
268 self.s_r.n = (v & 0x80) != 0;
269 v
270 }
271 /// Logically shift the value right and set the flags accordingly.
272 ///
273 /// Return the value after shifting.
274 /// * C is set to bit 0 of the value before shifting.
275 /// * Z is set if the result is 0.
276 /// ```
277 /// let mut cpu = yane::core::Cpu::new();
278 /// let value = cpu.lsr(0x81);
279 /// assert_eq!(value, 0x40);
280 /// assert_eq!(cpu.s_r.c, true);
281 /// assert_eq!(cpu.s_r.z, false);
282 /// ```
283 pub fn lsr(&mut self, value: u8) -> u8 {
284 self.s_r.c = (value & 0x01) != 0;
285 let v = value >> 1;
286 self.s_r.z = v == 0;
287 self.s_r.n = (v & 0x80) != 0;
288 v
289 }
290 /// Perform a bitwise OR with A and `value`.
291 ///
292 /// Modifies A and sets teh status register accordinly.
293 /// * Z is set if A == 0
294 /// * N is set if A is negative
295 /// ```
296 /// let mut cpu = yane::core::Cpu::new();
297 /// cpu.ora(0x18);
298 /// assert_eq!(cpu.a, 0x18);
299 /// assert_eq!(cpu.s_r.n, false);
300 /// assert_eq!(cpu.s_r.z, false);
301 /// cpu.ora(0x81);
302 /// assert_eq!(cpu.a, 0x99);
303 /// assert_eq!(cpu.s_r.n, true);
304 /// assert_eq!(cpu.s_r.z, false);
305 /// ```
306 pub fn ora(&mut self, value: u8) {
307 self.a |= value;
308 self.s_r.z = self.a == 0;
309 self.s_r.n = (self.a & 0x80) != 0;
310 }
311 /// Rotate a byte left and set the flags accordingly
312 ///
313 /// * C is set to the MSB of the value given
314 /// * Z is set if the result is 0
315 /// * N is set to the MSB of the result
316 pub fn rol(&mut self, value: u8) -> u8 {
317 let mut new_val = value << 1;
318 if self.s_r.c {
319 new_val |= 0x01;
320 }
321 self.s_r.c = (value & 0x80) != 0;
322 self.s_r.z = new_val == 0;
323 self.s_r.n = (new_val & 0x80) != 0;
324 new_val
325 }
326 /// Rotate a byte right and set the flags accordingly
327 ///
328 /// * C is set the the LSB of the value given (i.e. the value that is lost)
329 /// * Z is set is the result is 0
330 /// * N is set if the result is negative
331 pub fn ror(&mut self, value: u8) -> u8 {
332 let mut new_val = value >> 1;
333 if self.s_r.c {
334 new_val |= 0x80;
335 }
336 self.s_r.c = (value & 0x01) != 0;
337 self.s_r.z = new_val == 0;
338 self.s_r.n = (new_val & 0x80) != 0;
339 new_val
340 }
341 /// Subtract a number from the accumulator with the NOT of the C bit.
342 ///
343 /// If C is 0, then it will subtract `value` + 1.
344 /// * C is cleared if there is overflow
345 /// * Z is set if A is 0
346 /// * V is set if the sign bit is incorrect (i.e. if signed overflow has occurred)
347 /// * N is set if the MSB is set
348 pub fn sbc(&mut self, value: u8) {
349 // Two's complement addition
350 self.adc(value ^ 0xFF)
351 }
352 /// Shorthand for LDA then TAX
353 ///
354 /// Used only in unofficial opcodes
355 pub fn lax(&mut self, value: u8) {
356 self.lda(value);
357 self.x = self.a;
358 }
359 /// Shorthand for DEC then CMP
360 pub fn dcp(&mut self, value: u8) -> u8 {
361 let v = self.dec(value);
362 self.cmp(v);
363 v
364 }
365 /// Shorthand for INC then SBC
366 pub fn isc(&mut self, value: u8) -> u8 {
367 let v = self.inc(value);
368 self.sbc(v);
369 v
370 }
371 /// Shorthand for ROL then AND
372 pub fn rla(&mut self, value: u8) -> u8 {
373 let v = self.rol(value);
374 self.and(v);
375 v
376 }
377 /// Shorthand for ROR then ADC
378 pub fn rra(&mut self, value: u8) -> u8 {
379 let v = self.ror(value);
380 self.adc(v);
381 v
382 }
383 /// Shorthand for ASL then ORA
384 pub fn slo(&mut self, value: u8) -> u8 {
385 let v = self.asl(value);
386 self.ora(v);
387 v
388 }
389 /// Shorthand for LSR then EOR
390 pub fn sre(&mut self, value: u8) -> u8 {
391 let v = self.lsr(value);
392 self.eor(v);
393 v
394 }
395 // Set the status register's flags when loading (LDA, LDX, or LDY)
396 fn set_load_flags(&mut self, value: u8) {
397 self.s_r.z = value == 0;
398 self.s_r.n = (value & 0x80) != 0;
399 }
400}
401
402impl Debug for Cpu {
403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404 write!(
405 f,
406 "[PC={:4X} A={:2X} X={:2X} Y={:2X} SP={:2X} SR={:?}]",
407 self.p_c, self.a, self.x, self.y, self.s_p, self.s_r
408 )
409 }
410}