robo6502/
lib.rs

1// Copyright 2018 Ed McCardell
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![cfg_attr(feature = "cargo-clippy", feature(tool_lints))]
10
11use std::fmt;
12
13use machine_int::MachineInt;
14
15use self::mi::Byte;
16
17pub use crate::mi::Addr;
18pub use crate::cmos::Cmos;
19pub use crate::nmos::Nmos;
20
21mod cmos;
22mod mi;
23mod nmos;
24
25#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
26pub enum NmiLength {
27    One,
28    Two,
29    Plenty,
30}
31
32pub trait Sys {
33    fn read(&mut self, addr: u16) -> Option<u8>;
34
35    fn write(&mut self, addr: u16, val: u8) -> Option<()>;
36
37    #[inline]
38    fn set_sync(&mut self, _set: bool) {}
39
40    #[inline]
41    fn poll_nmi(&mut self) -> bool {
42        false
43    }
44
45    #[inline]
46    fn peek_nmi(&self) -> bool {
47        false
48    }
49
50    #[inline]
51    fn nmi_length(&self) -> NmiLength {
52        NmiLength::Plenty
53    }
54
55    #[inline]
56    fn irq(&self) -> bool {
57        false
58    }
59}
60
61pub trait Cpu: Clone + fmt::Debug {
62    fn is_nmos(&self) -> bool;
63    fn reset(&mut self);
64    fn pc(&self) -> u16;
65    fn set_pc(&mut self, val: u16);
66    fn sp(&self) -> u8;
67    fn set_sp(&mut self, val: u8);
68    fn a(&self) -> u8;
69    fn set_a(&mut self, val: u8);
70    fn x(&self) -> u8;
71    fn set_x(&mut self, val: u8);
72    fn y(&self) -> u8;
73    fn set_y(&mut self, val: u8);
74    fn status(&self) -> u8;
75    fn set_status(&mut self, val: u8);
76    fn flag(&self, f: Status) -> bool;
77    fn set_flag(&mut self, f: Status, set: bool);
78    fn run_instruction<S: Sys>(&mut self, sys: &mut S) -> Option<()>;
79    fn instruction_cycle(&self) -> u32;
80    fn halted(&self) -> bool;
81}
82
83#[derive(Copy, Clone)]
84pub enum Status {
85    N,
86    V,
87    D,
88    I,
89    Z,
90    C,
91}
92
93#[derive(Clone, Default)]
94struct Flags {
95    n: Byte,
96    v: Byte,
97    _r: u8,
98    _b: u8,
99    d: bool,
100    i: bool,
101    z: Byte,
102    c: Byte,
103}
104
105impl Flags {
106    #[inline]
107    fn n(&self) -> bool {
108        (self.n & 0x80) != 0
109    }
110
111    #[inline]
112    fn set_n(&mut self, set: bool) {
113        self.n = MachineInt((set as u8) << 7)
114    }
115
116    #[inline]
117    fn v(&self) -> bool {
118        self.v != 0
119    }
120
121    #[inline]
122    fn set_v(&mut self, set: bool) {
123        self.v = MachineInt(set as u8);
124    }
125
126    #[inline]
127    fn d(&self) -> bool {
128        self.d
129    }
130
131    #[inline]
132    fn set_d(&mut self, set: bool) {
133        self.d = set
134    }
135
136    #[inline]
137    fn i(&self) -> bool {
138        self.i
139    }
140
141    #[inline]
142    fn set_i(&mut self, set: bool) {
143        self.i = set
144    }
145
146    #[inline]
147    fn z(&self) -> bool {
148        self.z == 0
149    }
150
151    #[inline]
152    fn set_z(&mut self, set: bool) {
153        self.z = MachineInt(!set as u8);
154    }
155
156    #[inline]
157    pub fn c(&self) -> bool {
158        self.c != 0
159    }
160
161    #[inline]
162    pub fn set_c(&mut self, set: bool) {
163        self.c = MachineInt(set as u8);
164    }
165
166    #[inline]
167    fn nz(&mut self, val: Byte) {
168        self.n = val;
169        self.z = val;
170    }
171
172    fn to_byte(&self) -> Byte {
173        self.n & 0x80
174            | (self.v() as u8) << 6
175            | 0x30
176            | (self.d as u8) << 3
177            | (self.i as u8) << 2
178            | (self.z() as u8) << 1
179            | self.c
180    }
181
182    #[cfg_attr(
183        feature = "cargo-clippy",
184        allow(clippy::wrong_self_convention)
185    )]
186    fn from_byte(&mut self, val: Byte) {
187        self.n = val;
188        self.v = val & 0x40;
189        self.d = (val & 0x08) != 0;
190        self.i = (val & 0x04) != 0;
191        self.set_z((val & 0x02) != 0);
192        self.c = val & 1;
193    }
194}
195
196impl fmt::Debug for Flags {
197    #[cfg_attr(
198        feature = "cargo-clippy",
199        allow(clippy::many_single_char_names)
200    )]
201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202        let n = if self.n() { "N" } else { "n" };
203        let v = match self.v.0 {
204            0 => "v",
205            _ => "V",
206        };
207        let d = if self.d { "D" } else { "d" };
208        let i = if !self.i { "i" } else { "I" };
209        let z = match self.z.0 {
210            0 => "Z",
211            _ => "z",
212        };
213        let c = match self.c.0 {
214            0 => "c",
215            _ => "C",
216        };
217        write!(f, "{}{}-B{}{}{}{}", n, v, d, i, z, c)
218    }
219}
220
221#[cfg(test)]
222mod test;