fix signed fields
This commit is contained in:
parent
9e7f70444f
commit
b8199e678c
File diff suppressed because it is too large
Load Diff
|
@ -313,6 +313,26 @@ impl Ins {
|
||||||
pub fn bits(&self, range: Range<usize>) -> u32 {
|
pub fn bits(&self, range: Range<usize>) -> u32 {
|
||||||
bits(self.code, range)
|
bits(self.code, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn branch_offset(&self) -> Option<i32> {
|
||||||
|
match self.op {
|
||||||
|
Opcode::B => Some(self.li()),
|
||||||
|
Opcode::Bc | Opcode::Bcctr | Opcode::Bclr => Some(self.field_BD() as i32),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn branch_dest(&self) -> Option<u32> {
|
||||||
|
self.branch_offset().and_then(|offset| {
|
||||||
|
if offset < 0 {
|
||||||
|
self.addr.checked_sub((-offset) as u32)
|
||||||
|
} else {
|
||||||
|
self.addr.checked_add(offset as u32)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simplified PowerPC 750CL instruction.
|
/// A simplified PowerPC 750CL instruction.
|
||||||
|
|
|
@ -85,7 +85,7 @@ fn test_ins_andi_() {
|
||||||
fn test_ins_andis_() {
|
fn test_ins_andis_() {
|
||||||
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
|
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_b() {
|
fn test_ins_b() {
|
||||||
assert_asm!(0x48000000, "b 0x0");
|
assert_asm!(0x48000000, "b 0x0");
|
||||||
|
@ -96,6 +96,7 @@ fn test_ins_b() {
|
||||||
assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
|
assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_bc() {
|
fn test_ins_bc() {
|
||||||
assert_asm!(0x40800008, "bge 0x8");
|
assert_asm!(0x40800008, "bge 0x8");
|
||||||
|
|
|
@ -8,9 +8,9 @@ description = "Control flow graph analysis for PowerPC 750CL"
|
||||||
repository = "https://github.com/terorie/ppc750cl"
|
repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33"
|
clap = "3"
|
||||||
dol = { version = "0.1.0", path = "../dol" }
|
dol = { version = "0.1.0", path = "../dol" }
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
parse_int = "0.5"
|
parse_int = "0.6"
|
||||||
petgraph = "0.6"
|
petgraph = "0.6"
|
||||||
ppc750cl = { version = "0.1.1", path = "../disasm" }
|
ppc750cl = { version = "0.1.1", path = "../disasm" }
|
||||||
|
|
|
@ -55,14 +55,17 @@ impl<'a> BasicBlock<'a> {
|
||||||
Opcode::Addis => {
|
Opcode::Addis => {
|
||||||
if ins.a() == 0 {
|
if ins.a() == 0 {
|
||||||
// lis
|
// lis
|
||||||
defs.insert(ins.d(), ins.uimm());
|
defs.insert(ins.d(), ins.field_uimm() as u16);
|
||||||
} else {
|
} else {
|
||||||
defs.remove(&ins.d());
|
defs.remove(&ins.d());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Addi => {
|
Opcode::Addi => {
|
||||||
if let Some(hi) = defs.get(&ins.a()) {
|
if let Some(hi) = defs.get(&ins.a()) {
|
||||||
data_refs.insert(ins.addr / 4, ((*hi as u32) << 16) + (ins.uimm() as u32));
|
data_refs.insert(
|
||||||
|
ins.addr / 4,
|
||||||
|
((*hi as u32) << 16) + (ins.field_uimm() as u32),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
defs.remove(&ins.d());
|
defs.remove(&ins.d());
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl BasicSlices {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// We encountered some kind of control flow instruction.
|
// We encountered some kind of control flow instruction.
|
||||||
if ins.code != Opcode::BLR {
|
if ins.field_BO() == 20 && ins.field_BI() == 0 {
|
||||||
// There's a possibility that branch can be taken.
|
// There's a possibility that branch can be taken.
|
||||||
// Branch destinations are always the first instruction of a block.
|
// Branch destinations are always the first instruction of a block.
|
||||||
// Thus, we also found the end of another block.
|
// Thus, we also found the end of another block.
|
||||||
|
@ -58,5 +58,5 @@ fn is_conditional_branch(ins: &Ins) -> bool {
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
// Check whether bits "branch always".
|
// Check whether bits "branch always".
|
||||||
ins.bo() & 0b10100 != 0b10100
|
ins.field_BO() & 0b10100 != 0b10100
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,24 +97,49 @@ pub(crate) struct Field {
|
||||||
signed: bool,
|
signed: bool,
|
||||||
split: bool,
|
split: bool,
|
||||||
arg: Option<String>,
|
arg: Option<String>,
|
||||||
|
shift_left: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Field {
|
impl Field {
|
||||||
fn variant_identifier(&self) -> Option<TokenTree> {
|
fn variant_identifier(&self) -> Option<TokenTree> {
|
||||||
|
self.identifier("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identifier(&self, prefix: &str) -> Option<TokenTree> {
|
||||||
if self.name.strip_suffix(".nz").is_none() {
|
if self.name.strip_suffix(".nz").is_none() {
|
||||||
Some(to_rust_ident(&self.name))
|
Some(to_rust_ident(prefix, &self.name))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn express_value(&self, code: TokenStream) -> TokenStream {
|
fn express_value(&self, code: TokenStream) -> TokenStream {
|
||||||
|
let mut val = quote!(#code);
|
||||||
|
|
||||||
let shift = 32 - self.bits.0.end;
|
let shift = 32 - self.bits.0.end;
|
||||||
let mask = (1u32 << self.bits.0.len()) - 1;
|
if shift > 0 {
|
||||||
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
|
val = quote!((#val >> #shift));
|
||||||
quote! {
|
|
||||||
((#code >> #shift) & #mask)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mask = (1u32 << self.bits.0.len()) - 1;
|
||||||
|
if mask != 0xFFFF_FFFF {
|
||||||
|
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
|
||||||
|
val = quote!((#val & #mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||||
|
if self.signed {
|
||||||
|
let mask2 = 1u32 << (self.bits.0.len() - 1);
|
||||||
|
let mask2 = LitInt::new(&format!("0x{:x}", mask2), Span::call_site());
|
||||||
|
val = quote!(((#val ^ #mask2).wrapping_sub(#mask2)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let val_shift = self.shift_left;
|
||||||
|
if val_shift > 0 {
|
||||||
|
val = quote!((#val << #val_shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
fn express_value_self(&self) -> TokenStream {
|
fn express_value_self(&self) -> TokenStream {
|
||||||
|
@ -153,6 +178,27 @@ impl Field {
|
||||||
fn construct_variant_self(&self) -> TokenStream {
|
fn construct_variant_self(&self) -> TokenStream {
|
||||||
self.construct_variant(quote!(self.code))
|
self.construct_variant(quote!(self.code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn construct_accessor(&self) -> TokenStream {
|
||||||
|
let field_variant = match self.identifier("field_") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return TokenStream::new(),
|
||||||
|
};
|
||||||
|
if self.arg.is_none() {
|
||||||
|
return TokenStream::new();
|
||||||
|
}
|
||||||
|
let value = self.express_value_self();
|
||||||
|
let ret_type = if self.signed {
|
||||||
|
quote!(isize)
|
||||||
|
} else {
|
||||||
|
quote!(usize)
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
pub fn #field_variant(&self) -> #ret_type {
|
||||||
|
#value as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
|
@ -475,9 +521,15 @@ impl Isa {
|
||||||
let use_match_arms = token_stream!(use_match_arms);
|
let use_match_arms = token_stream!(use_match_arms);
|
||||||
let modifier_match_arms = token_stream!(modifier_match_arms);
|
let modifier_match_arms = token_stream!(modifier_match_arms);
|
||||||
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
|
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
|
||||||
|
let field_accessors = self
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| field.construct_accessor())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let field_accessors = token_stream!(field_accessors);
|
||||||
// Generate final fields function.
|
// Generate final fields function.
|
||||||
let ins_impl = quote! {
|
let ins_impl = quote! {
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all, unused_mut)]
|
||||||
impl Ins {
|
impl Ins {
|
||||||
pub(crate) fn _fields(&self) -> Vec<Field> {
|
pub(crate) fn _fields(&self) -> Vec<Field> {
|
||||||
match self.op {
|
match self.op {
|
||||||
|
@ -486,7 +538,6 @@ impl Isa {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
|
||||||
pub(crate) fn _defs(&self) -> Vec<Field> {
|
pub(crate) fn _defs(&self) -> Vec<Field> {
|
||||||
match self.op {
|
match self.op {
|
||||||
Opcode::Illegal => vec![],
|
Opcode::Illegal => vec![],
|
||||||
|
@ -494,7 +545,6 @@ impl Isa {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
|
||||||
pub(crate) fn _uses(&self) -> Vec<Field> {
|
pub(crate) fn _uses(&self) -> Vec<Field> {
|
||||||
match self.op {
|
match self.op {
|
||||||
Opcode::Illegal => vec![],
|
Opcode::Illegal => vec![],
|
||||||
|
@ -502,7 +552,6 @@ impl Isa {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
|
||||||
pub(crate) fn _modifiers(&self) -> Modifiers {
|
pub(crate) fn _modifiers(&self) -> Modifiers {
|
||||||
match self.op {
|
match self.op {
|
||||||
Opcode::Illegal => Modifiers::default(),
|
Opcode::Illegal => Modifiers::default(),
|
||||||
|
@ -518,14 +567,21 @@ impl Isa {
|
||||||
SimplifiedIns::basic_form(self)
|
SimplifiedIns::basic_form(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::all, non_snake_case)]
|
||||||
|
impl Ins {
|
||||||
|
#field_accessors
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(ins_impl)
|
Ok(ins_impl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the given key into an identifier.
|
/// Converts the given key into an identifier.
|
||||||
fn to_rust_ident(key: &str) -> TokenTree {
|
fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
|
||||||
TokenTree::Ident(Ident::new(&key.replace('.', "_"), Span::call_site()))
|
TokenTree::Ident(Ident::new(
|
||||||
|
&(prefix.to_owned() + &key.replace('.', "_")),
|
||||||
|
Span::call_site(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the given key into an enum variant key.
|
/// Converts the given key into an enum variant key.
|
||||||
|
|
2
isa.yaml
2
isa.yaml
|
@ -22,9 +22,11 @@ fields:
|
||||||
arg: BranchDest
|
arg: BranchDest
|
||||||
bits: 16..30
|
bits: 16..30
|
||||||
shift_left: 2
|
shift_left: 2
|
||||||
|
signed: true
|
||||||
- name: LI
|
- name: LI
|
||||||
arg: BranchDest
|
arg: BranchDest
|
||||||
bits: 6..30
|
bits: 6..30
|
||||||
|
signed: true
|
||||||
shift_left: 2
|
shift_left: 2
|
||||||
# Shift/rotate type fields
|
# Shift/rotate type fields
|
||||||
- name: SH
|
- name: SH
|
||||||
|
|
Loading…
Reference in New Issue