Skip to main content

k580_core/
tact.rs

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}