commit 1bf49eafe1b15bf94e488f7b280dee067b064527 Author: Able Date: Mon Apr 17 07:31:18 2023 -0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..352a6265 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + "./Cargo.toml" + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..ba1a6b48 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "holey_bytes" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..5d242e48 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "holey_bytes" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/DESIGN_DOC.md b/DESIGN_DOC.md new file mode 100644 index 00000000..898cf6d5 --- /dev/null +++ b/DESIGN_DOC.md @@ -0,0 +1,2 @@ +Holey Bytes has two bit widths +8 bit to help with byte level manipulation and 64 bit numbers because nothing else should ever be used. \ No newline at end of file diff --git a/src/bytecode.rs b/src/bytecode.rs new file mode 100644 index 00000000..5cc4ab21 --- /dev/null +++ b/src/bytecode.rs @@ -0,0 +1,49 @@ +pub const NOP: u8 = 0; +pub const ADD: u8 = 1; +pub const SUB: u8 = 2; +pub const MML: u8 = 3; +pub const DIV: u8 = 4; + +pub const CONST_U8: u8 = 0x00; +pub const CONST_I8: i8 = 0x01; + +pub const CONST_U16: u8 = 0x02; +pub const CONST_I16: u8 = 0x03; + +pub const CONST_U32: u8 = 0x04; +pub const CONST_I32: u8 = 0x05; +pub const CONST_F32: u8 = 0x06; + +pub const CONST_U64: u8 = 0x07; +pub const CONST_I64: u8 = 0x08; +pub const CONST_F64: u8 = 0x09; + +pub const ADDRESS: u8 = 0x10; + +pub const RegisterA8: u8 = 0xA0; +pub const RegisterB8: u8 = 0xB0; +pub const RegisterC8: u8 = 0xC0; +pub const RegisterD8: u8 = 0xD0; +pub const RegisterE8: u8 = 0xE0; +pub const RegisterF8: u8 = 0xF0; + +pub const RegisterA16: u8 = 0xA1; +pub const RegisterB16: u8 = 0xB1; +pub const RegisterC16: u8 = 0xC1; +pub const RegisterD16: u8 = 0xD1; +pub const RegisterE16: u8 = 0xE1; +pub const RegisterF16: u8 = 0xF1; + +pub const RegisterA32: u8 = 0xA2; +pub const RegisterB32: u8 = 0xB2; +pub const RegisterC32: u8 = 0xC2; +pub const RegisterD32: u8 = 0xD2; +pub const RegisterE32: u8 = 0xE2; +pub const RegisterF32: u8 = 0xF2; + +pub const RegisterA64: u8 = 0xA3; +pub const RegisterB64: u8 = 0xB3; +pub const RegisterC64: u8 = 0xC3; +pub const RegisterD64: u8 = 0xD3; +pub const RegisterE64: u8 = 0xE3; +pub const RegisterF64: u8 = 0xF3; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..9796419f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,341 @@ +#![allow(unused_assignments)] +#![allow(unused_must_use)] + +pub mod bytecode; +use bytecode::*; + +pub struct Page { + data: [u8; 4096], +} + +#[repr(u16)] +/// All instructions will use `op src dest` format (if they take arguments) +/// most `src`s can be replaced with a constant +pub enum Instructions { + Nop = 0, // No Operation or nothing to do + // Add takes two `src`s and adds into a `dest` + // add + Add, + Sub, + Mul, + Div, //HTML Div not division for that refer to ~~Blam~~ + + Store, + // Load a value from one src to one dest + // `load a8 c8` + Load, +} + +// A `src` may be any of the following +// Memory Address +// Register +// Constant +// ~~Port~~ + +// A `dest` may be any of the following +// Memory Address +// Register + +// 0000 ;; NOP +// // Once we get to an instruction that makes sense we can interpret the next bytes relative to that instruction +// 0001 ;; add + +// // EXAMPLE +// 0001 +// // This grouping is called a pairing and is useful as a short little guide for how to read AOB +// (0xC0 0x03)/*0xC0 represents a constant that is size u8, 0x03 is 3*/ +// (0xC1 0x01)/*0xC1 represents a constant that is size i8, 0x01 is 1*/ +// (0xA0 0x01)/* 0xA0 represents a the a8 register as an unsigned number, 0x01 is 1*/ +// 0002 +// (0xC3 0x01 0x00)/*0xC3 represents a constant that is size u16 , 0x01 0x00 is 256*/ +#[test] +fn main() { + #[rustfmt::skip] + let prog: Vec = vec![ + NOP, + ADD, CONST_U8, 1, CONST_U8, 20, RegisterA8, + ADD, CONST_U8, 1, CONST_U8, 0, RegisterB8, + SUB, CONST_U8, 3, RegisterA8, RegisterC8, + ]; + let mut eng = Engine::new(prog); + // eng.timer_callback = Some(time); + eng.run(); + eng.dump(); +} +pub fn time() -> u32 { + 9 +} + +pub enum RuntimeErrors { + InvalidOpcode(u8), + RegisterTooSmall, +} + +// If you solve the halting problem feel free to remove this +pub enum HaltStatus { + Halted, + Running, +} + +#[rustfmt::skip] +pub struct Registers{ + a8: u8, a16: u16, a32: u32, a64: u64, + b8: u8, b16: u16, b32: u32, b64: u64, + c8: u8, c16: u16, c32: u32, c64: u64, + d8: u8, d16: u16, d32: u32, d64: u64, + e8: u8, e16: u16, e32: u32, e64: u64, + f8: u8, f16: u16, f32: u32, f64: u64, +} +impl Registers { + #[rustfmt::skip] + pub fn new() -> Self{ + Self{ + a8: 0, a16: 0, a32: 0, a64: 0, + b8: 0, b16: 0, b32: 0, b64: 0, + c8: 0, c16: 0, c32: 0, c64: 0, + d8: 0, d16: 0, d32: 0, d64: 0, + e8: 0, e16: 0, e32: 0, e64: 0, + f8: 0, f16: 0, f32: 0, f64: 0, + } + } +} + +pub const ENGINE_DELTA: u32 = 1; + +pub struct Engine { + index: usize, + program: Vec, + registers: Registers, + /// BUG: This DOES NOT account for overflowing + last_timer_count: u32, + timer_callback: Option u32>, +} +impl Engine { + pub fn new(program: Vec) -> Self { + Self { + index: 0, + program, + registers: Registers::new(), + last_timer_count: 0, + timer_callback: None, + } + } + pub fn dump(&self) { + println!("Reg A8 {}", self.registers.a8); + println!("Reg B8 {}", self.registers.b8); + println!("Reg C8 {}", self.registers.c8); + println!("Reg D8 {}", self.registers.d8); + println!("Reg E8 {}", self.registers.e8); + println!("Reg F8 {}", self.registers.f8); + } + pub fn run(&mut self) -> Result { + use HaltStatus::*; + use RuntimeErrors::*; + loop { + // Break out of the loop + if self.index == self.program.len() { + break; + } + let op = self.program[self.index]; + match op { + NOP => self.index += 1, + ADD => { + print!("Add"); + self.index += 1; + let mut lhs: Vec = vec![]; + let mut rhs: Vec = vec![]; + let mut lhs_signed = false; + let mut rhs_signed = false; + + match self.program[self.index] { + CONST_U8 => { + self.index += 1; + lhs.push(self.program[self.index]); + print!(" constant {:?}", lhs[0]); + lhs_signed = false; + self.index += 1; + } + op => return Err(InvalidOpcode(op)), + } + + match self.program[self.index] { + CONST_U8 => { + self.index += 1; + rhs.push(self.program[self.index]); + rhs_signed = false; + print!(" constant {:?}", rhs[0]); + self.index += 1; + } + _ => { + panic!() + } + } + match self.program[self.index] { + RegisterA8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in A8"); + + let sum = lhs[0] + rhs[0]; + self.registers.a8 = sum; + self.index += 1; + } + RegisterB8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in B8"); + let sum = lhs[0] + rhs[0]; + self.registers.b8 = sum; + self.index += 1; + } + RegisterC8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in C8"); + let sum = lhs[0] + rhs[0]; + self.registers.c8 = sum; + self.index += 1; + } + + RegisterD8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in D8"); + let sum = lhs[0] + rhs[0]; + self.registers.d8 = sum; + self.index += 1; + } + + _ => { + panic!() + } + } + } + SUB => { + print!("Sub"); + self.index += 1; + let mut lhs: Vec = vec![]; + let mut rhs: Vec = vec![]; + let mut lhs_signed = false; + let mut rhs_signed = false; + + match self.program[self.index] { + RegA8 => { + lhs.push(self.registers.a8); + lhs_signed = false; + print!(" constant {:?}", self.registers.a8); + self.index += 1; + } + RegB8 => { + lhs.push(self.registers.b8); + lhs_signed = false; + print!(" constant {:?}", self.registers.b8); + self.index += 1; + } + CONST_U8 => { + self.index += 1; + lhs.push(self.program[self.index]); + print!(" constant {:?}", lhs[0]); + lhs_signed = false; + self.index += 1; + } + op => return Err(InvalidOpcode(op)), + } + + match self.program[self.index] { + RegB8 => { + rhs.push(self.registers.b8); + rhs_signed = false; + print!(" constant {:?}", self.registers.b8); + self.index += 1; + } + _ => { + panic!() + } + } + match self.program[self.index] { + RegisterA8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + println!(" store in A8"); + + let sum = lhs[0] - rhs[0]; + self.registers.a8 = sum; + self.index += 1; + } + RegisterB8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in B8"); + let sum = lhs[0] - rhs[0]; + self.registers.b8 = sum; + self.index += 1; + } + RegisterC8 => { + if lhs.len() > 1 { + panic!("LHS is not an 8 bit number") + } + if rhs.len() > 1 { + panic!("RHS is not an 8 bit number") + } + println!(" store in B8"); + let sum = lhs[0] - rhs[0]; + self.registers.c8 = sum; + self.index += 1; + } + _ => { + panic!() + } + } + } + op => { + println!("INVALID OPCODE {}", op); + self.index += 1; + } + } + // Finish step + + if self.timer_callback.is_some() { + let ret = self.timer_callback.unwrap()(); + if (ret - self.last_timer_count) >= ENGINE_DELTA { + return Ok(Running); + } + } + } + Ok(Halted) + } +} + +pub struct HandSide { + signed: bool, + num8: Option, + num64: Option, +} + +pub fn math_handler(math_op: u8, lhs: (bool, [u8; 4]), rhs: [u8; 4]) { + match math_op { + ADD => {} + _ => {} + } +}