1use crate::{CoreError, Cpu8080State, PortBus, TactOutcome, decode_opcode};
2
3struct TactSetup {
4 opcode: Option<u8>,
5 t_states: u8,
6 branch_taken: bool,
7}
8
9impl Cpu8080State {
10 pub fn step_tact<B: PortBus>(&mut self, bus: &mut B) -> Result<TactOutcome, CoreError> {
11 if self.active_tacts_remaining == 0 {
12 self.start_tact_walk()?;
13 }
14
15 let phase = self.active_tacts_total - self.active_tacts_remaining;
16 self.active_tacts_remaining -= 1;
17 self.cycle_count += 1;
18 self.last_completed_tact_phase = Some(phase);
19
20 let boundary = self.active_tacts_remaining == 0;
21 if boundary {
22 if self.active_opcode.is_some() || self.can_accept_interrupt() {
23 self.execute_instruction_boundary(bus)?;
24 }
25 self.clear_active_tact();
26 } else {
27 self.tact_phase = Some(phase + 1);
28 }
29
30 Ok(TactOutcome {
31 tact_phase: phase,
32 instruction_boundary: boundary,
33 cycle_count: self.cycle_count,
34 })
35 }
36
37 fn start_tact_walk(&mut self) -> Result<(), CoreError> {
38 let setup = self.tact_setup()?;
39 self.active_tacts_total = setup.t_states;
40 self.active_tacts_remaining = setup.t_states;
41 self.active_opcode = setup.opcode;
42 self.active_branch_taken = setup.branch_taken;
43 self.tact_phase = Some(0);
44
45 if let Some(opcode) = setup.opcode {
46 self.last_fetched_opcode = opcode;
47 self.last_address_bus = self.pc;
48 self.last_data_bus_byte = opcode;
49 }
50
51 Ok(())
52 }
53
54 fn tact_setup(&self) -> Result<TactSetup, CoreError> {
55 if self.can_accept_interrupt() {
56 return Ok(TactSetup {
57 opcode: self.interrupt_vector_byte,
58 t_states: 11,
59 branch_taken: true,
60 });
61 }
62 if self.halted {
63 return Ok(TactSetup {
64 opcode: None,
65 t_states: 1,
66 branch_taken: true,
67 });
68 }
69
70 let opcode = self.peek(self.pc);
71 let info = decode_opcode(opcode)?;
72 let branch_taken = self.branch_taken_for_tact(opcode);
73 Ok(TactSetup {
74 opcode: Some(opcode),
75 t_states: info.timing.for_branch(branch_taken),
76 branch_taken,
77 })
78 }
79
80 fn branch_taken_for_tact(&self, opcode: u8) -> bool {
81 if opcode & 0xC7 == 0xC0 || opcode & 0xC7 == 0xC2 || opcode & 0xC7 == 0xC4 {
82 self.condition((opcode >> 3) & 7)
83 } else {
84 true
85 }
86 }
87}