use crate::register::{Register, Condition};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Operand {
Register(Register),
Immediate(i64),
Label(String),
Memory {
base: Register,
offset: Option<i64>,
index: Option<Register>,
pre_indexed: bool,
post_indexed: bool,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum InstructionType {
ADD,
SUB,
MUL,
MADD,
MSUB,
UDIV,
SDIV,
SMULL,
UMULL,
NEG,
ADC,
SBC,
AND,
ORR,
EOR,
BIC,
ORN,
EON,
MVN,
LSL,
LSR,
ASR,
ROR,
UBFM,
SBFM,
BFM,
BFI,
BFXIL,
UBFX,
SBFX,
REV,
REV16,
REV32,
CLZ,
CLS,
RBIT,
LDR,
LDRB,
LDRH,
LDRSB,
LDRSH,
LDRSW,
LDP,
LDUR,
LDXR,
LDAR,
STR,
STRB,
STRH,
STP,
STUR,
STXR,
STLR,
LDADD,
LDADDAL,
LDCLR,
LDEOR,
LDSET,
SWP,
CAS,
CASAL,
B,
BL,
BR,
BLR,
RET,
BEQ,
BNE,
BCS,
BCC,
BMI,
BPL,
BVS,
BVC,
BHI,
BLS,
BGE,
BLT,
BGT,
BLE,
CBZ,
CBNZ,
TBZ,
TBNZ,
CMP,
CMN,
TST,
MOV,
MOVZ,
MOVK,
MOVN,
NOP,
SVC,
HLT,
BRK,
DMB,
DSB,
ISB,
WFE,
WFI,
YIELD,
MRS,
MSR,
FADD,
FSUB,
FMUL,
FDIV,
FMADD,
FMSUB,
FNEG,
FABS,
FSQRT,
FCMP,
FCMPE,
FCVT,
FCVTZS,
FCVTZU,
SCVTF,
UCVTF,
FMOV,
ADDV,
SMAXV,
SMINV,
UMAXV,
EXT,
ZIP1,
ZIP2,
UZP1,
TRN1,
TBL,
TBX,
LD1,
ST1,
LD2,
ST2,
AESE,
AESD,
AESMC,
AESIMC,
SHA1C,
SHA1H,
SHA1M,
SHA1P,
SHA256H,
SHA256H2,
SHA256SU0,
SHA256SU1,
CRC32B,
CRC32H,
CRC32W,
CRC32X,
CRC32CB,
PACIA,
PACDA,
AUTIA,
AUTDA,
IRG,
GMI,
LDG,
STG,
CSEL,
CSINC,
CSINV,
CSNEG,
CSET,
CSETM,
CINC,
CINV,
CNEG,
CCMP,
CCMN,
UBFIZ,
SBFIZ,
EXTR,
FMLA,
FMLS,
FMIN,
FMAX,
FMINNM,
FMAXNM,
FCVTAS,
FCVTAU,
FCVTMS,
FCVTMU,
FCVTNS,
FCVTNU,
FCVTPS,
FCVTPU,
FRINTA,
FRINTI,
FRINTM,
FRINTN,
FRINTP,
FRINTX,
FRINTZ,
UADDLV,
SADDLV,
UMINV,
INS,
DUP,
UZP2,
TRN2,
CNT,
SQADD,
UQADD,
SQSUB,
UQSUB,
SHL,
SSHR,
USHR,
SXTL,
UXTL,
LDADDH,
LDADDB,
LDADDLH,
LDADDLB,
CASA,
CASB,
CASH,
CASP,
STADD,
STADDL,
STADDB,
STADDH,
LDXRB,
LDXRH,
STXRB,
STXRH,
LDAXRB,
LDAXRH,
STLXRB,
STLXRH,
LDXP,
STXP,
ERET,
DRPS,
ADRP,
ADR,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Instruction {
pub instruction_type: InstructionType,
pub operands: Vec<Operand>,
pub address: u64,
pub encoding: Option<u32>,
pub condition: Option<Condition>,
}
impl Instruction {
pub fn new(
instruction_type: InstructionType,
operands: Vec<Operand>,
address: u64,
) -> Self {
Self {
instruction_type,
operands,
address,
encoding: None,
condition: None,
}
}
pub fn new_with_condition(
instruction_type: InstructionType,
operands: Vec<Operand>,
address: u64,
condition: Condition,
) -> Self {
Self {
instruction_type,
operands,
address,
encoding: None,
condition: Some(condition),
}
}
}
impl std::fmt::Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.instruction_type)?;
for (i, operand) in self.operands.iter().enumerate() {
if i == 0 {
write!(f, " ")?;
} else {
write!(f, ", ")?;
}
write!(f, "{:?}", operand)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_instruction_creation() {
let inst = Instruction::new(
InstructionType::ADD,
vec![
Operand::Register(Register::X0),
Operand::Register(Register::X1),
Operand::Immediate(10),
],
0x1000,
);
assert_eq!(inst.instruction_type, InstructionType::ADD);
assert_eq!(inst.operands.len(), 3);
assert_eq!(inst.address, 0x1000);
}
}