forked from MightyPork/crsn
add pretty-printer for assembled instructions
This commit is contained in:
@@ -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<DataDisp> 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<WrData> for RdData {
|
||||
fn from(s: WrData) -> Self {
|
||||
match s {
|
||||
|
||||
+13
-1
@@ -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(")?;
|
||||
|
||||
+15
-2
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<EvalRes, Fault> {
|
||||
@@ -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)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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 {
|
||||
|
||||
@@ -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<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))
|
||||
}
|
||||
|
||||
+52
-1
@@ -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<EvalRes, Fault> {
|
||||
@@ -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)])
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -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> {
|
||||
|
||||
+11
-1
@@ -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<Option<()>, Fault> {
|
||||
|
||||
@@ -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!("------------------------");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user