mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-06 01:20:11 +00:00
Added basic::Parsable for parsable basic instructions.
This commit is contained in:
parent
2e44a3e382
commit
17dfe03800
@ -24,7 +24,7 @@ pub use target::InstTarget;
|
||||
// Imports
|
||||
use self::{basic::Decodable as _, pseudo::Decodable as _};
|
||||
use crate::{DataTable, FuncTable, Pos};
|
||||
use std::{borrow::Borrow, ops::Deref};
|
||||
use std::{borrow::Borrow, convert::TryInto, ops::Deref};
|
||||
|
||||
/// An assembler instruction.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -750,6 +750,34 @@ impl<'a> InstFmt for Inst<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsing context
|
||||
pub trait ParseCtx {
|
||||
/// Returns the current position
|
||||
fn cur_pos(&self) -> Pos;
|
||||
|
||||
/// Returns the position of a label
|
||||
fn label_pos(&self, label: &str) -> Option<Pos>;
|
||||
|
||||
/// Retrieves a position from an argument
|
||||
fn arg_pos(&self, arg: &parse::Arg) -> Result<Pos, basic::ParseError> {
|
||||
match *arg {
|
||||
parse::Arg::Literal(pos) => pos.try_into().map(Pos).map_err(|_| basic::ParseError::LiteralOutOfRange),
|
||||
parse::Arg::Label(ref label) => self.label_pos(label).ok_or(basic::ParseError::UnknownLabel),
|
||||
_ => Err(basic::ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves a position and offset from an argument
|
||||
fn arg_pos_offset(&self, arg: &parse::Arg) -> Result<(Pos, i64), basic::ParseError> {
|
||||
match *arg {
|
||||
parse::Arg::Literal(pos) => pos.try_into().map(|pos| (Pos(pos), 0)).map_err(|_| basic::ParseError::LiteralOutOfRange),
|
||||
parse::Arg::Label(ref label) => self.label_pos(label).map(|pos| (pos, 0)).ok_or(basic::ParseError::UnknownLabel),
|
||||
parse::Arg::LabelOffset { ref label, offset } => self.label_pos(label).map(|pos| (pos, offset)).ok_or(basic::ParseError::UnknownLabel),
|
||||
_ => Err(basic::ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Label
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum Label {
|
||||
|
||||
@ -17,7 +17,7 @@ pub mod store;
|
||||
pub mod sys;
|
||||
|
||||
// Imports
|
||||
use super::{InstSize, Register};
|
||||
use super::{parse, InstSize, ParseCtx, Register};
|
||||
use crate::inst::InstFmt;
|
||||
|
||||
/// All basic instructions
|
||||
@ -93,6 +93,36 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
#[rustfmt::skip]
|
||||
let parsers: &[&dyn Fn() -> Result<Self, ParseError>] = &[
|
||||
&|| alu ::Inst::parse(mnemonic, args, ctx).map(Self::Alu ),
|
||||
&|| cond ::Inst::parse(mnemonic, args, ctx).map(Self::Cond ),
|
||||
&|| jmp ::Inst::parse(mnemonic, args, ctx).map(Self::Jmp ),
|
||||
&|| load ::Inst::parse(mnemonic, args, ctx).map(Self::Load ),
|
||||
&|| lui ::Inst::parse(mnemonic, args, ctx).map(Self::Lui ),
|
||||
&|| mult ::Inst::parse(mnemonic, args, ctx).map(Self::Mult ),
|
||||
&|| shift::Inst::parse(mnemonic, args, ctx).map(Self::Shift),
|
||||
&|| store::Inst::parse(mnemonic, args, ctx).map(Self::Store),
|
||||
&|| sys ::Inst::parse(mnemonic, args, ctx).map(Self::Sys ),
|
||||
&|| co ::Inst::parse(mnemonic, args, ctx).map(Self::Co ),
|
||||
];
|
||||
|
||||
// Try to parse each one one by one.
|
||||
// If we get an unknown mnemonic, try the next, else return the error.
|
||||
for parser in parsers {
|
||||
match parser() {
|
||||
Ok(inst) => return Ok(inst),
|
||||
Err(ParseError::UnknownMnemonic) => continue,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
Err(ParseError::UnknownMnemonic)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModifiesReg for Inst {
|
||||
#[rustfmt::skip]
|
||||
fn modifies_reg(&self, reg: Register) -> bool {
|
||||
@ -153,6 +183,40 @@ pub trait Encodable: Decodable {
|
||||
fn encode(&self) -> Self::Raw;
|
||||
}
|
||||
|
||||
/// Parsing error
|
||||
#[derive(PartialEq, Clone, Debug, thiserror::Error)]
|
||||
pub enum ParseError {
|
||||
/// Unknown mnemonic
|
||||
#[error("Unknown mnemonic")]
|
||||
UnknownMnemonic,
|
||||
|
||||
/// Literal was out of range
|
||||
#[error("Literal out of range")]
|
||||
LiteralOutOfRange,
|
||||
|
||||
/// Invalid arguments
|
||||
#[error("Invalid arguments")]
|
||||
InvalidArguments,
|
||||
|
||||
/// Relative jump is too far
|
||||
#[error("Relative jump is too far")]
|
||||
RelativeJumpTooFar,
|
||||
|
||||
/// Unknown label
|
||||
#[error("Unknown label")]
|
||||
UnknownLabel,
|
||||
|
||||
/// Target is not properly aligned
|
||||
#[error("Target is not properly aligned")]
|
||||
TargetAlign,
|
||||
}
|
||||
|
||||
/// Instruction parsing
|
||||
pub trait Parsable: Sized {
|
||||
/// Parses this instruction
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError>;
|
||||
}
|
||||
|
||||
/// Register modifying instructions
|
||||
pub trait ModifiesReg: Decodable {
|
||||
/// Returns if this instruction modifies `reg`.
|
||||
|
||||
@ -5,10 +5,10 @@ pub mod imm;
|
||||
pub mod reg;
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt,
|
||||
parse, InstFmt, ParseCtx,
|
||||
};
|
||||
|
||||
/// Alu register instructions
|
||||
@ -33,7 +33,20 @@ impl Decodable for Inst {
|
||||
|
||||
impl Encodable for Inst {
|
||||
fn encode(&self) -> Self::Raw {
|
||||
todo!();
|
||||
match self {
|
||||
Inst::Imm(inst) => inst.encode(),
|
||||
Inst::Reg(inst) => inst.encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
match imm::Inst::parse(mnemonic, args, ctx) {
|
||||
Ok(inst) => Ok(Self::Imm(inst)),
|
||||
Err(ParseError::UnknownMnemonic) => reg::Inst::parse(mnemonic, args, ctx).map(Self::Reg),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
// Imports
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::fmt;
|
||||
use std::{convert::TryInto, fmt};
|
||||
|
||||
/// Instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -122,6 +122,36 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
#[rustfmt::skip]
|
||||
let to_kind = match mnemonic {
|
||||
"addi" => |value: i64| value.try_into().map(Kind::Add ),
|
||||
"addiu" => |value: i64| value.try_into().map(Kind::AddUnsigned ),
|
||||
"slti" => |value: i64| value.try_into().map(Kind::SetLessThan ),
|
||||
"sltiu" => |value: i64| value.try_into().map(Kind::SetLessThanUnsigned),
|
||||
"andi" => |value: i64| value.try_into().map(Kind::And ),
|
||||
"ori" => |value: i64| value.try_into().map(Kind::Or ),
|
||||
"xori" => |value: i64| value.try_into().map(Kind::Xor ),
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
match *args {
|
||||
// Disallow `slti` and `sltiu` in short form
|
||||
[parse::Arg::Register(_), parse::Arg::Literal(_)] if ["slti", "sltiu"].contains(&mnemonic) => Err(ParseError::InvalidArguments),
|
||||
|
||||
// Else parse both `$dst, $lhs, value` and `$dst, value`.
|
||||
[parse::Arg::Register(lhs @ dst), parse::Arg::Literal(value)] |
|
||||
[parse::Arg::Register(dst), parse::Arg::Register(lhs), parse::Arg::Literal(value)] => Ok(Self {
|
||||
dst,
|
||||
lhs,
|
||||
kind: to_kind(value).map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
}),
|
||||
_ => Err(ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let Self { dst, lhs, kind } = self;
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
// Imports
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Alu register instruction kind
|
||||
@ -131,6 +131,36 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
#[rustfmt::skip]
|
||||
let kind = match mnemonic {
|
||||
"add" => Kind::Add ,
|
||||
"addu" => Kind::AddUnsigned ,
|
||||
"sub" => Kind::Sub ,
|
||||
"subu" => Kind::SubUnsigned ,
|
||||
"and" => Kind::And ,
|
||||
"or" => Kind::Or ,
|
||||
"xor" => Kind::Xor ,
|
||||
"nor" => Kind::Nor ,
|
||||
"slt" => Kind::SetLessThan ,
|
||||
"sltu" => Kind::SetLessThanUnsigned,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
match *args {
|
||||
// Disallow `slt` and `sltu` in short form
|
||||
[parse::Arg::Register(_), parse::Arg::Register(_)] if ["slt", "sltu"].contains(&mnemonic) => Err(ParseError::InvalidArguments),
|
||||
|
||||
// Else parse both `$dst, $lhs, $rhs` and `$dst, $rhs`.
|
||||
[parse::Arg::Register(lhs @ dst), parse::Arg::Register(rhs)] |
|
||||
[parse::Arg::Register(dst), parse::Arg::Register(lhs), parse::Arg::Register(rhs)] => Ok(Self { dst, lhs, rhs, kind }),
|
||||
_ => Err(ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
//! Co-processor instructions
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Co-processor register kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -168,6 +169,76 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let inst = match mnemonic {
|
||||
"cop0" | "cop1" | "cop2" | "cop3" => {
|
||||
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
|
||||
let imm = match *args {
|
||||
[parse::Arg::Literal(imm)] => imm.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
Inst { n, kind: Kind::CopN { imm } }
|
||||
},
|
||||
"mfc0" | "mfc1" | "mfc2" | "mfc3" | "cfc0" | "cfc1" | "cfc2" | "cfc3" | "mtc0" | "mtc1" | "mtc2" | "mtc3" | "ctc0" | "ctc1" |
|
||||
"ctc2" | "ctc3" => {
|
||||
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
|
||||
let (reg, imm) = match *args {
|
||||
[parse::Arg::Register(dst), parse::Arg::Literal(src)] => (dst, src.try_into().map_err(|_| ParseError::LiteralOutOfRange)?),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
let kind = match &mnemonic[0..=0] {
|
||||
"m" => RegisterKind::Data,
|
||||
"c" => RegisterKind::Control,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match &mnemonic[1..=1] {
|
||||
"f" => Inst {
|
||||
n,
|
||||
kind: Kind::MoveFrom { dst: reg, src: imm, kind },
|
||||
},
|
||||
"t" => Inst {
|
||||
n,
|
||||
kind: Kind::MoveTo { dst: imm, src: reg, kind },
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
"lwc0" | "lwc1" | "lwc2" | "lwc3" | "swc0" | "swc1" | "swc2" | "swc3" => {
|
||||
let n = mnemonic[3..].parse().expect("Unable to parse 0..=3");
|
||||
let (dst, src, offset) = match *args {
|
||||
[parse::Arg::Literal(dst), parse::Arg::RegisterOffset { register: src, offset }] => (
|
||||
dst.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
src,
|
||||
offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
match &mnemonic[0..=0] {
|
||||
"l" => Inst {
|
||||
n,
|
||||
kind: Kind::Load { dst, src, offset },
|
||||
},
|
||||
"s" => Inst {
|
||||
n,
|
||||
kind: Kind::Store { dst, src, offset },
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: bc{n}[f, t]
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
Ok(inst)
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
#[rustfmt::skip]
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
//! Condition branches
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::{
|
||||
inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstTarget, InstTargetFmt, Register,
|
||||
parse, InstTarget, InstTargetFmt, ParseCtx, Register,
|
||||
},
|
||||
Pos,
|
||||
};
|
||||
use int_conv::{SignExtended, Signed, Truncated, ZeroExtended};
|
||||
use std::fmt;
|
||||
use std::{convert::TryInto, fmt};
|
||||
|
||||
/// Instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -115,6 +115,78 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
// Note: Literals are absolute, not relative
|
||||
|
||||
// Calculates the offset between a position and the current one
|
||||
// with a possible offset
|
||||
let offset_of = |pos: Pos, offset: i64| -> Result<i16, ParseError> {
|
||||
use std::ops::{Add, Div, Sub};
|
||||
pos.sub(ctx.cur_pos())
|
||||
.add(offset)
|
||||
.div(4)
|
||||
.sub(1)
|
||||
.try_into()
|
||||
.map_err(|_| ParseError::RelativeJumpTooFar)
|
||||
};
|
||||
|
||||
// Calculates the offset of a literal/label/label offset argument
|
||||
let target_arg_to_offset = |arg| ctx.arg_pos_offset(arg).and_then(|(pos, offset)| offset_of(pos, offset));
|
||||
|
||||
let (arg, offset, kind) = match mnemonic {
|
||||
"b" => match args {
|
||||
[target] => (Register::Zr, target_arg_to_offset(target)?, Kind::Equal(Register::Zr)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"beqz" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::Equal(Register::Zr)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bnez" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::NotEqual(Register::Zr)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"beq" => match *args {
|
||||
[parse::Arg::Register(arg), parse::Arg::Register(reg), ref target] => (arg, target_arg_to_offset(target)?, Kind::Equal(reg)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bne" => match *args {
|
||||
[parse::Arg::Register(arg), parse::Arg::Register(reg), ref target] => (arg, target_arg_to_offset(target)?, Kind::NotEqual(reg)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"blez" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::LessOrEqualZero),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bgtz" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::GreaterThanZero),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bltz" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::LessThanZero),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bgez" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::GreaterOrEqualZero),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bltzal" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::LessThanZeroLink),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
"bgezal" => match *args {
|
||||
[parse::Arg::Register(arg), ref target] => (arg, target_arg_to_offset(target)?, Kind::GreaterOrEqualZeroLink),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
Ok(Self { arg, offset, kind })
|
||||
}
|
||||
}
|
||||
|
||||
impl InstTarget for Inst {
|
||||
fn target(&self, pos: Pos) -> Pos {
|
||||
Self::target_of(self.offset, pos)
|
||||
@ -126,8 +198,8 @@ impl InstTargetFmt for Inst {
|
||||
let Self { kind, arg, .. } = self;
|
||||
|
||||
// `beq $zr, $zr, offset` => `b offset`
|
||||
// `beq $zr, $arg, offset` => `beqz $arg, offset`
|
||||
// `bne $zr, $arg, offset` => `bnez $arg, offset`
|
||||
// `beq $arg, $zr, offset` => `beqz $arg, offset`
|
||||
// `bne $arg, $zr, offset` => `bnez $arg, offset`
|
||||
match kind {
|
||||
Kind::Equal(Register::Zr) => match arg {
|
||||
Register::Zr => write!(f, "b {target}"),
|
||||
|
||||
@ -5,10 +5,10 @@ pub mod imm;
|
||||
pub mod reg;
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Jmp register instructions
|
||||
@ -40,6 +40,16 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
match imm::Inst::parse(mnemonic, args, ctx) {
|
||||
Ok(inst) => Ok(Self::Imm(inst)),
|
||||
Err(ParseError::UnknownMnemonic) => reg::Inst::parse(mnemonic, args, ctx).map(Self::Reg),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
// Imports
|
||||
use crate::{
|
||||
inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstTarget, InstTargetFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstTarget, InstTargetFmt, ParseCtx, Register,
|
||||
},
|
||||
Pos,
|
||||
};
|
||||
@ -82,6 +82,34 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let (pos, kind) = match mnemonic {
|
||||
"j" => match args {
|
||||
[arg] => (ctx.arg_pos(arg)?, Kind::Jump),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
|
||||
"jal" => match args {
|
||||
[arg] => (ctx.arg_pos(arg)?, Kind::JumpLink),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
// If the position isn't word aligned, return Err
|
||||
if !pos.is_word_aligned() {
|
||||
return Err(ParseError::TargetAlign);
|
||||
}
|
||||
|
||||
// Else get our imm from it
|
||||
let imm = (pos.0 & 0x0fff_ffff) / 4;
|
||||
|
||||
Ok(Self { imm, kind })
|
||||
}
|
||||
}
|
||||
|
||||
impl InstTarget for Inst {
|
||||
fn target(&self, pos: Pos) -> Pos {
|
||||
Self::target_of(self.imm, pos)
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
// Imports
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Jmp register instruction kind
|
||||
@ -72,6 +72,28 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let (target, kind) = match mnemonic {
|
||||
"jr" => match *args {
|
||||
[parse::Arg::Register(target)] => (target, Kind::Jump),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
|
||||
"jalr" => match *args {
|
||||
[parse::Arg::Register(target), parse::Arg::Register(reg)] => (target, Kind::JumpLink(reg)),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
},
|
||||
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
Ok(Self { target, kind })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let Self { target, kind } = self;
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
//! Load instructions
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -115,12 +116,40 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let kind = match mnemonic {
|
||||
"lb" => Kind::Byte,
|
||||
"lh" => Kind::HalfWord,
|
||||
"lwl" => Kind::WordLeft,
|
||||
"lw" => Kind::Word,
|
||||
"lbu" => Kind::ByteUnsigned,
|
||||
"lhu" => Kind::HalfWordUnsigned,
|
||||
"lwr" => Kind::WordRight,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
let (value, addr, offset) = match *args {
|
||||
[parse::Arg::Register(value), parse::Arg::Register(addr)] => (value, addr, 0),
|
||||
[parse::Arg::Register(value), parse::Arg::RegisterOffset { register: addr, offset }] => {
|
||||
(value, addr, offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
|
||||
},
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
Ok(Self { value, addr, offset, kind })
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
let mnemonic = kind.mnemonic();
|
||||
|
||||
write!(f, "{mnemonic} {value}, {:#}({addr})", SignedHex(offset))
|
||||
match offset {
|
||||
0 => write!(f, "{mnemonic} {value}, {addr}"),
|
||||
_ => write!(f, "{mnemonic} {value}, {:#}({addr})", SignedHex(offset)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
//! Lui instruction
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use int_conv::{Truncated, ZeroExtended};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Load instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -35,6 +36,7 @@ impl Decodable for Inst {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Inst {
|
||||
#[bitmatch::bitmatch]
|
||||
fn encode(&self) -> Self::Raw {
|
||||
@ -45,6 +47,21 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
if mnemonic != "lui" {
|
||||
return Err(ParseError::UnknownMnemonic);
|
||||
}
|
||||
|
||||
match *args {
|
||||
[parse::Arg::Register(dst), parse::Arg::Literal(value)] => Ok(Self {
|
||||
dst,
|
||||
value: value.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
}),
|
||||
_ => Err(ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
//! Multiplications
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Operation kind
|
||||
@ -108,7 +108,7 @@ impl Decodable for Inst {
|
||||
"000000_sssss_ttttt_ddddd_?????_01ffff" => [s, t, d, f],
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
||||
Some(match f {
|
||||
// 00x0
|
||||
0x0 => Self::MoveFrom { dst: Register::new(d)?, src: MultReg::Hi },
|
||||
@ -130,44 +130,82 @@ impl Decodable for Inst {
|
||||
}
|
||||
|
||||
impl Encodable for Inst {
|
||||
#[rustfmt::skip]
|
||||
#[bitmatch::bitmatch]
|
||||
fn encode(&self) -> Self::Raw {
|
||||
let [s, t, d, f] = match self {
|
||||
Self::Mult { kind, mode, lhs, rhs } => [
|
||||
lhs.idx(),
|
||||
rhs.idx(),
|
||||
0,
|
||||
match (kind, mode) {
|
||||
(MultKind::Mult, MultMode::Signed) => 0x8,
|
||||
Self::Mult { kind, mode, lhs, rhs } => [lhs.idx(), rhs.idx(), 0, match (kind, mode) {
|
||||
(MultKind::Mult, MultMode::Signed ) => 0x8,
|
||||
(MultKind::Mult, MultMode::Unsigned) => 0x9,
|
||||
(MultKind::Div, MultMode::Signed) => 0xa,
|
||||
(MultKind::Div, MultMode::Unsigned) => 0xb,
|
||||
},
|
||||
],
|
||||
Self::MoveFrom { dst, src } => [
|
||||
0,
|
||||
0,
|
||||
dst.idx(),
|
||||
match src {
|
||||
(MultKind::Div , MultMode::Signed ) => 0xa,
|
||||
(MultKind::Div , MultMode::Unsigned) => 0xb,
|
||||
}],
|
||||
Self::MoveFrom { dst, src } => [0, 0, dst.idx(), match src {
|
||||
MultReg::Hi => 0x0,
|
||||
MultReg::Lo => 0x2,
|
||||
},
|
||||
],
|
||||
Self::MoveTo { dst, src } => [
|
||||
src.idx(),
|
||||
0,
|
||||
0,
|
||||
match dst {
|
||||
}],
|
||||
Self::MoveTo { dst, src } => [src.idx(), 0, 0, match dst {
|
||||
MultReg::Hi => 0x1,
|
||||
MultReg::Lo => 0x3,
|
||||
},
|
||||
],
|
||||
}],
|
||||
};
|
||||
|
||||
|
||||
bitpack!("000000_sssss_ttttt_ddddd_?????_01ffff")
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let inst = match mnemonic {
|
||||
"mflo" | "mfhi" | "mtlo" | "mthi" => {
|
||||
let reg = match *args {
|
||||
[parse::Arg::Register(reg)] => reg,
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
let mult_reg = match &mnemonic[2..=3] {
|
||||
"lo" => MultReg::Lo,
|
||||
"hi" => MultReg::Hi,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match &mnemonic[1..=1] {
|
||||
"f" => Inst::MoveFrom { dst: reg, src: mult_reg },
|
||||
"t" => Inst::MoveTo { dst: mult_reg, src: reg },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
|
||||
// Mult / Div
|
||||
"mult" | "multu" | "div" | "divu" => {
|
||||
let (lhs, rhs) = match *args {
|
||||
[parse::Arg::Register(lhs), parse::Arg::Register(rhs)] => (lhs, rhs),
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
Inst::Mult {
|
||||
lhs,
|
||||
rhs,
|
||||
mode: match mnemonic {
|
||||
"divu" | "multu" => MultMode::Unsigned,
|
||||
"div" | "mult" => MultMode::Signed,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
kind: match mnemonic {
|
||||
"mult" | "multu" => MultKind::Mult,
|
||||
"div" | "divu" => MultKind::Div,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
Ok(inst)
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let mnemonic = self.mnemonic();
|
||||
|
||||
@ -5,10 +5,10 @@ pub mod imm;
|
||||
pub mod reg;
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Alu register instructions
|
||||
@ -40,6 +40,16 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
match imm::Inst::parse(mnemonic, args, ctx) {
|
||||
Ok(inst) => Ok(Self::Imm(inst)),
|
||||
Err(ParseError::UnknownMnemonic) => reg::Inst::parse(mnemonic, args, ctx).map(Self::Reg),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@ -2,10 +2,11 @@
|
||||
|
||||
// Imports
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use int_conv::{Truncated, ZeroExtended};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Shift immediate instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -78,6 +79,9 @@ impl Decodable for Inst {
|
||||
impl Encodable for Inst {
|
||||
#[bitmatch::bitmatch]
|
||||
fn encode(&self) -> Self::Raw {
|
||||
// TODO: Maybe return error?
|
||||
assert!(self.rhs < 32);
|
||||
|
||||
let f: u32 = match self.kind {
|
||||
Kind::LeftLogical => 0x0,
|
||||
Kind::RightLogical => 0x2,
|
||||
@ -91,6 +95,28 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let kind = match mnemonic {
|
||||
"sll" => Kind::LeftLogical,
|
||||
"srl" => Kind::RightLogical,
|
||||
"sra" => Kind::RightArithmetic,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
match *args {
|
||||
[parse::Arg::Register(lhs @ dst), parse::Arg::Literal(rhs)] |
|
||||
[parse::Arg::Register(dst), parse::Arg::Register(lhs), parse::Arg::Literal(rhs)] => Ok(Self {
|
||||
dst,
|
||||
lhs,
|
||||
rhs: rhs.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
kind,
|
||||
}),
|
||||
_ => Err(ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
// Imports
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable, ModifiesReg},
|
||||
InstFmt, Register,
|
||||
basic::{Decodable, Encodable, ModifiesReg, Parsable, ParseError},
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
|
||||
/// Shift register instruction kind
|
||||
@ -73,6 +73,7 @@ impl Decodable for Inst {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Inst {
|
||||
#[bitmatch::bitmatch]
|
||||
fn encode(&self) -> Self::Raw {
|
||||
@ -90,6 +91,23 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let kind = match mnemonic {
|
||||
"sllv" => Kind::LeftLogical,
|
||||
"srlv" => Kind::RightLogical,
|
||||
"srav" => Kind::RightArithmetic,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
match *args {
|
||||
[parse::Arg::Register(lhs @ dst), parse::Arg::Register(rhs)] |
|
||||
[parse::Arg::Register(dst), parse::Arg::Register(lhs), parse::Arg::Register(rhs)] => Ok(Self { dst, lhs, rhs, kind }),
|
||||
_ => Err(ParseError::InvalidArguments),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
//! Store instructions
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Store instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -104,6 +105,29 @@ impl Encodable for Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let kind = match mnemonic {
|
||||
"sb" => Kind::Byte,
|
||||
"sh" => Kind::HalfWord,
|
||||
"swl" => Kind::WordLeft,
|
||||
"sw" => Kind::Word,
|
||||
"swr" => Kind::WordRight,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
let (value, addr, offset) = match *args {
|
||||
[parse::Arg::Register(value), parse::Arg::Register(addr)] => (value, addr, 0),
|
||||
[parse::Arg::Register(value), parse::Arg::RegisterOffset { register: addr, offset }] => {
|
||||
(value, addr, offset.try_into().map_err(|_| ParseError::LiteralOutOfRange)?)
|
||||
},
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
Ok(Self { value, addr, offset, kind })
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
//! System calls
|
||||
|
||||
// Imports
|
||||
use super::ModifiesReg;
|
||||
use super::{ModifiesReg, Parsable, ParseError};
|
||||
use crate::inst::{
|
||||
basic::{Decodable, Encodable},
|
||||
InstFmt, Register,
|
||||
parse, InstFmt, ParseCtx, Register,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Sys instruction func
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -62,6 +63,9 @@ impl Decodable for Inst {
|
||||
impl Encodable for Inst {
|
||||
#[bitmatch::bitmatch]
|
||||
fn encode(&self) -> Self::Raw {
|
||||
// TODO: Maybe return Error?
|
||||
assert!(self.comment < 0x100000);
|
||||
|
||||
let c = self.comment;
|
||||
let f: u32 = match self.kind {
|
||||
Kind::Sys => 0,
|
||||
@ -73,6 +77,24 @@ impl Encodable for Inst {
|
||||
}
|
||||
|
||||
|
||||
impl Parsable for Inst {
|
||||
fn parse<Ctx: ?Sized + ParseCtx>(mnemonic: &str, args: &[parse::Arg], _ctx: &Ctx) -> Result<Self, ParseError> {
|
||||
let kind = match mnemonic {
|
||||
"sys" => Kind::Sys,
|
||||
"break" => Kind::Break,
|
||||
_ => return Err(ParseError::UnknownMnemonic),
|
||||
};
|
||||
|
||||
let comment = match *args {
|
||||
[parse::Arg::Literal(comment)] => comment.try_into().map_err(|_| ParseError::LiteralOutOfRange)?,
|
||||
_ => return Err(ParseError::InvalidArguments),
|
||||
};
|
||||
|
||||
Ok(Self { comment, kind })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl InstFmt for Inst {
|
||||
fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let Self { comment, kind } = self;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user