Skip to main content

ras/encoder/
arx64.rs

1//! ARX64 binary instruction encoder.
2//!
3//! ARX64 base integer encodings currently track the RISC-style 32-bit formats
4//! implemented by the reference emulator. This encoder keeps ARX register
5//! spelling (`r0`-`r31`) at the assembly surface and delegates bit encoding to
6//! the existing RISC-V format encoder for the shared base subset.
7
8use crate::encoder::riscv::RiscVEncoder;
9use crate::encoder::traits::{InstructionEncoder, ParsedInstruction};
10use crate::error::RasError;
11
12pub struct Arx64Encoder {
13    inner: RiscVEncoder,
14}
15
16impl Arx64Encoder {
17    pub fn new() -> Self {
18        Self {
19            inner: RiscVEncoder::new(true),
20        }
21    }
22
23    fn normalize_operand(operand: &str) -> String {
24        let mut out = operand.to_string();
25        for reg in (0..32).rev() {
26            out = out.replace(&format!("r{}", reg), &format!("x{}", reg));
27            out = out.replace(&format!("%r{}", reg), &format!("x{}", reg));
28        }
29        out
30    }
31
32    fn normalize_instruction(inst: &ParsedInstruction) -> ParsedInstruction {
33        ParsedInstruction {
34            opcode: inst.opcode.clone(),
35            operands: inst
36                .operands
37                .iter()
38                .map(|operand| Self::normalize_operand(operand))
39                .collect(),
40        }
41    }
42}
43
44impl Default for Arx64Encoder {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl InstructionEncoder for Arx64Encoder {
51    fn encode_instruction(&mut self, inst: &ParsedInstruction) -> Result<Vec<u8>, RasError> {
52        let normalized = Self::normalize_instruction(inst);
53        self.inner.encode_instruction(&normalized)
54    }
55
56    fn current_position(&self) -> usize {
57        self.inner.current_position()
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    fn instr(opcode: &str, operands: &[&str]) -> ParsedInstruction {
66        ParsedInstruction {
67            opcode: opcode.to_string(),
68            operands: operands.iter().map(|s| s.to_string()).collect(),
69        }
70    }
71
72    #[test]
73    fn encodes_arx_register_names() {
74        let bytes = Arx64Encoder::new()
75            .encode_instruction(&instr("add", &["r5", "r6", "r7"]))
76            .expect("encode");
77        let word = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
78        assert_eq!((word >> 7) & 0x1f, 5);
79        assert_eq!((word >> 15) & 0x1f, 6);
80        assert_eq!((word >> 20) & 0x1f, 7);
81    }
82
83    #[test]
84    fn encodes_arx_memory_operand_names() {
85        let bytes = Arx64Encoder::new()
86            .encode_instruction(&instr("ld", &["r5", "8(r2)"]))
87            .expect("encode");
88        let word = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
89        assert_eq!(word & 0x7f, 0x03);
90        assert_eq!((word >> 7) & 0x1f, 5);
91        assert_eq!((word >> 15) & 0x1f, 2);
92    }
93}