add pretty-printer for assembled instructions

pull/21/head
Ondřej Hruška 4 years ago
parent 986f3be6a2
commit 34e339b1ca
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 28
      crsn/src/asm/data/mod.rs
  2. 14
      crsn/src/asm/data/rd.rs
  3. 17
      crsn/src/asm/data/wr.rs
  4. 19
      crsn/src/asm/instr/op.rs
  5. 71
      crsn/src/builtin/exec.rs
  6. 7
      crsn/src/module/mod.rs
  7. 20
      crsn/src/utils/mod.rs
  8. 53
      crsn_arith/src/exec.rs
  9. 13
      crsn_screen/src/exec.rs
  10. 12
      crsn_stacks/src/exec.rs
  11. 5
      launcher/src/main.rs

@ -8,7 +8,7 @@ pub use rd::RdObj;
pub use reg::Register; pub use reg::Register;
pub use wr::Wr; 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; use super::error::AsmError;
@ -83,6 +83,22 @@ pub enum RdData {
ObjectPtr(Register), 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<DataDisp> for RdData { impl TryFrom<DataDisp> for RdData {
type Error = AsmError; type Error = AsmError;
@ -107,6 +123,16 @@ pub enum WrData {
Discard, 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<WrData> for RdData { impl From<WrData> for RdData {
fn from(s: WrData) -> Self { fn from(s: WrData) -> Self {
match s { match s {

@ -1,4 +1,4 @@
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter, Display};
use std::fmt; use std::fmt;
use crate::asm::data::{DataDisp, Mask, RdData, Register}; 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 { impl Debug for Rd {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Rd(")?; 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 { impl Debug for RdObj {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Obj(")?; write!(f, "Obj(")?;

@ -1,4 +1,4 @@
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter, Display};
use std::fmt; use std::fmt;
use crate::asm::data::{DataDisp, Mask, Rd, WrData}; use crate::asm::data::{DataDisp, Mask, Rd, WrData};
@ -17,13 +17,26 @@ impl Wr {
pub fn mask(self) -> Mask { pub fn mask(self) -> Mask {
self.1 self.1
} }
pub fn as_rd(&self) -> Rd { pub fn as_rd(self) -> Rd {
Rd(self.0.into(), self.1) Rd(self.0.into(), self.1)
} }
pub fn discard() -> Wr { pub fn discard() -> Wr {
Wr(WrData::Discard, Mask::default()) 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 { impl Debug for Wr {

@ -5,6 +5,7 @@ use crate::builtin::defs::BuiltinOp;
use crate::module::{EvalRes, OpTrait}; use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::run_thread::{info::ThreadInfo, state::RunState}; use crate::runtime::run_thread::{info::ThreadInfo, state::RunState};
use sexp::{Sexp, Atom};
/// A higher level simple opration /// A higher level simple opration
#[derive(Debug)] #[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
}
} }

@ -8,6 +8,11 @@ use crate::module::{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::{state::RunState, ThreadInfo}; 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 { impl OpTrait for BuiltinOp {
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
@ -137,6 +142,68 @@ impl OpTrait for BuiltinOp {
Ok(res) 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)])
}
}
}

@ -1,6 +1,6 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use std::fmt::Debug; use std::fmt::{Debug, Display, Formatter};
pub use eval_res::EvalRes; pub use eval_res::EvalRes;
@ -13,6 +13,8 @@ use crate::asm::parse::arg_parser::TokenParser;
use crate::runtime::fault::Fault; use crate::runtime::fault::Fault;
use crate::runtime::run_thread::state::RunState; use crate::runtime::run_thread::state::RunState;
use crate::runtime::run_thread::ThreadInfo; use crate::runtime::run_thread::ThreadInfo;
use sexp::Sexp;
use std::fmt;
mod eval_res; mod eval_res;
@ -35,6 +37,9 @@ impl<'a> ParseRes<'a, OpKind> {
pub trait OpTrait: Debug + Send + Sync + 'static { pub trait OpTrait: Debug + Send + Sync + 'static {
fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault>; fn execute(&self, ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault>;
/// Turn into an S-expression that produces this instruction when parsed
fn to_sexp(&self) -> Sexp;
} }
pub trait CrsnExtension: Debug + Send + Sync + 'static { pub trait CrsnExtension: Debug + Send + Sync + 'static {

@ -1,4 +1,24 @@
pub use option_ext::UncheckedOptionExt; pub use option_ext::UncheckedOptionExt;
use std::fmt::Display;
use sexp::{Sexp, Atom};
use std::str::FromStr;
mod option_ext; 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<i64, _> = FromStr::from_str(&s);
if let Ok(x) = x {
return Sexp::Atom(Atom::I(x));
}
let y: Result<f64, _> = FromStr::from_str(&s);
if let Ok(y) = y {
return Sexp::Atom(Atom::F(y));
}
Sexp::Atom(Atom::S(s))
}

@ -8,6 +8,10 @@ use crsn::runtime::fault::Fault;
use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::defs::ArithOp; 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 { impl OpTrait for ArithOp {
fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> { fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
@ -191,6 +195,53 @@ impl OpTrait for ArithOp {
Ok(eres) 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)])
}
}

@ -10,6 +10,9 @@ use crsn::runtime::fault::Fault;
use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::defs::ScreenOp; use crate::defs::ScreenOp;
use crsn::sexp::Sexp;
use crsn::sexp;
use crsn::utils::A;
#[derive(Debug)] #[derive(Debug)]
struct Opts { struct Opts {
@ -123,7 +126,15 @@ impl OpTrait for ScreenOp {
Ok(eres) 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> { fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> {

@ -7,6 +7,9 @@ use crsn::runtime::fault::Fault;
use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::defs::StackOp; use crate::defs::StackOp;
use crsn::sexp::Sexp;
use crsn::sexp;
use crsn::utils::A;
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct Stacks { struct Stacks {
@ -64,7 +67,14 @@ impl OpTrait for StackOp {
Ok(eres) 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<Option<()>, Fault> { pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {

@ -14,6 +14,7 @@ use crsn::runtime::run_thread::{RunThread, ThreadToken};
use crsn_arith::ArithOps; use crsn_arith::ArithOps;
use crsn_screen::ScreenOps; use crsn_screen::ScreenOps;
use crsn_stacks::StackOps; use crsn_stacks::StackOps;
use crsn::module::OpTrait;
mod read_file; mod read_file;
mod serde_duration_millis; mod serde_duration_millis;
@ -130,13 +131,13 @@ fn main() -> anyhow::Result<()> {
if config.asm_only { if config.asm_only {
for (n, op) in parsed.ops.iter().enumerate() { for (n, op) in parsed.ops.iter().enumerate() {
println!("{:04} : {:?}", n, op); println!("{:04} : {}", n, op.to_sexp());
} }
return Ok(()); return Ok(());
} else { } else {
trace!("--- Compiled program ---"); trace!("--- Compiled program ---");
for (n, op) in parsed.ops.iter().enumerate() { for (n, op) in parsed.ops.iter().enumerate() {
trace!("{:04} : {:?}", n, op); trace!("{:04} : {}", n, op.to_sexp());
} }
trace!("------------------------"); trace!("------------------------");
} }

Loading…
Cancel
Save