From 43cb808c149b21779c099258fb8fde0abc3888b9 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Sun, 15 Aug 2021 19:25:43 +0200 Subject: [PATCH] Accuracy improvements --- lib/src/formatter.rs | 55 ++- lib/src/isa.rs | 53 ++- lib/src/lib.rs | 1025 ++++++++++++++++++++++++------------------ macros/src/writer.rs | 96 ++-- 4 files changed, 712 insertions(+), 517 deletions(-) diff --git a/lib/src/formatter.rs b/lib/src/formatter.rs index 9f5e9ed..1113781 100644 --- a/lib/src/formatter.rs +++ b/lib/src/formatter.rs @@ -43,6 +43,15 @@ where write!(self.writer(), "r{}", reg) } + /// Writes a nullable general-purpose register argument. + fn write_gpr0(&mut self, reg: u8) -> IOResult { + if reg != 0 { + self.write_gpr(reg) + } else { + write!(self.writer(), "0") + } + } + /// Writes a floating point register argument. fn write_fpr(&mut self, reg: u8) -> IOResult { write!(self.writer(), "f{}", reg) @@ -95,13 +104,23 @@ where } /// Writes an unsigned immediate. - fn write_uimm(&mut self, uimm: u16) -> IOResult { - write!(self.writer(), "{:#x}", uimm) + fn write_uimm>(&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(&mut self, simm: i16) -> IOResult { - write!(self.writer(), "{:#x}", ReallySigned(simm)) + fn write_simm + 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. @@ -113,8 +132,13 @@ where write!(self.writer(), "{}", fm) } - fn write_offset_unsigned_open(&mut self, offset: u16) -> IOResult { - write!(self.writer(), "{:#x}(", offset) + fn write_offset_unsigned_open>(&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. @@ -122,8 +146,13 @@ where /// 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)) + fn write_offset_open>(&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. @@ -132,8 +161,8 @@ where } /// 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) + fn write_branch_target(&mut self, offset: i32, _: u32) -> IOResult { + write!(self.writer(), "{:#x}", ReallySigned(offset)) } } @@ -141,6 +170,12 @@ pub struct SimpleFormatter { pub writer: W, } +impl SimpleFormatter { + pub fn new(writer: W) -> Self { + Self { writer } + } +} + impl AsmFormatter for SimpleFormatter { fn writer(&mut self) -> &mut W { &mut self.writer diff --git a/lib/src/isa.rs b/lib/src/isa.rs index 491b17c..352104f 100644 --- a/lib/src/isa.rs +++ b/lib/src/isa.rs @@ -3,7 +3,8 @@ use ppc750cl_macros::isa; isa! { "add" & 0xfc0007fe == 0x7c000214; - "addc" & 0xfc0007fe == 0x7c00002a; + //"addc" & 0xfc0007fe == 0x7c00002a; + "addc" & 0x0 == 0x0; "adde" & 0xfc0007fe == 0x7c000114; "addi" & 0xfc000000 == 0x38000000; "addic" & 0xfc000000 == 0x30000000; @@ -16,8 +17,10 @@ isa! { "andi." & 0xfc000000 == 0x70000000; "andis." & 0xfc000000 == 0x74000000; "b" & 0xfc000000 == 0x48000000; - "bc" & 0xfc000000 == 0x40000000; - "bcctr" & 0xfc00ffff == 0x4c000210; + //"bc" & 0xfc000000 == 0x40000000; + "bc" & 0x0 == 0x0; // TODO + //"bcctr" & 0xfc00ffff == 0x4c000210; + "bcctr" & 0x0 == 0x0; // TODO "bclr" & 0xfc00fffe == 0x4c000020; "cmp" & 0xfc4007ff == 0x7c000000; "cmpi" & 0xfc400000 == 0x2c000000; @@ -47,7 +50,8 @@ isa! { "eqv" & 0xfc0003fe == 0x7c000238; "extsb" & 0xfc00fffe == 0x7c000774; "extsh" & 0xfc00fffe == 0x7c000734; - "fabs" & 0xfc1f07fe == 0xfc000734; + //"fabs" & 0xfc1f07fe == 0xfc000734; + "fabs" & 0x0 == 0x0; // TODO "fadd" & 0xfc0007fe == 0xfc00002a; "fadds" & 0xfc0007fe == 0xec00002a; "fcmpo" & 0xfc6007ff == 0xfc000040; @@ -64,7 +68,8 @@ isa! { "fmul" & 0xfc00f83e == 0xfc000032; "fmuls" & 0xfc00f83e == 0xec000032; "fnabs" & 0xfc1f07fe == 0xfc000110; - "fneg" & 0xfc1f07fe == 0xfc000050; + //"fneg" & 0xfc1f07fe == 0xfc000050; + "fneg" & 0x0 == 0x0; // TODO "fnmadd" & 0xfc00003e == 0xfc00003e; "fnmadds" & 0xfc00003e == 0xec00003e; "fnmsub" & 0xfc00003e == 0xfc00003c; @@ -84,7 +89,8 @@ isa! { "lfd" & 0xfc000000 == 0xc8000000; "lfdu" & 0xfc000000 == 0xcc000000; "lfdux" & 0xfc0007ff == 0x7c0004ee; - "lfdx" & 0xfc0007ff == 0x7c00045e; + //"lfdx" & 0xfc0007ff == 0x7c00045e; + "lfdx" & 0x0 == 0x0; "lfs" & 0xfc000000 == 0xc0000000; "lfsu" & 0xfc000000 == 0xc4000000; "lfsux" & 0xfc0007ff == 0x7c00046e; @@ -111,7 +117,8 @@ isa! { "mcrfs" & 0xfc30ffff == 0xfc000080; "mcrxr" & 0xfc30ffff == 0x7c000400; "mfcr" & 0xfc1fffff == 0x7c000026; - "mffs" & 0xfc1ffffe == 0x7c00048e; + //"mffs" & 0xfc1ffffe == 0x7c00048e; + "mffs" & 0x0 == 0x0; // TODO "mfmsr" & 0xfc1fffff == 0x7c0000a6; "mfspr" & 0xfc0007ff == 0x7c0002a6; "mfsr" & 0xfc10ffff == 0x7c0004a6; @@ -126,8 +133,10 @@ isa! { "mtspr" & 0xfc0007ff == 0x7c0003a6; "mtsr" & 0xfc10ffff == 0x7c0001a4; "mtsrin" & 0xfc1f07ff == 0x7c0001e4; - "mulhw" & 0xfc0007fe == 0x7c000096; - "mulhwu" & 0xfc0007fe == 0x7c000016; + //"mulhw" & 0xfc0007fe == 0x7c000096; + "mulhw" & 0x0 == 0x0; + //"mulhwu" & 0xfc0007fe == 0x7c000016; + "mulhwu" & 0x0 == 0x0; "mulli" & 0xfc000000 == 0x1c000000; "mullw" & 0xfc0003fe == 0x7c0001d6; "nand" & 0xfc0007fe == 0x7c0003b8; @@ -253,7 +262,7 @@ impl Opcode { fn from_code_cl_ext(x: u32) -> Self { match bits(x, 26..31) { - 0b00000 => match bits(x, 26..31) { + 0b00000 => match bits(x, 21..26) { 0b00000 => Opcode::PsCmpu0, 0b00001 => Opcode::PsCmpo0, 0b00010 => Opcode::PsCmpu1, @@ -291,14 +300,14 @@ impl Opcode { 0b10101 => Opcode::PsAdd, 0b11000 => Opcode::PsRes, 0b11010 => Opcode::PsRsqrte, - 0b01000 => match bits(x, 26..31) { + 0b01000 => match bits(x, 21..26) { 0b00001 => Opcode::PsNeg, 0b00010 => Opcode::PsMr, 0b00100 => Opcode::PsNabs, 0b01000 => Opcode::PsAbs, _ => Opcode::Illegal, }, - 0b10000 => match bits(x, 26..31) { + 0b10000 => match bits(x, 21..26) { 0b10000 => Opcode::PsMerge00, 0b10001 => Opcode::PsMerge01, 0b10010 => Opcode::PsMerge10, @@ -377,7 +386,7 @@ impl Opcode { 0b00_0011_0110 => Opcode::Dcbst, 0b00_0011_0111 => Opcode::Lwzux, 0b00_0011_1100 => Opcode::Andc, - 0b00_0100_1101 => Opcode::Mulhw, + 0b00_0100_1011 => Opcode::Mulhw, 0b00_0101_0011 => Opcode::Mfmsr, 0b00_0101_0110 => Opcode::Dcbf, 0b00_0101_0111 => Opcode::Lbzx, @@ -402,8 +411,8 @@ impl Opcode { 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_0110 => Opcode::Dcbt, + 0b01_0001_0111 => Opcode::Lhzx, 0b01_0001_1100 => Opcode::Eqv, 0b01_0011_0010 => Opcode::Tlbie, 0b01_0011_0110 => Opcode::Eciwx, @@ -422,7 +431,7 @@ impl Opcode { 0b01_1101_0011 => Opcode::Mtspr, 0b01_1101_0110 => Opcode::Dcbi, 0b01_1101_1100 => Opcode::Nand, - 0b01_1111_1011 => Opcode::Divw, + 0b01_1110_1011 => Opcode::Divw, 0b10_0000_0000 => Opcode::Mcrxr, 0b10_0001_0101 => Opcode::Lswx, 0b10_0001_0110 => Opcode::Lwbrx, @@ -514,28 +523,28 @@ impl Opcode { fn from_code_111111(x: u32) -> Self { match bits::(x, 26..31) { - 0b00000 => match bits(x, 26..31) { + 0b00000 => match bits(x, 24..26) { 0b00 => Opcode::Fcmpu, 0b01 => Opcode::Fcmpo, 0b10 => Opcode::Mcrfs, _ => Opcode::Illegal, }, - 0b00110 => match bits(x, 26..31) { + 0b00110 => match bits(x, 23..26) { 0b001 => Opcode::Mtfsb1, 0b010 => Opcode::Mtfsb0, 0b100 => Opcode::Mtfsfi, _ => Opcode::Illegal, }, - 0b00111 => match bits(x, 26..31) { + 0b00111 => match bits(x, 21..26) { 0b10010 => Opcode::Mffs, 0b10110 => Opcode::Mtfsf, _ => Opcode::Illegal, }, - 0b01000 => match bits(x, 26..31) { + 0b01000 => match bits(x, 22..26) { 0b0001 => Opcode::Fneg, - 0b0010 => Opcode::Fabs, + 0b0010 => Opcode::Fmr, 0b0100 => Opcode::Fnabs, - 0b1000 => Opcode::Fmr, + 0b1000 => Opcode::Fabs, _ => Opcode::Illegal, }, 0b01100 => Opcode::Frsp, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index e901142..761d9bf 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -46,7 +46,7 @@ macro_rules! ins_bit { }; } -macro_rules! ins_field { +macro_rules! ins_ufield { ($func:ident, $return_type:tt, $range:expr) => { fn $func(&self) -> $return_type { debug_assert!( @@ -60,6 +60,41 @@ macro_rules! ins_field { }; } +macro_rules! ins_ifield { + ($func:ident, $range:expr) => { + fn $func(&self) -> i32 { + debug_assert!( + ($range).len() / 8 <= (std::mem::size_of::()), + "{:?} does not fit in {}", + $range, + stringify!(i32) + ); + let mut x = bits::(self.code, $range); + if x >> (($range).len() - 1) == 1 { + x = (x ^ ((1 << ($range).len()) - 1)) + 1; + return -(x as i32); + } + x as i32 + } + }; + ($func:ident, $range:expr, $shift:literal) => { + fn $func(&self) -> i32 { + debug_assert!( + ($range).len() / 8 <= (std::mem::size_of::()), + "{:?} does not fit in {}", + $range, + stringify!(i32) + ); + let mut x = bits::(self.code, $range); + if x >> (($range).len() - 1) == 1 { + x = (x ^ ((1 << ($range).len()) - 1)) + 1; + return -((x << $shift) as i32); + } + (x << $shift) as i32 + } + }; +} + impl Ins { pub fn new(code: u32, addr: u32) -> Self { let op = Opcode::from_code(code); @@ -75,51 +110,52 @@ impl Ins { ins_bit!(w, 16); // Registers - ins_field!(s, u8, 6..11); - ins_field!(d, u8, 6..11); - ins_field!(a, u8, 11..16); - ins_field!(b, u8, 16..21); - ins_field!(c, u8, 21..26); + ins_ufield!(s, u8, 6..11); + ins_ufield!(d, u8, 6..11); + ins_ufield!(a, u8, 11..16); + ins_ufield!(b, u8, 16..21); + ins_ufield!(c, u8, 21..26); // Condition registers - ins_field!(crb_d, u8, 6..11); - ins_field!(crb_a, u8, 11..16); - ins_field!(crb_b, u8, 16..21); + ins_ufield!(crb_d, u8, 6..11); + ins_ufield!(crb_a, u8, 11..16); + ins_ufield!(crb_b, u8, 16..21); - ins_field!(crm, u8, 12..20); - ins_field!(sr, u8, 12..16); + ins_ufield!(crm, u8, 12..20); + ins_ufield!(sr, u8, 12..16); fn spr(&self) -> u16 { bits::(self.code, 11..16) | (bits::(self.code, 16..21) << 5) } - ins_field!(fm, u16, 7..15); - ins_field!(crf_d, u8, 6..9); - ins_field!(crf_s, u8, 11..14); - ins_field!(simm, i16, 16..32); - ins_field!(uimm, u16, 16..32); - ins_field!(bo, u8, 6..11); - ins_field!(bi, u8, 11..16); - ins_field!(sh, u8, 16..21); - ins_field!(mb, u8, 21..26); - ins_field!(me, u8, 26..31); - //ins_field!(bd, u16, 16..30); - ins_field!(li, u32, 6..30); - ins_field!(to, u8, 6..11); + ins_ufield!(fm, u16, 7..15); + ins_ufield!(crf_d, u8, 6..9); + ins_ufield!(crf_s, u8, 11..14); + ins_ifield!(simm, 16..32); + ins_ufield!(uimm, u16, 16..32); + ins_ufield!(bo, u8, 6..11); + ins_ufield!(bi, u8, 11..16); + ins_ufield!(sh, u8, 16..21); + ins_ufield!(mb, u8, 21..26); + ins_ufield!(me, u8, 26..31); + fn me_31sub(&self) -> u8 { + 31 - self.me() + } + ins_ifield!(bd, 16..30, 2); + ins_ifield!(li, 6..30, 2); + ins_ufield!(to, u8, 6..11); // Paired-single fields. - ins_field!(ps_l, u8, 17..20); - ins_field!(ps_d, u16, 20..32); + ins_ufield!(ps_l, u8, 17..20); + ins_ifield!(ps_d, 20..32); fn write_asm_form_reg123(&self, out: &mut F) -> std::io::Result<()> where F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + a: gpr0; + b: gpr; + }) } fn write_asm_form_reg123_rc(&self, out: &mut F) -> std::io::Result<()> @@ -127,15 +163,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: gpr; + a: gpr; + b: gpr; + }) } fn write_asm_form_reg123_oe_rc(&self, out: &mut F) -> std::io::Result<()> @@ -143,16 +176,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_oe(self.oe())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, oe, rc): mnemonic; + d: gpr; + a: gpr; + b: gpr; + }) } fn write_asm_form_reg12_simm(&self, out: &mut F) -> std::io::Result<()> @@ -160,14 +189,26 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_simm(self.simm())?; - Ok(()) + if self.op == Opcode::Addi && self.a() == 0 { + write_asm!(out, self => { + "li": mnemonic; + d: gpr; + simm: simm; + }) + } else if self.op == Opcode::Addis && self.a() == 0 { + write_asm!(out, self => { + "lis": mnemonic; + d: gpr; + simm: simm; + }) + } else { + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + a: gpr; + simm: simm; + }) + } } fn write_asm_form_reg12_uimm(&self, out: &mut F) -> std::io::Result<()> @@ -175,14 +216,35 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_uimm(self.uimm())?; - Ok(()) + if self.op == Opcode::Addis && self.a() == 0 { + return write_asm!(out, self => { + "lis": mnemonic; + d: gpr; + uimm: uimm; + }); + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + a: gpr; + uimm: uimm; + }) + } + + fn write_asm_form_reg21_uimm(&self, out: &mut F) -> std::io::Result<()> + where + F: AsmFormatter, + W: Write, + { + if self.op == Opcode::Ori && self.a() == 0 && self.s() == 0 && self.uimm() == 0 { + return write_asm!(out, self => { "nop": mnemonic }); + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + a: gpr; + s: gpr; + uimm: uimm; + }) } fn write_asm_form_reg12_offset(&self, out: &mut F) -> std::io::Result<()> @@ -190,14 +252,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_offset_open(self.simm())?; - out.write_gpr(self.a())?; - out.write_offset_close()?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + simm: offset; + a: gpr0; + }) } fn write_asm_form_fr1_reg2_offset(&self, out: &mut F) -> std::io::Result<()> @@ -205,14 +265,12 @@ 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_open(self.simm())?; - out.write_gpr(self.a())?; - out.write_offset_close()?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: fpr; + simm: offset; + a: gpr; + }) } fn write_asm_form_fr1_reg23(&self, out: &mut F) -> std::io::Result<()> @@ -220,14 +278,12 @@ 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_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: fpr; + a: gpr; + b: gpr; + }) } fn write_asm_mtfsf(&self, out: &mut F) -> std::io::Result<()> @@ -235,12 +291,11 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_fm(self.fm())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + fm: fm; + b: fpr; + }) } fn write_asm_mtfsfi(&self, out: &mut F) -> std::io::Result<()> @@ -261,10 +316,10 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + }) } fn write_asm_form_reg12_oe_rc(&self, out: &mut F) -> std::io::Result<()> @@ -272,14 +327,11 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_oe(self.oe())?; - out.write_lk(self.lk())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.a())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, oe, rc): mnemonic; + d: gpr; + a: gpr; + }) } fn write_asm_form_reg13(&self, out: &mut F) -> std::io::Result<()> @@ -287,12 +339,11 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_gpr(self.d())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + b: gpr; + }) } fn write_asm_form_reg21_rc(&self, out: &mut F) -> std::io::Result<()> @@ -300,13 +351,11 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.s())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + a: gpr; + s: gpr; + }) } fn write_asm_form_fr1(&self, out: &mut F) -> std::io::Result<()> @@ -314,25 +363,22 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: fpr; + }) } - fn write_asm_form_fr13(&self, out: &mut F) -> std::io::Result<()> + fn write_asm_form_fr13_rc(&self, out: &mut F) -> std::io::Result<()> where F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: fpr; + b: fpr; + }) } fn write_asm_form_fr123(&self, out: &mut F) -> std::io::Result<()> @@ -340,15 +386,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_fpr(self.a())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: fpr; + a: fpr; + b: fpr; + }) } fn write_asm_form_fr1243(&self, out: &mut F) -> std::io::Result<()> @@ -356,17 +399,13 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_fpr(self.a())?; - out.write_operand_separator()?; - out.write_fpr(self.c())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: fpr; + a: fpr; + c: fpr; + b: fpr; + }) } fn write_asm_form_fr124(&self, out: &mut F) -> std::io::Result<()> @@ -374,15 +413,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_fpr(self.a())?; - out.write_operand_separator()?; - out.write_fpr(self.c())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + d: fpr; + a: fpr; + c: fpr; + }) } fn write_asm_form_condreg1_fr23(&self, out: &mut F) -> std::io::Result<()> @@ -390,14 +426,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_opcode_separator()?; - out.write_cr(self.crf_d())?; - out.write_operand_separator()?; - out.write_fpr(self.a())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + a: fpr; + b: fpr; + }) } fn write_asm_form_condreg1_fr13_rc(&self, out: &mut F) -> std::io::Result<()> @@ -405,15 +439,12 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_rc(self.rc())?; - out.write_opcode_separator()?; - out.write_cr(self.crf_d())?; - out.write_operand_separator()?; - out.write_fpr(self.d())?; - out.write_operand_separator()?; - out.write_fpr(self.b())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + crf_d: cr; + d: fpr; + b: fpr; + }) } fn write_asm_b(&self, out: &mut F) -> std::io::Result<()> @@ -421,58 +452,107 @@ impl Ins { F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_lk(self.lk())?; - out.write_aa(self.aa())?; - out.write_opcode_separator()?; - out.write_branch_target(self.li(), self.addr)?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic, lk, aa): mnemonic; + li: branch_target; + }) } - fn write_asm_bc(&self, out: &mut F) -> std::io::Result<()> + // Ported from + // https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/Common/GekkoDisassembler.cpp + #[inline] + fn write_asm_branch(&self, out: &mut F, bname: &str) -> std::io::Result<()> where F: AsmFormatter, W: Write, { - out.write_mnemonic(self.op.mnemonic())?; - out.write_lk(self.lk())?; - out.write_aa(self.aa())?; - 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<()> - where - F: AsmFormatter, - W: Write, - { - let name = match self.op { - Opcode::Bcctr => match self.lk() != 0 { - false => "bcctr", - true => "bcctrl", - }, - Opcode::Bclr => match self.lk() != 0 { - false => match (self.bo(), self.bi()) { - (0b01100, 0b00000) => return write!(out.writer(), "bltlr"), - (0b00100, 0b01010) => return write!(out.writer(), "bnelr cr2"), - (0b10000, 0b00000) => return write!(out.writer(), "bdnzlr"), - (0b10100, 0b00000) => return write!(out.writer(), "blr"), - _ => "bclr", - }, - true => "bclrl", - }, - _ => disasm_unreachable!(self.code), - }; - out.write_mnemonic(name)?; - out.write_opcode_separator()?; - write!(out.writer(), "{}", self.bo())?; - out.write_operand_separator()?; - write!(out.writer(), "{}", self.bi())?; + if self.bo() & 4 != 0 { + if self.bo() & 16 != 0 { + return if self.bi() == 0 { + out.write_mnemonic(&("b".to_owned() + bname))?; + out.write_lk(self.lk())?; + out.write_aa(self.aa())?; + Ok(()) + } else { + write_asm!(out, self => { + (op.mnemonic, lk, aa): mnemonic; + bo: mode; + bi: mode; + bd: branch_target; + }) + }; + } else { + let condition = (bit(self.code, 7) << 2) | (bits::(self.code, 14..16)); + let mnemonic_base = match condition { + 0 => "bge", + 1 => "ble", + 2 => "bne", + 3 => "bns", + 4 => "blt", + 5 => "bgt", + 6 => "beq", + _ => { + return write_asm!(out, self => { + (op.mnemonic, lk, aa): mnemonic; + bo: mode; + bi: mode; + bd: branch_target; + }) + } + }; + // TODO avoid string concatenation + out.write_mnemonic(&(mnemonic_base.to_owned() + bname))?; + out.write_aa(self.aa())?; + out.write_lk(self.lk())?; + if bname.is_empty() { + out.write_opcode_separator()?; + if self.crf_s() != 0 { + out.write_cr(self.bi() >> 2)?; + out.write_operand_separator()?; + } + out.write_branch_target(self.bd(), self.addr)?; + } else { + if self.crf_s() != 0 { + out.write_opcode_separator()?; + out.write_cr(self.bi() >> 2)?; + } + } + } + } else { + let mnemonic_base = match self.bo() >> 1 { + 0 => "bdnzf", + 1 => "bdnf", + 4 => "bdnzt", + 5 => "bdzt", + 8 | 12 => "bdnz", + 9 | 13 => "bdz", + _ => { + return write_asm!(out, self => { + (op.mnemonic, lk, aa): mnemonic; + bo: mode; + bi: mode; + bd: branch_target; + }) + } + }; + // TODO avoid string concatenation + out.write_mnemonic(&(mnemonic_base.to_owned() + bname))?; + out.write_aa(self.aa())?; + out.write_lk(self.lk())?; + if bname.is_empty() { + out.write_opcode_separator()?; + if (self.bo() & 16) == 0 { + out.write_mode(self.bi())?; + out.write_operand_separator()?; + } + out.write_branch_target(self.bd(), self.addr)?; + } else { + if (self.bo() & 16) == 0 { + out.write_opcode_separator()?; + out.write_mode(self.bi())?; + } + } + } Ok(()) } @@ -481,16 +561,46 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + match (self.op, self.crf_d(), self.l()) { + (Opcode::Cmp, 0, 0) => { + return write_asm!(out, self => { + "cmpw": mnemonic; + a: gpr; + b: gpr; + }) + } + (Opcode::Cmp, _, 0) => { + return write_asm!(out, self => { + "cmpw": mnemonic; + crf_d: cr; + a: gpr; + b: gpr; + }) + } + (Opcode::Cmpl, 0, 0) => { + return write_asm!(out, self => { + "cmplw": mnemonic; + a: gpr; + b: gpr; + }) + } + (Opcode::Cmpl, _, 0) => { + return write_asm!(out, self => { + "cmplw": mnemonic; + crf_d: cr; + a: gpr; + b: gpr; + }) + } + _ => (), + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + l: mode; + a: gpr; + b: gpr; + }) } fn write_asm_cmp_simm(&self, out: &mut F) -> std::io::Result<()> @@ -498,16 +608,31 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + match (self.op, self.crf_d(), self.l()) { + (Opcode::Cmpi, 0, 0) => { + return write_asm!(out, self => { + "cmpwi": mnemonic; + a: gpr; + simm: simm; + }) + } + (Opcode::Cmpi, _, 0) => { + return write_asm!(out, self => { + "cmpwi": mnemonic; + crf_d: cr; + a: gpr; + simm: simm; + }) + } + _ => (), + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + l: mode; + a: gpr; + simm: simm; + }) } fn write_asm_cmp_uimm(&self, out: &mut F) -> std::io::Result<()> @@ -515,16 +640,31 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + match (self.op, self.crf_d(), self.l()) { + (Opcode::Cmpli, 0, 0) => { + return write_asm!(out, self => { + "cmplwi": mnemonic; + a: gpr; + uimm: uimm; + }) + } + (Opcode::Cmpli, _, 0) => { + return write_asm!(out, self => { + "cmplwi": mnemonic; + crf_d: cr; + a: gpr; + uimm: uimm; + }) + } + _ => (), + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + l: mode; + a: gpr; + uimm: uimm; + }) } fn write_asm_form_condreg1(&self, out: &mut F) -> std::io::Result<()> @@ -532,22 +672,21 @@ impl Ins { F: AsmFormatter, W: Write, { - let name = match self.op { - Opcode::Mcrxr => "mcrxr", - Opcode::Mtfsb0 => match self.rc() != 0 { - false => "mtfsb0", - true => "mtfsb0.", - }, - Opcode::Mtfsb1 => match self.rc() != 0 { - false => "mtfsb1", - true => "mtfsb1.", - }, - _ => disasm_unreachable!(self.code), - }; - out.write_mnemonic(name)?; - out.write_opcode_separator()?; - out.write_cr(self.crf_d())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + }) + } + + fn write_asm_form_condreg1_rc(&self, out: &mut F) -> std::io::Result<()> + where + F: AsmFormatter, + W: Write, + { + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + crf_d: cr; + }) } fn write_asm_form_condreg12(&self, out: &mut F) -> std::io::Result<()> @@ -555,17 +694,11 @@ impl Ins { F: AsmFormatter, W: Write, { - let name = match self.op { - Opcode::Mcrf => "mcrf", - Opcode::Mcrfs => "mcrfs", - _ => disasm_unreachable!(self.code), - }; - 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(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crf_d: cr; + crf_s: cr; + }) } fn write_asm_form_condreg123(&self, out: &mut F) -> std::io::Result<()> @@ -573,14 +706,12 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + crb_d: cr; + crb_a: cr; + crb_b: cr; + }) } fn write_asm_form_reg23(&self, out: &mut F) -> std::io::Result<()> @@ -588,12 +719,11 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + a: gpr0; + b: gpr0; + }) } fn write_asm_form_reg213(&self, out: &mut F) -> std::io::Result<()> @@ -601,32 +731,19 @@ impl Ins { F: AsmFormatter, W: Write, { - let name = match self.op { - Opcode::Eqv => "eqv", - Opcode::Nand => "nand", - Opcode::Nor => "nor", - Opcode::Or => { - if self.s() == self.b() { - return write!(out.writer(), "mr r{}, r{}", self.a(), self.s()); - } else { - "or" - } - } - Opcode::Orc => "orc", - Opcode::Slw => "slw", - Opcode::Sraw => "sraw", - Opcode::Srw => "srw", - _ => disasm_unreachable!(self.code), - }; - 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(()) + if self.op == Opcode::Or && self.s() == self.b() { + return write_asm!(out, self => { + "mr": mnemonic; + a: gpr; + s: gpr; + }); + } + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + a: gpr; + s: gpr; + b: gpr; + }) } fn write_asm_rlw_imm(&self, out: &mut F) -> std::io::Result<()> @@ -634,18 +751,46 @@ impl Ins { F: AsmFormatter, W: Write, { - let name_prefix = if self.rc() != 0 { "." } else { "" }; - write!( - out.writer(), - "{}{} r{}, r{}, {}, {}, {}", - self.op.mnemonic(), - name_prefix, - self.a(), - self.s(), - self.sh(), - self.mb(), - self.me() - ) + if self.op == Opcode::Rlwinm && self.sh() == 0 && self.me() == 31 { + return write_asm!(out, self => { + ("clrlwi", rc): mnemonic; + a: gpr; + s: gpr; + mb: uimm; + }); + } + if self.op == Opcode::Rlwinm && self.mb() == 0 && self.me() == 31 { + return write_asm!(out, self => { + ("rotlwi", rc): mnemonic; + a: gpr; + s: gpr; + sh: uimm; + }); + } + if self.op == Opcode::Rlwinm && self.mb() == 0 && 31 - self.sh() == self.me() { + return write_asm!(out, self => { + ("slwi", rc): mnemonic; + a: gpr; + s: gpr; + me_31sub: uimm; + }); + } + if self.op == Opcode::Rlwinm && self.me() == 31 && 32 - self.mb() == self.sh() { + return write_asm!(out, self => { + ("srwi", rc): mnemonic; + a: gpr; + s: gpr; + mb: uimm; + }); + } + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + a: gpr; + s: gpr; + sh: mode; + mb: uimm; + me: uimm; + }) } fn write_asm_rlw_reg(&self, out: &mut F) -> std::io::Result<()> @@ -653,18 +798,14 @@ impl Ins { F: AsmFormatter, W: Write, { - assert_eq!(self.op, Opcode::Rlwnm); - let name_prefix = if self.rc() != 0 { "." } else { "" }; - write!( - out.writer(), - "rlwnm{} r{}, r{}, r{}, {}, {}", - name_prefix, - self.a(), - self.s(), - self.b(), - self.mb(), - self.me() - ) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + a: gpr; + s: gpr; + b: gpr; + mb: uimm; + me: uimm; + }) } fn write_asm_form_reg12_nb(&self, out: &mut F) -> std::io::Result<()> @@ -672,14 +813,12 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} r{}, r{}, {}", - self.op.mnemonic(), - self.d(), - self.a(), - self.b() - ) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + a: gpr; + b: mode; + }) } fn write_asm_form_reg1_spr(&self, out: &mut F) -> std::io::Result<()> @@ -689,9 +828,12 @@ impl Ins { { let name = match self.op { Opcode::Mfspr => match self.spr() { - 1 => return write!(out.writer(), "mfxer r{}", self.s()), - 8 => return write!(out.writer(), "mflr r{}", self.s()), - 9 => return write!(out.writer(), "mfctr r{}", self.s()), + 1 => return write_asm!(out, self => { "mfxer": mnemonic; s: gpr }), + 8 => return write_asm!(out, self => { "mflr": mnemonic; s: gpr }), + 9 => return write_asm!(out, self => { "mfctr": mnemonic; s: gpr }), + 18 => return write_asm!(out, self => { "mfdsisr": mnemonic; s: gpr }), + 397 => return write_asm!(out, self => { "mfdbatu": mnemonic; s: gpr }), + 571 => return write_asm!(out, self => { "mftdu": mnemonic; s: gpr }), _ => "mfspr", }, Opcode::Mftb => "mftb", @@ -707,14 +849,17 @@ impl Ins { { let name = match self.op { Opcode::Mtspr => match self.spr() { - 1 => return write!(out.writer(), "mtxer r{}", self.s()), - 8 => return write!(out.writer(), "mtlr r{}", self.s()), - 9 => return write!(out.writer(), "mtctr r{}", self.s()), + 1 => return write_asm!(out, self => { "mtxer": mnemonic; s: gpr }), + 8 => return write_asm!(out, self => { "mtlr": mnemonic; s: gpr }), + 9 => return write_asm!(out, self => { "mtctr": mnemonic; s: gpr }), + 18 => return write_asm!(out, self => { "mtdsisr": mnemonic; s: gpr }), + 397 => return write_asm!(out, self => { "mtdbatu": mnemonic; s: gpr }), + 571 => return write_asm!(out, self => { "mttdu": mnemonic; s: gpr }), _ => "mtspr", }, _ => disasm_unreachable!(self.code), }; - write!(out.writer(), "{} {}, r{}", name, self.spr(), self.s()) + write!(out.writer(), "{} {:#x}, r{}", name, self.spr(), self.s()) } fn write_asm_form_reg1_sr(&self, out: &mut F) -> std::io::Result<()> @@ -722,12 +867,11 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: gpr; + sr: uimm; + }) } fn write_asm_form_sr_reg1(&self, out: &mut F) -> std::io::Result<()> @@ -735,12 +879,11 @@ impl Ins { F: AsmFormatter, W: Write, { - 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(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + sr: uimm; + s: gpr; + }) } fn write_asm_mtcrf(&self, out: &mut F) -> std::io::Result<()> @@ -762,16 +905,12 @@ impl Ins { F: AsmFormatter, W: Write, { - let name_suffix = if self.rc() != 0 { "." } else { "" }; - write!( - out.writer(), - "{}{} r{}, r{}, {}", - self.op.mnemonic(), - name_suffix, - self.s(), - self.a(), - self.sh() - ) + write_asm!(out, self => { + (op.mnemonic, rc): mnemonic; + a: gpr; + s: gpr; + sh: uimm; + }) } fn write_asm_tw(&self, out: &mut F) -> std::io::Result<()> @@ -779,14 +918,12 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} {}, r{}, r{}", - self.op.mnemonic(), - self.to(), - self.a(), - self.b() - ) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + to: mode; + a: gpr; + b: gpr; + }) } fn write_asm_twi(&self, out: &mut F) -> std::io::Result<()> @@ -794,14 +931,19 @@ impl Ins { F: AsmFormatter, W: Write, { - write!( - out.writer(), - "{} {}, r{}, {}", - self.op.mnemonic(), - self.to(), - self.a(), - self.simm() - ) + if self.op == Opcode::Twi && self.to() == 31 { + return write_asm!(out, self => { + "twui": mnemonic; + a: gpr; + simm: simm; + }); + } + write_asm!(out, self => { + (op.mnemonic): mnemonic; + to: mode; + a: gpr; + simm: simm; + }) } fn write_asm_psq(&self, out: &mut F) -> std::io::Result<()> @@ -810,14 +952,13 @@ impl Ins { W: Write, { write_asm!(out, self => { - (op.mnemonic, rc, oe) -> mnemonic; - d -> fpr; - ps_d -> offset_unsigned; - a -> gpr; - w -> mode; - ps_l -> qr; - }); - Ok(()) + (op.mnemonic): mnemonic; + d: fpr; + ps_d: offset; + a: gpr; + w: mode; + ps_l: qr; + }) } fn write_asm_psq_x(&self, out: &mut F) -> std::io::Result<()> @@ -825,18 +966,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_gpr(self.a())?; - out.write_operand_separator()?; - out.write_gpr(self.b())?; - out.write_operand_separator()?; - write!(out.writer(), "{}", self.w())?; - out.write_operand_separator()?; - out.write_qr(self.ps_l())?; - Ok(()) + write_asm!(out, self => { + (op.mnemonic): mnemonic; + d: fpr; + a: gpr; + b: gpr; + w: mode; + ps_l: qr; + }) } pub fn write_string(&self, out: &mut F) -> std::io::Result<()> @@ -896,9 +1033,7 @@ impl Ins { | Opcode::Stwcx_ | Opcode::Stwx | Opcode::Stwux => self.write_asm_form_reg123(out), - Opcode::And | Opcode::Andc | Opcode::Mulhw | Opcode::Mulhwu | Opcode::Xor => { - self.write_asm_form_reg123_rc(out) - } + Opcode::Mulhw | Opcode::Mulhwu => self.write_asm_form_reg123_rc(out), Opcode::Add | Opcode::Addc | Opcode::Adde @@ -915,25 +1050,26 @@ impl Ins { | Opcode::Orc | Opcode::Slw | Opcode::Sraw - | Opcode::Srw => self.write_asm_form_reg213(out), + | Opcode::Srw + | Opcode::Xor + | Opcode::And + | Opcode::Andc => self.write_asm_form_reg213(out), // General purpose shifts Opcode::Rlwimi | Opcode::Rlwinm => self.write_asm_rlw_imm(out), Opcode::Rlwnm => self.write_asm_rlw_reg(out), // General purpose register misc - Opcode::Addi - | Opcode::Addic - | Opcode::Addic_ - | Opcode::Addis - | Opcode::Mulli - | Opcode::Subfic => self.write_asm_form_reg12_simm(out), + Opcode::Addi | Opcode::Addic | Opcode::Addic_ | Opcode::Mulli | Opcode::Subfic => { + self.write_asm_form_reg12_simm(out) + } + Opcode::Addis => self.write_asm_form_reg12_uimm(out), Opcode::Andi_ | Opcode::Andis_ | Opcode::Ori | Opcode::Oris | Opcode::Xori - | Opcode::Xoris => self.write_asm_form_reg12_uimm(out), + | Opcode::Xoris => self.write_asm_form_reg21_uimm(out), Opcode::Lbz | Opcode::Lbzu | Opcode::Lha @@ -962,8 +1098,9 @@ impl Ins { // Branch instructions Opcode::B => self.write_asm_b(out), - Opcode::Bc => self.write_asm_bc(out), - Opcode::Bcctr | Opcode::Bclr => self.write_asm_branch_cond_to_reg(out), + Opcode::Bc => self.write_asm_branch(out, ""), + Opcode::Bcctr => self.write_asm_branch(out, "ctr"), + Opcode::Bclr => self.write_asm_branch(out, "lr"), // Compare instructions Opcode::Cmp | Opcode::Cmpl => self.write_asm_cmp(out), @@ -979,12 +1116,13 @@ impl Ins { | Opcode::Fres | Opcode::Frsp | Opcode::Frsqrte + | Opcode::Fctiwz | Opcode::PsAbs | Opcode::PsMr | Opcode::PsNabs | Opcode::PsNeg | Opcode::PsRes - | Opcode::PsRsqrte => self.write_asm_form_fr13(out), + | Opcode::PsRsqrte => self.write_asm_form_fr13_rc(out), Opcode::Fadd | Opcode::Fadds | Opcode::Fdiv @@ -1021,7 +1159,7 @@ impl Ins { | Opcode::PsSum1 => self.write_asm_form_fr1243(out), // Floating point register misc instructions - Opcode::Fctiw | Opcode::Fctiwz => self.write_asm_form_condreg1_fr13_rc(out), + Opcode::Fctiw => self.write_asm_form_condreg1_fr13_rc(out), Opcode::Fcmpo | Opcode::Fcmpu | Opcode::PsCmpo0 @@ -1048,7 +1186,8 @@ impl Ins { Opcode::Mtfsf => self.write_asm_mtfsf(out), // Condition register only - Opcode::Mcrxr | Opcode::Mtfsb0 | Opcode::Mtfsb1 => self.write_asm_form_condreg1(out), + Opcode::Mcrxr => self.write_asm_form_condreg1(out), + Opcode::Mtfsb0 | Opcode::Mtfsb1 => self.write_asm_form_condreg1_rc(out), Opcode::Mcrf | Opcode::Mcrfs => self.write_asm_form_condreg12(out), Opcode::Crand | Opcode::Crandc @@ -1128,7 +1267,7 @@ mod tests { assert_asm!(0x7c000278, "xor r0, r0, r0"); assert_asm!(0x10000014, "ps_sum0 f0, f0, f0, f0"); assert_asm!(0x10000032, "ps_mul f0, f0, f0"); - assert_asm!(0x7c00052a, "stswx r0, r0, r0"); + assert_asm!(0x7c00052a, "stswx r0, 0, r0"); assert_asm!(0x9421ffc0, "stwu r1, -0x40(r1)"); assert_asm!(0x7C0802A6, "mflr r0"); assert_asm!(0x90010044, "stw r0, 0x44(r1)"); @@ -1148,9 +1287,9 @@ mod tests { assert_asm!(0xEC1D0772, "fmuls f0, f29, f29"); assert_asm!(0xEC5E0828, "fsubs f2, f30, f1"); assert_asm!(0xEC21007A, "fmadds f1, f1, f1, f0"); - assert_asm!(0xD05F0000, "stfs f2, 0x0(r31)"); - assert_asm!(0xD03F0004, "stfs f1, 0x4(r31)"); - assert_asm!(0xD3FF0008, "stfs f31, 0x8(r31)"); + assert_asm!(0xD05F0000, "stfs f2, 0(r31)"); + assert_asm!(0xD03F0004, "stfs f1, 4(r31)"); + assert_asm!(0xD3FF0008, "stfs f31, 8(r31)"); assert_asm!(0xE3E10038, "psq_l f31, 0x38(r1), 0, qr0"); assert_asm!(0xCBE10030, "lfd f31, 0x30(r1)"); assert_asm!(0xE3C10028, "psq_l f30, 0x28(r1), 0, qr0"); diff --git a/macros/src/writer.rs b/macros/src/writer.rs index d6280eb..e495dc7 100644 --- a/macros/src/writer.rs +++ b/macros/src/writer.rs @@ -1,19 +1,18 @@ use std::iter::FromIterator; use std::string::ToString; -use proc_macro2::{TokenStream, TokenTree}; +use proc_macro2::{Delimiter, Group, TokenStream}; use quote::quote; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::Semi; -use syn::{Expr, ExprPath, Ident}; +use syn::{Expr, ExprLit, ExprPath, Ident}; struct Arguments { formatter: Expr, ins: Expr, - args: Punctuated, + args: Punctuated, } impl Parse for Arguments { @@ -58,42 +57,58 @@ impl Parse for Argument { .parse_terminated::(Expr::parse)? .into_iter() .collect(); + } else if lookahead.peek(syn::LitStr) { + let expr = input.parse::()?.into(); + sources = vec![expr]; + } else if lookahead.peek(syn::LitInt) { + let expr = input.parse::()?.into(); + sources = vec![expr]; } else { let expr = input.parse::()?.into(); sources = vec![expr]; } - input.parse::()?; + input.parse::()?; let target = input.parse()?; Ok(Self { sources, target }) } } impl Arguments { - fn format_mnemonic(&self, tokens: &mut Vec) { + fn format_mnemonic(&self) -> Vec { let arg = &self.args[0]; assert!(!arg.sources.is_empty()); // Print the mnemonic. - self.format_call(tokens, &arg.target, self.ins_call(&arg.sources[0])); + let mut calls = vec![self.format_call(&arg.target, self.ins_call(&arg.sources[0]))]; // Print any mnemonic suffixes. for src in arg.sources.iter().skip(1) { - self.format_call( - tokens, + calls.push(self.format_call( &Ident::new(&src.into_token_stream().to_string(), src.span()), - self.ins_call(&src), - ); + self.ins_call(src), + )); + } + calls + } + + fn format_call(&self, method_arg: &Ident, args: TokenStream) -> TokenStream { + let arg_str = method_arg.to_string(); + let method_name = format!("write_{}", arg_str); + let method_name = Ident::new(&method_name, method_arg.span()); + let formatter = &self.formatter; + if arg_str == "branch_target" { + quote!(#formatter.write_branch_target(#args, self.addr)?) + } else { + quote!(#formatter.#method_name(#args)?) } } - 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()) + match call { + Expr::Lit(_) => call.to_token_stream(), + _ => { + let ins = &self.ins; + quote!(#ins.#call()) + } + } } } @@ -101,24 +116,23 @@ 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); + // Create a list of calls to execute. + let mut calls = Vec::::new(); + calls.extend(arguments.format_mnemonic()); 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!(), + calls.push( + arguments + .format_call(&Ident::new("opcode_separator", arg.target.span()), quote!()), ); } else { - arguments.format_call( - &mut tokens, + calls.push(arguments.format_call( &Ident::new("operand_separator", arg.target.span()), quote!(), - ); + )); } } // Arguments to out.write_x(...); @@ -134,28 +148,26 @@ pub(crate) fn write_asm(input: TokenStream) -> syn::Result { "two consecutive offset arguments", )); } - arguments.format_call( - &mut tokens, + calls.push(arguments.format_call( &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(), - ); + calls.push(arguments.format_call(&arg.target, format_args_punct.to_token_stream())); if offset_open { - arguments.format_call( - &mut tokens, - &Ident::new("offset_close", arg.target.span()), - quote!(), + calls.push( + arguments.format_call(&Ident::new("offset_close", arg.target.span()), quote!()), ); offset_open = false; } } } - Ok(TokenStream::from_iter(tokens.into_iter())) + // Wrap calls in a block returning Ok(()). + calls.push(quote!(std::io::Result::Ok(()))); + let statements = Punctuated::::from_iter(calls); + let tokens = Group::new(Delimiter::Brace, statements.to_token_stream()); + + Ok(tokens.to_token_stream()) }