Added basic::Parsable for parsable basic instructions.

This commit is contained in:
Filipe Rodrigues 2021-04-26 11:45:22 +01:00
parent 2e44a3e382
commit 17dfe03800
18 changed files with 618 additions and 66 deletions

View File

@ -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 {

View File

@ -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`.

View File

@ -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),
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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}"),

View File

@ -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 {

View File

@ -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)

View File

@ -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;

View File

@ -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)),
}
}
}

View File

@ -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 {

View File

@ -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();

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;