diff --git a/disasm-py/src/lib.rs b/disasm-py/src/lib.rs index cbd1fa8..efcd9aa 100644 --- a/disasm-py/src/lib.rs +++ b/disasm-py/src/lib.rs @@ -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)] diff --git a/disasm/src/generated.rs b/disasm/src/generated.rs index b259511..c1a3e61 100644 --- a/disasm/src/generated.rs +++ b/disasm/src/generated.rs @@ -1167,6 +1167,92 @@ pub enum Field { ctr, lr, } +impl Field { + pub fn argument(&self) -> Option { + 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 { diff --git a/disasm/src/lib.rs b/disasm/src/lib.rs index 985c0b2..6803399 100644 --- a/disasm/src/lib.rs +++ b/disasm/src/lib.rs @@ -166,50 +166,33 @@ impl Display for Argument { } } -impl Field { - pub fn argument(&self) -> Option { +impl Into 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 for &Field { + type Error = (); + fn try_into(self) -> Result { + self.argument().ok_or(()) + } +} + impl Opcode { /// Detects the opcode of a machine code instruction. pub fn detect(code: u32) -> Self { diff --git a/genisa/src/main.rs b/genisa/src/main.rs index 4591b9c..978f230 100644 --- a/genisa/src/main.rs +++ b/genisa/src/main.rs @@ -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 { + fn gen_opcode_detect(&self) -> Result { // Generate if chain. let if_chain = self .opcodes @@ -363,7 +364,7 @@ impl Isa { Ok(func) } - pub(crate) fn gen_field_enum(&self) -> Result { + fn gen_field_enum(&self) -> Result { // 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 { + fn gen_field_argument(&self) -> Result { + 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 { + match self { + #match_arms + _ => None, + } + } + }) + } + + fn gen_field_name(&self) -> Result { + 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 { + 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 { // Map fields by name. let mut field_by_name = HashMap::::new(); for field in &self.fields {