disasm-py: add fields() method

This commit is contained in:
Richard Patel 2022-04-09 17:19:05 +02:00
parent 88c6a478e2
commit 9dab42c364
4 changed files with 172 additions and 43 deletions

View File

@ -31,6 +31,14 @@ impl Ins {
fn __str__(&self) -> String {
FormattedIns(self.0.clone()).to_string()
}
fn fields(&self) -> Vec<(&'static str, i64)> {
self.0
.fields()
.iter()
.flat_map(|field| field.argument().map(|arg| (field.name(), arg.into())))
.collect()
}
}
#[allow(non_snake_case)]

View File

@ -1167,6 +1167,92 @@ pub enum Field {
ctr,
lr,
}
impl Field {
pub fn argument(&self) -> Option<Argument> {
match self {
Field::simm(x) => Some(Argument::Simm(*x)),
Field::uimm(x) => Some(Argument::Uimm(*x)),
Field::offset(x) => Some(Argument::Offset(*x)),
Field::ps_offset(x) => Some(Argument::Offset(*x)),
Field::BO(x) => Some(Argument::OpaqueU(*x)),
Field::BI(x) => Some(Argument::OpaqueU(*x)),
Field::BD(x) => Some(Argument::BranchDest(*x)),
Field::LI(x) => Some(Argument::BranchDest(*x)),
Field::SH(x) => Some(Argument::OpaqueU(*x)),
Field::MB(x) => Some(Argument::OpaqueU(*x)),
Field::ME(x) => Some(Argument::OpaqueU(*x)),
Field::rS(x) => Some(Argument::GPR(*x)),
Field::rD(x) => Some(Argument::GPR(*x)),
Field::rA(x) => Some(Argument::GPR(*x)),
Field::rB(x) => Some(Argument::GPR(*x)),
Field::rC(x) => Some(Argument::GPR(*x)),
Field::sr(x) => Some(Argument::SR(*x)),
Field::spr(x) => Some(Argument::SPR(*x)),
Field::frS(x) => Some(Argument::FPR(*x)),
Field::frD(x) => Some(Argument::FPR(*x)),
Field::frA(x) => Some(Argument::FPR(*x)),
Field::frB(x) => Some(Argument::FPR(*x)),
Field::frC(x) => Some(Argument::FPR(*x)),
Field::crbD(x) => Some(Argument::CRBit(*x)),
Field::crbA(x) => Some(Argument::CRBit(*x)),
Field::crbB(x) => Some(Argument::CRBit(*x)),
Field::crfD(x) => Some(Argument::CRField(*x)),
Field::crfS(x) => Some(Argument::CRField(*x)),
Field::crm(x) => Some(Argument::OpaqueU(*x)),
Field::ps_l(x) => Some(Argument::GQR(*x)),
Field::ps_W(x) => Some(Argument::OpaqueU(*x)),
Field::NB(x) => Some(Argument::OpaqueU(*x)),
Field::tbr(x) => Some(Argument::OpaqueU(*x)),
Field::mtfsf_FM(x) => Some(Argument::OpaqueU(*x)),
Field::mtfsf_IMM(x) => Some(Argument::OpaqueU(*x)),
Field::TO(x) => Some(Argument::OpaqueU(*x)),
_ => None,
}
}
pub fn name(&self) -> &'static str {
match self {
Field::simm(_) => "simm",
Field::uimm(_) => "uimm",
Field::offset(_) => "offset",
Field::ps_offset(_) => "ps_offset",
Field::BO(_) => "BO",
Field::BI(_) => "BI",
Field::BD(_) => "BD",
Field::LI(_) => "LI",
Field::SH(_) => "SH",
Field::MB(_) => "MB",
Field::ME(_) => "ME",
Field::rS(_) => "rS",
Field::rD(_) => "rD",
Field::rA(_) => "rA",
Field::rB(_) => "rB",
Field::rC(_) => "rC",
Field::sr(_) => "sr",
Field::spr(_) => "spr",
Field::frS(_) => "frS",
Field::frD(_) => "frD",
Field::frA(_) => "frA",
Field::frB(_) => "frB",
Field::frC(_) => "frC",
Field::crbD(_) => "crbD",
Field::crbA(_) => "crbA",
Field::crbB(_) => "crbB",
Field::crfD(_) => "crfD",
Field::crfS(_) => "crfS",
Field::crm(_) => "crm",
Field::ps_l(_) => "ps_l",
Field::ps_W(_) => "ps_W",
Field::NB(_) => "NB",
Field::tbr(_) => "tbr",
Field::mtfsf_FM(_) => "mtfsf_FM",
Field::mtfsf_IMM(_) => "mtfsf_IMM",
Field::TO(_) => "TO",
Field::xer => "xer",
Field::ctr => "ctr",
Field::lr => "lr",
}
}
}
#[allow(clippy::all, unused_mut)]
impl Ins {
pub(crate) fn _fields(&self) -> Vec<Field> {

View File

@ -166,50 +166,33 @@ impl Display for Argument {
}
}
impl Field {
pub fn argument(&self) -> Option<Argument> {
impl Into<i64> for Argument {
fn into(self) -> i64 {
match self {
Field::simm(x) => Some(Argument::Simm(*x)),
Field::uimm(x) => Some(Argument::Uimm(*x)),
Field::offset(x) => Some(Argument::Offset(*x)),
Field::ps_offset(x) => Some(Argument::Offset(*x)),
Field::BO(x) => Some(Argument::OpaqueU(*x)),
Field::BI(x) => Some(Argument::OpaqueU(*x)),
Field::BD(x) => Some(Argument::BranchDest(*x)),
Field::LI(x) => Some(Argument::BranchDest(*x)),
Field::SH(x) => Some(Argument::OpaqueU(*x)),
Field::MB(x) => Some(Argument::OpaqueU(*x)),
Field::ME(x) => Some(Argument::OpaqueU(*x)),
Field::rS(x) => Some(Argument::GPR(*x)),
Field::rD(x) => Some(Argument::GPR(*x)),
Field::rA(x) => Some(Argument::GPR(*x)),
Field::rB(x) => Some(Argument::GPR(*x)),
Field::rC(x) => Some(Argument::GPR(*x)),
Field::sr(x) => Some(Argument::SR(*x)),
Field::spr(x) => Some(Argument::SPR(*x)),
Field::frS(x) => Some(Argument::FPR(*x)),
Field::frD(x) => Some(Argument::FPR(*x)),
Field::frA(x) => Some(Argument::FPR(*x)),
Field::frB(x) => Some(Argument::FPR(*x)),
Field::frC(x) => Some(Argument::FPR(*x)),
Field::crbD(x) => Some(Argument::CRBit(*x)),
Field::crbA(x) => Some(Argument::CRBit(*x)),
Field::crbB(x) => Some(Argument::CRBit(*x)),
Field::crfD(x) => Some(Argument::CRField(*x)),
Field::crfS(x) => Some(Argument::CRField(*x)),
Field::crm(x) => Some(Argument::OpaqueU(*x)),
Field::ps_l(x) => Some(Argument::GQR(*x)),
Field::ps_W(x) => Some(Argument::OpaqueU(*x)),
Field::NB(x) => Some(Argument::OpaqueU(*x)),
Field::tbr(x) => Some(Argument::OpaqueU(*x)),
Field::mtfsf_FM(x) => Some(Argument::OpaqueU(*x)),
Field::mtfsf_IMM(x) => Some(Argument::OpaqueU(*x)),
Field::TO(x) => Some(Argument::OpaqueU(*x)),
_ => None,
Argument::GPR(x) => x.0 as i64,
Argument::FPR(x) => x.0 as i64,
Argument::SR(x) => x.0 as i64,
Argument::SPR(x) => x.0 as i64,
Argument::CRField(x) => x.0 as i64,
Argument::CRBit(x) => x.0 as i64,
Argument::GQR(x) => x.0 as i64,
Argument::Uimm(x) => x.0 as i64,
Argument::Simm(x) => x.0 as i64,
Argument::Offset(x) => x.0 as i64,
Argument::BranchDest(x) => x.0 as i64,
Argument::Bit(x) => x.0 as i64,
Argument::OpaqueU(x) => x.0 as i64,
}
}
}
impl TryInto<Argument> for &Field {
type Error = ();
fn try_into(self) -> Result<Argument, Self::Error> {
self.argument().ok_or(())
}
}
impl Opcode {
/// Detects the opcode of a machine code instruction.
pub fn detect(code: u32) -> Self {

View File

@ -40,6 +40,7 @@ fn _main() -> Result<()> {
)?;
writeln!(&mut unformatted_code, "{}", isa.gen_opcode_enum()?)?;
writeln!(&mut unformatted_code, "{}", isa.gen_field_enum()?)?;
writeln!(&mut unformatted_code, "{}", isa.gen_field_impl()?)?;
writeln!(&mut unformatted_code, "{}", isa.gen_ins_impl()?)?;
let formatted_code = rustfmt(unformatted_code);
@ -160,7 +161,7 @@ impl Field {
})
}
fn construct_variant(&self, code: TokenStream) -> TokenStream {
pub(crate) fn construct_variant(&self, code: TokenStream) -> TokenStream {
let field_variant = self.variant_identifier();
if let Some(arg) = &self.arg {
let field_arg = TokenTree::Ident(Ident::new(arg, Span::call_site()));
@ -334,7 +335,7 @@ impl Isa {
Ok(mnemonic_fn)
}
pub(crate) fn gen_opcode_detect(&self) -> Result<TokenStream> {
fn gen_opcode_detect(&self) -> Result<TokenStream> {
// Generate if chain.
let if_chain = self
.opcodes
@ -363,7 +364,7 @@ impl Isa {
Ok(func)
}
pub(crate) fn gen_field_enum(&self) -> Result<TokenStream> {
fn gen_field_enum(&self) -> Result<TokenStream> {
// Create enum variants.
let mut enum_variants = Vec::new();
for field in &self.fields {
@ -384,7 +385,58 @@ impl Isa {
Ok(field_enum)
}
pub(crate) fn gen_ins_impl(&self) -> Result<TokenStream> {
fn gen_field_argument(&self) -> Result<TokenStream> {
let mut match_arms = Vec::new();
for field in &self.fields {
if let Some(variant) = field.variant_identifier() {
if let Some(arg_str) = field.arg.as_ref() {
let arg = Ident::new(arg_str, Span::call_site());
match_arms.push(quote! { Field::#variant(x) => Some(Argument::#arg(*x)), });
}
}
}
let match_arms = token_stream!(match_arms);
Ok(quote! {
pub fn argument(&self) -> Option<Argument> {
match self {
#match_arms
_ => None,
}
}
})
}
fn gen_field_name(&self) -> Result<TokenStream> {
let mut match_arms = Vec::new();
for field in &self.fields {
if let Some(variant) = field.variant_identifier() {
let name = LitStr::new(&variant.to_string(), Span::call_site());
let arg = field.arg.as_ref().map(|_| quote!((_)));
match_arms.push(quote! { Field::#variant #arg => #name, });
}
}
let match_arms = token_stream!(match_arms);
Ok(quote! {
pub fn name(&self) -> &'static str {
match self {
#match_arms
}
}
})
}
fn gen_field_impl(&self) -> Result<TokenStream> {
let field_argument = self.gen_field_argument()?;
let field_name = self.gen_field_name()?;
Ok(quote! {
impl Field {
#field_argument
#field_name
}
})
}
fn gen_ins_impl(&self) -> Result<TokenStream> {
// Map fields by name.
let mut field_by_name = HashMap::<String, &Field>::new();
for field in &self.fields {