From 22cc821697b417e7fb2c7cc1b7d01aa348432c0a Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 2 May 2020 19:49:31 +0200 Subject: [PATCH] Fix add instruction - Add debug instruction --- README.md | 8 ++-- src/bin/lsambler.rs | 11 ++++-- src/bin/lsvm.rs | 16 +++++++- src/runtime.rs | 94 ++++++++++++++++++++------------------------- src/tokens.rs | 35 ++++++++++++++++- 5 files changed, 102 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 7aedf87..95ff4f9 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ A virtual machine for controlling a wifi led strip. | write (rgd, rgp) | writes the value in the data register to the address of the pointer register | 0x06 | | label (rgl) | creates a label with rgd as the name | 0x07 | | goto (rgl) | goes to the label with name rgd | 0x08 | +| debug (*) | prints out the state for debug information | 0x09 | | add (rgd, rgi, rgo) | adds the value of rgi to the value of rgd and writes the result into rgo | 0x10 | | sub (rgd, rgi, rgo) | substracts rgi from rgd and writes the result into rgo | 0x11 | | mul (rgd, rgi, rgo) | multiplies rgd by rgi and writes the result to rgo | 0x12 | @@ -27,8 +28,8 @@ A virtual machine for controlling a wifi led strip. | jl (rgd, rgi, rgl) | jumps to rgl if rgd < rgi | 0x21 | | je (rgd, rgi, rgl) | jumps to rgl if rgd == rgi | 0x22 | | pause (rgd) | pauses for rgd milliseconds | 0xF0 | -| cmd (rgd) | executes the command in rgd | 0xF1 | -| send (rcr, rcg, rcb) | sends the values stored in the color registers to the strip | 0xF2 +| cmd (rgd) | executes the command in rgd | 0xF1 | +| send (rcr, rcg, rcb)| sends the values stored in the color registers to the strip | 0xF2 | ### Registers @@ -50,4 +51,5 @@ A virtual machine for controlling a wifi led strip. - the rgp register stores a pointer to "memory" space - the rgi register stores the input for operations that require two input values - the rgo register stores the result of operations -- the rgl register stores as label name that can be jumped to \ No newline at end of file +- the rgl register stores as label name that can be jumped to +- comments start with # \ No newline at end of file diff --git a/src/bin/lsambler.rs b/src/bin/lsambler.rs index d403993..327e5ca 100644 --- a/src/bin/lsambler.rs +++ b/src/bin/lsambler.rs @@ -1,8 +1,8 @@ use ledstrip_vm::registers::get_register_code_by_name; use ledstrip_vm::tokens::{ - AddToken, ClearToken, CmdToken, CopyToken, DivToken, ExitToken, GotoToken, JeToken, JgToken, - JlToken, LabelToken, LoadToken, LshToken, ModToken, MulToken, PauseToken, RshToken, SendToken, - SetToken, SubToken, Token, WriteToken, + AddToken, ClearToken, CmdToken, CopyToken, DebugToken, DivToken, ExitToken, GotoToken, JeToken, + JgToken, JlToken, LabelToken, LoadToken, LshToken, ModToken, MulToken, PauseToken, RshToken, + SendToken, SetToken, SubToken, Token, WriteToken, }; use std::fs::{read_to_string, File}; use std::io; @@ -38,12 +38,14 @@ fn main() -> io::Result<()> { line_number += 1; if let Some(token) = get_token(line) { Some(token.to_bytecode()) - } else { + } else if line.replace("\\s", "").len() > 0 && !line.starts_with("#") { println!( "Failed to parse instruction '{}' \n-> {}:{}", line, &input_file_name, line_number ); None + } else { + None } }) .for_each(|code| { @@ -80,6 +82,7 @@ fn get_token(line: &str) -> Option> { "write" => some_box!(WriteToken), "label" => some_box!(LabelToken), "goto" => some_box!(GotoToken), + "debug" => some_box!(DebugToken), "add" => some_box!(AddToken), "sub" => some_box!(SubToken), "mul" => some_box!(MulToken), diff --git a/src/bin/lsvm.rs b/src/bin/lsvm.rs index 0b3c716..85f0a51 100644 --- a/src/bin/lsvm.rs +++ b/src/bin/lsvm.rs @@ -1,6 +1,7 @@ use ledstrip_vm::runtime::Runtime; use std::fs::read; use std::io; +use std::time::Instant; use structopt::StructOpt; #[derive(StructOpt, Debug)] @@ -20,11 +21,22 @@ fn main() -> io::Result<()> { let bytecode = read(opts.input_file)?; let mut runtime = Runtime::new(&opts.ip, opts.port); + let start = Instant::now(); runtime.parse_bytecode(bytecode); + println!("Parsing took {:?}\n", start.elapsed()); + let start = Instant::now(); match runtime.run() { - Ok(code) => println!("Runtime exited with code {}", code), - Err(e) => println!("Runtime exited with error {:?}", e), + Ok(code) => println!( + "Runtime exited with code {} after {:?}", + code, + start.elapsed() + ), + Err(e) => println!( + "Runtime exited with error {:?} after {:?}", + e, + start.elapsed() + ), } Ok(()) diff --git a/src/runtime.rs b/src/runtime.rs index 6de30f4..ac8f089 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -3,11 +3,11 @@ use crate::registers::{ Rcb, Rcg, Rcr, Rcs, Register, Rgd, Rgi, Rgl, Rgo, Rgp, RCB, RCG, RCR, RGD, RGI, RGL, RGO, RGP, }; use crate::tokens::{ - AddToken, ClearToken, CmdToken, CopyToken, DivToken, ExitToken, FromBytecode, GotoToken, - JeToken, JgToken, JlToken, LabelToken, LoadToken, LshToken, ModToken, MulToken, PauseToken, - RshToken, SendToken, SetToken, SubToken, Token, WriteToken, T_ADD, T_CLEAR, T_CMD, T_COPY, - T_DIV, T_EXIT, T_GOTO, T_JE, T_JG, T_JL, T_LABEL, T_LOAD, T_LSH, T_MOD, T_MUL, T_PAUSE, T_RSH, - T_SEND, T_SET, T_SUB, T_WRITE, + AddToken, ClearToken, CmdToken, CopyToken, DebugToken, DivToken, ExitToken, FromBytecode, + GotoToken, JeToken, JgToken, JlToken, LabelToken, LoadToken, LshToken, ModToken, MulToken, + PauseToken, RshToken, SendToken, SetToken, SubToken, Token, WriteToken, T_ADD, T_CLEAR, T_CMD, + T_COPY, T_DEBUG, T_DIV, T_EXIT, T_GOTO, T_JE, T_JG, T_JL, T_LABEL, T_LOAD, T_LSH, T_MOD, T_MUL, + T_PAUSE, T_RSH, T_SEND, T_SET, T_SUB, T_WRITE, }; use std::cell::RefCell; use std::collections::HashMap; @@ -62,56 +62,46 @@ impl Runtime { /// that can be executed pub fn parse_bytecode(&mut self, bytecode: Vec) { let mut code_iter = bytecode.iter(); + let mut text = self.text.borrow_mut(); while let Some(instruction) = code_iter.next() { match *instruction { - T_EXIT => self - .text - .borrow_mut() - .push(Box::new(ExitToken::from_bytecode(&[ - instruction, - code_iter.next().unwrap(), - ]))), - T_SET => self - .text - .borrow_mut() - .push(Box::new(SetToken::from_bytecode(&[ - instruction, - code_iter.next().unwrap(), - code_iter.next().unwrap(), - ]))), - T_COPY => self - .text - .borrow_mut() - .push(Box::new(CopyToken::from_bytecode(&[ - instruction, - code_iter.next().unwrap(), - code_iter.next().unwrap(), - ]))), - T_LOAD => self.text.borrow_mut().push(Box::new(LoadToken)), - T_CLEAR => self - .text - .borrow_mut() - .push(Box::new(ClearToken::from_bytecode(&[ - instruction, - code_iter.next().unwrap(), - ]))), - T_WRITE => self.text.borrow_mut().push(Box::new(WriteToken)), - T_LABEL => self.text.borrow_mut().push(Box::new(LabelToken)), - T_GOTO => self.text.borrow_mut().push(Box::new(GotoToken)), - T_ADD => self.text.borrow_mut().push(Box::new(AddToken)), - T_SUB => self.text.borrow_mut().push(Box::new(SubToken)), - T_MUL => self.text.borrow_mut().push(Box::new(MulToken)), - T_DIV => self.text.borrow_mut().push(Box::new(DivToken)), - T_MOD => self.text.borrow_mut().push(Box::new(ModToken)), - T_LSH => self.text.borrow_mut().push(Box::new(LshToken)), - T_RSH => self.text.borrow_mut().push(Box::new(RshToken)), - T_JG => self.text.borrow_mut().push(Box::new(JgToken)), - T_JL => self.text.borrow_mut().push(Box::new(JlToken)), - T_JE => self.text.borrow_mut().push(Box::new(JeToken)), - T_PAUSE => self.text.borrow_mut().push(Box::new(PauseToken)), - T_CMD => self.text.borrow_mut().push(Box::new(CmdToken)), - T_SEND => self.text.borrow_mut().push(Box::new(SendToken)), + T_EXIT => text.push(Box::new(ExitToken::from_bytecode(&[ + instruction, + code_iter.next().unwrap(), + ]))), + T_SET => text.push(Box::new(SetToken::from_bytecode(&[ + instruction, + code_iter.next().unwrap(), + code_iter.next().unwrap(), + ]))), + T_COPY => text.push(Box::new(CopyToken::from_bytecode(&[ + instruction, + code_iter.next().unwrap(), + code_iter.next().unwrap(), + ]))), + T_LOAD => text.push(Box::new(LoadToken)), + T_CLEAR => text.push(Box::new(ClearToken::from_bytecode(&[ + instruction, + code_iter.next().unwrap(), + ]))), + T_WRITE => text.push(Box::new(WriteToken)), + T_LABEL => text.push(Box::new(LabelToken)), + T_GOTO => text.push(Box::new(GotoToken)), + T_DEBUG => text.push(Box::new(DebugToken)), + T_ADD => text.push(Box::new(AddToken)), + T_SUB => text.push(Box::new(SubToken)), + T_MUL => text.push(Box::new(MulToken)), + T_DIV => text.push(Box::new(DivToken)), + T_MOD => text.push(Box::new(ModToken)), + T_LSH => text.push(Box::new(LshToken)), + T_RSH => text.push(Box::new(RshToken)), + T_JG => text.push(Box::new(JgToken)), + T_JL => text.push(Box::new(JlToken)), + T_JE => text.push(Box::new(JeToken)), + T_PAUSE => text.push(Box::new(PauseToken)), + T_CMD => text.push(Box::new(CmdToken)), + T_SEND => text.push(Box::new(SendToken)), _ => panic!("unknown instruction {}", instruction), }; } diff --git a/src/tokens.rs b/src/tokens.rs index ec29dfc..02f9339 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -13,6 +13,7 @@ pub const T_CLEAR: u8 = 0x05; pub const T_WRITE: u8 = 0x06; pub const T_LABEL: u8 = 0x07; pub const T_GOTO: u8 = 0x08; +pub const T_DEBUG: u8 = 0x09; pub const T_ADD: u8 = 0x10; pub const T_SUB: u8 = 0x11; pub const T_MUL: u8 = 0x12; @@ -137,13 +138,18 @@ impl Token for CopyToken { value = rg.get(); } else if self.register_1 == RCS { value = runtime.rcs.get() as u32; + } else { + panic!("unknown register {}", self.register_1); } + if let Some(mut rg) = runtime.get_1byte_register(self.register_2) { rg.set(value as u8); } else if let Some(mut rg) = runtime.get_4byte_register(self.register_2) { rg.set(value); } else if self.register_2 == RCS { runtime.rcs.set(value == 0); + } else { + panic!("unknown register {}", self.register_2); } Ok(()) @@ -269,6 +275,33 @@ impl Token for GotoToken { } } +#[derive(Debug, Clone)] +pub struct DebugToken; + +impl Token for DebugToken { + fn to_bytecode(&self) -> Vec { + vec![T_DEBUG] + } + + fn invoke(&self, runtime: &mut Runtime) -> io::Result<()> { + println!("--- Registers --"); + println!("rcs: {}", runtime.rcs.get()); + println!("rcr: {}", runtime.rcr.get()); + println!("rcg: {}", runtime.rcg.get()); + println!("rcb: {}", runtime.rcb.get()); + println!("rgd: {}", runtime.rgd.get()); + println!("rgp: {}", runtime.rgp.get()); + println!("rgi: {}", runtime.rgi.get()); + println!("rgo: {}", runtime.rgo.get()); + println!("rgl: {}", runtime.rgl.get()); + println!("\n--- Runtime ---"); + println!("Memory: {:?}", runtime.memory); + println!(); + + Ok(()) + } +} + impl FromBytecode for GotoToken { fn from_bytecode(_: &[&u8]) -> Self { Self @@ -284,7 +317,7 @@ impl Token for AddToken { } fn invoke(&self, runtime: &mut Runtime) -> io::Result<()> { - runtime.rgo.set(runtime.rgo.get() + runtime.rgi.get()); + runtime.rgo.set(runtime.rgd.get() + runtime.rgi.get()); Ok(()) }