chiprust_emu/
display.rs

1use std::cmp::Ordering;
2
3/// Expands 8-bit integer to 16-bit like this:
4/// 0b01010111 -> 0b0011001100111111
5/// 0b10101010 -> 0b1100110011001100
6fn expand(n: u8) -> u16 {
7    let mut result: u16 = 0;
8    for i in 0..8 {
9        result |= (n as u16 & (1 << i)) << i
10    }
11    result | (result << 1)
12}
13
14#[inline(always)]
15pub fn get_px(d: &[u128; 64], x: usize, y: usize) -> bool {
16    let (shifted, _) = d[y].overflowing_shr(127 - x as u32);
17    (shifted & 1) == 1
18}
19
20pub struct Display {
21    d: Box<[u128; 64]>,
22    hi_res: bool,
23    dirty: bool,
24}
25
26impl Display {
27    pub fn new() -> Display {
28        Display {
29            d: Box::new([0; 64]),
30            hi_res: false,
31            dirty: false,
32        }
33    }
34
35    pub fn hi_res_mode(&mut self) {
36        self.hi_res = true
37    }
38
39    pub fn low_res_mode(&mut self) {
40        self.hi_res = false
41    }
42
43    pub fn scroll_down(&mut self, n: u32) {
44        let n = n as usize;
45        self.dirty = true;
46        self.d.copy_within(..64-n, n);
47        for i in 0..n {
48            self.d[i] = 0
49        }
50    }
51
52    #[allow(arithmetic_overflow)]
53    pub fn scroll_side(&mut self, n: i32) {
54        self.dirty = true;
55        for row in &mut *self.d {
56            match n.cmp(&0) {
57                Ordering::Greater => *row >>= n,
58                Ordering::Less => *row <<= n.abs(),
59                Ordering::Equal => {},
60            }
61        }
62    }
63
64    pub fn clear(&mut self) {
65        self.dirty = true;
66        self.d = Box::new([0; 64])
67    }
68
69    pub fn write(&mut self, b: u8, mut x: usize, mut y: usize) -> bool {
70        let b = if !self.hi_res {
71            x *= 2;
72            y *= 2;
73            expand(b)
74        } else {
75            (b as u16) << 8
76        };
77
78        let x = x % 128;
79        let y = y % 64;
80
81        let mut erased = false;
82        self.dirty = true;
83        let mut b = (b as u128) << 112;
84        b = b.rotate_right(x as u32);
85
86        if b & self.d[y] != 0 {
87            erased = true
88        };
89        self.d[y] ^= b;
90
91        if !self.hi_res {
92            if b & self.d[y + 1] != 0 {
93                erased = true
94            };
95            self.d[y + 1] ^= b;
96        }
97
98        erased
99    }
100
101    pub fn read(&mut self) -> &[u128; 64] {
102        self.dirty = false;
103        &self.d
104    }
105
106    pub fn read_px(&mut self, x: usize, y: usize) -> bool {
107        self.dirty = false;
108        get_px(&self.d, x, y)
109    }
110
111    pub fn hi_res(&self) -> bool {
112        self.hi_res
113    }
114
115    pub fn dirty(&self) -> bool {
116        self.dirty
117    }
118}
119
120impl Default for Display {
121    fn default() -> Self {
122        Display::new()
123    }
124}
125
126pub const DEFAULT_FONT: [u8; 240] = [
127    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
128    0x20, 0x60, 0x20, 0x20, 0x70, // 1
129    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
130    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
131    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
132    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
133    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
134    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
135    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
136    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
137    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
138    0xE0, 0x90, 0xe0, 0x90, 0xE0, // B
139    0xF0, 0x80, 0x80, 0x80, 0x80, // C
140    0xF0, 0x90, 0x90, 0x90, 0xE0, // D
141    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
142    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
143    // Super CHIP fonts
144    0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, // 0
145    0x18, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, // 1
146    0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, // 2
147    0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, // 3
148    0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, // 4
149    0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, // 5
150    0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, // 6
151    0xFF, 0xFF, 0x03, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18, // 7
152    0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, // 8
153    0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, // 9
154    0x7E, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, // A
155    0xFC, 0xFC, 0xC3, 0xC3, 0xFC, 0xFC, 0xC3, 0xC3, 0xFC, 0xFC, // B
156    0x3C, 0xFF, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xFF, 0x3C, // C
157    0xFC, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, 0xFC, // D
158    0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, // E
159    0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, // F
160];