231 lines
9.6 KiB
Rust
231 lines
9.6 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 = 65535;
|
||
|
pub const MEMORY: usize = OFFSET + MEM_SIZE;
|
||
|
|
||
|
pub struct Machine {
|
||
|
pub memory: [u32; MEMORY],
|
||
|
}
|
||
|
|
||
|
impl Machine {
|
||
|
pub fn new() -> Machine {
|
||
|
let mut memory = [0; MEMORY];
|
||
|
|
||
|
memory[REGISTER_PAGE] = 0x00;
|
||
|
|
||
|
Machine { memory }
|
||
|
}
|
||
|
|
||
|
pub fn load(&mut self, memory: [u32; MEMORY]) {
|
||
|
self.memory = memory;
|
||
|
self.memory[INPUT_PAGE] = 0x00;
|
||
|
}
|
||
|
|
||
|
pub fn dump(&self) -> [u32; MEMORY] {
|
||
|
return self.memory;
|
||
|
}
|
||
|
|
||
|
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");
|
||
|
}
|
||
|
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(In)] = R(X)
|
||
|
let input_reg = ((instruction) >> 24 & 0x0F) as usize;
|
||
|
let reg = (instruction & 0x000000FF) as usize;
|
||
|
let addr = self.memory[REGISTER_PAGE + reg] as usize;
|
||
|
self.memory[addr] = self.memory[REGISTER_PAGE + input_reg];
|
||
|
}
|
||
|
0x07 => {
|
||
|
// LOAD 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[self.memory[REGISTER_PAGE + input_reg] as usize];
|
||
|
}
|
||
|
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 + b;
|
||
|
self.memory[REGISTER_PAGE + dest_reg] = result;
|
||
|
}
|
||
|
// 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 - b;
|
||
|
self.memory[REGISTER_PAGE + dest_reg] = result;
|
||
|
}
|
||
|
// 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 * b;
|
||
|
self.memory[REGISTER_PAGE + dest_reg] = result;
|
||
|
}
|
||
|
// 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;
|
||
|
}
|
||
|
op => {
|
||
|
unimplemented!("0x0 Addition Instruction {}", op)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
0x0E => {
|
||
|
match instruction >> 24 {
|
||
|
0xE0 => {
|
||
|
// Unconditional JMP
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
op => {
|
||
|
unimplemented!("0x0 JMP Instruction {}", op)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
x => {
|
||
|
panic!("unknown bytecode opcode {:X} {:X} {:X}", x, ip, instruction)
|
||
|
}
|
||
|
}
|
||
|
self.memory[REGISTER_PAGE] += 1;
|
||
|
//
|
||
|
}
|
||
|
}
|