362 lines
15 KiB
Rust
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;
|
|
//
|
|
}
|
|
}
|