const STACK_SIZE: usize = 1024; pub const MEMORY_SIZE: usize = 1<<20; pub const SCREEN_WIDTH: usize = 512; pub const SCREEN_HEIGHT: usize = 512; pub const SCREEN_UPDATE_ADDRESS: usize = 0x7FFFF; use minifb::Key; #[derive(Debug)] pub struct Stack { buffer: [u16;STACK_SIZE], index: usize } impl Stack { fn push(&mut self, value: u16) { self.buffer[self.index] = value; self.index = (self.index + 1) % STACK_SIZE; } fn pop(&mut self) -> u16 { self.index = (self.index + STACK_SIZE - 1) % STACK_SIZE; self.buffer[self.index] } } pub fn new_stack() -> Stack { Stack{ buffer: [0u16;STACK_SIZE], index: 0 } } pub struct Processor { pub stack_a: Stack, pub stack_b: Stack, pub memory: [u16;MEMORY_SIZE], pub carry: bool, pub pc: usize } impl Processor { pub fn run(&mut self) -> bool { let instruction = self.memory[self.pc] & 0x3FF; let (mut stack, off_stack) = { if (instruction & 0x200) == 0 { (&mut self.stack_a, &mut self.stack_b) } else {(&mut self.stack_b, &mut self.stack_a)} }; let mut is_jump = false; if instruction & 0x100 == 0 { //calculation self.carry = calc(&mut stack, instruction, self.carry); } else if instruction & 0x80 == 0 { //jump let push_pc = (instruction & 0x40) != 0; let conditional = (instruction & 0x20) != 0; if !conditional || self.carry { let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10); is_jump = true; if push_pc { let a = self.pc + 1; let upper = a & 0b11111111110000000000 >> 10; let lower = a & 0b1111111111; stack.push(upper as u16); stack.push(lower as u16); } self.pc = address; } } else { match instruction & 0x7F { 0 => { //immediate value self.pc += 1; stack.push(self.memory[self.pc] & 0x3FF); } 1 => { //push pc let upper = self.pc & 0b11111111110000000000 >> 10; let lower = self.pc & 0b1111111111; stack.push(upper as u16); stack.push(lower as u16); } 2 => { //swap let a = stack.pop(); let b = stack.pop(); stack.push(a); stack.push(b); } 3 => off_stack.push(stack.pop()), //move between stacks 4 => { //push from memory let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10); stack.push(self.memory[address]); } 5 => { //pop to memory let address = (stack.pop() as usize) | ((stack.pop() as usize) << 10); self.memory[address] = stack.pop(); } 6 => { //dup let a = stack.pop(); stack.push(a); stack.push(a); } 7 => { //over let a = stack.pop(); let b = stack.pop(); stack.push(b); stack.push(a); stack.push(b); } 8 => self.carry = false, //clear/set carry 9 => self.carry = true, 10 => _ = stack.pop(), //drop value 0x7F => return false, _ => () } } if !is_jump {self.pc += 1}; true } } fn calc(stack: &mut Stack, instruction: u16, carry_in: bool) -> bool { let operand_a = stack.pop(); let operand_b = stack.pop(); let mut carry = carry_in; let mut result = 0; for i in 0..10 { let count = ((operand_a >> i) & 1) + ((operand_b >> i) & 1) + (carry as u16); result += ((instruction >> (count+4)) & 1) << i; carry = ((instruction >> count) & 1) != 0; } stack.push(result); carry } pub fn mem_to_buf(memory: &[u16]) -> Vec { let mut result = Vec::new(); for byte in &memory[(MEMORY_SIZE-SCREEN_WIDTH*SCREEN_HEIGHT)..MEMORY_SIZE] { result.push((((byte & 0b111000000) as u32) << 15) | (((byte & 0b111000) as u32) << 10) | (((byte & 0b111) as u32) << 5)); //shifts 3 bits of each 10 bit value into the rgb channels of the buffer, from the last region of memory } result } pub fn keys_to_state(keys: Vec) -> Vec { //output is using only 10 bits each to match with let mut result = 0u128; //rest of system for key in keys { //see minifb docs for what number each key is result &= 1 << (key as usize); } let mut output = Vec::new(); for i in 0..11 { let slice = ((result>>(10*i))&0x3FF) as u16; output.push(slice); } output }