commit
This commit is contained in:
parent
1bf49eafe1
commit
fb2c859db1
|
@ -1,2 +1,37 @@
|
||||||
Holey Bytes has two bit widths
|
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.
|
8 bit to help with byte level manipulation and 64 bit numbers because nothing else should ever be used in a modern setting
|
||||||
|
|
||||||
|
this leaves us with an amount of registers that should be defined
|
||||||
|
I'd like to use a letter and a number to represent registers
|
||||||
|
like `a0` or `d0` the first of which would be reserved for 8 bit numbers and the later of which 64 bit.
|
||||||
|
|
||||||
|
instructions
|
||||||
|
### NOP
|
||||||
|
`0`
|
||||||
|
|
||||||
|
### ADD_8 TYPE LHS RHS LOCATION
|
||||||
|
`1`
|
||||||
|
### SUB TYPE LHS RHS LOCATION
|
||||||
|
`2`
|
||||||
|
### MUL TYPE LHS RHS LOCATION
|
||||||
|
`3`
|
||||||
|
### MUL TYPE LHS RHS LOCATION
|
||||||
|
`4`
|
||||||
|
### DIV TYPE LHS RHS LOCATION
|
||||||
|
`5`
|
||||||
|
|
||||||
|
### JUMP ADDR
|
||||||
|
`100`
|
||||||
|
an unconditional jump to an address
|
||||||
|
|
||||||
|
### JUMP_EQ LHS RHS ADDR
|
||||||
|
`101`
|
||||||
|
A conditional jump
|
||||||
|
if LHS is equal to RHS then jump to address
|
||||||
|
### JUMP_NEQ LHS RHS ADDR
|
||||||
|
`102`
|
||||||
|
A conditional jump
|
||||||
|
if LHS is not equal to RHS then jump to address
|
||||||
|
|
||||||
|
### RET
|
||||||
|
pop off the callstack
|
|
@ -1,49 +0,0 @@
|
||||||
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;
|
|
2
src/bytecode/mod.rs
Normal file
2
src/bytecode/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod ops;
|
||||||
|
pub mod types;
|
32
src/bytecode/ops.rs
Normal file
32
src/bytecode/ops.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum Operations {
|
||||||
|
NOP = 0,
|
||||||
|
ADD = 1,
|
||||||
|
SUB = 2,
|
||||||
|
MUL = 3,
|
||||||
|
DIV = 4,
|
||||||
|
|
||||||
|
// READs a register/memory address/constant into a register
|
||||||
|
READ = 5,
|
||||||
|
// WRITEs a register/memory address/constant into a memory address
|
||||||
|
WRITE = 6,
|
||||||
|
|
||||||
|
JUMP = 100,
|
||||||
|
JumpEq = 101,
|
||||||
|
JumpNeq = 102,
|
||||||
|
RET = 103,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MathTypes {
|
||||||
|
EightBit = 1,
|
||||||
|
SixtyFourBit = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RWTypes {
|
||||||
|
RegisterToAddress = 0,
|
||||||
|
RegisterToRegister = 1,
|
||||||
|
ConstantToAddress = 2,
|
||||||
|
ConstantToRegister = 3,
|
||||||
|
AddressToRegister = 4,
|
||||||
|
AddressToAddress = 5,
|
||||||
|
}
|
9
src/bytecode/types.rs
Normal file
9
src/bytecode/types.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
pub const CONST_U8: u8 = 0x00;
|
||||||
|
pub const CONST_I8: i8 = 0x01;
|
||||||
|
|
||||||
|
pub const CONST_U64: u8 = 0x02;
|
||||||
|
pub const CONST_I64: u8 = 0x03;
|
||||||
|
pub const CONST_F64: u8 = 0x04;
|
||||||
|
|
||||||
|
pub const ADDRESS: u8 = 0x05;
|
4
src/engine/call_stack.rs
Normal file
4
src/engine/call_stack.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub type CallStack = Vec<FnCall>;
|
||||||
|
pub struct FnCall {
|
||||||
|
ret: usize,
|
||||||
|
}
|
13
src/engine/config.rs
Normal file
13
src/engine/config.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
pub struct EngineConfig {
|
||||||
|
pub call_stack_depth: usize,
|
||||||
|
pub quantum: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EngineConfig {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
call_stack_depth: 32,
|
||||||
|
quantum: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
370
src/engine/mod.rs
Normal file
370
src/engine/mod.rs
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
pub mod call_stack;
|
||||||
|
pub mod config;
|
||||||
|
pub mod regs;
|
||||||
|
|
||||||
|
use crate::bytecode::ops::*;
|
||||||
|
use crate::bytecode::types::*;
|
||||||
|
|
||||||
|
use crate::HaltStatus;
|
||||||
|
use crate::Page;
|
||||||
|
use crate::RuntimeErrors;
|
||||||
|
use config::EngineConfig;
|
||||||
|
use regs::Registers;
|
||||||
|
|
||||||
|
use self::call_stack::CallStack;
|
||||||
|
|
||||||
|
pub struct Engine {
|
||||||
|
pub index: usize,
|
||||||
|
program: Vec<u8>,
|
||||||
|
registers: Registers,
|
||||||
|
config: EngineConfig,
|
||||||
|
|
||||||
|
/// BUG: This DOES NOT account for overflowing
|
||||||
|
last_timer_count: u32,
|
||||||
|
timer_callback: Option<fn() -> u32>,
|
||||||
|
memory: Vec<Page>,
|
||||||
|
call_stack: CallStack,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
pub fn new(program: Vec<u8>) -> Self {
|
||||||
|
Self {
|
||||||
|
index: 0,
|
||||||
|
program,
|
||||||
|
registers: Registers::new(),
|
||||||
|
config: EngineConfig::default(),
|
||||||
|
last_timer_count: 0,
|
||||||
|
timer_callback: None,
|
||||||
|
memory: vec![],
|
||||||
|
call_stack: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!("Registers");
|
||||||
|
println!(
|
||||||
|
"A {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}",
|
||||||
|
self.registers.a0,
|
||||||
|
self.registers.a1,
|
||||||
|
self.registers.a2,
|
||||||
|
self.registers.a3,
|
||||||
|
self.registers.a4,
|
||||||
|
self.registers.a5,
|
||||||
|
self.registers.a6,
|
||||||
|
self.registers.a7,
|
||||||
|
self.registers.a8,
|
||||||
|
self.registers.a9,
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"B {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}",
|
||||||
|
self.registers.b0,
|
||||||
|
self.registers.b1,
|
||||||
|
self.registers.b2,
|
||||||
|
self.registers.b3,
|
||||||
|
self.registers.b4,
|
||||||
|
self.registers.b5,
|
||||||
|
self.registers.b6,
|
||||||
|
self.registers.b7,
|
||||||
|
self.registers.b8,
|
||||||
|
self.registers.b9,
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"C {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}",
|
||||||
|
self.registers.c0,
|
||||||
|
self.registers.c1,
|
||||||
|
self.registers.c2,
|
||||||
|
self.registers.c3,
|
||||||
|
self.registers.c4,
|
||||||
|
self.registers.c5,
|
||||||
|
self.registers.c6,
|
||||||
|
self.registers.c7,
|
||||||
|
self.registers.c8,
|
||||||
|
self.registers.c9,
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"D0-D4 {:016X} {:016X} {:016X} {:016X} {:016X}
|
||||||
|
D5-D9 {:016X} {:016X} {:016X} {:016X} {:016X}",
|
||||||
|
self.registers.d0,
|
||||||
|
self.registers.d1,
|
||||||
|
self.registers.d2,
|
||||||
|
self.registers.d3,
|
||||||
|
self.registers.d4,
|
||||||
|
self.registers.d5,
|
||||||
|
self.registers.d6,
|
||||||
|
self.registers.d7,
|
||||||
|
self.registers.d8,
|
||||||
|
self.registers.d9,
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"E0-E4 {:016X} {:016X} {:016X} {:016X} {:016X}
|
||||||
|
E5-E9 {:016X} {:016X} {:016X} {:016X} {:016X}",
|
||||||
|
self.registers.e0,
|
||||||
|
self.registers.e1,
|
||||||
|
self.registers.e2,
|
||||||
|
self.registers.e3,
|
||||||
|
self.registers.e4,
|
||||||
|
self.registers.e5,
|
||||||
|
self.registers.e6,
|
||||||
|
self.registers.e7,
|
||||||
|
self.registers.e8,
|
||||||
|
self.registers.e9,
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"F0-F4 {:016X} {:016X} {:016X} {:016X} {:016X}
|
||||||
|
F5-F9 {:016X} {:016X} {:016X} {:016X} {:016X}",
|
||||||
|
self.registers.f0,
|
||||||
|
self.registers.f1,
|
||||||
|
self.registers.f2,
|
||||||
|
self.registers.f3,
|
||||||
|
self.registers.f4,
|
||||||
|
self.registers.f5,
|
||||||
|
self.registers.f6,
|
||||||
|
self.registers.f7,
|
||||||
|
self.registers.f8,
|
||||||
|
self.registers.f9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
println!("OP {} INDEX {}", self.program[self.index], 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;
|
||||||
|
}
|
||||||
|
CONST_U64 => {
|
||||||
|
self.index += 1;
|
||||||
|
lhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
lhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
lhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
lhs.push(self.program[self.index]);
|
||||||
|
|
||||||
|
lhs_signed = false;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xA0..=0xC9 => {
|
||||||
|
println!("TRACE: 8 bit lhs");
|
||||||
|
}
|
||||||
|
0xD0..=0xFF => {
|
||||||
|
println!("TRACE: 64 bit lhs");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONST_U64 => {
|
||||||
|
self.index += 1;
|
||||||
|
rhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
rhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
rhs.push(self.program[self.index]);
|
||||||
|
self.index += 1;
|
||||||
|
rhs.push(self.program[self.index]);
|
||||||
|
|
||||||
|
print!(" constant {:?}", rhs[0]);
|
||||||
|
rhs_signed = false;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xA0..=0xC9 => {
|
||||||
|
println!("TRACE: 8 bit rhs");
|
||||||
|
}
|
||||||
|
0xD0..=0xFF => {
|
||||||
|
println!("TRACE: 64 bit rhs");
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match self.program[self.index] {
|
||||||
|
0xA0 => {
|
||||||
|
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 A0");
|
||||||
|
|
||||||
|
let sum = lhs[0] + rhs[0];
|
||||||
|
self.registers.a0 = sum;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xB0 => {
|
||||||
|
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 B0");
|
||||||
|
let sum = lhs[0] + rhs[0];
|
||||||
|
self.registers.b0 = sum;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xC0 => {
|
||||||
|
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 C0");
|
||||||
|
let sum = lhs[0] + rhs[0];
|
||||||
|
self.registers.c8 = sum;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xD0 => {
|
||||||
|
if lhs.len() > 4 {
|
||||||
|
panic!("LHS is not an 8 bit number")
|
||||||
|
}
|
||||||
|
if rhs.len() > 4 {
|
||||||
|
panic!("RHS is not an 8 bit number")
|
||||||
|
}
|
||||||
|
println!(" store in D0");
|
||||||
|
let lhs: u64 = Into::<u64>::into(lhs[3]) << 60;
|
||||||
|
println!("{}", lhs);
|
||||||
|
println!("{}", 2);
|
||||||
|
// let rhs: u64 = (rhs[4] << 16).into();
|
||||||
|
let rhs: u64 = 0;
|
||||||
|
let sum = lhs + rhs;
|
||||||
|
self.registers.d0 = sum;
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
op => {
|
||||||
|
println!("{}", op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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] {
|
||||||
|
0xA0 => {
|
||||||
|
lhs.push(self.registers.a8);
|
||||||
|
lhs_signed = false;
|
||||||
|
print!(" constant {:?}", self.registers.a8);
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
0xB0 => {
|
||||||
|
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] {
|
||||||
|
0xB0 => {
|
||||||
|
rhs.push(self.registers.b8);
|
||||||
|
rhs_signed = false;
|
||||||
|
print!(" constant {:?}", self.registers.b8);
|
||||||
|
self.index += 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match self.program[self.index] {
|
||||||
|
0xA0 => {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
0xB0 => {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
0xC0 => {
|
||||||
|
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) >= self.config.quantum {
|
||||||
|
return Ok(Running);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Halted)
|
||||||
|
}
|
||||||
|
}
|
30
src/engine/regs.rs
Normal file
30
src/engine/regs.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub struct Registers{
|
||||||
|
pub a0: u8, pub b0: u8, pub c0: u8, pub d0: u64, pub e0: u64, pub f0: u64,
|
||||||
|
pub a1: u8, pub b1: u8, pub c1: u8, pub d1: u64, pub e1: u64, pub f1: u64,
|
||||||
|
pub a2: u8, pub b2: u8, pub c2: u8, pub d2: u64, pub e2: u64, pub f2: u64,
|
||||||
|
pub a3: u8, pub b3: u8, pub c3: u8, pub d3: u64, pub e3: u64, pub f3: u64,
|
||||||
|
pub a4: u8, pub b4: u8, pub c4: u8, pub d4: u64, pub e4: u64, pub f4: u64,
|
||||||
|
pub a5: u8, pub b5: u8, pub c5: u8, pub d5: u64, pub e5: u64, pub f5: u64,
|
||||||
|
pub a6: u8, pub b6: u8, pub c6: u8, pub d6: u64, pub e6: u64, pub f6: u64,
|
||||||
|
pub a7: u8, pub b7: u8, pub c7: u8, pub d7: u64, pub e7: u64, pub f7: u64,
|
||||||
|
pub a8: u8, pub b8: u8, pub c8: u8, pub d8: u64, pub e8: u64, pub f8: u64,
|
||||||
|
pub a9: u8, pub b9: u8, pub c9: u8, pub d9: u64, pub e9: u64, pub f9: u64,
|
||||||
|
}
|
||||||
|
impl Registers {
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub fn new() -> Self{
|
||||||
|
Self {
|
||||||
|
a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0,
|
||||||
|
a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0,
|
||||||
|
a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0,
|
||||||
|
a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0,
|
||||||
|
a4: 0, b4: 0, c4: 0, d4: 0, e4: 0, f4: 0,
|
||||||
|
a5: 0, b5: 0, c5: 0, d5: 0, e5: 0, f5: 0,
|
||||||
|
a6: 0, b6: 0, c6: 0, d6: 0, e6: 0, f6: 0,
|
||||||
|
a7: 0, b7: 0, c7: 0, d7: 0, e7: 0, f7: 0,
|
||||||
|
a8: 0, b8: 0, c8: 0, d8: 0, e8: 0, f8: 0,
|
||||||
|
a9: 0, b9: 0, c9: 0, d9: 0, e9: 0, f9: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
324
src/lib.rs
324
src/lib.rs
|
@ -1,71 +1,17 @@
|
||||||
#![allow(unused_assignments)]
|
|
||||||
#![allow(unused_must_use)]
|
|
||||||
|
|
||||||
pub mod bytecode;
|
pub mod bytecode;
|
||||||
use bytecode::*;
|
pub mod engine;
|
||||||
|
use bytecode::ops::*;
|
||||||
|
use bytecode::types::{CONST_F64, CONST_U8};
|
||||||
|
use engine::Engine;
|
||||||
|
|
||||||
pub struct Page {
|
pub struct Page {
|
||||||
data: [u8; 4096],
|
pub data: [u8; 4096 * 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 {
|
pub fn time() -> u32 {
|
||||||
9
|
9
|
||||||
}
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum RuntimeErrors {
|
pub enum RuntimeErrors {
|
||||||
InvalidOpcode(u8),
|
InvalidOpcode(u8),
|
||||||
RegisterTooSmall,
|
RegisterTooSmall,
|
||||||
|
@ -77,265 +23,9 @@ pub enum HaltStatus {
|
||||||
Running,
|
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 {
|
pub struct HandSide {
|
||||||
signed: bool,
|
signed: bool,
|
||||||
|
float: bool,
|
||||||
num8: Option<u8>,
|
num8: Option<u8>,
|
||||||
num64: Option<u64>,
|
num64: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn math_handler(math_op: u8, lhs: (bool, [u8; 4]), rhs: [u8; 4]) {
|
|
||||||
match math_op {
|
|
||||||
ADD => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
20
src/main.rs
Normal file
20
src/main.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use holey_bytes::bytecode::ops::Operations::*;
|
||||||
|
use holey_bytes::bytecode::types::CONST_U64;
|
||||||
|
use holey_bytes::RuntimeErrors;
|
||||||
|
use holey_bytes::{bytecode::types::CONST_U8, engine::Engine};
|
||||||
|
|
||||||
|
fn main() -> Result<(), RuntimeErrors> {
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let prog: Vec<u8> = vec![
|
||||||
|
NOP as u8,
|
||||||
|
ADD as u8, CONST_U8, 1, CONST_U8, 20, 0xA0,
|
||||||
|
ADD as u8, CONST_U8, 1, CONST_U8, 0, 0xB0,
|
||||||
|
ADD as u8, CONST_U64, 0, 0, 0, 2, CONST_U64, 0, 0, 0, 2, 0xD0,
|
||||||
|
// SUB, CONST_U8, 4, CONST_U8, 1, 0xC8,
|
||||||
|
];
|
||||||
|
let mut eng = Engine::new(prog);
|
||||||
|
// eng.timer_callback = Some(time);
|
||||||
|
eng.run()?;
|
||||||
|
// eng.dump();
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue