Successfully set up virtual machines to run in real time
This commit is contained in:
parent
314eaa024c
commit
6e0b775a86
@ -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
|
||||
|
@ -1,2 +1,3 @@
|
||||
pub mod time;
|
||||
pub mod log;
|
||||
pub mod log;
|
||||
pub mod vcr;
|
12
src/log.rs
12
src/log.rs
@ -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);
|
||||
}
|
||||
}
|
202
src/vcr.rs
202
src/vcr.rs
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user