1pub mod bus; 2mod instructions; 3 4use crate::bus::BusInterface; 5use crate::instructions::InstructionState; 6use bincode::{Decode, Encode}; 7use jgenesis_common::num::GetBit; 8 9#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 10pub enum StatusReadContext { 11 HardwareInterruptHandler, 12 Brk, 13 PushStack, 14} 15 16#[derive(Debug, Clone, Copy, Encode, Decode)] 17pub struct StatusFlags { 18 negative: bool, 19 overflow: bool, 20 decimal: bool, 21 interrupt_disable: bool, 22 zero: bool, 23 carry: bool, 24} 25 26impl StatusFlags { 27 #[must_use] 28 pub fn new() -> Self { 29 // I flag defaults to 1, others default to 0 30 Self { 31 negative: false, 32 overflow: false, 33 decimal: false, 34 interrupt_disable: true, 35 zero: false, 36 carry: false, 37 } 38 } 39 40 pub fn set_negative(&mut self, negative: bool) -> &mut Self { 41 self.negative = negative; 42 self 43 } 44 45 pub fn set_overflow(&mut self, overflow: bool) -> &mut Self { 46 self.overflow = overflow; 47 self 48 } 49 50 pub fn set_zero(&mut self, zero: bool) -> &mut Self { 51 self.zero = zero; 52 self 53 } 54 55 pub fn set_carry(&mut self, carry: bool) -> &mut Self { 56 self.carry = carry; 57 self 58 } 59 60 #[must_use] 61 pub fn to_byte(self, read_ctx: StatusReadContext) -> u8 { 62 // B flag is set during BRK and PHA/PHP, cleared during NMI & IRQ handlers 63 let b_flag = match read_ctx { 64 StatusReadContext::Brk | StatusReadContext::PushStack => 0x10, 65 StatusReadContext::HardwareInterruptHandler => 0x00, 66 }; 67 68 // Bit 5 is unused, always reads as 1 69 (u8::from(self.negative) << 7) 70 | (u8::from(self.overflow) << 6) 71 | 0x20 72 | b_flag 73 | (u8::from(self.decimal) << 3) 74 | (u8::from(self.interrupt_disable) << 2) 75 | (u8::from(self.zero) << 1) 76 | u8::from(self.carry) 77 } 78 79 #[must_use] 80 pub fn from_byte(byte: u8) -> Self { 81 Self { 82 negative: byte.bit(7), 83 overflow: byte.bit(6), 84 decimal: byte.bit(3), 85 interrupt_disable: byte.bit(2), 86 zero: byte.bit(1), 87 carry: byte.bit(0), 88 } 89 } 90} 91 92impl Default for StatusFlags { 93 fn default() -> Self { 94 Self::new() 95 } 96} 97 98#[derive(Debug, Clone, Encode, Decode)] 99pub struct CpuRegisters { 100 pub accumulator: u8, 101 pub x: u8, 102 pub y: u8, 103 pub status: StatusFlags, 104 pub pc: u16, 105 pub sp: u8, 106 pub enable_decimal_mode: bool, 107} 108 109impl CpuRegisters { 110 fn new(reset_vector: u16, enable_decimal_mode: bool) -> Self { 111 Self { 112 accumulator: 0, 113 x: 0, 114 y: 0, 115 status: StatusFlags::new(), 116 pc: reset_vector, 117 sp: 0xFD, 118 enable_decimal_mode, 119 } 120 } 121 122 fn in_decimal_mode(&self) -> bool { 123 self.enable_decimal_mode && self.status.decimal 124 } 125} 126 127#[derive(Debug, Clone, Encode, Decode)] 128pub struct Mos6502 { 129 registers: CpuRegisters, 130 state: InstructionState, 131 frozen: bool, 132} 133 134const NMI_VECTOR: u16 = 0xFFFA; 135const RESET_VECTOR: u16 = 0xFFFC; 136const IRQ_VECTOR: u16 = 0xFFFE; 137 138impl Mos6502 {
Create a new standard 6502 with the PC pointing to the RESET vector, read from $FFFC.
In the standard 6502, the decimal mode flag works as intended and toggles BCD arithmetic.
Create a new NES 6502 with the PC pointing to the RESET vector, read from $FFFC.
In the NES 6502, the decimal mode flag does nothing.
153 fn new<B: BusInterface>(bus: &mut B, enable_decimal_mode: bool) -> Self { 154 let reset_vector_lsb = bus.read(RESET_VECTOR); 155 let reset_vector_msb = bus.read(RESET_VECTOR + 1); 156 let reset_vector = u16::from_le_bytes([reset_vector_lsb, reset_vector_msb]); 157 158 Self { 159 registers: CpuRegisters::new(reset_vector, enable_decimal_mode), 160 state: InstructionState::default(), 161 frozen: false, 162 } 163 }
Reset the 6502, which does the following:
- Immediately update PC to point to the RESET vector, abandoning any in-progress instruction
- Subtract 3 from the stack pointer
- Disable IRQs
- If the CPU was frozen by an illegal KIL opcode, unfreeze it
170 pub fn reset<B: BusInterface>(&mut self, bus: &mut B) { 171 let reset_vector_lsb = bus.read(RESET_VECTOR); 172 let reset_vector_msb = bus.read(RESET_VECTOR + 1); 173 self.registers.pc = u16::from_le_bytes([reset_vector_lsb, reset_vector_msb]); 174 self.state = InstructionState::default(); 175 176 self.registers.sp = self.registers.sp.wrapping_sub(3); 177 178 self.registers.status.interrupt_disable = true; 179 180 self.frozen = false; 181 }
Run the CPU for 1 cycle.
184 #[inline] 185 pub fn tick<B: BusInterface>(&mut self, bus: &mut B) { 186 if self.frozen { 187 // CPU was frozen by an illegal KIL opcode; do nothing 188 return; 189 } 190 191 if self.state.instruction_complete { 192 // Opcode is always read, even if handling an interrupt 193 let opcode = bus.read(self.registers.pc); 194 195 if self.state.pending_interrupt { 196 self.state.pending_interrupt = false; 197 self.state.executing_interrupt = true; 198 } else { 199 self.registers.pc = self.registers.pc.wrapping_add(1); 200 self.state.opcode = opcode; 201 } 202 203 self.state.instruction_complete = false; 204 self.state.cycle = 0; 205 return; 206 } 207 208 instructions::execute_cycle(self, bus); 209 }
211 #[inline] 212 #[must_use] 213 pub fn pc(&self) -> u16 { 214 self.registers.pc 215 } 216 217 #[must_use] 218 pub fn is_mid_instruction(&self) -> bool { 219 !self.state.instruction_complete 220 } 221 222 #[must_use] 223 pub fn registers(&self) -> &CpuRegisters { 224 &self.registers 225 } 226 227 pub fn set_registers(&mut self, registers: CpuRegisters) { 228 self.registers = registers; 229 }