1pub mod bus; 2mod instructions; 3 4use crate::bus::{BusInterface, InterruptLines}; 5use crate::instructions::InstructionExecutor; 6use bincode::{Decode, Encode}; 7use jgenesis_common::num::GetBit; 8use std::array; 9 10#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 11pub struct Flags { 12 pub negative: bool, 13 pub overflow: bool, 14 pub memory_op: bool, // T bit; causes AND/ORA/EOR/ADC to operate on ZeroPage[X] instead of A 15 pub decimal: bool, 16 pub irq_disable: bool, 17 pub zero: bool, 18 pub carry: bool, 19} 20 21impl Flags { 22 fn random() -> Self { 23 Self { 24 negative: rand::random(), 25 overflow: rand::random(), 26 memory_op: rand::random(), 27 decimal: rand::random(), 28 irq_disable: rand::random(), 29 zero: rand::random(), 30 carry: rand::random(), 31 } 32 } 33 34 #[must_use] 35 pub fn to_u8_interrupt(self) -> u8 { 36 (u8::from(self.negative) << 7) 37 | (u8::from(self.overflow) << 6) 38 | (u8::from(self.memory_op) << 5) 39 | (u8::from(self.decimal) << 3) 40 | (u8::from(self.irq_disable) << 2) 41 | (u8::from(self.zero) << 1) 42 | u8::from(self.carry) 43 } 44 45 #[must_use] 46 pub fn to_u8_brk(self) -> u8 { 47 self.to_u8_interrupt() | (1 << 4) 48 } 49 50 fn set_zero_negative(&mut self, value: u8) { 51 self.zero = value == 0; 52 self.negative = value.bit(7); 53 } 54} 55 56impl From<u8> for Flags { 57 fn from(value: u8) -> Self { 58 Self { 59 negative: value.bit(7), 60 overflow: value.bit(6), 61 memory_op: value.bit(5), 62 decimal: value.bit(3), 63 irq_disable: value.bit(2), 64 zero: value.bit(1), 65 carry: value.bit(0), 66 } 67 } 68} 69 70#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] 71pub struct Registers { 72 pub a: u8, 73 pub x: u8, 74 pub y: u8, 75 pub pc: u16, 76 pub s: u8, 77 pub p: Flags, 78 pub mpr: [u8; 8], 79} 80 81impl Registers { 82 fn random() -> Self { 83 Self { 84 a: rand::random(), 85 x: rand::random(), 86 y: rand::random(), 87 pc: rand::random(), 88 s: rand::random(), 89 p: Flags::random(), 90 mpr: array::from_fn(|_| rand::random()), 91 } 92 } 93 94 fn map_address(&self, logical_addr: u16) -> u32 { 95 let bank_base_addr = u32::from(self.mpr[(logical_addr >> 13) as usize]) << 13; 96 bank_base_addr | u32::from(logical_addr & 0x1FFF) 97 } 98} 99 100#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 101enum BlockTransferStep { 102 Increment, 103 Decrement, 104 Alternate, 105 None, 106} 107 108impl BlockTransferStep { 109 #[must_use] 110 fn apply(self, address: u16, count: u8) -> u16 { 111 match self { 112 Self::Increment => address.wrapping_add(1), 113 Self::Decrement => address.wrapping_sub(1), 114 Self::Alternate => { 115 if count & 1 == 0 { 116 address.wrapping_add(1) 117 } else { 118 address.wrapping_sub(1) 119 } 120 } 121 Self::None => address, 122 } 123 } 124} 125 126#[derive(Debug, Clone, Encode, Decode)] 127struct BlockTransferState { 128 source: u16, 129 destination: u16, 130 length: u16, 131 source_step: BlockTransferStep, 132 destination_step: BlockTransferStep, 133 count: u8, 134} 135 136#[derive(Debug, Clone, Encode, Decode)] 137struct State { 138 memory_op_at_fetch: bool, // T bit at the most recent opcode fetch (before it gets cleared) 139 mpr_buffer: u8, // Last MPR read or write in a TAM/TMA instruction 140 pending_interrupt: bool, 141 latched_interrupt_lines: InterruptLines, 142 block_transfer: Option<BlockTransferState>, 143} 144 145impl State { 146 fn new() -> Self { 147 Self { 148 memory_op_at_fetch: false, 149 mpr_buffer: 0, 150 pending_interrupt: false, 151 latched_interrupt_lines: InterruptLines::default(), 152 block_transfer: None, 153 } 154 } 155} 156 157#[derive(Debug, Clone, Encode, Decode)] 158pub struct Huc6280 { 159 registers: Registers, 160 state: State, 161} 162 163impl Huc6280 { 164 #[must_use] 165 pub fn new() -> Self { 166 Self { registers: Registers::random(), state: State::new() } 167 } 168 169 pub fn reset(&mut self, bus: &mut impl BusInterface) { 170 // Most register contents are randomized at power-on but MPR7 is always $00, T and D are 171 // always clear, and I is always set 172 self.registers.mpr[7] = 0x00; 173 174 self.registers.p.memory_op = false; 175 self.registers.p.decimal = false; 176 self.registers.p.irq_disable = true; 177 178 // RESET vector is always read from physical address $001FFE ($FFFE with MPR7=$00) 179 let pc_lsb = bus.read(0x001FFE); 180 let pc_msb = bus.read(0x001FFF); 181 self.registers.pc = u16::from_le_bytes([pc_lsb, pc_msb]); 182 183 self.state = State::new(); 184 } 185 186 /// Execute a single instruction. Each CPU cycle will make exactly one call to `bus.read()`, 187 /// `bus.write()`, or `bus.idle()`. 188 /// 189 /// When executing a block transfer instruction (TAI/TDD/TIA/TII/TIN), each call to this method 190 /// will progress the transfer by one byte. 191 pub fn execute_instruction(&mut self, bus: &mut impl BusInterface) { 192 InstructionExecutor::new(self, bus).execute_instruction(); 193 } 194 195 #[cfg(feature = "test-apis")] 196 #[must_use] 197 pub fn registers(&self) -> &Registers { 198 &self.registers 199 } 200 201 #[cfg(feature = "test-apis")] 202 pub fn set_registers(&mut self, registers: Registers) { 203 self.registers = registers; 204 } 205 206 #[cfg(feature = "test-apis")] 207 #[must_use] 208 pub fn is_mid_block_transfer(&self) -> bool { 209 self.state.block_transfer.is_some() 210 } 211} 212 213impl Default for Huc6280 { 214 fn default() -> Self { 215 Self::new() 216 } 217}