preparations for module data storage, remove broken tests (dyn trait can't implement PartialEq because ???)

pull/21/head
Ondřej Hruška 4 years ago
parent 44e7cd3a8f
commit ba0e3d0fd2
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      crsn/src/asm/instr/mod.rs
  2. 17
      crsn/src/asm/instr/op.rs
  3. 323
      crsn/src/asm/mod.rs
  4. 11
      crsn/src/asm/parse/parse_op.rs
  5. 3
      crsn/src/runtime/fault.rs
  6. 8
      crsn/src/runtime/program.rs
  7. 21
      crsn/src/runtime/run_thread.rs
  8. 8
      crsn_arith/src/parse.rs

@ -11,7 +11,7 @@ pub mod cond;
mod flatten; mod flatten;
/// A higher-level instruction /// A higher-level instruction
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct Instr { pub struct Instr {
pub op: OpWrapper, pub op: OpWrapper,
pub branches: Option<Vec<(Cond, Vec<Instr>)>>, pub branches: Option<Vec<(Cond, Vec<Instr>)>>,

@ -1,8 +1,5 @@
use std::fmt::Debug; use std::fmt::Debug;
use dyn_clonable::*;
use sexp::Sexp;
use crate::asm::data::{ use crate::asm::data::{
literal::DebugMsg, literal::Label, literal::DebugMsg, literal::Label,
literal::RoutineName, literal::RoutineName,
@ -11,13 +8,13 @@ use crate::asm::data::{
}; };
use crate::asm::error::Error; use crate::asm::error::Error;
use crate::asm::instr::Cond; use crate::asm::instr::Cond;
use crate::asm::parse::arg_parser::ArgParser;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::frame::{CallStack, StackFrame}; use crate::runtime::frame::{CallStack, StackFrame};
use crate::runtime::program::Program; use crate::runtime::program::Program;
use crate::asm::parse::arg_parser::ArgParser;
/// A higher level simple opration /// A higher level simple opration
#[derive(Clone, Debug)] #[derive(Debug)]
pub enum OpWrapper { pub enum OpWrapper {
/// Mark a jump target. /// Mark a jump target.
Label(Label), Label(Label),
@ -30,7 +27,7 @@ pub enum OpWrapper {
} }
/// A low level instruction /// A low level instruction
#[derive(Clone, Debug)] #[derive(Debug)]
pub enum Op { pub enum Op {
/// Do nothing /// Do nothing
Nop, Nop,
@ -72,18 +69,16 @@ impl From<Op> for OpWrapper {
} }
} }
#[clonable] pub trait OpTrait: Debug + Send + Sync + 'static {
pub trait OpTrait: Clone + Debug + Send + 'static {
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault>; fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<(), Fault>;
} }
pub enum ParseOpResult { pub enum ParseOpResult {
Parsed(Box<dyn OpTrait>), Parsed(Box<dyn OpTrait + Send>),
Unknown(ArgParser), Unknown(ArgParser),
} }
#[clonable] pub trait AsmModule: Debug + Send + 'static {
pub trait AsmModule: Clone + Debug + Send + 'static {
/// Get name of the module /// Get name of the module
fn name(&self) -> &'static str; fn name(&self) -> &'static str;

@ -12,326 +12,3 @@ pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Op>,
let parsed = parse::parse(source, parsers)?; let parsed = parse::parse(source, parsers)?;
Ok(lower(parsed)?) Ok(lower(parsed)?)
} }
#[cfg(test)]
mod tests {
use std::sync::atomic::AtomicU32;
use crate::asm::data::{DstDisp, Rd, Register, SrcDisp, Wr};
use crate::asm::data::literal::{Addr, Label};
use crate::asm::instr::{Flatten, OpWrapper, Instr, lower, Op};
use crate::asm::instr::Cond;
use crate::asm::parse::{parse, parse_instructions};
#[test]
fn test_parse_empty() {
let parsed = parse("
()
").unwrap();
assert_eq!(Vec::<OpWrapper>::new(), parsed);
}
#[test]
fn test_parse_empty_routine() {
let parsed = parse("
(
(hello)
)
").unwrap();
assert_eq!(vec![
OpWrapper::Op(Op::Routine("hello".into())),
OpWrapper::Op(Op::Barrier(Some("Routine \"hello\" overrun".into())))
], parsed);
let parsed = parse("
(
(hello)
(world)
)
").unwrap();
assert_eq!(vec![
OpWrapper::Op(Op::Routine("hello".into())),
OpWrapper::Op(Op::Barrier(Some("Routine \"hello\" overrun".into()))),
OpWrapper::Op(Op::Routine("world".into())),
OpWrapper::Op(Op::Barrier(Some("Routine \"world\" overrun".into())))
], parsed);
}
#[test]
fn test_parse_data_formats() {
let parsed = parse("
(
(move
(mov r0 r1)
(mov r15 7)
(mov r15 0xabcd)
(mov r7 0b11110000)
(mov r7 arg1)
(mov r255 arg255)
(mov r7 res0)
(mov r7 res255)
(mov @r0 @r0) ; test in both Rd and Wr positions
(mov @r0 @arg0)
(mov @r0 @res0)
(mov @123456 @0x123456)
(mov @0b010101 @0b010101)
)
)
").unwrap();
assert_eq!(vec![
OpWrapper::Op(Op::Routine("move".into())),
// (mov r0 r1)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
// (mov r15 7)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(7)),
)),
// (mov r15 0xabcd)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(15))),
Rd::new(SrcDisp::Immediate(0xabcd)),
)),
// (mov r7 0b11110000)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Immediate(0b11110000)),
)),
// (mov r7 arg1)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Arg(1))),
)),
// (mov r255 arg255)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(255))),
Rd::new(SrcDisp::Register(Register::Arg(255))),
)),
// (mov r7 res0)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(0))),
)),
// (mov r7 res255)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(7))),
Rd::new(SrcDisp::Register(Register::Res(255))),
)),
// (mov @r0 @r0)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Gen(0))),
)),
// (mov @r0 @arg0)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Arg(0))),
)),
// (mov @r0 @res0)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::RegisterPtr(Register::Gen(0))),
Rd::new(SrcDisp::RegisterPtr(Register::Res(0))),
)),
// (mov @123456 @0x123456)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(123456))),
Rd::new(SrcDisp::ImmediatePtr(Addr(0x123456))),
)),
// (mov @0b010101 @0b010101)
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::ImmediatePtr(Addr(0b010101))),
Rd::new(SrcDisp::ImmediatePtr(Addr(0b010101))),
)),
OpWrapper::Op(Op::Barrier(Some("Routine \"move\" overrun".into()))),
], parsed);
}
fn parse_single_instr(src: &str) -> anyhow::Result<Instr> {
Ok(parse_instructions(vec![sexp::parse(src)?])?.remove(0))
}
fn parse_single_op(src: &str) -> anyhow::Result<Vec<OpWrapper>> {
let num = AtomicU32::new(0);
Ok(parse_single_instr(src)?.flatten(&num)?)
}
#[test]
fn test_parse_single() {
let parsed = parse_single_op("(mov r0 r1)").unwrap();
assert_eq!(vec![
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
], parsed);
}
#[test]
fn test_branches_instr() {
let parsed = parse_single_instr("
(cmp r0 r1 (eq? (mov r0 r0) (mov r1 r2)) (>? (mov r0 r0) (mov r1 r1)))
").unwrap();
assert_eq!(
Instr {
op: OpWrapper::Op(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
branches: Some(vec![
(
Cond::Equal,
vec![
Instr {
op: OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
branches: None,
},
Instr {
op: OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))),
)),
branches: None,
}
]
),
(
Cond::Greater,
vec![
Instr {
op: OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
branches: None,
},
Instr {
op: OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
branches: None,
}
]
)
]),
}
, parsed);
}
#[test]
fn test_branches_op() {
let parsed = parse_single_op("
(cmp r0 r1
(eq?
(mov r0 r0)
(mov r1 r2))
(>?
(mov r0 r0)
(mov r1 r1)))
").unwrap();
assert_eq!(
vec![
OpWrapper::Op(Op::Cmp(
Rd::new(SrcDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
OpWrapper::JumpIf(Cond::NotEqual, Label::Numbered(1)),
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(2))),
)),
OpWrapper::Jump(Label::Numbered(0)),
OpWrapper::Label(Label::Numbered(1)),
OpWrapper::JumpIf(Cond::LowerOrEqual, Label::Numbered(0)),
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
)),
OpWrapper::Op(Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(1))),
Rd::new(SrcDisp::Register(Register::Gen(1))),
)),
OpWrapper::Label(Label::Numbered(0)),
], parsed);
}
#[test]
fn test_jumps_to_skips() {
let parsed = parse("(
(foo
(:foo)
(:unused)
(:whatever)
(mov r0 r0)
(j :foo)
(j :foo)
(mov r0 r0)
(mov r0 r0)
(j :whatever)
(j.if eq :whatever)
)
)").unwrap();
assert_eq!(
vec![
Op::Routine("foo".into()).into(),
OpWrapper::Label(Label::Named("foo".to_string())),
OpWrapper::Label(Label::Named("unused".to_string())),
OpWrapper::Label(Label::Named("whatever".to_string())),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
).into(),
OpWrapper::Jump(Label::Named("foo".to_string())),
OpWrapper::Jump(Label::Named("foo".to_string())),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
).into(),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
).into(),
OpWrapper::Jump(Label::Named("whatever".to_string())),
OpWrapper::JumpIf(Cond::Equal, Label::Named("whatever".to_string())),
Op::Barrier(Some("Routine \"foo\" overrun".into())).into(),
], parsed);
// Labels are removed and jumps become skips
let cleaned = lower(parsed).unwrap();
assert_eq!(
vec![
Op::Routine("foo".into()),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Skip(Rd::new(SrcDisp::Immediate(-1))),
Op::Skip(Rd::new(SrcDisp::Immediate(-2))),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Mov(
Wr::new(DstDisp::Register(Register::Gen(0))),
Rd::new(SrcDisp::Register(Register::Gen(0))),
),
Op::Skip(Rd::new(SrcDisp::Immediate(-5))),
Op::SkipIf(Cond::Equal, Rd::new(SrcDisp::Immediate(-6))),
Op::Barrier(Some("Routine \"foo\" overrun".into())),
], cleaned);
}
}

@ -1,16 +1,13 @@
use sexp::Sexp;
use crate::asm::data::literal::{Label, RoutineName}; use crate::asm::data::literal::{Label, RoutineName};
use crate::asm::error::{AsmError, Error}; use crate::asm::error::Error;
use crate::asm::instr::{OpWrapper, Op}; use crate::asm::instr::{Op, OpWrapper};
use crate::asm::instr::cond::parse_cond; use crate::asm::instr::cond::parse_cond;
use crate::asm::instr::op::{AsmModule, ParseOpResult}; use crate::asm::instr::op::{AsmModule, ParseOpResult};
use crate::asm::parse::parse_data::{parse_label, parse_rd, parse_wr};
use crate::asm::parse::sexp_expect::expect_string_atom;
use crate::asm::parse::arg_parser::ArgParser; use crate::asm::parse::arg_parser::ArgParser;
use crate::asm::parse::parse_data::{parse_label, parse_rd};
use crate::asm::parse::sexp_expect::expect_string_atom;
pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<OpWrapper, Error> { pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<OpWrapper, Error> {
Ok(match keyword { Ok(match keyword {
"j" => { "j" => {
let dest = parse_label(arg_tokens.next())?; let dest = parse_label(arg_tokens.next())?;

@ -60,6 +60,9 @@ pub enum Fault {
#[error("Call stack underflow")] #[error("Call stack underflow")]
CallStackUnderflow, CallStackUnderflow,
#[error("Attempt to read undefined extension data store")]
ExtDataNotDefined,
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]

@ -1,10 +1,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::asm::data::literal::{Addr, Label, RoutineName}; use crate::asm::data::literal::{Addr, Label, RoutineName};
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use std::sync::Arc;
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct Program { pub struct Program {
ops: Vec<Op>, ops: Vec<Op>,
routines: HashMap<RoutineName, Addr>, routines: HashMap<RoutineName, Addr>,
@ -13,7 +15,7 @@ pub struct Program {
} }
impl Program { impl Program {
pub fn new(ops: Vec<Op>) -> Self { pub fn new(ops: Vec<Op>) -> Arc<Self> {
let mut p = Self { let mut p = Self {
ops, ops,
routines: Default::default(), routines: Default::default(),
@ -21,7 +23,7 @@ impl Program {
barriers: Default::default(), barriers: Default::default(),
}; };
p.scan(); p.scan();
p Arc::new(p)
} }
/// Find all the named things /// Find all the named things

@ -1,3 +1,5 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use std::time::Duration; use std::time::Duration;
@ -5,6 +7,8 @@ use crate::asm::data::literal::Addr;
use crate::runtime::exec::EvalRes; use crate::runtime::exec::EvalRes;
use crate::runtime::frame::{CallStack, StackFrame}; use crate::runtime::frame::{CallStack, StackFrame};
use crate::runtime::program::Program; use crate::runtime::program::Program;
use std::sync::Arc;
const CYCLE_TIME: Duration = Duration::from_millis(0); const CYCLE_TIME: Duration = Duration::from_millis(0);
//const CYCLE_TIME : Duration = Duration::from_millis(100); //const CYCLE_TIME : Duration = Duration::from_millis(100);
@ -20,11 +24,13 @@ pub struct RunThread {
/// Call stack /// Call stack
pub call_stack: CallStack, pub call_stack: CallStack,
/// Program to run /// Program to run
pub program: Program, pub program: Arc<Program>,
/// Extension data
ext_data: HashMap<TypeId, Box<dyn Any + Send>>,
} }
impl RunThread { impl RunThread {
pub fn new(id: ThreadToken, program: Program, pc: Addr, args: &[u64]) -> Self { pub fn new(id: ThreadToken, program: Arc<Program>, pc: Addr, args: &[u64]) -> Self {
let sf = StackFrame::new(pc, args); let sf = StackFrame::new(pc, args);
Self { Self {
@ -32,6 +38,7 @@ impl RunThread {
frame: sf, frame: sf,
call_stack: vec![], call_stack: vec![],
program, program,
ext_data: Default::default(),
} }
} }
@ -58,5 +65,13 @@ impl RunThread {
} }
} }
} }
}
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
if !self.ext_data.contains_key(&TypeId::of::<T>()) {
self.ext_data.insert(TypeId::of::<T>(), Box::new(T::default()));
}
self.ext_data.get_mut(&TypeId::of::<T>()).unwrap()
.downcast_mut().unwrap()
}
}

@ -1,8 +1,8 @@
use crsn::asm::data::{Rd, Wr}; use crsn::asm::data::{Rd, Wr};
use crsn::asm::error::{AsmError, Error}; use crsn::asm::error::{Error};
use crsn::asm::instr::op::{AsmModule, OpTrait, ParseOpResult}; use crsn::asm::instr::op::{AsmModule, ParseOpResult};
use crsn::asm::parse::parse_data::{parse_rd, parse_wr};
use crsn::sexp::Sexp;
use crate::defs::ArithOp; use crate::defs::ArithOp;
use crsn::asm::parse::arg_parser::ArgParser; use crsn::asm::parse::arg_parser::ArgParser;

Loading…
Cancel
Save