Skip to main content

mc6809_core/
registers.rs

1//   Copyright 2026 Martin Ã…kesson
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15use std::fmt;
16
17// ---------------------------------------------------------------------------
18// Condition Code Register
19// ---------------------------------------------------------------------------
20
21/// Bit positions in the CC register.
22pub(crate) const CC_C: u8 = 0x01; // Carry
23pub(crate) const CC_V: u8 = 0x02; // Overflow
24pub(crate) const CC_Z: u8 = 0x04; // Zero
25pub(crate) const CC_N: u8 = 0x08; // Negative
26pub(crate) const CC_I: u8 = 0x10; // IRQ inhibit
27pub(crate) const CC_H: u8 = 0x20; // Half-carry
28pub(crate) const CC_F: u8 = 0x40; // FIRQ inhibit
29pub(crate) const CC_E: u8 = 0x80; // Entire state saved
30
31/// The 6809 Condition Code register, stored as a packed byte.
32///
33/// `#[repr(transparent)]` guarantees that this type has exactly the same
34/// memory layout as a `u8`, making it safe to use in `#[repr(C)]` structs
35/// and directly accessible from JIT-emitted code.
36#[repr(transparent)]
37#[derive(Clone, Copy, Default, PartialEq, Eq)]
38pub struct ConditionCodes(pub(crate) u8);
39impl ConditionCodes {
40    pub const fn new() -> Self {
41        Self(0)
42    }
43
44    pub const fn from_byte(b: u8) -> Self {
45        Self(b)
46    }
47
48    pub const fn to_byte(self) -> u8 {
49        self.0
50    }
51
52    // ---- flag readers ----
53
54    pub const fn carry(self) -> bool {
55        self.0 & CC_C != 0
56    }
57    pub const fn overflow(self) -> bool {
58        self.0 & CC_V != 0
59    }
60    pub const fn zero(self) -> bool {
61        self.0 & CC_Z != 0
62    }
63    pub const fn negative(self) -> bool {
64        self.0 & CC_N != 0
65    }
66    pub const fn irq_inhibit(self) -> bool {
67        self.0 & CC_I != 0
68    }
69    pub const fn half_carry(self) -> bool {
70        self.0 & CC_H != 0
71    }
72    pub const fn firq_inhibit(self) -> bool {
73        self.0 & CC_F != 0
74    }
75    pub const fn entire(self) -> bool {
76        self.0 & CC_E != 0
77    }
78
79    // ---- flag writers ----
80
81    pub fn set_carry(&mut self, v: bool) {
82        self.set_bit(CC_C, v);
83    }
84    pub fn set_overflow(&mut self, v: bool) {
85        self.set_bit(CC_V, v);
86    }
87    pub fn set_zero(&mut self, v: bool) {
88        self.set_bit(CC_Z, v);
89    }
90    pub fn set_negative(&mut self, v: bool) {
91        self.set_bit(CC_N, v);
92    }
93    pub fn set_irq_inhibit(&mut self, v: bool) {
94        self.set_bit(CC_I, v);
95    }
96    pub fn set_half_carry(&mut self, v: bool) {
97        self.set_bit(CC_H, v);
98    }
99    pub fn set_firq_inhibit(&mut self, v: bool) {
100        self.set_bit(CC_F, v);
101    }
102    pub fn set_entire(&mut self, v: bool) {
103        self.set_bit(CC_E, v);
104    }
105
106    /// Set N and Z based on an 8-bit result.
107    pub fn set_nz8(&mut self, val: u8) {
108        self.set_negative(val & 0x80 != 0);
109        self.set_zero(val == 0);
110    }
111
112    /// Set N and Z based on a 16-bit result.
113    pub fn set_nz16(&mut self, val: u16) {
114        self.set_negative(val & 0x8000 != 0);
115        self.set_zero(val == 0);
116    }
117
118    /// OR the CC byte with a mask (used by ORCC).
119    pub fn or_with(&mut self, mask: u8) {
120        self.0 |= mask;
121    }
122
123    /// AND the CC byte with a mask (used by ANDCC).
124    pub fn and_with(&mut self, mask: u8) {
125        self.0 &= mask;
126    }
127
128    fn set_bit(&mut self, mask: u8, v: bool) {
129        if v {
130            self.0 |= mask;
131        } else {
132            self.0 &= !mask;
133        }
134    }
135}
136
137impl fmt::Debug for ConditionCodes {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        write!(
140            f,
141            "CC({:02X} {}{}{}{}{}{}{}{})",
142            self.0,
143            if self.entire() { 'E' } else { '.' },
144            if self.firq_inhibit() { 'F' } else { '.' },
145            if self.half_carry() { 'H' } else { '.' },
146            if self.irq_inhibit() { 'I' } else { '.' },
147            if self.negative() { 'N' } else { '.' },
148            if self.zero() { 'Z' } else { '.' },
149            if self.overflow() { 'V' } else { '.' },
150            if self.carry() { 'C' } else { '.' },
151        )
152    }
153}
154
155impl fmt::Display for ConditionCodes {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        fmt::Debug::fmt(self, f)
158    }
159}
160
161// ---------------------------------------------------------------------------
162// Register file
163// ---------------------------------------------------------------------------
164
165/// The 6809 programmer-visible register set.
166///
167/// Register D is stored as a `u16` with A in the high byte and B in the low byte,
168/// matching the hardware layout.
169///
170/// `#[repr(C)]` guarantees a stable, predictable memory layout for use in
171/// JIT-compiled code and FFI contexts. Field offsets (bytes):
172/// `d`=0, `x`=2, `y`=4, `u`=6, `s`=8, `pc`=10, `dp`=12, `cc`=13.
173#[repr(C)]
174#[derive(Clone, Copy, Debug, Default)]
175pub struct Registers {
176    /// Accumulator D (A:B). A = high byte, B = low byte.
177    pub d: u16,
178    /// Index register X
179    pub x: u16,
180    /// Index register Y
181    pub y: u16,
182    /// User stack pointer
183    pub u: u16,
184    /// Hardware stack pointer
185    pub s: u16,
186    /// Program counter
187    pub pc: u16,
188    /// Direct page register
189    pub dp: u8,
190    /// Condition codes
191    pub cc: ConditionCodes,
192}
193
194impl Registers {
195    pub const fn new() -> Self {
196        Self {
197            d: 0,
198            x: 0,
199            y: 0,
200            u: 0,
201            s: 0,
202            pc: 0,
203            dp: 0,
204            cc: ConditionCodes::new(),
205        }
206    }
207
208    // ---- A / B accessors (D = A:B, big-endian) ----
209
210    /// Read accumulator A (high byte of D).
211    pub const fn a(self) -> u8 {
212        (self.d >> 8) as u8
213    }
214
215    /// Read accumulator B (low byte of D).
216    pub const fn b(self) -> u8 {
217        self.d as u8
218    }
219
220    /// Write accumulator A (high byte of D), preserving B.
221    pub fn set_a(&mut self, val: u8) {
222        self.d = (self.d & 0x00FF) | ((val as u16) << 8);
223    }
224
225    /// Write accumulator B (low byte of D), preserving A.
226    pub fn set_b(&mut self, val: u8) {
227        self.d = (self.d & 0xFF00) | (val as u16);
228    }
229}
230
231impl fmt::Display for Registers {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        write!(
234            f,
235            "PC={:04X} A={:02X} B={:02X} X={:04X} Y={:04X} U={:04X} S={:04X} DP={:02X} {}",
236            self.pc,
237            self.a(),
238            self.b(),
239            self.x,
240            self.y,
241            self.u,
242            self.s,
243            self.dp,
244            self.cc,
245        )
246    }
247}