forked from MightyPork/crsn
cleaning
This commit is contained in:
@@ -4,15 +4,15 @@ use std::sync::atomic::AtomicU32;
|
|||||||
use crate::asm::data::{Rd, SrcDisp};
|
use crate::asm::data::{Rd, SrcDisp};
|
||||||
use crate::asm::data::literal::{Label, Value};
|
use crate::asm::data::literal::{Label, Value};
|
||||||
use crate::asm::error::{AsmError, Error};
|
use crate::asm::error::{AsmError, Error};
|
||||||
use crate::asm::instr::{Cond, OpWrapper, Instr, Op, Routine};
|
use crate::asm::instr::{Cond, Instr, Op, Routine};
|
||||||
|
|
||||||
/// A trait for something that can turn into multiple instructions
|
/// A trait for something that can turn into multiple instructions
|
||||||
pub trait Flatten {
|
pub trait Flatten {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<OpWrapper>, Error>;
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Instr {
|
impl Flatten for Instr {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<OpWrapper>, Error> {
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
||||||
let mut ops = vec![self.op];
|
let mut ops = vec![self.op];
|
||||||
|
|
||||||
if let Some(branches) = self.branches {
|
if let Some(branches) = self.branches {
|
||||||
@@ -29,18 +29,18 @@ impl Flatten for Instr {
|
|||||||
} else {
|
} else {
|
||||||
Label::unique(label_num)
|
Label::unique(label_num)
|
||||||
};
|
};
|
||||||
ops.push(OpWrapper::JumpIf(!cond, next_lbl.clone()));
|
ops.push(Op::JumpIf(!cond, next_lbl.clone()));
|
||||||
|
|
||||||
for branch_instr in branch {
|
for branch_instr in branch {
|
||||||
ops.extend(branch_instr.flatten(label_num)?);
|
ops.extend(branch_instr.flatten(label_num)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cnt != branch_count - 1 {
|
if cnt != branch_count - 1 {
|
||||||
ops.push(OpWrapper::Jump(end_lbl.clone()));
|
ops.push(Op::Jump(end_lbl.clone()));
|
||||||
ops.push(OpWrapper::Label(next_lbl));
|
ops.push(Op::Label(next_lbl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ops.push(OpWrapper::Label(end_lbl));
|
ops.push(Op::Label(end_lbl));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ops)
|
Ok(ops)
|
||||||
@@ -48,7 +48,7 @@ impl Flatten for Instr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Routine {
|
impl Flatten for Routine {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<OpWrapper>, Error> {
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
||||||
let mut ops = vec![
|
let mut ops = vec![
|
||||||
Op::Routine(self.name.clone()).into(),
|
Op::Routine(self.name.clone()).into(),
|
||||||
];
|
];
|
||||||
@@ -61,44 +61,3 @@ impl Flatten for Routine {
|
|||||||
Ok(ops)
|
Ok(ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert jumps to relative skips
|
|
||||||
pub fn lower(ops: Vec<OpWrapper>) -> Result<Vec<Op>, Error> {
|
|
||||||
let mut label_positions = HashMap::<Label, usize>::new();
|
|
||||||
for (n, op) in ops.iter().enumerate() {
|
|
||||||
if let OpWrapper::Label(name) = op {
|
|
||||||
label_positions.insert(name.clone(), n - label_positions.len());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cleaned = vec![];
|
|
||||||
let mut skipped = 0;
|
|
||||||
for (n, op) in ops.into_iter().enumerate() {
|
|
||||||
match op {
|
|
||||||
OpWrapper::Label(_) => {
|
|
||||||
skipped += 1;
|
|
||||||
}
|
|
||||||
OpWrapper::Jump(target) => {
|
|
||||||
if let Some(dest) = label_positions.get(&target) {
|
|
||||||
let skip = *dest as isize - n as isize + skipped;
|
|
||||||
cleaned.push(Op::Skip(Rd::new(SrcDisp::Immediate(skip as Value))));
|
|
||||||
} else {
|
|
||||||
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpWrapper::JumpIf(cond, target) => {
|
|
||||||
if let Some(dest) = label_positions.get(&target) {
|
|
||||||
let skip = *dest as isize - n as isize + skipped;
|
|
||||||
cleaned.push(Op::SkipIf(cond, Rd::new(SrcDisp::Immediate(skip as Value))));
|
|
||||||
} else {
|
|
||||||
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpWrapper::Op(op) => {
|
|
||||||
cleaned.push(op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(cleaned)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
pub use cond::Cond;
|
pub use cond::Cond;
|
||||||
pub use flatten::Flatten;
|
pub use flatten::Flatten;
|
||||||
pub use flatten::lower;
|
|
||||||
pub use op::OpWrapper;
|
|
||||||
pub use op::Op;
|
pub use op::Op;
|
||||||
|
|
||||||
use crate::asm::data::literal::RoutineName;
|
use crate::asm::data::literal::RoutineName;
|
||||||
@@ -13,7 +11,7 @@ mod flatten;
|
|||||||
/// A higher-level instruction
|
/// A higher-level instruction
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Instr {
|
pub struct Instr {
|
||||||
pub op: OpWrapper,
|
pub op: Op,
|
||||||
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
|
pub branches: Option<Vec<(Cond, Vec<Instr>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+145
-20
@@ -6,6 +6,7 @@ use crate::asm::data::{
|
|||||||
Rd,
|
Rd,
|
||||||
Wr,
|
Wr,
|
||||||
};
|
};
|
||||||
|
use crate::asm::data::literal::Addr;
|
||||||
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::asm::parse::arg_parser::ArgParser;
|
||||||
@@ -15,22 +16,15 @@ use crate::runtime::program::Program;
|
|||||||
|
|
||||||
/// A higher level simple opration
|
/// A higher level simple opration
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum OpWrapper {
|
pub enum Op {
|
||||||
|
/// Do nothing
|
||||||
|
Nop,
|
||||||
/// Mark a jump target.
|
/// Mark a jump target.
|
||||||
Label(Label),
|
Label(Label),
|
||||||
/// Jump to a label
|
/// Jump to a label
|
||||||
Jump(Label),
|
Jump(Label),
|
||||||
/// Jump to a label if a flag is set
|
/// Jump to a label if a flag is set
|
||||||
JumpIf(Cond, Label),
|
JumpIf(Cond, Label),
|
||||||
/// Low level op
|
|
||||||
Op(Op),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A low level instruction
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Op {
|
|
||||||
/// Do nothing
|
|
||||||
Nop,
|
|
||||||
/// Mark a far jump target (can be jumped to from another routine).
|
/// Mark a far jump target (can be jumped to from another routine).
|
||||||
/// This label is preserved in optimized code.
|
/// This label is preserved in optimized code.
|
||||||
FarLabel(Label),
|
FarLabel(Label),
|
||||||
@@ -58,23 +52,16 @@ pub enum Op {
|
|||||||
StoreStatus { dst: Wr },
|
StoreStatus { dst: Wr },
|
||||||
/// Load runtime status from a register
|
/// Load runtime status from a register
|
||||||
LoadStatus { src: Rd },
|
LoadStatus { src: Rd },
|
||||||
|
/// Instruction added by an extension
|
||||||
Extension(Box<dyn OpTrait>),
|
Extension(Box<dyn OpTrait>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make "into" work
|
|
||||||
impl From<Op> for OpWrapper {
|
|
||||||
fn from(op: Op) -> Self {
|
|
||||||
OpWrapper::Op(op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait OpTrait: Debug + Send + Sync + 'static {
|
pub trait OpTrait: Debug + Send + Sync + '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<EvalRes, Fault>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParseOpResult {
|
pub enum ParseOpResult {
|
||||||
Parsed(Box<dyn OpTrait + Send>),
|
Parsed(Box<dyn OpTrait>),
|
||||||
Unknown(ArgParser),
|
Unknown(ArgParser),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,3 +76,141 @@ pub trait AsmModule: Debug + Send + 'static {
|
|||||||
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
|
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
|
||||||
fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpResult, Error>;
|
fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpResult, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub type CyclesSpent = usize;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EvalRes {
|
||||||
|
pub cycles: CyclesSpent,
|
||||||
|
pub advance: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EvalRes {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
cycles: 1,
|
||||||
|
advance: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl OpTrait for Op {
|
||||||
|
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
||||||
|
let mut res = EvalRes::default();
|
||||||
|
match self {
|
||||||
|
Op::Nop => {}
|
||||||
|
Op::Label(_) | Op::FarLabel(_) | Op::Routine(_) => {
|
||||||
|
/* this is nop, but without any cost - just markers */
|
||||||
|
res.cycles = 0;
|
||||||
|
}
|
||||||
|
Op::Barrier(msg) => {
|
||||||
|
return Err(Fault::Barrier {
|
||||||
|
msg: msg.clone().unwrap_or_else(|| "BARRIER".into())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Op::Fault(msg) => {
|
||||||
|
return Err(Fault::FaultInstr {
|
||||||
|
msg: msg.clone().unwrap_or_else(|| "FAULT".into())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Op::FarJump(name) => {
|
||||||
|
match program.find_far_label(name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Jump(name) => {
|
||||||
|
match program.find_local_label(frame.pc, name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::JumpIf(cond, name) => {
|
||||||
|
if frame.status.test(*cond) {
|
||||||
|
match program.find_local_label(frame.pc, name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Call(name, args) => {
|
||||||
|
match program.find_routine(&name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
let mut values = Vec::with_capacity(args.len());
|
||||||
|
for arg in args {
|
||||||
|
values.push(frame.read(*arg)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut frame2 = StackFrame::new(pos, &values);
|
||||||
|
std::mem::swap(frame, &mut frame2);
|
||||||
|
call_stack.push(frame2);
|
||||||
|
res.advance = 0;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Ret(retvals) => {
|
||||||
|
match call_stack.pop() {
|
||||||
|
Some(previous) => {
|
||||||
|
let mut values = Vec::with_capacity(retvals.len());
|
||||||
|
for arg in retvals {
|
||||||
|
values.push(frame.read(*arg)?);
|
||||||
|
}
|
||||||
|
*frame = previous;
|
||||||
|
frame.set_retvals(&values);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(Fault::CallStackUnderflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Skip(val) => {
|
||||||
|
let steps = frame.read(*val)?;
|
||||||
|
res.advance = i64::from_ne_bytes(steps.to_ne_bytes());
|
||||||
|
program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?;
|
||||||
|
}
|
||||||
|
Op::SkipIf(cond, val) => {
|
||||||
|
if frame.status.test(*cond) {
|
||||||
|
let steps = frame.read(*val)?;
|
||||||
|
res.advance = i64::from_ne_bytes(steps.to_ne_bytes());
|
||||||
|
program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::Move { dst, src } => {
|
||||||
|
frame.status.clear();
|
||||||
|
let val = frame.read(*src)?;
|
||||||
|
frame.status.update(val);
|
||||||
|
frame.write(*dst, val)?;
|
||||||
|
}
|
||||||
|
Op::StoreStatus { dst } => {
|
||||||
|
let packed = frame.status.store();
|
||||||
|
frame.write(*dst, packed)?;
|
||||||
|
}
|
||||||
|
Op::LoadStatus { src } => {
|
||||||
|
let x = frame.read(*src)?;
|
||||||
|
frame.status.load(x);
|
||||||
|
}
|
||||||
|
Op::Extension(xop) => {
|
||||||
|
xop.execute(&program, call_stack, frame)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+7
-4
@@ -1,5 +1,8 @@
|
|||||||
use crate::asm::instr::{lower, Op};
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::instr::op::AsmModule;
|
use crate::asm::instr::op::AsmModule;
|
||||||
|
use crate::runtime::program::Program;
|
||||||
|
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
@@ -8,7 +11,7 @@ pub mod parse;
|
|||||||
pub mod patches;
|
pub mod patches;
|
||||||
|
|
||||||
/// Parse a program from string and assemble a low level instruction sequence from it.
|
/// Parse a program from string and assemble a low level instruction sequence from it.
|
||||||
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Op>, error::Error> {
|
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Program>, error::Error> {
|
||||||
let parsed = parse::parse(source, parsers)?;
|
let ops = parse::parse(source, parsers)?;
|
||||||
Ok(lower(parsed)?)
|
Ok(Program::new(ops))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::asm::data::{Rd, Wr};
|
use crate::asm::data::{Rd, Wr};
|
||||||
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
@@ -24,7 +25,7 @@ impl ArgParser {
|
|||||||
args.reverse();
|
args.reverse();
|
||||||
Self {
|
Self {
|
||||||
orig_len: args.len(),
|
orig_len: args.len(),
|
||||||
args
|
args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ pub use parse_instr::parse_instructions;
|
|||||||
use parse_routines::parse_routines;
|
use parse_routines::parse_routines;
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::asm::instr::{Flatten, OpWrapper, Routine};
|
use crate::asm::instr::{Flatten, Op, Routine};
|
||||||
use crate::asm::instr::op::AsmModule;
|
use crate::asm::instr::op::AsmModule;
|
||||||
use crate::asm::parse::sexp_expect::expect_list;
|
use crate::asm::parse::sexp_expect::expect_list;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ mod parse_op;
|
|||||||
|
|
||||||
pub mod arg_parser;
|
pub mod arg_parser;
|
||||||
|
|
||||||
pub fn parse(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<OpWrapper>, Error> {
|
pub fn parse(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Op>, Error> {
|
||||||
let root = sexp::parse(source)?;
|
let root = sexp::parse(source)?;
|
||||||
|
|
||||||
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;
|
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ use sexp::Sexp;
|
|||||||
use crate::asm::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::asm::instr::Instr;
|
use crate::asm::instr::Instr;
|
||||||
use crate::asm::instr::op::AsmModule;
|
use crate::asm::instr::op::AsmModule;
|
||||||
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::asm::parse::parse_cond::parse_cond_branch;
|
use crate::asm::parse::parse_cond::parse_cond_branch;
|
||||||
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||||
use crate::asm::patches::SexpIsA;
|
use crate::asm::patches::SexpIsA;
|
||||||
|
|
||||||
use super::parse_op::parse_op;
|
use super::parse_op::parse_op;
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
|
||||||
|
|
||||||
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Instr>, Error> {
|
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) -> Result<Vec<Instr>, Error> {
|
||||||
let mut parsed = vec![];
|
let mut parsed = vec![];
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
use crate::asm::data::literal::{Label, RoutineName};
|
use crate::asm::data::literal::{Label, RoutineName};
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::Error;
|
||||||
use crate::asm::instr::{Op, OpWrapper};
|
use crate::asm::instr::Op;
|
||||||
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::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::asm::parse::parse_data::{parse_label, parse_rd};
|
use crate::asm::parse::parse_data::{parse_label, parse_rd};
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
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<Op, Error> {
|
||||||
Ok(match keyword {
|
Ok(match keyword {
|
||||||
"j" => {
|
"j" => {
|
||||||
let dest = parse_label(arg_tokens.next())?;
|
let dest = parse_label(arg_tokens.next())?;
|
||||||
if far {
|
if far {
|
||||||
OpWrapper::Op(Op::FarJump(dest))
|
Op::FarJump(dest)
|
||||||
} else {
|
} else {
|
||||||
OpWrapper::Jump(dest)
|
Op::Jump(dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[
|
|||||||
for t in arg_tokens {
|
for t in arg_tokens {
|
||||||
args.push(parse_rd(Some(t))?);
|
args.push(parse_rd(Some(t))?);
|
||||||
}
|
}
|
||||||
OpWrapper::Op(Op::Call(dest, args))
|
Op::Call(dest, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
"ret" => {
|
"ret" => {
|
||||||
@@ -33,63 +33,63 @@ pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[
|
|||||||
for t in arg_tokens {
|
for t in arg_tokens {
|
||||||
args.push(parse_rd(Some(t))?);
|
args.push(parse_rd(Some(t))?);
|
||||||
}
|
}
|
||||||
OpWrapper::Op(Op::Ret(args))
|
Op::Ret(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
"routine" => {
|
"routine" => {
|
||||||
let dest = RoutineName(arg_tokens.next_string()?);
|
let dest = RoutineName(arg_tokens.next_string()?);
|
||||||
OpWrapper::Op(Op::Routine(dest))
|
Op::Routine(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
"s" => {
|
"s" => {
|
||||||
OpWrapper::Op(Op::Skip(arg_tokens.next_rd()?))
|
Op::Skip(arg_tokens.next_rd()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
"sif" => {
|
"sif" => {
|
||||||
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
||||||
let offs = arg_tokens.next_rd()?;
|
let offs = arg_tokens.next_rd()?;
|
||||||
OpWrapper::Op(Op::SkipIf(cond, offs))
|
Op::SkipIf(cond, offs)
|
||||||
}
|
}
|
||||||
|
|
||||||
"jif" => {
|
"jif" => {
|
||||||
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
||||||
let dest = parse_label(arg_tokens.next())?;
|
let dest = parse_label(arg_tokens.next())?;
|
||||||
OpWrapper::JumpIf(cond, dest)
|
Op::JumpIf(cond, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
"barrier" => {
|
"barrier" => {
|
||||||
OpWrapper::Op(Op::Barrier(match arg_tokens.next() {
|
Op::Barrier(match arg_tokens.next() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
"fault" => {
|
"fault" => {
|
||||||
OpWrapper::Op(Op::Fault(match arg_tokens.next() {
|
Op::Fault(match arg_tokens.next() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
"ld" => {
|
"ld" => {
|
||||||
OpWrapper::Op(Op::Move {
|
Op::Move {
|
||||||
dst: arg_tokens.next_wr()?,
|
dst: arg_tokens.next_wr()?,
|
||||||
src: arg_tokens.next_rd()?,
|
src: arg_tokens.next_rd()?,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
other => {
|
other => {
|
||||||
if let Some(label) = other.strip_prefix(':') {
|
if let Some(label) = other.strip_prefix(':') {
|
||||||
let label = Label::Named(label.to_string());
|
let label = Label::Named(label.to_string());
|
||||||
if far {
|
if far {
|
||||||
OpWrapper::Op(Op::FarLabel(label))
|
Op::FarLabel(label)
|
||||||
} else {
|
} else {
|
||||||
OpWrapper::Label(label)
|
Op::Label(label)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for p in parsers {
|
for p in parsers {
|
||||||
arg_tokens = match p.parse_op(keyword, arg_tokens) {
|
arg_tokens = match p.parse_op(keyword, arg_tokens) {
|
||||||
Ok(ParseOpResult::Parsed(op)) => return Ok(OpWrapper::Op(Op::Extension(op))),
|
Ok(ParseOpResult::Parsed(op)) => return Ok(Op::Extension(op)),
|
||||||
Ok(ParseOpResult::Unknown(to_reuse)) => {
|
Ok(ParseOpResult::Unknown(to_reuse)) => {
|
||||||
if to_reuse.parsing_started() {
|
if to_reuse.parsing_started() {
|
||||||
panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword);
|
panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword);
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
use crate::asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
|
use crate::asm::instr::op::{EvalRes, OpTrait};
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::frame::StackFrame;
|
use crate::runtime::frame::StackFrame;
|
||||||
use crate::runtime::run_thread::RunThread;
|
use crate::runtime::run_thread::RunThread;
|
||||||
|
|
||||||
pub type CyclesSpent = usize;
|
|
||||||
|
|
||||||
pub struct EvalRes {
|
|
||||||
pub cycles: u8,
|
|
||||||
pub advance: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunThread {
|
impl RunThread {
|
||||||
// TODO unit tests
|
// TODO unit tests
|
||||||
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
|
pub fn eval_op(&mut self) -> Result<EvalRes, Fault> {
|
||||||
@@ -27,101 +21,7 @@ impl RunThread {
|
|||||||
/* Operations can be given different execution times when run in slow mode. */
|
/* Operations can be given different execution times when run in slow mode. */
|
||||||
/* Presently, all that do anything use 1 cycle. */
|
/* Presently, all that do anything use 1 cycle. */
|
||||||
|
|
||||||
match op {
|
op.execute(&self.program, &mut self.call_stack, frame)?;
|
||||||
Op::Nop => {}
|
|
||||||
Op::FarLabel(_) | Op::Routine(_) => {
|
|
||||||
/* this is nop, but without any cost - just markers */
|
|
||||||
cycles = 0;
|
|
||||||
}
|
|
||||||
Op::Barrier(msg) => {
|
|
||||||
return Err(Fault::Barrier {
|
|
||||||
msg: msg.clone().unwrap_or_else(|| "No msg".into())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Op::Fault(msg) => {
|
|
||||||
return Err(Fault::FaultInstr {
|
|
||||||
msg: msg.clone().unwrap_or_else(|| "No msg".into())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Op::FarJump(name) => {
|
|
||||||
debug!("Far jump to {}", name);
|
|
||||||
match self.program.find_far_label(name) {
|
|
||||||
Ok(pos) => {
|
|
||||||
debug!("label is at {}", pos);
|
|
||||||
self.frame.pc = pos;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Op::Call(name, args) => {
|
|
||||||
debug!("Call routine {}", name);
|
|
||||||
match self.program.find_routine(name) {
|
|
||||||
Ok(pos) => {
|
|
||||||
debug!("routine is at {}", pos);
|
|
||||||
|
|
||||||
let mut values = Vec::with_capacity(args.len());
|
|
||||||
for arg in args {
|
|
||||||
values.push(self.frame.read(*arg)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut frame2 = StackFrame::new(pos, &values);
|
|
||||||
std::mem::swap(&mut self.frame, &mut frame2);
|
|
||||||
self.call_stack.push(frame2);
|
|
||||||
advance = 0;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Op::Ret(retvals) => {
|
|
||||||
match self.call_stack.pop() {
|
|
||||||
Some(previous) => {
|
|
||||||
let mut values = Vec::with_capacity(retvals.len());
|
|
||||||
for arg in retvals {
|
|
||||||
values.push(frame.read(*arg)?);
|
|
||||||
}
|
|
||||||
*frame = previous;
|
|
||||||
frame.set_retvals(&values);
|
|
||||||
advance = 1; // advance past the call
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(Fault::CallStackUnderflow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Op::Skip(val) => {
|
|
||||||
let steps = frame.read(*val)?;
|
|
||||||
advance = i64::from_ne_bytes(steps.to_ne_bytes());
|
|
||||||
self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?;
|
|
||||||
}
|
|
||||||
Op::SkipIf(cond, val) => {
|
|
||||||
if frame.status.test(*cond) {
|
|
||||||
let steps = frame.read(*val)?;
|
|
||||||
advance = i64::from_ne_bytes(steps.to_ne_bytes());
|
|
||||||
self.program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + advance) as u64))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Op::Move { dst, src } => {
|
|
||||||
frame.status.clear();
|
|
||||||
let val = frame.read(*src)?;
|
|
||||||
frame.status.update(val);
|
|
||||||
frame.write(*dst, val)?;
|
|
||||||
}
|
|
||||||
Op::Extension(xop) => {
|
|
||||||
xop.execute(&self.program, &mut self.call_stack, frame)?;
|
|
||||||
}
|
|
||||||
Op::StoreStatus { dst } => {
|
|
||||||
let packed = frame.status.store();
|
|
||||||
frame.write(*dst, packed)?;
|
|
||||||
}
|
|
||||||
Op::LoadStatus { src } => {
|
|
||||||
let x = frame.read(*src)?;
|
|
||||||
frame.status.load(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EvalRes {
|
Ok(EvalRes {
|
||||||
cycles,
|
cycles,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ pub enum Fault {
|
|||||||
},
|
},
|
||||||
|
|
||||||
#[error("Jump to undefined far label: {label}")]
|
#[error("Jump to undefined far label: {label}")]
|
||||||
NoSuchFarLabel {
|
NoSuchLabel {
|
||||||
label: Label,
|
label: Label,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
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(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
ops: Vec<Op>,
|
pub ops: Vec<Op>,
|
||||||
routines: HashMap<RoutineName, Addr>,
|
routines: HashMap<RoutineName, Addr>,
|
||||||
far_labels: HashMap<Label, Addr>,
|
far_labels: HashMap<Label, Addr>,
|
||||||
barriers: Vec<Addr>,
|
barriers: Vec<Addr>,
|
||||||
@@ -82,7 +81,39 @@ impl Program {
|
|||||||
/// Find far label by name
|
/// Find far label by name
|
||||||
pub fn find_far_label(&self, name: &Label) -> Result<Addr, Fault> {
|
pub fn find_far_label(&self, name: &Label) -> Result<Addr, Fault> {
|
||||||
self.far_labels.get(name).copied()
|
self.far_labels.get(name).copied()
|
||||||
.ok_or_else(|| Fault::NoSuchFarLabel { label: name.clone() })
|
.ok_or_else(|| Fault::NoSuchLabel { label: name.clone() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find local label by name (label within a boundary-delimited region).
|
||||||
|
/// If more than one such label exists, the outcome is undefined.
|
||||||
|
pub fn find_local_label(&self, pc: Addr, name: &Label) -> Result<Addr, Fault> {
|
||||||
|
// TODO more efficient impl with look-up
|
||||||
|
|
||||||
|
for at in (0..=pc.0).rev() {
|
||||||
|
match &self.ops[at as usize] {
|
||||||
|
Op::Label(lbl) if lbl == name => {
|
||||||
|
return Ok(at.into());
|
||||||
|
}
|
||||||
|
Op::Barrier(_) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for at in pc.0..(self.ops.len() as u64) {
|
||||||
|
match &self.ops[at as usize] {
|
||||||
|
Op::Label(lbl) if lbl == name => {
|
||||||
|
return Ok(at.into());
|
||||||
|
}
|
||||||
|
Op::Barrier(_) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Fault::NoSuchLabel { label: name.clone() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::asm::data::literal::Addr;
|
use crate::asm::data::literal::Addr;
|
||||||
use crate::runtime::exec::EvalRes;
|
use crate::asm::instr::op::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);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::ops::Rem;
|
|||||||
|
|
||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
use crsn::asm::instr::op::OpTrait;
|
use crsn::asm::instr::op::{OpTrait, EvalRes};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::frame::{CallStack, StackFrame};
|
use crsn::runtime::frame::{CallStack, StackFrame};
|
||||||
use crsn::runtime::program::Program;
|
use crsn::runtime::program::Program;
|
||||||
@@ -10,7 +10,8 @@ use crsn::runtime::program::Program;
|
|||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
|
||||||
impl OpTrait for ArithOp {
|
impl OpTrait for ArithOp {
|
||||||
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<EvalRes, Fault> {
|
||||||
|
let eres = EvalRes::default();
|
||||||
match self {
|
match self {
|
||||||
ArithOp::Test { a } => {
|
ArithOp::Test { a } => {
|
||||||
frame.status.clear();
|
frame.status.clear();
|
||||||
@@ -188,7 +189,7 @@ impl OpTrait for ArithOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(eres)
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ fn main() {
|
|||||||
let program = "
|
let program = "
|
||||||
(
|
(
|
||||||
(main
|
(main
|
||||||
|
(j :lbl)
|
||||||
(ld _ arg0)
|
(ld _ arg0)
|
||||||
|
(fault)
|
||||||
|
(:lbl)
|
||||||
(call fibo 5)
|
(call fibo 5)
|
||||||
(ld r0 res0)
|
(ld r0 res0)
|
||||||
)
|
)
|
||||||
@@ -69,12 +72,12 @@ fn main() {
|
|||||||
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
||||||
|
|
||||||
debug!("---");
|
debug!("---");
|
||||||
for op in &parsed {
|
for op in &parsed.ops {
|
||||||
debug!("{:?}", op);
|
debug!("{:?}", op);
|
||||||
}
|
}
|
||||||
debug!("---");
|
debug!("---");
|
||||||
|
|
||||||
let thread = RunThread::new(ThreadToken(0), Program::new(parsed), Addr(0), &[]);
|
let thread = RunThread::new(ThreadToken(0), parsed, Addr(0), &[]);
|
||||||
|
|
||||||
thread.start().join().unwrap();
|
thread.start().join().unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user