mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-09 03:40:23 +00:00
Added pseudo::Decodable trait for decoding pseudo instructions.
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user