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}