diff --git a/Cargo.lock b/Cargo.lock index 422175f..4c386d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,14 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "boo" +version = "0.1.0" +dependencies = [ + "image", + "minifb", +] + [[package]] name = "bumpalo" version = "3.8.0" @@ -285,12 +293,6 @@ dependencies = [ "miniz_oxide 0.4.4", ] -[[package]] -name = "font8x8" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e" - [[package]] name = "getrandom" version = "0.2.3" @@ -781,15 +783,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -[[package]] -name = "side" -version = "0.1.0" -dependencies = [ - "font8x8", - "image", - "minifb", -] - [[package]] name = "smallvec" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index df2c274..b2b7429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "side" +name = "boo" version = "0.1.0" edition = "2018" @@ -7,5 +7,4 @@ edition = "2018" [dependencies] minifb = "0.19.3" -font8x8 = "0.3.1" image = "0.23.14" \ No newline at end of file diff --git a/graphics.asm b/graphics.asm index d45766a..89d8497 100644 --- a/graphics.asm +++ b/graphics.asm @@ -126,14 +126,14 @@ label draw_rect: label draw_image: - ldstore $4 $7 ; width + rload $4 $7 ; width inc $4 - ldstore $4 $8 ; height + rload $4 $8 ; height inc $4 loadi $3 $0 loadi $6 $0 label draw_pixels: - ldstore $4 $5 + rload $4 $5 rstore $5 $B inc $B; Increment VBuf Pointer inc $4 diff --git a/example.asm b/kernel.asm similarity index 77% rename from example.asm rename to kernel.asm index 5b84ded..0ce9655 100644 --- a/example.asm +++ b/kernel.asm @@ -35,7 +35,7 @@ import graphics.asm; draw_vline, draw_hline, draw_rect ; Common Strings data ascii boo_os_version Boo OS v0.0.1 -data ascii HelloWorld Welcome to Boo OS Running on Boo Byte Code! +data ascii prompt [sarah@boo] > data ascii Welcome !@#$%^&*()_+=-0987654321 data ascii Introspection We Can Now Do Introspection: data ascii label_rax RAX: @@ -47,17 +47,21 @@ data image boo_os_small.png booos-small.png data image wallpaper.png wallpaper.png data ascii quit_label QUIT -data buffer command_line_input 256 +data buffer command_line_input 64 + + +data buffers 48 terminal 64 meta + ; strcmp compares 2 strings in a byte-by-byte manner, incrementing ptrs as it goes. Returns 1 if both bytes ; point to 0. Returns 0 (fail) if it encounters 2 different bytes ; clobbers $1 $2 $4 $5 label strcmp: label strcmp_loop: - ldstore $4 $1 - ldstore $5 $2 + rload $4 $1 + rload $5 $2 jeq +3 ; if either of these differ then return 0 to indicate these strings don't match loadi $1 0 ret @@ -70,6 +74,23 @@ label strcmp: jmp strcmp_loop +label shift_terminal: + ; copy terminal 0 to terminal 1 + loadi $4 terminal[1] ;src + bcopy $4 terminal[2] ; dest + + ; copy terminal 0 to terminal 1 + loadi $4 terminal[0] ;src + bcopy $4 terminal[1] ; dest + + ; copy command line to terminal 0 + loadi $4 command_line_input ;src + bcopy $4 terminal[0] ; dest + + bzero command_line_input + + ret + label handle_keypress: @@ -83,13 +104,14 @@ label handle_keypress: ; Check for Return loadi $1 $0A tx $2 $4 - jneq +8 + jneq +9 loadi $4 @command_line_input loadi $5 quit_label call strcmp loadi $2 1 jneq +2 ; if the command is QUIT, then hlt the machine!! A shell is born hlt + call shift_terminal ret bappend $4 command_line_input @@ -132,8 +154,7 @@ label handle_keypress: loadi $A 20; call set_pos - loadi $4 HelloWorld - call draw_string; + @@ -144,13 +165,31 @@ label handle_keypress: tx $4 $2 call handle_keypress - loadi $9 1; - loadi $A 60; + loadi $9 5; + loadi $A 1A0; call set_pos - loadi $4 @command_line_input + loadi $4 @terminal[1] call draw_string; + loadi $9 5; + loadi $A 1B0; + call set_pos + loadi $4 @terminal[0] + call draw_string; + loadi $9 5; + loadi $A 1C0; + call set_pos + + loadi $4 prompt + call draw_string; + + loadi $9 70; + loadi $A 1C0; + call set_pos + + loadi $4 @command_line_input + call draw_string; updsp clr diff --git a/src/assembler.rs b/src/assembler.rs index eae730b..3ecc630 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -1,9 +1,9 @@ use crate::{Machine, MEMORY}; +use image::io::Reader; +use image::png::PngDecoder; +use image::GenericImageView; use std::collections::HashMap; use std::fs::read_to_string; -use image::png::PngDecoder; -use image::io::Reader; -use image::GenericImageView; pub struct ImageAssembler { memory: Vec, @@ -32,11 +32,8 @@ impl ImageAssembler { for line in lines { let parts = line.split_once(';'); - let mut command = match parts { - Some((command, _comment)) => { - command.trim() - }, + Some((command, _comment)) => command.trim(), _ => line.trim(), }; @@ -134,6 +131,12 @@ impl ImageAssembler { println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]); self.ptr += 1; } + "bzero" => { + let addr = self.parse_addr(command_parts[1]); + self.memory[self.ptr] = 0xB0000000 + addr; + println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]); + self.ptr += 1; + } "import" => { self.assemble(command_parts[1]); } @@ -143,7 +146,7 @@ impl ImageAssembler { } } else if command_parts.len() == 3 && command_parts[0] != "data" { match command_parts[0] { - "ldstore" => { + "rload" => { // Load Immediate let target_reg = self.parse_addr(command_parts[1]); let inst = (0x70 + target_reg) << 24; @@ -204,6 +207,14 @@ impl ImageAssembler { println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]); self.ptr += 1; } + "bcopy" => { + let target_reg = self.parse_addr(command_parts[1]); + let inst = (0xD0 + target_reg) << 24; + let reg = self.parse_addr(command_parts[2]); + self.memory[self.ptr] = inst + reg; + println!("{:X}: {:X}", self.ptr, self.memory[self.ptr]); + self.ptr += 1; + } "bdelete" => { let target_reg = self.parse_addr(command_parts[1]); let inst = (0x03 + target_reg) << 24; @@ -274,46 +285,81 @@ impl ImageAssembler { } self.memory[self.ptr] = 0x00; self.ptr += 1; - }, + } "image" => { - if command_parts.len() !=4 { + if command_parts.len() != 4 { panic!("data buffer label len") } self.labels .insert(command_parts[2].replace(":", ""), self.ptr); let img = Reader::open(command_parts[3]).unwrap().decode().unwrap(); - self.memory[self.ptr] = img.width(); self.ptr+=1; - self.memory[self.ptr] = img.height(); self.ptr+=1; + self.memory[self.ptr] = img.width(); + self.ptr += 1; + self.memory[self.ptr] = img.height(); + self.ptr += 1; for h in 0..img.height() { - for w in 0..img.width() { - let pixel = img.get_pixel(w,h).0; + for w in 0..img.width() { + let pixel = img.get_pixel(w, h).0; let a = (pixel[3] as u32) << 24; let r = (pixel[0] as u32) << 16; let g = (pixel[1] as u32) << 8; let b = (pixel[2] as u32); - self.memory[self.ptr] = a+r+g+b ; self.ptr+=1; + self.memory[self.ptr] = a + r + g + b; + self.ptr += 1; } } self.memory[self.ptr] = 0x00; - self.ptr+=1; + self.ptr += 1; } "buffer" => { - if command_parts.len() !=4 { + if command_parts.len() != 4 { panic!("data buffer label len") } self.labels .insert(command_parts[2].replace(":", ""), self.ptr); let len = command_parts[3].parse().unwrap_or_default(); self.memory[self.ptr] = len; - self.ptr+=1; + self.ptr += 1; self.memory[self.ptr] = 0x00; - self.ptr+=1; + self.ptr += 1; // Pad with 0's for i in 0..=len { self.memory[self.ptr] = 0x00; - self.ptr+=1 + self.ptr += 1 } } + "buffers" => { + if command_parts.len() != 5 { + panic!("data buffers length label buffer_len") + } + + let len = command_parts[2].parse().unwrap_or_default(); + let buffer_len = command_parts[4].parse().unwrap_or_default(); + for i in 0..len { + self.labels.insert( + format!("{}[{}]", command_parts[3].replace(":", ""), i), + self.ptr, + ); + self.memory[self.ptr] = buffer_len; + self.ptr += 1; + self.memory[self.ptr] = 0x00; + self.ptr += 1; + // Pad with 0's + for _x in 0..=buffer_len { + self.memory[self.ptr] = 0x00; + self.ptr += 1 + } + } + } + "ptr" => { + if command_parts.len() != 4 { + panic!("data ptr label init") + } + self.labels + .insert(command_parts[2].replace(":", ""), self.ptr); + self.memory[self.ptr] = self.parse_addr(command_parts[3]); + self.ptr += 1; + } _ => { panic!("unknown type {}", command_parts[1]) } @@ -327,19 +373,17 @@ impl ImageAssembler { } fn parse_addr(&self, input: &str) -> u32 { - if input.starts_with('@') { - match self.labels.get(input.replace("@", "").as_str()){ + match self.labels.get(input.replace("@", "").as_str()) { Some(addr) => { - return addr.clone() as u32 +2; - } - None =>{ + return addr.clone() as u32 + 2; } + None => {} } } if input.starts_with('+') { - match usize::from_str_radix(input.replace("+", "").as_str(),10) { + match usize::from_str_radix(input.replace("+", "").as_str(), 10) { Ok(offeset) => { return (self.ptr + offeset) as u32; } @@ -353,37 +397,31 @@ impl ImageAssembler { Ok(addr) => { return addr; } - _ => { - match input.split_once("+") { - Some((input, offset)) => { - match self.labels.get(input) { - Some(addr) => { - match usize::from_str_radix(offset.replace("+", "").as_str(), 10) { - Ok(offset) => { - return addr.clone() as u32 + offset as u32; - } - _ => { - panic!("Not a Hex Encoded Address {:?}", input) - } - } - } - _ => { - panic!("Not a Hex Encoded Address {:?}", input) - } - } - }, - _ => { - match self.labels.get(input) { - Some(addr) => { - return addr.clone() as u32; + _ => match input.split_once("+") { + Some((input, offset)) => match self.labels.get(input) { + Some(addr) => { + match usize::from_str_radix(offset.replace("+", "").as_str(), 10) { + Ok(offset) => { + return addr.clone() as u32 + offset as u32; } _ => { panic!("Not a Hex Encoded Address {:?}", input) } } } - } - } + _ => { + panic!("Not a Hex Encoded Address {:?}", input) + } + }, + _ => match self.labels.get(input) { + Some(addr) => { + return addr.clone() as u32; + } + _ => { + panic!("Not a Hex Encoded Address {:?}", input) + } + }, + }, } } } diff --git a/src/lib.rs b/src/lib.rs index 83e3985..336fc69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ impl Machine { } pub fn set_keypress(&mut self, char: u32) { - self.memory[INPUT_PAGE+1] = char + self.memory[INPUT_PAGE + 1] = char } pub fn load(&mut self, memory: Vec) { @@ -74,17 +74,17 @@ impl Machine { panic!("HLT"); } 0x04 => { - for i in 0..VRAM{ + for i in 0..VRAM { self.memory[i] = 0x00; } self.memory[REGISTER_PAGE + 63] = 0x00; } 0x07 => { let addr = (instruction & 0x00FFFFFF) as usize; - let ptr = (self.memory[addr+1]) as usize; + let ptr = (self.memory[addr + 1]) as usize; if ptr > 0 { - self.memory[addr+1]-=1; - self.memory[addr+2+ptr-1] = 0x00; + self.memory[addr + 1] -= 1; + self.memory[addr + 2 + ptr - 1] = 0x00; } } op => { @@ -201,12 +201,18 @@ impl Machine { 0x0B => { let input_reg = ((instruction) >> 24 & 0x0F) as usize; let addr = (instruction & 0x00FFFFFF) as usize; + let max_len = (self.memory[addr]) as usize; if input_reg != 0 { let max_len = (self.memory[addr]) as usize; - let ptr = (self.memory[addr+1]) as usize; + let ptr = (self.memory[addr + 1]) as usize; if ptr < max_len { - self.memory[addr+1]+=1; - self.memory[addr+2+ptr] = self.memory[REGISTER_PAGE + input_reg]; + self.memory[addr + 1] += 1; + self.memory[addr + 2 + ptr] = self.memory[REGISTER_PAGE + input_reg]; + } + } else { + self.memory[addr + 1] = 0; + for ptr in 0..max_len { + self.memory[addr + 1 + ptr] = 0x00; } } } @@ -232,7 +238,22 @@ impl Machine { } } 0x0D => { - + let input_reg = ((instruction) >> 24 & 0x0F) as usize; + let dest_ptr = (instruction & 0x00FFFFFF) as usize; + if input_reg != 0 { + // Input Reg must point to a Buffer + let src_ptr = self.memory[REGISTER_PAGE + input_reg] as usize; + if self.memory[dest_ptr] == self.memory[src_ptr] { + for i in 0..self.memory[dest_ptr] as usize { + self.memory[dest_ptr + i] = self.memory[src_ptr + i] + } + } else { + panic!( + "attempt to copy buffers of different lengths {} {}", + self.memory[dest_ptr], self.memory[src_ptr] + ) + } + } } 0x0E => { match instruction >> 24 { diff --git a/src/main.rs b/src/main.rs index 3bbea3d..b8f2925 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,15 @@ extern crate minifb; -use minifb::{Key, Scale, Window, WindowOptions, KeyRepeat}; -use side::assembler::ImageAssembler; -use side::{Machine, REGISTER_PAGE}; +use boo::assembler::ImageAssembler; +use boo::{Machine, REGISTER_PAGE}; +use minifb::{Key, KeyRepeat, Scale, Window, WindowOptions}; use std::env; use std::time::Duration; -//use font8x8::{BASIC_FONTS, UnicodeFonts}; - const WIDTH: usize = 640; const HEIGHT: usize = 480; fn main() { - // for font in BASIC_FONTS.iter().skip(0x20) { - // println!("label char_{}:", font.0); - // println!("\t${:02x}{:02x}{:02x}{:02x}", font.1[0],font.1[1],font.1[2],font.1[3]); - // println!("\t${:02x}{:02x}{:02x}{:02x}", font.1[4],font.1[5],font.1[6],font.1[7]); - // } - // return; - let args: Vec = env::args().collect(); let mut machine = Machine::new(); @@ -38,19 +29,13 @@ fn main() { let mut opts = WindowOptions::default(); opts.scale = Scale::X1; - let mut window = Window::new("Test - ESC to exit", WIDTH, HEIGHT, opts).unwrap_or_else(|e| { panic!("{}", e); }); - - while window.is_open() && !window.is_key_down(Key::Escape) { - - machine.cycle(); - if machine.memory[REGISTER_PAGE + 63] == 0x01 { // We unwrap here as we want this code to exit if it fails. Real applications may want to handle this in a different way window @@ -58,8 +43,6 @@ fn main() { .unwrap(); machine.memory[REGISTER_PAGE + 63] = 0x00; - - match window.get_keys_pressed(KeyRepeat::No) { None => {} Some(keys) => { @@ -67,56 +50,51 @@ fn main() { None => { //machine.set_keypress(0) } - Some(key) => { - match key { - Key::Key0 => {machine.set_keypress('0' as u32)} - Key::Key1 => {machine.set_keypress('1' as u32)} - Key::Key2 => {machine.set_keypress('2' as u32)} - Key::Key3 =>{machine.set_keypress('3' as u32)} - Key::Key4 => {machine.set_keypress('4' as u32)} - Key::Key5 => {machine.set_keypress('5' as u32)} - Key::Key6 => {machine.set_keypress('6' as u32)} - Key::Key7 => {machine.set_keypress('7' as u32)} - Key::Key8 => {machine.set_keypress('8' as u32)} - Key::Key9 => {machine.set_keypress('9' as u32)} - Key::A => {machine.set_keypress('A' as u32)} - Key::B => {machine.set_keypress('B' as u32)} - Key::C => {machine.set_keypress('C' as u32)} - Key::D => {machine.set_keypress('D' as u32)} - Key::E => {machine.set_keypress('E' as u32)} - Key::F => {machine.set_keypress('F' as u32)} - Key::G => {machine.set_keypress('G' as u32)} - Key::H => {machine.set_keypress('H' as u32)} - Key::I => {machine.set_keypress('I' as u32)} - Key::J => {machine.set_keypress('J' as u32)} - Key::K => {machine.set_keypress('K' as u32)} - Key::L => {machine.set_keypress('L' as u32)} - Key::M => {machine.set_keypress('M' as u32)} - Key::N => {machine.set_keypress('N' as u32)} - Key::O => {machine.set_keypress('O' as u32)} - Key::P => {machine.set_keypress('P' as u32)} - Key::Q => {machine.set_keypress('Q' as u32)} - Key::R => {machine.set_keypress('R' as u32)} - Key::S => {machine.set_keypress('S' as u32)} - Key::T => {machine.set_keypress('T' as u32)} - Key::U => {machine.set_keypress('U' as u32)} - Key::V => {machine.set_keypress('V' as u32)} - Key::W => {machine.set_keypress('W' as u32)} - Key::X => {machine.set_keypress('X' as u32)} - Key::Y => {machine.set_keypress('Y' as u32)} - Key::Z => {machine.set_keypress('Z' as u32)} - Key::Space => {machine.set_keypress(' ' as u32)} - Key::Backspace => {machine.set_keypress(0x7F as u32)} - Key::Enter => {machine.set_keypress(0x0A as u32)} - _=> { - machine.set_keypress('!' as u32) - } - } - } + Some(key) => match key { + Key::Key0 => machine.set_keypress('0' as u32), + Key::Key1 => machine.set_keypress('1' as u32), + Key::Key2 => machine.set_keypress('2' as u32), + Key::Key3 => machine.set_keypress('3' as u32), + Key::Key4 => machine.set_keypress('4' as u32), + Key::Key5 => machine.set_keypress('5' as u32), + Key::Key6 => machine.set_keypress('6' as u32), + Key::Key7 => machine.set_keypress('7' as u32), + Key::Key8 => machine.set_keypress('8' as u32), + Key::Key9 => machine.set_keypress('9' as u32), + Key::A => machine.set_keypress('A' as u32), + Key::B => machine.set_keypress('B' as u32), + Key::C => machine.set_keypress('C' as u32), + Key::D => machine.set_keypress('D' as u32), + Key::E => machine.set_keypress('E' as u32), + Key::F => machine.set_keypress('F' as u32), + Key::G => machine.set_keypress('G' as u32), + Key::H => machine.set_keypress('H' as u32), + Key::I => machine.set_keypress('I' as u32), + Key::J => machine.set_keypress('J' as u32), + Key::K => machine.set_keypress('K' as u32), + Key::L => machine.set_keypress('L' as u32), + Key::M => machine.set_keypress('M' as u32), + Key::N => machine.set_keypress('N' as u32), + Key::O => machine.set_keypress('O' as u32), + Key::P => machine.set_keypress('P' as u32), + Key::Q => machine.set_keypress('Q' as u32), + Key::R => machine.set_keypress('R' as u32), + Key::S => machine.set_keypress('S' as u32), + Key::T => machine.set_keypress('T' as u32), + Key::U => machine.set_keypress('U' as u32), + Key::V => machine.set_keypress('V' as u32), + Key::W => machine.set_keypress('W' as u32), + Key::X => machine.set_keypress('X' as u32), + Key::Y => machine.set_keypress('Y' as u32), + Key::Z => machine.set_keypress('Z' as u32), + Key::Space => machine.set_keypress(' ' as u32), + Key::Backspace => machine.set_keypress(0x7F as u32), + Key::Enter => machine.set_keypress(0x0A as u32), + _ => machine.set_keypress('!' as u32), + }, }; } }; - } } } diff --git a/strings.asm b/strings.asm index a7a16ad..f9e3133 100644 --- a/strings.asm +++ b/strings.asm @@ -15,6 +15,7 @@ rstore 1 $B; Transfer RAX to the Address Stored in R11 tx $2 $C + inc $B; Increment VBuf Pointer inc 2; INC Scratch Pixel @@ -23,7 +24,7 @@ ret label draw_char: - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 loadi 6 $18; shift 3 6 5; Shift To First Byte @@ -64,7 +65,7 @@ add $6 $B $B ; Move VBUF inc 4; Move to Second Part - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 loadi 6 $18; shift 3 6 5; Shift To First Byte @@ -108,7 +109,7 @@ label draw_string: label draw_next_char: - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 store 4 _scratch_draw_string loadi $2 $20 ; Load Addr of [SPACE] in $2 @@ -130,7 +131,7 @@ load $4 _scratch_draw_string inc $4; - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 tx $2 $3 loadi $1 0 jneq draw_next_char @@ -139,7 +140,7 @@ label num_to_char: loadi $2 HEX_TABLE add $2 $4 $4 - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 loadi $2 $20 ; Load Addr of [SPACE] in $2 sub $3 $2 $1 ; Sub the Character From Space loadi $2 2 diff --git a/util.asm b/util.asm index 1239f5c..2c85245 100644 --- a/util.asm +++ b/util.asm @@ -2,7 +2,7 @@ label _scratch_print_var: nop label print_addr: - ldstore 4 3; Load Arg 1 in 3 + rload 4 3; Load Arg 1 in 3 store $3 _scratch_print_var ; preserve rax loadi $7 $1C