Accuracy improvements
This commit is contained in:
parent
32394a4905
commit
43cb808c14
|
@ -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,14 +104,24 @@ where
|
|||
}
|
||||
|
||||
/// Writes an unsigned immediate.
|
||||
fn write_uimm(&mut self, uimm: u16) -> IOResult {
|
||||
fn write_uimm<T: Into<u16>>(&mut self, uimm: T) -> IOResult {
|
||||
let uimm = uimm.into();
|
||||
if uimm < 16 {
|
||||
write!(self.writer(), "{}", uimm)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}", uimm)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a signed immediate.
|
||||
fn write_simm(&mut self, simm: i16) -> IOResult {
|
||||
fn write_simm<T: PrimInt + Into<i32> + Display>(&mut self, simm: T) -> IOResult {
|
||||
let simm: i32 = simm.into();
|
||||
if simm < 8 {
|
||||
write!(self.writer(), "{}", simm)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}", ReallySigned(simm))
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an instruction-specific field like the compare mode.
|
||||
fn write_mode<P: PrimInt + Display>(&mut self, mode: P) -> IOResult {
|
||||
|
@ -113,18 +132,28 @@ where
|
|||
write!(self.writer(), "{}", fm)
|
||||
}
|
||||
|
||||
fn write_offset_unsigned_open(&mut self, offset: u16) -> IOResult {
|
||||
fn write_offset_unsigned_open<T: Into<u32>>(&mut self, offset: T) -> IOResult {
|
||||
let offset = offset.into();
|
||||
if offset < 15 {
|
||||
write!(self.writer(), "{}(", offset)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}(", offset)
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes an offset prefix.
|
||||
///
|
||||
/// The next write calls that follow should be:
|
||||
/// - An operand (almost always a general-purpose register)
|
||||
/// - `write_offset_close()`
|
||||
fn write_offset_open(&mut self, offset: i16) -> IOResult {
|
||||
fn write_offset_open<T: Into<i32>>(&mut self, offset: T) -> IOResult {
|
||||
let offset = offset.into();
|
||||
if -9 < offset && offset < 10 {
|
||||
write!(self.writer(), "{}(", offset)
|
||||
} else {
|
||||
write!(self.writer(), "{:#x}(", ReallySigned(offset))
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes an offset prefix.
|
||||
fn write_offset_close(&mut self) -> IOResult {
|
||||
|
@ -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<W: Write> {
|
|||
pub writer: W,
|
||||
}
|
||||
|
||||
impl<W: Write> SimpleFormatter<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self { writer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> AsmFormatter<W> for SimpleFormatter<W> {
|
||||
fn writer(&mut self) -> &mut W {
|
||||
&mut self.writer
|
||||
|
|
|
@ -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::<u32>(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,
|
||||
|
|
1011
lib/src/lib.rs
1011
lib/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -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<Argument, Semi>,
|
||||
args: Punctuated<Argument, syn::token::Semi>,
|
||||
}
|
||||
|
||||
impl Parse for Arguments {
|
||||
|
@ -58,67 +57,82 @@ impl Parse for Argument {
|
|||
.parse_terminated::<Expr, syn::token::Comma>(Expr::parse)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
} else if lookahead.peek(syn::LitStr) {
|
||||
let expr = input.parse::<ExprLit>()?.into();
|
||||
sources = vec![expr];
|
||||
} else if lookahead.peek(syn::LitInt) {
|
||||
let expr = input.parse::<ExprLit>()?.into();
|
||||
sources = vec![expr];
|
||||
} else {
|
||||
let expr = input.parse::<ExprPath>()?.into();
|
||||
sources = vec![expr];
|
||||
}
|
||||
input.parse::<syn::token::RArrow>()?;
|
||||
input.parse::<syn::token::Colon>()?;
|
||||
let target = input.parse()?;
|
||||
Ok(Self { sources, target })
|
||||
}
|
||||
}
|
||||
|
||||
impl Arguments {
|
||||
fn format_mnemonic(&self, tokens: &mut Vec<TokenTree>) {
|
||||
fn format_mnemonic(&self) -> Vec<TokenStream> {
|
||||
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, tokens: &mut Vec<TokenTree>, method_arg: &Ident, args: TokenStream) {
|
||||
let method_name = format!("write_{}", method_arg.to_string());
|
||||
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;
|
||||
tokens.extend(quote!(#formatter.#method_name(#args)?;))
|
||||
if arg_str == "branch_target" {
|
||||
quote!(#formatter.write_branch_target(#args, self.addr)?)
|
||||
} else {
|
||||
quote!(#formatter.#method_name(#args)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn ins_call(&self, call: &Expr) -> TokenStream {
|
||||
match call {
|
||||
Expr::Lit(_) => call.to_token_stream(),
|
||||
_ => {
|
||||
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);
|
||||
// Create a list of calls to execute.
|
||||
let mut calls = Vec::<TokenStream>::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<TokenStream> {
|
|||
"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::<TokenStream, syn::token::Semi>::from_iter(calls);
|
||||
let tokens = Group::new(Delimiter::Brace, statements.to_token_stream());
|
||||
|
||||
Ok(tokens.to_token_stream())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue