Added pseudo::jmp.

Refactored `basic::{jmp, cond}`'s target calculation.
This commit is contained in:
2021-01-11 16:58:20 +00:00
parent b72a857a8a
commit e29c3ed4e0
5 changed files with 122 additions and 61 deletions

View File

@@ -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::<i32>()),
_ => 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,

View File

@@ -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::<i32>()
}
}
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::<i32>();
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}"),
}
}
}

View File

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

View File

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

View File

@@ -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<Item = u32> + Clone>) -> Option<Self> {
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<Item = basic::Inst> + Clone) -> Option<Self> {
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)),
}
}
}