use core::fmt;
use crate::common::{
Instruction as InstructionTrait,
Register as RegisterTrait,
};
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Register(pub u8);
impl Register {
pub const fn new(reg: u8) -> Self {
Self(reg)
}
pub fn value(self) -> u8 {
self.0
}
}
impl RegisterTrait for Register {
fn id(&self) -> u32 {
self.0 as u32
}
fn abi_class(&self) -> crate::common::AbiClass {
use crate::common::AbiClass;
match self.0 {
0..=7 => AbiClass::CallerSaved, 8..=15 => AbiClass::CallerSaved, 16..=17 => AbiClass::CallerSaved, 18 => AbiClass::CallerSaved,
19..=28 => AbiClass::CalleeSaved,
29 => AbiClass::Special, 30 => AbiClass::Special, 31 => AbiClass::Special,
_ => AbiClass::Special,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Instruction(pub u32);
impl Instruction {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn value(self) -> u32 {
self.0
}
pub fn bytes(self) -> Vec<u8> {
self.0.to_le_bytes().to_vec()
}
}
impl InstructionTrait for Instruction {
fn value(&self) -> u64 {
self.0 as u64
}
fn bytes(&self) -> Vec<u8> {
self.0.to_le_bytes().to_vec()
}
fn size(&self) -> usize {
4
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:08x}", self.0)
}
}
pub fn encode_add_sub_reg(sf: u8, op: u8, s: u8, rm: Register, imm6: u8, rn: Register, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) |
((op as u32) << 30) |
((s as u32) << 29) |
(0b01011 << 24) | (0b00 << 22) | (0 << 21) | ((rm.value() as u32) << 16) |
((imm6 as u32) << 10) |
((rn.value() as u32) << 5) |
(rd.value() as u32);
Instruction::new(instr)
}
pub fn encode_add_sub_imm(sf: u8, op: u8, s: u8, sh: u8, imm12: u16, rn: Register, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) |
((op as u32) << 30) |
((s as u32) << 29) |
(0b10001 << 24) | ((sh as u32) << 22) |
((imm12 as u32) << 10) |
((rn.value() as u32) << 5) |
(rd.value() as u32);
Instruction::new(instr)
}
pub fn encode_logical_reg(sf: u8, opc: u8, shift: u8, n: u8, rm: Register, imm6: u8, rn: Register, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) |
((opc as u32) << 29) |
(0b01010 << 24) | ((shift as u32) << 22) |
((n as u32) << 21) |
((rm.value() as u32) << 16) |
((imm6 as u32) << 10) |
((rn.value() as u32) << 5) |
(rd.value() as u32);
Instruction::new(instr)
}
pub fn encode_multiply(sf: u8, op31: u8, rm: Register, o0: u8, ra: Register, rn: Register, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) | (0b00 << 29) | (0b11011 << 24) | ((op31 as u32) << 21) | ((rm.value() as u32) << 16) | ((o0 as u32) << 15) | ((ra.value() as u32) << 10) | ((rn.value() as u32) << 5) | (rd.value() as u32); Instruction::new(instr)
}
pub fn encode_divide(sf: u8, opcode: u8, rm: Register, _o0: u8, rn: Register, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) | (0b0 << 30) | (0b0 << 29) | (0b11010110 << 21) | ((rm.value() as u32) << 16) | ((opcode as u32) << 10) | ((rn.value() as u32) << 5) | (rd.value() as u32); Instruction::new(instr)
}
pub fn encode_move_reg(sf: u8, rm: Register, rd: Register) -> Instruction {
encode_logical_reg(sf, 0b01, 0b00, 0, rm, 0, Register::new(31), rd)
}
pub fn encode_ret(rn: Register) -> Instruction {
let instr = 0xd6000000 | (0x5f << 16) | ((rn.value() as u32) << 5); Instruction::new(instr)
}
pub fn encode_branch_reg(opc: u8, op2: u8, op3: u8, rn: Register, op4: u8) -> Instruction {
let instr = (0b1101011 << 25) |
((opc as u32) << 21) |
((op2 as u32) << 16) |
((op3 as u32) << 10) |
((rn.value() as u32) << 5) |
(op4 as u32);
Instruction::new(instr)
}
pub mod reg {
use super::Register;
pub const X0: Register = Register::new(0);
pub const X1: Register = Register::new(1);
pub const X2: Register = Register::new(2);
pub const X3: Register = Register::new(3);
pub const X4: Register = Register::new(4);
pub const X5: Register = Register::new(5);
pub const X6: Register = Register::new(6);
pub const X7: Register = Register::new(7);
pub const X8: Register = Register::new(8);
pub const X9: Register = Register::new(9);
pub const X10: Register = Register::new(10);
pub const X11: Register = Register::new(11);
pub const X12: Register = Register::new(12);
pub const X13: Register = Register::new(13);
pub const X14: Register = Register::new(14);
pub const X15: Register = Register::new(15);
pub const X16: Register = Register::new(16);
pub const X17: Register = Register::new(17);
pub const X18: Register = Register::new(18);
pub const X19: Register = Register::new(19);
pub const X20: Register = Register::new(20);
pub const X21: Register = Register::new(21);
pub const X22: Register = Register::new(22);
pub const X23: Register = Register::new(23);
pub const X24: Register = Register::new(24);
pub const X25: Register = Register::new(25);
pub const X26: Register = Register::new(26);
pub const X27: Register = Register::new(27);
pub const X28: Register = Register::new(28);
pub const X29: Register = Register::new(29);
pub const X30: Register = Register::new(30);
pub const SP: Register = Register::new(31); pub const XZR: Register = Register::new(31); pub const WZR: Register = Register::new(31);
pub const FP: Register = X29; pub const LR: Register = X30; }
pub fn encode_movz(sf: u8, hw: u8, imm16: u16, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) | (0b10 << 29) | (0b100101 << 23) | ((hw as u32) << 21) | ((imm16 as u32) << 5) | (rd.value() as u32); Instruction::new(instr)
}
pub fn encode_movk(sf: u8, hw: u8, imm16: u16, rd: Register) -> Instruction {
let instr = ((sf as u32) << 31) | (0b11 << 29) | (0b100101 << 23) | ((hw as u32) << 21) | ((imm16 as u32) << 5) | (rd.value() as u32); Instruction::new(instr)
}