diff --git a/examples/first.asm b/examples/first.asm index 2c30fd6..cd1cd2c 100644 --- a/examples/first.asm +++ b/examples/first.asm @@ -1,11 +1,7 @@ ;#include "../src/foot.asm" label: -CNST. r0, 0xFBFF -CNST. r29, 0x400 - +CNST. r0, #0xFBFF +CNST. r30, #0x400 ADDI.r [r0++], [r0], r0 - -CNST. r31, label - -data: \ No newline at end of file +CNST. r31, #label \ No newline at end of file diff --git a/examples/mandelbrot.asm b/examples/mandelbrot.asm new file mode 100644 index 0000000..d32768b --- /dev/null +++ b/examples/mandelbrot.asm @@ -0,0 +1,18 @@ +;#include "../src/foot.asm" + +value_count = 1024 + +; generate starting values +CNST. r30, #value_count +CNST. r0, #xvals +ADDI.r [r0++], r30, #0 + + +end: +CNST + +xvals: +#res value_count + +yvals: +#res value_count \ No newline at end of file diff --git a/src/foot.asm b/src/foot.asm index 08cd966..782a647 100644 --- a/src/foot.asm +++ b/src/foot.asm @@ -2,7 +2,7 @@ #subruledef operand { - #{immediate: u5} => 0b000 @ immediate + #{immediate: i5} => 0b000 @ immediate r{register: u5} => 0b001 @ register [r{register: u5}++] => 0b010 @ register [r{register: u5}--] => 0b011 @ register @@ -30,7 +30,7 @@ #ruledef { - CNST{flags: crflags} {dst: operand}, {imm: i16} => imm @ flags @ 0b0000 @ dst + CNST{flags: crflags} {dst: operand}, #{imm: i16} => imm @ flags @ 0b0000 @ dst CMPR{flags: crflags} {dst: operand}, {a: operand} => 0x00 @ a @ flags @ 0b0001 @ dst BWNG{flags: crflags} {dst: operand}, {a: operand} => 0x01 @ a @ flags @ 0b0001 @ dst ARNG{flags: crflags} {dst: operand}, {a: operand} => 0x02 @ a @ flags @ 0b0001 @ dst @@ -44,9 +44,11 @@ CLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1000 @ dst ADDI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1001 @ dst SUBT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1010 @ dst - MULT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1011 @ dst - DIVI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1100 @ dst - MODU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1101 @ dst + MULL{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1011 @ dst + MULS{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1100 @ dst + MULU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1101 @ dst + DIVI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1110 @ dst + MODU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1111 @ dst } #bankdef mem diff --git a/src/main.rs b/src/main.rs index 1b7b000..3ce0515 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,14 @@ use winit::event::{StartCause, WindowEvent}; use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; use winit::window::{Window, WindowAttributes, WindowButtons, WindowId}; +const WIDTH: u32 = 64; +const HEIGHT: u32 = 64; +const BITS_PER_PIXEL: u32 = 4; +const PIXELS_PER_ADDRESS: u32 = 16 / BITS_PER_PIXEL; +const MEMORY_SLOTS: u32 = WIDTH * HEIGHT / PIXELS_PER_ADDRESS; +const BASE_ADDRESS: u32 = 0xFFFF - MEMORY_SLOTS; +const PIXEL_SCALE: u32 = 8; + pub struct App { vm: FootVM, @@ -42,24 +50,20 @@ impl App let pixels = &mut self.pixels.as_mut().unwrap(); let frame = pixels.frame_mut(); - for i in 0u16..32u16 + for ptr in 0..MEMORY_SLOTS { - for j in 0u16..32u16 + let mut value = self.vm[(ptr + BASE_ADDRESS) as u16]; + + for k in 0..PIXELS_PER_ADDRESS { - let index = i + j * 32; - let mut value = self.vm[index + 0xFBFF]; + let pixel_value = ((value & 0xF) * 17) as u8; + let pixel_index = ((ptr * PIXELS_PER_ADDRESS + k) * 4) as usize; + frame[pixel_index + 0] = pixel_value; + frame[pixel_index + 1] = pixel_value; + frame[pixel_index + 2] = pixel_value; + frame[pixel_index + 3] = 0xFF; - for k in 0..16 - { - let pixel_value = ((value & 1) * 255) as u8; - let pixel_index = (index as usize * 64) + k * 4; - frame[pixel_index + 0] = pixel_value; - frame[pixel_index + 1] = pixel_value; - frame[pixel_index + 2] = pixel_value; - frame[pixel_index + 3] = 0xFF; - - value >>= 1; - } + value >>= BITS_PER_PIXEL; } } @@ -84,21 +88,18 @@ impl ApplicationHandler for App fn resumed(&mut self, event_loop: &ActiveEventLoop) { - const WIDTH: u32 = 128; - const HEIGHT: u32 = 128; - let window = event_loop.create_window( WindowAttributes::default() .with_resizable(false) .with_enabled_buttons(WindowButtons::CLOSE | WindowButtons::MINIMIZE) - .with_inner_size(LogicalSize::new(WIDTH * 4, HEIGHT * 4)) + .with_inner_size(LogicalSize::new(WIDTH * PIXEL_SCALE, HEIGHT * PIXEL_SCALE)) .with_title("foot vm") ).unwrap(); let window = Arc::new(window); self.window = Some(window); - let surface_texture = SurfaceTexture::new(WIDTH * 4, HEIGHT * 4, self.window.as_ref().unwrap().clone()); + let surface_texture = SurfaceTexture::new(WIDTH * PIXEL_SCALE, HEIGHT * PIXEL_SCALE, self.window.as_ref().unwrap().clone()); self.pixels = Some(Pixels::new(WIDTH, HEIGHT, surface_texture).unwrap()); } diff --git a/src/vm.rs b/src/vm.rs index f61a79a..1395890 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -110,7 +110,9 @@ enum Instruction CLSH(ConditionalExecutionFlag, bool, Operand, Operand, Operand), ADDI(ConditionalExecutionFlag, bool, Operand, Operand, Operand), SUBT(ConditionalExecutionFlag, bool, Operand, Operand, Operand), - MULT(ConditionalExecutionFlag, bool, Operand, Operand, Operand), + MULL(ConditionalExecutionFlag, bool, Operand, Operand, Operand), + MULS(ConditionalExecutionFlag, bool, Operand, Operand, Operand), + MULU(ConditionalExecutionFlag, bool, Operand, Operand, Operand), DIVI(ConditionalExecutionFlag, bool, Operand, Operand, Operand), MODU(ConditionalExecutionFlag, bool, Operand, Operand, Operand) } @@ -144,7 +146,7 @@ impl TryFrom for Instruction { let a: Operand = (value & 0xFF).try_into()?; let b: Operand = ((value >> 8) & 0xFF).try_into()?; - match (value >> 24) & 0xF + match opcode { 2 => Ok(BWOR(ceflag, rflag, dst, b, a)), 3 => Ok(BAND(ceflag, rflag, dst, b, a)), @@ -155,9 +157,11 @@ impl TryFrom for Instruction 8 => Ok(CLSH(ceflag, rflag, dst, b, a)), 9 => Ok(ADDI(ceflag, rflag, dst, b, a)), 10 => Ok(SUBT(ceflag, rflag, dst, b, a)), - 11 => Ok(MULT(ceflag, rflag, dst, b, a)), - 12 => Ok(DIVI(ceflag, rflag, dst, b, a)), - 13 => Ok(MODU(ceflag, rflag, dst, b, a)), + 11 => Ok(MULL(ceflag, rflag, dst, b, a)), + 12 => Ok(MULS(ceflag, rflag, dst, b, a)), + 13 => Ok(MULU(ceflag, rflag, dst, b, a)), + 14 => Ok(DIVI(ceflag, rflag, dst, b, a)), + 15 => Ok(MODU(ceflag, rflag, dst, b, a)), _ => Err(()) } }, @@ -197,13 +201,17 @@ macro_rules! run_instruction { if $rep { - while $self.should_repeat() + let loop_count = $self.loop_count(); + for i in 0..loop_count { + *$self.mut_loop_count() = i; if $self.check($cef) { $self.$name($d, $a) } } + + *$self.mut_loop_count() = loop_count; } else if $self.check($cef) { @@ -214,13 +222,17 @@ macro_rules! run_instruction { if $rep { - while $self.should_repeat() + let loop_count = $self.loop_count(); + for i in 0..loop_count { + *$self.mut_loop_count() = i; if $self.check($cef) { $self.$name($d, $a, $b) } } + + *$self.mut_loop_count() = loop_count; } else if $self.check($cef) { @@ -294,7 +306,7 @@ impl FootVM { let first_word = self[self.program_counter()]; let second_word = self[self.program_counter() + 1]; - let full_instruction_bits = (second_word as u32) << 16 | first_word as u32; + let full_instruction_bits = u32::from(second_word) << 16 | u32::from(first_word); *self.mut_program_counter() = self.program_counter().wrapping_add(2); match full_instruction_bits.try_into() { @@ -326,8 +338,12 @@ impl FootVM run_instruction!(self, cef, rep, addi, dst, a, b), Ok(SUBT(cef, rep, dst, b, a)) => run_instruction!(self, cef, rep, subt, dst, a, b), - Ok(MULT(cef, rep, dst, b, a)) => - run_instruction!(self, cef, rep, mult, dst, a, b), + Ok(MULL(cef, rep, dst, b, a)) => + run_instruction!(self, cef, rep, mull, dst, a, b), + Ok(MULS(cef, rep, dst, b, a)) => + run_instruction!(self, cef, rep, muls, dst, a, b), + Ok(MULU(cef, rep, dst, b, a)) => + run_instruction!(self, cef, rep, mulu, dst, a, b), Ok(DIVI(cef, rep, dst, b, a)) => run_instruction!(self, cef, rep, divi, dst, a, b), Ok(MODU(cef, rep, dst, b, a)) => @@ -422,7 +438,7 @@ impl FootVM { let a = self.load_operand(src_a); let b = self.load_operand(src_b); - self.store_operand(dst, a.rotate_left(b as u32)); + self.store_operand(dst, a.rotate_left(u32::from(b))); } fn addi(&mut self, dst: Operand, src_a: Operand, src_b: Operand) @@ -439,11 +455,25 @@ impl FootVM self.store_operand(dst, a.wrapping_sub(b)); } - fn mult(&mut self, dst: Operand, src_a: Operand, src_b: Operand) + fn mull(&mut self, dst: Operand, src_a: Operand, src_b: Operand) { - let a = self.load_operand(src_a); - let b = self.load_operand(src_b); - self.store_operand(dst, a.wrapping_mul(b)); + let a = u32::from(self.load_operand(src_a)); + let b = u32::from(self.load_operand(src_b)); + self.store_operand(dst, (a * b) as u16); + } + + fn muls(&mut self, dst: Operand, src_a: Operand, src_b: Operand) + { + let a = i32::from(self.load_operand(src_a)); + let b = i32::from(self.load_operand(src_b)); + self.store_operand(dst, ((a * b) >> 16) as u16); + } + + fn mulu(&mut self, dst: Operand, src_a: Operand, src_b: Operand) + { + let a = u32::from(self.load_operand(src_a)); + let b = u32::from(self.load_operand(src_b)); + self.store_operand(dst,((a * b) >> 16) as u16); } fn divi(&mut self, dst: Operand, src_a: Operand, src_b: Operand) @@ -522,26 +552,12 @@ impl FootVM fn loop_count(&self) -> u16 { - self.registers[29] + self.registers[30] } fn mut_loop_count(&mut self) -> &mut u16 { - &mut self.registers[29] - } - - fn should_repeat(&mut self) -> bool - { - if self.loop_count() > 0 - { - *self.mut_loop_count() -= 1; - - true - } - else - { - false - } + &mut self.registers[30] } fn check(&self, cef: ConditionalExecutionFlag) -> bool