vcpu/core/
execute.rs

1use crate::{
2  core::{
3    cpu::{Cpu, StatusFlags},
4    instruction::{AddressingMode, Instruction, OpCode},
5  },
6  error::CpuError,
7};
8
9impl Cpu {
10  /// Returns how many cycles needed for completion of instruction
11  pub(crate) fn execute(&mut self, instruction: Instruction) -> Result<u8, CpuError> {
12    let Instruction {
13      opcode,
14      mode,
15      mut cycles,
16    } = instruction;
17
18    let (data, address) = self.interpret_payload(&mode, &mut cycles);
19
20    match opcode {
21      OpCode::ADC => {
22        let input_carry = self.is_flag(StatusFlags::Carry);
23        let (result, carry) = self.a.carrying_add(data, input_carry);
24        let overflow = input_carry != carry; // https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
25        self.set_flag(StatusFlags::Overflow, overflow);
26        self.set_flag(StatusFlags::Carry, carry);
27        self.set_flag(StatusFlags::Zero, result == 0x00);
28        self.set_flag(StatusFlags::Negative, (result & 0x80) == 0x80);
29        self.a = result;
30      }
31      OpCode::AND => {
32        self.a &= data;
33        self.set_flag(StatusFlags::Zero, self.a == 0x00);
34        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
35      }
36      OpCode::ASL => {
37        let shifted = (data as u16) << 1;
38        self.set_flag(StatusFlags::Carry, (shifted & 0xFF00) > 0);
39        self.set_flag(StatusFlags::Zero, (shifted & 0xFF00) > 0);
40        self.set_flag(StatusFlags::Negative, (shifted & 0x0080) == 0x0080);
41        if let AddressingMode::Implied | AddressingMode::Accumulator = mode {
42          self.a = shifted as u8;
43        } else {
44          self.write(address, shifted as u8);
45        }
46      }
47      OpCode::BCC => {
48        if !self.is_flag(StatusFlags::Carry) {
49          cycles += 1;
50          let (addr, overflow) = self.program_counter.overflowing_add(address);
51          if overflow {
52            cycles += 1;
53          }
54          self.program_counter = addr;
55        }
56      }
57      OpCode::BCS => {
58        if self.is_flag(StatusFlags::Carry) {
59          self.branch(address, &mut cycles);
60        }
61      }
62      OpCode::BEQ => {
63        if self.is_flag(StatusFlags::Zero) {
64          self.branch(address, &mut cycles);
65        }
66      }
67      OpCode::BIT => {
68        let temp = self.a & data;
69        self.set_flag(StatusFlags::Overflow, temp == 0x00);
70        self.set_flag(StatusFlags::Zero, data & (1 << 7) == (1 << 7));
71        self.set_flag(StatusFlags::Negative, data & (1 << 6) == (1 << 6));
72      }
73      OpCode::BMI => {
74        if self.is_flag(StatusFlags::Negative) {
75          self.branch(address, &mut cycles);
76        }
77      }
78      OpCode::BNE => {
79        if !self.is_flag(StatusFlags::Zero) {
80          self.branch(address, &mut cycles);
81        }
82      }
83      OpCode::BPL => {
84        if !self.is_flag(StatusFlags::Negative) {
85          self.branch(address, &mut cycles);
86        }
87      }
88      OpCode::BRK => {
89        self.set_flag(StatusFlags::Interrupt, true);
90        let [lo, hi] = self.program_counter.to_le_bytes();
91        self.push(hi);
92        self.push(lo);
93        self.set_flag(StatusFlags::Break, true);
94        self.push(self.status.bits());
95        self.set_flag(StatusFlags::Break, false);
96
97        let lo = self.read(Self::INTERRUPT_ADDRESS);
98        let hi = self.read(Self::INTERRUPT_ADDRESS + 1);
99        self.program_counter = u16::from_le_bytes([lo, hi]);
100      }
101      OpCode::BVC => {
102        if !self.is_flag(StatusFlags::Overflow) {
103          self.branch(address, &mut cycles);
104        }
105      }
106      OpCode::BVS => {
107        if self.is_flag(StatusFlags::Overflow) {
108          self.branch(address, &mut cycles);
109        }
110      }
111      OpCode::CLC => {
112        self.set_flag(StatusFlags::Carry, false);
113      }
114      OpCode::CLD => {
115        self.set_flag(StatusFlags::Decimal, false);
116      }
117      OpCode::CLI => {
118        self.set_flag(StatusFlags::Interrupt, false);
119      }
120      OpCode::CLV => {
121        self.set_flag(StatusFlags::Overflow, false);
122      }
123      OpCode::CMP => {
124        let temp = self.a - data;
125        self.set_flag(StatusFlags::Carry, self.a >= data);
126        self.set_flag(StatusFlags::Zero, temp == 0x00);
127        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
128      }
129      OpCode::CPX => {
130        let temp = self.x - data;
131        self.set_flag(StatusFlags::Carry, self.a >= data);
132        self.set_flag(StatusFlags::Zero, temp == 0x00);
133        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
134      }
135      OpCode::CPY => {
136        let temp = self.y - data;
137        self.set_flag(StatusFlags::Carry, self.a >= data);
138        self.set_flag(StatusFlags::Zero, temp == 0x00);
139        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
140      }
141      OpCode::DEC => {
142        let temp = data - 1;
143        self.write(address, temp);
144        self.set_flag(StatusFlags::Zero, temp == 0x00);
145        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
146      }
147      OpCode::DEX => {
148        self.x -= 1;
149        self.set_flag(StatusFlags::Zero, self.x == 0x00);
150        self.set_flag(StatusFlags::Negative, (self.x & 0x80) == 0x80);
151      }
152      OpCode::DEY => {
153        self.y -= 1;
154        self.set_flag(StatusFlags::Zero, self.y == 0x00);
155        self.set_flag(StatusFlags::Negative, (self.y & 0x80) == 0x80);
156      }
157      OpCode::EOR => {
158        self.a ^= data;
159        self.set_flag(StatusFlags::Zero, self.a == 0x00);
160        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
161      }
162      OpCode::INC => {
163        let temp = data + 1;
164        self.write(address, temp);
165        self.set_flag(StatusFlags::Zero, temp == 0x00);
166        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
167      }
168      OpCode::INX => {
169        self.x += 1;
170        self.set_flag(StatusFlags::Zero, self.x == 0x00);
171        self.set_flag(StatusFlags::Negative, (self.x & 0x80) == 0x80);
172      }
173      OpCode::INY => {
174        self.y += 1;
175        self.set_flag(StatusFlags::Zero, self.y == 0x00);
176        self.set_flag(StatusFlags::Negative, (self.y & 0x80) == 0x80);
177      }
178      OpCode::JMP => {
179        self.program_counter = address;
180      }
181      OpCode::JSR => {
182        // self.program_counter -= 1;
183        let [lo, hi] = self.program_counter.to_le_bytes();
184        self.push(hi);
185        self.push(lo);
186        self.program_counter = address;
187      }
188      OpCode::LDA => {
189        self.a = data;
190        self.set_flag(StatusFlags::Zero, self.a == 0x00);
191        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
192      }
193      OpCode::LDX => {
194        self.x = data;
195        self.set_flag(StatusFlags::Zero, self.x == 0x00);
196        self.set_flag(StatusFlags::Negative, (self.x & 0x80) == 0x80);
197      }
198      OpCode::LDY => {
199        self.y = data;
200        self.set_flag(StatusFlags::Zero, self.y == 0x00);
201        self.set_flag(StatusFlags::Negative, (self.y & 0x80) == 0x80);
202      }
203      OpCode::LSR => {
204        self.set_flag(StatusFlags::Carry, (data & 0x01) == 0x01);
205        let temp = data >> 1;
206        self.set_flag(StatusFlags::Zero, temp == 0x00);
207        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
208        if let AddressingMode::Implied | AddressingMode::Accumulator = mode {
209          self.a = temp;
210        } else {
211          self.write(address, temp);
212        }
213      }
214      OpCode::NOP => (),
215      OpCode::ORA => {
216        self.a |= data;
217        self.set_flag(StatusFlags::Zero, self.a == 0x00);
218        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
219      }
220      OpCode::PHA => {
221        self.push(self.a);
222      }
223      OpCode::PHP => {
224        self.push((self.status | StatusFlags::Unused | StatusFlags::Break).bits());
225        self.set_flag(StatusFlags::Break, false);
226        self.set_flag(StatusFlags::Unused, false);
227      }
228      OpCode::PLA => {
229        self.a = self.pop();
230        self.set_flag(StatusFlags::Zero, self.a == 0x00);
231        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
232      }
233      OpCode::PLP => {
234        self.status = self.pop().try_into().map_err(|e| CpuError::Other(format!("{e}")))?;
235        self.set_flag(StatusFlags::Unused, true);
236      }
237      OpCode::ROL => {
238        let carry = self.is_flag(StatusFlags::Carry) as u8;
239        let new_carry = (data & 0x80) == 0x80;
240        let temp = (data << 1) | carry;
241        self.set_flag(StatusFlags::Carry, new_carry);
242        self.set_flag(StatusFlags::Zero, temp == 0x00);
243        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
244        if let AddressingMode::Implied | AddressingMode::Accumulator = mode {
245          self.a = temp;
246        } else {
247          self.write(address, temp);
248        }
249      }
250      OpCode::ROR => {
251        let carry = self.is_flag(StatusFlags::Carry) as u8;
252        let new_carry = (data & 0x01) == 0x01;
253        let temp = (carry << 7) | (data >> 1);
254        self.set_flag(StatusFlags::Carry, new_carry);
255        self.set_flag(StatusFlags::Zero, temp == 0x00);
256        self.set_flag(StatusFlags::Negative, (temp & 0x80) == 0x80);
257        if let AddressingMode::Implied | AddressingMode::Accumulator = mode {
258          self.a = temp;
259        } else {
260          self.write(address, temp);
261        }
262      }
263      OpCode::RTI => {
264        self.status = self.pop().try_into().map_err(|e| CpuError::Other(format!("{e}")))?;
265        self.status.toggle(StatusFlags::Break);
266        self.status.toggle(StatusFlags::Unused);
267
268        let lo = self.pop();
269        let hi = self.pop();
270        self.program_counter = u16::from_le_bytes([lo, hi]);
271      }
272      OpCode::RTS => {
273        let lo = self.pop();
274        let hi = self.pop();
275        self.program_counter = u16::from_le_bytes([lo, hi]);
276      }
277      OpCode::SBC => {
278        let input_data = !data;
279        let input_carry = self.is_flag(StatusFlags::Carry);
280        let (result, carry) = self.a.carrying_add(input_data, input_carry);
281        let overflow = input_carry != carry; // https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
282        self.set_flag(StatusFlags::Overflow, overflow);
283        self.set_flag(StatusFlags::Carry, carry);
284        self.set_flag(StatusFlags::Zero, result == 0x00);
285        self.set_flag(StatusFlags::Negative, (result & 0x80) == 0x80);
286        self.a = result;
287      }
288      OpCode::SEC => {
289        self.set_flag(StatusFlags::Carry, true);
290      }
291      OpCode::SED => {
292        self.set_flag(StatusFlags::Decimal, true);
293      }
294      OpCode::SEI => {
295        self.set_flag(StatusFlags::Interrupt, true);
296      }
297      OpCode::STA => {
298        self.write(address, self.a);
299      }
300      OpCode::STX => {
301        self.write(address, self.x);
302      }
303      OpCode::STY => {
304        self.write(address, self.y);
305      }
306      OpCode::TAX => {
307        self.x = self.a;
308        self.set_flag(StatusFlags::Zero, self.x == 0x00);
309        self.set_flag(StatusFlags::Negative, (self.x & 0x80) == 0x80);
310      }
311      OpCode::TAY => {
312        self.y = self.a;
313        self.set_flag(StatusFlags::Zero, self.y == 0x00);
314        self.set_flag(StatusFlags::Negative, (self.y & 0x80) == 0x80);
315      }
316      OpCode::TSX => {
317        self.x = self.stack_ptr;
318        self.set_flag(StatusFlags::Zero, self.x == 0x00);
319        self.set_flag(StatusFlags::Negative, (self.x & 0x80) == 0x80);
320      }
321      OpCode::TXA => {
322        self.a = self.x;
323        self.set_flag(StatusFlags::Zero, self.a == 0x00);
324        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
325      }
326      OpCode::TXS => {
327        self.stack_ptr = self.x;
328      }
329      OpCode::TYA => {
330        self.a = self.y;
331        self.set_flag(StatusFlags::Zero, self.a == 0x00);
332        self.set_flag(StatusFlags::Negative, (self.a & 0x80) == 0x80);
333      }
334    }
335
336    Ok(cycles)
337  }
338
339  fn interpret_payload(&mut self, mode: &AddressingMode, cycles: &mut u8) -> (u8, u16) {
340    let address = match mode {
341      AddressingMode::Accumulator => self.a as u16,
342      AddressingMode::Implied => {
343        return (self.a, 0);
344      }
345      AddressingMode::Immediate(value) => {
346        return (*value, self.program_counter - 1);
347      }
348      AddressingMode::Relative(addr) => {
349        let mut address = *addr as u16;
350        if (address & 0x80) == 0x80 {
351          // 7th bit is 1, so this is supposed to be signed. set the top bits to all 1s to
352          // enable 2s compliment arithmetic
353          address |= 0xFF00;
354        }
355        address
356      }
357      AddressingMode::ZeroPage(addr) => *addr as u16 & 0x00FF,
358      AddressingMode::ZeroPageX(addr) => (addr + self.x as u16) & 0x00FF,
359      AddressingMode::ZeroPageY(addr) => (addr + self.y as u16) & 0x00FF,
360      AddressingMode::Absolute(addr) => *addr,
361      AddressingMode::AbsoluteX(addr) => {
362        let (addr, overflow) = addr.overflowing_add(self.x as u16);
363        if overflow {
364          *cycles += 1;
365        }
366        addr
367      }
368      AddressingMode::AbsoluteY(addr) => {
369        let (addr, overflow) = addr.overflowing_add(self.y as u16);
370        if overflow {
371          *cycles += 1;
372        }
373        addr
374      }
375      AddressingMode::Indirect(ptr) => {
376        if (ptr & 0x00FF) == 0x00FF {
377          // simulate hardware bug
378          let lo = self.read(*ptr);
379          let hi = self.read(ptr & 0xFF00);
380          u16::from_le_bytes([lo, hi])
381        } else {
382          // behave normally
383          let lo = self.read(*ptr);
384          let hi = self.read(ptr + 1);
385          u16::from_le_bytes([lo, hi])
386        }
387      }
388      AddressingMode::IndirectX(ptr) => {
389        let lo = self.read((ptr + self.x as u16) & 0x00FF);
390        let hi = self.read((ptr + self.x as u16 + 1) & 0x00FF);
391        u16::from_le_bytes([lo, hi])
392      }
393      AddressingMode::IndirectY(ptr) => {
394        let lo = self.read((ptr) & 0x00FF);
395        let hi = self.read((ptr + 1) & 0x00FF);
396        let (addr, overflow) = u16::from_le_bytes([lo, hi]).overflowing_add(self.y as u16);
397        if overflow {
398          *cycles += 1;
399        }
400        addr
401      }
402    };
403
404    let data = self.read(address);
405
406    (data, address)
407  }
408
409  fn branch(&mut self, payload: u16, cycles: &mut u8) {
410    *cycles += 1;
411    let (addr, overflow) = self.program_counter.overflowing_add(payload);
412    if overflow {
413      *cycles += 1;
414    }
415    self.program_counter = addr;
416  }
417}