scroll down works on CHIP-8 and High-Res modes

scroll left and right work in stdef and hidef
adds octo test roms
adds schip fonts to memory
This commit is contained in:
2024-10-25 08:19:03 -04:00
parent a978ddc41e
commit e29ac45c84
65 changed files with 13342 additions and 230 deletions
+2 -1
View File
@@ -44,6 +44,7 @@ impl Chip8Computer {
self.registers.reset();
self.delay_timer.reset();
self.sound_timer.reset();
self.stack.reset();
}
pub fn dump_keypad_to_string(&self) -> String {
@@ -55,7 +56,7 @@ impl Chip8Computer {
}
pub fn dump_video_to_string(&self) -> String {
self.video_memory.format_as_string()
self.clone().video_memory.format_as_string()
}
pub fn new_with_program(new_program: Vec<u16>) -> Self {
+1 -3
View File
@@ -5,14 +5,12 @@ use std::time::{Duration, Instant};
use crate::chip8::computer::Chip8Computer;
use crate::chip8::cpu_states::Chip8CpuStates;
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
pub enum ManagerDumpables {
Video,
Registers,
Keyboard
}
pub struct Chip8ComputerManager {
core_should_run: bool,
one_step: bool,
@@ -76,7 +74,7 @@ impl Chip8ComputerManager {
WaitingForInstruction => {
self.core_last_cycle_start = Instant::now();
self.computer.step_system();
println!("SYSTEM STEP");
// println!("SYSTEM STEP");
}
_ => {}
}
+8 -6
View File
@@ -880,25 +880,27 @@ impl Chip8CpuInstructions {
}
Chip8CpuInstructions::XXXXERRORINSTRUCTION => {}
Chip8CpuInstructions::SDN(x) => {
println!("SCROLLING DOWN {x} LINES");
input.video_memory.scroll_down(*x as i32);
}
Chip8CpuInstructions::SRT => {
println!("SCROLING RIGHT 4 LINES");
input.video_memory.scroll_right();
}
Chip8CpuInstructions::SLF => {
println!("SCROLLING LEFT 4 LINES");
input.video_memory.scroll_left();
}
Chip8CpuInstructions::DIS => {
println!("DISABLE VIDEO MODE");
input.video_memory.set_lowres();
}
Chip8CpuInstructions::ENA => {
println!("ENABLE VIDEO MODE");
input.video_memory.set_highres();
}
Chip8CpuInstructions::EXIT => {
println!("EXIT INTERPRETER");
}
Chip8CpuInstructions::LDF2(x) => {
println!("POINTING TO FONT AT {x:02x}");
// base = 0x100 + 0x0A*X
input.registers.poke_i(0x100 + (0xA * x) as u16);
}
Chip8CpuInstructions::STR(x) => {
println!("STORING FROM RPL FOR {x}");
@@ -922,7 +924,7 @@ impl Chip8CpuInstructions {
#[cfg(test)]
mod test {
use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_9};
use crate::chip8::system_memory::{*};
use crate::constants::CHIP8_VIDEO_MEMORY;
use super::*;
+4
View File
@@ -34,6 +34,10 @@ impl Chip8Stack {
items: vec![]
}
}
pub fn reset(&mut self) {
self.items = vec![]
}
}
#[cfg(test)]
+18 -19
View File
@@ -1,24 +1,6 @@
use log::{trace};
use crate::constants::{CHIP8_MEMORY_SIZE};
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
pub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0];
pub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10];
pub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0];
pub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40];
pub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0];
pub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90];
pub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0];
pub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0];
pub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];
pub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];
pub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80];
use crate::constants::*;
#[derive(Clone, Copy)]
pub struct Chip8SystemMemory {
@@ -33,6 +15,7 @@ impl Default for Chip8SystemMemory {
};
x.load_fonts_to_memory();
x.load_schip_fonts_to_memory();
x
}
}
@@ -87,6 +70,22 @@ impl Chip8SystemMemory {
}
}
}
pub fn load_schip_fonts_to_memory(&mut self) {
let all_font_characters = [
SCHIPFONT_0, SCHIPFONT_1, SCHIPFONT_2, SCHIPFONT_3,
SCHIPFONT_4, SCHIPFONT_5, SCHIPFONT_6, SCHIPFONT_7,
SCHIPFONT_8, SCHIPFONT_9, SCHIPFONT_A, SCHIPFONT_B,
SCHIPFONT_C, SCHIPFONT_D, SCHIPFONT_E, SCHIPFONT_F
];
for (font_index, current_font) in all_font_characters.iter().enumerate() {
let base_offset = 0x100;
for font_mem_offset in 0..=4 {
let real_offset = base_offset + font_index * 0x10 + font_mem_offset;
self.poke(real_offset as u16, current_font[font_mem_offset]);
}
}
}
}
#[cfg(test)]
+213 -102
View File
@@ -1,18 +1,18 @@
use log::{debug};
use crate::chip8::video::Chip8VideoModes::{HighRes, LowRes};
use crate::constants::{CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY};
use crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH};
#[derive(Clone, Copy)]
enum Chip8VideoModes {
LowRes,
HighRes
HighRes,
}
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct Chip8Video {
memory: [bool; CHIP8_VIDEO_MEMORY],
memory: Vec<bool>,
pub has_frame_changed: bool,
current_res: Chip8VideoModes
current_res: Chip8VideoModes,
}
impl Chip8Video {
@@ -21,13 +21,13 @@ impl Chip8Video {
self.start_frame();
}
pub fn is_highres(&self) -> bool {
matches!(self.current_res, HighRes)
}
pub fn set_highres(&mut self) {
self.current_res = HighRes
self.current_res = HighRes;
self.cls();
}
pub fn set_lowres(&mut self) {
@@ -39,14 +39,17 @@ impl Chip8Video {
}
pub fn cls(&mut self) {
match self.current_res {
self.memory.clear();
let num_loops = match self.current_res {
LowRes => {
self.memory = [false; CHIP8_VIDEO_MEMORY];
CHIP8_VIDEO_MEMORY
}
HighRes => {
// self.memory = [0u8; ]
SCHIP_VIDE_MEMORY
}
};
for i in 0..num_loops {
self.memory.push(false);
}
}
@@ -54,15 +57,15 @@ impl Chip8Video {
self.has_frame_changed = false;
}
pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self {
pub fn new(initial_configuration: Box<Vec<bool>>) -> Self {
Self {
memory: initial_configuration,
memory: *initial_configuration,
has_frame_changed: false,
current_res: Chip8VideoModes::LowRes,
}
}
pub fn peek(self, address: u16) -> bool {
pub fn peek(&self, address: u16) -> bool {
let loop_value: u16 = if self.is_highres() {
SCHIP_VIDE_MEMORY as u16
} else {
@@ -75,12 +78,7 @@ impl Chip8Video {
}
pub fn poke(&mut self, address: u16, new_value: bool) {
// println!("OFFSET: {address} - POKING {new_value}");
let loop_value: u16 = if self.is_highres() {
SCHIP_VIDE_MEMORY as u16
} else {
CHIP8_VIDEO_MEMORY as u16
};
let loop_value: u16 = self.get_memory_size() as u16;
// Loop the address
let effective_address = address % loop_value;
@@ -93,6 +91,7 @@ impl Chip8Video {
};
}
// println!("VIDEO POKE COMPLETE WITH {effective_address} SET TO {xored_value}");
self.memory[effective_address as usize] = xored_value;
}
@@ -110,13 +109,15 @@ impl Chip8Video {
}
}
pub fn format_as_string(self) -> String {
pub fn format_as_string(&self) -> String {
let (width, height) = self.get_resolution();
println!("FORMATTING {width}x{height}");
let mut output = String::new();
for row in 0..32 {
for column in 0..64 {
let data_offset = row * 64 + column;
debug!("Rendering {data_offset} with value {}", self.memory[data_offset]);
if self.memory[data_offset] {
for row in 0..height {
for column in 0..width {
let data_offset = row * width + column;
debug!("Rendering {data_offset} with value {}", self.memory[data_offset as usize]);
if self.memory[data_offset as usize] {
output += "*"
} else {
output += " "
@@ -124,39 +125,127 @@ impl Chip8Video {
}
output += "\n";
}
output
}
pub fn get_resolution(&self) -> (i32, i32) {
if self.is_highres() {
(SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)
} else {
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
}
}
fn get_memory_size(&self) -> i32 {
let w = self.get_resolution();
w.1 * w.0
}
pub fn tick(&mut self) {
self.has_frame_changed = false;
}
pub fn scroll_right(&mut self) {
let (width, height) = self.get_resolution();
for current_row in 0..height {
let row_offset: usize = (current_row * width) as usize;
for current_column in (0..(width - 4)).rev() {
let source_address = row_offset + current_column as usize;
let target_address = source_address + 4;
self.memory[target_address] = self.memory[source_address];
}
self.memory[row_offset..row_offset + 4].fill(false);
}
}
pub fn scroll_left(&mut self) {
let (width, height) = self.get_resolution();
for current_row in 0..height {
let row_offset = current_row * width;
for current_column in (0..width - 4) {
let source: usize = (row_offset + current_column) as usize;
let target: usize = source + 4;
self.memory[target] = self.memory[source];
}
let clear_start: usize = (row_offset + width - 4) as usize;
let clear_end: usize = clear_start + 4;
self.memory[clear_start..clear_end].fill(false);
}
}
pub fn scroll_down(&mut self, how_far: i32) {
let (width, height) = self.get_resolution();
let row_shift = how_far * width;
let max_source_row = height - how_far;
for current_source_row in (0..max_source_row).rev() {
let current_source_offset = current_source_row * width;
for current_source_column in (0..width) {
let base_offset: usize = (current_source_offset + current_source_column) as usize;
let extended_offset: usize = base_offset + row_shift as usize;
self.memory[extended_offset] = self.memory[base_offset];
};
}
// Clear the new top rows after shifting
let clear_end = (how_far * width) as usize;
self.memory[0..clear_end].fill(false);
}
}
impl Default for Chip8Video {
fn default() -> Self {
Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false, current_res: Chip8VideoModes::LowRes }
let mut mem = vec![];
for _ in 0..CHIP8_VIDEO_MEMORY { mem.push(false); }
Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes }
}
}
#[cfg(test)]
mod test {
use std::io::Read;
use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7};
use crate::constants::*;
use super::*;
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
fn build_checkerboard() -> Chip8Video {
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
let mut r = Chip8Video::default();
let (width, height) = if in_hd {
r.set_highres();
(SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)
} else {
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
};
for i in 0..CHIP8_VIDEO_MEMORY {
r.poke(i as u16, i % 2 == 0);
println!("BUILDING BOARD WITH SIZE OF {width}x{height}");
for row in 0..height {
let data_offset = row * width;
for col in 0..width {
// XOR row and column indices to alternate in a checkerboard pattern
let to_poke = (row % 2) ^ (col % 2) == 1;
let local_offset: u16 = (data_offset + col) as u16;
r.poke(local_offset, to_poke);
}
}
r
}
fn build_checkboard_hd() -> Chip8Video {
real_build_checkboard(true)
}
fn build_checkerboard() -> Chip8Video {
real_build_checkboard(false)
}
fn read_test_result(suffix: &str) -> String {
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
.unwrap()
@@ -178,36 +267,7 @@ mod test {
}
#[test]
fn string_test_1() {
let mut x = Chip8Video::default();
let mut working_string = String::new();
for i in 0..32 {
working_string += &*(" ".repeat(64) + "\n");
}
assert_eq!(working_string, x.format_as_string());
let mut working_string = String::new();
// set a checkerboard...
for cb_row in 0..32 {
for cb_col in 0..64 {
let data_offset = cb_row * 64 + cb_col;
if data_offset % 2 == 0 {
x.poke(data_offset, true);
working_string += "*";
} else {
x.poke(data_offset, false);
working_string += " ";
}
}
working_string += "\n";
}
assert_eq!(working_string, x.format_as_string());
}
#[test]
fn set_initial_memory() {
fn set_initial_memory_sd() {
let mut x = Chip8Video::default();
// let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
let mut ws = String::new();
@@ -242,10 +302,10 @@ mod test {
#[test]
fn poke_2byte_test() {
let to_poke: [u8; 2] = [
0b11001111,
0b00111100
];
let to_poke: [u8; 2] = [
0b11001111,
0b00111100
];
let mut x = Chip8Video::default();
x.poke_2byte(0x00, to_poke);
@@ -265,22 +325,18 @@ mod test {
}
#[test]
fn cls() {
let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
fn cls_stddef() {
let width = 64;
let height = 32;
let mut initial_memory = vec![];
let mut ws = String::new();
let mut set_x = Chip8Video::new(initial_memory.into());
for cbr in 0..32 {
for cbc in 0..64 {
let dof = cbr * 64 + cbc;
if (dof as i32 % 2) == 0 {
initial_memory[dof] = true;
}
ws += " ";
}
ws += &*" ".repeat(width);
ws += "\n";
}
let mut set_x = Chip8Video::new(initial_memory);
set_x.cls();
assert_eq!(set_x.format_as_string(), ws);
}
@@ -289,16 +345,16 @@ mod test {
let to_poke = 0b10101010;
let mut v = Chip8Video::default();
v.poke_byte(0x00, to_poke);
assert!(v.peek(0x00));
assert!(!v.peek(0x01));
assert!(v.peek(0x02));
assert!(!v.peek(0x03));
assert!(v.peek(0x04));
assert!(!v.peek(0x05));
assert!(v.peek(0x06));
assert!(!v.peek(0x07));
assert!(v.clone().peek(0x00));
assert!(!v.clone().peek(0x01));
assert!(v.clone().peek(0x02));
assert!(!v.clone().peek(0x03));
assert!(v.clone().peek(0x04));
assert!(!v.clone().peek(0x05));
assert!(v.clone().peek(0x06));
assert!(!v.clone().peek(0x07));
for i in 0x8..CHIP8_VIDEO_MEMORY {
assert!(!v.peek(i as u16));
assert!(!v.clone().peek(i as u16));
}
}
@@ -329,7 +385,7 @@ mod test {
assert!(v.clone().peek(0x47));
// row 3 column 1
assert!(!v.peek(0xC0));
assert!(!v.clone().peek(0xC0));
assert!(v.clone().peek(0xC1));
assert!(!v.clone().peek(0xC2));
assert!(v.clone().peek(0xC3));
@@ -360,7 +416,7 @@ mod test {
}
let test_offset = (x_offset * 64 + y_offset) as u16;
assert!(!v.peek(test_offset));
assert!(!v.clone().peek(test_offset));
assert!(!v.clone().peek(test_offset + 1));
assert!(!v.clone().peek(test_offset + 2));
assert!(!v.clone().peek(test_offset + 3));
@@ -394,8 +450,7 @@ mod test {
#[test]
fn write_checkboard() {
let mut v = build_checkerboard();
assert_eq!(v.format_as_string(), read_test_result("test_video_write_checkerboard.asc"));
assert_eq!(v.clone().format_as_string(), read_test_result("test_video_write_checkerboard.asc"));
}
#[test]
@@ -426,16 +481,7 @@ mod test {
#[test]
fn reset_test() {
let mut x = Chip8Video::default();
let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];
for (index, sprite) in to_draw.iter().enumerate() {
let data_base_offset = index * 0x8;
for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {
x.poke_byte((data_base_offset + offset) as u16, sprite[index]);
}
}
let mut x = build_checkerboard();
x.reset();
assert_eq!(x.format_as_string(), read_test_result("test_reset_clears_video.asc"));
}
@@ -453,7 +499,7 @@ mod test {
// it becomes unset and theres a frame changed
assert_eq!(false, x.peek(0x00));
assert_eq!(true, x.has_frame_changed);
assert_eq!(true, x.clone().has_frame_changed);
}
#[test]
@@ -481,5 +527,70 @@ mod test {
assert!(true);
}
#[test]
fn scroll_down_1_row_test() {
let mut x = build_checkerboard();
x.scroll_down(1);
assert_eq!(read_test_result("test_video_scroll_down_1.asc"), x.format_as_string());
}
#[test]
fn scroll_down_10_row_test() {
let mut x = build_checkerboard();
x.scroll_down(10);
assert_eq!(read_test_result("test_video_scroll_down_10.asc"), x.format_as_string());
}
#[test]
fn high_res_has_right_resolution() {
let mut x = build_checkboard_hd();
println!("[{}]", x.format_as_string());
assert_eq!(read_test_result("test_video_highdef.asc"), x.format_as_string());
}
#[test]
fn scroll_down_1_row_test_schip() {
let mut x = build_checkboard_hd();
x.scroll_down(1);
println!("[{}]", x.format_as_string());
println!("[{}]", read_test_result("test_scroll_down_1_hd.asc"));
assert_eq!(read_test_result("test_scroll_down_1_hd.asc"), x.format_as_string());
}
#[test]
fn scroll_down_10_row_test_schip() {
let mut x = build_checkboard_hd();
x.scroll_down(10);
assert_eq!(read_test_result("test_scroll_down_10_hd.asc"), x.format_as_string());
}
#[test]
fn scroll_left_4_row_test_std_def() {
let mut x = build_checkerboard();
x.scroll_left();
assert_eq!(read_test_result("test_scroll_left_4.asc"), x.format_as_string());
}
#[test]
fn scroll_left_4_row_test_high_def() {
let mut x = build_checkboard_hd();
x.scroll_left();
assert_eq!(read_test_result("test_scroll_left_4_hd.asc"), x.format_as_string());
}
#[test]
fn scroll_right_4_row_test_std_def() {
let mut x = build_checkerboard();
x.scroll_right();
assert_eq!(read_test_result("test_scroll_right_4.asc"), x.format_as_string());
}
#[test]
fn scroll_right_4_row_test_high_def() {
let mut x = build_checkboard_hd();
x.scroll_right();
assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string());
}
}
+62
View File
@@ -63,3 +63,65 @@ pub const INST_ORY: &str = "ORY";
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
pub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0];
pub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10];
pub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0];
pub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40];
pub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0];
pub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0];
pub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90];
pub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0];
pub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0];
pub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];
pub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];
pub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80];
pub const SCHIPFONT_0: [u8; 0x10] = [0xF0, 0xFC, 0xFE, 0xFF, 0xF3, 0xE1, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFE, 0x7C];
pub const SCHIPFONT_1: [u8; 0x10] = [0x18, 0x3C, 0x7E, 0xFF, 0xF7, 0xE3, 0xC1, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0
];
pub const SCHIPFONT_2: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF
];
pub const SCHIPFONT_3: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF];
pub const SCHIPFONT_4: [u8; 0x10] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1,
0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0];
pub const SCHIPFONT_5: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F,
0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
pub const SCHIPFONT_6: [u8; 0x10] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
];
pub const SCHIPFONT_7: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C,
0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01
];
pub const SCHIPFONT_8: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C
];
pub const SCHIPFONT_9: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C
];
pub const SCHIPFONT_A: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3
];
pub const SCHIPFONT_B: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF,
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE
];
pub const SCHIPFONT_C: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01,
0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78
];
pub const SCHIPFONT_D: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3,
0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C
];
pub const SCHIPFONT_E: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF
];
pub const SCHIPFONT_F: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03];