Accuracy improvements

This commit is contained in:
Richard Patel 2021-08-15 19:25:43 +02:00
parent 32394a4905
commit 43cb808c14
4 changed files with 712 additions and 517 deletions

View File

@ -43,6 +43,15 @@ where
write!(self.writer(), "r{}", reg) 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. /// 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)
@ -95,13 +104,23 @@ where
} }
/// Writes an unsigned immediate. /// Writes an unsigned immediate.
fn write_uimm(&mut self, uimm: u16) -> IOResult { fn write_uimm<T: Into<u16>>(&mut self, uimm: T) -> IOResult {
write!(self.writer(), "{:#x}", uimm) let uimm = uimm.into();
if uimm < 16 {
write!(self.writer(), "{}", uimm)
} else {
write!(self.writer(), "{:#x}", uimm)
}
} }
/// Writes a signed immediate. /// 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 {
write!(self.writer(), "{:#x}", ReallySigned(simm)) 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. /// Writes an instruction-specific field like the compare mode.
@ -113,8 +132,13 @@ where
write!(self.writer(), "{}", fm) 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 {
write!(self.writer(), "{:#x}(", offset) let offset = offset.into();
if offset < 15 {
write!(self.writer(), "{}(", offset)
} else {
write!(self.writer(), "{:#x}(", offset)
}
} }
/// Writes an offset prefix. /// Writes an offset prefix.
@ -122,8 +146,13 @@ where
/// The next write calls that follow should be: /// The next write calls that follow should be:
/// - An operand (almost always a general-purpose register) /// - An operand (almost always a general-purpose register)
/// - `write_offset_close()` /// - `write_offset_close()`
fn write_offset_open(&mut self, offset: i16) -> IOResult { fn write_offset_open<T: Into<i32>>(&mut self, offset: T) -> IOResult {
write!(self.writer(), "{:#x}(", ReallySigned(offset)) let offset = offset.into();
if -9 < offset && offset < 10 {
write!(self.writer(), "{}(", offset)
} else {
write!(self.writer(), "{:#x}(", ReallySigned(offset))
}
} }
/// Closes an offset prefix. /// Closes an offset prefix.
@ -132,8 +161,8 @@ where
} }
/// Writes a branch target given the jump offset and current program counter. /// Writes a branch target given the jump offset and current program counter.
fn write_branch_target(&mut self, offset: u32, pc: u32) -> IOResult { fn write_branch_target(&mut self, offset: i32, _: u32) -> IOResult {
write!(self.writer(), "{:#x}", offset + pc) write!(self.writer(), "{:#x}", ReallySigned(offset))
} }
} }
@ -141,6 +170,12 @@ pub struct SimpleFormatter<W: Write> {
pub writer: W, pub writer: W,
} }
impl<W: Write> SimpleFormatter<W> {
pub fn new(writer: W) -> Self {
Self { writer }
}
}
impl<W: Write> AsmFormatter<W> for SimpleFormatter<W> { impl<W: Write> AsmFormatter<W> for SimpleFormatter<W> {
fn writer(&mut self) -> &mut W { fn writer(&mut self) -> &mut W {
&mut self.writer &mut self.writer

View File

@ -3,7 +3,8 @@ use ppc750cl_macros::isa;
isa! { isa! {
"add" & 0xfc0007fe == 0x7c000214; "add" & 0xfc0007fe == 0x7c000214;
"addc" & 0xfc0007fe == 0x7c00002a; //"addc" & 0xfc0007fe == 0x7c00002a;
"addc" & 0x0 == 0x0;
"adde" & 0xfc0007fe == 0x7c000114; "adde" & 0xfc0007fe == 0x7c000114;
"addi" & 0xfc000000 == 0x38000000; "addi" & 0xfc000000 == 0x38000000;
"addic" & 0xfc000000 == 0x30000000; "addic" & 0xfc000000 == 0x30000000;
@ -16,8 +17,10 @@ isa! {
"andi." & 0xfc000000 == 0x70000000; "andi." & 0xfc000000 == 0x70000000;
"andis." & 0xfc000000 == 0x74000000; "andis." & 0xfc000000 == 0x74000000;
"b" & 0xfc000000 == 0x48000000; "b" & 0xfc000000 == 0x48000000;
"bc" & 0xfc000000 == 0x40000000; //"bc" & 0xfc000000 == 0x40000000;
"bcctr" & 0xfc00ffff == 0x4c000210; "bc" & 0x0 == 0x0; // TODO
//"bcctr" & 0xfc00ffff == 0x4c000210;
"bcctr" & 0x0 == 0x0; // TODO
"bclr" & 0xfc00fffe == 0x4c000020; "bclr" & 0xfc00fffe == 0x4c000020;
"cmp" & 0xfc4007ff == 0x7c000000; "cmp" & 0xfc4007ff == 0x7c000000;
"cmpi" & 0xfc400000 == 0x2c000000; "cmpi" & 0xfc400000 == 0x2c000000;
@ -47,7 +50,8 @@ isa! {
"eqv" & 0xfc0003fe == 0x7c000238; "eqv" & 0xfc0003fe == 0x7c000238;
"extsb" & 0xfc00fffe == 0x7c000774; "extsb" & 0xfc00fffe == 0x7c000774;
"extsh" & 0xfc00fffe == 0x7c000734; "extsh" & 0xfc00fffe == 0x7c000734;
"fabs" & 0xfc1f07fe == 0xfc000734; //"fabs" & 0xfc1f07fe == 0xfc000734;
"fabs" & 0x0 == 0x0; // TODO
"fadd" & 0xfc0007fe == 0xfc00002a; "fadd" & 0xfc0007fe == 0xfc00002a;
"fadds" & 0xfc0007fe == 0xec00002a; "fadds" & 0xfc0007fe == 0xec00002a;
"fcmpo" & 0xfc6007ff == 0xfc000040; "fcmpo" & 0xfc6007ff == 0xfc000040;
@ -64,7 +68,8 @@ isa! {
"fmul" & 0xfc00f83e == 0xfc000032; "fmul" & 0xfc00f83e == 0xfc000032;
"fmuls" & 0xfc00f83e == 0xec000032; "fmuls" & 0xfc00f83e == 0xec000032;
"fnabs" & 0xfc1f07fe == 0xfc000110; "fnabs" & 0xfc1f07fe == 0xfc000110;
"fneg" & 0xfc1f07fe == 0xfc000050; //"fneg" & 0xfc1f07fe == 0xfc000050;
"fneg" & 0x0 == 0x0; // TODO
"fnmadd" & 0xfc00003e == 0xfc00003e; "fnmadd" & 0xfc00003e == 0xfc00003e;
"fnmadds" & 0xfc00003e == 0xec00003e; "fnmadds" & 0xfc00003e == 0xec00003e;
"fnmsub" & 0xfc00003e == 0xfc00003c; "fnmsub" & 0xfc00003e == 0xfc00003c;
@ -84,7 +89,8 @@ isa! {
"lfd" & 0xfc000000 == 0xc8000000; "lfd" & 0xfc000000 == 0xc8000000;
"lfdu" & 0xfc000000 == 0xcc000000; "lfdu" & 0xfc000000 == 0xcc000000;
"lfdux" & 0xfc0007ff == 0x7c0004ee; "lfdux" & 0xfc0007ff == 0x7c0004ee;
"lfdx" & 0xfc0007ff == 0x7c00045e; //"lfdx" & 0xfc0007ff == 0x7c00045e;
"lfdx" & 0x0 == 0x0;
"lfs" & 0xfc000000 == 0xc0000000; "lfs" & 0xfc000000 == 0xc0000000;
"lfsu" & 0xfc000000 == 0xc4000000; "lfsu" & 0xfc000000 == 0xc4000000;
"lfsux" & 0xfc0007ff == 0x7c00046e; "lfsux" & 0xfc0007ff == 0x7c00046e;
@ -111,7 +117,8 @@ isa! {
"mcrfs" & 0xfc30ffff == 0xfc000080; "mcrfs" & 0xfc30ffff == 0xfc000080;
"mcrxr" & 0xfc30ffff == 0x7c000400; "mcrxr" & 0xfc30ffff == 0x7c000400;
"mfcr" & 0xfc1fffff == 0x7c000026; "mfcr" & 0xfc1fffff == 0x7c000026;
"mffs" & 0xfc1ffffe == 0x7c00048e; //"mffs" & 0xfc1ffffe == 0x7c00048e;
"mffs" & 0x0 == 0x0; // TODO
"mfmsr" & 0xfc1fffff == 0x7c0000a6; "mfmsr" & 0xfc1fffff == 0x7c0000a6;
"mfspr" & 0xfc0007ff == 0x7c0002a6; "mfspr" & 0xfc0007ff == 0x7c0002a6;
"mfsr" & 0xfc10ffff == 0x7c0004a6; "mfsr" & 0xfc10ffff == 0x7c0004a6;
@ -126,8 +133,10 @@ isa! {
"mtspr" & 0xfc0007ff == 0x7c0003a6; "mtspr" & 0xfc0007ff == 0x7c0003a6;
"mtsr" & 0xfc10ffff == 0x7c0001a4; "mtsr" & 0xfc10ffff == 0x7c0001a4;
"mtsrin" & 0xfc1f07ff == 0x7c0001e4; "mtsrin" & 0xfc1f07ff == 0x7c0001e4;
"mulhw" & 0xfc0007fe == 0x7c000096; //"mulhw" & 0xfc0007fe == 0x7c000096;
"mulhwu" & 0xfc0007fe == 0x7c000016; "mulhw" & 0x0 == 0x0;
//"mulhwu" & 0xfc0007fe == 0x7c000016;
"mulhwu" & 0x0 == 0x0;
"mulli" & 0xfc000000 == 0x1c000000; "mulli" & 0xfc000000 == 0x1c000000;
"mullw" & 0xfc0003fe == 0x7c0001d6; "mullw" & 0xfc0003fe == 0x7c0001d6;
"nand" & 0xfc0007fe == 0x7c0003b8; "nand" & 0xfc0007fe == 0x7c0003b8;
@ -253,7 +262,7 @@ impl Opcode {
fn from_code_cl_ext(x: u32) -> Self { fn from_code_cl_ext(x: u32) -> Self {
match bits(x, 26..31) { match bits(x, 26..31) {
0b00000 => match bits(x, 26..31) { 0b00000 => match bits(x, 21..26) {
0b00000 => Opcode::PsCmpu0, 0b00000 => Opcode::PsCmpu0,
0b00001 => Opcode::PsCmpo0, 0b00001 => Opcode::PsCmpo0,
0b00010 => Opcode::PsCmpu1, 0b00010 => Opcode::PsCmpu1,
@ -291,14 +300,14 @@ impl Opcode {
0b10101 => Opcode::PsAdd, 0b10101 => Opcode::PsAdd,
0b11000 => Opcode::PsRes, 0b11000 => Opcode::PsRes,
0b11010 => Opcode::PsRsqrte, 0b11010 => Opcode::PsRsqrte,
0b01000 => match bits(x, 26..31) { 0b01000 => match bits(x, 21..26) {
0b00001 => Opcode::PsNeg, 0b00001 => Opcode::PsNeg,
0b00010 => Opcode::PsMr, 0b00010 => Opcode::PsMr,
0b00100 => Opcode::PsNabs, 0b00100 => Opcode::PsNabs,
0b01000 => Opcode::PsAbs, 0b01000 => Opcode::PsAbs,
_ => Opcode::Illegal, _ => Opcode::Illegal,
}, },
0b10000 => match bits(x, 26..31) { 0b10000 => match bits(x, 21..26) {
0b10000 => Opcode::PsMerge00, 0b10000 => Opcode::PsMerge00,
0b10001 => Opcode::PsMerge01, 0b10001 => Opcode::PsMerge01,
0b10010 => Opcode::PsMerge10, 0b10010 => Opcode::PsMerge10,
@ -377,7 +386,7 @@ impl Opcode {
0b00_0011_0110 => Opcode::Dcbst, 0b00_0011_0110 => Opcode::Dcbst,
0b00_0011_0111 => Opcode::Lwzux, 0b00_0011_0111 => Opcode::Lwzux,
0b00_0011_1100 => Opcode::Andc, 0b00_0011_1100 => Opcode::Andc,
0b00_0100_1101 => Opcode::Mulhw, 0b00_0100_1011 => Opcode::Mulhw,
0b00_0101_0011 => Opcode::Mfmsr, 0b00_0101_0011 => Opcode::Mfmsr,
0b00_0101_0110 => Opcode::Dcbf, 0b00_0101_0110 => Opcode::Dcbf,
0b00_0101_0111 => Opcode::Lbzx, 0b00_0101_0111 => Opcode::Lbzx,
@ -402,8 +411,8 @@ impl Opcode {
0b00_1111_0110 => Opcode::Dcbtst, 0b00_1111_0110 => Opcode::Dcbtst,
0b00_1111_0111 => Opcode::Stbux, 0b00_1111_0111 => Opcode::Stbux,
0b01_0000_1010 => Opcode::Add, 0b01_0000_1010 => Opcode::Add,
0b01_0000_0110 => Opcode::Dcbt, 0b01_0001_0110 => Opcode::Dcbt,
0b01_0000_0111 => Opcode::Lhzx, 0b01_0001_0111 => Opcode::Lhzx,
0b01_0001_1100 => Opcode::Eqv, 0b01_0001_1100 => Opcode::Eqv,
0b01_0011_0010 => Opcode::Tlbie, 0b01_0011_0010 => Opcode::Tlbie,
0b01_0011_0110 => Opcode::Eciwx, 0b01_0011_0110 => Opcode::Eciwx,
@ -422,7 +431,7 @@ impl Opcode {
0b01_1101_0011 => Opcode::Mtspr, 0b01_1101_0011 => Opcode::Mtspr,
0b01_1101_0110 => Opcode::Dcbi, 0b01_1101_0110 => Opcode::Dcbi,
0b01_1101_1100 => Opcode::Nand, 0b01_1101_1100 => Opcode::Nand,
0b01_1111_1011 => Opcode::Divw, 0b01_1110_1011 => Opcode::Divw,
0b10_0000_0000 => Opcode::Mcrxr, 0b10_0000_0000 => Opcode::Mcrxr,
0b10_0001_0101 => Opcode::Lswx, 0b10_0001_0101 => Opcode::Lswx,
0b10_0001_0110 => Opcode::Lwbrx, 0b10_0001_0110 => Opcode::Lwbrx,
@ -514,28 +523,28 @@ impl Opcode {
fn from_code_111111(x: u32) -> Self { fn from_code_111111(x: u32) -> Self {
match bits::<u32>(x, 26..31) { match bits::<u32>(x, 26..31) {
0b00000 => match bits(x, 26..31) { 0b00000 => match bits(x, 24..26) {
0b00 => Opcode::Fcmpu, 0b00 => Opcode::Fcmpu,
0b01 => Opcode::Fcmpo, 0b01 => Opcode::Fcmpo,
0b10 => Opcode::Mcrfs, 0b10 => Opcode::Mcrfs,
_ => Opcode::Illegal, _ => Opcode::Illegal,
}, },
0b00110 => match bits(x, 26..31) { 0b00110 => match bits(x, 23..26) {
0b001 => Opcode::Mtfsb1, 0b001 => Opcode::Mtfsb1,
0b010 => Opcode::Mtfsb0, 0b010 => Opcode::Mtfsb0,
0b100 => Opcode::Mtfsfi, 0b100 => Opcode::Mtfsfi,
_ => Opcode::Illegal, _ => Opcode::Illegal,
}, },
0b00111 => match bits(x, 26..31) { 0b00111 => match bits(x, 21..26) {
0b10010 => Opcode::Mffs, 0b10010 => Opcode::Mffs,
0b10110 => Opcode::Mtfsf, 0b10110 => Opcode::Mtfsf,
_ => Opcode::Illegal, _ => Opcode::Illegal,
}, },
0b01000 => match bits(x, 26..31) { 0b01000 => match bits(x, 22..26) {
0b0001 => Opcode::Fneg, 0b0001 => Opcode::Fneg,
0b0010 => Opcode::Fabs, 0b0010 => Opcode::Fmr,
0b0100 => Opcode::Fnabs, 0b0100 => Opcode::Fnabs,
0b1000 => Opcode::Fmr, 0b1000 => Opcode::Fabs,
_ => Opcode::Illegal, _ => Opcode::Illegal,
}, },
0b01100 => Opcode::Frsp, 0b01100 => Opcode::Frsp,

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,18 @@
use std::iter::FromIterator; use std::iter::FromIterator;
use std::string::ToString; use std::string::ToString;
use proc_macro2::{TokenStream, TokenTree}; use proc_macro2::{Delimiter, Group, TokenStream};
use quote::quote; use quote::quote;
use quote::ToTokens; use quote::ToTokens;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::token::Semi; use syn::{Expr, ExprLit, ExprPath, Ident};
use syn::{Expr, ExprPath, Ident};
struct Arguments { struct Arguments {
formatter: Expr, formatter: Expr,
ins: Expr, ins: Expr,
args: Punctuated<Argument, Semi>, args: Punctuated<Argument, syn::token::Semi>,
} }
impl Parse for Arguments { impl Parse for Arguments {
@ -58,42 +57,58 @@ impl Parse for Argument {
.parse_terminated::<Expr, syn::token::Comma>(Expr::parse)? .parse_terminated::<Expr, syn::token::Comma>(Expr::parse)?
.into_iter() .into_iter()
.collect(); .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 { } else {
let expr = input.parse::<ExprPath>()?.into(); let expr = input.parse::<ExprPath>()?.into();
sources = vec![expr]; sources = vec![expr];
} }
input.parse::<syn::token::RArrow>()?; input.parse::<syn::token::Colon>()?;
let target = input.parse()?; let target = input.parse()?;
Ok(Self { sources, target }) Ok(Self { sources, target })
} }
} }
impl Arguments { impl Arguments {
fn format_mnemonic(&self, tokens: &mut Vec<TokenTree>) { fn format_mnemonic(&self) -> Vec<TokenStream> {
let arg = &self.args[0]; let arg = &self.args[0];
assert!(!arg.sources.is_empty()); assert!(!arg.sources.is_empty());
// Print the mnemonic. // 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. // Print any mnemonic suffixes.
for src in arg.sources.iter().skip(1) { for src in arg.sources.iter().skip(1) {
self.format_call( calls.push(self.format_call(
tokens,
&Ident::new(&src.into_token_stream().to_string(), src.span()), &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<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 { fn ins_call(&self, call: &Expr) -> TokenStream {
let ins = &self.ins; match call {
quote!(#ins.#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<TokenStream> {
let arguments: Arguments = syn::parse2(input)?; let arguments: Arguments = syn::parse2(input)?;
assert!(!arguments.args.is_empty()); assert!(!arguments.args.is_empty());
let mut tokens = Vec::<TokenTree>::new(); // Create a list of calls to execute.
arguments.format_mnemonic(&mut tokens); let mut calls = Vec::<TokenStream>::new();
calls.extend(arguments.format_mnemonic());
let mut offset_open = false; let mut offset_open = false;
for (i, arg) in arguments.args.iter().enumerate().skip(1) { for (i, arg) in arguments.args.iter().enumerate().skip(1) {
// Separate operands from one another unless the last one was an offset. // Separate operands from one another unless the last one was an offset.
if !offset_open { if !offset_open {
if i == 1 { if i == 1 {
arguments.format_call( calls.push(
&mut tokens, arguments
&Ident::new("opcode_separator", arg.target.span()), .format_call(&Ident::new("opcode_separator", arg.target.span()), quote!()),
quote!(),
); );
} else { } else {
arguments.format_call( calls.push(arguments.format_call(
&mut tokens,
&Ident::new("operand_separator", arg.target.span()), &Ident::new("operand_separator", arg.target.span()),
quote!(), quote!(),
); ));
} }
} }
// Arguments to out.write_x(...); // Arguments to out.write_x(...);
@ -134,28 +148,26 @@ pub(crate) fn write_asm(input: TokenStream) -> syn::Result<TokenStream> {
"two consecutive offset arguments", "two consecutive offset arguments",
)); ));
} }
arguments.format_call( calls.push(arguments.format_call(
&mut tokens,
&Ident::new(&(arg.target.to_string() + "_open"), arg.target.span()), &Ident::new(&(arg.target.to_string() + "_open"), arg.target.span()),
format_args_punct.to_token_stream(), format_args_punct.to_token_stream(),
); ));
offset_open = true; offset_open = true;
} else { } else {
arguments.format_call( calls.push(arguments.format_call(&arg.target, format_args_punct.to_token_stream()));
&mut tokens,
&arg.target,
format_args_punct.to_token_stream(),
);
if offset_open { if offset_open {
arguments.format_call( calls.push(
&mut tokens, arguments.format_call(&Ident::new("offset_close", arg.target.span()), quote!()),
&Ident::new("offset_close", arg.target.span()),
quote!(),
); );
offset_open = false; 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())
} }