diff --git a/dcb-exe/src/exe/func/table.rs b/dcb-exe/src/exe/func/table.rs index ab43003..b477051 100644 --- a/dcb-exe/src/exe/func/table.rs +++ b/dcb-exe/src/exe/func/table.rs @@ -135,7 +135,7 @@ impl FuncTable { kind: basic::jmp::imm::Kind::Jump, .. }, - ))) => Some(inst.address(pos)), + ))) => Some(inst.target(pos)), // Conditional jumps Inst::Basic(basic::Inst::Cond(basic::cond::Inst { offset, .. })) => Some(pos + offset.sign_extended::()), _ => None, @@ -152,7 +152,7 @@ impl FuncTable { kind: basic::jmp::imm::Kind::JumpLink, .. }, - ))) => Some(inst.address(pos)), + ))) => Some(inst.target(pos)), // `dw` Inst::Directive(Directive::Dw(address)) => Some(Pos(address)), _ => None, diff --git a/dcb-exe/src/exe/inst/basic/cond.rs b/dcb-exe/src/exe/inst/basic/cond.rs index 6de532d..ab66894 100644 --- a/dcb-exe/src/exe/inst/basic/cond.rs +++ b/dcb-exe/src/exe/inst/basic/cond.rs @@ -1,9 +1,12 @@ //! Condition branches // Imports -use crate::exe::inst::{ - basic::{Decodable, Encodable}, - InstFmt, Register, +use crate::{ + exe::inst::{ + basic::{Decodable, Encodable}, + InstFmt, Register, + }, + Pos, }; use int_conv::{SignExtended, Signed, Truncated, ZeroExtended}; use std::fmt; @@ -82,6 +85,20 @@ pub struct Inst { pub kind: Kind, } +impl Inst { + /// Returns the target for this instruction + #[must_use] + pub fn target(self, pos: Pos) -> Pos { + Self::target_of(self.offset, pos) + } + + /// Returns the target using an offset + #[must_use] + pub fn target_of(offset: i16, pos: Pos) -> Pos { + pos + 4 * offset.sign_extended::() + } +} + impl Decodable for Inst { type Raw = Raw; @@ -135,19 +152,19 @@ impl InstFmt for Inst { self.kind.mnemonic() } - fn fmt(&self, pos: crate::Pos, f: &mut fmt::Formatter) -> fmt::Result { - let Self { arg, offset, kind } = self; + fn fmt(&self, pos: Pos, f: &mut fmt::Formatter) -> fmt::Result { + let Self { kind, arg, .. } = self; let mnemonic = kind.mnemonic(); - let address = pos + 4 * offset.sign_extended::(); + let target = self.target(pos); match kind { - Kind::Equal(reg) | Kind::NotEqual(reg) => write!(f, "{mnemonic} {arg}, {reg}, {address}"), + Kind::Equal(reg) | Kind::NotEqual(reg) => write!(f, "{mnemonic} {arg}, {reg}, {target}"), Kind::LessOrEqualZero | Kind::GreaterThanZero | Kind::LessThanZero | Kind::GreaterOrEqualZero | Kind::LessThanZeroLink | - Kind::GreaterOrEqualZeroLink => write!(f, "{mnemonic} {arg}, {address}"), + Kind::GreaterOrEqualZeroLink => write!(f, "{mnemonic} {arg}, {target}"), } } } diff --git a/dcb-exe/src/exe/inst/basic/jmp/imm.rs b/dcb-exe/src/exe/inst/basic/jmp/imm.rs index 96ccde6..041c50a 100644 --- a/dcb-exe/src/exe/inst/basic/jmp/imm.rs +++ b/dcb-exe/src/exe/inst/basic/jmp/imm.rs @@ -43,18 +43,24 @@ pub struct Raw { /// Jmp register instructions #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Inst { - /// Target - pub target: u32, + /// Immediate + pub imm: u32, /// Kind pub kind: Kind, } impl Inst { - /// Returns the address of this instruction + /// Returns the target of this instruction #[must_use] - pub fn address(self, pos: Pos) -> Pos { - (pos & 0xf0000000) + self.target * 4 + pub fn target(self, pos: Pos) -> Pos { + Self::target_of(self.imm, pos) + } + + /// Returns the target using an immediate + #[must_use] + pub fn target_of(imm: u32, pos: Pos) -> Pos { + (pos & 0xf0000000) + imm * 4 } } @@ -68,7 +74,7 @@ impl Decodable for Inst { _ => return None, }; - Some(Self { target: raw.i, kind }) + Some(Self { imm: raw.i, kind }) } } @@ -78,7 +84,7 @@ impl Encodable for Inst { Kind::Jump => 0, Kind::JumpLink => 1, }; - let i = self.target; + let i = self.imm; Raw { p, i } } @@ -91,8 +97,8 @@ impl InstFmt for Inst { fn fmt(&self, pos: Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mnemonic = self.kind.mnemonic(); - let address = self.address(pos); + let target = self.target(pos); - write!(f, "{mnemonic} {address}") + write!(f, "{mnemonic} {target}") } } diff --git a/dcb-exe/src/exe/inst/pseudo.rs b/dcb-exe/src/exe/inst/pseudo.rs index 3aa0f87..182afaf 100644 --- a/dcb-exe/src/exe/inst/pseudo.rs +++ b/dcb-exe/src/exe/inst/pseudo.rs @@ -6,8 +6,8 @@ // Modules pub mod alu_assign; +pub mod jmp; pub mod load_imm; -//pub mod jmp; //pub mod load; pub mod move_reg; pub mod nop; @@ -31,19 +31,17 @@ pub enum Inst { /// Move register MoveReg(move_reg::Inst), + + /// Jump + Jmp(jmp::Inst), /* /// Load Load(LoadPseudoInst), /// Store Store(StorePseudoInst), - - - - /// Load immediate - LoadImm(LoadImmInst), - */ + /* /// Subtract immediate /// Alias for `addi $rt, $rs, -imm` @@ -74,6 +72,7 @@ impl Decodable for Inst { load_imm ::Inst::decode(insts.clone()).map(Self::LoadImm ) .or_else( || alu_assign::Inst::decode(insts.clone()).map(Self::AluAssign)) .or_else( || nop ::Inst::decode(insts.clone()).map(Self::Nop )) + .or_else( || jmp ::Inst::decode(insts.clone()).map(Self::Jmp )) .or_else(move || move_reg ::Inst::decode( insts ).map(Self::MoveReg )) } } @@ -85,6 +84,7 @@ impl InstSize for Inst { Self::LoadImm(inst) => inst.size(), Self::Nop(inst) => inst.size(), Self::MoveReg(inst) => inst.size(), + Self::Jmp(inst) => inst.size(), } } } @@ -96,6 +96,7 @@ impl InstFmt for Inst { Self::LoadImm(inst) => inst.mnemonic(), Self::Nop(inst) => inst.mnemonic(), Self::MoveReg(inst) => inst.mnemonic(), + Self::Jmp(inst) => inst.mnemonic(), } } @@ -105,6 +106,7 @@ impl InstFmt for Inst { Self::LoadImm(inst) => inst.fmt(pos, f), Self::Nop(inst) => inst.fmt(pos, f), Self::MoveReg(inst) => inst.fmt(pos, f), + Self::Jmp(inst) => inst.fmt(pos, f), } } } diff --git a/dcb-exe/src/exe/inst/pseudo/jmp.rs b/dcb-exe/src/exe/inst/pseudo/jmp.rs index 8f2def2..27789bf 100644 --- a/dcb-exe/src/exe/inst/pseudo/jmp.rs +++ b/dcb-exe/src/exe/inst/pseudo/jmp.rs @@ -1,62 +1,98 @@ //! Jump pseudo instructions // Imports -use crate::exe::inst::{ - basic::{ - cond::CondKind, - special::{jmp::JmpKind, JmpInst}, - CondInst, InstIter, SpecialInst, - }, - BasicInst, Pos, Register, -}; +use crate::exe::inst::{basic, InstFmt, InstSize, Register}; + +use super::Decodable; /// Jump / Branch instructions #[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[derive(derive_more::Display)] -pub enum JmpPseudoInst { +pub enum Inst { /// Jump and link with return address - /// Alias for `jalr $ra, $dst` - #[display(fmt = "jalr {target}")] - JalrRa { target: Register }, + /// Alias for `jalr $target, $ra` + JalrRa { + /// Target for the jump + target: Register, + }, /// Branch if equal to zero /// Alias for `beq $arg, $zr, offset` - #[display(fmt = "beqz {arg}, {offset:#x}")] - Beqz { arg: Register, offset: Pos }, + Beqz { + /// Argument to compare + arg: Register, + + /// Jump offset + offset: i16, + }, /// Branch if different from zero /// Alias for `bne $arg, $zr, offset` - #[display(fmt = "bnez {arg}, {offset:#x}")] - Bnez { arg: Register, offset: Pos }, + Bnez { + /// Argument to compare + arg: Register, + + /// Jump offset + offset: i16, + }, /// Jump relative /// Alias for `beq $zr, $zr, offset` - #[display(fmt = "b {offset:#x}")] - B { offset: Pos }, + B { + /// Jump offset + offset: i16, + }, } -impl JmpPseudoInst { - /// Decodes this pseudo instruction - #[must_use] - pub fn decode(iter: InstIter<'_, impl Iterator + Clone>) -> Option { - let peeker = iter.peeker(); - let inst = match peeker.next()?? { - BasicInst::Cond(CondInst { arg, offset, kind }) => match kind { - CondKind::Equal(Register::Zr) => match arg == Register::Zr { - true => Self::B { offset }, - false => Self::Beqz { arg, offset }, +impl Decodable for Inst { + fn decode(mut insts: impl Iterator + Clone) -> Option { + let inst = match insts.next()? { + basic::Inst::Cond(basic::cond::Inst { arg, offset, kind }) => match kind { + basic::cond::Kind::Equal(Register::Zr) => match arg { + // `beq $zr, $zr, offset` + Register::Zr => Self::B { offset }, + // `beq $zr, $arg, offset` + _ => Self::Beqz { arg, offset }, }, - CondKind::NotEqual(Register::Zr) => Self::Bnez { arg, offset }, - _ => return None, - }, - BasicInst::Special(SpecialInst::Jmp(JmpInst { target, kind })) => match kind { - JmpKind::Link(Register::At) => Self::JalrRa { target }, + // `bnq $zr, $arg, offset` + basic::cond::Kind::NotEqual(Register::Zr) => Self::Bnez { arg, offset }, _ => return None, }, + // `jalr $ra, $target` + basic::Inst::Jmp(basic::jmp::Inst::Reg(basic::jmp::reg::Inst { + target, + kind: basic::jmp::reg::Kind::JumpLink(Register::Ra), + })) => Self::JalrRa { target }, + _ => return None, }; - peeker.apply(); Some(inst) } } + +impl InstSize for Inst { + fn size(&self) -> usize { + 4 + } +} + +impl InstFmt for Inst { + fn mnemonic(&self) -> &'static str { + match self { + Self::JalrRa { .. } => "jalr", + Self::Beqz { .. } => "beqz", + Self::Bnez { .. } => "bnez", + Self::B { .. } => "b", + } + } + + fn fmt(&self, pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let mnemonic = self.mnemonic(); + + match *self { + Self::JalrRa { target } => write!(f, "{mnemonic} {target}"), + Self::Beqz { arg, offset } | Self::Bnez { arg, offset } => write!(f, "{mnemonic} {arg}, {}", basic::cond::Inst::target_of(offset, pos)), + Self::B { offset } => write!(f, "{mnemonic} {}", basic::cond::Inst::target_of(offset, pos)), + } + } +}