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, } 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) { self.memory = memory; self.memory[INPUT_PAGE] = 0x00; } pub fn dump(&self) -> Vec { 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; // } }