1use synth_core::Result;
6use synth_core::target::FPUPrecision;
7use synth_synthesis::contracts::encoding as encoding_contracts;
8use synth_synthesis::{ArmOp, MemAddr, MveSize, Operand2, QReg, Reg, VfpReg};
9
10pub struct ArmEncoder {
12 thumb_mode: bool,
14 #[allow(dead_code)]
16 fpu: Option<FPUPrecision>,
17}
18
19impl ArmEncoder {
20 pub fn new_arm32() -> Self {
22 Self {
23 thumb_mode: false,
24 fpu: None,
25 }
26 }
27
28 pub fn new_thumb2() -> Self {
30 Self {
31 thumb_mode: true,
32 fpu: None,
33 }
34 }
35
36 pub fn new_thumb2_with_fpu(fpu: Option<FPUPrecision>) -> Self {
38 Self {
39 thumb_mode: true,
40 fpu,
41 }
42 }
43
44 pub fn encode(&self, op: &ArmOp) -> Result<Vec<u8>> {
46 if self.thumb_mode {
47 self.encode_thumb(op)
48 } else {
49 self.encode_arm(op)
50 }
51 }
52
53 fn encode_arm_reg_offset_mem(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
61 use synth_synthesis::Reg;
62 let addr = match op {
63 ArmOp::Ldr { addr, .. }
64 | ArmOp::Str { addr, .. }
65 | ArmOp::Ldrb { addr, .. }
66 | ArmOp::Strb { addr, .. }
67 | ArmOp::Ldrh { addr, .. }
68 | ArmOp::Strh { addr, .. }
69 | ArmOp::Ldrsb { addr, .. }
70 | ArmOp::Ldrsh { addr, .. } => addr,
71 _ => return Ok(None),
72 };
73 let Some(rm) = addr.offset_reg else {
74 return Ok(None);
75 };
76 let ip = Reg::R12;
77 let add: u32 = 0xE0800000
79 | (reg_to_bits(&addr.base) << 16)
80 | (reg_to_bits(&ip) << 12)
81 | reg_to_bits(&rm);
82 let mut bytes = add.to_le_bytes().to_vec();
83 let imm_addr = MemAddr::imm(ip, addr.offset);
86 let imm_op = match op {
87 ArmOp::Ldr { rd, .. } => ArmOp::Ldr {
88 rd: *rd,
89 addr: imm_addr,
90 },
91 ArmOp::Str { rd, .. } => ArmOp::Str {
92 rd: *rd,
93 addr: imm_addr,
94 },
95 ArmOp::Ldrb { rd, .. } => ArmOp::Ldrb {
96 rd: *rd,
97 addr: imm_addr,
98 },
99 ArmOp::Strb { rd, .. } => ArmOp::Strb {
100 rd: *rd,
101 addr: imm_addr,
102 },
103 ArmOp::Ldrh { rd, .. } => ArmOp::Ldrh {
104 rd: *rd,
105 addr: imm_addr,
106 },
107 ArmOp::Strh { rd, .. } => ArmOp::Strh {
108 rd: *rd,
109 addr: imm_addr,
110 },
111 ArmOp::Ldrsb { rd, .. } => ArmOp::Ldrsb {
112 rd: *rd,
113 addr: imm_addr,
114 },
115 ArmOp::Ldrsh { rd, .. } => ArmOp::Ldrsh {
116 rd: *rd,
117 addr: imm_addr,
118 },
119 _ => unreachable!(),
120 };
121 bytes.extend(self.encode_arm(&imm_op)?);
122 Ok(Some(bytes))
123 }
124
125 fn encode_arm_call_indirect(table_index_reg: &Reg) -> Vec<u8> {
138 let idx = reg_to_bits(table_index_reg);
139 let mut bytes = Vec::with_capacity(12);
140 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
143 bytes.extend_from_slice(&mov.to_le_bytes());
144 let ldr: u32 = 0xE79BC00C;
146 bytes.extend_from_slice(&ldr.to_le_bytes());
147 let blx: u32 = 0xE12FFF3C;
149 bytes.extend_from_slice(&blx.to_le_bytes());
150 bytes
151 }
152
153 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
154 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
161 return Ok(bytes);
162 }
163 if let ArmOp::CallIndirect {
169 table_index_reg, ..
170 } = op
171 {
172 return Ok(Self::encode_arm_call_indirect(table_index_reg));
173 }
174 let instr: u32 = match op {
175 ArmOp::Add { rd, rn, op2 } => {
177 let rd_bits = reg_to_bits(rd);
178 let rn_bits = reg_to_bits(rn);
179 let (op2_bits, i_flag) = encode_operand2(op2)?;
180
181 0xE0800000 | (i_flag << 25)
184 | (rn_bits << 16)
185 | (rd_bits << 12)
186 | op2_bits
187 }
188
189 ArmOp::Sub { rd, rn, op2 } => {
190 let rd_bits = reg_to_bits(rd);
191 let rn_bits = reg_to_bits(rn);
192 let (op2_bits, i_flag) = encode_operand2(op2)?;
193
194 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
196 }
197
198 ArmOp::Adds { rd, rn, op2 } => {
200 let rd_bits = reg_to_bits(rd);
201 let rn_bits = reg_to_bits(rn);
202 let (op2_bits, i_flag) = encode_operand2(op2)?;
203
204 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
206 }
207
208 ArmOp::Adc { rd, rn, op2 } => {
209 let rd_bits = reg_to_bits(rd);
210 let rn_bits = reg_to_bits(rn);
211 let (op2_bits, i_flag) = encode_operand2(op2)?;
212
213 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
215 }
216
217 ArmOp::Subs { rd, rn, op2 } => {
218 let rd_bits = reg_to_bits(rd);
219 let rn_bits = reg_to_bits(rn);
220 let (op2_bits, i_flag) = encode_operand2(op2)?;
221
222 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
224 }
225
226 ArmOp::Sbc { rd, rn, op2 } => {
227 let rd_bits = reg_to_bits(rd);
228 let rn_bits = reg_to_bits(rn);
229 let (op2_bits, i_flag) = encode_operand2(op2)?;
230
231 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
233 }
234
235 ArmOp::Mul { rd, rn, rm } => {
236 let rd_bits = reg_to_bits(rd);
237 let rn_bits = reg_to_bits(rn);
238 let rm_bits = reg_to_bits(rm);
239
240 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
242 }
243
244 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
245 let rdlo_bits = reg_to_bits(rdlo);
246 let rdhi_bits = reg_to_bits(rdhi);
247 let rn_bits = reg_to_bits(rn);
248 let rm_bits = reg_to_bits(rm);
249
250 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
252 }
253
254 ArmOp::Sdiv { rd, rn, rm } => {
255 let rd_bits = reg_to_bits(rd);
256 let rn_bits = reg_to_bits(rn);
257 let rm_bits = reg_to_bits(rm);
258
259 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
262 }
263
264 ArmOp::Udiv { rd, rn, rm } => {
265 let rd_bits = reg_to_bits(rd);
266 let rn_bits = reg_to_bits(rn);
267 let rm_bits = reg_to_bits(rm);
268
269 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
272 }
273
274 ArmOp::Mls { rd, rn, rm, ra } => {
275 let rd_bits = reg_to_bits(rd);
276 let rn_bits = reg_to_bits(rn);
277 let rm_bits = reg_to_bits(rm);
278 let ra_bits = reg_to_bits(ra);
279
280 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
283 }
284
285 ArmOp::Mla { rd, rn, rm, ra } => {
286 let rd_bits = reg_to_bits(rd);
287 let rn_bits = reg_to_bits(rn);
288 let rm_bits = reg_to_bits(rm);
289 let ra_bits = reg_to_bits(ra);
290
291 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
294 }
295
296 ArmOp::And { rd, rn, op2 } => {
297 let rd_bits = reg_to_bits(rd);
298 let rn_bits = reg_to_bits(rn);
299 let (op2_bits, i_flag) = encode_operand2(op2)?;
300
301 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
303 }
304
305 ArmOp::Orr { rd, rn, op2 } => {
306 let rd_bits = reg_to_bits(rd);
307 let rn_bits = reg_to_bits(rn);
308 let (op2_bits, i_flag) = encode_operand2(op2)?;
309
310 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
312 }
313
314 ArmOp::Eor { rd, rn, op2 } => {
315 let rd_bits = reg_to_bits(rd);
316 let rn_bits = reg_to_bits(rn);
317 let (op2_bits, i_flag) = encode_operand2(op2)?;
318
319 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
321 }
322
323 ArmOp::Lsl { rd, rn, shift } => {
325 let rd_bits = reg_to_bits(rd);
326 let rn_bits = reg_to_bits(rn);
327 let shift_bits = *shift & 0x1F;
328
329 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
331 }
332
333 ArmOp::Lsr { rd, rn, shift } => {
334 let rd_bits = reg_to_bits(rd);
335 let rn_bits = reg_to_bits(rn);
336 let shift_bits = *shift & 0x1F;
337
338 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
340 }
341
342 ArmOp::Asr { rd, rn, shift } => {
343 let rd_bits = reg_to_bits(rd);
344 let rn_bits = reg_to_bits(rn);
345 let shift_bits = *shift & 0x1F;
346
347 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
349 }
350
351 ArmOp::Ror { rd, rn, shift } => {
352 let rd_bits = reg_to_bits(rd);
353 let rn_bits = reg_to_bits(rn);
354 let shift_bits = *shift & 0x1F;
355
356 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
358 }
359
360 ArmOp::LslReg { rd, rn, rm } => {
363 let rd_bits = reg_to_bits(rd);
364 let rn_bits = reg_to_bits(rn);
365 let rm_bits = reg_to_bits(rm);
366 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
367 }
368 ArmOp::LsrReg { rd, rn, rm } => {
369 let rd_bits = reg_to_bits(rd);
370 let rn_bits = reg_to_bits(rn);
371 let rm_bits = reg_to_bits(rm);
372 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
373 }
374 ArmOp::AsrReg { rd, rn, rm } => {
375 let rd_bits = reg_to_bits(rd);
376 let rn_bits = reg_to_bits(rn);
377 let rm_bits = reg_to_bits(rm);
378 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
379 }
380 ArmOp::RorReg { rd, rn, rm } => {
381 let rd_bits = reg_to_bits(rd);
382 let rn_bits = reg_to_bits(rn);
383 let rm_bits = reg_to_bits(rm);
384 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
385 }
386
387 ArmOp::Rsb { rd, rn, imm } => {
389 let rd_bits = reg_to_bits(rd);
390 let rn_bits = reg_to_bits(rn);
391 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
394 }
395
396 ArmOp::Clz { rd, rm } => {
398 let rd_bits = reg_to_bits(rd);
399 let rm_bits = reg_to_bits(rm);
400
401 0xE16F0F10 | (rd_bits << 12) | rm_bits
404 }
405
406 ArmOp::Rbit { rd, rm } => {
407 let rd_bits = reg_to_bits(rd);
408 let rm_bits = reg_to_bits(rm);
409
410 0xE6FF0F30 | (rd_bits << 12) | rm_bits
413 }
414
415 ArmOp::Sxtb { rd, rm } => {
416 let rd_bits = reg_to_bits(rd);
417 let rm_bits = reg_to_bits(rm);
418
419 0xE6AF0070 | (rd_bits << 12) | rm_bits
422 }
423
424 ArmOp::Sxth { rd, rm } => {
425 let rd_bits = reg_to_bits(rd);
426 let rm_bits = reg_to_bits(rm);
427
428 0xE6BF0070 | (rd_bits << 12) | rm_bits
431 }
432
433 ArmOp::Uxtb { rd, rm } => {
434 let rd_bits = reg_to_bits(rd);
435 let rm_bits = reg_to_bits(rm);
436 0xE6EF0070 | (rd_bits << 12) | rm_bits
438 }
439
440 ArmOp::Uxth { rd, rm } => {
441 let rd_bits = reg_to_bits(rd);
442 let rm_bits = reg_to_bits(rm);
443 0xE6FF0070 | (rd_bits << 12) | rm_bits
445 }
446
447 ArmOp::Mov { rd, op2 } => {
449 let rd_bits = reg_to_bits(rd);
450 let (op2_bits, i_flag) = encode_operand2(op2)?;
451
452 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
454 }
455
456 ArmOp::Mvn { rd, op2 } => {
457 let rd_bits = reg_to_bits(rd);
458 let (op2_bits, i_flag) = encode_operand2(op2)?;
459
460 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
462 }
463
464 ArmOp::Movw { rd, imm16 } => {
467 let rd_bits = reg_to_bits(rd);
468 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
469 let imm12 = (*imm16 as u32) & 0xFFF;
470 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
471 }
472
473 ArmOp::Movt { rd, imm16 } => {
476 let rd_bits = reg_to_bits(rd);
477 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
478 let imm12 = (*imm16 as u32) & 0xFFF;
479 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
480 }
481
482 ArmOp::MovwSym { rd, addend, .. } => {
485 let rd_bits = reg_to_bits(rd);
486 let v = (*addend as u32) & 0xffff;
487 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
488 }
489 ArmOp::MovtSym { rd, addend, .. } => {
490 let rd_bits = reg_to_bits(rd);
491 let v = ((*addend as u32) >> 16) & 0xffff;
492 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
493 }
494
495 ArmOp::LdrSym { .. } => {
499 return Err(synth_core::Error::synthesis(
500 "LdrSym (literal-pool address load) is Thumb-2-only",
501 ));
502 }
503
504 ArmOp::Cmp { rn, op2 } => {
506 let rn_bits = reg_to_bits(rn);
507 let (op2_bits, i_flag) = encode_operand2(op2)?;
508
509 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
511 }
512
513 ArmOp::Cmn { rn, op2 } => {
515 let rn_bits = reg_to_bits(rn);
516 let (op2_bits, i_flag) = encode_operand2(op2)?;
517
518 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
520 }
521
522 ArmOp::Ldr { rd, addr } => {
524 let rd_bits = reg_to_bits(rd);
525 let (base_bits, offset_bits) = encode_mem_addr(addr);
526
527 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
530 }
531
532 ArmOp::Str { rd, addr } => {
533 let rd_bits = reg_to_bits(rd);
534 let (base_bits, offset_bits) = encode_mem_addr(addr);
535
536 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
538 }
539
540 ArmOp::Ldrb { rd, addr } => {
542 let rd_bits = reg_to_bits(rd);
543 let (base_bits, offset_bits) = encode_mem_addr(addr);
544 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
546 }
547
548 ArmOp::Ldrsb { rd, addr } => {
549 let rd_bits = reg_to_bits(rd);
550 let (base_bits, offset_bits) = encode_mem_addr(addr);
551 let offset_val = offset_bits & 0xFF;
554 let imm4h = (offset_val >> 4) & 0xF;
555 let imm4l = offset_val & 0xF;
556 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
557 }
558
559 ArmOp::Ldrh { rd, addr } => {
560 let rd_bits = reg_to_bits(rd);
561 let (base_bits, offset_bits) = encode_mem_addr(addr);
562 let offset_val = offset_bits & 0xFF;
564 let imm4h = (offset_val >> 4) & 0xF;
565 let imm4l = offset_val & 0xF;
566 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
567 }
568
569 ArmOp::Ldrsh { rd, addr } => {
570 let rd_bits = reg_to_bits(rd);
571 let (base_bits, offset_bits) = encode_mem_addr(addr);
572 let offset_val = offset_bits & 0xFF;
574 let imm4h = (offset_val >> 4) & 0xF;
575 let imm4l = offset_val & 0xF;
576 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
577 }
578
579 ArmOp::Strb { rd, addr } => {
581 let rd_bits = reg_to_bits(rd);
582 let (base_bits, offset_bits) = encode_mem_addr(addr);
583 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
585 }
586
587 ArmOp::Strh { rd, addr } => {
588 let rd_bits = reg_to_bits(rd);
589 let (base_bits, offset_bits) = encode_mem_addr(addr);
590 let offset_val = offset_bits & 0xFF;
592 let imm4h = (offset_val >> 4) & 0xF;
593 let imm4l = offset_val & 0xF;
594 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
595 }
596
597 ArmOp::MemorySize { rd } => {
599 let rd_bits = reg_to_bits(rd);
600 0xE1A00820 | (rd_bits << 12) | 0x0A }
605
606 ArmOp::MemoryGrow { rd, .. } => {
607 let rd_bits = reg_to_bits(rd);
608 0xE3E00000 | (rd_bits << 12) }
611
612 ArmOp::Label { .. } => {
614 return Ok(Vec::new());
615 }
616
617 ArmOp::B { label: _ } => {
619 0xEA000000
622 }
623
624 ArmOp::Bcc { cond, label: _ } => {
626 use synth_synthesis::Condition;
627 let cond_bits: u32 = match cond {
628 Condition::EQ => 0x0,
629 Condition::NE => 0x1,
630 Condition::HS => 0x2,
631 Condition::LO => 0x3,
632 Condition::HI => 0x8,
633 Condition::LS => 0x9,
634 Condition::GE => 0xA,
635 Condition::LT => 0xB,
636 Condition::GT => 0xC,
637 Condition::LE => 0xD,
638 };
639 (cond_bits << 28) | 0x0A000000
641 }
642
643 ArmOp::Bhs { label: _ } => {
645 0x2A000000 }
648
649 ArmOp::Blo { label: _ } => {
651 0x3A000000 }
654
655 ArmOp::BOffset { offset } => {
659 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
669 0xEA000000 | offset_bits
670 }
671
672 ArmOp::BCondOffset { cond, offset } => {
674 use synth_synthesis::Condition;
675 let cond_bits: u32 = match cond {
676 Condition::EQ => 0x0,
677 Condition::NE => 0x1,
678 Condition::HS => 0x2,
679 Condition::LO => 0x3,
680 Condition::HI => 0x8,
681 Condition::LS => 0x9,
682 Condition::GE => 0xA,
683 Condition::LT => 0xB,
684 Condition::GT => 0xC,
685 Condition::LE => 0xD,
686 };
687 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
691 (cond_bits << 28) | 0x0A000000 | offset_bits
692 }
693
694 ArmOp::Bl { label: _ } => {
695 0xEB000000
697 }
698
699 ArmOp::Bx { rm } => {
700 let rm_bits = reg_to_bits(rm);
701
702 0xE12FFF10 | rm_bits
704 }
705
706 ArmOp::Blx { rm } => {
707 let rm_bits = reg_to_bits(rm);
708
709 0xE12FFF30 | rm_bits
711 }
712
713 ArmOp::Push { regs } => {
714 let mut reg_list: u32 = 0;
716 for r in regs {
717 reg_list |= 1 << reg_to_bits(r);
718 }
719 0xE92D0000 | reg_list
720 }
721
722 ArmOp::Pop { regs } => {
723 let mut reg_list: u32 = 0;
725 for r in regs {
726 reg_list |= 1 << reg_to_bits(r);
727 }
728 0xE8BD0000 | reg_list
729 }
730
731 ArmOp::Nop => {
732 0xE1A00000
734 }
735
736 ArmOp::Udf { imm } => {
737 let imm8 = *imm as u32;
740 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
741 }
742
743 ArmOp::Popcnt { .. } => {
746 0xE1A00000 }
750
751 ArmOp::SetCond { .. } => {
752 0xE1A00000 }
756
757 ArmOp::SelectMove { .. } => {
758 0xE1A00000 }
762
763 ArmOp::Select { .. } => {
764 0xE1A00000 }
768
769 ArmOp::LocalGet { .. } => {
770 0xE1A00000 }
774
775 ArmOp::LocalSet { .. } => {
776 0xE1A00000 }
780
781 ArmOp::LocalTee { .. } => {
782 0xE1A00000 }
786
787 ArmOp::GlobalGet { .. } => {
788 0xE1A00000 }
792
793 ArmOp::GlobalSet { .. } => {
794 0xE1A00000 }
798
799 ArmOp::BrTable { .. } => {
800 0xE1A00000 }
804
805 ArmOp::Call { .. } => {
806 0xE1A00000 }
810
811 ArmOp::CallIndirect { .. } => {
815 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
816 }
817
818 ArmOp::I64Add { .. } => 0xE1A00000, ArmOp::I64Sub { .. } => 0xE1A00000, ArmOp::I64DivS { .. } => 0xE1A00000, ArmOp::I64DivU { .. } => 0xE1A00000, ArmOp::I64RemS { .. } => 0xE1A00000, ArmOp::I64RemU { .. } => 0xE1A00000, ArmOp::I64Clz { .. } => 0xE1A00000, ArmOp::I64Ctz { .. } => 0xE1A00000, ArmOp::I64Popcnt { .. } => 0xE1A00000, ArmOp::I64And { .. } => 0xE1A00000, ArmOp::I64Or { .. } => 0xE1A00000, ArmOp::I64Xor { .. } => 0xE1A00000, ArmOp::I64Eqz { .. } => 0xE1A00000, ArmOp::I64Eq { .. } => 0xE1A00000, ArmOp::I64Ne { .. } => 0xE1A00000, ArmOp::I64LtS { .. } => 0xE1A00000, ArmOp::I64LtU { .. } => 0xE1A00000, ArmOp::I64LeS { .. } => 0xE1A00000, ArmOp::I64LeU { .. } => 0xE1A00000, ArmOp::I64GtS { .. } => 0xE1A00000, ArmOp::I64GtU { .. } => 0xE1A00000, ArmOp::I64GeS { .. } => 0xE1A00000, ArmOp::I64GeU { .. } => 0xE1A00000, ArmOp::I64Const { .. } => 0xE1A00000, ArmOp::I64Ldr { .. } => 0xE1A00000, ArmOp::I64Str { .. } => 0xE1A00000, ArmOp::I64ExtendI32S { .. } => 0xE1A00000, ArmOp::I64ExtendI32U { .. } => 0xE1A00000, ArmOp::I64Extend8S { .. } => 0xE1A00000, ArmOp::I64Extend16S { .. } => 0xE1A00000, ArmOp::I64Extend32S { .. } => 0xE1A00000, ArmOp::I32WrapI64 { .. } => 0xE1A00000, ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
855 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
856 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
857 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
858 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
859 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
860 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
861
862 ArmOp::F32Ceil { sd, sm } => {
865 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
867 ArmOp::F32Floor { sd, sm } => {
868 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
870 ArmOp::F32Trunc { sd, sm } => {
871 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
873 ArmOp::F32Nearest { sd, sm } => {
874 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
876 ArmOp::F32Min { sd, sn, sm } => {
877 return self.encode_arm_f32_minmax(sd, sn, sm, true);
878 }
879 ArmOp::F32Max { sd, sn, sm } => {
880 return self.encode_arm_f32_minmax(sd, sn, sm, false);
881 }
882 ArmOp::F32Copysign { sd, sn, sm } => {
883 return self.encode_arm_f32_copysign(sd, sn, sm);
884 }
885
886 ArmOp::F32Eq { rd, sn, sm } => {
888 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
890 ArmOp::F32Ne { rd, sn, sm } => {
891 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
893 ArmOp::F32Lt { rd, sn, sm } => {
894 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
896 ArmOp::F32Le { rd, sn, sm } => {
897 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
899 ArmOp::F32Gt { rd, sn, sm } => {
900 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
902 ArmOp::F32Ge { rd, sn, sm } => {
903 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
905
906 ArmOp::F32Const { sd, value } => {
908 return self.encode_arm_f32_const(sd, *value);
909 }
910
911 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
912 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
913
914 ArmOp::F32ConvertI32S { sd, rm } => {
916 return self.encode_arm_f32_convert_i32(sd, rm, true);
917 }
918 ArmOp::F32ConvertI32U { sd, rm } => {
919 return self.encode_arm_f32_convert_i32(sd, rm, false);
920 }
921 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
922 return Err(synth_core::Error::synthesis(
923 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
924 ));
925 }
926 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
927 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
928 ArmOp::I32TruncF32S { rd, sm } => {
929 return self.encode_arm_i32_trunc_f32(rd, sm, true);
930 }
931 ArmOp::I32TruncF32U { rd, sm } => {
932 return self.encode_arm_i32_trunc_f32(rd, sm, false);
933 }
934
935 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
938 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
939 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
940 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
941 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
942 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
943 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
944
945 ArmOp::F64Ceil { dd, dm } => {
948 return self.encode_arm_f64_rounding(dd, dm, 0b01);
949 }
950 ArmOp::F64Floor { dd, dm } => {
951 return self.encode_arm_f64_rounding(dd, dm, 0b10);
952 }
953 ArmOp::F64Trunc { dd, dm } => {
954 return self.encode_arm_f64_rounding(dd, dm, 0b11);
955 }
956 ArmOp::F64Nearest { dd, dm } => {
957 return self.encode_arm_f64_rounding(dd, dm, 0b00);
958 }
959 ArmOp::F64Min { dd, dn, dm } => {
960 return self.encode_arm_f64_minmax(dd, dn, dm, true);
961 }
962 ArmOp::F64Max { dd, dn, dm } => {
963 return self.encode_arm_f64_minmax(dd, dn, dm, false);
964 }
965 ArmOp::F64Copysign { dd, dn, dm } => {
966 return self.encode_arm_f64_copysign(dd, dn, dm);
967 }
968
969 ArmOp::F64Eq { rd, dn, dm } => {
971 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
972 }
973 ArmOp::F64Ne { rd, dn, dm } => {
974 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
975 }
976 ArmOp::F64Lt { rd, dn, dm } => {
977 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
978 }
979 ArmOp::F64Le { rd, dn, dm } => {
980 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
981 }
982 ArmOp::F64Gt { rd, dn, dm } => {
983 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
984 }
985 ArmOp::F64Ge { rd, dn, dm } => {
986 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
987 }
988
989 ArmOp::F64Const { dd, value } => {
990 return self.encode_arm_f64_const(dd, *value);
991 }
992
993 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
994 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
995
996 ArmOp::F64ConvertI32S { dd, rm } => {
997 return self.encode_arm_f64_convert_i32(dd, rm, true);
998 }
999 ArmOp::F64ConvertI32U { dd, rm } => {
1000 return self.encode_arm_f64_convert_i32(dd, rm, false);
1001 }
1002 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1003 return Err(synth_core::Error::synthesis(
1004 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1005 ));
1006 }
1007 ArmOp::F64PromoteF32 { dd, sm } => {
1008 return self.encode_arm_f64_promote_f32(dd, sm);
1009 }
1010 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1011 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1012 }
1013 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1014 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1015 }
1016 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1017 return Err(synth_core::Error::synthesis(
1018 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
1019 ));
1020 }
1021 ArmOp::I32TruncF64S { rd, dm } => {
1022 return self.encode_arm_i32_trunc_f64(rd, dm, true);
1023 }
1024 ArmOp::I32TruncF64U { rd, dm } => {
1025 return self.encode_arm_i32_trunc_f64(rd, dm, false);
1026 }
1027 ArmOp::I64SetCond { .. }
1029 | ArmOp::I64SetCondZ { .. }
1030 | ArmOp::I64Mul { .. }
1031 | ArmOp::I64Shl { .. }
1032 | ArmOp::I64ShrS { .. }
1033 | ArmOp::I64ShrU { .. }
1034 | ArmOp::I64Rotl { .. }
1035 | ArmOp::I64Rotr { .. } => 0xE1A00000, ArmOp::MveLoad { .. }
1039 | ArmOp::MveStore { .. }
1040 | ArmOp::MveConst { .. }
1041 | ArmOp::MveAnd { .. }
1042 | ArmOp::MveOrr { .. }
1043 | ArmOp::MveEor { .. }
1044 | ArmOp::MveMvn { .. }
1045 | ArmOp::MveBic { .. }
1046 | ArmOp::MveAddI { .. }
1047 | ArmOp::MveSubI { .. }
1048 | ArmOp::MveMulI { .. }
1049 | ArmOp::MveNegI { .. }
1050 | ArmOp::MveCmpEqI { .. }
1051 | ArmOp::MveCmpNeI { .. }
1052 | ArmOp::MveCmpLtS { .. }
1053 | ArmOp::MveCmpLtU { .. }
1054 | ArmOp::MveCmpGtS { .. }
1055 | ArmOp::MveCmpGtU { .. }
1056 | ArmOp::MveCmpLeS { .. }
1057 | ArmOp::MveCmpLeU { .. }
1058 | ArmOp::MveCmpGeS { .. }
1059 | ArmOp::MveCmpGeU { .. }
1060 | ArmOp::MveDup { .. }
1061 | ArmOp::MveExtractLane { .. }
1062 | ArmOp::MveInsertLane { .. }
1063 | ArmOp::MveAddF32 { .. }
1064 | ArmOp::MveSubF32 { .. }
1065 | ArmOp::MveMulF32 { .. }
1066 | ArmOp::MveNegF32 { .. }
1067 | ArmOp::MveAbsF32 { .. }
1068 | ArmOp::MveCmpEqF32 { .. }
1069 | ArmOp::MveCmpNeF32 { .. }
1070 | ArmOp::MveCmpLtF32 { .. }
1071 | ArmOp::MveCmpLeF32 { .. }
1072 | ArmOp::MveCmpGtF32 { .. }
1073 | ArmOp::MveCmpGeF32 { .. }
1074 | ArmOp::MveDupF32 { .. }
1075 | ArmOp::MveExtractLaneF32 { .. }
1076 | ArmOp::MveReplaceLaneF32 { .. }
1077 | ArmOp::MveDivF32 { .. }
1078 | ArmOp::MveSqrtF32 { .. } => 0xE1A00000, };
1080
1081 Ok(instr.to_le_bytes().to_vec())
1083 }
1084
1085 fn encode_arm_f32_compare(
1089 &self,
1090 rd: &Reg,
1091 sn: &VfpReg,
1092 sm: &VfpReg,
1093 cond_code: u32,
1094 ) -> Result<Vec<u8>> {
1095 let mut bytes = Vec::new();
1096
1097 let sn_num = vfp_sreg_to_num(sn)?;
1099 let sm_num = vfp_sreg_to_num(sm)?;
1100 let (vd, d) = encode_sreg(sn_num);
1101 let (vm, m) = encode_sreg(sm_num);
1102 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1103 bytes.extend_from_slice(&vcmp.to_le_bytes());
1104
1105 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1107
1108 let rd_bits = reg_to_bits(rd);
1110 let mov_zero = 0xE3A00000 | (rd_bits << 12);
1111 bytes.extend_from_slice(&mov_zero.to_le_bytes());
1112
1113 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
1115 bytes.extend_from_slice(&mov_one.to_le_bytes());
1116
1117 Ok(bytes)
1118 }
1119
1120 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
1122 let mut bytes = Vec::new();
1123 let bits = value.to_bits();
1124
1125 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
1130 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
1131 bytes.extend_from_slice(&movw.to_le_bytes());
1132
1133 let hi16 = (bits >> 16) & 0xFFFF;
1135 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
1136 bytes.extend_from_slice(&movt.to_le_bytes());
1137
1138 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
1140 bytes.extend_from_slice(&vmov.to_le_bytes());
1141
1142 Ok(bytes)
1143 }
1144
1145 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
1147 let mut bytes = Vec::new();
1148
1149 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
1151 bytes.extend_from_slice(&vmov.to_le_bytes());
1152
1153 let sd_num = vfp_sreg_to_num(sd)?;
1156 let (vd, d) = encode_sreg(sd_num);
1157 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
1159 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
1160 bytes.extend_from_slice(&vcvt.to_le_bytes());
1161
1162 Ok(bytes)
1163 }
1164
1165 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
1177 let mut bytes = Vec::new();
1178 let sm_num = vfp_sreg_to_num(sm)?;
1179 let sd_num = vfp_sreg_to_num(sd)?;
1180 let (vd_s, d_s) = encode_sreg(sd_num);
1181 let (vm_s, m_s) = encode_sreg(sm_num);
1182
1183 if mode == 0b11 {
1184 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
1187 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1188 } else {
1189 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
1194 bytes.extend_from_slice(&vmrs.to_le_bytes());
1195
1196 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
1199 bytes.extend_from_slice(&bic.to_le_bytes());
1200
1201 if mode != 0 {
1203 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
1205 bytes.extend_from_slice(&orr.to_le_bytes());
1206 }
1207
1208 let vmsr = 0xEEE10A10 | (rt << 12);
1210 bytes.extend_from_slice(&vmsr.to_le_bytes());
1211
1212 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
1214 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1215
1216 bytes.extend_from_slice(&vmrs.to_le_bytes());
1218 bytes.extend_from_slice(&bic.to_le_bytes());
1219 bytes.extend_from_slice(&vmsr.to_le_bytes());
1220 }
1221
1222 let (vd2, d2) = encode_sreg(sd_num);
1224 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
1225 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
1226
1227 Ok(bytes)
1228 }
1229
1230 fn encode_arm_f32_minmax(
1232 &self,
1233 sd: &VfpReg,
1234 sn: &VfpReg,
1235 sm: &VfpReg,
1236 is_min: bool,
1237 ) -> Result<Vec<u8>> {
1238 let mut bytes = Vec::new();
1239 let sn_num = vfp_sreg_to_num(sn)?;
1240 let sm_num = vfp_sreg_to_num(sm)?;
1241 let sd_num = vfp_sreg_to_num(sd)?;
1242
1243 let (vd, d) = encode_sreg(sd_num);
1245 let (vn, n) = encode_sreg(sn_num);
1246 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
1247 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
1248
1249 let (vm, m) = encode_sreg(sm_num);
1251 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
1252 bytes.extend_from_slice(&vcmp.to_le_bytes());
1253
1254 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1256
1257 let cond = if is_min { 0xCu32 } else { 0x4u32 };
1260
1261 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1263 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
1264
1265 Ok(bytes)
1266 }
1267
1268 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
1270 let mut bytes = Vec::new();
1271
1272 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
1274 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
1275
1276 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
1278 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
1279
1280 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
1284 bytes.extend_from_slice(&and_sign.to_le_bytes());
1285
1286 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
1289 bytes.extend_from_slice(&bic_sign.to_le_bytes());
1290
1291 let orr = 0xE1800000u32 | 12;
1294 bytes.extend_from_slice(&orr.to_le_bytes());
1295
1296 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
1298 bytes.extend_from_slice(&vmov_result.to_le_bytes());
1299
1300 Ok(bytes)
1301 }
1302
1303 fn encode_arm_f64_compare(
1305 &self,
1306 rd: &Reg,
1307 dn: &VfpReg,
1308 dm: &VfpReg,
1309 cond_code: u32,
1310 ) -> Result<Vec<u8>> {
1311 let mut bytes = Vec::new();
1312
1313 let dn_num = vfp_dreg_to_num(dn)?;
1315 let dm_num = vfp_dreg_to_num(dm)?;
1316 let (vd, d) = encode_dreg(dn_num);
1317 let (vm, m) = encode_dreg(dm_num);
1318 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1319 bytes.extend_from_slice(&vcmp.to_le_bytes());
1320
1321 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1323
1324 let rd_bits = reg_to_bits(rd);
1326 let mov_zero = 0xE3A00000 | (rd_bits << 12);
1327 bytes.extend_from_slice(&mov_zero.to_le_bytes());
1328
1329 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
1331 bytes.extend_from_slice(&mov_one.to_le_bytes());
1332
1333 Ok(bytes)
1334 }
1335
1336 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
1338 let mut bytes = Vec::new();
1339 let bits = value.to_bits();
1340 let lo32 = bits as u32;
1341 let hi32 = (bits >> 32) as u32;
1342
1343 let lo16 = lo32 & 0xFFFF;
1345 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
1346 bytes.extend_from_slice(&movw_r0.to_le_bytes());
1347 let hi16 = (lo32 >> 16) & 0xFFFF;
1348 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
1349 bytes.extend_from_slice(&movt_r0.to_le_bytes());
1350
1351 let lo16 = hi32 & 0xFFFF;
1353 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
1354 bytes.extend_from_slice(&movw_r12.to_le_bytes());
1355 let hi16 = (hi32 >> 16) & 0xFFFF;
1356 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
1357 bytes.extend_from_slice(&movt_r12.to_le_bytes());
1358
1359 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
1361 bytes.extend_from_slice(&vmov.to_le_bytes());
1362
1363 Ok(bytes)
1364 }
1365
1366 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
1368 let mut bytes = Vec::new();
1369
1370 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
1372 bytes.extend_from_slice(&vmov.to_le_bytes());
1373
1374 let dd_num = vfp_dreg_to_num(dd)?;
1377 let (vd, d) = encode_dreg(dd_num);
1378 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
1379 let vcvt = base | (d << 22) | (vd << 12);
1381 bytes.extend_from_slice(&vcvt.to_le_bytes());
1382
1383 Ok(bytes)
1384 }
1385
1386 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
1388 let dd_num = vfp_dreg_to_num(dd)?;
1389 let sm_num = vfp_sreg_to_num(sm)?;
1390 let (vd, d) = encode_dreg(dd_num);
1391 let (vm, m) = encode_sreg(sm_num);
1392
1393 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
1395 Ok(vcvt.to_le_bytes().to_vec())
1396 }
1397
1398 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
1400 let mut bytes = Vec::new();
1401 let dm_num = vfp_dreg_to_num(dm)?;
1402 let (vm, m) = encode_dreg(dm_num);
1403
1404 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
1407 let vcvt = base | (m << 5) | vm;
1408 bytes.extend_from_slice(&vcvt.to_le_bytes());
1409
1410 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
1412 bytes.extend_from_slice(&vmov.to_le_bytes());
1413
1414 Ok(bytes)
1415 }
1416
1417 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
1425 let mut bytes = Vec::new();
1426 let dm_num = vfp_dreg_to_num(dm)?;
1427 let dd_num = vfp_dreg_to_num(dd)?;
1428 let (vm, m) = encode_dreg(dm_num);
1429 let (vd, d) = encode_dreg(dd_num);
1430
1431 if mode == 0b11 {
1432 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
1434 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1435 } else {
1436 let rt: u32 = 12;
1438
1439 let vmrs = 0xEEF10A10 | (rt << 12);
1441 bytes.extend_from_slice(&vmrs.to_le_bytes());
1442
1443 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
1445 bytes.extend_from_slice(&bic.to_le_bytes());
1446
1447 if mode != 0 {
1449 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
1450 bytes.extend_from_slice(&orr.to_le_bytes());
1451 }
1452
1453 let vmsr = 0xEEE10A10 | (rt << 12);
1455 bytes.extend_from_slice(&vmsr.to_le_bytes());
1456
1457 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
1459 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1460
1461 bytes.extend_from_slice(&vmrs.to_le_bytes());
1463 bytes.extend_from_slice(&bic.to_le_bytes());
1464 bytes.extend_from_slice(&vmsr.to_le_bytes());
1465 }
1466
1467 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
1469 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
1470
1471 Ok(bytes)
1472 }
1473
1474 fn encode_arm_f64_minmax(
1476 &self,
1477 dd: &VfpReg,
1478 dn: &VfpReg,
1479 dm: &VfpReg,
1480 is_min: bool,
1481 ) -> Result<Vec<u8>> {
1482 let mut bytes = Vec::new();
1483 let dn_num = vfp_dreg_to_num(dn)?;
1484 let dm_num = vfp_dreg_to_num(dm)?;
1485 let dd_num = vfp_dreg_to_num(dd)?;
1486
1487 let (vd, d) = encode_dreg(dd_num);
1489 let (vn, n) = encode_dreg(dn_num);
1490 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
1491 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
1492
1493 let (vm, m) = encode_dreg(dm_num);
1495 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
1496 bytes.extend_from_slice(&vcmp.to_le_bytes());
1497
1498 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1500
1501 let cond = if is_min { 0xCu32 } else { 0x4u32 };
1502 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1503 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
1504
1505 Ok(bytes)
1506 }
1507
1508 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
1510 let mut bytes = Vec::new();
1511
1512 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
1514 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
1515
1516 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
1519 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
1520
1521 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
1523 bytes.extend_from_slice(&and_sign.to_le_bytes());
1524
1525 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
1527 bytes.extend_from_slice(&bic_sign.to_le_bytes());
1528
1529 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
1531 bytes.extend_from_slice(&orr.to_le_bytes());
1532
1533 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
1535 bytes.extend_from_slice(&vmov_result.to_le_bytes());
1536
1537 Ok(bytes)
1538 }
1539
1540 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
1542 let mut bytes = Vec::new();
1543
1544 let sm_num = vfp_sreg_to_num(sm)?;
1547 let (vd, d) = encode_sreg(sm_num);
1548 let (vm, m) = encode_sreg(sm_num);
1549 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
1550 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
1551 bytes.extend_from_slice(&vcvt.to_le_bytes());
1552
1553 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
1555 bytes.extend_from_slice(&vmov.to_le_bytes());
1556
1557 Ok(bytes)
1558 }
1559
1560 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
1562 match op {
1565 ArmOp::Add { rd, rn, op2 } => {
1567 let rd_bits = reg_to_bits(rd) as u16;
1568 let rn_bits = reg_to_bits(rn) as u16;
1569
1570 if let Operand2::Reg(rm) = op2 {
1571 let rm_bits = reg_to_bits(rm) as u16;
1572 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1580 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1582 Ok(instr.to_le_bytes().to_vec())
1583 } else {
1584 self.encode_thumb32_add_reg_raw(
1586 rd_bits as u32,
1587 rn_bits as u32,
1588 rm_bits as u32,
1589 )
1590 }
1591 } else if let Operand2::Imm(imm) = op2 {
1592 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
1593 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
1595 Ok(instr.to_le_bytes().to_vec())
1596 } else {
1597 self.encode_thumb32_add(rd, rn, *imm as u32)
1599 }
1600 } else {
1601 self.encode_thumb32_add(rd, rn, 0)
1603 }
1604 }
1605
1606 ArmOp::Sub { rd, rn, op2 } => {
1607 let rd_bits = reg_to_bits(rd) as u16;
1608 let rn_bits = reg_to_bits(rn) as u16;
1609
1610 if let Operand2::Reg(rm) = op2 {
1611 let rm_bits = reg_to_bits(rm) as u16;
1612 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1614 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1616 Ok(instr.to_le_bytes().to_vec())
1617 } else {
1618 self.encode_thumb32_sub_reg_raw(
1620 rd_bits as u32,
1621 rn_bits as u32,
1622 rm_bits as u32,
1623 )
1624 }
1625 } else if let Operand2::Imm(imm) = op2 {
1626 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
1627 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
1629 Ok(instr.to_le_bytes().to_vec())
1630 } else {
1631 self.encode_thumb32_sub(rd, rn, *imm as u32)
1632 }
1633 } else {
1634 self.encode_thumb32_sub(rd, rn, 0)
1635 }
1636 }
1637
1638 ArmOp::Mov { rd, op2 } => {
1639 let rd_bits = reg_to_bits(rd) as u16;
1640
1641 if let Operand2::Imm(imm) = op2 {
1642 if *imm <= 255 && rd_bits < 8 {
1643 let imm_bits = (*imm as u16) & 0xFF;
1645 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
1646 Ok(instr.to_le_bytes().to_vec())
1647 } else {
1648 self.encode_thumb32_movw(rd, *imm as u32)
1650 }
1651 } else if let Operand2::Reg(rm) = op2 {
1652 let rm_bits = reg_to_bits(rm) as u16;
1653 let d_bit = (rd_bits >> 3) & 1;
1656 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
1657 Ok(instr.to_le_bytes().to_vec())
1658 } else {
1659 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
1661 }
1662 }
1663
1664 ArmOp::Push { regs } => {
1665 let mut reg_list: u16 = 0;
1669 let mut need_32bit = false;
1670 for r in regs {
1671 let bit = reg_to_bits(r);
1672 if bit >= 8 && *r != Reg::LR {
1673 need_32bit = true;
1674 }
1675 reg_list |= 1 << bit;
1676 }
1677 if !need_32bit {
1678 let m_bit = if reg_list & (1 << 14) != 0 {
1680 1u16
1681 } else {
1682 0u16
1683 };
1684 let low_regs = reg_list & 0xFF;
1685 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
1686 Ok(instr.to_le_bytes().to_vec())
1687 } else {
1688 let hw1: u16 = 0xE92D;
1690 let hw2: u16 = reg_list;
1691 let mut bytes = hw1.to_le_bytes().to_vec();
1692 bytes.extend_from_slice(&hw2.to_le_bytes());
1693 Ok(bytes)
1694 }
1695 }
1696
1697 ArmOp::Pop { regs } => {
1698 let mut reg_list: u16 = 0;
1702 let mut need_32bit = false;
1703 for r in regs {
1704 let bit = reg_to_bits(r);
1705 if bit >= 8 && *r != Reg::PC {
1706 need_32bit = true;
1707 }
1708 reg_list |= 1 << bit;
1709 }
1710 if !need_32bit {
1711 let p_bit = if reg_list & (1 << 15) != 0 {
1713 1u16
1714 } else {
1715 0u16
1716 };
1717 let low_regs = reg_list & 0xFF;
1718 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
1719 Ok(instr.to_le_bytes().to_vec())
1720 } else {
1721 let hw1: u16 = 0xE8BD;
1723 let hw2: u16 = reg_list;
1724 let mut bytes = hw1.to_le_bytes().to_vec();
1725 bytes.extend_from_slice(&hw2.to_le_bytes());
1726 Ok(bytes)
1727 }
1728 }
1729
1730 ArmOp::Nop => {
1731 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
1733 }
1734
1735 ArmOp::Udf { imm } => {
1736 let instr: u16 = 0xDE00 | (*imm as u16);
1739 let bytes = instr.to_le_bytes().to_vec();
1740 encoding_contracts::verify_thumb16(&bytes);
1741 Ok(bytes)
1742 }
1743
1744 ArmOp::Adds { rd, rn, op2 } => {
1747 let rd_bits = reg_to_bits(rd) as u16;
1748 let rn_bits = reg_to_bits(rn) as u16;
1749
1750 if let Operand2::Reg(rm) = op2 {
1751 let rm_bits = reg_to_bits(rm) as u16;
1752 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1757 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1759 Ok(instr.to_le_bytes().to_vec())
1760 } else {
1761 self.encode_thumb32_adds_reg_raw(
1762 rd_bits as u32,
1763 rn_bits as u32,
1764 rm_bits as u32,
1765 )
1766 }
1767 } else {
1768 self.encode_thumb32_adds(rd, rn, 0)
1770 }
1771 }
1772
1773 ArmOp::Adc { rd, rn, op2 } => {
1776 let rd_bits = reg_to_bits(rd);
1777 let rn_bits = reg_to_bits(rn);
1778
1779 if let Operand2::Reg(rm) = op2 {
1780 let rm_bits = reg_to_bits(rm);
1781 let hw1: u16 = (0xEB40 | rn_bits) as u16;
1783 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1784
1785 let mut bytes = hw1.to_le_bytes().to_vec();
1786 bytes.extend_from_slice(&hw2.to_le_bytes());
1787 Ok(bytes)
1788 } else {
1789 let hw1: u16 = (0xF140 | rn_bits) as u16;
1791 let hw2: u16 = (rd_bits << 8) as u16;
1792 let mut bytes = hw1.to_le_bytes().to_vec();
1793 bytes.extend_from_slice(&hw2.to_le_bytes());
1794 Ok(bytes)
1795 }
1796 }
1797
1798 ArmOp::Subs { rd, rn, op2 } => {
1800 let rd_bits = reg_to_bits(rd) as u16;
1801 let rn_bits = reg_to_bits(rn) as u16;
1802
1803 if let Operand2::Reg(rm) = op2 {
1804 let rm_bits = reg_to_bits(rm) as u16;
1805 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1809 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1811 Ok(instr.to_le_bytes().to_vec())
1812 } else {
1813 self.encode_thumb32_subs_reg_raw(
1814 rd_bits as u32,
1815 rn_bits as u32,
1816 rm_bits as u32,
1817 )
1818 }
1819 } else {
1820 self.encode_thumb32_subs(rd, rn, 0)
1822 }
1823 }
1824
1825 ArmOp::Sbc { rd, rn, op2 } => {
1828 let rd_bits = reg_to_bits(rd);
1829 let rn_bits = reg_to_bits(rn);
1830
1831 if let Operand2::Reg(rm) = op2 {
1832 let rm_bits = reg_to_bits(rm);
1833 let hw1: u16 = (0xEB60 | rn_bits) as u16;
1835 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1836
1837 let mut bytes = hw1.to_le_bytes().to_vec();
1838 bytes.extend_from_slice(&hw2.to_le_bytes());
1839 Ok(bytes)
1840 } else {
1841 let hw1: u16 = (0xF160 | rn_bits) as u16;
1843 let hw2: u16 = (rd_bits << 8) as u16;
1844 let mut bytes = hw1.to_le_bytes().to_vec();
1845 bytes.extend_from_slice(&hw2.to_le_bytes());
1846 Ok(bytes)
1847 }
1848 }
1849
1850 ArmOp::Sdiv { rd, rn, rm } => {
1854 let rd_bits = reg_to_bits(rd);
1855 let rn_bits = reg_to_bits(rn);
1856 let rm_bits = reg_to_bits(rm);
1857 reg_bits_checked(rd_bits)?;
1858 reg_bits_checked(rn_bits)?;
1859 reg_bits_checked(rm_bits)?;
1860
1861 let hw1: u16 = (0xFB90 | rn_bits) as u16;
1865 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
1866
1867 let mut bytes = hw1.to_le_bytes().to_vec();
1869 bytes.extend_from_slice(&hw2.to_le_bytes());
1870 encoding_contracts::verify_thumb32(&bytes);
1871 Ok(bytes)
1872 }
1873
1874 ArmOp::Udiv { rd, rn, rm } => {
1876 let rd_bits = reg_to_bits(rd);
1877 let rn_bits = reg_to_bits(rn);
1878 let rm_bits = reg_to_bits(rm);
1879 reg_bits_checked(rd_bits)?;
1880 reg_bits_checked(rn_bits)?;
1881 reg_bits_checked(rm_bits)?;
1882
1883 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
1885 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
1886
1887 let mut bytes = hw1.to_le_bytes().to_vec();
1888 bytes.extend_from_slice(&hw2.to_le_bytes());
1889 encoding_contracts::verify_thumb32(&bytes);
1890 Ok(bytes)
1891 }
1892
1893 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1894 let rdlo_bits = reg_to_bits(rdlo);
1895 let rdhi_bits = reg_to_bits(rdhi);
1896 let rn_bits = reg_to_bits(rn);
1897 let rm_bits = reg_to_bits(rm);
1898 reg_bits_checked(rdlo_bits)?;
1899 reg_bits_checked(rdhi_bits)?;
1900 reg_bits_checked(rn_bits)?;
1901 reg_bits_checked(rm_bits)?;
1902
1903 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
1905 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
1906
1907 let mut bytes = hw1.to_le_bytes().to_vec();
1908 bytes.extend_from_slice(&hw2.to_le_bytes());
1909 encoding_contracts::verify_thumb32(&bytes);
1910 Ok(bytes)
1911 }
1912
1913 ArmOp::Mul { rd, rn, rm } => {
1915 let rd_bits = reg_to_bits(rd);
1916 let rn_bits = reg_to_bits(rn);
1917 let rm_bits = reg_to_bits(rm);
1918
1919 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1922 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
1923
1924 let mut bytes = hw1.to_le_bytes().to_vec();
1925 bytes.extend_from_slice(&hw2.to_le_bytes());
1926 Ok(bytes)
1927 }
1928
1929 ArmOp::Mls { rd, rn, rm, ra } => {
1931 let rd_bits = reg_to_bits(rd);
1932 let rn_bits = reg_to_bits(rn);
1933 let rm_bits = reg_to_bits(rm);
1934 let ra_bits = reg_to_bits(ra);
1935
1936 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1939 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
1940
1941 let mut bytes = hw1.to_le_bytes().to_vec();
1942 bytes.extend_from_slice(&hw2.to_le_bytes());
1943 Ok(bytes)
1944 }
1945
1946 ArmOp::Mla { rd, rn, rm, ra } => {
1947 let rd_bits = reg_to_bits(rd);
1948 let rn_bits = reg_to_bits(rn);
1949 let rm_bits = reg_to_bits(rm);
1950 let ra_bits = reg_to_bits(ra);
1951
1952 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1955 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
1956
1957 let mut bytes = hw1.to_le_bytes().to_vec();
1958 bytes.extend_from_slice(&hw2.to_le_bytes());
1959 Ok(bytes)
1960 }
1961
1962 ArmOp::And { rd, rn, op2 } => {
1964 if let Operand2::Reg(rm) = op2 {
1965 let rd_bits = reg_to_bits(rd);
1966 let rn_bits = reg_to_bits(rn);
1967 let rm_bits = reg_to_bits(rm);
1968
1969 let hw1: u16 = (0xEA00 | rn_bits) as u16;
1971 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1972
1973 let mut bytes = hw1.to_le_bytes().to_vec();
1974 bytes.extend_from_slice(&hw2.to_le_bytes());
1975 Ok(bytes)
1976 } else if let Operand2::Imm(imm) = op2 {
1977 let rd_bits = reg_to_bits(rd);
1978 let rn_bits = reg_to_bits(rn);
1979
1980 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
1987 synth_core::Error::synthesis(
1988 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
1989 )
1990 })?;
1991 let i_bit = (field >> 11) & 1;
1992 let imm3 = (field >> 8) & 0x7;
1993 let imm8 = field & 0xFF;
1994
1995 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
1996 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
1997
1998 let mut bytes = hw1.to_le_bytes().to_vec();
1999 bytes.extend_from_slice(&hw2.to_le_bytes());
2000 Ok(bytes)
2001 } else {
2002 let instr: u16 = 0xBF00;
2004 Ok(instr.to_le_bytes().to_vec())
2005 }
2006 }
2007
2008 ArmOp::Orr { rd, rn, op2 } => {
2010 if let Operand2::Reg(rm) = op2 {
2011 let rd_bits = reg_to_bits(rd);
2012 let rn_bits = reg_to_bits(rn);
2013 let rm_bits = reg_to_bits(rm);
2014
2015 let hw1: u16 = (0xEA40 | rn_bits) as u16;
2017 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2018
2019 let mut bytes = hw1.to_le_bytes().to_vec();
2020 bytes.extend_from_slice(&hw2.to_le_bytes());
2021 Ok(bytes)
2022 } else if let Operand2::Imm(imm) = op2 {
2023 let imm_val = *imm as u32;
2028 if imm_val > 0xFF {
2029 return Err(synth_core::Error::synthesis(
2030 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2031 ));
2032 }
2033 let rd_bits = reg_to_bits(rd);
2034 let rn_bits = reg_to_bits(rn);
2035 let hw1: u16 = (0xF040 | rn_bits) as u16;
2036 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2037 let mut bytes = hw1.to_le_bytes().to_vec();
2038 bytes.extend_from_slice(&hw2.to_le_bytes());
2039 Ok(bytes)
2040 } else {
2041 let instr: u16 = 0xBF00;
2042 Ok(instr.to_le_bytes().to_vec())
2043 }
2044 }
2045
2046 ArmOp::Eor { rd, rn, op2 } => {
2048 if let Operand2::Reg(rm) = op2 {
2049 let rd_bits = reg_to_bits(rd);
2050 let rn_bits = reg_to_bits(rn);
2051 let rm_bits = reg_to_bits(rm);
2052
2053 let hw1: u16 = (0xEA80 | rn_bits) as u16;
2055 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2056
2057 let mut bytes = hw1.to_le_bytes().to_vec();
2058 bytes.extend_from_slice(&hw2.to_le_bytes());
2059 Ok(bytes)
2060 } else if let Operand2::Imm(imm) = op2 {
2061 let imm_val = *imm as u32;
2065 if imm_val > 0xFF {
2066 return Err(synth_core::Error::synthesis(
2067 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2068 ));
2069 }
2070 let rd_bits = reg_to_bits(rd);
2071 let rn_bits = reg_to_bits(rn);
2072 let hw1: u16 = (0xF080 | rn_bits) as u16;
2073 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2074 let mut bytes = hw1.to_le_bytes().to_vec();
2075 bytes.extend_from_slice(&hw2.to_le_bytes());
2076 Ok(bytes)
2077 } else {
2078 let instr: u16 = 0xBF00;
2079 Ok(instr.to_le_bytes().to_vec())
2080 }
2081 }
2082
2083 ArmOp::Lsl { rd, rn, shift } => {
2085 let rd_bits = reg_to_bits(rd) as u16;
2086 let rn_bits = reg_to_bits(rn) as u16;
2087 let shift_bits = (*shift as u16) & 0x1F;
2088
2089 if rd_bits < 8 && rn_bits < 8 {
2090 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2092 Ok(instr.to_le_bytes().to_vec())
2093 } else {
2094 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
2097 }
2098
2099 ArmOp::Lsr { rd, rn, shift } => {
2100 let rd_bits = reg_to_bits(rd) as u16;
2101 let rn_bits = reg_to_bits(rn) as u16;
2102 let shift_bits = (*shift as u16) & 0x1F;
2103
2104 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
2105 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2107 Ok(instr.to_le_bytes().to_vec())
2108 } else {
2109 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
2111 }
2112
2113 ArmOp::Asr { rd, rn, shift } => {
2114 let rd_bits = reg_to_bits(rd) as u16;
2115 let rn_bits = reg_to_bits(rn) as u16;
2116 let shift_bits = (*shift as u16) & 0x1F;
2117
2118 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
2119 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2121 Ok(instr.to_le_bytes().to_vec())
2122 } else {
2123 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
2125 }
2126
2127 ArmOp::Ror { rd, rn, shift } => {
2128 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
2131
2132 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
2136 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
2137 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
2138 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
2139
2140 ArmOp::Rsb { rd, rn, imm } => {
2143 let rd_bits = reg_to_bits(rd);
2144 let rn_bits = reg_to_bits(rn);
2145 let imm_val = *imm;
2146
2147 let i_bit = (imm_val >> 11) & 1;
2148 let imm3 = (imm_val >> 8) & 0x7;
2149 let imm8 = imm_val & 0xFF;
2150
2151 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
2153 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
2155
2156 let mut bytes = hw1.to_le_bytes().to_vec();
2157 bytes.extend_from_slice(&hw2.to_le_bytes());
2158 Ok(bytes)
2159 }
2160
2161 ArmOp::Clz { rd, rm } => {
2163 let rd_bits = reg_to_bits(rd);
2164 let rm_bits = reg_to_bits(rm);
2165
2166 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
2169 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
2170
2171 let mut bytes = hw1.to_le_bytes().to_vec();
2172 bytes.extend_from_slice(&hw2.to_le_bytes());
2173 Ok(bytes)
2174 }
2175
2176 ArmOp::Rbit { rd, rm } => {
2178 let rd_bits = reg_to_bits(rd);
2179 let rm_bits = reg_to_bits(rm);
2180
2181 let hw1: u16 = (0xFA90 | rm_bits) as u16;
2184 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
2185
2186 let mut bytes = hw1.to_le_bytes().to_vec();
2187 bytes.extend_from_slice(&hw2.to_le_bytes());
2188 Ok(bytes)
2189 }
2190
2191 ArmOp::Sxtb { rd, rm } => {
2193 let rd_bits = reg_to_bits(rd) as u16;
2194 let rm_bits = reg_to_bits(rm) as u16;
2195
2196 if rd_bits < 8 && rm_bits < 8 {
2197 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
2199 Ok(instr.to_le_bytes().to_vec())
2200 } else {
2201 let rd_bits32 = rd_bits as u32;
2204 let rm_bits32 = rm_bits as u32;
2205 let hw1: u16 = 0xFA4F;
2206 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
2207 let mut bytes = hw1.to_le_bytes().to_vec();
2208 bytes.extend_from_slice(&hw2.to_le_bytes());
2209 Ok(bytes)
2210 }
2211 }
2212
2213 ArmOp::Sxth { rd, rm } => {
2215 let rd_bits = reg_to_bits(rd) as u16;
2216 let rm_bits = reg_to_bits(rm) as u16;
2217
2218 if rd_bits < 8 && rm_bits < 8 {
2219 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
2221 Ok(instr.to_le_bytes().to_vec())
2222 } else {
2223 let rd_bits32 = rd_bits as u32;
2226 let rm_bits32 = rm_bits as u32;
2227 let hw1: u16 = 0xFA0F;
2228 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
2229 let mut bytes = hw1.to_le_bytes().to_vec();
2230 bytes.extend_from_slice(&hw2.to_le_bytes());
2231 Ok(bytes)
2232 }
2233 }
2234
2235 ArmOp::Uxtb { rd, rm } => {
2237 let rd_bits = reg_to_bits(rd) as u16;
2238 let rm_bits = reg_to_bits(rm) as u16;
2239 if rd_bits < 8 && rm_bits < 8 {
2240 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
2242 Ok(instr.to_le_bytes().to_vec())
2243 } else {
2244 let hw1: u16 = 0xFA5F;
2246 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
2247 let mut bytes = hw1.to_le_bytes().to_vec();
2248 bytes.extend_from_slice(&hw2.to_le_bytes());
2249 Ok(bytes)
2250 }
2251 }
2252
2253 ArmOp::Uxth { rd, rm } => {
2255 let rd_bits = reg_to_bits(rd) as u16;
2256 let rm_bits = reg_to_bits(rm) as u16;
2257 if rd_bits < 8 && rm_bits < 8 {
2258 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
2260 Ok(instr.to_le_bytes().to_vec())
2261 } else {
2262 let hw1: u16 = 0xFA1F;
2264 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
2265 let mut bytes = hw1.to_le_bytes().to_vec();
2266 bytes.extend_from_slice(&hw2.to_le_bytes());
2267 Ok(bytes)
2268 }
2269 }
2270
2271 ArmOp::Cmp { rn, op2 } => {
2273 let rn_bits = reg_to_bits(rn) as u16;
2274
2275 if let Operand2::Imm(imm) = op2 {
2276 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
2279 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
2281 Ok(instr.to_le_bytes().to_vec())
2282 } else {
2283 self.encode_thumb32_cmp_imm(rn, *imm as u32)
2284 }
2285 } else if let Operand2::Reg(rm) = op2 {
2286 let rm_bits = reg_to_bits(rm) as u16;
2287 if rn_bits < 8 && rm_bits < 8 {
2288 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
2290 Ok(instr.to_le_bytes().to_vec())
2291 } else {
2292 let n_bit = (rn_bits >> 3) & 1;
2294 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
2295 Ok(instr.to_le_bytes().to_vec())
2296 }
2297 } else {
2298 let instr: u16 = 0xBF00;
2299 Ok(instr.to_le_bytes().to_vec())
2300 }
2301 }
2302
2303 ArmOp::Cmn { rn, op2 } => {
2306 let rn_bits = reg_to_bits(rn) as u16;
2307
2308 if let Operand2::Imm(imm) = op2 {
2309 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2315 synth_core::Error::synthesis(
2316 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
2317 )
2318 })?;
2319 let i_bit = (field >> 11) & 1;
2320 let imm3 = (field >> 8) & 0x7;
2321 let imm8 = field & 0xFF;
2322 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
2323 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
2324 let mut bytes = hw1.to_le_bytes().to_vec();
2325 bytes.extend_from_slice(&hw2.to_le_bytes());
2326 Ok(bytes)
2327 } else if let Operand2::Reg(rm) = op2 {
2328 let rm_bits = reg_to_bits(rm) as u16;
2329 if rn_bits < 8 && rm_bits < 8 {
2335 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
2337 Ok(instr.to_le_bytes().to_vec())
2338 } else {
2339 let hw1: u16 = 0xEB10 | rn_bits;
2340 let hw2: u16 = 0x0F00 | rm_bits;
2341 let mut bytes = hw1.to_le_bytes().to_vec();
2342 bytes.extend_from_slice(&hw2.to_le_bytes());
2343 Ok(bytes)
2344 }
2345 } else {
2346 Ok(vec![0xBF, 0x00])
2347 }
2348 }
2349
2350 ArmOp::Ldr { rd, addr } => {
2352 let rd_bits = reg_to_bits(rd);
2353 let base_bits = reg_to_bits(&addr.base);
2354
2355 if let Some(offset_reg) = &addr.offset_reg {
2357 let rm_bits = reg_to_bits(offset_reg);
2358
2359 if addr.offset != 0 {
2361 let scratch = Reg::R12;
2364 let mut bytes =
2365 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2366 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
2367 return Ok(bytes);
2368 }
2369
2370 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
2373 let instr: u16 = 0x5800
2375 | ((rm_bits as u16) << 6)
2376 | ((base_bits as u16) << 3)
2377 | (rd_bits as u16);
2378 return Ok(instr.to_le_bytes().to_vec());
2379 }
2380
2381 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
2383 }
2384
2385 let offset = addr.offset as u32;
2387
2388 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
2389 let imm5 = (offset >> 2) as u16;
2391 let instr: u16 =
2392 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2393 Ok(instr.to_le_bytes().to_vec())
2394 } else {
2395 self.encode_thumb32_ldr(rd, &addr.base, offset)
2396 }
2397 }
2398
2399 ArmOp::Str { rd, addr } => {
2401 let rd_bits = reg_to_bits(rd);
2402 let base_bits = reg_to_bits(&addr.base);
2403
2404 if let Some(offset_reg) = &addr.offset_reg {
2406 let rm_bits = reg_to_bits(offset_reg);
2407
2408 if addr.offset != 0 {
2410 let scratch = Reg::R12;
2413 let mut bytes =
2414 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2415 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
2416 return Ok(bytes);
2417 }
2418
2419 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
2422 let instr: u16 = 0x5000
2424 | ((rm_bits as u16) << 6)
2425 | ((base_bits as u16) << 3)
2426 | (rd_bits as u16);
2427 return Ok(instr.to_le_bytes().to_vec());
2428 }
2429
2430 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
2432 }
2433
2434 let offset = addr.offset as u32;
2436
2437 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
2438 let imm5 = (offset >> 2) as u16;
2440 let instr: u16 =
2441 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2442 Ok(instr.to_le_bytes().to_vec())
2443 } else {
2444 self.encode_thumb32_str(rd, &addr.base, offset)
2445 }
2446 }
2447
2448 ArmOp::Ldrb { rd, addr } => {
2450 let rd_bits = reg_to_bits(rd);
2451 let base_bits = reg_to_bits(&addr.base);
2452
2453 if let Some(offset_reg) = &addr.offset_reg {
2454 if addr.offset != 0 {
2455 let scratch = Reg::R12;
2456 let mut bytes =
2457 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2458 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
2459 return Ok(bytes);
2460 }
2461 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
2462 }
2463
2464 let offset = addr.offset as u32;
2465 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
2466 let instr: u16 = 0x7800
2468 | ((offset as u16) << 6)
2469 | ((base_bits as u16) << 3)
2470 | (rd_bits as u16);
2471 Ok(instr.to_le_bytes().to_vec())
2472 } else {
2473 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
2474 }
2475 }
2476
2477 ArmOp::Ldrsb { rd, addr } => {
2479 let rd_bits = reg_to_bits(rd);
2480 let base_bits = reg_to_bits(&addr.base);
2481
2482 if let Some(offset_reg) = &addr.offset_reg {
2483 if addr.offset != 0 {
2484 let scratch = Reg::R12;
2485 let mut bytes =
2486 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2487 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
2488 return Ok(bytes);
2489 }
2490 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
2491 }
2492
2493 let offset = addr.offset as u32;
2494 if rd_bits < 8 && base_bits < 8 && offset == 0 {
2497 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
2499 } else {
2500 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
2501 }
2502 }
2503
2504 ArmOp::Ldrh { rd, addr } => {
2506 let rd_bits = reg_to_bits(rd);
2507 let base_bits = reg_to_bits(&addr.base);
2508
2509 if let Some(offset_reg) = &addr.offset_reg {
2510 if addr.offset != 0 {
2511 let scratch = Reg::R12;
2512 let mut bytes =
2513 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2514 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
2515 return Ok(bytes);
2516 }
2517 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
2518 }
2519
2520 let offset = addr.offset as u32;
2521 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
2522 let imm5 = (offset >> 1) as u16;
2524 let instr: u16 =
2525 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2526 Ok(instr.to_le_bytes().to_vec())
2527 } else {
2528 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
2529 }
2530 }
2531
2532 ArmOp::Ldrsh { rd, addr } => {
2534 if let Some(offset_reg) = &addr.offset_reg {
2535 if addr.offset != 0 {
2536 let scratch = Reg::R12;
2537 let mut bytes =
2538 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2539 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
2540 return Ok(bytes);
2541 }
2542 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
2543 }
2544
2545 let offset = addr.offset as u32;
2546 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
2547 }
2548
2549 ArmOp::Strb { rd, addr } => {
2551 let rd_bits = reg_to_bits(rd);
2552 let base_bits = reg_to_bits(&addr.base);
2553
2554 if let Some(offset_reg) = &addr.offset_reg {
2555 if addr.offset != 0 {
2556 let scratch = Reg::R12;
2557 let mut bytes =
2558 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2559 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
2560 return Ok(bytes);
2561 }
2562 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
2563 }
2564
2565 let offset = addr.offset as u32;
2566 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
2567 let instr: u16 = 0x7000
2569 | ((offset as u16) << 6)
2570 | ((base_bits as u16) << 3)
2571 | (rd_bits as u16);
2572 Ok(instr.to_le_bytes().to_vec())
2573 } else {
2574 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
2575 }
2576 }
2577
2578 ArmOp::Strh { rd, addr } => {
2580 let rd_bits = reg_to_bits(rd);
2581 let base_bits = reg_to_bits(&addr.base);
2582
2583 if let Some(offset_reg) = &addr.offset_reg {
2584 if addr.offset != 0 {
2585 let scratch = Reg::R12;
2586 let mut bytes =
2587 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2588 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
2589 return Ok(bytes);
2590 }
2591 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
2592 }
2593
2594 let offset = addr.offset as u32;
2595 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
2596 let imm5 = (offset >> 1) as u16;
2598 let instr: u16 =
2599 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2600 Ok(instr.to_le_bytes().to_vec())
2601 } else {
2602 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
2603 }
2604 }
2605
2606 ArmOp::MemorySize { rd } => {
2608 let rd_bits = reg_to_bits(rd);
2611 let r10_bits = reg_to_bits(&Reg::R10);
2612 if rd_bits < 8 && r10_bits < 8 {
2613 let instr: u16 =
2614 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
2615 Ok(instr.to_le_bytes().to_vec())
2616 } else {
2617 let imm5: u32 = 16;
2619 let imm3 = (imm5 >> 2) & 0x7;
2620 let imm2 = imm5 & 0x3;
2621 let hw1: u16 = 0xEA4F;
2622 let hw2: u16 =
2623 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
2624 let mut bytes = hw1.to_le_bytes().to_vec();
2625 bytes.extend_from_slice(&hw2.to_le_bytes());
2626 Ok(bytes)
2627 }
2628 }
2629
2630 ArmOp::MemoryGrow { rd, .. } => {
2632 let rd_bits = reg_to_bits(rd);
2636 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
2639 bytes.extend_from_slice(&hw2.to_le_bytes());
2640 Ok(bytes)
2641 }
2642
2643 ArmOp::Bx { rm } => {
2645 let rm_bits = reg_to_bits(rm) as u16;
2646 let instr: u16 = 0x4700 | (rm_bits << 3);
2648 Ok(instr.to_le_bytes().to_vec())
2649 }
2650
2651 ArmOp::Blx { rm } => {
2654 let rm_bits = reg_to_bits(rm) as u16;
2655 let instr: u16 = 0x4780 | (rm_bits << 3);
2656 Ok(instr.to_le_bytes().to_vec())
2657 }
2658
2659 ArmOp::CallIndirect {
2663 rd: _,
2664 type_idx: _,
2665 table_index_reg,
2666 } => {
2667 let idx_reg = reg_to_bits(table_index_reg);
2668 let mut bytes = Vec::new();
2669
2670 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
2690 bytes.extend_from_slice(&hw1.to_le_bytes());
2691 bytes.extend_from_slice(&hw2.to_le_bytes());
2692
2693 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
2699 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
2700
2701 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
2705
2706 Ok(bytes)
2707 }
2708
2709 ArmOp::Label { .. } => Ok(Vec::new()),
2711
2712 ArmOp::Bcc { cond, label: _ } => {
2714 use synth_synthesis::Condition;
2715 let cond_bits: u16 = match cond {
2716 Condition::EQ => 0x0,
2717 Condition::NE => 0x1,
2718 Condition::HS => 0x2,
2719 Condition::LO => 0x3,
2720 Condition::HI => 0x8,
2721 Condition::LS => 0x9,
2722 Condition::GE => 0xA,
2723 Condition::LT => 0xB,
2724 Condition::GT => 0xC,
2725 Condition::LE => 0xD,
2726 };
2727 let instr: u16 = 0xD000 | (cond_bits << 8);
2729 Ok(instr.to_le_bytes().to_vec())
2730 }
2731
2732 ArmOp::B { label: _ } => {
2734 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
2738 }
2739
2740 ArmOp::Bhs { label: _ } => {
2743 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
2747 }
2748
2749 ArmOp::Blo { label: _ } => {
2752 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
2756 }
2757
2758 ArmOp::BOffset { offset } => {
2761 let halfword_offset = *offset;
2764
2765 if (-1024..=1022).contains(&halfword_offset) {
2768 let imm11 = (halfword_offset as u16) & 0x7FF;
2770 let instr: u16 = 0xE000 | imm11;
2771 Ok(instr.to_le_bytes().to_vec())
2772 } else {
2773 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
2789 let uoffset = signed_offset as u32;
2790 let imm10 = (uoffset >> 12) & 0x3FF; let imm11 = (uoffset >> 1) & 0x7FF; let i1 = (uoffset >> 23) & 1; let i2 = (uoffset >> 22) & 1; let j1 = (!(i1 ^ s)) & 1; let j2 = (!(i2 ^ s)) & 1; let hw1: u16 = (0xF000 | (s << 10) | imm10) as u16;
2798 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2799
2800 let mut bytes = hw1.to_le_bytes().to_vec();
2801 bytes.extend_from_slice(&hw2.to_le_bytes());
2802 Ok(bytes)
2803 }
2804 }
2805
2806 ArmOp::BCondOffset { cond, offset } => {
2808 use synth_synthesis::Condition;
2809 let cond_bits: u16 = match cond {
2810 Condition::EQ => 0x0,
2811 Condition::NE => 0x1,
2812 Condition::HS => 0x2,
2813 Condition::LO => 0x3,
2814 Condition::HI => 0x8,
2815 Condition::LS => 0x9,
2816 Condition::GE => 0xA,
2817 Condition::LT => 0xB,
2818 Condition::GT => 0xC,
2819 Condition::LE => 0xD,
2820 };
2821
2822 let halfword_offset = *offset;
2825
2826 if (-128..=127).contains(&halfword_offset) {
2829 let imm8 = (halfword_offset as u16) & 0xFF;
2830 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
2831 Ok(instr.to_le_bytes().to_vec())
2832 } else {
2833 let offset = halfword_offset >> 1;
2837 let s = if offset < 0 { 1u32 } else { 0u32 };
2838 let imm6 = ((offset >> 11) as u32) & 0x3F;
2839 let imm11 = (offset as u32) & 0x7FF;
2840 let j1 = if s == 1 { 1 } else { 0 };
2841 let j2 = if s == 1 { 1 } else { 0 };
2842
2843 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
2844 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2845
2846 let mut bytes = hw1.to_le_bytes().to_vec();
2847 bytes.extend_from_slice(&hw2.to_le_bytes());
2848 Ok(bytes)
2849 }
2850 }
2851
2852 ArmOp::Bl { label: _ } => {
2853 let hw1: u16 = 0xF7FF;
2868 let hw2: u16 = 0xFFFE;
2869 let mut bytes = hw1.to_le_bytes().to_vec();
2870 bytes.extend_from_slice(&hw2.to_le_bytes());
2871 Ok(bytes)
2872 }
2873
2874 ArmOp::Mvn { rd, op2 } => {
2876 if let Operand2::Reg(rm) = op2 {
2877 let rd_bits = reg_to_bits(rd) as u16;
2878 let rm_bits = reg_to_bits(rm) as u16;
2879
2880 if rd_bits < 8 && rm_bits < 8 {
2881 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
2883 Ok(instr.to_le_bytes().to_vec())
2884 } else {
2885 let hw1: u16 = 0xEA6F_u16;
2887 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
2888 let mut bytes = hw1.to_le_bytes().to_vec();
2889 bytes.extend_from_slice(&hw2.to_le_bytes());
2890 Ok(bytes)
2891 }
2892 } else {
2893 let instr: u16 = 0xBF00;
2894 Ok(instr.to_le_bytes().to_vec())
2895 }
2896 }
2897
2898 ArmOp::Movw { rd, imm16 } => {
2900 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
2901 }
2902
2903 ArmOp::Movt { rd, imm16 } => {
2905 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
2906 }
2907
2908 ArmOp::MovwSym { rd, addend, .. } => {
2913 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
2914 }
2915 ArmOp::MovtSym { rd, addend, .. } => {
2916 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
2917 }
2918
2919 ArmOp::LdrSym { rd, .. } => {
2927 let rt = reg_to_bits(rd) as u16;
2928 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
2931 bytes.extend_from_slice(&hw1.to_le_bytes());
2932 bytes.extend_from_slice(&hw2.to_le_bytes());
2933 Ok(bytes)
2934 }
2935
2936 ArmOp::SetCond { rd, cond } => {
2942 let rd_bits = reg_to_bits(rd) as u16;
2943
2944 use synth_synthesis::Condition;
2946 let cond_bits: u16 = match cond {
2947 Condition::EQ => 0x0,
2948 Condition::NE => 0x1,
2949 Condition::LT => 0xB,
2950 Condition::LE => 0xD,
2951 Condition::GT => 0xC,
2952 Condition::GE => 0xA,
2953 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
2958
2959 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
2964 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
2965
2966 let mut bytes = ite_instr.to_le_bytes().to_vec();
2977 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
2978 if rd_bits <= 7 {
2979 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
2981 } else {
2982 let hw1: u16 = 0xF04F;
2984 let hw2: u16 = (rd_bits << 8) | imm;
2985 bytes.extend_from_slice(&hw1.to_le_bytes());
2986 bytes.extend_from_slice(&hw2.to_le_bytes());
2987 }
2988 };
2989 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
2992 }
2993
2994 ArmOp::I64SetCond {
2999 rd,
3000 rn_lo,
3001 rn_hi,
3002 rm_lo,
3003 rm_hi,
3004 cond,
3005 } => {
3006 use synth_synthesis::Condition;
3007 let rd_bits = reg_to_bits(rd) as u16;
3008 let mut bytes = Vec::new();
3009
3010 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3012 rm: &synth_synthesis::Reg|
3013 -> Vec<u8> {
3014 let rn_bits = reg_to_bits(rn) as u16;
3015 let rm_bits = reg_to_bits(rm) as u16;
3016 if rn_bits < 8 && rm_bits < 8 {
3017 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3018 instr.to_le_bytes().to_vec()
3019 } else {
3020 let n_bit = (rn_bits >> 3) & 1;
3021 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3022 instr.to_le_bytes().to_vec()
3023 }
3024 };
3025
3026 let encode_ite = |cond_bits: u16| -> Vec<u8> {
3028 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3029 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3030 ite_instr.to_le_bytes().to_vec()
3031 };
3032
3033 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
3035 let mut b = encode_ite(cond_bits);
3036 if rd_bits < 8 {
3037 let mov_one: u16 = 0x2001 | (rd_bits << 8);
3038 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
3039 b.extend_from_slice(&mov_one.to_le_bytes());
3040 b.extend_from_slice(&mov_zero.to_le_bytes());
3041 } else {
3042 for imm in [1u16, 0u16] {
3050 let hw1: u16 = 0xF04F;
3051 let hw2: u16 = (rd_bits << 8) | imm;
3052 b.extend_from_slice(&hw1.to_le_bytes());
3053 b.extend_from_slice(&hw2.to_le_bytes());
3054 }
3055 }
3056 b
3057 };
3058
3059 match cond {
3060 Condition::EQ | Condition::NE => {
3061 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3063
3064 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
3067
3068 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
3070
3071 let cond_bits: u16 = match cond {
3073 Condition::EQ => 0x0,
3074 Condition::NE => 0x1,
3075 _ => unreachable!(),
3076 };
3077 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
3078 }
3079
3080 Condition::LT => {
3081 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3083
3084 let rn_hi_bits = reg_to_bits(rn_hi);
3087 let rm_hi_bits = reg_to_bits(rm_hi);
3088 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3089 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3090 bytes.extend_from_slice(&hw1.to_le_bytes());
3091 bytes.extend_from_slice(&hw2.to_le_bytes());
3092
3093 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3096
3097 Condition::GT => {
3098 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3101
3102 let rm_hi_bits = reg_to_bits(rm_hi);
3104 let rn_hi_bits = reg_to_bits(rn_hi);
3105 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3106 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3107 bytes.extend_from_slice(&hw1.to_le_bytes());
3108 bytes.extend_from_slice(&hw2.to_le_bytes());
3109
3110 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3113
3114 Condition::LE => {
3115 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3119
3120 let rm_hi_bits = reg_to_bits(rm_hi);
3122 let rn_hi_bits = reg_to_bits(rn_hi);
3123 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3124 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3125 bytes.extend_from_slice(&hw1.to_le_bytes());
3126 bytes.extend_from_slice(&hw2.to_le_bytes());
3127
3128 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3131
3132 Condition::GE => {
3133 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3136
3137 let rn_hi_bits = reg_to_bits(rn_hi);
3139 let rm_hi_bits = reg_to_bits(rm_hi);
3140 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3141 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3142 bytes.extend_from_slice(&hw1.to_le_bytes());
3143 bytes.extend_from_slice(&hw2.to_le_bytes());
3144
3145 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3148
3149 Condition::LO => {
3151 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3153 let rn_hi_bits = reg_to_bits(rn_hi);
3154 let rm_hi_bits = reg_to_bits(rm_hi);
3155 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3156 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3157 bytes.extend_from_slice(&hw1.to_le_bytes());
3158 bytes.extend_from_slice(&hw2.to_le_bytes());
3159 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3161
3162 Condition::HI => {
3163 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3165 let rm_hi_bits = reg_to_bits(rm_hi);
3166 let rn_hi_bits = reg_to_bits(rn_hi);
3167 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3168 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3169 bytes.extend_from_slice(&hw1.to_le_bytes());
3170 bytes.extend_from_slice(&hw2.to_le_bytes());
3171 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3173
3174 Condition::LS => {
3175 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3177 let rm_hi_bits = reg_to_bits(rm_hi);
3178 let rn_hi_bits = reg_to_bits(rn_hi);
3179 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3180 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3181 bytes.extend_from_slice(&hw1.to_le_bytes());
3182 bytes.extend_from_slice(&hw2.to_le_bytes());
3183 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3185
3186 Condition::HS => {
3187 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3189 let rn_hi_bits = reg_to_bits(rn_hi);
3190 let rm_hi_bits = reg_to_bits(rm_hi);
3191 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3192 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3193 bytes.extend_from_slice(&hw1.to_le_bytes());
3194 bytes.extend_from_slice(&hw2.to_le_bytes());
3195 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3197 }
3198
3199 Ok(bytes)
3200 }
3201
3202 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
3205 let rd_bits = reg_to_bits(rd);
3206 let rn_lo_bits = reg_to_bits(rn_lo);
3207 let rn_hi_bits = reg_to_bits(rn_hi);
3208 let mut bytes = Vec::new();
3209
3210 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
3212 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
3213 bytes.extend_from_slice(&hw1.to_le_bytes());
3214 bytes.extend_from_slice(&hw2.to_le_bytes());
3215
3216 if rd_bits < 8 {
3221 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
3222 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
3223 } else {
3224 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
3225 let hw2: u16 = 0x0F00;
3226 bytes.extend_from_slice(&hw1.to_le_bytes());
3227 bytes.extend_from_slice(&hw2.to_le_bytes());
3228 }
3229
3230 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
3234 bytes.extend_from_slice(&ite_instr.to_le_bytes());
3235 if rd_bits < 8 {
3236 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
3237 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
3238 bytes.extend_from_slice(&mov_one.to_le_bytes());
3239 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3240 } else {
3241 for imm in [1u16, 0u16] {
3242 let hw1: u16 = 0xF04F;
3243 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
3244 bytes.extend_from_slice(&hw1.to_le_bytes());
3245 bytes.extend_from_slice(&hw2.to_le_bytes());
3246 }
3247 }
3248
3249 Ok(bytes)
3250 }
3251
3252 ArmOp::I64Mul {
3256 rd_lo,
3257 rd_hi,
3258 rn_lo,
3259 rn_hi,
3260 rm_lo,
3261 rm_hi,
3262 } => {
3263 let rd_lo_bits = reg_to_bits(rd_lo);
3264 let rd_hi_bits = reg_to_bits(rd_hi);
3265 let rn_lo_bits = reg_to_bits(rn_lo);
3266 let rn_hi_bits = reg_to_bits(rn_hi);
3267 let rm_lo_bits = reg_to_bits(rm_lo);
3268 let rm_hi_bits = reg_to_bits(rm_hi);
3269 let r12: u32 = 12; let mut bytes = Vec::new();
3271
3272 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
3275 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
3276 bytes.extend_from_slice(&hw1.to_le_bytes());
3277 bytes.extend_from_slice(&hw2.to_le_bytes());
3278
3279 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
3282 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
3283 bytes.extend_from_slice(&hw1.to_le_bytes());
3284 bytes.extend_from_slice(&hw2.to_le_bytes());
3285
3286 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
3289 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3290 bytes.extend_from_slice(&hw1.to_le_bytes());
3291 bytes.extend_from_slice(&hw2.to_le_bytes());
3292
3293 let d_bit = (rd_hi_bits >> 3) & 1;
3296 let add_instr: u16 =
3297 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
3298 bytes.extend_from_slice(&add_instr.to_le_bytes());
3299
3300 Ok(bytes)
3301 }
3302
3303 ArmOp::I64Shl {
3306 rd_lo,
3307 rd_hi,
3308 rn_lo,
3309 rn_hi,
3310 rm_lo,
3311 rm_hi,
3312 } => {
3313 let rd_lo_bits = reg_to_bits(rd_lo);
3314 let rd_hi_bits = reg_to_bits(rd_hi);
3315 let rn_lo_bits = reg_to_bits(rn_lo);
3316 let rn_hi_bits = reg_to_bits(rn_hi);
3317 let rm_lo_bits = reg_to_bits(rm_lo);
3318 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3320
3321 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3323 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3324 bytes.extend_from_slice(&hw1.to_le_bytes());
3325 bytes.extend_from_slice(&hw2.to_le_bytes());
3326
3327 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3329 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3330 bytes.extend_from_slice(&hw1.to_le_bytes());
3331 bytes.extend_from_slice(&hw2.to_le_bytes());
3332
3333 let bpl: u16 = 0xD50A;
3335 bytes.extend_from_slice(&bpl.to_le_bytes());
3336
3337 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3340 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3341 bytes.extend_from_slice(&hw1.to_le_bytes());
3342 bytes.extend_from_slice(&hw2.to_le_bytes());
3343
3344 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3346 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3347 bytes.extend_from_slice(&hw1.to_le_bytes());
3348 bytes.extend_from_slice(&hw2.to_le_bytes());
3349
3350 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3352 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3353 bytes.extend_from_slice(&hw1.to_le_bytes());
3354 bytes.extend_from_slice(&hw2.to_le_bytes());
3355
3356 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3358 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
3359 bytes.extend_from_slice(&hw1.to_le_bytes());
3360 bytes.extend_from_slice(&hw2.to_le_bytes());
3361
3362 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3364 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3365 bytes.extend_from_slice(&hw1.to_le_bytes());
3366 bytes.extend_from_slice(&hw2.to_le_bytes());
3367
3368 let b_done: u16 = 0xE002;
3370 bytes.extend_from_slice(&b_done.to_le_bytes());
3371
3372 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3375 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
3376 bytes.extend_from_slice(&hw1.to_le_bytes());
3377 bytes.extend_from_slice(&hw2.to_le_bytes());
3378
3379 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
3381 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3382
3383 Ok(bytes) }
3385
3386 ArmOp::I64ShrU {
3388 rd_lo,
3389 rd_hi,
3390 rn_lo,
3391 rn_hi,
3392 rm_lo,
3393 rm_hi,
3394 } => {
3395 let rd_lo_bits = reg_to_bits(rd_lo);
3396 let rd_hi_bits = reg_to_bits(rd_hi);
3397 let rn_lo_bits = reg_to_bits(rn_lo);
3398 let rn_hi_bits = reg_to_bits(rn_hi);
3399 let rm_lo_bits = reg_to_bits(rm_lo);
3400 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3402
3403 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3405 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3406 bytes.extend_from_slice(&hw1.to_le_bytes());
3407 bytes.extend_from_slice(&hw2.to_le_bytes());
3408
3409 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3411 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3412 bytes.extend_from_slice(&hw1.to_le_bytes());
3413 bytes.extend_from_slice(&hw2.to_le_bytes());
3414
3415 let bpl: u16 = 0xD50A;
3417 bytes.extend_from_slice(&bpl.to_le_bytes());
3418
3419 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3422 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3423 bytes.extend_from_slice(&hw1.to_le_bytes());
3424 bytes.extend_from_slice(&hw2.to_le_bytes());
3425
3426 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3428 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3429 bytes.extend_from_slice(&hw1.to_le_bytes());
3430 bytes.extend_from_slice(&hw2.to_le_bytes());
3431
3432 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3434 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3435 bytes.extend_from_slice(&hw1.to_le_bytes());
3436 bytes.extend_from_slice(&hw2.to_le_bytes());
3437
3438 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3440 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3441 bytes.extend_from_slice(&hw1.to_le_bytes());
3442 bytes.extend_from_slice(&hw2.to_le_bytes());
3443
3444 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3446 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3447 bytes.extend_from_slice(&hw1.to_le_bytes());
3448 bytes.extend_from_slice(&hw2.to_le_bytes());
3449
3450 let b_done: u16 = 0xE002;
3452 bytes.extend_from_slice(&b_done.to_le_bytes());
3453
3454 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3457 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3458 bytes.extend_from_slice(&hw1.to_le_bytes());
3459 bytes.extend_from_slice(&hw2.to_le_bytes());
3460
3461 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
3463 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3464
3465 Ok(bytes) }
3467
3468 ArmOp::I64ShrS {
3470 rd_lo,
3471 rd_hi,
3472 rn_lo,
3473 rn_hi,
3474 rm_lo,
3475 rm_hi,
3476 } => {
3477 let rd_lo_bits = reg_to_bits(rd_lo);
3478 let rd_hi_bits = reg_to_bits(rd_hi);
3479 let rn_lo_bits = reg_to_bits(rn_lo);
3480 let rn_hi_bits = reg_to_bits(rn_hi);
3481 let rm_lo_bits = reg_to_bits(rm_lo);
3482 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3484
3485 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3487 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3488 bytes.extend_from_slice(&hw1.to_le_bytes());
3489 bytes.extend_from_slice(&hw2.to_le_bytes());
3490
3491 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3493 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3494 bytes.extend_from_slice(&hw1.to_le_bytes());
3495 bytes.extend_from_slice(&hw2.to_le_bytes());
3496
3497 let bpl: u16 = 0xD50A;
3499 bytes.extend_from_slice(&bpl.to_le_bytes());
3500
3501 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3504 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3505 bytes.extend_from_slice(&hw1.to_le_bytes());
3506 bytes.extend_from_slice(&hw2.to_le_bytes());
3507
3508 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3510 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3511 bytes.extend_from_slice(&hw1.to_le_bytes());
3512 bytes.extend_from_slice(&hw2.to_le_bytes());
3513
3514 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3516 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3517 bytes.extend_from_slice(&hw1.to_le_bytes());
3518 bytes.extend_from_slice(&hw2.to_le_bytes());
3519
3520 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3522 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3523 bytes.extend_from_slice(&hw1.to_le_bytes());
3524 bytes.extend_from_slice(&hw2.to_le_bytes());
3525
3526 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3528 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3529 bytes.extend_from_slice(&hw1.to_le_bytes());
3530 bytes.extend_from_slice(&hw2.to_le_bytes());
3531
3532 let b_done: u16 = 0xE003;
3534 bytes.extend_from_slice(&b_done.to_le_bytes());
3535
3536 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3539 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3540 bytes.extend_from_slice(&hw1.to_le_bytes());
3541 bytes.extend_from_slice(&hw2.to_le_bytes());
3542
3543 let hw1: u16 = 0xEA4F;
3547 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
3548 bytes.extend_from_slice(&hw1.to_le_bytes());
3549 bytes.extend_from_slice(&hw2.to_le_bytes());
3550
3551 Ok(bytes) }
3553
3554 ArmOp::I64Rotl {
3565 rdlo,
3566 rdhi,
3567 rnlo,
3568 rnhi,
3569 shift,
3570 } => {
3571 let mut bytes = Vec::new();
3572 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
3573
3574 let core: [u16; 35] = [
3575 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA20, 0xFC03, 0xFA21, 0xF303, 0xFA01, 0xF102, 0xEA41, 0x010C, 0xFA00, 0xF002, 0xEA40, 0x0003, 0xE00E, 0xF1C3, 0x0220, 0xFA21, 0xFC02, 0xFA20, 0xF202, 0xFA00, 0xF003, 0xFA01, 0xF103, 0xEA40, 0x0C0C, 0xEA41, 0x0002, 0x4661, ];
3598 for hw in core {
3599 bytes.extend_from_slice(&hw.to_le_bytes());
3600 }
3601
3602 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
3603 Ok(bytes) }
3605
3606 ArmOp::I64Rotr {
3613 rdlo,
3614 rdhi,
3615 rnlo,
3616 rnhi,
3617 shift,
3618 } => {
3619 let mut bytes = Vec::new();
3620 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
3621
3622 let core: [u16; 35] = [
3623 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA01, 0xFC03, 0xFA00, 0xF303, 0xFA20, 0xF002, 0xEA40, 0x000C, 0xFA21, 0xF102, 0xEA41, 0x0103, 0xE00E, 0xF1C3, 0x0220, 0xFA00, 0xFC02, 0xFA01, 0xF202, 0xFA21, 0xF103, 0xEA41, 0x0C0C, 0xFA20, 0xF103, 0xEA41, 0x0102, 0x4660, ];
3646 for hw in core {
3647 bytes.extend_from_slice(&hw.to_le_bytes());
3648 }
3649
3650 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
3651 Ok(bytes) }
3653
3654 ArmOp::I64Clz { rd, rnlo, rnhi } => {
3668 let rd_bits = reg_to_bits(rd);
3669 let rn_lo_bits = reg_to_bits(rnlo);
3670 let rn_hi_bits = reg_to_bits(rnhi);
3671 let mut bytes = Vec::new();
3672
3673 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
3675 let hw2: u16 = 0x0F00;
3676 bytes.extend_from_slice(&hw1.to_le_bytes());
3677 bytes.extend_from_slice(&hw2.to_le_bytes());
3678
3679 let beq: u16 = 0xD003;
3682 bytes.extend_from_slice(&beq.to_le_bytes());
3683
3684 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
3687 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
3688 bytes.extend_from_slice(&hw1.to_le_bytes());
3689 bytes.extend_from_slice(&hw2.to_le_bytes());
3690
3691 let b_done: u16 = 0xE004;
3694 bytes.extend_from_slice(&b_done.to_le_bytes());
3695
3696 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3698
3699 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
3703 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
3704 bytes.extend_from_slice(&hw1.to_le_bytes());
3705 bytes.extend_from_slice(&hw2.to_le_bytes());
3706
3707 let hw1: u16 = (0xF100 | rd_bits) as u16;
3709 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3710 bytes.extend_from_slice(&hw1.to_le_bytes());
3711 bytes.extend_from_slice(&hw2.to_le_bytes());
3712
3713 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3717 bytes.extend_from_slice(&mov0.to_le_bytes());
3718
3719 Ok(bytes)
3720 }
3721
3722 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
3738 let rd_bits = reg_to_bits(rd);
3739 let rn_lo_bits = reg_to_bits(rnlo);
3740 let rn_hi_bits = reg_to_bits(rnhi);
3741 let mut bytes = Vec::new();
3742
3743 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
3745 let hw2: u16 = 0x0F00;
3746 bytes.extend_from_slice(&hw1.to_le_bytes());
3747 bytes.extend_from_slice(&hw2.to_le_bytes());
3748
3749 let beq: u16 = 0xD005;
3752 bytes.extend_from_slice(&beq.to_le_bytes());
3753
3754 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
3757 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
3758 bytes.extend_from_slice(&hw1.to_le_bytes());
3759 bytes.extend_from_slice(&hw2.to_le_bytes());
3760
3761 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3764 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3765 bytes.extend_from_slice(&hw1.to_le_bytes());
3766 bytes.extend_from_slice(&hw2.to_le_bytes());
3767
3768 let b_done: u16 = 0xE006;
3771 bytes.extend_from_slice(&b_done.to_le_bytes());
3772
3773 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3775
3776 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
3780 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
3781 bytes.extend_from_slice(&hw1.to_le_bytes());
3782 bytes.extend_from_slice(&hw2.to_le_bytes());
3783
3784 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3787 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3788 bytes.extend_from_slice(&hw1.to_le_bytes());
3789 bytes.extend_from_slice(&hw2.to_le_bytes());
3790
3791 let hw1: u16 = (0xF100 | rd_bits) as u16;
3793 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3794 bytes.extend_from_slice(&hw1.to_le_bytes());
3795 bytes.extend_from_slice(&hw2.to_le_bytes());
3796
3797 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3800 bytes.extend_from_slice(&mov0.to_le_bytes());
3801
3802 Ok(bytes)
3803 }
3804
3805 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
3809 let rd_bits = reg_to_bits(rd);
3810 let rn_lo_bits = reg_to_bits(rnlo);
3811 let rn_hi_bits = reg_to_bits(rnhi);
3812 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
3815
3816 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
3818
3819 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_lo_bits << 3) | (4 & 0x7)) as u16;
3829 bytes.extend_from_slice(&mov.to_le_bytes());
3830
3831 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_hi_bits << 3) | (5 & 0x7)) as u16;
3834 bytes.extend_from_slice(&mov.to_le_bytes());
3835
3836 let hw1: u16 = 0xEA4F;
3840 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
3841 bytes.extend_from_slice(&hw1.to_le_bytes());
3842 bytes.extend_from_slice(&hw2.to_le_bytes());
3843
3844 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
3847 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
3848 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
3850 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
3851
3852 let hw1: u16 = (0xEA00 | r12) as u16;
3854 let hw2: u16 = ((r12 << 8) | r3) as u16;
3855 bytes.extend_from_slice(&hw1.to_le_bytes());
3856 bytes.extend_from_slice(&hw2.to_le_bytes());
3857
3858 let hw1: u16 = (0xEBA0 | 4) as u16;
3860 let hw2: u16 = ((4 << 8) | r12) as u16;
3861 bytes.extend_from_slice(&hw1.to_le_bytes());
3862 bytes.extend_from_slice(&hw2.to_le_bytes());
3863
3864 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
3868 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
3869 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
3871 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
3872
3873 let hw1: u16 = (0xEA00 | 4) as u16;
3875 let hw2: u16 = ((r12 << 8) | r3) as u16;
3876 bytes.extend_from_slice(&hw1.to_le_bytes());
3877 bytes.extend_from_slice(&hw2.to_le_bytes());
3878
3879 let hw1: u16 = 0xEA4F;
3881 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
3882 bytes.extend_from_slice(&hw1.to_le_bytes());
3883 bytes.extend_from_slice(&hw2.to_le_bytes());
3884
3885 let hw1: u16 = (0xEA00 | 4) as u16;
3887 let hw2: u16 = ((4 << 8) | r3) as u16;
3888 bytes.extend_from_slice(&hw1.to_le_bytes());
3889 bytes.extend_from_slice(&hw2.to_le_bytes());
3890
3891 let hw1: u16 = (0xEB00 | 4) as u16;
3893 let hw2: u16 = ((4 << 8) | r12) as u16;
3894 bytes.extend_from_slice(&hw1.to_le_bytes());
3895 bytes.extend_from_slice(&hw2.to_le_bytes());
3896
3897 let hw1: u16 = 0xEA4F;
3902 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
3903 bytes.extend_from_slice(&hw1.to_le_bytes());
3904 bytes.extend_from_slice(&hw2.to_le_bytes());
3905
3906 let hw1: u16 = (0xEB00 | 4) as u16;
3908 let hw2: u16 = ((4 << 8) | r12) as u16;
3909 bytes.extend_from_slice(&hw1.to_le_bytes());
3910 bytes.extend_from_slice(&hw2.to_le_bytes());
3911
3912 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
3917 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
3918 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
3920 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
3921
3922 let hw1: u16 = (0xEA00 | 4) as u16;
3924 let hw2: u16 = ((4 << 8) | r3) as u16;
3925 bytes.extend_from_slice(&hw1.to_le_bytes());
3926 bytes.extend_from_slice(&hw2.to_le_bytes());
3927
3928 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
3932 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
3933 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
3935 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
3936
3937 let hw1: u16 = (0xFB00 | 4) as u16;
3940 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
3941 bytes.extend_from_slice(&hw1.to_le_bytes());
3942 bytes.extend_from_slice(&hw2.to_le_bytes());
3943
3944 let hw1: u16 = 0xEA4F;
3947 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
3948 bytes.extend_from_slice(&hw1.to_le_bytes());
3949 bytes.extend_from_slice(&hw2.to_le_bytes());
3950
3951 let hw1: u16 = 0xEA4F;
3954 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
3955 bytes.extend_from_slice(&hw1.to_le_bytes());
3956 bytes.extend_from_slice(&hw2.to_le_bytes());
3957
3958 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
3960 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
3961 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
3962 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
3963
3964 let hw1: u16 = (0xEA00 | r12) as u16;
3965 let hw2: u16 = ((r12 << 8) | r3) as u16;
3966 bytes.extend_from_slice(&hw1.to_le_bytes());
3967 bytes.extend_from_slice(&hw2.to_le_bytes());
3968
3969 let hw1: u16 = (0xEBA0 | 5) as u16;
3970 let hw2: u16 = ((5 << 8) | r12) as u16;
3971 bytes.extend_from_slice(&hw1.to_le_bytes());
3972 bytes.extend_from_slice(&hw2.to_le_bytes());
3973
3974 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
3976 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
3977 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
3978 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
3979
3980 let hw1: u16 = (0xEA00 | 5) as u16;
3981 let hw2: u16 = ((r12 << 8) | r3) as u16;
3982 bytes.extend_from_slice(&hw1.to_le_bytes());
3983 bytes.extend_from_slice(&hw2.to_le_bytes());
3984
3985 let hw1: u16 = 0xEA4F;
3986 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
3987 bytes.extend_from_slice(&hw1.to_le_bytes());
3988 bytes.extend_from_slice(&hw2.to_le_bytes());
3989
3990 let hw1: u16 = (0xEA00 | 5) as u16;
3991 let hw2: u16 = ((5 << 8) | r3) as u16;
3992 bytes.extend_from_slice(&hw1.to_le_bytes());
3993 bytes.extend_from_slice(&hw2.to_le_bytes());
3994
3995 let hw1: u16 = (0xEB00 | 5) as u16;
3996 let hw2: u16 = ((5 << 8) | r12) as u16;
3997 bytes.extend_from_slice(&hw1.to_le_bytes());
3998 bytes.extend_from_slice(&hw2.to_le_bytes());
3999
4000 let hw1: u16 = 0xEA4F;
4003 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4004 bytes.extend_from_slice(&hw1.to_le_bytes());
4005 bytes.extend_from_slice(&hw2.to_le_bytes());
4006
4007 let hw1: u16 = (0xEB00 | 5) as u16;
4008 let hw2: u16 = ((5 << 8) | r12) as u16;
4009 bytes.extend_from_slice(&hw1.to_le_bytes());
4010 bytes.extend_from_slice(&hw2.to_le_bytes());
4011
4012 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4014 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4015 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4016 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4017
4018 let hw1: u16 = (0xEA00 | 5) as u16;
4019 let hw2: u16 = ((5 << 8) | r3) as u16;
4020 bytes.extend_from_slice(&hw1.to_le_bytes());
4021 bytes.extend_from_slice(&hw2.to_le_bytes());
4022
4023 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4025 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4026 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4027 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4028
4029 let hw1: u16 = (0xFB00 | 5) as u16;
4032 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
4033 bytes.extend_from_slice(&hw1.to_le_bytes());
4034 bytes.extend_from_slice(&hw2.to_le_bytes());
4035
4036 let hw1: u16 = 0xEA4F;
4039 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
4040 bytes.extend_from_slice(&hw1.to_le_bytes());
4041 bytes.extend_from_slice(&hw2.to_le_bytes());
4042
4043 let rd_bits_u16 = rd_bits as u16;
4046 let instr: u16 = 0x1800 | (5 << 6) | (4 << 3) | rd_bits_u16;
4047 bytes.extend_from_slice(&instr.to_le_bytes());
4048
4049 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
4051
4052 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4054 bytes.extend_from_slice(&mov0.to_le_bytes());
4055
4056 Ok(bytes)
4057 }
4058
4059 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
4062 let rdlo_bits = reg_to_bits(rdlo);
4063 let rdhi_bits = reg_to_bits(rdhi);
4064 let rnlo_bits = reg_to_bits(rnlo);
4065 let mut bytes = Vec::new();
4066
4067 let hw1: u16 = 0xFA4F_u16;
4070 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4071 bytes.extend_from_slice(&hw1.to_le_bytes());
4072 bytes.extend_from_slice(&hw2.to_le_bytes());
4073
4074 let hw1: u16 = 0xEA4F;
4079 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4080 bytes.extend_from_slice(&hw1.to_le_bytes());
4081 bytes.extend_from_slice(&hw2.to_le_bytes());
4082
4083 Ok(bytes)
4084 }
4085
4086 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
4089 let rdlo_bits = reg_to_bits(rdlo);
4090 let rdhi_bits = reg_to_bits(rdhi);
4091 let rnlo_bits = reg_to_bits(rnlo);
4092 let mut bytes = Vec::new();
4093
4094 let hw1: u16 = 0xFA0F_u16;
4097 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4098 bytes.extend_from_slice(&hw1.to_le_bytes());
4099 bytes.extend_from_slice(&hw2.to_le_bytes());
4100
4101 let hw1: u16 = 0xEA4F;
4103 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4104 bytes.extend_from_slice(&hw1.to_le_bytes());
4105 bytes.extend_from_slice(&hw2.to_le_bytes());
4106
4107 Ok(bytes)
4108 }
4109
4110 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
4113 let rdlo_bits = reg_to_bits(rdlo);
4114 let rdhi_bits = reg_to_bits(rdhi);
4115 let rnlo_bits = reg_to_bits(rnlo);
4116 let mut bytes = Vec::new();
4117
4118 if rdlo_bits != rnlo_bits {
4120 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
4122 let mov: u16 = 0x4600
4123 | (d_bit << 7)
4124 | ((rnlo_bits as u16) << 3)
4125 | ((rdlo_bits & 0x7) as u16);
4126 bytes.extend_from_slice(&mov.to_le_bytes());
4127 }
4128
4129 let hw1: u16 = 0xEA4F;
4131 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
4132 bytes.extend_from_slice(&hw1.to_le_bytes());
4133 bytes.extend_from_slice(&hw2.to_le_bytes());
4134
4135 Ok(bytes)
4136 }
4137
4138 ArmOp::SelectMove { rd, rm, cond } => {
4141 let rd_bits = reg_to_bits(rd) as u16;
4142 let rm_bits = reg_to_bits(rm) as u16;
4143
4144 use synth_synthesis::Condition;
4146 let cond_bits: u16 = match cond {
4147 Condition::EQ => 0x0, Condition::NE => 0x1, Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA, Condition::LT => 0xB, Condition::GT => 0xC, Condition::LE => 0xD, };
4158
4159 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
4162
4163 let d_bit = (rd_bits >> 3) & 1;
4166 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4167
4168 let mut bytes = it_instr.to_le_bytes().to_vec();
4170 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4171 Ok(bytes)
4172 }
4173
4174 ArmOp::Popcnt { rd, rm } => {
4185 let mut bytes = Vec::new();
4186
4187 if rd != rm {
4189 let rd_bits = reg_to_bits(rd) as u16;
4190 let rm_bits = reg_to_bits(rm) as u16;
4191 let d_bit = (rd_bits >> 3) & 1;
4193 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4194 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4195 }
4196
4197 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
4200 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
4201
4202 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
4205
4206 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
4208
4209 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
4211 reg_to_bits(rd),
4212 reg_to_bits(rd),
4213 11,
4214 )?);
4215
4216 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
4219 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
4220
4221 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4223 11,
4224 reg_to_bits(rd),
4225 12,
4226 )?);
4227
4228 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
4230 reg_to_bits(rd),
4231 reg_to_bits(rd),
4232 2,
4233 )?);
4234
4235 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4237 reg_to_bits(rd),
4238 reg_to_bits(rd),
4239 12,
4240 )?);
4241
4242 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4244 reg_to_bits(rd),
4245 reg_to_bits(rd),
4246 11,
4247 )?);
4248
4249 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
4252
4253 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4255 reg_to_bits(rd),
4256 reg_to_bits(rd),
4257 11,
4258 )?);
4259
4260 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
4262 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
4263
4264 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4266 reg_to_bits(rd),
4267 reg_to_bits(rd),
4268 12,
4269 )?);
4270
4271 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
4274
4275 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4277 reg_to_bits(rd),
4278 reg_to_bits(rd),
4279 11,
4280 )?);
4281
4282 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
4285
4286 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4288 reg_to_bits(rd),
4289 reg_to_bits(rd),
4290 11,
4291 )?);
4292
4293 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
4296 reg_to_bits(rd),
4297 reg_to_bits(rd),
4298 0x3F,
4299 )?);
4300
4301 Ok(bytes)
4302 }
4303
4304 ArmOp::I64DivU {
4315 rdlo,
4316 rdhi,
4317 rnlo,
4318 rnhi,
4319 rmlo,
4320 rmhi,
4321 } => {
4322 let mut bytes = Vec::new();
4323 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
4324 emit_i64_divisor_zero_trap(&mut bytes);
4325
4326 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
4330
4331 bytes.extend_from_slice(&0x2400u16.to_le_bytes()); bytes.extend_from_slice(&0x2500u16.to_le_bytes()); bytes.extend_from_slice(&0x2600u16.to_le_bytes()); bytes.extend_from_slice(&0x2700u16.to_le_bytes()); bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4342 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
4343
4344 let loop_start = bytes.len();
4346
4347 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
4358 bytes.extend_from_slice(&0x75D4u16.to_le_bytes()); bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes());
4367 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4368 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
4372 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4373
4374 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
4379 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4380 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes());
4411 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4412 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4415
4416 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
4420 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
4421
4422 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4425 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4426 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4427
4428 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
4436
4437 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4438 Ok(bytes)
4439 }
4440
4441 ArmOp::I64DivS {
4447 rdlo,
4448 rdhi,
4449 rnlo,
4450 rnhi,
4451 rmlo,
4452 rmhi,
4453 } => {
4454 let mut bytes = Vec::new();
4455 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
4456 emit_i64_divisor_zero_trap(&mut bytes);
4457
4458 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4460 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4461
4462 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
4465 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
4466
4467 bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
4480
4481 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
4491
4492 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4495 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4496 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4498 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4499 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4501 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4502
4503 let loop_start = bytes.len();
4504
4505 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4509 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4515 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4518
4519 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4523 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4536 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4538
4539 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4542
4543 let branch_offset_bytes = bytes.len() - loop_start + 4;
4544 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4545 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4546 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4547
4548 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
4555 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
4563
4564 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4566 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4567
4568 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4569 Ok(bytes)
4570 }
4571
4572 ArmOp::I64RemU {
4577 rdlo,
4578 rdhi,
4579 rnlo,
4580 rnhi,
4581 rmlo,
4582 rmhi,
4583 } => {
4584 let mut bytes = Vec::new();
4585 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
4586 emit_i64_divisor_zero_trap(&mut bytes);
4587
4588 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4590 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4591
4592 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4594 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4595 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4597 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4598 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4600 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4601
4602 let loop_start = bytes.len();
4603
4604 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4608 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4614 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4617
4618 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4622 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4635 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4637
4638 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4641
4642 let branch_offset_bytes = bytes.len() - loop_start + 4;
4643 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4644 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4645 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4646
4647 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4653 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4654
4655 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4656 Ok(bytes)
4657 }
4658
4659 ArmOp::I64RemS {
4665 rdlo,
4666 rdhi,
4667 rnlo,
4668 rnhi,
4669 rmlo,
4670 rmhi,
4671 } => {
4672 let mut bytes = Vec::new();
4673 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
4674 emit_i64_divisor_zero_trap(&mut bytes);
4675
4676 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4678 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4679
4680 bytes.extend_from_slice(&0x4689u16.to_le_bytes()); bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
4694
4695 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
4705
4706 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4709 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4710 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4712 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4713 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4715 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4716
4717 let loop_start = bytes.len();
4718
4719 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4723 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4729 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4732
4733 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4737 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4750 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4752
4753 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4756
4757 let branch_offset_bytes = bytes.len() - loop_start + 4;
4758 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4759 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4760 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4761
4762 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
4769 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
4777
4778 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4780 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4781
4782 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4783 Ok(bytes)
4784 }
4785
4786 ArmOp::F32Add { sd, sn, sm } => {
4789 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
4790 }
4791 ArmOp::F32Sub { sd, sn, sm } => {
4792 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
4793 }
4794 ArmOp::F32Mul { sd, sn, sm } => {
4795 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
4796 }
4797 ArmOp::F32Div { sd, sn, sm } => {
4798 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
4799 }
4800 ArmOp::F32Abs { sd, sm } => {
4801 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
4802 }
4803 ArmOp::F32Neg { sd, sm } => {
4804 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
4805 }
4806 ArmOp::F32Sqrt { sd, sm } => {
4807 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
4808 }
4809
4810 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
4813 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
4814 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
4815 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
4816 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
4817 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
4818 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
4819
4820 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
4822 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
4823 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
4824 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
4825 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
4826 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
4827
4828 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
4829
4830 ArmOp::F32Load { sd, addr } => {
4831 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
4832 }
4833 ArmOp::F32Store { sd, addr } => {
4834 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
4835 }
4836
4837 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
4838 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
4839 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
4840 Err(synth_core::Error::synthesis(
4841 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
4842 ))
4843 }
4844 ArmOp::F32ReinterpretI32 { sd, rm } => {
4845 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
4846 }
4847 ArmOp::I32ReinterpretF32 { rd, sm } => {
4848 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
4849 }
4850 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
4851 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
4852
4853 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
4856 0xEE300B00, dd, dn, dm,
4857 )?)),
4858 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
4859 0xEE300B40, dd, dn, dm,
4860 )?)),
4861 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
4862 0xEE200B00, dd, dn, dm,
4863 )?)),
4864 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
4865 0xEE800B00, dd, dn, dm,
4866 )?)),
4867 ArmOp::F64Abs { dd, dm } => {
4868 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
4869 }
4870 ArmOp::F64Neg { dd, dm } => {
4871 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
4872 }
4873 ArmOp::F64Sqrt { dd, dm } => {
4874 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
4875 }
4876
4877 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
4880 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
4881 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
4882 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
4883 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
4884 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
4885 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
4886
4887 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
4889 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
4890 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
4891 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
4892 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
4893 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
4894
4895 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
4896
4897 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
4898 0xED900B00, dd, addr,
4899 )?)),
4900 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
4901 0xED800B00, dd, addr,
4902 )?)),
4903
4904 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
4905 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
4906 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
4907 Err(synth_core::Error::synthesis(
4908 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
4909 ))
4910 }
4911 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
4912 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
4913 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
4914 )),
4915 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
4916 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
4917 )),
4918 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
4919 Err(synth_core::Error::synthesis(
4920 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
4921 ))
4922 }
4923 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
4924 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
4925
4926 ArmOp::I64Add {
4930 rdlo,
4931 rdhi,
4932 rnlo,
4933 rnhi,
4934 rmlo,
4935 rmhi,
4936 } => {
4937 let mut bytes = Vec::new();
4938 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
4940 rd: *rdlo,
4941 rn: *rnlo,
4942 op2: Operand2::Reg(*rmlo),
4943 })?);
4944 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
4946 rd: *rdhi,
4947 rn: *rnhi,
4948 op2: Operand2::Reg(*rmhi),
4949 })?);
4950 Ok(bytes)
4951 }
4952
4953 ArmOp::I64Sub {
4955 rdlo,
4956 rdhi,
4957 rnlo,
4958 rnhi,
4959 rmlo,
4960 rmhi,
4961 } => {
4962 let mut bytes = Vec::new();
4963 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
4965 rd: *rdlo,
4966 rn: *rnlo,
4967 op2: Operand2::Reg(*rmlo),
4968 })?);
4969 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
4971 rd: *rdhi,
4972 rn: *rnhi,
4973 op2: Operand2::Reg(*rmhi),
4974 })?);
4975 Ok(bytes)
4976 }
4977
4978 ArmOp::I64And {
4980 rdlo,
4981 rdhi,
4982 rnlo,
4983 rnhi,
4984 rmlo,
4985 rmhi,
4986 } => {
4987 let mut bytes = Vec::new();
4988 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
4989 rd: *rdlo,
4990 rn: *rnlo,
4991 op2: Operand2::Reg(*rmlo),
4992 })?);
4993 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
4994 rd: *rdhi,
4995 rn: *rnhi,
4996 op2: Operand2::Reg(*rmhi),
4997 })?);
4998 Ok(bytes)
4999 }
5000
5001 ArmOp::I64Or {
5003 rdlo,
5004 rdhi,
5005 rnlo,
5006 rnhi,
5007 rmlo,
5008 rmhi,
5009 } => {
5010 let mut bytes = Vec::new();
5011 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5012 rd: *rdlo,
5013 rn: *rnlo,
5014 op2: Operand2::Reg(*rmlo),
5015 })?);
5016 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5017 rd: *rdhi,
5018 rn: *rnhi,
5019 op2: Operand2::Reg(*rmhi),
5020 })?);
5021 Ok(bytes)
5022 }
5023
5024 ArmOp::I64Xor {
5026 rdlo,
5027 rdhi,
5028 rnlo,
5029 rnhi,
5030 rmlo,
5031 rmhi,
5032 } => {
5033 let mut bytes = Vec::new();
5034 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5035 rd: *rdlo,
5036 rn: *rnlo,
5037 op2: Operand2::Reg(*rmlo),
5038 })?);
5039 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5040 rd: *rdhi,
5041 rn: *rnhi,
5042 op2: Operand2::Reg(*rmhi),
5043 })?);
5044 Ok(bytes)
5045 }
5046
5047 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
5049 rd: *rd,
5050 rn_lo: *rnlo,
5051 rn_hi: *rnhi,
5052 }),
5053
5054 ArmOp::I64Eq {
5056 rd,
5057 rnlo,
5058 rnhi,
5059 rmlo,
5060 rmhi,
5061 } => self.encode_thumb(&ArmOp::I64SetCond {
5062 rd: *rd,
5063 rn_lo: *rnlo,
5064 rn_hi: *rnhi,
5065 rm_lo: *rmlo,
5066 rm_hi: *rmhi,
5067 cond: synth_synthesis::Condition::EQ,
5068 }),
5069
5070 ArmOp::I64Ne {
5071 rd,
5072 rnlo,
5073 rnhi,
5074 rmlo,
5075 rmhi,
5076 } => self.encode_thumb(&ArmOp::I64SetCond {
5077 rd: *rd,
5078 rn_lo: *rnlo,
5079 rn_hi: *rnhi,
5080 rm_lo: *rmlo,
5081 rm_hi: *rmhi,
5082 cond: synth_synthesis::Condition::NE,
5083 }),
5084
5085 ArmOp::I64LtS {
5086 rd,
5087 rnlo,
5088 rnhi,
5089 rmlo,
5090 rmhi,
5091 } => self.encode_thumb(&ArmOp::I64SetCond {
5092 rd: *rd,
5093 rn_lo: *rnlo,
5094 rn_hi: *rnhi,
5095 rm_lo: *rmlo,
5096 rm_hi: *rmhi,
5097 cond: synth_synthesis::Condition::LT,
5098 }),
5099
5100 ArmOp::I64LtU {
5101 rd,
5102 rnlo,
5103 rnhi,
5104 rmlo,
5105 rmhi,
5106 } => self.encode_thumb(&ArmOp::I64SetCond {
5107 rd: *rd,
5108 rn_lo: *rnlo,
5109 rn_hi: *rnhi,
5110 rm_lo: *rmlo,
5111 rm_hi: *rmhi,
5112 cond: synth_synthesis::Condition::LO,
5113 }),
5114
5115 ArmOp::I64LeS {
5116 rd,
5117 rnlo,
5118 rnhi,
5119 rmlo,
5120 rmhi,
5121 } => self.encode_thumb(&ArmOp::I64SetCond {
5122 rd: *rd,
5123 rn_lo: *rnlo,
5124 rn_hi: *rnhi,
5125 rm_lo: *rmlo,
5126 rm_hi: *rmhi,
5127 cond: synth_synthesis::Condition::LE,
5128 }),
5129
5130 ArmOp::I64LeU {
5131 rd,
5132 rnlo,
5133 rnhi,
5134 rmlo,
5135 rmhi,
5136 } => self.encode_thumb(&ArmOp::I64SetCond {
5137 rd: *rd,
5138 rn_lo: *rnlo,
5139 rn_hi: *rnhi,
5140 rm_lo: *rmlo,
5141 rm_hi: *rmhi,
5142 cond: synth_synthesis::Condition::LS,
5143 }),
5144
5145 ArmOp::I64GtS {
5146 rd,
5147 rnlo,
5148 rnhi,
5149 rmlo,
5150 rmhi,
5151 } => self.encode_thumb(&ArmOp::I64SetCond {
5152 rd: *rd,
5153 rn_lo: *rnlo,
5154 rn_hi: *rnhi,
5155 rm_lo: *rmlo,
5156 rm_hi: *rmhi,
5157 cond: synth_synthesis::Condition::GT,
5158 }),
5159
5160 ArmOp::I64GtU {
5161 rd,
5162 rnlo,
5163 rnhi,
5164 rmlo,
5165 rmhi,
5166 } => self.encode_thumb(&ArmOp::I64SetCond {
5167 rd: *rd,
5168 rn_lo: *rnlo,
5169 rn_hi: *rnhi,
5170 rm_lo: *rmlo,
5171 rm_hi: *rmhi,
5172 cond: synth_synthesis::Condition::HI,
5173 }),
5174
5175 ArmOp::I64GeS {
5176 rd,
5177 rnlo,
5178 rnhi,
5179 rmlo,
5180 rmhi,
5181 } => self.encode_thumb(&ArmOp::I64SetCond {
5182 rd: *rd,
5183 rn_lo: *rnlo,
5184 rn_hi: *rnhi,
5185 rm_lo: *rmlo,
5186 rm_hi: *rmhi,
5187 cond: synth_synthesis::Condition::GE,
5188 }),
5189
5190 ArmOp::I64GeU {
5191 rd,
5192 rnlo,
5193 rnhi,
5194 rmlo,
5195 rmhi,
5196 } => self.encode_thumb(&ArmOp::I64SetCond {
5197 rd: *rd,
5198 rn_lo: *rnlo,
5199 rn_hi: *rnhi,
5200 rm_lo: *rmlo,
5201 rm_hi: *rmhi,
5202 cond: synth_synthesis::Condition::HS,
5203 }),
5204
5205 ArmOp::I64Const { rdlo, rdhi, value } => {
5207 let lo32 = *value as u32;
5208 let hi32 = (*value >> 32) as u32;
5209 let mut bytes = Vec::new();
5210 bytes.extend_from_slice(
5212 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
5213 );
5214 if lo32 > 0xFFFF {
5215 bytes.extend_from_slice(
5216 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
5217 );
5218 }
5219 bytes.extend_from_slice(
5221 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
5222 );
5223 if hi32 > 0xFFFF {
5224 bytes.extend_from_slice(
5225 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
5226 );
5227 }
5228 Ok(bytes)
5229 }
5230
5231 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
5233 let mut bytes = Vec::new();
5234 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5245 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
5246 bytes.extend_from_slice(&self.encode_thumb32_ldr(
5247 rdhi,
5248 &base,
5249 offset.wrapping_add(4),
5250 )?);
5251 Ok(bytes)
5252 }
5253
5254 ArmOp::I64Str { rdlo, rdhi, addr } => {
5256 let mut bytes = Vec::new();
5257 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5260 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
5261 bytes.extend_from_slice(&self.encode_thumb32_str(
5262 rdhi,
5263 &base,
5264 offset.wrapping_add(4),
5265 )?);
5266 Ok(bytes)
5267 }
5268
5269 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
5271 let mut bytes = Vec::new();
5272 if rdlo != rn {
5273 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5275 rd: *rdlo,
5276 op2: Operand2::Reg(*rn),
5277 })?);
5278 }
5279 bytes.extend_from_slice(
5281 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
5283 Ok(bytes)
5284 }
5285
5286 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
5288 let mut bytes = Vec::new();
5289 if rdlo != rn {
5290 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5292 rd: *rdlo,
5293 op2: Operand2::Reg(*rn),
5294 })?);
5295 }
5296 let rdhi_bits = reg_to_bits(rdhi) as u16;
5298 let instr: u16 = 0x2000 | (rdhi_bits << 8);
5299 bytes.extend_from_slice(&instr.to_le_bytes());
5300 Ok(bytes)
5301 }
5302
5303 ArmOp::I32WrapI64 { rd, rnlo } => {
5305 if rd == rnlo {
5306 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5309 } else {
5310 self.encode_thumb(&ArmOp::Mov {
5312 rd: *rd,
5313 op2: Operand2::Reg(*rnlo),
5314 })
5315 }
5316 }
5317
5318 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
5320 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
5321 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
5322 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5323 0xEF000150, qd, qn, qm,
5324 ))),
5325 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5326 0xEF200150, qd, qn, qm,
5327 ))),
5328 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5329 0xFF000150, qd, qn, qm,
5330 ))),
5331 ArmOp::MveMvn { qd, qm } => {
5332 let qd_enc = qreg_to_num(qd);
5334 let qm_enc = qreg_to_num(qm);
5335 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5336 Ok(vfp_to_thumb_bytes(instr))
5337 }
5338 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5339 0xEF100150, qd, qn, qm,
5340 ))),
5341 ArmOp::MveAddI { qd, qn, qm, size } => {
5342 let sz = mve_size_bits(size);
5343 let base: u32 = 0xEF000840 | (sz << 20);
5344 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5345 }
5346 ArmOp::MveSubI { qd, qn, qm, size } => {
5347 let sz = mve_size_bits(size);
5348 let base: u32 = 0xFF000840 | (sz << 20);
5349 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5350 }
5351 ArmOp::MveMulI { qd, qn, qm, size } => {
5352 let sz = mve_size_bits(size);
5353 let base: u32 = 0xEF000950 | (sz << 20);
5354 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5355 }
5356 ArmOp::MveNegI { qd, qm, size } => {
5357 let sz = mve_size_bits(size);
5358 let qd_enc = qreg_to_num(qd);
5360 let qm_enc = qreg_to_num(qm);
5361 let base: u32 = 0xFFB103C0 | (sz << 18);
5362 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
5363 Ok(vfp_to_thumb_bytes(instr))
5364 }
5365 ArmOp::MveDup { qd, rn, size } => {
5366 let sz = mve_size_bits(size);
5367 let qd_enc = qreg_to_num(qd);
5368 let rn_bits = reg_to_bits(rn);
5369 let be = match sz {
5372 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
5376 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
5377 Ok(vfp_to_thumb_bytes(instr))
5378 }
5379 ArmOp::MveExtractLane { rd, qn, lane, size } => {
5380 let qn_enc = qreg_to_num(qn);
5381 let rd_bits = reg_to_bits(rd);
5382 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
5385 let lane_in_d = (*lane as u32) & 1;
5386 let _sz = mve_size_bits(size);
5387 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
5389 Ok(vfp_to_thumb_bytes(instr))
5390 }
5391 ArmOp::MveInsertLane { qd, rn, lane, size } => {
5392 let qd_enc = qreg_to_num(qd);
5393 let rn_bits = reg_to_bits(rn);
5394 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
5395 let lane_in_d = (*lane as u32) & 1;
5396 let _sz = mve_size_bits(size);
5397 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
5399 Ok(vfp_to_thumb_bytes(instr))
5400 }
5401
5402 ArmOp::MveCmpEqI { qd, qn, qm, size }
5404 | ArmOp::MveCmpNeI { qd, qn, qm, size }
5405 | ArmOp::MveCmpLtS { qd, qn, qm, size }
5406 | ArmOp::MveCmpLtU { qd, qn, qm, size }
5407 | ArmOp::MveCmpGtS { qd, qn, qm, size }
5408 | ArmOp::MveCmpGtU { qd, qn, qm, size }
5409 | ArmOp::MveCmpLeS { qd, qn, qm, size }
5410 | ArmOp::MveCmpLeU { qd, qn, qm, size }
5411 | ArmOp::MveCmpGeS { qd, qn, qm, size }
5412 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
5413 let sz = mve_size_bits(size);
5416 let base: u32 = 0xEF000840 | (sz << 20);
5417 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5418 }
5419
5420 ArmOp::MveAddF32 { qd, qn, qm } => {
5422 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5424 }
5425 ArmOp::MveSubF32 { qd, qn, qm } => {
5426 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
5428 }
5429 ArmOp::MveMulF32 { qd, qn, qm } => {
5430 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
5432 }
5433 ArmOp::MveNegF32 { qd, qm } => {
5434 let qd_enc = qreg_to_num(qd);
5435 let qm_enc = qreg_to_num(qm);
5436 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5438 Ok(vfp_to_thumb_bytes(instr))
5439 }
5440 ArmOp::MveAbsF32 { qd, qm } => {
5441 let qd_enc = qreg_to_num(qd);
5442 let qm_enc = qreg_to_num(qm);
5443 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5445 Ok(vfp_to_thumb_bytes(instr))
5446 }
5447 ArmOp::MveCmpEqF32 { qd, qn, qm }
5448 | ArmOp::MveCmpNeF32 { qd, qn, qm }
5449 | ArmOp::MveCmpLtF32 { qd, qn, qm }
5450 | ArmOp::MveCmpLeF32 { qd, qn, qm }
5451 | ArmOp::MveCmpGtF32 { qd, qn, qm }
5452 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
5453 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5455 }
5456 ArmOp::MveDupF32 { qd, rn } => {
5457 let qd_enc = qreg_to_num(qd);
5458 let rn_bits = reg_to_bits(rn);
5459 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
5461 Ok(vfp_to_thumb_bytes(instr))
5462 }
5463 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
5464 let qn_enc = qreg_to_num(qn);
5465 let rd_bits = reg_to_bits(rd);
5466 let s_num = qn_enc * 4 + (*lane as u32);
5468 let (vn, n) = encode_sreg(s_num);
5469 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
5470 Ok(vfp_to_thumb_bytes(instr))
5471 }
5472 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
5473 let qd_enc = qreg_to_num(qd);
5474 let rn_bits = reg_to_bits(rn);
5475 let s_num = qd_enc * 4 + (*lane as u32);
5477 let (vn, n) = encode_sreg(s_num);
5478 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
5479 Ok(vfp_to_thumb_bytes(instr))
5480 }
5481 ArmOp::MveDivF32 { qd, qn, qm } => {
5482 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
5484 }
5485 ArmOp::MveSqrtF32 { qd, qm } => {
5486 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
5488 }
5489
5490 _ => {
5492 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5494 }
5495 }
5496 }
5497
5498 fn encode_thumb_f32_compare(
5502 &self,
5503 rd: &Reg,
5504 sn: &VfpReg,
5505 sm: &VfpReg,
5506 cond_code: u32,
5507 ) -> Result<Vec<u8>> {
5508 let mut bytes = Vec::new();
5509 let rd_bits = reg_to_bits(rd);
5510
5511 let sn_num = vfp_sreg_to_num(sn)?;
5513 let sm_num = vfp_sreg_to_num(sm)?;
5514 let (vd, d) = encode_sreg(sn_num);
5515 let (vm, m) = encode_sreg(sm_num);
5516 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5517 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5518
5519 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5521
5522 if rd_bits < 8 {
5524 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5525 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5526 } else {
5527 let hw1: u16 = 0xF04F;
5529 let hw2: u16 = (rd_bits as u16) << 8;
5530 bytes.extend_from_slice(&hw1.to_le_bytes());
5531 bytes.extend_from_slice(&hw2.to_le_bytes());
5532 }
5533
5534 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5538 bytes.extend_from_slice(&it.to_le_bytes());
5539
5540 if rd_bits < 8 {
5542 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5543 bytes.extend_from_slice(&mov_one.to_le_bytes());
5544 } else {
5545 let hw1: u16 = 0xF04F;
5547 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5548 bytes.extend_from_slice(&hw1.to_le_bytes());
5549 bytes.extend_from_slice(&hw2.to_le_bytes());
5550 }
5551
5552 Ok(bytes)
5553 }
5554
5555 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
5557 let mut bytes = Vec::new();
5558 let bits = value.to_bits();
5559 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
5564 let imm4 = (lo16 >> 12) & 0xF;
5565 let i_bit = (lo16 >> 11) & 1;
5566 let imm3 = (lo16 >> 8) & 0x7;
5567 let imm8 = lo16 & 0xFF;
5568 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
5569 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5570 bytes.extend_from_slice(&hw1.to_le_bytes());
5571 bytes.extend_from_slice(&hw2.to_le_bytes());
5572
5573 let hi16 = (bits >> 16) & 0xFFFF;
5575 let imm4 = (hi16 >> 12) & 0xF;
5576 let i_bit = (hi16 >> 11) & 1;
5577 let imm3 = (hi16 >> 8) & 0x7;
5578 let imm8 = hi16 & 0xFF;
5579 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
5580 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5581 bytes.extend_from_slice(&hw1.to_le_bytes());
5582 bytes.extend_from_slice(&hw2.to_le_bytes());
5583
5584 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
5586 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5587
5588 Ok(bytes)
5589 }
5590
5591 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
5593 let mut bytes = Vec::new();
5594
5595 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
5597 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5598
5599 let sd_num = vfp_sreg_to_num(sd)?;
5601 let (vd, d) = encode_sreg(sd_num);
5602 let (vm, m) = encode_sreg(sd_num);
5603 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
5604 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
5605 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
5606
5607 Ok(bytes)
5608 }
5609
5610 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
5618 let mut bytes = Vec::new();
5619 let sm_num = vfp_sreg_to_num(sm)?;
5620 let sd_num = vfp_sreg_to_num(sd)?;
5621 let (vd_s, d_s) = encode_sreg(sd_num);
5622 let (vm_s, m_s) = encode_sreg(sm_num);
5623
5624 if mode == 0b11 {
5625 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5627 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5628 } else {
5629 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
5634 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5635
5636 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
5642 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5643 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5644
5645 if mode != 0 {
5647 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
5649 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
5650 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
5651 }
5652
5653 let vmsr = 0xEEE10A10 | (rt << 12);
5655 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5656
5657 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5659 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5660
5661 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5663 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5664 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5665 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5666 }
5667
5668 let (vd2, d2) = encode_sreg(sd_num);
5670 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
5671 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
5672
5673 Ok(bytes)
5674 }
5675
5676 fn encode_thumb_f32_minmax(
5678 &self,
5679 sd: &VfpReg,
5680 sn: &VfpReg,
5681 sm: &VfpReg,
5682 is_min: bool,
5683 ) -> Result<Vec<u8>> {
5684 let mut bytes = Vec::new();
5685 let sn_num = vfp_sreg_to_num(sn)?;
5686 let sm_num = vfp_sreg_to_num(sm)?;
5687 let sd_num = vfp_sreg_to_num(sd)?;
5688
5689 let (vd, d) = encode_sreg(sd_num);
5691 let (vn, n) = encode_sreg(sn_num);
5692 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
5693 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
5694
5695 let (vm, m) = encode_sreg(sm_num);
5697 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
5698 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5699
5700 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5702
5703 let cond: u16 = if is_min { 0xC } else { 0x4 };
5705 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
5706 bytes.extend_from_slice(&it.to_le_bytes());
5707
5708 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5710 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
5711
5712 Ok(bytes)
5713 }
5714
5715 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
5717 let mut bytes = Vec::new();
5718
5719 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5721 false,
5722 sm,
5723 &Reg::R12,
5724 )?));
5725
5726 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5728 false,
5729 sn,
5730 &Reg::R0,
5731 )?));
5732
5733 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5745 bytes.extend_from_slice(&hw2.to_le_bytes());
5746
5747 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5751 bytes.extend_from_slice(&hw2.to_le_bytes());
5752
5753 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
5757 bytes.extend_from_slice(&hw2.to_le_bytes());
5758
5759 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5761 true,
5762 sd,
5763 &Reg::R0,
5764 )?));
5765
5766 Ok(bytes)
5767 }
5768
5769 fn encode_thumb_f64_compare(
5771 &self,
5772 rd: &Reg,
5773 dn: &VfpReg,
5774 dm: &VfpReg,
5775 cond_code: u32,
5776 ) -> Result<Vec<u8>> {
5777 let mut bytes = Vec::new();
5778 let rd_bits = reg_to_bits(rd);
5779
5780 let dn_num = vfp_dreg_to_num(dn)?;
5782 let dm_num = vfp_dreg_to_num(dm)?;
5783 let (vd, d) = encode_dreg(dn_num);
5784 let (vm, m) = encode_dreg(dm_num);
5785 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5786 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5787
5788 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5790
5791 if rd_bits < 8 {
5793 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5794 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5795 } else {
5796 let hw1: u16 = 0xF04F;
5797 let hw2: u16 = (rd_bits as u16) << 8;
5798 bytes.extend_from_slice(&hw1.to_le_bytes());
5799 bytes.extend_from_slice(&hw2.to_le_bytes());
5800 }
5801
5802 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5804 bytes.extend_from_slice(&it.to_le_bytes());
5805
5806 if rd_bits < 8 {
5808 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5809 bytes.extend_from_slice(&mov_one.to_le_bytes());
5810 } else {
5811 let hw1: u16 = 0xF04F;
5812 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5813 bytes.extend_from_slice(&hw1.to_le_bytes());
5814 bytes.extend_from_slice(&hw2.to_le_bytes());
5815 }
5816
5817 Ok(bytes)
5818 }
5819
5820 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
5822 let mut bytes = Vec::new();
5823 let bits = value.to_bits();
5824 let lo32 = bits as u32;
5825 let hi32 = (bits >> 32) as u32;
5826
5827 let lo16 = lo32 & 0xFFFF;
5829 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
5830
5831 let hi16 = (lo32 >> 16) & 0xFFFF;
5833 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
5834
5835 let lo16 = hi32 & 0xFFFF;
5837 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
5838
5839 let hi16 = (hi32 >> 16) & 0xFFFF;
5841 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
5842
5843 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
5845 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5846
5847 Ok(bytes)
5848 }
5849
5850 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
5852 let mut bytes = Vec::new();
5853
5854 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
5856 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5857
5858 let dd_num = vfp_dreg_to_num(dd)?;
5860 let (vd, d) = encode_dreg(dd_num);
5861 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
5862 let vcvt = base | (d << 22) | (vd << 12);
5863 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
5864
5865 Ok(bytes)
5866 }
5867
5868 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
5870 let dd_num = vfp_dreg_to_num(dd)?;
5871 let sm_num = vfp_sreg_to_num(sm)?;
5872 let (vd, d) = encode_dreg(dd_num);
5873 let (vm, m) = encode_sreg(sm_num);
5874
5875 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
5876 Ok(vfp_to_thumb_bytes(vcvt))
5877 }
5878
5879 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
5881 let mut bytes = Vec::new();
5882 let dm_num = vfp_dreg_to_num(dm)?;
5883 let (vm, m) = encode_dreg(dm_num);
5884
5885 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
5887 let vcvt = base | (m << 5) | vm;
5888 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
5889
5890 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
5892 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5893
5894 Ok(bytes)
5895 }
5896
5897 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
5901 let mut bytes = Vec::new();
5902 let dm_num = vfp_dreg_to_num(dm)?;
5903 let dd_num = vfp_dreg_to_num(dd)?;
5904 let (vm, m) = encode_dreg(dm_num);
5905 let (vd, d) = encode_dreg(dd_num);
5906
5907 if mode == 0b11 {
5908 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
5910 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5911 } else {
5912 let rt: u32 = 12;
5913
5914 let vmrs = 0xEEF10A10 | (rt << 12);
5916 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5917
5918 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
5920 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
5921 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5922 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5923
5924 if mode != 0 {
5926 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
5927 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
5928 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
5929 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
5930 }
5931
5932 let vmsr = 0xEEE10A10 | (rt << 12);
5934 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5935
5936 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
5938 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5939
5940 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5942 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5943 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5944 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5945 }
5946
5947 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
5949 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
5950
5951 Ok(bytes)
5952 }
5953
5954 fn encode_thumb_f64_minmax(
5956 &self,
5957 dd: &VfpReg,
5958 dn: &VfpReg,
5959 dm: &VfpReg,
5960 is_min: bool,
5961 ) -> Result<Vec<u8>> {
5962 let mut bytes = Vec::new();
5963 let dn_num = vfp_dreg_to_num(dn)?;
5964 let dm_num = vfp_dreg_to_num(dm)?;
5965 let dd_num = vfp_dreg_to_num(dd)?;
5966
5967 let (vd, d) = encode_dreg(dd_num);
5969 let (vn, n) = encode_dreg(dn_num);
5970 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
5971 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
5972
5973 let (vm, m) = encode_dreg(dm_num);
5975 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
5976 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5977
5978 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5980
5981 let cond: u16 = if is_min { 0xC } else { 0x4 };
5983 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
5984 bytes.extend_from_slice(&it.to_le_bytes());
5985
5986 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5988 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
5989
5990 Ok(bytes)
5991 }
5992
5993 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
5995 let mut bytes = Vec::new();
5996
5997 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
5999 false,
6000 dm,
6001 &Reg::R0,
6002 &Reg::R12,
6003 )?));
6004
6005 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6007 false,
6008 dn,
6009 &Reg::R1,
6010 &Reg::R2,
6011 )?));
6012
6013 let hw1: u16 = 0xF000 | 12;
6015 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
6016 bytes.extend_from_slice(&hw1.to_le_bytes());
6017 bytes.extend_from_slice(&hw2.to_le_bytes());
6018
6019 let hw1: u16 = 0xF020 | 2;
6021 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
6022 bytes.extend_from_slice(&hw1.to_le_bytes());
6023 bytes.extend_from_slice(&hw2.to_le_bytes());
6024
6025 let hw1: u16 = 0xEA40 | 2;
6027 let hw2: u16 = (2 << 8) | 12;
6028 bytes.extend_from_slice(&hw1.to_le_bytes());
6029 bytes.extend_from_slice(&hw2.to_le_bytes());
6030
6031 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6033 true,
6034 dd,
6035 &Reg::R1,
6036 &Reg::R2,
6037 )?));
6038
6039 Ok(bytes)
6040 }
6041
6042 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6044 let mut bytes = Vec::new();
6045
6046 let sm_num = vfp_sreg_to_num(sm)?;
6047 let (vd, d) = encode_sreg(sm_num);
6048 let (vm, m) = encode_sreg(sm_num);
6049 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
6050 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6051 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6052
6053 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
6055 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6056
6057 Ok(bytes)
6058 }
6059
6060 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6064 let rd_bits = reg_to_bits(rd);
6065 let rn_bits = reg_to_bits(rn);
6066
6067 let i_bit = (imm >> 11) & 1;
6069 let imm3 = (imm >> 8) & 0x7;
6070 let imm8 = imm & 0xFF;
6071
6072 let hw1_base = if imm <= 0xFF {
6073 0xF100
6077 } else if imm <= 0xFFF {
6078 0xF200
6082 } else {
6083 return Err(synth_core::Error::synthesis(
6084 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6085 ));
6086 };
6087
6088 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6089 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6090
6091 let mut bytes = hw1.to_le_bytes().to_vec();
6092 bytes.extend_from_slice(&hw2.to_le_bytes());
6093 Ok(bytes)
6094 }
6095
6096 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6098 let rd_bits = reg_to_bits(rd);
6099 let rn_bits = reg_to_bits(rn);
6100
6101 let i_bit = (imm >> 11) & 1;
6102 let imm3 = (imm >> 8) & 0x7;
6103 let imm8 = imm & 0xFF;
6104
6105 let hw1_base = if imm <= 0xFF {
6106 0xF1A0
6109 } else if imm <= 0xFFF {
6110 0xF2A0
6113 } else {
6114 return Err(synth_core::Error::synthesis(
6115 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6116 ));
6117 };
6118
6119 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6120 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6121
6122 let mut bytes = hw1.to_le_bytes().to_vec();
6123 bytes.extend_from_slice(&hw2.to_le_bytes());
6124 Ok(bytes)
6125 }
6126
6127 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6129 let rd_bits = reg_to_bits(rd);
6130 let rn_bits = reg_to_bits(rn);
6131
6132 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6135 synth_core::Error::synthesis(
6136 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
6137 )
6138 })?;
6139 let i_bit = (field >> 11) & 1;
6140 let imm3 = (field >> 8) & 0x7;
6141 let imm8 = field & 0xFF;
6142
6143 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
6146 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6147
6148 let mut bytes = hw1.to_le_bytes().to_vec();
6149 bytes.extend_from_slice(&hw2.to_le_bytes());
6150 Ok(bytes)
6151 }
6152
6153 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6155 let rd_bits = reg_to_bits(rd);
6156 let rn_bits = reg_to_bits(rn);
6157
6158 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6161 synth_core::Error::synthesis(
6162 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
6163 )
6164 })?;
6165 let i_bit = (field >> 11) & 1;
6166 let imm3 = (field >> 8) & 0x7;
6167 let imm8 = field & 0xFF;
6168
6169 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6172 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6173
6174 let mut bytes = hw1.to_le_bytes().to_vec();
6175 bytes.extend_from_slice(&hw2.to_le_bytes());
6176 Ok(bytes)
6177 }
6178
6179 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
6188 let rd_bits = reg_to_bits(rd);
6189 reg_bits_checked(rd_bits)?;
6190 let imm16 = imm & 0xFFFF;
6191
6192 let imm4 = (imm16 >> 12) & 0xF;
6195 let i_bit = (imm16 >> 11) & 1;
6196 let imm3 = (imm16 >> 8) & 0x7;
6197 let imm8 = imm16 & 0xFF;
6198
6199 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6200 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6201
6202 let mut bytes = hw1.to_le_bytes().to_vec();
6203 bytes.extend_from_slice(&hw2.to_le_bytes());
6204 encoding_contracts::verify_thumb32(&bytes);
6205 Ok(bytes)
6206 }
6207
6208 fn encode_thumb32_shift(
6216 &self,
6217 rd: &Reg,
6218 rm: &Reg,
6219 shift: u32,
6220 shift_type: u8,
6221 ) -> Result<Vec<u8>> {
6222 let rd_bits = reg_to_bits(rd);
6223 let rm_bits = reg_to_bits(rm);
6224 reg_bits_checked(rd_bits)?;
6225 reg_bits_checked(rm_bits)?;
6226 let imm5 = shift & 0x1F;
6227 let imm2 = imm5 & 0x3;
6228 let imm3 = (imm5 >> 2) & 0x7;
6229
6230 let hw1: u16 = 0xEA4F;
6233 let hw2: u16 =
6234 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
6235 as u16;
6236
6237 let mut bytes = hw1.to_le_bytes().to_vec();
6238 bytes.extend_from_slice(&hw2.to_le_bytes());
6239 Ok(bytes)
6240 }
6241
6242 fn encode_thumb32_shift_reg(
6246 &self,
6247 rd: &Reg,
6248 rn: &Reg,
6249 rm: &Reg,
6250 shift_type: u8,
6251 ) -> Result<Vec<u8>> {
6252 let rd_bits = reg_to_bits(rd);
6253 let rn_bits = reg_to_bits(rn);
6254 let rm_bits = reg_to_bits(rm);
6255
6256 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
6258 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
6260
6261 let mut bytes = hw1.to_le_bytes().to_vec();
6262 bytes.extend_from_slice(&hw2.to_le_bytes());
6263 Ok(bytes)
6264 }
6265
6266 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6268 let rn_bits = reg_to_bits(rn);
6269
6270 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6274 synth_core::Error::synthesis(
6275 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
6276 )
6277 })?;
6278 let i_bit = (field >> 11) & 1;
6279 let imm3 = (field >> 8) & 0x7;
6280 let imm8 = field & 0xFF;
6281
6282 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6284 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
6285
6286 let mut bytes = hw1.to_le_bytes().to_vec();
6287 bytes.extend_from_slice(&hw2.to_le_bytes());
6288 Ok(bytes)
6289 }
6290
6291 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
6313 let offset = if addr.offset < 0 {
6314 0u32
6315 } else {
6316 addr.offset as u32
6317 };
6318 match addr.offset_reg {
6319 Some(idx) => {
6320 let ip = Reg::R12;
6321 if offset.wrapping_add(4) > 0xFFF {
6322 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
6326 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
6328 reg_to_bits(&ip),
6329 reg_to_bits(&ip),
6330 reg_to_bits(&addr.base),
6331 )?);
6332 Ok((ip, 0))
6333 } else {
6334 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
6336 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
6337 bytes.extend_from_slice(&hw1.to_le_bytes());
6338 bytes.extend_from_slice(&hw2.to_le_bytes());
6339 Ok((ip, offset))
6340 }
6341 }
6342 None => Ok((addr.base, offset)),
6343 }
6344 }
6345
6346 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6348 let rd_bits = reg_to_bits(rd);
6349 let base_bits = reg_to_bits(base);
6350
6351 check_ldst_imm12(offset)?;
6353 let hw1: u16 = (0xF8D0 | base_bits) as u16;
6354 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6355
6356 let mut bytes = hw1.to_le_bytes().to_vec();
6357 bytes.extend_from_slice(&hw2.to_le_bytes());
6358 Ok(bytes)
6359 }
6360
6361 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6363 let rd_bits = reg_to_bits(rd);
6364 let base_bits = reg_to_bits(base);
6365
6366 check_ldst_imm12(offset)?;
6368 let hw1: u16 = (0xF8C0 | base_bits) as u16;
6369 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6370
6371 let mut bytes = hw1.to_le_bytes().to_vec();
6372 bytes.extend_from_slice(&hw2.to_le_bytes());
6373 Ok(bytes)
6374 }
6375
6376 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6378 let rd_bits = reg_to_bits(rd);
6379 let base_bits = reg_to_bits(base);
6380 let rm_bits = reg_to_bits(offset_reg);
6381
6382 let hw1: u16 = (0xF850 | base_bits) as u16;
6386 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6387
6388 let mut bytes = hw1.to_le_bytes().to_vec();
6389 bytes.extend_from_slice(&hw2.to_le_bytes());
6390 Ok(bytes)
6391 }
6392
6393 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6395 let rd_bits = reg_to_bits(rd);
6396 let base_bits = reg_to_bits(base);
6397 let rm_bits = reg_to_bits(offset_reg);
6398
6399 let hw1: u16 = (0xF840 | base_bits) as u16;
6403 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6404
6405 let mut bytes = hw1.to_le_bytes().to_vec();
6406 bytes.extend_from_slice(&hw2.to_le_bytes());
6407 Ok(bytes)
6408 }
6409
6410 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6414 let rd_bits = reg_to_bits(rd);
6415 let base_bits = reg_to_bits(base);
6416 check_ldst_imm12(offset)?;
6418 let hw1: u16 = (0xF890 | base_bits) as u16;
6419 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6420 let mut bytes = hw1.to_le_bytes().to_vec();
6421 bytes.extend_from_slice(&hw2.to_le_bytes());
6422 Ok(bytes)
6423 }
6424
6425 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6427 let rd_bits = reg_to_bits(rd);
6428 let base_bits = reg_to_bits(base);
6429 let rm_bits = reg_to_bits(offset_reg);
6430 let hw1: u16 = (0xF810 | base_bits) as u16;
6432 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6433 let mut bytes = hw1.to_le_bytes().to_vec();
6434 bytes.extend_from_slice(&hw2.to_le_bytes());
6435 Ok(bytes)
6436 }
6437
6438 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6440 let rd_bits = reg_to_bits(rd);
6441 let base_bits = reg_to_bits(base);
6442 check_ldst_imm12(offset)?;
6444 let hw1: u16 = (0xF990 | base_bits) as u16;
6445 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6446 let mut bytes = hw1.to_le_bytes().to_vec();
6447 bytes.extend_from_slice(&hw2.to_le_bytes());
6448 Ok(bytes)
6449 }
6450
6451 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6453 let rd_bits = reg_to_bits(rd);
6454 let base_bits = reg_to_bits(base);
6455 let rm_bits = reg_to_bits(offset_reg);
6456 let hw1: u16 = (0xF910 | base_bits) as u16;
6458 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6459 let mut bytes = hw1.to_le_bytes().to_vec();
6460 bytes.extend_from_slice(&hw2.to_le_bytes());
6461 Ok(bytes)
6462 }
6463
6464 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6466 let rd_bits = reg_to_bits(rd);
6467 let base_bits = reg_to_bits(base);
6468 check_ldst_imm12(offset)?;
6470 let hw1: u16 = (0xF8B0 | base_bits) as u16;
6471 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6472 let mut bytes = hw1.to_le_bytes().to_vec();
6473 bytes.extend_from_slice(&hw2.to_le_bytes());
6474 Ok(bytes)
6475 }
6476
6477 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6479 let rd_bits = reg_to_bits(rd);
6480 let base_bits = reg_to_bits(base);
6481 let rm_bits = reg_to_bits(offset_reg);
6482 let hw1: u16 = (0xF830 | base_bits) as u16;
6484 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6485 let mut bytes = hw1.to_le_bytes().to_vec();
6486 bytes.extend_from_slice(&hw2.to_le_bytes());
6487 Ok(bytes)
6488 }
6489
6490 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6492 let rd_bits = reg_to_bits(rd);
6493 let base_bits = reg_to_bits(base);
6494 check_ldst_imm12(offset)?;
6496 let hw1: u16 = (0xF9B0 | base_bits) as u16;
6497 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6498 let mut bytes = hw1.to_le_bytes().to_vec();
6499 bytes.extend_from_slice(&hw2.to_le_bytes());
6500 Ok(bytes)
6501 }
6502
6503 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6505 let rd_bits = reg_to_bits(rd);
6506 let base_bits = reg_to_bits(base);
6507 let rm_bits = reg_to_bits(offset_reg);
6508 let hw1: u16 = (0xF930 | base_bits) as u16;
6510 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6511 let mut bytes = hw1.to_le_bytes().to_vec();
6512 bytes.extend_from_slice(&hw2.to_le_bytes());
6513 Ok(bytes)
6514 }
6515
6516 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6518 let rd_bits = reg_to_bits(rd);
6519 let base_bits = reg_to_bits(base);
6520 check_ldst_imm12(offset)?;
6522 let hw1: u16 = (0xF880 | base_bits) as u16;
6523 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6524 let mut bytes = hw1.to_le_bytes().to_vec();
6525 bytes.extend_from_slice(&hw2.to_le_bytes());
6526 Ok(bytes)
6527 }
6528
6529 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6531 let rd_bits = reg_to_bits(rd);
6532 let base_bits = reg_to_bits(base);
6533 let rm_bits = reg_to_bits(offset_reg);
6534 let hw1: u16 = (0xF800 | base_bits) as u16;
6536 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6537 let mut bytes = hw1.to_le_bytes().to_vec();
6538 bytes.extend_from_slice(&hw2.to_le_bytes());
6539 Ok(bytes)
6540 }
6541
6542 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6544 let rd_bits = reg_to_bits(rd);
6545 let base_bits = reg_to_bits(base);
6546 check_ldst_imm12(offset)?;
6548 let hw1: u16 = (0xF8A0 | base_bits) as u16;
6549 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6550 let mut bytes = hw1.to_le_bytes().to_vec();
6551 bytes.extend_from_slice(&hw2.to_le_bytes());
6552 Ok(bytes)
6553 }
6554
6555 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6557 let rd_bits = reg_to_bits(rd);
6558 let base_bits = reg_to_bits(base);
6559 let rm_bits = reg_to_bits(offset_reg);
6560 let hw1: u16 = (0xF820 | base_bits) as u16;
6562 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6563 let mut bytes = hw1.to_le_bytes().to_vec();
6564 bytes.extend_from_slice(&hw2.to_le_bytes());
6565 Ok(bytes)
6566 }
6567
6568 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6570 let rd_bits = reg_to_bits(rd);
6571 let rn_bits = reg_to_bits(rn);
6572
6573 if imm <= 0xFFF {
6579 let i_bit = (imm >> 11) & 1;
6580 let imm3 = (imm >> 8) & 0x7;
6581 let imm8 = imm & 0xFF;
6582
6583 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
6584 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6585
6586 let mut bytes = hw1.to_le_bytes().to_vec();
6587 bytes.extend_from_slice(&hw2.to_le_bytes());
6588 Ok(bytes)
6589 } else {
6590 let scratch: u32 = if rd_bits == rn_bits {
6604 12 } else {
6606 rd_bits };
6608 if scratch == rn_bits {
6616 return Err(synth_core::Error::synthesis(format!(
6617 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
6618 register (R12 is the reserved encoder scratch and aliases Rn here)"
6619 )));
6620 }
6621
6622 let lo16 = imm & 0xFFFF;
6623 let hi16 = (imm >> 16) & 0xFFFF;
6624
6625 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
6626 if hi16 != 0 {
6627 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
6628 }
6629 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
6630 Ok(bytes)
6631 }
6632 }
6633
6634 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6644 reg_bits_checked(rd)?;
6645 encoding_contracts::verify_imm16(imm16);
6646 let imm16 = imm16 & 0xFFFF;
6649 let imm4 = (imm16 >> 12) & 0xF;
6650 let i_bit = (imm16 >> 11) & 1;
6651 let imm3 = (imm16 >> 8) & 0x7;
6652 let imm8 = imm16 & 0xFF;
6653
6654 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6655 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6656
6657 let mut bytes = hw1.to_le_bytes().to_vec();
6658 bytes.extend_from_slice(&hw2.to_le_bytes());
6659 encoding_contracts::verify_thumb32(&bytes);
6660 Ok(bytes)
6661 }
6662
6663 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6671 reg_bits_checked(rd)?;
6672 encoding_contracts::verify_imm16(imm16);
6673 let imm16 = imm16 & 0xFFFF;
6676 let imm4 = (imm16 >> 12) & 0xF;
6677 let i_bit = (imm16 >> 11) & 1;
6678 let imm3 = (imm16 >> 8) & 0x7;
6679 let imm8 = imm16 & 0xFF;
6680
6681 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6682 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6683
6684 let mut bytes = hw1.to_le_bytes().to_vec();
6685 bytes.extend_from_slice(&hw2.to_le_bytes());
6686 encoding_contracts::verify_thumb32(&bytes);
6687 Ok(bytes)
6688 }
6689
6690 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
6692 let imm5 = shift & 0x1F;
6695 let imm2 = imm5 & 0x3;
6696 let imm3 = (imm5 >> 2) & 0x7;
6697
6698 let hw1: u16 = 0xEA4F;
6699 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
6700
6701 let mut bytes = hw1.to_le_bytes().to_vec();
6702 bytes.extend_from_slice(&hw2.to_le_bytes());
6703 Ok(bytes)
6704 }
6705
6706 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6708 let hw1: u16 = (0xEA00 | rn) as u16;
6711 let hw2: u16 = ((rd << 8) | rm) as u16;
6712
6713 let mut bytes = hw1.to_le_bytes().to_vec();
6714 bytes.extend_from_slice(&hw2.to_le_bytes());
6715 Ok(bytes)
6716 }
6717
6718 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
6720 let i_bit = (imm >> 11) & 1;
6724 let imm3 = (imm >> 8) & 0x7;
6725 let imm8 = imm & 0xFF;
6726
6727 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
6728 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6729
6730 let mut bytes = hw1.to_le_bytes().to_vec();
6731 bytes.extend_from_slice(&hw2.to_le_bytes());
6732 Ok(bytes)
6733 }
6734
6735 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6737 let hw1: u16 = (0xEBA0 | rn) as u16;
6740 let hw2: u16 = ((rd << 8) | rm) as u16;
6741
6742 let mut bytes = hw1.to_le_bytes().to_vec();
6743 bytes.extend_from_slice(&hw2.to_le_bytes());
6744 Ok(bytes)
6745 }
6746
6747 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6749 let hw1: u16 = (0xEB00 | rn) as u16;
6752 let hw2: u16 = ((rd << 8) | rm) as u16;
6753
6754 let mut bytes = hw1.to_le_bytes().to_vec();
6755 bytes.extend_from_slice(&hw2.to_le_bytes());
6756 Ok(bytes)
6757 }
6758
6759 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6763 let hw1: u16 = (0xEB10 | rn) as u16;
6765 let hw2: u16 = ((rd << 8) | rm) as u16;
6766 let mut bytes = hw1.to_le_bytes().to_vec();
6767 bytes.extend_from_slice(&hw2.to_le_bytes());
6768 Ok(bytes)
6769 }
6770
6771 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6774 let hw1: u16 = (0xEBB0 | rn) as u16;
6776 let hw2: u16 = ((rd << 8) | rm) as u16;
6777 let mut bytes = hw1.to_le_bytes().to_vec();
6778 bytes.extend_from_slice(&hw2.to_le_bytes());
6779 Ok(bytes)
6780 }
6781
6782 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
6784 let mut code = Vec::new();
6785
6786 for op in ops {
6787 let encoded = self.encode(op)?;
6788 code.extend_from_slice(&encoded);
6789 }
6790
6791 Ok(code)
6792 }
6793}
6794
6795fn try_thumb_expand_imm(value: u32) -> Option<u32> {
6803 if value <= 0xFF {
6805 return Some(value);
6806 }
6807 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
6811 return Some(0x100 | b0);
6812 }
6813 if value == (b1 << 24) | (b1 << 8) {
6815 return Some(0x200 | b1);
6816 }
6817 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
6819 return Some(0x300 | b0);
6820 }
6821 for rot in 8..=31u32 {
6825 let unrot = value.rotate_left(rot);
6826 if (0x80..=0xFF).contains(&unrot) {
6827 return Some((rot << 7) | (unrot & 0x7F));
6828 }
6829 }
6830 None
6831}
6832
6833fn check_ldst_imm12(offset: u32) -> Result<()> {
6839 if offset > 0xFFF {
6840 Err(synth_core::Error::synthesis(
6841 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
6842 ))
6843 } else {
6844 Ok(())
6845 }
6846}
6847
6848fn reg_to_bits(reg: &Reg) -> u32 {
6849 match reg {
6850 Reg::R0 => 0,
6851 Reg::R1 => 1,
6852 Reg::R2 => 2,
6853 Reg::R3 => 3,
6854 Reg::R4 => 4,
6855 Reg::R5 => 5,
6856 Reg::R6 => 6,
6857 Reg::R7 => 7,
6858 Reg::R8 => 8,
6859 Reg::R9 => 9,
6860 Reg::R10 => 10,
6861 Reg::R11 => 11,
6862 Reg::R12 => 12,
6863 Reg::SP => 13,
6864 Reg::LR => 14,
6865 Reg::PC => 15,
6866 }
6867}
6868
6869fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
6900 debug_assert!(srcs.len() <= 4);
6901 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
6903 for src in srcs.iter().rev() {
6905 let rt = reg_to_bits(src) as u16;
6906 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
6907 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
6908 }
6909 for i in 0..srcs.len() as u16 {
6911 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
6912 }
6913}
6914
6915fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
6919 let lo = reg_to_bits(rdlo);
6920 let hi = reg_to_bits(rdhi);
6921 if lo == 1 && hi == 0 {
6922 return Err(synth_core::Error::synthesis(
6925 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
6926 ));
6927 }
6928 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
6929 let d = ((rd >> 3) & 1) as u16;
6930 bytes.extend_from_slice(
6931 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
6932 );
6933 };
6934 if hi == 0 {
6935 mov16(bytes, lo, 0);
6937 mov16(bytes, hi, 1);
6938 } else {
6939 mov16(bytes, hi, 1);
6941 mov16(bytes, lo, 0);
6942 }
6943 for i in 0..4u32 {
6944 if i == lo || i == hi {
6945 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
6948 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
6950 }
6951 Ok(())
6952}
6953
6954fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
6958 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
6960 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
6963
6964fn reg_bits_checked(bits: u32) -> Result<()> {
6972 if bits > 14 {
6973 return Err(synth_core::Error::synthesis(format!(
6974 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
6975 )));
6976 }
6977 Ok(())
6978}
6979
6980fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
6983 if val == 0 {
6984 return Some((0, 1));
6985 }
6986 for rot in 0..16u32 {
6987 let shift = rot * 2;
6988 let unrotated = val.rotate_left(shift);
6990 if unrotated <= 0xFF {
6991 return Some(((rot << 8) | unrotated, 1));
6993 }
6994 }
6995 None
6996}
6997
6998fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
7003 match op2 {
7004 Operand2::Imm(val) => {
7005 let uval = *val as u32;
7006 if let Some(encoded) = try_encode_rotated_imm(uval) {
7008 Ok(encoded)
7009 } else {
7010 Err(synth_core::Error::synthesis(format!(
7019 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
7020 rotated immediate — the selector must materialize large \
7021 constants via MOVW/MOVT"
7022 )))
7023 }
7024 }
7025
7026 Operand2::Reg(reg) => {
7027 let reg_bits = reg_to_bits(reg);
7028 Ok((reg_bits, 0)) }
7030
7031 Operand2::RegShift {
7032 rm,
7033 shift: _,
7034 amount,
7035 } => {
7036 let rm_bits = reg_to_bits(rm);
7038 let shift_bits = (*amount & 0x1F) << 7;
7039 Ok((shift_bits | rm_bits, 0))
7040 }
7041 }
7042}
7043
7044fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
7046 let base_bits = reg_to_bits(&addr.base);
7047 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
7049}
7050
7051fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
7053 match reg {
7054 VfpReg::S0 => Ok(0),
7055 VfpReg::S1 => Ok(1),
7056 VfpReg::S2 => Ok(2),
7057 VfpReg::S3 => Ok(3),
7058 VfpReg::S4 => Ok(4),
7059 VfpReg::S5 => Ok(5),
7060 VfpReg::S6 => Ok(6),
7061 VfpReg::S7 => Ok(7),
7062 VfpReg::S8 => Ok(8),
7063 VfpReg::S9 => Ok(9),
7064 VfpReg::S10 => Ok(10),
7065 VfpReg::S11 => Ok(11),
7066 VfpReg::S12 => Ok(12),
7067 VfpReg::S13 => Ok(13),
7068 VfpReg::S14 => Ok(14),
7069 VfpReg::S15 => Ok(15),
7070 VfpReg::S16 => Ok(16),
7071 VfpReg::S17 => Ok(17),
7072 VfpReg::S18 => Ok(18),
7073 VfpReg::S19 => Ok(19),
7074 VfpReg::S20 => Ok(20),
7075 VfpReg::S21 => Ok(21),
7076 VfpReg::S22 => Ok(22),
7077 VfpReg::S23 => Ok(23),
7078 VfpReg::S24 => Ok(24),
7079 VfpReg::S25 => Ok(25),
7080 VfpReg::S26 => Ok(26),
7081 VfpReg::S27 => Ok(27),
7082 VfpReg::S28 => Ok(28),
7083 VfpReg::S29 => Ok(29),
7084 VfpReg::S30 => Ok(30),
7085 VfpReg::S31 => Ok(31),
7086 _ => Err(synth_core::Error::SynthesisError(
7088 "D-register not supported in single-precision VFP encoding".to_string(),
7089 )),
7090 }
7091}
7092
7093fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
7095 match reg {
7096 VfpReg::D0 => Ok(0),
7097 VfpReg::D1 => Ok(1),
7098 VfpReg::D2 => Ok(2),
7099 VfpReg::D3 => Ok(3),
7100 VfpReg::D4 => Ok(4),
7101 VfpReg::D5 => Ok(5),
7102 VfpReg::D6 => Ok(6),
7103 VfpReg::D7 => Ok(7),
7104 VfpReg::D8 => Ok(8),
7105 VfpReg::D9 => Ok(9),
7106 VfpReg::D10 => Ok(10),
7107 VfpReg::D11 => Ok(11),
7108 VfpReg::D12 => Ok(12),
7109 VfpReg::D13 => Ok(13),
7110 VfpReg::D14 => Ok(14),
7111 VfpReg::D15 => Ok(15),
7112 _ => Err(synth_core::Error::SynthesisError(
7114 "S-register not supported in double-precision VFP encoding".to_string(),
7115 )),
7116 }
7117}
7118
7119fn encode_sreg(s: u32) -> (u32, u32) {
7123 (s >> 1, s & 1)
7124}
7125
7126fn encode_dreg(d: u32) -> (u32, u32) {
7130 (d & 0xF, (d >> 4) & 1)
7131}
7132
7133fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
7139 let sd_num = vfp_sreg_to_num(sd)?;
7140 let sn_num = vfp_sreg_to_num(sn)?;
7141 let sm_num = vfp_sreg_to_num(sm)?;
7142 let (vd, d) = encode_sreg(sd_num);
7143 let (vn, n) = encode_sreg(sn_num);
7144 let (vm, m) = encode_sreg(sm_num);
7145
7146 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7147}
7148
7149fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
7152 let sd_num = vfp_sreg_to_num(sd)?;
7153 let sm_num = vfp_sreg_to_num(sm)?;
7154 let (vd, d) = encode_sreg(sd_num);
7155 let (vm, m) = encode_sreg(sm_num);
7156
7157 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7158}
7159
7160fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7164 let sd_num = vfp_sreg_to_num(sd)?;
7165 let (vd, d) = encode_sreg(sd_num);
7166 let rn = reg_to_bits(&addr.base);
7167
7168 let offset = addr.offset;
7169 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7170 let abs_offset = offset.unsigned_abs();
7171 let imm8 = (abs_offset / 4) & 0xFF;
7172
7173 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7174}
7175
7176fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
7180 let s_num = vfp_sreg_to_num(sreg)?;
7181 let (vn, n) = encode_sreg(s_num);
7182 let rt = reg_to_bits(core);
7183
7184 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
7185 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
7186}
7187
7188fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
7192 let dd_num = vfp_dreg_to_num(dd)?;
7193 let dn_num = vfp_dreg_to_num(dn)?;
7194 let dm_num = vfp_dreg_to_num(dm)?;
7195 let (vd, d) = encode_dreg(dd_num);
7196 let (vn, n) = encode_dreg(dn_num);
7197 let (vm, m) = encode_dreg(dm_num);
7198
7199 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7200}
7201
7202fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
7204 let dd_num = vfp_dreg_to_num(dd)?;
7205 let dm_num = vfp_dreg_to_num(dm)?;
7206 let (vd, d) = encode_dreg(dd_num);
7207 let (vm, m) = encode_dreg(dm_num);
7208
7209 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7210}
7211
7212fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7215 let dd_num = vfp_dreg_to_num(dd)?;
7216 let (vd, d) = encode_dreg(dd_num);
7217 let rn = reg_to_bits(&addr.base);
7218
7219 let offset = addr.offset;
7220 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7221 let abs_offset = offset.unsigned_abs();
7222 let imm8 = (abs_offset / 4) & 0xFF;
7223
7224 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7225}
7226
7227fn encode_vmov_core_dreg(
7231 to_dreg: bool,
7232 dreg: &VfpReg,
7233 core_lo: &Reg,
7234 core_hi: &Reg,
7235) -> Result<u32> {
7236 let d_num = vfp_dreg_to_num(dreg)?;
7237 let (vm, m) = encode_dreg(d_num);
7238 let rt = reg_to_bits(core_lo);
7239 let rt2 = reg_to_bits(core_hi);
7240
7241 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
7242 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
7243}
7244
7245fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
7247 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
7248 let hw2 = (instr & 0xFFFF) as u16;
7249 let mut bytes = hw1.to_le_bytes().to_vec();
7250 bytes.extend_from_slice(&hw2.to_le_bytes());
7251 bytes
7252}
7253
7254fn qreg_to_num(reg: &QReg) -> u32 {
7260 match reg {
7261 QReg::Q0 => 0,
7262 QReg::Q1 => 1,
7263 QReg::Q2 => 2,
7264 QReg::Q3 => 3,
7265 QReg::Q4 => 4,
7266 QReg::Q5 => 5,
7267 QReg::Q6 => 6,
7268 QReg::Q7 => 7,
7269 }
7270}
7271
7272fn mve_size_bits(size: &MveSize) -> u32 {
7274 match size {
7275 MveSize::S8 => 0b00,
7276 MveSize::S16 => 0b01,
7277 MveSize::S32 => 0b10,
7278 }
7279}
7280
7281fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7285 let d = qreg_to_num(qd) * 2;
7286 let n = qreg_to_num(qn) * 2;
7287 let m = qreg_to_num(qm) * 2;
7288
7289 let vd = d & 0xF;
7294 let d_bit = (d >> 4) & 1;
7295 let vn = n & 0xF;
7296 let n_bit = (n >> 4) & 1;
7297 let vm = m & 0xF;
7298 let m_bit = (m >> 4) & 1;
7299
7300 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
7301}
7302
7303fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7305 encode_mve_3reg(base, qd, qn, qm)
7306}
7307
7308fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
7311 let qd_enc = qreg_to_num(qd) * 2;
7312 let rn = reg_to_bits(&addr.base);
7313 let offset = addr.offset;
7314 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7315 let abs_offset = offset.unsigned_abs();
7316 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
7320 | (u_bit << 23)
7321 | ((qd_enc >> 4) << 22)
7322 | (rn << 16)
7323 | ((qd_enc & 0xF) << 12)
7324 | (imm7 & 0x7F)
7325}
7326
7327fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
7329 let qd_enc = qreg_to_num(qd) * 2;
7330 let rn = reg_to_bits(&addr.base);
7331 let offset = addr.offset;
7332 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7333 let abs_offset = offset.unsigned_abs();
7334 let imm7 = (abs_offset / 4) & 0x7F;
7335
7336 0xED000E80
7337 | (u_bit << 23)
7338 | ((qd_enc >> 4) << 22)
7339 | (rn << 16)
7340 | ((qd_enc & 0xF) << 12)
7341 | (imm7 & 0x7F)
7342}
7343
7344impl ArmEncoder {
7345 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
7347 let mut result = Vec::new();
7348 let qd_num = qreg_to_num(qd);
7349
7350 for i in 0..4 {
7352 let word = u32::from_le_bytes([
7353 bytes[i * 4],
7354 bytes[i * 4 + 1],
7355 bytes[i * 4 + 2],
7356 bytes[i * 4 + 3],
7357 ]);
7358 let lo16 = word & 0xFFFF;
7359 let hi16 = (word >> 16) & 0xFFFF;
7360
7361 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7363 if hi16 != 0 {
7365 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7366 }
7367
7368 let s_num = qd_num * 4 + i as u32;
7370 let (vn, n) = encode_sreg(s_num);
7371 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
7372 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7373 }
7374
7375 Ok(result)
7376 }
7377
7378 fn encode_thumb_mve_lane_wise_f32_binop(
7380 &self,
7381 qd: &QReg,
7382 qn: &QReg,
7383 qm: &QReg,
7384 vfp_base: u32,
7385 ) -> Result<Vec<u8>> {
7386 let mut result = Vec::new();
7387 let qd_num = qreg_to_num(qd);
7388 let qn_num = qreg_to_num(qn);
7389 let qm_num = qreg_to_num(qm);
7390
7391 for i in 0..4u32 {
7393 let sd = qd_num * 4 + i;
7394 let sn = qn_num * 4 + i;
7395 let sm = qm_num * 4 + i;
7396
7397 let (vd, d) = encode_sreg(sd);
7398 let (vn, n) = encode_sreg(sn);
7399 let (vm, m) = encode_sreg(sm);
7400
7401 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7402 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7403 }
7404
7405 Ok(result)
7406 }
7407
7408 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
7410 let mut result = Vec::new();
7411 let qd_num = qreg_to_num(qd);
7412 let qm_num = qreg_to_num(qm);
7413
7414 for i in 0..4u32 {
7416 let sd = qd_num * 4 + i;
7417 let sm = qm_num * 4 + i;
7418
7419 let (vd, d) = encode_sreg(sd);
7420 let (vm, m) = encode_sreg(sm);
7421
7422 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7423 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7424 }
7425
7426 Ok(result)
7427 }
7428}
7429
7430#[cfg(test)]
7431mod tests {
7432 use super::*;
7433
7434 #[test]
7435 fn test_encoder_creation() {
7436 let encoder_arm = ArmEncoder::new_arm32();
7437 assert!(!encoder_arm.thumb_mode);
7438
7439 let encoder_thumb = ArmEncoder::new_thumb2();
7440 assert!(encoder_thumb.thumb_mode);
7441 }
7442
7443 #[test]
7455 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
7456 use synth_synthesis::{ArmOp, Condition, Reg};
7457 let enc = ArmEncoder::new_thumb2();
7458 let bytes = enc
7459 .encode(&ArmOp::I64SetCond {
7460 rd: Reg::R8,
7461 rn_lo: Reg::R2,
7462 rn_hi: Reg::R3,
7463 rm_lo: Reg::R6,
7464 rm_hi: Reg::R7,
7465 cond: Condition::EQ,
7466 })
7467 .unwrap();
7468 let halfwords: Vec<u16> = bytes
7471 .chunks(2)
7472 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7473 .collect();
7474 assert!(
7475 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
7476 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
7477 );
7478 assert!(
7479 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
7480 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
7481 );
7482
7483 let bytes_z = enc
7484 .encode(&ArmOp::I64SetCondZ {
7485 rd: Reg::R8,
7486 rn_lo: Reg::R2,
7487 rn_hi: Reg::R3,
7488 })
7489 .unwrap();
7490 let hw_z: Vec<u16> = bytes_z
7491 .chunks(2)
7492 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7493 .collect();
7494 assert!(
7495 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
7496 "SetCondZ high rd MOV.W: {hw_z:04x?}"
7497 );
7498 assert!(
7500 hw_z.contains(&(0xF1B0 | 8)),
7501 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
7502 );
7503 }
7504
7505 #[test]
7506 fn test_encode_setcond_high_reg_uses_mov_w_204() {
7507 use synth_synthesis::{ArmOp, Condition, Reg};
7508 let enc = ArmEncoder::new_thumb2();
7509 let hi = enc
7511 .encode(&ArmOp::SetCond {
7512 rd: Reg::R12,
7513 cond: Condition::NE,
7514 })
7515 .unwrap();
7516 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
7517 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
7519 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
7520 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
7521 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
7522 let lo = enc
7524 .encode(&ArmOp::SetCond {
7525 rd: Reg::R0,
7526 cond: Condition::NE,
7527 })
7528 .unwrap();
7529 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
7530 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
7531 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
7532 }
7533
7534 #[test]
7538 fn test_encode_umull_209b() {
7539 use synth_synthesis::{ArmOp, Reg};
7540 let op = ArmOp::Umull {
7541 rdlo: Reg::R4,
7542 rdhi: Reg::R5,
7543 rn: Reg::R0,
7544 rm: Reg::R3,
7545 };
7546 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
7548 assert_eq!(
7549 t,
7550 vec![0xA0, 0xFB, 0x03, 0x45],
7551 "umull r4,r5,r0,r3 (T2): {t:02x?}"
7552 );
7553 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
7555 assert_eq!(
7556 a,
7557 0xE085_4390u32.to_le_bytes().to_vec(),
7558 "umull (A32): {a:02x?}"
7559 );
7560 }
7561
7562 #[test]
7569 fn test_encode_arm32_indexed_load_keeps_index_206() {
7570 use synth_synthesis::{ArmOp, MemAddr, Reg};
7571 let enc = ArmEncoder::new_arm32();
7572 let bytes = enc
7574 .encode(&ArmOp::Ldr {
7575 rd: Reg::R0,
7576 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
7577 })
7578 .unwrap();
7579 assert_eq!(
7580 bytes.len(),
7581 8,
7582 "expected ADD ip + LDR (2 words): {bytes:02x?}"
7583 );
7584 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7585 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7586 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
7588 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
7590 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
7592 }
7593
7594 #[test]
7600 fn test_encode_arm32_call_indirect_is_real_call_594() {
7601 use synth_synthesis::{ArmOp, Reg};
7602 let enc = ArmEncoder::new_arm32();
7603 let bytes = enc
7604 .encode(&ArmOp::CallIndirect {
7605 rd: Reg::R0,
7606 type_idx: 0,
7607 table_index_reg: Reg::R0,
7608 })
7609 .unwrap();
7610 assert_eq!(
7611 bytes.len(),
7612 12,
7613 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
7614 );
7615 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7616 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7617 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
7618 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
7620 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
7622 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
7624 assert!(
7626 !bytes
7627 .chunks_exact(4)
7628 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
7629 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
7630 );
7631
7632 let bytes = enc
7634 .encode(&ArmOp::CallIndirect {
7635 rd: Reg::R0,
7636 type_idx: 0,
7637 table_index_reg: Reg::R4,
7638 })
7639 .unwrap();
7640 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7641 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
7642 }
7643
7644 #[test]
7660 fn test_encode_thumb_call_indirect_lsl2_597() {
7661 use synth_synthesis::{ArmOp, Reg};
7662 let enc = ArmEncoder::new_thumb2();
7663 let bytes = enc
7664 .encode(&ArmOp::CallIndirect {
7665 rd: Reg::R0,
7666 type_idx: 0,
7667 table_index_reg: Reg::R0,
7668 })
7669 .unwrap();
7670 assert_eq!(
7671 bytes,
7672 vec![0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
7673 "Thumb-2 CallIndirect: mov.w ip,r0,LSL#2; ldr.w ip,[r11,ip]; blx ip: {bytes:02x?}"
7674 );
7675 assert_ne!(
7677 &bytes[0..4],
7678 &[0x4F, 0xEA, 0x20, 0x0C],
7679 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
7680 );
7681
7682 let bytes = enc
7684 .encode(&ArmOp::CallIndirect {
7685 rd: Reg::R0,
7686 type_idx: 0,
7687 table_index_reg: Reg::R4,
7688 })
7689 .unwrap();
7690 assert_eq!(
7691 &bytes[0..4],
7692 &[0x4F, 0xEA, 0x84, 0x0C],
7693 "mov.w ip, r4, LSL #2: {bytes:02x?}"
7694 );
7695 }
7696
7697 #[test]
7704 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
7705 let encoder = ArmEncoder::new_thumb2();
7706
7707 let code = encoder
7709 .encode(&ArmOp::Add {
7710 rd: Reg::R12,
7711 rn: Reg::R12,
7712 op2: Operand2::Reg(Reg::R0),
7713 })
7714 .unwrap();
7715 assert_eq!(
7717 code,
7718 vec![0x0C, 0xEB, 0x00, 0x0C],
7719 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
7720 );
7721 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
7723
7724 let lo = encoder
7726 .encode(&ArmOp::Add {
7727 rd: Reg::R1,
7728 rn: Reg::R2,
7729 op2: Operand2::Reg(Reg::R3),
7730 })
7731 .unwrap();
7732 assert_eq!(
7733 lo.len(),
7734 2,
7735 "low-reg ADD should remain 16-bit, got {lo:02X?}"
7736 );
7737 }
7738
7739 #[test]
7742 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
7743 let encoder = ArmEncoder::new_thumb2();
7744
7745 let adds = encoder
7747 .encode(&ArmOp::Adds {
7748 rd: Reg::R10,
7749 rn: Reg::R10,
7750 op2: Operand2::Reg(Reg::R8),
7751 })
7752 .unwrap();
7753 assert_eq!(
7754 adds,
7755 vec![0x1A, 0xEB, 0x08, 0x0A],
7756 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
7757 );
7758
7759 let subs = encoder
7761 .encode(&ArmOp::Subs {
7762 rd: Reg::R10,
7763 rn: Reg::R10,
7764 op2: Operand2::Reg(Reg::R8),
7765 })
7766 .unwrap();
7767 assert_eq!(
7768 subs,
7769 vec![0xBA, 0xEB, 0x08, 0x0A],
7770 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
7771 );
7772 }
7773
7774 #[test]
7777 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
7778 let encoder = ArmEncoder::new_thumb2();
7779
7780 let cmn = encoder
7782 .encode(&ArmOp::Cmn {
7783 rn: Reg::R10,
7784 op2: Operand2::Reg(Reg::R8),
7785 })
7786 .unwrap();
7787 assert_eq!(
7788 cmn,
7789 vec![0x1A, 0xEB, 0x08, 0x0F],
7790 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
7791 );
7792
7793 let lo = encoder
7795 .encode(&ArmOp::Cmn {
7796 rn: Reg::R1,
7797 op2: Operand2::Reg(Reg::R2),
7798 })
7799 .unwrap();
7800 assert_eq!(
7801 lo.len(),
7802 2,
7803 "low-reg CMN should remain 16-bit, got {lo:02X?}"
7804 );
7805 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
7806 }
7807
7808 #[test]
7812 fn test_encode_pc_operand_returns_err_not_panic_185() {
7813 let encoder = ArmEncoder::new_thumb2();
7814 for op in [
7815 ArmOp::Sdiv {
7816 rd: Reg::PC,
7817 rn: Reg::R0,
7818 rm: Reg::R1,
7819 },
7820 ArmOp::Udiv {
7821 rd: Reg::R0,
7822 rn: Reg::PC,
7823 rm: Reg::R1,
7824 },
7825 ArmOp::Sdiv {
7826 rd: Reg::R0,
7827 rn: Reg::R1,
7828 rm: Reg::PC,
7829 },
7830 ] {
7831 let r = encoder.encode(&op);
7832 assert!(
7833 r.is_err(),
7834 "encode({op:?}) must return Err for a PC operand, got {r:?}"
7835 );
7836 }
7837 assert!(
7839 encoder
7840 .encode(&ArmOp::Sdiv {
7841 rd: Reg::R0,
7842 rn: Reg::R1,
7843 rm: Reg::R2
7844 })
7845 .is_ok()
7846 );
7847 }
7848
7849 #[test]
7850 fn test_encode_nop_arm32() {
7851 let encoder = ArmEncoder::new_arm32();
7852 let code = encoder.encode(&ArmOp::Nop).unwrap();
7853
7854 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
7857
7858 #[test]
7859 fn test_encode_nop_thumb() {
7860 let encoder = ArmEncoder::new_thumb2();
7861 let code = encoder.encode(&ArmOp::Nop).unwrap();
7862
7863 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
7866
7867 #[test]
7868 fn test_encode_mov_immediate_arm32() {
7869 let encoder = ArmEncoder::new_arm32();
7870 let op = ArmOp::Mov {
7871 rd: Reg::R0,
7872 op2: Operand2::Imm(42),
7873 };
7874
7875 let code = encoder.encode(&op).unwrap();
7876 assert_eq!(code.len(), 4);
7877
7878 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7880 assert_eq!(instr & 0x0E000000, 0x02000000); }
7882
7883 #[test]
7884 fn test_encode_add_registers_arm32() {
7885 let encoder = ArmEncoder::new_arm32();
7886 let op = ArmOp::Add {
7887 rd: Reg::R0,
7888 rn: Reg::R1,
7889 op2: Operand2::Reg(Reg::R2),
7890 };
7891
7892 let code = encoder.encode(&op).unwrap();
7893 assert_eq!(code.len(), 4);
7894
7895 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7896 assert_eq!(instr & 0x0FE00000, 0x00800000);
7898 }
7899
7900 #[test]
7904 fn test_encode_add_imm_large_350() {
7905 let enc = ArmEncoder::new_thumb2();
7906
7907 let small = enc
7909 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
7910 .unwrap();
7911 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
7912
7913 fn movx_imm16(b: &[u8]) -> u32 {
7915 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
7916 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
7917 let imm4 = hw1 & 0xF;
7918 let i = (hw1 >> 10) & 1;
7919 let imm3 = (hw2 >> 12) & 0x7;
7920 let imm8 = hw2 & 0xFF;
7921 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
7922 }
7923 fn movx_rd(b: &[u8]) -> u32 {
7924 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
7925 }
7926
7927 let seq = enc
7930 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
7931 .unwrap();
7932 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
7933 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
7935 assert_eq!(movx_rd(&seq[0..4]), 12);
7936 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
7937 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
7939 assert_eq!(movx_rd(&seq[4..8]), 12);
7940 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
7941 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
7943 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
7944 assert_eq!(add1 & 0xFFF0, 0xEB00);
7945 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
7950 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
7951 70000
7952 );
7953
7954 let seq16 = enc
7956 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
7957 .unwrap();
7958 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
7959 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
7960 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
7965 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
7966 .unwrap();
7967 assert_eq!(inplace.len(), 12);
7968 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
7969 assert_eq!(
7970 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
7971 0x12345
7972 );
7973 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
7975 assert_eq!(ip_add2 & 0xF, 12);
7976 assert_eq!((ip_add2 >> 8) & 0xF, 5);
7977 }
7978
7979 #[test]
7987 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
7988 let enc = ArmEncoder::new_thumb2();
7989 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
7991 assert!(
7992 r.is_err(),
7993 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
7994 );
7995 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
7999 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
8000 }
8001
8002 #[test]
8011 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
8012 let enc = ArmEncoder::new_arm32();
8013 let bad = enc.encode(&ArmOp::Add {
8014 rd: Reg::R0,
8015 rn: Reg::R1,
8016 op2: Operand2::Imm(0x1FF),
8017 });
8018 assert!(
8019 bad.is_err(),
8020 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
8021 to 0xFF), got {bad:?}"
8022 );
8023 let ok = enc.encode(&ArmOp::Add {
8025 rd: Reg::R0,
8026 rn: Reg::R1,
8027 op2: Operand2::Imm(0xFF),
8028 });
8029 assert!(
8030 ok.is_ok(),
8031 "0xFF is a valid rotated immediate, must stay Ok"
8032 );
8033 }
8034
8035 #[test]
8036 fn test_encode_ldr_arm32() {
8037 let encoder = ArmEncoder::new_arm32();
8038 let op = ArmOp::Ldr {
8039 rd: Reg::R0,
8040 addr: MemAddr::imm(Reg::R1, 4),
8041 };
8042
8043 let code = encoder.encode(&op).unwrap();
8044 assert_eq!(code.len(), 4);
8045
8046 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8047 assert_eq!(instr & 0x00100000, 0x00100000);
8049 }
8050
8051 #[test]
8052 fn test_encode_str_arm32() {
8053 let encoder = ArmEncoder::new_arm32();
8054 let op = ArmOp::Str {
8055 rd: Reg::R0,
8056 addr: MemAddr::imm(Reg::SP, 0),
8057 };
8058
8059 let code = encoder.encode(&op).unwrap();
8060 assert_eq!(code.len(), 4);
8061 }
8062
8063 #[test]
8064 fn test_encode_branch_arm32() {
8065 let encoder = ArmEncoder::new_arm32();
8066 let op = ArmOp::Bl {
8067 label: "main".to_string(),
8068 };
8069
8070 let code = encoder.encode(&op).unwrap();
8071 assert_eq!(code.len(), 4);
8072
8073 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8074 assert_eq!(instr & 0x0F000000, 0x0B000000);
8076 }
8077
8078 #[test]
8088 fn test_encode_thumb_bl_placeholder_addend_167_174() {
8089 let encoder = ArmEncoder::new_thumb2();
8090 let op = ArmOp::Bl {
8091 label: "callee".to_string(),
8092 };
8093
8094 let code = encoder.encode(&op).unwrap();
8095 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
8096
8097 let hw1 = u16::from_le_bytes([code[0], code[1]]);
8098 let hw2 = u16::from_le_bytes([code[2], code[3]]);
8099 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
8100 assert_eq!(
8101 hw2, 0xFFFE,
8102 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
8103 );
8104 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
8105 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
8106 }
8107
8108 #[test]
8109 fn test_encode_sequence() {
8110 let encoder = ArmEncoder::new_arm32();
8111 let ops = vec![
8112 ArmOp::Mov {
8113 rd: Reg::R0,
8114 op2: Operand2::Imm(42),
8115 },
8116 ArmOp::Mov {
8117 rd: Reg::R1,
8118 op2: Operand2::Imm(10),
8119 },
8120 ArmOp::Add {
8121 rd: Reg::R2,
8122 rn: Reg::R0,
8123 op2: Operand2::Reg(Reg::R1),
8124 },
8125 ];
8126
8127 let code = encoder.encode_sequence(&ops).unwrap();
8128 assert_eq!(code.len(), 12); }
8130
8131 #[test]
8132 fn test_reg_to_bits() {
8133 assert_eq!(reg_to_bits(&Reg::R0), 0);
8134 assert_eq!(reg_to_bits(&Reg::R7), 7);
8135 assert_eq!(reg_to_bits(&Reg::SP), 13);
8136 assert_eq!(reg_to_bits(&Reg::LR), 14);
8137 assert_eq!(reg_to_bits(&Reg::PC), 15);
8138 }
8139
8140 #[test]
8141 fn test_encode_bitwise_operations() {
8142 let encoder = ArmEncoder::new_arm32();
8143
8144 let and_op = ArmOp::And {
8145 rd: Reg::R0,
8146 rn: Reg::R1,
8147 op2: Operand2::Reg(Reg::R2),
8148 };
8149 let and_code = encoder.encode(&and_op).unwrap();
8150 assert_eq!(and_code.len(), 4);
8151
8152 let orr_op = ArmOp::Orr {
8153 rd: Reg::R0,
8154 rn: Reg::R1,
8155 op2: Operand2::Reg(Reg::R2),
8156 };
8157 let orr_code = encoder.encode(&orr_op).unwrap();
8158 assert_eq!(orr_code.len(), 4);
8159
8160 let eor_op = ArmOp::Eor {
8161 rd: Reg::R0,
8162 rn: Reg::R1,
8163 op2: Operand2::Reg(Reg::R2),
8164 };
8165 let eor_code = encoder.encode(&eor_op).unwrap();
8166 assert_eq!(eor_code.len(), 4);
8167 }
8168
8169 #[test]
8172 fn test_encode_sdiv_thumb2() {
8173 let encoder = ArmEncoder::new_thumb2();
8174 let op = ArmOp::Sdiv {
8175 rd: Reg::R0,
8176 rn: Reg::R1,
8177 rm: Reg::R2,
8178 };
8179
8180 let code = encoder.encode(&op).unwrap();
8181 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
8188 assert_eq!(code[1], 0xFB);
8189 assert_eq!(code[2], 0xF2);
8190 assert_eq!(code[3], 0xF0);
8191 }
8192
8193 #[test]
8194 fn test_encode_udiv_thumb2() {
8195 let encoder = ArmEncoder::new_thumb2();
8196 let op = ArmOp::Udiv {
8197 rd: Reg::R0,
8198 rn: Reg::R1,
8199 rm: Reg::R2,
8200 };
8201
8202 let code = encoder.encode(&op).unwrap();
8203 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
8208 assert_eq!(code[1], 0xFB);
8209 assert_eq!(code[2], 0xF2);
8210 assert_eq!(code[3], 0xF0);
8211 }
8212
8213 #[test]
8214 fn test_encode_mul_thumb2() {
8215 let encoder = ArmEncoder::new_thumb2();
8216 let op = ArmOp::Mul {
8217 rd: Reg::R0,
8218 rn: Reg::R1,
8219 rm: Reg::R2,
8220 };
8221
8222 let code = encoder.encode(&op).unwrap();
8223 assert_eq!(code.len(), 4); }
8225
8226 #[test]
8227 fn test_encode_and_thumb2() {
8228 let encoder = ArmEncoder::new_thumb2();
8229 let op = ArmOp::And {
8230 rd: Reg::R0,
8231 rn: Reg::R1,
8232 op2: Operand2::Reg(Reg::R2),
8233 };
8234
8235 let code = encoder.encode(&op).unwrap();
8236 assert_eq!(code.len(), 4); }
8238
8239 #[test]
8240 fn test_encode_lsl_thumb2_low_regs() {
8241 let encoder = ArmEncoder::new_thumb2();
8242 let op = ArmOp::Lsl {
8243 rd: Reg::R0,
8244 rn: Reg::R1,
8245 shift: 5,
8246 };
8247
8248 let code = encoder.encode(&op).unwrap();
8249 assert_eq!(code.len(), 2); }
8251
8252 #[test]
8253 fn test_encode_clz_thumb2() {
8254 let encoder = ArmEncoder::new_thumb2();
8255 let op = ArmOp::Clz {
8256 rd: Reg::R0,
8257 rm: Reg::R1,
8258 };
8259
8260 let code = encoder.encode(&op).unwrap();
8261 assert_eq!(code.len(), 4); }
8263
8264 #[test]
8265 fn test_encode_bx_thumb2() {
8266 let encoder = ArmEncoder::new_thumb2();
8267 let op = ArmOp::Bx { rm: Reg::LR };
8268
8269 let code = encoder.encode(&op).unwrap();
8270 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
8274 }
8275
8276 #[test]
8281 fn test_encode_f32_abs_arm32() {
8282 let encoder = ArmEncoder::new_arm32();
8283 let op = ArmOp::F32Abs {
8284 sd: VfpReg::S0,
8285 sm: VfpReg::S2,
8286 };
8287 let code = encoder.encode(&op).unwrap();
8288 assert_eq!(code.len(), 4); }
8290
8291 #[test]
8292 fn test_encode_f32_neg_arm32() {
8293 let encoder = ArmEncoder::new_arm32();
8294 let op = ArmOp::F32Neg {
8295 sd: VfpReg::S0,
8296 sm: VfpReg::S2,
8297 };
8298 let code = encoder.encode(&op).unwrap();
8299 assert_eq!(code.len(), 4);
8300 }
8301
8302 #[test]
8303 fn test_encode_f32_sqrt_arm32() {
8304 let encoder = ArmEncoder::new_arm32();
8305 let op = ArmOp::F32Sqrt {
8306 sd: VfpReg::S0,
8307 sm: VfpReg::S2,
8308 };
8309 let code = encoder.encode(&op).unwrap();
8310 assert_eq!(code.len(), 4);
8311 }
8312
8313 #[test]
8314 fn test_encode_f32_ceil_arm32() {
8315 let encoder = ArmEncoder::new_arm32();
8316 let op = ArmOp::F32Ceil {
8317 sd: VfpReg::S0,
8318 sm: VfpReg::S2,
8319 };
8320 let code = encoder.encode(&op).unwrap();
8321 assert_eq!(code.len(), 36);
8323 }
8324
8325 #[test]
8326 fn test_encode_f32_floor_thumb2() {
8327 let encoder = ArmEncoder::new_thumb2();
8328 let op = ArmOp::F32Floor {
8329 sd: VfpReg::S0,
8330 sm: VfpReg::S2,
8331 };
8332 let code = encoder.encode(&op).unwrap();
8333 assert_eq!(code.len(), 36);
8335 }
8336
8337 #[test]
8338 fn test_encode_f32_min_arm32() {
8339 let encoder = ArmEncoder::new_arm32();
8340 let op = ArmOp::F32Min {
8341 sd: VfpReg::S0,
8342 sn: VfpReg::S2,
8343 sm: VfpReg::S4,
8344 };
8345 let code = encoder.encode(&op).unwrap();
8346 assert_eq!(code.len(), 16); }
8348
8349 #[test]
8350 fn test_encode_f32_max_thumb2() {
8351 let encoder = ArmEncoder::new_thumb2();
8352 let op = ArmOp::F32Max {
8353 sd: VfpReg::S0,
8354 sn: VfpReg::S2,
8355 sm: VfpReg::S4,
8356 };
8357 let code = encoder.encode(&op).unwrap();
8358 assert_eq!(code.len(), 18);
8360 }
8361
8362 #[test]
8363 fn test_encode_f32_copysign_arm32() {
8364 let encoder = ArmEncoder::new_arm32();
8365 let op = ArmOp::F32Copysign {
8366 sd: VfpReg::S0,
8367 sn: VfpReg::S2,
8368 sm: VfpReg::S4,
8369 };
8370 let code = encoder.encode(&op).unwrap();
8371 assert_eq!(code.len(), 24);
8373 }
8374
8375 #[test]
8380 fn test_encode_f64_add_arm32() {
8381 let encoder = ArmEncoder::new_arm32();
8382 let op = ArmOp::F64Add {
8383 dd: VfpReg::D0,
8384 dn: VfpReg::D1,
8385 dm: VfpReg::D2,
8386 };
8387 let code = encoder.encode(&op).unwrap();
8388 assert_eq!(code.len(), 4);
8389 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8391 assert_eq!((instr >> 8) & 0xF, 0xB); }
8393
8394 #[test]
8395 fn test_encode_f64_sub_thumb2() {
8396 let encoder = ArmEncoder::new_thumb2();
8397 let op = ArmOp::F64Sub {
8398 dd: VfpReg::D0,
8399 dn: VfpReg::D1,
8400 dm: VfpReg::D2,
8401 };
8402 let code = encoder.encode(&op).unwrap();
8403 assert_eq!(code.len(), 4); }
8405
8406 #[test]
8407 fn test_encode_f64_mul_arm32() {
8408 let encoder = ArmEncoder::new_arm32();
8409 let op = ArmOp::F64Mul {
8410 dd: VfpReg::D0,
8411 dn: VfpReg::D1,
8412 dm: VfpReg::D2,
8413 };
8414 let code = encoder.encode(&op).unwrap();
8415 assert_eq!(code.len(), 4);
8416 }
8417
8418 #[test]
8419 fn test_encode_f64_div_arm32() {
8420 let encoder = ArmEncoder::new_arm32();
8421 let op = ArmOp::F64Div {
8422 dd: VfpReg::D0,
8423 dn: VfpReg::D1,
8424 dm: VfpReg::D2,
8425 };
8426 let code = encoder.encode(&op).unwrap();
8427 assert_eq!(code.len(), 4);
8428 }
8429
8430 #[test]
8431 fn test_encode_f64_abs_arm32() {
8432 let encoder = ArmEncoder::new_arm32();
8433 let op = ArmOp::F64Abs {
8434 dd: VfpReg::D0,
8435 dm: VfpReg::D2,
8436 };
8437 let code = encoder.encode(&op).unwrap();
8438 assert_eq!(code.len(), 4);
8439 }
8440
8441 #[test]
8442 fn test_encode_f64_neg_arm32() {
8443 let encoder = ArmEncoder::new_arm32();
8444 let op = ArmOp::F64Neg {
8445 dd: VfpReg::D0,
8446 dm: VfpReg::D2,
8447 };
8448 let code = encoder.encode(&op).unwrap();
8449 assert_eq!(code.len(), 4);
8450 }
8451
8452 #[test]
8453 fn test_encode_f64_sqrt_arm32() {
8454 let encoder = ArmEncoder::new_arm32();
8455 let op = ArmOp::F64Sqrt {
8456 dd: VfpReg::D0,
8457 dm: VfpReg::D2,
8458 };
8459 let code = encoder.encode(&op).unwrap();
8460 assert_eq!(code.len(), 4);
8461 }
8462
8463 #[test]
8464 fn test_encode_f64_load_arm32() {
8465 let encoder = ArmEncoder::new_arm32();
8466 let op = ArmOp::F64Load {
8467 dd: VfpReg::D0,
8468 addr: MemAddr::imm(Reg::R0, 8),
8469 };
8470 let code = encoder.encode(&op).unwrap();
8471 assert_eq!(code.len(), 4);
8472 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8473 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
8476
8477 #[test]
8478 fn test_encode_f64_store_thumb2() {
8479 let encoder = ArmEncoder::new_thumb2();
8480 let op = ArmOp::F64Store {
8481 dd: VfpReg::D0,
8482 addr: MemAddr::imm(Reg::SP, 0),
8483 };
8484 let code = encoder.encode(&op).unwrap();
8485 assert_eq!(code.len(), 4);
8486 }
8487
8488 #[test]
8489 fn test_encode_f64_compare_arm32() {
8490 let encoder = ArmEncoder::new_arm32();
8491 let op = ArmOp::F64Eq {
8492 rd: Reg::R0,
8493 dn: VfpReg::D0,
8494 dm: VfpReg::D1,
8495 };
8496 let code = encoder.encode(&op).unwrap();
8497 assert_eq!(code.len(), 16); }
8499
8500 #[test]
8501 fn test_encode_f64_compare_thumb2() {
8502 let encoder = ArmEncoder::new_thumb2();
8503 let op = ArmOp::F64Lt {
8504 rd: Reg::R0,
8505 dn: VfpReg::D0,
8506 dm: VfpReg::D1,
8507 };
8508 let code = encoder.encode(&op).unwrap();
8509 assert_eq!(code.len(), 14);
8511 }
8512
8513 #[test]
8514 fn test_encode_f64_const_arm32() {
8515 let encoder = ArmEncoder::new_arm32();
8516 let op = ArmOp::F64Const {
8517 dd: VfpReg::D0,
8518 value: 3.125,
8519 };
8520 let code = encoder.encode(&op).unwrap();
8521 assert_eq!(code.len(), 20);
8523 }
8524
8525 #[test]
8526 fn test_encode_f64_const_thumb2() {
8527 let encoder = ArmEncoder::new_thumb2();
8528 let op = ArmOp::F64Const {
8529 dd: VfpReg::D0,
8530 value: 2.5,
8531 };
8532 let code = encoder.encode(&op).unwrap();
8533 assert_eq!(code.len(), 20);
8535 }
8536
8537 #[test]
8538 fn test_encode_f64_convert_i32s_arm32() {
8539 let encoder = ArmEncoder::new_arm32();
8540 let op = ArmOp::F64ConvertI32S {
8541 dd: VfpReg::D0,
8542 rm: Reg::R0,
8543 };
8544 let code = encoder.encode(&op).unwrap();
8545 assert_eq!(code.len(), 8);
8547 }
8548
8549 #[test]
8550 fn test_encode_f64_promote_f32_arm32() {
8551 let encoder = ArmEncoder::new_arm32();
8552 let op = ArmOp::F64PromoteF32 {
8553 dd: VfpReg::D0,
8554 sm: VfpReg::S0,
8555 };
8556 let code = encoder.encode(&op).unwrap();
8557 assert_eq!(code.len(), 4); }
8559
8560 #[test]
8561 fn test_encode_f64_promote_f32_thumb2() {
8562 let encoder = ArmEncoder::new_thumb2();
8563 let op = ArmOp::F64PromoteF32 {
8564 dd: VfpReg::D0,
8565 sm: VfpReg::S0,
8566 };
8567 let code = encoder.encode(&op).unwrap();
8568 assert_eq!(code.len(), 4);
8569 }
8570
8571 #[test]
8572 fn test_encode_i32_trunc_f64s_arm32() {
8573 let encoder = ArmEncoder::new_arm32();
8574 let op = ArmOp::I32TruncF64S {
8575 rd: Reg::R0,
8576 dm: VfpReg::D0,
8577 };
8578 let code = encoder.encode(&op).unwrap();
8579 assert_eq!(code.len(), 8);
8581 }
8582
8583 #[test]
8584 fn test_encode_f64_reinterpret_i64_arm32() {
8585 let encoder = ArmEncoder::new_arm32();
8586 let op = ArmOp::F64ReinterpretI64 {
8587 dd: VfpReg::D0,
8588 rmlo: Reg::R0,
8589 rmhi: Reg::R1,
8590 };
8591 let code = encoder.encode(&op).unwrap();
8592 assert_eq!(code.len(), 4); }
8594
8595 #[test]
8596 fn test_encode_i64_reinterpret_f64_thumb2() {
8597 let encoder = ArmEncoder::new_thumb2();
8598 let op = ArmOp::I64ReinterpretF64 {
8599 rdlo: Reg::R0,
8600 rdhi: Reg::R1,
8601 dm: VfpReg::D0,
8602 };
8603 let code = encoder.encode(&op).unwrap();
8604 assert_eq!(code.len(), 4);
8605 }
8606
8607 #[test]
8608 fn test_encode_f64_trunc_thumb2() {
8609 let encoder = ArmEncoder::new_thumb2();
8610 let op = ArmOp::F64Trunc {
8611 dd: VfpReg::D0,
8612 dm: VfpReg::D1,
8613 };
8614 let code = encoder.encode(&op).unwrap();
8615 assert_eq!(code.len(), 8);
8617 }
8618
8619 #[test]
8620 fn test_encode_f64_min_arm32() {
8621 let encoder = ArmEncoder::new_arm32();
8622 let op = ArmOp::F64Min {
8623 dd: VfpReg::D0,
8624 dn: VfpReg::D1,
8625 dm: VfpReg::D2,
8626 };
8627 let code = encoder.encode(&op).unwrap();
8628 assert_eq!(code.len(), 16);
8630 }
8631
8632 #[test]
8633 fn test_f64_cp11_encoding() {
8634 let encoder = ArmEncoder::new_arm32();
8636
8637 let code = encoder
8639 .encode(&ArmOp::F64Add {
8640 dd: VfpReg::D0,
8641 dn: VfpReg::D0,
8642 dm: VfpReg::D0,
8643 })
8644 .unwrap();
8645 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8646 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
8647
8648 let code = encoder
8650 .encode(&ArmOp::F32Add {
8651 sd: VfpReg::S0,
8652 sn: VfpReg::S0,
8653 sm: VfpReg::S0,
8654 })
8655 .unwrap();
8656 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8657 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
8658 }
8659
8660 #[test]
8661 fn test_dreg_encoding_higher_registers() {
8662 let encoder = ArmEncoder::new_arm32();
8663
8664 let op = ArmOp::F64Add {
8666 dd: VfpReg::D15,
8667 dn: VfpReg::D14,
8668 dm: VfpReg::D13,
8669 };
8670 let code = encoder.encode(&op).unwrap();
8671 assert_eq!(code.len(), 4);
8672
8673 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8675 assert_eq!((instr >> 8) & 0xF, 0xB); }
8677
8678 #[test]
8683 fn test_encode_label_emits_no_bytes() {
8684 let encoder = ArmEncoder::new_thumb2();
8685 let op = ArmOp::Label {
8686 name: ".Lblock_end_0".to_string(),
8687 };
8688 let code = encoder.encode(&op).unwrap();
8689 assert!(code.is_empty(), "Label should emit zero bytes");
8690
8691 let encoder32 = ArmEncoder::new_arm32();
8692 let code32 = encoder32.encode(&op).unwrap();
8693 assert!(
8694 code32.is_empty(),
8695 "Label should emit zero bytes in ARM32 too"
8696 );
8697 }
8698
8699 #[test]
8700 fn test_encode_bcc_eq_thumb2() {
8701 use synth_synthesis::Condition;
8702 let encoder = ArmEncoder::new_thumb2();
8703 let op = ArmOp::Bcc {
8704 cond: Condition::EQ,
8705 label: "target".to_string(),
8706 };
8707 let code = encoder.encode(&op).unwrap();
8708 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
8712 }
8713
8714 #[test]
8715 fn test_encode_bcc_ne_thumb2() {
8716 use synth_synthesis::Condition;
8717 let encoder = ArmEncoder::new_thumb2();
8718 let op = ArmOp::Bcc {
8719 cond: Condition::NE,
8720 label: "target".to_string(),
8721 };
8722 let code = encoder.encode(&op).unwrap();
8723 assert_eq!(code.len(), 2);
8724
8725 assert_eq!(code, vec![0x00, 0xD1]);
8727 }
8728
8729 #[test]
8730 fn test_encode_bcc_arm32() {
8731 use synth_synthesis::Condition;
8732 let encoder = ArmEncoder::new_arm32();
8733 let op = ArmOp::Bcc {
8734 cond: Condition::EQ,
8735 label: "target".to_string(),
8736 };
8737 let code = encoder.encode(&op).unwrap();
8738 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8741 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
8745
8746 #[test]
8747 fn test_encode_udf_thumb2() {
8748 let encoder = ArmEncoder::new_thumb2();
8749 let op = ArmOp::Udf { imm: 0 };
8750 let code = encoder.encode(&op).unwrap();
8751 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
8755 }
8756
8757 #[test]
8763 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
8764 let encoder = ArmEncoder::new_thumb2();
8765 for op in [
8766 ArmOp::I64Rotl {
8767 rdlo: Reg::R4,
8768 rdhi: Reg::R5,
8769 rnlo: Reg::R0,
8770 rnhi: Reg::R1,
8771 shift: Reg::R2,
8772 },
8773 ArmOp::I64Rotr {
8774 rdlo: Reg::R4,
8775 rdhi: Reg::R5,
8776 rnlo: Reg::R0,
8777 rnhi: Reg::R1,
8778 shift: Reg::R2,
8779 },
8780 ] {
8781 let code = encoder.encode(&op).unwrap();
8782 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
8783 let tail: Vec<u16> = code[code.len() - 12..]
8786 .chunks(2)
8787 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8788 .collect();
8789 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
8790 }
8791 }
8792
8793 #[test]
8796 fn test_610_i64_div_rem_expansion_guard_and_rd() {
8797 let encoder = ArmEncoder::new_thumb2();
8798 let mk = |which: u8| {
8799 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
8800 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
8801 match which {
8802 0 => ArmOp::I64DivU {
8803 rdlo,
8804 rdhi,
8805 rnlo,
8806 rnhi,
8807 rmlo,
8808 rmhi,
8809 },
8810 1 => ArmOp::I64RemU {
8811 rdlo,
8812 rdhi,
8813 rnlo,
8814 rnhi,
8815 rmlo,
8816 rmhi,
8817 },
8818 2 => ArmOp::I64DivS {
8819 rdlo,
8820 rdhi,
8821 rnlo,
8822 rnhi,
8823 rmlo,
8824 rmhi,
8825 },
8826 _ => ArmOp::I64RemS {
8827 rdlo,
8828 rdhi,
8829 rnlo,
8830 rnhi,
8831 rmlo,
8832 rmhi,
8833 },
8834 }
8835 };
8836 for which in 0..4u8 {
8837 let code = encoder.encode(&mk(which)).unwrap();
8838 let guard: Vec<u16> = code[26..34]
8840 .chunks(2)
8841 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8842 .collect();
8843 assert_eq!(
8844 guard,
8845 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
8846 "ORRS R12,R2,R3; BNE +0; UDF #0"
8847 );
8848 let tail: Vec<u16> = code[code.len() - 12..]
8850 .chunks(2)
8851 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8852 .collect();
8853 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
8854 }
8855 }
8856
8857 #[test]
8860 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
8861 let encoder = ArmEncoder::new_thumb2();
8862 let code = encoder
8863 .encode(&ArmOp::I64DivU {
8864 rdlo: Reg::R0,
8865 rdhi: Reg::R1,
8866 rnlo: Reg::R0,
8867 rnhi: Reg::R1,
8868 rmlo: Reg::R2,
8869 rmhi: Reg::R3,
8870 })
8871 .unwrap();
8872 let tail: Vec<u16> = code[code.len() - 12..]
8873 .chunks(2)
8874 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8875 .collect();
8876 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
8879 }
8880
8881 #[test]
8885 fn test_610_i64_swapped_rd_pair_rejected() {
8886 let encoder = ArmEncoder::new_thumb2();
8887 let result = encoder.encode(&ArmOp::I64RemU {
8888 rdlo: Reg::R1,
8889 rdhi: Reg::R0,
8890 rnlo: Reg::R2,
8891 rnhi: Reg::R3,
8892 rmlo: Reg::R4,
8893 rmhi: Reg::R5,
8894 });
8895 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
8896 }
8897
8898 #[test]
8899 fn test_encode_nop_thumb2() {
8900 let encoder = ArmEncoder::new_thumb2();
8901 let op = ArmOp::Nop;
8902 let code = encoder.encode(&op).unwrap();
8903 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
8907 }
8908
8909 #[test]
8914 fn test_encode_i64_add_thumb2() {
8915 let encoder = ArmEncoder::new_thumb2();
8916 let op = ArmOp::I64Add {
8917 rdlo: Reg::R0,
8918 rdhi: Reg::R1,
8919 rnlo: Reg::R0,
8920 rnhi: Reg::R1,
8921 rmlo: Reg::R2,
8922 rmhi: Reg::R3,
8923 };
8924 let code = encoder.encode(&op).unwrap();
8925 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
8927 }
8928
8929 #[test]
8930 fn test_encode_i64_sub_thumb2() {
8931 let encoder = ArmEncoder::new_thumb2();
8932 let op = ArmOp::I64Sub {
8933 rdlo: Reg::R0,
8934 rdhi: Reg::R1,
8935 rnlo: Reg::R0,
8936 rnhi: Reg::R1,
8937 rmlo: Reg::R2,
8938 rmhi: Reg::R3,
8939 };
8940 let code = encoder.encode(&op).unwrap();
8941 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
8943 }
8944
8945 #[test]
8946 fn test_encode_i64_and_thumb2() {
8947 let encoder = ArmEncoder::new_thumb2();
8948 let op = ArmOp::I64And {
8949 rdlo: Reg::R0,
8950 rdhi: Reg::R1,
8951 rnlo: Reg::R0,
8952 rnhi: Reg::R1,
8953 rmlo: Reg::R2,
8954 rmhi: Reg::R3,
8955 };
8956 let code = encoder.encode(&op).unwrap();
8957 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
8959 }
8960
8961 #[test]
8962 fn test_encode_i64_or_thumb2() {
8963 let encoder = ArmEncoder::new_thumb2();
8964 let op = ArmOp::I64Or {
8965 rdlo: Reg::R0,
8966 rdhi: Reg::R1,
8967 rnlo: Reg::R0,
8968 rnhi: Reg::R1,
8969 rmlo: Reg::R2,
8970 rmhi: Reg::R3,
8971 };
8972 let code = encoder.encode(&op).unwrap();
8973 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
8974 }
8975
8976 #[test]
8977 fn test_encode_i64_xor_thumb2() {
8978 let encoder = ArmEncoder::new_thumb2();
8979 let op = ArmOp::I64Xor {
8980 rdlo: Reg::R0,
8981 rdhi: Reg::R1,
8982 rnlo: Reg::R0,
8983 rnhi: Reg::R1,
8984 rmlo: Reg::R2,
8985 rmhi: Reg::R3,
8986 };
8987 let code = encoder.encode(&op).unwrap();
8988 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
8989 }
8990
8991 #[test]
8992 fn test_encode_i64_const_small_thumb2() {
8993 let encoder = ArmEncoder::new_thumb2();
8994 let op = ArmOp::I64Const {
8996 rdlo: Reg::R0,
8997 rdhi: Reg::R1,
8998 value: 42,
8999 };
9000 let code = encoder.encode(&op).unwrap();
9001 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
9003 }
9004
9005 #[test]
9006 fn test_encode_i64_const_large_thumb2() {
9007 let encoder = ArmEncoder::new_thumb2();
9008 let op = ArmOp::I64Const {
9010 rdlo: Reg::R0,
9011 rdhi: Reg::R1,
9012 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
9013 };
9014 let code = encoder.encode(&op).unwrap();
9015 assert_eq!(
9017 code.len(),
9018 16,
9019 "I64Const with large value should be 16 bytes"
9020 );
9021 }
9022
9023 #[test]
9024 fn test_encode_i64_extend_i32_s_thumb2() {
9025 let encoder = ArmEncoder::new_thumb2();
9026 let op = ArmOp::I64ExtendI32S {
9027 rdlo: Reg::R0,
9028 rdhi: Reg::R1,
9029 rn: Reg::R0,
9030 };
9031 let code = encoder.encode(&op).unwrap();
9032 assert_eq!(
9034 code.len(),
9035 4,
9036 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
9037 );
9038 }
9039
9040 #[test]
9041 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
9042 let encoder = ArmEncoder::new_thumb2();
9043 let op = ArmOp::I64ExtendI32S {
9044 rdlo: Reg::R0,
9045 rdhi: Reg::R1,
9046 rn: Reg::R2,
9047 };
9048 let code = encoder.encode(&op).unwrap();
9049 assert!(
9051 code.len() >= 6,
9052 "I64ExtendI32S (diff reg) should be at least 6 bytes"
9053 );
9054 }
9055
9056 #[test]
9057 fn test_encode_i64_extend_i32_u_thumb2() {
9058 let encoder = ArmEncoder::new_thumb2();
9059 let op = ArmOp::I64ExtendI32U {
9060 rdlo: Reg::R0,
9061 rdhi: Reg::R1,
9062 rn: Reg::R0,
9063 };
9064 let code = encoder.encode(&op).unwrap();
9065 assert_eq!(
9067 code.len(),
9068 2,
9069 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
9070 );
9071 }
9072
9073 #[test]
9074 fn test_encode_i32_wrap_i64_nop_thumb2() {
9075 let encoder = ArmEncoder::new_thumb2();
9076 let op = ArmOp::I32WrapI64 {
9078 rd: Reg::R0,
9079 rnlo: Reg::R0,
9080 };
9081 let code = encoder.encode(&op).unwrap();
9082 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
9083 assert_eq!(code, vec![0x00, 0xBF]); }
9085
9086 #[test]
9087 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
9088 let encoder = ArmEncoder::new_thumb2();
9089 let op = ArmOp::I32WrapI64 {
9090 rd: Reg::R2,
9091 rnlo: Reg::R0,
9092 };
9093 let code = encoder.encode(&op).unwrap();
9094 assert!(
9096 code.len() >= 2,
9097 "I32WrapI64 diff reg should emit at least 2 bytes"
9098 );
9099 }
9100
9101 #[test]
9102 fn test_encode_i64_eqz_thumb2() {
9103 let encoder = ArmEncoder::new_thumb2();
9104 let op = ArmOp::I64Eqz {
9105 rd: Reg::R0,
9106 rnlo: Reg::R0,
9107 rnhi: Reg::R1,
9108 };
9109 let code = encoder.encode(&op).unwrap();
9110 assert!(
9112 code.len() >= 6,
9113 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
9114 );
9115 }
9116
9117 #[test]
9118 fn test_encode_i64_eq_thumb2() {
9119 let encoder = ArmEncoder::new_thumb2();
9120 let op = ArmOp::I64Eq {
9121 rd: Reg::R0,
9122 rnlo: Reg::R0,
9123 rnhi: Reg::R1,
9124 rmlo: Reg::R2,
9125 rmhi: Reg::R3,
9126 };
9127 let code = encoder.encode(&op).unwrap();
9128 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
9130 }
9131
9132 #[test]
9133 fn test_encode_i64_ldr_thumb2() {
9134 let encoder = ArmEncoder::new_thumb2();
9135 let op = ArmOp::I64Ldr {
9136 rdlo: Reg::R0,
9137 rdhi: Reg::R1,
9138 addr: MemAddr::imm(Reg::SP, 0),
9139 };
9140 let code = encoder.encode(&op).unwrap();
9141 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
9143 }
9144
9145 #[test]
9146 fn test_372_i64_ldr_indexed_materializes_address() {
9147 let encoder = ArmEncoder::new_thumb2();
9152 let indexed = encoder
9153 .encode(&ArmOp::I64Ldr {
9154 rdlo: Reg::R0,
9155 rdhi: Reg::R1,
9156 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
9157 })
9158 .unwrap();
9159 assert_eq!(
9161 &indexed[0..4],
9162 &[0x0b, 0xeb, 0x00, 0x0c],
9163 "indexed I64Ldr must start with ADD.W ip, base, index"
9164 );
9165 let frame = encoder
9166 .encode(&ArmOp::I64Ldr {
9167 rdlo: Reg::R0,
9168 rdhi: Reg::R1,
9169 addr: MemAddr::imm(Reg::SP, 8),
9170 })
9171 .unwrap();
9172 assert_ne!(
9174 &frame[0..2],
9175 &[0x0b, 0xeb],
9176 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
9177 );
9178 }
9179
9180 #[test]
9181 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
9182 let encoder = ArmEncoder::new_thumb2();
9188 let ld = encoder
9191 .encode(&ArmOp::I64Ldr {
9192 rdlo: Reg::R0,
9193 rdhi: Reg::R1,
9194 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9195 })
9196 .expect("large-offset i64.load must lower, not skip");
9197 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
9199 assert_ne!(
9202 &ld[0..2],
9203 &[0x0b, 0xeb],
9204 "must materialize the large offset"
9205 );
9206 assert_eq!(
9208 &ld[4..20],
9209 &[
9210 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
9215 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
9216 );
9217
9218 let st = encoder
9220 .encode(&ArmOp::I64Str {
9221 rdlo: Reg::R2,
9222 rdhi: Reg::R3,
9223 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9224 })
9225 .expect("large-offset i64.store must lower, not skip");
9226 assert_eq!(st.len(), 20);
9227 assert_eq!(
9228 &st[4..20],
9229 &[
9230 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
9235 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
9236 );
9237
9238 let small = encoder
9242 .encode(&ArmOp::I64Ldr {
9243 rdlo: Reg::R0,
9244 rdhi: Reg::R1,
9245 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
9246 })
9247 .unwrap();
9248 assert_eq!(
9249 &small[0..4],
9250 &[0x0b, 0xeb, 0x00, 0x0c],
9251 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
9252 );
9253 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
9254 }
9255
9256 #[test]
9257 fn test_encode_i64_str_thumb2() {
9258 let encoder = ArmEncoder::new_thumb2();
9259 let op = ArmOp::I64Str {
9260 rdlo: Reg::R0,
9261 rdhi: Reg::R1,
9262 addr: MemAddr::imm(Reg::SP, 0),
9263 };
9264 let code = encoder.encode(&op).unwrap();
9265 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
9267 }
9268
9269 #[test]
9270 fn test_encode_i64_all_comparisons_thumb2() {
9271 let encoder = ArmEncoder::new_thumb2();
9272
9273 let ops = vec![
9274 ArmOp::I64Ne {
9275 rd: Reg::R0,
9276 rnlo: Reg::R0,
9277 rnhi: Reg::R1,
9278 rmlo: Reg::R2,
9279 rmhi: Reg::R3,
9280 },
9281 ArmOp::I64LtS {
9282 rd: Reg::R0,
9283 rnlo: Reg::R0,
9284 rnhi: Reg::R1,
9285 rmlo: Reg::R2,
9286 rmhi: Reg::R3,
9287 },
9288 ArmOp::I64LtU {
9289 rd: Reg::R0,
9290 rnlo: Reg::R0,
9291 rnhi: Reg::R1,
9292 rmlo: Reg::R2,
9293 rmhi: Reg::R3,
9294 },
9295 ArmOp::I64LeS {
9296 rd: Reg::R0,
9297 rnlo: Reg::R0,
9298 rnhi: Reg::R1,
9299 rmlo: Reg::R2,
9300 rmhi: Reg::R3,
9301 },
9302 ArmOp::I64LeU {
9303 rd: Reg::R0,
9304 rnlo: Reg::R0,
9305 rnhi: Reg::R1,
9306 rmlo: Reg::R2,
9307 rmhi: Reg::R3,
9308 },
9309 ArmOp::I64GtS {
9310 rd: Reg::R0,
9311 rnlo: Reg::R0,
9312 rnhi: Reg::R1,
9313 rmlo: Reg::R2,
9314 rmhi: Reg::R3,
9315 },
9316 ArmOp::I64GtU {
9317 rd: Reg::R0,
9318 rnlo: Reg::R0,
9319 rnhi: Reg::R1,
9320 rmlo: Reg::R2,
9321 rmhi: Reg::R3,
9322 },
9323 ArmOp::I64GeS {
9324 rd: Reg::R0,
9325 rnlo: Reg::R0,
9326 rnhi: Reg::R1,
9327 rmlo: Reg::R2,
9328 rmhi: Reg::R3,
9329 },
9330 ArmOp::I64GeU {
9331 rd: Reg::R0,
9332 rnlo: Reg::R0,
9333 rnhi: Reg::R1,
9334 rmlo: Reg::R2,
9335 rmhi: Reg::R3,
9336 },
9337 ];
9338
9339 for op in &ops {
9340 let code = encoder.encode(op).unwrap();
9341 assert!(
9342 code.len() >= 8,
9343 "i64 comparison {:?} should emit at least 8 bytes, got {}",
9344 op,
9345 code.len()
9346 );
9347 }
9348 }
9349
9350 #[test]
9351 fn test_encode_i64_const_zero_thumb2() {
9352 let encoder = ArmEncoder::new_thumb2();
9353 let op = ArmOp::I64Const {
9354 rdlo: Reg::R0,
9355 rdhi: Reg::R1,
9356 value: 0,
9357 };
9358 let code = encoder.encode(&op).unwrap();
9359 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
9361 }
9362
9363 #[test]
9364 fn test_encode_i64_const_negative_one_thumb2() {
9365 let encoder = ArmEncoder::new_thumb2();
9366 let op = ArmOp::I64Const {
9367 rdlo: Reg::R0,
9368 rdhi: Reg::R1,
9369 value: -1, };
9371 let code = encoder.encode(&op).unwrap();
9372 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
9374 }
9375
9376 #[test]
9381 fn test_encode_ldrb_arm32() {
9382 let encoder = ArmEncoder::new_arm32();
9383 let op = ArmOp::Ldrb {
9384 rd: Reg::R0,
9385 addr: MemAddr::imm(Reg::R1, 4),
9386 };
9387 let code = encoder.encode(&op).unwrap();
9388 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
9389 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9391 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
9392 }
9393
9394 #[test]
9395 fn test_encode_strb_arm32() {
9396 let encoder = ArmEncoder::new_arm32();
9397 let op = ArmOp::Strb {
9398 rd: Reg::R0,
9399 addr: MemAddr::imm(Reg::R1, 0),
9400 };
9401 let code = encoder.encode(&op).unwrap();
9402 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
9403 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9405 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
9406 }
9407
9408 #[test]
9409 fn test_encode_ldrh_arm32() {
9410 let encoder = ArmEncoder::new_arm32();
9411 let op = ArmOp::Ldrh {
9412 rd: Reg::R0,
9413 addr: MemAddr::imm(Reg::R1, 2),
9414 };
9415 let code = encoder.encode(&op).unwrap();
9416 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
9417 }
9418
9419 #[test]
9420 fn test_encode_strh_arm32() {
9421 let encoder = ArmEncoder::new_arm32();
9422 let op = ArmOp::Strh {
9423 rd: Reg::R0,
9424 addr: MemAddr::imm(Reg::R1, 0),
9425 };
9426 let code = encoder.encode(&op).unwrap();
9427 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
9428 }
9429
9430 #[test]
9431 fn test_encode_ldrsb_arm32() {
9432 let encoder = ArmEncoder::new_arm32();
9433 let op = ArmOp::Ldrsb {
9434 rd: Reg::R0,
9435 addr: MemAddr::imm(Reg::R1, 0),
9436 };
9437 let code = encoder.encode(&op).unwrap();
9438 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
9439 }
9440
9441 #[test]
9442 fn test_encode_ldrsh_arm32() {
9443 let encoder = ArmEncoder::new_arm32();
9444 let op = ArmOp::Ldrsh {
9445 rd: Reg::R0,
9446 addr: MemAddr::imm(Reg::R1, 0),
9447 };
9448 let code = encoder.encode(&op).unwrap();
9449 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
9450 }
9451
9452 #[test]
9453 fn test_encode_ldrb_thumb2_16bit() {
9454 let encoder = ArmEncoder::new_thumb2();
9455 let op = ArmOp::Ldrb {
9456 rd: Reg::R0,
9457 addr: MemAddr::imm(Reg::R1, 4),
9458 };
9459 let code = encoder.encode(&op).unwrap();
9460 assert_eq!(
9462 code.len(),
9463 2,
9464 "Thumb-2 LDRB with small offset should be 16-bit"
9465 );
9466 }
9467
9468 #[test]
9469 fn test_encode_ldrb_thumb2_32bit() {
9470 let encoder = ArmEncoder::new_thumb2();
9471 let op = ArmOp::Ldrb {
9472 rd: Reg::R0,
9473 addr: MemAddr::imm(Reg::R1, 100), };
9475 let code = encoder.encode(&op).unwrap();
9476 assert_eq!(
9477 code.len(),
9478 4,
9479 "Thumb-2 LDRB with large offset should be 32-bit"
9480 );
9481 }
9482
9483 #[test]
9484 fn test_encode_strb_thumb2_16bit() {
9485 let encoder = ArmEncoder::new_thumb2();
9486 let op = ArmOp::Strb {
9487 rd: Reg::R0,
9488 addr: MemAddr::imm(Reg::R1, 10),
9489 };
9490 let code = encoder.encode(&op).unwrap();
9491 assert_eq!(
9492 code.len(),
9493 2,
9494 "Thumb-2 STRB with small offset should be 16-bit"
9495 );
9496 }
9497
9498 #[test]
9499 fn test_encode_ldrh_thumb2_16bit() {
9500 let encoder = ArmEncoder::new_thumb2();
9501 let op = ArmOp::Ldrh {
9502 rd: Reg::R0,
9503 addr: MemAddr::imm(Reg::R1, 4), };
9505 let code = encoder.encode(&op).unwrap();
9506 assert_eq!(
9507 code.len(),
9508 2,
9509 "Thumb-2 LDRH with small aligned offset should be 16-bit"
9510 );
9511 }
9512
9513 #[test]
9514 fn test_encode_strh_thumb2_16bit() {
9515 let encoder = ArmEncoder::new_thumb2();
9516 let op = ArmOp::Strh {
9517 rd: Reg::R0,
9518 addr: MemAddr::imm(Reg::R1, 4),
9519 };
9520 let code = encoder.encode(&op).unwrap();
9521 assert_eq!(
9522 code.len(),
9523 2,
9524 "Thumb-2 STRH with small aligned offset should be 16-bit"
9525 );
9526 }
9527
9528 #[test]
9529 fn test_encode_ldrsb_thumb2() {
9530 let encoder = ArmEncoder::new_thumb2();
9531 let op = ArmOp::Ldrsb {
9532 rd: Reg::R0,
9533 addr: MemAddr::imm(Reg::R1, 0),
9534 };
9535 let code = encoder.encode(&op).unwrap();
9536 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
9538 }
9539
9540 #[test]
9541 fn test_encode_ldrsh_thumb2() {
9542 let encoder = ArmEncoder::new_thumb2();
9543 let op = ArmOp::Ldrsh {
9544 rd: Reg::R0,
9545 addr: MemAddr::imm(Reg::R1, 0),
9546 };
9547 let code = encoder.encode(&op).unwrap();
9548 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
9549 }
9550
9551 #[test]
9552 fn test_encode_memory_size_thumb2() {
9553 let encoder = ArmEncoder::new_thumb2();
9554 let op = ArmOp::MemorySize { rd: Reg::R0 };
9555 let code = encoder.encode(&op).unwrap();
9556 assert!(!code.is_empty(), "MemorySize should produce code");
9558 }
9559
9560 #[test]
9561 fn test_encode_memory_grow_thumb2() {
9562 let encoder = ArmEncoder::new_thumb2();
9563 let op = ArmOp::MemoryGrow {
9564 rd: Reg::R0,
9565 rn: Reg::R0,
9566 };
9567 let code = encoder.encode(&op).unwrap();
9568 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
9569 }
9570
9571 #[test]
9572 fn test_encode_subword_reg_offset_thumb2() {
9573 let encoder = ArmEncoder::new_thumb2();
9574
9575 let op = ArmOp::Ldrb {
9577 rd: Reg::R0,
9578 addr: MemAddr::reg(Reg::R1, Reg::R2),
9579 };
9580 let code = encoder.encode(&op).unwrap();
9581 assert_eq!(
9582 code.len(),
9583 4,
9584 "Thumb-2 LDRB with reg offset should be 32-bit"
9585 );
9586
9587 let op = ArmOp::Strb {
9589 rd: Reg::R0,
9590 addr: MemAddr::reg(Reg::R1, Reg::R2),
9591 };
9592 let code = encoder.encode(&op).unwrap();
9593 assert_eq!(
9594 code.len(),
9595 4,
9596 "Thumb-2 STRB with reg offset should be 32-bit"
9597 );
9598
9599 let op = ArmOp::Ldrh {
9601 rd: Reg::R0,
9602 addr: MemAddr::reg(Reg::R1, Reg::R2),
9603 };
9604 let code = encoder.encode(&op).unwrap();
9605 assert_eq!(
9606 code.len(),
9607 4,
9608 "Thumb-2 LDRH with reg offset should be 32-bit"
9609 );
9610
9611 let op = ArmOp::Strh {
9613 rd: Reg::R0,
9614 addr: MemAddr::reg(Reg::R1, Reg::R2),
9615 };
9616 let code = encoder.encode(&op).unwrap();
9617 assert_eq!(
9618 code.len(),
9619 4,
9620 "Thumb-2 STRH with reg offset should be 32-bit"
9621 );
9622 }
9623
9624 #[test]
9625 fn test_encode_subword_reg_imm_offset_thumb2() {
9626 let encoder = ArmEncoder::new_thumb2();
9627
9628 let op = ArmOp::Ldrb {
9630 rd: Reg::R0,
9631 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
9632 };
9633 let code = encoder.encode(&op).unwrap();
9634 assert_eq!(
9636 code.len(),
9637 8,
9638 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
9639 );
9640 }
9641
9642 #[test]
9647 fn test_encode_mve_addi32_thumb2() {
9648 let encoder = ArmEncoder::new_thumb2();
9649 let op = ArmOp::MveAddI {
9650 qd: QReg::Q0,
9651 qn: QReg::Q1,
9652 qm: QReg::Q2,
9653 size: MveSize::S32,
9654 };
9655 let code = encoder.encode(&op).unwrap();
9656 assert_eq!(
9657 code.len(),
9658 4,
9659 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
9660 );
9661 }
9662
9663 #[test]
9664 fn test_encode_mve_subi16_thumb2() {
9665 let encoder = ArmEncoder::new_thumb2();
9666 let op = ArmOp::MveSubI {
9667 qd: QReg::Q0,
9668 qn: QReg::Q1,
9669 qm: QReg::Q2,
9670 size: MveSize::S16,
9671 };
9672 let code = encoder.encode(&op).unwrap();
9673 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
9674 }
9675
9676 #[test]
9677 fn test_encode_mve_muli8_thumb2() {
9678 let encoder = ArmEncoder::new_thumb2();
9679 let op = ArmOp::MveMulI {
9680 qd: QReg::Q0,
9681 qn: QReg::Q1,
9682 qm: QReg::Q2,
9683 size: MveSize::S8,
9684 };
9685 let code = encoder.encode(&op).unwrap();
9686 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
9687 }
9688
9689 #[test]
9690 fn test_encode_mve_bitwise_thumb2() {
9691 let encoder = ArmEncoder::new_thumb2();
9692
9693 let ops = vec![
9694 ArmOp::MveAnd {
9695 qd: QReg::Q0,
9696 qn: QReg::Q1,
9697 qm: QReg::Q2,
9698 },
9699 ArmOp::MveOrr {
9700 qd: QReg::Q0,
9701 qn: QReg::Q1,
9702 qm: QReg::Q2,
9703 },
9704 ArmOp::MveEor {
9705 qd: QReg::Q0,
9706 qn: QReg::Q1,
9707 qm: QReg::Q2,
9708 },
9709 ArmOp::MveBic {
9710 qd: QReg::Q0,
9711 qn: QReg::Q1,
9712 qm: QReg::Q2,
9713 },
9714 ];
9715 for op in ops {
9716 let code = encoder.encode(&op).unwrap();
9717 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
9718 }
9719 }
9720
9721 #[test]
9722 fn test_encode_mve_mvn_thumb2() {
9723 let encoder = ArmEncoder::new_thumb2();
9724 let op = ArmOp::MveMvn {
9725 qd: QReg::Q0,
9726 qm: QReg::Q1,
9727 };
9728 let code = encoder.encode(&op).unwrap();
9729 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
9730 }
9731
9732 #[test]
9733 fn test_encode_mve_load_store_thumb2() {
9734 let encoder = ArmEncoder::new_thumb2();
9735
9736 let load = ArmOp::MveLoad {
9737 qd: QReg::Q0,
9738 addr: MemAddr::imm(Reg::R0, 16),
9739 };
9740 let code = encoder.encode(&load).unwrap();
9741 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
9742
9743 let store = ArmOp::MveStore {
9744 qd: QReg::Q1,
9745 addr: MemAddr::imm(Reg::R1, 0),
9746 };
9747 let code = encoder.encode(&store).unwrap();
9748 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
9749 }
9750
9751 #[test]
9752 fn test_encode_mve_const_thumb2() {
9753 let encoder = ArmEncoder::new_thumb2();
9754 let op = ArmOp::MveConst {
9755 qd: QReg::Q0,
9756 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
9757 };
9758 let code = encoder.encode(&op).unwrap();
9759 assert!(
9762 code.len() >= 24,
9763 "MVE const should produce multiple instructions"
9764 );
9765 }
9766
9767 #[test]
9768 fn test_encode_mve_dup_thumb2() {
9769 let encoder = ArmEncoder::new_thumb2();
9770 let op = ArmOp::MveDup {
9771 qd: QReg::Q0,
9772 rn: Reg::R0,
9773 size: MveSize::S32,
9774 };
9775 let code = encoder.encode(&op).unwrap();
9776 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
9777 }
9778
9779 #[test]
9780 fn test_encode_mve_extract_lane_thumb2() {
9781 let encoder = ArmEncoder::new_thumb2();
9782 let op = ArmOp::MveExtractLane {
9783 rd: Reg::R0,
9784 qn: QReg::Q1,
9785 lane: 2,
9786 size: MveSize::S32,
9787 };
9788 let code = encoder.encode(&op).unwrap();
9789 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
9790 }
9791
9792 #[test]
9793 fn test_encode_mve_insert_lane_thumb2() {
9794 let encoder = ArmEncoder::new_thumb2();
9795 let op = ArmOp::MveInsertLane {
9796 qd: QReg::Q0,
9797 rn: Reg::R1,
9798 lane: 3,
9799 size: MveSize::S32,
9800 };
9801 let code = encoder.encode(&op).unwrap();
9802 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
9803 }
9804
9805 #[test]
9806 fn test_encode_mve_addf32_thumb2() {
9807 let encoder = ArmEncoder::new_thumb2();
9808 let op = ArmOp::MveAddF32 {
9809 qd: QReg::Q0,
9810 qn: QReg::Q1,
9811 qm: QReg::Q2,
9812 };
9813 let code = encoder.encode(&op).unwrap();
9814 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
9815 }
9816
9817 #[test]
9818 fn test_encode_mve_divf32_thumb2() {
9819 let encoder = ArmEncoder::new_thumb2();
9820 let op = ArmOp::MveDivF32 {
9821 qd: QReg::Q0,
9822 qn: QReg::Q1,
9823 qm: QReg::Q2,
9824 };
9825 let code = encoder.encode(&op).unwrap();
9826 assert_eq!(
9828 code.len(),
9829 16,
9830 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
9831 );
9832 }
9833
9834 #[test]
9835 fn test_encode_mve_sqrtf32_thumb2() {
9836 let encoder = ArmEncoder::new_thumb2();
9837 let op = ArmOp::MveSqrtF32 {
9838 qd: QReg::Q0,
9839 qm: QReg::Q1,
9840 };
9841 let code = encoder.encode(&op).unwrap();
9842 assert_eq!(
9844 code.len(),
9845 16,
9846 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
9847 );
9848 }
9849
9850 #[test]
9851 fn test_encode_mve_negf32_thumb2() {
9852 let encoder = ArmEncoder::new_thumb2();
9853 let op = ArmOp::MveNegF32 {
9854 qd: QReg::Q0,
9855 qm: QReg::Q1,
9856 };
9857 let code = encoder.encode(&op).unwrap();
9858 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
9859 }
9860
9861 #[test]
9862 fn test_encode_mve_absf32_thumb2() {
9863 let encoder = ArmEncoder::new_thumb2();
9864 let op = ArmOp::MveAbsF32 {
9865 qd: QReg::Q0,
9866 qm: QReg::Q1,
9867 };
9868 let code = encoder.encode(&op).unwrap();
9869 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
9870 }
9871
9872 #[test]
9887 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
9888 let encoder = ArmEncoder::new_thumb2();
9889 let op = ArmOp::And {
9890 rd: Reg::R2,
9891 rn: Reg::R0,
9892 op2: Operand2::Imm(0x7e),
9893 };
9894 let code = encoder.encode(&op).unwrap();
9895 assert_eq!(
9896 code,
9897 vec![0x00, 0xf0, 0x7e, 0x02],
9898 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
9899 );
9900 }
9901
9902 #[test]
9909 fn try_thumb_expand_imm_encodes_modified_immediates() {
9910 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
9912 assert_eq!(try_thumb_expand_imm(0x0001_0001), Some(0x101)); assert_eq!(try_thumb_expand_imm(0xff00_ff00), Some(0x2ff)); assert_eq!(try_thumb_expand_imm(0xffff_ffff), Some(0x3ff)); assert_eq!(try_thumb_expand_imm(0x100), Some(0xf80)); assert_eq!(try_thumb_expand_imm(0x8000_0000), Some(0x400)); assert_eq!(try_thumb_expand_imm(1000), Some(0xf7a)); assert_eq!(try_thumb_expand_imm(0x101), None);
9920 assert_eq!(try_thumb_expand_imm(0x12345), None);
9921 }
9922
9923 #[test]
9928 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
9929 let encoder = ArmEncoder::new_thumb2();
9930 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
9932 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
9933 assert!(
9935 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
9936 "cmp #0x101 must error, not compare the wrong constant"
9937 );
9938 assert!(
9939 encoder
9940 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
9941 .is_err()
9942 );
9943 assert!(
9944 encoder
9945 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
9946 .is_err()
9947 );
9948 assert!(
9950 encoder
9951 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
9952 .is_ok()
9953 );
9954 }
9955
9956 #[test]
9959 fn mla_thumb2_encodes_correctly() {
9960 let encoder = ArmEncoder::new_thumb2();
9961 let code = encoder
9962 .encode(&ArmOp::Mla {
9963 rd: Reg::R2,
9964 rn: Reg::R3,
9965 rm: Reg::R4,
9966 ra: Reg::R8,
9967 })
9968 .unwrap();
9969 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
9971 }
9972
9973 #[test]
9978 fn ldst_imm12_offset_errors_when_out_of_range() {
9979 let encoder = ArmEncoder::new_thumb2();
9980 assert!(
9982 encoder
9983 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
9984 .is_ok()
9985 );
9986 assert!(
9988 encoder
9989 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
9990 .is_err(),
9991 "ldr offset 4096 must error, not wrap to 0"
9992 );
9993 assert!(
9994 encoder
9995 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
9996 .is_err()
9997 );
9998 assert!(
9999 encoder
10000 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
10001 .is_err()
10002 );
10003 assert!(
10004 encoder
10005 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
10006 .is_err()
10007 );
10008 }
10009
10010 #[test]
10017 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
10018 let encoder = ArmEncoder::new_thumb2();
10019 assert_eq!(
10021 encoder
10022 .encode(&ArmOp::Add {
10023 rd: Reg::SP,
10024 rn: Reg::SP,
10025 op2: Operand2::Imm(256),
10026 })
10027 .unwrap(),
10028 vec![0x0d, 0xf2, 0x00, 0x1d],
10029 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
10030 );
10031 assert_eq!(
10033 encoder
10034 .encode(&ArmOp::Sub {
10035 rd: Reg::SP,
10036 rn: Reg::SP,
10037 op2: Operand2::Imm(256),
10038 })
10039 .unwrap(),
10040 vec![0xad, 0xf2, 0x00, 0x1d],
10041 );
10042 assert!(
10044 encoder
10045 .encode(&ArmOp::Add {
10046 rd: Reg::SP,
10047 rn: Reg::SP,
10048 op2: Operand2::Imm(5000),
10049 })
10050 .is_err(),
10051 "add #5000 must error (no single ADDW), not mis-encode"
10052 );
10053 }
10054
10055 #[test]
10060 fn and_cmn_immediate_thumb_expand_else_error() {
10061 let encoder = ArmEncoder::new_thumb2();
10062 assert_eq!(
10064 encoder
10065 .encode(&ArmOp::And {
10066 rd: Reg::R2,
10067 rn: Reg::R0,
10068 op2: Operand2::Imm(0x7e),
10069 })
10070 .unwrap(),
10071 vec![0x00, 0xf0, 0x7e, 0x02],
10072 );
10073 assert!(
10075 encoder
10076 .encode(&ArmOp::And {
10077 rd: Reg::R2,
10078 rn: Reg::R0,
10079 op2: Operand2::Imm(0xff00ff00u32 as i32),
10080 })
10081 .is_ok()
10082 );
10083 assert!(
10085 encoder
10086 .encode(&ArmOp::And {
10087 rd: Reg::R2,
10088 rn: Reg::R0,
10089 op2: Operand2::Imm(0x101),
10090 })
10091 .is_err()
10092 );
10093 assert!(
10094 encoder
10095 .encode(&ArmOp::Cmn {
10096 rn: Reg::R0,
10097 op2: Operand2::Imm(0x101),
10098 })
10099 .is_err(),
10100 "CMN #0x101 must error, not emit a NOP"
10101 );
10102 }
10103
10104 #[test]
10108 fn orr_eor_immediate_encode_in_byte_range_else_error() {
10109 let encoder = ArmEncoder::new_thumb2();
10110 assert_eq!(
10112 encoder
10113 .encode(&ArmOp::Orr {
10114 rd: Reg::R2,
10115 rn: Reg::R0,
10116 op2: Operand2::Imm(0x7e),
10117 })
10118 .unwrap(),
10119 vec![0x40, 0xf0, 0x7e, 0x02],
10120 );
10121 assert_eq!(
10123 encoder
10124 .encode(&ArmOp::Eor {
10125 rd: Reg::R2,
10126 rn: Reg::R0,
10127 op2: Operand2::Imm(0x7e),
10128 })
10129 .unwrap(),
10130 vec![0x80, 0xf0, 0x7e, 0x02],
10131 );
10132 assert!(
10134 encoder
10135 .encode(&ArmOp::Orr {
10136 rd: Reg::R2,
10137 rn: Reg::R0,
10138 op2: Operand2::Imm(0x140),
10139 })
10140 .is_err(),
10141 "ORR #0x140 must error, not emit a NOP"
10142 );
10143 }
10144
10145 #[test]
10146 fn test_encode_mve_different_qregs() {
10147 let encoder = ArmEncoder::new_thumb2();
10148
10149 let op1 = ArmOp::MveAddI {
10151 qd: QReg::Q0,
10152 qn: QReg::Q0,
10153 qm: QReg::Q0,
10154 size: MveSize::S32,
10155 };
10156 let op2 = ArmOp::MveAddI {
10157 qd: QReg::Q3,
10158 qn: QReg::Q5,
10159 qm: QReg::Q7,
10160 size: MveSize::S32,
10161 };
10162 let code1 = encoder.encode(&op1).unwrap();
10163 let code2 = encoder.encode(&op2).unwrap();
10164 assert_ne!(
10165 code1, code2,
10166 "Different Q-registers should produce different encodings"
10167 );
10168 }
10169
10170 #[test]
10171 fn test_encode_mve_arm32_nop() {
10172 let encoder = ArmEncoder::new_arm32();
10174 let op = ArmOp::MveAddI {
10175 qd: QReg::Q0,
10176 qn: QReg::Q1,
10177 qm: QReg::Q2,
10178 size: MveSize::S32,
10179 };
10180 let code = encoder.encode(&op).unwrap();
10181 assert_eq!(code.len(), 4, "ARM32 MVE should be 4 bytes (NOP)");
10182 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10184 assert_eq!(instr, 0xE1A00000, "ARM32 MVE should encode as NOP");
10185 }
10186}