mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-06 17:35:40 +00:00
Improved dcb-exe slightly, now gets compiled.
This commit is contained in:
parent
38ea8db1db
commit
c78822db7e
@ -4,7 +4,7 @@ members = [
|
||||
"dcb",
|
||||
"dcb-io",
|
||||
"dcb-util",
|
||||
# "dcb-exe",
|
||||
"dcb-exe",
|
||||
"dcb-bytes",
|
||||
"dcb-bytes-derive",
|
||||
"dcb-tools"
|
||||
|
||||
@ -7,7 +7,9 @@ edition = "2018"
|
||||
[dependencies]
|
||||
|
||||
# Dcb
|
||||
dcb-bytes = { version = "0.1", path = "../dcb-bytes" }
|
||||
dcb-bytes = { path = "../dcb-bytes" }
|
||||
dcb-io = { path = "../dcb-io" }
|
||||
dcb-util = { path = "../dcb-util" }
|
||||
|
||||
# Log
|
||||
log = "0.4"
|
||||
|
||||
@ -20,8 +20,8 @@ pub use instruction::Instruction;
|
||||
pub use pos::Pos;
|
||||
|
||||
// Imports
|
||||
use crate::{io::address::Data as DataAddress, GameFile};
|
||||
use dcb_bytes::{ByteArray, Bytes};
|
||||
use dcb_io::GameFile;
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
io::{Read, Seek, Write},
|
||||
@ -45,7 +45,7 @@ impl Exe {
|
||||
/// Everything outside of this range will be considered data.
|
||||
pub const CODE_RANGE: std::ops::Range<Pos> = Pos(0x80013e4c)..Pos(0x8006dd3c);
|
||||
/// Start address of the executable
|
||||
const START_ADDRESS: DataAddress = DataAddress::from_u64(0x58b9000);
|
||||
const START_ADDRESS: dcb_io::Data = dcb_io::Data::from_u64(0x58b9000);
|
||||
}
|
||||
|
||||
impl Exe {
|
||||
|
||||
@ -16,7 +16,8 @@ pub use error::GetKnownError;
|
||||
|
||||
// Imports
|
||||
use super::Data;
|
||||
use crate::{exe::Pos, util::DiscardingSortedMergeIter};
|
||||
use crate::exe::Pos;
|
||||
use dcb_util::DiscardingSortedMergeIter;
|
||||
use std::{collections::BTreeSet, fs::File, iter::FromIterator};
|
||||
|
||||
/// Data table
|
||||
|
||||
@ -9,12 +9,9 @@ use std::fmt;
|
||||
pub use error::{FromBytesError, ToBytesError};
|
||||
|
||||
// Import
|
||||
use crate::{
|
||||
util::{array_split, null_ascii_string::NullAsciiString},
|
||||
AsciiStrArr,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use dcb_bytes::Bytes;
|
||||
use dcb_util::{array_split, null_ascii_string::NullAsciiString, AsciiStrArr};
|
||||
|
||||
/// The header of the executable.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
// Imports
|
||||
use super::Header;
|
||||
use crate::util::null_ascii_string;
|
||||
use dcb_util::null_ascii_string;
|
||||
|
||||
/// Error type for [`Bytes::from_bytes`](dcb_bytes::Bytes::from_bytes)
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
|
||||
@ -10,7 +10,6 @@ pub mod iter;
|
||||
pub mod jmp;
|
||||
pub mod load;
|
||||
pub mod lui;
|
||||
//pub mod special;
|
||||
pub mod mult;
|
||||
pub mod store;
|
||||
pub mod sys;
|
||||
@ -19,12 +18,12 @@ pub mod sys;
|
||||
pub use alu::{AluInst, AluInstRaw};
|
||||
pub use cond::{CondInst, CondRaw};
|
||||
pub use iter::InstIter;
|
||||
pub use jmp::{JmpInst, JmpRaw};
|
||||
pub use jmp::{JmpInst, JmpInstRaw};
|
||||
pub use load::{LoadInst, LoadRaw};
|
||||
pub use lui::{LuiInst, LuiRaw};
|
||||
//pub use special::{SpecialInst, SpecialRaw};
|
||||
pub use store::{StoreInst, StoreRaw};
|
||||
pub use sys::{SysInst, SysRaw};
|
||||
pub use sys::{SysInst, SysInstRaw};
|
||||
|
||||
/// All basic instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -35,7 +34,7 @@ pub enum BasicInst {
|
||||
|
||||
/// Load
|
||||
Load(LoadInst),
|
||||
|
||||
|
||||
/// Condition
|
||||
Cond(CondInst),
|
||||
|
||||
@ -47,48 +46,53 @@ pub enum BasicInst {
|
||||
|
||||
/// Load upper immediate
|
||||
Lui(LuiInst),
|
||||
|
||||
/// Syscalls
|
||||
Sys(SysInst),s
|
||||
|
||||
// Syscall
|
||||
Sys(SysInst),
|
||||
}
|
||||
|
||||
impl BasicInst {
|
||||
// TODO: MAybe extract the strings if the bitmatch macro allows for it.
|
||||
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
#[bitmatch::bitmatch]
|
||||
#[allow(clippy::many_single_char_names)] // `bitmatch` can only output single character names.
|
||||
pub fn decode(raw: u32) -> Option<Self> {
|
||||
Some(
|
||||
#[bitmatch]
|
||||
match raw {
|
||||
//"000000_sssss_ttttt_ddddd_iiiii_ffffff" => Self::Special(SpecialInst::decode(SpecialRaw { s, t, d, i, f })?),
|
||||
"00001p_iiiii_iiiii_iiiii_iiiii_iiiiii" => Self::Jmp(JmpInst::decode(JmpRaw { p, i })),
|
||||
"000ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Self::Cond(CondInst::decode(CondRaw { p, s, t, i })?),
|
||||
"001111_?????_ttttt_iiiii_iiiii_iiiiii" => Self::Lui(LuiInst::decode(LuiRaw { t, i })?),
|
||||
//"001ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Self::Alu(AluInst::decode(AluInstRaw { p, s, t, i })?),
|
||||
"100ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Self::Store(StoreInst::decode(StoreRaw { p, s, t, i })?),
|
||||
"101ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Self::Load(LoadInst::decode(LoadRaw { p, s, t, i })?),
|
||||
use BasicInst::*;
|
||||
let inst = #[bitmatch]
|
||||
match raw {
|
||||
// Jump
|
||||
"00001p_iiiii_iiiii_iiiii_iiiii_iiiiii" => Jmp(JmpInst::decode(JmpInstRaw::Imm(jmp::JmpImmInstRaw { p, i }))),
|
||||
"000000_sssss_?????_ddddd_?????_00100f" => Jmp(JmpInst::decode(JmpInstRaw::Reg(jmp::JmpRegInstRaw { s, d, f }))),
|
||||
|
||||
// Alu
|
||||
"000000_sssss_ttttt_ddddd_?????_ffffff" => Self::Alu(AluInst::decode(AluInstRaw::Imm(alu::AluRegInstRaw { s, t, d, f }))?),
|
||||
"001ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Self::Alu(AluInst::decode(AluInstRaw::Reg(alu::AluImmInstRaw { p, s, t, i }))?),
|
||||
"000ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Cond(CondInst::decode(CondRaw { p, s, t, i })?),
|
||||
"001111_?????_ttttt_iiiii_iiiii_iiiiii" => Lui(LuiInst::decode(LuiRaw { t, i })?),
|
||||
|
||||
/*
|
||||
"0100nn_1iiii_iiiii_iiiii_iiiii_iiiiii" => CopN { n: n.truncate(), imm: i},
|
||||
"0100nn_00000_ttttt_ddddd_?????_000000" => MfcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00010_ttttt_ddddd_?????_000000" => CfcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00100_ttttt_ddddd_?????_000000" => MtcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00110_ttttt_ddddd_?????_000000" => CtcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_01000_00000_iiiii_iiiii_iiiiii" => BcNf { n: n.truncate(), target: i.truncate() },
|
||||
"0100nn_01000_00001_iiiii_iiiii_iiiiii" => BcNt { n: n.truncate(), target: i.truncate() },
|
||||
"1100nn_sssss_ttttt_iiiii_iiiii_iiiiii" => LwcN { n: n.truncate(), rs: reg(s)?, rt: reg(t)?, imm: i.truncate() },
|
||||
"1110nn_sssss_ttttt_iiiii_iiiii_iiiiii" => SwcN { n: n.truncate(), rs: reg(s)?, rt: reg(t)?, imm: i.truncate() },
|
||||
*/
|
||||
_ => return None,
|
||||
},
|
||||
)
|
||||
// Alu
|
||||
"000000_sssss_ttttt_ddddd_?????_10ffff" => Alu(AluInst::decode(AluInstRaw::Imm(alu::AluRegInstRaw { s, t, d, f }))?),
|
||||
"001ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Alu(AluInst::decode(AluInstRaw::Reg(alu::AluImmInstRaw { p, s, t, i }))?),
|
||||
|
||||
// Syscall
|
||||
"000000_ccccc_ccccc_ccccc_ccccc_00110f" => Sys(SysInst::decode(SysInstRaw { c, f })?),
|
||||
|
||||
// Store / Load
|
||||
"100ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Store(StoreInst::decode(StoreRaw { p, s, t, i })?),
|
||||
"101ppp_sssss_ttttt_iiiii_iiiii_iiiiii" => Load(LoadInst::decode(LoadRaw { p, s, t, i })?),
|
||||
|
||||
/*
|
||||
"0100nn_1iiii_iiiii_iiiii_iiiii_iiiiii" => CopN { n: n.truncate(), imm: i},
|
||||
"0100nn_00000_ttttt_ddddd_?????_000000" => MfcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00010_ttttt_ddddd_?????_000000" => CfcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00100_ttttt_ddddd_?????_000000" => MtcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_00110_ttttt_ddddd_?????_000000" => CtcN { n: n.truncate(), rt: reg(t)?, rd: reg(d)? },
|
||||
"0100nn_01000_00000_iiiii_iiiii_iiiiii" => BcNf { n: n.truncate(), target: i.truncate() },
|
||||
"0100nn_01000_00001_iiiii_iiiii_iiiiii" => BcNt { n: n.truncate(), target: i.truncate() },
|
||||
"1100nn_sssss_ttttt_iiiii_iiiii_iiiiii" => LwcN { n: n.truncate(), rs: reg(s)?, rt: reg(t)?, imm: i.truncate() },
|
||||
"1110nn_sssss_ttttt_iiiii_iiiii_iiiiii" => SwcN { n: n.truncate(), rs: reg(s)?, rt: reg(t)?, imm: i.truncate() },
|
||||
*/
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(inst)
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
@ -97,14 +101,7 @@ impl BasicInst {
|
||||
pub fn encode(self) -> u32 {
|
||||
#[rustfmt::skip]
|
||||
match self {
|
||||
//Self::Special(inst) => { let SpecialRaw { s, t, d, i, f } = inst.encode(); bitpack!("000000_sssss_ttttt_ddddd_iiiii_ffffff") },
|
||||
Self::Jmp (inst) => { let JmpRaw { p, i } = inst.encode(); bitpack!("00001p_iiiii_iiiii_iiiii_iiiii_iiiiii") },
|
||||
Self::Cond (inst) => { let CondRaw { p, s, t, i } = inst.encode(); bitpack!("000ppp_sssss_ttttt_iiiii_iiiii_iiiiii") },
|
||||
Self::Lui (inst) => { let LuiRaw { t, i } = inst.encode(); bitpack!("001111_00000_ttttt_iiiii_iiiii_iiiiii") },
|
||||
//Self::Alu (inst) => { let AluInstRaw { p, s, t, i } = inst.encode(); bitpack!("001ppp_sssss_ttttt_iiiii_iiiii_iiiiii") },
|
||||
Self::Alu(_) => todo!(),
|
||||
Self::Store(inst) => { let StoreRaw { p, s, t, i } = inst.encode(); bitpack!("100ppp_sssss_ttttt_iiiii_iiiii_iiiiii") },
|
||||
Self::Load (inst) => { let LoadRaw { p, s, t, i } = inst.encode(); bitpack!("101ppp_sssss_ttttt_iiiii_iiiii_iiiiii") },
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,27 +1,11 @@
|
||||
//! Alu immediate instructions
|
||||
|
||||
// Imports
|
||||
use crate::{exe::instruction::Register, util::SignedHex};
|
||||
use crate::exe::instruction::Register;
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::fmt;
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluImmInstRaw {
|
||||
/// Opcode (lower 3 bits)
|
||||
pub p: u32,
|
||||
|
||||
/// Rs
|
||||
pub s: u32,
|
||||
|
||||
/// Rt
|
||||
pub t: u32,
|
||||
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
}
|
||||
|
||||
|
||||
/// Alu immediate instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum AluImmInstKind {
|
||||
@ -81,6 +65,22 @@ impl AluImmInstKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluImmInstRaw {
|
||||
/// Opcode (lower 3 bits)
|
||||
pub p: u32,
|
||||
|
||||
/// Rs
|
||||
pub s: u32,
|
||||
|
||||
/// Rt
|
||||
pub t: u32,
|
||||
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
}
|
||||
|
||||
/// Alu register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
|
||||
@ -3,22 +3,6 @@
|
||||
// Imports
|
||||
use crate::exe::instruction::Register;
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluRegInstRaw {
|
||||
/// Rs
|
||||
s: u32,
|
||||
|
||||
/// Rt
|
||||
t: u32,
|
||||
|
||||
/// Rd
|
||||
d: u32,
|
||||
|
||||
/// Func
|
||||
f: u32,
|
||||
}
|
||||
|
||||
/// Alu register instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
@ -64,6 +48,22 @@ pub enum AluRegInstKind {
|
||||
SetLessThanUnsigned,
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluRegInstRaw {
|
||||
/// Rs
|
||||
s: u32,
|
||||
|
||||
/// Rt
|
||||
t: u32,
|
||||
|
||||
/// Rd
|
||||
d: u32,
|
||||
|
||||
/// Func (lower 4 bits)
|
||||
f: u32,
|
||||
}
|
||||
|
||||
/// Alu register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
@ -87,16 +87,16 @@ impl AluRegInst {
|
||||
#[must_use]
|
||||
pub fn decode(raw: AluRegInstRaw) -> Option<Self> {
|
||||
let kind = match raw.f {
|
||||
0x20 => AluRegInstKind::Add,
|
||||
0x21 => AluRegInstKind::AddUnsigned,
|
||||
0x22 => AluRegInstKind::Sub,
|
||||
0x23 => AluRegInstKind::SubUnsigned,
|
||||
0x24 => AluRegInstKind::And,
|
||||
0x25 => AluRegInstKind::Or,
|
||||
0x26 => AluRegInstKind::Xor,
|
||||
0x27 => AluRegInstKind::Nor,
|
||||
0x2a => AluRegInstKind::SetLessThan,
|
||||
0x2b => AluRegInstKind::SetLessThanUnsigned,
|
||||
0x0 => AluRegInstKind::Add,
|
||||
0x1 => AluRegInstKind::AddUnsigned,
|
||||
0x2 => AluRegInstKind::Sub,
|
||||
0x3 => AluRegInstKind::SubUnsigned,
|
||||
0x4 => AluRegInstKind::And,
|
||||
0x5 => AluRegInstKind::Or,
|
||||
0x6 => AluRegInstKind::Xor,
|
||||
0x7 => AluRegInstKind::Nor,
|
||||
0xa => AluRegInstKind::SetLessThan,
|
||||
0xb => AluRegInstKind::SetLessThanUnsigned,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
@ -112,16 +112,16 @@ impl AluRegInst {
|
||||
#[must_use]
|
||||
pub fn encode(self) -> AluRegInstRaw {
|
||||
let f = match self.kind {
|
||||
AluRegInstKind::Add => 0x20,
|
||||
AluRegInstKind::AddUnsigned => 0x21,
|
||||
AluRegInstKind::Sub => 0x22,
|
||||
AluRegInstKind::SubUnsigned => 0x23,
|
||||
AluRegInstKind::And => 0x24,
|
||||
AluRegInstKind::Or => 0x25,
|
||||
AluRegInstKind::Xor => 0x26,
|
||||
AluRegInstKind::Nor => 0x27,
|
||||
AluRegInstKind::SetLessThan => 0x2a,
|
||||
AluRegInstKind::SetLessThanUnsigned => 0x2b,
|
||||
AluRegInstKind::Add => 0x0,
|
||||
AluRegInstKind::AddUnsigned => 0x1,
|
||||
AluRegInstKind::Sub => 0x2,
|
||||
AluRegInstKind::SubUnsigned => 0x3,
|
||||
AluRegInstKind::And => 0x4,
|
||||
AluRegInstKind::Or => 0x5,
|
||||
AluRegInstKind::Xor => 0x6,
|
||||
AluRegInstKind::Nor => 0x7,
|
||||
AluRegInstKind::SetLessThan => 0xa,
|
||||
AluRegInstKind::SetLessThanUnsigned => 0xb,
|
||||
};
|
||||
|
||||
let d = self.dst.idx();
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
//! Condition branches
|
||||
|
||||
// Imports
|
||||
use crate::{exe::instruction::Register, util::SignedHex};
|
||||
use crate::exe::instruction::Register;
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::fmt;
|
||||
|
||||
|
||||
@ -1,74 +1,50 @@
|
||||
//! Alu register instructions
|
||||
//! Jmp register instructions
|
||||
|
||||
// Imports
|
||||
use std::fmt;
|
||||
// Modules
|
||||
pub mod imm;
|
||||
pub mod reg;
|
||||
|
||||
/// Alu register func (bottom bit)
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum JmpKind {
|
||||
/// Jump
|
||||
Jump,
|
||||
|
||||
/// Jump and link
|
||||
Link,
|
||||
}
|
||||
// Exports
|
||||
pub use imm::{JmpImmInst, JmpImmInstRaw};
|
||||
pub use reg::{JmpRegInst, JmpRegInstRaw};
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct JmpRaw {
|
||||
/// Opcode (bottom bit)
|
||||
pub p: u32,
|
||||
|
||||
pub enum JmpInstRaw {
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
Imm(JmpImmInstRaw),
|
||||
|
||||
/// Register
|
||||
Reg(JmpRegInstRaw),
|
||||
}
|
||||
|
||||
/// Alu register instructions
|
||||
/// Jmp register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct JmpInst {
|
||||
/// Target
|
||||
pub target: u32,
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum JmpInst {
|
||||
/// Immediate
|
||||
Imm(JmpImmInst),
|
||||
|
||||
/// Kind
|
||||
pub kind: JmpKind,
|
||||
/// Register
|
||||
Reg(JmpRegInst),
|
||||
}
|
||||
|
||||
impl JmpInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(raw: JmpRaw) -> Self {
|
||||
let kind = match raw.p {
|
||||
0 => JmpKind::Jump,
|
||||
1 => JmpKind::Link,
|
||||
_ => unreachable!("Received invalid bit in opcode."),
|
||||
};
|
||||
|
||||
Self { target: raw.i, kind }
|
||||
pub fn decode(raw: JmpInstRaw) -> Option<Self> {
|
||||
match raw {
|
||||
JmpInstRaw::Imm(raw) => Self::Imm(JmpImmInst::decode(raw)?),
|
||||
JmpInstRaw::Reg(raw) => Self::Reg(JmpRegInst::decode(raw)?),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
pub const fn encode(self) -> JmpRaw {
|
||||
let p = match self.kind {
|
||||
JmpKind::Jump => 0,
|
||||
JmpKind::Link => 1,
|
||||
};
|
||||
|
||||
JmpRaw { p, i: self.target }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Format with `pc` / `label`.
|
||||
|
||||
impl fmt::Display for JmpInst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Self { target, kind } = self;
|
||||
|
||||
let mnemonic = match kind {
|
||||
JmpKind::Jump => "j",
|
||||
JmpKind::Link => "jal",
|
||||
};
|
||||
|
||||
write!(f, "{mnemonic} {target:#x}")
|
||||
pub fn encode(self) -> JmpInstRaw {
|
||||
match self {
|
||||
JmpInst::Imm(inst) => JmpInstRaw::Imm(inst.encode()),
|
||||
JmpInst::Reg(inst) => JmpInstRaw::Reg(inst.encode()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
69
dcb-exe/src/exe/instruction/basic/jmp/imm.rs
Normal file
69
dcb-exe/src/exe/instruction/basic/jmp/imm.rs
Normal file
@ -0,0 +1,69 @@
|
||||
//! Jump immediate instructions
|
||||
|
||||
/// Jmp immediate instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum JmpImmInstKind {
|
||||
/// Jump
|
||||
Jump,
|
||||
|
||||
/// Jump and link
|
||||
JumpLink,
|
||||
}
|
||||
|
||||
impl JmpImmInstKind {
|
||||
/// Returns this kind's mnemonic
|
||||
pub fn mnemonic(self) -> &'static str {
|
||||
match self {
|
||||
JmpImmInstKind::Jump => "j",
|
||||
JmpImmInstKind::JumpLink => "jal",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct JmpImmInstRaw {
|
||||
/// Opcode (lower bit)
|
||||
pub p: u32,
|
||||
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
}
|
||||
|
||||
/// Jmp register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
#[display(fmt = "{} {target}", "kind.mnemonic()")]
|
||||
pub struct JmpImmInst {
|
||||
/// Target
|
||||
pub target: u32,
|
||||
|
||||
/// Kind
|
||||
pub kind: JmpImmInstKind,
|
||||
}
|
||||
|
||||
impl JmpImmInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(raw: JmpImmInstRaw) -> Option<Self> {
|
||||
let kind = match raw.p {
|
||||
0 => JmpImmInstKind::Jump,
|
||||
1 => JmpImmInstKind::JumpLink,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(Self { target: raw.i, kind })
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
pub fn encode(self) -> JmpImmInstRaw {
|
||||
let (p, i) = match self.kind {
|
||||
JmpImmInstKind::Jump => 0,
|
||||
JmpImmInstKind::JumpLink => 1,
|
||||
};
|
||||
let i = self.target;
|
||||
|
||||
JmpImmInstRaw { p, i }
|
||||
}
|
||||
}
|
||||
87
dcb-exe/src/exe/instruction/basic/jmp/reg.rs
Normal file
87
dcb-exe/src/exe/instruction/basic/jmp/reg.rs
Normal file
@ -0,0 +1,87 @@
|
||||
//! Jump register instructions
|
||||
|
||||
// Imports
|
||||
use crate::exe::instruction::Register;
|
||||
use std::fmt;
|
||||
|
||||
/// Jmp register instruction kind
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum JmpRegInstKind {
|
||||
/// Jump
|
||||
Jump,
|
||||
|
||||
/// Jump and link
|
||||
JumpLink(Register),
|
||||
}
|
||||
|
||||
impl JmpRegInstKind {
|
||||
/// Returns this kind's mnemonic
|
||||
pub fn mnemonic(self) -> &'static str {
|
||||
match self {
|
||||
JmpRegInstKind::Jump => "j",
|
||||
JmpRegInstKind::JumpLink(_) => "jal",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct JmpRegInstRaw {
|
||||
/// Rs
|
||||
s: u32,
|
||||
|
||||
/// Rd
|
||||
d: u32,
|
||||
|
||||
/// Func (lower bit)
|
||||
f: u32,
|
||||
}
|
||||
|
||||
/// Jmp register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct JmpRegInst {
|
||||
/// Target
|
||||
pub target: Register,
|
||||
|
||||
/// Kind
|
||||
pub kind: JmpRegInstKind,
|
||||
}
|
||||
|
||||
impl JmpRegInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(raw: JmpRegInstRaw) -> Option<Self> {
|
||||
let kind = match raw.f {
|
||||
0 => JmpRegInstKind::Jump,
|
||||
1 => JmpRegInstKind::JumpLink(Register::new(raw.d)?),
|
||||
_ => return None,
|
||||
};
|
||||
let target = Register::new(raw.s)?;
|
||||
|
||||
Some(Self { target, kind })
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
pub fn encode(self) -> JmpRegInstRaw {
|
||||
let (f, d) = match self.kind {
|
||||
JmpRegInstKind::Jump => (0, 0),
|
||||
JmpRegInstKind::JumpLink(reg) => (1, reg.idx()),
|
||||
};
|
||||
let s = self.target.idx();
|
||||
|
||||
JmpRegInstRaw { s, d, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JmpRegInst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mnemonic = self.kind.mnemonic();
|
||||
let target = self.target;
|
||||
|
||||
match self.kind {
|
||||
JmpRegInstKind::Jump => write!(f, "{mnemonic} {target}"),
|
||||
JmpRegInstKind::JumpLink(reg) => write!(f, "{mnemonic} {target}, {reg}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
//! Load instructions
|
||||
|
||||
// Imports
|
||||
use crate::{exe::instruction::Register, util::SignedHex};
|
||||
use crate::exe::instruction::Register;
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
//! ALU instructions
|
||||
|
||||
// Modules
|
||||
pub mod jmp;
|
||||
pub mod mult;
|
||||
pub mod shift;
|
||||
|
||||
// Exports
|
||||
pub use jmp::{JmpInst, JmpRaw};
|
||||
pub use mult::{MultInst, MultRaw};
|
||||
pub use shift::{ShiftInst, ShiftRaw};
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct SpecialRaw {
|
||||
/// Rs
|
||||
pub s: u32,
|
||||
|
||||
/// Rt
|
||||
pub t: u32,
|
||||
|
||||
/// Rd
|
||||
pub d: u32,
|
||||
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
|
||||
/// Func
|
||||
pub f: u32,
|
||||
}
|
||||
|
||||
impl From<SpecialRaw> for ShiftRaw {
|
||||
fn from(SpecialRaw { t, d, s, i, f }: SpecialRaw) -> Self {
|
||||
Self { t, d, s, i, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ShiftRaw> for SpecialRaw {
|
||||
fn from(ShiftRaw { t, d, s, i, f }: ShiftRaw) -> Self {
|
||||
Self { t, d, s, i, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpecialRaw> for JmpRaw {
|
||||
fn from(SpecialRaw { d, s, f, .. }: SpecialRaw) -> Self {
|
||||
Self { d, s, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JmpRaw> for SpecialRaw {
|
||||
fn from(JmpRaw { d, s, f }: JmpRaw) -> Self {
|
||||
Self { t: 0, d, s, i: 0, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpecialRaw> for SysRaw {
|
||||
fn from(SpecialRaw { t, d, s, i, f }: SpecialRaw) -> Self {
|
||||
Self { t, d, s, i, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SysRaw> for SpecialRaw {
|
||||
fn from(SysRaw { t, d, s, i, f }: SysRaw) -> Self {
|
||||
Self { t, d, s, i, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpecialRaw> for MultRaw {
|
||||
fn from(SpecialRaw { t, d, s, f, .. }: SpecialRaw) -> Self {
|
||||
Self { t, d, s, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MultRaw> for SpecialRaw {
|
||||
fn from(MultRaw { t, d, s, f }: MultRaw) -> Self {
|
||||
Self { t, d, s, i: 0, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpecialRaw> for AluRegRaw {
|
||||
fn from(SpecialRaw { t, d, s, f, .. }: SpecialRaw) -> Self {
|
||||
Self { t, d, s, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AluRegRaw> for SpecialRaw {
|
||||
fn from(AluRegRaw { t, d, s, f }: AluRegRaw) -> Self {
|
||||
Self { t, d, s, i: 0, f }
|
||||
}
|
||||
}
|
||||
|
||||
/// Special instructions for `opcode: 0`
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum SpecialInst {
|
||||
/// Shift instruction
|
||||
Shift(ShiftInst),
|
||||
|
||||
/// Jump
|
||||
Jmp(JmpInst),
|
||||
|
||||
/// Sys
|
||||
Sys(SysInst),
|
||||
|
||||
/// Mult
|
||||
Mult(MultInst),
|
||||
|
||||
/// Alu
|
||||
Alu(AluRegInst),
|
||||
}
|
||||
|
||||
impl SpecialInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(raw: SpecialRaw) -> Option<Self> {
|
||||
Some(match raw.f {
|
||||
0x00..0x08 => Self::Shift(ShiftInst::decode(raw.into())?),
|
||||
0x08..0x0c => Self::Jmp(JmpInst::decode(raw.into())?),
|
||||
0x0c..0x10 => Self::Sys(SysInst::decode(raw.into())?),
|
||||
0x10..0x20 => Self::Mult(MultInst::decode(raw.into())?),
|
||||
0x20..0x30 => Self::Alu(AluRegInst::decode(raw.into())?),
|
||||
0x30..0x40 => return None,
|
||||
|
||||
_ => unreachable!("Func was larger than 6 bits."),
|
||||
})
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
pub fn encode(self) -> SpecialRaw {
|
||||
match self {
|
||||
Self::Shift(inst) => inst.encode().into(),
|
||||
Self::Jmp(inst) => inst.encode().into(),
|
||||
Self::Sys(inst) => inst.encode().into(),
|
||||
Self::Mult(inst) => inst.encode().into(),
|
||||
Self::Alu(inst) => inst.encode().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
//! Alu register instructions
|
||||
|
||||
// Imports
|
||||
use crate::exe::instruction::Register;
|
||||
use int_conv::{Truncated, ZeroExtended};
|
||||
use std::{convert::TryFrom, fmt};
|
||||
|
||||
/// Alu register instruction kind
|
||||
///
|
||||
/// Each variant's value is equal to the lower 4 bits of the opcode
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum AluRegKind {
|
||||
/// Add
|
||||
Add = 0x20,
|
||||
|
||||
/// Add unsigned
|
||||
AddUnsigned = 0x21,
|
||||
|
||||
/// Sub
|
||||
Sub = 0x22,
|
||||
|
||||
/// Sub unsigned
|
||||
SubUnsigned = 0x23,
|
||||
|
||||
/// And
|
||||
And = 0x24,
|
||||
|
||||
/// Or
|
||||
Or = 0x25,
|
||||
|
||||
/// Xor
|
||||
Xor = 0x26,
|
||||
|
||||
/// Nor
|
||||
Nor = 0x27,
|
||||
|
||||
/// Set less than
|
||||
SetLessThan = 0x2a,
|
||||
|
||||
/// Set less than unsigned
|
||||
SetLessThanUnsigned = 0x2b,
|
||||
}
|
||||
|
||||
impl AluRegKind {
|
||||
pub fn mnemonic(self) -> &'static str {
|
||||
match self {
|
||||
Self::Add => "add",
|
||||
Self::AddUnsigned => "addu",
|
||||
Self::Sub => "sub",
|
||||
Self::SubUnsigned => "subu",
|
||||
Self::And => "and",
|
||||
Self::Or => "or",
|
||||
Self::Xor => "xor",
|
||||
Self::Nor => "nor",
|
||||
Self::SetLessThan => "slt",
|
||||
Self::SetLessThanUnsigned => "sltu",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluRegRaw {
|
||||
/// Rs
|
||||
pub s: u32,
|
||||
|
||||
/// Rt
|
||||
pub t: u32,
|
||||
|
||||
/// Rd
|
||||
pub d: u32,
|
||||
|
||||
/// Func
|
||||
pub f: u32,
|
||||
}
|
||||
|
||||
/// Alu register instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct AluRegInst {
|
||||
/// Destination register, `rd`
|
||||
pub dst: Register,
|
||||
|
||||
/// Lhs argument, `rs`
|
||||
pub lhs: Register,
|
||||
|
||||
/// Rhs argument, `rt`
|
||||
pub rhs: Register,
|
||||
|
||||
/// Kind
|
||||
pub kind: AluRegKind,
|
||||
}
|
||||
|
||||
impl AluRegInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(raw: AluRegRaw) -> Option<Self> {
|
||||
let kind = AluRegKind::try_from(raw.f.truncated::<u8>()).ok()?;
|
||||
|
||||
Some(Self {
|
||||
dst: Register::new(raw.d)?,
|
||||
lhs: Register::new(raw.s)?,
|
||||
rhs: Register::new(raw.t)?,
|
||||
kind,
|
||||
})
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
pub fn encode(self) -> AluRegRaw {
|
||||
let d = self.dst.idx();
|
||||
let s = self.lhs.idx();
|
||||
let t = self.rhs.idx();
|
||||
let f = u8::from(self.kind).zero_extended::<u32>();
|
||||
|
||||
AluRegRaw { f, t, d, s }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AluRegInst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Self { dst, lhs, rhs, kind } = self;
|
||||
|
||||
let mnemonic = kind.mnemonic();
|
||||
|
||||
write!(f, "{mnemonic} {dst}, {lhs}, {rhs}")
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
//! Store instructions
|
||||
|
||||
// Imports
|
||||
use crate::{exe::instruction::Register, util::SignedHex};
|
||||
use crate::exe::instruction::Register;
|
||||
use dcb_util::SignedHex;
|
||||
use int_conv::{Signed, Truncated, ZeroExtended};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
||||
@ -1,89 +1,70 @@
|
||||
//! System calls
|
||||
|
||||
// Imports
|
||||
use int_conv::{Truncated, ZeroExtended};
|
||||
use std::{convert::TryFrom, fmt};
|
||||
|
||||
/// Sys instruction func
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum SysFunc {
|
||||
/// Sys
|
||||
Sys = 0xc,
|
||||
pub enum SysInstKind {
|
||||
/// Syscall
|
||||
Sys,
|
||||
|
||||
/// Break
|
||||
Break = 0xd,
|
||||
Break,
|
||||
}
|
||||
|
||||
impl SysInstKind {
|
||||
/// Returns the mnemonic associated with this syscall kind
|
||||
pub fn mnemonic(self) -> &'static str {
|
||||
match self {
|
||||
SysInstKind::Sys => "sys",
|
||||
SysInstKind::Break => "break",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw representation
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct SysRaw {
|
||||
/// Rs
|
||||
pub s: u32,
|
||||
pub struct SysInstRaw {
|
||||
/// Comment
|
||||
pub c: u32,
|
||||
|
||||
/// Rt
|
||||
pub t: u32,
|
||||
|
||||
/// Rd
|
||||
pub d: u32,
|
||||
|
||||
/// Immediate
|
||||
pub i: u32,
|
||||
|
||||
/// Func
|
||||
/// Func (bottom bit)
|
||||
pub f: u32,
|
||||
}
|
||||
|
||||
/// Syscall instructions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
#[display(fmt = "{}, {comment:#x}", "kind.mnemonic()")]
|
||||
pub struct SysInst {
|
||||
/// Comment
|
||||
pub comment: u32,
|
||||
|
||||
/// Function
|
||||
pub func: SysFunc,
|
||||
/// Kind
|
||||
pub kind: SysInstKind,
|
||||
}
|
||||
|
||||
impl SysInst {
|
||||
/// Decodes this instruction
|
||||
#[must_use]
|
||||
pub fn decode(SysRaw { t, d, s, i, f }: SysRaw) -> Option<Self> {
|
||||
let s = s.truncated::<u8>();
|
||||
let t = t.truncated::<u8>();
|
||||
let d = d.truncated::<u8>();
|
||||
let i = i.truncated::<u8>();
|
||||
let comment = u32::from_be_bytes([s, t, d, i]);
|
||||
pub fn decode(SysInstRaw { c, f }: SysInstRaw) -> Option<Self> {
|
||||
let kind = match f {
|
||||
0 => SysInstKind::Sys,
|
||||
1 => SysInstKind::Break,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let func = SysFunc::try_from(f.truncated::<u8>()).ok()?;
|
||||
|
||||
Some(Self { comment, func })
|
||||
Some(Self { comment: c, kind })
|
||||
}
|
||||
|
||||
/// Encodes this instruction
|
||||
#[must_use]
|
||||
#[allow(clippy::many_single_char_names)] // `Raw` has single character names
|
||||
pub fn encode(self) -> SysRaw {
|
||||
let [s, t, d, i] = self.comment.to_be_bytes();
|
||||
let s = s.zero_extended::<u32>();
|
||||
let t = t.zero_extended::<u32>();
|
||||
let d = d.zero_extended::<u32>();
|
||||
let i = i.zero_extended::<u32>();
|
||||
let f = u8::from(self.func).zero_extended::<u32>();
|
||||
|
||||
SysRaw { s, t, d, i, f }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SysInst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Self { func, comment } = self;
|
||||
|
||||
let mnemonic = match func {
|
||||
SysFunc::Sys => "sys",
|
||||
SysFunc::Break => "break",
|
||||
pub fn encode(self) -> SysInstRaw {
|
||||
let c = self.comment.to_be_bytes();
|
||||
let f = match self.kind {
|
||||
SysInstKind::Sys => 0,
|
||||
SysInstKind::Break => 1,
|
||||
};
|
||||
|
||||
write!(f, "{mnemonic} {comment:#x}")
|
||||
SysInstRaw { c, f }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
//! Load immediate
|
||||
|
||||
// Imports
|
||||
use crate::{
|
||||
exe::instruction::{
|
||||
basic::{alu_imm::AluImmKind, AluImmInst, InstIter},
|
||||
BasicInst, Register,
|
||||
},
|
||||
util::SignedHex,
|
||||
use crate::exe::instruction::{
|
||||
basic::{alu_imm::AluImmKind, AluImmInst, InstIter},
|
||||
BasicInst, Register,
|
||||
};
|
||||
use dcb_util::SignedHex;
|
||||
use std::fmt;
|
||||
|
||||
/// Immediate kind
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user