more flexible modifier handling
This commit is contained in:
parent
99c7f252f8
commit
4c5735e403
|
@ -2,6 +2,17 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
@ -17,12 +28,33 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"os_str_bytes",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dol"
|
||||
version = "0.1.0"
|
||||
|
@ -38,6 +70,12 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.6"
|
||||
|
@ -95,6 +133,12 @@ version = "0.5.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
|
@ -114,6 +158,34 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse_int"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl"
|
||||
version = "0.1.1"
|
||||
|
@ -122,6 +194,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl-flow-graph"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"dol",
|
||||
"itertools",
|
||||
"parse_int",
|
||||
"petgraph",
|
||||
"ppc750cl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl-fuzz"
|
||||
version = "0.1.1"
|
||||
|
@ -253,6 +337,12 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.91"
|
||||
|
@ -264,6 +354,21 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
@ -296,6 +401,37 @@ version = "0.10.2+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
|
|
@ -4,5 +4,6 @@ members = [
|
|||
"dol",
|
||||
"fuzz",
|
||||
"genisa",
|
||||
"flow-graph",
|
||||
"rand",
|
||||
]
|
||||
|
|
|
@ -7,7 +7,7 @@ pub struct FormattedIns(pub Ins);
|
|||
impl Display for FormattedIns {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let simple = self.0.clone().simplified();
|
||||
write!(f, "{}{}", simple.mnemonic, simple.modifiers)?;
|
||||
write!(f, "{}{}", simple.mnemonic, simple.ins.suffix())?;
|
||||
let mut writing_offset = false;
|
||||
for (i, arg) in simple.args.iter().enumerate() {
|
||||
if i == 0 {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,6 @@ pub mod prelude {
|
|||
pub use crate::Argument;
|
||||
pub use crate::Field::*;
|
||||
pub use crate::Ins;
|
||||
pub use crate::Modifiers;
|
||||
pub use crate::Opcode::*;
|
||||
pub use crate::SimplifiedIns;
|
||||
pub use crate::{
|
||||
|
@ -210,32 +209,6 @@ impl Field {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Modifiers {
|
||||
pub oe: bool,
|
||||
pub rc: bool,
|
||||
pub lk: bool,
|
||||
pub aa: bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Modifiers {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
if self.aa {
|
||||
write!(f, "a")?;
|
||||
}
|
||||
if self.lk {
|
||||
write!(f, "l")?;
|
||||
}
|
||||
if self.oe {
|
||||
write!(f, "o")?;
|
||||
}
|
||||
if self.rc {
|
||||
write!(f, ".")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
/// Detects the opcode of a machine code instruction.
|
||||
pub fn detect(code: u32) -> Self {
|
||||
|
@ -289,9 +262,9 @@ impl Ins {
|
|||
self._fields() // auto-generated
|
||||
}
|
||||
|
||||
/// Gets the modifiers of an instruction.
|
||||
pub fn modifiers(&self) -> Modifiers {
|
||||
self._modifiers() // auto-generated
|
||||
/// Gets the suffix of an instruction mnemonic.
|
||||
pub fn suffix(&self) -> String {
|
||||
self._suffix() // auto-generated
|
||||
}
|
||||
|
||||
/// Gets the defs of an instruction.
|
||||
|
@ -314,10 +287,9 @@ impl Ins {
|
|||
bits(self.code, range)
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn branch_offset(&self) -> Option<i32> {
|
||||
match self.op {
|
||||
Opcode::B => Some(self.li()),
|
||||
Opcode::B => Some(self.field_LI() as i32),
|
||||
Opcode::Bc | Opcode::Bcctr | Opcode::Bclr => Some(self.field_BD() as i32),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -332,20 +304,18 @@ impl Ins {
|
|||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// A simplified PowerPC 750CL instruction.
|
||||
pub struct SimplifiedIns {
|
||||
pub ins: Ins,
|
||||
pub mnemonic: &'static str,
|
||||
pub modifiers: Modifiers,
|
||||
pub args: Vec<Argument>,
|
||||
}
|
||||
|
||||
impl Display for SimplifiedIns {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}{} ", self.mnemonic, self.modifiers)?;
|
||||
write!(f, "{}{} ", self.mnemonic, self.ins.suffix())?;
|
||||
let mut writing_offset = false;
|
||||
for (i, argument) in self.args.iter().enumerate() {
|
||||
write!(f, "{}", argument)?;
|
||||
|
@ -370,7 +340,6 @@ impl SimplifiedIns {
|
|||
pub(crate) fn basic_form(ins: Ins) -> Self {
|
||||
Self {
|
||||
mnemonic: ins.op.mnemonic(),
|
||||
modifiers: ins.modifiers(),
|
||||
args: ins
|
||||
.fields()
|
||||
.iter()
|
||||
|
|
|
@ -8,6 +8,7 @@ use petgraph::algo::dominators::Dominators;
|
|||
use petgraph::graph::{DefaultIx, NodeIndex};
|
||||
use petgraph::Graph;
|
||||
|
||||
use ppc750cl::formatter::FormattedIns;
|
||||
use ppc750cl::{Ins, Opcode};
|
||||
|
||||
use crate::slices::{BasicSlices, CodeIdx};
|
||||
|
@ -53,21 +54,21 @@ impl<'a> BasicBlock<'a> {
|
|||
for ins in code {
|
||||
match ins.op {
|
||||
Opcode::Addis => {
|
||||
if ins.a() == 0 {
|
||||
if ins.field_rA() == 0 {
|
||||
// lis
|
||||
defs.insert(ins.d(), ins.field_uimm() as u16);
|
||||
defs.insert(ins.field_rD() as u8, ins.field_uimm() as u16);
|
||||
} else {
|
||||
defs.remove(&ins.d());
|
||||
defs.remove(&(ins.field_rD() as u8));
|
||||
}
|
||||
}
|
||||
Opcode::Addi => {
|
||||
if let Some(hi) = defs.get(&ins.a()) {
|
||||
if let Some(hi) = defs.get(&(ins.field_rA() as u8)) {
|
||||
data_refs.insert(
|
||||
ins.addr / 4,
|
||||
((*hi as u32) << 16) + (ins.field_uimm() as u32),
|
||||
);
|
||||
}
|
||||
defs.remove(&ins.d());
|
||||
defs.remove(&(ins.field_rD() as u8));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -91,7 +92,7 @@ impl<'a> Debug for BasicBlock<'a> {
|
|||
self.range.end * 4
|
||||
)?;
|
||||
for ins in self.code {
|
||||
writeln!(f, "{}", ins.to_string())?;
|
||||
writeln!(f, "{}", FormattedIns(ins.clone()))?;
|
||||
if let Some(addr) = self.data_refs.get(&(ins.addr / 4)) {
|
||||
writeln!(f, " ref: {:0>#8x}", addr)?;
|
||||
}
|
||||
|
@ -154,8 +155,8 @@ impl<'a> FlowGraph<'a> {
|
|||
// Get last instruction of left block.
|
||||
// Unless it's an unconditional branch, we can connect the blocks.
|
||||
let last_ins = &src_block.code.last().unwrap();
|
||||
if last_ins.code == Opcode::BLR
|
||||
|| (last_ins.op == Opcode::B && last_ins.bo() == 0b10100)
|
||||
if last_ins.code == 0x4E800020
|
||||
|| (last_ins.op == Opcode::B && last_ins.field_BO() == 0b10100)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ impl BasicSlices {
|
|||
let is_control_flow_ins = match ins.op {
|
||||
// Direct branches are control flow instructions if they don't save the link register.
|
||||
// If they do, we encountered a function call.
|
||||
Opcode::B | Opcode::Bc => ins.lk() == 0,
|
||||
Opcode::B | Opcode::Bc => !ins.field_LK(),
|
||||
// Switch table
|
||||
Opcode::Bcctr => panic!("jump tables not supported yet"),
|
||||
_ => false,
|
||||
|
|
|
@ -9,7 +9,7 @@ use itertools::Itertools;
|
|||
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
|
||||
use quote::quote;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use syn::{LitInt, LitStr};
|
||||
use syn::{LitChar, LitInt, LitStr};
|
||||
|
||||
macro_rules! token_stream {
|
||||
($stream:ident) => {
|
||||
|
@ -194,6 +194,7 @@ impl Field {
|
|||
quote!(usize)
|
||||
};
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
pub fn #field_variant(&self) -> #ret_type {
|
||||
#value as _
|
||||
}
|
||||
|
@ -236,12 +237,32 @@ pub(crate) struct Mnemonic {
|
|||
pub(crate) struct Modifier {
|
||||
name: String,
|
||||
suffix: char,
|
||||
bit: u8,
|
||||
}
|
||||
|
||||
impl Modifier {
|
||||
fn express_value_self(&self) -> TokenStream {
|
||||
let modifier_bit = self.bit as usize;
|
||||
quote!(self.bit(#modifier_bit))
|
||||
}
|
||||
|
||||
fn construct_accessor(&self) -> TokenStream {
|
||||
let field_variant = to_rust_ident("field_", &self.name);
|
||||
let value = self.express_value_self();
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
pub fn #field_variant(&self) -> bool {
|
||||
#value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Isa {
|
||||
fields: Vec<Field>,
|
||||
modifiers: Vec<Modifier>,
|
||||
opcodes: Vec<Opcode>,
|
||||
mnemonics: Vec<Mnemonic>,
|
||||
}
|
||||
|
@ -294,8 +315,7 @@ impl Isa {
|
|||
.iter()
|
||||
.map(|opcode| {
|
||||
let variant = opcode.variant_identifier()?;
|
||||
let literal =
|
||||
Literal::string(opcode.name.strip_suffix('.').unwrap_or(&opcode.name));
|
||||
let literal = Literal::string(&opcode.name);
|
||||
Ok(quote! {
|
||||
Opcode::#variant => #literal,
|
||||
})
|
||||
|
@ -370,6 +390,10 @@ impl Isa {
|
|||
for field in &self.fields {
|
||||
field_by_name.insert(field.name.clone(), field);
|
||||
}
|
||||
let mut modifier_by_name = HashMap::<String, &Modifier>::new();
|
||||
for modifier in &self.modifiers {
|
||||
modifier_by_name.insert(modifier.name.clone(), modifier);
|
||||
}
|
||||
// Map mnemonics by opcode.
|
||||
let mut mnemonics_by_opcode = HashMap::<&String, Vec<&Mnemonic>>::new();
|
||||
for simple in &self.mnemonics {
|
||||
|
@ -382,7 +406,7 @@ impl Isa {
|
|||
let mut field_match_arms = Vec::new();
|
||||
let mut def_match_arms = Vec::new();
|
||||
let mut use_match_arms = Vec::new();
|
||||
let mut modifier_match_arms = Vec::new();
|
||||
let mut suffix_match_arms = Vec::new();
|
||||
let mut simplified_ins_match_arms = Vec::new();
|
||||
for opcode in &self.opcodes {
|
||||
// Generate fields of opcode.
|
||||
|
@ -402,13 +426,9 @@ impl Isa {
|
|||
});
|
||||
|
||||
// Generate modifiers.
|
||||
let modifiers = ModifiersExpr {
|
||||
modifiers: opcode.modifiers.clone(),
|
||||
side_effects: opcode.side_effects.clone(),
|
||||
}
|
||||
.build()?;
|
||||
modifier_match_arms.push(quote! {
|
||||
Opcode::#ident => #modifiers,
|
||||
let suffix = express_suffix(&modifier_by_name, opcode)?;
|
||||
suffix_match_arms.push(quote! {
|
||||
Opcode::#ident => #suffix,
|
||||
});
|
||||
|
||||
// Generate defs.
|
||||
|
@ -480,12 +500,6 @@ impl Isa {
|
|||
)?);
|
||||
// Emit branch.
|
||||
let mnemonic_lit = LitStr::new(&mnemonic.name, Span::call_site());
|
||||
// Extract modifier bits.
|
||||
let modifiers = ModifiersExpr {
|
||||
modifiers: mnemonic.modifiers.clone(),
|
||||
side_effects: vec![],
|
||||
}
|
||||
.build()?;
|
||||
// Extract arguments.
|
||||
let mut args = Vec::new();
|
||||
for arg in &mnemonic.args {
|
||||
|
@ -501,7 +515,6 @@ impl Isa {
|
|||
{
|
||||
return SimplifiedIns {
|
||||
mnemonic: #mnemonic_lit,
|
||||
modifiers: #modifiers,
|
||||
args: vec![#args],
|
||||
ins: self,
|
||||
};
|
||||
|
@ -519,7 +532,7 @@ impl Isa {
|
|||
let field_match_arms = token_stream!(field_match_arms);
|
||||
let def_match_arms = token_stream!(def_match_arms);
|
||||
let use_match_arms = token_stream!(use_match_arms);
|
||||
let modifier_match_arms = token_stream!(modifier_match_arms);
|
||||
let suffix_match_arms = token_stream!(suffix_match_arms);
|
||||
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
|
||||
let field_accessors = self
|
||||
.fields
|
||||
|
@ -527,6 +540,12 @@ impl Isa {
|
|||
.map(|field| field.construct_accessor())
|
||||
.collect::<Vec<_>>();
|
||||
let field_accessors = token_stream!(field_accessors);
|
||||
let modifier_accessors = self
|
||||
.modifiers
|
||||
.iter()
|
||||
.map(|modifier| modifier.construct_accessor())
|
||||
.collect::<Vec<_>>();
|
||||
let modifier_accessors = token_stream!(modifier_accessors);
|
||||
// Generate final fields function.
|
||||
let ins_impl = quote! {
|
||||
#[allow(clippy::all, unused_mut)]
|
||||
|
@ -552,10 +571,10 @@ impl Isa {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn _modifiers(&self) -> Modifiers {
|
||||
pub(crate) fn _suffix(&self) -> String {
|
||||
match self.op {
|
||||
Opcode::Illegal => Modifiers::default(),
|
||||
#modifier_match_arms
|
||||
Opcode::Illegal => String::new(),
|
||||
#suffix_match_arms
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,6 +589,7 @@ impl Isa {
|
|||
#[allow(clippy::all, non_snake_case)]
|
||||
impl Ins {
|
||||
#field_accessors
|
||||
#modifier_accessors
|
||||
}
|
||||
};
|
||||
Ok(ins_impl)
|
||||
|
@ -624,56 +644,6 @@ fn to_rust_variant_str(key: &str) -> Result<String> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ModifiersExpr {
|
||||
pub(crate) modifiers: Vec<String>,
|
||||
pub(crate) side_effects: Vec<String>,
|
||||
}
|
||||
|
||||
impl ModifiersExpr {
|
||||
fn build(&self) -> Result<TokenStream> {
|
||||
if self.modifiers.is_empty() && self.side_effects.is_empty() {
|
||||
return Ok(Self::build_empty());
|
||||
}
|
||||
let mut statements: Vec<TokenTree> = Vec::new();
|
||||
for modifier in &self.modifiers {
|
||||
statements.extend(match modifier.as_str() {
|
||||
"OE" => quote! { m.oe = self.bit(21); },
|
||||
"Rc" => quote! { m.rc = self.bit(31); },
|
||||
"AA" => quote! { m.aa = self.bit(30); },
|
||||
"LK" => quote! { m.lk = self.bit(31); },
|
||||
_ => {
|
||||
return Err(format!("unsupported modifier {}", modifier).into());
|
||||
}
|
||||
})
|
||||
}
|
||||
for modifier in &self.side_effects {
|
||||
statements.extend(match modifier.as_str() {
|
||||
// TODO dedup modifiers
|
||||
"OE" => quote! { m.oe = true; },
|
||||
"Rc" => quote! { m.rc = true; },
|
||||
"AA" => quote! { m.aa = true; },
|
||||
"LK" => quote! { m.lk = true; },
|
||||
_ => {
|
||||
return Err(format!("unsupported modifier {}", modifier).into());
|
||||
}
|
||||
})
|
||||
}
|
||||
let statements = token_stream!(statements);
|
||||
Ok(quote! {
|
||||
{
|
||||
let mut m = Modifiers::default();
|
||||
#statements
|
||||
m
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn build_empty() -> TokenStream {
|
||||
quote!(Modifiers::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Compiles conditions such as `S == B` into valid Rust expressions on a PowerPC instruction.
|
||||
fn compile_mnemonic_condition(
|
||||
field_by_name: &HashMap<String, &Field>,
|
||||
|
@ -690,3 +660,34 @@ fn compile_mnemonic_condition(
|
|||
});
|
||||
Ok(TokenStream::from_iter(token_iter))
|
||||
}
|
||||
|
||||
fn express_suffix(
|
||||
modifier_by_name: &HashMap<String, &Modifier>,
|
||||
opcode: &Opcode,
|
||||
) -> Result<TokenStream> {
|
||||
Ok(if opcode.modifiers.is_empty() {
|
||||
quote!(String::new())
|
||||
} else {
|
||||
let mut chars = Vec::new();
|
||||
for mod_name in &opcode.modifiers {
|
||||
let modifier: &Modifier = modifier_by_name
|
||||
.get(mod_name)
|
||||
.ok_or_else(|| Error::from(format!("undefined modifier {}", mod_name)))?;
|
||||
let lit_char = LitChar::new(modifier.suffix, Span::call_site());
|
||||
let modifier_bit = modifier.express_value_self();
|
||||
chars.push(quote! {
|
||||
if #modifier_bit {
|
||||
s.push(#lit_char);
|
||||
}
|
||||
});
|
||||
}
|
||||
let chars = token_stream!(chars);
|
||||
quote!({
|
||||
{
|
||||
let mut s = String::with_capacity(4);
|
||||
#chars
|
||||
s
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue