create write_asm macro

This commit is contained in:
Richard Patel 2021-08-15 10:32:46 +02:00
parent 0c65617c69
commit 67efa31bbd
12 changed files with 668 additions and 501 deletions

View File

@ -14,7 +14,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
rust: [nightly] rust: [stable]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
sccache-path: /home/runner/.cache/sccache sccache-path: /home/runner/.cache/sccache

1
Cargo.lock generated
View File

@ -80,6 +80,7 @@ name = "ppc750cl-macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote",
"syn", "syn",
] ]

View File

@ -98,7 +98,7 @@ impl Fuzzer {
fn disasm(x: u32) { fn disasm(x: u32) {
let devnull = DevNull; let devnull = DevNull;
let mut formatter = SimpleFormatter { writer: devnull }; let mut formatter = SimpleFormatter { writer: devnull };
let ins = Ins::disasm(x); let ins = Ins::new(x, 0x8000_0000u32);
ins.write_string(&mut formatter).unwrap(); ins.write_string(&mut formatter).unwrap();
} }

View File

@ -1,51 +1,68 @@
use crate::Ins; use std::fmt::{Display, LowerHex, UpperHex};
use num_traits::PrimInt;
use std::fmt::{LowerHex, UpperHex};
use std::io::Write; use std::io::Write;
use num_traits::PrimInt;
use crate::Ins;
type IOResult = std::io::Result<()>; type IOResult = std::io::Result<()>;
pub trait AsmFormatter<W> pub trait AsmFormatter<W>
where where
W: Write, W: Write,
{ {
/// Returns the underlying writer.
fn writer(&mut self) -> &mut W; fn writer(&mut self) -> &mut W;
/// Callback for custom styling before writing an instruction.
fn before_instruction(&mut self, _: &Ins) -> IOResult { fn before_instruction(&mut self, _: &Ins) -> IOResult {
Ok(()) Ok(())
} }
/// Callback for custom styling after writing an instruction.
fn after_instruction(&mut self, _: &Ins) -> IOResult { fn after_instruction(&mut self, _: &Ins) -> IOResult {
Ok(()) Ok(())
} }
/// Writes the instruction mnemonic.
fn write_mnemonic(&mut self, name: &str) -> IOResult { fn write_mnemonic(&mut self, name: &str) -> IOResult {
write!(self.writer(), "{}", name) write!(self.writer(), "{}", name)
} }
/// Separates the instruction mnemonic and arguments.
fn write_opcode_separator(&mut self) -> IOResult { fn write_opcode_separator(&mut self) -> IOResult {
write!(self.writer(), " ") write!(self.writer(), " ")
} }
/// Separates two instruction arguments (e.g. registers).
fn write_operand_separator(&mut self) -> IOResult { fn write_operand_separator(&mut self) -> IOResult {
write!(self.writer(), ", ") write!(self.writer(), ", ")
} }
/// Writes a general-purpose register argument.
fn write_gpr(&mut self, reg: u8) -> IOResult { fn write_gpr(&mut self, reg: u8) -> IOResult {
write!(self.writer(), "r{}", reg) write!(self.writer(), "r{}", reg)
} }
/// Writes a floating point register argument.
fn write_fpr(&mut self, reg: u8) -> IOResult { fn write_fpr(&mut self, reg: u8) -> IOResult {
write!(self.writer(), "f{}", reg) write!(self.writer(), "f{}", reg)
} }
/// Writes a condition register argument.
fn write_cr(&mut self, reg: u8) -> IOResult { fn write_cr(&mut self, reg: u8) -> IOResult {
write!(self.writer(), "cr{}", reg) write!(self.writer(), "cr{}", reg)
} }
/// Writes a paired-singles quantization register argument.
fn write_qr(&mut self, reg: u8) -> IOResult { fn write_qr(&mut self, reg: u8) -> IOResult {
write!(self.writer(), "qr{}", reg) write!(self.writer(), "qr{}", reg)
} }
fn write_sr(&mut self, reg: u8) -> IOResult {
write!(self.writer(), "{}", reg)
}
/// Sets the mnemonic 'o' suffix.
fn write_oe(&mut self, oe: u8) -> IOResult { fn write_oe(&mut self, oe: u8) -> IOResult {
if oe != 0 { if oe != 0 {
write!(self.writer(), "o")?; write!(self.writer(), "o")?;
@ -53,6 +70,7 @@ where
Ok(()) Ok(())
} }
/// Sets the mnemonic 'a' suffix.
fn write_aa(&mut self, aa: u8) -> IOResult { fn write_aa(&mut self, aa: u8) -> IOResult {
if aa != 0 { if aa != 0 {
write!(self.writer(), "a")?; write!(self.writer(), "a")?;
@ -60,6 +78,7 @@ where
Ok(()) Ok(())
} }
/// Sets the mnemonic 'l' suffix.
fn write_lk(&mut self, lk: u8) -> IOResult { fn write_lk(&mut self, lk: u8) -> IOResult {
if lk != 0 { if lk != 0 {
write!(self.writer(), "l")?; write!(self.writer(), "l")?;
@ -67,6 +86,7 @@ where
Ok(()) Ok(())
} }
/// Sets the mnemonic '.' suffix.
fn write_rc(&mut self, rc: u8) -> IOResult { fn write_rc(&mut self, rc: u8) -> IOResult {
if rc != 0 { if rc != 0 {
write!(self.writer(), ".")?; write!(self.writer(), ".")?;
@ -74,14 +94,21 @@ where
Ok(()) Ok(())
} }
/// Writes an unsigned immediate.
fn write_uimm(&mut self, uimm: u16) -> IOResult { fn write_uimm(&mut self, uimm: u16) -> IOResult {
write!(self.writer(), "{:#x}", uimm) write!(self.writer(), "{:#x}", uimm)
} }
/// Writes a signed immediate.
fn write_simm(&mut self, simm: i16) -> IOResult { fn write_simm(&mut self, simm: i16) -> IOResult {
write!(self.writer(), "{:#x}", ReallySigned(simm)) 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 { fn write_fm(&mut self, fm: u16) -> IOResult {
write!(self.writer(), "{}", fm) write!(self.writer(), "{}", fm)
} }
@ -90,13 +117,24 @@ where
write!(self.writer(), "{:#x}(", offset) 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(&mut self, offset: i16) -> IOResult { fn write_offset_open(&mut self, offset: i16) -> IOResult {
write!(self.writer(), "{:#x}(", ReallySigned(offset)) write!(self.writer(), "{:#x}(", ReallySigned(offset))
} }
/// Closes an offset prefix.
fn write_offset_close(&mut self) -> IOResult { fn write_offset_close(&mut self) -> IOResult {
write!(self.writer(), ")") write!(self.writer(), ")")
} }
/// Writes a branch target given the jump offset and current program counter.
fn write_branch_target(&mut self, offset: u32, pc: u32) -> IOResult {
write!(self.writer(), "{:#x}", offset + pc)
}
} }
pub struct SimpleFormatter<W: Write> { pub struct SimpleFormatter<W: Write> {

View File

@ -1,3 +1,4 @@
use crate::{bit, bits};
use ppc750cl_macros::isa; use ppc750cl_macros::isa;
isa! { isa! {
@ -224,3 +225,333 @@ isa! {
"xori" & 0xfc000000 == 0x68000000; "xori" & 0xfc000000 == 0x68000000;
"xoris" & 0xfc000000 == 0x6c000000; "xoris" & 0xfc000000 == 0x6c000000;
} }
impl Opcode {
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, 26..31) {
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, 26..31) {
0b00001 => Opcode::PsNeg,
0b00010 => Opcode::PsMr,
0b00100 => Opcode::PsNabs,
0b01000 => Opcode::PsAbs,
_ => Opcode::Illegal,
},
0b10000 => match bits(x, 26..31) {
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_1101 => 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_0000_0110 => Opcode::Dcbt,
0b01_0000_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_1111_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, 26..31) {
0b00 => Opcode::Fcmpu,
0b01 => Opcode::Fcmpo,
0b10 => Opcode::Mcrfs,
_ => Opcode::Illegal,
},
0b00110 => match bits(x, 26..31) {
0b001 => Opcode::Mtfsb1,
0b010 => Opcode::Mtfsb0,
0b100 => Opcode::Mtfsfi,
_ => Opcode::Illegal,
},
0b00111 => match bits(x, 26..31) {
0b10010 => Opcode::Mffs,
0b10110 => Opcode::Mtfsf,
_ => Opcode::Illegal,
},
0b01000 => match bits(x, 26..31) {
0b0001 => Opcode::Fneg,
0b0010 => Opcode::Fabs,
0b0100 => Opcode::Fnabs,
0b1000 => Opcode::Fmr,
_ => 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,
}
}
}

View File

@ -5,6 +5,10 @@ use std::ops::Range;
use num_traits::AsPrimitive; use num_traits::AsPrimitive;
use ppc750cl_macros::write_asm;
#[macro_use]
mod macros;
pub mod formatter; pub mod formatter;
mod isa; mod isa;
@ -15,6 +19,7 @@ pub use crate::isa::Opcode;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Ins { pub struct Ins {
pub code: u32, pub code: u32,
pub addr: u32,
pub op: Opcode, pub op: Opcode,
} }
@ -33,15 +38,6 @@ where
masked.as_() masked.as_()
} }
macro_rules! disasm_unreachable {
($msg:expr $(,)?) => {{
panic!(
"internal error: entered unreachable code disassembling instruction 0x{:08x}",
$msg
)
}};
}
macro_rules! ins_bit { macro_rules! ins_bit {
($func:ident, $idx:expr) => { ($func:ident, $idx:expr) => {
fn $func(&self) -> u8 { fn $func(&self) -> u8 {
@ -65,12 +61,9 @@ macro_rules! ins_field {
} }
impl Ins { impl Ins {
fn new(code: u32, op: Opcode) -> Self { pub fn new(code: u32, addr: u32) -> Self {
Ins { code, op } let op = Opcode::from_code(code);
} Self { code, addr, op }
fn illegal() -> Self {
Default::default()
} }
//ins_bit!(w, 21); //ins_bit!(w, 21);
@ -114,344 +107,6 @@ impl Ins {
ins_field!(ps_l, u8, 17..20); ins_field!(ps_l, u8, 17..20);
ins_field!(ps_d, u16, 20..32); ins_field!(ps_d, u16, 20..32);
pub fn disasm(x: u32) -> Self {
let family = bits(x, 0..6);
let mut ins = match family {
0b000011 => Ins::new(x, Opcode::Twi),
0b000100 => Self::disasm_cl_ext(x),
0b000111..=0b001111 => Self::disasm_basic1(x),
0b010000 => Ins::new(x, Opcode::Bc),
0b010001 => Ins::new(x, Opcode::Sc),
0b010010 => Ins::new(x, Opcode::B),
0b010011 => Self::disasm_010011(x),
0b010100..=0b011101 => Self::disasm_basic2(x),
0b011111 => Self::disasm_011111(x),
0b100000..=0b110111 => Self::disasm_basic3(x),
0b111000..=0b111001 => Self::disasm_psq(x),
0b111011 => Self::disasm_111011(x),
0b111100..=0b111101 => Self::disasm_psq(x),
0b111111 => Self::disasm_111111(x),
_ => Self::illegal(),
};
if !ins.op.is_valid(x) {
ins.op = Opcode::Illegal;
}
ins
}
fn disasm_cl_ext(x: u32) -> Self {
let op = match bits(x, 26..31) {
0b00000 => match bits(x, 26..31) {
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, 26..31) {
0b00001 => Opcode::PsNeg,
0b00010 => Opcode::PsMr,
0b00100 => Opcode::PsNabs,
0b01000 => Opcode::PsAbs,
_ => Opcode::Illegal,
},
0b10000 => match bits(x, 26..31) {
0b10000 => Opcode::PsMerge00,
0b10001 => Opcode::PsMerge01,
0b10010 => Opcode::PsMerge10,
0b10011 => Opcode::PsMerge11,
_ => Opcode::Illegal,
},
0b10110 => Opcode::DcbzL,
// Unknown paired-singles key.
_ => Opcode::Illegal,
};
Ins::new(x, op)
}
fn disasm_basic1(x: u32) -> Self {
let op = 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,
};
Ins::new(x, op)
}
fn disasm_010011(x: u32) -> Self {
let op = 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,
};
Ins::new(x, op)
}
fn disasm_basic2(x: u32) -> Self {
let op = 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,
};
Ins::new(x, op)
}
fn disasm_011111(x: u32) -> Self {
let op = 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_1101 => 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_0000_0110 => Opcode::Dcbt,
0b01_0000_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_1111_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,
};
Ins::new(x, op)
}
fn disasm_basic3(x: u32) -> Self {
let op = 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),
};
Ins::new(x, op)
}
fn disasm_psq(x: u32) -> Self {
let op = match bits(x, 0..6) {
0b111000 => Opcode::PsqL,
0b111001 => Opcode::PsqLu,
0b111100 => Opcode::PsqSt,
0b111101 => Opcode::PsqStu,
_ => disasm_unreachable!(x),
};
Ins::new(x, op)
}
fn disasm_111011(x: u32) -> Self {
let op = 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,
};
Ins::new(x, op)
}
fn disasm_111111(x: u32) -> Self {
let op = match bits::<u32>(x, 26..31) {
0b00000 => match bits(x, 26..31) {
0b00 => Opcode::Fcmpu,
0b01 => Opcode::Fcmpo,
0b10 => Opcode::Mcrfs,
_ => Opcode::Illegal,
},
0b00110 => match bits(x, 26..31) {
0b001 => Opcode::Mtfsb1,
0b010 => Opcode::Mtfsb0,
0b100 => Opcode::Mtfsfi,
_ => Opcode::Illegal,
},
0b00111 => match bits(x, 26..31) {
0b10010 => Opcode::Mffs,
0b10110 => Opcode::Mtfsf,
_ => Opcode::Illegal,
},
0b01000 => match bits(x, 26..31) {
0b0001 => Opcode::Fneg,
0b0010 => Opcode::Fabs,
0b0100 => Opcode::Fnabs,
0b1000 => Opcode::Fmr,
_ => 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,
};
Ins::new(x, op)
}
fn write_asm_form_reg123<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_reg123<F, W>(&self, out: &mut F) -> std::io::Result<()>
where where
F: AsmFormatter<W>, F: AsmFormatter<W>,
@ -769,8 +424,9 @@ impl Ins {
out.write_mnemonic(self.op.mnemonic())?; out.write_mnemonic(self.op.mnemonic())?;
out.write_lk(self.lk())?; out.write_lk(self.lk())?;
out.write_aa(self.aa())?; out.write_aa(self.aa())?;
// TODO absolute address out.write_opcode_separator()?;
write!(out.writer(), "0x{:x}", self.li()) out.write_branch_target(self.li(), self.addr)?;
Ok(())
} }
fn write_asm_bc<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_bc<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -781,14 +437,13 @@ impl Ins {
out.write_mnemonic(self.op.mnemonic())?; out.write_mnemonic(self.op.mnemonic())?;
out.write_lk(self.lk())?; out.write_lk(self.lk())?;
out.write_aa(self.aa())?; out.write_aa(self.aa())?;
// TODO absolute address out.write_opcode_separator()?;
write!( write!(out.writer(), "{}", self.bo())?;
out.writer(), out.write_operand_separator()?;
"0x{:x}, 0x{:x}, 0x{:x}", write!(out.writer(), "{}", self.bi())?;
self.bo(), out.write_operand_separator()?;
self.bi(), out.write_branch_target(self.li(), self.addr)?;
self.li() Ok(())
)
} }
fn write_asm_branch_cond_to_reg<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_branch_cond_to_reg<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -813,13 +468,12 @@ impl Ins {
}, },
_ => disasm_unreachable!(self.code), _ => disasm_unreachable!(self.code),
}; };
write!( out.write_mnemonic(name)?;
out.writer(), out.write_opcode_separator()?;
"{} 0x{:x}, 0x{:x}", write!(out.writer(), "{}", self.bo())?;
name, out.write_operand_separator()?;
self.bo(), write!(out.writer(), "{}", self.bi())?;
self.bi() Ok(())
)
} }
fn write_asm_cmp<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_cmp<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -827,15 +481,16 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} crf{}, {}, r{}, r{}", out.write_cr(self.crf_d())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.crf_d(), write!(out.writer(), "{}", self.l())?;
self.l() as u8, out.write_operand_separator()?;
self.a(), out.write_gpr(self.a())?;
self.b() out.write_operand_separator()?;
) out.write_gpr(self.b())?;
Ok(())
} }
fn write_asm_cmp_simm<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_cmp_simm<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -843,15 +498,16 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} crf{}, {}, r{}, {}", out.write_cr(self.crf_d())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.crf_d(), write!(out.writer(), "{}", self.l())?;
self.l() as u8, out.write_operand_separator()?;
self.a(), out.write_gpr(self.a())?;
self.simm() out.write_operand_separator()?;
) out.write_simm(self.simm())?;
Ok(())
} }
fn write_asm_cmp_uimm<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_cmp_uimm<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -859,15 +515,16 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} crf{}, {}, r{}, {}", out.write_cr(self.crf_d())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.crf_d(), write!(out.writer(), "{}", self.l())?;
self.l() as u8, out.write_operand_separator()?;
self.a(), out.write_gpr(self.a())?;
self.uimm() out.write_operand_separator()?;
) out.write_uimm(self.uimm())?;
Ok(())
} }
fn write_asm_form_condreg1<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_condreg1<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -887,7 +544,10 @@ impl Ins {
}, },
_ => disasm_unreachable!(self.code), _ => disasm_unreachable!(self.code),
}; };
write!(out.writer(), "{} crf{}", name, self.crf_d()) out.write_mnemonic(name)?;
out.write_opcode_separator()?;
out.write_cr(self.crf_d())?;
Ok(())
} }
fn write_asm_form_condreg12<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_condreg12<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -900,13 +560,12 @@ impl Ins {
Opcode::Mcrfs => "mcrfs", Opcode::Mcrfs => "mcrfs",
_ => disasm_unreachable!(self.code), _ => disasm_unreachable!(self.code),
}; };
write!( out.write_mnemonic(name)?;
out.writer(), out.write_opcode_separator()?;
"{} crf{}, crf{}", out.write_cr(self.crf_d())?;
name, out.write_operand_separator()?;
self.crf_d(), out.write_cr(self.crf_s())?;
self.crf_s() Ok(())
)
} }
fn write_asm_form_condreg123<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_condreg123<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -914,14 +573,14 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} crb{}, crb{}, crb{}", out.write_cr(self.crb_d())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.crb_d(), out.write_cr(self.crb_a())?;
self.crb_a(), out.write_operand_separator()?;
self.crb_b() out.write_cr(self.crb_b())?;
) Ok(())
} }
fn write_asm_form_reg23<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_reg23<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -929,13 +588,12 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} r{}, r{}", out.write_gpr(self.a())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.a(), out.write_gpr(self.b())?;
self.b() Ok(())
)
} }
fn write_asm_form_reg213<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_reg213<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -943,7 +601,6 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
let name_suffix = if self.rc() != 0 { "." } else { "" };
let name = match self.op { let name = match self.op {
Opcode::Eqv => "eqv", Opcode::Eqv => "eqv",
Opcode::Nand => "nand", Opcode::Nand => "nand",
@ -961,15 +618,15 @@ impl Ins {
Opcode::Srw => "srw", Opcode::Srw => "srw",
_ => disasm_unreachable!(self.code), _ => disasm_unreachable!(self.code),
}; };
write!( out.write_mnemonic(name)?;
out.writer(), out.write_rc(self.rc())?;
"{}{} r{}, r{}, r{}", out.write_opcode_separator()?;
name, out.write_gpr(self.a())?;
name_suffix, out.write_operand_separator()?;
self.a(), out.write_gpr(self.s())?;
self.s(), out.write_operand_separator()?;
self.b() out.write_gpr(self.b())?;
) Ok(())
} }
fn write_asm_rlw_imm<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_rlw_imm<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -1065,13 +722,12 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} r{}, {}", out.write_gpr(self.d())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.d(), out.write_sr(self.sr())?;
self.sr() Ok(())
)
} }
fn write_asm_form_sr_reg1<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_form_sr_reg1<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -1079,13 +735,12 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
write!( out.write_mnemonic(self.op.mnemonic())?;
out.writer(), out.write_opcode_separator()?;
"{} {}, r{}", out.write_sr(self.sr())?;
self.op.mnemonic(), out.write_operand_separator()?;
self.sr(), out.write_gpr(self.s())?;
self.s() Ok(())
)
} }
fn write_asm_mtcrf<F, W>(&self, out: &mut F) -> std::io::Result<()> fn write_asm_mtcrf<F, W>(&self, out: &mut F) -> std::io::Result<()>
@ -1154,17 +809,14 @@ impl Ins {
F: AsmFormatter<W>, F: AsmFormatter<W>,
W: Write, W: Write,
{ {
out.write_mnemonic(self.op.mnemonic())?; write_asm!(out, self => {
out.write_opcode_separator()?; (op.mnemonic, rc, oe) -> mnemonic;
out.write_fpr(self.d())?; (d) -> fpr;
out.write_operand_separator()?; (ps_d) -> offset_unsigned;
out.write_offset_unsigned_open(self.ps_d())?; (a) -> gpr;
out.write_gpr(self.a())?; (w) -> mode;
out.write_offset_close()?; (ps_l) -> qr;
out.write_operand_separator()?; });
write!(out.writer(), "{}", self.w())?;
out.write_operand_separator()?;
out.write_qr(self.ps_l())?;
Ok(()) Ok(())
} }
@ -1446,7 +1098,7 @@ mod tests {
fn test_opcodes() { fn test_opcodes() {
macro_rules! assert_op { macro_rules! assert_op {
($code:expr, $op:expr) => {{ ($code:expr, $op:expr) => {{
assert_eq!(Ins::disasm($code).op, $op) assert_eq!(Ins::new($code, 0x8000_0000u32).op, $op)
}}; }};
} }
@ -1469,10 +1121,10 @@ mod tests {
fn test_to_string() { fn test_to_string() {
macro_rules! assert_asm { macro_rules! assert_asm {
($code:expr, $disasm:expr) => {{ ($code:expr, $disasm:expr) => {{
assert_eq!(Ins::disasm($code).to_string(), $disasm) assert_eq!(Ins::new($code, 0x8000_0000u32).to_string(), $disasm)
}}; }};
} }
assert_asm!(0x4c000000, "mcrf crf0, crf0"); assert_asm!(0x4c000000, "mcrf cr0, cr0");
assert_asm!(0x7c000278, "xor r0, r0, r0"); assert_asm!(0x7c000278, "xor r0, r0, r0");
assert_asm!(0x10000014, "ps_sum0 f0, f0, f0, f0"); assert_asm!(0x10000014, "ps_sum0 f0, f0, f0, f0");
assert_asm!(0x10000032, "ps_mul f0, f0, f0"); assert_asm!(0x10000032, "ps_mul f0, f0, f0");

View File

@ -0,0 +1,8 @@
macro_rules! disasm_unreachable {
($msg:expr $(,)?) => {{
panic!(
"internal error: entered unreachable code disassembling instruction 0x{:08x}",
$msg
)
}};
}

View File

@ -12,4 +12,5 @@ proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "1.0.28" proc-macro2 = "1.0.28"
syn = { version = "1.0.74", features = ["full"] } quote = "1.0.9"
syn = { version = "1.0.74", features = ["full", "parsing"] }

View File

@ -1,12 +1,14 @@
use proc_macro::{quote, Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree};
use std::iter::FromIterator; use std::iter::FromIterator;
use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree};
use quote::quote;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::token::{And, EqEq}; use syn::token::{And, EqEq, Semi};
use syn::{LitInt, LitStr, Token}; use syn::{LitInt, LitStr};
struct Opcodes { struct Opcodes {
opcodes: Punctuated<Opcode, Token![;]>, opcodes: Punctuated<Opcode, Semi>,
} }
impl Parse for Opcodes { impl Parse for Opcodes {
@ -140,22 +142,20 @@ fn gen_mnemonic_fn(tokens: &mut Vec<TokenTree>, opcodes: &Opcodes) {
tokens.push(TokenTree::Group(body)); tokens.push(TokenTree::Group(body));
} }
pub(crate) fn isa(input: TokenStream) -> TokenStream { pub(crate) fn isa(input: TokenStream) -> syn::Result<TokenStream> {
let opcodes = syn::parse_macro_input!(input as Opcodes); let opcodes: Opcodes = syn::parse2(input)?;
// Assemble root stream. // Assemble root stream.
let mut root = Vec::<TokenTree>::new(); let mut root = Vec::<TokenTree>::new();
// Define enum derives and header. // Define enum derives and header.
let derives = quote!(#[derive(Debug, Copy, Clone, Eq, PartialEq)]); root.extend(quote!(#[derive(Debug, Copy, Clone, Eq, PartialEq)]));
root.append(&mut derives.into_iter().collect()); root.extend(quote!(pub enum Opcode));
let enum_header = quote!(pub enum Opcode);
root.append(&mut enum_header.into_iter().collect());
// Create entries. // Create entries.
// First entry is going to be the illegal entry. // First entry is going to be the illegal entry.
let mut enum_entries = Vec::<TokenTree>::new(); let mut enum_entries = Vec::<TokenTree>::new();
enum_entries.append(&mut (quote!(Illegal = -1,).into_iter().collect())); enum_entries.extend(quote!(Illegal = -1,));
// Append the actual opcodes. // Append the actual opcodes.
for opcode in &opcodes.opcodes { for opcode in &opcodes.opcodes {
enum_entries.push(TokenTree::Ident(Ident::new( enum_entries.push(TokenTree::Ident(Ident::new(
@ -169,19 +169,8 @@ pub(crate) fn isa(input: TokenStream) -> TokenStream {
let enum_body = Group::new(Delimiter::Brace, TokenStream::from_iter(enum_entries)); let enum_body = Group::new(Delimiter::Brace, TokenStream::from_iter(enum_entries));
root.push(TokenTree::Group(enum_body)); root.push(TokenTree::Group(enum_body));
// Default implementation.
let opcode_default = quote! {
impl Default for Opcode {
fn default() -> Self {
Opcode::Illegal
}
}
};
root.append(&mut opcode_default.into_iter().collect());
// impl Opcode block. // impl Opcode block.
let impl_opcode_header = quote!(impl Opcode); root.extend(quote!(impl Opcode));
root.append(&mut impl_opcode_header.into_iter().collect());
let mut impl_opcode_body_parts = Vec::<TokenTree>::new(); let mut impl_opcode_body_parts = Vec::<TokenTree>::new();
gen_is_valid_fn(&mut impl_opcode_body_parts, &opcodes); gen_is_valid_fn(&mut impl_opcode_body_parts, &opcodes);
gen_mnemonic_fn(&mut impl_opcode_body_parts, &opcodes); gen_mnemonic_fn(&mut impl_opcode_body_parts, &opcodes);
@ -191,21 +180,25 @@ pub(crate) fn isa(input: TokenStream) -> TokenStream {
); );
root.push(TokenTree::Group(impl_opcode_body)); root.push(TokenTree::Group(impl_opcode_body));
// impl ToString block. // Extra code.
let to_string_trait_impl = quote! { root.extend(quote! {
impl Default for Opcode {
fn default() -> Self {
Opcode::Illegal
}
}
impl std::string::ToString for Opcode { impl std::string::ToString for Opcode {
fn to_string(&self) -> String { fn to_string(&self) -> String {
let mnemonic = self.mnemonic(); let mnemonic = self.mnemonic();
mnemonic.to_owned() mnemonic.to_owned()
} }
} }
}; });
root.append(&mut to_string_trait_impl.into_iter().collect());
TokenStream::from_iter(root) Ok(TokenStream::from_iter(root))
} }
#[proc_macro]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -1,11 +1,22 @@
#![feature(proc_macro_quote)]
use proc_macro::TokenStream;
#[macro_use]
mod isa; mod isa;
mod writer;
#[proc_macro] #[proc_macro]
pub fn isa(input: TokenStream) -> TokenStream { pub fn isa(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
crate::isa::isa(input) let input = proc_macro2::TokenStream::from(input);
let output = match crate::isa::isa(input) {
Ok(v) => v,
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
};
proc_macro::TokenStream::from(output)
}
#[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) {
Ok(v) => v,
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
};
proc_macro::TokenStream::from(output)
} }

132
macros/src/writer.rs Normal file
View File

@ -0,0 +1,132 @@
use std::iter::FromIterator;
use std::string::ToString;
use proc_macro2::{TokenStream, TokenTree};
use quote::quote;
use quote::ToTokens;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::token::Semi;
use syn::{Expr, Ident};
struct Arguments {
formatter: Expr,
ins: Expr,
args: Punctuated<Argument, Semi>,
}
impl Parse for Arguments {
fn parse(input: ParseStream) -> syn::Result<Self> {
let formatter = input.parse()?;
input.parse::<syn::token::Comma>()?;
let ins = input.parse()?;
input.parse::<syn::token::FatArrow>()?;
let content;
syn::braced!(content in input);
let args = Punctuated::parse_terminated(&content)?;
Ok(Self {
formatter,
ins,
args,
})
}
}
struct Argument {
sources: Punctuated<Expr, syn::token::Comma>,
target: Ident,
}
impl Parse for Argument {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
syn::parenthesized!(content in input);
let sources = content.parse_terminated(Expr::parse)?;
input.parse::<syn::token::RArrow>()?;
let target = input.parse()?;
Ok(Self { sources, target })
}
}
impl Arguments {
fn format_mnemonic(&self, tokens: &mut Vec<TokenTree>) {
let arg = &self.args[0];
assert!(!arg.sources.is_empty());
self.format_call(tokens, &arg.target, self.ins_call(&arg.sources[0]))
}
fn format_call(&self, tokens: &mut Vec<TokenTree>, method_arg: &Ident, args: TokenStream) {
let method_name = format!("write_{}", method_arg.to_string());
let method_name = Ident::new(&method_name, method_arg.span());
let formatter = &self.formatter;
tokens.extend(quote!(#formatter.#method_name(#args)?;))
}
fn ins_call(&self, call: &Expr) -> TokenStream {
let ins = &self.ins;
quote!(#ins.#call())
}
}
pub(crate) fn write_asm(input: TokenStream) -> syn::Result<TokenStream> {
let arguments: Arguments = syn::parse2(input)?;
assert!(!arguments.args.is_empty());
let mut tokens = Vec::<TokenTree>::new();
arguments.format_mnemonic(&mut tokens);
let mut offset_open = false;
for (i, arg) in arguments.args.iter().enumerate().skip(1) {
// Separate operands from one another unless the last one was an offset.
if !offset_open {
if i == 1 {
arguments.format_call(
&mut tokens,
&Ident::new("opcode_separator", arg.target.span()),
quote!(),
);
} else {
arguments.format_call(
&mut tokens,
&Ident::new("operand_separator", arg.target.span()),
quote!(),
);
}
}
// Arguments to out.write_x(...);
let format_args = arg.sources.iter().map(|src| arguments.ins_call(src));
let format_args_punct: Punctuated<TokenStream, syn::token::Comma> =
Punctuated::from_iter(format_args);
// Create call.
if arg.target.to_string().starts_with("offset") {
// Offsets are a special case since we need to call close afterwards.
if offset_open {
return Err(syn::Error::new(
arg.target.span(),
"two consecutive offset arguments",
));
}
arguments.format_call(
&mut tokens,
&Ident::new(&(arg.target.to_string() + "_open"), arg.target.span()),
format_args_punct.to_token_stream(),
);
offset_open = true;
} else {
arguments.format_call(
&mut tokens,
&arg.target,
format_args_punct.to_token_stream(),
);
if offset_open {
arguments.format_call(
&mut tokens,
&Ident::new("offset_close", arg.target.span()),
quote!(),
);
offset_open = false;
}
}
}
Ok(TokenStream::from_iter(tokens.into_iter()))
}

View File

@ -12,7 +12,7 @@ fn main() {
let stream = BufWriter::with_capacity(1_000_000, stdout_lock); let stream = BufWriter::with_capacity(1_000_000, stdout_lock);
let mut formatter = SimpleFormatter { writer: stream }; let mut formatter = SimpleFormatter { writer: stream };
loop { loop {
let ins = Ins::disasm(rng.next_u32()); let ins = Ins::new(rng.next_u32(), 0);
if ins.op == Opcode::Illegal { if ins.op == Opcode::Illegal {
continue; continue;
} }