diff --git a/Cargo.lock b/Cargo.lock index 9008f8b..8f5e5b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1217,6 +1217,7 @@ version = "0.1.0" dependencies = [ "pixels", "rand", + "vasm", "vcore", "winit", ] diff --git a/vcore/src/cpu.rs b/vcore/src/cpu.rs index a0bd92d..982de88 100644 --- a/vcore/src/cpu.rs +++ b/vcore/src/cpu.rs @@ -271,7 +271,11 @@ impl CPU { let r = self.peek_call(); self.push_data(r) } - Opcode::Debug => { /* TODO This should print the stack or something */ } + Opcode::Debug => { + for v in self.get_stack().iter() { + println!("{:#08x}", u32::from(*v)); + } + } _ => {} // This can never happen } self.pc + instruction.length as i32 @@ -369,6 +373,27 @@ impl CPU { match self.fetch() { Ok(instr) => { + let stack_str: Vec = self + .get_stack() + .iter() + .map(|w| format!("{:#08x} ", u32::from(*w))) + .collect(); + let call_str: Vec = self + .get_call() + .iter() + .map(|w| format!("{:#08x} ", u32::from(*w))) + .collect(); + let arg_str = instr + .arg + .map_or(String::from(""), |w| format!("{:#08x}", u32::from(w))); + println!( + "{:#8x}: {} <{}> ( {}) [ {}]", + u32::from(self.pc), + instr.opcode, + arg_str, + stack_str.join(" "), + call_str.join(" ") + ); self.pc = if let Some(err) = self.error(instr) { self.handle_error(err) } else { @@ -380,6 +405,28 @@ impl CPU { } } + pub fn interrupt(&mut self, int: usize, arg: Option) { + if int >= self.iv.len() { + panic!("Invalid interrupt: {}", int) + } + if self.int_enabled { + if self.halted { + self.start() + } + self.int_enabled = false; + let room = self.sp - self.dp; + self.pc = if room == 0 || room == 1 && arg.is_some() { + self.handle_error(ExecutionError::Overflow) + } else { + self.push_call(self.pc); + if let Some(val) = arg { + self.push_data(val) + } + self.iv[int] + } + } + } + pub fn start(&mut self) { self.halted = false } diff --git a/vemu/Cargo.toml b/vemu/Cargo.toml index d66dfbb..4c83198 100644 --- a/vemu/Cargo.toml +++ b/vemu/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] vcore = { path = "../vcore" } +vasm = { path = "../vasm" } rand = "0.8.0" winit = "0.26.1" pixels = "0.9.0" \ No newline at end of file diff --git a/vemu/src/keyboard.rs b/vemu/src/keyboard.rs new file mode 100644 index 0000000..93efa20 --- /dev/null +++ b/vemu/src/keyboard.rs @@ -0,0 +1,117 @@ +use winit::event::VirtualKeyCode; + +pub fn convert_keycode(vkey: VirtualKeyCode) -> u8 { + match vkey { + VirtualKeyCode::A => 0x04, + VirtualKeyCode::B => 0x05, + VirtualKeyCode::C => 0x06, + VirtualKeyCode::D => 0x07, + VirtualKeyCode::E => 0x08, + VirtualKeyCode::F => 0x09, + VirtualKeyCode::G => 0x0a, + VirtualKeyCode::H => 0x0b, + VirtualKeyCode::I => 0x0c, + VirtualKeyCode::J => 0x0d, + VirtualKeyCode::K => 0x0e, + VirtualKeyCode::L => 0x0f, + VirtualKeyCode::M => 0x10, + VirtualKeyCode::N => 0x11, + VirtualKeyCode::O => 0x12, + VirtualKeyCode::P => 0x13, + VirtualKeyCode::Q => 0x14, + VirtualKeyCode::R => 0x15, + VirtualKeyCode::S => 0x16, + VirtualKeyCode::T => 0x17, + VirtualKeyCode::U => 0x18, + VirtualKeyCode::V => 0x19, + VirtualKeyCode::W => 0x1a, + VirtualKeyCode::X => 0x1b, + VirtualKeyCode::Y => 0x1c, + VirtualKeyCode::Z => 0x1d, + VirtualKeyCode::Key1 => 0x1e, + VirtualKeyCode::Key2 => 0x1f, + VirtualKeyCode::Key3 => 0x20, + VirtualKeyCode::Key4 => 0x21, + VirtualKeyCode::Key5 => 0x22, + VirtualKeyCode::Key6 => 0x23, + VirtualKeyCode::Key7 => 0x24, + VirtualKeyCode::Key8 => 0x25, + VirtualKeyCode::Key9 => 0x26, + VirtualKeyCode::Key0 => 0x27, + VirtualKeyCode::Return => 0x28, + VirtualKeyCode::Escape => 0x29, + VirtualKeyCode::Back => 0x2a, + VirtualKeyCode::Tab => 0x2b, + VirtualKeyCode::Space => 0x2c, + VirtualKeyCode::Minus => 0x2d, + VirtualKeyCode::Equals => 0x2e, + VirtualKeyCode::LBracket => 0x2f, + VirtualKeyCode::RBracket => 0x30, + VirtualKeyCode::Backslash => 0x31, + // 0x32 is a non-US keyboard key: hash and tilde + VirtualKeyCode::Semicolon => 0x33, + VirtualKeyCode::Apostrophe => 0x34, + VirtualKeyCode::Grave => 0x35, + VirtualKeyCode::Comma => 0x36, + VirtualKeyCode::Period => 0x37, + VirtualKeyCode::Slash => 0x38, + VirtualKeyCode::Capital => 0x39, + VirtualKeyCode::F1 => 0x3a, + VirtualKeyCode::F2 => 0x3b, + VirtualKeyCode::F3 => 0x3c, + VirtualKeyCode::F4 => 0x3d, + VirtualKeyCode::F5 => 0x3e, + VirtualKeyCode::F6 => 0x3f, + VirtualKeyCode::F7 => 0x40, + VirtualKeyCode::F8 => 0x41, + VirtualKeyCode::F9 => 0x42, + VirtualKeyCode::F10 => 0x43, + VirtualKeyCode::F11 => 0x44, + VirtualKeyCode::F12 => 0x45, + VirtualKeyCode::Sysrq => 0x46, + VirtualKeyCode::Scroll => 0x47, + VirtualKeyCode::Pause => 0x48, + VirtualKeyCode::Insert => 0x49, + VirtualKeyCode::Home => 0x4a, + VirtualKeyCode::PageUp => 0x4b, + VirtualKeyCode::Delete => 0x4c, + VirtualKeyCode::End => 0x4d, + VirtualKeyCode::PageDown => 0x4e, + VirtualKeyCode::Right => 0x4f, + VirtualKeyCode::Left => 0x50, + VirtualKeyCode::Down => 0x51, + VirtualKeyCode::Up => 0x52, + VirtualKeyCode::Numlock => 0x53, + VirtualKeyCode::NumpadDivide => 0x54, + VirtualKeyCode::NumpadMultiply => 0x55, + VirtualKeyCode::NumpadSubtract => 0x56, + VirtualKeyCode::NumpadAdd => 0x57, + VirtualKeyCode::NumpadEnter => 0x58, + VirtualKeyCode::Numpad1 => 0x59, + VirtualKeyCode::Numpad2 => 0x5a, + VirtualKeyCode::Numpad3 => 0x5b, + VirtualKeyCode::Numpad4 => 0x5c, + VirtualKeyCode::Numpad5 => 0x5d, + VirtualKeyCode::Numpad6 => 0x5e, + VirtualKeyCode::Numpad7 => 0x5f, + VirtualKeyCode::Numpad8 => 0x60, + VirtualKeyCode::Numpad9 => 0x61, + VirtualKeyCode::Numpad0 => 0x62, + VirtualKeyCode::NumpadDecimal => 0x63, + // 0x64 is a non-US keyboard key: backslash and bar + VirtualKeyCode::Compose => 0x65, + // 0x66 is a non-standard key: power + VirtualKeyCode::NumpadEquals => 0x67, + // 0x68-0x73 is extended function keys + // 0x74-0xdf is a bunch of international stuff and keypad stuff + VirtualKeyCode::LControl => 0xe0, + VirtualKeyCode::LShift => 0xe1, + VirtualKeyCode::LAlt => 0xe2, + VirtualKeyCode::LWin => 0xe3, + VirtualKeyCode::RControl => 0xe4, + VirtualKeyCode::RShift => 0xe5, + VirtualKeyCode::RAlt => 0xe6, + VirtualKeyCode::RWin => 0xe7, + _ => 0xff, + } +} diff --git a/vemu/src/main.rs b/vemu/src/main.rs index e839a9d..c3f2854 100644 --- a/vemu/src/main.rs +++ b/vemu/src/main.rs @@ -1,4 +1,5 @@ mod display; +mod keyboard; use winit::{ dpi::LogicalSize, @@ -7,11 +8,15 @@ use winit::{ window::WindowBuilder, }; +use crate::keyboard::convert_keycode; +use pixels::{Pixels, SurfaceTexture}; +use std::collections::VecDeque; +use std::time::{Duration, Instant}; +use vasm::assemble_snippet; use vcore::cpu::CPU; use vcore::memory::{Memory, PeekPoke}; use vcore::word::Word; -use pixels::{Pixels, SurfaceTexture}; -use std::time::{Instant, Duration}; +use winit::event::ElementState; use winit::window::Window; fn main() { @@ -43,12 +48,16 @@ fn main() { // cpu.poke(Word::from(0x10000 + 128 * n + 127), 0b00000011); // cpu.poke(Word::from(0x10000 + 128 * 127 + n), 0b00011100); // } - cpu.poke_slice(Word::from(0x400), include_bytes!("gfx_test.rom")); + let code = assemble_snippet(include_str!("typewriter.asm").lines()).expect("Assemble error"); + //cpu.poke_slice(Word::from(0x400), include_bytes!("gfx_test.rom")); + cpu.poke_slice(0x400.into(), code.as_slice()); cpu.start(); window_loop(event_loop, window, pixels, cpu) } fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mut cpu: CPU) -> ! { + let mut interrupt_events: VecDeque<(usize, Option)> = VecDeque::new(); + event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; @@ -60,16 +69,35 @@ fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mu Event::WindowEvent { event: WindowEvent::Resized(new_size), - window_id + window_id, } if window_id == window.id() => { pixels.resize_surface(new_size.width, new_size.height); } + Event::WindowEvent { + event: WindowEvent::KeyboardInput { input, .. }, + window_id, + } if window_id == window.id() => { + if let (Some(vk), state) = (input.virtual_keycode, input.state) { + let byte = convert_keycode(vk); + let word = Word::from_bytes([ + byte, + if state == ElementState::Pressed { 1 } else { 0 }, + 0, + ]); + println!("Saw: {:#4x}", u32::from(word)); + interrupt_events.push_back((5, Some(word))) + } + } + Event::MainEventsCleared => { let start = Instant::now(); draw(pixels.get_frame(), &mut cpu); pixels.render().expect("Problem displaying framebuffer"); while Instant::now() < start + Duration::from_millis(25) { + if let Some((int, arg)) = interrupt_events.pop_front() { + cpu.interrupt(int, arg) + } for _ in 1..1000 { cpu.tick() } diff --git a/vemu/src/typewriter.asm b/vemu/src/typewriter.asm new file mode 100644 index 0000000..765b776 --- /dev/null +++ b/vemu/src/typewriter.asm @@ -0,0 +1,131 @@ +.org 0x400 +screen: .equ 0x10000 +reg: .equ 16 + +;;;;; Start + push on_key + setiv 5 + setint 1 + call clear_screen + call set_video + push msg + push screen + call print +wfi_loop: hlt + jmpr @wfi_loop +;;;;; + +set_video: + push 30 + storew reg + 10 + push 40 + storew reg + 13 + ret + +clear_screen: + push screen + #while + dup + lt screen + 40 * 30 + #do + dup + swap 0 + store + + dup + add 40 * 30 + swap 0b10010010 + store + + add 1 + #end + pop + ret + +print: ; ( msg addr -- ) + pushr + #while + dup + load + #do + dup + load + peekr + store + popr + add 1 + pushr + add 1 + #end + pop + popr + pop + ret + +on_key: + setint 1 ; this can be reentrant, doesn't hurt anything + call is_press ; check for press + #if + ; if is alpha, look up in map and print + dup + call is_alpha + #if + call to_alpha_char + call putc + #else + pop + #end + #else + ; TODO: + ; if is punc, look up in punc map and print + ; if shift, set shift flag + ; if return inc cursor + ; if backspace, clear cursor and dec + ; else release: + ; if shift, clear shift flag + pop + #end + ret + +is_press: ; ( event -- key bool ) + dup + and 0xff + swap + and 0xff00 + ret + +is_alpha: ; ( key -- bool ) + dup + gt 0x03 + swap + lt 0x27 + and + ret + +is_punc: ; ( key -- bool ) + dup + gt 0x2b + swap + lt 0x39 + and + ret + +to_alpha_char: ; ( key -- ch ) + sub 0x04 + add alpha_table + load + ret + +putc: ; ( ch -- ) (also modifies cursor) + loadw cursor + dup + pushr + store + popr + add 1 + storew cursor + ret + +cursor: .db screen + 40 +msg: .db "Type something:\0" +alpha_table: .db "abcdefghijklmnopqrstuvwxyz1234567890" \ No newline at end of file