From 848d7d23cc9392137d262496a2990dcab5261537 Mon Sep 17 00:00:00 2001 From: commonkestrel Date: Mon, 29 Jul 2024 14:40:49 -0700 Subject: [PATCH] Add colors --- examples/box.asm | 15 +++++-- misc/icon.png | Bin 0 -> 279 bytes src/emulator.rs | 15 ++++--- src/emulator/display.rs | 94 ++++++++++++++++++++++++++++++++-------- 4 files changed, 95 insertions(+), 29 deletions(-) create mode 100644 misc/icon.png diff --git a/examples/box.asm b/examples/box.asm index e6d4a93..933e183 100644 --- a/examples/box.asm +++ b/examples/box.asm @@ -1,4 +1,4 @@ -@define TEXT_BUFFER 0xF800 +@define TEXT_BUFFER 0xF000 @define SCREEN_WIDTH 80 @define SCREEN_HEIGHT 25 @define BOX_WIDTH (SCREEN_WIDTH - 2) @@ -13,6 +13,8 @@ @define WALL 0xBA @define DASH 0xCD +@define STYLE 0x0F + /// math = https://github.com/commonkestrel/fateful_math @include @@ -137,14 +139,19 @@ draw_character: push A, C; save X coordinate and character push B, 0, SCREEN_WIDTH, 0 - call [mul16] ; get Y offset - pop H, L ; get value + call [mul16] ; calculate Y offset + pop H, L ; get value of Y offset pop C, A ; get character and X coordinate - add16 H, L, (TEXT_BUFFER >> 8), (TEXT_BUFFER & 0xFF) ; Shift address to text-buffer space add16 H, L, 0, A ; add X to address + add16 H, L, H, L ; double address to account for modifier bytes + add16 H, L, (TEXT_BUFFER >> 8), (TEXT_BUFFER & 0xFF) ; Shift address to text-buffer space + + st C + inc H, L + mv C, STYLE st C ret diff --git a/misc/icon.png b/misc/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2afde67114c406f5e86a2481cffbd8e24ad5382b GIT binary patch literal 279 zcmV+y0qFjTP)d{GZ-eG&j2y;g10g%48l+Dz|}C)#Q>14$N;Acu(=)NEp%ritAl$1n`T(J zkZi#J|KM=N0E~) -> Self { State { pc: 0, - sp: 0xF7FF, + sp: 0xEFFF, ctrl: Control::default(), sreg: SReg::empty(), timer: 0, @@ -665,8 +665,8 @@ impl State { ) } else if cw.contains(ControlWord::LA) { match self.addr { - 0x0000..=0xF7FF => self.mem[self.addr as usize], - 0xF800..=0xFFCF => self.text_buffer.get(self.addr - 0xF800), + 0x0000..=0xEFFF => self.mem[self.addr as usize], + 0xF000..=0xFFCF => self.text_buffer.get(self.addr - 0xF000), 0xFFD0..=0xFFFC => match self.peripherals.get(&((self.addr - 0xFFC0) as u8)) { Some(periph) => unsafe { if let Ok(stateful_read) = @@ -708,11 +708,11 @@ impl State { if cw.contains(ControlWord::SA) { match self.addr { - 0x0000..=0xF7FF => { + 0x0000..=0xEFFF => { self.mem[self.addr as usize] = bus; } - 0xF800..=0xFFCF => { - self.text_buffer.set(self.addr - 0xF800, bus); + 0xF000..=0xFFCF => { + self.text_buffer.set(self.addr - 0xF000, bus); } 0xFFD0..=0xFFFC => match self.peripherals.get(&((self.addr - 0xFFC0) as u8)) { Some(periph) => unsafe { @@ -845,9 +845,10 @@ impl State { self.ctrl.clock = 0; self.mem.fill(0); self.sreg = SReg::from_bits_retain(0); - self.sp = 0xF7FF; + self.sp = 0xEFFF; self.alu.clear(); self.bank.clear(); + self.text_buffer.reset(); for periph in self.peripherals.values() { unsafe { diff --git a/src/emulator/display.rs b/src/emulator/display.rs index 2a0e26a..2562bf4 100644 --- a/src/emulator/display.rs +++ b/src/emulator/display.rs @@ -1,41 +1,84 @@ -use std::{ - cell::UnsafeCell, - marker::PhantomData, - pin::Pin, - sync::atomic::{AtomicU16, AtomicU8, Ordering}, -}; +use std::pin::Pin; +use std::str::FromStr; use async_std::task::JoinHandle; -use minifb::{Scale, ScaleMode, WindowOptions}; +use minifb::{Icon, Scale, ScaleMode, WindowOptions}; const FONT: &[u8; 1 << 12] = include_bytes!("../vga-font.rom"); const WIDTH: usize = 640; const HEIGHT: usize = 400; +const COLORS: [u32; 16] = [ + 0x000000, + 0x0000aa, + 0x00aa00, + 0x00aaaa, + 0xaa0000, + 0xaa00aa, + 0xaa5500, + 0xaaaaaa, + 0x555555, + 0x5555ff, + 0x55ff55, + 0x55ffff, + 0xff5555, + 0xff55ff, + 0xffff55, + 0xffffff, +]; + #[derive(Debug)] pub struct TextBuffer { - data: Pin>, + chars: Pin>, + modifiers: Pin>, handle: JoinHandle<()>, } -struct BufferPtr(*const [u8; 1 << 12]); +struct BufferPtr{ + chars: *const [u8; 1 << 11], + modifiers: *const [u8; 1 << 11], +} + unsafe impl Send for BufferPtr {} impl TextBuffer { pub fn spawn() -> TextBuffer { - let data = Box::pin([0; 1 << 12]); + let chars = Box::pin([0; 1 << 11]); + let modifiers = Box::pin([0; 1 << 11]); - let handle = async_std::task::spawn(run_handle(BufferPtr(&*data))); + let handle = async_std::task::spawn(run_handle(BufferPtr{ + chars: &*chars, + modifiers: &*modifiers, + })); - TextBuffer { data, handle } + TextBuffer { chars, modifiers, handle } } pub fn get(&self, addr: u16) -> u8 { - self.data[addr as usize] + if addr % 2 == 0 { + let sub_index = (addr >> 1) as usize; + self.chars[sub_index] + } else { + let sub_index = (addr >> 1) as usize; + self.modifiers[sub_index] + } } pub fn set(&mut self, addr: u16, data: u8) { - self.data[addr as usize] = data; + println!("setting {addr} to {data}"); + + if addr % 2 == 0 { + let sub_index = (addr >> 1) as usize; + self.chars[sub_index] = data; + } else { + let sub_index = (addr >> 1) as usize; + self.modifiers[sub_index] = data; + } + } + + pub fn reset(&mut self) { + self.chars.fill(0); + self.modifiers.fill(0); } } @@ -47,6 +90,12 @@ async fn run_handle(buffer: BufferPtr) { let mut window = minifb::Window::new("f8ful", WIDTH, HEIGHT, opts).expect("should be able to create window"); + // match the VGA standard + window.set_target_fps(75); + if let Some(icon) = get_icon() { + window.set_icon(icon); + } + let mut fb = [0x00000000; WIDTH * HEIGHT]; while window.is_open() { @@ -58,15 +107,19 @@ async fn run_handle(buffer: BufferPtr) { let char_x = x / 8; let char_y = y / 16; let char_idx = char_x + char_y * WIDTH / 8; - let character = 0x10; - let character = unsafe { (*buffer.0)[char_idx] }; + let (character, modifier) = unsafe {( + (*buffer.chars)[char_idx], + (*buffer.modifiers)[char_idx] + )}; let font_addr = ((character as usize) << 4) + font_y; let lit = FONT[font_addr] & (1 << (7 - font_x)) > 0; // This part isn't part of the actual CPU, - // the real value will be transmitted via wire instead of stored. - fb[x + y * WIDTH] = if lit { 0x00FFFFFF } else { 0x00000000 }; + // the real value will be transmitted via VGA instead of stored. + let fg = COLORS[(modifier & 0xf) as usize]; + let bg = COLORS[(modifier >> 4) as usize]; + fb[x + y * WIDTH] = if lit { fg } else { bg }; } } @@ -76,3 +129,8 @@ async fn run_handle(buffer: BufferPtr) { } } + +fn get_icon() -> Option { + // TODO: actually add icon + None +}