create write_asm macro
This commit is contained in:
parent
0c65617c69
commit
67efa31bbd
|
@ -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
|
||||||
|
|
|
@ -80,6 +80,7 @@ name = "ppc750cl-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
331
lib/src/isa.rs
331
lib/src/isa.rs
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
568
lib/src/lib.rs
568
lib/src/lib.rs
|
@ -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");
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
macro_rules! disasm_unreachable {
|
||||||
|
($msg:expr $(,)?) => {{
|
||||||
|
panic!(
|
||||||
|
"internal error: entered unreachable code disassembling instruction 0x{:08x}",
|
||||||
|
$msg
|
||||||
|
)
|
||||||
|
}};
|
||||||
|
}
|
|
@ -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"] }
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()))
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue