k580_core/machine_cycle/
mod.rs1mod tables;
7#[cfg(test)]
8mod tests;
9
10#[cfg(test)]
11pub(crate) use tables::kinds_for;
12pub use tables::{kind_at, layout_for};
13
14pub type MachineCycleLengths = &'static [u8];
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct MachineCycleLayout {
18 pub taken: MachineCycleLengths,
19 pub not_taken: Option<MachineCycleLengths>,
20}
21
22impl MachineCycleLayout {
23 pub const fn fixed(cycles: MachineCycleLengths) -> Self {
24 Self {
25 taken: cycles,
26 not_taken: None,
27 }
28 }
29
30 pub(crate) const fn branch(taken: MachineCycleLengths, not_taken: MachineCycleLengths) -> Self {
31 Self {
32 taken,
33 not_taken: Some(not_taken),
34 }
35 }
36
37 pub fn total_t_states(self, branch_taken: bool) -> u8 {
38 let cycles = if branch_taken {
39 self.taken
40 } else {
41 self.not_taken.unwrap_or(self.taken)
42 };
43 let mut sum = 0u8;
44 let mut i = 0;
45 while i < cycles.len() {
46 sum += cycles[i];
47 i += 1;
48 }
49 sum
50 }
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub struct MachineCyclePosition {
55 pub m_cycle: u8,
56 pub t_in_cycle: u8,
57 pub m_cycle_length: u8,
58}
59
60pub fn position_for(
61 layout: MachineCycleLayout,
62 branch_taken: bool,
63 linear_phase: u8,
64) -> Option<MachineCyclePosition> {
65 let cycles = if branch_taken {
66 layout.taken
67 } else {
68 layout.not_taken.unwrap_or(layout.taken)
69 };
70 if cycles.is_empty() {
71 return None;
72 }
73 let mut consumed = 0u8;
74 for (idx, &length) in cycles.iter().enumerate() {
75 if linear_phase < consumed + length {
76 return Some(MachineCyclePosition {
77 m_cycle: (idx as u8) + 1,
78 t_in_cycle: linear_phase - consumed + 1,
79 m_cycle_length: length,
80 });
81 }
82 consumed += length;
83 }
84 None
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq)]
92pub enum MachineCycleKind {
93 M1Fetch,
94 MemoryRead,
95 MemoryWrite,
96 StackRead,
97 StackWrite,
98 IoRead,
99 IoWrite,
100 InterruptAck,
101 HaltAck,
102 BusIdle,
104}
105
106impl MachineCycleKind {
107 pub fn status_byte(self) -> u8 {
108 match self {
109 Self::M1Fetch => 0b1010_0010,
110 Self::MemoryRead => 0b1000_0010,
111 Self::MemoryWrite => 0b0000_0000,
112 Self::StackRead => 0b1000_0110,
113 Self::StackWrite => 0b0000_0100,
114 Self::IoRead => 0b0100_0010,
115 Self::IoWrite => 0b0001_0000,
116 Self::InterruptAck => 0b0010_0011,
117 Self::HaltAck => 0b1000_1010,
118 Self::BusIdle => 0,
119 }
120 }
121
122 pub fn label_ru(self) -> &'static str {
123 match self {
124 Self::M1Fetch => "Загрузка опкода",
125 Self::MemoryRead => "Чтение памяти",
126 Self::MemoryWrite => "Запись в память",
127 Self::StackRead => "Чтение из стека",
128 Self::StackWrite => "Запись в стек",
129 Self::IoRead => "Чтение из порта",
130 Self::IoWrite => "Запись в порт",
131 Self::InterruptAck => "Подтв. прерывания",
132 Self::HaltAck => "Подтв. останова",
133 Self::BusIdle => "Внутренний цикл",
134 }
135 }
136
137 pub fn label_en(self) -> &'static str {
138 match self {
139 Self::M1Fetch => "Opcode fetch",
140 Self::MemoryRead => "Memory read",
141 Self::MemoryWrite => "Memory write",
142 Self::StackRead => "Stack read",
143 Self::StackWrite => "Stack write",
144 Self::IoRead => "Port read",
145 Self::IoWrite => "Port write",
146 Self::InterruptAck => "Interrupt ack",
147 Self::HaltAck => "Halt ack",
148 Self::BusIdle => "Internal cycle",
149 }
150 }
151}
152
153pub type MachineCycleKinds = &'static [MachineCycleKind];