use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub struct FlagsNZCV {
pub n: bool, pub z: bool, pub c: bool, pub v: bool, }
impl FlagsNZCV {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
*self = Self::default();
}
pub fn as_u64(&self) -> u64 {
((self.n as u64) << 31)
| ((self.z as u64) << 30)
| ((self.c as u64) << 29)
| ((self.v as u64) << 28)
}
pub fn from_u64(&mut self, val: u64) {
self.n = (val >> 31) & 1 != 0;
self.z = (val >> 30) & 1 != 0;
self.c = (val >> 29) & 1 != 0;
self.v = (val >> 28) & 1 != 0;
}
pub fn update_add64(&mut self, a: u64, b: u64, result: u64) {
self.n = (result as i64) < 0;
self.z = result == 0;
self.c = result < a; self.v = ((a as i64 ^ result as i64) & (b as i64 ^ result as i64)) < 0;
}
pub fn update_add32(&mut self, a: u32, b: u32, result: u32) {
self.n = (result as i32) < 0;
self.z = result == 0;
self.c = result < a;
self.v = ((a as i32 ^ result as i32) & (b as i32 ^ result as i32)) < 0;
}
pub fn update_sub64(&mut self, a: u64, b: u64, result: u64) {
self.n = (result as i64) < 0;
self.z = result == 0;
self.c = a >= b; self.v = ((a as i64 ^ b as i64) & (a as i64 ^ result as i64)) < 0;
}
pub fn update_sub32(&mut self, a: u32, b: u32, result: u32) {
self.n = (result as i32) < 0;
self.z = result == 0;
self.c = a >= b;
self.v = ((a as i32 ^ b as i32) & (a as i32 ^ result as i32)) < 0;
}
pub fn update_logic64(&mut self, result: u64) {
self.n = (result as i64) < 0;
self.z = result == 0;
self.c = false;
self.v = false;
}
pub fn update_logic32(&mut self, result: u32) {
self.n = (result as i32) < 0;
self.z = result == 0;
self.c = false;
self.v = false;
}
pub fn eval_condition(&self, cond: u8) -> bool {
match cond & 0xf {
0b0000 => self.z, 0b0001 => !self.z, 0b0010 => self.c, 0b0011 => !self.c, 0b0100 => self.n, 0b0101 => !self.n, 0b0110 => self.v, 0b0111 => !self.v, 0b1000 => self.c && !self.z, 0b1001 => !self.c || self.z, 0b1010 => self.n == self.v, 0b1011 => self.n != self.v, 0b1100 => !self.z && (self.n == self.v), 0b1101 => self.z || (self.n != self.v), 0b1110 => true, 0b1111 => true, _ => unreachable!(),
}
}
pub fn diff(a: &FlagsNZCV, b: &FlagsNZCV) -> String {
let mut s = String::new();
if a.n != b.n { s.push_str(&format!("N: {} -> {} ", a.n, b.n)); }
if a.z != b.z { s.push_str(&format!("Z: {} -> {} ", a.z, b.z)); }
if a.c != b.c { s.push_str(&format!("C: {} -> {} ", a.c, b.c)); }
if a.v != b.v { s.push_str(&format!("V: {} -> {} ", a.v, b.v)); }
s
}
}
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct RegsAarch64 {
pub x: [u64; 31],
pub sp: u64,
pub pc: u64,
pub nzcv: FlagsNZCV,
pub tpidr_el0: u64, pub fpcr: u64, pub fpsr: u64,
pub v: [u128; 32],
}
impl RegsAarch64 {
pub fn new() -> Self {
Self {
x: [0u64; 31],
sp: 0,
pc: 0,
nzcv: FlagsNZCV::new(),
tpidr_el0: 0,
fpcr: 0,
fpsr: 0,
v: [0u128; 32],
}
}
pub fn get_x(&self, reg: usize) -> u64 {
if reg == 31 { 0 } else { self.x[reg] }
}
pub fn get_w(&self, reg: usize) -> u32 {
self.get_x(reg) as u32
}
pub fn set_x(&mut self, reg: usize, val: u64) {
if reg < 31 {
self.x[reg] = val;
}
}
pub fn set_w(&mut self, reg: usize, val: u32) {
self.set_x(reg, val as u64);
}
pub fn get_x_or_sp(&self, reg: usize) -> u64 {
if reg == 31 { self.sp } else { self.x[reg] }
}
pub fn set_x_or_sp(&mut self, reg: usize, val: u64) {
if reg == 31 {
self.sp = val;
} else {
self.x[reg] = val;
}
}
pub fn get_by_name(&self, name: &str) -> Option<u64> {
let lower = name.to_lowercase();
if lower == "sp" {
return Some(self.sp);
}
if lower == "pc" {
return Some(self.pc);
}
if lower == "nzcv" {
return Some(self.nzcv.as_u64());
}
if lower == "tpidr_el0" {
return Some(self.tpidr_el0);
}
if lower == "lr" {
return Some(self.x[30]);
}
if lower == "fp" {
return Some(self.x[29]);
}
if let Some(n) = lower.strip_prefix('x') {
if let Ok(i) = n.parse::<usize>() {
if i < 31 {
return Some(self.x[i]);
}
}
}
if let Some(n) = lower.strip_prefix('w') {
if let Ok(i) = n.parse::<usize>() {
if i < 31 {
return Some(self.x[i] & 0xffffffff);
}
}
}
None
}
pub fn set_by_name(&mut self, name: &str, val: u64) -> bool {
let lower = name.to_lowercase();
if lower == "sp" {
self.sp = val;
return true;
}
if lower == "pc" {
self.pc = val;
return true;
}
if lower == "lr" {
self.x[30] = val;
return true;
}
if lower == "fp" {
self.x[29] = val;
return true;
}
if let Some(n) = lower.strip_prefix('x') {
if let Ok(i) = n.parse::<usize>() {
if i < 31 {
self.x[i] = val;
return true;
}
}
}
if let Some(n) = lower.strip_prefix('w') {
if let Ok(i) = n.parse::<usize>() {
if i < 31 {
self.x[i] = val & 0xffffffff;
return true;
}
}
}
false
}
pub fn diff(a: &RegsAarch64, b: &RegsAarch64) -> String {
let mut s = String::new();
for i in 0..31 {
if a.x[i] != b.x[i] {
s.push_str(&format!("x{}: 0x{:x} -> 0x{:x} ", i, a.x[i], b.x[i]));
}
}
if a.sp != b.sp {
s.push_str(&format!("sp: 0x{:x} -> 0x{:x} ", a.sp, b.sp));
}
if a.pc != b.pc {
s.push_str(&format!("pc: 0x{:x} -> 0x{:x} ", a.pc, b.pc));
}
let flags_diff = FlagsNZCV::diff(&a.nzcv, &b.nzcv);
if !flags_diff.is_empty() {
s.push_str(&flags_diff);
}
s
}
}