forked from MightyPork/crsn
Convert builtin ops into a pseudo-extension
This commit is contained in:
@@ -38,7 +38,7 @@ impl Display for Addr {
|
|||||||
if self.0 > 0x7fff_ffff_ffff_ffff {
|
if self.0 > 0x7fff_ffff_ffff_ffff {
|
||||||
write!(f, "{}", i64::from_ne_bytes(self.0.to_ne_bytes()))
|
write!(f, "{}", i64::from_ne_bytes(self.0.to_ne_bytes()))
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{:#010x}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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, Instr, Op, Routine};
|
use crate::asm::instr::{Cond, Instr, Op, Routine};
|
||||||
|
use crate::builtin::defs::BuiltinOp;
|
||||||
|
|
||||||
/// 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 {
|
||||||
@@ -29,18 +30,18 @@ impl Flatten for Instr {
|
|||||||
} else {
|
} else {
|
||||||
Label::unique(label_num)
|
Label::unique(label_num)
|
||||||
};
|
};
|
||||||
ops.push(Op::JumpIf(!cond, next_lbl.clone()));
|
ops.push(BuiltinOp::JumpIf(!cond, next_lbl.clone()).into());
|
||||||
|
|
||||||
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(Op::Jump(end_lbl.clone()));
|
ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
|
||||||
ops.push(Op::Label(next_lbl));
|
ops.push(BuiltinOp::Label(next_lbl).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ops.push(Op::Label(end_lbl));
|
ops.push(BuiltinOp::Label(end_lbl).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ops)
|
Ok(ops)
|
||||||
@@ -50,14 +51,56 @@ impl Flatten for Instr {
|
|||||||
impl Flatten for Routine {
|
impl Flatten for Routine {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, 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(),
|
BuiltinOp::Routine(self.name.clone()).into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
for instr in self.body {
|
for instr in self.body {
|
||||||
ops.extend(instr.flatten(label_num)?);
|
ops.extend(instr.flatten(label_num)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
ops.push(Op::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into());
|
ops.push(BuiltinOp::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into());
|
||||||
Ok(ops)
|
|
||||||
|
numbered_labels_to_skips(ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert jumps to relative skips
|
||||||
|
fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
|
||||||
|
let mut label_positions = HashMap::<Label, usize>::new();
|
||||||
|
for (n, op) in ops.iter().enumerate() {
|
||||||
|
if let Op::BuiltIn(BuiltinOp::Label(name @ Label::Numbered(_))) = 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 {
|
||||||
|
Op::BuiltIn(BuiltinOp::Label(Label::Numbered(_))) => {
|
||||||
|
skipped += 1;
|
||||||
|
}
|
||||||
|
Op::BuiltIn(BuiltinOp::Jump(target @ Label::Numbered(_))) => {
|
||||||
|
if let Some(dest) = label_positions.get(&target) {
|
||||||
|
let skip = *dest as isize - n as isize + skipped;
|
||||||
|
cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(SrcDisp::Immediate(skip as Value)))));
|
||||||
|
} else {
|
||||||
|
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => {
|
||||||
|
if let Some(dest) = label_positions.get(&target) {
|
||||||
|
let skip = *dest as isize - n as isize + skipped;
|
||||||
|
cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(SrcDisp::Immediate(skip as Value)))));
|
||||||
|
} else {
|
||||||
|
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
cleaned.push(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cleaned)
|
||||||
|
}
|
||||||
|
|||||||
+8
-147
@@ -10,6 +10,7 @@ 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;
|
||||||
|
use crate::builtin::defs::BuiltinOp;
|
||||||
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;
|
||||||
@@ -17,43 +18,9 @@ use crate::runtime::program::Program;
|
|||||||
/// A higher level simple opration
|
/// A higher level simple opration
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
/// Do nothing
|
BuiltIn(BuiltinOp),
|
||||||
Nop,
|
|
||||||
/// Mark a jump target.
|
|
||||||
Label(Label),
|
|
||||||
/// Jump to a label
|
|
||||||
Jump(Label),
|
|
||||||
/// Jump to a label if a flag is set
|
|
||||||
JumpIf(Cond, Label),
|
|
||||||
/// Mark a far jump target (can be jumped to from another routine).
|
|
||||||
/// This label is preserved in optimized code.
|
|
||||||
FarLabel(Label),
|
|
||||||
/// Jump to a label that can be in another function
|
|
||||||
FarJump(Label),
|
|
||||||
/// Call a routine with arguments.
|
|
||||||
/// The arguments are passed as argX. Return values are stored in resX registers.
|
|
||||||
Call(RoutineName, Vec<Rd>),
|
|
||||||
/// Exit the current routine with return values
|
|
||||||
Ret(Vec<Rd>),
|
|
||||||
/// Mark a routine entry point (call target).
|
|
||||||
/// Kept in the low level instruction file for position-independent code
|
|
||||||
Routine(RoutineName),
|
|
||||||
/// Skip backward or forward
|
|
||||||
Skip(Rd),
|
|
||||||
/// Skip if a flag is set
|
|
||||||
SkipIf(Cond, Rd),
|
|
||||||
/// Deny jumps, skips and run across this address, producing a run-time fault with a message.
|
|
||||||
Barrier(Option<DebugMsg>),
|
|
||||||
/// Generate a run-time fault with a debugger message
|
|
||||||
Fault(Option<DebugMsg>),
|
|
||||||
/// Copy value
|
|
||||||
Move { dst: Wr, src: Rd },
|
|
||||||
/// Store runtime status to a register
|
|
||||||
StoreStatus { dst: Wr },
|
|
||||||
/// Load runtime status from a register
|
|
||||||
LoadStatus { src: Rd },
|
|
||||||
/// Instruction added by an extension
|
/// Instruction added by an extension
|
||||||
Extension(Box<dyn OpTrait>),
|
Ext(Box<dyn OpTrait>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait OpTrait: Debug + Send + Sync + 'static {
|
pub trait OpTrait: Debug + Send + Sync + 'static {
|
||||||
@@ -61,7 +28,7 @@ pub trait OpTrait: Debug + Send + Sync + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParseOpResult {
|
pub enum ParseOpResult {
|
||||||
Parsed(Box<dyn OpTrait>),
|
Parsed(Op),
|
||||||
Unknown(ArgParser),
|
Unknown(ArgParser),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,119 +65,13 @@ impl Default for EvalRes {
|
|||||||
|
|
||||||
impl OpTrait for Op {
|
impl OpTrait for Op {
|
||||||
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
||||||
let mut res = EvalRes::default();
|
|
||||||
match self {
|
match self {
|
||||||
Op::Nop => {}
|
Op::BuiltIn(op) => {
|
||||||
Op::Label(_) | Op::FarLabel(_) | Op::Routine(_) => {
|
op.execute(&program, call_stack, frame)
|
||||||
/* this is nop, but without any cost - just markers */
|
|
||||||
res.cycles = 0;
|
|
||||||
}
|
}
|
||||||
Op::Barrier(msg) => {
|
Op::Ext(op) => {
|
||||||
return Err(Fault::Barrier {
|
op.execute(&program, call_stack, frame)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,12 @@ 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<Arc<Program>, error::Error> {
|
pub fn assemble(source: &str, parsers: &[Box<dyn AsmModule>]) -> Result<Arc<Program>, error::Error> {
|
||||||
let ops = parse::parse(source, parsers)?;
|
let ops = parse::parse(source, parsers)?;
|
||||||
|
|
||||||
|
trace!("--- Compiled program ---");
|
||||||
|
for (n, op) in ops.iter().enumerate() {
|
||||||
|
trace!("{:04} : {:?}", n, op);
|
||||||
|
}
|
||||||
|
trace!("------------------------");
|
||||||
|
|
||||||
Ok(Program::new(ops))
|
Ok(Program::new(ops))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ impl ArgParser {
|
|||||||
self.args.pop()
|
self.args.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look at the next entry
|
||||||
|
pub fn peek(&mut self) -> Option<&Sexp> {
|
||||||
|
self.args.last()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next string entry
|
/// Get the next string entry
|
||||||
pub fn next_string(&mut self) -> anyhow::Result<String> {
|
pub fn next_string(&mut self) -> anyhow::Result<String> {
|
||||||
Ok(expect_string_atom(self.next())?)
|
Ok(expect_string_atom(self.next())?)
|
||||||
|
|||||||
@@ -16,15 +16,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) ->
|
|||||||
let tokens = expect_list(Some(expr), false)?;
|
let tokens = expect_list(Some(expr), false)?;
|
||||||
|
|
||||||
let mut toki = tokens.into_iter();
|
let mut toki = tokens.into_iter();
|
||||||
|
let name = expect_string_atom(toki.next())?;
|
||||||
let mut name = expect_string_atom(toki.next())?;
|
|
||||||
|
|
||||||
let far = if name == "far" {
|
|
||||||
name = expect_string_atom(toki.next())?;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let arg_tokens = ArgParser::new(toki.clone().take_while(|e| e.is_atom()).collect());
|
let arg_tokens = ArgParser::new(toki.clone().take_while(|e| e.is_atom()).collect());
|
||||||
let branch_tokens = toki
|
let branch_tokens = toki
|
||||||
@@ -44,7 +36,7 @@ pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn AsmModule>]) ->
|
|||||||
};
|
};
|
||||||
|
|
||||||
parsed.push(Instr {
|
parsed.push(Instr {
|
||||||
op: parse_op(name.as_str(), far, arg_tokens, parsers)?,
|
op: parse_op(name.as_str(), arg_tokens, parsers)?,
|
||||||
branches,
|
branches,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,90 +6,15 @@ 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;
|
||||||
|
use crate::builtin::parse::BuiltinOpParser;
|
||||||
|
|
||||||
pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<Op, Error> {
|
pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn AsmModule>]) -> Result<Op, Error> {
|
||||||
Ok(match keyword {
|
// Include built-in instructions
|
||||||
"j" => {
|
let builtins = [BuiltinOpParser::new()];
|
||||||
let dest = parse_label(arg_tokens.next())?;
|
|
||||||
if far {
|
|
||||||
Op::FarJump(dest)
|
|
||||||
} else {
|
|
||||||
Op::Jump(dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"call" => {
|
for p in builtins.iter().chain(parsers) {
|
||||||
let dest = RoutineName(arg_tokens.next_string()?);
|
|
||||||
|
|
||||||
let mut args = vec![];
|
|
||||||
for t in arg_tokens {
|
|
||||||
args.push(parse_rd(Some(t))?);
|
|
||||||
}
|
|
||||||
Op::Call(dest, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
"ret" => {
|
|
||||||
let mut args = vec![];
|
|
||||||
for t in arg_tokens {
|
|
||||||
args.push(parse_rd(Some(t))?);
|
|
||||||
}
|
|
||||||
Op::Ret(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
"routine" => {
|
|
||||||
let dest = RoutineName(arg_tokens.next_string()?);
|
|
||||||
Op::Routine(dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
"s" => {
|
|
||||||
Op::Skip(arg_tokens.next_rd()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
"sif" => {
|
|
||||||
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
|
||||||
let offs = arg_tokens.next_rd()?;
|
|
||||||
Op::SkipIf(cond, offs)
|
|
||||||
}
|
|
||||||
|
|
||||||
"jif" => {
|
|
||||||
let cond = parse_cond(&arg_tokens.next_string()?)?;
|
|
||||||
let dest = parse_label(arg_tokens.next())?;
|
|
||||||
Op::JumpIf(cond, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
"barrier" => {
|
|
||||||
Op::Barrier(match arg_tokens.next() {
|
|
||||||
None => None,
|
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
"fault" => {
|
|
||||||
Op::Fault(match arg_tokens.next() {
|
|
||||||
None => None,
|
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
"ld" => {
|
|
||||||
Op::Move {
|
|
||||||
dst: arg_tokens.next_wr()?,
|
|
||||||
src: arg_tokens.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
other => {
|
|
||||||
if let Some(label) = other.strip_prefix(':') {
|
|
||||||
let label = Label::Named(label.to_string());
|
|
||||||
if far {
|
|
||||||
Op::FarLabel(label)
|
|
||||||
} else {
|
|
||||||
Op::Label(label)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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(Op::Extension(op)),
|
Ok(ParseOpResult::Parsed(op)) => return Ok(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);
|
||||||
@@ -102,8 +27,5 @@ pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(Error::Parse(format!("Unknown instruction: {}", other).into()));
|
return Err(Error::Parse(format!("Unknown instruction: {}", keyword).into()));
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
use crate::asm::data::literal::{Label, RoutineName, DebugMsg};
|
||||||
|
use crate::asm::instr::{Cond, Op};
|
||||||
|
use crate::asm::data::{Rd, Wr};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BuiltinOp {
|
||||||
|
/// Do nothing
|
||||||
|
Nop,
|
||||||
|
/// Mark a jump target.
|
||||||
|
Label(Label),
|
||||||
|
/// Jump to a label
|
||||||
|
Jump(Label),
|
||||||
|
/// Jump to a label if a flag is set
|
||||||
|
JumpIf(Cond, Label),
|
||||||
|
/// Far jump to a label if a flag is set
|
||||||
|
FarJumpIf(Cond, Label),
|
||||||
|
/// Mark a far jump target (can be jumped to from another routine).
|
||||||
|
/// This label is preserved in optimized code.
|
||||||
|
FarLabel(Label),
|
||||||
|
/// Jump to a label that can be in another function
|
||||||
|
FarJump(Label),
|
||||||
|
/// Call a routine with arguments.
|
||||||
|
/// The arguments are passed as argX. Return values are stored in resX registers.
|
||||||
|
Call(RoutineName, Vec<Rd>),
|
||||||
|
/// Exit the current routine with return values
|
||||||
|
Ret(Vec<Rd>),
|
||||||
|
/// Mark a routine entry point (call target).
|
||||||
|
/// Kept in the low level instruction file for position-independent code
|
||||||
|
Routine(RoutineName),
|
||||||
|
/// Skip backward or forward
|
||||||
|
Skip(Rd),
|
||||||
|
/// Skip if a flag is set
|
||||||
|
SkipIf(Cond, Rd),
|
||||||
|
/// Deny jumps, skips and run across this address, producing a run-time fault with a message.
|
||||||
|
Barrier(Option<DebugMsg>),
|
||||||
|
/// Generate a run-time fault with a debugger message
|
||||||
|
Fault(Option<DebugMsg>),
|
||||||
|
/// Copy value
|
||||||
|
Move { dst: Wr, src: Rd },
|
||||||
|
/// Store runtime status to a register
|
||||||
|
StoreStatus { dst: Wr },
|
||||||
|
/// Load runtime status from a register
|
||||||
|
LoadStatus { src: Rd },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BuiltinOp> for Op {
|
||||||
|
fn from(bo: BuiltinOp) -> Self {
|
||||||
|
Op::BuiltIn(bo)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
use std::ops::Rem;
|
||||||
|
|
||||||
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
|
use crate::asm::instr::op::{OpTrait, EvalRes};
|
||||||
|
use crate::runtime::fault::Fault;
|
||||||
|
use crate::runtime::frame::{CallStack, StackFrame};
|
||||||
|
use crate::runtime::program::Program;
|
||||||
|
use crate::builtin::defs::BuiltinOp;
|
||||||
|
use crate::asm::data::literal::Addr;
|
||||||
|
|
||||||
|
impl OpTrait for BuiltinOp {
|
||||||
|
fn execute(&self, program: &Program, call_stack: &mut CallStack, frame: &mut StackFrame) -> Result<EvalRes, Fault> {
|
||||||
|
let mut res = EvalRes::default();
|
||||||
|
match self {
|
||||||
|
BuiltinOp::Nop => {}
|
||||||
|
BuiltinOp::Label(_) | BuiltinOp::FarLabel(_) | BuiltinOp::Routine(_) => {
|
||||||
|
/* this is nop, but without any cost - just markers */
|
||||||
|
res.cycles = 0;
|
||||||
|
}
|
||||||
|
BuiltinOp::Barrier(msg) => {
|
||||||
|
return Err(Fault::Barrier {
|
||||||
|
msg: msg.clone().unwrap_or_else(|| "BARRIER".into())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
BuiltinOp::Fault(msg) => {
|
||||||
|
return Err(Fault::FaultInstr {
|
||||||
|
msg: msg.clone().unwrap_or_else(|| "FAULT".into())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
BuiltinOp::FarJump(name) => {
|
||||||
|
match program.find_far_label(name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::Jump(name) => {
|
||||||
|
match program.find_local_label(frame.pc, name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::FarJumpIf(cond, name) => {
|
||||||
|
if frame.status.test(*cond) {
|
||||||
|
match program.find_far_label(name) {
|
||||||
|
Ok(pos) => {
|
||||||
|
frame.pc = pos;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::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))?;
|
||||||
|
}
|
||||||
|
BuiltinOp::SkipIf(cond, val) => {
|
||||||
|
if frame.status.test(*cond) {
|
||||||
|
debug!("Skipping");
|
||||||
|
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))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BuiltinOp::Move { dst, src } => {
|
||||||
|
frame.status.clear();
|
||||||
|
let val = frame.read(*src)?;
|
||||||
|
frame.status.update(val);
|
||||||
|
frame.write(*dst, val)?;
|
||||||
|
}
|
||||||
|
BuiltinOp::StoreStatus { dst } => {
|
||||||
|
let packed = frame.status.store();
|
||||||
|
frame.write(*dst, packed)?;
|
||||||
|
}
|
||||||
|
BuiltinOp::LoadStatus { src } => {
|
||||||
|
let x = frame.read(*src)?;
|
||||||
|
frame.status.load(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod defs;
|
||||||
|
pub mod exec;
|
||||||
|
pub mod parse;
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use crate::asm::data::{Rd, Wr};
|
||||||
|
use crate::asm::error::{Error};
|
||||||
|
use crate::asm::instr::op::{AsmModule, ParseOpResult};
|
||||||
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
|
use crate::asm::data::literal::{Label, RoutineName};
|
||||||
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
use crate::asm::parse::parse_data::{parse_label, parse_rd};
|
||||||
|
use crate::asm::instr::cond::parse_cond;
|
||||||
|
use crate::asm::instr::Op;
|
||||||
|
use crate::builtin::defs::BuiltinOp;
|
||||||
|
use sexp::{Sexp, Atom};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BuiltinOpParser {
|
||||||
|
_internal: ()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltinOpParser {
|
||||||
|
pub fn new() -> Box<dyn AsmModule> {
|
||||||
|
Box::new(Self {
|
||||||
|
_internal: ()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsmModule for BuiltinOpParser {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"builtin"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
||||||
|
Ok(ParseOpResult::Parsed(Op::BuiltIn(match keyword {
|
||||||
|
"j" => {
|
||||||
|
let dest = parse_label(args.next())?;
|
||||||
|
BuiltinOp::Jump(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
"fj" => {
|
||||||
|
let dest = parse_label(args.next())?;
|
||||||
|
BuiltinOp::FarJump(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
"call" => {
|
||||||
|
let dest = RoutineName(args.next_string()?);
|
||||||
|
|
||||||
|
let mut call_args = vec![];
|
||||||
|
for t in args {
|
||||||
|
call_args.push(parse_rd(Some(t))?);
|
||||||
|
}
|
||||||
|
BuiltinOp::Call(dest, call_args)
|
||||||
|
}
|
||||||
|
|
||||||
|
"ret" => {
|
||||||
|
let mut ret_vals = vec![];
|
||||||
|
for t in args {
|
||||||
|
ret_vals.push(parse_rd(Some(t))?);
|
||||||
|
}
|
||||||
|
BuiltinOp::Ret(ret_vals)
|
||||||
|
}
|
||||||
|
|
||||||
|
"routine" => {
|
||||||
|
let dest = RoutineName(args.next_string()?);
|
||||||
|
BuiltinOp::Routine(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
"s" => {
|
||||||
|
BuiltinOp::Skip(args.next_rd()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
"sif" => {
|
||||||
|
let cond = parse_cond(&args.next_string()?)?;
|
||||||
|
let offs = args.next_rd()?;
|
||||||
|
BuiltinOp::SkipIf(cond, offs)
|
||||||
|
}
|
||||||
|
|
||||||
|
"jif" => {
|
||||||
|
let cond = parse_cond(&args.next_string()?)?;
|
||||||
|
let dest = parse_label(args.next())?;
|
||||||
|
BuiltinOp::JumpIf(cond, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
"fjif" => {
|
||||||
|
let cond = parse_cond(&args.next_string()?)?;
|
||||||
|
let dest = parse_label(args.next())?;
|
||||||
|
BuiltinOp::FarJumpIf(cond, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
"barrier" => {
|
||||||
|
BuiltinOp::Barrier(match args.next() {
|
||||||
|
None => None,
|
||||||
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
"fault" => {
|
||||||
|
BuiltinOp::Fault(match args.next() {
|
||||||
|
None => None,
|
||||||
|
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
"ld" => {
|
||||||
|
BuiltinOp::Move {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
src: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"far" => {
|
||||||
|
if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() {
|
||||||
|
if let Some(label) = label.strip_prefix(':') {
|
||||||
|
let label = Label::Named(label.to_string());
|
||||||
|
BuiltinOp::FarLabel(label)
|
||||||
|
} else {
|
||||||
|
return Ok(ParseOpResult::Unknown(args));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(ParseOpResult::Unknown(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other => {
|
||||||
|
if let Some(label) = other.strip_prefix(':') {
|
||||||
|
let label = Label::Named(label.to_string());
|
||||||
|
BuiltinOp::Label(label)
|
||||||
|
} else {
|
||||||
|
return Ok(ParseOpResult::Unknown(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,5 +4,6 @@ extern crate log;
|
|||||||
pub use sexp;
|
pub use sexp;
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
|
pub mod builtin;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|
||||||
|
|||||||
@@ -8,24 +8,17 @@ use crate::runtime::run_thread::RunThread;
|
|||||||
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> {
|
||||||
let mut cycles = 1;
|
|
||||||
let mut advance = 1;
|
|
||||||
|
|
||||||
let frame = &mut self.frame;
|
let frame = &mut self.frame;
|
||||||
|
|
||||||
let op = self.program.read(frame.pc);
|
let op = self.program.read(frame.pc);
|
||||||
|
|
||||||
debug!("------------------------");
|
trace!("### {:04} : {:?}", frame.pc.0, op);
|
||||||
debug!("{} | {:?}", frame.pc, op);
|
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
|
||||||
op.execute(&self.program, &mut self.call_stack, frame)?;
|
let rv = op.execute(&self.program, &mut self.call_stack, frame);
|
||||||
|
trace!("-> {:?}", rv);
|
||||||
Ok(EvalRes {
|
rv
|
||||||
cycles,
|
|
||||||
advance,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ impl StackFrame {
|
|||||||
if rn >= REG_COUNT as u8 {
|
if rn >= REG_COUNT as u8 {
|
||||||
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
|
||||||
} else {
|
} else {
|
||||||
debug!("Rd {:?} = {}", rd, self.res[rn as usize]);
|
trace!("Rd {:?} = {}", rd, self.res[rn as usize]);
|
||||||
Ok(self.res[rn as usize])
|
Ok(self.res[rn as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ impl StackFrame {
|
|||||||
if rn >= REG_COUNT as u8 {
|
if rn >= REG_COUNT as u8 {
|
||||||
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
|
||||||
} else {
|
} else {
|
||||||
debug!("Rd {:?} = {}", rd, self.arg[rn as usize]);
|
trace!("Rd {:?} = {}", rd, self.arg[rn as usize]);
|
||||||
Ok(self.arg[rn as usize])
|
Ok(self.arg[rn as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ impl StackFrame {
|
|||||||
if rn >= REG_COUNT as u8 {
|
if rn >= REG_COUNT as u8 {
|
||||||
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
|
||||||
} else {
|
} else {
|
||||||
debug!("Rd {:?} = {}", rd, self.gen[rn as usize]);
|
trace!("Rd {:?} = {}", rd, self.gen[rn as usize]);
|
||||||
Ok(self.gen[rn as usize])
|
Ok(self.gen[rn as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ impl StackFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
|
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
|
||||||
debug!("WR {:?} := {}", wr, val);
|
trace!("WR {:?} := {}", wr, val);
|
||||||
|
|
||||||
match wr.d() {
|
match wr.d() {
|
||||||
DstDisp::ImmediatePtr(_) => {
|
DstDisp::ImmediatePtr(_) => {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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 crate::builtin::defs::BuiltinOp;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
@@ -29,13 +30,13 @@ impl Program {
|
|||||||
fn scan(&mut self) {
|
fn scan(&mut self) {
|
||||||
for (pos, op) in self.ops.iter().enumerate() {
|
for (pos, op) in self.ops.iter().enumerate() {
|
||||||
match op {
|
match op {
|
||||||
Op::FarLabel(name) => {
|
Op::BuiltIn(BuiltinOp::FarLabel(name)) => {
|
||||||
self.far_labels.insert(name.clone(), pos.into());
|
self.far_labels.insert(name.clone(), pos.into());
|
||||||
}
|
}
|
||||||
Op::Routine(name) => {
|
Op::BuiltIn(BuiltinOp::Routine(name)) => {
|
||||||
self.routines.insert(name.clone(), pos.into());
|
self.routines.insert(name.clone(), pos.into());
|
||||||
}
|
}
|
||||||
Op::Barrier(_) => {
|
Op::BuiltIn(BuiltinOp::Barrier(_)) => {
|
||||||
self.barriers.push(pos.into());
|
self.barriers.push(pos.into());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -46,7 +47,7 @@ impl Program {
|
|||||||
/// Read a program instruction at address
|
/// Read a program instruction at address
|
||||||
pub fn read(&self, addr: Addr) -> &Op {
|
pub fn read(&self, addr: Addr) -> &Op {
|
||||||
if addr.0 >= self.ops.len() as u64 {
|
if addr.0 >= self.ops.len() as u64 {
|
||||||
&Op::Nop
|
&Op::BuiltIn(BuiltinOp::Nop)
|
||||||
} else {
|
} else {
|
||||||
&self.ops[addr.0 as usize]
|
&self.ops[addr.0 as usize]
|
||||||
}
|
}
|
||||||
@@ -60,7 +61,7 @@ impl Program {
|
|||||||
|
|
||||||
for b in &self.barriers {
|
for b in &self.barriers {
|
||||||
if *b >= from && *b <= to {
|
if *b >= from && *b <= to {
|
||||||
if let Op::Barrier(msg) = self.read(*b) {
|
if let Op::BuiltIn(BuiltinOp::Barrier(msg)) = self.read(*b) {
|
||||||
return Err(Fault::JumpThroughBarrier {
|
return Err(Fault::JumpThroughBarrier {
|
||||||
msg: msg.clone().unwrap_or("No msg".into())
|
msg: msg.clone().unwrap_or("No msg".into())
|
||||||
});
|
});
|
||||||
@@ -91,10 +92,10 @@ impl Program {
|
|||||||
|
|
||||||
for at in (0..=pc.0).rev() {
|
for at in (0..=pc.0).rev() {
|
||||||
match &self.ops[at as usize] {
|
match &self.ops[at as usize] {
|
||||||
Op::Label(lbl) if lbl == name => {
|
Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => {
|
||||||
return Ok(at.into());
|
return Ok(at.into());
|
||||||
}
|
}
|
||||||
Op::Barrier(_) => {
|
Op::BuiltIn(BuiltinOp::Barrier(_)) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -103,10 +104,10 @@ impl Program {
|
|||||||
|
|
||||||
for at in pc.0..(self.ops.len() as u64) {
|
for at in pc.0..(self.ops.len() as u64) {
|
||||||
match &self.ops[at as usize] {
|
match &self.ops[at as usize] {
|
||||||
Op::Label(lbl) if lbl == name => {
|
Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => {
|
||||||
return Ok(at.into());
|
return Ok(at.into());
|
||||||
}
|
}
|
||||||
Op::Barrier(_) => {
|
Op::BuiltIn(BuiltinOp::Barrier(_)) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl RunThread {
|
|||||||
cycles, advance
|
cycles, advance
|
||||||
}) => {
|
}) => {
|
||||||
std::thread::sleep(CYCLE_TIME * (cycles as u32));
|
std::thread::sleep(CYCLE_TIME * (cycles as u32));
|
||||||
debug!("Step {}; Status = {}", advance, self.frame.status);
|
trace!("Step {}; Status = {}", advance, self.frame.status);
|
||||||
self.frame.pc.advance(advance);
|
self.frame.pc.advance(advance);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use crsn::asm::data::{Rd, Wr};
|
use crsn::asm::data::{Rd, Wr};
|
||||||
use crsn::asm::error::{Error};
|
use crsn::asm::error::Error;
|
||||||
use crsn::asm::instr::op::{AsmModule, ParseOpResult};
|
use crsn::asm::instr::op::{AsmModule, ParseOpResult};
|
||||||
|
use crsn::asm::instr::Op;
|
||||||
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
use crsn::asm::parse::arg_parser::ArgParser;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ArithOpParser {
|
pub struct ArithOpParser {
|
||||||
@@ -26,7 +25,7 @@ impl AsmModule for ArithOpParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpResult, Error> {
|
||||||
Ok(ParseOpResult::Parsed(Box::new(match keyword {
|
Ok(ParseOpResult::Parsed(Op::Ext(Box::new(match keyword {
|
||||||
"cmp" => {
|
"cmp" => {
|
||||||
ArithOp::Compare {
|
ArithOp::Compare {
|
||||||
a: args.next_rd()?,
|
a: args.next_rd()?,
|
||||||
@@ -451,6 +450,6 @@ impl AsmModule for ArithOpParser {
|
|||||||
_other => {
|
_other => {
|
||||||
return Ok(ParseOpResult::Unknown(args));
|
return Ok(ParseOpResult::Unknown(args));
|
||||||
}
|
}
|
||||||
})))
|
}))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,12 +71,6 @@ fn main() {
|
|||||||
|
|
||||||
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
let parsed = crsn::asm::assemble(program, parsers.as_slice()).unwrap();
|
||||||
|
|
||||||
debug!("---");
|
|
||||||
for op in &parsed.ops {
|
|
||||||
debug!("{:?}", op);
|
|
||||||
}
|
|
||||||
debug!("---");
|
|
||||||
|
|
||||||
let thread = RunThread::new(ThreadToken(0), 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