forked from AbleOS/holey-bytes
Initial commit
This commit is contained in:
commit
1bf49eafe1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"./Cargo.toml"
|
||||
]
|
||||
}
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -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"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -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]
|
2
DESIGN_DOC.md
Normal file
2
DESIGN_DOC.md
Normal file
|
@ -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.
|
49
src/bytecode.rs
Normal file
49
src/bytecode.rs
Normal file
|
@ -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;
|
341
src/lib.rs
Normal file
341
src/lib.rs
Normal file
|
@ -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<u8> = 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<u8>,
|
||||
registers: Registers,
|
||||
/// BUG: This DOES NOT account for overflowing
|
||||
last_timer_count: u32,
|
||||
timer_callback: Option<fn() -> u32>,
|
||||
}
|
||||
impl Engine {
|
||||
pub fn new(program: Vec<u8>) -> 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<HaltStatus, RuntimeErrors> {
|
||||
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<u8> = vec![];
|
||||
let mut rhs: Vec<u8> = 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<u8> = vec![];
|
||||
let mut rhs: Vec<u8> = 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<u8>,
|
||||
num64: Option<u64>,
|
||||
}
|
||||
|
||||
pub fn math_handler(math_op: u8, lhs: (bool, [u8; 4]), rhs: [u8; 4]) {
|
||||
match math_op {
|
||||
ADD => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue