SimpleInstruction is now defined using bitmatch instead of a macro.

This commit is contained in:
Filipe Rodrigues 2020-10-26 01:14:16 +00:00
parent 2d931f10cb
commit eb51f448ce
8 changed files with 245 additions and 714 deletions

View File

@ -65,6 +65,8 @@
#![allow(clippy::large_digit_groups)]
// We don't put the final `else` if it's empty
#![allow(clippy::else_if_without_else)]
// We're usually fine with missing future variants
#![allow(clippy::wildcard_enum_match_arm)]
// Modules
mod cli;
@ -150,9 +152,9 @@ fn main() -> Result<(), anyhow::Error> {
// Get all function jumps
let funcs_pos: HashMap<Pos, usize> = instructions
.iter()
.filter_map(|(_, instruction)| match instruction {
Instruction::Simple(SimpleInstruction::Jal { target }) |
Instruction::Directive(Directive::Dw(target) | Directive::DwRepeated { value: target, .. }) => Some(Pos(*target)),
.filter_map(|(_, instruction)| match *instruction {
Instruction::Simple(SimpleInstruction::Jal { target }) => Some(target),
Instruction::Directive(Directive::Dw(target) | Directive::DwRepeated { value: target, .. }) => Some(Pos(target)),
_ => None,
})
.filter(|target| (Instruction::CODE_START..Instruction::CODE_END).contains(target) && offsets.contains(target))
@ -163,7 +165,7 @@ fn main() -> Result<(), anyhow::Error> {
// Get all local jumps
let locals_pos: HashMap<Pos, usize> = instructions
.iter()
.filter_map(|(_, instruction)| match instruction {
.filter_map(|(_, instruction)| match *instruction {
Instruction::Simple(
SimpleInstruction::J { target } |
SimpleInstruction::Beq { target, .. } |
@ -177,7 +179,7 @@ fn main() -> Result<(), anyhow::Error> {
) |
Instruction::Pseudo(
PseudoInstruction::Beqz { target, .. } | PseudoInstruction::Bnez { target, .. } | PseudoInstruction::B { target },
) => Some(Pos(*target)),
) => Some(target),
_ => None,
})
.filter(|target| (Instruction::CODE_START..Instruction::CODE_END).contains(target) && offsets.contains(target))
@ -270,10 +272,10 @@ fn main() -> Result<(), anyhow::Error> {
SimpleInstruction::Bgezal { target, .. },
) => {
print!(" #");
if let Some(func_idx) = funcs_pos.get(Pos::ref_cast(target)) {
if let Some(func_idx) = funcs_pos.get(target) {
print!(" func_{func_idx}");
}
if let Some(local_idx) = locals_pos.get(Pos::ref_cast(target)) {
if let Some(local_idx) = locals_pos.get(target) {
print!(" .{local_idx}");
}
},

View File

@ -18,6 +18,7 @@ ascii = { version = "1.0", features = ["serde"] }
arrayref = "0.3"
int-conv = "0.1"
indoc = "1.0"
bitmatch = "0.1"
# Serde
serde = { version = "1.0", features = ["derive"] }

View File

@ -53,7 +53,6 @@ impl FromRawIter for Directive {
let raw = iter.next()?;
// Try to get an ascii string from the raw and check for nulls
#[allow(clippy::wildcard_enum_match_arm)] // Option won't get more variants
match AsciiString::from_ascii(raw.repr.to_ne_bytes()).map(check_nulls) {
// If we got a string with at least 1 non-null, but
// at least 1 null and uniformly null, return just it

View File

@ -223,24 +223,23 @@ pub enum PseudoInstruction {
/// Branch if equal to zero
/// Alias for `beq $rx, $zr, target`
#[display(fmt = "beqz {rx}, {target:#x}")]
Beqz { rx: Register, target: u32 },
Beqz { rx: Register, target: Pos },
/// Branch if different from zero
/// Alias for `bne $rx, $zr, target`
#[display(fmt = "bnez {rx}, {target:#x}")]
Bnez { rx: Register, target: u32 },
Bnez { rx: Register, target: Pos },
/// Jump relative
/// Alias for `beq $zr, $zr, target`
#[display(fmt = "b {target:#x}")]
B { target: u32 },
B { target: Pos },
// TODO: Push / Pop
}
impl FromRawIter for PseudoInstruction {
type Decoded = Option<(Pos, Self)>;
#[allow(clippy::wildcard_enum_match_arm)] // New entries won't affect this function, it can only act on entries it knows.
#[allow(clippy::similar_names)] // With register names, this happens too much
#[allow(clippy::too_many_lines, clippy::clippy::cognitive_complexity)] // We can't separate this into several functions, it's just 1 big match
fn decode<I: Iterator<Item = Raw> + Clone>(iter: &mut I) -> Self::Decoded {

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
//! Raw instruction representation
// Imports
use super::Raw;
use int_conv::Truncate;
/// An instruction's raw representation, including
/// it's current address.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[allow(clippy::missing_docs_in_private_items)]
pub struct RawRepr {
pub op: u8,
pub rs: u8,
pub rt: u8,
pub rd: u8,
pub imm5: u8,
pub op2: u8,
pub imm16: u16,
pub imm25: u32,
pub imm26: u32,
/// Syscall / Break immediate
pub sys_imm: u32,
/// Co-processor opcode
pub co_op: u8,
/// Co-processor number
pub co_n: u8,
/// Co-processor highest `rs` bit.
pub co_rs0: u8,
/// Co-processor lowest `rs` bits.
pub co_rs1: u8,
/// Position of the instruction
pub pos: u32,
}
#[allow(clippy::inconsistent_digit_grouping)] // We're grouping 6-5-5-5-5-6 as per docs.
impl RawRepr {
/// Creates a new split instruction
#[must_use]
#[rustfmt::skip]
pub fn new(Raw {repr, pos}: Raw) -> Self {
Self {
op : ((repr & 0b111111_00000_00000_00000_00000_000000) >> 26).truncate(),
rs : ((repr & 0b000000_11111_00000_00000_00000_000000) >> 21).truncate(),
rt : ((repr & 0b000000_00000_11111_00000_00000_000000) >> 16).truncate(),
rd : ((repr & 0b000000_00000_00000_11111_00000_000000) >> 11).truncate(),
imm5 : ((repr & 0b000000_00000_00000_00000_11111_000000) >> 6 ).truncate(),
op2 : ((repr & 0b000000_00000_00000_00000_00000_111111) >> 0 ).truncate(),
imm16 : ((repr & 0b000000_00000_00000_11111_11111_111111) >> 0 ).truncate(),
imm25 : ((repr & 0b000000_01111_11111_11111_11111_111111) >> 0 ),
imm26 : ((repr & 0b000000_11111_11111_11111_11111_111111) >> 0 ),
sys_imm: ((repr & 0b000000_11111_11111_11111_11111_000000) >> 0 ),
co_op : ((repr & 0b111100_00000_00000_00000_00000_000000) >> 28).truncate(),
co_rs0 : ((repr & 0b000000_10000_00000_00000_00000_000000) >> 25).truncate(),
co_rs1 : ((repr & 0b000000_01111_00000_00000_00000_000000) >> 21).truncate(),
co_n : ((repr & 0b000011_00000_00000_00000_00000_000000) >> 26).truncate(),
pos: pos.0,
}
}
}

View File

@ -2,6 +2,7 @@
// TODO: More implementations for `Pos`
// Imports
use int_conv::Signed;
use std::{fmt, ops};
/// An instruction position
@ -26,6 +27,30 @@ impl ops::Sub<u32> for Pos {
}
}
impl ops::Add<u32> for Pos {
type Output = Self;
fn add(self, rhs: u32) -> Self::Output {
Self(self.0 + rhs)
}
}
impl ops::Add<i32> for Pos {
type Output = Self;
fn add(self, rhs: i32) -> Self::Output {
Self((self.0.as_signed() + rhs).as_unsigned())
}
}
impl ops::BitAnd<u32> for Pos {
type Output = Self;
fn bitand(self, rhs: u32) -> Self::Output {
Self(self.0 & rhs)
}
}
impl<'a, T> ops::Sub<T> for &'_ Pos
where
Pos: ops::Sub<T, Output = Pos>,
@ -36,3 +61,14 @@ where
<Pos as ops::Sub<T>>::sub(Pos(self.0), rhs)
}
}
impl<'a, T> ops::Add<T> for &'_ Pos
where
Pos: ops::Add<T, Output = Pos>,
{
type Output = Pos;
fn add(self, rhs: T) -> Self::Output {
<Pos as ops::Add<T>>::add(Pos(self.0), rhs)
}
}

View File

@ -102,6 +102,8 @@
#![allow(clippy::panic_in_result_fn)]
// A `match Option / Result / Bool` can sometimes look cleaner than a `if let / else`
#![allow(clippy::single_match_else, clippy::match_bool)]
// We're usually fine with missing future variants
#![allow(clippy::wildcard_enum_match_arm)]
// Modules