master
Sarah Jamie Lewis 1 year ago
parent 2947f12356
commit 5b958337a6
  1. 23
      Cargo.lock
  2. 3
      Cargo.toml
  3. 6
      graphics.asm
  4. 59
      kernel.asm
  5. 138
      src/assembler.rs
  6. 39
      src/lib.rs
  7. 112
      src/main.rs
  8. 11
      strings.asm
  9. 2
      util.asm

23
Cargo.lock generated

@ -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"

@ -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"

@ -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

@ -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

@ -1,9 +1,9 @@
use crate::{Machine, MEMORY};
use std::collections::HashMap;
use std::fs::read_to_string;
use image::png::PngDecoder;
use image::io::Reader;
use image::png::PngDecoder;
use image::GenericImageView;
use std::collections::HashMap;
use std::fs::read_to_string;
pub struct ImageAssembler {
memory: Vec<u32>,
@ -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,45 +285,80 @@ 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)
}
}
_ => 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)
}
}
},
}
_ => {
match self.labels.get(input) {
Some(addr) => {
return addr.clone() 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)
}
},
},
}
}
}

@ -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<u32>) {
@ -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 {

@ -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<String> = 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),
},
};
}
};
}
}
}

@ -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

@ -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

Loading…
Cancel
Save