Keyboard handling, "Type something:"
This commit is contained in:
Generated
+1
@@ -1217,6 +1217,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"pixels",
|
"pixels",
|
||||||
"rand",
|
"rand",
|
||||||
|
"vasm",
|
||||||
"vcore",
|
"vcore",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|||||||
+48
-1
@@ -271,7 +271,11 @@ impl CPU {
|
|||||||
let r = self.peek_call();
|
let r = self.peek_call();
|
||||||
self.push_data(r)
|
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
|
_ => {} // This can never happen
|
||||||
}
|
}
|
||||||
self.pc + instruction.length as i32
|
self.pc + instruction.length as i32
|
||||||
@@ -369,6 +373,27 @@ impl CPU {
|
|||||||
|
|
||||||
match self.fetch() {
|
match self.fetch() {
|
||||||
Ok(instr) => {
|
Ok(instr) => {
|
||||||
|
let stack_str: Vec<String> = self
|
||||||
|
.get_stack()
|
||||||
|
.iter()
|
||||||
|
.map(|w| format!("{:#08x} ", u32::from(*w)))
|
||||||
|
.collect();
|
||||||
|
let call_str: Vec<String> = 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.pc = if let Some(err) = self.error(instr) {
|
||||||
self.handle_error(err)
|
self.handle_error(err)
|
||||||
} else {
|
} else {
|
||||||
@@ -380,6 +405,28 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interrupt(&mut self, int: usize, arg: Option<Word>) {
|
||||||
|
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) {
|
pub fn start(&mut self) {
|
||||||
self.halted = false
|
self.halted = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vcore = { path = "../vcore" }
|
vcore = { path = "../vcore" }
|
||||||
|
vasm = { path = "../vasm" }
|
||||||
rand = "0.8.0"
|
rand = "0.8.0"
|
||||||
winit = "0.26.1"
|
winit = "0.26.1"
|
||||||
pixels = "0.9.0"
|
pixels = "0.9.0"
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-4
@@ -1,4 +1,5 @@
|
|||||||
mod display;
|
mod display;
|
||||||
|
mod keyboard;
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::LogicalSize,
|
dpi::LogicalSize,
|
||||||
@@ -7,11 +8,15 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
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::cpu::CPU;
|
||||||
use vcore::memory::{Memory, PeekPoke};
|
use vcore::memory::{Memory, PeekPoke};
|
||||||
use vcore::word::Word;
|
use vcore::word::Word;
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use winit::event::ElementState;
|
||||||
use std::time::{Instant, Duration};
|
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -43,12 +48,16 @@ fn main() {
|
|||||||
// cpu.poke(Word::from(0x10000 + 128 * n + 127), 0b00000011);
|
// cpu.poke(Word::from(0x10000 + 128 * n + 127), 0b00000011);
|
||||||
// cpu.poke(Word::from(0x10000 + 128 * 127 + n), 0b00011100);
|
// 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();
|
cpu.start();
|
||||||
window_loop(event_loop, window, pixels, cpu)
|
window_loop(event_loop, window, pixels, cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mut cpu: CPU) -> ! {
|
fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mut cpu: CPU) -> ! {
|
||||||
|
let mut interrupt_events: VecDeque<(usize, Option<Word>)> = VecDeque::new();
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
*control_flow = ControlFlow::Poll;
|
*control_flow = ControlFlow::Poll;
|
||||||
|
|
||||||
@@ -60,16 +69,35 @@ fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mu
|
|||||||
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(new_size),
|
event: WindowEvent::Resized(new_size),
|
||||||
window_id
|
window_id,
|
||||||
} if window_id == window.id() => {
|
} if window_id == window.id() => {
|
||||||
pixels.resize_surface(new_size.width, new_size.height);
|
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 => {
|
Event::MainEventsCleared => {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
draw(pixels.get_frame(), &mut cpu);
|
draw(pixels.get_frame(), &mut cpu);
|
||||||
pixels.render().expect("Problem displaying framebuffer");
|
pixels.render().expect("Problem displaying framebuffer");
|
||||||
while Instant::now() < start + Duration::from_millis(25) {
|
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 {
|
for _ in 1..1000 {
|
||||||
cpu.tick()
|
cpu.tick()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
Reference in New Issue
Block a user