Added InstDisplay for better instruction formatting.

This commit is contained in:
Filipe Rodrigues 2021-04-26 14:24:43 +01:00
parent 3c7bed14e6
commit d0bd0d22b3
19 changed files with 507 additions and 34 deletions

View File

@ -15,7 +15,7 @@ pub mod target;
// Exports
pub use directive::Directive;
pub use error::DecodeError;
pub use fmt::{InstFmt, InstTargetFmt};
pub use fmt::{DisplayCtx, InstDisplay, InstFmt, InstFmtArg, InstTargetFmt};
pub use iter::ParseIter;
pub use parse::{Parsable, ParseCtx, ParseError};
pub use reg::Register;

View File

@ -17,8 +17,12 @@ pub mod store;
pub mod sys;
// Imports
use super::{parse::LineArg, InstSize, ParseCtx, ParseError, Register};
use super::{
parse::{LineArg, Parsable},
DisplayCtx, InstDisplay, InstFmtArg, InstSize, ParseCtx, ParseError, Register,
};
use crate::inst::InstFmt;
use std::fmt;
/// All basic instructions
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -55,7 +59,6 @@ pub enum Inst {
Co(co::Inst),
}
impl Decode for Inst {
#[rustfmt::skip]
fn decode(raw: u32) -> Option<Self> {
@ -73,7 +76,6 @@ impl Decode for Inst {
}
}
/// Encode error
#[derive(PartialEq, Clone, Debug, thiserror::Error)]
pub enum EncodeError {
@ -106,7 +108,7 @@ impl TryEncode for Inst {
}
}
impl super::parse::Parsable for Inst {
impl Parsable for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[LineArg], ctx: &Ctx) -> Result<Self, ParseError> {
#[rustfmt::skip]
let parsers: &[&dyn Fn() -> Result<Self, ParseError>] = &[
@ -136,6 +138,45 @@ impl super::parse::Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = impl Iterator<Item = InstFmtArg>;
type Mnemonic = impl fmt::Display;
#[auto_enums::auto_enum(Display)]
#[rustfmt::skip]
fn mnemonic<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Mnemonic {
match self {
Inst::Alu (inst) => inst.mnemonic(ctx),
Inst::Cond (inst) => inst.mnemonic(ctx),
Inst::Jmp (inst) => inst.mnemonic(ctx),
Inst::Load (inst) => inst.mnemonic(ctx),
Inst::Lui (inst) => inst.mnemonic(ctx),
Inst::Mult (inst) => inst.mnemonic(ctx),
Inst::Shift(inst) => inst.mnemonic(ctx),
Inst::Store(inst) => inst.mnemonic(ctx),
Inst::Sys (inst) => inst.mnemonic(ctx),
Inst::Co (inst) => inst.mnemonic(ctx),
}
}
#[auto_enums::auto_enum(Iterator)]
#[rustfmt::skip]
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
match self {
Inst::Alu (inst) => inst.args(ctx),
Inst::Cond (inst) => inst.args(ctx),
Inst::Jmp (inst) => inst.args(ctx),
Inst::Load (inst) => inst.args(ctx),
Inst::Lui (inst) => inst.args(ctx),
Inst::Mult (inst) => inst.args(ctx),
Inst::Shift(inst) => inst.args(ctx),
Inst::Store(inst) => inst.args(ctx),
Inst::Sys (inst) => inst.args(ctx),
Inst::Co (inst) => inst.args(ctx),
}
}
}
impl ModifiesReg for Inst {
#[rustfmt::skip]
fn modifies_reg(&self, reg: Register) -> bool {

View File

@ -9,7 +9,7 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError,
};
/// Alu register instructions
@ -49,6 +49,28 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl Iterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Mnemonic {
match self {
Inst::Imm(inst) => inst.mnemonic(ctx),
Inst::Reg(inst) => inst.mnemonic(ctx),
}
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
match self {
Inst::Imm(inst) => inst.args(ctx).into_iter(),
Inst::Reg(inst) => inst.args(ctx).into_iter(),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {

View File

@ -4,11 +4,11 @@
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use dcb_util::SignedHex;
use int_conv::{Signed, Truncated, ZeroExtended};
use std::{convert::TryInto, fmt};
use std::{array, convert::TryInto, fmt};
/// Instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -50,9 +50,18 @@ impl Kind {
}
}
/// Returns the value of this kind as a `i64`
#[must_use]
pub fn value(self) -> i64 {
match self {
Kind::Add(value) | Kind::AddUnsigned(value) | Kind::SetLessThan(value) => i64::from(value),
Kind::SetLessThanUnsigned(value) | Kind::And(value) | Kind::Or(value) | Kind::Xor(value) => i64::from(value),
}
}
/// Returns a displayable with the value of this kind
#[must_use]
pub fn value_fmt(self) -> impl fmt::Display {
fn value_fmt(self) -> impl fmt::Display {
dcb_util::DisplayWrapper::new(move |f| match self {
// Signed
Self::Add(rhs) | Self::AddUnsigned(rhs) | Self::SetLessThan(rhs) => write!(f, "{:#}", SignedHex(rhs)),
@ -152,6 +161,29 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl IntoIterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { dst, lhs, kind } = self;
let value = kind.value();
// If we're not `slti[u]` and if `$dst` and `$lhs` are the same,
// only return one of them
match !matches!(kind, Kind::SetLessThan(_) | Kind::SetLessThanUnsigned(_)) && dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(value)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::literal(value)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { dst, lhs, kind } = self;

View File

@ -4,8 +4,9 @@
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::array;
/// Alu register instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -160,6 +161,28 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl IntoIterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { dst, lhs, rhs, kind } = self;
// If we're not `slt[u]` and if `$dst` and `$lhs` are the same,
// only return one of them
match !matches!(kind, Kind::SetLessThan | Kind::SetLessThanUnsigned) && dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@ -5,11 +5,11 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use dcb_util::SignedHex;
use int_conv::{Signed, Truncated, ZeroExtended};
use std::convert::TryInto;
use std::{array, convert::TryInto, fmt};
/// Co-processor register kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -238,9 +238,52 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = impl Iterator<Item = InstFmtArg>;
type Mnemonic = impl fmt::Display;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
/// Wrapper necessary for `impl Trait` to work without using `Ctx`.
fn wrapper(n: u32, kind: Kind) -> impl fmt::Display {
dcb_util::DisplayWrapper::new(move |f| match kind {
Kind::CopN { .. } => write!(f, "cop{n}"),
Kind::MoveFrom { kind, .. } => match kind {
RegisterKind::Control => write!(f, "cfc{n}"),
RegisterKind::Data => write!(f, "mfc{n}"),
},
Kind::MoveTo { kind, .. } => match kind {
RegisterKind::Data => write!(f, "mtc{n}"),
RegisterKind::Control => write!(f, "ctc{n}"),
},
Kind::Branch { on, .. } => match on {
true => write!(f, "bc{n}f"),
false => write!(f, "bc{n}t"),
},
Kind::Load { .. } => write!(f, "lwc{n}"),
Kind::Store { .. } => write!(f, "swc{n}"),
})
}
wrapper(self.n, self.kind)
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { kind, .. } = self;
match kind {
Kind::CopN { imm } => array::IntoIter::new([InstFmtArg::literal(imm)]),
Kind::MoveFrom { dst, src, .. } => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(src)]),
Kind::MoveTo { dst, src, .. } => array::IntoIter::new([InstFmtArg::Register(src), InstFmtArg::literal(dst)]),
Kind::Branch { offset, .. } => array::IntoIter::new([InstFmtArg::literal(offset)]),
Kind::Load { dst, src, offset } => array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)]),
Kind::Store { dst, src, offset } => array::IntoIter::new([InstFmtArg::literal(dst), InstFmtArg::register_offset(src, offset)]),
}
}
}
impl InstFmt for Inst {
#[rustfmt::skip]
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fn fmt(&self, _pos: crate::Pos, f: &mut fmt::Formatter) -> fmt::Result {
let Self { n, kind } = self;
match kind {
Kind::CopN { imm } => write!(f, "cop{n} {imm:#x}"),

View File

@ -6,12 +6,12 @@ use crate::{
inst::{
basic::{Decode, Encode},
parse::LineArg,
InstTarget, InstTargetFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmtArg, InstTarget, InstTargetFmt, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{SignExtended, Signed, Truncated, ZeroExtended};
use std::{convert::TryInto, fmt};
use std::{array, convert::TryInto, fmt};
/// Instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -186,6 +186,59 @@ impl Parsable for Inst {
}
}
/// Variants:
/// `beq $zr, $zr, offset` => `b offset`
/// `beq $arg, $zr, offset` => `beqz $arg, offset`
/// `bne $arg, $zr, offset` => `bnez $arg, offset`
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl Iterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
match self.kind {
Kind::Equal(Register::Zr) => match self.arg {
Register::Zr => "b",
_ => "beqz",
},
Kind::Equal(_) => "beq",
Kind::NotEqual(Register::Zr) => "bnez",
Kind::NotEqual(_) => "bne",
Kind::LessOrEqualZero => "blez",
Kind::GreaterThanZero => "bgtz",
Kind::LessThanZero => "bltz",
Kind::GreaterOrEqualZero => "bgez",
Kind::LessThanZeroLink => "bltzal",
Kind::GreaterOrEqualZeroLink => "bgezal",
}
}
#[auto_enums::auto_enum(Iterator)]
#[rustfmt::skip]
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
use InstFmtArg::Register as register;
let &Self { arg, offset, kind } = self;
let target = Self::target_of(offset, ctx.cur_pos());
match (arg, kind) {
(Register::Zr, Kind::Equal (Register::Zr)) => array::IntoIter::new([ InstFmtArg::Target(target)]),
(_ , Kind::Equal (Register::Zr)) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
(_ , Kind::Equal (reg) ) => array::IntoIter::new([register(arg), register(reg), InstFmtArg::Target(target)]),
(_ , Kind::NotEqual(Register::Zr)) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
(_ , Kind::NotEqual(reg) ) => array::IntoIter::new([register(arg), register(reg), InstFmtArg::Target(target)]),
(
_,
Kind::LessOrEqualZero |
Kind::GreaterThanZero |
Kind::LessThanZero |
Kind::GreaterOrEqualZero |
Kind::LessThanZeroLink |
Kind::GreaterOrEqualZeroLink,
) => array::IntoIter::new([register(arg), InstFmtArg::Target(target)]),
}
}
}
impl InstTarget for Inst {
fn target(&self, pos: Pos) -> Pos {
Self::target_of(self.offset, pos)

View File

@ -9,7 +9,7 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
/// Jmp register instructions
@ -49,6 +49,28 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl Iterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Mnemonic {
match self {
Inst::Imm(inst) => inst.mnemonic(ctx),
Inst::Reg(inst) => inst.mnemonic(ctx),
}
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
match self {
Inst::Imm(inst) => inst.args(ctx),
Inst::Reg(inst) => inst.args(ctx).into_iter(),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {

View File

@ -5,10 +5,11 @@ use crate::{
inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
InstTarget, InstTargetFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmtArg, InstTarget, InstTargetFmt, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use std::array;
/// Jmp immediate instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -109,6 +110,20 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = array::IntoIter<InstFmtArg, 1>;
type Mnemonic = &'static str;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
array::IntoIter::new([InstFmtArg::Target(Self::target_of(self.imm, ctx.cur_pos()))])
}
}
impl InstTarget for Inst {
fn target(&self, pos: Pos) -> Pos {
Self::target_of(self.imm, pos)

View File

@ -4,8 +4,9 @@
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::array;
/// Jmp register instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -92,6 +93,27 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl IntoIterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { target, kind } = self;
match kind {
// If linking with `$ra`, don't output it
Kind::Jump | Kind::JumpLink(Register::Ra) => array::IntoIter::new([InstFmtArg::Register(target)]),
Kind::JumpLink(reg) => array::IntoIter::new([InstFmtArg::Register(target), InstFmtArg::Register(reg)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@ -5,11 +5,11 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use dcb_util::SignedHex;
use int_conv::{Signed, Truncated, ZeroExtended};
use std::convert::TryInto;
use std::{array, convert::TryInto};
/// Instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -140,6 +140,21 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = array::IntoIter<InstFmtArg, 2>;
type Mnemonic = &'static str;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { value, addr, offset, .. } = self;
array::IntoIter::new([InstFmtArg::Register(value), InstFmtArg::register_offset(addr, offset)])
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { addr, value, offset, kind } = self;

View File

@ -5,10 +5,10 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use std::convert::TryInto;
use std::{array, convert::TryInto};
/// Load instructions
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -62,6 +62,21 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = array::IntoIter<InstFmtArg, 2>;
type Mnemonic = &'static str;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
"lui"
}
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { dst, value } = self;
array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(value)])
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { dst, value } = self;

View File

@ -5,8 +5,9 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::array;
/// Operation kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -205,9 +206,27 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl Iterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
Self::mnemonic(*self)
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
match *self {
Self::Mult { lhs, rhs, .. } => array::IntoIter::new([InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
Self::MoveFrom { dst: arg, .. } | Self::MoveTo { src: arg, .. } => array::IntoIter::new([InstFmtArg::Register(arg)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mnemonic = self.mnemonic();
let mnemonic = Self::mnemonic(*self);
match self {
Self::Mult { lhs, rhs, .. } => write!(f, "{mnemonic} {lhs}, {rhs}"),
Self::MoveFrom { dst: arg, .. } | Self::MoveTo { src: arg, .. } => write!(f, "{mnemonic} {arg}"),

View File

@ -8,7 +8,7 @@ pub mod reg;
use crate::inst::{
basic::{Decode, Encode, ModifiesReg, TryEncode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
/// Alu register instructions
@ -58,6 +58,27 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl Iterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Mnemonic {
match self {
Inst::Imm(inst) => inst.mnemonic(ctx),
Inst::Reg(inst) => inst.mnemonic(ctx),
}
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args {
match self {
Inst::Imm(inst) => inst.args(ctx).into_iter(),
Inst::Reg(inst) => inst.args(ctx).into_iter(),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {

View File

@ -4,10 +4,10 @@
use crate::inst::{
basic::{Decode, ModifiesReg, TryEncode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use std::convert::TryInto;
use std::{array, convert::TryInto};
/// Shift immediate instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -128,6 +128,27 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl IntoIterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { dst, lhs, rhs, .. } = self;
// If `$dst` and `$lhs` are the same, only print one of them
match dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::literal(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::literal(rhs)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { dst, lhs, rhs, kind } = self;

View File

@ -4,8 +4,9 @@
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::array;
/// Shift register instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -108,6 +109,27 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Mnemonic = &'static str;
type Args = impl IntoIterator<Item = InstFmtArg>;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
#[auto_enums::auto_enum(Iterator)]
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { dst, lhs, rhs, .. } = self;
// If `$dst` and `$lhs` are the same, only print one of them
match dst == lhs {
true => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(rhs)]),
false => array::IntoIter::new([InstFmtArg::Register(dst), InstFmtArg::Register(lhs), InstFmtArg::Register(rhs)]),
}
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { dst, lhs, rhs, kind } = self;

View File

@ -5,11 +5,11 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use dcb_util::SignedHex;
use int_conv::{Signed, Truncated, ZeroExtended};
use std::convert::TryInto;
use std::{array, convert::TryInto};
/// Store instruction kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -127,6 +127,21 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = array::IntoIter<InstFmtArg, 2>;
type Mnemonic = &'static str;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
let &Self { value, addr, offset, .. } = self;
array::IntoIter::new([InstFmtArg::Register(value), InstFmtArg::register_offset(addr, offset)])
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self { addr, value, offset, kind } = self;

View File

@ -5,9 +5,9 @@ use super::ModifiesReg;
use crate::inst::{
basic::{Decode, TryEncode},
parse::LineArg,
InstFmt, Parsable, ParseCtx, ParseError, Register,
DisplayCtx, InstDisplay, InstFmt, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use std::convert::TryInto;
use std::{array, convert::TryInto};
/// Sys instruction func
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@ -86,7 +86,6 @@ impl TryEncode for Inst {
}
}
impl Parsable for Inst {
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[LineArg], _ctx: &Ctx) -> Result<Self, ParseError> {
let kind = match mnemonic {
@ -104,6 +103,18 @@ impl Parsable for Inst {
}
}
impl InstDisplay for Inst {
type Args = array::IntoIter<InstFmtArg, 1>;
type Mnemonic = &'static str;
fn mnemonic<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Mnemonic {
self.kind.mnemonic()
}
fn args<Ctx: DisplayCtx>(&self, _ctx: &Ctx) -> Self::Args {
array::IntoIter::new([InstFmtArg::literal(self.comment)])
}
}
impl InstFmt for Inst {
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@ -4,9 +4,70 @@
// Imports
use super::InstTarget;
use crate::Pos;
use crate::{inst::Register, Pos};
use std::fmt;
/// Instruction display
pub trait InstDisplay {
/// Mnemonic type
type Mnemonic: fmt::Display;
/// Args type
type Args: IntoIterator<Item = InstFmtArg>;
/// Returns this instruction's mnemonic
fn mnemonic<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Mnemonic;
/// Returns all arguments of this instruction
fn args<Ctx: DisplayCtx>(&self, ctx: &Ctx) -> Self::Args;
}
/// Display context
pub trait DisplayCtx {
/// Current position
fn cur_pos(&self) -> Pos;
}
/// An formattable argument
#[derive(PartialEq, Clone, Debug)]
pub enum InstFmtArg {
/// Register
Register(Register),
/// Register offset
RegisterOffset {
/// The register
register: Register,
/// The offset
offset: i64,
},
/// Literal
Literal(i64),
/// Target
Target(Pos),
}
impl InstFmtArg {
/// Creates a `Literal` variant
#[must_use]
pub fn literal(value: impl Into<i64>) -> Self {
Self::Literal(value.into())
}
/// Creates a `RegisterOffset` variant
#[must_use]
pub fn register_offset(register: Register, offset: impl Into<i64>) -> Self {
Self::RegisterOffset {
register,
offset: offset.into(),
}
}
}
/// A formattable instruction
///
/// This trait defines formatting for all instruction, which may require the