From 34e339b1cade1f11f89c4c3436ed1a35f39441a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 5 Oct 2020 00:32:08 +0200 Subject: [PATCH] add pretty-printer for assembled instructions --- crsn/src/asm/data/mod.rs | 28 +++++++++++++++- crsn/src/asm/data/rd.rs | 14 +++++++- crsn/src/asm/data/wr.rs | 17 ++++++++-- crsn/src/asm/instr/op.rs | 19 +++++++++++ crsn/src/builtin/exec.rs | 71 ++++++++++++++++++++++++++++++++++++++-- crsn/src/module/mod.rs | 7 +++- crsn/src/utils/mod.rs | 20 +++++++++++ crsn_arith/src/exec.rs | 53 +++++++++++++++++++++++++++++- crsn_screen/src/exec.rs | 13 +++++++- crsn_stacks/src/exec.rs | 12 ++++++- launcher/src/main.rs | 5 +-- 11 files changed, 247 insertions(+), 12 deletions(-) diff --git a/crsn/src/asm/data/mod.rs b/crsn/src/asm/data/mod.rs index 079c218..d796dab 100644 --- a/crsn/src/asm/data/mod.rs +++ b/crsn/src/asm/data/mod.rs @@ -8,7 +8,7 @@ pub use rd::RdObj; pub use reg::Register; pub use wr::Wr; -use crate::asm::data::literal::{as_signed, Value}; +use crate::asm::data::literal::{as_signed, is_negative, Value}; use super::error::AsmError; @@ -83,6 +83,22 @@ pub enum RdData { ObjectPtr(Register), } +impl Display for RdData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + RdData::Immediate(v) => { + if is_negative(*v) { + write!(f, "{}", as_signed(*v)) + } else { + write!(f, "{}", *v) + } + } + RdData::Register(r) => write!(f, "{}", r), + RdData::ObjectPtr(r) => write!(f, "@{}", r) + } + } +} + impl TryFrom for RdData { type Error = AsmError; @@ -107,6 +123,16 @@ pub enum WrData { Discard, } +impl Display for WrData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + WrData::Discard => f.write_str("_"), + WrData::Register(r) => write!(f, "{}", r), + WrData::ObjectPtr(r) => write!(f, "@{}", r) + } + } +} + impl From for RdData { fn from(s: WrData) -> Self { match s { diff --git a/crsn/src/asm/data/rd.rs b/crsn/src/asm/data/rd.rs index 8cd1568..435c267 100644 --- a/crsn/src/asm/data/rd.rs +++ b/crsn/src/asm/data/rd.rs @@ -1,4 +1,4 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Formatter, Display}; use std::fmt; use crate::asm::data::{DataDisp, Mask, RdData, Register}; @@ -24,6 +24,12 @@ impl Rd { } } +impl Display for Rd { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) // TODO mask, when implemented + } +} + impl Debug for Rd { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Rd(")?; @@ -50,6 +56,12 @@ impl RdObj { } } +impl Display for RdObj { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "@{}", self.0) + } +} + impl Debug for RdObj { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Obj(")?; diff --git a/crsn/src/asm/data/wr.rs b/crsn/src/asm/data/wr.rs index 2b92530..75509d6 100644 --- a/crsn/src/asm/data/wr.rs +++ b/crsn/src/asm/data/wr.rs @@ -1,4 +1,4 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Formatter, Display}; use std::fmt; use crate::asm::data::{DataDisp, Mask, Rd, WrData}; @@ -17,13 +17,26 @@ impl Wr { pub fn mask(self) -> Mask { self.1 } - pub fn as_rd(&self) -> Rd { + pub fn as_rd(self) -> Rd { Rd(self.0.into(), self.1) } pub fn discard() -> Wr { Wr(WrData::Discard, Mask::default()) } + + pub fn is_discard(self) -> bool { + match self.0 { + WrData::Discard => true, + _ => false + } + } +} + +impl Display for Wr { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) // TODO mask, when implemented + } } impl Debug for Wr { diff --git a/crsn/src/asm/instr/op.rs b/crsn/src/asm/instr/op.rs index f6e7f6d..0c6e982 100644 --- a/crsn/src/asm/instr/op.rs +++ b/crsn/src/asm/instr/op.rs @@ -5,6 +5,7 @@ use crate::builtin::defs::BuiltinOp; use crate::module::{EvalRes, OpTrait}; use crate::runtime::fault::Fault; use crate::runtime::run_thread::{info::ThreadInfo, state::RunState}; +use sexp::{Sexp, Atom}; /// A higher level simple opration #[derive(Debug)] @@ -40,4 +41,22 @@ impl OpTrait for Op { } } } + + fn to_sexp(&self) -> Sexp { + let mut se = match &self.kind { + OpKind::BuiltIn(op) => op.to_sexp(), + OpKind::Ext(op) => op.to_sexp() + }; + + if let Some(cond) = self.cond { + if let Sexp::List(items) = &mut se { + if let Some(Sexp::Atom(Atom::S(s))) = &mut items.get_mut(0) { + s.push('.'); + s.push_str(&cond.to_string()); + } + } + } + + se + } } diff --git a/crsn/src/builtin/exec.rs b/crsn/src/builtin/exec.rs index 485805c..f65f8a6 100644 --- a/crsn/src/builtin/exec.rs +++ b/crsn/src/builtin/exec.rs @@ -8,6 +8,11 @@ use crate::module::{EvalRes, OpTrait}; use crate::runtime::fault::Fault; use crate::runtime::frame::StackFrame; use crate::runtime::run_thread::{state::RunState, ThreadInfo}; +use sexp::Sexp; +use sexp::Atom; +use std::str::FromStr; +use std::fmt::Display; +use crate::utils::A; impl OpTrait for BuiltinOp { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { @@ -137,6 +142,68 @@ impl OpTrait for BuiltinOp { Ok(res) } - // -} + fn to_sexp(&self) -> Sexp { + match self { + BuiltinOp::Nop => sexp::list(&[A("nop")]), + BuiltinOp::Halt => sexp::list(&[A("halt")]), + BuiltinOp::Sleep { micros } => sexp::list(&[A("sleep"), A(micros)]), + BuiltinOp::Label(label) => sexp::list(&[A(label)]), + BuiltinOp::Jump(label) => sexp::list(&[A("j"), A(label)]), + BuiltinOp::FarLabel(label) => sexp::list(&[A("far"), A(label)]), + BuiltinOp::FarJump(label) => sexp::list(&[A("fj"), A(label)]), + BuiltinOp::Call(name, args) => { + if args.is_empty() { + sexp::list(&[A("call"), A(name)]) + } else { + let mut inner = vec![A("call"), A(&name.name)]; + inner.extend(args.iter().map(A)); + sexp::list(&inner) + } + }, + BuiltinOp::Ret(values) => { + if values.is_empty() { + sexp::list(&[A("ret")]) + } else { + let mut inner = vec![A("ret")]; + inner.extend(values.iter().map(A)); + sexp::list(&inner) + } + } + BuiltinOp::Routine(name) => sexp::list(&[A("routine"), A(name)]), + BuiltinOp::Skip(n) => sexp::list(&[A("skip"), A(n)]), + BuiltinOp::Barrier { kind, msg } => { + let mut inner = vec![]; + match kind { + Barrier::Open(label) => { + inner.push(A("barrier-open")); + inner.push(A(label)); + } + Barrier::Close(label) => { + inner.push(A("barrier-close")); + inner.push(A(label)); + } + Barrier::Standalone => { + inner.push(A("barrier")); + + if let Some(msg) = msg { + inner.push(A(msg)); + } + } + } + sexp::list(&inner) + } + BuiltinOp::Fault(msg) => { + if let Some(msg) = msg { + sexp::list(&[A("fault"), A(msg)]) + } else { + sexp::list(&[A("fault")]) + } + } + BuiltinOp::Drop(obj) => sexp::list(&[A("drop"), A(obj)]), + BuiltinOp::Move { dst, src } => sexp::list(&[A("mov"), A(dst), A(src)]), + BuiltinOp::StoreStatus { dst } => sexp::list(&[A("sst"), A(dst)]), + BuiltinOp::LoadStatus { src } => sexp::list(&[A("lst"), A(src)]) + } + } +} diff --git a/crsn/src/module/mod.rs b/crsn/src/module/mod.rs index 9e894e1..18b4edb 100644 --- a/crsn/src/module/mod.rs +++ b/crsn/src/module/mod.rs @@ -1,6 +1,6 @@ #![allow(unused_variables)] -use std::fmt::Debug; +use std::fmt::{Debug, Display, Formatter}; pub use eval_res::EvalRes; @@ -13,6 +13,8 @@ use crate::asm::parse::arg_parser::TokenParser; use crate::runtime::fault::Fault; use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::ThreadInfo; +use sexp::Sexp; +use std::fmt; mod eval_res; @@ -35,6 +37,9 @@ impl<'a> ParseRes<'a, OpKind> { pub trait OpTrait: Debug + Send + Sync + 'static { fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result; + + /// Turn into an S-expression that produces this instruction when parsed + fn to_sexp(&self) -> Sexp; } pub trait CrsnExtension: Debug + Send + Sync + 'static { diff --git a/crsn/src/utils/mod.rs b/crsn/src/utils/mod.rs index 7f10c80..d2e94f1 100644 --- a/crsn/src/utils/mod.rs +++ b/crsn/src/utils/mod.rs @@ -1,4 +1,24 @@ pub use option_ext::UncheckedOptionExt; +use std::fmt::Display; +use sexp::{Sexp, Atom}; +use std::str::FromStr; mod option_ext; +/// Convert a string token to Sexp +#[allow(non_snake_case)] +pub fn A(s: impl Display) -> Sexp { + let s = s.to_string(); + + let x: Result = FromStr::from_str(&s); + if let Ok(x) = x { + return Sexp::Atom(Atom::I(x)); + } + + let y: Result = FromStr::from_str(&s); + if let Ok(y) = y { + return Sexp::Atom(Atom::F(y)); + } + + Sexp::Atom(Atom::S(s)) +} diff --git a/crsn_arith/src/exec.rs b/crsn_arith/src/exec.rs index 30d61f2..7118d91 100644 --- a/crsn_arith/src/exec.rs +++ b/crsn_arith/src/exec.rs @@ -8,6 +8,10 @@ use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::defs::ArithOp; +use crsn::sexp::Sexp; +use crsn::sexp; +use crsn::utils::A; +use crsn::asm::data::{Rd, Wr}; impl OpTrait for ArithOp { fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result { @@ -191,6 +195,53 @@ impl OpTrait for ArithOp { Ok(eres) } - // + + fn to_sexp(&self) -> Sexp { + match self { + ArithOp::Add { dst, a, b } => to_sexp_2_or_3("add", dst, a, b), + ArithOp::Test { a } => sexp::list(&[A("test"), A(a)]), + ArithOp::Compare { a, b } => sexp::list(&[A("cmp"), A(a), A(b)]), + ArithOp::Sub { dst, a, b } => to_sexp_2_or_3("sub", dst, a, b), + ArithOp::Mul { dst, a, b } => to_sexp_2_or_3("mul", dst, a, b), + ArithOp::Div { dst, rem, a, div } => { + if rem.is_discard() { + if &dst.as_rd() == a { + sexp::list(&[A("div"), A(dst), A(div)]) + } else { + sexp::list(&[A("div"), A(dst), A(a), A(div)]) + } + } else { + if &dst.as_rd() == a { + sexp::list(&[A("divr"), A(dst), A(rem), A(div)]) + } else { + sexp::list(&[A("divr"), A(dst), A(rem), A(a), A(div)]) + } + } + } + ArithOp::Mod { dst, a, div } => to_sexp_2_or_3("mod", dst, a, div), + ArithOp::And { dst, a, b } => to_sexp_2_or_3("and", dst, a, b), + ArithOp::Or { dst, a, b } => to_sexp_2_or_3("or", dst, a, b), + ArithOp::Xor { dst, a, b } => to_sexp_2_or_3("xor", dst, a, b), + ArithOp::Cpl { dst, a } => { + if &dst.as_rd() == a { + sexp::list(&[A("cpl"), A(dst)]) + } else { + sexp::list(&[A("cpl"), A(dst), A(a)]) + } + } + ArithOp::Rol { dst, a, n } => to_sexp_2_or_3("rol", dst, a, n), + ArithOp::Ror { dst, a, n } => to_sexp_2_or_3("ror", dst, a, n), + ArithOp::Lsl { dst, a, n } => to_sexp_2_or_3("lsl", dst, a, n), + ArithOp::Lsr { dst, a, n } => to_sexp_2_or_3("lsr", dst, a, n), + ArithOp::Asr { dst, a, n } => to_sexp_2_or_3("asr", dst, a, n), + } + } } +fn to_sexp_2_or_3(name: &str, dst : &Wr, a: &Rd, b: &Rd) -> Sexp { + if &dst.as_rd() == a { + sexp::list(&[A(name), A(dst), A(b)]) + } else { + sexp::list(&[A(name), A(dst), A(a), A(b)]) + } +} diff --git a/crsn_screen/src/exec.rs b/crsn_screen/src/exec.rs index b8c3f86..b567540 100644 --- a/crsn_screen/src/exec.rs +++ b/crsn_screen/src/exec.rs @@ -10,6 +10,9 @@ use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::defs::ScreenOp; +use crsn::sexp::Sexp; +use crsn::sexp; +use crsn::utils::A; #[derive(Debug)] struct Opts { @@ -123,7 +126,15 @@ impl OpTrait for ScreenOp { Ok(eres) } - // + + fn to_sexp(&self) -> Sexp { + match self { + ScreenOp::SetOpt { opt, val } => sexp::list(&[A("sc-opt"), A(opt), A(val)]), + ScreenOp::ScreenInit { width, height } => sexp::list(&[A("sc-init"), A(width), A(height)]), + ScreenOp::SetPixel { x, y, color } => sexp::list(&[A("sc-px"), A(x), A(y), A(color)]), + ScreenOp::Blit { force } => sexp::list(&[A("sc-blit"), A(force)]) + } + } } fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> { diff --git a/crsn_stacks/src/exec.rs b/crsn_stacks/src/exec.rs index b96ee1f..b574306 100644 --- a/crsn_stacks/src/exec.rs +++ b/crsn_stacks/src/exec.rs @@ -7,6 +7,9 @@ use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::defs::StackOp; +use crsn::sexp::Sexp; +use crsn::sexp; +use crsn::utils::A; #[derive(Debug, Default)] struct Stacks { @@ -64,7 +67,14 @@ impl OpTrait for StackOp { Ok(eres) } - // + + fn to_sexp(&self) -> Sexp { + match self { + StackOp::NewStack { dst } => sexp::list(&[A("stack"), A(dst)]), + StackOp::Push { obj, src } => sexp::list(&[A("push"), A(obj), A(src)]), + StackOp::Pop { dst, obj } => sexp::list(&[A("pop"), A(dst), A(obj)]), + } + } } pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result, Fault> { diff --git a/launcher/src/main.rs b/launcher/src/main.rs index a996299..7beee45 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -14,6 +14,7 @@ use crsn::runtime::run_thread::{RunThread, ThreadToken}; use crsn_arith::ArithOps; use crsn_screen::ScreenOps; use crsn_stacks::StackOps; +use crsn::module::OpTrait; mod read_file; mod serde_duration_millis; @@ -130,13 +131,13 @@ fn main() -> anyhow::Result<()> { if config.asm_only { for (n, op) in parsed.ops.iter().enumerate() { - println!("{:04} : {:?}", n, op); + println!("{:04} : {}", n, op.to_sexp()); } return Ok(()); } else { trace!("--- Compiled program ---"); for (n, op) in parsed.ops.iter().enumerate() { - trace!("{:04} : {:?}", n, op); + trace!("{:04} : {}", n, op.to_sexp()); } trace!("------------------------"); }