lib.rsannotatedlib.rssource217 lines · 5.7 KB · raw
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    }

Execute a single instruction. Each CPU cycle will make exactly one call to bus.read(), bus.write(), or bus.idle().

When executing a block transfer instruction (TAI/TDD/TIA/TII/TIN), each call to this method 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    }
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}