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)
}
/// 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<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 {
write!(self.writer(), "{:#x}", ReallySigned(simm))
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.
@ -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<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.
@ -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<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.
@ -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

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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,42 +57,58 @@ 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, 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 {
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<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())
}