big rewrite, everything half broken
This commit is contained in:
parent
ec727af8dd
commit
7a6b4df8d4
|
@ -83,6 +83,12 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
|
@ -211,6 +217,12 @@ version = "0.2.99"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
|
@ -314,6 +326,7 @@ version = "0.1.1"
|
|||
dependencies = [
|
||||
"num-traits",
|
||||
"ppc750cl-macros",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -340,8 +353,11 @@ dependencies = [
|
|||
name = "ppc750cl-macros"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"syn",
|
||||
]
|
||||
|
||||
|
@ -499,24 +515,36 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.128"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834"
|
||||
checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.128"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4"
|
||||
checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6375dbd828ed6964c3748e4ef6d18e7a175d408ffe184bca01698d0c73f915a9"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sfmt"
|
||||
version = "0.6.0"
|
||||
|
@ -630,3 +658,12 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -11,3 +11,4 @@ repository = "https://github.com/terorie/ppc750cl"
|
|||
[dependencies]
|
||||
num-traits = "0.2.14"
|
||||
ppc750cl-macros = { path = "../macros", version = "0.1.1" }
|
||||
serde = "1.0.129"
|
||||
|
|
|
@ -5,208 +5,103 @@ use num_traits::PrimInt;
|
|||
|
||||
use crate::Ins;
|
||||
|
||||
/*
|
||||
type IOResult = std::io::Result<()>;
|
||||
|
||||
pub trait AsmFormatter<W>
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
/// Returns the underlying writer.
|
||||
fn writer(&mut self) -> &mut W;
|
||||
fn write_ins(ins: &Ins);
|
||||
}
|
||||
|
||||
/// Callback for custom styling before writing an instruction.
|
||||
fn before_instruction(&mut self, _: &Ins) -> IOResult {
|
||||
Ok(())
|
||||
}
|
||||
/// Callback for custom styling after writing an instruction.
|
||||
fn after_instruction(&mut self, _: &Ins) -> IOResult {
|
||||
Ok(())
|
||||
}
|
||||
pub struct SimpleFormatter();
|
||||
|
||||
impl<W: Write> SimpleFormatter {
|
||||
/// Writes the instruction mnemonic.
|
||||
fn write_mnemonic(&mut self, name: &str) -> IOResult {
|
||||
write!(self.writer(), "{}", name)
|
||||
fn write_mnemonic(writer: &mut W, name: &str) -> IOResult {
|
||||
write!(writer, "{}", name)
|
||||
}
|
||||
|
||||
/// Separates the instruction mnemonic and arguments.
|
||||
fn write_opcode_separator(&mut self) -> IOResult {
|
||||
write!(self.writer(), " ")
|
||||
fn write_opcode_separator(writer: &mut W) -> IOResult {
|
||||
write!(writer, " ")
|
||||
}
|
||||
|
||||
/// Separates two instruction arguments (e.g. registers).
|
||||
fn write_operand_separator(&mut self) -> IOResult {
|
||||
write!(self.writer(), ", ")
|
||||
fn write_operand_separator(writer: &mut W) -> IOResult {
|
||||
write!(writer, ", ")
|
||||
}
|
||||
|
||||
/// Writes a general-purpose register argument.
|
||||
fn write_gpr(&mut self, reg: u8) -> IOResult {
|
||||
write!(self.writer(), "r{}", reg)
|
||||
fn write_gpr(writer: &mut W, reg: u8) -> IOResult {
|
||||
write!(writer, "r{}", reg)
|
||||
}
|
||||
|
||||
/// Writes a nullable general-purpose register argument.
|
||||
fn write_gpr0(&mut self, reg: u8) -> IOResult {
|
||||
fn write_gpr0(writer: &mut W, reg: u8) -> IOResult {
|
||||
if reg != 0 {
|
||||
self.write_gpr(reg)
|
||||
Self::write_gpr(writer, reg)
|
||||
} else {
|
||||
write!(self.writer(), "0")
|
||||
write!(writer, "0")
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a floating point register argument.
|
||||
fn write_fpr(&mut self, reg: u8) -> IOResult {
|
||||
write!(self.writer(), "f{}", reg)
|
||||
fn write_fpr(writer: &mut W, reg: u8) -> IOResult {
|
||||
write!(writer, "f{}", reg)
|
||||
}
|
||||
|
||||
/// Writes a condition register argument.
|
||||
fn write_cr(&mut self, reg: u8) -> IOResult {
|
||||
write!(self.writer(), "cr{}", reg)
|
||||
fn write_cr(writer: &mut W, reg: u8) -> IOResult {
|
||||
write!(writer, "cr{}", reg)
|
||||
}
|
||||
|
||||
/// Writes a paired-singles quantization register argument.
|
||||
fn write_qr(&mut self, reg: u8) -> IOResult {
|
||||
write!(self.writer(), "qr{}", reg)
|
||||
fn write_qr(writer: &mut W, reg: u8) -> IOResult {
|
||||
write!(writer, "qr{}", reg)
|
||||
}
|
||||
|
||||
fn write_sr(&mut self, reg: u8) -> IOResult {
|
||||
write!(self.writer(), "{}", reg)
|
||||
fn write_sr(writer: &mut W, reg: u8) -> IOResult {
|
||||
write!(writer, "{}", reg)
|
||||
}
|
||||
|
||||
/// Sets the mnemonic 'o' suffix.
|
||||
fn write_oe(&mut self, oe: u8) -> IOResult {
|
||||
fn write_oe(writer: &mut W, oe: u8) -> IOResult {
|
||||
if oe != 0 {
|
||||
write!(self.writer(), "o")?;
|
||||
write!(writer, "o")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the mnemonic 'a' suffix.
|
||||
fn write_aa(&mut self, aa: u8) -> IOResult {
|
||||
fn write_aa(writer: &mut W, aa: u8) -> IOResult {
|
||||
if aa != 0 {
|
||||
write!(self.writer(), "a")?;
|
||||
write!(writer, "a")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the mnemonic 'l' suffix.
|
||||
fn write_lk(&mut self, lk: u8) -> IOResult {
|
||||
fn write_lk(writer: &mut W, lk: u8) -> IOResult {
|
||||
if lk != 0 {
|
||||
write!(self.writer(), "l")?;
|
||||
write!(writer, "l")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the mnemonic '.' suffix.
|
||||
fn write_rc(&mut self, rc: u8) -> IOResult {
|
||||
fn write_rc(writer: &mut W, rc: u8) -> IOResult {
|
||||
if rc != 0 {
|
||||
write!(self.writer(), ".")?;
|
||||
write!(writer, ".")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes an unsigned immediate.
|
||||
fn write_uimm<T: Into<u16>>(&mut self, uimm: T) -> IOResult {
|
||||
let uimm = uimm.into();
|
||||
if uimm < 16 {
|
||||
write!(self.writer(), "{}", uimm)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}", uimm)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a signed immediate.
|
||||
fn write_simm<T: PrimInt + Into<i32> + Display>(&mut self, simm: T) -> IOResult {
|
||||
let simm: i32 = simm.into();
|
||||
if simm < 8 {
|
||||
write!(self.writer(), "{}", simm)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}", ReallySigned(simm))
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an instruction-specific field like the compare mode.
|
||||
fn write_mode<P: PrimInt + Display>(&mut self, mode: P) -> IOResult {
|
||||
write!(self.writer(), "{}", mode)
|
||||
}
|
||||
|
||||
fn write_fm(&mut self, fm: u16) -> IOResult {
|
||||
write!(self.writer(), "{}", fm)
|
||||
}
|
||||
|
||||
fn write_offset_unsigned_open<T: Into<u32>>(&mut self, offset: T) -> IOResult {
|
||||
let offset = offset.into();
|
||||
if offset < 15 {
|
||||
write!(self.writer(), "{}(", offset)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}(", offset)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an offset prefix.
|
||||
///
|
||||
/// The next write calls that follow should be:
|
||||
/// - An operand (almost always a general-purpose register)
|
||||
/// - `write_offset_close()`
|
||||
fn write_offset_open<T: Into<i32>>(&mut self, offset: T) -> IOResult {
|
||||
let offset = offset.into();
|
||||
if -9 < offset && offset < 10 {
|
||||
write!(self.writer(), "{}(", offset)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}(", ReallySigned(offset))
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes an offset prefix.
|
||||
fn write_offset_close(&mut self) -> IOResult {
|
||||
write!(self.writer(), ")")
|
||||
}
|
||||
|
||||
/// Writes a branch target given the jump offset and current program counter.
|
||||
fn write_branch_target(&mut self, offset: i32, _: u32) -> IOResult {
|
||||
write!(self.writer(), "{:#x}", ReallySigned(offset))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleFormatter<W: Write> {
|
||||
pub writer: W,
|
||||
}
|
||||
|
||||
impl<W: Write> SimpleFormatter<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self { writer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> AsmFormatter<W> for SimpleFormatter<W> {
|
||||
fn writer(&mut self) -> &mut W {
|
||||
&mut self.writer
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DoldecompFormatter<W: Write> {
|
||||
pub writer: W,
|
||||
}
|
||||
|
||||
impl<W: Write> DoldecompFormatter<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self { writer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> AsmFormatter<W> for DoldecompFormatter<W> {
|
||||
fn writer(&mut self) -> &mut W {
|
||||
&mut self.writer
|
||||
}
|
||||
|
||||
fn before_instruction(&mut self, ins: &Ins) -> IOResult {
|
||||
write!(
|
||||
&mut self.writer,
|
||||
"/* {:0>8X} {:0>2X} {:0>2X} {:0>2X} {:0>2X} */\t",
|
||||
ins.addr,
|
||||
(ins.code >> 24) as u8,
|
||||
(ins.code >> 16) as u8,
|
||||
(ins.code >> 8) as u8,
|
||||
ins.code as u8
|
||||
)
|
||||
fn write_ins(ins: &Ins) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,22 +125,4 @@ impl<N: PrimInt> UpperHex for ReallySigned<N> {
|
|||
f.pad_integral(num >= 0, prefix, &bare_hex)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_doldecomp_formatter() {
|
||||
let buf = Vec::<u8>::new();
|
||||
let mut formatter = DoldecompFormatter::new(buf);
|
||||
|
||||
let ins = Ins::new(0x48000007, 6);
|
||||
ins.write_string(&mut formatter).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
String::from_utf8(formatter.writer).unwrap(),
|
||||
"/* 00000006 48 00 00 07 */\tbla 0x4"
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,570 +0,0 @@
|
|||
#![allow(clippy::bad_bit_mask)]
|
||||
|
||||
use crate::{bit, bits};
|
||||
use ppc750cl_macros::isa;
|
||||
|
||||
isa! {
|
||||
"add" & 0xfc0007fe == 0x7c000214;
|
||||
//"addc" & 0xfc0007fe == 0x7c00002a;
|
||||
"addc" & 0x0 == 0x0;
|
||||
"adde" & 0xfc0007fe == 0x7c000114;
|
||||
"addi" & 0xfc000000 == 0x38000000;
|
||||
"addic" & 0xfc000000 == 0x30000000;
|
||||
"addic." & 0xfc000000 == 0x34000000;
|
||||
"addis" & 0xfc000000 == 0x3c000000;
|
||||
"addme" & 0xfc00fbfe == 0x7c0001d4;
|
||||
"addze" & 0xfc00fbfe == 0x7c000194;
|
||||
"and" & 0xfc0007fe == 0x7c000038;
|
||||
"andc" & 0xfc0007fe == 0x7c000078;
|
||||
"andi." & 0xfc000000 == 0x70000000;
|
||||
"andis." & 0xfc000000 == 0x74000000;
|
||||
"b" & 0xfc000000 == 0x48000000;
|
||||
//"bc" & 0xfc000000 == 0x40000000;
|
||||
"bc" & 0x0 == 0x0; // TODO
|
||||
//"bcctr" & 0xfc00ffff == 0x4c000210;
|
||||
"bcctr" & 0x0 == 0x0; // TODO
|
||||
"bclr" & 0xfc00fffe == 0x4c000020;
|
||||
"cmp" & 0xfc4007ff == 0x7c000000;
|
||||
"cmpi" & 0xfc400000 == 0x2c000000;
|
||||
"cmpl" & 0xfc4007ff == 0x7c000040;
|
||||
"cmpli" & 0xfc400000 == 0x28000000;
|
||||
"cntlzw" & 0xfc00fffe == 0x7c000034;
|
||||
"crand" & 0xfc0007ff == 0x4c000202;
|
||||
"crandc" & 0xfc0007ff == 0x4c000102;
|
||||
"creqv" & 0xfc0007ff == 0x4c000242;
|
||||
"crnand" & 0xfc0007ff == 0x4c0001c2;
|
||||
"crnor" & 0xfc0007ff == 0x4c000042;
|
||||
"cror" & 0xfc0007ff == 0x4c000382;
|
||||
"crorc" & 0xfc0007ff == 0x4c000342;
|
||||
"crxor" & 0xfc0007ff == 0x4c000182;
|
||||
"dcbf" & 0xffe007ff == 0x7c0000ac;
|
||||
"dcbi" & 0xffe007ff == 0x7c0003ac;
|
||||
"dcbst" & 0xffe007ff == 0x7c00006c;
|
||||
"dcbt" & 0xffe007ff == 0x7c00022c;
|
||||
"dcbtst" & 0xffe007ff == 0x7c0001ec;
|
||||
"dcbz" & 0xffe007ff == 0x7c0007ec;
|
||||
"dcbz_l" & 0xffe007ff == 0x100007ec;
|
||||
"divw" & 0xfc0003fe == 0x7c0003d6;
|
||||
"divwu" & 0xfc0003fe == 0x7c000396;
|
||||
"eciwx" & 0xfc0003ff == 0x7c00026c;
|
||||
"ecowx" & 0xfc0003ff == 0x7c00036c;
|
||||
"eieio" & 0xffffffff == 0x7c0006ac;
|
||||
"eqv" & 0xfc0003fe == 0x7c000238;
|
||||
"extsb" & 0xfc00fffe == 0x7c000774;
|
||||
"extsh" & 0xfc00fffe == 0x7c000734;
|
||||
//"fabs" & 0xfc1f07fe == 0xfc000734;
|
||||
"fabs" & 0x0 == 0x0; // TODO
|
||||
"fadd" & 0xfc0007fe == 0xfc00002a;
|
||||
"fadds" & 0xfc0007fe == 0xec00002a;
|
||||
"fcmpo" & 0xfc6007ff == 0xfc000040;
|
||||
"fcmpu" & 0xfc6007ff == 0xfc000000;
|
||||
"fctiw" & 0xfc1f07fe == 0xfc00001c;
|
||||
"fctiwz" & 0xfc1f07fe == 0xfc00001e;
|
||||
"fdiv" & 0xfc0007fe == 0xfc000024;
|
||||
"fdivs" & 0xfc0007fe == 0xec000024;
|
||||
"fmadd" & 0xfc00003e == 0xfc00003a;
|
||||
"fmadds" & 0xfc00003e == 0xec00003a;
|
||||
"fmr" & 0xfc1f07fe == 0xfc000090;
|
||||
"fmsub" & 0xfc00003e == 0xfc000038;
|
||||
"fmsubs" & 0xfc00003e == 0xec000038;
|
||||
"fmul" & 0xfc00f83e == 0xfc000032;
|
||||
"fmuls" & 0xfc00f83e == 0xec000032;
|
||||
"fnabs" & 0xfc1f07fe == 0xfc000110;
|
||||
//"fneg" & 0xfc1f07fe == 0xfc000050;
|
||||
"fneg" & 0x0 == 0x0; // TODO
|
||||
"fnmadd" & 0xfc00003e == 0xfc00003e;
|
||||
"fnmadds" & 0xfc00003e == 0xec00003e;
|
||||
"fnmsub" & 0xfc00003e == 0xfc00003c;
|
||||
"fnmsubs" & 0xfc00003e == 0xec00003c;
|
||||
"fres" & 0xfc1f07fe == 0xec000030;
|
||||
"frsp" & 0xfc1f07fe == 0xfc000018;
|
||||
"frsqrte" & 0xfc1f07fe == 0xfc000034;
|
||||
"fsel" & 0xfc00003e == 0xfc00002e;
|
||||
"fsub" & 0xfc0007fe == 0xfc000028;
|
||||
"fsubs" & 0xfc0007fe == 0xec000028;
|
||||
"icbi" & 0xffe007ff == 0x7c0007ac;
|
||||
"isync" & 0xffffffff == 0x4c00012c;
|
||||
"lbz" & 0xfc000000 == 0x88000000;
|
||||
"lbzu" & 0xfc000000 == 0x8c000000;
|
||||
"lbzux" & 0xfc0007ff == 0x7c0000ee;
|
||||
"lbzx" & 0xfc0007ff == 0x7c0000ae;
|
||||
"lfd" & 0xfc000000 == 0xc8000000;
|
||||
"lfdu" & 0xfc000000 == 0xcc000000;
|
||||
"lfdux" & 0xfc0007ff == 0x7c0004ee;
|
||||
//"lfdx" & 0xfc0007ff == 0x7c00045e;
|
||||
"lfdx" & 0x0 == 0x0;
|
||||
"lfs" & 0xfc000000 == 0xc0000000;
|
||||
"lfsu" & 0xfc000000 == 0xc4000000;
|
||||
"lfsux" & 0xfc0007ff == 0x7c00046e;
|
||||
"lfsx" & 0xfc0007ff == 0x7c00042e;
|
||||
"lha" & 0xfc000000 == 0xa8000000;
|
||||
"lhau" & 0xfc000000 == 0xac000000;
|
||||
"lhaux" & 0xfc0007ff == 0x7c0002ee;
|
||||
"lhax" & 0xfc0007ff == 0x7c0002ae;
|
||||
"lhbrx" & 0xfc0007ff == 0x7c00062c;
|
||||
"lhz" & 0xfc000000 == 0xa0000000;
|
||||
"lhzu" & 0xfc000000 == 0xa4000000;
|
||||
"lhzux" & 0xfc0007ff == 0x7c00026e;
|
||||
"lhzx" & 0xfc0007ff == 0x7c00022e;
|
||||
"lmw" & 0xfc000000 == 0xb8000000;
|
||||
"lswi" & 0xfc0007ff == 0x7c0004aa;
|
||||
"lswx" & 0xfc0007ff == 0x7c00042a;
|
||||
"lwarx" & 0xfc0007ff == 0x7c000028;
|
||||
"lwbrx" & 0xfc0007ff == 0x7c00042c;
|
||||
"lwz" & 0xfc000000 == 0x80000000;
|
||||
"lwzu" & 0xfc000000 == 0x84000000;
|
||||
"lwzux" & 0xfc0007ff == 0x7c00006e;
|
||||
"lwzx" & 0xfc0007ff == 0x7c00002e;
|
||||
"mcrf" & 0xfc300fff == 0x4c000000;
|
||||
"mcrfs" & 0xfc30ffff == 0xfc000080;
|
||||
"mcrxr" & 0xfc30ffff == 0x7c000400;
|
||||
"mfcr" & 0xfc1fffff == 0x7c000026;
|
||||
//"mffs" & 0xfc1ffffe == 0x7c00048e;
|
||||
"mffs" & 0x0 == 0x0; // TODO
|
||||
"mfmsr" & 0xfc1fffff == 0x7c0000a6;
|
||||
"mfspr" & 0xfc0007ff == 0x7c0002a6;
|
||||
"mfsr" & 0xfc10ffff == 0x7c0004a6;
|
||||
"mfsrin" & 0xfc1f07ff == 0x7c000526;
|
||||
"mftb" & 0xfc0007ff == 0x7c0002e6;
|
||||
"mtcrf" & 0xfc100fff == 0x7c000120;
|
||||
"mtfsb0" & 0xfc1ffffe == 0xfc00008c;
|
||||
"mtfsb1" & 0xfc1ffffe == 0xfc00004c;
|
||||
"mtfsf" & 0xfe0107fe == 0xfc00058e;
|
||||
"mtfsfi" & 0xfc7f0ffe == 0xfc00010c;
|
||||
"mtmsr" & 0xfc1fffff == 0x7c000124;
|
||||
"mtspr" & 0xfc0007ff == 0x7c0003a6;
|
||||
"mtsr" & 0xfc10ffff == 0x7c0001a4;
|
||||
"mtsrin" & 0xfc1f07ff == 0x7c0001e4;
|
||||
//"mulhw" & 0xfc0007fe == 0x7c000096;
|
||||
"mulhw" & 0x0 == 0x0;
|
||||
//"mulhwu" & 0xfc0007fe == 0x7c000016;
|
||||
"mulhwu" & 0x0 == 0x0;
|
||||
"mulli" & 0xfc000000 == 0x1c000000;
|
||||
"mullw" & 0xfc0003fe == 0x7c0001d6;
|
||||
"nand" & 0xfc0007fe == 0x7c0003b8;
|
||||
"neg" & 0xfc00fffe == 0x7c0000d0;
|
||||
"nor" & 0xfc0007fe == 0x7c0000f8;
|
||||
"or" & 0xfc0007fe == 0x7c000378;
|
||||
"orc" & 0xfc0007fe == 0x7c000338;
|
||||
"ori" & 0xfc000000 == 0x60000000;
|
||||
"oris" & 0xfc000000 == 0x64000000;
|
||||
"psq_l" & 0xfc000000 == 0xe0000000;
|
||||
"psq_lu" & 0xfc000000 == 0xe4000000;
|
||||
"psq_lux" & 0xfc00007f == 0x1000004c;
|
||||
"psq_lx" & 0xfc00007f == 0x1000000c;
|
||||
"psq_st" & 0xfc000000 == 0xf0000000;
|
||||
"psq_stu" & 0xfc000000 == 0xf4000000;
|
||||
"psq_stux" & 0xfc00007f == 0x1000004e;
|
||||
"psq_stx" & 0xfc00007f == 0x1000000e;
|
||||
"ps_abs" & 0xfc1f07fe == 0x10000210;
|
||||
"ps_add" & 0xfc0007fe == 0x1000002a;
|
||||
"ps_cmpo0" & 0xfc6007ff == 0x10000040;
|
||||
"ps_cmpo1" & 0xfc6007ff == 0x100000c0;
|
||||
"ps_cmpu0" & 0xfc6007ff == 0x10000000;
|
||||
"ps_cmpu1" & 0xfc6007ff == 0x10000080;
|
||||
"ps_div" & 0xfc0007fe == 0x10000024;
|
||||
"ps_madd" & 0xfc00003e == 0x1000003a;
|
||||
"ps_madds0" & 0xfc00003e == 0x1000001c;
|
||||
"ps_madds1" & 0xfc00003e == 0x1000001e;
|
||||
"ps_merge00" & 0xfc0007fe == 0x10000420;
|
||||
"ps_merge01" & 0xfc0007fe == 0x10000460;
|
||||
"ps_merge10" & 0xfc0007fe == 0x100004a0;
|
||||
"ps_merge11" & 0xfc0007fe == 0x100004e0;
|
||||
"ps_mr" & 0xfc1f07fe == 0x10000090;
|
||||
"ps_msub" & 0xfc00003e == 0x10000038;
|
||||
"ps_mul" & 0xfc00f83e == 0x10000032;
|
||||
"ps_muls0" & 0xfc00f83e == 0x10000018;
|
||||
"ps_muls1" & 0xfc00f83e == 0x1000001a;
|
||||
"ps_nabs" & 0xfc1f07fe == 0x10000110;
|
||||
"ps_neg" & 0xfc1f07fe == 0x10000050;
|
||||
"ps_nmadd" & 0xfc00003e == 0x1000003e;
|
||||
"ps_nmsub" & 0xfc00003e == 0x1000003c;
|
||||
"ps_res" & 0xfc1f07fe == 0x10000030;
|
||||
"ps_rsqrte" & 0xfc1f07fe == 0x10000034;
|
||||
"ps_sel" & 0xfc00003e == 0x1000002e;
|
||||
"ps_sub" & 0xfc0007fe == 0x10000028;
|
||||
"ps_sum0" & 0xfc00003e == 0x10000014;
|
||||
"ps_sum1" & 0xfc00003e == 0x10000016;
|
||||
"rfi" & 0xfffff801 == 0x4c000000;
|
||||
"rlwimi" & 0xfc000000 == 0x50000000;
|
||||
"rlwinm" & 0xfc000000 == 0x54000000;
|
||||
"rlwnm" & 0xfc000000 == 0x5c000000;
|
||||
"sc" & 0xffffffff == 0x44000002;
|
||||
"slw" & 0xfc0007fe == 0x7c000030;
|
||||
"sraw" & 0xfc0007fe == 0x7c000630;
|
||||
"srawi" & 0xfc0007fe == 0x7c000670;
|
||||
"srw" & 0xfc0007fe == 0x7c000430;
|
||||
"stb" & 0xfc000000 == 0x98000000;
|
||||
"stbu" & 0xfc000000 == 0x9c000000;
|
||||
"stbux" & 0xfc0003ff == 0x7c0001ee;
|
||||
"stbx" & 0xfc0003ff == 0x7c0001ae;
|
||||
"stfd" & 0xfc000000 == 0xd8000000;
|
||||
"stfdu" & 0xfc000000 == 0xdc000000;
|
||||
"stfdux" & 0xfc0007ff == 0x7c0005ee;
|
||||
"stfdx" & 0xfc0007ff == 0x7c0005ae;
|
||||
"stfiwx" & 0xfc0007ff == 0x7c0007ae;
|
||||
"stfs" & 0xfc000000 == 0xd0000000;
|
||||
"stfsu" & 0xfc000000 == 0xd4000000;
|
||||
"stfsux" & 0xfc0007ff == 0x7c00056e;
|
||||
"stfsx" & 0xfc0007ff == 0x7c00052e;
|
||||
"sth" & 0xfc000000 == 0xb0000000;
|
||||
"sthbrx" & 0xfc0007ff == 0x7c00072c;
|
||||
"sthu" & 0xfc000000 == 0xb4000000;
|
||||
"sthux" & 0xfc0007ff == 0x7c00036e;
|
||||
"sthx" & 0xfc0007ff == 0x7c00032e;
|
||||
"stmw" & 0xfc000000 == 0xbc000000;
|
||||
"stswi" & 0xfc0007ff == 0x7c0005aa;
|
||||
"stswx" & 0xfc0007ff == 0x7c00052a;
|
||||
"stw" & 0xfc000000 == 0x90000000;
|
||||
"stwbrx" & 0xfc0007ff == 0x7c00052c;
|
||||
"stwcx." & 0xfc0007ff == 0x7c00012d;
|
||||
"stwu" & 0xfc000000 == 0x94000000;
|
||||
"stwux" & 0xfc0007ff == 0x7c00016e;
|
||||
"stwx" & 0xfc0007ff == 0x7c00012e;
|
||||
"subf" & 0xfc0003fe == 0x7c000050;
|
||||
"subfc" & 0xfc0003fe == 0x7c000010;
|
||||
"subfe" & 0xfc0003fe == 0x7c000110;
|
||||
"subfic" & 0xfc000000 == 0x20000000;
|
||||
"subfme" & 0xfc00fbfe == 0x7c0001d0;
|
||||
"subfze" & 0xfc00fbfe == 0x7c000190;
|
||||
"sync" & 0xffffffff == 0x7c0004ac;
|
||||
"tlbie" & 0xffff07ff == 0x7c000264;
|
||||
"tlbsync" & 0xffffffff == 0x7c00046c;
|
||||
"tw" & 0xfc0007ff == 0x7c000008;
|
||||
"twi" & 0xfc000000 == 0xc000000;
|
||||
"xor" & 0xfc0007fe == 0x7c000278;
|
||||
"xori" & 0xfc000000 == 0x68000000;
|
||||
"xoris" & 0xfc000000 == 0x6c000000;
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
pub const BLR: u32 = 0x4c000020;
|
||||
|
||||
pub fn from_code(x: u32) -> Self {
|
||||
let op = match bits(x, 0..6) {
|
||||
0b000011 => Opcode::Twi,
|
||||
0b000100 => Self::from_code_cl_ext(x),
|
||||
0b000111..=0b001111 => Self::from_code_basic1(x),
|
||||
0b010000 => Opcode::Bc,
|
||||
0b010001 => Opcode::Sc,
|
||||
0b010010 => Opcode::B,
|
||||
0b010011 => Self::from_code_010011(x),
|
||||
0b010100..=0b011101 => Self::from_code_basic2(x),
|
||||
0b011111 => Self::from_code_011111(x),
|
||||
0b100000..=0b110111 => Self::from_code_basic3(x),
|
||||
0b111000..=0b111001 => Self::from_code_psq(x),
|
||||
0b111011 => Self::from_code_111011(x),
|
||||
0b111100..=0b111101 => Self::from_code_psq(x),
|
||||
0b111111 => Self::from_code_111111(x),
|
||||
_ => Opcode::Illegal,
|
||||
};
|
||||
if !op.is_valid(x) {
|
||||
return Opcode::Illegal;
|
||||
}
|
||||
op
|
||||
}
|
||||
|
||||
fn from_code_cl_ext(x: u32) -> Self {
|
||||
match bits(x, 26..31) {
|
||||
0b00000 => match bits(x, 21..26) {
|
||||
0b00000 => Opcode::PsCmpu0,
|
||||
0b00001 => Opcode::PsCmpo0,
|
||||
0b00010 => Opcode::PsCmpu1,
|
||||
0b00011 => Opcode::PsCmpo1,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b00110 => {
|
||||
if bit(x, 25) == 0 {
|
||||
Opcode::PsqLx
|
||||
} else {
|
||||
Opcode::PsqLux
|
||||
}
|
||||
}
|
||||
0b00111 => {
|
||||
if bit(x, 25) == 0 {
|
||||
Opcode::PsqStx
|
||||
} else {
|
||||
Opcode::PsqStux
|
||||
}
|
||||
}
|
||||
0b01010 => Opcode::PsSum0,
|
||||
0b01011 => Opcode::PsSum1,
|
||||
0b01110 => Opcode::PsMadds0,
|
||||
0b01111 => Opcode::PsMadds1,
|
||||
0b10111 => Opcode::PsSel,
|
||||
0b11100 => Opcode::PsMsub,
|
||||
0b11101 => Opcode::PsMadd,
|
||||
0b11110 => Opcode::PsNmsub,
|
||||
0b11111 => Opcode::PsNmadd,
|
||||
0b01100 => Opcode::PsMuls0,
|
||||
0b01101 => Opcode::PsMuls1,
|
||||
0b11001 => Opcode::PsMul,
|
||||
0b10010 => Opcode::PsDiv,
|
||||
0b10100 => Opcode::PsSub,
|
||||
0b10101 => Opcode::PsAdd,
|
||||
0b11000 => Opcode::PsRes,
|
||||
0b11010 => Opcode::PsRsqrte,
|
||||
0b01000 => match bits(x, 21..26) {
|
||||
0b00001 => Opcode::PsNeg,
|
||||
0b00010 => Opcode::PsMr,
|
||||
0b00100 => Opcode::PsNabs,
|
||||
0b01000 => Opcode::PsAbs,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b10000 => match bits(x, 21..26) {
|
||||
0b10000 => Opcode::PsMerge00,
|
||||
0b10001 => Opcode::PsMerge01,
|
||||
0b10010 => Opcode::PsMerge10,
|
||||
0b10011 => Opcode::PsMerge11,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b10110 => Opcode::DcbzL,
|
||||
// Unknown paired-singles key.
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_basic1(x: u32) -> Self {
|
||||
match bits(x, 0..6) {
|
||||
0b000111 => Opcode::Mulli,
|
||||
0b001000 => Opcode::Subfic,
|
||||
0b001010 => Opcode::Cmpli,
|
||||
0b001011 => Opcode::Cmpi,
|
||||
0b001100 => Opcode::Addic,
|
||||
0b001101 => Opcode::Addic_,
|
||||
0b001110 => Opcode::Addi,
|
||||
0b001111 => Opcode::Addis,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_010011(x: u32) -> Self {
|
||||
match bits(x, 21..27) {
|
||||
0b000000 => Opcode::Mcrf,
|
||||
0b000001 => Opcode::Bclr,
|
||||
0b100001 => Opcode::Bcctr,
|
||||
0b000011 => Opcode::Rfi,
|
||||
0b001001 => Opcode::Isync,
|
||||
0b000010 => Opcode::Crnor,
|
||||
0b001000 => Opcode::Crandc,
|
||||
0b001100 => Opcode::Crxor,
|
||||
0b001110 => Opcode::Crnand,
|
||||
0b010000 => Opcode::Crand,
|
||||
0b010010 => Opcode::Creqv,
|
||||
0b011010 => Opcode::Crorc,
|
||||
0b011100 => Opcode::Cror,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_basic2(x: u32) -> Self {
|
||||
match bits(x, 0..6) {
|
||||
0b10100 => Opcode::Rlwimi,
|
||||
0b10101 => Opcode::Rlwinm,
|
||||
0b10111 => Opcode::Rlwnm,
|
||||
0b11000 => Opcode::Ori,
|
||||
0b11001 => Opcode::Oris,
|
||||
0b11010 => Opcode::Xori,
|
||||
0b11011 => Opcode::Xoris,
|
||||
0b11100 => Opcode::Andi_,
|
||||
0b11101 => Opcode::Andis_,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_011111(x: u32) -> Self {
|
||||
match bits::<u32>(x, 21..31) {
|
||||
0b00_0000_0000 => Opcode::Cmp,
|
||||
0b00_0010_0000 => Opcode::Cmpl,
|
||||
0b00_0000_0100 => Opcode::Tw,
|
||||
0b00_0000_1000 => Opcode::Subfc,
|
||||
0b00_0000_1010 => Opcode::Addc,
|
||||
0b00_0000_1011 => Opcode::Mulhwu,
|
||||
0b00_0001_0011 => Opcode::Mfcr,
|
||||
0b00_0001_0100 => Opcode::Lwarx,
|
||||
0b00_0001_0111 => Opcode::Lwzx,
|
||||
0b00_0001_1000 => Opcode::Slw,
|
||||
0b00_0001_1010 => Opcode::Cntlzw,
|
||||
0b00_0001_1100 => Opcode::And,
|
||||
0b00_0010_1000 => Opcode::Subf,
|
||||
0b00_0011_0110 => Opcode::Dcbst,
|
||||
0b00_0011_0111 => Opcode::Lwzux,
|
||||
0b00_0011_1100 => Opcode::Andc,
|
||||
0b00_0100_1011 => Opcode::Mulhw,
|
||||
0b00_0101_0011 => Opcode::Mfmsr,
|
||||
0b00_0101_0110 => Opcode::Dcbf,
|
||||
0b00_0101_0111 => Opcode::Lbzx,
|
||||
0b00_0110_1000 => Opcode::Neg,
|
||||
0b00_0111_0111 => Opcode::Lbzux,
|
||||
0b00_0111_1100 => Opcode::Nor,
|
||||
0b00_1000_1000 => Opcode::Subfe,
|
||||
0b00_1000_1010 => Opcode::Adde,
|
||||
0b00_1001_0000 => Opcode::Mtcrf,
|
||||
0b00_1001_0010 => Opcode::Mtmsr,
|
||||
0b00_1001_0110 => Opcode::Stwcx_,
|
||||
0b00_1001_0111 => Opcode::Stwx,
|
||||
0b00_1011_0111 => Opcode::Stwux,
|
||||
0b00_1100_1000 => Opcode::Subfze,
|
||||
0b00_1100_1010 => Opcode::Addze,
|
||||
0b00_1101_0010 => Opcode::Mtsr,
|
||||
0b00_1101_0111 => Opcode::Stbx,
|
||||
0b00_1110_1000 => Opcode::Subfme,
|
||||
0b00_1110_1010 => Opcode::Addme,
|
||||
0b00_1110_1011 => Opcode::Mullw,
|
||||
0b00_1111_0010 => Opcode::Mtsrin,
|
||||
0b00_1111_0110 => Opcode::Dcbtst,
|
||||
0b00_1111_0111 => Opcode::Stbux,
|
||||
0b01_0000_1010 => Opcode::Add,
|
||||
0b01_0001_0110 => Opcode::Dcbt,
|
||||
0b01_0001_0111 => Opcode::Lhzx,
|
||||
0b01_0001_1100 => Opcode::Eqv,
|
||||
0b01_0011_0010 => Opcode::Tlbie,
|
||||
0b01_0011_0110 => Opcode::Eciwx,
|
||||
0b01_0011_0111 => Opcode::Lhzux,
|
||||
0b01_0011_1100 => Opcode::Xor,
|
||||
0b01_0101_0011 => Opcode::Mfspr,
|
||||
0b01_0101_0111 => Opcode::Lhax,
|
||||
0b01_0111_0011 => Opcode::Mftb,
|
||||
0b01_0111_0111 => Opcode::Lhaux,
|
||||
0b01_1001_0111 => Opcode::Sthx,
|
||||
0b01_1001_1100 => Opcode::Orc,
|
||||
0b01_1011_0110 => Opcode::Ecowx,
|
||||
0b01_1011_0111 => Opcode::Sthux,
|
||||
0b01_1011_1100 => Opcode::Or,
|
||||
0b01_1100_1011 => Opcode::Divwu,
|
||||
0b01_1101_0011 => Opcode::Mtspr,
|
||||
0b01_1101_0110 => Opcode::Dcbi,
|
||||
0b01_1101_1100 => Opcode::Nand,
|
||||
0b01_1110_1011 => Opcode::Divw,
|
||||
0b10_0000_0000 => Opcode::Mcrxr,
|
||||
0b10_0001_0101 => Opcode::Lswx,
|
||||
0b10_0001_0110 => Opcode::Lwbrx,
|
||||
0b10_0001_0111 => Opcode::Lfsx,
|
||||
0b10_0001_1000 => Opcode::Srw,
|
||||
0b10_0011_0110 => Opcode::Tlbsync,
|
||||
0b10_0011_0111 => Opcode::Lfsux,
|
||||
0b10_0101_0011 => Opcode::Mfsr,
|
||||
0b10_0101_0101 => Opcode::Lswi,
|
||||
0b10_0101_0110 => Opcode::Sync,
|
||||
0b10_0101_0111 => Opcode::Lfdx,
|
||||
0b10_0111_0111 => Opcode::Lfdux,
|
||||
0b10_1001_0011 => Opcode::Mfsrin,
|
||||
0b10_1001_0101 => Opcode::Stswx,
|
||||
0b10_1001_0110 => Opcode::Stwbrx,
|
||||
0b10_1001_0111 => Opcode::Stfsx,
|
||||
0b10_1011_0111 => Opcode::Stfsux,
|
||||
0b10_1101_0101 => Opcode::Stswi,
|
||||
0b10_1101_0111 => Opcode::Stfdx,
|
||||
0b10_1111_0111 => Opcode::Stfdux,
|
||||
0b11_0001_0110 => Opcode::Lhbrx,
|
||||
0b11_0001_1000 => Opcode::Sraw,
|
||||
0b11_0011_1000 => Opcode::Srawi,
|
||||
0b11_0101_0110 => Opcode::Eieio,
|
||||
0b11_1001_0110 => Opcode::Sthbrx,
|
||||
0b11_1001_1010 => Opcode::Extsh,
|
||||
0b11_1011_1010 => Opcode::Extsb,
|
||||
0b11_1101_0110 => Opcode::Icbi,
|
||||
0b11_1101_0111 => Opcode::Stfiwx,
|
||||
0b11_1111_0110 => Opcode::Dcbz,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_basic3(x: u32) -> Self {
|
||||
match bits(x, 0..6) {
|
||||
0b100000 => Opcode::Lwz,
|
||||
0b100001 => Opcode::Lwzu,
|
||||
0b100010 => Opcode::Lbz,
|
||||
0b100011 => Opcode::Lbzu,
|
||||
0b100100 => Opcode::Stw,
|
||||
0b100101 => Opcode::Stwu,
|
||||
0b100110 => Opcode::Stb,
|
||||
0b100111 => Opcode::Stbu,
|
||||
0b101000 => Opcode::Lhz,
|
||||
0b101001 => Opcode::Lhzu,
|
||||
0b101010 => Opcode::Lha,
|
||||
0b101011 => Opcode::Lhau,
|
||||
0b101100 => Opcode::Sth,
|
||||
0b101101 => Opcode::Sthu,
|
||||
0b101110 => Opcode::Lmw,
|
||||
0b101111 => Opcode::Stmw,
|
||||
0b110000 => Opcode::Lfs,
|
||||
0b110001 => Opcode::Lfsu,
|
||||
0b110010 => Opcode::Lfd,
|
||||
0b110011 => Opcode::Lfdu,
|
||||
0b110100 => Opcode::Stfs,
|
||||
0b110101 => Opcode::Stfsu,
|
||||
0b110110 => Opcode::Stfd,
|
||||
0b110111 => Opcode::Stfdu,
|
||||
_ => disasm_unreachable!(x),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_psq(x: u32) -> Self {
|
||||
match bits(x, 0..6) {
|
||||
0b111000 => Opcode::PsqL,
|
||||
0b111001 => Opcode::PsqLu,
|
||||
0b111100 => Opcode::PsqSt,
|
||||
0b111101 => Opcode::PsqStu,
|
||||
_ => disasm_unreachable!(x),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_111011(x: u32) -> Self {
|
||||
match bits(x, 26..31) {
|
||||
0b10010 => Opcode::Fdivs,
|
||||
0b10100 => Opcode::Fsubs,
|
||||
0b10101 => Opcode::Fadds,
|
||||
0b11000 => Opcode::Fres,
|
||||
0b11001 => Opcode::Fmuls,
|
||||
0b11100 => Opcode::Fmsubs,
|
||||
0b11101 => Opcode::Fmadds,
|
||||
0b11110 => Opcode::Fnmsubs,
|
||||
0b11111 => Opcode::Fnmadds,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_code_111111(x: u32) -> Self {
|
||||
match bits::<u32>(x, 26..31) {
|
||||
0b00000 => match bits(x, 24..26) {
|
||||
0b00 => Opcode::Fcmpu,
|
||||
0b01 => Opcode::Fcmpo,
|
||||
0b10 => Opcode::Mcrfs,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b00110 => match bits(x, 23..26) {
|
||||
0b001 => Opcode::Mtfsb1,
|
||||
0b010 => Opcode::Mtfsb0,
|
||||
0b100 => Opcode::Mtfsfi,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b00111 => match bits(x, 21..26) {
|
||||
0b10010 => Opcode::Mffs,
|
||||
0b10110 => Opcode::Mtfsf,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b01000 => match bits(x, 22..26) {
|
||||
0b0001 => Opcode::Fneg,
|
||||
0b0010 => Opcode::Fmr,
|
||||
0b0100 => Opcode::Fnabs,
|
||||
0b1000 => Opcode::Fabs,
|
||||
_ => Opcode::Illegal,
|
||||
},
|
||||
0b01100 => Opcode::Frsp,
|
||||
0b01110 => Opcode::Fctiw,
|
||||
0b01111 => Opcode::Fctiwz,
|
||||
0b10010 => Opcode::Fdiv,
|
||||
0b10100 => Opcode::Fsub,
|
||||
0b10101 => Opcode::Fadd,
|
||||
0b10111 => Opcode::Fsel,
|
||||
0b11001 => Opcode::Fmul,
|
||||
0b11010 => Opcode::Frsqrte,
|
||||
0b11100 => Opcode::Fmsub,
|
||||
0b11101 => Opcode::Fmadd,
|
||||
0b11110 => Opcode::Fnmsub,
|
||||
0b11111 => Opcode::Fnmadd,
|
||||
_ => Opcode::Illegal,
|
||||
}
|
||||
}
|
||||
}
|
1951
disasm/src/lib.rs
1951
disasm/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
|||
macro_rules! disasm_unreachable {
|
||||
($msg:expr $(,)?) => {{
|
||||
panic!(
|
||||
"internal error: entered unreachable code disassembling instruction 0x{:08x}",
|
||||
$msg
|
||||
)
|
||||
}};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub use crate::Field::*;
|
||||
pub use crate::Ins;
|
||||
pub use crate::Opcode::*;
|
|
@ -0,0 +1,952 @@
|
|||
use ppc750cl::prelude::*;
|
||||
use ppc750cl::GPR;
|
||||
|
||||
#[test]
|
||||
fn test_ins_addi() {
|
||||
let ins = Ins::new(0x7c002014, 0x8000_0000u32);
|
||||
assert_eq!(ins.op, Addc);
|
||||
assert_eq!(ins.fields(), vec![rD(GPR(0)), rA(GPR(0)), rB(GPR(4))]);
|
||||
}
|
||||
|
||||
/*
|
||||
macro_rules! assert_asm {
|
||||
($code:expr, $disasm:expr) => {{
|
||||
assert_eq!(Ins::new($code, 0x8000_0000u32).to_string(), $disasm)
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addc() {
|
||||
assert_asm!(0x7c002014, "addc r0, r0, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_adde() {
|
||||
assert_asm!(0x7c006114, "adde r0, r0, r12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addi() {
|
||||
assert_asm!(0x38010008, "addi r0, r1, 0x8");
|
||||
assert_asm!(0x38010010, "addi r0, r1, 0x10");
|
||||
assert_asm!(0x38010018, "addi r0, r1, 0x18");
|
||||
assert_asm!(0x38010140, "addi r0, r1, 0x140");
|
||||
assert_asm!(0x38049000, "addi r0, r4, -28672");
|
||||
assert_asm!(0x38a00000, "li r5, 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addic() {
|
||||
assert_asm!(0x3060ffff, "addic r3, r0, -1");
|
||||
assert_asm!(0x30840800, "addic r4, r4, 0x800");
|
||||
assert_asm!(0x30a50008, "addic r5, r5, 0x8");
|
||||
assert_asm!(0x37DF001C, "addic. r30, r31, 0x1c");
|
||||
assert_asm!(0x37E06278, "addic. r31, r0, 0x6278");
|
||||
assert_asm!(0x37E3FFFF, "addic. r31, r3, -1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addic_() {
|
||||
assert_asm!(0x341D001C, "addic. r0, r29, 0x1c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addis() {
|
||||
assert_asm!(0x3C030000, "addis r0, r3, 0");
|
||||
assert_asm!(0x3C038000, "addis r0, r3, 0x8000");
|
||||
assert_asm!(0x3D00EFCE, "lis r8, 0xefce");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_addze() {
|
||||
assert_asm!(0x7C000194, "addze r0, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_and() {
|
||||
assert_asm!(0x7C001838, "and r0, r0, r3");
|
||||
assert_asm!(0x7C001839, "and. r0, r0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_andc() {
|
||||
assert_asm!(0x7C001878, "andc r0, r0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_andi_() {
|
||||
assert_asm!(0x70000009, "andi. r0, r0, 9");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_andis_() {
|
||||
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_b() {
|
||||
assert_asm!(0x48000000, "b 0x0");
|
||||
assert_asm!(0x48000004, "b 0x4");
|
||||
assert_asm!(0x4800A5C9, "bl 0xa5c8");
|
||||
assert_asm!(0x4823B4D9, "bl 0x23b4d8");
|
||||
assert_asm!(0x4BE03C99, "bl -0x1fc368");
|
||||
assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_bc() {
|
||||
assert_asm!(0x40800008, "bge 0x8");
|
||||
assert_asm!(0x40802350, "bge 0x2350");
|
||||
assert_asm!(0x4080FC7C, "bge -0x384");
|
||||
assert_asm!(0x408100AC, "ble 0xac");
|
||||
assert_asm!(0x4081F788, "ble -0x878");
|
||||
assert_asm!(0x40821BA0, "bne 0x1ba0");
|
||||
assert_asm!(0x4082E3C4, "bne -0x1c3c");
|
||||
assert_asm!(0x408600D8, "bne cr1, 0xd8");
|
||||
assert_asm!(0x4086FECC, "bne cr1, -0x134");
|
||||
assert_asm!(0x409C000C, "bge cr7, 0xc");
|
||||
// assert_asm!(0x40A10010, "ble+ 0x10");
|
||||
assert_asm!(0x4180000C, "blt 0xc");
|
||||
assert_asm!(0x4180F9C0, "blt -0x640");
|
||||
assert_asm!(0x4181021C, "bgt 0x21c");
|
||||
assert_asm!(0x4181FD80, "bgt -0x280");
|
||||
assert_asm!(0x41822304, "beq 0x2304");
|
||||
assert_asm!(0x4182FE3C, "beq -0x1c4");
|
||||
assert_asm!(0x418401AC, "blt cr1, 0x1ac");
|
||||
assert_asm!(0x4184FCE4, "blt cr1, -0x31c");
|
||||
assert_asm!(0x418500C0, "bgt cr1, 0xc0");
|
||||
assert_asm!(0x418502E4, "bgt cr1, 0x2e4");
|
||||
assert_asm!(0x419A0138, "beq cr6, 0x138");
|
||||
assert_asm!(0x419C0008, "blt cr7, 0x8");
|
||||
assert_asm!(0x4200F560, "bdnz -0xaa0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_bcctr() {
|
||||
assert_asm!(0x4E800420, "bctr");
|
||||
assert_asm!(0x4E800421, "bctrl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_bclr() {
|
||||
assert_asm!(0x4C800020, "bgelr");
|
||||
assert_asm!(0x4C810020, "blelr");
|
||||
assert_asm!(0x4C820020, "bnelr");
|
||||
assert_asm!(0x4C9E0020, "bnelr cr7");
|
||||
assert_asm!(0x4D800020, "bltlr");
|
||||
assert_asm!(0x4D810020, "bgtlr");
|
||||
assert_asm!(0x4D820020, "beqlr");
|
||||
assert_asm!(0x4D860020, "beqlr cr1");
|
||||
assert_asm!(0x4E800020, "blr");
|
||||
assert_asm!(0x4E800021, "blrl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cmp() {
|
||||
assert_asm!(0x7C030000, "cmpw r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cmpi() {
|
||||
assert_asm!(0x2C050D00, "cmpwi r5, 0xd00");
|
||||
assert_asm!(0x2F1F0000, "cmpwi cr6, r31, 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cmpl() {
|
||||
assert_asm!(0x7C9A2040, "cmplw cr1, r26, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cmpli() {
|
||||
assert_asm!(0x2803FFF3, "cmplwi r3, 0xfff3");
|
||||
assert_asm!(0x2884F8F0, "cmplwi cr1, r4, 0xf8f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cntlzw() {
|
||||
assert_asm!(0x7C030034, "cntlzw r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_cror() {
|
||||
assert_asm!(0x4C411382, "cror cr2, cr1, cr2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbf() {
|
||||
assert_asm!(0x7C0028AC, "dcbf 0, r5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbi() {
|
||||
assert_asm!(0x7C001BAC, "dcbi 0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbst() {
|
||||
assert_asm!(0x7C00286C, "dcbst 0, r5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbt() {
|
||||
assert_asm!(0x7C001A2C, "dcbt 0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbz() {
|
||||
assert_asm!(0x7C001FEC, "dcbz 0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_dcbz_l() {
|
||||
assert_asm!(0x10061FEC, "dcbz_l r6, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_divw() {
|
||||
assert_asm!(0x7C8073D6, "divw r4, r0, r14");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_divwu() {
|
||||
assert_asm!(0x7C69E396, "divwu r3, r9, r28");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_extsb() {
|
||||
assert_asm!(0x7C650774, "extsb r5, r3");
|
||||
assert_asm!(0x7C650775, "extsb. r5, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_extsh() {
|
||||
assert_asm!(0x7C000734, "extsh r0, r0");
|
||||
assert_asm!(0x7C000735, "extsh. r0, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fabs() {
|
||||
assert_asm!(0xFC000A10, "fabs f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fadd() {
|
||||
assert_asm!(0xFC00282A, "fadd f0, f0, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fadds() {
|
||||
assert_asm!(0xEC41602A, "fadds f2, f1, f12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fcmpo() {
|
||||
assert_asm!(0xFC00C840, "fcmpo cr0, f0, f25");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fcmpu() {
|
||||
assert_asm!(0xFC00D000, "fcmpu cr0, f0, f26");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fctiwz() {
|
||||
assert_asm!(0xFC20001E, "fctiwz f1, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fdiv() {
|
||||
assert_asm!(0xFC200024, "fdiv f1, f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fdivs() {
|
||||
assert_asm!(0xEC01F824, "fdivs f0, f1, f31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fmadds() {
|
||||
assert_asm!(0xEC0200FA, "fmadds f0, f2, f3, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fmsub() {
|
||||
assert_asm!(0xFC000028, "fsub f0, f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fmsubs() {
|
||||
assert_asm!(0xEC00B828, "fsubs f0, f0, f23");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fmul() {
|
||||
assert_asm!(0xFC0000B2, "fmul f0, f0, f2");
|
||||
assert_asm!(0xFC0000F2, "fmul f0, f0, f3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fmuls() {
|
||||
assert_asm!(0xEC0007B2, "fmuls f0, f0, f30");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fneg() {
|
||||
assert_asm!(0xFCE00050, "fneg f7, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fnmsub() {
|
||||
assert_asm!(0xFCC640BC, "fnmsub f6, f6, f2, f8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fnmsubs() {
|
||||
assert_asm!(0xEC022B3C, "fnmsubs f0, f2, f12, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fres() {
|
||||
assert_asm!(0xEC000830, "fres f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_frsp() {
|
||||
assert_asm!(0xFC000018, "frsp f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_frsqrte() {
|
||||
assert_asm!(0xFC000834, "frsqrte f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fsel() {
|
||||
assert_asm!(0xFC01F82E, "fsel f0, f1, f0, f31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fsub() {
|
||||
assert_asm!(0xFC000828, "fsub f0, f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_fsubs() {
|
||||
assert_asm!(0xEC000828, "fsubs f0, f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_icbi() {
|
||||
assert_asm!(0x7C001FAC, "icbi 0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_isync() {
|
||||
assert_asm!(0x4C00012C, "isync");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lbz() {
|
||||
assert_asm!(0x880104CC, "lbz r0, 0x4cc(r1)");
|
||||
assert_asm!(0x8802801B, "lbz r0, -0x7fe5(r2)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lbzu() {
|
||||
assert_asm!(0x8D9DCA10, "lbzu r12, -0x35f0(r29)");
|
||||
assert_asm!(0x8E3053EC, "lbzu r17, 0x53ec(r16)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lbzux() {
|
||||
assert_asm!(0x7C0400EE, "lbzux r0, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lbzx() {
|
||||
assert_asm!(0x7C0300AE, "lbzx r0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfd() {
|
||||
assert_asm!(0xC80140C8, "lfd f0, 0x40c8(r1)");
|
||||
assert_asm!(0xC8028090, "lfd f0, -0x7f70(r2)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfdu() {
|
||||
assert_asm!(0xCC03FFC0, "lfdu f0, -0x40(r3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfdx() {
|
||||
assert_asm!(0x7C0404AE, "lfdx f0, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfs() {
|
||||
assert_asm!(0xC001027C, "lfs f0, 0x27c(r1)");
|
||||
assert_asm!(0xC0028000, "lfs f0, -0x8000(r2)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfsu() {
|
||||
assert_asm!(0xC404FFF4, "lfsu f0, -0xc(r4)");
|
||||
assert_asm!(0xC4170084, "lfsu f0, 0x84(r23)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfsux() {
|
||||
assert_asm!(0x7C03846E, "lfsux f0, r3, r16");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lfsx() {
|
||||
assert_asm!(0x7C03042E, "lfsx f0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lha() {
|
||||
assert_asm!(0xA861000E, "lha r3, 0xe(r1)");
|
||||
assert_asm!(0xA80D9F64, "lha r0, -0x609c(r13)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhau() {
|
||||
assert_asm!(0xAC060006, "lhau r0, 6(r6)");
|
||||
assert_asm!(0xAC06FFFA, "lhau r0, -6(r6)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhax() {
|
||||
assert_asm!(0x7C0402AE, "lhax r0, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhz() {
|
||||
assert_asm!(0xA00104D6, "lhz r0, 0x4d6(r1)");
|
||||
assert_asm!(0xA00296DA, "lhz r0, -0x6926(r2)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhzu() {
|
||||
assert_asm!(0xA40A0004, "lhzu r0, 4(r10)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhzux() {
|
||||
assert_asm!(0x7C04026E, "lhzux r0, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lhzx() {
|
||||
assert_asm!(0x7C03022E, "lhzx r0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lmw() {
|
||||
assert_asm!(0xBB210444, "lmw r25, 0x444(r1)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lwbrx() {
|
||||
assert_asm!(0x7D80242C, "lwbrx r12, 0, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lwz() {
|
||||
assert_asm!(0x800294F4, "lwz r0, -0x6b0c(r2)");
|
||||
assert_asm!(0x80011254, "lwz r0, 0x1254(r1)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lwzu() {
|
||||
assert_asm!(0x84038608, "lwzu r0, -0x79f8(r3)");
|
||||
assert_asm!(0x873E5058, "lwzu r25, 0x5058(r30)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lwzux() {
|
||||
assert_asm!(0x7C03006E, "lwzux r0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_lwzx() {
|
||||
assert_asm!(0x7C03002E, "lwzx r0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mfcr() {
|
||||
assert_asm!(0x7C000026, "mfcr r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mffs() {
|
||||
assert_asm!(0xFC00048E, "mffs f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mfmsr() {
|
||||
assert_asm!(0x7C0000A6, "mfmsr r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mfspr() {
|
||||
assert_asm!(0x7E1A02A6, "mfspr r16, 0x1a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mfsr() {
|
||||
assert_asm!(0x7E0004A6, "mfsr r16, 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mftb() {
|
||||
assert_asm!(0x7C8C42E6, "mftb r4, 0x10c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtcrf() {
|
||||
assert_asm!(0x7C6FF120, "mtcrf 255, r3");
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn test_ins_mtfsb0() {}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtfsb1() {
|
||||
assert_asm!(0xFFA0004C, "mtfsb1 0x1d");
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtfsf() {
|
||||
assert_asm!(0xFDFE058E, "mtfsf 255, f0");
|
||||
assert_asm!(0xFDFEFD8E, "mtfsf 255, f31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtmsr() {
|
||||
assert_asm!(0x7C000124, "mtmsr r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtspr() {
|
||||
assert_asm!(0x7E75FBA6, "mtspr 0x3f5, r19");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mtsr() {
|
||||
assert_asm!(0x7E0001A4, "mtsr 0, r16");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mulhw() {
|
||||
assert_asm!(0x7C7F2096, "mulhw r3, r31, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mulhwu() {
|
||||
assert_asm!(0x7C7D0016, "mulhwu r3, r29, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mulli() {
|
||||
assert_asm!(0x1C001880, "mulli r0, r0, 0x1880");
|
||||
assert_asm!(0x1FBD0030, "mulli r29, r29, 0x30");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_mullw() {
|
||||
assert_asm!(0x7C7D01D6, "mullw r3, r29, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_nand() {
|
||||
assert_asm!(0x7C7D03B8, "nand r29, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_neg() {
|
||||
assert_asm!(0x7C0600D0, "neg r0, r6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_nor() {
|
||||
assert_asm!(0x7C0500F8, "nor r5, r0, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_or() {
|
||||
assert_asm!(0x7C04DB78, "or r4, r0, r27");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_orc() {
|
||||
assert_asm!(0x7C042338, "orc r4, r0, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ori() {
|
||||
assert_asm!(0x60002204, "ori r0, r0, 0x2204");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_oris() {
|
||||
assert_asm!(0x67A06800, "oris r0, r29, 0x6800");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_l() {
|
||||
assert_asm!(0xE02500AC, "psq_l f1, 0xac(r5), 0, qr0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_lu() {
|
||||
assert_asm!(0xE5435010, "psq_lu f10, 0x10(r3), 0, qr5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_lx() {
|
||||
assert_asm!(0x1000000C, "psq_lx f0, r0, r0, 0, qr0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_st() {
|
||||
assert_asm!(0xF1230210, "psq_st f9, 0x210(r3), 0, qr0");
|
||||
assert_asm!(0xF1238008, "psq_st f9, 8(r3), 1, qr0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_stu() {
|
||||
assert_asm!(0xF40A0020, "psq_stu f0, 0x20(r10), 0, qr0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_psq_stx() {
|
||||
assert_asm!(0x13E1000E, "psq_stx f31, r1, r0, 0, qr0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_abs() {
|
||||
assert_asm!(0x10A03210, "ps_abs f5, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_add() {
|
||||
assert_asm!(0x1006382A, "ps_add f0, f6, f7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_cmpo0() {
|
||||
assert_asm!(0x10070840, "ps_cmpo0 cr0, f7, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_cmpu0() {
|
||||
assert_asm!(0x10003000, "ps_cmpu0 cr0, f0, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_cmpu1() {
|
||||
assert_asm!(0x10003080, "ps_cmpu1 cr0, f0, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_madd() {
|
||||
assert_asm!(0x112141FA, "ps_madd f9, f1, f7, f8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_madds0() {
|
||||
assert_asm!(0x10AC299C, "ps_madds0 f5, f12, f6, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_madds1() {
|
||||
assert_asm!(0x110640DE, "ps_madds1 f8, f6, f3, f8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_merge00() {
|
||||
assert_asm!(0x10400420, "ps_merge00 f2, f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_merge01() {
|
||||
assert_asm!(0x10400C60, "ps_merge01 f2, f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_merge10() {
|
||||
assert_asm!(0x104004A0, "ps_merge10 f2, f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_merge11() {
|
||||
assert_asm!(0x10AA14E0, "ps_merge11 f5, f10, f2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_msub() {
|
||||
assert_asm!(0x10A53778, "ps_msub f5, f5, f29, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_mul() {
|
||||
assert_asm!(0x10000032, "ps_mul f0, f0, f0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_muls0() {
|
||||
assert_asm!(0x100002D8, "ps_muls0 f0, f0, f11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_muls1() {
|
||||
assert_asm!(0x10A2005A, "ps_muls1 f5, f2, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_nabs() {
|
||||
assert_asm!(0x10803210, "ps_abs f4, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_neg() {
|
||||
assert_asm!(0x10E03850, "ps_neg f7, f7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_nmadd() {
|
||||
assert_asm!(0x10CB30FE, "ps_nmadd f6, f11, f3, f6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_nmsub() {
|
||||
assert_asm!(0x107E083C, "ps_nmsub f3, f30, f0, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_sel() {
|
||||
assert_asm!(0x106428EE, "ps_sel f3, f4, f3, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_sub() {
|
||||
assert_asm!(0x10A92828, "ps_sub f5, f9, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_sum0() {
|
||||
assert_asm!(0x10230854, "ps_sum0 f1, f3, f1, f1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_ps_sum1() {
|
||||
assert_asm!(0x10A12956, "ps_sum1 f5, f1, f5, f5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_rfi() {
|
||||
assert_asm!(0x4C000064, "rfi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_rlwimi() {
|
||||
assert_asm!(0x500306FE, "rlwimi r3, r0, 0, 0x1b, 0x1f");
|
||||
assert_asm!(0x50032D74, "rlwimi r3, r0, 5, 0x15, 0x1a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_rlwinm() {
|
||||
assert_asm!(0x54000423, "rlwinm. r0, r0, 0, 0x10, 0x11");
|
||||
assert_asm!(0x54000432, "rlwinm r0, r0, 0, 0x10, 0x19");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_rlwnm() {
|
||||
assert_asm!(0x5D6A67FE, "rlwnm r10, r11, r12, 0x1f, 0x1f");
|
||||
assert_asm!(0x5FC52EFE, "rlwnm r5, r30, r5, 0x1b, 0x1f");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sc() {
|
||||
assert_asm!(0x44000002, "sc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_slw() {
|
||||
assert_asm!(0x7C042830, "slw r4, r0, r5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sraw() {
|
||||
assert_asm!(0x7C043E30, "sraw r4, r0, r7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_srawi() {
|
||||
assert_asm!(0x7C000E70, "srawi r0, r0, 1");
|
||||
assert_asm!(0x7C001670, "srawi r0, r0, 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_srw() {
|
||||
assert_asm!(0x7C001C30, "srw r0, r0, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stb() {
|
||||
assert_asm!(0x980105EC, "stb r0, 0x5ec(r1)");
|
||||
assert_asm!(0x98030000, "stb r0, 0(r3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stbu() {
|
||||
assert_asm!(0x9D2A7428, "stbu r9, 0x7428(r10)");
|
||||
assert_asm!(0x9D66FFFF, "stbu r11, -1(r6)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stbux() {
|
||||
assert_asm!(0x7C08F9EE, "stbux r0, r8, r31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stbx() {
|
||||
assert_asm!(0x7C03F9AE, "stbx r0, r3, r31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stfd() {
|
||||
assert_asm!(0xD80D97B0, "stfd f0, -0x6850(r13)");
|
||||
assert_asm!(0xD8050090, "stfd f0, 0x90(r5)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stfdu() {
|
||||
assert_asm!(0xDC24FFC0, "stfdu f1, -0x40(r4)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stfdx() {
|
||||
assert_asm!(0x7C4405AE, "stfdx f2, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stfs() {
|
||||
assert_asm!(0xD003086C, "stfs f0, 0x86c(r3)");
|
||||
assert_asm!(0xD0038000, "stfs f0, -0x8000(r3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stfsx() {
|
||||
assert_asm!(0x7C465D2E, "stfsx f2, r6, r11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sth() {
|
||||
assert_asm!(0xB0038A7C, "sth r0, -0x7584(r3)");
|
||||
assert_asm!(0xB0035036, "sth r0, 0x5036(r3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sthbrx() {
|
||||
assert_asm!(0x7C60072C, "sthbrx r3, 0, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sthu() {
|
||||
assert_asm!(0xB4055B88, "sthu r0, 0x5b88(r5)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sthux() {
|
||||
assert_asm!(0x7C03236E, "sthux r0, r3, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sthx() {
|
||||
assert_asm!(0x7C1C2B2E, "sthx r0, r28, r5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stmw() {
|
||||
assert_asm!(0xBFA202A4, "stmw r29, 0x2a4(r2)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stw() {
|
||||
assert_asm!(0x900140CC, "stw r0, 0x40cc(r1)");
|
||||
assert_asm!(0x9003FFBC, "stw r0, -0x44(r3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stwbrx() {
|
||||
assert_asm!(0x7C00FD2C, "stwbrx r0, 0, r31");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stwu() {
|
||||
assert_asm!(0x9421EBC0, "stwu r1, -0x1440(r1)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stwux() {
|
||||
assert_asm!(0x7C01B96E, "stwux r0, r1, r23");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_stwx() {
|
||||
assert_asm!(0x7C03212E, "stwx r0, r3, r4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_subf() {
|
||||
assert_asm!(0x7C051850, "subf r0, r5, r3");
|
||||
assert_asm!(0x7C051851, "subf. r0, r5, r3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_subfc() {
|
||||
assert_asm!(0x7C040010, "subfc r0, r4, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_subfe() {
|
||||
assert_asm!(0x7C030110, "subfe r0, r3, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_subfic() {
|
||||
assert_asm!(0x200602FF, "subfic r0, r6, 0x2ff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_subfze() {
|
||||
assert_asm!(0x7C000190, "subfze r0, r0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_sync() {
|
||||
assert_asm!(0x7C0004AC, "sync");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_xor() {
|
||||
assert_asm!(0x7C052A78, "xor r5, r0, r5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_xori() {
|
||||
assert_asm!(0x68E71021, "xori r7, r7, 0x1021");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ins_xoris() {
|
||||
assert_asm!(0x6E3D8000, "xoris r29, r17, 0x8000");
|
||||
}
|
||||
*/
|
|
@ -4,13 +4,16 @@ version = "0.1.1"
|
|||
edition = "2018"
|
||||
authors = ["Richard Patel <me@terorie.dev>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
description = "Procedural macros for powerpc750cl"
|
||||
description = "Auxiliary procedural macros for the ppc750cl disassembler"
|
||||
repository = "https://github.com/terorie/ppc750cl"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.28"
|
||||
quote = "1.0.9"
|
||||
syn = { version = "1.0.74", features = ["full", "parsing"] }
|
||||
itertools = "0.10.1"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml = "0.8"
|
||||
syn = { version = "1.0", features = ["full", "parsing"] }
|
||||
|
|
|
@ -1,215 +1,312 @@
|
|||
use std::iter::FromIterator;
|
||||
use std::ops::Range;
|
||||
|
||||
use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree};
|
||||
use itertools::Itertools;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::token::{And, EqEq, Semi};
|
||||
use syn::{LitInt, LitStr};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::HashMap;
|
||||
use syn::LitInt;
|
||||
|
||||
struct Opcodes {
|
||||
opcodes: Punctuated<Opcode, Semi>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub(crate) struct BitRange(Range<u8>);
|
||||
|
||||
impl Parse for Opcodes {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self {
|
||||
opcodes: Punctuated::parse_terminated(input)?,
|
||||
})
|
||||
impl<'de> Deserialize<'de> for BitRange {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let range_str: String = Deserialize::deserialize(deserializer)?;
|
||||
if let Some((start_str, stop_str)) = range_str.split_once("..") {
|
||||
let start = start_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||
let stop = stop_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||
Ok(Self(start..stop))
|
||||
} else {
|
||||
let bit_idx = range_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||
Ok(Self(bit_idx..bit_idx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Opcode {
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Field {
|
||||
name: String,
|
||||
variant_name: String,
|
||||
mask: u32,
|
||||
bits: u32,
|
||||
desc: String,
|
||||
bits: BitRange,
|
||||
signed: bool,
|
||||
split: bool,
|
||||
arg: String,
|
||||
}
|
||||
|
||||
impl Parse for Opcode {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let name = input.parse::<LitStr>()?;
|
||||
input.parse::<And>()?;
|
||||
let mask = input.parse::<LitInt>()?;
|
||||
input.parse::<EqEq>()?;
|
||||
let bits = input.parse::<LitInt>()?;
|
||||
Ok(Self {
|
||||
name: name.value(),
|
||||
variant_name: opcode_to_variant_name(&name)?,
|
||||
mask: hex_from_lit_int(&mask)?,
|
||||
bits: hex_from_lit_int(&bits)?,
|
||||
})
|
||||
impl Field {
|
||||
fn variant_identifier(&self) -> TokenTree {
|
||||
to_rust_ident(&self.name)
|
||||
}
|
||||
|
||||
fn express_value(&self, code: TokenStream) -> TokenStream {
|
||||
let mask_stop = self.bits.0.end;
|
||||
let mask_size = self.bits.0.len();
|
||||
quote! {
|
||||
(((#code) >> (32 - #mask_stop)) & ((1 << #mask_size) - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex_from_lit_int(int: &LitInt) -> syn::Result<u32> {
|
||||
let str = int.to_string();
|
||||
let hex = match str.strip_prefix("0x") {
|
||||
None => return Err(syn::Error::new(int.span(), "not a hex integer")),
|
||||
Some(x) => x,
|
||||
};
|
||||
u32::from_str_radix(hex, 16).map_err(|e| syn::Error::new(int.span(), e))
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Opcode {
|
||||
name: String,
|
||||
desc: String,
|
||||
bitmask: u32,
|
||||
pattern: u32,
|
||||
modifiers: Vec<String>,
|
||||
side_effects: Vec<String>,
|
||||
args: Vec<String>,
|
||||
defs: Vec<String>,
|
||||
uses: Vec<String>,
|
||||
}
|
||||
|
||||
fn opcode_to_variant_name(opcode: &LitStr) -> syn::Result<String> {
|
||||
impl Opcode {
|
||||
fn variant_identifier(&self) -> syn::Result<TokenTree> {
|
||||
to_rust_variant(&self.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Mnemonic {
|
||||
name: String,
|
||||
opcode: String,
|
||||
args: Vec<String>,
|
||||
condition: String,
|
||||
#[serde(rename = "match")]
|
||||
matcher: Vec<MatchField>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct MatchField {
|
||||
arg: String,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Modifier {
|
||||
name: String,
|
||||
suffix: char,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Isa {
|
||||
fields: Vec<Field>,
|
||||
opcodes: Vec<Opcode>,
|
||||
mnemonics: Vec<Mnemonic>,
|
||||
}
|
||||
|
||||
impl Isa {
|
||||
pub(crate) fn gen_opcode_enum(&self) -> syn::Result<TokenStream> {
|
||||
// Create enum variants.
|
||||
let enum_variants = self
|
||||
.opcodes
|
||||
.iter()
|
||||
.map(|opcode| -> syn::Result<TokenStream> {
|
||||
let ident = opcode.variant_identifier()?;
|
||||
Ok(quote! {
|
||||
#ident,
|
||||
})
|
||||
})
|
||||
.try_collect::<TokenStream, Vec<TokenStream>, syn::Error>()?
|
||||
.into_iter();
|
||||
let enum_variants = TokenStream::from_iter(enum_variants);
|
||||
|
||||
// Create functions.
|
||||
let mnemonic_fn = self.gen_mnemonic_fn()?;
|
||||
let detect_fn = self.gen_opcode_detect()?;
|
||||
|
||||
// Create final enum.
|
||||
let opcode_enum = quote! {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Opcode {
|
||||
Illegal = -1,
|
||||
#enum_variants
|
||||
}
|
||||
impl Opcode {
|
||||
#mnemonic_fn
|
||||
#detect_fn
|
||||
}
|
||||
};
|
||||
Ok(opcode_enum)
|
||||
}
|
||||
|
||||
fn gen_mnemonic_fn(&self) -> syn::Result<TokenStream> {
|
||||
// Create match arms.
|
||||
let match_arms = self
|
||||
.opcodes
|
||||
.iter()
|
||||
.map(|opcode| {
|
||||
let variant = opcode.variant_identifier()?;
|
||||
let literal = Literal::string(&opcode.name);
|
||||
Ok(quote! {
|
||||
Opcode::#variant => #literal,
|
||||
})
|
||||
})
|
||||
.try_collect::<TokenStream, Vec<TokenStream>, syn::Error>()?
|
||||
.into_iter();
|
||||
let match_arms = TokenStream::from_iter(match_arms);
|
||||
// Create final function.
|
||||
let mnemonic_fn = quote! {
|
||||
pub fn mnemonic(self) -> &'static str {
|
||||
match self {
|
||||
Opcode::Illegal => "<illegal>",
|
||||
#match_arms
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(mnemonic_fn)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_opcode_detect(&self) -> syn::Result<TokenStream> {
|
||||
// Generate if chain.
|
||||
let if_chain = self
|
||||
.opcodes
|
||||
.iter()
|
||||
.map(|opcode| {
|
||||
let bitmask_str = format!("{:>#8x}", opcode.bitmask);
|
||||
let bitmask = LitInt::new(&bitmask_str, Span::call_site());
|
||||
let pattern_str = format!("{:>#8x}", opcode.pattern);
|
||||
let pattern = LitInt::new(&pattern_str, Span::call_site());
|
||||
let identifier = opcode.variant_identifier()?;
|
||||
Ok(quote! {
|
||||
if code & #bitmask == #pattern {
|
||||
return Opcode::#identifier;
|
||||
}
|
||||
})
|
||||
})
|
||||
.try_collect::<TokenStream, Vec<TokenStream>, syn::Error>()?
|
||||
.into_iter();
|
||||
let if_chain = TokenStream::from_iter(if_chain);
|
||||
// Generate function.
|
||||
let func = quote! {
|
||||
pub fn detect(code: u32) -> Self {
|
||||
#if_chain
|
||||
Opcode::Illegal
|
||||
}
|
||||
};
|
||||
Ok(func)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_field_enum(&self) -> syn::Result<TokenStream> {
|
||||
// Create enum variants.
|
||||
let enum_variants = self.fields.iter().map(|field| {
|
||||
let ident = field.variant_identifier();
|
||||
let arg = TokenTree::Ident(Ident::new(&field.arg, Span::call_site()));
|
||||
quote! {
|
||||
#ident(#arg),
|
||||
}
|
||||
});
|
||||
let enum_variants = TokenStream::from_iter(enum_variants);
|
||||
|
||||
// Create final enum.
|
||||
let field_enum = quote! {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Field {
|
||||
#enum_variants
|
||||
}
|
||||
};
|
||||
Ok(field_enum)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_ins_impl(&self) -> syn::Result<TokenStream> {
|
||||
// Map fields by name.
|
||||
let mut field_by_name = HashMap::<String, &Field>::new();
|
||||
for field in &self.fields {
|
||||
field_by_name.insert(field.name.clone(), field);
|
||||
}
|
||||
// Generate match arms for each opcode.
|
||||
let mut match_arms = Vec::new();
|
||||
for opcode in &self.opcodes {
|
||||
// Generate fields of opcode.
|
||||
// TODO Support mnemonics.
|
||||
let mut fields = Vec::new();
|
||||
for arg in &opcode.args {
|
||||
let field: &Field = field_by_name.get(arg).ok_or_else(|| {
|
||||
syn::Error::new(Span::call_site(), format!("undefined field {}", arg))
|
||||
})?;
|
||||
let field_variant = field.variant_identifier();
|
||||
let field_arg = TokenTree::Ident(Ident::new(&field.arg, Span::call_site()));
|
||||
let value = field.express_value(quote!(self.code));
|
||||
fields.extend(quote! {
|
||||
Field::#field_variant(#field_arg(#value as _)),
|
||||
})
|
||||
}
|
||||
let fields = TokenStream::from_iter(fields.into_iter());
|
||||
// Emit match arm.
|
||||
let ident = opcode.variant_identifier()?;
|
||||
match_arms.push(quote! {
|
||||
#ident => vec![#fields],
|
||||
})
|
||||
}
|
||||
let match_arms = TokenStream::from_iter(match_arms.into_iter());
|
||||
// Generate final fields function.
|
||||
let ins_impl = quote! {
|
||||
impl Ins {
|
||||
fn _fields(&self) -> Vec<Field> {
|
||||
match self.op {
|
||||
Opcode::Illegal => vec![],
|
||||
#match_arms
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ins_impl)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the given key into an identifier.
|
||||
fn to_rust_ident(key: &str) -> TokenTree {
|
||||
TokenTree::Ident(Ident::new(&key.replace(".", "_"), Span::call_site()))
|
||||
}
|
||||
|
||||
/// Converts the given key into a struct variant key.
|
||||
fn to_rust_variant(key: &str) -> syn::Result<TokenTree> {
|
||||
Ok(TokenTree::Ident(Ident::new(
|
||||
&to_rust_variant_str(key).map_err(|e| syn::Error::new(Span::call_site(), e))?,
|
||||
Span::call_site(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn to_rust_variant_str(key: &str) -> Result<String, String> {
|
||||
let mut s = String::new();
|
||||
let opcode_value = opcode.value();
|
||||
let mut chars = opcode_value.chars();
|
||||
let mut chars = key.chars();
|
||||
loop {
|
||||
// Make first char uppercase.
|
||||
let c = match chars.next() {
|
||||
None => return Ok(s),
|
||||
Some(c) => c,
|
||||
};
|
||||
match c {
|
||||
'a'..='z' => s.push(c.to_ascii_uppercase()),
|
||||
_ => return Err(syn::Error::new(opcode.span(), "invalid opcode name")),
|
||||
}
|
||||
s.push(match c {
|
||||
'a'..='z' => c.to_ascii_uppercase(),
|
||||
'A'..='Z' => c,
|
||||
_ => return Err(format!("invalid identifier: {}", key)),
|
||||
});
|
||||
loop {
|
||||
let c = match chars.next() {
|
||||
None => return Ok(s),
|
||||
Some(c) => c,
|
||||
};
|
||||
match c {
|
||||
match c.to_ascii_lowercase() {
|
||||
'0'..='9' | 'a'..='z' => s.push(c),
|
||||
'_' => break,
|
||||
'.' => {
|
||||
s.push('_');
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(syn::Error::new(
|
||||
opcode.span(),
|
||||
"invalid character in opcode name",
|
||||
))
|
||||
}
|
||||
_ => return Err(format!("invalid character in opcode name: {}", key)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_is_valid_fn(tokens: &mut Vec<TokenTree>, opcodes: &Opcodes) {
|
||||
tokens.extend(quote!(pub fn is_valid(self, code: u32) -> bool));
|
||||
|
||||
let mut parts = Vec::<TokenTree>::new();
|
||||
parts.extend(quote!(match self));
|
||||
|
||||
let mut match_parts = Vec::<TokenTree>::new();
|
||||
match_parts.extend(quote!(Opcode::Illegal => false,));
|
||||
|
||||
for opcode in &opcodes.opcodes {
|
||||
match_parts.extend(quote!(Opcode::));
|
||||
match_parts.push(TokenTree::Ident(Ident::new(
|
||||
&opcode.variant_name,
|
||||
Span::call_site(),
|
||||
)));
|
||||
match_parts.extend(quote!(=> code &));
|
||||
match_parts.push(TokenTree::Literal(Literal::u32_suffixed(opcode.mask)));
|
||||
match_parts.extend(quote!(==));
|
||||
match_parts.push(TokenTree::Literal(Literal::u32_suffixed(opcode.bits)));
|
||||
match_parts.extend(quote!(,));
|
||||
}
|
||||
let match_body = Group::new(Delimiter::Brace, TokenStream::from_iter(match_parts));
|
||||
parts.push(TokenTree::Group(match_body));
|
||||
let body = Group::new(Delimiter::Brace, TokenStream::from_iter(parts));
|
||||
tokens.push(TokenTree::Group(body));
|
||||
}
|
||||
|
||||
fn gen_mnemonic_fn(tokens: &mut Vec<TokenTree>, opcodes: &Opcodes) {
|
||||
tokens.extend(quote!(pub fn mnemonic(self) -> &'static str));
|
||||
|
||||
let mut parts = Vec::<TokenTree>::new();
|
||||
parts.extend(quote!(match self));
|
||||
|
||||
let mut match_parts = Vec::<TokenTree>::new();
|
||||
match_parts.extend(quote!(Opcode::Illegal => "<illegal>",));
|
||||
for opcode in &opcodes.opcodes {
|
||||
match_parts.extend(quote!(Opcode::));
|
||||
match_parts.push(TokenTree::Ident(Ident::new(
|
||||
&opcode.variant_name,
|
||||
Span::call_site(),
|
||||
)));
|
||||
match_parts.extend(quote!(=>));
|
||||
match_parts.push(TokenTree::Literal(Literal::string(&opcode.name)));
|
||||
match_parts.extend(quote!(,));
|
||||
}
|
||||
|
||||
let match_body = Group::new(Delimiter::Brace, TokenStream::from_iter(match_parts));
|
||||
parts.push(TokenTree::Group(match_body));
|
||||
|
||||
let body = Group::new(Delimiter::Brace, TokenStream::from_iter(parts));
|
||||
tokens.push(TokenTree::Group(body));
|
||||
}
|
||||
|
||||
pub(crate) fn isa(input: TokenStream) -> syn::Result<TokenStream> {
|
||||
let opcodes: Opcodes = syn::parse2(input)?;
|
||||
|
||||
// Assemble root stream.
|
||||
let mut root = Vec::<TokenTree>::new();
|
||||
|
||||
// Define enum derives and header.
|
||||
root.extend(quote!(#[derive(Debug, Copy, Clone, Eq, PartialEq)]));
|
||||
root.extend(quote!(pub enum Opcode));
|
||||
|
||||
// Create entries.
|
||||
// First entry is going to be the illegal entry.
|
||||
let mut enum_entries = Vec::<TokenTree>::new();
|
||||
enum_entries.extend(quote!(Illegal = -1,));
|
||||
// Append the actual opcodes.
|
||||
for opcode in &opcodes.opcodes {
|
||||
enum_entries.push(TokenTree::Ident(Ident::new(
|
||||
&opcode.variant_name,
|
||||
Span::call_site(),
|
||||
)));
|
||||
enum_entries.extend(quote!(,));
|
||||
}
|
||||
|
||||
// Create body.
|
||||
let enum_body = Group::new(Delimiter::Brace, TokenStream::from_iter(enum_entries));
|
||||
root.push(TokenTree::Group(enum_body));
|
||||
|
||||
// impl Opcode block.
|
||||
root.extend(quote!(impl Opcode));
|
||||
let mut impl_opcode_body_parts = Vec::<TokenTree>::new();
|
||||
gen_is_valid_fn(&mut impl_opcode_body_parts, &opcodes);
|
||||
gen_mnemonic_fn(&mut impl_opcode_body_parts, &opcodes);
|
||||
let impl_opcode_body = Group::new(
|
||||
Delimiter::Brace,
|
||||
TokenStream::from_iter(impl_opcode_body_parts),
|
||||
);
|
||||
root.push(TokenTree::Group(impl_opcode_body));
|
||||
|
||||
// Extra code.
|
||||
root.extend(quote! {
|
||||
impl Default for Opcode {
|
||||
fn default() -> Self {
|
||||
Opcode::Illegal
|
||||
}
|
||||
}
|
||||
|
||||
impl std::string::ToString for Opcode {
|
||||
fn to_string(&self) -> String {
|
||||
let mnemonic = self.mnemonic();
|
||||
mnemonic.to_owned()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(TokenStream::from_iter(root))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn _opcode_to_variant_name(input: &str) -> String {
|
||||
opcode_to_variant_name(&LitStr::new(input, proc_macro2::Span::call_site())).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_opcode_to_variant_name() {
|
||||
assert_eq!(_opcode_to_variant_name("lol_lel."), "LolLel_");
|
||||
assert_eq!(_opcode_to_variant_name("ps_nmsub"), "PsNmsub");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,87 +1,150 @@
|
|||
fields:
|
||||
- name: "Rc"
|
||||
desc: "record"
|
||||
bits: "31"
|
||||
# Immediates
|
||||
- name: "simm"
|
||||
arg: "Simm"
|
||||
bits: "16..32"
|
||||
signed: true
|
||||
- name: "uimm"
|
||||
arg: "Uimm"
|
||||
bits: "16..32"
|
||||
- name: "offset"
|
||||
arg: "Offset"
|
||||
bits: "16..32"
|
||||
signed: true
|
||||
# Branch fields
|
||||
- name: "BO"
|
||||
arg: "OpaqueU"
|
||||
bits: "6..11"
|
||||
- name: "BI"
|
||||
arg: "OpaqueU"
|
||||
bits: "11..16"
|
||||
- name: "BD"
|
||||
desc: "branch destination"
|
||||
arg: "BranchDest"
|
||||
bits: "16..30"
|
||||
shift_left: 2
|
||||
- name: "LI"
|
||||
desc: "branch destination"
|
||||
arg: "BranchDest"
|
||||
bits: "6..30"
|
||||
shift_left: 2
|
||||
# Shift/rotate type fields
|
||||
- name: "SH"
|
||||
arg: "OpaqueU"
|
||||
desc: "Shift"
|
||||
bits: "16..21"
|
||||
- name: "MB"
|
||||
arg: "OpaqueU"
|
||||
desc: "Mask start"
|
||||
bits: "21..26"
|
||||
- name: "ME"
|
||||
arg: "OpaqueU"
|
||||
desc: "Mask stop"
|
||||
bits: "26..31"
|
||||
# Branch bits
|
||||
- name: "AA"
|
||||
desc: "absolute"
|
||||
bits: "30"
|
||||
- name: "LK"
|
||||
desc: "save to link register"
|
||||
bits: "31"
|
||||
# Arithmetic bits
|
||||
- name: "OE"
|
||||
desc: "overflow"
|
||||
bits: "21"
|
||||
# Registers
|
||||
- name: "rS"
|
||||
arg: "GPR"
|
||||
bits: "6..11"
|
||||
- name: "rD"
|
||||
arg: "GPR"
|
||||
bits: "6..11"
|
||||
- name: "rA"
|
||||
arg: "GPR"
|
||||
bits: "11..16"
|
||||
- name: "rA.nz"
|
||||
arg: "GPR"
|
||||
bits: "11..16"
|
||||
- name: "rB"
|
||||
arg: "GPR"
|
||||
bits: "16..21"
|
||||
- name: "rC"
|
||||
arg: "GPR"
|
||||
bits: "21..26"
|
||||
- name: "sr"
|
||||
arg: "SR"
|
||||
bits: "12..16"
|
||||
- name: "spr"
|
||||
arg: "SPR"
|
||||
bits: "11..21"
|
||||
split: true
|
||||
# Floating-point registers
|
||||
- name: "frS"
|
||||
arg: "FPR"
|
||||
bits: "6..11"
|
||||
- name: "frD"
|
||||
arg: "FPR"
|
||||
bits: "6..11"
|
||||
- name: "frA"
|
||||
arg: "FPR"
|
||||
bits: "11..16"
|
||||
- name: "frB"
|
||||
arg: "FPR"
|
||||
bits: "16..21"
|
||||
- name: "frC"
|
||||
arg: "FPR"
|
||||
bits: "21..26"
|
||||
# Condition registers
|
||||
# TODO This looks swapped the wrong way around
|
||||
- name: "crbD"
|
||||
arg: "CRField"
|
||||
bits: "6..11"
|
||||
- name: "crbA"
|
||||
arg: "CRField"
|
||||
bits: "11..16"
|
||||
- name: "crbB"
|
||||
arg: "CRField"
|
||||
bits: "16..21"
|
||||
# Condition register fields
|
||||
- name: "crfD"
|
||||
desc: "condition register field"
|
||||
arg: "CRBit"
|
||||
bits: "6..9"
|
||||
- name: "crfS"
|
||||
desc: "condition register field"
|
||||
arg: "CRBit"
|
||||
bits: "11..14"
|
||||
# Condition register misc
|
||||
- name: "crm"
|
||||
desc: "condition register field mask"
|
||||
arg: "OpaqueU"
|
||||
bits: "12..20"
|
||||
|
||||
- name: "cmpL"
|
||||
arg: "OpaqueU"
|
||||
bits: "10"
|
||||
# Paired single fields
|
||||
- name: "ps_l"
|
||||
arg: "GQR"
|
||||
bits: "17..20"
|
||||
- name: "ps_W"
|
||||
arg: "OpaqueU"
|
||||
bits: "16"
|
||||
# Misc
|
||||
- name: "sr"
|
||||
desc: "Segment register"
|
||||
bits: "12..16"
|
||||
- name: "spr"
|
||||
desc: "Special-purpose register"
|
||||
- name: "NB"
|
||||
arg: "OpaqueU"
|
||||
bits: "16..21"
|
||||
- name: "tbr"
|
||||
arg: "OpaqueU"
|
||||
desc: "Time Base"
|
||||
bits: "11..21"
|
||||
split: true
|
||||
- name: "mtfsf_FM"
|
||||
arg: "OpaqueU"
|
||||
desc: "Field Mask for mtfsf"
|
||||
bits: "7..15"
|
||||
- name: "mtfsf_IMM"
|
||||
arg: "OpaqueU"
|
||||
desc: "Immediate for mtfsfi"
|
||||
bits: "16..20"
|
||||
- name: "tw_TO"
|
||||
arg: "OpaqueU"
|
||||
desc: "Bitset for tw and twi"
|
||||
bits: "6..11"
|
||||
|
||||
# TODO Add defs/uses for modifiers.
|
||||
modifiers:
|
||||
- name: "OE"
|
||||
suffix: "o"
|
||||
- name: "Rc"
|
||||
suffix: "."
|
||||
- name: "LK"
|
||||
suffix: "l"
|
||||
- name: "AA"
|
||||
suffix: "a"
|
||||
|
||||
opcodes:
|
||||
- name: "add"
|
||||
|
@ -972,7 +1035,7 @@ opcodes:
|
|||
desc: "Move to Condition Register from XER"
|
||||
bitmask: 0xfc30ffff
|
||||
pattern: 0x7c000400
|
||||
args: [ "crfD", "xer" ]
|
||||
args: [ "crfD" ]
|
||||
defs: [ "crfD", "xer" ]
|
||||
|
||||
- name: "mfcr"
|
||||
|
@ -1054,7 +1117,7 @@ opcodes:
|
|||
bitmask: 0xfe0107fe
|
||||
pattern: 0xfc00058e
|
||||
modifier: [ "Rc" ]
|
||||
args: [ "FM", "frB" ]
|
||||
args: [ "mtfsf_FM", "frB" ]
|
||||
uses: [ "frB" ]
|
||||
|
||||
- name: "mtfsfi"
|
||||
|
@ -1062,7 +1125,7 @@ opcodes:
|
|||
bitmask: 0xfc7f0ffe
|
||||
pattern: 0xfc00010c
|
||||
modifier: [ "Rc" ]
|
||||
args: [ "crfD", "IMM" ]
|
||||
args: [ "crfD", "mtfsf_IMM" ]
|
||||
defs: [ "crfD" ]
|
||||
|
||||
- name: "mtmsr"
|
||||
|
@ -1194,7 +1257,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Load"
|
||||
bitmask: 0xfc000000
|
||||
pattern: 0xe0000000
|
||||
args: [ "frD", "offset", "rA", "W", "ps_l" ]
|
||||
args: [ "frD", "offset", "rA", "ps_W", "ps_l" ]
|
||||
defs: [ "frD" ]
|
||||
uses: [ "rA.nz" ]
|
||||
|
||||
|
@ -1202,7 +1265,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Load with Update"
|
||||
bitmask: 0xfc000000
|
||||
pattern: 0xe4000000
|
||||
args: [ "frD", "offset", "rA", "W", "ps_l" ]
|
||||
args: [ "frD", "offset", "rA", "ps_W", "ps_l" ]
|
||||
defs: [ "frD", "rA" ]
|
||||
uses: [ "rA" ]
|
||||
|
||||
|
@ -1210,7 +1273,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Load with Update Indexed"
|
||||
bitmask: 0xfc00007f
|
||||
pattern: 0x1000004c
|
||||
args: [ "frD", "rA", "rB", "W", "ps_l" ]
|
||||
args: [ "frD", "rA", "rB", "ps_W", "ps_l" ]
|
||||
defs: [ "frD", "rA" ]
|
||||
uses: [ "rA", "rB" ]
|
||||
|
||||
|
@ -1218,7 +1281,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Load Indexed"
|
||||
bitmask: 0xfc00007f
|
||||
pattern: 0x1000000c
|
||||
args: [ "frD", "rA", "rB", "W", "ps_l" ]
|
||||
args: [ "frD", "rA", "rB", "ps_W", "ps_l" ]
|
||||
defs: [ "frD" ]
|
||||
uses: [ "rA.nz", "rB" ]
|
||||
|
||||
|
@ -1226,14 +1289,14 @@ opcodes:
|
|||
desc: "Paired Single Quantized Store"
|
||||
bitmask: 0xfc000000
|
||||
pattern: 0xf0000000
|
||||
args: [ "frS", "offset", "rA", "W", "ps_l" ]
|
||||
args: [ "frS", "offset", "rA", "ps_W", "ps_l" ]
|
||||
uses: [ "frS", "rA.nz" ]
|
||||
|
||||
- name: "psq_stu"
|
||||
desc: "Paired Single Quantized Store with Update"
|
||||
bitmask: 0xfc000000
|
||||
pattern: 0xf4000000
|
||||
args: [ "frS", "offset", "rA", "W", "ps_l" ]
|
||||
args: [ "frS", "offset", "rA", "ps_W", "ps_l" ]
|
||||
defs: [ "rA" ]
|
||||
uses: [ "frS", "rA" ]
|
||||
|
||||
|
@ -1241,7 +1304,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Store with Update Indexed"
|
||||
bitmask: 0xfc00007f
|
||||
pattern: 0x1000004e
|
||||
args: [ "frS", "rA", "rB", "W", "ps_l" ]
|
||||
args: [ "frS", "rA", "rB", "ps_W", "ps_l" ]
|
||||
defs: [ "rA" ]
|
||||
uses: [ "frS", "rA", "rB" ]
|
||||
|
||||
|
@ -1249,7 +1312,7 @@ opcodes:
|
|||
desc: "Paired Single Quantized Store Indexed"
|
||||
bitmask: 0xfc00007f
|
||||
pattern: 0x1000000e
|
||||
args: [ "frS", "rA", "rB", "W", "ps_l" ]
|
||||
args: [ "frS", "rA", "rB", "ps_W", "ps_l" ]
|
||||
uses: [ "frS", "rA.nz", "rB" ]
|
||||
|
||||
- name: "ps_abs"
|
||||
|
@ -1855,14 +1918,14 @@ opcodes:
|
|||
desc: "Trap Word"
|
||||
bitmask: 0xfc0007ff
|
||||
pattern: 0x7c000008
|
||||
args: [ "TO", "rA", "rB" ]
|
||||
args: [ "tw_TO", "rA", "rB" ]
|
||||
uses: [ "rA", "rB" ]
|
||||
|
||||
- name: "twi"
|
||||
desc: "Trap Word Immediate"
|
||||
bitmask: 0xfc000000
|
||||
pattern: 0xc0000000
|
||||
args: [ "TO", "rA", "simm" ]
|
||||
args: [ "tw_TO", "rA", "simm" ]
|
||||
uses: [ "rA" ]
|
||||
|
||||
- name: "xor"
|
||||
|
@ -1909,7 +1972,7 @@ mnemonics:
|
|||
condition: "S == B"
|
||||
- name: "nop"
|
||||
opcode: "ori"
|
||||
condition:
|
||||
match:
|
||||
- arg: "rA"
|
||||
value: 0
|
||||
- arg: "rS"
|
|
@ -1,22 +1,66 @@
|
|||
#![feature(proc_macro_span, proc_macro_def_site)]
|
||||
|
||||
mod isa;
|
||||
mod writer;
|
||||
//mod writer;
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
use proc_macro::Span;
|
||||
|
||||
use crate::isa::Isa;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn isa(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = proc_macro2::TokenStream::from(input);
|
||||
let output = match crate::isa::isa(input) {
|
||||
pub fn opcodes(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let isa = match load_isa() {
|
||||
Ok(v) => v,
|
||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
||||
Err(err) => return err,
|
||||
};
|
||||
proc_macro::TokenStream::from(output)
|
||||
match isa.gen_opcode_enum() {
|
||||
Ok(v) => v.into(),
|
||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn write_asm(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = proc_macro2::TokenStream::from(input);
|
||||
let output = match crate::writer::write_asm(input) {
|
||||
pub fn fields(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let isa = match load_isa() {
|
||||
Ok(v) => v,
|
||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
||||
Err(err) => return err,
|
||||
};
|
||||
proc_macro::TokenStream::from(output)
|
||||
match isa.gen_field_enum() {
|
||||
Ok(v) => v.into(),
|
||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn ins_impl(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let isa = match load_isa() {
|
||||
Ok(v) => v,
|
||||
Err(err) => return err,
|
||||
};
|
||||
match isa.gen_ins_impl() {
|
||||
Ok(v) => v.into(),
|
||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_isa() -> Result<Isa, proc_macro::TokenStream> {
|
||||
_load_isa().map_err(|err| {
|
||||
proc_macro::TokenStream::from(
|
||||
syn::Error::new(Span::def_site().into(), err).to_compile_error(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn _load_isa() -> Result<Isa, Box<dyn std::error::Error>> {
|
||||
// Figure out YAML path.
|
||||
let def_site = Span::def_site();
|
||||
let rust_path = def_site.source_file().path();
|
||||
let yaml_path = rust_path.parent().unwrap().join("isa.yaml");
|
||||
// Open and deserialize YAML file.
|
||||
let yaml_file = File::open(yaml_path).map_err(|e| syn::Error::new(def_site.into(), e))?;
|
||||
let isa: Isa =
|
||||
serde_yaml::from_reader(yaml_file).map_err(|e| syn::Error::new(def_site.into(), e))?;
|
||||
Ok(isa)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue