Added pseudo::Decodable trait for decoding pseudo instructions.

This commit is contained in:
2021-01-10 15:01:16 +00:00
parent 543283f04f
commit affd7034e6
5 changed files with 89 additions and 58 deletions

View File

@@ -113,6 +113,7 @@ impl Raw {
/// All basic instructions
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[derive(derive_more::TryInto)]
pub enum Inst {
/// Alu
Alu(alu::Inst),

View File

@@ -2,11 +2,12 @@
// Imports
use super::{
basic::{self, Decodable},
pseudo, Directive, Inst,
basic::{self, Decodable as _},
pseudo::{self, Decodable as _},
Directive, Inst,
};
use crate::Pos;
use dcb_util::NextFromBytes;
use std::convert::TryFrom;
/// Parsing iterator, reads instructions from a `[u8]` slice
#[derive(PartialEq, Eq, Clone, Debug)]
@@ -47,34 +48,42 @@ impl<'a> Iterator for ParseIter<'a> {
return Some((pos, Inst::Directive(directive)));
}
// Else decode an instruction, falling back to a directive if unable to
match self.bytes.next_u32().and_then(basic::Raw::from_u32).and_then(basic::Inst::decode) {
// If we got one, update our bytes and check if it's a pseudo instruction
Some(inst) => {
self.bytes = &self.bytes[4..];
let pos = self.cur_pos;
self.cur_pos += 4;
match pseudo::Inst::decode(inst, self.bytes) {
Some((inst, len)) => {
self.bytes = &self.bytes[len..];
self.cur_pos += len as u32;
Some((pos, Inst::Pseudo(inst)))
},
None => Some((pos, Inst::Basic(inst))),
}
},
// Else make the instruction iterator
// Note: We fuse it to make sure that pseudo instructions don't try to skip
// invalid instructions.
let mut insts = self
.bytes
.chunks(4)
.map(|word| u32::from_ne_bytes([word[0], word[1], word[2], word[3]]))
.map_while(|word| basic::Raw::from_u32(word).and_then(basic::Inst::decode))
.fuse();
// If we don't have enough for a `u32` or we didn't manage to
// parse an instruction, try to parse a directive
None => match Directive::decode(self.cur_pos, self.bytes) {
Some((directive, len)) => {
self.bytes = &self.bytes[len..];
let pos = self.cur_pos;
self.cur_pos += len as u32;
Some((pos, Inst::Directive(directive)))
},
None => None,
// Try to decode a pseudo-instruction
if let Some(inst) = pseudo::Inst::decode(insts.clone()) {
let len = inst.size() * 4;
self.bytes = &self.bytes[usize::try_from(len).expect("Instruction size didn't fit into a `usize`")..];
let pos = self.cur_pos;
self.cur_pos += len;
return Some((pos, Inst::Pseudo(inst)));
}
// Else try to decode it as an basic instruction
if let Some(inst) = insts.next() {
self.bytes = &self.bytes[4..];
let pos = self.cur_pos;
self.cur_pos += 4;
return Some((pos, Inst::Basic(inst)));
}
// Else read it as a directive
match Directive::decode(self.cur_pos, self.bytes) {
Some((directive, len)) => {
self.bytes = &self.bytes[len..];
let pos = self.cur_pos;
self.cur_pos += len as u32;
Some((pos, Inst::Directive(directive)))
},
None => None,
}
}
}

View File

@@ -1,7 +1,8 @@
//! Pseudo instructions
//!
//! This modules defines all the pseudo instructions usually
//! used in mips. They are variable length.
//! All instructions in this module are variable length, and are decoded
//! from a starting basic instruction and remaining instruction bytes,
//! via the [`Decodable`] trait.
// Modules
pub mod alu_assign;
@@ -60,12 +61,15 @@ pub enum Inst {
*/
}
impl Inst {
/// Attempts to parse a pseudo instruction from a start
/// basic instruction and remaining bytes
#[must_use]
pub fn decode(inst: basic::Inst, bytes: &[u8]) -> Option<(Self, usize)> {
alu_assign::Inst::decode(inst, bytes).map(|(inst, len)| (Self::AluAssign(inst), len))
impl Decodable for Inst {
fn decode(insts: impl Iterator<Item = basic::Inst> + Clone) -> Option<Self> {
alu_assign::Inst::decode(insts).map(Self::AluAssign)
}
fn size(&self) -> u32 {
match self {
Self::AluAssign(inst) => inst.size(),
}
}
}
@@ -96,3 +100,22 @@ impl PseudoInst {
}
}
*/
/// A decodable pseudo instruction
pub trait Decodable: Sized {
/// Decodes this instruction
#[must_use]
fn decode(insts: impl Iterator<Item = basic::Inst> + Clone) -> Option<Self>;
/// Returns how many _words_ long this instruction is
fn size(&self) -> u32;
}
/*
/// An encodable pseudo instruction
pub trait Encodable: Decodable {
/// Encodes this instruction
#[must_use]
fn encode(&self) -> Self::Raw;
}
*/

View File

@@ -1,11 +1,12 @@
//! Alu self-assign instructions
// Imports
use super::Decodable;
use crate::exe::inst::{
basic::{self, alu},
InstFmt, Register,
};
use std::fmt;
use std::{convert::TryInto, fmt};
/// Alu assign kind
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
@@ -61,30 +62,26 @@ pub struct Inst {
pub kind: Kind,
}
impl Inst {
/// Decodes this pseudo instruction
#[must_use]
pub fn decode(inst: basic::Inst, _bytes: &[u8]) -> Option<(Self, usize)> {
let inst = match inst {
basic::Inst::Alu(inst) => match inst {
alu::Inst::Imm(alu::imm::Inst { dst, lhs, kind }) if dst == lhs => Some(Self {
dst,
kind: Kind::Imm { kind },
}),
alu::Inst::Reg(alu::reg::Inst { dst, lhs, rhs, kind }) if dst == lhs => Some(Self {
dst,
kind: Kind::Reg { kind, rhs },
}),
_ => None,
},
impl Decodable for Inst {
fn decode(mut insts: impl Iterator<Item = basic::Inst> + Clone) -> Option<Self> {
match insts.next()?.try_into().ok()? {
alu::Inst::Imm(alu::imm::Inst { dst, lhs, kind }) if dst == lhs => Some(Self {
dst,
kind: Kind::Imm { kind },
}),
alu::Inst::Reg(alu::reg::Inst { dst, lhs, rhs, kind }) if dst == lhs => Some(Self {
dst,
kind: Kind::Reg { kind, rhs },
}),
_ => None,
};
}
}
inst.map(|inst| (inst, 0))
fn size(&self) -> u32 {
1
}
}
impl InstFmt for Inst {
fn mnemonic(&self) -> &'static str {
self.kind.mnemonic()

View File

@@ -13,7 +13,8 @@
never_type,
or_patterns,
associated_type_bounds,
bindings_after_at
bindings_after_at,
iter_map_while,
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]