boo-os/src/lib.rs

362 lines
15 KiB
Rust

pub mod assembler;
pub const VRAM: usize = 640 * 480;
pub const REGISTER_PAGE: usize = VRAM;
pub const INPUT_PAGE: usize = VRAM + 64;
pub const OFFSET: usize = INPUT_PAGE;
pub const MEM_SIZE: usize = 0xFFFFFF - OFFSET;
pub const MEMORY: usize = OFFSET + MEM_SIZE;
pub struct Machine {
pub memory: Vec<u32>,
}
impl Machine {
pub fn new() -> Machine {
let mut memory = vec![0; MEMORY];
memory[REGISTER_PAGE] = 0x00;
Machine { memory }
}
pub fn hlt(&self, ip: usize, instruction: u32) {
println!("---");
println!("{:x} {:x}", ip, instruction);
println!(
"REG 1:{:X} 2:{:X} 3:{:X} 4:{:X}",
self.memory[REGISTER_PAGE + 1],
self.memory[REGISTER_PAGE + 2],
self.memory[REGISTER_PAGE + 3],
self.memory[REGISTER_PAGE + 4]
);
println!(
"REG 5:{:X} 6:{:X} 7:{:X} 8:{:X}",
self.memory[REGISTER_PAGE + 5],
self.memory[REGISTER_PAGE + 6],
self.memory[REGISTER_PAGE + 7],
self.memory[REGISTER_PAGE + 8],
);
println!(
"REG 9:{:X} A:{:X} B:{:X} C:{:X}",
self.memory[REGISTER_PAGE + 9],
self.memory[REGISTER_PAGE + 10],
self.memory[REGISTER_PAGE + 11],
self.memory[REGISTER_PAGE + 12],
);
panic!("hlt")
}
pub fn set_keypress(&mut self, char: u32) {
self.memory[INPUT_PAGE + 1] = char
}
pub fn load(&mut self, memory: Vec<u32>) {
self.memory = memory;
self.memory[INPUT_PAGE] = 0x00;
}
pub fn dump(&self) -> Vec<u32> {
return self.memory.clone();
}
pub fn cycle(&mut self) {
let ip = self.memory[REGISTER_PAGE] as usize;
let instruction = self.memory[ip];
self.memory[INPUT_PAGE] += 1;
match instruction >> 28 {
0x0 => {
match instruction >> 24 {
0x00 => {
// NOP
}
0x01 => {
self.memory[REGISTER_PAGE + 63] = 0x01;
}
0x0F => {
println!("---");
println!(
"REG 1:{:X} 2:{:X} 3:{:X} 4:{:X}",
self.memory[REGISTER_PAGE + 1],
self.memory[REGISTER_PAGE + 2],
self.memory[REGISTER_PAGE + 3],
self.memory[REGISTER_PAGE + 4]
);
println!(
"REG 5:{:X} 6:{:X} 7:{:X} 8:{:X}",
self.memory[REGISTER_PAGE + 5],
self.memory[REGISTER_PAGE + 6],
self.memory[REGISTER_PAGE + 7],
self.memory[REGISTER_PAGE + 8],
);
println!(
"REG 9:{:X} A:{:X} B:{:X} C:{:X}",
self.memory[REGISTER_PAGE + 9],
self.memory[REGISTER_PAGE + 10],
self.memory[REGISTER_PAGE + 11],
self.memory[REGISTER_PAGE + 12],
);
panic!("HLT");
}
0x04 => {
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;
if ptr > 0 {
self.memory[addr + 1] -= 1;
self.memory[addr + 2 + ptr - 1] = 0x00;
self.memory[addr + 2 + ptr - 1] = 0x00;
}
}
op => {
unimplemented!("0x0 Meta Instruction {}", op)
}
}
}
0x1 => {
// STORE R(X) => ADDR
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
let mem = instruction & 0x00FFFFFF;
self.memory[mem as usize] = self.memory[REGISTER_PAGE + input_reg];
}
0x2 => {
// LOAD ADDR => R(X)
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE + input_reg] = self.memory[mem as usize];
}
0x3 => {
// LOAD IMMEDIATE => R(X)
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
let imm = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE + input_reg] = imm;
}
0x04 => {
// INC R(X)
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
self.memory[REGISTER_PAGE + input_reg] += 1;
}
0x05 => {
// DEC R(X)
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
self.memory[REGISTER_PAGE + input_reg] -= 1;
}
0x06 => {
// STORE Mem[R(Addr)] = R(In)
let reg = (instruction & 0x000000FF) as usize;// 4
let addr = self.memory[REGISTER_PAGE + reg] as usize; // R(
let input_reg = ((instruction) >> 24 & 0x0F) as usize; // C4)
// Mem(4) = R(C)
self.memory[addr] = self.memory[REGISTER_PAGE + input_reg];
}
0x07 => {
// RLOAD R(X) = MEM(R(In))
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
let reg = (instruction & 0x000000FF) as usize;
self.memory[REGISTER_PAGE + reg] =
self.memory.get(self.memory[REGISTER_PAGE + input_reg] as usize).unwrap_or_else(|| { println!("could not rload: {:x} {:x} {:x}", input_reg, reg, self.memory[REGISTER_PAGE + input_reg] as usize); self.hlt(ip, instruction); unreachable!()}).clone();
}
0x08 => {
// TX R(In) => R(X)
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
let reg = (instruction & 0x000000FF) as usize;
self.memory[REGISTER_PAGE + input_reg] = self.memory[REGISTER_PAGE + reg];
}
0x0A => {
match instruction >> 24 {
// ADD A B => C
0xA1 => {
let a_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let b_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let a = self.memory[REGISTER_PAGE + a_reg];
let b = self.memory[REGISTER_PAGE + b_reg];
let result = a.overflowing_add(b);
if result.1 {
}
self.memory[REGISTER_PAGE + dest_reg] = result.0;
}
// SUB A B => C
0xA2 => {
let a_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let b_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let a = self.memory[REGISTER_PAGE + a_reg];
let b = self.memory[REGISTER_PAGE + b_reg];
let result = a.overflowing_sub(b);
if result.1 {
}
self.memory[REGISTER_PAGE + dest_reg] = result.0;
}
// MUL A B => C
0xA3 => {
let a_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let b_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let a = self.memory[REGISTER_PAGE + a_reg];
let b = self.memory[REGISTER_PAGE + b_reg];
let result = a.overflowing_mul(b);
if result.1 {
}
self.memory[REGISTER_PAGE + dest_reg] = result.0;
}
// RSHIFT A >> B => C
0xA5 => {
let source_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let bit_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let source = self.memory[REGISTER_PAGE + source_reg];
let bits = self.memory[REGISTER_PAGE + bit_reg];
let result = source >> bits;
self.memory[REGISTER_PAGE + dest_reg] = result;
}
// AND A & B => C
0xA6 => {
let source_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let mask_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let source = self.memory[REGISTER_PAGE + source_reg];
let bits = self.memory[REGISTER_PAGE + mask_reg];
let result = source & bits;
self.memory[REGISTER_PAGE + dest_reg] = result;
}
// LSHIFT A << B => C
0xA7 => {
let source_reg = ((instruction & 0x00FF0000) >> 16) as usize;
let bit_reg = ((instruction & 0x0000FF00) >> 8) as usize;
let dest_reg = (instruction & 0xFF) as usize;
let source = self.memory[REGISTER_PAGE + source_reg];
let bits = self.memory[REGISTER_PAGE + bit_reg];
let result = source << bits;
self.memory[REGISTER_PAGE + dest_reg] = result;
}
op => {
unimplemented!("0x0 Addition Instruction {}", op)
}
}
}
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;
if ptr < max_len {
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;
}
}
}
0x0C => {
match instruction >> 24 {
// RET (Pops call stack and JMPs)
0xC0 => {
let sp = self.memory[REGISTER_PAGE + 62] as usize;
self.memory[REGISTER_PAGE] = self.memory[REGISTER_PAGE + 62 - sp];
self.memory[REGISTER_PAGE + 62] -= 1;
}
// CALL Addr (Pushed Addr and JMPS)
0xC1 => {
self.memory[REGISTER_PAGE + 62] += 1;
let sp = self.memory[REGISTER_PAGE + 62] as usize;
self.memory[REGISTER_PAGE + 62 - sp] = self.memory[REGISTER_PAGE];
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
op => {
unimplemented!("0x0 Call Strack Instruction {}", op)
}
}
}
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 {
0xE0 => {
// Unconditional JMP
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
0xE1 => {
// JEQ ADDR if R(1) != R(2)
if self.memory[REGISTER_PAGE + 1] == self.memory[REGISTER_PAGE + 2] {
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
}
0xE2 => {
// JEQ ADDR if R(1) != R(2)
if self.memory[REGISTER_PAGE + 1] != self.memory[REGISTER_PAGE + 2] {
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
}
0xE3 => {
// JMP ADDR if R(1) > R(2)
if self.memory[REGISTER_PAGE + 1] > self.memory[REGISTER_PAGE + 2] {
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
}
0xE4 => {
// JMP ADDR if R(1) > R(2)
if self.memory[REGISTER_PAGE + 1] < self.memory[REGISTER_PAGE + 2] {
let mem = instruction & 0x00FFFFFF;
self.memory[REGISTER_PAGE] = mem - 1;
}
}
0xEf => {
let mem = instruction & 0x0000FF;
self.memory[REGISTER_PAGE] = self.memory[REGISTER_PAGE+mem as usize]-1;
}
op => {
unimplemented!("0x0 JMP Instruction {}", op)
}
}
}
x => {
panic!("unknown bytecode opcode {:X} {:X} {:X}", x, ip, instruction)
}
}
self.memory[REGISTER_PAGE] += 1;
//
}
}