Successfully set up virtual machines to run in real time

This commit is contained in:
Skye Terran 2021-12-28 15:15:50 -08:00
parent 314eaa024c
commit 6e0b775a86
4 changed files with 228 additions and 10 deletions

View File

@ -1,9 +1,16 @@
use std::env;
use slipwave::time::{State, Loop};
use slipwave::log::{Logger};
use slipwave::vcr::{ComputeObject};
fn main() {
println!("Slipwave Engine | 2021 | Skye Terran");
// Create a logger
let log_time = Logger::new("time");
// create a sim loop
log_time.print("Creating sim loop...");
let mut sim = Loop::new();
// set the loop update interval
@ -15,18 +22,24 @@ fn main() {
// datastream
let mut x: i32 = 0;
// Create a compute object
let args: Vec<String> = env::args().collect();
let file_path: &String = &args[1];
// execute the sim loop
log_time.print("Executing loop...");
loop {
// step the sim forward
sim.step();
// update logic goes here
if sim.is_awake() {
//x += 1;
//println!("x: {}", x);
// Create and execute a compute object
let mut vm = ComputeObject::from_file(file_path);
println!("{:?}", vm.execute());
}
sim.get_state().debug_time();
//sim.get_state().debug_time();
// display logic goes here
// problem: the timestep is not what we want here. we need to get the elapsed time

View File

@ -1,2 +1,3 @@
pub mod time;
pub mod log;
pub mod log;
pub mod vcr;

View File

@ -1,11 +1,13 @@
pub struct Logger {
categories: Vec<String>
name: String
}
impl Logger {
pub fn print(self, output: &String, category: &String) {
if self.categories.contains(category) {
println!(output);
}
pub fn new(name: &str) -> Logger {
Logger { name: name.to_string() }
}
pub fn print(&self, output: &str) {
println!("[{}] {}", self.name, output);
}
}

View File

@ -0,0 +1,202 @@
use std::io;
use std::fs;
use std::fs::File;
use std::io::Read;
enum VCROperationKind {
Generic,
Type,
Value
}
pub struct ComputeObject {
instructions: Vec<u8>,
values: Vec<f32>
}
impl ComputeObject {
pub fn from_file(file_path: &String) -> ComputeObject {
ComputeObject {
instructions: get_file_as_byte_vec(file_path),
values: vec![]
}
}
pub fn execute(&mut self) -> &Vec<f32> {
//println!("Executing bytecode instructions...\n");
let mut iter = self.instructions.iter();
// Handle literals
let mut op_type = VCROperationKind::Generic;
let mut literal = [0u8; 4];
let mut lit_digit = 0;
// Handle each opcode in order
loop {
let byte_opt = iter.next();
// Contextually handle opcodes depending on their type
match op_type {
// Treat the opcode as a literal type declaration
VCROperationKind::Type => {
// Consume the literal type
let byte = byte_opt.unwrap();
// The following opcodes are expected to be a literal value
op_type = VCROperationKind::Value;
},
// Treat the opcode as a literal value
VCROperationKind::Value => {
if byte_opt.is_some() {
let byte = byte_opt.unwrap();
// Record another of the literal's bytes
literal[lit_digit] = *byte;
// Continue consuming the literal
if lit_digit >= 3 {
let num = f32::from_bits(as_u32_be(&literal));
self.values.push(num);
//println!("LIT {:?}", num);
//println!("Values: {:?}\n", self.values);
op_type = VCROperationKind::Generic;
lit_digit = 0;
} else {
lit_digit += 1;
}
} else {
break;
}
},
// Treat the opcode as a generic command
_ => {
if byte_opt.is_some() {
let byte = byte_opt.unwrap();
match byte {
0x01 => op_type = VCROperationKind::Type,
0x02 => swap(&mut self.values),
0x03 => del(&mut self.values),
0x04 => copy(&mut self.values),
0x10 => add(&mut self.values),
0x11 => sub(&mut self.values),
0x12 => mul(&mut self.values),
0x19 => floor(&mut self.values),
_ => break
}
// DEBUG - show the value stack upon every generic command
if let VCROperationKind::Generic = op_type {
//println!("Values: {:?}\n", self.values);
}
} else {
break;
}
}
}
}
self.instructions.clear();
&self.values
}
}
fn add(values: &mut Vec<f32>) {
//println!("ADD");
let b_opt = values.pop();
let a_opt = values.pop();
if a_opt.is_some() && b_opt.is_some() {
let a = a_opt.unwrap();
let b = b_opt.unwrap();
values.push(a + b);
} else {
//println!("Not enough values.");
}
}
fn sub(values: &mut Vec<f32>) {
//println!("SUB");
let b_opt = values.pop();
let a_opt = values.pop();
if a_opt.is_some() && b_opt.is_some() {
let a = a_opt.unwrap();
let b = b_opt.unwrap();
values.push(a - b);
} else {
//println!("Not enough values.");
}
}
fn mul(values: &mut Vec<f32>) {
//println!("MUL");
let b_opt = values.pop();
let a_opt = values.pop();
if a_opt.is_some() && b_opt.is_some() {
let a = a_opt.unwrap();
let b = b_opt.unwrap();
values.push(a * b);
} else {
//println!("Not enough values.");
}
}
fn del(values: &mut Vec<f32>) {
//println!("DEL");
values.pop();
}
fn copy(values: &mut Vec<f32>) {
//println!("COPY");
let a_opt = values.pop();
if a_opt.is_some() {
let a = a_opt.unwrap();
values.push(a);
values.push(a);
} else {
//println!("Not enough values.");
}
}
fn swap(values: &mut Vec<f32>) {
//println!("SWAP");
let b_opt = values.pop();
let a_opt = values.pop();
if a_opt.is_some() && b_opt.is_some() {
let a = a_opt.unwrap();
let b = b_opt.unwrap();
values.push(b);
values.push(a);
} else {
//println!("Not enough values.");
}
}
fn floor(values: &mut Vec<f32>) {
//println!("FLOOR");
let a_opt = values.pop();
if a_opt.is_some() {
let a = a_opt.unwrap();
let a = a.floor();
values.push(a);
}
}
fn as_u32_be(array: &[u8; 4]) -> u32 {
((array[0] as u32) << 24) +
((array[1] as u32) << 16) +
((array[2] as u32) << 8) +
((array[3] as u32) << 0)
}
fn as_u32_le(array: &[u8; 4]) -> u32 {
((array[0] as u32) << 0) +
((array[1] as u32) << 8) +
((array[2] as u32) << 16) +
((array[3] as u32) << 24)
}
fn get_file_as_byte_vec(filename: &String) -> Vec<u8> {
let mut f = File::open(&filename).expect("no file found");
let metadata = fs::metadata(&filename).expect("unable to read metadata");
let mut buffer = vec![0; metadata.len() as usize];
f.read(&mut buffer).expect("buffer overflow");
buffer
}