From 847e88d4905c60f379ef0e5751192e0ce211fe49 Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Mon, 11 Jan 2021 13:45:16 +0000 Subject: [PATCH] Added `inst::InstSize`. Removed `Pos + i16` implementation. Added `Pos + usize` implementation. --- dcb-exe/src/exe/data.rs | 2 +- dcb-exe/src/exe/data/table.rs | 3 +- dcb-exe/src/exe/data/ty.rs | 16 +++++------ dcb-exe/src/exe/func/table.rs | 3 +- dcb-exe/src/exe/inst.rs | 12 ++++++++ dcb-exe/src/exe/inst/basic.rs | 8 ++++++ dcb-exe/src/exe/inst/basic/cond.rs | 10 +++---- dcb-exe/src/exe/inst/directive.rs | 34 +++++++++++------------ dcb-exe/src/exe/inst/iter.rs | 11 ++++---- dcb-exe/src/exe/inst/pseudo.rs | 11 ++++---- dcb-exe/src/exe/inst/pseudo/alu_assign.rs | 8 ++++-- dcb-exe/src/exe/inst/size.rs | 7 +++++ dcb-exe/src/exe/pos.rs | 8 +++--- 13 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 dcb-exe/src/exe/inst/size.rs diff --git a/dcb-exe/src/exe/data.rs b/dcb-exe/src/exe/data.rs index 2fce239..669bd8c 100644 --- a/dcb-exe/src/exe/data.rs +++ b/dcb-exe/src/exe/data.rs @@ -54,7 +54,7 @@ impl Data { /// Returns the size, in bytes, of this data #[must_use] - pub fn size(&self) -> u32 { + pub fn size(&self) -> usize { self.ty.size() } } diff --git a/dcb-exe/src/exe/data/table.rs b/dcb-exe/src/exe/data/table.rs index cc4cb3e..d2bb5f4 100644 --- a/dcb-exe/src/exe/data/table.rs +++ b/dcb-exe/src/exe/data/table.rs @@ -14,6 +14,7 @@ pub mod error; // Exports pub use error::GetKnownError; use inst::directive::Directive; +use int_conv::SignExtended; // Imports use super::{Data, DataType}; @@ -88,7 +89,7 @@ impl DataTable { .clone() .filter_map(|(pos, inst)| match inst { Inst::Basic(basic::Inst::Load(basic::load::Inst { offset, .. }) | basic::Inst::Store(basic::store::Inst { offset, .. })) => { - Some(pos + offset) + Some(pos + offset.sign_extended::()) }, /* Instruction::Pseudo( diff --git a/dcb-exe/src/exe/data/ty.rs b/dcb-exe/src/exe/data/ty.rs index b82559e..a602c8a 100644 --- a/dcb-exe/src/exe/data/ty.rs +++ b/dcb-exe/src/exe/data/ty.rs @@ -33,14 +33,14 @@ pub enum DataType { ty: Box, /// Array length - len: u32, + len: usize, }, } impl DataType { /// Returns the size of this data kind #[must_use] - pub fn size(&self) -> u32 { + pub fn size(&self) -> usize { match self { Self::Word => 4, Self::HalfWord => 2, @@ -107,7 +107,7 @@ impl std::str::FromStr for DataType { let ty = Self::from_str(ty).map_err(|err| FromStrError::InvalidArrayTy(Box::new(err)))?; let ty = Box::new(ty); - let len = self::parse_u32(len).map_err(|err| FromStrError::InvalidArrayLen { len: len.to_owned(), err })?; + let len = self::parse_usize(len).map_err(|err| FromStrError::InvalidArrayLen { len: len.to_owned(), err })?; return Ok(Self::Array { ty, len }); } @@ -160,13 +160,13 @@ impl serde::Serialize for DataType { } /// Helper function to parse a `u32` from a string with any base. -pub fn parse_u32(s: &str) -> Result { +pub fn parse_usize(s: &str) -> Result { let (s, base) = match s.trim().as_bytes() { - [b'0', b'x', len @ ..] => (len, 16), - [b'0', b'o', len @ ..] => (len, 8), - [b'0', b'b', len @ ..] => (len, 2), + [b'0', b'x', rest @ ..] => (rest, 16), + [b'0', b'o', rest @ ..] => (rest, 8), + [b'0', b'b', rest @ ..] => (rest, 2), s => (s, 10), }; let s = std::str::from_utf8(s).expect("Failed to convert `str` -> `[u8]` -> `str`"); - u32::from_str_radix(s, base) + usize::from_str_radix(s, base) } diff --git a/dcb-exe/src/exe/func/table.rs b/dcb-exe/src/exe/func/table.rs index 7557386..3a90bc8 100644 --- a/dcb-exe/src/exe/func/table.rs +++ b/dcb-exe/src/exe/func/table.rs @@ -14,6 +14,7 @@ pub mod error; // Exports pub use error::GetKnownError; +use int_conv::SignExtended; //pub use iter::WithInstructionsIter; // Imports @@ -136,7 +137,7 @@ impl FuncTable { }, ))) => Some(inst.address(pos)), // Conditional jumps - Inst::Basic(basic::Inst::Cond(basic::cond::Inst { offset, .. })) => Some(pos + offset), + Inst::Basic(basic::Inst::Cond(basic::cond::Inst { offset, .. })) => Some(pos + offset.sign_extended::()), _ => None, }) .filter(|target| Inst::CODE_RANGE.contains(target)) diff --git a/dcb-exe/src/exe/inst.rs b/dcb-exe/src/exe/inst.rs index a6cdd43..cce987c 100644 --- a/dcb-exe/src/exe/inst.rs +++ b/dcb-exe/src/exe/inst.rs @@ -25,12 +25,14 @@ pub mod fmt; pub mod iter; pub mod pseudo; pub mod reg; +pub mod size; // Exports pub use directive::Directive; pub use fmt::InstFmt; pub use iter::ParseIter; pub use reg::Register; +pub use size::InstSize; // Imports use crate::Pos; @@ -57,6 +59,16 @@ impl Inst { pub const CODE_START: Pos = Pos(0x80013e4c); } +impl InstSize for Inst { + fn size(&self) -> usize { + match self { + Self::Basic(inst) => inst.size(), + Self::Pseudo(inst) => inst.size(), + Self::Directive(directive) => directive.size(), + } + } +} + impl InstFmt for Inst { fn mnemonic(&self) -> &'static str { match self { diff --git a/dcb-exe/src/exe/inst/basic.rs b/dcb-exe/src/exe/inst/basic.rs index 9a6265d..82a1709 100644 --- a/dcb-exe/src/exe/inst/basic.rs +++ b/dcb-exe/src/exe/inst/basic.rs @@ -16,6 +16,7 @@ pub mod store; pub mod sys; // Imports +use super::InstSize; use crate::exe::inst::InstFmt; /// Raw instruction @@ -183,6 +184,13 @@ impl Encodable for Inst { } } +// Any basic decodable instruction is 4 bytes +impl InstSize for T { + fn size(&self) -> usize { + 4 + } +} + impl InstFmt for Inst { #[rustfmt::skip] fn mnemonic(&self) -> &'static str { diff --git a/dcb-exe/src/exe/inst/basic/cond.rs b/dcb-exe/src/exe/inst/basic/cond.rs index 2f5809b..4f4f87b 100644 --- a/dcb-exe/src/exe/inst/basic/cond.rs +++ b/dcb-exe/src/exe/inst/basic/cond.rs @@ -5,7 +5,7 @@ use crate::exe::inst::{ basic::{Decodable, Encodable}, InstFmt, Register, }; -use int_conv::{Signed, Truncated, ZeroExtended}; +use int_conv::{SignExtended, Signed, Truncated, ZeroExtended}; use std::fmt; /// Raw representation @@ -136,11 +136,11 @@ impl InstFmt for Inst { } fn fmt(&self, pos: crate::Pos, _bytes: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - let address = pos + 4 * self.offset; - let mnemonic = self.kind.mnemonic(); - let arg = self.arg; + let Self { arg, offset, kind } = self; + let mnemonic = kind.mnemonic(); + let address = pos + 4 * offset.sign_extended::(); - match self.kind { + match kind { Kind::Equal(reg) | Kind::NotEqual(reg) => write!(f, "{mnemonic} {arg}, {reg}, {address}"), Kind::LessOrEqualZero | Kind::GreaterThanZero | diff --git a/dcb-exe/src/exe/inst/directive.rs b/dcb-exe/src/exe/inst/directive.rs index 7313f09..329f2f9 100644 --- a/dcb-exe/src/exe/inst/directive.rs +++ b/dcb-exe/src/exe/inst/directive.rs @@ -2,7 +2,7 @@ // Imports //use super::{FromRawIter, Instruction, Raw}; -use super::{Inst, InstFmt}; +use super::{Inst, InstFmt, InstSize}; use crate::exe::Pos; use ascii::{AsciiChar, AsciiStr}; use dcb_util::NextFromBytes; @@ -26,7 +26,7 @@ pub enum Directive { /// Ascii string Ascii { /// String length - len: u32, + len: usize, }, } @@ -94,19 +94,6 @@ impl Directive { kind: ForceDecodeKind::Word, }, ]; - - /// Returns the size of this directive - #[must_use] - pub const fn size(self) -> u32 { - match self { - Self::Dw(_) => 4, - Self::Dh(_) => 2, - Self::Db(_) => 1, - // Round ascii strings' len up to the - // nearest word (or one after if exactly 1 word). - Self::Ascii { len } => len + 4 - (len % 4), - } - } } impl Directive { @@ -139,6 +126,19 @@ impl Directive { } } +impl InstSize for Directive { + fn size(&self) -> usize { + match self { + Self::Dw(_) => 4, + Self::Dh(_) => 2, + Self::Db(_) => 1, + // Round ascii strings' len up to the + // nearest word (or one after if exactly 1 word). + Self::Ascii { len } => len + 4 - (len % 4), + } + } +} + impl InstFmt for Directive { fn mnemonic(&self) -> &'static str { match self { @@ -170,7 +170,7 @@ impl InstFmt for Directive { /// /// Will always read in multiples of a word (4 bytes), including the null. #[allow(clippy::as_conversions, clippy::cast_possible_truncation)] // Our length will always fit into a `u32`. -fn read_ascii_until_null(pos: Pos, bytes: &[u8]) -> Option<(u32, usize)> { +fn read_ascii_until_null(pos: Pos, bytes: &[u8]) -> Option<(usize, usize)> { // Get the next null or invalid character let (idx, null) = bytes.iter().enumerate().find_map(|(idx, &byte)| match AsciiChar::from_ascii(byte) { Ok(AsciiChar::Null) => Some((idx, true)), @@ -191,5 +191,5 @@ fn read_ascii_until_null(pos: Pos, bytes: &[u8]) -> Option<(u32, usize)> { } // Else return both lengths - Some((idx as u32, idx + nulls_len)) + Some((idx, idx + nulls_len)) } diff --git a/dcb-exe/src/exe/inst/iter.rs b/dcb-exe/src/exe/inst/iter.rs index 6da9433..aa7f750 100644 --- a/dcb-exe/src/exe/inst/iter.rs +++ b/dcb-exe/src/exe/inst/iter.rs @@ -4,12 +4,13 @@ use super::{ basic::{self, Decodable as _}, pseudo::{self, Decodable as _}, - Directive, Inst, + Directive, Inst, InstSize, }; use crate::Pos; -use std::convert::TryFrom; -/// Parsing iterator, reads instructions from a `[u8]` slice +/// Parsing iterator. +/// +/// Parses instructions from a byte slice, `[u8]` along with it's position. #[derive(PartialEq, Eq, Clone, Debug)] pub struct ParseIter<'a> { /// Remaining bytes @@ -59,8 +60,8 @@ impl<'a> Iterator for ParseIter<'a> { // 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 len = inst.size(); + self.bytes = &self.bytes[len..]; let pos = self.cur_pos; self.cur_pos += len; return Some((pos, Inst::Pseudo(inst))); diff --git a/dcb-exe/src/exe/inst/pseudo.rs b/dcb-exe/src/exe/inst/pseudo.rs index bd2dd1f..f643bc2 100644 --- a/dcb-exe/src/exe/inst/pseudo.rs +++ b/dcb-exe/src/exe/inst/pseudo.rs @@ -14,7 +14,7 @@ pub mod alu_assign; //pub mod store; // Imports -use super::{basic, InstFmt}; +use super::{basic, InstFmt, InstSize}; /// A pseudo instruction #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -65,8 +65,10 @@ impl Decodable for Inst { fn decode(insts: impl Iterator + Clone) -> Option { alu_assign::Inst::decode(insts).map(Self::AluAssign) } +} - fn size(&self) -> u32 { +impl InstSize for Inst { + fn size(&self) -> usize { match self { Self::AluAssign(inst) => inst.size(), } @@ -102,13 +104,10 @@ impl PseudoInst { */ /// A decodable pseudo instruction -pub trait Decodable: Sized { +pub trait Decodable: InstSize + Sized { /// Decodes this instruction #[must_use] fn decode(insts: impl Iterator + Clone) -> Option; - - /// Returns how many _words_ long this instruction is - fn size(&self) -> u32; } /* diff --git a/dcb-exe/src/exe/inst/pseudo/alu_assign.rs b/dcb-exe/src/exe/inst/pseudo/alu_assign.rs index 54a0e0b..fd3cf58 100644 --- a/dcb-exe/src/exe/inst/pseudo/alu_assign.rs +++ b/dcb-exe/src/exe/inst/pseudo/alu_assign.rs @@ -4,7 +4,7 @@ use super::Decodable; use crate::exe::inst::{ basic::{self, alu}, - InstFmt, Register, + InstFmt, InstSize, Register, }; use std::{convert::TryInto, fmt}; @@ -76,9 +76,11 @@ impl Decodable for Inst { _ => None, } } +} - fn size(&self) -> u32 { - 1 +impl InstSize for Inst { + fn size(&self) -> usize { + 4 } } diff --git a/dcb-exe/src/exe/inst/size.rs b/dcb-exe/src/exe/inst/size.rs new file mode 100644 index 0000000..d2c3461 --- /dev/null +++ b/dcb-exe/src/exe/inst/size.rs @@ -0,0 +1,7 @@ +//! Instruction sizes + +/// Trait to report the size of an instruction +pub trait InstSize { + /// Returns the size of this instruction, in bytes. + fn size(&self) -> usize; +} diff --git a/dcb-exe/src/exe/pos.rs b/dcb-exe/src/exe/pos.rs index 6e0d92e..e26f375 100644 --- a/dcb-exe/src/exe/pos.rs +++ b/dcb-exe/src/exe/pos.rs @@ -47,12 +47,12 @@ impl ops::Add for Pos { } } -// `Pos + i16 = Pos` -impl ops::Add for Pos { +// `Pos + usize = Pos` +impl ops::Add for Pos { type Output = Self; - fn add(self, rhs: i16) -> Self::Output { - self + rhs.sign_extended::() + fn add(self, rhs: usize) -> Self::Output { + self + u32::try_from(rhs).expect("Value was too large") } }