diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45a44f7..2a82eb2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - rust: [nightly] + rust: [stable] include: - os: ubuntu-latest sccache-path: /home/runner/.cache/sccache diff --git a/Cargo.lock b/Cargo.lock index 1cb9fdc..b25a613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,7 @@ name = "ppc750cl-macros" version = "0.1.0" dependencies = [ "proc-macro2", + "quote", "syn", ] diff --git a/fuzz/src/main.rs b/fuzz/src/main.rs index 166e9d6..e4d1d84 100644 --- a/fuzz/src/main.rs +++ b/fuzz/src/main.rs @@ -98,7 +98,7 @@ impl Fuzzer { fn disasm(x: u32) { let devnull = 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(); } diff --git a/lib/src/formatter.rs b/lib/src/formatter.rs index f96dfb2..9f5e9ed 100644 --- a/lib/src/formatter.rs +++ b/lib/src/formatter.rs @@ -1,51 +1,68 @@ -use crate::Ins; -use num_traits::PrimInt; -use std::fmt::{LowerHex, UpperHex}; +use std::fmt::{Display, LowerHex, UpperHex}; use std::io::Write; +use num_traits::PrimInt; + +use crate::Ins; + type IOResult = std::io::Result<()>; pub trait AsmFormatter where W: Write, { + /// Returns the underlying writer. fn writer(&mut self) -> &mut W; + /// 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(()) } + /// Writes the instruction mnemonic. fn write_mnemonic(&mut self, name: &str) -> IOResult { write!(self.writer(), "{}", name) } + /// Separates the instruction mnemonic and arguments. fn write_opcode_separator(&mut self) -> IOResult { write!(self.writer(), " ") } + /// Separates two instruction arguments (e.g. registers). fn write_operand_separator(&mut self) -> IOResult { write!(self.writer(), ", ") } + /// Writes a general-purpose register argument. fn write_gpr(&mut self, reg: u8) -> IOResult { write!(self.writer(), "r{}", reg) } + /// Writes a floating point register argument. fn write_fpr(&mut self, reg: u8) -> IOResult { write!(self.writer(), "f{}", reg) } + /// Writes a condition register argument. fn write_cr(&mut self, reg: u8) -> IOResult { write!(self.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_sr(&mut self, reg: u8) -> IOResult { + write!(self.writer(), "{}", reg) + } + + /// Sets the mnemonic 'o' suffix. fn write_oe(&mut self, oe: u8) -> IOResult { if oe != 0 { write!(self.writer(), "o")?; @@ -53,6 +70,7 @@ where Ok(()) } + /// Sets the mnemonic 'a' suffix. fn write_aa(&mut self, aa: u8) -> IOResult { if aa != 0 { write!(self.writer(), "a")?; @@ -60,6 +78,7 @@ where Ok(()) } + /// Sets the mnemonic 'l' suffix. fn write_lk(&mut self, lk: u8) -> IOResult { if lk != 0 { write!(self.writer(), "l")?; @@ -67,6 +86,7 @@ where Ok(()) } + /// Sets the mnemonic '.' suffix. fn write_rc(&mut self, rc: u8) -> IOResult { if rc != 0 { write!(self.writer(), ".")?; @@ -74,14 +94,21 @@ where Ok(()) } + /// Writes an unsigned immediate. fn write_uimm(&mut self, uimm: u16) -> IOResult { write!(self.writer(), "{:#x}", uimm) } + /// Writes a signed immediate. fn write_simm(&mut self, simm: i16) -> IOResult { write!(self.writer(), "{:#x}", ReallySigned(simm)) } + /// Writes an instruction-specific field like the compare mode. + fn write_mode(&mut self, mode: P) -> IOResult { + write!(self.writer(), "{}", mode) + } + fn write_fm(&mut self, fm: u16) -> IOResult { write!(self.writer(), "{}", fm) } @@ -90,13 +117,24 @@ where 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 { 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: u32, pc: u32) -> IOResult { + write!(self.writer(), "{:#x}", offset + pc) + } } pub struct SimpleFormatter { diff --git a/lib/src/isa.rs b/lib/src/isa.rs index ea6a61d..491b17c 100644 --- a/lib/src/isa.rs +++ b/lib/src/isa.rs @@ -1,3 +1,4 @@ +use crate::{bit, bits}; use ppc750cl_macros::isa; isa! { @@ -224,3 +225,333 @@ isa! { "xori" & 0xfc000000 == 0x68000000; "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::(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::(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, + } + } +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f185cc9..3d4e51a 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -5,6 +5,10 @@ use std::ops::Range; use num_traits::AsPrimitive; +use ppc750cl_macros::write_asm; + +#[macro_use] +mod macros; pub mod formatter; mod isa; @@ -15,6 +19,7 @@ pub use crate::isa::Opcode; #[derive(Default, Clone)] pub struct Ins { pub code: u32, + pub addr: u32, pub op: Opcode, } @@ -33,15 +38,6 @@ where masked.as_() } -macro_rules! disasm_unreachable { - ($msg:expr $(,)?) => {{ - panic!( - "internal error: entered unreachable code disassembling instruction 0x{:08x}", - $msg - ) - }}; -} - macro_rules! ins_bit { ($func:ident, $idx:expr) => { fn $func(&self) -> u8 { @@ -65,12 +61,9 @@ macro_rules! ins_field { } impl Ins { - fn new(code: u32, op: Opcode) -> Self { - Ins { code, op } - } - - fn illegal() -> Self { - Default::default() + pub fn new(code: u32, addr: u32) -> Self { + let op = Opcode::from_code(code); + Self { code, addr, op } } //ins_bit!(w, 21); @@ -114,344 +107,6 @@ impl Ins { ins_field!(ps_l, u8, 17..20); 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::(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::(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(&self, out: &mut F) -> std::io::Result<()> where F: AsmFormatter, @@ -769,8 +424,9 @@ impl Ins { out.write_mnemonic(self.op.mnemonic())?; out.write_lk(self.lk())?; out.write_aa(self.aa())?; - // TODO absolute address - write!(out.writer(), "0x{:x}", self.li()) + out.write_opcode_separator()?; + out.write_branch_target(self.li(), self.addr)?; + Ok(()) } fn write_asm_bc(&self, out: &mut F) -> std::io::Result<()> @@ -781,14 +437,13 @@ impl Ins { out.write_mnemonic(self.op.mnemonic())?; out.write_lk(self.lk())?; out.write_aa(self.aa())?; - // TODO absolute address - write!( - out.writer(), - "0x{:x}, 0x{:x}, 0x{:x}", - self.bo(), - self.bi(), - self.li() - ) + out.write_opcode_separator()?; + write!(out.writer(), "{}", self.bo())?; + out.write_operand_separator()?; + write!(out.writer(), "{}", self.bi())?; + out.write_operand_separator()?; + out.write_branch_target(self.li(), self.addr)?; + Ok(()) } fn write_asm_branch_cond_to_reg(&self, out: &mut F) -> std::io::Result<()> @@ -813,13 +468,12 @@ impl Ins { }, _ => disasm_unreachable!(self.code), }; - write!( - out.writer(), - "{} 0x{:x}, 0x{:x}", - name, - self.bo(), - self.bi() - ) + out.write_mnemonic(name)?; + out.write_opcode_separator()?; + write!(out.writer(), "{}", self.bo())?; + out.write_operand_separator()?; + write!(out.writer(), "{}", self.bi())?; + Ok(()) } fn write_asm_cmp(&self, out: &mut F) -> std::io::Result<()> @@ -827,15 +481,16 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} crf{}, {}, r{}, r{}", - self.op.mnemonic(), - self.crf_d(), - self.l() as u8, - self.a(), - self.b() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_cr(self.crf_d())?; + out.write_operand_separator()?; + write!(out.writer(), "{}", self.l())?; + out.write_operand_separator()?; + out.write_gpr(self.a())?; + out.write_operand_separator()?; + out.write_gpr(self.b())?; + Ok(()) } fn write_asm_cmp_simm(&self, out: &mut F) -> std::io::Result<()> @@ -843,15 +498,16 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} crf{}, {}, r{}, {}", - self.op.mnemonic(), - self.crf_d(), - self.l() as u8, - self.a(), - self.simm() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_cr(self.crf_d())?; + out.write_operand_separator()?; + write!(out.writer(), "{}", self.l())?; + out.write_operand_separator()?; + out.write_gpr(self.a())?; + out.write_operand_separator()?; + out.write_simm(self.simm())?; + Ok(()) } fn write_asm_cmp_uimm(&self, out: &mut F) -> std::io::Result<()> @@ -859,15 +515,16 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} crf{}, {}, r{}, {}", - self.op.mnemonic(), - self.crf_d(), - self.l() as u8, - self.a(), - self.uimm() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_cr(self.crf_d())?; + out.write_operand_separator()?; + write!(out.writer(), "{}", self.l())?; + out.write_operand_separator()?; + out.write_gpr(self.a())?; + out.write_operand_separator()?; + out.write_uimm(self.uimm())?; + Ok(()) } fn write_asm_form_condreg1(&self, out: &mut F) -> std::io::Result<()> @@ -887,7 +544,10 @@ impl Ins { }, _ => 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(&self, out: &mut F) -> std::io::Result<()> @@ -900,13 +560,12 @@ impl Ins { Opcode::Mcrfs => "mcrfs", _ => disasm_unreachable!(self.code), }; - write!( - out.writer(), - "{} crf{}, crf{}", - name, - self.crf_d(), - self.crf_s() - ) + out.write_mnemonic(name)?; + out.write_opcode_separator()?; + out.write_cr(self.crf_d())?; + out.write_operand_separator()?; + out.write_cr(self.crf_s())?; + Ok(()) } fn write_asm_form_condreg123(&self, out: &mut F) -> std::io::Result<()> @@ -914,14 +573,14 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} crb{}, crb{}, crb{}", - self.op.mnemonic(), - self.crb_d(), - self.crb_a(), - self.crb_b() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_cr(self.crb_d())?; + out.write_operand_separator()?; + out.write_cr(self.crb_a())?; + out.write_operand_separator()?; + out.write_cr(self.crb_b())?; + Ok(()) } fn write_asm_form_reg23(&self, out: &mut F) -> std::io::Result<()> @@ -929,13 +588,12 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} r{}, r{}", - self.op.mnemonic(), - self.a(), - self.b() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_gpr(self.a())?; + out.write_operand_separator()?; + out.write_gpr(self.b())?; + Ok(()) } fn write_asm_form_reg213(&self, out: &mut F) -> std::io::Result<()> @@ -943,7 +601,6 @@ impl Ins { F: AsmFormatter, W: Write, { - let name_suffix = if self.rc() != 0 { "." } else { "" }; let name = match self.op { Opcode::Eqv => "eqv", Opcode::Nand => "nand", @@ -961,15 +618,15 @@ impl Ins { Opcode::Srw => "srw", _ => disasm_unreachable!(self.code), }; - write!( - out.writer(), - "{}{} r{}, r{}, r{}", - name, - name_suffix, - self.a(), - self.s(), - self.b() - ) + out.write_mnemonic(name)?; + out.write_rc(self.rc())?; + out.write_opcode_separator()?; + out.write_gpr(self.a())?; + out.write_operand_separator()?; + out.write_gpr(self.s())?; + out.write_operand_separator()?; + out.write_gpr(self.b())?; + Ok(()) } fn write_asm_rlw_imm(&self, out: &mut F) -> std::io::Result<()> @@ -1065,13 +722,12 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} r{}, {}", - self.op.mnemonic(), - self.d(), - self.sr() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_gpr(self.d())?; + out.write_operand_separator()?; + out.write_sr(self.sr())?; + Ok(()) } fn write_asm_form_sr_reg1(&self, out: &mut F) -> std::io::Result<()> @@ -1079,13 +735,12 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} {}, r{}", - self.op.mnemonic(), - self.sr(), - self.s() - ) + out.write_mnemonic(self.op.mnemonic())?; + out.write_opcode_separator()?; + out.write_sr(self.sr())?; + out.write_operand_separator()?; + out.write_gpr(self.s())?; + Ok(()) } fn write_asm_mtcrf(&self, out: &mut F) -> std::io::Result<()> @@ -1154,17 +809,14 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_offset_unsigned_open(self.ps_d())?; - out.write_gpr(self.a())?; - out.write_offset_close()?; - out.write_operand_separator()?; - write!(out.writer(), "{}", self.w())?; - out.write_operand_separator()?; - out.write_qr(self.ps_l())?; + write_asm!(out, self => { + (op.mnemonic, rc, oe) -> mnemonic; + (d) -> fpr; + (ps_d) -> offset_unsigned; + (a) -> gpr; + (w) -> mode; + (ps_l) -> qr; + }); Ok(()) } @@ -1446,7 +1098,7 @@ mod tests { fn test_opcodes() { macro_rules! assert_op { ($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() { macro_rules! assert_asm { ($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!(0x10000014, "ps_sum0 f0, f0, f0, f0"); assert_asm!(0x10000032, "ps_mul f0, f0, f0"); diff --git a/lib/src/macros.rs b/lib/src/macros.rs index e69de29..60718d2 100644 --- a/lib/src/macros.rs +++ b/lib/src/macros.rs @@ -0,0 +1,8 @@ +macro_rules! disasm_unreachable { + ($msg:expr $(,)?) => {{ + panic!( + "internal error: entered unreachable code disassembling instruction 0x{:08x}", + $msg + ) + }}; +} diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 7ec29f8..6594b19 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -12,4 +12,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.28" -syn = { version = "1.0.74", features = ["full"] } +quote = "1.0.9" +syn = { version = "1.0.74", features = ["full", "parsing"] } diff --git a/macros/src/isa.rs b/macros/src/isa.rs index 7a7785e..2b089fc 100644 --- a/macros/src/isa.rs +++ b/macros/src/isa.rs @@ -1,12 +1,14 @@ -use proc_macro::{quote, Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree}; use std::iter::FromIterator; + +use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree}; +use quote::quote; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; -use syn::token::{And, EqEq}; -use syn::{LitInt, LitStr, Token}; +use syn::token::{And, EqEq, Semi}; +use syn::{LitInt, LitStr}; struct Opcodes { - opcodes: Punctuated, + opcodes: Punctuated, } impl Parse for Opcodes { @@ -140,22 +142,20 @@ fn gen_mnemonic_fn(tokens: &mut Vec, opcodes: &Opcodes) { tokens.push(TokenTree::Group(body)); } -pub(crate) fn isa(input: TokenStream) -> TokenStream { - let opcodes = syn::parse_macro_input!(input as Opcodes); +pub(crate) fn isa(input: TokenStream) -> syn::Result { + let opcodes: Opcodes = syn::parse2(input)?; // Assemble root stream. let mut root = Vec::::new(); // Define enum derives and header. - let derives = quote!(#[derive(Debug, Copy, Clone, Eq, PartialEq)]); - root.append(&mut derives.into_iter().collect()); - let enum_header = quote!(pub enum Opcode); - root.append(&mut enum_header.into_iter().collect()); + 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::::new(); - enum_entries.append(&mut (quote!(Illegal = -1,).into_iter().collect())); + enum_entries.extend(quote!(Illegal = -1,)); // Append the actual opcodes. for opcode in &opcodes.opcodes { 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)); 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. - let impl_opcode_header = quote!(impl Opcode); - root.append(&mut impl_opcode_header.into_iter().collect()); + root.extend(quote!(impl Opcode)); let mut impl_opcode_body_parts = Vec::::new(); gen_is_valid_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)); - // impl ToString block. - let to_string_trait_impl = quote! { + // 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() } } - }; - root.append(&mut to_string_trait_impl.into_iter().collect()); + }); - TokenStream::from_iter(root) + Ok(TokenStream::from_iter(root)) } -#[proc_macro] #[cfg(test)] mod tests { use super::*; diff --git a/macros/src/lib.rs b/macros/src/lib.rs index d0d136c..64339b0 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,11 +1,22 @@ -#![feature(proc_macro_quote)] - -use proc_macro::TokenStream; - -#[macro_use] mod isa; +mod writer; #[proc_macro] -pub fn isa(input: TokenStream) -> TokenStream { - crate::isa::isa(input) +pub fn isa(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + 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) } diff --git a/macros/src/writer.rs b/macros/src/writer.rs new file mode 100644 index 0000000..db5381f --- /dev/null +++ b/macros/src/writer.rs @@ -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, +} + +impl Parse for Arguments { + fn parse(input: ParseStream) -> syn::Result { + let formatter = input.parse()?; + input.parse::()?; + let ins = input.parse()?; + input.parse::()?; + let content; + syn::braced!(content in input); + let args = Punctuated::parse_terminated(&content)?; + Ok(Self { + formatter, + ins, + args, + }) + } +} + +struct Argument { + sources: Punctuated, + target: Ident, +} + +impl Parse for Argument { + fn parse(input: ParseStream) -> syn::Result { + let content; + syn::parenthesized!(content in input); + let sources = content.parse_terminated(Expr::parse)?; + input.parse::()?; + let target = input.parse()?; + Ok(Self { sources, target }) + } +} + +impl Arguments { + fn format_mnemonic(&self, tokens: &mut Vec) { + 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, 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 { + let arguments: Arguments = syn::parse2(input)?; + assert!(!arguments.args.is_empty()); + + let mut tokens = Vec::::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 = + 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())) +} diff --git a/rand/src/main.rs b/rand/src/main.rs index 3a19923..eefd5c1 100644 --- a/rand/src/main.rs +++ b/rand/src/main.rs @@ -12,7 +12,7 @@ fn main() { let stream = BufWriter::with_capacity(1_000_000, stdout_lock); let mut formatter = SimpleFormatter { writer: stream }; loop { - let ins = Ins::disasm(rng.next_u32()); + let ins = Ins::new(rng.next_u32(), 0); if ins.op == Opcode::Illegal { continue; }