Initial commit

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-01-25 19:17:39 -05:00
commit ddfcec0427
20 changed files with 1561 additions and 0 deletions

5
src/common/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
pub mod span;
pub mod prelude {
pub use super::span::*;
}

67
src/common/span.rs Normal file
View File

@@ -0,0 +1,67 @@
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Pos {
pub source: usize,
pub line: usize,
pub col: usize,
pub byte: usize,
pub len: usize,
}
impl Pos {
pub fn new(source: usize, line: usize, col: usize, byte: usize, len: usize) -> Self {
Pos {
source,
line,
col,
byte,
len,
}
}
pub fn from_char(c: char, source: usize, line: usize, col: usize, byte: usize) -> Self {
Pos::new(source, line, col, byte, c.len_utf8())
}
pub fn adv_char(self, c: char) -> Self {
let mut next = self;
next.byte += next.len;
next.len = c.len_utf8();
next.source += 1;
next.col += 1;
next
}
pub fn adv_line(self) -> Self {
let mut next = self;
next.line += 1;
next
}
}
impl PartialOrd for Pos {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.source.partial_cmp(&other.source)
}
}
impl Ord for Pos {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
start: Pos,
end: Pos,
}
impl Span {
pub fn union(self, other: Span) -> Self {
let start = self.start.min(other.start);
let end = self.end.max(other.end);
Span { start, end, }
}
}

7
src/main.rs Normal file
View File

@@ -0,0 +1,7 @@
mod common;
//mod syn;
mod vm;
fn main() {
println!("Hello, world!");
}

2
src/syn/lexer.rs Normal file
View File

@@ -0,0 +1,2 @@
pub struct Lexer {
}

1
src/syn/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod lexer;

8
src/vm/flags.rs Normal file
View File

@@ -0,0 +1,8 @@
use bitflags::bitflags;
bitflags! {
pub struct Flags: u64 {
const HALT = 1;
const COMPARE = 1 << 1;
}
}

30
src/vm/inst.rs Normal file
View File

@@ -0,0 +1,30 @@
use crate::vm::reg::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Inst {
Add(Reg, Reg),
Mul(Reg, Reg),
Div(Reg, Reg),
Neg(Reg),
And(Reg, Reg),
Or(Reg, Reg),
Xor(Reg, Reg),
Shl(Reg, Reg),
Shr(Reg, Reg),
CmpEq(Reg, Reg),
CmpLt(Reg, Reg),
Jz(Reg),
Jnz(Reg),
Load(Reg, Reg),
Store(Reg, Reg),
StoreImm(Reg, u32),
Copy(Reg, Reg),
Nop,
Halt,
}
// https://crates.io/crates/packed_struct

5
src/vm/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
pub mod syn;
pub mod inst;
pub mod reg;
pub mod vm;
pub mod flags;

83
src/vm/reg.rs Normal file
View File

@@ -0,0 +1,83 @@
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Reg {
// https://crates.io/crates/packed_struct
// TODO : check this muffugin shit out!!
/// Instruction pointer
Ip = 0,
/// Stack pointer
Sp,
/// Frame pointer
Fp,
/// Flags
Flags,
Unused00,
Unused01,
Unused02,
Unused03,
Unused04,
Unused05,
Unused06,
Unused07,
Unused08,
/// General status code
Status,
R00,
R01,
R02,
R03,
R04,
R05,
R06,
R07,
R08,
R09,
R10,
R11,
R12,
R13,
R14,
R15,
R16,
R17,
R18,
R19,
R20,
R21,
R22,
R23,
R24,
R25,
R26,
R27,
R28,
R29,
R30,
R31,
R32,
R33,
R34,
R35,
R36,
R37,
R38,
R39,
R40,
R41,
R42,
R43,
R44,
R45,
R46,
R47,
R48,
R49,
}

46
src/vm/syn/ast.rs Normal file
View File

@@ -0,0 +1,46 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Line {
Section(Section),
Inst(Inst),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Section {
Code,
Data,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InstOp {
Add,
Mul,
Div,
Neg,
And,
Or,
Xor,
Shl,
Shr,
CmpEq,
CmpLt,
Jz,
Jnz,
Load,
Store,
StoreImm,
Copy,
Nop,
Halt,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Inst {
pub op: InstOp,
pub args: Vec<Value>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
Number(u64),
Label(String),
}

4
src/vm/syn/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
use lalrpop_util::lalrpop_mod;
lalrpop_mod!(pub parser, "/vm/syn/parser.rs");
pub mod ast;

73
src/vm/syn/parser.lalrpop Normal file
View File

@@ -0,0 +1,73 @@
use std::str::FromStr;
use crate::vm::{
syn::ast::*,
};
grammar;
// TODO : instkind
InstOp: InstOp = {
"add" => InstOp::Add,
"mul" => InstOp::Mul,
"div" => InstOp::Div,
"neg" => InstOp::Neg,
"and" => InstOp::And,
"or" => InstOp::Or,
"xor" => InstOp::Xor,
"shl" => InstOp::Shl,
"shr" => InstOp::Shr,
"cmpeq" => InstOp::CmpEq,
"cmplt" => InstOp::CmpLt,
"jz" => InstOp::Jz,
"jnz" => InstOp::Jnz,
"load" => InstOp::Load,
"store" => InstOp::Store,
"storeimm" => InstOp::StoreImm,
"copy" => InstOp::Copy,
"nop" => InstOp::Nop,
"halt" => InstOp::Halt,
}
LabelDef: String = {
<Label> ":" => <>
}
pub Label: String = {
"[a-zA-Z]+" => String::from(<>),
}
pub Section: Section = {
".code" => Section::Code,
".data" => Section::Data,
}
pub Inst: Inst = {
<op:InstOp> <head:Value> <tail:("," <Value>)+> => {
Inst {
op,
args: {
let mut tail = tail;
tail.insert(0, head);
tail
}
}
},
<op:InstOp> <head:Value?> => {
Inst { op, args: if let Some(head) = head { vec![head] } else { vec![] } }
}
}
pub Value: Value = {
<Number> => Value::Number(<>),
<Label> => Value::Label(<>),
}
pub Number: u64 = {
<s:r"[0-9]+"> => u64::from_str(s).unwrap()
}
pub Line: Line = {
<Section> => Line::Section(<>),
<Inst> => Line::Inst(<>),
}

19
src/vm/syn/pass.rs Normal file
View File

@@ -0,0 +1,19 @@
use crate::vm::syn::ast::*;
pub trait Pass<In> {
type Out;
fn pass(self, inval: In) -> Self::Out;
}
/// Confirms the instructions and their validity.
pub struct InstPass {
}
impl Pass<Vec<Line>> for InstPass {
type Out = Vec<Line>;
fn pass(self, inval: Vec<Line>) -> Self::Out {
inval
}
}

315
src/vm/vm.rs Normal file
View File

@@ -0,0 +1,315 @@
use crate::vm::{
reg::*,
inst::*,
flags::*,
};
use byteorder::{LE, ReadBytesExt, WriteBytesExt};
use std::{
mem,
io::Cursor,
};
pub type Word = u64;
pub type HalfWord = u32;
pub type Registers = [Word; 64];
pub struct Vm {
code: Vec<Inst>,
memory: Vec<u8>,
registers: Registers,
}
#[allow(dead_code)]
impl Vm {
pub fn new(code: Vec<Inst>, memory: Vec<u8>, registers: Registers) -> Self {
Vm { code, memory, registers }
}
pub fn run(&mut self) {
while !self.is_halted() {
self.tick();
}
}
pub fn tick(&mut self) {
let inst = self.decode();
let ip = self.ip();
self.set_reg(Reg::Ip, ip + 1);
self.execute(inst);
}
pub fn resume(&mut self) {
self.remove_flags(Flags::HALT);
}
pub fn is_halted(&self) -> bool {
self.flags().contains(Flags::HALT)
}
pub fn get_word(&self, addr: Word) -> Word {
let mut reader = Cursor::new(&self.memory[(addr as usize)..]);
reader.read_u64::<LE>()
.expect("word outside of address range")
}
pub fn get_halfword(&self, addr: Word) -> HalfWord {
let mut reader = Cursor::new(&self.memory[(addr as usize)..]);
reader.read_u32::<LE>()
.expect("word outside of address range")
}
pub fn get_byte(&self, addr: Word) -> u8 {
let mut reader = Cursor::new(&self.memory[(addr as usize)..]);
reader.read_u8()
.expect("word outside of address range")
}
pub fn set_word(&mut self, addr: Word, value: Word) {
let mut writer = Cursor::new(&mut self.memory[(addr as usize)..]);
writer.write_u64::<LE>(value)
.expect("word outside of address range");
}
pub fn set_halfword(&mut self, addr: Word, value: HalfWord) {
let mut writer = Cursor::new(&mut self.memory[(addr as usize)..]);
writer.write_u32::<LE>(value)
.expect("word outside of address range");
}
pub fn set_byte(&mut self, addr: Word, value: u8) {
let mut writer = Cursor::new(&mut self.memory[(addr as usize)..]);
writer.write_u8(value)
.expect("word outside of address range");
}
pub fn load(&self, reg: Reg) -> Word {
self.get_word(self.get_reg(reg))
}
pub fn store(&mut self, reg: Reg, value: Word) {
let addr = self.get_reg(reg);
self.set_word(addr, value);
}
pub fn get_reg(&self, reg: Reg) -> Word {
self.registers[reg as usize]
}
pub fn set_reg(&mut self, reg: Reg, value: Word) -> Word {
mem::replace(&mut self.registers[reg as usize], value)
}
pub fn ip(&self) -> Word {
self.get_reg(Reg::Ip)
}
pub fn flags(&self) -> Flags {
// this is safe because it's OK if there are random bits flipped - this shouldn't happen
// anyway, but if it does, they're ignored
unsafe { Flags::from_bits_unchecked(self.get_reg(Reg::Flags)) }
}
pub fn insert_flags(&mut self, flags: Flags) {
let mut new_flags = self.flags();
new_flags.insert(flags);
self.set_flags(new_flags);
}
pub fn remove_flags(&mut self, flags: Flags) {
let mut new_flags = self.flags();
new_flags.remove(flags);
self.set_flags(new_flags);
}
pub fn set_flags(&mut self, flags: Flags) {
self.set_reg(Reg::Flags, flags.bits());
}
pub fn map_flags<F>(&mut self, mapping: F)
where F: FnOnce(Flags) -> Flags
{
let in_flags = self.flags();
self.set_flags((mapping)(in_flags));
}
pub fn decode(&self) -> Inst {
self.code[self.ip() as usize]
}
pub fn execute(&mut self, inst: Inst) {
macro_rules! map {
($r0:ident = $($tail:tt)*) => {{
let w0 = map!($($tail)+);
self.set_reg($r0, w0);
}};
($r1:ident $sym:tt $r2:ident) => {{
let w1 = self.get_reg($r1);
let w2 = self.get_reg($r2);
(w1 $sym w2)
}}
}
match inst {
Inst::Add(r1, r2) => {
let w1 = self.get_reg(r1);
let w2 = self.get_reg(r2);
let value = w1.wrapping_add(w2);
self.set_reg(r1, value);
}
Inst::Mul(r1, r2) => {
let w1 = self.get_reg(r1);
let w2 = self.get_reg(r2);
let value = w1.wrapping_mul(w2);
self.set_reg(r1, value);
}
Inst::Div(r1, r2) => map!(r1 = r1 / r2),
Inst::Neg(r1) => {
let value = self.get_reg(r1);
let ivalue = -i64::from_ne_bytes(value.to_ne_bytes());
let uvalue = u64::from_ne_bytes(ivalue.to_ne_bytes());
self.set_reg(r1, uvalue);
}
Inst::And(r1, r2) => map!(r1 = r1 & r2),
Inst::Or(r1, r2) => map!(r1 = r1 | r2),
Inst::Xor(r1, r2) => map!(r1 = r1 ^ r2),
Inst::Shl(r1, r2) => map!(r1 = r1 << r2),
Inst::Shr(r1, r2) => map!(r1 = r1 >> r2),
Inst::CmpEq(r1, r2) => {
if map!(r1 == r2) {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
}
Inst::CmpLt(r1, r2) => {
if map!(r1 < r2) {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
}
Inst::Jz(r1) => {
if !self.flags().contains(Flags::COMPARE) {
let w1 = self.get_reg(r1);
self.set_reg(Reg::Ip, w1);
}
}
Inst::Jnz(r1) => {
if self.flags().contains(Flags::COMPARE) {
let w1 = self.get_reg(r1);
self.set_reg(Reg::Ip, w1);
}
}
Inst::Load(r1, r2) => {
let value = self.load(r2);
self.set_reg(r1, value);
}
Inst::Store(r1, r2) => {
let value = self.get_reg(r1);
self.store(r2, value);
}
Inst::StoreImm(r1, value) => {
self.set_reg(r1, value as u64);
}
Inst::Copy(r1, r2) => {
let w1 = self.load(r2);
self.store(r1, w1);
}
Inst::Nop => {}
Inst::Halt => {
self.insert_flags(Flags::HALT);
}
}
}
fn with_registers<F, B>(&self, r1: Reg, r2: Reg, map_fn: F) -> B
where F: FnOnce(Word, Word) -> B
{
let w1 = self.get_reg(r1);
let w2 = self.get_reg(r2);
(map_fn)(w1, w2)
}
}
#[cfg(test)]
mod test {
use super::*;
macro_rules! itou {
{ $expr:expr } => { u64::from_ne_bytes(($expr).to_ne_bytes()) };
}
#[test]
fn test_arithmetic() {
use Inst::*;
use Reg::*;
let code = vec![
StoreImm(R01, 25),
Add(R00, R01),
Halt,
Mul(R00, R01),
Halt,
Div(R00, R01),
Halt,
StoreImm(R01, 15),
And(R00, R01),
Halt, // should be 9
// Storing large numbers
StoreImm(R00, 0xABCD_EF98),
StoreImm(R01, 32),
Shl(R00, R01),
Or(R00, R01),
Halt,
Shr(R00, R01),
Halt,
Xor(R00, R00),
Halt,
];
let mut vm = Vm::new(code, Default::default(), [0; 64]);
vm.run();
assert_eq!(vm.get_reg(R00), 25);
assert_eq!(vm.get_reg(R01), 25);
vm.resume();
vm.run();
assert_eq!(vm.get_reg(R00), 625);
assert_eq!(vm.get_reg(R01), 25);
vm.resume();
vm.run();
assert_eq!(vm.get_reg(R00), 25);
assert_eq!(vm.get_reg(R01), 25);
vm.resume();
vm.run();
assert_eq!(vm.get_reg(R00), 9);
assert_eq!(vm.get_reg(R01), 15);
vm.resume();
vm.run();
assert_eq!(vm.get_reg(R00), 0xABCD_EF98_0000_0020);
assert_eq!(vm.get_reg(R01), 32);
vm.resume();
// TODO : signed instructions
vm.run();
assert_eq!(vm.get_reg(R00), 0xABCD_EF98);
vm.resume();
vm.run();
assert_eq!(vm.get_reg(R00), 0);
vm.resume();
}
}