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 << 4)) | idx_reg) as u16;
2686 bytes.extend_from_slice(&hw1.to_le_bytes());
2687 bytes.extend_from_slice(&hw2.to_le_bytes());
2688
2689 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
2695 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
2696
2697 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
2701
2702 Ok(bytes)
2703 }
2704
2705 ArmOp::Label { .. } => Ok(Vec::new()),
2707
2708 ArmOp::Bcc { cond, label: _ } => {
2710 use synth_synthesis::Condition;
2711 let cond_bits: u16 = match cond {
2712 Condition::EQ => 0x0,
2713 Condition::NE => 0x1,
2714 Condition::HS => 0x2,
2715 Condition::LO => 0x3,
2716 Condition::HI => 0x8,
2717 Condition::LS => 0x9,
2718 Condition::GE => 0xA,
2719 Condition::LT => 0xB,
2720 Condition::GT => 0xC,
2721 Condition::LE => 0xD,
2722 };
2723 let instr: u16 = 0xD000 | (cond_bits << 8);
2725 Ok(instr.to_le_bytes().to_vec())
2726 }
2727
2728 ArmOp::B { label: _ } => {
2730 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
2734 }
2735
2736 ArmOp::Bhs { label: _ } => {
2739 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
2743 }
2744
2745 ArmOp::Blo { label: _ } => {
2748 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
2752 }
2753
2754 ArmOp::BOffset { offset } => {
2757 let halfword_offset = *offset;
2760
2761 if (-1024..=1022).contains(&halfword_offset) {
2764 let imm11 = (halfword_offset as u16) & 0x7FF;
2766 let instr: u16 = 0xE000 | imm11;
2767 Ok(instr.to_le_bytes().to_vec())
2768 } else {
2769 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
2785 let uoffset = signed_offset as u32;
2786 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;
2794 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2795
2796 let mut bytes = hw1.to_le_bytes().to_vec();
2797 bytes.extend_from_slice(&hw2.to_le_bytes());
2798 Ok(bytes)
2799 }
2800 }
2801
2802 ArmOp::BCondOffset { cond, offset } => {
2804 use synth_synthesis::Condition;
2805 let cond_bits: u16 = match cond {
2806 Condition::EQ => 0x0,
2807 Condition::NE => 0x1,
2808 Condition::HS => 0x2,
2809 Condition::LO => 0x3,
2810 Condition::HI => 0x8,
2811 Condition::LS => 0x9,
2812 Condition::GE => 0xA,
2813 Condition::LT => 0xB,
2814 Condition::GT => 0xC,
2815 Condition::LE => 0xD,
2816 };
2817
2818 let halfword_offset = *offset;
2821
2822 if (-128..=127).contains(&halfword_offset) {
2825 let imm8 = (halfword_offset as u16) & 0xFF;
2826 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
2827 Ok(instr.to_le_bytes().to_vec())
2828 } else {
2829 let offset = halfword_offset >> 1;
2833 let s = if offset < 0 { 1u32 } else { 0u32 };
2834 let imm6 = ((offset >> 11) as u32) & 0x3F;
2835 let imm11 = (offset as u32) & 0x7FF;
2836 let j1 = if s == 1 { 1 } else { 0 };
2837 let j2 = if s == 1 { 1 } else { 0 };
2838
2839 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
2840 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2841
2842 let mut bytes = hw1.to_le_bytes().to_vec();
2843 bytes.extend_from_slice(&hw2.to_le_bytes());
2844 Ok(bytes)
2845 }
2846 }
2847
2848 ArmOp::Bl { label: _ } => {
2849 let hw1: u16 = 0xF7FF;
2864 let hw2: u16 = 0xFFFE;
2865 let mut bytes = hw1.to_le_bytes().to_vec();
2866 bytes.extend_from_slice(&hw2.to_le_bytes());
2867 Ok(bytes)
2868 }
2869
2870 ArmOp::Mvn { rd, op2 } => {
2872 if let Operand2::Reg(rm) = op2 {
2873 let rd_bits = reg_to_bits(rd) as u16;
2874 let rm_bits = reg_to_bits(rm) as u16;
2875
2876 if rd_bits < 8 && rm_bits < 8 {
2877 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
2879 Ok(instr.to_le_bytes().to_vec())
2880 } else {
2881 let hw1: u16 = 0xEA6F_u16;
2883 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
2884 let mut bytes = hw1.to_le_bytes().to_vec();
2885 bytes.extend_from_slice(&hw2.to_le_bytes());
2886 Ok(bytes)
2887 }
2888 } else {
2889 let instr: u16 = 0xBF00;
2890 Ok(instr.to_le_bytes().to_vec())
2891 }
2892 }
2893
2894 ArmOp::Movw { rd, imm16 } => {
2896 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
2897 }
2898
2899 ArmOp::Movt { rd, imm16 } => {
2901 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
2902 }
2903
2904 ArmOp::MovwSym { rd, addend, .. } => {
2909 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
2910 }
2911 ArmOp::MovtSym { rd, addend, .. } => {
2912 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
2913 }
2914
2915 ArmOp::LdrSym { rd, .. } => {
2923 let rt = reg_to_bits(rd) as u16;
2924 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
2927 bytes.extend_from_slice(&hw1.to_le_bytes());
2928 bytes.extend_from_slice(&hw2.to_le_bytes());
2929 Ok(bytes)
2930 }
2931
2932 ArmOp::SetCond { rd, cond } => {
2938 let rd_bits = reg_to_bits(rd) as u16;
2939
2940 use synth_synthesis::Condition;
2942 let cond_bits: u16 = match cond {
2943 Condition::EQ => 0x0,
2944 Condition::NE => 0x1,
2945 Condition::LT => 0xB,
2946 Condition::LE => 0xD,
2947 Condition::GT => 0xC,
2948 Condition::GE => 0xA,
2949 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
2954
2955 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
2960 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
2961
2962 let mut bytes = ite_instr.to_le_bytes().to_vec();
2973 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
2974 if rd_bits <= 7 {
2975 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
2977 } else {
2978 let hw1: u16 = 0xF04F;
2980 let hw2: u16 = (rd_bits << 8) | imm;
2981 bytes.extend_from_slice(&hw1.to_le_bytes());
2982 bytes.extend_from_slice(&hw2.to_le_bytes());
2983 }
2984 };
2985 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
2988 }
2989
2990 ArmOp::I64SetCond {
2995 rd,
2996 rn_lo,
2997 rn_hi,
2998 rm_lo,
2999 rm_hi,
3000 cond,
3001 } => {
3002 use synth_synthesis::Condition;
3003 let rd_bits = reg_to_bits(rd) as u16;
3004 let mut bytes = Vec::new();
3005
3006 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3008 rm: &synth_synthesis::Reg|
3009 -> Vec<u8> {
3010 let rn_bits = reg_to_bits(rn) as u16;
3011 let rm_bits = reg_to_bits(rm) as u16;
3012 if rn_bits < 8 && rm_bits < 8 {
3013 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3014 instr.to_le_bytes().to_vec()
3015 } else {
3016 let n_bit = (rn_bits >> 3) & 1;
3017 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3018 instr.to_le_bytes().to_vec()
3019 }
3020 };
3021
3022 let encode_ite = |cond_bits: u16| -> Vec<u8> {
3024 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3025 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3026 ite_instr.to_le_bytes().to_vec()
3027 };
3028
3029 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
3031 let mut b = encode_ite(cond_bits);
3032 if rd_bits < 8 {
3033 let mov_one: u16 = 0x2001 | (rd_bits << 8);
3034 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
3035 b.extend_from_slice(&mov_one.to_le_bytes());
3036 b.extend_from_slice(&mov_zero.to_le_bytes());
3037 } else {
3038 for imm in [1u16, 0u16] {
3046 let hw1: u16 = 0xF04F;
3047 let hw2: u16 = (rd_bits << 8) | imm;
3048 b.extend_from_slice(&hw1.to_le_bytes());
3049 b.extend_from_slice(&hw2.to_le_bytes());
3050 }
3051 }
3052 b
3053 };
3054
3055 match cond {
3056 Condition::EQ | Condition::NE => {
3057 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3059
3060 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
3063
3064 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
3066
3067 let cond_bits: u16 = match cond {
3069 Condition::EQ => 0x0,
3070 Condition::NE => 0x1,
3071 _ => unreachable!(),
3072 };
3073 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
3074 }
3075
3076 Condition::LT => {
3077 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3079
3080 let rn_hi_bits = reg_to_bits(rn_hi);
3083 let rm_hi_bits = reg_to_bits(rm_hi);
3084 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3085 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3086 bytes.extend_from_slice(&hw1.to_le_bytes());
3087 bytes.extend_from_slice(&hw2.to_le_bytes());
3088
3089 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3092
3093 Condition::GT => {
3094 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3097
3098 let rm_hi_bits = reg_to_bits(rm_hi);
3100 let rn_hi_bits = reg_to_bits(rn_hi);
3101 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3102 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3103 bytes.extend_from_slice(&hw1.to_le_bytes());
3104 bytes.extend_from_slice(&hw2.to_le_bytes());
3105
3106 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3109
3110 Condition::LE => {
3111 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3115
3116 let rm_hi_bits = reg_to_bits(rm_hi);
3118 let rn_hi_bits = reg_to_bits(rn_hi);
3119 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3120 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3121 bytes.extend_from_slice(&hw1.to_le_bytes());
3122 bytes.extend_from_slice(&hw2.to_le_bytes());
3123
3124 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3127
3128 Condition::GE => {
3129 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3132
3133 let rn_hi_bits = reg_to_bits(rn_hi);
3135 let rm_hi_bits = reg_to_bits(rm_hi);
3136 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3137 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3138 bytes.extend_from_slice(&hw1.to_le_bytes());
3139 bytes.extend_from_slice(&hw2.to_le_bytes());
3140
3141 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3144
3145 Condition::LO => {
3147 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3149 let rn_hi_bits = reg_to_bits(rn_hi);
3150 let rm_hi_bits = reg_to_bits(rm_hi);
3151 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3152 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3153 bytes.extend_from_slice(&hw1.to_le_bytes());
3154 bytes.extend_from_slice(&hw2.to_le_bytes());
3155 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3157
3158 Condition::HI => {
3159 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3161 let rm_hi_bits = reg_to_bits(rm_hi);
3162 let rn_hi_bits = reg_to_bits(rn_hi);
3163 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3164 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3165 bytes.extend_from_slice(&hw1.to_le_bytes());
3166 bytes.extend_from_slice(&hw2.to_le_bytes());
3167 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3169
3170 Condition::LS => {
3171 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3173 let rm_hi_bits = reg_to_bits(rm_hi);
3174 let rn_hi_bits = reg_to_bits(rn_hi);
3175 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3176 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3177 bytes.extend_from_slice(&hw1.to_le_bytes());
3178 bytes.extend_from_slice(&hw2.to_le_bytes());
3179 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3181
3182 Condition::HS => {
3183 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3185 let rn_hi_bits = reg_to_bits(rn_hi);
3186 let rm_hi_bits = reg_to_bits(rm_hi);
3187 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3188 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3189 bytes.extend_from_slice(&hw1.to_le_bytes());
3190 bytes.extend_from_slice(&hw2.to_le_bytes());
3191 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3193 }
3194
3195 Ok(bytes)
3196 }
3197
3198 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
3201 let rd_bits = reg_to_bits(rd);
3202 let rn_lo_bits = reg_to_bits(rn_lo);
3203 let rn_hi_bits = reg_to_bits(rn_hi);
3204 let mut bytes = Vec::new();
3205
3206 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
3208 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
3209 bytes.extend_from_slice(&hw1.to_le_bytes());
3210 bytes.extend_from_slice(&hw2.to_le_bytes());
3211
3212 if rd_bits < 8 {
3217 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
3218 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
3219 } else {
3220 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
3221 let hw2: u16 = 0x0F00;
3222 bytes.extend_from_slice(&hw1.to_le_bytes());
3223 bytes.extend_from_slice(&hw2.to_le_bytes());
3224 }
3225
3226 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
3230 bytes.extend_from_slice(&ite_instr.to_le_bytes());
3231 if rd_bits < 8 {
3232 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
3233 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
3234 bytes.extend_from_slice(&mov_one.to_le_bytes());
3235 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3236 } else {
3237 for imm in [1u16, 0u16] {
3238 let hw1: u16 = 0xF04F;
3239 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
3240 bytes.extend_from_slice(&hw1.to_le_bytes());
3241 bytes.extend_from_slice(&hw2.to_le_bytes());
3242 }
3243 }
3244
3245 Ok(bytes)
3246 }
3247
3248 ArmOp::I64Mul {
3252 rd_lo,
3253 rd_hi,
3254 rn_lo,
3255 rn_hi,
3256 rm_lo,
3257 rm_hi,
3258 } => {
3259 let rd_lo_bits = reg_to_bits(rd_lo);
3260 let rd_hi_bits = reg_to_bits(rd_hi);
3261 let rn_lo_bits = reg_to_bits(rn_lo);
3262 let rn_hi_bits = reg_to_bits(rn_hi);
3263 let rm_lo_bits = reg_to_bits(rm_lo);
3264 let rm_hi_bits = reg_to_bits(rm_hi);
3265 let r12: u32 = 12; let mut bytes = Vec::new();
3267
3268 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
3271 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
3272 bytes.extend_from_slice(&hw1.to_le_bytes());
3273 bytes.extend_from_slice(&hw2.to_le_bytes());
3274
3275 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
3278 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
3279 bytes.extend_from_slice(&hw1.to_le_bytes());
3280 bytes.extend_from_slice(&hw2.to_le_bytes());
3281
3282 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
3285 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3286 bytes.extend_from_slice(&hw1.to_le_bytes());
3287 bytes.extend_from_slice(&hw2.to_le_bytes());
3288
3289 let d_bit = (rd_hi_bits >> 3) & 1;
3292 let add_instr: u16 =
3293 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
3294 bytes.extend_from_slice(&add_instr.to_le_bytes());
3295
3296 Ok(bytes)
3297 }
3298
3299 ArmOp::I64Shl {
3302 rd_lo,
3303 rd_hi,
3304 rn_lo,
3305 rn_hi,
3306 rm_lo,
3307 rm_hi,
3308 } => {
3309 let rd_lo_bits = reg_to_bits(rd_lo);
3310 let rd_hi_bits = reg_to_bits(rd_hi);
3311 let rn_lo_bits = reg_to_bits(rn_lo);
3312 let rn_hi_bits = reg_to_bits(rn_hi);
3313 let rm_lo_bits = reg_to_bits(rm_lo);
3314 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3316
3317 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3319 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3320 bytes.extend_from_slice(&hw1.to_le_bytes());
3321 bytes.extend_from_slice(&hw2.to_le_bytes());
3322
3323 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3325 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3326 bytes.extend_from_slice(&hw1.to_le_bytes());
3327 bytes.extend_from_slice(&hw2.to_le_bytes());
3328
3329 let bpl: u16 = 0xD50A;
3331 bytes.extend_from_slice(&bpl.to_le_bytes());
3332
3333 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3336 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3337 bytes.extend_from_slice(&hw1.to_le_bytes());
3338 bytes.extend_from_slice(&hw2.to_le_bytes());
3339
3340 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3342 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3343 bytes.extend_from_slice(&hw1.to_le_bytes());
3344 bytes.extend_from_slice(&hw2.to_le_bytes());
3345
3346 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3348 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3349 bytes.extend_from_slice(&hw1.to_le_bytes());
3350 bytes.extend_from_slice(&hw2.to_le_bytes());
3351
3352 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3354 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
3355 bytes.extend_from_slice(&hw1.to_le_bytes());
3356 bytes.extend_from_slice(&hw2.to_le_bytes());
3357
3358 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3360 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3361 bytes.extend_from_slice(&hw1.to_le_bytes());
3362 bytes.extend_from_slice(&hw2.to_le_bytes());
3363
3364 let b_done: u16 = 0xE002;
3366 bytes.extend_from_slice(&b_done.to_le_bytes());
3367
3368 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3371 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
3372 bytes.extend_from_slice(&hw1.to_le_bytes());
3373 bytes.extend_from_slice(&hw2.to_le_bytes());
3374
3375 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
3377 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3378
3379 Ok(bytes) }
3381
3382 ArmOp::I64ShrU {
3384 rd_lo,
3385 rd_hi,
3386 rn_lo,
3387 rn_hi,
3388 rm_lo,
3389 rm_hi,
3390 } => {
3391 let rd_lo_bits = reg_to_bits(rd_lo);
3392 let rd_hi_bits = reg_to_bits(rd_hi);
3393 let rn_lo_bits = reg_to_bits(rn_lo);
3394 let rn_hi_bits = reg_to_bits(rn_hi);
3395 let rm_lo_bits = reg_to_bits(rm_lo);
3396 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3398
3399 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3401 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3402 bytes.extend_from_slice(&hw1.to_le_bytes());
3403 bytes.extend_from_slice(&hw2.to_le_bytes());
3404
3405 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3407 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3408 bytes.extend_from_slice(&hw1.to_le_bytes());
3409 bytes.extend_from_slice(&hw2.to_le_bytes());
3410
3411 let bpl: u16 = 0xD50A;
3413 bytes.extend_from_slice(&bpl.to_le_bytes());
3414
3415 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3418 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3419 bytes.extend_from_slice(&hw1.to_le_bytes());
3420 bytes.extend_from_slice(&hw2.to_le_bytes());
3421
3422 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3424 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3425 bytes.extend_from_slice(&hw1.to_le_bytes());
3426 bytes.extend_from_slice(&hw2.to_le_bytes());
3427
3428 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3430 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3431 bytes.extend_from_slice(&hw1.to_le_bytes());
3432 bytes.extend_from_slice(&hw2.to_le_bytes());
3433
3434 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3436 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3437 bytes.extend_from_slice(&hw1.to_le_bytes());
3438 bytes.extend_from_slice(&hw2.to_le_bytes());
3439
3440 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3442 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3443 bytes.extend_from_slice(&hw1.to_le_bytes());
3444 bytes.extend_from_slice(&hw2.to_le_bytes());
3445
3446 let b_done: u16 = 0xE002;
3448 bytes.extend_from_slice(&b_done.to_le_bytes());
3449
3450 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3453 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3454 bytes.extend_from_slice(&hw1.to_le_bytes());
3455 bytes.extend_from_slice(&hw2.to_le_bytes());
3456
3457 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
3459 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3460
3461 Ok(bytes) }
3463
3464 ArmOp::I64ShrS {
3466 rd_lo,
3467 rd_hi,
3468 rn_lo,
3469 rn_hi,
3470 rm_lo,
3471 rm_hi,
3472 } => {
3473 let rd_lo_bits = reg_to_bits(rd_lo);
3474 let rd_hi_bits = reg_to_bits(rd_hi);
3475 let rn_lo_bits = reg_to_bits(rn_lo);
3476 let rn_hi_bits = reg_to_bits(rn_hi);
3477 let rm_lo_bits = reg_to_bits(rm_lo);
3478 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3480
3481 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3483 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3484 bytes.extend_from_slice(&hw1.to_le_bytes());
3485 bytes.extend_from_slice(&hw2.to_le_bytes());
3486
3487 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3489 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3490 bytes.extend_from_slice(&hw1.to_le_bytes());
3491 bytes.extend_from_slice(&hw2.to_le_bytes());
3492
3493 let bpl: u16 = 0xD50A;
3495 bytes.extend_from_slice(&bpl.to_le_bytes());
3496
3497 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3500 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3501 bytes.extend_from_slice(&hw1.to_le_bytes());
3502 bytes.extend_from_slice(&hw2.to_le_bytes());
3503
3504 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3506 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3507 bytes.extend_from_slice(&hw1.to_le_bytes());
3508 bytes.extend_from_slice(&hw2.to_le_bytes());
3509
3510 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3512 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3513 bytes.extend_from_slice(&hw1.to_le_bytes());
3514 bytes.extend_from_slice(&hw2.to_le_bytes());
3515
3516 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3518 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3519 bytes.extend_from_slice(&hw1.to_le_bytes());
3520 bytes.extend_from_slice(&hw2.to_le_bytes());
3521
3522 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3524 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3525 bytes.extend_from_slice(&hw1.to_le_bytes());
3526 bytes.extend_from_slice(&hw2.to_le_bytes());
3527
3528 let b_done: u16 = 0xE003;
3530 bytes.extend_from_slice(&b_done.to_le_bytes());
3531
3532 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3535 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3536 bytes.extend_from_slice(&hw1.to_le_bytes());
3537 bytes.extend_from_slice(&hw2.to_le_bytes());
3538
3539 let hw1: u16 = 0xEA4F;
3543 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
3544 bytes.extend_from_slice(&hw1.to_le_bytes());
3545 bytes.extend_from_slice(&hw2.to_le_bytes());
3546
3547 Ok(bytes) }
3549
3550 ArmOp::I64Rotl {
3555 rdlo,
3556 rdhi,
3557 rnlo,
3558 rnhi,
3559 shift,
3560 } => {
3561 let rd_lo_bits = reg_to_bits(rdlo);
3562 let rd_hi_bits = reg_to_bits(rdhi);
3563 let rn_lo_bits = reg_to_bits(rnlo);
3564 let rn_hi_bits = reg_to_bits(rnhi);
3565 let shift_bits = reg_to_bits(shift);
3566 let r12: u32 = 12; let r3: u32 = 3; let r4: u32 = 4; let mut bytes = Vec::new();
3570
3571 bytes.extend_from_slice(&0xB410u16.to_le_bytes());
3573
3574 let hw1: u16 = (0xF000 | shift_bits) as u16;
3576 let hw2: u16 = ((shift_bits << 8) | 0x3F) as u16;
3577 bytes.extend_from_slice(&hw1.to_le_bytes());
3578 bytes.extend_from_slice(&hw2.to_le_bytes());
3579
3580 let hw1: u16 = (0xF1B0 | shift_bits) as u16;
3582 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3583 bytes.extend_from_slice(&hw1.to_le_bytes());
3584 bytes.extend_from_slice(&hw2.to_le_bytes());
3585
3586 let bpl: u16 = 0xD50E;
3588 bytes.extend_from_slice(&bpl.to_le_bytes());
3589
3590 let hw1: u16 = (0xF1C0 | shift_bits) as u16;
3593 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3594 bytes.extend_from_slice(&hw1.to_le_bytes());
3595 bytes.extend_from_slice(&hw2.to_le_bytes());
3596
3597 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3599 let hw2: u16 = (0xF000 | (r4 << 8) | r3) as u16;
3600 bytes.extend_from_slice(&hw1.to_le_bytes());
3601 bytes.extend_from_slice(&hw2.to_le_bytes());
3602
3603 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3605 let hw2: u16 = (0xF000 | (r12 << 8) | r3) as u16;
3606 bytes.extend_from_slice(&hw1.to_le_bytes());
3607 bytes.extend_from_slice(&hw2.to_le_bytes());
3608
3609 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3611 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | shift_bits) as u16;
3612 bytes.extend_from_slice(&hw1.to_le_bytes());
3613 bytes.extend_from_slice(&hw2.to_le_bytes());
3614
3615 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3617 let hw2: u16 = ((rd_hi_bits << 8) | r4) as u16;
3618 bytes.extend_from_slice(&hw1.to_le_bytes());
3619 bytes.extend_from_slice(&hw2.to_le_bytes());
3620
3621 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3623 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | shift_bits) as u16;
3624 bytes.extend_from_slice(&hw1.to_le_bytes());
3625 bytes.extend_from_slice(&hw2.to_le_bytes());
3626
3627 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3629 let hw2: u16 = ((rd_lo_bits << 8) | r12) as u16;
3630 bytes.extend_from_slice(&hw1.to_le_bytes());
3631 bytes.extend_from_slice(&hw2.to_le_bytes());
3632
3633 let b_done: u16 = 0xE00E;
3635 bytes.extend_from_slice(&b_done.to_le_bytes());
3636
3637 let hw1: u16 = (0xF1C0 | r3) as u16;
3641 let hw2: u16 = ((r4 << 8) | 0x20) as u16;
3642 bytes.extend_from_slice(&hw1.to_le_bytes());
3643 bytes.extend_from_slice(&hw2.to_le_bytes());
3644
3645 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3647 let hw2: u16 = (0xF000 | (r12 << 8) | r4) as u16;
3648 bytes.extend_from_slice(&hw1.to_le_bytes());
3649 bytes.extend_from_slice(&hw2.to_le_bytes());
3650
3651 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3653 let hw2: u16 = (0xF000 | (r4 << 8) | r4) as u16;
3654 bytes.extend_from_slice(&hw1.to_le_bytes());
3655 bytes.extend_from_slice(&hw2.to_le_bytes());
3656
3657 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3659 let hw2: u16 = (0xF000 | (shift_bits << 8) | r3) as u16;
3660 bytes.extend_from_slice(&hw1.to_le_bytes());
3661 bytes.extend_from_slice(&hw2.to_le_bytes());
3662
3663 let hw1: u16 = (0xEA40 | shift_bits) as u16;
3665 let hw2: u16 = ((shift_bits << 8) | r12) as u16;
3666 bytes.extend_from_slice(&hw1.to_le_bytes());
3667 bytes.extend_from_slice(&hw2.to_le_bytes());
3668
3669 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3671 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | r3) as u16;
3672 bytes.extend_from_slice(&hw1.to_le_bytes());
3673 bytes.extend_from_slice(&hw2.to_le_bytes());
3674
3675 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3677 let hw2: u16 = ((rd_lo_bits << 8) | r4) as u16;
3678 bytes.extend_from_slice(&hw1.to_le_bytes());
3679 bytes.extend_from_slice(&hw2.to_le_bytes());
3680
3681 let d_bit = (rd_hi_bits >> 3) & 1;
3683 let mov_instr: u16 =
3684 (0x4600 | (d_bit << 7) | (shift_bits << 3) | (rd_hi_bits & 0x7)) as u16;
3685 bytes.extend_from_slice(&mov_instr.to_le_bytes());
3686
3687 bytes.extend_from_slice(&0xBC10u16.to_le_bytes());
3689
3690 Ok(bytes) }
3692
3693 ArmOp::I64Rotr {
3698 rdlo,
3699 rdhi,
3700 rnlo,
3701 rnhi,
3702 shift,
3703 } => {
3704 let rd_lo_bits = reg_to_bits(rdlo);
3705 let rd_hi_bits = reg_to_bits(rdhi);
3706 let rn_lo_bits = reg_to_bits(rnlo);
3707 let rn_hi_bits = reg_to_bits(rnhi);
3708 let shift_bits = reg_to_bits(shift);
3709 let r12: u32 = 12;
3710 let r3: u32 = 3;
3711 let r4: u32 = 4;
3712 let mut bytes = Vec::new();
3713
3714 bytes.extend_from_slice(&0xB410u16.to_le_bytes());
3716
3717 let hw1: u16 = (0xF000 | shift_bits) as u16;
3719 let hw2: u16 = ((shift_bits << 8) | 0x3F) as u16;
3720 bytes.extend_from_slice(&hw1.to_le_bytes());
3721 bytes.extend_from_slice(&hw2.to_le_bytes());
3722
3723 let hw1: u16 = (0xF1B0 | shift_bits) as u16;
3725 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3726 bytes.extend_from_slice(&hw1.to_le_bytes());
3727 bytes.extend_from_slice(&hw2.to_le_bytes());
3728
3729 let bpl: u16 = 0xD50E;
3731 bytes.extend_from_slice(&bpl.to_le_bytes());
3732
3733 let hw1: u16 = (0xF1C0 | shift_bits) as u16;
3736 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3737 bytes.extend_from_slice(&hw1.to_le_bytes());
3738 bytes.extend_from_slice(&hw2.to_le_bytes());
3739
3740 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3742 let hw2: u16 = (0xF000 | (r4 << 8) | r3) as u16;
3743 bytes.extend_from_slice(&hw1.to_le_bytes());
3744 bytes.extend_from_slice(&hw2.to_le_bytes());
3745
3746 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3748 let hw2: u16 = (0xF000 | (r12 << 8) | r3) as u16;
3749 bytes.extend_from_slice(&hw1.to_le_bytes());
3750 bytes.extend_from_slice(&hw2.to_le_bytes());
3751
3752 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3754 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | shift_bits) as u16;
3755 bytes.extend_from_slice(&hw1.to_le_bytes());
3756 bytes.extend_from_slice(&hw2.to_le_bytes());
3757
3758 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3760 let hw2: u16 = ((rd_lo_bits << 8) | r4) as u16;
3761 bytes.extend_from_slice(&hw1.to_le_bytes());
3762 bytes.extend_from_slice(&hw2.to_le_bytes());
3763
3764 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3766 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | shift_bits) as u16;
3767 bytes.extend_from_slice(&hw1.to_le_bytes());
3768 bytes.extend_from_slice(&hw2.to_le_bytes());
3769
3770 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3772 let hw2: u16 = ((rd_hi_bits << 8) | r12) as u16;
3773 bytes.extend_from_slice(&hw1.to_le_bytes());
3774 bytes.extend_from_slice(&hw2.to_le_bytes());
3775
3776 let b_done: u16 = 0xE00E;
3778 bytes.extend_from_slice(&b_done.to_le_bytes());
3779
3780 let hw1: u16 = (0xF1C0 | r3) as u16;
3783 let hw2: u16 = ((r4 << 8) | 0x20) as u16;
3784 bytes.extend_from_slice(&hw1.to_le_bytes());
3785 bytes.extend_from_slice(&hw2.to_le_bytes());
3786
3787 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3789 let hw2: u16 = (0xF000 | (r12 << 8) | r4) as u16;
3790 bytes.extend_from_slice(&hw1.to_le_bytes());
3791 bytes.extend_from_slice(&hw2.to_le_bytes());
3792
3793 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3795 let hw2: u16 = (0xF000 | (r4 << 8) | r4) as u16;
3796 bytes.extend_from_slice(&hw1.to_le_bytes());
3797 bytes.extend_from_slice(&hw2.to_le_bytes());
3798
3799 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3801 let hw2: u16 = (0xF000 | (shift_bits << 8) | r3) as u16;
3802 bytes.extend_from_slice(&hw1.to_le_bytes());
3803 bytes.extend_from_slice(&hw2.to_le_bytes());
3804
3805 let hw1: u16 = (0xEA40 | shift_bits) as u16;
3807 let hw2: u16 = ((shift_bits << 8) | r12) as u16;
3808 bytes.extend_from_slice(&hw1.to_le_bytes());
3809 bytes.extend_from_slice(&hw2.to_le_bytes());
3810
3811 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3813 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | r3) as u16;
3814 bytes.extend_from_slice(&hw1.to_le_bytes());
3815 bytes.extend_from_slice(&hw2.to_le_bytes());
3816
3817 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3819 let hw2: u16 = ((rd_hi_bits << 8) | r4) as u16;
3820 bytes.extend_from_slice(&hw1.to_le_bytes());
3821 bytes.extend_from_slice(&hw2.to_le_bytes());
3822
3823 let d_bit = (rd_lo_bits >> 3) & 1;
3825 let mov_instr: u16 =
3826 (0x4600 | (d_bit << 7) | (shift_bits << 3) | (rd_lo_bits & 0x7)) as u16;
3827 bytes.extend_from_slice(&mov_instr.to_le_bytes());
3828
3829 bytes.extend_from_slice(&0xBC10u16.to_le_bytes());
3831
3832 Ok(bytes) }
3834
3835 ArmOp::I64Clz { rd, rnlo, rnhi } => {
3849 let rd_bits = reg_to_bits(rd);
3850 let rn_lo_bits = reg_to_bits(rnlo);
3851 let rn_hi_bits = reg_to_bits(rnhi);
3852 let mut bytes = Vec::new();
3853
3854 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
3856 let hw2: u16 = 0x0F00;
3857 bytes.extend_from_slice(&hw1.to_le_bytes());
3858 bytes.extend_from_slice(&hw2.to_le_bytes());
3859
3860 let beq: u16 = 0xD003;
3863 bytes.extend_from_slice(&beq.to_le_bytes());
3864
3865 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
3868 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
3869 bytes.extend_from_slice(&hw1.to_le_bytes());
3870 bytes.extend_from_slice(&hw2.to_le_bytes());
3871
3872 let b_done: u16 = 0xE004;
3875 bytes.extend_from_slice(&b_done.to_le_bytes());
3876
3877 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3879
3880 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
3884 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
3885 bytes.extend_from_slice(&hw1.to_le_bytes());
3886 bytes.extend_from_slice(&hw2.to_le_bytes());
3887
3888 let hw1: u16 = (0xF100 | rd_bits) as u16;
3890 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3891 bytes.extend_from_slice(&hw1.to_le_bytes());
3892 bytes.extend_from_slice(&hw2.to_le_bytes());
3893
3894 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3898 bytes.extend_from_slice(&mov0.to_le_bytes());
3899
3900 Ok(bytes)
3901 }
3902
3903 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
3919 let rd_bits = reg_to_bits(rd);
3920 let rn_lo_bits = reg_to_bits(rnlo);
3921 let rn_hi_bits = reg_to_bits(rnhi);
3922 let mut bytes = Vec::new();
3923
3924 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
3926 let hw2: u16 = 0x0F00;
3927 bytes.extend_from_slice(&hw1.to_le_bytes());
3928 bytes.extend_from_slice(&hw2.to_le_bytes());
3929
3930 let beq: u16 = 0xD005;
3933 bytes.extend_from_slice(&beq.to_le_bytes());
3934
3935 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
3938 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
3939 bytes.extend_from_slice(&hw1.to_le_bytes());
3940 bytes.extend_from_slice(&hw2.to_le_bytes());
3941
3942 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3945 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3946 bytes.extend_from_slice(&hw1.to_le_bytes());
3947 bytes.extend_from_slice(&hw2.to_le_bytes());
3948
3949 let b_done: u16 = 0xE006;
3952 bytes.extend_from_slice(&b_done.to_le_bytes());
3953
3954 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3956
3957 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
3961 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
3962 bytes.extend_from_slice(&hw1.to_le_bytes());
3963 bytes.extend_from_slice(&hw2.to_le_bytes());
3964
3965 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3968 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3969 bytes.extend_from_slice(&hw1.to_le_bytes());
3970 bytes.extend_from_slice(&hw2.to_le_bytes());
3971
3972 let hw1: u16 = (0xF100 | rd_bits) as u16;
3974 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3975 bytes.extend_from_slice(&hw1.to_le_bytes());
3976 bytes.extend_from_slice(&hw2.to_le_bytes());
3977
3978 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3981 bytes.extend_from_slice(&mov0.to_le_bytes());
3982
3983 Ok(bytes)
3984 }
3985
3986 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
3990 let rd_bits = reg_to_bits(rd);
3991 let rn_lo_bits = reg_to_bits(rnlo);
3992 let rn_hi_bits = reg_to_bits(rnhi);
3993 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
3996
3997 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
3999
4000 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_lo_bits << 3) | (4 & 0x7)) as u16;
4010 bytes.extend_from_slice(&mov.to_le_bytes());
4011
4012 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_hi_bits << 3) | (5 & 0x7)) as u16;
4015 bytes.extend_from_slice(&mov.to_le_bytes());
4016
4017 let hw1: u16 = 0xEA4F;
4021 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4022 bytes.extend_from_slice(&hw1.to_le_bytes());
4023 bytes.extend_from_slice(&hw2.to_le_bytes());
4024
4025 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4028 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4029 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4031 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4032
4033 let hw1: u16 = (0xEA00 | r12) as u16;
4035 let hw2: u16 = ((r12 << 8) | r3) as u16;
4036 bytes.extend_from_slice(&hw1.to_le_bytes());
4037 bytes.extend_from_slice(&hw2.to_le_bytes());
4038
4039 let hw1: u16 = (0xEBA0 | 4) as u16;
4041 let hw2: u16 = ((4 << 8) | r12) as u16;
4042 bytes.extend_from_slice(&hw1.to_le_bytes());
4043 bytes.extend_from_slice(&hw2.to_le_bytes());
4044
4045 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4049 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4050 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4052 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4053
4054 let hw1: u16 = (0xEA00 | 4) as u16;
4056 let hw2: u16 = ((r12 << 8) | r3) as u16;
4057 bytes.extend_from_slice(&hw1.to_le_bytes());
4058 bytes.extend_from_slice(&hw2.to_le_bytes());
4059
4060 let hw1: u16 = 0xEA4F;
4062 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4063 bytes.extend_from_slice(&hw1.to_le_bytes());
4064 bytes.extend_from_slice(&hw2.to_le_bytes());
4065
4066 let hw1: u16 = (0xEA00 | 4) as u16;
4068 let hw2: u16 = ((4 << 8) | r3) as u16;
4069 bytes.extend_from_slice(&hw1.to_le_bytes());
4070 bytes.extend_from_slice(&hw2.to_le_bytes());
4071
4072 let hw1: u16 = (0xEB00 | 4) as u16;
4074 let hw2: u16 = ((4 << 8) | r12) as u16;
4075 bytes.extend_from_slice(&hw1.to_le_bytes());
4076 bytes.extend_from_slice(&hw2.to_le_bytes());
4077
4078 let hw1: u16 = 0xEA4F;
4083 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
4084 bytes.extend_from_slice(&hw1.to_le_bytes());
4085 bytes.extend_from_slice(&hw2.to_le_bytes());
4086
4087 let hw1: u16 = (0xEB00 | 4) as u16;
4089 let hw2: u16 = ((4 << 8) | r12) as u16;
4090 bytes.extend_from_slice(&hw1.to_le_bytes());
4091 bytes.extend_from_slice(&hw2.to_le_bytes());
4092
4093 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4098 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4099 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4101 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4102
4103 let hw1: u16 = (0xEA00 | 4) as u16;
4105 let hw2: u16 = ((4 << 8) | r3) as u16;
4106 bytes.extend_from_slice(&hw1.to_le_bytes());
4107 bytes.extend_from_slice(&hw2.to_le_bytes());
4108
4109 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4113 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4114 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4116 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4117
4118 let hw1: u16 = (0xFB00 | 4) as u16;
4121 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4122 bytes.extend_from_slice(&hw1.to_le_bytes());
4123 bytes.extend_from_slice(&hw2.to_le_bytes());
4124
4125 let hw1: u16 = 0xEA4F;
4128 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
4129 bytes.extend_from_slice(&hw1.to_le_bytes());
4130 bytes.extend_from_slice(&hw2.to_le_bytes());
4131
4132 let hw1: u16 = 0xEA4F;
4135 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
4136 bytes.extend_from_slice(&hw1.to_le_bytes());
4137 bytes.extend_from_slice(&hw2.to_le_bytes());
4138
4139 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4141 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4142 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4143 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4144
4145 let hw1: u16 = (0xEA00 | r12) as u16;
4146 let hw2: u16 = ((r12 << 8) | r3) as u16;
4147 bytes.extend_from_slice(&hw1.to_le_bytes());
4148 bytes.extend_from_slice(&hw2.to_le_bytes());
4149
4150 let hw1: u16 = (0xEBA0 | 5) as u16;
4151 let hw2: u16 = ((5 << 8) | r12) as u16;
4152 bytes.extend_from_slice(&hw1.to_le_bytes());
4153 bytes.extend_from_slice(&hw2.to_le_bytes());
4154
4155 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4157 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4158 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4159 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4160
4161 let hw1: u16 = (0xEA00 | 5) as u16;
4162 let hw2: u16 = ((r12 << 8) | r3) as u16;
4163 bytes.extend_from_slice(&hw1.to_le_bytes());
4164 bytes.extend_from_slice(&hw2.to_le_bytes());
4165
4166 let hw1: u16 = 0xEA4F;
4167 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
4168 bytes.extend_from_slice(&hw1.to_le_bytes());
4169 bytes.extend_from_slice(&hw2.to_le_bytes());
4170
4171 let hw1: u16 = (0xEA00 | 5) as u16;
4172 let hw2: u16 = ((5 << 8) | r3) as u16;
4173 bytes.extend_from_slice(&hw1.to_le_bytes());
4174 bytes.extend_from_slice(&hw2.to_le_bytes());
4175
4176 let hw1: u16 = (0xEB00 | 5) as u16;
4177 let hw2: u16 = ((5 << 8) | r12) as u16;
4178 bytes.extend_from_slice(&hw1.to_le_bytes());
4179 bytes.extend_from_slice(&hw2.to_le_bytes());
4180
4181 let hw1: u16 = 0xEA4F;
4184 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4185 bytes.extend_from_slice(&hw1.to_le_bytes());
4186 bytes.extend_from_slice(&hw2.to_le_bytes());
4187
4188 let hw1: u16 = (0xEB00 | 5) as u16;
4189 let hw2: u16 = ((5 << 8) | r12) as u16;
4190 bytes.extend_from_slice(&hw1.to_le_bytes());
4191 bytes.extend_from_slice(&hw2.to_le_bytes());
4192
4193 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4195 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4196 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4197 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4198
4199 let hw1: u16 = (0xEA00 | 5) as u16;
4200 let hw2: u16 = ((5 << 8) | r3) as u16;
4201 bytes.extend_from_slice(&hw1.to_le_bytes());
4202 bytes.extend_from_slice(&hw2.to_le_bytes());
4203
4204 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4206 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4207 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4208 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4209
4210 let hw1: u16 = (0xFB00 | 5) as u16;
4213 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
4214 bytes.extend_from_slice(&hw1.to_le_bytes());
4215 bytes.extend_from_slice(&hw2.to_le_bytes());
4216
4217 let hw1: u16 = 0xEA4F;
4220 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
4221 bytes.extend_from_slice(&hw1.to_le_bytes());
4222 bytes.extend_from_slice(&hw2.to_le_bytes());
4223
4224 let rd_bits_u16 = rd_bits as u16;
4227 let instr: u16 = 0x1800 | (5 << 6) | (4 << 3) | rd_bits_u16;
4228 bytes.extend_from_slice(&instr.to_le_bytes());
4229
4230 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
4232
4233 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4235 bytes.extend_from_slice(&mov0.to_le_bytes());
4236
4237 Ok(bytes)
4238 }
4239
4240 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
4243 let rdlo_bits = reg_to_bits(rdlo);
4244 let rdhi_bits = reg_to_bits(rdhi);
4245 let rnlo_bits = reg_to_bits(rnlo);
4246 let mut bytes = Vec::new();
4247
4248 let hw1: u16 = 0xFA4F_u16;
4251 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4252 bytes.extend_from_slice(&hw1.to_le_bytes());
4253 bytes.extend_from_slice(&hw2.to_le_bytes());
4254
4255 let hw1: u16 = 0xEA4F;
4260 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4261 bytes.extend_from_slice(&hw1.to_le_bytes());
4262 bytes.extend_from_slice(&hw2.to_le_bytes());
4263
4264 Ok(bytes)
4265 }
4266
4267 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
4270 let rdlo_bits = reg_to_bits(rdlo);
4271 let rdhi_bits = reg_to_bits(rdhi);
4272 let rnlo_bits = reg_to_bits(rnlo);
4273 let mut bytes = Vec::new();
4274
4275 let hw1: u16 = 0xFA0F_u16;
4278 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4279 bytes.extend_from_slice(&hw1.to_le_bytes());
4280 bytes.extend_from_slice(&hw2.to_le_bytes());
4281
4282 let hw1: u16 = 0xEA4F;
4284 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4285 bytes.extend_from_slice(&hw1.to_le_bytes());
4286 bytes.extend_from_slice(&hw2.to_le_bytes());
4287
4288 Ok(bytes)
4289 }
4290
4291 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
4294 let rdlo_bits = reg_to_bits(rdlo);
4295 let rdhi_bits = reg_to_bits(rdhi);
4296 let rnlo_bits = reg_to_bits(rnlo);
4297 let mut bytes = Vec::new();
4298
4299 if rdlo_bits != rnlo_bits {
4301 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
4303 let mov: u16 = 0x4600
4304 | (d_bit << 7)
4305 | ((rnlo_bits as u16) << 3)
4306 | ((rdlo_bits & 0x7) as u16);
4307 bytes.extend_from_slice(&mov.to_le_bytes());
4308 }
4309
4310 let hw1: u16 = 0xEA4F;
4312 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
4313 bytes.extend_from_slice(&hw1.to_le_bytes());
4314 bytes.extend_from_slice(&hw2.to_le_bytes());
4315
4316 Ok(bytes)
4317 }
4318
4319 ArmOp::SelectMove { rd, rm, cond } => {
4322 let rd_bits = reg_to_bits(rd) as u16;
4323 let rm_bits = reg_to_bits(rm) as u16;
4324
4325 use synth_synthesis::Condition;
4327 let cond_bits: u16 = match cond {
4328 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, };
4339
4340 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
4343
4344 let d_bit = (rd_bits >> 3) & 1;
4347 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4348
4349 let mut bytes = it_instr.to_le_bytes().to_vec();
4351 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4352 Ok(bytes)
4353 }
4354
4355 ArmOp::Popcnt { rd, rm } => {
4366 let mut bytes = Vec::new();
4367
4368 if rd != rm {
4370 let rd_bits = reg_to_bits(rd) as u16;
4371 let rm_bits = reg_to_bits(rm) as u16;
4372 let d_bit = (rd_bits >> 3) & 1;
4374 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4375 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4376 }
4377
4378 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
4381 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
4382
4383 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
4386
4387 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
4389
4390 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
4392 reg_to_bits(rd),
4393 reg_to_bits(rd),
4394 11,
4395 )?);
4396
4397 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
4400 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
4401
4402 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4404 11,
4405 reg_to_bits(rd),
4406 12,
4407 )?);
4408
4409 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
4411 reg_to_bits(rd),
4412 reg_to_bits(rd),
4413 2,
4414 )?);
4415
4416 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4418 reg_to_bits(rd),
4419 reg_to_bits(rd),
4420 12,
4421 )?);
4422
4423 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4425 reg_to_bits(rd),
4426 reg_to_bits(rd),
4427 11,
4428 )?);
4429
4430 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
4433
4434 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4436 reg_to_bits(rd),
4437 reg_to_bits(rd),
4438 11,
4439 )?);
4440
4441 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
4443 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
4444
4445 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4447 reg_to_bits(rd),
4448 reg_to_bits(rd),
4449 12,
4450 )?);
4451
4452 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
4455
4456 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4458 reg_to_bits(rd),
4459 reg_to_bits(rd),
4460 11,
4461 )?);
4462
4463 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
4466
4467 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4469 reg_to_bits(rd),
4470 reg_to_bits(rd),
4471 11,
4472 )?);
4473
4474 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
4477 reg_to_bits(rd),
4478 reg_to_bits(rd),
4479 0x3F,
4480 )?);
4481
4482 Ok(bytes)
4483 }
4484
4485 ArmOp::I64DivU {
4490 rdlo: _,
4491 rdhi: _,
4492 rnlo: _,
4493 rnhi: _,
4494 rmlo: _,
4495 rmhi: _,
4496 } => {
4497 let mut bytes = Vec::new();
4498
4499 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
4503
4504 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());
4515 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
4516
4517 let loop_start = bytes.len();
4519
4520 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
4531 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());
4540 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4541 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
4545 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4546
4547 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
4552 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4553 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());
4584 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4585 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4588
4589 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
4593 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
4594
4595 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4598 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4599 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4600
4601 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
4609
4610 Ok(bytes)
4611 }
4612
4613 ArmOp::I64DivS {
4618 rdlo: _,
4619 rdhi: _,
4620 rnlo: _,
4621 rnhi: _,
4622 rmlo: _,
4623 rmhi: _,
4624 } => {
4625 let mut bytes = Vec::new();
4626
4627 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4629 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4630
4631 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
4634 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
4635
4636 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());
4649
4650 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());
4660
4661 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4664 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4665 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4667 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4668 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4670 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4671
4672 let loop_start = bytes.len();
4673
4674 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4678 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());
4684 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4687
4688 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4692 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());
4705 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4707
4708 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4711
4712 let branch_offset_bytes = bytes.len() - loop_start + 4;
4713 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4714 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4715 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4716
4717 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());
4724 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());
4732
4733 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4735 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4736
4737 Ok(bytes)
4738 }
4739
4740 ArmOp::I64RemU {
4745 rdlo: _,
4746 rdhi: _,
4747 rnlo: _,
4748 rnhi: _,
4749 rmlo: _,
4750 rmhi: _,
4751 } => {
4752 let mut bytes = Vec::new();
4753
4754 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4756 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4757
4758 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4760 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4761 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4763 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4764 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4766 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4767
4768 let loop_start = bytes.len();
4769
4770 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4774 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());
4780 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4783
4784 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4788 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());
4801 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4803
4804 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4807
4808 let branch_offset_bytes = bytes.len() - loop_start + 4;
4809 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4810 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4811 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4812
4813 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4819 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4820
4821 Ok(bytes)
4822 }
4823
4824 ArmOp::I64RemS {
4829 rdlo: _,
4830 rdhi: _,
4831 rnlo: _,
4832 rnhi: _,
4833 rmlo: _,
4834 rmhi: _,
4835 } => {
4836 let mut bytes = Vec::new();
4837
4838 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4840 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4841
4842 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());
4856
4857 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());
4867
4868 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4871 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4872 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4874 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4875 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4877 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4878
4879 let loop_start = bytes.len();
4880
4881 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4885 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());
4891 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4894
4895 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4899 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());
4912 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4914
4915 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4918
4919 let branch_offset_bytes = bytes.len() - loop_start + 4;
4920 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4921 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4922 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4923
4924 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());
4931 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());
4939
4940 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4942 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4943
4944 Ok(bytes)
4945 }
4946
4947 ArmOp::F32Add { sd, sn, sm } => {
4950 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
4951 }
4952 ArmOp::F32Sub { sd, sn, sm } => {
4953 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
4954 }
4955 ArmOp::F32Mul { sd, sn, sm } => {
4956 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
4957 }
4958 ArmOp::F32Div { sd, sn, sm } => {
4959 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
4960 }
4961 ArmOp::F32Abs { sd, sm } => {
4962 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
4963 }
4964 ArmOp::F32Neg { sd, sm } => {
4965 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
4966 }
4967 ArmOp::F32Sqrt { sd, sm } => {
4968 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
4969 }
4970
4971 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
4974 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
4975 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
4976 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
4977 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
4978 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
4979 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
4980
4981 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
4983 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
4984 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
4985 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
4986 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
4987 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
4988
4989 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
4990
4991 ArmOp::F32Load { sd, addr } => {
4992 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
4993 }
4994 ArmOp::F32Store { sd, addr } => {
4995 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
4996 }
4997
4998 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
4999 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5000 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5001 Err(synth_core::Error::synthesis(
5002 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5003 ))
5004 }
5005 ArmOp::F32ReinterpretI32 { sd, rm } => {
5006 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5007 }
5008 ArmOp::I32ReinterpretF32 { rd, sm } => {
5009 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5010 }
5011 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5012 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5013
5014 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5017 0xEE300B00, dd, dn, dm,
5018 )?)),
5019 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5020 0xEE300B40, dd, dn, dm,
5021 )?)),
5022 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5023 0xEE200B00, dd, dn, dm,
5024 )?)),
5025 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5026 0xEE800B00, dd, dn, dm,
5027 )?)),
5028 ArmOp::F64Abs { dd, dm } => {
5029 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5030 }
5031 ArmOp::F64Neg { dd, dm } => {
5032 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5033 }
5034 ArmOp::F64Sqrt { dd, dm } => {
5035 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5036 }
5037
5038 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5041 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5042 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5043 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5044 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5045 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5046 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5047
5048 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5050 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5051 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5052 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5053 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5054 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5055
5056 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5057
5058 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5059 0xED900B00, dd, addr,
5060 )?)),
5061 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5062 0xED800B00, dd, addr,
5063 )?)),
5064
5065 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5066 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5067 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
5068 Err(synth_core::Error::synthesis(
5069 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5070 ))
5071 }
5072 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
5073 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
5074 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
5075 )),
5076 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
5077 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
5078 )),
5079 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
5080 Err(synth_core::Error::synthesis(
5081 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
5082 ))
5083 }
5084 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
5085 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
5086
5087 ArmOp::I64Add {
5091 rdlo,
5092 rdhi,
5093 rnlo,
5094 rnhi,
5095 rmlo,
5096 rmhi,
5097 } => {
5098 let mut bytes = Vec::new();
5099 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
5101 rd: *rdlo,
5102 rn: *rnlo,
5103 op2: Operand2::Reg(*rmlo),
5104 })?);
5105 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
5107 rd: *rdhi,
5108 rn: *rnhi,
5109 op2: Operand2::Reg(*rmhi),
5110 })?);
5111 Ok(bytes)
5112 }
5113
5114 ArmOp::I64Sub {
5116 rdlo,
5117 rdhi,
5118 rnlo,
5119 rnhi,
5120 rmlo,
5121 rmhi,
5122 } => {
5123 let mut bytes = Vec::new();
5124 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
5126 rd: *rdlo,
5127 rn: *rnlo,
5128 op2: Operand2::Reg(*rmlo),
5129 })?);
5130 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
5132 rd: *rdhi,
5133 rn: *rnhi,
5134 op2: Operand2::Reg(*rmhi),
5135 })?);
5136 Ok(bytes)
5137 }
5138
5139 ArmOp::I64And {
5141 rdlo,
5142 rdhi,
5143 rnlo,
5144 rnhi,
5145 rmlo,
5146 rmhi,
5147 } => {
5148 let mut bytes = Vec::new();
5149 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5150 rd: *rdlo,
5151 rn: *rnlo,
5152 op2: Operand2::Reg(*rmlo),
5153 })?);
5154 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5155 rd: *rdhi,
5156 rn: *rnhi,
5157 op2: Operand2::Reg(*rmhi),
5158 })?);
5159 Ok(bytes)
5160 }
5161
5162 ArmOp::I64Or {
5164 rdlo,
5165 rdhi,
5166 rnlo,
5167 rnhi,
5168 rmlo,
5169 rmhi,
5170 } => {
5171 let mut bytes = Vec::new();
5172 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5173 rd: *rdlo,
5174 rn: *rnlo,
5175 op2: Operand2::Reg(*rmlo),
5176 })?);
5177 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5178 rd: *rdhi,
5179 rn: *rnhi,
5180 op2: Operand2::Reg(*rmhi),
5181 })?);
5182 Ok(bytes)
5183 }
5184
5185 ArmOp::I64Xor {
5187 rdlo,
5188 rdhi,
5189 rnlo,
5190 rnhi,
5191 rmlo,
5192 rmhi,
5193 } => {
5194 let mut bytes = Vec::new();
5195 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5196 rd: *rdlo,
5197 rn: *rnlo,
5198 op2: Operand2::Reg(*rmlo),
5199 })?);
5200 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5201 rd: *rdhi,
5202 rn: *rnhi,
5203 op2: Operand2::Reg(*rmhi),
5204 })?);
5205 Ok(bytes)
5206 }
5207
5208 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
5210 rd: *rd,
5211 rn_lo: *rnlo,
5212 rn_hi: *rnhi,
5213 }),
5214
5215 ArmOp::I64Eq {
5217 rd,
5218 rnlo,
5219 rnhi,
5220 rmlo,
5221 rmhi,
5222 } => self.encode_thumb(&ArmOp::I64SetCond {
5223 rd: *rd,
5224 rn_lo: *rnlo,
5225 rn_hi: *rnhi,
5226 rm_lo: *rmlo,
5227 rm_hi: *rmhi,
5228 cond: synth_synthesis::Condition::EQ,
5229 }),
5230
5231 ArmOp::I64Ne {
5232 rd,
5233 rnlo,
5234 rnhi,
5235 rmlo,
5236 rmhi,
5237 } => self.encode_thumb(&ArmOp::I64SetCond {
5238 rd: *rd,
5239 rn_lo: *rnlo,
5240 rn_hi: *rnhi,
5241 rm_lo: *rmlo,
5242 rm_hi: *rmhi,
5243 cond: synth_synthesis::Condition::NE,
5244 }),
5245
5246 ArmOp::I64LtS {
5247 rd,
5248 rnlo,
5249 rnhi,
5250 rmlo,
5251 rmhi,
5252 } => self.encode_thumb(&ArmOp::I64SetCond {
5253 rd: *rd,
5254 rn_lo: *rnlo,
5255 rn_hi: *rnhi,
5256 rm_lo: *rmlo,
5257 rm_hi: *rmhi,
5258 cond: synth_synthesis::Condition::LT,
5259 }),
5260
5261 ArmOp::I64LtU {
5262 rd,
5263 rnlo,
5264 rnhi,
5265 rmlo,
5266 rmhi,
5267 } => self.encode_thumb(&ArmOp::I64SetCond {
5268 rd: *rd,
5269 rn_lo: *rnlo,
5270 rn_hi: *rnhi,
5271 rm_lo: *rmlo,
5272 rm_hi: *rmhi,
5273 cond: synth_synthesis::Condition::LO,
5274 }),
5275
5276 ArmOp::I64LeS {
5277 rd,
5278 rnlo,
5279 rnhi,
5280 rmlo,
5281 rmhi,
5282 } => self.encode_thumb(&ArmOp::I64SetCond {
5283 rd: *rd,
5284 rn_lo: *rnlo,
5285 rn_hi: *rnhi,
5286 rm_lo: *rmlo,
5287 rm_hi: *rmhi,
5288 cond: synth_synthesis::Condition::LE,
5289 }),
5290
5291 ArmOp::I64LeU {
5292 rd,
5293 rnlo,
5294 rnhi,
5295 rmlo,
5296 rmhi,
5297 } => self.encode_thumb(&ArmOp::I64SetCond {
5298 rd: *rd,
5299 rn_lo: *rnlo,
5300 rn_hi: *rnhi,
5301 rm_lo: *rmlo,
5302 rm_hi: *rmhi,
5303 cond: synth_synthesis::Condition::LS,
5304 }),
5305
5306 ArmOp::I64GtS {
5307 rd,
5308 rnlo,
5309 rnhi,
5310 rmlo,
5311 rmhi,
5312 } => self.encode_thumb(&ArmOp::I64SetCond {
5313 rd: *rd,
5314 rn_lo: *rnlo,
5315 rn_hi: *rnhi,
5316 rm_lo: *rmlo,
5317 rm_hi: *rmhi,
5318 cond: synth_synthesis::Condition::GT,
5319 }),
5320
5321 ArmOp::I64GtU {
5322 rd,
5323 rnlo,
5324 rnhi,
5325 rmlo,
5326 rmhi,
5327 } => self.encode_thumb(&ArmOp::I64SetCond {
5328 rd: *rd,
5329 rn_lo: *rnlo,
5330 rn_hi: *rnhi,
5331 rm_lo: *rmlo,
5332 rm_hi: *rmhi,
5333 cond: synth_synthesis::Condition::HI,
5334 }),
5335
5336 ArmOp::I64GeS {
5337 rd,
5338 rnlo,
5339 rnhi,
5340 rmlo,
5341 rmhi,
5342 } => self.encode_thumb(&ArmOp::I64SetCond {
5343 rd: *rd,
5344 rn_lo: *rnlo,
5345 rn_hi: *rnhi,
5346 rm_lo: *rmlo,
5347 rm_hi: *rmhi,
5348 cond: synth_synthesis::Condition::GE,
5349 }),
5350
5351 ArmOp::I64GeU {
5352 rd,
5353 rnlo,
5354 rnhi,
5355 rmlo,
5356 rmhi,
5357 } => self.encode_thumb(&ArmOp::I64SetCond {
5358 rd: *rd,
5359 rn_lo: *rnlo,
5360 rn_hi: *rnhi,
5361 rm_lo: *rmlo,
5362 rm_hi: *rmhi,
5363 cond: synth_synthesis::Condition::HS,
5364 }),
5365
5366 ArmOp::I64Const { rdlo, rdhi, value } => {
5368 let lo32 = *value as u32;
5369 let hi32 = (*value >> 32) as u32;
5370 let mut bytes = Vec::new();
5371 bytes.extend_from_slice(
5373 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
5374 );
5375 if lo32 > 0xFFFF {
5376 bytes.extend_from_slice(
5377 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
5378 );
5379 }
5380 bytes.extend_from_slice(
5382 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
5383 );
5384 if hi32 > 0xFFFF {
5385 bytes.extend_from_slice(
5386 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
5387 );
5388 }
5389 Ok(bytes)
5390 }
5391
5392 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
5394 let mut bytes = Vec::new();
5395 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5406 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
5407 bytes.extend_from_slice(&self.encode_thumb32_ldr(
5408 rdhi,
5409 &base,
5410 offset.wrapping_add(4),
5411 )?);
5412 Ok(bytes)
5413 }
5414
5415 ArmOp::I64Str { rdlo, rdhi, addr } => {
5417 let mut bytes = Vec::new();
5418 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5421 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
5422 bytes.extend_from_slice(&self.encode_thumb32_str(
5423 rdhi,
5424 &base,
5425 offset.wrapping_add(4),
5426 )?);
5427 Ok(bytes)
5428 }
5429
5430 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
5432 let mut bytes = Vec::new();
5433 if rdlo != rn {
5434 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5436 rd: *rdlo,
5437 op2: Operand2::Reg(*rn),
5438 })?);
5439 }
5440 bytes.extend_from_slice(
5442 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
5444 Ok(bytes)
5445 }
5446
5447 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
5449 let mut bytes = Vec::new();
5450 if rdlo != rn {
5451 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5453 rd: *rdlo,
5454 op2: Operand2::Reg(*rn),
5455 })?);
5456 }
5457 let rdhi_bits = reg_to_bits(rdhi) as u16;
5459 let instr: u16 = 0x2000 | (rdhi_bits << 8);
5460 bytes.extend_from_slice(&instr.to_le_bytes());
5461 Ok(bytes)
5462 }
5463
5464 ArmOp::I32WrapI64 { rd, rnlo } => {
5466 if rd == rnlo {
5467 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5470 } else {
5471 self.encode_thumb(&ArmOp::Mov {
5473 rd: *rd,
5474 op2: Operand2::Reg(*rnlo),
5475 })
5476 }
5477 }
5478
5479 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
5481 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
5482 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
5483 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5484 0xEF000150, qd, qn, qm,
5485 ))),
5486 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5487 0xEF200150, qd, qn, qm,
5488 ))),
5489 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5490 0xFF000150, qd, qn, qm,
5491 ))),
5492 ArmOp::MveMvn { qd, qm } => {
5493 let qd_enc = qreg_to_num(qd);
5495 let qm_enc = qreg_to_num(qm);
5496 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5497 Ok(vfp_to_thumb_bytes(instr))
5498 }
5499 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5500 0xEF100150, qd, qn, qm,
5501 ))),
5502 ArmOp::MveAddI { qd, qn, qm, size } => {
5503 let sz = mve_size_bits(size);
5504 let base: u32 = 0xEF000840 | (sz << 20);
5505 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5506 }
5507 ArmOp::MveSubI { qd, qn, qm, size } => {
5508 let sz = mve_size_bits(size);
5509 let base: u32 = 0xFF000840 | (sz << 20);
5510 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5511 }
5512 ArmOp::MveMulI { qd, qn, qm, size } => {
5513 let sz = mve_size_bits(size);
5514 let base: u32 = 0xEF000950 | (sz << 20);
5515 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5516 }
5517 ArmOp::MveNegI { qd, qm, size } => {
5518 let sz = mve_size_bits(size);
5519 let qd_enc = qreg_to_num(qd);
5521 let qm_enc = qreg_to_num(qm);
5522 let base: u32 = 0xFFB103C0 | (sz << 18);
5523 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
5524 Ok(vfp_to_thumb_bytes(instr))
5525 }
5526 ArmOp::MveDup { qd, rn, size } => {
5527 let sz = mve_size_bits(size);
5528 let qd_enc = qreg_to_num(qd);
5529 let rn_bits = reg_to_bits(rn);
5530 let be = match sz {
5533 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
5537 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
5538 Ok(vfp_to_thumb_bytes(instr))
5539 }
5540 ArmOp::MveExtractLane { rd, qn, lane, size } => {
5541 let qn_enc = qreg_to_num(qn);
5542 let rd_bits = reg_to_bits(rd);
5543 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
5546 let lane_in_d = (*lane as u32) & 1;
5547 let _sz = mve_size_bits(size);
5548 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
5550 Ok(vfp_to_thumb_bytes(instr))
5551 }
5552 ArmOp::MveInsertLane { qd, rn, lane, size } => {
5553 let qd_enc = qreg_to_num(qd);
5554 let rn_bits = reg_to_bits(rn);
5555 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
5556 let lane_in_d = (*lane as u32) & 1;
5557 let _sz = mve_size_bits(size);
5558 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
5560 Ok(vfp_to_thumb_bytes(instr))
5561 }
5562
5563 ArmOp::MveCmpEqI { qd, qn, qm, size }
5565 | ArmOp::MveCmpNeI { qd, qn, qm, size }
5566 | ArmOp::MveCmpLtS { qd, qn, qm, size }
5567 | ArmOp::MveCmpLtU { qd, qn, qm, size }
5568 | ArmOp::MveCmpGtS { qd, qn, qm, size }
5569 | ArmOp::MveCmpGtU { qd, qn, qm, size }
5570 | ArmOp::MveCmpLeS { qd, qn, qm, size }
5571 | ArmOp::MveCmpLeU { qd, qn, qm, size }
5572 | ArmOp::MveCmpGeS { qd, qn, qm, size }
5573 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
5574 let sz = mve_size_bits(size);
5577 let base: u32 = 0xEF000840 | (sz << 20);
5578 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5579 }
5580
5581 ArmOp::MveAddF32 { qd, qn, qm } => {
5583 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5585 }
5586 ArmOp::MveSubF32 { qd, qn, qm } => {
5587 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
5589 }
5590 ArmOp::MveMulF32 { qd, qn, qm } => {
5591 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
5593 }
5594 ArmOp::MveNegF32 { qd, qm } => {
5595 let qd_enc = qreg_to_num(qd);
5596 let qm_enc = qreg_to_num(qm);
5597 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5599 Ok(vfp_to_thumb_bytes(instr))
5600 }
5601 ArmOp::MveAbsF32 { qd, qm } => {
5602 let qd_enc = qreg_to_num(qd);
5603 let qm_enc = qreg_to_num(qm);
5604 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5606 Ok(vfp_to_thumb_bytes(instr))
5607 }
5608 ArmOp::MveCmpEqF32 { qd, qn, qm }
5609 | ArmOp::MveCmpNeF32 { qd, qn, qm }
5610 | ArmOp::MveCmpLtF32 { qd, qn, qm }
5611 | ArmOp::MveCmpLeF32 { qd, qn, qm }
5612 | ArmOp::MveCmpGtF32 { qd, qn, qm }
5613 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
5614 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5616 }
5617 ArmOp::MveDupF32 { qd, rn } => {
5618 let qd_enc = qreg_to_num(qd);
5619 let rn_bits = reg_to_bits(rn);
5620 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
5622 Ok(vfp_to_thumb_bytes(instr))
5623 }
5624 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
5625 let qn_enc = qreg_to_num(qn);
5626 let rd_bits = reg_to_bits(rd);
5627 let s_num = qn_enc * 4 + (*lane as u32);
5629 let (vn, n) = encode_sreg(s_num);
5630 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
5631 Ok(vfp_to_thumb_bytes(instr))
5632 }
5633 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
5634 let qd_enc = qreg_to_num(qd);
5635 let rn_bits = reg_to_bits(rn);
5636 let s_num = qd_enc * 4 + (*lane as u32);
5638 let (vn, n) = encode_sreg(s_num);
5639 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
5640 Ok(vfp_to_thumb_bytes(instr))
5641 }
5642 ArmOp::MveDivF32 { qd, qn, qm } => {
5643 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
5645 }
5646 ArmOp::MveSqrtF32 { qd, qm } => {
5647 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
5649 }
5650
5651 _ => {
5653 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5655 }
5656 }
5657 }
5658
5659 fn encode_thumb_f32_compare(
5663 &self,
5664 rd: &Reg,
5665 sn: &VfpReg,
5666 sm: &VfpReg,
5667 cond_code: u32,
5668 ) -> Result<Vec<u8>> {
5669 let mut bytes = Vec::new();
5670 let rd_bits = reg_to_bits(rd);
5671
5672 let sn_num = vfp_sreg_to_num(sn)?;
5674 let sm_num = vfp_sreg_to_num(sm)?;
5675 let (vd, d) = encode_sreg(sn_num);
5676 let (vm, m) = encode_sreg(sm_num);
5677 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5678 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5679
5680 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5682
5683 if rd_bits < 8 {
5685 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5686 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5687 } else {
5688 let hw1: u16 = 0xF04F;
5690 let hw2: u16 = (rd_bits as u16) << 8;
5691 bytes.extend_from_slice(&hw1.to_le_bytes());
5692 bytes.extend_from_slice(&hw2.to_le_bytes());
5693 }
5694
5695 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5699 bytes.extend_from_slice(&it.to_le_bytes());
5700
5701 if rd_bits < 8 {
5703 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5704 bytes.extend_from_slice(&mov_one.to_le_bytes());
5705 } else {
5706 let hw1: u16 = 0xF04F;
5708 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5709 bytes.extend_from_slice(&hw1.to_le_bytes());
5710 bytes.extend_from_slice(&hw2.to_le_bytes());
5711 }
5712
5713 Ok(bytes)
5714 }
5715
5716 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
5718 let mut bytes = Vec::new();
5719 let bits = value.to_bits();
5720 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
5725 let imm4 = (lo16 >> 12) & 0xF;
5726 let i_bit = (lo16 >> 11) & 1;
5727 let imm3 = (lo16 >> 8) & 0x7;
5728 let imm8 = lo16 & 0xFF;
5729 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
5730 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5731 bytes.extend_from_slice(&hw1.to_le_bytes());
5732 bytes.extend_from_slice(&hw2.to_le_bytes());
5733
5734 let hi16 = (bits >> 16) & 0xFFFF;
5736 let imm4 = (hi16 >> 12) & 0xF;
5737 let i_bit = (hi16 >> 11) & 1;
5738 let imm3 = (hi16 >> 8) & 0x7;
5739 let imm8 = hi16 & 0xFF;
5740 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
5741 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5742 bytes.extend_from_slice(&hw1.to_le_bytes());
5743 bytes.extend_from_slice(&hw2.to_le_bytes());
5744
5745 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
5747 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5748
5749 Ok(bytes)
5750 }
5751
5752 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
5754 let mut bytes = Vec::new();
5755
5756 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
5758 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5759
5760 let sd_num = vfp_sreg_to_num(sd)?;
5762 let (vd, d) = encode_sreg(sd_num);
5763 let (vm, m) = encode_sreg(sd_num);
5764 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
5765 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
5766 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
5767
5768 Ok(bytes)
5769 }
5770
5771 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
5779 let mut bytes = Vec::new();
5780 let sm_num = vfp_sreg_to_num(sm)?;
5781 let sd_num = vfp_sreg_to_num(sd)?;
5782 let (vd_s, d_s) = encode_sreg(sd_num);
5783 let (vm_s, m_s) = encode_sreg(sm_num);
5784
5785 if mode == 0b11 {
5786 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5788 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5789 } else {
5790 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
5795 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5796
5797 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
5803 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5804 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5805
5806 if mode != 0 {
5808 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
5810 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
5811 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
5812 }
5813
5814 let vmsr = 0xEEE10A10 | (rt << 12);
5816 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5817
5818 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5820 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5821
5822 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5824 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5825 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5826 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5827 }
5828
5829 let (vd2, d2) = encode_sreg(sd_num);
5831 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
5832 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
5833
5834 Ok(bytes)
5835 }
5836
5837 fn encode_thumb_f32_minmax(
5839 &self,
5840 sd: &VfpReg,
5841 sn: &VfpReg,
5842 sm: &VfpReg,
5843 is_min: bool,
5844 ) -> Result<Vec<u8>> {
5845 let mut bytes = Vec::new();
5846 let sn_num = vfp_sreg_to_num(sn)?;
5847 let sm_num = vfp_sreg_to_num(sm)?;
5848 let sd_num = vfp_sreg_to_num(sd)?;
5849
5850 let (vd, d) = encode_sreg(sd_num);
5852 let (vn, n) = encode_sreg(sn_num);
5853 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
5854 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
5855
5856 let (vm, m) = encode_sreg(sm_num);
5858 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
5859 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5860
5861 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5863
5864 let cond: u16 = if is_min { 0xC } else { 0x4 };
5866 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
5867 bytes.extend_from_slice(&it.to_le_bytes());
5868
5869 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5871 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
5872
5873 Ok(bytes)
5874 }
5875
5876 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
5878 let mut bytes = Vec::new();
5879
5880 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5882 false,
5883 sm,
5884 &Reg::R12,
5885 )?));
5886
5887 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5889 false,
5890 sn,
5891 &Reg::R0,
5892 )?));
5893
5894 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5906 bytes.extend_from_slice(&hw2.to_le_bytes());
5907
5908 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5912 bytes.extend_from_slice(&hw2.to_le_bytes());
5913
5914 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
5918 bytes.extend_from_slice(&hw2.to_le_bytes());
5919
5920 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5922 true,
5923 sd,
5924 &Reg::R0,
5925 )?));
5926
5927 Ok(bytes)
5928 }
5929
5930 fn encode_thumb_f64_compare(
5932 &self,
5933 rd: &Reg,
5934 dn: &VfpReg,
5935 dm: &VfpReg,
5936 cond_code: u32,
5937 ) -> Result<Vec<u8>> {
5938 let mut bytes = Vec::new();
5939 let rd_bits = reg_to_bits(rd);
5940
5941 let dn_num = vfp_dreg_to_num(dn)?;
5943 let dm_num = vfp_dreg_to_num(dm)?;
5944 let (vd, d) = encode_dreg(dn_num);
5945 let (vm, m) = encode_dreg(dm_num);
5946 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5947 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5948
5949 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5951
5952 if rd_bits < 8 {
5954 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5955 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5956 } else {
5957 let hw1: u16 = 0xF04F;
5958 let hw2: u16 = (rd_bits as u16) << 8;
5959 bytes.extend_from_slice(&hw1.to_le_bytes());
5960 bytes.extend_from_slice(&hw2.to_le_bytes());
5961 }
5962
5963 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5965 bytes.extend_from_slice(&it.to_le_bytes());
5966
5967 if rd_bits < 8 {
5969 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5970 bytes.extend_from_slice(&mov_one.to_le_bytes());
5971 } else {
5972 let hw1: u16 = 0xF04F;
5973 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5974 bytes.extend_from_slice(&hw1.to_le_bytes());
5975 bytes.extend_from_slice(&hw2.to_le_bytes());
5976 }
5977
5978 Ok(bytes)
5979 }
5980
5981 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
5983 let mut bytes = Vec::new();
5984 let bits = value.to_bits();
5985 let lo32 = bits as u32;
5986 let hi32 = (bits >> 32) as u32;
5987
5988 let lo16 = lo32 & 0xFFFF;
5990 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
5991
5992 let hi16 = (lo32 >> 16) & 0xFFFF;
5994 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
5995
5996 let lo16 = hi32 & 0xFFFF;
5998 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
5999
6000 let hi16 = (hi32 >> 16) & 0xFFFF;
6002 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6003
6004 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6006 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6007
6008 Ok(bytes)
6009 }
6010
6011 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6013 let mut bytes = Vec::new();
6014
6015 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6017 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6018
6019 let dd_num = vfp_dreg_to_num(dd)?;
6021 let (vd, d) = encode_dreg(dd_num);
6022 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6023 let vcvt = base | (d << 22) | (vd << 12);
6024 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6025
6026 Ok(bytes)
6027 }
6028
6029 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6031 let dd_num = vfp_dreg_to_num(dd)?;
6032 let sm_num = vfp_sreg_to_num(sm)?;
6033 let (vd, d) = encode_dreg(dd_num);
6034 let (vm, m) = encode_sreg(sm_num);
6035
6036 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6037 Ok(vfp_to_thumb_bytes(vcvt))
6038 }
6039
6040 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6042 let mut bytes = Vec::new();
6043 let dm_num = vfp_dreg_to_num(dm)?;
6044 let (vm, m) = encode_dreg(dm_num);
6045
6046 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6048 let vcvt = base | (m << 5) | vm;
6049 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6050
6051 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6053 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6054
6055 Ok(bytes)
6056 }
6057
6058 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6062 let mut bytes = Vec::new();
6063 let dm_num = vfp_dreg_to_num(dm)?;
6064 let dd_num = vfp_dreg_to_num(dd)?;
6065 let (vm, m) = encode_dreg(dm_num);
6066 let (vd, d) = encode_dreg(dd_num);
6067
6068 if mode == 0b11 {
6069 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
6071 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6072 } else {
6073 let rt: u32 = 12;
6074
6075 let vmrs = 0xEEF10A10 | (rt << 12);
6077 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6078
6079 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
6081 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6082 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6083 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6084
6085 if mode != 0 {
6087 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
6088 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6089 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6090 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6091 }
6092
6093 let vmsr = 0xEEE10A10 | (rt << 12);
6095 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6096
6097 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
6099 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6100
6101 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6103 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6104 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6105 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6106 }
6107
6108 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
6110 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6111
6112 Ok(bytes)
6113 }
6114
6115 fn encode_thumb_f64_minmax(
6117 &self,
6118 dd: &VfpReg,
6119 dn: &VfpReg,
6120 dm: &VfpReg,
6121 is_min: bool,
6122 ) -> Result<Vec<u8>> {
6123 let mut bytes = Vec::new();
6124 let dn_num = vfp_dreg_to_num(dn)?;
6125 let dm_num = vfp_dreg_to_num(dm)?;
6126 let dd_num = vfp_dreg_to_num(dd)?;
6127
6128 let (vd, d) = encode_dreg(dd_num);
6130 let (vn, n) = encode_dreg(dn_num);
6131 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6132 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
6133
6134 let (vm, m) = encode_dreg(dm_num);
6136 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6137 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6138
6139 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6141
6142 let cond: u16 = if is_min { 0xC } else { 0x4 };
6144 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6145 bytes.extend_from_slice(&it.to_le_bytes());
6146
6147 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6149 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
6150
6151 Ok(bytes)
6152 }
6153
6154 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
6156 let mut bytes = Vec::new();
6157
6158 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6160 false,
6161 dm,
6162 &Reg::R0,
6163 &Reg::R12,
6164 )?));
6165
6166 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6168 false,
6169 dn,
6170 &Reg::R1,
6171 &Reg::R2,
6172 )?));
6173
6174 let hw1: u16 = 0xF000 | 12;
6176 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
6177 bytes.extend_from_slice(&hw1.to_le_bytes());
6178 bytes.extend_from_slice(&hw2.to_le_bytes());
6179
6180 let hw1: u16 = 0xF020 | 2;
6182 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
6183 bytes.extend_from_slice(&hw1.to_le_bytes());
6184 bytes.extend_from_slice(&hw2.to_le_bytes());
6185
6186 let hw1: u16 = 0xEA40 | 2;
6188 let hw2: u16 = (2 << 8) | 12;
6189 bytes.extend_from_slice(&hw1.to_le_bytes());
6190 bytes.extend_from_slice(&hw2.to_le_bytes());
6191
6192 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6194 true,
6195 dd,
6196 &Reg::R1,
6197 &Reg::R2,
6198 )?));
6199
6200 Ok(bytes)
6201 }
6202
6203 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6205 let mut bytes = Vec::new();
6206
6207 let sm_num = vfp_sreg_to_num(sm)?;
6208 let (vd, d) = encode_sreg(sm_num);
6209 let (vm, m) = encode_sreg(sm_num);
6210 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
6211 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6212 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6213
6214 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
6216 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6217
6218 Ok(bytes)
6219 }
6220
6221 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6225 let rd_bits = reg_to_bits(rd);
6226 let rn_bits = reg_to_bits(rn);
6227
6228 let i_bit = (imm >> 11) & 1;
6230 let imm3 = (imm >> 8) & 0x7;
6231 let imm8 = imm & 0xFF;
6232
6233 let hw1_base = if imm <= 0xFF {
6234 0xF100
6238 } else if imm <= 0xFFF {
6239 0xF200
6243 } else {
6244 return Err(synth_core::Error::synthesis(
6245 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6246 ));
6247 };
6248
6249 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6250 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6251
6252 let mut bytes = hw1.to_le_bytes().to_vec();
6253 bytes.extend_from_slice(&hw2.to_le_bytes());
6254 Ok(bytes)
6255 }
6256
6257 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6259 let rd_bits = reg_to_bits(rd);
6260 let rn_bits = reg_to_bits(rn);
6261
6262 let i_bit = (imm >> 11) & 1;
6263 let imm3 = (imm >> 8) & 0x7;
6264 let imm8 = imm & 0xFF;
6265
6266 let hw1_base = if imm <= 0xFF {
6267 0xF1A0
6270 } else if imm <= 0xFFF {
6271 0xF2A0
6274 } else {
6275 return Err(synth_core::Error::synthesis(
6276 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6277 ));
6278 };
6279
6280 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6281 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6282
6283 let mut bytes = hw1.to_le_bytes().to_vec();
6284 bytes.extend_from_slice(&hw2.to_le_bytes());
6285 Ok(bytes)
6286 }
6287
6288 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6290 let rd_bits = reg_to_bits(rd);
6291 let rn_bits = reg_to_bits(rn);
6292
6293 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6296 synth_core::Error::synthesis(
6297 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
6298 )
6299 })?;
6300 let i_bit = (field >> 11) & 1;
6301 let imm3 = (field >> 8) & 0x7;
6302 let imm8 = field & 0xFF;
6303
6304 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
6307 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6308
6309 let mut bytes = hw1.to_le_bytes().to_vec();
6310 bytes.extend_from_slice(&hw2.to_le_bytes());
6311 Ok(bytes)
6312 }
6313
6314 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6316 let rd_bits = reg_to_bits(rd);
6317 let rn_bits = reg_to_bits(rn);
6318
6319 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6322 synth_core::Error::synthesis(
6323 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
6324 )
6325 })?;
6326 let i_bit = (field >> 11) & 1;
6327 let imm3 = (field >> 8) & 0x7;
6328 let imm8 = field & 0xFF;
6329
6330 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6333 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6334
6335 let mut bytes = hw1.to_le_bytes().to_vec();
6336 bytes.extend_from_slice(&hw2.to_le_bytes());
6337 Ok(bytes)
6338 }
6339
6340 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
6349 let rd_bits = reg_to_bits(rd);
6350 reg_bits_checked(rd_bits)?;
6351 let imm16 = imm & 0xFFFF;
6352
6353 let imm4 = (imm16 >> 12) & 0xF;
6356 let i_bit = (imm16 >> 11) & 1;
6357 let imm3 = (imm16 >> 8) & 0x7;
6358 let imm8 = imm16 & 0xFF;
6359
6360 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6361 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6362
6363 let mut bytes = hw1.to_le_bytes().to_vec();
6364 bytes.extend_from_slice(&hw2.to_le_bytes());
6365 encoding_contracts::verify_thumb32(&bytes);
6366 Ok(bytes)
6367 }
6368
6369 fn encode_thumb32_shift(
6377 &self,
6378 rd: &Reg,
6379 rm: &Reg,
6380 shift: u32,
6381 shift_type: u8,
6382 ) -> Result<Vec<u8>> {
6383 let rd_bits = reg_to_bits(rd);
6384 let rm_bits = reg_to_bits(rm);
6385 reg_bits_checked(rd_bits)?;
6386 reg_bits_checked(rm_bits)?;
6387 let imm5 = shift & 0x1F;
6388 let imm2 = imm5 & 0x3;
6389 let imm3 = (imm5 >> 2) & 0x7;
6390
6391 let hw1: u16 = 0xEA4F;
6394 let hw2: u16 =
6395 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
6396 as u16;
6397
6398 let mut bytes = hw1.to_le_bytes().to_vec();
6399 bytes.extend_from_slice(&hw2.to_le_bytes());
6400 Ok(bytes)
6401 }
6402
6403 fn encode_thumb32_shift_reg(
6407 &self,
6408 rd: &Reg,
6409 rn: &Reg,
6410 rm: &Reg,
6411 shift_type: u8,
6412 ) -> Result<Vec<u8>> {
6413 let rd_bits = reg_to_bits(rd);
6414 let rn_bits = reg_to_bits(rn);
6415 let rm_bits = reg_to_bits(rm);
6416
6417 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
6419 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
6421
6422 let mut bytes = hw1.to_le_bytes().to_vec();
6423 bytes.extend_from_slice(&hw2.to_le_bytes());
6424 Ok(bytes)
6425 }
6426
6427 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6429 let rn_bits = reg_to_bits(rn);
6430
6431 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6435 synth_core::Error::synthesis(
6436 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
6437 )
6438 })?;
6439 let i_bit = (field >> 11) & 1;
6440 let imm3 = (field >> 8) & 0x7;
6441 let imm8 = field & 0xFF;
6442
6443 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6445 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
6446
6447 let mut bytes = hw1.to_le_bytes().to_vec();
6448 bytes.extend_from_slice(&hw2.to_le_bytes());
6449 Ok(bytes)
6450 }
6451
6452 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
6474 let offset = if addr.offset < 0 {
6475 0u32
6476 } else {
6477 addr.offset as u32
6478 };
6479 match addr.offset_reg {
6480 Some(idx) => {
6481 let ip = Reg::R12;
6482 if offset.wrapping_add(4) > 0xFFF {
6483 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
6487 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
6489 reg_to_bits(&ip),
6490 reg_to_bits(&ip),
6491 reg_to_bits(&addr.base),
6492 )?);
6493 Ok((ip, 0))
6494 } else {
6495 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
6497 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
6498 bytes.extend_from_slice(&hw1.to_le_bytes());
6499 bytes.extend_from_slice(&hw2.to_le_bytes());
6500 Ok((ip, offset))
6501 }
6502 }
6503 None => Ok((addr.base, offset)),
6504 }
6505 }
6506
6507 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6509 let rd_bits = reg_to_bits(rd);
6510 let base_bits = reg_to_bits(base);
6511
6512 check_ldst_imm12(offset)?;
6514 let hw1: u16 = (0xF8D0 | base_bits) as u16;
6515 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6516
6517 let mut bytes = hw1.to_le_bytes().to_vec();
6518 bytes.extend_from_slice(&hw2.to_le_bytes());
6519 Ok(bytes)
6520 }
6521
6522 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6524 let rd_bits = reg_to_bits(rd);
6525 let base_bits = reg_to_bits(base);
6526
6527 check_ldst_imm12(offset)?;
6529 let hw1: u16 = (0xF8C0 | base_bits) as u16;
6530 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6531
6532 let mut bytes = hw1.to_le_bytes().to_vec();
6533 bytes.extend_from_slice(&hw2.to_le_bytes());
6534 Ok(bytes)
6535 }
6536
6537 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6539 let rd_bits = reg_to_bits(rd);
6540 let base_bits = reg_to_bits(base);
6541 let rm_bits = reg_to_bits(offset_reg);
6542
6543 let hw1: u16 = (0xF850 | base_bits) as u16;
6547 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6548
6549 let mut bytes = hw1.to_le_bytes().to_vec();
6550 bytes.extend_from_slice(&hw2.to_le_bytes());
6551 Ok(bytes)
6552 }
6553
6554 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6556 let rd_bits = reg_to_bits(rd);
6557 let base_bits = reg_to_bits(base);
6558 let rm_bits = reg_to_bits(offset_reg);
6559
6560 let hw1: u16 = (0xF840 | base_bits) as u16;
6564 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6565
6566 let mut bytes = hw1.to_le_bytes().to_vec();
6567 bytes.extend_from_slice(&hw2.to_le_bytes());
6568 Ok(bytes)
6569 }
6570
6571 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6575 let rd_bits = reg_to_bits(rd);
6576 let base_bits = reg_to_bits(base);
6577 check_ldst_imm12(offset)?;
6579 let hw1: u16 = (0xF890 | base_bits) as u16;
6580 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6581 let mut bytes = hw1.to_le_bytes().to_vec();
6582 bytes.extend_from_slice(&hw2.to_le_bytes());
6583 Ok(bytes)
6584 }
6585
6586 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6588 let rd_bits = reg_to_bits(rd);
6589 let base_bits = reg_to_bits(base);
6590 let rm_bits = reg_to_bits(offset_reg);
6591 let hw1: u16 = (0xF810 | base_bits) as u16;
6593 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6594 let mut bytes = hw1.to_le_bytes().to_vec();
6595 bytes.extend_from_slice(&hw2.to_le_bytes());
6596 Ok(bytes)
6597 }
6598
6599 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6601 let rd_bits = reg_to_bits(rd);
6602 let base_bits = reg_to_bits(base);
6603 check_ldst_imm12(offset)?;
6605 let hw1: u16 = (0xF990 | base_bits) as u16;
6606 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6607 let mut bytes = hw1.to_le_bytes().to_vec();
6608 bytes.extend_from_slice(&hw2.to_le_bytes());
6609 Ok(bytes)
6610 }
6611
6612 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6614 let rd_bits = reg_to_bits(rd);
6615 let base_bits = reg_to_bits(base);
6616 let rm_bits = reg_to_bits(offset_reg);
6617 let hw1: u16 = (0xF910 | base_bits) as u16;
6619 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6620 let mut bytes = hw1.to_le_bytes().to_vec();
6621 bytes.extend_from_slice(&hw2.to_le_bytes());
6622 Ok(bytes)
6623 }
6624
6625 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6627 let rd_bits = reg_to_bits(rd);
6628 let base_bits = reg_to_bits(base);
6629 check_ldst_imm12(offset)?;
6631 let hw1: u16 = (0xF8B0 | base_bits) as u16;
6632 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6633 let mut bytes = hw1.to_le_bytes().to_vec();
6634 bytes.extend_from_slice(&hw2.to_le_bytes());
6635 Ok(bytes)
6636 }
6637
6638 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6640 let rd_bits = reg_to_bits(rd);
6641 let base_bits = reg_to_bits(base);
6642 let rm_bits = reg_to_bits(offset_reg);
6643 let hw1: u16 = (0xF830 | base_bits) as u16;
6645 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6646 let mut bytes = hw1.to_le_bytes().to_vec();
6647 bytes.extend_from_slice(&hw2.to_le_bytes());
6648 Ok(bytes)
6649 }
6650
6651 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6653 let rd_bits = reg_to_bits(rd);
6654 let base_bits = reg_to_bits(base);
6655 check_ldst_imm12(offset)?;
6657 let hw1: u16 = (0xF9B0 | base_bits) as u16;
6658 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6659 let mut bytes = hw1.to_le_bytes().to_vec();
6660 bytes.extend_from_slice(&hw2.to_le_bytes());
6661 Ok(bytes)
6662 }
6663
6664 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6666 let rd_bits = reg_to_bits(rd);
6667 let base_bits = reg_to_bits(base);
6668 let rm_bits = reg_to_bits(offset_reg);
6669 let hw1: u16 = (0xF930 | base_bits) as u16;
6671 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6672 let mut bytes = hw1.to_le_bytes().to_vec();
6673 bytes.extend_from_slice(&hw2.to_le_bytes());
6674 Ok(bytes)
6675 }
6676
6677 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6679 let rd_bits = reg_to_bits(rd);
6680 let base_bits = reg_to_bits(base);
6681 check_ldst_imm12(offset)?;
6683 let hw1: u16 = (0xF880 | base_bits) as u16;
6684 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6685 let mut bytes = hw1.to_le_bytes().to_vec();
6686 bytes.extend_from_slice(&hw2.to_le_bytes());
6687 Ok(bytes)
6688 }
6689
6690 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6692 let rd_bits = reg_to_bits(rd);
6693 let base_bits = reg_to_bits(base);
6694 let rm_bits = reg_to_bits(offset_reg);
6695 let hw1: u16 = (0xF800 | base_bits) as u16;
6697 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6698 let mut bytes = hw1.to_le_bytes().to_vec();
6699 bytes.extend_from_slice(&hw2.to_le_bytes());
6700 Ok(bytes)
6701 }
6702
6703 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6705 let rd_bits = reg_to_bits(rd);
6706 let base_bits = reg_to_bits(base);
6707 check_ldst_imm12(offset)?;
6709 let hw1: u16 = (0xF8A0 | base_bits) as u16;
6710 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6711 let mut bytes = hw1.to_le_bytes().to_vec();
6712 bytes.extend_from_slice(&hw2.to_le_bytes());
6713 Ok(bytes)
6714 }
6715
6716 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6718 let rd_bits = reg_to_bits(rd);
6719 let base_bits = reg_to_bits(base);
6720 let rm_bits = reg_to_bits(offset_reg);
6721 let hw1: u16 = (0xF820 | base_bits) as u16;
6723 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6724 let mut bytes = hw1.to_le_bytes().to_vec();
6725 bytes.extend_from_slice(&hw2.to_le_bytes());
6726 Ok(bytes)
6727 }
6728
6729 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6731 let rd_bits = reg_to_bits(rd);
6732 let rn_bits = reg_to_bits(rn);
6733
6734 if imm <= 0xFFF {
6740 let i_bit = (imm >> 11) & 1;
6741 let imm3 = (imm >> 8) & 0x7;
6742 let imm8 = imm & 0xFF;
6743
6744 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
6745 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6746
6747 let mut bytes = hw1.to_le_bytes().to_vec();
6748 bytes.extend_from_slice(&hw2.to_le_bytes());
6749 Ok(bytes)
6750 } else {
6751 let scratch: u32 = if rd_bits == rn_bits {
6765 12 } else {
6767 rd_bits };
6769 if scratch == rn_bits {
6777 return Err(synth_core::Error::synthesis(format!(
6778 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
6779 register (R12 is the reserved encoder scratch and aliases Rn here)"
6780 )));
6781 }
6782
6783 let lo16 = imm & 0xFFFF;
6784 let hi16 = (imm >> 16) & 0xFFFF;
6785
6786 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
6787 if hi16 != 0 {
6788 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
6789 }
6790 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
6791 Ok(bytes)
6792 }
6793 }
6794
6795 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6805 reg_bits_checked(rd)?;
6806 encoding_contracts::verify_imm16(imm16);
6807 let imm16 = imm16 & 0xFFFF;
6810 let imm4 = (imm16 >> 12) & 0xF;
6811 let i_bit = (imm16 >> 11) & 1;
6812 let imm3 = (imm16 >> 8) & 0x7;
6813 let imm8 = imm16 & 0xFF;
6814
6815 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6816 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6817
6818 let mut bytes = hw1.to_le_bytes().to_vec();
6819 bytes.extend_from_slice(&hw2.to_le_bytes());
6820 encoding_contracts::verify_thumb32(&bytes);
6821 Ok(bytes)
6822 }
6823
6824 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6832 reg_bits_checked(rd)?;
6833 encoding_contracts::verify_imm16(imm16);
6834 let imm16 = imm16 & 0xFFFF;
6837 let imm4 = (imm16 >> 12) & 0xF;
6838 let i_bit = (imm16 >> 11) & 1;
6839 let imm3 = (imm16 >> 8) & 0x7;
6840 let imm8 = imm16 & 0xFF;
6841
6842 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6843 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6844
6845 let mut bytes = hw1.to_le_bytes().to_vec();
6846 bytes.extend_from_slice(&hw2.to_le_bytes());
6847 encoding_contracts::verify_thumb32(&bytes);
6848 Ok(bytes)
6849 }
6850
6851 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
6853 let imm5 = shift & 0x1F;
6856 let imm2 = imm5 & 0x3;
6857 let imm3 = (imm5 >> 2) & 0x7;
6858
6859 let hw1: u16 = 0xEA4F;
6860 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
6861
6862 let mut bytes = hw1.to_le_bytes().to_vec();
6863 bytes.extend_from_slice(&hw2.to_le_bytes());
6864 Ok(bytes)
6865 }
6866
6867 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6869 let hw1: u16 = (0xEA00 | rn) as u16;
6872 let hw2: u16 = ((rd << 8) | rm) as u16;
6873
6874 let mut bytes = hw1.to_le_bytes().to_vec();
6875 bytes.extend_from_slice(&hw2.to_le_bytes());
6876 Ok(bytes)
6877 }
6878
6879 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
6881 let i_bit = (imm >> 11) & 1;
6885 let imm3 = (imm >> 8) & 0x7;
6886 let imm8 = imm & 0xFF;
6887
6888 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
6889 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6890
6891 let mut bytes = hw1.to_le_bytes().to_vec();
6892 bytes.extend_from_slice(&hw2.to_le_bytes());
6893 Ok(bytes)
6894 }
6895
6896 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6898 let hw1: u16 = (0xEBA0 | rn) as u16;
6901 let hw2: u16 = ((rd << 8) | rm) as u16;
6902
6903 let mut bytes = hw1.to_le_bytes().to_vec();
6904 bytes.extend_from_slice(&hw2.to_le_bytes());
6905 Ok(bytes)
6906 }
6907
6908 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6910 let hw1: u16 = (0xEB00 | rn) as u16;
6913 let hw2: u16 = ((rd << 8) | rm) as u16;
6914
6915 let mut bytes = hw1.to_le_bytes().to_vec();
6916 bytes.extend_from_slice(&hw2.to_le_bytes());
6917 Ok(bytes)
6918 }
6919
6920 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6924 let hw1: u16 = (0xEB10 | rn) as u16;
6926 let hw2: u16 = ((rd << 8) | rm) as u16;
6927 let mut bytes = hw1.to_le_bytes().to_vec();
6928 bytes.extend_from_slice(&hw2.to_le_bytes());
6929 Ok(bytes)
6930 }
6931
6932 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6935 let hw1: u16 = (0xEBB0 | rn) as u16;
6937 let hw2: u16 = ((rd << 8) | rm) as u16;
6938 let mut bytes = hw1.to_le_bytes().to_vec();
6939 bytes.extend_from_slice(&hw2.to_le_bytes());
6940 Ok(bytes)
6941 }
6942
6943 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
6945 let mut code = Vec::new();
6946
6947 for op in ops {
6948 let encoded = self.encode(op)?;
6949 code.extend_from_slice(&encoded);
6950 }
6951
6952 Ok(code)
6953 }
6954}
6955
6956fn try_thumb_expand_imm(value: u32) -> Option<u32> {
6964 if value <= 0xFF {
6966 return Some(value);
6967 }
6968 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
6972 return Some(0x100 | b0);
6973 }
6974 if value == (b1 << 24) | (b1 << 8) {
6976 return Some(0x200 | b1);
6977 }
6978 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
6980 return Some(0x300 | b0);
6981 }
6982 for rot in 8..=31u32 {
6986 let unrot = value.rotate_left(rot);
6987 if (0x80..=0xFF).contains(&unrot) {
6988 return Some((rot << 7) | (unrot & 0x7F));
6989 }
6990 }
6991 None
6992}
6993
6994fn check_ldst_imm12(offset: u32) -> Result<()> {
7000 if offset > 0xFFF {
7001 Err(synth_core::Error::synthesis(
7002 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7003 ))
7004 } else {
7005 Ok(())
7006 }
7007}
7008
7009fn reg_to_bits(reg: &Reg) -> u32 {
7010 match reg {
7011 Reg::R0 => 0,
7012 Reg::R1 => 1,
7013 Reg::R2 => 2,
7014 Reg::R3 => 3,
7015 Reg::R4 => 4,
7016 Reg::R5 => 5,
7017 Reg::R6 => 6,
7018 Reg::R7 => 7,
7019 Reg::R8 => 8,
7020 Reg::R9 => 9,
7021 Reg::R10 => 10,
7022 Reg::R11 => 11,
7023 Reg::R12 => 12,
7024 Reg::SP => 13,
7025 Reg::LR => 14,
7026 Reg::PC => 15,
7027 }
7028}
7029
7030fn reg_bits_checked(bits: u32) -> Result<()> {
7038 if bits > 14 {
7039 return Err(synth_core::Error::synthesis(format!(
7040 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
7041 )));
7042 }
7043 Ok(())
7044}
7045
7046fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
7049 if val == 0 {
7050 return Some((0, 1));
7051 }
7052 for rot in 0..16u32 {
7053 let shift = rot * 2;
7054 let unrotated = val.rotate_left(shift);
7056 if unrotated <= 0xFF {
7057 return Some(((rot << 8) | unrotated, 1));
7059 }
7060 }
7061 None
7062}
7063
7064fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
7069 match op2 {
7070 Operand2::Imm(val) => {
7071 let uval = *val as u32;
7072 if let Some(encoded) = try_encode_rotated_imm(uval) {
7074 Ok(encoded)
7075 } else {
7076 Err(synth_core::Error::synthesis(format!(
7085 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
7086 rotated immediate — the selector must materialize large \
7087 constants via MOVW/MOVT"
7088 )))
7089 }
7090 }
7091
7092 Operand2::Reg(reg) => {
7093 let reg_bits = reg_to_bits(reg);
7094 Ok((reg_bits, 0)) }
7096
7097 Operand2::RegShift {
7098 rm,
7099 shift: _,
7100 amount,
7101 } => {
7102 let rm_bits = reg_to_bits(rm);
7104 let shift_bits = (*amount & 0x1F) << 7;
7105 Ok((shift_bits | rm_bits, 0))
7106 }
7107 }
7108}
7109
7110fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
7112 let base_bits = reg_to_bits(&addr.base);
7113 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
7115}
7116
7117fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
7119 match reg {
7120 VfpReg::S0 => Ok(0),
7121 VfpReg::S1 => Ok(1),
7122 VfpReg::S2 => Ok(2),
7123 VfpReg::S3 => Ok(3),
7124 VfpReg::S4 => Ok(4),
7125 VfpReg::S5 => Ok(5),
7126 VfpReg::S6 => Ok(6),
7127 VfpReg::S7 => Ok(7),
7128 VfpReg::S8 => Ok(8),
7129 VfpReg::S9 => Ok(9),
7130 VfpReg::S10 => Ok(10),
7131 VfpReg::S11 => Ok(11),
7132 VfpReg::S12 => Ok(12),
7133 VfpReg::S13 => Ok(13),
7134 VfpReg::S14 => Ok(14),
7135 VfpReg::S15 => Ok(15),
7136 VfpReg::S16 => Ok(16),
7137 VfpReg::S17 => Ok(17),
7138 VfpReg::S18 => Ok(18),
7139 VfpReg::S19 => Ok(19),
7140 VfpReg::S20 => Ok(20),
7141 VfpReg::S21 => Ok(21),
7142 VfpReg::S22 => Ok(22),
7143 VfpReg::S23 => Ok(23),
7144 VfpReg::S24 => Ok(24),
7145 VfpReg::S25 => Ok(25),
7146 VfpReg::S26 => Ok(26),
7147 VfpReg::S27 => Ok(27),
7148 VfpReg::S28 => Ok(28),
7149 VfpReg::S29 => Ok(29),
7150 VfpReg::S30 => Ok(30),
7151 VfpReg::S31 => Ok(31),
7152 _ => Err(synth_core::Error::SynthesisError(
7154 "D-register not supported in single-precision VFP encoding".to_string(),
7155 )),
7156 }
7157}
7158
7159fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
7161 match reg {
7162 VfpReg::D0 => Ok(0),
7163 VfpReg::D1 => Ok(1),
7164 VfpReg::D2 => Ok(2),
7165 VfpReg::D3 => Ok(3),
7166 VfpReg::D4 => Ok(4),
7167 VfpReg::D5 => Ok(5),
7168 VfpReg::D6 => Ok(6),
7169 VfpReg::D7 => Ok(7),
7170 VfpReg::D8 => Ok(8),
7171 VfpReg::D9 => Ok(9),
7172 VfpReg::D10 => Ok(10),
7173 VfpReg::D11 => Ok(11),
7174 VfpReg::D12 => Ok(12),
7175 VfpReg::D13 => Ok(13),
7176 VfpReg::D14 => Ok(14),
7177 VfpReg::D15 => Ok(15),
7178 _ => Err(synth_core::Error::SynthesisError(
7180 "S-register not supported in double-precision VFP encoding".to_string(),
7181 )),
7182 }
7183}
7184
7185fn encode_sreg(s: u32) -> (u32, u32) {
7189 (s >> 1, s & 1)
7190}
7191
7192fn encode_dreg(d: u32) -> (u32, u32) {
7196 (d & 0xF, (d >> 4) & 1)
7197}
7198
7199fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
7205 let sd_num = vfp_sreg_to_num(sd)?;
7206 let sn_num = vfp_sreg_to_num(sn)?;
7207 let sm_num = vfp_sreg_to_num(sm)?;
7208 let (vd, d) = encode_sreg(sd_num);
7209 let (vn, n) = encode_sreg(sn_num);
7210 let (vm, m) = encode_sreg(sm_num);
7211
7212 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7213}
7214
7215fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
7218 let sd_num = vfp_sreg_to_num(sd)?;
7219 let sm_num = vfp_sreg_to_num(sm)?;
7220 let (vd, d) = encode_sreg(sd_num);
7221 let (vm, m) = encode_sreg(sm_num);
7222
7223 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7224}
7225
7226fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7230 let sd_num = vfp_sreg_to_num(sd)?;
7231 let (vd, d) = encode_sreg(sd_num);
7232 let rn = reg_to_bits(&addr.base);
7233
7234 let offset = addr.offset;
7235 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7236 let abs_offset = offset.unsigned_abs();
7237 let imm8 = (abs_offset / 4) & 0xFF;
7238
7239 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7240}
7241
7242fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
7246 let s_num = vfp_sreg_to_num(sreg)?;
7247 let (vn, n) = encode_sreg(s_num);
7248 let rt = reg_to_bits(core);
7249
7250 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
7251 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
7252}
7253
7254fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
7258 let dd_num = vfp_dreg_to_num(dd)?;
7259 let dn_num = vfp_dreg_to_num(dn)?;
7260 let dm_num = vfp_dreg_to_num(dm)?;
7261 let (vd, d) = encode_dreg(dd_num);
7262 let (vn, n) = encode_dreg(dn_num);
7263 let (vm, m) = encode_dreg(dm_num);
7264
7265 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7266}
7267
7268fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
7270 let dd_num = vfp_dreg_to_num(dd)?;
7271 let dm_num = vfp_dreg_to_num(dm)?;
7272 let (vd, d) = encode_dreg(dd_num);
7273 let (vm, m) = encode_dreg(dm_num);
7274
7275 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7276}
7277
7278fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7281 let dd_num = vfp_dreg_to_num(dd)?;
7282 let (vd, d) = encode_dreg(dd_num);
7283 let rn = reg_to_bits(&addr.base);
7284
7285 let offset = addr.offset;
7286 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7287 let abs_offset = offset.unsigned_abs();
7288 let imm8 = (abs_offset / 4) & 0xFF;
7289
7290 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7291}
7292
7293fn encode_vmov_core_dreg(
7297 to_dreg: bool,
7298 dreg: &VfpReg,
7299 core_lo: &Reg,
7300 core_hi: &Reg,
7301) -> Result<u32> {
7302 let d_num = vfp_dreg_to_num(dreg)?;
7303 let (vm, m) = encode_dreg(d_num);
7304 let rt = reg_to_bits(core_lo);
7305 let rt2 = reg_to_bits(core_hi);
7306
7307 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
7308 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
7309}
7310
7311fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
7313 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
7314 let hw2 = (instr & 0xFFFF) as u16;
7315 let mut bytes = hw1.to_le_bytes().to_vec();
7316 bytes.extend_from_slice(&hw2.to_le_bytes());
7317 bytes
7318}
7319
7320fn qreg_to_num(reg: &QReg) -> u32 {
7326 match reg {
7327 QReg::Q0 => 0,
7328 QReg::Q1 => 1,
7329 QReg::Q2 => 2,
7330 QReg::Q3 => 3,
7331 QReg::Q4 => 4,
7332 QReg::Q5 => 5,
7333 QReg::Q6 => 6,
7334 QReg::Q7 => 7,
7335 }
7336}
7337
7338fn mve_size_bits(size: &MveSize) -> u32 {
7340 match size {
7341 MveSize::S8 => 0b00,
7342 MveSize::S16 => 0b01,
7343 MveSize::S32 => 0b10,
7344 }
7345}
7346
7347fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7351 let d = qreg_to_num(qd) * 2;
7352 let n = qreg_to_num(qn) * 2;
7353 let m = qreg_to_num(qm) * 2;
7354
7355 let vd = d & 0xF;
7360 let d_bit = (d >> 4) & 1;
7361 let vn = n & 0xF;
7362 let n_bit = (n >> 4) & 1;
7363 let vm = m & 0xF;
7364 let m_bit = (m >> 4) & 1;
7365
7366 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
7367}
7368
7369fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7371 encode_mve_3reg(base, qd, qn, qm)
7372}
7373
7374fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
7377 let qd_enc = qreg_to_num(qd) * 2;
7378 let rn = reg_to_bits(&addr.base);
7379 let offset = addr.offset;
7380 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7381 let abs_offset = offset.unsigned_abs();
7382 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
7386 | (u_bit << 23)
7387 | ((qd_enc >> 4) << 22)
7388 | (rn << 16)
7389 | ((qd_enc & 0xF) << 12)
7390 | (imm7 & 0x7F)
7391}
7392
7393fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
7395 let qd_enc = qreg_to_num(qd) * 2;
7396 let rn = reg_to_bits(&addr.base);
7397 let offset = addr.offset;
7398 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7399 let abs_offset = offset.unsigned_abs();
7400 let imm7 = (abs_offset / 4) & 0x7F;
7401
7402 0xED000E80
7403 | (u_bit << 23)
7404 | ((qd_enc >> 4) << 22)
7405 | (rn << 16)
7406 | ((qd_enc & 0xF) << 12)
7407 | (imm7 & 0x7F)
7408}
7409
7410impl ArmEncoder {
7411 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
7413 let mut result = Vec::new();
7414 let qd_num = qreg_to_num(qd);
7415
7416 for i in 0..4 {
7418 let word = u32::from_le_bytes([
7419 bytes[i * 4],
7420 bytes[i * 4 + 1],
7421 bytes[i * 4 + 2],
7422 bytes[i * 4 + 3],
7423 ]);
7424 let lo16 = word & 0xFFFF;
7425 let hi16 = (word >> 16) & 0xFFFF;
7426
7427 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7429 if hi16 != 0 {
7431 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7432 }
7433
7434 let s_num = qd_num * 4 + i as u32;
7436 let (vn, n) = encode_sreg(s_num);
7437 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
7438 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7439 }
7440
7441 Ok(result)
7442 }
7443
7444 fn encode_thumb_mve_lane_wise_f32_binop(
7446 &self,
7447 qd: &QReg,
7448 qn: &QReg,
7449 qm: &QReg,
7450 vfp_base: u32,
7451 ) -> Result<Vec<u8>> {
7452 let mut result = Vec::new();
7453 let qd_num = qreg_to_num(qd);
7454 let qn_num = qreg_to_num(qn);
7455 let qm_num = qreg_to_num(qm);
7456
7457 for i in 0..4u32 {
7459 let sd = qd_num * 4 + i;
7460 let sn = qn_num * 4 + i;
7461 let sm = qm_num * 4 + i;
7462
7463 let (vd, d) = encode_sreg(sd);
7464 let (vn, n) = encode_sreg(sn);
7465 let (vm, m) = encode_sreg(sm);
7466
7467 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7468 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7469 }
7470
7471 Ok(result)
7472 }
7473
7474 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
7476 let mut result = Vec::new();
7477 let qd_num = qreg_to_num(qd);
7478 let qm_num = qreg_to_num(qm);
7479
7480 for i in 0..4u32 {
7482 let sd = qd_num * 4 + i;
7483 let sm = qm_num * 4 + i;
7484
7485 let (vd, d) = encode_sreg(sd);
7486 let (vm, m) = encode_sreg(sm);
7487
7488 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7489 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7490 }
7491
7492 Ok(result)
7493 }
7494}
7495
7496#[cfg(test)]
7497mod tests {
7498 use super::*;
7499
7500 #[test]
7501 fn test_encoder_creation() {
7502 let encoder_arm = ArmEncoder::new_arm32();
7503 assert!(!encoder_arm.thumb_mode);
7504
7505 let encoder_thumb = ArmEncoder::new_thumb2();
7506 assert!(encoder_thumb.thumb_mode);
7507 }
7508
7509 #[test]
7521 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
7522 use synth_synthesis::{ArmOp, Condition, Reg};
7523 let enc = ArmEncoder::new_thumb2();
7524 let bytes = enc
7525 .encode(&ArmOp::I64SetCond {
7526 rd: Reg::R8,
7527 rn_lo: Reg::R2,
7528 rn_hi: Reg::R3,
7529 rm_lo: Reg::R6,
7530 rm_hi: Reg::R7,
7531 cond: Condition::EQ,
7532 })
7533 .unwrap();
7534 let halfwords: Vec<u16> = bytes
7537 .chunks(2)
7538 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7539 .collect();
7540 assert!(
7541 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
7542 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
7543 );
7544 assert!(
7545 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
7546 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
7547 );
7548
7549 let bytes_z = enc
7550 .encode(&ArmOp::I64SetCondZ {
7551 rd: Reg::R8,
7552 rn_lo: Reg::R2,
7553 rn_hi: Reg::R3,
7554 })
7555 .unwrap();
7556 let hw_z: Vec<u16> = bytes_z
7557 .chunks(2)
7558 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7559 .collect();
7560 assert!(
7561 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
7562 "SetCondZ high rd MOV.W: {hw_z:04x?}"
7563 );
7564 assert!(
7566 hw_z.contains(&(0xF1B0 | 8)),
7567 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
7568 );
7569 }
7570
7571 #[test]
7572 fn test_encode_setcond_high_reg_uses_mov_w_204() {
7573 use synth_synthesis::{ArmOp, Condition, Reg};
7574 let enc = ArmEncoder::new_thumb2();
7575 let hi = enc
7577 .encode(&ArmOp::SetCond {
7578 rd: Reg::R12,
7579 cond: Condition::NE,
7580 })
7581 .unwrap();
7582 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
7583 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
7585 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
7586 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
7587 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
7588 let lo = enc
7590 .encode(&ArmOp::SetCond {
7591 rd: Reg::R0,
7592 cond: Condition::NE,
7593 })
7594 .unwrap();
7595 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
7596 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
7597 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
7598 }
7599
7600 #[test]
7604 fn test_encode_umull_209b() {
7605 use synth_synthesis::{ArmOp, Reg};
7606 let op = ArmOp::Umull {
7607 rdlo: Reg::R4,
7608 rdhi: Reg::R5,
7609 rn: Reg::R0,
7610 rm: Reg::R3,
7611 };
7612 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
7614 assert_eq!(
7615 t,
7616 vec![0xA0, 0xFB, 0x03, 0x45],
7617 "umull r4,r5,r0,r3 (T2): {t:02x?}"
7618 );
7619 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
7621 assert_eq!(
7622 a,
7623 0xE085_4390u32.to_le_bytes().to_vec(),
7624 "umull (A32): {a:02x?}"
7625 );
7626 }
7627
7628 #[test]
7635 fn test_encode_arm32_indexed_load_keeps_index_206() {
7636 use synth_synthesis::{ArmOp, MemAddr, Reg};
7637 let enc = ArmEncoder::new_arm32();
7638 let bytes = enc
7640 .encode(&ArmOp::Ldr {
7641 rd: Reg::R0,
7642 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
7643 })
7644 .unwrap();
7645 assert_eq!(
7646 bytes.len(),
7647 8,
7648 "expected ADD ip + LDR (2 words): {bytes:02x?}"
7649 );
7650 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7651 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7652 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
7654 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
7656 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
7658 }
7659
7660 #[test]
7666 fn test_encode_arm32_call_indirect_is_real_call_594() {
7667 use synth_synthesis::{ArmOp, Reg};
7668 let enc = ArmEncoder::new_arm32();
7669 let bytes = enc
7670 .encode(&ArmOp::CallIndirect {
7671 rd: Reg::R0,
7672 type_idx: 0,
7673 table_index_reg: Reg::R0,
7674 })
7675 .unwrap();
7676 assert_eq!(
7677 bytes.len(),
7678 12,
7679 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
7680 );
7681 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7682 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7683 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
7684 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
7686 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
7688 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
7690 assert!(
7692 !bytes
7693 .chunks_exact(4)
7694 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
7695 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
7696 );
7697
7698 let bytes = enc
7700 .encode(&ArmOp::CallIndirect {
7701 rd: Reg::R0,
7702 type_idx: 0,
7703 table_index_reg: Reg::R4,
7704 })
7705 .unwrap();
7706 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7707 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
7708 }
7709
7710 #[test]
7720 fn test_encode_thumb_call_indirect_unchanged_594() {
7721 use synth_synthesis::{ArmOp, Reg};
7722 let enc = ArmEncoder::new_thumb2();
7723 let bytes = enc
7724 .encode(&ArmOp::CallIndirect {
7725 rd: Reg::R0,
7726 type_idx: 0,
7727 table_index_reg: Reg::R0,
7728 })
7729 .unwrap();
7730 assert_eq!(
7731 bytes,
7732 vec![0x4F, 0xEA, 0x20, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
7733 "Thumb-2 CallIndirect bytes must stay frozen in this PR: {bytes:02x?}"
7734 );
7735 }
7736
7737 #[test]
7744 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
7745 let encoder = ArmEncoder::new_thumb2();
7746
7747 let code = encoder
7749 .encode(&ArmOp::Add {
7750 rd: Reg::R12,
7751 rn: Reg::R12,
7752 op2: Operand2::Reg(Reg::R0),
7753 })
7754 .unwrap();
7755 assert_eq!(
7757 code,
7758 vec![0x0C, 0xEB, 0x00, 0x0C],
7759 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
7760 );
7761 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
7763
7764 let lo = encoder
7766 .encode(&ArmOp::Add {
7767 rd: Reg::R1,
7768 rn: Reg::R2,
7769 op2: Operand2::Reg(Reg::R3),
7770 })
7771 .unwrap();
7772 assert_eq!(
7773 lo.len(),
7774 2,
7775 "low-reg ADD should remain 16-bit, got {lo:02X?}"
7776 );
7777 }
7778
7779 #[test]
7782 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
7783 let encoder = ArmEncoder::new_thumb2();
7784
7785 let adds = encoder
7787 .encode(&ArmOp::Adds {
7788 rd: Reg::R10,
7789 rn: Reg::R10,
7790 op2: Operand2::Reg(Reg::R8),
7791 })
7792 .unwrap();
7793 assert_eq!(
7794 adds,
7795 vec![0x1A, 0xEB, 0x08, 0x0A],
7796 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
7797 );
7798
7799 let subs = encoder
7801 .encode(&ArmOp::Subs {
7802 rd: Reg::R10,
7803 rn: Reg::R10,
7804 op2: Operand2::Reg(Reg::R8),
7805 })
7806 .unwrap();
7807 assert_eq!(
7808 subs,
7809 vec![0xBA, 0xEB, 0x08, 0x0A],
7810 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
7811 );
7812 }
7813
7814 #[test]
7817 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
7818 let encoder = ArmEncoder::new_thumb2();
7819
7820 let cmn = encoder
7822 .encode(&ArmOp::Cmn {
7823 rn: Reg::R10,
7824 op2: Operand2::Reg(Reg::R8),
7825 })
7826 .unwrap();
7827 assert_eq!(
7828 cmn,
7829 vec![0x1A, 0xEB, 0x08, 0x0F],
7830 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
7831 );
7832
7833 let lo = encoder
7835 .encode(&ArmOp::Cmn {
7836 rn: Reg::R1,
7837 op2: Operand2::Reg(Reg::R2),
7838 })
7839 .unwrap();
7840 assert_eq!(
7841 lo.len(),
7842 2,
7843 "low-reg CMN should remain 16-bit, got {lo:02X?}"
7844 );
7845 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
7846 }
7847
7848 #[test]
7852 fn test_encode_pc_operand_returns_err_not_panic_185() {
7853 let encoder = ArmEncoder::new_thumb2();
7854 for op in [
7855 ArmOp::Sdiv {
7856 rd: Reg::PC,
7857 rn: Reg::R0,
7858 rm: Reg::R1,
7859 },
7860 ArmOp::Udiv {
7861 rd: Reg::R0,
7862 rn: Reg::PC,
7863 rm: Reg::R1,
7864 },
7865 ArmOp::Sdiv {
7866 rd: Reg::R0,
7867 rn: Reg::R1,
7868 rm: Reg::PC,
7869 },
7870 ] {
7871 let r = encoder.encode(&op);
7872 assert!(
7873 r.is_err(),
7874 "encode({op:?}) must return Err for a PC operand, got {r:?}"
7875 );
7876 }
7877 assert!(
7879 encoder
7880 .encode(&ArmOp::Sdiv {
7881 rd: Reg::R0,
7882 rn: Reg::R1,
7883 rm: Reg::R2
7884 })
7885 .is_ok()
7886 );
7887 }
7888
7889 #[test]
7890 fn test_encode_nop_arm32() {
7891 let encoder = ArmEncoder::new_arm32();
7892 let code = encoder.encode(&ArmOp::Nop).unwrap();
7893
7894 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
7897
7898 #[test]
7899 fn test_encode_nop_thumb() {
7900 let encoder = ArmEncoder::new_thumb2();
7901 let code = encoder.encode(&ArmOp::Nop).unwrap();
7902
7903 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
7906
7907 #[test]
7908 fn test_encode_mov_immediate_arm32() {
7909 let encoder = ArmEncoder::new_arm32();
7910 let op = ArmOp::Mov {
7911 rd: Reg::R0,
7912 op2: Operand2::Imm(42),
7913 };
7914
7915 let code = encoder.encode(&op).unwrap();
7916 assert_eq!(code.len(), 4);
7917
7918 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7920 assert_eq!(instr & 0x0E000000, 0x02000000); }
7922
7923 #[test]
7924 fn test_encode_add_registers_arm32() {
7925 let encoder = ArmEncoder::new_arm32();
7926 let op = ArmOp::Add {
7927 rd: Reg::R0,
7928 rn: Reg::R1,
7929 op2: Operand2::Reg(Reg::R2),
7930 };
7931
7932 let code = encoder.encode(&op).unwrap();
7933 assert_eq!(code.len(), 4);
7934
7935 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7936 assert_eq!(instr & 0x0FE00000, 0x00800000);
7938 }
7939
7940 #[test]
7944 fn test_encode_add_imm_large_350() {
7945 let enc = ArmEncoder::new_thumb2();
7946
7947 let small = enc
7949 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
7950 .unwrap();
7951 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
7952
7953 fn movx_imm16(b: &[u8]) -> u32 {
7955 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
7956 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
7957 let imm4 = hw1 & 0xF;
7958 let i = (hw1 >> 10) & 1;
7959 let imm3 = (hw2 >> 12) & 0x7;
7960 let imm8 = hw2 & 0xFF;
7961 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
7962 }
7963 fn movx_rd(b: &[u8]) -> u32 {
7964 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
7965 }
7966
7967 let seq = enc
7970 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
7971 .unwrap();
7972 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
7973 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
7975 assert_eq!(movx_rd(&seq[0..4]), 12);
7976 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
7977 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
7979 assert_eq!(movx_rd(&seq[4..8]), 12);
7980 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
7981 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
7983 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
7984 assert_eq!(add1 & 0xFFF0, 0xEB00);
7985 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
7990 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
7991 70000
7992 );
7993
7994 let seq16 = enc
7996 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
7997 .unwrap();
7998 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
7999 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
8000 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
8005 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
8006 .unwrap();
8007 assert_eq!(inplace.len(), 12);
8008 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
8009 assert_eq!(
8010 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
8011 0x12345
8012 );
8013 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
8015 assert_eq!(ip_add2 & 0xF, 12);
8016 assert_eq!((ip_add2 >> 8) & 0xF, 5);
8017 }
8018
8019 #[test]
8027 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
8028 let enc = ArmEncoder::new_thumb2();
8029 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
8031 assert!(
8032 r.is_err(),
8033 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
8034 );
8035 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
8039 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
8040 }
8041
8042 #[test]
8051 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
8052 let enc = ArmEncoder::new_arm32();
8053 let bad = enc.encode(&ArmOp::Add {
8054 rd: Reg::R0,
8055 rn: Reg::R1,
8056 op2: Operand2::Imm(0x1FF),
8057 });
8058 assert!(
8059 bad.is_err(),
8060 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
8061 to 0xFF), got {bad:?}"
8062 );
8063 let ok = enc.encode(&ArmOp::Add {
8065 rd: Reg::R0,
8066 rn: Reg::R1,
8067 op2: Operand2::Imm(0xFF),
8068 });
8069 assert!(
8070 ok.is_ok(),
8071 "0xFF is a valid rotated immediate, must stay Ok"
8072 );
8073 }
8074
8075 #[test]
8076 fn test_encode_ldr_arm32() {
8077 let encoder = ArmEncoder::new_arm32();
8078 let op = ArmOp::Ldr {
8079 rd: Reg::R0,
8080 addr: MemAddr::imm(Reg::R1, 4),
8081 };
8082
8083 let code = encoder.encode(&op).unwrap();
8084 assert_eq!(code.len(), 4);
8085
8086 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8087 assert_eq!(instr & 0x00100000, 0x00100000);
8089 }
8090
8091 #[test]
8092 fn test_encode_str_arm32() {
8093 let encoder = ArmEncoder::new_arm32();
8094 let op = ArmOp::Str {
8095 rd: Reg::R0,
8096 addr: MemAddr::imm(Reg::SP, 0),
8097 };
8098
8099 let code = encoder.encode(&op).unwrap();
8100 assert_eq!(code.len(), 4);
8101 }
8102
8103 #[test]
8104 fn test_encode_branch_arm32() {
8105 let encoder = ArmEncoder::new_arm32();
8106 let op = ArmOp::Bl {
8107 label: "main".to_string(),
8108 };
8109
8110 let code = encoder.encode(&op).unwrap();
8111 assert_eq!(code.len(), 4);
8112
8113 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8114 assert_eq!(instr & 0x0F000000, 0x0B000000);
8116 }
8117
8118 #[test]
8128 fn test_encode_thumb_bl_placeholder_addend_167_174() {
8129 let encoder = ArmEncoder::new_thumb2();
8130 let op = ArmOp::Bl {
8131 label: "callee".to_string(),
8132 };
8133
8134 let code = encoder.encode(&op).unwrap();
8135 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
8136
8137 let hw1 = u16::from_le_bytes([code[0], code[1]]);
8138 let hw2 = u16::from_le_bytes([code[2], code[3]]);
8139 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
8140 assert_eq!(
8141 hw2, 0xFFFE,
8142 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
8143 );
8144 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
8145 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
8146 }
8147
8148 #[test]
8149 fn test_encode_sequence() {
8150 let encoder = ArmEncoder::new_arm32();
8151 let ops = vec![
8152 ArmOp::Mov {
8153 rd: Reg::R0,
8154 op2: Operand2::Imm(42),
8155 },
8156 ArmOp::Mov {
8157 rd: Reg::R1,
8158 op2: Operand2::Imm(10),
8159 },
8160 ArmOp::Add {
8161 rd: Reg::R2,
8162 rn: Reg::R0,
8163 op2: Operand2::Reg(Reg::R1),
8164 },
8165 ];
8166
8167 let code = encoder.encode_sequence(&ops).unwrap();
8168 assert_eq!(code.len(), 12); }
8170
8171 #[test]
8172 fn test_reg_to_bits() {
8173 assert_eq!(reg_to_bits(&Reg::R0), 0);
8174 assert_eq!(reg_to_bits(&Reg::R7), 7);
8175 assert_eq!(reg_to_bits(&Reg::SP), 13);
8176 assert_eq!(reg_to_bits(&Reg::LR), 14);
8177 assert_eq!(reg_to_bits(&Reg::PC), 15);
8178 }
8179
8180 #[test]
8181 fn test_encode_bitwise_operations() {
8182 let encoder = ArmEncoder::new_arm32();
8183
8184 let and_op = ArmOp::And {
8185 rd: Reg::R0,
8186 rn: Reg::R1,
8187 op2: Operand2::Reg(Reg::R2),
8188 };
8189 let and_code = encoder.encode(&and_op).unwrap();
8190 assert_eq!(and_code.len(), 4);
8191
8192 let orr_op = ArmOp::Orr {
8193 rd: Reg::R0,
8194 rn: Reg::R1,
8195 op2: Operand2::Reg(Reg::R2),
8196 };
8197 let orr_code = encoder.encode(&orr_op).unwrap();
8198 assert_eq!(orr_code.len(), 4);
8199
8200 let eor_op = ArmOp::Eor {
8201 rd: Reg::R0,
8202 rn: Reg::R1,
8203 op2: Operand2::Reg(Reg::R2),
8204 };
8205 let eor_code = encoder.encode(&eor_op).unwrap();
8206 assert_eq!(eor_code.len(), 4);
8207 }
8208
8209 #[test]
8212 fn test_encode_sdiv_thumb2() {
8213 let encoder = ArmEncoder::new_thumb2();
8214 let op = ArmOp::Sdiv {
8215 rd: Reg::R0,
8216 rn: Reg::R1,
8217 rm: Reg::R2,
8218 };
8219
8220 let code = encoder.encode(&op).unwrap();
8221 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
8228 assert_eq!(code[1], 0xFB);
8229 assert_eq!(code[2], 0xF2);
8230 assert_eq!(code[3], 0xF0);
8231 }
8232
8233 #[test]
8234 fn test_encode_udiv_thumb2() {
8235 let encoder = ArmEncoder::new_thumb2();
8236 let op = ArmOp::Udiv {
8237 rd: Reg::R0,
8238 rn: Reg::R1,
8239 rm: Reg::R2,
8240 };
8241
8242 let code = encoder.encode(&op).unwrap();
8243 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
8248 assert_eq!(code[1], 0xFB);
8249 assert_eq!(code[2], 0xF2);
8250 assert_eq!(code[3], 0xF0);
8251 }
8252
8253 #[test]
8254 fn test_encode_mul_thumb2() {
8255 let encoder = ArmEncoder::new_thumb2();
8256 let op = ArmOp::Mul {
8257 rd: Reg::R0,
8258 rn: Reg::R1,
8259 rm: Reg::R2,
8260 };
8261
8262 let code = encoder.encode(&op).unwrap();
8263 assert_eq!(code.len(), 4); }
8265
8266 #[test]
8267 fn test_encode_and_thumb2() {
8268 let encoder = ArmEncoder::new_thumb2();
8269 let op = ArmOp::And {
8270 rd: Reg::R0,
8271 rn: Reg::R1,
8272 op2: Operand2::Reg(Reg::R2),
8273 };
8274
8275 let code = encoder.encode(&op).unwrap();
8276 assert_eq!(code.len(), 4); }
8278
8279 #[test]
8280 fn test_encode_lsl_thumb2_low_regs() {
8281 let encoder = ArmEncoder::new_thumb2();
8282 let op = ArmOp::Lsl {
8283 rd: Reg::R0,
8284 rn: Reg::R1,
8285 shift: 5,
8286 };
8287
8288 let code = encoder.encode(&op).unwrap();
8289 assert_eq!(code.len(), 2); }
8291
8292 #[test]
8293 fn test_encode_clz_thumb2() {
8294 let encoder = ArmEncoder::new_thumb2();
8295 let op = ArmOp::Clz {
8296 rd: Reg::R0,
8297 rm: Reg::R1,
8298 };
8299
8300 let code = encoder.encode(&op).unwrap();
8301 assert_eq!(code.len(), 4); }
8303
8304 #[test]
8305 fn test_encode_bx_thumb2() {
8306 let encoder = ArmEncoder::new_thumb2();
8307 let op = ArmOp::Bx { rm: Reg::LR };
8308
8309 let code = encoder.encode(&op).unwrap();
8310 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
8314 }
8315
8316 #[test]
8321 fn test_encode_f32_abs_arm32() {
8322 let encoder = ArmEncoder::new_arm32();
8323 let op = ArmOp::F32Abs {
8324 sd: VfpReg::S0,
8325 sm: VfpReg::S2,
8326 };
8327 let code = encoder.encode(&op).unwrap();
8328 assert_eq!(code.len(), 4); }
8330
8331 #[test]
8332 fn test_encode_f32_neg_arm32() {
8333 let encoder = ArmEncoder::new_arm32();
8334 let op = ArmOp::F32Neg {
8335 sd: VfpReg::S0,
8336 sm: VfpReg::S2,
8337 };
8338 let code = encoder.encode(&op).unwrap();
8339 assert_eq!(code.len(), 4);
8340 }
8341
8342 #[test]
8343 fn test_encode_f32_sqrt_arm32() {
8344 let encoder = ArmEncoder::new_arm32();
8345 let op = ArmOp::F32Sqrt {
8346 sd: VfpReg::S0,
8347 sm: VfpReg::S2,
8348 };
8349 let code = encoder.encode(&op).unwrap();
8350 assert_eq!(code.len(), 4);
8351 }
8352
8353 #[test]
8354 fn test_encode_f32_ceil_arm32() {
8355 let encoder = ArmEncoder::new_arm32();
8356 let op = ArmOp::F32Ceil {
8357 sd: VfpReg::S0,
8358 sm: VfpReg::S2,
8359 };
8360 let code = encoder.encode(&op).unwrap();
8361 assert_eq!(code.len(), 36);
8363 }
8364
8365 #[test]
8366 fn test_encode_f32_floor_thumb2() {
8367 let encoder = ArmEncoder::new_thumb2();
8368 let op = ArmOp::F32Floor {
8369 sd: VfpReg::S0,
8370 sm: VfpReg::S2,
8371 };
8372 let code = encoder.encode(&op).unwrap();
8373 assert_eq!(code.len(), 36);
8375 }
8376
8377 #[test]
8378 fn test_encode_f32_min_arm32() {
8379 let encoder = ArmEncoder::new_arm32();
8380 let op = ArmOp::F32Min {
8381 sd: VfpReg::S0,
8382 sn: VfpReg::S2,
8383 sm: VfpReg::S4,
8384 };
8385 let code = encoder.encode(&op).unwrap();
8386 assert_eq!(code.len(), 16); }
8388
8389 #[test]
8390 fn test_encode_f32_max_thumb2() {
8391 let encoder = ArmEncoder::new_thumb2();
8392 let op = ArmOp::F32Max {
8393 sd: VfpReg::S0,
8394 sn: VfpReg::S2,
8395 sm: VfpReg::S4,
8396 };
8397 let code = encoder.encode(&op).unwrap();
8398 assert_eq!(code.len(), 18);
8400 }
8401
8402 #[test]
8403 fn test_encode_f32_copysign_arm32() {
8404 let encoder = ArmEncoder::new_arm32();
8405 let op = ArmOp::F32Copysign {
8406 sd: VfpReg::S0,
8407 sn: VfpReg::S2,
8408 sm: VfpReg::S4,
8409 };
8410 let code = encoder.encode(&op).unwrap();
8411 assert_eq!(code.len(), 24);
8413 }
8414
8415 #[test]
8420 fn test_encode_f64_add_arm32() {
8421 let encoder = ArmEncoder::new_arm32();
8422 let op = ArmOp::F64Add {
8423 dd: VfpReg::D0,
8424 dn: VfpReg::D1,
8425 dm: VfpReg::D2,
8426 };
8427 let code = encoder.encode(&op).unwrap();
8428 assert_eq!(code.len(), 4);
8429 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8431 assert_eq!((instr >> 8) & 0xF, 0xB); }
8433
8434 #[test]
8435 fn test_encode_f64_sub_thumb2() {
8436 let encoder = ArmEncoder::new_thumb2();
8437 let op = ArmOp::F64Sub {
8438 dd: VfpReg::D0,
8439 dn: VfpReg::D1,
8440 dm: VfpReg::D2,
8441 };
8442 let code = encoder.encode(&op).unwrap();
8443 assert_eq!(code.len(), 4); }
8445
8446 #[test]
8447 fn test_encode_f64_mul_arm32() {
8448 let encoder = ArmEncoder::new_arm32();
8449 let op = ArmOp::F64Mul {
8450 dd: VfpReg::D0,
8451 dn: VfpReg::D1,
8452 dm: VfpReg::D2,
8453 };
8454 let code = encoder.encode(&op).unwrap();
8455 assert_eq!(code.len(), 4);
8456 }
8457
8458 #[test]
8459 fn test_encode_f64_div_arm32() {
8460 let encoder = ArmEncoder::new_arm32();
8461 let op = ArmOp::F64Div {
8462 dd: VfpReg::D0,
8463 dn: VfpReg::D1,
8464 dm: VfpReg::D2,
8465 };
8466 let code = encoder.encode(&op).unwrap();
8467 assert_eq!(code.len(), 4);
8468 }
8469
8470 #[test]
8471 fn test_encode_f64_abs_arm32() {
8472 let encoder = ArmEncoder::new_arm32();
8473 let op = ArmOp::F64Abs {
8474 dd: VfpReg::D0,
8475 dm: VfpReg::D2,
8476 };
8477 let code = encoder.encode(&op).unwrap();
8478 assert_eq!(code.len(), 4);
8479 }
8480
8481 #[test]
8482 fn test_encode_f64_neg_arm32() {
8483 let encoder = ArmEncoder::new_arm32();
8484 let op = ArmOp::F64Neg {
8485 dd: VfpReg::D0,
8486 dm: VfpReg::D2,
8487 };
8488 let code = encoder.encode(&op).unwrap();
8489 assert_eq!(code.len(), 4);
8490 }
8491
8492 #[test]
8493 fn test_encode_f64_sqrt_arm32() {
8494 let encoder = ArmEncoder::new_arm32();
8495 let op = ArmOp::F64Sqrt {
8496 dd: VfpReg::D0,
8497 dm: VfpReg::D2,
8498 };
8499 let code = encoder.encode(&op).unwrap();
8500 assert_eq!(code.len(), 4);
8501 }
8502
8503 #[test]
8504 fn test_encode_f64_load_arm32() {
8505 let encoder = ArmEncoder::new_arm32();
8506 let op = ArmOp::F64Load {
8507 dd: VfpReg::D0,
8508 addr: MemAddr::imm(Reg::R0, 8),
8509 };
8510 let code = encoder.encode(&op).unwrap();
8511 assert_eq!(code.len(), 4);
8512 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8513 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
8516
8517 #[test]
8518 fn test_encode_f64_store_thumb2() {
8519 let encoder = ArmEncoder::new_thumb2();
8520 let op = ArmOp::F64Store {
8521 dd: VfpReg::D0,
8522 addr: MemAddr::imm(Reg::SP, 0),
8523 };
8524 let code = encoder.encode(&op).unwrap();
8525 assert_eq!(code.len(), 4);
8526 }
8527
8528 #[test]
8529 fn test_encode_f64_compare_arm32() {
8530 let encoder = ArmEncoder::new_arm32();
8531 let op = ArmOp::F64Eq {
8532 rd: Reg::R0,
8533 dn: VfpReg::D0,
8534 dm: VfpReg::D1,
8535 };
8536 let code = encoder.encode(&op).unwrap();
8537 assert_eq!(code.len(), 16); }
8539
8540 #[test]
8541 fn test_encode_f64_compare_thumb2() {
8542 let encoder = ArmEncoder::new_thumb2();
8543 let op = ArmOp::F64Lt {
8544 rd: Reg::R0,
8545 dn: VfpReg::D0,
8546 dm: VfpReg::D1,
8547 };
8548 let code = encoder.encode(&op).unwrap();
8549 assert_eq!(code.len(), 14);
8551 }
8552
8553 #[test]
8554 fn test_encode_f64_const_arm32() {
8555 let encoder = ArmEncoder::new_arm32();
8556 let op = ArmOp::F64Const {
8557 dd: VfpReg::D0,
8558 value: 3.125,
8559 };
8560 let code = encoder.encode(&op).unwrap();
8561 assert_eq!(code.len(), 20);
8563 }
8564
8565 #[test]
8566 fn test_encode_f64_const_thumb2() {
8567 let encoder = ArmEncoder::new_thumb2();
8568 let op = ArmOp::F64Const {
8569 dd: VfpReg::D0,
8570 value: 2.5,
8571 };
8572 let code = encoder.encode(&op).unwrap();
8573 assert_eq!(code.len(), 20);
8575 }
8576
8577 #[test]
8578 fn test_encode_f64_convert_i32s_arm32() {
8579 let encoder = ArmEncoder::new_arm32();
8580 let op = ArmOp::F64ConvertI32S {
8581 dd: VfpReg::D0,
8582 rm: Reg::R0,
8583 };
8584 let code = encoder.encode(&op).unwrap();
8585 assert_eq!(code.len(), 8);
8587 }
8588
8589 #[test]
8590 fn test_encode_f64_promote_f32_arm32() {
8591 let encoder = ArmEncoder::new_arm32();
8592 let op = ArmOp::F64PromoteF32 {
8593 dd: VfpReg::D0,
8594 sm: VfpReg::S0,
8595 };
8596 let code = encoder.encode(&op).unwrap();
8597 assert_eq!(code.len(), 4); }
8599
8600 #[test]
8601 fn test_encode_f64_promote_f32_thumb2() {
8602 let encoder = ArmEncoder::new_thumb2();
8603 let op = ArmOp::F64PromoteF32 {
8604 dd: VfpReg::D0,
8605 sm: VfpReg::S0,
8606 };
8607 let code = encoder.encode(&op).unwrap();
8608 assert_eq!(code.len(), 4);
8609 }
8610
8611 #[test]
8612 fn test_encode_i32_trunc_f64s_arm32() {
8613 let encoder = ArmEncoder::new_arm32();
8614 let op = ArmOp::I32TruncF64S {
8615 rd: Reg::R0,
8616 dm: VfpReg::D0,
8617 };
8618 let code = encoder.encode(&op).unwrap();
8619 assert_eq!(code.len(), 8);
8621 }
8622
8623 #[test]
8624 fn test_encode_f64_reinterpret_i64_arm32() {
8625 let encoder = ArmEncoder::new_arm32();
8626 let op = ArmOp::F64ReinterpretI64 {
8627 dd: VfpReg::D0,
8628 rmlo: Reg::R0,
8629 rmhi: Reg::R1,
8630 };
8631 let code = encoder.encode(&op).unwrap();
8632 assert_eq!(code.len(), 4); }
8634
8635 #[test]
8636 fn test_encode_i64_reinterpret_f64_thumb2() {
8637 let encoder = ArmEncoder::new_thumb2();
8638 let op = ArmOp::I64ReinterpretF64 {
8639 rdlo: Reg::R0,
8640 rdhi: Reg::R1,
8641 dm: VfpReg::D0,
8642 };
8643 let code = encoder.encode(&op).unwrap();
8644 assert_eq!(code.len(), 4);
8645 }
8646
8647 #[test]
8648 fn test_encode_f64_trunc_thumb2() {
8649 let encoder = ArmEncoder::new_thumb2();
8650 let op = ArmOp::F64Trunc {
8651 dd: VfpReg::D0,
8652 dm: VfpReg::D1,
8653 };
8654 let code = encoder.encode(&op).unwrap();
8655 assert_eq!(code.len(), 8);
8657 }
8658
8659 #[test]
8660 fn test_encode_f64_min_arm32() {
8661 let encoder = ArmEncoder::new_arm32();
8662 let op = ArmOp::F64Min {
8663 dd: VfpReg::D0,
8664 dn: VfpReg::D1,
8665 dm: VfpReg::D2,
8666 };
8667 let code = encoder.encode(&op).unwrap();
8668 assert_eq!(code.len(), 16);
8670 }
8671
8672 #[test]
8673 fn test_f64_cp11_encoding() {
8674 let encoder = ArmEncoder::new_arm32();
8676
8677 let code = encoder
8679 .encode(&ArmOp::F64Add {
8680 dd: VfpReg::D0,
8681 dn: VfpReg::D0,
8682 dm: VfpReg::D0,
8683 })
8684 .unwrap();
8685 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8686 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
8687
8688 let code = encoder
8690 .encode(&ArmOp::F32Add {
8691 sd: VfpReg::S0,
8692 sn: VfpReg::S0,
8693 sm: VfpReg::S0,
8694 })
8695 .unwrap();
8696 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8697 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
8698 }
8699
8700 #[test]
8701 fn test_dreg_encoding_higher_registers() {
8702 let encoder = ArmEncoder::new_arm32();
8703
8704 let op = ArmOp::F64Add {
8706 dd: VfpReg::D15,
8707 dn: VfpReg::D14,
8708 dm: VfpReg::D13,
8709 };
8710 let code = encoder.encode(&op).unwrap();
8711 assert_eq!(code.len(), 4);
8712
8713 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8715 assert_eq!((instr >> 8) & 0xF, 0xB); }
8717
8718 #[test]
8723 fn test_encode_label_emits_no_bytes() {
8724 let encoder = ArmEncoder::new_thumb2();
8725 let op = ArmOp::Label {
8726 name: ".Lblock_end_0".to_string(),
8727 };
8728 let code = encoder.encode(&op).unwrap();
8729 assert!(code.is_empty(), "Label should emit zero bytes");
8730
8731 let encoder32 = ArmEncoder::new_arm32();
8732 let code32 = encoder32.encode(&op).unwrap();
8733 assert!(
8734 code32.is_empty(),
8735 "Label should emit zero bytes in ARM32 too"
8736 );
8737 }
8738
8739 #[test]
8740 fn test_encode_bcc_eq_thumb2() {
8741 use synth_synthesis::Condition;
8742 let encoder = ArmEncoder::new_thumb2();
8743 let op = ArmOp::Bcc {
8744 cond: Condition::EQ,
8745 label: "target".to_string(),
8746 };
8747 let code = encoder.encode(&op).unwrap();
8748 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
8752 }
8753
8754 #[test]
8755 fn test_encode_bcc_ne_thumb2() {
8756 use synth_synthesis::Condition;
8757 let encoder = ArmEncoder::new_thumb2();
8758 let op = ArmOp::Bcc {
8759 cond: Condition::NE,
8760 label: "target".to_string(),
8761 };
8762 let code = encoder.encode(&op).unwrap();
8763 assert_eq!(code.len(), 2);
8764
8765 assert_eq!(code, vec![0x00, 0xD1]);
8767 }
8768
8769 #[test]
8770 fn test_encode_bcc_arm32() {
8771 use synth_synthesis::Condition;
8772 let encoder = ArmEncoder::new_arm32();
8773 let op = ArmOp::Bcc {
8774 cond: Condition::EQ,
8775 label: "target".to_string(),
8776 };
8777 let code = encoder.encode(&op).unwrap();
8778 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8781 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
8785
8786 #[test]
8787 fn test_encode_udf_thumb2() {
8788 let encoder = ArmEncoder::new_thumb2();
8789 let op = ArmOp::Udf { imm: 0 };
8790 let code = encoder.encode(&op).unwrap();
8791 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
8795 }
8796
8797 #[test]
8798 fn test_encode_nop_thumb2() {
8799 let encoder = ArmEncoder::new_thumb2();
8800 let op = ArmOp::Nop;
8801 let code = encoder.encode(&op).unwrap();
8802 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
8806 }
8807
8808 #[test]
8813 fn test_encode_i64_add_thumb2() {
8814 let encoder = ArmEncoder::new_thumb2();
8815 let op = ArmOp::I64Add {
8816 rdlo: Reg::R0,
8817 rdhi: Reg::R1,
8818 rnlo: Reg::R0,
8819 rnhi: Reg::R1,
8820 rmlo: Reg::R2,
8821 rmhi: Reg::R3,
8822 };
8823 let code = encoder.encode(&op).unwrap();
8824 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
8826 }
8827
8828 #[test]
8829 fn test_encode_i64_sub_thumb2() {
8830 let encoder = ArmEncoder::new_thumb2();
8831 let op = ArmOp::I64Sub {
8832 rdlo: Reg::R0,
8833 rdhi: Reg::R1,
8834 rnlo: Reg::R0,
8835 rnhi: Reg::R1,
8836 rmlo: Reg::R2,
8837 rmhi: Reg::R3,
8838 };
8839 let code = encoder.encode(&op).unwrap();
8840 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
8842 }
8843
8844 #[test]
8845 fn test_encode_i64_and_thumb2() {
8846 let encoder = ArmEncoder::new_thumb2();
8847 let op = ArmOp::I64And {
8848 rdlo: Reg::R0,
8849 rdhi: Reg::R1,
8850 rnlo: Reg::R0,
8851 rnhi: Reg::R1,
8852 rmlo: Reg::R2,
8853 rmhi: Reg::R3,
8854 };
8855 let code = encoder.encode(&op).unwrap();
8856 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
8858 }
8859
8860 #[test]
8861 fn test_encode_i64_or_thumb2() {
8862 let encoder = ArmEncoder::new_thumb2();
8863 let op = ArmOp::I64Or {
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 let code = encoder.encode(&op).unwrap();
8872 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
8873 }
8874
8875 #[test]
8876 fn test_encode_i64_xor_thumb2() {
8877 let encoder = ArmEncoder::new_thumb2();
8878 let op = ArmOp::I64Xor {
8879 rdlo: Reg::R0,
8880 rdhi: Reg::R1,
8881 rnlo: Reg::R0,
8882 rnhi: Reg::R1,
8883 rmlo: Reg::R2,
8884 rmhi: Reg::R3,
8885 };
8886 let code = encoder.encode(&op).unwrap();
8887 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
8888 }
8889
8890 #[test]
8891 fn test_encode_i64_const_small_thumb2() {
8892 let encoder = ArmEncoder::new_thumb2();
8893 let op = ArmOp::I64Const {
8895 rdlo: Reg::R0,
8896 rdhi: Reg::R1,
8897 value: 42,
8898 };
8899 let code = encoder.encode(&op).unwrap();
8900 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
8902 }
8903
8904 #[test]
8905 fn test_encode_i64_const_large_thumb2() {
8906 let encoder = ArmEncoder::new_thumb2();
8907 let op = ArmOp::I64Const {
8909 rdlo: Reg::R0,
8910 rdhi: Reg::R1,
8911 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
8912 };
8913 let code = encoder.encode(&op).unwrap();
8914 assert_eq!(
8916 code.len(),
8917 16,
8918 "I64Const with large value should be 16 bytes"
8919 );
8920 }
8921
8922 #[test]
8923 fn test_encode_i64_extend_i32_s_thumb2() {
8924 let encoder = ArmEncoder::new_thumb2();
8925 let op = ArmOp::I64ExtendI32S {
8926 rdlo: Reg::R0,
8927 rdhi: Reg::R1,
8928 rn: Reg::R0,
8929 };
8930 let code = encoder.encode(&op).unwrap();
8931 assert_eq!(
8933 code.len(),
8934 4,
8935 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
8936 );
8937 }
8938
8939 #[test]
8940 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
8941 let encoder = ArmEncoder::new_thumb2();
8942 let op = ArmOp::I64ExtendI32S {
8943 rdlo: Reg::R0,
8944 rdhi: Reg::R1,
8945 rn: Reg::R2,
8946 };
8947 let code = encoder.encode(&op).unwrap();
8948 assert!(
8950 code.len() >= 6,
8951 "I64ExtendI32S (diff reg) should be at least 6 bytes"
8952 );
8953 }
8954
8955 #[test]
8956 fn test_encode_i64_extend_i32_u_thumb2() {
8957 let encoder = ArmEncoder::new_thumb2();
8958 let op = ArmOp::I64ExtendI32U {
8959 rdlo: Reg::R0,
8960 rdhi: Reg::R1,
8961 rn: Reg::R0,
8962 };
8963 let code = encoder.encode(&op).unwrap();
8964 assert_eq!(
8966 code.len(),
8967 2,
8968 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
8969 );
8970 }
8971
8972 #[test]
8973 fn test_encode_i32_wrap_i64_nop_thumb2() {
8974 let encoder = ArmEncoder::new_thumb2();
8975 let op = ArmOp::I32WrapI64 {
8977 rd: Reg::R0,
8978 rnlo: Reg::R0,
8979 };
8980 let code = encoder.encode(&op).unwrap();
8981 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
8982 assert_eq!(code, vec![0x00, 0xBF]); }
8984
8985 #[test]
8986 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
8987 let encoder = ArmEncoder::new_thumb2();
8988 let op = ArmOp::I32WrapI64 {
8989 rd: Reg::R2,
8990 rnlo: Reg::R0,
8991 };
8992 let code = encoder.encode(&op).unwrap();
8993 assert!(
8995 code.len() >= 2,
8996 "I32WrapI64 diff reg should emit at least 2 bytes"
8997 );
8998 }
8999
9000 #[test]
9001 fn test_encode_i64_eqz_thumb2() {
9002 let encoder = ArmEncoder::new_thumb2();
9003 let op = ArmOp::I64Eqz {
9004 rd: Reg::R0,
9005 rnlo: Reg::R0,
9006 rnhi: Reg::R1,
9007 };
9008 let code = encoder.encode(&op).unwrap();
9009 assert!(
9011 code.len() >= 6,
9012 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
9013 );
9014 }
9015
9016 #[test]
9017 fn test_encode_i64_eq_thumb2() {
9018 let encoder = ArmEncoder::new_thumb2();
9019 let op = ArmOp::I64Eq {
9020 rd: Reg::R0,
9021 rnlo: Reg::R0,
9022 rnhi: Reg::R1,
9023 rmlo: Reg::R2,
9024 rmhi: Reg::R3,
9025 };
9026 let code = encoder.encode(&op).unwrap();
9027 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
9029 }
9030
9031 #[test]
9032 fn test_encode_i64_ldr_thumb2() {
9033 let encoder = ArmEncoder::new_thumb2();
9034 let op = ArmOp::I64Ldr {
9035 rdlo: Reg::R0,
9036 rdhi: Reg::R1,
9037 addr: MemAddr::imm(Reg::SP, 0),
9038 };
9039 let code = encoder.encode(&op).unwrap();
9040 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
9042 }
9043
9044 #[test]
9045 fn test_372_i64_ldr_indexed_materializes_address() {
9046 let encoder = ArmEncoder::new_thumb2();
9051 let indexed = encoder
9052 .encode(&ArmOp::I64Ldr {
9053 rdlo: Reg::R0,
9054 rdhi: Reg::R1,
9055 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
9056 })
9057 .unwrap();
9058 assert_eq!(
9060 &indexed[0..4],
9061 &[0x0b, 0xeb, 0x00, 0x0c],
9062 "indexed I64Ldr must start with ADD.W ip, base, index"
9063 );
9064 let frame = encoder
9065 .encode(&ArmOp::I64Ldr {
9066 rdlo: Reg::R0,
9067 rdhi: Reg::R1,
9068 addr: MemAddr::imm(Reg::SP, 8),
9069 })
9070 .unwrap();
9071 assert_ne!(
9073 &frame[0..2],
9074 &[0x0b, 0xeb],
9075 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
9076 );
9077 }
9078
9079 #[test]
9080 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
9081 let encoder = ArmEncoder::new_thumb2();
9087 let ld = encoder
9090 .encode(&ArmOp::I64Ldr {
9091 rdlo: Reg::R0,
9092 rdhi: Reg::R1,
9093 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9094 })
9095 .expect("large-offset i64.load must lower, not skip");
9096 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
9098 assert_ne!(
9101 &ld[0..2],
9102 &[0x0b, 0xeb],
9103 "must materialize the large offset"
9104 );
9105 assert_eq!(
9107 &ld[4..20],
9108 &[
9109 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
9114 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
9115 );
9116
9117 let st = encoder
9119 .encode(&ArmOp::I64Str {
9120 rdlo: Reg::R2,
9121 rdhi: Reg::R3,
9122 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9123 })
9124 .expect("large-offset i64.store must lower, not skip");
9125 assert_eq!(st.len(), 20);
9126 assert_eq!(
9127 &st[4..20],
9128 &[
9129 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
9134 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
9135 );
9136
9137 let small = encoder
9141 .encode(&ArmOp::I64Ldr {
9142 rdlo: Reg::R0,
9143 rdhi: Reg::R1,
9144 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
9145 })
9146 .unwrap();
9147 assert_eq!(
9148 &small[0..4],
9149 &[0x0b, 0xeb, 0x00, 0x0c],
9150 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
9151 );
9152 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
9153 }
9154
9155 #[test]
9156 fn test_encode_i64_str_thumb2() {
9157 let encoder = ArmEncoder::new_thumb2();
9158 let op = ArmOp::I64Str {
9159 rdlo: Reg::R0,
9160 rdhi: Reg::R1,
9161 addr: MemAddr::imm(Reg::SP, 0),
9162 };
9163 let code = encoder.encode(&op).unwrap();
9164 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
9166 }
9167
9168 #[test]
9169 fn test_encode_i64_all_comparisons_thumb2() {
9170 let encoder = ArmEncoder::new_thumb2();
9171
9172 let ops = vec![
9173 ArmOp::I64Ne {
9174 rd: Reg::R0,
9175 rnlo: Reg::R0,
9176 rnhi: Reg::R1,
9177 rmlo: Reg::R2,
9178 rmhi: Reg::R3,
9179 },
9180 ArmOp::I64LtS {
9181 rd: Reg::R0,
9182 rnlo: Reg::R0,
9183 rnhi: Reg::R1,
9184 rmlo: Reg::R2,
9185 rmhi: Reg::R3,
9186 },
9187 ArmOp::I64LtU {
9188 rd: Reg::R0,
9189 rnlo: Reg::R0,
9190 rnhi: Reg::R1,
9191 rmlo: Reg::R2,
9192 rmhi: Reg::R3,
9193 },
9194 ArmOp::I64LeS {
9195 rd: Reg::R0,
9196 rnlo: Reg::R0,
9197 rnhi: Reg::R1,
9198 rmlo: Reg::R2,
9199 rmhi: Reg::R3,
9200 },
9201 ArmOp::I64LeU {
9202 rd: Reg::R0,
9203 rnlo: Reg::R0,
9204 rnhi: Reg::R1,
9205 rmlo: Reg::R2,
9206 rmhi: Reg::R3,
9207 },
9208 ArmOp::I64GtS {
9209 rd: Reg::R0,
9210 rnlo: Reg::R0,
9211 rnhi: Reg::R1,
9212 rmlo: Reg::R2,
9213 rmhi: Reg::R3,
9214 },
9215 ArmOp::I64GtU {
9216 rd: Reg::R0,
9217 rnlo: Reg::R0,
9218 rnhi: Reg::R1,
9219 rmlo: Reg::R2,
9220 rmhi: Reg::R3,
9221 },
9222 ArmOp::I64GeS {
9223 rd: Reg::R0,
9224 rnlo: Reg::R0,
9225 rnhi: Reg::R1,
9226 rmlo: Reg::R2,
9227 rmhi: Reg::R3,
9228 },
9229 ArmOp::I64GeU {
9230 rd: Reg::R0,
9231 rnlo: Reg::R0,
9232 rnhi: Reg::R1,
9233 rmlo: Reg::R2,
9234 rmhi: Reg::R3,
9235 },
9236 ];
9237
9238 for op in &ops {
9239 let code = encoder.encode(op).unwrap();
9240 assert!(
9241 code.len() >= 8,
9242 "i64 comparison {:?} should emit at least 8 bytes, got {}",
9243 op,
9244 code.len()
9245 );
9246 }
9247 }
9248
9249 #[test]
9250 fn test_encode_i64_const_zero_thumb2() {
9251 let encoder = ArmEncoder::new_thumb2();
9252 let op = ArmOp::I64Const {
9253 rdlo: Reg::R0,
9254 rdhi: Reg::R1,
9255 value: 0,
9256 };
9257 let code = encoder.encode(&op).unwrap();
9258 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
9260 }
9261
9262 #[test]
9263 fn test_encode_i64_const_negative_one_thumb2() {
9264 let encoder = ArmEncoder::new_thumb2();
9265 let op = ArmOp::I64Const {
9266 rdlo: Reg::R0,
9267 rdhi: Reg::R1,
9268 value: -1, };
9270 let code = encoder.encode(&op).unwrap();
9271 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
9273 }
9274
9275 #[test]
9280 fn test_encode_ldrb_arm32() {
9281 let encoder = ArmEncoder::new_arm32();
9282 let op = ArmOp::Ldrb {
9283 rd: Reg::R0,
9284 addr: MemAddr::imm(Reg::R1, 4),
9285 };
9286 let code = encoder.encode(&op).unwrap();
9287 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
9288 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9290 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
9291 }
9292
9293 #[test]
9294 fn test_encode_strb_arm32() {
9295 let encoder = ArmEncoder::new_arm32();
9296 let op = ArmOp::Strb {
9297 rd: Reg::R0,
9298 addr: MemAddr::imm(Reg::R1, 0),
9299 };
9300 let code = encoder.encode(&op).unwrap();
9301 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
9302 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9304 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
9305 }
9306
9307 #[test]
9308 fn test_encode_ldrh_arm32() {
9309 let encoder = ArmEncoder::new_arm32();
9310 let op = ArmOp::Ldrh {
9311 rd: Reg::R0,
9312 addr: MemAddr::imm(Reg::R1, 2),
9313 };
9314 let code = encoder.encode(&op).unwrap();
9315 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
9316 }
9317
9318 #[test]
9319 fn test_encode_strh_arm32() {
9320 let encoder = ArmEncoder::new_arm32();
9321 let op = ArmOp::Strh {
9322 rd: Reg::R0,
9323 addr: MemAddr::imm(Reg::R1, 0),
9324 };
9325 let code = encoder.encode(&op).unwrap();
9326 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
9327 }
9328
9329 #[test]
9330 fn test_encode_ldrsb_arm32() {
9331 let encoder = ArmEncoder::new_arm32();
9332 let op = ArmOp::Ldrsb {
9333 rd: Reg::R0,
9334 addr: MemAddr::imm(Reg::R1, 0),
9335 };
9336 let code = encoder.encode(&op).unwrap();
9337 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
9338 }
9339
9340 #[test]
9341 fn test_encode_ldrsh_arm32() {
9342 let encoder = ArmEncoder::new_arm32();
9343 let op = ArmOp::Ldrsh {
9344 rd: Reg::R0,
9345 addr: MemAddr::imm(Reg::R1, 0),
9346 };
9347 let code = encoder.encode(&op).unwrap();
9348 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
9349 }
9350
9351 #[test]
9352 fn test_encode_ldrb_thumb2_16bit() {
9353 let encoder = ArmEncoder::new_thumb2();
9354 let op = ArmOp::Ldrb {
9355 rd: Reg::R0,
9356 addr: MemAddr::imm(Reg::R1, 4),
9357 };
9358 let code = encoder.encode(&op).unwrap();
9359 assert_eq!(
9361 code.len(),
9362 2,
9363 "Thumb-2 LDRB with small offset should be 16-bit"
9364 );
9365 }
9366
9367 #[test]
9368 fn test_encode_ldrb_thumb2_32bit() {
9369 let encoder = ArmEncoder::new_thumb2();
9370 let op = ArmOp::Ldrb {
9371 rd: Reg::R0,
9372 addr: MemAddr::imm(Reg::R1, 100), };
9374 let code = encoder.encode(&op).unwrap();
9375 assert_eq!(
9376 code.len(),
9377 4,
9378 "Thumb-2 LDRB with large offset should be 32-bit"
9379 );
9380 }
9381
9382 #[test]
9383 fn test_encode_strb_thumb2_16bit() {
9384 let encoder = ArmEncoder::new_thumb2();
9385 let op = ArmOp::Strb {
9386 rd: Reg::R0,
9387 addr: MemAddr::imm(Reg::R1, 10),
9388 };
9389 let code = encoder.encode(&op).unwrap();
9390 assert_eq!(
9391 code.len(),
9392 2,
9393 "Thumb-2 STRB with small offset should be 16-bit"
9394 );
9395 }
9396
9397 #[test]
9398 fn test_encode_ldrh_thumb2_16bit() {
9399 let encoder = ArmEncoder::new_thumb2();
9400 let op = ArmOp::Ldrh {
9401 rd: Reg::R0,
9402 addr: MemAddr::imm(Reg::R1, 4), };
9404 let code = encoder.encode(&op).unwrap();
9405 assert_eq!(
9406 code.len(),
9407 2,
9408 "Thumb-2 LDRH with small aligned offset should be 16-bit"
9409 );
9410 }
9411
9412 #[test]
9413 fn test_encode_strh_thumb2_16bit() {
9414 let encoder = ArmEncoder::new_thumb2();
9415 let op = ArmOp::Strh {
9416 rd: Reg::R0,
9417 addr: MemAddr::imm(Reg::R1, 4),
9418 };
9419 let code = encoder.encode(&op).unwrap();
9420 assert_eq!(
9421 code.len(),
9422 2,
9423 "Thumb-2 STRH with small aligned offset should be 16-bit"
9424 );
9425 }
9426
9427 #[test]
9428 fn test_encode_ldrsb_thumb2() {
9429 let encoder = ArmEncoder::new_thumb2();
9430 let op = ArmOp::Ldrsb {
9431 rd: Reg::R0,
9432 addr: MemAddr::imm(Reg::R1, 0),
9433 };
9434 let code = encoder.encode(&op).unwrap();
9435 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
9437 }
9438
9439 #[test]
9440 fn test_encode_ldrsh_thumb2() {
9441 let encoder = ArmEncoder::new_thumb2();
9442 let op = ArmOp::Ldrsh {
9443 rd: Reg::R0,
9444 addr: MemAddr::imm(Reg::R1, 0),
9445 };
9446 let code = encoder.encode(&op).unwrap();
9447 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
9448 }
9449
9450 #[test]
9451 fn test_encode_memory_size_thumb2() {
9452 let encoder = ArmEncoder::new_thumb2();
9453 let op = ArmOp::MemorySize { rd: Reg::R0 };
9454 let code = encoder.encode(&op).unwrap();
9455 assert!(!code.is_empty(), "MemorySize should produce code");
9457 }
9458
9459 #[test]
9460 fn test_encode_memory_grow_thumb2() {
9461 let encoder = ArmEncoder::new_thumb2();
9462 let op = ArmOp::MemoryGrow {
9463 rd: Reg::R0,
9464 rn: Reg::R0,
9465 };
9466 let code = encoder.encode(&op).unwrap();
9467 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
9468 }
9469
9470 #[test]
9471 fn test_encode_subword_reg_offset_thumb2() {
9472 let encoder = ArmEncoder::new_thumb2();
9473
9474 let op = ArmOp::Ldrb {
9476 rd: Reg::R0,
9477 addr: MemAddr::reg(Reg::R1, Reg::R2),
9478 };
9479 let code = encoder.encode(&op).unwrap();
9480 assert_eq!(
9481 code.len(),
9482 4,
9483 "Thumb-2 LDRB with reg offset should be 32-bit"
9484 );
9485
9486 let op = ArmOp::Strb {
9488 rd: Reg::R0,
9489 addr: MemAddr::reg(Reg::R1, Reg::R2),
9490 };
9491 let code = encoder.encode(&op).unwrap();
9492 assert_eq!(
9493 code.len(),
9494 4,
9495 "Thumb-2 STRB with reg offset should be 32-bit"
9496 );
9497
9498 let op = ArmOp::Ldrh {
9500 rd: Reg::R0,
9501 addr: MemAddr::reg(Reg::R1, Reg::R2),
9502 };
9503 let code = encoder.encode(&op).unwrap();
9504 assert_eq!(
9505 code.len(),
9506 4,
9507 "Thumb-2 LDRH with reg offset should be 32-bit"
9508 );
9509
9510 let op = ArmOp::Strh {
9512 rd: Reg::R0,
9513 addr: MemAddr::reg(Reg::R1, Reg::R2),
9514 };
9515 let code = encoder.encode(&op).unwrap();
9516 assert_eq!(
9517 code.len(),
9518 4,
9519 "Thumb-2 STRH with reg offset should be 32-bit"
9520 );
9521 }
9522
9523 #[test]
9524 fn test_encode_subword_reg_imm_offset_thumb2() {
9525 let encoder = ArmEncoder::new_thumb2();
9526
9527 let op = ArmOp::Ldrb {
9529 rd: Reg::R0,
9530 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
9531 };
9532 let code = encoder.encode(&op).unwrap();
9533 assert_eq!(
9535 code.len(),
9536 8,
9537 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
9538 );
9539 }
9540
9541 #[test]
9546 fn test_encode_mve_addi32_thumb2() {
9547 let encoder = ArmEncoder::new_thumb2();
9548 let op = ArmOp::MveAddI {
9549 qd: QReg::Q0,
9550 qn: QReg::Q1,
9551 qm: QReg::Q2,
9552 size: MveSize::S32,
9553 };
9554 let code = encoder.encode(&op).unwrap();
9555 assert_eq!(
9556 code.len(),
9557 4,
9558 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
9559 );
9560 }
9561
9562 #[test]
9563 fn test_encode_mve_subi16_thumb2() {
9564 let encoder = ArmEncoder::new_thumb2();
9565 let op = ArmOp::MveSubI {
9566 qd: QReg::Q0,
9567 qn: QReg::Q1,
9568 qm: QReg::Q2,
9569 size: MveSize::S16,
9570 };
9571 let code = encoder.encode(&op).unwrap();
9572 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
9573 }
9574
9575 #[test]
9576 fn test_encode_mve_muli8_thumb2() {
9577 let encoder = ArmEncoder::new_thumb2();
9578 let op = ArmOp::MveMulI {
9579 qd: QReg::Q0,
9580 qn: QReg::Q1,
9581 qm: QReg::Q2,
9582 size: MveSize::S8,
9583 };
9584 let code = encoder.encode(&op).unwrap();
9585 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
9586 }
9587
9588 #[test]
9589 fn test_encode_mve_bitwise_thumb2() {
9590 let encoder = ArmEncoder::new_thumb2();
9591
9592 let ops = vec![
9593 ArmOp::MveAnd {
9594 qd: QReg::Q0,
9595 qn: QReg::Q1,
9596 qm: QReg::Q2,
9597 },
9598 ArmOp::MveOrr {
9599 qd: QReg::Q0,
9600 qn: QReg::Q1,
9601 qm: QReg::Q2,
9602 },
9603 ArmOp::MveEor {
9604 qd: QReg::Q0,
9605 qn: QReg::Q1,
9606 qm: QReg::Q2,
9607 },
9608 ArmOp::MveBic {
9609 qd: QReg::Q0,
9610 qn: QReg::Q1,
9611 qm: QReg::Q2,
9612 },
9613 ];
9614 for op in ops {
9615 let code = encoder.encode(&op).unwrap();
9616 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
9617 }
9618 }
9619
9620 #[test]
9621 fn test_encode_mve_mvn_thumb2() {
9622 let encoder = ArmEncoder::new_thumb2();
9623 let op = ArmOp::MveMvn {
9624 qd: QReg::Q0,
9625 qm: QReg::Q1,
9626 };
9627 let code = encoder.encode(&op).unwrap();
9628 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
9629 }
9630
9631 #[test]
9632 fn test_encode_mve_load_store_thumb2() {
9633 let encoder = ArmEncoder::new_thumb2();
9634
9635 let load = ArmOp::MveLoad {
9636 qd: QReg::Q0,
9637 addr: MemAddr::imm(Reg::R0, 16),
9638 };
9639 let code = encoder.encode(&load).unwrap();
9640 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
9641
9642 let store = ArmOp::MveStore {
9643 qd: QReg::Q1,
9644 addr: MemAddr::imm(Reg::R1, 0),
9645 };
9646 let code = encoder.encode(&store).unwrap();
9647 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
9648 }
9649
9650 #[test]
9651 fn test_encode_mve_const_thumb2() {
9652 let encoder = ArmEncoder::new_thumb2();
9653 let op = ArmOp::MveConst {
9654 qd: QReg::Q0,
9655 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
9656 };
9657 let code = encoder.encode(&op).unwrap();
9658 assert!(
9661 code.len() >= 24,
9662 "MVE const should produce multiple instructions"
9663 );
9664 }
9665
9666 #[test]
9667 fn test_encode_mve_dup_thumb2() {
9668 let encoder = ArmEncoder::new_thumb2();
9669 let op = ArmOp::MveDup {
9670 qd: QReg::Q0,
9671 rn: Reg::R0,
9672 size: MveSize::S32,
9673 };
9674 let code = encoder.encode(&op).unwrap();
9675 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
9676 }
9677
9678 #[test]
9679 fn test_encode_mve_extract_lane_thumb2() {
9680 let encoder = ArmEncoder::new_thumb2();
9681 let op = ArmOp::MveExtractLane {
9682 rd: Reg::R0,
9683 qn: QReg::Q1,
9684 lane: 2,
9685 size: MveSize::S32,
9686 };
9687 let code = encoder.encode(&op).unwrap();
9688 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
9689 }
9690
9691 #[test]
9692 fn test_encode_mve_insert_lane_thumb2() {
9693 let encoder = ArmEncoder::new_thumb2();
9694 let op = ArmOp::MveInsertLane {
9695 qd: QReg::Q0,
9696 rn: Reg::R1,
9697 lane: 3,
9698 size: MveSize::S32,
9699 };
9700 let code = encoder.encode(&op).unwrap();
9701 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
9702 }
9703
9704 #[test]
9705 fn test_encode_mve_addf32_thumb2() {
9706 let encoder = ArmEncoder::new_thumb2();
9707 let op = ArmOp::MveAddF32 {
9708 qd: QReg::Q0,
9709 qn: QReg::Q1,
9710 qm: QReg::Q2,
9711 };
9712 let code = encoder.encode(&op).unwrap();
9713 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
9714 }
9715
9716 #[test]
9717 fn test_encode_mve_divf32_thumb2() {
9718 let encoder = ArmEncoder::new_thumb2();
9719 let op = ArmOp::MveDivF32 {
9720 qd: QReg::Q0,
9721 qn: QReg::Q1,
9722 qm: QReg::Q2,
9723 };
9724 let code = encoder.encode(&op).unwrap();
9725 assert_eq!(
9727 code.len(),
9728 16,
9729 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
9730 );
9731 }
9732
9733 #[test]
9734 fn test_encode_mve_sqrtf32_thumb2() {
9735 let encoder = ArmEncoder::new_thumb2();
9736 let op = ArmOp::MveSqrtF32 {
9737 qd: QReg::Q0,
9738 qm: QReg::Q1,
9739 };
9740 let code = encoder.encode(&op).unwrap();
9741 assert_eq!(
9743 code.len(),
9744 16,
9745 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
9746 );
9747 }
9748
9749 #[test]
9750 fn test_encode_mve_negf32_thumb2() {
9751 let encoder = ArmEncoder::new_thumb2();
9752 let op = ArmOp::MveNegF32 {
9753 qd: QReg::Q0,
9754 qm: QReg::Q1,
9755 };
9756 let code = encoder.encode(&op).unwrap();
9757 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
9758 }
9759
9760 #[test]
9761 fn test_encode_mve_absf32_thumb2() {
9762 let encoder = ArmEncoder::new_thumb2();
9763 let op = ArmOp::MveAbsF32 {
9764 qd: QReg::Q0,
9765 qm: QReg::Q1,
9766 };
9767 let code = encoder.encode(&op).unwrap();
9768 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
9769 }
9770
9771 #[test]
9786 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
9787 let encoder = ArmEncoder::new_thumb2();
9788 let op = ArmOp::And {
9789 rd: Reg::R2,
9790 rn: Reg::R0,
9791 op2: Operand2::Imm(0x7e),
9792 };
9793 let code = encoder.encode(&op).unwrap();
9794 assert_eq!(
9795 code,
9796 vec![0x00, 0xf0, 0x7e, 0x02],
9797 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
9798 );
9799 }
9800
9801 #[test]
9808 fn try_thumb_expand_imm_encodes_modified_immediates() {
9809 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
9811 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);
9819 assert_eq!(try_thumb_expand_imm(0x12345), None);
9820 }
9821
9822 #[test]
9827 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
9828 let encoder = ArmEncoder::new_thumb2();
9829 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
9831 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
9832 assert!(
9834 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
9835 "cmp #0x101 must error, not compare the wrong constant"
9836 );
9837 assert!(
9838 encoder
9839 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
9840 .is_err()
9841 );
9842 assert!(
9843 encoder
9844 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
9845 .is_err()
9846 );
9847 assert!(
9849 encoder
9850 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
9851 .is_ok()
9852 );
9853 }
9854
9855 #[test]
9858 fn mla_thumb2_encodes_correctly() {
9859 let encoder = ArmEncoder::new_thumb2();
9860 let code = encoder
9861 .encode(&ArmOp::Mla {
9862 rd: Reg::R2,
9863 rn: Reg::R3,
9864 rm: Reg::R4,
9865 ra: Reg::R8,
9866 })
9867 .unwrap();
9868 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
9870 }
9871
9872 #[test]
9877 fn ldst_imm12_offset_errors_when_out_of_range() {
9878 let encoder = ArmEncoder::new_thumb2();
9879 assert!(
9881 encoder
9882 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
9883 .is_ok()
9884 );
9885 assert!(
9887 encoder
9888 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
9889 .is_err(),
9890 "ldr offset 4096 must error, not wrap to 0"
9891 );
9892 assert!(
9893 encoder
9894 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
9895 .is_err()
9896 );
9897 assert!(
9898 encoder
9899 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
9900 .is_err()
9901 );
9902 assert!(
9903 encoder
9904 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
9905 .is_err()
9906 );
9907 }
9908
9909 #[test]
9916 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
9917 let encoder = ArmEncoder::new_thumb2();
9918 assert_eq!(
9920 encoder
9921 .encode(&ArmOp::Add {
9922 rd: Reg::SP,
9923 rn: Reg::SP,
9924 op2: Operand2::Imm(256),
9925 })
9926 .unwrap(),
9927 vec![0x0d, 0xf2, 0x00, 0x1d],
9928 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
9929 );
9930 assert_eq!(
9932 encoder
9933 .encode(&ArmOp::Sub {
9934 rd: Reg::SP,
9935 rn: Reg::SP,
9936 op2: Operand2::Imm(256),
9937 })
9938 .unwrap(),
9939 vec![0xad, 0xf2, 0x00, 0x1d],
9940 );
9941 assert!(
9943 encoder
9944 .encode(&ArmOp::Add {
9945 rd: Reg::SP,
9946 rn: Reg::SP,
9947 op2: Operand2::Imm(5000),
9948 })
9949 .is_err(),
9950 "add #5000 must error (no single ADDW), not mis-encode"
9951 );
9952 }
9953
9954 #[test]
9959 fn and_cmn_immediate_thumb_expand_else_error() {
9960 let encoder = ArmEncoder::new_thumb2();
9961 assert_eq!(
9963 encoder
9964 .encode(&ArmOp::And {
9965 rd: Reg::R2,
9966 rn: Reg::R0,
9967 op2: Operand2::Imm(0x7e),
9968 })
9969 .unwrap(),
9970 vec![0x00, 0xf0, 0x7e, 0x02],
9971 );
9972 assert!(
9974 encoder
9975 .encode(&ArmOp::And {
9976 rd: Reg::R2,
9977 rn: Reg::R0,
9978 op2: Operand2::Imm(0xff00ff00u32 as i32),
9979 })
9980 .is_ok()
9981 );
9982 assert!(
9984 encoder
9985 .encode(&ArmOp::And {
9986 rd: Reg::R2,
9987 rn: Reg::R0,
9988 op2: Operand2::Imm(0x101),
9989 })
9990 .is_err()
9991 );
9992 assert!(
9993 encoder
9994 .encode(&ArmOp::Cmn {
9995 rn: Reg::R0,
9996 op2: Operand2::Imm(0x101),
9997 })
9998 .is_err(),
9999 "CMN #0x101 must error, not emit a NOP"
10000 );
10001 }
10002
10003 #[test]
10007 fn orr_eor_immediate_encode_in_byte_range_else_error() {
10008 let encoder = ArmEncoder::new_thumb2();
10009 assert_eq!(
10011 encoder
10012 .encode(&ArmOp::Orr {
10013 rd: Reg::R2,
10014 rn: Reg::R0,
10015 op2: Operand2::Imm(0x7e),
10016 })
10017 .unwrap(),
10018 vec![0x40, 0xf0, 0x7e, 0x02],
10019 );
10020 assert_eq!(
10022 encoder
10023 .encode(&ArmOp::Eor {
10024 rd: Reg::R2,
10025 rn: Reg::R0,
10026 op2: Operand2::Imm(0x7e),
10027 })
10028 .unwrap(),
10029 vec![0x80, 0xf0, 0x7e, 0x02],
10030 );
10031 assert!(
10033 encoder
10034 .encode(&ArmOp::Orr {
10035 rd: Reg::R2,
10036 rn: Reg::R0,
10037 op2: Operand2::Imm(0x140),
10038 })
10039 .is_err(),
10040 "ORR #0x140 must error, not emit a NOP"
10041 );
10042 }
10043
10044 #[test]
10045 fn test_encode_mve_different_qregs() {
10046 let encoder = ArmEncoder::new_thumb2();
10047
10048 let op1 = ArmOp::MveAddI {
10050 qd: QReg::Q0,
10051 qn: QReg::Q0,
10052 qm: QReg::Q0,
10053 size: MveSize::S32,
10054 };
10055 let op2 = ArmOp::MveAddI {
10056 qd: QReg::Q3,
10057 qn: QReg::Q5,
10058 qm: QReg::Q7,
10059 size: MveSize::S32,
10060 };
10061 let code1 = encoder.encode(&op1).unwrap();
10062 let code2 = encoder.encode(&op2).unwrap();
10063 assert_ne!(
10064 code1, code2,
10065 "Different Q-registers should produce different encodings"
10066 );
10067 }
10068
10069 #[test]
10070 fn test_encode_mve_arm32_nop() {
10071 let encoder = ArmEncoder::new_arm32();
10073 let op = ArmOp::MveAddI {
10074 qd: QReg::Q0,
10075 qn: QReg::Q1,
10076 qm: QReg::Q2,
10077 size: MveSize::S32,
10078 };
10079 let code = encoder.encode(&op).unwrap();
10080 assert_eq!(code.len(), 4, "ARM32 MVE should be 4 bytes (NOP)");
10081 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10083 assert_eq!(instr, 0xE1A00000, "ARM32 MVE should encode as NOP");
10084 }
10085}