lemurs_8080/chip/
access.rs

1use crate::prelude::*;
2use core::{mem, ops::{Shl, ShlAssign}};
3
4/// This enumerates the internal byte registers of the 8080. You can access these
5/// by indexing the State struct with them; `let val = st[Register::D];`
6#[cfg(target_endian="little")]
7#[derive(Debug, Clone, Copy, PartialEq)]
8#[repr(u8)]
9pub enum Register {
10    A = 6,
11    B = 1,
12    C = 0,
13    D = 3,
14    E = 2,
15    H = 5,
16    L = 4,
17}
18
19#[cfg(target_endian="big")]
20#[derive(Debug, Clone, Copy, PartialEq)]
21#[repr(u8)]
22pub enum Register {
23    A = 6,
24    B = 0,
25    C = 1,
26    D = 2,
27    E = 3,
28    H = 4,
29    L = 5,
30}
31
32/// A register pair in the CPU, interpreted as a little-endian 16-bit value,
33/// where the `B`, `D` or `H` register contains the more-significant byte and
34/// the `C`, `E` or `L` register contains the less-significant byte.
35#[derive(Debug, Clone, Copy, PartialEq)]
36#[repr(u8)]
37pub enum Double {
38    BC = 0,
39    DE = 1,
40    HL = 2,
41}
42
43use self::{Register as R, Double as D, Internal as I, Word as W};
44
45/// `Byte` enumerates any one-byte region that can be specified for a read or write:
46#[derive(Debug, Clone, Copy, PartialEq)]
47pub enum Byte {
48    /// - A byte register on the CPU chip (B, C, D, E, H, L, A)
49    Single(Register),
50    /// - A byte in memory at the address contained in the `HL` register pair
51    Indirect,
52    /// - A byte in memory at a specified address (usually for ops like `LXI`)
53    RAM(u16),
54}
55
56/// Any of the 16-bit registers in the CPU, including the register pairs,
57/// but also the program counter and the stack pointer.
58#[derive(Debug, Clone, Copy, PartialEq)]
59pub enum Internal {
60    Wide(Double),
61    ProgramCounter,
62    StackPointer,
63}
64#[doc(hidden)]
65#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum Word {
67    OnBoard(Internal),
68    ProgramStatus,
69    RAM(u16),
70    Stack,
71}
72
73#[disclose(super)]
74impl State {
75    /// This method exposes the flag bits of the 8080 in the same format as the PSW
76    /// pseudo-register, `mz0a0p1c`, where
77    ///
78    /// - `m` is the sign flag;
79    /// - `z` is the zero flag;
80    /// - `a` is the auxilliary carry flag;
81    /// - `p` is the even-parity flag;
82    /// - `c` is the carry flag.
83    pub fn flags(&self) -> raw::u8 {
84        self.c as raw::u8 |
85        0b10u8 |
86        (self.p as raw::u8) << 2 |
87        (self.a as raw::u8) << 4 |
88        (self.z as raw::u8) << 6 |
89        (self.m as raw::u8) << 7
90    }
91    /// Whether or not the processor is in a stopped state (not executing operations from the PC).
92    /// The processor will return to an active state if it receives an interrupt.
93    ///
94    /// Note that if interrupts are disabled when the processor is halted, the processor will
95    /// remain stopped until it is reset from outside.
96    pub fn is_stopped(&self) -> bool { !self.active }
97    /// Whether the processor is accepting interrupts; this is disabled automatically when an
98    /// interrupt is received, to allow the interrupt to finish processing without being further
99    /// disrupted. It is also set by the `EI` operation and reset by the `DI` operation.
100    pub fn is_interrupt_ready(&self) -> bool { self.interrupts }
101    fn extract_flags(&mut self, bits: raw::u8) {
102        (self.c, self.p, self.a, self.z, self.m) = (
103            bits & 0b00000001 != 0,
104            bits & 0b00000100 != 0,
105            bits & 0b00010000 != 0,
106            bits & 0b01000000 != 0,
107            bits & 0b10000000 != 0,
108        );
109    }
110    #[must_use]
111    fn update_flags(&mut self) -> &mut bool {
112        self.update_flags_for(self[Register::A])
113    }
114    #[must_use]
115    fn update_flags_for(&mut self, value: u8) -> &mut bool {
116        let value = value.0;
117        let mut parity = value;
118        for offset in [4, 2, 1] {
119            parity ^= parity >> offset;
120        }
121        self.p = (parity & 0x01) == 0;
122        self.z = value == 0;
123        self.m = value & 0b1000_0000 != 0;
124        self.a = false;
125        &mut self.c
126    }
127    fn status(&self) -> u16 {
128        Wrapping(raw::u16::from_le_bytes([self[Register::A].0, self.flags()]))
129    }
130
131    fn push(&mut self) -> u16 {
132        self.sp -= 2;
133        self.sp
134    }
135
136    fn pop(&mut self) -> u16 {
137        let address = self.sp;
138        self.sp += 2;
139        address
140    }
141
142    fn resolve(&self, target: Byte) -> Byte {
143        match target {
144            Byte::Indirect => Byte::RAM(self[D::HL]),
145            _ => target
146        }
147    }
148}
149
150impl Index<Register> for State {
151    type Output = u8;
152    fn index(&self, index: Register) -> &Self::Output { &self.register[index as usize] }
153}
154
155impl IndexMut<Register> for State {
156    fn index_mut(&mut self, index: Register) -> &mut Self::Output { &mut self.register[index as usize] }
157}
158
159impl Index<Double> for State {
160    type Output = u16;
161    fn index(&self, index: Double) -> &Self::Output {
162        let index = 2 * index as raw::u8;
163        unsafe{ mem::transmute::<&u8, &Self::Output>(&self.register[index as usize]) }
164    }
165}
166
167impl IndexMut<Double> for State {
168    fn index_mut(&mut self, index: Double) -> &mut Self::Output {
169        let index = 2 * index as raw::u8;
170        unsafe{ mem::transmute::<&mut u8, &mut Self::Output>(&mut self.register[index as usize]) }
171    }
172}
173
174impl Index<Internal> for State {
175    type Output = u16;
176    fn index(&self, index: Internal) -> &Self::Output {
177        match index {
178            I::Wide(pair) => &self[pair],
179            I::ProgramCounter => &self.pc,
180            I::StackPointer => &self.sp,
181        }
182    }
183}
184
185impl IndexMut<Internal> for State {
186    fn index_mut(&mut self, index: Internal) -> &mut Self::Output {
187        match index {
188            I::Wide(pair) => &mut self[pair],
189            I::ProgramCounter => &mut self.pc,
190            I::StackPointer => &mut self.sp,
191        }
192    }
193}
194
195impl<H: Harness + ?Sized, C: BorrowMut<H>> Shl<&Machine<H, C>> for u16 {
196    type Output = u16;
197    fn shl(self, host: &Machine<H, C>) -> Self::Output {
198        host.read_word(self)
199    }
200}
201
202impl<H: Harness + ?Sized, C: BorrowMut<H>> Shl<&Machine<H, C>> for Word {
203    type Output = u16;
204    fn shl(self, host: &Machine<H, C>) -> Self::Output {
205        match self {
206            Self::OnBoard(internal) => host.chip[internal],
207            Self::ProgramStatus => {
208            	Wrapping(raw::u16::from_le_bytes([host.chip.register[6].0, host.chip.flags()]))
209            }
210            Self::RAM(i) => host.read_word(i),
211            Self::Stack => panic!("Can't pop from stack without mutate access"),
212        }
213    }
214}
215
216impl<H: Harness + ?Sized, C: BorrowMut<H>> Shl<&mut Machine<H, C>> for Word {
217    type Output = u16;
218    fn shl(self, host: &mut Machine<H, C>) -> Self::Output {
219        match self {
220            Word::Stack => {
221                let addr = host.chip.sp;
222                host.chip.sp += 2;
223                host.read_word(addr)
224            }
225            _ => self << &*host,
226        }
227    }
228}
229
230impl<H: Harness + ?Sized, C: BorrowMut<H>> ShlAssign<(u16, u16)> for Machine<H, C> {
231    fn shl_assign(&mut self, (index, value): (u16, u16)) {
232        self.write_word(index, value);
233    }
234}
235
236impl<H: Harness + ?Sized, C: BorrowMut<H>> ShlAssign<(Word, u16)> for Machine<H, C> {
237    fn shl_assign(&mut self, (index, value): (Word, u16)) {
238        match index {
239            W::OnBoard(internal) => self.chip[internal] = value,
240            W::RAM(address) => self.write_word(address, value),
241            W::ProgramStatus => {
242                let [a, f] = value.0.to_le_bytes();
243                self.chip[R::A] = Wrapping(a);
244                self.chip.extract_flags(f);
245            }
246            W::Stack => {
247                self.chip.sp -= 2;
248                let sp = self.chip.sp;
249                self.write_word(sp, value);
250            }
251        }
252    }
253}