diff --git a/dcb-exe/src/exe/inst/basic/co.rs b/dcb-exe/src/exe/inst/basic/co.rs index f4e6c97..5ad3a3b 100644 --- a/dcb-exe/src/exe/inst/basic/co.rs +++ b/dcb-exe/src/exe/inst/basic/co.rs @@ -1,18 +1,21 @@ //! Co-processor instructions -// Modules -//pub mod exec; -//pub mod move_reg; -//pub mod cond; -//pub mod load; -//pub mod store; - // Imports use crate::exe::inst::{ basic::{Decodable, Encodable}, InstFmt, Register, }; -use int_conv::{Signed, Truncated}; +use int_conv::{Signed, Truncated, ZeroExtended}; + +/// Co-processor register kind +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RegisterKind { + /// Data + Data, + + /// Control + Control, +} /// Co-processor instruction kind #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -23,55 +26,43 @@ pub enum Kind { imm: u32, }, - /// Move data register from co-processor - MfcN { + /// Move register from co-processor + MoveFrom { /// Destination dst: Register, /// Source - src: Register, + src: u8, + + /// Register kind + kind: RegisterKind, }, - /// Move control register from co-processor - CfcN { + /// Move register to co-processor + MoveTo { /// Destination - dst: Register, + dst: u8, /// Source src: Register, - }, - /// Move data register to co-processor - MtcN { - /// Destination - dst: Register, - /// Source - src: Register, + /// Register kind + kind: RegisterKind, }, - /// Move control register to co-processor - CtcN { - /// Destination - dst: Register, - /// Source - src: Register, - }, - /// Branch if true - BcNf { + /// Branch if + Branch { /// Offset offset: i16, - }, - /// Branch if false - BcNt { - /// Offset - offset: i16, + /// Value to branch on + on: bool, }, /// Load co-processor - LwcN { + Load { /// Destination - dst: Register, + dst: u8, /// Source src: Register, @@ -81,9 +72,9 @@ pub enum Kind { }, /// Store co-processor - SwcN { + Store { /// Destination - dst: Register, + dst: u8, /// Source src: Register, @@ -108,17 +99,21 @@ impl Decodable for Inst { #[bitmatch::bitmatch] fn decode(raw: Self::Raw) -> Option { + // Get `n` + #[bitmatch] + let "????nn_?????_?????_?????_?????_??????" = raw; + #[rustfmt::skip] - let (n, kind) = #[bitmatch] match raw { - "0100nn_1iiii_iiiii_iiiii_iiiii_iiiiii" => (n, Kind::CopN { imm: i }), - "0100nn_00000_ttttt_ddddd_?????_000000" => (n, Kind::MfcN { dst: Register::new(t)?, src: Register::new(d)? }), - "0100nn_00010_ttttt_ddddd_?????_000000" => (n, Kind::CfcN { dst: Register::new(t)?, src: Register::new(d)? }), - "0100nn_00100_ttttt_ddddd_?????_000000" => (n, Kind::MtcN { dst: Register::new(d)?, src: Register::new(t)? }), - "0100nn_00110_ttttt_ddddd_?????_000000" => (n, Kind::CtcN { dst: Register::new(d)?, src: Register::new(t)? }), - "0100nn_01000_00000_iiiii_iiiii_iiiiii" => (n, Kind::BcNf { offset: i.truncated::().as_signed() }), - "0100nn_01000_00001_iiiii_iiiii_iiiiii" => (n, Kind::BcNt { offset: i.truncated::().as_signed() }), - "1100nn_sssss_ttttt_iiiii_iiiii_iiiiii" => (n, Kind::LwcN { dst: Register::new(t)?, src: Register::new(s)?, offset: i.truncated::().as_signed() }), - "1110nn_sssss_ttttt_iiiii_iiiii_iiiiii" => (n, Kind::SwcN { dst: Register::new(s)?, src: Register::new(t)?, offset: i.truncated::().as_signed() }), + let kind = #[bitmatch] match raw { + "0100??_1iiii_iiiii_iiiii_iiiii_iiiiii" => Kind::CopN { imm: i }, + "0100??_00000_ttttt_ddddd_?????_000000" => Kind::MoveFrom { dst: Register::new(t)?, src: d.truncated(), kind: RegisterKind::Data }, + "0100??_00010_ttttt_ddddd_?????_000000" => Kind::MoveFrom { dst: Register::new(t)?, src: d.truncated(), kind: RegisterKind::Control }, + "0100??_00100_ttttt_ddddd_?????_000000" => Kind::MoveTo { dst: d.truncated(), src: Register::new(t)?, kind: RegisterKind::Data }, + "0100??_00110_ttttt_ddddd_?????_000000" => Kind::MoveTo { dst: d.truncated(), src: Register::new(t)?, kind: RegisterKind::Control }, + "0100??_01000_00000_iiiii_iiiii_iiiiii" => Kind::Branch { offset: i.truncated::().as_signed(), on: false }, + "0100??_01000_00001_iiiii_iiiii_iiiiii" => Kind::Branch { offset: i.truncated::().as_signed(), on: true }, + "1100??_sssss_ttttt_iiiii_iiiii_iiiiii" => Kind::Load { dst: t.truncated(), src: Register::new(s)?, offset: i.truncated::().as_signed() }, + "1110??_sssss_ttttt_iiiii_iiiii_iiiiii" => Kind::Store { dst: t.truncated(), src: Register::new(s)?, offset: i.truncated::().as_signed() }, _ => return None, }; @@ -126,13 +121,71 @@ impl Decodable for Inst { } } impl Encodable for Inst { + #[bitmatch::bitmatch] fn encode(&self) -> Self::Raw { - todo!(); + let n = self.n; + + match self.kind { + Kind::CopN { imm: i } => bitpack!("0100nn_1iiii_iiiii_iiiii_iiiii_iiiiii"), + Kind::MoveFrom { dst, src, kind } => { + let t = dst.idx(); + let d = src.zero_extended::(); + match kind { + RegisterKind::Data => bitpack!("0100nn_00000_ttttt_ddddd_?????_000000"), + RegisterKind::Control => bitpack!("0100nn_00010_ttttt_ddddd_?????_000000"), + } + }, + Kind::MoveTo { dst, src, kind } => { + let d = dst.zero_extended::(); + let t = src.idx(); + match kind { + RegisterKind::Data => bitpack!("0100nn_00100_ttttt_ddddd_?????_000000"), + RegisterKind::Control => bitpack!("0100nn_00110_ttttt_ddddd_?????_000000"), + } + }, + Kind::Branch { offset, on } => { + let i = offset.as_unsigned().zero_extended::(); + match on { + true => bitpack!("0100nn_01000_00001_iiiii_iiiii_iiiiii"), + false => bitpack!("0100nn_01000_00000_iiiii_iiiii_iiiiii"), + } + }, + Kind::Load { dst, src, offset } => { + let t = dst.zero_extended::(); + let s = src.idx(); + let i = offset.as_unsigned().zero_extended::(); + bitpack!("1100nn_sssss_ttttt_iiiii_iiiii_iiiiii") + }, + Kind::Store { dst, src, offset } => { + let t = dst.zero_extended::(); + let s = src.idx(); + let i = offset.as_unsigned().zero_extended::(); + bitpack!("1110nn_sssss_ttttt_iiiii_iiiii_iiiiii") + }, + } } } impl InstFmt for Inst { - fn fmt(&self, _pos: crate::Pos, _f: &mut std::fmt::Formatter) -> std::fmt::Result { - todo!(); + #[rustfmt::skip] + fn fmt(&self, _pos: crate::Pos, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let Self { n, kind } = self; + match kind { + Kind::CopN { imm } => write!(f, "cop{n} {imm:#x}"), + Kind::MoveFrom { dst, src, kind } => match kind { + RegisterKind::Control => write!(f, "cfc{n} {dst}, ${src:#x}"), + RegisterKind::Data => write!(f, "mfc{n} {dst}, ${src:#x}"), + } + Kind::MoveTo { dst, src, kind } => match kind { + RegisterKind::Data => write!(f, "mtc{n} {src}, ${dst:#x}"), + RegisterKind::Control => write!(f, "ctc{n} {src}, ${dst:#x}"), + } + Kind::Branch { offset, on } => match on { + true => write!(f, "bc{n}f {offset:#x}"), + false => write!(f, "bc{n}t {offset:#x}"), + } + Kind::Load { dst, src, offset } => write!(f, "lwc{n} ${dst:#x}, {offset:#x}({src})"), + Kind::Store { dst, src, offset } => write!(f, "swc{n} ${dst:#x}, {offset:#x}({src})"), + } } } diff --git a/dcb-exe/src/lib.rs b/dcb-exe/src/lib.rs index d858234..337adfa 100644 --- a/dcb-exe/src/lib.rs +++ b/dcb-exe/src/lib.rs @@ -58,7 +58,9 @@ // We only use wildcards when we only care about certain variants #![allow(clippy::wildcard_enum_match_arm, clippy::match_wildcard_for_single_variants)] // We're fine with shadowing, as long as it's related -#![allow(clippy::shadow_reuse)] +#![allow(clippy::shadow_reuse, clippy::shadow_same)] +// Matching on booleans can look better than `if / else` +#![allow(clippy::match_bool)] // Modules pub mod exe;