1use crate::{
2 CoreError, Flags, MachineCycleLayout, Memory64K, PortBus, RegisterName, Registers,
3 ValidationError,
4};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Cpu8080State {
8 pub registers: Registers,
9 pub pc: u16,
10 pub sp: u16,
11 pub flags: Flags,
12 pub memory: Memory64K,
13 pub interrupt_request_pending: bool,
14 pub interrupt_enable: bool,
15 pub interrupt_enable_pending: bool,
16 pub halted: bool,
17 pub cycle_count: u64,
18 pub interrupt_vector_byte: Option<u8>,
19 pub tact_phase: Option<u8>,
20 pub last_completed_tact_phase: Option<u8>,
25 pub(crate) active_tacts_remaining: u8,
26 pub(crate) active_tacts_total: u8,
27 pub(crate) active_opcode: Option<u8>,
28 pub(crate) active_branch_taken: bool,
29 pub last_fetched_opcode: u8,
33 pub last_data_bus_byte: u8,
36 pub last_address_bus: u16,
40}
41
42impl Default for Cpu8080State {
44 fn default() -> Self {
45 Self {
46 registers: Registers::default(),
47 pc: 0,
48 sp: Self::RESET_SP,
49 flags: Flags::default(),
50 memory: Memory64K::default(),
51 interrupt_request_pending: false,
52 interrupt_enable: false,
53 interrupt_enable_pending: false,
54 halted: false,
55 cycle_count: 0,
56 interrupt_vector_byte: None,
57 tact_phase: None,
58 last_completed_tact_phase: None,
59 active_tacts_remaining: 0,
60 active_tacts_total: 0,
61 active_opcode: None,
62 active_branch_taken: true,
63 last_fetched_opcode: 0,
64 last_data_bus_byte: 0,
65 last_address_bus: 0,
66 }
67 }
68}
69
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct InstructionOutcome {
72 pub opcode: Option<u8>,
73 pub mnemonic: String,
74 pub pc_before: u16,
75 pub pc_after: u16,
76 pub t_states: u8,
77 pub halted: bool,
78 pub interrupt_accepted: bool,
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct TactOutcome {
83 pub tact_phase: u8,
84 pub instruction_boundary: bool,
85 pub cycle_count: u64,
86}
87
88impl Cpu8080State {
89 pub const RESET_SP: u16 = 0xFFFF;
92
93 pub fn reset_cpu(&mut self) {
94 let memory = core::mem::take(&mut self.memory);
95 *self = Self {
96 memory,
97 sp: Self::RESET_SP,
98 ..Self::default()
99 };
100 }
101
102 pub fn reset_ram(&mut self) {
103 self.memory.clear();
104 }
105
106 pub fn request_interrupt(&mut self, vector_byte: u8) {
107 self.interrupt_request_pending = true;
108 self.interrupt_vector_byte = Some(vector_byte);
109 }
110
111 pub fn set_register(&mut self, register: RegisterName, value: u8) {
112 self.registers.set(register, value);
113 }
114
115 pub fn get_register(&self, register: RegisterName) -> u8 {
116 self.registers.get(register)
117 }
118
119 pub fn set_memory(&mut self, address: u16, value: u8) {
120 self.memory.write(address, value);
121 }
122
123 pub fn set_memory_block(&mut self, start: u16, values: &[u8]) -> Result<(), ValidationError> {
124 let end = u32::from(start) + values.len() as u32;
125 if end > Memory64K::SIZE as u32 {
126 return Err(ValidationError::MemoryRange { start, end });
127 }
128 self.memory.as_mut_slice()[start as usize..end as usize].copy_from_slice(values);
129 Ok(())
130 }
131
132 pub(crate) fn bus_read(&mut self, address: u16) -> u8 {
135 let value = self.memory.read(address);
136 self.last_address_bus = address;
137 self.last_data_bus_byte = value;
138 value
139 }
140
141 pub(crate) fn bus_write(&mut self, address: u16, value: u8) {
142 self.memory.write(address, value);
143 self.last_address_bus = address;
144 self.last_data_bus_byte = value;
145 }
146
147 pub(crate) fn bus_read_word(&mut self, address: u16) -> u16 {
149 let lo = self.bus_read(address);
150 let hi = self.bus_read(address.wrapping_add(1));
151 u16::from(lo) | (u16::from(hi) << 8)
152 }
153
154 pub(crate) fn fetch_opcode(&mut self) -> u8 {
155 let opcode = self.bus_read(self.pc);
156 self.last_fetched_opcode = opcode;
157 opcode
158 }
159
160 pub fn peek(&self, address: u16) -> u8 {
163 self.memory.read(address)
164 }
165
166 pub fn step_instruction<B: PortBus>(
167 &mut self,
168 bus: &mut B,
169 ) -> Result<InstructionOutcome, CoreError> {
170 if self.active_tacts_remaining > 0 {
171 let remaining = self.active_tacts_remaining;
172 let total = self.active_tacts_total;
173 let outcome = self.execute_instruction_boundary(bus)?;
174 self.cycle_count += u64::from(remaining);
175 if total > 0 {
176 self.last_completed_tact_phase = Some(total - 1);
177 }
178 self.clear_active_tact();
179 return Ok(outcome);
180 }
181
182 let outcome = self.execute_instruction_boundary(bus)?;
183 self.cycle_count += u64::from(outcome.t_states);
184 if outcome.t_states > 0 {
185 self.last_completed_tact_phase = Some(outcome.t_states - 1);
186 }
187 Ok(outcome)
188 }
189
190 pub(crate) fn clear_active_tact(&mut self) {
191 self.active_tacts_remaining = 0;
192 self.active_tacts_total = 0;
193 self.active_opcode = None;
194 self.active_branch_taken = true;
195 self.tact_phase = None;
196 }
197
198 pub fn timing_opcode(&self) -> u8 {
199 self.active_opcode.unwrap_or(self.last_fetched_opcode)
200 }
201
202 pub fn timing_branch_taken(&self, layout: MachineCycleLayout, phase: u8) -> bool {
203 if self.active_tacts_remaining > 0 {
204 return self.active_branch_taken;
205 }
206 if let Some(not_taken) = layout.not_taken {
207 let not_taken_total: u8 = not_taken.iter().sum();
208 if phase < not_taken_total {
209 return false;
210 }
211 }
212 true
213 }
214
215 pub fn tact_walk_active(&self) -> bool {
216 self.active_tacts_remaining > 0
217 }
218
219 pub fn run_for_t_states<B: PortBus>(
220 &mut self,
221 bus: &mut B,
222 t_states: u64,
223 ) -> Result<(), CoreError> {
224 for _ in 0..t_states {
225 self.step_tact(bus)?;
226 }
227 Ok(())
228 }
229
230 pub fn run_until_halt<B: PortBus>(
231 &mut self,
232 bus: &mut B,
233 max_instructions: u64,
234 ) -> Result<u64, CoreError> {
235 let mut executed = 0;
236 while !self.halted && executed < max_instructions {
237 self.step_instruction(bus)?;
238 executed += 1;
239 }
240 Ok(executed)
241 }
242}