1use synth_core::Result;
6use synth_core::target::FPUPrecision;
7use synth_synthesis::contracts::encoding as encoding_contracts;
8use synth_synthesis::{ArmOp, MemAddr, MveSize, Operand2, QReg, Reg, VfpReg};
9
10pub struct ArmEncoder {
12 thumb_mode: bool,
14 #[allow(dead_code)]
16 fpu: Option<FPUPrecision>,
17}
18
19impl ArmEncoder {
20 pub fn new_arm32() -> Self {
22 Self {
23 thumb_mode: false,
24 fpu: None,
25 }
26 }
27
28 pub fn new_thumb2() -> Self {
30 Self {
31 thumb_mode: true,
32 fpu: None,
33 }
34 }
35
36 pub fn new_thumb2_with_fpu(fpu: Option<FPUPrecision>) -> Self {
38 Self {
39 thumb_mode: true,
40 fpu,
41 }
42 }
43
44 pub fn encode(&self, op: &ArmOp) -> Result<Vec<u8>> {
46 if self.thumb_mode {
47 self.encode_thumb(op)
48 } else {
49 self.encode_arm(op)
50 }
51 }
52
53 fn encode_arm_reg_offset_mem(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
61 use synth_synthesis::Reg;
62 let addr = match op {
63 ArmOp::Ldr { addr, .. }
64 | ArmOp::Str { addr, .. }
65 | ArmOp::Ldrb { addr, .. }
66 | ArmOp::Strb { addr, .. }
67 | ArmOp::Ldrh { addr, .. }
68 | ArmOp::Strh { addr, .. }
69 | ArmOp::Ldrsb { addr, .. }
70 | ArmOp::Ldrsh { addr, .. } => addr,
71 _ => return Ok(None),
72 };
73 let Some(rm) = addr.offset_reg else {
74 return Ok(None);
75 };
76 let ip = Reg::R12;
77 let add: u32 = 0xE0800000
79 | (reg_to_bits(&addr.base) << 16)
80 | (reg_to_bits(&ip) << 12)
81 | reg_to_bits(&rm);
82 let mut bytes = add.to_le_bytes().to_vec();
83 let imm_addr = MemAddr::imm(ip, addr.offset);
86 let imm_op = match op {
87 ArmOp::Ldr { rd, .. } => ArmOp::Ldr {
88 rd: *rd,
89 addr: imm_addr,
90 },
91 ArmOp::Str { rd, .. } => ArmOp::Str {
92 rd: *rd,
93 addr: imm_addr,
94 },
95 ArmOp::Ldrb { rd, .. } => ArmOp::Ldrb {
96 rd: *rd,
97 addr: imm_addr,
98 },
99 ArmOp::Strb { rd, .. } => ArmOp::Strb {
100 rd: *rd,
101 addr: imm_addr,
102 },
103 ArmOp::Ldrh { rd, .. } => ArmOp::Ldrh {
104 rd: *rd,
105 addr: imm_addr,
106 },
107 ArmOp::Strh { rd, .. } => ArmOp::Strh {
108 rd: *rd,
109 addr: imm_addr,
110 },
111 ArmOp::Ldrsb { rd, .. } => ArmOp::Ldrsb {
112 rd: *rd,
113 addr: imm_addr,
114 },
115 ArmOp::Ldrsh { rd, .. } => ArmOp::Ldrsh {
116 rd: *rd,
117 addr: imm_addr,
118 },
119 _ => unreachable!(),
120 };
121 bytes.extend(self.encode_arm(&imm_op)?);
122 Ok(Some(bytes))
123 }
124
125 fn encode_arm_call_indirect(table_index_reg: &Reg) -> Vec<u8> {
138 let idx = reg_to_bits(table_index_reg);
139 let mut bytes = Vec::with_capacity(12);
140 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
143 bytes.extend_from_slice(&mov.to_le_bytes());
144 let ldr: u32 = 0xE79BC00C;
146 bytes.extend_from_slice(&ldr.to_le_bytes());
147 let blx: u32 = 0xE12FFF3C;
149 bytes.extend_from_slice(&blx.to_le_bytes());
150 bytes
151 }
152
153 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
154 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
161 return Ok(bytes);
162 }
163 if let ArmOp::CallIndirect {
169 table_index_reg, ..
170 } = op
171 {
172 return Ok(Self::encode_arm_call_indirect(table_index_reg));
173 }
174 let instr: u32 = match op {
175 ArmOp::Add { rd, rn, op2 } => {
177 let rd_bits = reg_to_bits(rd);
178 let rn_bits = reg_to_bits(rn);
179 let (op2_bits, i_flag) = encode_operand2(op2)?;
180
181 0xE0800000 | (i_flag << 25)
184 | (rn_bits << 16)
185 | (rd_bits << 12)
186 | op2_bits
187 }
188
189 ArmOp::Sub { rd, rn, op2 } => {
190 let rd_bits = reg_to_bits(rd);
191 let rn_bits = reg_to_bits(rn);
192 let (op2_bits, i_flag) = encode_operand2(op2)?;
193
194 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
196 }
197
198 ArmOp::Adds { rd, rn, op2 } => {
200 let rd_bits = reg_to_bits(rd);
201 let rn_bits = reg_to_bits(rn);
202 let (op2_bits, i_flag) = encode_operand2(op2)?;
203
204 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
206 }
207
208 ArmOp::Adc { rd, rn, op2 } => {
209 let rd_bits = reg_to_bits(rd);
210 let rn_bits = reg_to_bits(rn);
211 let (op2_bits, i_flag) = encode_operand2(op2)?;
212
213 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
215 }
216
217 ArmOp::Subs { rd, rn, op2 } => {
218 let rd_bits = reg_to_bits(rd);
219 let rn_bits = reg_to_bits(rn);
220 let (op2_bits, i_flag) = encode_operand2(op2)?;
221
222 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
224 }
225
226 ArmOp::Sbc { rd, rn, op2 } => {
227 let rd_bits = reg_to_bits(rd);
228 let rn_bits = reg_to_bits(rn);
229 let (op2_bits, i_flag) = encode_operand2(op2)?;
230
231 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
233 }
234
235 ArmOp::Mul { rd, rn, rm } => {
236 let rd_bits = reg_to_bits(rd);
237 let rn_bits = reg_to_bits(rn);
238 let rm_bits = reg_to_bits(rm);
239
240 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
242 }
243
244 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
245 let rdlo_bits = reg_to_bits(rdlo);
246 let rdhi_bits = reg_to_bits(rdhi);
247 let rn_bits = reg_to_bits(rn);
248 let rm_bits = reg_to_bits(rm);
249
250 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
252 }
253
254 ArmOp::Sdiv { rd, rn, rm } => {
255 let rd_bits = reg_to_bits(rd);
256 let rn_bits = reg_to_bits(rn);
257 let rm_bits = reg_to_bits(rm);
258
259 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
262 }
263
264 ArmOp::Udiv { rd, rn, rm } => {
265 let rd_bits = reg_to_bits(rd);
266 let rn_bits = reg_to_bits(rn);
267 let rm_bits = reg_to_bits(rm);
268
269 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
272 }
273
274 ArmOp::Mls { rd, rn, rm, ra } => {
275 let rd_bits = reg_to_bits(rd);
276 let rn_bits = reg_to_bits(rn);
277 let rm_bits = reg_to_bits(rm);
278 let ra_bits = reg_to_bits(ra);
279
280 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
283 }
284
285 ArmOp::Mla { rd, rn, rm, ra } => {
286 let rd_bits = reg_to_bits(rd);
287 let rn_bits = reg_to_bits(rn);
288 let rm_bits = reg_to_bits(rm);
289 let ra_bits = reg_to_bits(ra);
290
291 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
294 }
295
296 ArmOp::And { rd, rn, op2 } => {
297 let rd_bits = reg_to_bits(rd);
298 let rn_bits = reg_to_bits(rn);
299 let (op2_bits, i_flag) = encode_operand2(op2)?;
300
301 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
303 }
304
305 ArmOp::Orr { rd, rn, op2 } => {
306 let rd_bits = reg_to_bits(rd);
307 let rn_bits = reg_to_bits(rn);
308 let (op2_bits, i_flag) = encode_operand2(op2)?;
309
310 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
312 }
313
314 ArmOp::Eor { rd, rn, op2 } => {
315 let rd_bits = reg_to_bits(rd);
316 let rn_bits = reg_to_bits(rn);
317 let (op2_bits, i_flag) = encode_operand2(op2)?;
318
319 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
321 }
322
323 ArmOp::Lsl { rd, rn, shift } => {
325 let rd_bits = reg_to_bits(rd);
326 let rn_bits = reg_to_bits(rn);
327 let shift_bits = *shift & 0x1F;
328
329 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
331 }
332
333 ArmOp::Lsr { rd, rn, shift } => {
334 let rd_bits = reg_to_bits(rd);
335 let rn_bits = reg_to_bits(rn);
336 let shift_bits = *shift & 0x1F;
337
338 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
340 }
341
342 ArmOp::Asr { rd, rn, shift } => {
343 let rd_bits = reg_to_bits(rd);
344 let rn_bits = reg_to_bits(rn);
345 let shift_bits = *shift & 0x1F;
346
347 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
349 }
350
351 ArmOp::Ror { rd, rn, shift } => {
352 let rd_bits = reg_to_bits(rd);
353 let rn_bits = reg_to_bits(rn);
354 let shift_bits = *shift & 0x1F;
355
356 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
358 }
359
360 ArmOp::LslReg { rd, rn, rm } => {
363 let rd_bits = reg_to_bits(rd);
364 let rn_bits = reg_to_bits(rn);
365 let rm_bits = reg_to_bits(rm);
366 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
367 }
368 ArmOp::LsrReg { rd, rn, rm } => {
369 let rd_bits = reg_to_bits(rd);
370 let rn_bits = reg_to_bits(rn);
371 let rm_bits = reg_to_bits(rm);
372 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
373 }
374 ArmOp::AsrReg { rd, rn, rm } => {
375 let rd_bits = reg_to_bits(rd);
376 let rn_bits = reg_to_bits(rn);
377 let rm_bits = reg_to_bits(rm);
378 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
379 }
380 ArmOp::RorReg { rd, rn, rm } => {
381 let rd_bits = reg_to_bits(rd);
382 let rn_bits = reg_to_bits(rn);
383 let rm_bits = reg_to_bits(rm);
384 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
385 }
386
387 ArmOp::Rsb { rd, rn, imm } => {
389 let rd_bits = reg_to_bits(rd);
390 let rn_bits = reg_to_bits(rn);
391 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
394 }
395
396 ArmOp::Clz { rd, rm } => {
398 let rd_bits = reg_to_bits(rd);
399 let rm_bits = reg_to_bits(rm);
400
401 0xE16F0F10 | (rd_bits << 12) | rm_bits
404 }
405
406 ArmOp::Rbit { rd, rm } => {
407 let rd_bits = reg_to_bits(rd);
408 let rm_bits = reg_to_bits(rm);
409
410 0xE6FF0F30 | (rd_bits << 12) | rm_bits
413 }
414
415 ArmOp::Sxtb { rd, rm } => {
416 let rd_bits = reg_to_bits(rd);
417 let rm_bits = reg_to_bits(rm);
418
419 0xE6AF0070 | (rd_bits << 12) | rm_bits
422 }
423
424 ArmOp::Sxth { rd, rm } => {
425 let rd_bits = reg_to_bits(rd);
426 let rm_bits = reg_to_bits(rm);
427
428 0xE6BF0070 | (rd_bits << 12) | rm_bits
431 }
432
433 ArmOp::Uxtb { rd, rm } => {
434 let rd_bits = reg_to_bits(rd);
435 let rm_bits = reg_to_bits(rm);
436 0xE6EF0070 | (rd_bits << 12) | rm_bits
438 }
439
440 ArmOp::Uxth { rd, rm } => {
441 let rd_bits = reg_to_bits(rd);
442 let rm_bits = reg_to_bits(rm);
443 0xE6FF0070 | (rd_bits << 12) | rm_bits
445 }
446
447 ArmOp::Mov { rd, op2 } => {
449 let rd_bits = reg_to_bits(rd);
450 let (op2_bits, i_flag) = encode_operand2(op2)?;
451
452 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
454 }
455
456 ArmOp::Mvn { rd, op2 } => {
457 let rd_bits = reg_to_bits(rd);
458 let (op2_bits, i_flag) = encode_operand2(op2)?;
459
460 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
462 }
463
464 ArmOp::Movw { rd, imm16 } => {
467 let rd_bits = reg_to_bits(rd);
468 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
469 let imm12 = (*imm16 as u32) & 0xFFF;
470 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
471 }
472
473 ArmOp::Movt { rd, imm16 } => {
476 let rd_bits = reg_to_bits(rd);
477 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
478 let imm12 = (*imm16 as u32) & 0xFFF;
479 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
480 }
481
482 ArmOp::MovwSym { rd, addend, .. } => {
485 let rd_bits = reg_to_bits(rd);
486 let v = (*addend as u32) & 0xffff;
487 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
488 }
489 ArmOp::MovtSym { rd, addend, .. } => {
490 let rd_bits = reg_to_bits(rd);
491 let v = ((*addend as u32) >> 16) & 0xffff;
492 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
493 }
494
495 ArmOp::LdrSym { .. } => {
499 return Err(synth_core::Error::synthesis(
500 "LdrSym (literal-pool address load) is Thumb-2-only",
501 ));
502 }
503
504 ArmOp::Cmp { rn, op2 } => {
506 let rn_bits = reg_to_bits(rn);
507 let (op2_bits, i_flag) = encode_operand2(op2)?;
508
509 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
511 }
512
513 ArmOp::Cmn { rn, op2 } => {
515 let rn_bits = reg_to_bits(rn);
516 let (op2_bits, i_flag) = encode_operand2(op2)?;
517
518 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
520 }
521
522 ArmOp::Ldr { rd, addr } => {
524 let rd_bits = reg_to_bits(rd);
525 let (base_bits, offset_bits) = encode_mem_addr(addr);
526
527 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
530 }
531
532 ArmOp::Str { rd, addr } => {
533 let rd_bits = reg_to_bits(rd);
534 let (base_bits, offset_bits) = encode_mem_addr(addr);
535
536 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
538 }
539
540 ArmOp::Ldrb { rd, addr } => {
542 let rd_bits = reg_to_bits(rd);
543 let (base_bits, offset_bits) = encode_mem_addr(addr);
544 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
546 }
547
548 ArmOp::Ldrsb { rd, addr } => {
549 let rd_bits = reg_to_bits(rd);
550 let (base_bits, offset_bits) = encode_mem_addr(addr);
551 let offset_val = offset_bits & 0xFF;
554 let imm4h = (offset_val >> 4) & 0xF;
555 let imm4l = offset_val & 0xF;
556 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
557 }
558
559 ArmOp::Ldrh { rd, addr } => {
560 let rd_bits = reg_to_bits(rd);
561 let (base_bits, offset_bits) = encode_mem_addr(addr);
562 let offset_val = offset_bits & 0xFF;
564 let imm4h = (offset_val >> 4) & 0xF;
565 let imm4l = offset_val & 0xF;
566 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
567 }
568
569 ArmOp::Ldrsh { rd, addr } => {
570 let rd_bits = reg_to_bits(rd);
571 let (base_bits, offset_bits) = encode_mem_addr(addr);
572 let offset_val = offset_bits & 0xFF;
574 let imm4h = (offset_val >> 4) & 0xF;
575 let imm4l = offset_val & 0xF;
576 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
577 }
578
579 ArmOp::Strb { rd, addr } => {
581 let rd_bits = reg_to_bits(rd);
582 let (base_bits, offset_bits) = encode_mem_addr(addr);
583 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
585 }
586
587 ArmOp::Strh { rd, addr } => {
588 let rd_bits = reg_to_bits(rd);
589 let (base_bits, offset_bits) = encode_mem_addr(addr);
590 let offset_val = offset_bits & 0xFF;
592 let imm4h = (offset_val >> 4) & 0xF;
593 let imm4l = offset_val & 0xF;
594 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
595 }
596
597 ArmOp::MemorySize { rd } => {
599 let rd_bits = reg_to_bits(rd);
600 0xE1A00820 | (rd_bits << 12) | 0x0A }
605
606 ArmOp::MemoryGrow { rd, .. } => {
607 let rd_bits = reg_to_bits(rd);
608 0xE3E00000 | (rd_bits << 12) }
611
612 ArmOp::Label { .. } => {
614 return Ok(Vec::new());
615 }
616
617 ArmOp::B { label: _ } => {
619 0xEA000000
622 }
623
624 ArmOp::Bcc { cond, label: _ } => {
626 use synth_synthesis::Condition;
627 let cond_bits: u32 = match cond {
628 Condition::EQ => 0x0,
629 Condition::NE => 0x1,
630 Condition::HS => 0x2,
631 Condition::LO => 0x3,
632 Condition::HI => 0x8,
633 Condition::LS => 0x9,
634 Condition::GE => 0xA,
635 Condition::LT => 0xB,
636 Condition::GT => 0xC,
637 Condition::LE => 0xD,
638 };
639 (cond_bits << 28) | 0x0A000000
641 }
642
643 ArmOp::Bhs { label: _ } => {
645 0x2A000000 }
648
649 ArmOp::Blo { label: _ } => {
651 0x3A000000 }
654
655 ArmOp::BOffset { offset } => {
659 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
669 0xEA000000 | offset_bits
670 }
671
672 ArmOp::BCondOffset { cond, offset } => {
674 use synth_synthesis::Condition;
675 let cond_bits: u32 = match cond {
676 Condition::EQ => 0x0,
677 Condition::NE => 0x1,
678 Condition::HS => 0x2,
679 Condition::LO => 0x3,
680 Condition::HI => 0x8,
681 Condition::LS => 0x9,
682 Condition::GE => 0xA,
683 Condition::LT => 0xB,
684 Condition::GT => 0xC,
685 Condition::LE => 0xD,
686 };
687 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
691 (cond_bits << 28) | 0x0A000000 | offset_bits
692 }
693
694 ArmOp::Bl { label: _ } => {
695 0xEB000000
697 }
698
699 ArmOp::Bx { rm } => {
700 let rm_bits = reg_to_bits(rm);
701
702 0xE12FFF10 | rm_bits
704 }
705
706 ArmOp::Blx { rm } => {
707 let rm_bits = reg_to_bits(rm);
708
709 0xE12FFF30 | rm_bits
711 }
712
713 ArmOp::Push { regs } => {
714 let mut reg_list: u32 = 0;
716 for r in regs {
717 reg_list |= 1 << reg_to_bits(r);
718 }
719 0xE92D0000 | reg_list
720 }
721
722 ArmOp::Pop { regs } => {
723 let mut reg_list: u32 = 0;
725 for r in regs {
726 reg_list |= 1 << reg_to_bits(r);
727 }
728 0xE8BD0000 | reg_list
729 }
730
731 ArmOp::Nop => {
732 0xE1A00000
734 }
735
736 ArmOp::Udf { imm } => {
737 let imm8 = *imm as u32;
740 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
741 }
742
743 ArmOp::Popcnt { .. } => {
746 0xE1A00000 }
750
751 ArmOp::SetCond { .. } => {
752 0xE1A00000 }
756
757 ArmOp::SelectMove { .. } => {
758 0xE1A00000 }
762
763 ArmOp::Select { .. } => {
764 0xE1A00000 }
768
769 ArmOp::LocalGet { .. } => {
770 0xE1A00000 }
774
775 ArmOp::LocalSet { .. } => {
776 0xE1A00000 }
780
781 ArmOp::LocalTee { .. } => {
782 0xE1A00000 }
786
787 ArmOp::GlobalGet { .. } => {
788 0xE1A00000 }
792
793 ArmOp::GlobalSet { .. } => {
794 0xE1A00000 }
798
799 ArmOp::BrTable { .. } => {
800 0xE1A00000 }
804
805 ArmOp::Call { .. } => {
806 0xE1A00000 }
810
811 ArmOp::CallIndirect { .. } => {
815 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
816 }
817
818 ArmOp::I64Add { .. } => 0xE1A00000, ArmOp::I64Sub { .. } => 0xE1A00000, ArmOp::I64DivS { .. } => 0xE1A00000, ArmOp::I64DivU { .. } => 0xE1A00000, ArmOp::I64RemS { .. } => 0xE1A00000, ArmOp::I64RemU { .. } => 0xE1A00000, ArmOp::I64Clz { .. } => 0xE1A00000, ArmOp::I64Ctz { .. } => 0xE1A00000, ArmOp::I64Popcnt { .. } => 0xE1A00000, ArmOp::I64And { .. } => 0xE1A00000, ArmOp::I64Or { .. } => 0xE1A00000, ArmOp::I64Xor { .. } => 0xE1A00000, ArmOp::I64Eqz { .. } => 0xE1A00000, ArmOp::I64Eq { .. } => 0xE1A00000, ArmOp::I64Ne { .. } => 0xE1A00000, ArmOp::I64LtS { .. } => 0xE1A00000, ArmOp::I64LtU { .. } => 0xE1A00000, ArmOp::I64LeS { .. } => 0xE1A00000, ArmOp::I64LeU { .. } => 0xE1A00000, ArmOp::I64GtS { .. } => 0xE1A00000, ArmOp::I64GtU { .. } => 0xE1A00000, ArmOp::I64GeS { .. } => 0xE1A00000, ArmOp::I64GeU { .. } => 0xE1A00000, ArmOp::I64Const { .. } => 0xE1A00000, ArmOp::I64Ldr { .. } => 0xE1A00000, ArmOp::I64Str { .. } => 0xE1A00000, ArmOp::I64ExtendI32S { .. } => 0xE1A00000, ArmOp::I64ExtendI32U { .. } => 0xE1A00000, ArmOp::I64Extend8S { .. } => 0xE1A00000, ArmOp::I64Extend16S { .. } => 0xE1A00000, ArmOp::I64Extend32S { .. } => 0xE1A00000, ArmOp::I32WrapI64 { .. } => 0xE1A00000, ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
855 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
856 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
857 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
858 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
859 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
860 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
861
862 ArmOp::F32Ceil { sd, sm } => {
865 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
867 ArmOp::F32Floor { sd, sm } => {
868 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
870 ArmOp::F32Trunc { sd, sm } => {
871 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
873 ArmOp::F32Nearest { sd, sm } => {
874 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
876 ArmOp::F32Min { sd, sn, sm } => {
877 return self.encode_arm_f32_minmax(sd, sn, sm, true);
878 }
879 ArmOp::F32Max { sd, sn, sm } => {
880 return self.encode_arm_f32_minmax(sd, sn, sm, false);
881 }
882 ArmOp::F32Copysign { sd, sn, sm } => {
883 return self.encode_arm_f32_copysign(sd, sn, sm);
884 }
885
886 ArmOp::F32Eq { rd, sn, sm } => {
888 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
890 ArmOp::F32Ne { rd, sn, sm } => {
891 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
893 ArmOp::F32Lt { rd, sn, sm } => {
894 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
896 ArmOp::F32Le { rd, sn, sm } => {
897 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
899 ArmOp::F32Gt { rd, sn, sm } => {
900 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
902 ArmOp::F32Ge { rd, sn, sm } => {
903 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
905
906 ArmOp::F32Const { sd, value } => {
908 return self.encode_arm_f32_const(sd, *value);
909 }
910
911 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
912 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
913
914 ArmOp::F32ConvertI32S { sd, rm } => {
916 return self.encode_arm_f32_convert_i32(sd, rm, true);
917 }
918 ArmOp::F32ConvertI32U { sd, rm } => {
919 return self.encode_arm_f32_convert_i32(sd, rm, false);
920 }
921 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
922 return Err(synth_core::Error::synthesis(
923 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
924 ));
925 }
926 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
927 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
928 ArmOp::I32TruncF32S { rd, sm } => {
929 return self.encode_arm_i32_trunc_f32(rd, sm, true);
930 }
931 ArmOp::I32TruncF32U { rd, sm } => {
932 return self.encode_arm_i32_trunc_f32(rd, sm, false);
933 }
934
935 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
938 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
939 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
940 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
941 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
942 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
943 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
944
945 ArmOp::F64Ceil { dd, dm } => {
948 return self.encode_arm_f64_rounding(dd, dm, 0b01);
949 }
950 ArmOp::F64Floor { dd, dm } => {
951 return self.encode_arm_f64_rounding(dd, dm, 0b10);
952 }
953 ArmOp::F64Trunc { dd, dm } => {
954 return self.encode_arm_f64_rounding(dd, dm, 0b11);
955 }
956 ArmOp::F64Nearest { dd, dm } => {
957 return self.encode_arm_f64_rounding(dd, dm, 0b00);
958 }
959 ArmOp::F64Min { dd, dn, dm } => {
960 return self.encode_arm_f64_minmax(dd, dn, dm, true);
961 }
962 ArmOp::F64Max { dd, dn, dm } => {
963 return self.encode_arm_f64_minmax(dd, dn, dm, false);
964 }
965 ArmOp::F64Copysign { dd, dn, dm } => {
966 return self.encode_arm_f64_copysign(dd, dn, dm);
967 }
968
969 ArmOp::F64Eq { rd, dn, dm } => {
971 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
972 }
973 ArmOp::F64Ne { rd, dn, dm } => {
974 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
975 }
976 ArmOp::F64Lt { rd, dn, dm } => {
977 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
978 }
979 ArmOp::F64Le { rd, dn, dm } => {
980 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
981 }
982 ArmOp::F64Gt { rd, dn, dm } => {
983 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
984 }
985 ArmOp::F64Ge { rd, dn, dm } => {
986 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
987 }
988
989 ArmOp::F64Const { dd, value } => {
990 return self.encode_arm_f64_const(dd, *value);
991 }
992
993 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
994 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
995
996 ArmOp::F64ConvertI32S { dd, rm } => {
997 return self.encode_arm_f64_convert_i32(dd, rm, true);
998 }
999 ArmOp::F64ConvertI32U { dd, rm } => {
1000 return self.encode_arm_f64_convert_i32(dd, rm, false);
1001 }
1002 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1003 return Err(synth_core::Error::synthesis(
1004 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1005 ));
1006 }
1007 ArmOp::F64PromoteF32 { dd, sm } => {
1008 return self.encode_arm_f64_promote_f32(dd, sm);
1009 }
1010 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1011 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1012 }
1013 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1014 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1015 }
1016 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1017 return Err(synth_core::Error::synthesis(
1018 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
1019 ));
1020 }
1021 ArmOp::I32TruncF64S { rd, dm } => {
1022 return self.encode_arm_i32_trunc_f64(rd, dm, true);
1023 }
1024 ArmOp::I32TruncF64U { rd, dm } => {
1025 return self.encode_arm_i32_trunc_f64(rd, dm, false);
1026 }
1027 ArmOp::I64SetCond { .. }
1029 | ArmOp::I64SetCondZ { .. }
1030 | ArmOp::I64Mul { .. }
1031 | ArmOp::I64Shl { .. }
1032 | ArmOp::I64ShrS { .. }
1033 | ArmOp::I64ShrU { .. }
1034 | ArmOp::I64Rotl { .. }
1035 | ArmOp::I64Rotr { .. } => 0xE1A00000, ArmOp::MveLoad { .. }
1039 | ArmOp::MveStore { .. }
1040 | ArmOp::MveConst { .. }
1041 | ArmOp::MveAnd { .. }
1042 | ArmOp::MveOrr { .. }
1043 | ArmOp::MveEor { .. }
1044 | ArmOp::MveMvn { .. }
1045 | ArmOp::MveBic { .. }
1046 | ArmOp::MveAddI { .. }
1047 | ArmOp::MveSubI { .. }
1048 | ArmOp::MveMulI { .. }
1049 | ArmOp::MveNegI { .. }
1050 | ArmOp::MveCmpEqI { .. }
1051 | ArmOp::MveCmpNeI { .. }
1052 | ArmOp::MveCmpLtS { .. }
1053 | ArmOp::MveCmpLtU { .. }
1054 | ArmOp::MveCmpGtS { .. }
1055 | ArmOp::MveCmpGtU { .. }
1056 | ArmOp::MveCmpLeS { .. }
1057 | ArmOp::MveCmpLeU { .. }
1058 | ArmOp::MveCmpGeS { .. }
1059 | ArmOp::MveCmpGeU { .. }
1060 | ArmOp::MveDup { .. }
1061 | ArmOp::MveExtractLane { .. }
1062 | ArmOp::MveInsertLane { .. }
1063 | ArmOp::MveAddF32 { .. }
1064 | ArmOp::MveSubF32 { .. }
1065 | ArmOp::MveMulF32 { .. }
1066 | ArmOp::MveNegF32 { .. }
1067 | ArmOp::MveAbsF32 { .. }
1068 | ArmOp::MveCmpEqF32 { .. }
1069 | ArmOp::MveCmpNeF32 { .. }
1070 | ArmOp::MveCmpLtF32 { .. }
1071 | ArmOp::MveCmpLeF32 { .. }
1072 | ArmOp::MveCmpGtF32 { .. }
1073 | ArmOp::MveCmpGeF32 { .. }
1074 | ArmOp::MveDupF32 { .. }
1075 | ArmOp::MveExtractLaneF32 { .. }
1076 | ArmOp::MveReplaceLaneF32 { .. }
1077 | ArmOp::MveDivF32 { .. }
1078 | ArmOp::MveSqrtF32 { .. } => 0xE1A00000, };
1080
1081 Ok(instr.to_le_bytes().to_vec())
1083 }
1084
1085 fn encode_arm_f32_compare(
1089 &self,
1090 rd: &Reg,
1091 sn: &VfpReg,
1092 sm: &VfpReg,
1093 cond_code: u32,
1094 ) -> Result<Vec<u8>> {
1095 let mut bytes = Vec::new();
1096
1097 let sn_num = vfp_sreg_to_num(sn)?;
1099 let sm_num = vfp_sreg_to_num(sm)?;
1100 let (vd, d) = encode_sreg(sn_num);
1101 let (vm, m) = encode_sreg(sm_num);
1102 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1103 bytes.extend_from_slice(&vcmp.to_le_bytes());
1104
1105 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1107
1108 let rd_bits = reg_to_bits(rd);
1110 let mov_zero = 0xE3A00000 | (rd_bits << 12);
1111 bytes.extend_from_slice(&mov_zero.to_le_bytes());
1112
1113 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
1115 bytes.extend_from_slice(&mov_one.to_le_bytes());
1116
1117 Ok(bytes)
1118 }
1119
1120 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
1122 let mut bytes = Vec::new();
1123 let bits = value.to_bits();
1124
1125 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
1130 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
1131 bytes.extend_from_slice(&movw.to_le_bytes());
1132
1133 let hi16 = (bits >> 16) & 0xFFFF;
1135 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
1136 bytes.extend_from_slice(&movt.to_le_bytes());
1137
1138 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
1140 bytes.extend_from_slice(&vmov.to_le_bytes());
1141
1142 Ok(bytes)
1143 }
1144
1145 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
1147 let mut bytes = Vec::new();
1148
1149 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
1151 bytes.extend_from_slice(&vmov.to_le_bytes());
1152
1153 let sd_num = vfp_sreg_to_num(sd)?;
1156 let (vd, d) = encode_sreg(sd_num);
1157 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
1159 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
1160 bytes.extend_from_slice(&vcvt.to_le_bytes());
1161
1162 Ok(bytes)
1163 }
1164
1165 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
1177 let mut bytes = Vec::new();
1178 let sm_num = vfp_sreg_to_num(sm)?;
1179 let sd_num = vfp_sreg_to_num(sd)?;
1180 let (vd_s, d_s) = encode_sreg(sd_num);
1181 let (vm_s, m_s) = encode_sreg(sm_num);
1182
1183 if mode == 0b11 {
1184 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
1187 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1188 } else {
1189 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
1194 bytes.extend_from_slice(&vmrs.to_le_bytes());
1195
1196 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
1199 bytes.extend_from_slice(&bic.to_le_bytes());
1200
1201 if mode != 0 {
1203 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
1205 bytes.extend_from_slice(&orr.to_le_bytes());
1206 }
1207
1208 let vmsr = 0xEEE10A10 | (rt << 12);
1210 bytes.extend_from_slice(&vmsr.to_le_bytes());
1211
1212 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
1214 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1215
1216 bytes.extend_from_slice(&vmrs.to_le_bytes());
1218 bytes.extend_from_slice(&bic.to_le_bytes());
1219 bytes.extend_from_slice(&vmsr.to_le_bytes());
1220 }
1221
1222 let (vd2, d2) = encode_sreg(sd_num);
1224 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
1225 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
1226
1227 Ok(bytes)
1228 }
1229
1230 fn encode_arm_f32_minmax(
1232 &self,
1233 sd: &VfpReg,
1234 sn: &VfpReg,
1235 sm: &VfpReg,
1236 is_min: bool,
1237 ) -> Result<Vec<u8>> {
1238 let mut bytes = Vec::new();
1239 let sn_num = vfp_sreg_to_num(sn)?;
1240 let sm_num = vfp_sreg_to_num(sm)?;
1241 let sd_num = vfp_sreg_to_num(sd)?;
1242
1243 let (vd, d) = encode_sreg(sd_num);
1245 let (vn, n) = encode_sreg(sn_num);
1246 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
1247 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
1248
1249 let (vm, m) = encode_sreg(sm_num);
1251 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
1252 bytes.extend_from_slice(&vcmp.to_le_bytes());
1253
1254 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1256
1257 let cond = if is_min { 0xCu32 } else { 0x4u32 };
1260
1261 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1263 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
1264
1265 Ok(bytes)
1266 }
1267
1268 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
1270 let mut bytes = Vec::new();
1271
1272 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
1274 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
1275
1276 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
1278 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
1279
1280 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
1284 bytes.extend_from_slice(&and_sign.to_le_bytes());
1285
1286 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
1289 bytes.extend_from_slice(&bic_sign.to_le_bytes());
1290
1291 let orr = 0xE1800000u32 | 12;
1294 bytes.extend_from_slice(&orr.to_le_bytes());
1295
1296 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
1298 bytes.extend_from_slice(&vmov_result.to_le_bytes());
1299
1300 Ok(bytes)
1301 }
1302
1303 fn encode_arm_f64_compare(
1305 &self,
1306 rd: &Reg,
1307 dn: &VfpReg,
1308 dm: &VfpReg,
1309 cond_code: u32,
1310 ) -> Result<Vec<u8>> {
1311 let mut bytes = Vec::new();
1312
1313 let dn_num = vfp_dreg_to_num(dn)?;
1315 let dm_num = vfp_dreg_to_num(dm)?;
1316 let (vd, d) = encode_dreg(dn_num);
1317 let (vm, m) = encode_dreg(dm_num);
1318 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1319 bytes.extend_from_slice(&vcmp.to_le_bytes());
1320
1321 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1323
1324 let rd_bits = reg_to_bits(rd);
1326 let mov_zero = 0xE3A00000 | (rd_bits << 12);
1327 bytes.extend_from_slice(&mov_zero.to_le_bytes());
1328
1329 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
1331 bytes.extend_from_slice(&mov_one.to_le_bytes());
1332
1333 Ok(bytes)
1334 }
1335
1336 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
1338 let mut bytes = Vec::new();
1339 let bits = value.to_bits();
1340 let lo32 = bits as u32;
1341 let hi32 = (bits >> 32) as u32;
1342
1343 let lo16 = lo32 & 0xFFFF;
1345 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
1346 bytes.extend_from_slice(&movw_r0.to_le_bytes());
1347 let hi16 = (lo32 >> 16) & 0xFFFF;
1348 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
1349 bytes.extend_from_slice(&movt_r0.to_le_bytes());
1350
1351 let lo16 = hi32 & 0xFFFF;
1353 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
1354 bytes.extend_from_slice(&movw_r12.to_le_bytes());
1355 let hi16 = (hi32 >> 16) & 0xFFFF;
1356 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
1357 bytes.extend_from_slice(&movt_r12.to_le_bytes());
1358
1359 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
1361 bytes.extend_from_slice(&vmov.to_le_bytes());
1362
1363 Ok(bytes)
1364 }
1365
1366 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
1368 let mut bytes = Vec::new();
1369
1370 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
1372 bytes.extend_from_slice(&vmov.to_le_bytes());
1373
1374 let dd_num = vfp_dreg_to_num(dd)?;
1377 let (vd, d) = encode_dreg(dd_num);
1378 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
1379 let vcvt = base | (d << 22) | (vd << 12);
1381 bytes.extend_from_slice(&vcvt.to_le_bytes());
1382
1383 Ok(bytes)
1384 }
1385
1386 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
1388 let dd_num = vfp_dreg_to_num(dd)?;
1389 let sm_num = vfp_sreg_to_num(sm)?;
1390 let (vd, d) = encode_dreg(dd_num);
1391 let (vm, m) = encode_sreg(sm_num);
1392
1393 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
1395 Ok(vcvt.to_le_bytes().to_vec())
1396 }
1397
1398 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
1400 let mut bytes = Vec::new();
1401 let dm_num = vfp_dreg_to_num(dm)?;
1402 let (vm, m) = encode_dreg(dm_num);
1403
1404 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
1407 let vcvt = base | (m << 5) | vm;
1408 bytes.extend_from_slice(&vcvt.to_le_bytes());
1409
1410 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
1412 bytes.extend_from_slice(&vmov.to_le_bytes());
1413
1414 Ok(bytes)
1415 }
1416
1417 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
1425 let mut bytes = Vec::new();
1426 let dm_num = vfp_dreg_to_num(dm)?;
1427 let dd_num = vfp_dreg_to_num(dd)?;
1428 let (vm, m) = encode_dreg(dm_num);
1429 let (vd, d) = encode_dreg(dd_num);
1430
1431 if mode == 0b11 {
1432 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
1434 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1435 } else {
1436 let rt: u32 = 12;
1438
1439 let vmrs = 0xEEF10A10 | (rt << 12);
1441 bytes.extend_from_slice(&vmrs.to_le_bytes());
1442
1443 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
1445 bytes.extend_from_slice(&bic.to_le_bytes());
1446
1447 if mode != 0 {
1449 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
1450 bytes.extend_from_slice(&orr.to_le_bytes());
1451 }
1452
1453 let vmsr = 0xEEE10A10 | (rt << 12);
1455 bytes.extend_from_slice(&vmsr.to_le_bytes());
1456
1457 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
1459 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
1460
1461 bytes.extend_from_slice(&vmrs.to_le_bytes());
1463 bytes.extend_from_slice(&bic.to_le_bytes());
1464 bytes.extend_from_slice(&vmsr.to_le_bytes());
1465 }
1466
1467 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
1469 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
1470
1471 Ok(bytes)
1472 }
1473
1474 fn encode_arm_f64_minmax(
1476 &self,
1477 dd: &VfpReg,
1478 dn: &VfpReg,
1479 dm: &VfpReg,
1480 is_min: bool,
1481 ) -> Result<Vec<u8>> {
1482 let mut bytes = Vec::new();
1483 let dn_num = vfp_dreg_to_num(dn)?;
1484 let dm_num = vfp_dreg_to_num(dm)?;
1485 let dd_num = vfp_dreg_to_num(dd)?;
1486
1487 let (vd, d) = encode_dreg(dd_num);
1489 let (vn, n) = encode_dreg(dn_num);
1490 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
1491 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
1492
1493 let (vm, m) = encode_dreg(dm_num);
1495 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
1496 bytes.extend_from_slice(&vcmp.to_le_bytes());
1497
1498 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
1500
1501 let cond = if is_min { 0xCu32 } else { 0x4u32 };
1502 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
1503 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
1504
1505 Ok(bytes)
1506 }
1507
1508 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
1510 let mut bytes = Vec::new();
1511
1512 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
1514 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
1515
1516 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
1519 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
1520
1521 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
1523 bytes.extend_from_slice(&and_sign.to_le_bytes());
1524
1525 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
1527 bytes.extend_from_slice(&bic_sign.to_le_bytes());
1528
1529 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
1531 bytes.extend_from_slice(&orr.to_le_bytes());
1532
1533 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
1535 bytes.extend_from_slice(&vmov_result.to_le_bytes());
1536
1537 Ok(bytes)
1538 }
1539
1540 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
1542 let mut bytes = Vec::new();
1543
1544 let sm_num = vfp_sreg_to_num(sm)?;
1547 let (vd, d) = encode_sreg(sm_num);
1548 let (vm, m) = encode_sreg(sm_num);
1549 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
1550 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
1551 bytes.extend_from_slice(&vcvt.to_le_bytes());
1552
1553 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
1555 bytes.extend_from_slice(&vmov.to_le_bytes());
1556
1557 Ok(bytes)
1558 }
1559
1560 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
1562 match op {
1565 ArmOp::Add { rd, rn, op2 } => {
1567 let rd_bits = reg_to_bits(rd) as u16;
1568 let rn_bits = reg_to_bits(rn) as u16;
1569
1570 if let Operand2::Reg(rm) = op2 {
1571 let rm_bits = reg_to_bits(rm) as u16;
1572 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1580 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1582 Ok(instr.to_le_bytes().to_vec())
1583 } else {
1584 self.encode_thumb32_add_reg_raw(
1586 rd_bits as u32,
1587 rn_bits as u32,
1588 rm_bits as u32,
1589 )
1590 }
1591 } else if let Operand2::Imm(imm) = op2 {
1592 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
1593 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
1595 Ok(instr.to_le_bytes().to_vec())
1596 } else {
1597 self.encode_thumb32_add(rd, rn, *imm as u32)
1599 }
1600 } else {
1601 self.encode_thumb32_add(rd, rn, 0)
1603 }
1604 }
1605
1606 ArmOp::Sub { rd, rn, op2 } => {
1607 let rd_bits = reg_to_bits(rd) as u16;
1608 let rn_bits = reg_to_bits(rn) as u16;
1609
1610 if let Operand2::Reg(rm) = op2 {
1611 let rm_bits = reg_to_bits(rm) as u16;
1612 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1614 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1616 Ok(instr.to_le_bytes().to_vec())
1617 } else {
1618 self.encode_thumb32_sub_reg_raw(
1620 rd_bits as u32,
1621 rn_bits as u32,
1622 rm_bits as u32,
1623 )
1624 }
1625 } else if let Operand2::Imm(imm) = op2 {
1626 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
1627 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
1629 Ok(instr.to_le_bytes().to_vec())
1630 } else {
1631 self.encode_thumb32_sub(rd, rn, *imm as u32)
1632 }
1633 } else {
1634 self.encode_thumb32_sub(rd, rn, 0)
1635 }
1636 }
1637
1638 ArmOp::Mov { rd, op2 } => {
1639 let rd_bits = reg_to_bits(rd) as u16;
1640
1641 if let Operand2::Imm(imm) = op2 {
1642 if *imm <= 255 && rd_bits < 8 {
1643 let imm_bits = (*imm as u16) & 0xFF;
1645 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
1646 Ok(instr.to_le_bytes().to_vec())
1647 } else {
1648 self.encode_thumb32_movw(rd, *imm as u32)
1650 }
1651 } else if let Operand2::Reg(rm) = op2 {
1652 let rm_bits = reg_to_bits(rm) as u16;
1653 let d_bit = (rd_bits >> 3) & 1;
1656 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
1657 Ok(instr.to_le_bytes().to_vec())
1658 } else {
1659 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
1661 }
1662 }
1663
1664 ArmOp::Push { regs } => {
1665 let mut reg_list: u16 = 0;
1669 let mut need_32bit = false;
1670 for r in regs {
1671 let bit = reg_to_bits(r);
1672 if bit >= 8 && *r != Reg::LR {
1673 need_32bit = true;
1674 }
1675 reg_list |= 1 << bit;
1676 }
1677 if !need_32bit {
1678 let m_bit = if reg_list & (1 << 14) != 0 {
1680 1u16
1681 } else {
1682 0u16
1683 };
1684 let low_regs = reg_list & 0xFF;
1685 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
1686 Ok(instr.to_le_bytes().to_vec())
1687 } else {
1688 let hw1: u16 = 0xE92D;
1690 let hw2: u16 = reg_list;
1691 let mut bytes = hw1.to_le_bytes().to_vec();
1692 bytes.extend_from_slice(&hw2.to_le_bytes());
1693 Ok(bytes)
1694 }
1695 }
1696
1697 ArmOp::Pop { regs } => {
1698 let mut reg_list: u16 = 0;
1702 let mut need_32bit = false;
1703 for r in regs {
1704 let bit = reg_to_bits(r);
1705 if bit >= 8 && *r != Reg::PC {
1706 need_32bit = true;
1707 }
1708 reg_list |= 1 << bit;
1709 }
1710 if !need_32bit {
1711 let p_bit = if reg_list & (1 << 15) != 0 {
1713 1u16
1714 } else {
1715 0u16
1716 };
1717 let low_regs = reg_list & 0xFF;
1718 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
1719 Ok(instr.to_le_bytes().to_vec())
1720 } else {
1721 let hw1: u16 = 0xE8BD;
1723 let hw2: u16 = reg_list;
1724 let mut bytes = hw1.to_le_bytes().to_vec();
1725 bytes.extend_from_slice(&hw2.to_le_bytes());
1726 Ok(bytes)
1727 }
1728 }
1729
1730 ArmOp::Nop => {
1731 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
1733 }
1734
1735 ArmOp::Udf { imm } => {
1736 let instr: u16 = 0xDE00 | (*imm as u16);
1739 let bytes = instr.to_le_bytes().to_vec();
1740 encoding_contracts::verify_thumb16(&bytes);
1741 Ok(bytes)
1742 }
1743
1744 ArmOp::Adds { rd, rn, op2 } => {
1747 let rd_bits = reg_to_bits(rd) as u16;
1748 let rn_bits = reg_to_bits(rn) as u16;
1749
1750 if let Operand2::Reg(rm) = op2 {
1751 let rm_bits = reg_to_bits(rm) as u16;
1752 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1757 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1759 Ok(instr.to_le_bytes().to_vec())
1760 } else {
1761 self.encode_thumb32_adds_reg_raw(
1762 rd_bits as u32,
1763 rn_bits as u32,
1764 rm_bits as u32,
1765 )
1766 }
1767 } else {
1768 self.encode_thumb32_adds(rd, rn, 0)
1770 }
1771 }
1772
1773 ArmOp::Adc { rd, rn, op2 } => {
1776 let rd_bits = reg_to_bits(rd);
1777 let rn_bits = reg_to_bits(rn);
1778
1779 if let Operand2::Reg(rm) = op2 {
1780 let rm_bits = reg_to_bits(rm);
1781 let hw1: u16 = (0xEB40 | rn_bits) as u16;
1783 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1784
1785 let mut bytes = hw1.to_le_bytes().to_vec();
1786 bytes.extend_from_slice(&hw2.to_le_bytes());
1787 Ok(bytes)
1788 } else {
1789 let hw1: u16 = (0xF140 | rn_bits) as u16;
1791 let hw2: u16 = (rd_bits << 8) as u16;
1792 let mut bytes = hw1.to_le_bytes().to_vec();
1793 bytes.extend_from_slice(&hw2.to_le_bytes());
1794 Ok(bytes)
1795 }
1796 }
1797
1798 ArmOp::Subs { rd, rn, op2 } => {
1800 let rd_bits = reg_to_bits(rd) as u16;
1801 let rn_bits = reg_to_bits(rn) as u16;
1802
1803 if let Operand2::Reg(rm) = op2 {
1804 let rm_bits = reg_to_bits(rm) as u16;
1805 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
1809 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
1811 Ok(instr.to_le_bytes().to_vec())
1812 } else {
1813 self.encode_thumb32_subs_reg_raw(
1814 rd_bits as u32,
1815 rn_bits as u32,
1816 rm_bits as u32,
1817 )
1818 }
1819 } else {
1820 self.encode_thumb32_subs(rd, rn, 0)
1822 }
1823 }
1824
1825 ArmOp::Sbc { rd, rn, op2 } => {
1828 let rd_bits = reg_to_bits(rd);
1829 let rn_bits = reg_to_bits(rn);
1830
1831 if let Operand2::Reg(rm) = op2 {
1832 let rm_bits = reg_to_bits(rm);
1833 let hw1: u16 = (0xEB60 | rn_bits) as u16;
1835 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1836
1837 let mut bytes = hw1.to_le_bytes().to_vec();
1838 bytes.extend_from_slice(&hw2.to_le_bytes());
1839 Ok(bytes)
1840 } else {
1841 let hw1: u16 = (0xF160 | rn_bits) as u16;
1843 let hw2: u16 = (rd_bits << 8) as u16;
1844 let mut bytes = hw1.to_le_bytes().to_vec();
1845 bytes.extend_from_slice(&hw2.to_le_bytes());
1846 Ok(bytes)
1847 }
1848 }
1849
1850 ArmOp::Sdiv { rd, rn, rm } => {
1854 let rd_bits = reg_to_bits(rd);
1855 let rn_bits = reg_to_bits(rn);
1856 let rm_bits = reg_to_bits(rm);
1857 reg_bits_checked(rd_bits)?;
1858 reg_bits_checked(rn_bits)?;
1859 reg_bits_checked(rm_bits)?;
1860
1861 let hw1: u16 = (0xFB90 | rn_bits) as u16;
1865 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
1866
1867 let mut bytes = hw1.to_le_bytes().to_vec();
1869 bytes.extend_from_slice(&hw2.to_le_bytes());
1870 encoding_contracts::verify_thumb32(&bytes);
1871 Ok(bytes)
1872 }
1873
1874 ArmOp::Udiv { rd, rn, rm } => {
1876 let rd_bits = reg_to_bits(rd);
1877 let rn_bits = reg_to_bits(rn);
1878 let rm_bits = reg_to_bits(rm);
1879 reg_bits_checked(rd_bits)?;
1880 reg_bits_checked(rn_bits)?;
1881 reg_bits_checked(rm_bits)?;
1882
1883 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
1885 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
1886
1887 let mut bytes = hw1.to_le_bytes().to_vec();
1888 bytes.extend_from_slice(&hw2.to_le_bytes());
1889 encoding_contracts::verify_thumb32(&bytes);
1890 Ok(bytes)
1891 }
1892
1893 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1894 let rdlo_bits = reg_to_bits(rdlo);
1895 let rdhi_bits = reg_to_bits(rdhi);
1896 let rn_bits = reg_to_bits(rn);
1897 let rm_bits = reg_to_bits(rm);
1898 reg_bits_checked(rdlo_bits)?;
1899 reg_bits_checked(rdhi_bits)?;
1900 reg_bits_checked(rn_bits)?;
1901 reg_bits_checked(rm_bits)?;
1902
1903 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
1905 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
1906
1907 let mut bytes = hw1.to_le_bytes().to_vec();
1908 bytes.extend_from_slice(&hw2.to_le_bytes());
1909 encoding_contracts::verify_thumb32(&bytes);
1910 Ok(bytes)
1911 }
1912
1913 ArmOp::Mul { rd, rn, rm } => {
1915 let rd_bits = reg_to_bits(rd);
1916 let rn_bits = reg_to_bits(rn);
1917 let rm_bits = reg_to_bits(rm);
1918
1919 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1922 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
1923
1924 let mut bytes = hw1.to_le_bytes().to_vec();
1925 bytes.extend_from_slice(&hw2.to_le_bytes());
1926 Ok(bytes)
1927 }
1928
1929 ArmOp::Mls { rd, rn, rm, ra } => {
1931 let rd_bits = reg_to_bits(rd);
1932 let rn_bits = reg_to_bits(rn);
1933 let rm_bits = reg_to_bits(rm);
1934 let ra_bits = reg_to_bits(ra);
1935
1936 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1939 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
1940
1941 let mut bytes = hw1.to_le_bytes().to_vec();
1942 bytes.extend_from_slice(&hw2.to_le_bytes());
1943 Ok(bytes)
1944 }
1945
1946 ArmOp::Mla { rd, rn, rm, ra } => {
1947 let rd_bits = reg_to_bits(rd);
1948 let rn_bits = reg_to_bits(rn);
1949 let rm_bits = reg_to_bits(rm);
1950 let ra_bits = reg_to_bits(ra);
1951
1952 let hw1: u16 = (0xFB00 | rn_bits) as u16;
1955 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
1956
1957 let mut bytes = hw1.to_le_bytes().to_vec();
1958 bytes.extend_from_slice(&hw2.to_le_bytes());
1959 Ok(bytes)
1960 }
1961
1962 ArmOp::And { rd, rn, op2 } => {
1964 if let Operand2::Reg(rm) = op2 {
1965 let rd_bits = reg_to_bits(rd);
1966 let rn_bits = reg_to_bits(rn);
1967 let rm_bits = reg_to_bits(rm);
1968
1969 let hw1: u16 = (0xEA00 | rn_bits) as u16;
1971 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
1972
1973 let mut bytes = hw1.to_le_bytes().to_vec();
1974 bytes.extend_from_slice(&hw2.to_le_bytes());
1975 Ok(bytes)
1976 } else if let Operand2::Imm(imm) = op2 {
1977 let rd_bits = reg_to_bits(rd);
1978 let rn_bits = reg_to_bits(rn);
1979
1980 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
1987 synth_core::Error::synthesis(
1988 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
1989 )
1990 })?;
1991 let i_bit = (field >> 11) & 1;
1992 let imm3 = (field >> 8) & 0x7;
1993 let imm8 = field & 0xFF;
1994
1995 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
1996 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
1997
1998 let mut bytes = hw1.to_le_bytes().to_vec();
1999 bytes.extend_from_slice(&hw2.to_le_bytes());
2000 Ok(bytes)
2001 } else {
2002 let instr: u16 = 0xBF00;
2004 Ok(instr.to_le_bytes().to_vec())
2005 }
2006 }
2007
2008 ArmOp::Orr { rd, rn, op2 } => {
2010 if let Operand2::Reg(rm) = op2 {
2011 let rd_bits = reg_to_bits(rd);
2012 let rn_bits = reg_to_bits(rn);
2013 let rm_bits = reg_to_bits(rm);
2014
2015 let hw1: u16 = (0xEA40 | rn_bits) as u16;
2017 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2018
2019 let mut bytes = hw1.to_le_bytes().to_vec();
2020 bytes.extend_from_slice(&hw2.to_le_bytes());
2021 Ok(bytes)
2022 } else if let Operand2::Imm(imm) = op2 {
2023 let imm_val = *imm as u32;
2028 if imm_val > 0xFF {
2029 return Err(synth_core::Error::synthesis(
2030 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2031 ));
2032 }
2033 let rd_bits = reg_to_bits(rd);
2034 let rn_bits = reg_to_bits(rn);
2035 let hw1: u16 = (0xF040 | rn_bits) as u16;
2036 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2037 let mut bytes = hw1.to_le_bytes().to_vec();
2038 bytes.extend_from_slice(&hw2.to_le_bytes());
2039 Ok(bytes)
2040 } else {
2041 let instr: u16 = 0xBF00;
2042 Ok(instr.to_le_bytes().to_vec())
2043 }
2044 }
2045
2046 ArmOp::Eor { rd, rn, op2 } => {
2048 if let Operand2::Reg(rm) = op2 {
2049 let rd_bits = reg_to_bits(rd);
2050 let rn_bits = reg_to_bits(rn);
2051 let rm_bits = reg_to_bits(rm);
2052
2053 let hw1: u16 = (0xEA80 | rn_bits) as u16;
2055 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2056
2057 let mut bytes = hw1.to_le_bytes().to_vec();
2058 bytes.extend_from_slice(&hw2.to_le_bytes());
2059 Ok(bytes)
2060 } else if let Operand2::Imm(imm) = op2 {
2061 let imm_val = *imm as u32;
2065 if imm_val > 0xFF {
2066 return Err(synth_core::Error::synthesis(
2067 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
2068 ));
2069 }
2070 let rd_bits = reg_to_bits(rd);
2071 let rn_bits = reg_to_bits(rn);
2072 let hw1: u16 = (0xF080 | rn_bits) as u16;
2073 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
2074 let mut bytes = hw1.to_le_bytes().to_vec();
2075 bytes.extend_from_slice(&hw2.to_le_bytes());
2076 Ok(bytes)
2077 } else {
2078 let instr: u16 = 0xBF00;
2079 Ok(instr.to_le_bytes().to_vec())
2080 }
2081 }
2082
2083 ArmOp::Lsl { rd, rn, shift } => {
2085 let rd_bits = reg_to_bits(rd) as u16;
2086 let rn_bits = reg_to_bits(rn) as u16;
2087 let shift_bits = (*shift as u16) & 0x1F;
2088
2089 if rd_bits < 8 && rn_bits < 8 {
2090 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2092 Ok(instr.to_le_bytes().to_vec())
2093 } else {
2094 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
2097 }
2098
2099 ArmOp::Lsr { rd, rn, shift } => {
2100 let rd_bits = reg_to_bits(rd) as u16;
2101 let rn_bits = reg_to_bits(rn) as u16;
2102 let shift_bits = (*shift as u16) & 0x1F;
2103
2104 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
2105 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2107 Ok(instr.to_le_bytes().to_vec())
2108 } else {
2109 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
2111 }
2112
2113 ArmOp::Asr { rd, rn, shift } => {
2114 let rd_bits = reg_to_bits(rd) as u16;
2115 let rn_bits = reg_to_bits(rn) as u16;
2116 let shift_bits = (*shift as u16) & 0x1F;
2117
2118 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
2119 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
2121 Ok(instr.to_le_bytes().to_vec())
2122 } else {
2123 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
2125 }
2126
2127 ArmOp::Ror { rd, rn, shift } => {
2128 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
2131
2132 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
2136 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
2137 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
2138 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
2139
2140 ArmOp::Rsb { rd, rn, imm } => {
2143 let rd_bits = reg_to_bits(rd);
2144 let rn_bits = reg_to_bits(rn);
2145 let imm_val = *imm;
2146
2147 let i_bit = (imm_val >> 11) & 1;
2148 let imm3 = (imm_val >> 8) & 0x7;
2149 let imm8 = imm_val & 0xFF;
2150
2151 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
2153 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
2155
2156 let mut bytes = hw1.to_le_bytes().to_vec();
2157 bytes.extend_from_slice(&hw2.to_le_bytes());
2158 Ok(bytes)
2159 }
2160
2161 ArmOp::Clz { rd, rm } => {
2163 let rd_bits = reg_to_bits(rd);
2164 let rm_bits = reg_to_bits(rm);
2165
2166 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
2169 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
2170
2171 let mut bytes = hw1.to_le_bytes().to_vec();
2172 bytes.extend_from_slice(&hw2.to_le_bytes());
2173 Ok(bytes)
2174 }
2175
2176 ArmOp::Rbit { rd, rm } => {
2178 let rd_bits = reg_to_bits(rd);
2179 let rm_bits = reg_to_bits(rm);
2180
2181 let hw1: u16 = (0xFA90 | rm_bits) as u16;
2184 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
2185
2186 let mut bytes = hw1.to_le_bytes().to_vec();
2187 bytes.extend_from_slice(&hw2.to_le_bytes());
2188 Ok(bytes)
2189 }
2190
2191 ArmOp::Sxtb { rd, rm } => {
2193 let rd_bits = reg_to_bits(rd) as u16;
2194 let rm_bits = reg_to_bits(rm) as u16;
2195
2196 if rd_bits < 8 && rm_bits < 8 {
2197 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
2199 Ok(instr.to_le_bytes().to_vec())
2200 } else {
2201 let rd_bits32 = rd_bits as u32;
2204 let rm_bits32 = rm_bits as u32;
2205 let hw1: u16 = 0xFA4F;
2206 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
2207 let mut bytes = hw1.to_le_bytes().to_vec();
2208 bytes.extend_from_slice(&hw2.to_le_bytes());
2209 Ok(bytes)
2210 }
2211 }
2212
2213 ArmOp::Sxth { rd, rm } => {
2215 let rd_bits = reg_to_bits(rd) as u16;
2216 let rm_bits = reg_to_bits(rm) as u16;
2217
2218 if rd_bits < 8 && rm_bits < 8 {
2219 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
2221 Ok(instr.to_le_bytes().to_vec())
2222 } else {
2223 let rd_bits32 = rd_bits as u32;
2226 let rm_bits32 = rm_bits as u32;
2227 let hw1: u16 = 0xFA0F;
2228 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
2229 let mut bytes = hw1.to_le_bytes().to_vec();
2230 bytes.extend_from_slice(&hw2.to_le_bytes());
2231 Ok(bytes)
2232 }
2233 }
2234
2235 ArmOp::Uxtb { rd, rm } => {
2237 let rd_bits = reg_to_bits(rd) as u16;
2238 let rm_bits = reg_to_bits(rm) as u16;
2239 if rd_bits < 8 && rm_bits < 8 {
2240 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
2242 Ok(instr.to_le_bytes().to_vec())
2243 } else {
2244 let hw1: u16 = 0xFA5F;
2246 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
2247 let mut bytes = hw1.to_le_bytes().to_vec();
2248 bytes.extend_from_slice(&hw2.to_le_bytes());
2249 Ok(bytes)
2250 }
2251 }
2252
2253 ArmOp::Uxth { rd, rm } => {
2255 let rd_bits = reg_to_bits(rd) as u16;
2256 let rm_bits = reg_to_bits(rm) as u16;
2257 if rd_bits < 8 && rm_bits < 8 {
2258 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
2260 Ok(instr.to_le_bytes().to_vec())
2261 } else {
2262 let hw1: u16 = 0xFA1F;
2264 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
2265 let mut bytes = hw1.to_le_bytes().to_vec();
2266 bytes.extend_from_slice(&hw2.to_le_bytes());
2267 Ok(bytes)
2268 }
2269 }
2270
2271 ArmOp::Cmp { rn, op2 } => {
2273 let rn_bits = reg_to_bits(rn) as u16;
2274
2275 if let Operand2::Imm(imm) = op2 {
2276 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
2279 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
2281 Ok(instr.to_le_bytes().to_vec())
2282 } else {
2283 self.encode_thumb32_cmp_imm(rn, *imm as u32)
2284 }
2285 } else if let Operand2::Reg(rm) = op2 {
2286 let rm_bits = reg_to_bits(rm) as u16;
2287 if rn_bits < 8 && rm_bits < 8 {
2288 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
2290 Ok(instr.to_le_bytes().to_vec())
2291 } else {
2292 let n_bit = (rn_bits >> 3) & 1;
2294 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
2295 Ok(instr.to_le_bytes().to_vec())
2296 }
2297 } else {
2298 let instr: u16 = 0xBF00;
2299 Ok(instr.to_le_bytes().to_vec())
2300 }
2301 }
2302
2303 ArmOp::Cmn { rn, op2 } => {
2306 let rn_bits = reg_to_bits(rn) as u16;
2307
2308 if let Operand2::Imm(imm) = op2 {
2309 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2315 synth_core::Error::synthesis(
2316 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
2317 )
2318 })?;
2319 let i_bit = (field >> 11) & 1;
2320 let imm3 = (field >> 8) & 0x7;
2321 let imm8 = field & 0xFF;
2322 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
2323 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
2324 let mut bytes = hw1.to_le_bytes().to_vec();
2325 bytes.extend_from_slice(&hw2.to_le_bytes());
2326 Ok(bytes)
2327 } else if let Operand2::Reg(rm) = op2 {
2328 let rm_bits = reg_to_bits(rm) as u16;
2329 if rn_bits < 8 && rm_bits < 8 {
2335 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
2337 Ok(instr.to_le_bytes().to_vec())
2338 } else {
2339 let hw1: u16 = 0xEB10 | rn_bits;
2340 let hw2: u16 = 0x0F00 | rm_bits;
2341 let mut bytes = hw1.to_le_bytes().to_vec();
2342 bytes.extend_from_slice(&hw2.to_le_bytes());
2343 Ok(bytes)
2344 }
2345 } else {
2346 Ok(vec![0xBF, 0x00])
2347 }
2348 }
2349
2350 ArmOp::Ldr { rd, addr } => {
2352 let rd_bits = reg_to_bits(rd);
2353 let base_bits = reg_to_bits(&addr.base);
2354
2355 if let Some(offset_reg) = &addr.offset_reg {
2357 let rm_bits = reg_to_bits(offset_reg);
2358
2359 if addr.offset != 0 {
2361 let scratch = Reg::R12;
2364 let mut bytes =
2365 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2366 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
2367 return Ok(bytes);
2368 }
2369
2370 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
2373 let instr: u16 = 0x5800
2375 | ((rm_bits as u16) << 6)
2376 | ((base_bits as u16) << 3)
2377 | (rd_bits as u16);
2378 return Ok(instr.to_le_bytes().to_vec());
2379 }
2380
2381 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
2383 }
2384
2385 let offset = addr.offset as u32;
2387
2388 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
2389 let imm5 = (offset >> 2) as u16;
2391 let instr: u16 =
2392 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2393 Ok(instr.to_le_bytes().to_vec())
2394 } else {
2395 self.encode_thumb32_ldr(rd, &addr.base, offset)
2396 }
2397 }
2398
2399 ArmOp::Str { rd, addr } => {
2401 let rd_bits = reg_to_bits(rd);
2402 let base_bits = reg_to_bits(&addr.base);
2403
2404 if let Some(offset_reg) = &addr.offset_reg {
2406 let rm_bits = reg_to_bits(offset_reg);
2407
2408 if addr.offset != 0 {
2410 let scratch = Reg::R12;
2413 let mut bytes =
2414 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2415 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
2416 return Ok(bytes);
2417 }
2418
2419 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
2422 let instr: u16 = 0x5000
2424 | ((rm_bits as u16) << 6)
2425 | ((base_bits as u16) << 3)
2426 | (rd_bits as u16);
2427 return Ok(instr.to_le_bytes().to_vec());
2428 }
2429
2430 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
2432 }
2433
2434 let offset = addr.offset as u32;
2436
2437 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
2438 let imm5 = (offset >> 2) as u16;
2440 let instr: u16 =
2441 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2442 Ok(instr.to_le_bytes().to_vec())
2443 } else {
2444 self.encode_thumb32_str(rd, &addr.base, offset)
2445 }
2446 }
2447
2448 ArmOp::Ldrb { rd, addr } => {
2450 let rd_bits = reg_to_bits(rd);
2451 let base_bits = reg_to_bits(&addr.base);
2452
2453 if let Some(offset_reg) = &addr.offset_reg {
2454 if addr.offset != 0 {
2455 let scratch = Reg::R12;
2456 let mut bytes =
2457 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2458 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
2459 return Ok(bytes);
2460 }
2461 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
2462 }
2463
2464 let offset = addr.offset as u32;
2465 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
2466 let instr: u16 = 0x7800
2468 | ((offset as u16) << 6)
2469 | ((base_bits as u16) << 3)
2470 | (rd_bits as u16);
2471 Ok(instr.to_le_bytes().to_vec())
2472 } else {
2473 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
2474 }
2475 }
2476
2477 ArmOp::Ldrsb { rd, addr } => {
2479 let rd_bits = reg_to_bits(rd);
2480 let base_bits = reg_to_bits(&addr.base);
2481
2482 if let Some(offset_reg) = &addr.offset_reg {
2483 if addr.offset != 0 {
2484 let scratch = Reg::R12;
2485 let mut bytes =
2486 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2487 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
2488 return Ok(bytes);
2489 }
2490 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
2491 }
2492
2493 let offset = addr.offset as u32;
2494 if rd_bits < 8 && base_bits < 8 && offset == 0 {
2497 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
2499 } else {
2500 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
2501 }
2502 }
2503
2504 ArmOp::Ldrh { rd, addr } => {
2506 let rd_bits = reg_to_bits(rd);
2507 let base_bits = reg_to_bits(&addr.base);
2508
2509 if let Some(offset_reg) = &addr.offset_reg {
2510 if addr.offset != 0 {
2511 let scratch = Reg::R12;
2512 let mut bytes =
2513 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2514 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
2515 return Ok(bytes);
2516 }
2517 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
2518 }
2519
2520 let offset = addr.offset as u32;
2521 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
2522 let imm5 = (offset >> 1) as u16;
2524 let instr: u16 =
2525 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2526 Ok(instr.to_le_bytes().to_vec())
2527 } else {
2528 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
2529 }
2530 }
2531
2532 ArmOp::Ldrsh { rd, addr } => {
2534 if let Some(offset_reg) = &addr.offset_reg {
2535 if addr.offset != 0 {
2536 let scratch = Reg::R12;
2537 let mut bytes =
2538 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2539 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
2540 return Ok(bytes);
2541 }
2542 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
2543 }
2544
2545 let offset = addr.offset as u32;
2546 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
2547 }
2548
2549 ArmOp::Strb { rd, addr } => {
2551 let rd_bits = reg_to_bits(rd);
2552 let base_bits = reg_to_bits(&addr.base);
2553
2554 if let Some(offset_reg) = &addr.offset_reg {
2555 if addr.offset != 0 {
2556 let scratch = Reg::R12;
2557 let mut bytes =
2558 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2559 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
2560 return Ok(bytes);
2561 }
2562 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
2563 }
2564
2565 let offset = addr.offset as u32;
2566 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
2567 let instr: u16 = 0x7000
2569 | ((offset as u16) << 6)
2570 | ((base_bits as u16) << 3)
2571 | (rd_bits as u16);
2572 Ok(instr.to_le_bytes().to_vec())
2573 } else {
2574 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
2575 }
2576 }
2577
2578 ArmOp::Strh { rd, addr } => {
2580 let rd_bits = reg_to_bits(rd);
2581 let base_bits = reg_to_bits(&addr.base);
2582
2583 if let Some(offset_reg) = &addr.offset_reg {
2584 if addr.offset != 0 {
2585 let scratch = Reg::R12;
2586 let mut bytes =
2587 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
2588 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
2589 return Ok(bytes);
2590 }
2591 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
2592 }
2593
2594 let offset = addr.offset as u32;
2595 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
2596 let imm5 = (offset >> 1) as u16;
2598 let instr: u16 =
2599 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
2600 Ok(instr.to_le_bytes().to_vec())
2601 } else {
2602 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
2603 }
2604 }
2605
2606 ArmOp::MemorySize { rd } => {
2608 let rd_bits = reg_to_bits(rd);
2611 let r10_bits = reg_to_bits(&Reg::R10);
2612 if rd_bits < 8 && r10_bits < 8 {
2613 let instr: u16 =
2614 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
2615 Ok(instr.to_le_bytes().to_vec())
2616 } else {
2617 let imm5: u32 = 16;
2619 let imm3 = (imm5 >> 2) & 0x7;
2620 let imm2 = imm5 & 0x3;
2621 let hw1: u16 = 0xEA4F;
2622 let hw2: u16 =
2623 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
2624 let mut bytes = hw1.to_le_bytes().to_vec();
2625 bytes.extend_from_slice(&hw2.to_le_bytes());
2626 Ok(bytes)
2627 }
2628 }
2629
2630 ArmOp::MemoryGrow { rd, .. } => {
2632 let rd_bits = reg_to_bits(rd);
2636 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
2639 bytes.extend_from_slice(&hw2.to_le_bytes());
2640 Ok(bytes)
2641 }
2642
2643 ArmOp::Bx { rm } => {
2645 let rm_bits = reg_to_bits(rm) as u16;
2646 let instr: u16 = 0x4700 | (rm_bits << 3);
2648 Ok(instr.to_le_bytes().to_vec())
2649 }
2650
2651 ArmOp::Blx { rm } => {
2654 let rm_bits = reg_to_bits(rm) as u16;
2655 let instr: u16 = 0x4780 | (rm_bits << 3);
2656 Ok(instr.to_le_bytes().to_vec())
2657 }
2658
2659 ArmOp::CallIndirect {
2663 rd: _,
2664 type_idx: _,
2665 table_index_reg,
2666 } => {
2667 let idx_reg = reg_to_bits(table_index_reg);
2668 let mut bytes = Vec::new();
2669
2670 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
2690 bytes.extend_from_slice(&hw1.to_le_bytes());
2691 bytes.extend_from_slice(&hw2.to_le_bytes());
2692
2693 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
2699 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
2700
2701 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
2705
2706 Ok(bytes)
2707 }
2708
2709 ArmOp::Label { .. } => Ok(Vec::new()),
2711
2712 ArmOp::Bcc { cond, label: _ } => {
2714 use synth_synthesis::Condition;
2715 let cond_bits: u16 = match cond {
2716 Condition::EQ => 0x0,
2717 Condition::NE => 0x1,
2718 Condition::HS => 0x2,
2719 Condition::LO => 0x3,
2720 Condition::HI => 0x8,
2721 Condition::LS => 0x9,
2722 Condition::GE => 0xA,
2723 Condition::LT => 0xB,
2724 Condition::GT => 0xC,
2725 Condition::LE => 0xD,
2726 };
2727 let instr: u16 = 0xD000 | (cond_bits << 8);
2729 Ok(instr.to_le_bytes().to_vec())
2730 }
2731
2732 ArmOp::B { label: _ } => {
2734 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
2738 }
2739
2740 ArmOp::Bhs { label: _ } => {
2743 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
2747 }
2748
2749 ArmOp::Blo { label: _ } => {
2752 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
2756 }
2757
2758 ArmOp::BOffset { offset } => {
2761 let halfword_offset = *offset;
2764
2765 if (-1024..=1022).contains(&halfword_offset) {
2768 let imm11 = (halfword_offset as u16) & 0x7FF;
2770 let instr: u16 = 0xE000 | imm11;
2771 Ok(instr.to_le_bytes().to_vec())
2772 } else {
2773 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
2789 let uoffset = signed_offset as u32;
2790 let imm10 = (uoffset >> 12) & 0x3FF; let imm11 = (uoffset >> 1) & 0x7FF; let i1 = (uoffset >> 23) & 1; let i2 = (uoffset >> 22) & 1; let j1 = (!(i1 ^ s)) & 1; let j2 = (!(i2 ^ s)) & 1; let hw1: u16 = (0xF000 | (s << 10) | imm10) as u16;
2798 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2799
2800 let mut bytes = hw1.to_le_bytes().to_vec();
2801 bytes.extend_from_slice(&hw2.to_le_bytes());
2802 Ok(bytes)
2803 }
2804 }
2805
2806 ArmOp::BCondOffset { cond, offset } => {
2808 use synth_synthesis::Condition;
2809 let cond_bits: u16 = match cond {
2810 Condition::EQ => 0x0,
2811 Condition::NE => 0x1,
2812 Condition::HS => 0x2,
2813 Condition::LO => 0x3,
2814 Condition::HI => 0x8,
2815 Condition::LS => 0x9,
2816 Condition::GE => 0xA,
2817 Condition::LT => 0xB,
2818 Condition::GT => 0xC,
2819 Condition::LE => 0xD,
2820 };
2821
2822 let halfword_offset = *offset;
2825
2826 if (-128..=127).contains(&halfword_offset) {
2829 let imm8 = (halfword_offset as u16) & 0xFF;
2830 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
2831 Ok(instr.to_le_bytes().to_vec())
2832 } else {
2833 let offset = halfword_offset >> 1;
2837 let s = if offset < 0 { 1u32 } else { 0u32 };
2838 let imm6 = ((offset >> 11) as u32) & 0x3F;
2839 let imm11 = (offset as u32) & 0x7FF;
2840 let j1 = if s == 1 { 1 } else { 0 };
2841 let j2 = if s == 1 { 1 } else { 0 };
2842
2843 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
2844 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
2845
2846 let mut bytes = hw1.to_le_bytes().to_vec();
2847 bytes.extend_from_slice(&hw2.to_le_bytes());
2848 Ok(bytes)
2849 }
2850 }
2851
2852 ArmOp::Bl { label: _ } => {
2853 let hw1: u16 = 0xF7FF;
2868 let hw2: u16 = 0xFFFE;
2869 let mut bytes = hw1.to_le_bytes().to_vec();
2870 bytes.extend_from_slice(&hw2.to_le_bytes());
2871 Ok(bytes)
2872 }
2873
2874 ArmOp::Mvn { rd, op2 } => {
2876 if let Operand2::Reg(rm) = op2 {
2877 let rd_bits = reg_to_bits(rd) as u16;
2878 let rm_bits = reg_to_bits(rm) as u16;
2879
2880 if rd_bits < 8 && rm_bits < 8 {
2881 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
2883 Ok(instr.to_le_bytes().to_vec())
2884 } else {
2885 let hw1: u16 = 0xEA6F_u16;
2887 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
2888 let mut bytes = hw1.to_le_bytes().to_vec();
2889 bytes.extend_from_slice(&hw2.to_le_bytes());
2890 Ok(bytes)
2891 }
2892 } else {
2893 let instr: u16 = 0xBF00;
2894 Ok(instr.to_le_bytes().to_vec())
2895 }
2896 }
2897
2898 ArmOp::Movw { rd, imm16 } => {
2900 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
2901 }
2902
2903 ArmOp::Movt { rd, imm16 } => {
2905 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
2906 }
2907
2908 ArmOp::MovwSym { rd, addend, .. } => {
2913 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
2914 }
2915 ArmOp::MovtSym { rd, addend, .. } => {
2916 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
2917 }
2918
2919 ArmOp::LdrSym { rd, .. } => {
2927 let rt = reg_to_bits(rd) as u16;
2928 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
2931 bytes.extend_from_slice(&hw1.to_le_bytes());
2932 bytes.extend_from_slice(&hw2.to_le_bytes());
2933 Ok(bytes)
2934 }
2935
2936 ArmOp::SetCond { rd, cond } => {
2942 let rd_bits = reg_to_bits(rd) as u16;
2943
2944 use synth_synthesis::Condition;
2946 let cond_bits: u16 = match cond {
2947 Condition::EQ => 0x0,
2948 Condition::NE => 0x1,
2949 Condition::LT => 0xB,
2950 Condition::LE => 0xD,
2951 Condition::GT => 0xC,
2952 Condition::GE => 0xA,
2953 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
2958
2959 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
2964 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
2965
2966 let mut bytes = ite_instr.to_le_bytes().to_vec();
2977 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
2978 if rd_bits <= 7 {
2979 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
2981 } else {
2982 let hw1: u16 = 0xF04F;
2984 let hw2: u16 = (rd_bits << 8) | imm;
2985 bytes.extend_from_slice(&hw1.to_le_bytes());
2986 bytes.extend_from_slice(&hw2.to_le_bytes());
2987 }
2988 };
2989 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
2992 }
2993
2994 ArmOp::I64SetCond {
2999 rd,
3000 rn_lo,
3001 rn_hi,
3002 rm_lo,
3003 rm_hi,
3004 cond,
3005 } => {
3006 use synth_synthesis::Condition;
3007 let rd_bits = reg_to_bits(rd) as u16;
3008 let mut bytes = Vec::new();
3009
3010 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3012 rm: &synth_synthesis::Reg|
3013 -> Vec<u8> {
3014 let rn_bits = reg_to_bits(rn) as u16;
3015 let rm_bits = reg_to_bits(rm) as u16;
3016 if rn_bits < 8 && rm_bits < 8 {
3017 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3018 instr.to_le_bytes().to_vec()
3019 } else {
3020 let n_bit = (rn_bits >> 3) & 1;
3021 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3022 instr.to_le_bytes().to_vec()
3023 }
3024 };
3025
3026 let encode_ite = |cond_bits: u16| -> Vec<u8> {
3028 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3029 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3030 ite_instr.to_le_bytes().to_vec()
3031 };
3032
3033 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
3035 let mut b = encode_ite(cond_bits);
3036 if rd_bits < 8 {
3037 let mov_one: u16 = 0x2001 | (rd_bits << 8);
3038 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
3039 b.extend_from_slice(&mov_one.to_le_bytes());
3040 b.extend_from_slice(&mov_zero.to_le_bytes());
3041 } else {
3042 for imm in [1u16, 0u16] {
3050 let hw1: u16 = 0xF04F;
3051 let hw2: u16 = (rd_bits << 8) | imm;
3052 b.extend_from_slice(&hw1.to_le_bytes());
3053 b.extend_from_slice(&hw2.to_le_bytes());
3054 }
3055 }
3056 b
3057 };
3058
3059 match cond {
3060 Condition::EQ | Condition::NE => {
3061 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3063
3064 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
3067
3068 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
3070
3071 let cond_bits: u16 = match cond {
3073 Condition::EQ => 0x0,
3074 Condition::NE => 0x1,
3075 _ => unreachable!(),
3076 };
3077 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
3078 }
3079
3080 Condition::LT => {
3081 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3083
3084 let rn_hi_bits = reg_to_bits(rn_hi);
3087 let rm_hi_bits = reg_to_bits(rm_hi);
3088 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3089 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3090 bytes.extend_from_slice(&hw1.to_le_bytes());
3091 bytes.extend_from_slice(&hw2.to_le_bytes());
3092
3093 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3096
3097 Condition::GT => {
3098 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3101
3102 let rm_hi_bits = reg_to_bits(rm_hi);
3104 let rn_hi_bits = reg_to_bits(rn_hi);
3105 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3106 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3107 bytes.extend_from_slice(&hw1.to_le_bytes());
3108 bytes.extend_from_slice(&hw2.to_le_bytes());
3109
3110 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
3113
3114 Condition::LE => {
3115 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3119
3120 let rm_hi_bits = reg_to_bits(rm_hi);
3122 let rn_hi_bits = reg_to_bits(rn_hi);
3123 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3124 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3125 bytes.extend_from_slice(&hw1.to_le_bytes());
3126 bytes.extend_from_slice(&hw2.to_le_bytes());
3127
3128 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3131
3132 Condition::GE => {
3133 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3136
3137 let rn_hi_bits = reg_to_bits(rn_hi);
3139 let rm_hi_bits = reg_to_bits(rm_hi);
3140 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3141 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3142 bytes.extend_from_slice(&hw1.to_le_bytes());
3143 bytes.extend_from_slice(&hw2.to_le_bytes());
3144
3145 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
3148
3149 Condition::LO => {
3151 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3153 let rn_hi_bits = reg_to_bits(rn_hi);
3154 let rm_hi_bits = reg_to_bits(rm_hi);
3155 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3156 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3157 bytes.extend_from_slice(&hw1.to_le_bytes());
3158 bytes.extend_from_slice(&hw2.to_le_bytes());
3159 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3161
3162 Condition::HI => {
3163 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3165 let rm_hi_bits = reg_to_bits(rm_hi);
3166 let rn_hi_bits = reg_to_bits(rn_hi);
3167 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3168 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3169 bytes.extend_from_slice(&hw1.to_le_bytes());
3170 bytes.extend_from_slice(&hw2.to_le_bytes());
3171 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
3173
3174 Condition::LS => {
3175 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
3177 let rm_hi_bits = reg_to_bits(rm_hi);
3178 let rn_hi_bits = reg_to_bits(rn_hi);
3179 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
3180 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
3181 bytes.extend_from_slice(&hw1.to_le_bytes());
3182 bytes.extend_from_slice(&hw2.to_le_bytes());
3183 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3185
3186 Condition::HS => {
3187 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
3189 let rn_hi_bits = reg_to_bits(rn_hi);
3190 let rm_hi_bits = reg_to_bits(rm_hi);
3191 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
3192 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
3193 bytes.extend_from_slice(&hw1.to_le_bytes());
3194 bytes.extend_from_slice(&hw2.to_le_bytes());
3195 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
3197 }
3198
3199 Ok(bytes)
3200 }
3201
3202 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
3205 let rd_bits = reg_to_bits(rd);
3206 let rn_lo_bits = reg_to_bits(rn_lo);
3207 let rn_hi_bits = reg_to_bits(rn_hi);
3208 let mut bytes = Vec::new();
3209
3210 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
3212 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
3213 bytes.extend_from_slice(&hw1.to_le_bytes());
3214 bytes.extend_from_slice(&hw2.to_le_bytes());
3215
3216 if rd_bits < 8 {
3221 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
3222 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
3223 } else {
3224 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
3225 let hw2: u16 = 0x0F00;
3226 bytes.extend_from_slice(&hw1.to_le_bytes());
3227 bytes.extend_from_slice(&hw2.to_le_bytes());
3228 }
3229
3230 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
3234 bytes.extend_from_slice(&ite_instr.to_le_bytes());
3235 if rd_bits < 8 {
3236 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
3237 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
3238 bytes.extend_from_slice(&mov_one.to_le_bytes());
3239 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3240 } else {
3241 for imm in [1u16, 0u16] {
3242 let hw1: u16 = 0xF04F;
3243 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
3244 bytes.extend_from_slice(&hw1.to_le_bytes());
3245 bytes.extend_from_slice(&hw2.to_le_bytes());
3246 }
3247 }
3248
3249 Ok(bytes)
3250 }
3251
3252 ArmOp::I64Mul {
3256 rd_lo,
3257 rd_hi,
3258 rn_lo,
3259 rn_hi,
3260 rm_lo,
3261 rm_hi,
3262 } => {
3263 let rd_lo_bits = reg_to_bits(rd_lo);
3264 let rd_hi_bits = reg_to_bits(rd_hi);
3265 let rn_lo_bits = reg_to_bits(rn_lo);
3266 let rn_hi_bits = reg_to_bits(rn_hi);
3267 let rm_lo_bits = reg_to_bits(rm_lo);
3268 let rm_hi_bits = reg_to_bits(rm_hi);
3269 let r12: u32 = 12; let mut bytes = Vec::new();
3271
3272 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
3275 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
3276 bytes.extend_from_slice(&hw1.to_le_bytes());
3277 bytes.extend_from_slice(&hw2.to_le_bytes());
3278
3279 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
3282 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
3283 bytes.extend_from_slice(&hw1.to_le_bytes());
3284 bytes.extend_from_slice(&hw2.to_le_bytes());
3285
3286 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
3289 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3290 bytes.extend_from_slice(&hw1.to_le_bytes());
3291 bytes.extend_from_slice(&hw2.to_le_bytes());
3292
3293 let d_bit = (rd_hi_bits >> 3) & 1;
3296 let add_instr: u16 =
3297 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
3298 bytes.extend_from_slice(&add_instr.to_le_bytes());
3299
3300 Ok(bytes)
3301 }
3302
3303 ArmOp::I64Shl {
3306 rd_lo,
3307 rd_hi,
3308 rn_lo,
3309 rn_hi,
3310 rm_lo,
3311 rm_hi,
3312 } => {
3313 let rd_lo_bits = reg_to_bits(rd_lo);
3314 let rd_hi_bits = reg_to_bits(rd_hi);
3315 let rn_lo_bits = reg_to_bits(rn_lo);
3316 let rn_hi_bits = reg_to_bits(rn_hi);
3317 let rm_lo_bits = reg_to_bits(rm_lo);
3318 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3320
3321 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3323 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3324 bytes.extend_from_slice(&hw1.to_le_bytes());
3325 bytes.extend_from_slice(&hw2.to_le_bytes());
3326
3327 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3329 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3330 bytes.extend_from_slice(&hw1.to_le_bytes());
3331 bytes.extend_from_slice(&hw2.to_le_bytes());
3332
3333 let bpl: u16 = 0xD50A;
3335 bytes.extend_from_slice(&bpl.to_le_bytes());
3336
3337 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3340 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3341 bytes.extend_from_slice(&hw1.to_le_bytes());
3342 bytes.extend_from_slice(&hw2.to_le_bytes());
3343
3344 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3346 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3347 bytes.extend_from_slice(&hw1.to_le_bytes());
3348 bytes.extend_from_slice(&hw2.to_le_bytes());
3349
3350 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3352 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3353 bytes.extend_from_slice(&hw1.to_le_bytes());
3354 bytes.extend_from_slice(&hw2.to_le_bytes());
3355
3356 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3358 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
3359 bytes.extend_from_slice(&hw1.to_le_bytes());
3360 bytes.extend_from_slice(&hw2.to_le_bytes());
3361
3362 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3364 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3365 bytes.extend_from_slice(&hw1.to_le_bytes());
3366 bytes.extend_from_slice(&hw2.to_le_bytes());
3367
3368 let b_done: u16 = 0xE002;
3370 bytes.extend_from_slice(&b_done.to_le_bytes());
3371
3372 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3375 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
3376 bytes.extend_from_slice(&hw1.to_le_bytes());
3377 bytes.extend_from_slice(&hw2.to_le_bytes());
3378
3379 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
3381 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3382
3383 Ok(bytes) }
3385
3386 ArmOp::I64ShrU {
3388 rd_lo,
3389 rd_hi,
3390 rn_lo,
3391 rn_hi,
3392 rm_lo,
3393 rm_hi,
3394 } => {
3395 let rd_lo_bits = reg_to_bits(rd_lo);
3396 let rd_hi_bits = reg_to_bits(rd_hi);
3397 let rn_lo_bits = reg_to_bits(rn_lo);
3398 let rn_hi_bits = reg_to_bits(rn_hi);
3399 let rm_lo_bits = reg_to_bits(rm_lo);
3400 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3402
3403 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3405 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3406 bytes.extend_from_slice(&hw1.to_le_bytes());
3407 bytes.extend_from_slice(&hw2.to_le_bytes());
3408
3409 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3411 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3412 bytes.extend_from_slice(&hw1.to_le_bytes());
3413 bytes.extend_from_slice(&hw2.to_le_bytes());
3414
3415 let bpl: u16 = 0xD50A;
3417 bytes.extend_from_slice(&bpl.to_le_bytes());
3418
3419 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3422 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3423 bytes.extend_from_slice(&hw1.to_le_bytes());
3424 bytes.extend_from_slice(&hw2.to_le_bytes());
3425
3426 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3428 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3429 bytes.extend_from_slice(&hw1.to_le_bytes());
3430 bytes.extend_from_slice(&hw2.to_le_bytes());
3431
3432 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3434 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3435 bytes.extend_from_slice(&hw1.to_le_bytes());
3436 bytes.extend_from_slice(&hw2.to_le_bytes());
3437
3438 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3440 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3441 bytes.extend_from_slice(&hw1.to_le_bytes());
3442 bytes.extend_from_slice(&hw2.to_le_bytes());
3443
3444 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3446 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3447 bytes.extend_from_slice(&hw1.to_le_bytes());
3448 bytes.extend_from_slice(&hw2.to_le_bytes());
3449
3450 let b_done: u16 = 0xE002;
3452 bytes.extend_from_slice(&b_done.to_le_bytes());
3453
3454 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3457 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3458 bytes.extend_from_slice(&hw1.to_le_bytes());
3459 bytes.extend_from_slice(&hw2.to_le_bytes());
3460
3461 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
3463 bytes.extend_from_slice(&mov_zero.to_le_bytes());
3464
3465 Ok(bytes) }
3467
3468 ArmOp::I64ShrS {
3470 rd_lo,
3471 rd_hi,
3472 rn_lo,
3473 rn_hi,
3474 rm_lo,
3475 rm_hi,
3476 } => {
3477 let rd_lo_bits = reg_to_bits(rd_lo);
3478 let rd_hi_bits = reg_to_bits(rd_hi);
3479 let rn_lo_bits = reg_to_bits(rn_lo);
3480 let rn_hi_bits = reg_to_bits(rn_hi);
3481 let rm_lo_bits = reg_to_bits(rm_lo);
3482 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
3484
3485 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
3487 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
3488 bytes.extend_from_slice(&hw1.to_le_bytes());
3489 bytes.extend_from_slice(&hw2.to_le_bytes());
3490
3491 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
3493 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3494 bytes.extend_from_slice(&hw1.to_le_bytes());
3495 bytes.extend_from_slice(&hw2.to_le_bytes());
3496
3497 let bpl: u16 = 0xD50A;
3499 bytes.extend_from_slice(&bpl.to_le_bytes());
3500
3501 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
3504 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
3505 bytes.extend_from_slice(&hw1.to_le_bytes());
3506 bytes.extend_from_slice(&hw2.to_le_bytes());
3507
3508 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3510 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
3511 bytes.extend_from_slice(&hw1.to_le_bytes());
3512 bytes.extend_from_slice(&hw2.to_le_bytes());
3513
3514 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3516 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
3517 bytes.extend_from_slice(&hw1.to_le_bytes());
3518 bytes.extend_from_slice(&hw2.to_le_bytes());
3519
3520 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3522 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
3523 bytes.extend_from_slice(&hw1.to_le_bytes());
3524 bytes.extend_from_slice(&hw2.to_le_bytes());
3525
3526 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3528 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
3529 bytes.extend_from_slice(&hw1.to_le_bytes());
3530 bytes.extend_from_slice(&hw2.to_le_bytes());
3531
3532 let b_done: u16 = 0xE003;
3534 bytes.extend_from_slice(&b_done.to_le_bytes());
3535
3536 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
3539 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
3540 bytes.extend_from_slice(&hw1.to_le_bytes());
3541 bytes.extend_from_slice(&hw2.to_le_bytes());
3542
3543 let hw1: u16 = 0xEA4F;
3547 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
3548 bytes.extend_from_slice(&hw1.to_le_bytes());
3549 bytes.extend_from_slice(&hw2.to_le_bytes());
3550
3551 Ok(bytes) }
3553
3554 ArmOp::I64Rotl {
3559 rdlo,
3560 rdhi,
3561 rnlo,
3562 rnhi,
3563 shift,
3564 } => {
3565 let rd_lo_bits = reg_to_bits(rdlo);
3566 let rd_hi_bits = reg_to_bits(rdhi);
3567 let rn_lo_bits = reg_to_bits(rnlo);
3568 let rn_hi_bits = reg_to_bits(rnhi);
3569 let shift_bits = reg_to_bits(shift);
3570 let r12: u32 = 12; let r3: u32 = 3; let r4: u32 = 4; let mut bytes = Vec::new();
3574
3575 bytes.extend_from_slice(&0xB410u16.to_le_bytes());
3577
3578 let hw1: u16 = (0xF000 | shift_bits) as u16;
3580 let hw2: u16 = ((shift_bits << 8) | 0x3F) as u16;
3581 bytes.extend_from_slice(&hw1.to_le_bytes());
3582 bytes.extend_from_slice(&hw2.to_le_bytes());
3583
3584 let hw1: u16 = (0xF1B0 | shift_bits) as u16;
3586 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3587 bytes.extend_from_slice(&hw1.to_le_bytes());
3588 bytes.extend_from_slice(&hw2.to_le_bytes());
3589
3590 let bpl: u16 = 0xD50E;
3592 bytes.extend_from_slice(&bpl.to_le_bytes());
3593
3594 let hw1: u16 = (0xF1C0 | shift_bits) as u16;
3597 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3598 bytes.extend_from_slice(&hw1.to_le_bytes());
3599 bytes.extend_from_slice(&hw2.to_le_bytes());
3600
3601 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3603 let hw2: u16 = (0xF000 | (r4 << 8) | r3) as u16;
3604 bytes.extend_from_slice(&hw1.to_le_bytes());
3605 bytes.extend_from_slice(&hw2.to_le_bytes());
3606
3607 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3609 let hw2: u16 = (0xF000 | (r12 << 8) | r3) as u16;
3610 bytes.extend_from_slice(&hw1.to_le_bytes());
3611 bytes.extend_from_slice(&hw2.to_le_bytes());
3612
3613 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3615 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | shift_bits) as u16;
3616 bytes.extend_from_slice(&hw1.to_le_bytes());
3617 bytes.extend_from_slice(&hw2.to_le_bytes());
3618
3619 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3621 let hw2: u16 = ((rd_hi_bits << 8) | r4) as u16;
3622 bytes.extend_from_slice(&hw1.to_le_bytes());
3623 bytes.extend_from_slice(&hw2.to_le_bytes());
3624
3625 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3627 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | shift_bits) as u16;
3628 bytes.extend_from_slice(&hw1.to_le_bytes());
3629 bytes.extend_from_slice(&hw2.to_le_bytes());
3630
3631 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3633 let hw2: u16 = ((rd_lo_bits << 8) | r12) as u16;
3634 bytes.extend_from_slice(&hw1.to_le_bytes());
3635 bytes.extend_from_slice(&hw2.to_le_bytes());
3636
3637 let b_done: u16 = 0xE00E;
3639 bytes.extend_from_slice(&b_done.to_le_bytes());
3640
3641 let hw1: u16 = (0xF1C0 | r3) as u16;
3645 let hw2: u16 = ((r4 << 8) | 0x20) as u16;
3646 bytes.extend_from_slice(&hw1.to_le_bytes());
3647 bytes.extend_from_slice(&hw2.to_le_bytes());
3648
3649 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3651 let hw2: u16 = (0xF000 | (r12 << 8) | r4) as u16;
3652 bytes.extend_from_slice(&hw1.to_le_bytes());
3653 bytes.extend_from_slice(&hw2.to_le_bytes());
3654
3655 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3657 let hw2: u16 = (0xF000 | (r4 << 8) | r4) as u16;
3658 bytes.extend_from_slice(&hw1.to_le_bytes());
3659 bytes.extend_from_slice(&hw2.to_le_bytes());
3660
3661 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3663 let hw2: u16 = (0xF000 | (shift_bits << 8) | r3) as u16;
3664 bytes.extend_from_slice(&hw1.to_le_bytes());
3665 bytes.extend_from_slice(&hw2.to_le_bytes());
3666
3667 let hw1: u16 = (0xEA40 | shift_bits) as u16;
3669 let hw2: u16 = ((shift_bits << 8) | r12) as u16;
3670 bytes.extend_from_slice(&hw1.to_le_bytes());
3671 bytes.extend_from_slice(&hw2.to_le_bytes());
3672
3673 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3675 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | r3) as u16;
3676 bytes.extend_from_slice(&hw1.to_le_bytes());
3677 bytes.extend_from_slice(&hw2.to_le_bytes());
3678
3679 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3681 let hw2: u16 = ((rd_lo_bits << 8) | r4) as u16;
3682 bytes.extend_from_slice(&hw1.to_le_bytes());
3683 bytes.extend_from_slice(&hw2.to_le_bytes());
3684
3685 let d_bit = (rd_hi_bits >> 3) & 1;
3687 let mov_instr: u16 =
3688 (0x4600 | (d_bit << 7) | (shift_bits << 3) | (rd_hi_bits & 0x7)) as u16;
3689 bytes.extend_from_slice(&mov_instr.to_le_bytes());
3690
3691 bytes.extend_from_slice(&0xBC10u16.to_le_bytes());
3693
3694 Ok(bytes) }
3696
3697 ArmOp::I64Rotr {
3702 rdlo,
3703 rdhi,
3704 rnlo,
3705 rnhi,
3706 shift,
3707 } => {
3708 let rd_lo_bits = reg_to_bits(rdlo);
3709 let rd_hi_bits = reg_to_bits(rdhi);
3710 let rn_lo_bits = reg_to_bits(rnlo);
3711 let rn_hi_bits = reg_to_bits(rnhi);
3712 let shift_bits = reg_to_bits(shift);
3713 let r12: u32 = 12;
3714 let r3: u32 = 3;
3715 let r4: u32 = 4;
3716 let mut bytes = Vec::new();
3717
3718 bytes.extend_from_slice(&0xB410u16.to_le_bytes());
3720
3721 let hw1: u16 = (0xF000 | shift_bits) as u16;
3723 let hw2: u16 = ((shift_bits << 8) | 0x3F) as u16;
3724 bytes.extend_from_slice(&hw1.to_le_bytes());
3725 bytes.extend_from_slice(&hw2.to_le_bytes());
3726
3727 let hw1: u16 = (0xF1B0 | shift_bits) as u16;
3729 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3730 bytes.extend_from_slice(&hw1.to_le_bytes());
3731 bytes.extend_from_slice(&hw2.to_le_bytes());
3732
3733 let bpl: u16 = 0xD50E;
3735 bytes.extend_from_slice(&bpl.to_le_bytes());
3736
3737 let hw1: u16 = (0xF1C0 | shift_bits) as u16;
3740 let hw2: u16 = ((r3 << 8) | 0x20) as u16;
3741 bytes.extend_from_slice(&hw1.to_le_bytes());
3742 bytes.extend_from_slice(&hw2.to_le_bytes());
3743
3744 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3746 let hw2: u16 = (0xF000 | (r4 << 8) | r3) as u16;
3747 bytes.extend_from_slice(&hw1.to_le_bytes());
3748 bytes.extend_from_slice(&hw2.to_le_bytes());
3749
3750 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3752 let hw2: u16 = (0xF000 | (r12 << 8) | r3) as u16;
3753 bytes.extend_from_slice(&hw1.to_le_bytes());
3754 bytes.extend_from_slice(&hw2.to_le_bytes());
3755
3756 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3758 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | shift_bits) as u16;
3759 bytes.extend_from_slice(&hw1.to_le_bytes());
3760 bytes.extend_from_slice(&hw2.to_le_bytes());
3761
3762 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
3764 let hw2: u16 = ((rd_lo_bits << 8) | r4) as u16;
3765 bytes.extend_from_slice(&hw1.to_le_bytes());
3766 bytes.extend_from_slice(&hw2.to_le_bytes());
3767
3768 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3770 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | shift_bits) as u16;
3771 bytes.extend_from_slice(&hw1.to_le_bytes());
3772 bytes.extend_from_slice(&hw2.to_le_bytes());
3773
3774 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3776 let hw2: u16 = ((rd_hi_bits << 8) | r12) as u16;
3777 bytes.extend_from_slice(&hw1.to_le_bytes());
3778 bytes.extend_from_slice(&hw2.to_le_bytes());
3779
3780 let b_done: u16 = 0xE00E;
3782 bytes.extend_from_slice(&b_done.to_le_bytes());
3783
3784 let hw1: u16 = (0xF1C0 | r3) as u16;
3787 let hw2: u16 = ((r4 << 8) | 0x20) as u16;
3788 bytes.extend_from_slice(&hw1.to_le_bytes());
3789 bytes.extend_from_slice(&hw2.to_le_bytes());
3790
3791 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
3793 let hw2: u16 = (0xF000 | (r12 << 8) | r4) as u16;
3794 bytes.extend_from_slice(&hw1.to_le_bytes());
3795 bytes.extend_from_slice(&hw2.to_le_bytes());
3796
3797 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
3799 let hw2: u16 = (0xF000 | (r4 << 8) | r4) as u16;
3800 bytes.extend_from_slice(&hw1.to_le_bytes());
3801 bytes.extend_from_slice(&hw2.to_le_bytes());
3802
3803 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
3805 let hw2: u16 = (0xF000 | (shift_bits << 8) | r3) as u16;
3806 bytes.extend_from_slice(&hw1.to_le_bytes());
3807 bytes.extend_from_slice(&hw2.to_le_bytes());
3808
3809 let hw1: u16 = (0xEA40 | shift_bits) as u16;
3811 let hw2: u16 = ((shift_bits << 8) | r12) as u16;
3812 bytes.extend_from_slice(&hw1.to_le_bytes());
3813 bytes.extend_from_slice(&hw2.to_le_bytes());
3814
3815 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
3817 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | r3) as u16;
3818 bytes.extend_from_slice(&hw1.to_le_bytes());
3819 bytes.extend_from_slice(&hw2.to_le_bytes());
3820
3821 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
3823 let hw2: u16 = ((rd_hi_bits << 8) | r4) as u16;
3824 bytes.extend_from_slice(&hw1.to_le_bytes());
3825 bytes.extend_from_slice(&hw2.to_le_bytes());
3826
3827 let d_bit = (rd_lo_bits >> 3) & 1;
3829 let mov_instr: u16 =
3830 (0x4600 | (d_bit << 7) | (shift_bits << 3) | (rd_lo_bits & 0x7)) as u16;
3831 bytes.extend_from_slice(&mov_instr.to_le_bytes());
3832
3833 bytes.extend_from_slice(&0xBC10u16.to_le_bytes());
3835
3836 Ok(bytes) }
3838
3839 ArmOp::I64Clz { rd, rnlo, rnhi } => {
3853 let rd_bits = reg_to_bits(rd);
3854 let rn_lo_bits = reg_to_bits(rnlo);
3855 let rn_hi_bits = reg_to_bits(rnhi);
3856 let mut bytes = Vec::new();
3857
3858 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
3860 let hw2: u16 = 0x0F00;
3861 bytes.extend_from_slice(&hw1.to_le_bytes());
3862 bytes.extend_from_slice(&hw2.to_le_bytes());
3863
3864 let beq: u16 = 0xD003;
3867 bytes.extend_from_slice(&beq.to_le_bytes());
3868
3869 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
3872 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
3873 bytes.extend_from_slice(&hw1.to_le_bytes());
3874 bytes.extend_from_slice(&hw2.to_le_bytes());
3875
3876 let b_done: u16 = 0xE004;
3879 bytes.extend_from_slice(&b_done.to_le_bytes());
3880
3881 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3883
3884 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
3888 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
3889 bytes.extend_from_slice(&hw1.to_le_bytes());
3890 bytes.extend_from_slice(&hw2.to_le_bytes());
3891
3892 let hw1: u16 = (0xF100 | rd_bits) as u16;
3894 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3895 bytes.extend_from_slice(&hw1.to_le_bytes());
3896 bytes.extend_from_slice(&hw2.to_le_bytes());
3897
3898 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3902 bytes.extend_from_slice(&mov0.to_le_bytes());
3903
3904 Ok(bytes)
3905 }
3906
3907 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
3923 let rd_bits = reg_to_bits(rd);
3924 let rn_lo_bits = reg_to_bits(rnlo);
3925 let rn_hi_bits = reg_to_bits(rnhi);
3926 let mut bytes = Vec::new();
3927
3928 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
3930 let hw2: u16 = 0x0F00;
3931 bytes.extend_from_slice(&hw1.to_le_bytes());
3932 bytes.extend_from_slice(&hw2.to_le_bytes());
3933
3934 let beq: u16 = 0xD005;
3937 bytes.extend_from_slice(&beq.to_le_bytes());
3938
3939 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
3942 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
3943 bytes.extend_from_slice(&hw1.to_le_bytes());
3944 bytes.extend_from_slice(&hw2.to_le_bytes());
3945
3946 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3949 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3950 bytes.extend_from_slice(&hw1.to_le_bytes());
3951 bytes.extend_from_slice(&hw2.to_le_bytes());
3952
3953 let b_done: u16 = 0xE006;
3956 bytes.extend_from_slice(&b_done.to_le_bytes());
3957
3958 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
3960
3961 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
3965 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
3966 bytes.extend_from_slice(&hw1.to_le_bytes());
3967 bytes.extend_from_slice(&hw2.to_le_bytes());
3968
3969 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
3972 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
3973 bytes.extend_from_slice(&hw1.to_le_bytes());
3974 bytes.extend_from_slice(&hw2.to_le_bytes());
3975
3976 let hw1: u16 = (0xF100 | rd_bits) as u16;
3978 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
3979 bytes.extend_from_slice(&hw1.to_le_bytes());
3980 bytes.extend_from_slice(&hw2.to_le_bytes());
3981
3982 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
3985 bytes.extend_from_slice(&mov0.to_le_bytes());
3986
3987 Ok(bytes)
3988 }
3989
3990 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
3994 let rd_bits = reg_to_bits(rd);
3995 let rn_lo_bits = reg_to_bits(rnlo);
3996 let rn_hi_bits = reg_to_bits(rnhi);
3997 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4000
4001 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4003
4004 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_lo_bits << 3) | (4 & 0x7)) as u16;
4014 bytes.extend_from_slice(&mov.to_le_bytes());
4015
4016 let d_bit: u32 = 0; let mov: u16 = (0x4600 | (d_bit << 7) | (rn_hi_bits << 3) | (5 & 0x7)) as u16;
4019 bytes.extend_from_slice(&mov.to_le_bytes());
4020
4021 let hw1: u16 = 0xEA4F;
4025 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4026 bytes.extend_from_slice(&hw1.to_le_bytes());
4027 bytes.extend_from_slice(&hw2.to_le_bytes());
4028
4029 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4032 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4033 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4035 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4036
4037 let hw1: u16 = (0xEA00 | r12) as u16;
4039 let hw2: u16 = ((r12 << 8) | r3) as u16;
4040 bytes.extend_from_slice(&hw1.to_le_bytes());
4041 bytes.extend_from_slice(&hw2.to_le_bytes());
4042
4043 let hw1: u16 = (0xEBA0 | 4) as u16;
4045 let hw2: u16 = ((4 << 8) | r12) as u16;
4046 bytes.extend_from_slice(&hw1.to_le_bytes());
4047 bytes.extend_from_slice(&hw2.to_le_bytes());
4048
4049 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4053 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4054 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4056 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4057
4058 let hw1: u16 = (0xEA00 | 4) as u16;
4060 let hw2: u16 = ((r12 << 8) | r3) as u16;
4061 bytes.extend_from_slice(&hw1.to_le_bytes());
4062 bytes.extend_from_slice(&hw2.to_le_bytes());
4063
4064 let hw1: u16 = 0xEA4F;
4066 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4067 bytes.extend_from_slice(&hw1.to_le_bytes());
4068 bytes.extend_from_slice(&hw2.to_le_bytes());
4069
4070 let hw1: u16 = (0xEA00 | 4) as u16;
4072 let hw2: u16 = ((4 << 8) | r3) as u16;
4073 bytes.extend_from_slice(&hw1.to_le_bytes());
4074 bytes.extend_from_slice(&hw2.to_le_bytes());
4075
4076 let hw1: u16 = (0xEB00 | 4) as u16;
4078 let hw2: u16 = ((4 << 8) | r12) as u16;
4079 bytes.extend_from_slice(&hw1.to_le_bytes());
4080 bytes.extend_from_slice(&hw2.to_le_bytes());
4081
4082 let hw1: u16 = 0xEA4F;
4087 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
4088 bytes.extend_from_slice(&hw1.to_le_bytes());
4089 bytes.extend_from_slice(&hw2.to_le_bytes());
4090
4091 let hw1: u16 = (0xEB00 | 4) as u16;
4093 let hw2: u16 = ((4 << 8) | r12) as u16;
4094 bytes.extend_from_slice(&hw1.to_le_bytes());
4095 bytes.extend_from_slice(&hw2.to_le_bytes());
4096
4097 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4102 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4103 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4105 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4106
4107 let hw1: u16 = (0xEA00 | 4) as u16;
4109 let hw2: u16 = ((4 << 8) | r3) as u16;
4110 bytes.extend_from_slice(&hw1.to_le_bytes());
4111 bytes.extend_from_slice(&hw2.to_le_bytes());
4112
4113 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4117 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4118 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4120 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4121
4122 let hw1: u16 = (0xFB00 | 4) as u16;
4125 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4126 bytes.extend_from_slice(&hw1.to_le_bytes());
4127 bytes.extend_from_slice(&hw2.to_le_bytes());
4128
4129 let hw1: u16 = 0xEA4F;
4132 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
4133 bytes.extend_from_slice(&hw1.to_le_bytes());
4134 bytes.extend_from_slice(&hw2.to_le_bytes());
4135
4136 let hw1: u16 = 0xEA4F;
4139 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
4140 bytes.extend_from_slice(&hw1.to_le_bytes());
4141 bytes.extend_from_slice(&hw2.to_le_bytes());
4142
4143 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4145 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4146 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4147 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4148
4149 let hw1: u16 = (0xEA00 | r12) as u16;
4150 let hw2: u16 = ((r12 << 8) | r3) as u16;
4151 bytes.extend_from_slice(&hw1.to_le_bytes());
4152 bytes.extend_from_slice(&hw2.to_le_bytes());
4153
4154 let hw1: u16 = (0xEBA0 | 5) as u16;
4155 let hw2: u16 = ((5 << 8) | r12) as u16;
4156 bytes.extend_from_slice(&hw1.to_le_bytes());
4157 bytes.extend_from_slice(&hw2.to_le_bytes());
4158
4159 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4161 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4162 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4163 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4164
4165 let hw1: u16 = (0xEA00 | 5) as u16;
4166 let hw2: u16 = ((r12 << 8) | r3) as u16;
4167 bytes.extend_from_slice(&hw1.to_le_bytes());
4168 bytes.extend_from_slice(&hw2.to_le_bytes());
4169
4170 let hw1: u16 = 0xEA4F;
4171 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
4172 bytes.extend_from_slice(&hw1.to_le_bytes());
4173 bytes.extend_from_slice(&hw2.to_le_bytes());
4174
4175 let hw1: u16 = (0xEA00 | 5) as u16;
4176 let hw2: u16 = ((5 << 8) | r3) as u16;
4177 bytes.extend_from_slice(&hw1.to_le_bytes());
4178 bytes.extend_from_slice(&hw2.to_le_bytes());
4179
4180 let hw1: u16 = (0xEB00 | 5) as u16;
4181 let hw2: u16 = ((5 << 8) | r12) as u16;
4182 bytes.extend_from_slice(&hw1.to_le_bytes());
4183 bytes.extend_from_slice(&hw2.to_le_bytes());
4184
4185 let hw1: u16 = 0xEA4F;
4188 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4189 bytes.extend_from_slice(&hw1.to_le_bytes());
4190 bytes.extend_from_slice(&hw2.to_le_bytes());
4191
4192 let hw1: u16 = (0xEB00 | 5) as u16;
4193 let hw2: u16 = ((5 << 8) | r12) as u16;
4194 bytes.extend_from_slice(&hw1.to_le_bytes());
4195 bytes.extend_from_slice(&hw2.to_le_bytes());
4196
4197 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4199 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4200 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4201 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4202
4203 let hw1: u16 = (0xEA00 | 5) as u16;
4204 let hw2: u16 = ((5 << 8) | r3) as u16;
4205 bytes.extend_from_slice(&hw1.to_le_bytes());
4206 bytes.extend_from_slice(&hw2.to_le_bytes());
4207
4208 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4210 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4211 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4212 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4213
4214 let hw1: u16 = (0xFB00 | 5) as u16;
4217 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
4218 bytes.extend_from_slice(&hw1.to_le_bytes());
4219 bytes.extend_from_slice(&hw2.to_le_bytes());
4220
4221 let hw1: u16 = 0xEA4F;
4224 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
4225 bytes.extend_from_slice(&hw1.to_le_bytes());
4226 bytes.extend_from_slice(&hw2.to_le_bytes());
4227
4228 let rd_bits_u16 = rd_bits as u16;
4231 let instr: u16 = 0x1800 | (5 << 6) | (4 << 3) | rd_bits_u16;
4232 bytes.extend_from_slice(&instr.to_le_bytes());
4233
4234 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
4236
4237 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4239 bytes.extend_from_slice(&mov0.to_le_bytes());
4240
4241 Ok(bytes)
4242 }
4243
4244 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
4247 let rdlo_bits = reg_to_bits(rdlo);
4248 let rdhi_bits = reg_to_bits(rdhi);
4249 let rnlo_bits = reg_to_bits(rnlo);
4250 let mut bytes = Vec::new();
4251
4252 let hw1: u16 = 0xFA4F_u16;
4255 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4256 bytes.extend_from_slice(&hw1.to_le_bytes());
4257 bytes.extend_from_slice(&hw2.to_le_bytes());
4258
4259 let hw1: u16 = 0xEA4F;
4264 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4265 bytes.extend_from_slice(&hw1.to_le_bytes());
4266 bytes.extend_from_slice(&hw2.to_le_bytes());
4267
4268 Ok(bytes)
4269 }
4270
4271 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
4274 let rdlo_bits = reg_to_bits(rdlo);
4275 let rdhi_bits = reg_to_bits(rdhi);
4276 let rnlo_bits = reg_to_bits(rnlo);
4277 let mut bytes = Vec::new();
4278
4279 let hw1: u16 = 0xFA0F_u16;
4282 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
4283 bytes.extend_from_slice(&hw1.to_le_bytes());
4284 bytes.extend_from_slice(&hw2.to_le_bytes());
4285
4286 let hw1: u16 = 0xEA4F;
4288 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
4289 bytes.extend_from_slice(&hw1.to_le_bytes());
4290 bytes.extend_from_slice(&hw2.to_le_bytes());
4291
4292 Ok(bytes)
4293 }
4294
4295 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
4298 let rdlo_bits = reg_to_bits(rdlo);
4299 let rdhi_bits = reg_to_bits(rdhi);
4300 let rnlo_bits = reg_to_bits(rnlo);
4301 let mut bytes = Vec::new();
4302
4303 if rdlo_bits != rnlo_bits {
4305 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
4307 let mov: u16 = 0x4600
4308 | (d_bit << 7)
4309 | ((rnlo_bits as u16) << 3)
4310 | ((rdlo_bits & 0x7) as u16);
4311 bytes.extend_from_slice(&mov.to_le_bytes());
4312 }
4313
4314 let hw1: u16 = 0xEA4F;
4316 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
4317 bytes.extend_from_slice(&hw1.to_le_bytes());
4318 bytes.extend_from_slice(&hw2.to_le_bytes());
4319
4320 Ok(bytes)
4321 }
4322
4323 ArmOp::SelectMove { rd, rm, cond } => {
4326 let rd_bits = reg_to_bits(rd) as u16;
4327 let rm_bits = reg_to_bits(rm) as u16;
4328
4329 use synth_synthesis::Condition;
4331 let cond_bits: u16 = match cond {
4332 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, };
4343
4344 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
4347
4348 let d_bit = (rd_bits >> 3) & 1;
4351 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4352
4353 let mut bytes = it_instr.to_le_bytes().to_vec();
4355 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4356 Ok(bytes)
4357 }
4358
4359 ArmOp::Popcnt { rd, rm } => {
4370 let mut bytes = Vec::new();
4371
4372 if rd != rm {
4374 let rd_bits = reg_to_bits(rd) as u16;
4375 let rm_bits = reg_to_bits(rm) as u16;
4376 let d_bit = (rd_bits >> 3) & 1;
4378 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
4379 bytes.extend_from_slice(&mov_instr.to_le_bytes());
4380 }
4381
4382 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
4385 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
4386
4387 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
4390
4391 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
4393
4394 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
4396 reg_to_bits(rd),
4397 reg_to_bits(rd),
4398 11,
4399 )?);
4400
4401 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
4404 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
4405
4406 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4408 11,
4409 reg_to_bits(rd),
4410 12,
4411 )?);
4412
4413 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
4415 reg_to_bits(rd),
4416 reg_to_bits(rd),
4417 2,
4418 )?);
4419
4420 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4422 reg_to_bits(rd),
4423 reg_to_bits(rd),
4424 12,
4425 )?);
4426
4427 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4429 reg_to_bits(rd),
4430 reg_to_bits(rd),
4431 11,
4432 )?);
4433
4434 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
4437
4438 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4440 reg_to_bits(rd),
4441 reg_to_bits(rd),
4442 11,
4443 )?);
4444
4445 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
4447 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
4448
4449 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
4451 reg_to_bits(rd),
4452 reg_to_bits(rd),
4453 12,
4454 )?);
4455
4456 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
4459
4460 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4462 reg_to_bits(rd),
4463 reg_to_bits(rd),
4464 11,
4465 )?);
4466
4467 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
4470
4471 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
4473 reg_to_bits(rd),
4474 reg_to_bits(rd),
4475 11,
4476 )?);
4477
4478 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
4481 reg_to_bits(rd),
4482 reg_to_bits(rd),
4483 0x3F,
4484 )?);
4485
4486 Ok(bytes)
4487 }
4488
4489 ArmOp::I64DivU {
4494 rdlo: _,
4495 rdhi: _,
4496 rnlo: _,
4497 rnhi: _,
4498 rmlo: _,
4499 rmhi: _,
4500 } => {
4501 let mut bytes = Vec::new();
4502
4503 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
4507
4508 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());
4519 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
4520
4521 let loop_start = bytes.len();
4523
4524 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
4535 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());
4544 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
4545 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
4549 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4550
4551 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
4556 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4557 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());
4588 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
4589 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4592
4593 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
4597 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
4598
4599 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4602 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4603 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4604
4605 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
4613
4614 Ok(bytes)
4615 }
4616
4617 ArmOp::I64DivS {
4622 rdlo: _,
4623 rdhi: _,
4624 rnlo: _,
4625 rnhi: _,
4626 rmlo: _,
4627 rmhi: _,
4628 } => {
4629 let mut bytes = Vec::new();
4630
4631 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4633 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4634
4635 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
4638 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
4639
4640 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());
4653
4654 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());
4664
4665 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4668 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4669 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4671 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4672 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4674 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4675
4676 let loop_start = bytes.len();
4677
4678 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4682 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());
4688 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4691
4692 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4696 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());
4709 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4711
4712 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4715
4716 let branch_offset_bytes = bytes.len() - loop_start + 4;
4717 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4718 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4719 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4720
4721 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());
4728 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());
4736
4737 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4739 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4740
4741 Ok(bytes)
4742 }
4743
4744 ArmOp::I64RemU {
4749 rdlo: _,
4750 rdhi: _,
4751 rnlo: _,
4752 rnhi: _,
4753 rmlo: _,
4754 rmhi: _,
4755 } => {
4756 let mut bytes = Vec::new();
4757
4758 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4760 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4761
4762 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4764 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4765 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4767 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4768 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4770 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4771
4772 let loop_start = bytes.len();
4773
4774 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4778 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());
4784 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4787
4788 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4792 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());
4805 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4807
4808 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4811
4812 let branch_offset_bytes = bytes.len() - loop_start + 4;
4813 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4814 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4815 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4816
4817 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4823 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
4824
4825 Ok(bytes)
4826 }
4827
4828 ArmOp::I64RemS {
4833 rdlo: _,
4834 rdhi: _,
4835 rnlo: _,
4836 rnhi: _,
4837 rmlo: _,
4838 rmhi: _,
4839 } => {
4840 let mut bytes = Vec::new();
4841
4842 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
4844 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4845
4846 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());
4860
4861 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());
4871
4872 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
4875 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
4876 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
4878 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
4879 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
4881 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
4882
4883 let loop_start = bytes.len();
4884
4885 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
4889 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());
4895 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
4898
4899 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
4903 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());
4916 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
4918
4919 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
4922
4923 let branch_offset_bytes = bytes.len() - loop_start + 4;
4924 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
4925 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
4926 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
4927
4928 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());
4935 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());
4943
4944 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
4946 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
4947
4948 Ok(bytes)
4949 }
4950
4951 ArmOp::F32Add { sd, sn, sm } => {
4954 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
4955 }
4956 ArmOp::F32Sub { sd, sn, sm } => {
4957 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
4958 }
4959 ArmOp::F32Mul { sd, sn, sm } => {
4960 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
4961 }
4962 ArmOp::F32Div { sd, sn, sm } => {
4963 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
4964 }
4965 ArmOp::F32Abs { sd, sm } => {
4966 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
4967 }
4968 ArmOp::F32Neg { sd, sm } => {
4969 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
4970 }
4971 ArmOp::F32Sqrt { sd, sm } => {
4972 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
4973 }
4974
4975 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
4978 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
4979 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
4980 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
4981 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
4982 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
4983 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
4984
4985 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
4987 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
4988 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
4989 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
4990 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
4991 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
4992
4993 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
4994
4995 ArmOp::F32Load { sd, addr } => {
4996 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
4997 }
4998 ArmOp::F32Store { sd, addr } => {
4999 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5000 }
5001
5002 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5003 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5004 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5005 Err(synth_core::Error::synthesis(
5006 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5007 ))
5008 }
5009 ArmOp::F32ReinterpretI32 { sd, rm } => {
5010 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5011 }
5012 ArmOp::I32ReinterpretF32 { rd, sm } => {
5013 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5014 }
5015 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5016 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5017
5018 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5021 0xEE300B00, dd, dn, dm,
5022 )?)),
5023 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5024 0xEE300B40, dd, dn, dm,
5025 )?)),
5026 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5027 0xEE200B00, dd, dn, dm,
5028 )?)),
5029 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5030 0xEE800B00, dd, dn, dm,
5031 )?)),
5032 ArmOp::F64Abs { dd, dm } => {
5033 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5034 }
5035 ArmOp::F64Neg { dd, dm } => {
5036 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5037 }
5038 ArmOp::F64Sqrt { dd, dm } => {
5039 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5040 }
5041
5042 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5045 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5046 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5047 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5048 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5049 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5050 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5051
5052 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5054 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5055 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5056 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5057 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5058 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5059
5060 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5061
5062 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5063 0xED900B00, dd, addr,
5064 )?)),
5065 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5066 0xED800B00, dd, addr,
5067 )?)),
5068
5069 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5070 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5071 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
5072 Err(synth_core::Error::synthesis(
5073 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5074 ))
5075 }
5076 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
5077 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
5078 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
5079 )),
5080 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
5081 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
5082 )),
5083 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
5084 Err(synth_core::Error::synthesis(
5085 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
5086 ))
5087 }
5088 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
5089 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
5090
5091 ArmOp::I64Add {
5095 rdlo,
5096 rdhi,
5097 rnlo,
5098 rnhi,
5099 rmlo,
5100 rmhi,
5101 } => {
5102 let mut bytes = Vec::new();
5103 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
5105 rd: *rdlo,
5106 rn: *rnlo,
5107 op2: Operand2::Reg(*rmlo),
5108 })?);
5109 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
5111 rd: *rdhi,
5112 rn: *rnhi,
5113 op2: Operand2::Reg(*rmhi),
5114 })?);
5115 Ok(bytes)
5116 }
5117
5118 ArmOp::I64Sub {
5120 rdlo,
5121 rdhi,
5122 rnlo,
5123 rnhi,
5124 rmlo,
5125 rmhi,
5126 } => {
5127 let mut bytes = Vec::new();
5128 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
5130 rd: *rdlo,
5131 rn: *rnlo,
5132 op2: Operand2::Reg(*rmlo),
5133 })?);
5134 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
5136 rd: *rdhi,
5137 rn: *rnhi,
5138 op2: Operand2::Reg(*rmhi),
5139 })?);
5140 Ok(bytes)
5141 }
5142
5143 ArmOp::I64And {
5145 rdlo,
5146 rdhi,
5147 rnlo,
5148 rnhi,
5149 rmlo,
5150 rmhi,
5151 } => {
5152 let mut bytes = Vec::new();
5153 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5154 rd: *rdlo,
5155 rn: *rnlo,
5156 op2: Operand2::Reg(*rmlo),
5157 })?);
5158 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
5159 rd: *rdhi,
5160 rn: *rnhi,
5161 op2: Operand2::Reg(*rmhi),
5162 })?);
5163 Ok(bytes)
5164 }
5165
5166 ArmOp::I64Or {
5168 rdlo,
5169 rdhi,
5170 rnlo,
5171 rnhi,
5172 rmlo,
5173 rmhi,
5174 } => {
5175 let mut bytes = Vec::new();
5176 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5177 rd: *rdlo,
5178 rn: *rnlo,
5179 op2: Operand2::Reg(*rmlo),
5180 })?);
5181 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
5182 rd: *rdhi,
5183 rn: *rnhi,
5184 op2: Operand2::Reg(*rmhi),
5185 })?);
5186 Ok(bytes)
5187 }
5188
5189 ArmOp::I64Xor {
5191 rdlo,
5192 rdhi,
5193 rnlo,
5194 rnhi,
5195 rmlo,
5196 rmhi,
5197 } => {
5198 let mut bytes = Vec::new();
5199 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5200 rd: *rdlo,
5201 rn: *rnlo,
5202 op2: Operand2::Reg(*rmlo),
5203 })?);
5204 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
5205 rd: *rdhi,
5206 rn: *rnhi,
5207 op2: Operand2::Reg(*rmhi),
5208 })?);
5209 Ok(bytes)
5210 }
5211
5212 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
5214 rd: *rd,
5215 rn_lo: *rnlo,
5216 rn_hi: *rnhi,
5217 }),
5218
5219 ArmOp::I64Eq {
5221 rd,
5222 rnlo,
5223 rnhi,
5224 rmlo,
5225 rmhi,
5226 } => self.encode_thumb(&ArmOp::I64SetCond {
5227 rd: *rd,
5228 rn_lo: *rnlo,
5229 rn_hi: *rnhi,
5230 rm_lo: *rmlo,
5231 rm_hi: *rmhi,
5232 cond: synth_synthesis::Condition::EQ,
5233 }),
5234
5235 ArmOp::I64Ne {
5236 rd,
5237 rnlo,
5238 rnhi,
5239 rmlo,
5240 rmhi,
5241 } => self.encode_thumb(&ArmOp::I64SetCond {
5242 rd: *rd,
5243 rn_lo: *rnlo,
5244 rn_hi: *rnhi,
5245 rm_lo: *rmlo,
5246 rm_hi: *rmhi,
5247 cond: synth_synthesis::Condition::NE,
5248 }),
5249
5250 ArmOp::I64LtS {
5251 rd,
5252 rnlo,
5253 rnhi,
5254 rmlo,
5255 rmhi,
5256 } => self.encode_thumb(&ArmOp::I64SetCond {
5257 rd: *rd,
5258 rn_lo: *rnlo,
5259 rn_hi: *rnhi,
5260 rm_lo: *rmlo,
5261 rm_hi: *rmhi,
5262 cond: synth_synthesis::Condition::LT,
5263 }),
5264
5265 ArmOp::I64LtU {
5266 rd,
5267 rnlo,
5268 rnhi,
5269 rmlo,
5270 rmhi,
5271 } => self.encode_thumb(&ArmOp::I64SetCond {
5272 rd: *rd,
5273 rn_lo: *rnlo,
5274 rn_hi: *rnhi,
5275 rm_lo: *rmlo,
5276 rm_hi: *rmhi,
5277 cond: synth_synthesis::Condition::LO,
5278 }),
5279
5280 ArmOp::I64LeS {
5281 rd,
5282 rnlo,
5283 rnhi,
5284 rmlo,
5285 rmhi,
5286 } => self.encode_thumb(&ArmOp::I64SetCond {
5287 rd: *rd,
5288 rn_lo: *rnlo,
5289 rn_hi: *rnhi,
5290 rm_lo: *rmlo,
5291 rm_hi: *rmhi,
5292 cond: synth_synthesis::Condition::LE,
5293 }),
5294
5295 ArmOp::I64LeU {
5296 rd,
5297 rnlo,
5298 rnhi,
5299 rmlo,
5300 rmhi,
5301 } => self.encode_thumb(&ArmOp::I64SetCond {
5302 rd: *rd,
5303 rn_lo: *rnlo,
5304 rn_hi: *rnhi,
5305 rm_lo: *rmlo,
5306 rm_hi: *rmhi,
5307 cond: synth_synthesis::Condition::LS,
5308 }),
5309
5310 ArmOp::I64GtS {
5311 rd,
5312 rnlo,
5313 rnhi,
5314 rmlo,
5315 rmhi,
5316 } => self.encode_thumb(&ArmOp::I64SetCond {
5317 rd: *rd,
5318 rn_lo: *rnlo,
5319 rn_hi: *rnhi,
5320 rm_lo: *rmlo,
5321 rm_hi: *rmhi,
5322 cond: synth_synthesis::Condition::GT,
5323 }),
5324
5325 ArmOp::I64GtU {
5326 rd,
5327 rnlo,
5328 rnhi,
5329 rmlo,
5330 rmhi,
5331 } => self.encode_thumb(&ArmOp::I64SetCond {
5332 rd: *rd,
5333 rn_lo: *rnlo,
5334 rn_hi: *rnhi,
5335 rm_lo: *rmlo,
5336 rm_hi: *rmhi,
5337 cond: synth_synthesis::Condition::HI,
5338 }),
5339
5340 ArmOp::I64GeS {
5341 rd,
5342 rnlo,
5343 rnhi,
5344 rmlo,
5345 rmhi,
5346 } => self.encode_thumb(&ArmOp::I64SetCond {
5347 rd: *rd,
5348 rn_lo: *rnlo,
5349 rn_hi: *rnhi,
5350 rm_lo: *rmlo,
5351 rm_hi: *rmhi,
5352 cond: synth_synthesis::Condition::GE,
5353 }),
5354
5355 ArmOp::I64GeU {
5356 rd,
5357 rnlo,
5358 rnhi,
5359 rmlo,
5360 rmhi,
5361 } => self.encode_thumb(&ArmOp::I64SetCond {
5362 rd: *rd,
5363 rn_lo: *rnlo,
5364 rn_hi: *rnhi,
5365 rm_lo: *rmlo,
5366 rm_hi: *rmhi,
5367 cond: synth_synthesis::Condition::HS,
5368 }),
5369
5370 ArmOp::I64Const { rdlo, rdhi, value } => {
5372 let lo32 = *value as u32;
5373 let hi32 = (*value >> 32) as u32;
5374 let mut bytes = Vec::new();
5375 bytes.extend_from_slice(
5377 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
5378 );
5379 if lo32 > 0xFFFF {
5380 bytes.extend_from_slice(
5381 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
5382 );
5383 }
5384 bytes.extend_from_slice(
5386 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
5387 );
5388 if hi32 > 0xFFFF {
5389 bytes.extend_from_slice(
5390 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
5391 );
5392 }
5393 Ok(bytes)
5394 }
5395
5396 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
5398 let mut bytes = Vec::new();
5399 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5410 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
5411 bytes.extend_from_slice(&self.encode_thumb32_ldr(
5412 rdhi,
5413 &base,
5414 offset.wrapping_add(4),
5415 )?);
5416 Ok(bytes)
5417 }
5418
5419 ArmOp::I64Str { rdlo, rdhi, addr } => {
5421 let mut bytes = Vec::new();
5422 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
5425 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
5426 bytes.extend_from_slice(&self.encode_thumb32_str(
5427 rdhi,
5428 &base,
5429 offset.wrapping_add(4),
5430 )?);
5431 Ok(bytes)
5432 }
5433
5434 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
5436 let mut bytes = Vec::new();
5437 if rdlo != rn {
5438 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5440 rd: *rdlo,
5441 op2: Operand2::Reg(*rn),
5442 })?);
5443 }
5444 bytes.extend_from_slice(
5446 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
5448 Ok(bytes)
5449 }
5450
5451 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
5453 let mut bytes = Vec::new();
5454 if rdlo != rn {
5455 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
5457 rd: *rdlo,
5458 op2: Operand2::Reg(*rn),
5459 })?);
5460 }
5461 let rdhi_bits = reg_to_bits(rdhi) as u16;
5463 let instr: u16 = 0x2000 | (rdhi_bits << 8);
5464 bytes.extend_from_slice(&instr.to_le_bytes());
5465 Ok(bytes)
5466 }
5467
5468 ArmOp::I32WrapI64 { rd, rnlo } => {
5470 if rd == rnlo {
5471 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5474 } else {
5475 self.encode_thumb(&ArmOp::Mov {
5477 rd: *rd,
5478 op2: Operand2::Reg(*rnlo),
5479 })
5480 }
5481 }
5482
5483 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
5485 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
5486 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
5487 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5488 0xEF000150, qd, qn, qm,
5489 ))),
5490 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5491 0xEF200150, qd, qn, qm,
5492 ))),
5493 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5494 0xFF000150, qd, qn, qm,
5495 ))),
5496 ArmOp::MveMvn { qd, qm } => {
5497 let qd_enc = qreg_to_num(qd);
5499 let qm_enc = qreg_to_num(qm);
5500 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5501 Ok(vfp_to_thumb_bytes(instr))
5502 }
5503 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
5504 0xEF100150, qd, qn, qm,
5505 ))),
5506 ArmOp::MveAddI { qd, qn, qm, size } => {
5507 let sz = mve_size_bits(size);
5508 let base: u32 = 0xEF000840 | (sz << 20);
5509 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5510 }
5511 ArmOp::MveSubI { qd, qn, qm, size } => {
5512 let sz = mve_size_bits(size);
5513 let base: u32 = 0xFF000840 | (sz << 20);
5514 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5515 }
5516 ArmOp::MveMulI { qd, qn, qm, size } => {
5517 let sz = mve_size_bits(size);
5518 let base: u32 = 0xEF000950 | (sz << 20);
5519 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5520 }
5521 ArmOp::MveNegI { qd, qm, size } => {
5522 let sz = mve_size_bits(size);
5523 let qd_enc = qreg_to_num(qd);
5525 let qm_enc = qreg_to_num(qm);
5526 let base: u32 = 0xFFB103C0 | (sz << 18);
5527 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
5528 Ok(vfp_to_thumb_bytes(instr))
5529 }
5530 ArmOp::MveDup { qd, rn, size } => {
5531 let sz = mve_size_bits(size);
5532 let qd_enc = qreg_to_num(qd);
5533 let rn_bits = reg_to_bits(rn);
5534 let be = match sz {
5537 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
5541 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
5542 Ok(vfp_to_thumb_bytes(instr))
5543 }
5544 ArmOp::MveExtractLane { rd, qn, lane, size } => {
5545 let qn_enc = qreg_to_num(qn);
5546 let rd_bits = reg_to_bits(rd);
5547 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
5550 let lane_in_d = (*lane as u32) & 1;
5551 let _sz = mve_size_bits(size);
5552 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
5554 Ok(vfp_to_thumb_bytes(instr))
5555 }
5556 ArmOp::MveInsertLane { qd, rn, lane, size } => {
5557 let qd_enc = qreg_to_num(qd);
5558 let rn_bits = reg_to_bits(rn);
5559 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
5560 let lane_in_d = (*lane as u32) & 1;
5561 let _sz = mve_size_bits(size);
5562 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
5564 Ok(vfp_to_thumb_bytes(instr))
5565 }
5566
5567 ArmOp::MveCmpEqI { qd, qn, qm, size }
5569 | ArmOp::MveCmpNeI { qd, qn, qm, size }
5570 | ArmOp::MveCmpLtS { qd, qn, qm, size }
5571 | ArmOp::MveCmpLtU { qd, qn, qm, size }
5572 | ArmOp::MveCmpGtS { qd, qn, qm, size }
5573 | ArmOp::MveCmpGtU { qd, qn, qm, size }
5574 | ArmOp::MveCmpLeS { qd, qn, qm, size }
5575 | ArmOp::MveCmpLeU { qd, qn, qm, size }
5576 | ArmOp::MveCmpGeS { qd, qn, qm, size }
5577 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
5578 let sz = mve_size_bits(size);
5581 let base: u32 = 0xEF000840 | (sz << 20);
5582 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
5583 }
5584
5585 ArmOp::MveAddF32 { qd, qn, qm } => {
5587 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5589 }
5590 ArmOp::MveSubF32 { qd, qn, qm } => {
5591 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
5593 }
5594 ArmOp::MveMulF32 { qd, qn, qm } => {
5595 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
5597 }
5598 ArmOp::MveNegF32 { qd, qm } => {
5599 let qd_enc = qreg_to_num(qd);
5600 let qm_enc = qreg_to_num(qm);
5601 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5603 Ok(vfp_to_thumb_bytes(instr))
5604 }
5605 ArmOp::MveAbsF32 { qd, qm } => {
5606 let qd_enc = qreg_to_num(qd);
5607 let qm_enc = qreg_to_num(qm);
5608 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
5610 Ok(vfp_to_thumb_bytes(instr))
5611 }
5612 ArmOp::MveCmpEqF32 { qd, qn, qm }
5613 | ArmOp::MveCmpNeF32 { qd, qn, qm }
5614 | ArmOp::MveCmpLtF32 { qd, qn, qm }
5615 | ArmOp::MveCmpLeF32 { qd, qn, qm }
5616 | ArmOp::MveCmpGtF32 { qd, qn, qm }
5617 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
5618 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
5620 }
5621 ArmOp::MveDupF32 { qd, rn } => {
5622 let qd_enc = qreg_to_num(qd);
5623 let rn_bits = reg_to_bits(rn);
5624 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
5626 Ok(vfp_to_thumb_bytes(instr))
5627 }
5628 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
5629 let qn_enc = qreg_to_num(qn);
5630 let rd_bits = reg_to_bits(rd);
5631 let s_num = qn_enc * 4 + (*lane as u32);
5633 let (vn, n) = encode_sreg(s_num);
5634 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
5635 Ok(vfp_to_thumb_bytes(instr))
5636 }
5637 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
5638 let qd_enc = qreg_to_num(qd);
5639 let rn_bits = reg_to_bits(rn);
5640 let s_num = qd_enc * 4 + (*lane as u32);
5642 let (vn, n) = encode_sreg(s_num);
5643 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
5644 Ok(vfp_to_thumb_bytes(instr))
5645 }
5646 ArmOp::MveDivF32 { qd, qn, qm } => {
5647 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
5649 }
5650 ArmOp::MveSqrtF32 { qd, qm } => {
5651 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
5653 }
5654
5655 _ => {
5657 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
5659 }
5660 }
5661 }
5662
5663 fn encode_thumb_f32_compare(
5667 &self,
5668 rd: &Reg,
5669 sn: &VfpReg,
5670 sm: &VfpReg,
5671 cond_code: u32,
5672 ) -> Result<Vec<u8>> {
5673 let mut bytes = Vec::new();
5674 let rd_bits = reg_to_bits(rd);
5675
5676 let sn_num = vfp_sreg_to_num(sn)?;
5678 let sm_num = vfp_sreg_to_num(sm)?;
5679 let (vd, d) = encode_sreg(sn_num);
5680 let (vm, m) = encode_sreg(sm_num);
5681 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5682 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5683
5684 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5686
5687 if rd_bits < 8 {
5689 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5690 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5691 } else {
5692 let hw1: u16 = 0xF04F;
5694 let hw2: u16 = (rd_bits as u16) << 8;
5695 bytes.extend_from_slice(&hw1.to_le_bytes());
5696 bytes.extend_from_slice(&hw2.to_le_bytes());
5697 }
5698
5699 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5703 bytes.extend_from_slice(&it.to_le_bytes());
5704
5705 if rd_bits < 8 {
5707 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5708 bytes.extend_from_slice(&mov_one.to_le_bytes());
5709 } else {
5710 let hw1: u16 = 0xF04F;
5712 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5713 bytes.extend_from_slice(&hw1.to_le_bytes());
5714 bytes.extend_from_slice(&hw2.to_le_bytes());
5715 }
5716
5717 Ok(bytes)
5718 }
5719
5720 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
5722 let mut bytes = Vec::new();
5723 let bits = value.to_bits();
5724 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
5729 let imm4 = (lo16 >> 12) & 0xF;
5730 let i_bit = (lo16 >> 11) & 1;
5731 let imm3 = (lo16 >> 8) & 0x7;
5732 let imm8 = lo16 & 0xFF;
5733 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
5734 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5735 bytes.extend_from_slice(&hw1.to_le_bytes());
5736 bytes.extend_from_slice(&hw2.to_le_bytes());
5737
5738 let hi16 = (bits >> 16) & 0xFFFF;
5740 let imm4 = (hi16 >> 12) & 0xF;
5741 let i_bit = (hi16 >> 11) & 1;
5742 let imm3 = (hi16 >> 8) & 0x7;
5743 let imm8 = hi16 & 0xFF;
5744 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
5745 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
5746 bytes.extend_from_slice(&hw1.to_le_bytes());
5747 bytes.extend_from_slice(&hw2.to_le_bytes());
5748
5749 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
5751 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5752
5753 Ok(bytes)
5754 }
5755
5756 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
5758 let mut bytes = Vec::new();
5759
5760 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
5762 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
5763
5764 let sd_num = vfp_sreg_to_num(sd)?;
5766 let (vd, d) = encode_sreg(sd_num);
5767 let (vm, m) = encode_sreg(sd_num);
5768 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
5769 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
5770 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
5771
5772 Ok(bytes)
5773 }
5774
5775 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
5783 let mut bytes = Vec::new();
5784 let sm_num = vfp_sreg_to_num(sm)?;
5785 let sd_num = vfp_sreg_to_num(sd)?;
5786 let (vd_s, d_s) = encode_sreg(sd_num);
5787 let (vm_s, m_s) = encode_sreg(sm_num);
5788
5789 if mode == 0b11 {
5790 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5792 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5793 } else {
5794 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
5799 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5800
5801 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
5807 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5808 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5809
5810 if mode != 0 {
5812 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
5814 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
5815 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
5816 }
5817
5818 let vmsr = 0xEEE10A10 | (rt << 12);
5820 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5821
5822 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
5824 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
5825
5826 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
5828 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
5829 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
5830 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
5831 }
5832
5833 let (vd2, d2) = encode_sreg(sd_num);
5835 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
5836 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
5837
5838 Ok(bytes)
5839 }
5840
5841 fn encode_thumb_f32_minmax(
5843 &self,
5844 sd: &VfpReg,
5845 sn: &VfpReg,
5846 sm: &VfpReg,
5847 is_min: bool,
5848 ) -> Result<Vec<u8>> {
5849 let mut bytes = Vec::new();
5850 let sn_num = vfp_sreg_to_num(sn)?;
5851 let sm_num = vfp_sreg_to_num(sm)?;
5852 let sd_num = vfp_sreg_to_num(sd)?;
5853
5854 let (vd, d) = encode_sreg(sd_num);
5856 let (vn, n) = encode_sreg(sn_num);
5857 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
5858 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
5859
5860 let (vm, m) = encode_sreg(sm_num);
5862 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
5863 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5864
5865 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5867
5868 let cond: u16 = if is_min { 0xC } else { 0x4 };
5870 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
5871 bytes.extend_from_slice(&it.to_le_bytes());
5872
5873 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5875 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
5876
5877 Ok(bytes)
5878 }
5879
5880 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
5882 let mut bytes = Vec::new();
5883
5884 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5886 false,
5887 sm,
5888 &Reg::R12,
5889 )?));
5890
5891 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5893 false,
5894 sn,
5895 &Reg::R0,
5896 )?));
5897
5898 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5910 bytes.extend_from_slice(&hw2.to_le_bytes());
5911
5912 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
5916 bytes.extend_from_slice(&hw2.to_le_bytes());
5917
5918 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
5922 bytes.extend_from_slice(&hw2.to_le_bytes());
5923
5924 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
5926 true,
5927 sd,
5928 &Reg::R0,
5929 )?));
5930
5931 Ok(bytes)
5932 }
5933
5934 fn encode_thumb_f64_compare(
5936 &self,
5937 rd: &Reg,
5938 dn: &VfpReg,
5939 dm: &VfpReg,
5940 cond_code: u32,
5941 ) -> Result<Vec<u8>> {
5942 let mut bytes = Vec::new();
5943 let rd_bits = reg_to_bits(rd);
5944
5945 let dn_num = vfp_dreg_to_num(dn)?;
5947 let dm_num = vfp_dreg_to_num(dm)?;
5948 let (vd, d) = encode_dreg(dn_num);
5949 let (vm, m) = encode_dreg(dm_num);
5950 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
5951 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
5952
5953 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
5955
5956 if rd_bits < 8 {
5958 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
5959 bytes.extend_from_slice(&movs_zero.to_le_bytes());
5960 } else {
5961 let hw1: u16 = 0xF04F;
5962 let hw2: u16 = (rd_bits as u16) << 8;
5963 bytes.extend_from_slice(&hw1.to_le_bytes());
5964 bytes.extend_from_slice(&hw2.to_le_bytes());
5965 }
5966
5967 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
5969 bytes.extend_from_slice(&it.to_le_bytes());
5970
5971 if rd_bits < 8 {
5973 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
5974 bytes.extend_from_slice(&mov_one.to_le_bytes());
5975 } else {
5976 let hw1: u16 = 0xF04F;
5977 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
5978 bytes.extend_from_slice(&hw1.to_le_bytes());
5979 bytes.extend_from_slice(&hw2.to_le_bytes());
5980 }
5981
5982 Ok(bytes)
5983 }
5984
5985 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
5987 let mut bytes = Vec::new();
5988 let bits = value.to_bits();
5989 let lo32 = bits as u32;
5990 let hi32 = (bits >> 32) as u32;
5991
5992 let lo16 = lo32 & 0xFFFF;
5994 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
5995
5996 let hi16 = (lo32 >> 16) & 0xFFFF;
5998 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
5999
6000 let lo16 = hi32 & 0xFFFF;
6002 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6003
6004 let hi16 = (hi32 >> 16) & 0xFFFF;
6006 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6007
6008 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6010 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6011
6012 Ok(bytes)
6013 }
6014
6015 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6017 let mut bytes = Vec::new();
6018
6019 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6021 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6022
6023 let dd_num = vfp_dreg_to_num(dd)?;
6025 let (vd, d) = encode_dreg(dd_num);
6026 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6027 let vcvt = base | (d << 22) | (vd << 12);
6028 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6029
6030 Ok(bytes)
6031 }
6032
6033 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6035 let dd_num = vfp_dreg_to_num(dd)?;
6036 let sm_num = vfp_sreg_to_num(sm)?;
6037 let (vd, d) = encode_dreg(dd_num);
6038 let (vm, m) = encode_sreg(sm_num);
6039
6040 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6041 Ok(vfp_to_thumb_bytes(vcvt))
6042 }
6043
6044 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6046 let mut bytes = Vec::new();
6047 let dm_num = vfp_dreg_to_num(dm)?;
6048 let (vm, m) = encode_dreg(dm_num);
6049
6050 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6052 let vcvt = base | (m << 5) | vm;
6053 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6054
6055 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6057 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6058
6059 Ok(bytes)
6060 }
6061
6062 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6066 let mut bytes = Vec::new();
6067 let dm_num = vfp_dreg_to_num(dm)?;
6068 let dd_num = vfp_dreg_to_num(dd)?;
6069 let (vm, m) = encode_dreg(dm_num);
6070 let (vd, d) = encode_dreg(dd_num);
6071
6072 if mode == 0b11 {
6073 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
6075 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6076 } else {
6077 let rt: u32 = 12;
6078
6079 let vmrs = 0xEEF10A10 | (rt << 12);
6081 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6082
6083 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
6085 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6086 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6087 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6088
6089 if mode != 0 {
6091 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
6092 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6093 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6094 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6095 }
6096
6097 let vmsr = 0xEEE10A10 | (rt << 12);
6099 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6100
6101 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
6103 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6104
6105 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6107 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6108 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6109 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6110 }
6111
6112 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
6114 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6115
6116 Ok(bytes)
6117 }
6118
6119 fn encode_thumb_f64_minmax(
6121 &self,
6122 dd: &VfpReg,
6123 dn: &VfpReg,
6124 dm: &VfpReg,
6125 is_min: bool,
6126 ) -> Result<Vec<u8>> {
6127 let mut bytes = Vec::new();
6128 let dn_num = vfp_dreg_to_num(dn)?;
6129 let dm_num = vfp_dreg_to_num(dm)?;
6130 let dd_num = vfp_dreg_to_num(dd)?;
6131
6132 let (vd, d) = encode_dreg(dd_num);
6134 let (vn, n) = encode_dreg(dn_num);
6135 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6136 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
6137
6138 let (vm, m) = encode_dreg(dm_num);
6140 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6141 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6142
6143 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6145
6146 let cond: u16 = if is_min { 0xC } else { 0x4 };
6148 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6149 bytes.extend_from_slice(&it.to_le_bytes());
6150
6151 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6153 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
6154
6155 Ok(bytes)
6156 }
6157
6158 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
6160 let mut bytes = Vec::new();
6161
6162 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6164 false,
6165 dm,
6166 &Reg::R0,
6167 &Reg::R12,
6168 )?));
6169
6170 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6172 false,
6173 dn,
6174 &Reg::R1,
6175 &Reg::R2,
6176 )?));
6177
6178 let hw1: u16 = 0xF000 | 12;
6180 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
6181 bytes.extend_from_slice(&hw1.to_le_bytes());
6182 bytes.extend_from_slice(&hw2.to_le_bytes());
6183
6184 let hw1: u16 = 0xF020 | 2;
6186 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
6187 bytes.extend_from_slice(&hw1.to_le_bytes());
6188 bytes.extend_from_slice(&hw2.to_le_bytes());
6189
6190 let hw1: u16 = 0xEA40 | 2;
6192 let hw2: u16 = (2 << 8) | 12;
6193 bytes.extend_from_slice(&hw1.to_le_bytes());
6194 bytes.extend_from_slice(&hw2.to_le_bytes());
6195
6196 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
6198 true,
6199 dd,
6200 &Reg::R1,
6201 &Reg::R2,
6202 )?));
6203
6204 Ok(bytes)
6205 }
6206
6207 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6209 let mut bytes = Vec::new();
6210
6211 let sm_num = vfp_sreg_to_num(sm)?;
6212 let (vd, d) = encode_sreg(sm_num);
6213 let (vm, m) = encode_sreg(sm_num);
6214 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
6215 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6216 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6217
6218 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
6220 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6221
6222 Ok(bytes)
6223 }
6224
6225 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6229 let rd_bits = reg_to_bits(rd);
6230 let rn_bits = reg_to_bits(rn);
6231
6232 let i_bit = (imm >> 11) & 1;
6234 let imm3 = (imm >> 8) & 0x7;
6235 let imm8 = imm & 0xFF;
6236
6237 let hw1_base = if imm <= 0xFF {
6238 0xF100
6242 } else if imm <= 0xFFF {
6243 0xF200
6247 } else {
6248 return Err(synth_core::Error::synthesis(
6249 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6250 ));
6251 };
6252
6253 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6254 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6255
6256 let mut bytes = hw1.to_le_bytes().to_vec();
6257 bytes.extend_from_slice(&hw2.to_le_bytes());
6258 Ok(bytes)
6259 }
6260
6261 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6263 let rd_bits = reg_to_bits(rd);
6264 let rn_bits = reg_to_bits(rn);
6265
6266 let i_bit = (imm >> 11) & 1;
6267 let imm3 = (imm >> 8) & 0x7;
6268 let imm8 = imm & 0xFF;
6269
6270 let hw1_base = if imm <= 0xFF {
6271 0xF1A0
6274 } else if imm <= 0xFFF {
6275 0xF2A0
6278 } else {
6279 return Err(synth_core::Error::synthesis(
6280 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
6281 ));
6282 };
6283
6284 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
6285 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6286
6287 let mut bytes = hw1.to_le_bytes().to_vec();
6288 bytes.extend_from_slice(&hw2.to_le_bytes());
6289 Ok(bytes)
6290 }
6291
6292 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6294 let rd_bits = reg_to_bits(rd);
6295 let rn_bits = reg_to_bits(rn);
6296
6297 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6300 synth_core::Error::synthesis(
6301 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
6302 )
6303 })?;
6304 let i_bit = (field >> 11) & 1;
6305 let imm3 = (field >> 8) & 0x7;
6306 let imm8 = field & 0xFF;
6307
6308 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
6311 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6312
6313 let mut bytes = hw1.to_le_bytes().to_vec();
6314 bytes.extend_from_slice(&hw2.to_le_bytes());
6315 Ok(bytes)
6316 }
6317
6318 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6320 let rd_bits = reg_to_bits(rd);
6321 let rn_bits = reg_to_bits(rn);
6322
6323 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6326 synth_core::Error::synthesis(
6327 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
6328 )
6329 })?;
6330 let i_bit = (field >> 11) & 1;
6331 let imm3 = (field >> 8) & 0x7;
6332 let imm8 = field & 0xFF;
6333
6334 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6337 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6338
6339 let mut bytes = hw1.to_le_bytes().to_vec();
6340 bytes.extend_from_slice(&hw2.to_le_bytes());
6341 Ok(bytes)
6342 }
6343
6344 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
6353 let rd_bits = reg_to_bits(rd);
6354 reg_bits_checked(rd_bits)?;
6355 let imm16 = imm & 0xFFFF;
6356
6357 let imm4 = (imm16 >> 12) & 0xF;
6360 let i_bit = (imm16 >> 11) & 1;
6361 let imm3 = (imm16 >> 8) & 0x7;
6362 let imm8 = imm16 & 0xFF;
6363
6364 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6365 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6366
6367 let mut bytes = hw1.to_le_bytes().to_vec();
6368 bytes.extend_from_slice(&hw2.to_le_bytes());
6369 encoding_contracts::verify_thumb32(&bytes);
6370 Ok(bytes)
6371 }
6372
6373 fn encode_thumb32_shift(
6381 &self,
6382 rd: &Reg,
6383 rm: &Reg,
6384 shift: u32,
6385 shift_type: u8,
6386 ) -> Result<Vec<u8>> {
6387 let rd_bits = reg_to_bits(rd);
6388 let rm_bits = reg_to_bits(rm);
6389 reg_bits_checked(rd_bits)?;
6390 reg_bits_checked(rm_bits)?;
6391 let imm5 = shift & 0x1F;
6392 let imm2 = imm5 & 0x3;
6393 let imm3 = (imm5 >> 2) & 0x7;
6394
6395 let hw1: u16 = 0xEA4F;
6398 let hw2: u16 =
6399 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
6400 as u16;
6401
6402 let mut bytes = hw1.to_le_bytes().to_vec();
6403 bytes.extend_from_slice(&hw2.to_le_bytes());
6404 Ok(bytes)
6405 }
6406
6407 fn encode_thumb32_shift_reg(
6411 &self,
6412 rd: &Reg,
6413 rn: &Reg,
6414 rm: &Reg,
6415 shift_type: u8,
6416 ) -> Result<Vec<u8>> {
6417 let rd_bits = reg_to_bits(rd);
6418 let rn_bits = reg_to_bits(rn);
6419 let rm_bits = reg_to_bits(rm);
6420
6421 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
6423 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
6425
6426 let mut bytes = hw1.to_le_bytes().to_vec();
6427 bytes.extend_from_slice(&hw2.to_le_bytes());
6428 Ok(bytes)
6429 }
6430
6431 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6433 let rn_bits = reg_to_bits(rn);
6434
6435 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
6439 synth_core::Error::synthesis(
6440 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
6441 )
6442 })?;
6443 let i_bit = (field >> 11) & 1;
6444 let imm3 = (field >> 8) & 0x7;
6445 let imm8 = field & 0xFF;
6446
6447 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
6449 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
6450
6451 let mut bytes = hw1.to_le_bytes().to_vec();
6452 bytes.extend_from_slice(&hw2.to_le_bytes());
6453 Ok(bytes)
6454 }
6455
6456 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
6478 let offset = if addr.offset < 0 {
6479 0u32
6480 } else {
6481 addr.offset as u32
6482 };
6483 match addr.offset_reg {
6484 Some(idx) => {
6485 let ip = Reg::R12;
6486 if offset.wrapping_add(4) > 0xFFF {
6487 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
6491 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
6493 reg_to_bits(&ip),
6494 reg_to_bits(&ip),
6495 reg_to_bits(&addr.base),
6496 )?);
6497 Ok((ip, 0))
6498 } else {
6499 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
6501 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
6502 bytes.extend_from_slice(&hw1.to_le_bytes());
6503 bytes.extend_from_slice(&hw2.to_le_bytes());
6504 Ok((ip, offset))
6505 }
6506 }
6507 None => Ok((addr.base, offset)),
6508 }
6509 }
6510
6511 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6513 let rd_bits = reg_to_bits(rd);
6514 let base_bits = reg_to_bits(base);
6515
6516 check_ldst_imm12(offset)?;
6518 let hw1: u16 = (0xF8D0 | base_bits) as u16;
6519 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6520
6521 let mut bytes = hw1.to_le_bytes().to_vec();
6522 bytes.extend_from_slice(&hw2.to_le_bytes());
6523 Ok(bytes)
6524 }
6525
6526 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6528 let rd_bits = reg_to_bits(rd);
6529 let base_bits = reg_to_bits(base);
6530
6531 check_ldst_imm12(offset)?;
6533 let hw1: u16 = (0xF8C0 | base_bits) as u16;
6534 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6535
6536 let mut bytes = hw1.to_le_bytes().to_vec();
6537 bytes.extend_from_slice(&hw2.to_le_bytes());
6538 Ok(bytes)
6539 }
6540
6541 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6543 let rd_bits = reg_to_bits(rd);
6544 let base_bits = reg_to_bits(base);
6545 let rm_bits = reg_to_bits(offset_reg);
6546
6547 let hw1: u16 = (0xF850 | base_bits) as u16;
6551 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6552
6553 let mut bytes = hw1.to_le_bytes().to_vec();
6554 bytes.extend_from_slice(&hw2.to_le_bytes());
6555 Ok(bytes)
6556 }
6557
6558 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6560 let rd_bits = reg_to_bits(rd);
6561 let base_bits = reg_to_bits(base);
6562 let rm_bits = reg_to_bits(offset_reg);
6563
6564 let hw1: u16 = (0xF840 | base_bits) as u16;
6568 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6569
6570 let mut bytes = hw1.to_le_bytes().to_vec();
6571 bytes.extend_from_slice(&hw2.to_le_bytes());
6572 Ok(bytes)
6573 }
6574
6575 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6579 let rd_bits = reg_to_bits(rd);
6580 let base_bits = reg_to_bits(base);
6581 check_ldst_imm12(offset)?;
6583 let hw1: u16 = (0xF890 | base_bits) as u16;
6584 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6585 let mut bytes = hw1.to_le_bytes().to_vec();
6586 bytes.extend_from_slice(&hw2.to_le_bytes());
6587 Ok(bytes)
6588 }
6589
6590 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6592 let rd_bits = reg_to_bits(rd);
6593 let base_bits = reg_to_bits(base);
6594 let rm_bits = reg_to_bits(offset_reg);
6595 let hw1: u16 = (0xF810 | base_bits) as u16;
6597 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6598 let mut bytes = hw1.to_le_bytes().to_vec();
6599 bytes.extend_from_slice(&hw2.to_le_bytes());
6600 Ok(bytes)
6601 }
6602
6603 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6605 let rd_bits = reg_to_bits(rd);
6606 let base_bits = reg_to_bits(base);
6607 check_ldst_imm12(offset)?;
6609 let hw1: u16 = (0xF990 | base_bits) as u16;
6610 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6611 let mut bytes = hw1.to_le_bytes().to_vec();
6612 bytes.extend_from_slice(&hw2.to_le_bytes());
6613 Ok(bytes)
6614 }
6615
6616 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6618 let rd_bits = reg_to_bits(rd);
6619 let base_bits = reg_to_bits(base);
6620 let rm_bits = reg_to_bits(offset_reg);
6621 let hw1: u16 = (0xF910 | base_bits) as u16;
6623 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6624 let mut bytes = hw1.to_le_bytes().to_vec();
6625 bytes.extend_from_slice(&hw2.to_le_bytes());
6626 Ok(bytes)
6627 }
6628
6629 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6631 let rd_bits = reg_to_bits(rd);
6632 let base_bits = reg_to_bits(base);
6633 check_ldst_imm12(offset)?;
6635 let hw1: u16 = (0xF8B0 | base_bits) as u16;
6636 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6637 let mut bytes = hw1.to_le_bytes().to_vec();
6638 bytes.extend_from_slice(&hw2.to_le_bytes());
6639 Ok(bytes)
6640 }
6641
6642 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6644 let rd_bits = reg_to_bits(rd);
6645 let base_bits = reg_to_bits(base);
6646 let rm_bits = reg_to_bits(offset_reg);
6647 let hw1: u16 = (0xF830 | base_bits) as u16;
6649 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6650 let mut bytes = hw1.to_le_bytes().to_vec();
6651 bytes.extend_from_slice(&hw2.to_le_bytes());
6652 Ok(bytes)
6653 }
6654
6655 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6657 let rd_bits = reg_to_bits(rd);
6658 let base_bits = reg_to_bits(base);
6659 check_ldst_imm12(offset)?;
6661 let hw1: u16 = (0xF9B0 | base_bits) as u16;
6662 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6663 let mut bytes = hw1.to_le_bytes().to_vec();
6664 bytes.extend_from_slice(&hw2.to_le_bytes());
6665 Ok(bytes)
6666 }
6667
6668 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6670 let rd_bits = reg_to_bits(rd);
6671 let base_bits = reg_to_bits(base);
6672 let rm_bits = reg_to_bits(offset_reg);
6673 let hw1: u16 = (0xF930 | base_bits) as u16;
6675 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6676 let mut bytes = hw1.to_le_bytes().to_vec();
6677 bytes.extend_from_slice(&hw2.to_le_bytes());
6678 Ok(bytes)
6679 }
6680
6681 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6683 let rd_bits = reg_to_bits(rd);
6684 let base_bits = reg_to_bits(base);
6685 check_ldst_imm12(offset)?;
6687 let hw1: u16 = (0xF880 | base_bits) as u16;
6688 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6689 let mut bytes = hw1.to_le_bytes().to_vec();
6690 bytes.extend_from_slice(&hw2.to_le_bytes());
6691 Ok(bytes)
6692 }
6693
6694 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6696 let rd_bits = reg_to_bits(rd);
6697 let base_bits = reg_to_bits(base);
6698 let rm_bits = reg_to_bits(offset_reg);
6699 let hw1: u16 = (0xF800 | base_bits) as u16;
6701 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6702 let mut bytes = hw1.to_le_bytes().to_vec();
6703 bytes.extend_from_slice(&hw2.to_le_bytes());
6704 Ok(bytes)
6705 }
6706
6707 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
6709 let rd_bits = reg_to_bits(rd);
6710 let base_bits = reg_to_bits(base);
6711 check_ldst_imm12(offset)?;
6713 let hw1: u16 = (0xF8A0 | base_bits) as u16;
6714 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
6715 let mut bytes = hw1.to_le_bytes().to_vec();
6716 bytes.extend_from_slice(&hw2.to_le_bytes());
6717 Ok(bytes)
6718 }
6719
6720 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
6722 let rd_bits = reg_to_bits(rd);
6723 let base_bits = reg_to_bits(base);
6724 let rm_bits = reg_to_bits(offset_reg);
6725 let hw1: u16 = (0xF820 | base_bits) as u16;
6727 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
6728 let mut bytes = hw1.to_le_bytes().to_vec();
6729 bytes.extend_from_slice(&hw2.to_le_bytes());
6730 Ok(bytes)
6731 }
6732
6733 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
6735 let rd_bits = reg_to_bits(rd);
6736 let rn_bits = reg_to_bits(rn);
6737
6738 if imm <= 0xFFF {
6744 let i_bit = (imm >> 11) & 1;
6745 let imm3 = (imm >> 8) & 0x7;
6746 let imm8 = imm & 0xFF;
6747
6748 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
6749 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
6750
6751 let mut bytes = hw1.to_le_bytes().to_vec();
6752 bytes.extend_from_slice(&hw2.to_le_bytes());
6753 Ok(bytes)
6754 } else {
6755 let scratch: u32 = if rd_bits == rn_bits {
6769 12 } else {
6771 rd_bits };
6773 if scratch == rn_bits {
6781 return Err(synth_core::Error::synthesis(format!(
6782 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
6783 register (R12 is the reserved encoder scratch and aliases Rn here)"
6784 )));
6785 }
6786
6787 let lo16 = imm & 0xFFFF;
6788 let hi16 = (imm >> 16) & 0xFFFF;
6789
6790 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
6791 if hi16 != 0 {
6792 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
6793 }
6794 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
6795 Ok(bytes)
6796 }
6797 }
6798
6799 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6809 reg_bits_checked(rd)?;
6810 encoding_contracts::verify_imm16(imm16);
6811 let imm16 = imm16 & 0xFFFF;
6814 let imm4 = (imm16 >> 12) & 0xF;
6815 let i_bit = (imm16 >> 11) & 1;
6816 let imm3 = (imm16 >> 8) & 0x7;
6817 let imm8 = imm16 & 0xFF;
6818
6819 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6820 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6821
6822 let mut bytes = hw1.to_le_bytes().to_vec();
6823 bytes.extend_from_slice(&hw2.to_le_bytes());
6824 encoding_contracts::verify_thumb32(&bytes);
6825 Ok(bytes)
6826 }
6827
6828 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
6836 reg_bits_checked(rd)?;
6837 encoding_contracts::verify_imm16(imm16);
6838 let imm16 = imm16 & 0xFFFF;
6841 let imm4 = (imm16 >> 12) & 0xF;
6842 let i_bit = (imm16 >> 11) & 1;
6843 let imm3 = (imm16 >> 8) & 0x7;
6844 let imm8 = imm16 & 0xFF;
6845
6846 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6847 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6848
6849 let mut bytes = hw1.to_le_bytes().to_vec();
6850 bytes.extend_from_slice(&hw2.to_le_bytes());
6851 encoding_contracts::verify_thumb32(&bytes);
6852 Ok(bytes)
6853 }
6854
6855 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
6857 let imm5 = shift & 0x1F;
6860 let imm2 = imm5 & 0x3;
6861 let imm3 = (imm5 >> 2) & 0x7;
6862
6863 let hw1: u16 = 0xEA4F;
6864 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
6865
6866 let mut bytes = hw1.to_le_bytes().to_vec();
6867 bytes.extend_from_slice(&hw2.to_le_bytes());
6868 Ok(bytes)
6869 }
6870
6871 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6873 let hw1: u16 = (0xEA00 | rn) as u16;
6876 let hw2: u16 = ((rd << 8) | rm) as u16;
6877
6878 let mut bytes = hw1.to_le_bytes().to_vec();
6879 bytes.extend_from_slice(&hw2.to_le_bytes());
6880 Ok(bytes)
6881 }
6882
6883 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
6885 let i_bit = (imm >> 11) & 1;
6889 let imm3 = (imm >> 8) & 0x7;
6890 let imm8 = imm & 0xFF;
6891
6892 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
6893 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
6894
6895 let mut bytes = hw1.to_le_bytes().to_vec();
6896 bytes.extend_from_slice(&hw2.to_le_bytes());
6897 Ok(bytes)
6898 }
6899
6900 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6902 let hw1: u16 = (0xEBA0 | rn) as u16;
6905 let hw2: u16 = ((rd << 8) | rm) as u16;
6906
6907 let mut bytes = hw1.to_le_bytes().to_vec();
6908 bytes.extend_from_slice(&hw2.to_le_bytes());
6909 Ok(bytes)
6910 }
6911
6912 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6914 let hw1: u16 = (0xEB00 | rn) as u16;
6917 let hw2: u16 = ((rd << 8) | rm) as u16;
6918
6919 let mut bytes = hw1.to_le_bytes().to_vec();
6920 bytes.extend_from_slice(&hw2.to_le_bytes());
6921 Ok(bytes)
6922 }
6923
6924 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6928 let hw1: u16 = (0xEB10 | rn) as u16;
6930 let hw2: u16 = ((rd << 8) | rm) as u16;
6931 let mut bytes = hw1.to_le_bytes().to_vec();
6932 bytes.extend_from_slice(&hw2.to_le_bytes());
6933 Ok(bytes)
6934 }
6935
6936 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
6939 let hw1: u16 = (0xEBB0 | rn) as u16;
6941 let hw2: u16 = ((rd << 8) | rm) as u16;
6942 let mut bytes = hw1.to_le_bytes().to_vec();
6943 bytes.extend_from_slice(&hw2.to_le_bytes());
6944 Ok(bytes)
6945 }
6946
6947 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
6949 let mut code = Vec::new();
6950
6951 for op in ops {
6952 let encoded = self.encode(op)?;
6953 code.extend_from_slice(&encoded);
6954 }
6955
6956 Ok(code)
6957 }
6958}
6959
6960fn try_thumb_expand_imm(value: u32) -> Option<u32> {
6968 if value <= 0xFF {
6970 return Some(value);
6971 }
6972 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
6976 return Some(0x100 | b0);
6977 }
6978 if value == (b1 << 24) | (b1 << 8) {
6980 return Some(0x200 | b1);
6981 }
6982 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
6984 return Some(0x300 | b0);
6985 }
6986 for rot in 8..=31u32 {
6990 let unrot = value.rotate_left(rot);
6991 if (0x80..=0xFF).contains(&unrot) {
6992 return Some((rot << 7) | (unrot & 0x7F));
6993 }
6994 }
6995 None
6996}
6997
6998fn check_ldst_imm12(offset: u32) -> Result<()> {
7004 if offset > 0xFFF {
7005 Err(synth_core::Error::synthesis(
7006 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7007 ))
7008 } else {
7009 Ok(())
7010 }
7011}
7012
7013fn reg_to_bits(reg: &Reg) -> u32 {
7014 match reg {
7015 Reg::R0 => 0,
7016 Reg::R1 => 1,
7017 Reg::R2 => 2,
7018 Reg::R3 => 3,
7019 Reg::R4 => 4,
7020 Reg::R5 => 5,
7021 Reg::R6 => 6,
7022 Reg::R7 => 7,
7023 Reg::R8 => 8,
7024 Reg::R9 => 9,
7025 Reg::R10 => 10,
7026 Reg::R11 => 11,
7027 Reg::R12 => 12,
7028 Reg::SP => 13,
7029 Reg::LR => 14,
7030 Reg::PC => 15,
7031 }
7032}
7033
7034fn reg_bits_checked(bits: u32) -> Result<()> {
7042 if bits > 14 {
7043 return Err(synth_core::Error::synthesis(format!(
7044 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
7045 )));
7046 }
7047 Ok(())
7048}
7049
7050fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
7053 if val == 0 {
7054 return Some((0, 1));
7055 }
7056 for rot in 0..16u32 {
7057 let shift = rot * 2;
7058 let unrotated = val.rotate_left(shift);
7060 if unrotated <= 0xFF {
7061 return Some(((rot << 8) | unrotated, 1));
7063 }
7064 }
7065 None
7066}
7067
7068fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
7073 match op2 {
7074 Operand2::Imm(val) => {
7075 let uval = *val as u32;
7076 if let Some(encoded) = try_encode_rotated_imm(uval) {
7078 Ok(encoded)
7079 } else {
7080 Err(synth_core::Error::synthesis(format!(
7089 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
7090 rotated immediate — the selector must materialize large \
7091 constants via MOVW/MOVT"
7092 )))
7093 }
7094 }
7095
7096 Operand2::Reg(reg) => {
7097 let reg_bits = reg_to_bits(reg);
7098 Ok((reg_bits, 0)) }
7100
7101 Operand2::RegShift {
7102 rm,
7103 shift: _,
7104 amount,
7105 } => {
7106 let rm_bits = reg_to_bits(rm);
7108 let shift_bits = (*amount & 0x1F) << 7;
7109 Ok((shift_bits | rm_bits, 0))
7110 }
7111 }
7112}
7113
7114fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
7116 let base_bits = reg_to_bits(&addr.base);
7117 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
7119}
7120
7121fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
7123 match reg {
7124 VfpReg::S0 => Ok(0),
7125 VfpReg::S1 => Ok(1),
7126 VfpReg::S2 => Ok(2),
7127 VfpReg::S3 => Ok(3),
7128 VfpReg::S4 => Ok(4),
7129 VfpReg::S5 => Ok(5),
7130 VfpReg::S6 => Ok(6),
7131 VfpReg::S7 => Ok(7),
7132 VfpReg::S8 => Ok(8),
7133 VfpReg::S9 => Ok(9),
7134 VfpReg::S10 => Ok(10),
7135 VfpReg::S11 => Ok(11),
7136 VfpReg::S12 => Ok(12),
7137 VfpReg::S13 => Ok(13),
7138 VfpReg::S14 => Ok(14),
7139 VfpReg::S15 => Ok(15),
7140 VfpReg::S16 => Ok(16),
7141 VfpReg::S17 => Ok(17),
7142 VfpReg::S18 => Ok(18),
7143 VfpReg::S19 => Ok(19),
7144 VfpReg::S20 => Ok(20),
7145 VfpReg::S21 => Ok(21),
7146 VfpReg::S22 => Ok(22),
7147 VfpReg::S23 => Ok(23),
7148 VfpReg::S24 => Ok(24),
7149 VfpReg::S25 => Ok(25),
7150 VfpReg::S26 => Ok(26),
7151 VfpReg::S27 => Ok(27),
7152 VfpReg::S28 => Ok(28),
7153 VfpReg::S29 => Ok(29),
7154 VfpReg::S30 => Ok(30),
7155 VfpReg::S31 => Ok(31),
7156 _ => Err(synth_core::Error::SynthesisError(
7158 "D-register not supported in single-precision VFP encoding".to_string(),
7159 )),
7160 }
7161}
7162
7163fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
7165 match reg {
7166 VfpReg::D0 => Ok(0),
7167 VfpReg::D1 => Ok(1),
7168 VfpReg::D2 => Ok(2),
7169 VfpReg::D3 => Ok(3),
7170 VfpReg::D4 => Ok(4),
7171 VfpReg::D5 => Ok(5),
7172 VfpReg::D6 => Ok(6),
7173 VfpReg::D7 => Ok(7),
7174 VfpReg::D8 => Ok(8),
7175 VfpReg::D9 => Ok(9),
7176 VfpReg::D10 => Ok(10),
7177 VfpReg::D11 => Ok(11),
7178 VfpReg::D12 => Ok(12),
7179 VfpReg::D13 => Ok(13),
7180 VfpReg::D14 => Ok(14),
7181 VfpReg::D15 => Ok(15),
7182 _ => Err(synth_core::Error::SynthesisError(
7184 "S-register not supported in double-precision VFP encoding".to_string(),
7185 )),
7186 }
7187}
7188
7189fn encode_sreg(s: u32) -> (u32, u32) {
7193 (s >> 1, s & 1)
7194}
7195
7196fn encode_dreg(d: u32) -> (u32, u32) {
7200 (d & 0xF, (d >> 4) & 1)
7201}
7202
7203fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
7209 let sd_num = vfp_sreg_to_num(sd)?;
7210 let sn_num = vfp_sreg_to_num(sn)?;
7211 let sm_num = vfp_sreg_to_num(sm)?;
7212 let (vd, d) = encode_sreg(sd_num);
7213 let (vn, n) = encode_sreg(sn_num);
7214 let (vm, m) = encode_sreg(sm_num);
7215
7216 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7217}
7218
7219fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
7222 let sd_num = vfp_sreg_to_num(sd)?;
7223 let sm_num = vfp_sreg_to_num(sm)?;
7224 let (vd, d) = encode_sreg(sd_num);
7225 let (vm, m) = encode_sreg(sm_num);
7226
7227 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7228}
7229
7230fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7234 let sd_num = vfp_sreg_to_num(sd)?;
7235 let (vd, d) = encode_sreg(sd_num);
7236 let rn = reg_to_bits(&addr.base);
7237
7238 let offset = addr.offset;
7239 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7240 let abs_offset = offset.unsigned_abs();
7241 let imm8 = (abs_offset / 4) & 0xFF;
7242
7243 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7244}
7245
7246fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
7250 let s_num = vfp_sreg_to_num(sreg)?;
7251 let (vn, n) = encode_sreg(s_num);
7252 let rt = reg_to_bits(core);
7253
7254 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
7255 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
7256}
7257
7258fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
7262 let dd_num = vfp_dreg_to_num(dd)?;
7263 let dn_num = vfp_dreg_to_num(dn)?;
7264 let dm_num = vfp_dreg_to_num(dm)?;
7265 let (vd, d) = encode_dreg(dd_num);
7266 let (vn, n) = encode_dreg(dn_num);
7267 let (vm, m) = encode_dreg(dm_num);
7268
7269 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
7270}
7271
7272fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
7274 let dd_num = vfp_dreg_to_num(dd)?;
7275 let dm_num = vfp_dreg_to_num(dm)?;
7276 let (vd, d) = encode_dreg(dd_num);
7277 let (vm, m) = encode_dreg(dm_num);
7278
7279 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
7280}
7281
7282fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
7285 let dd_num = vfp_dreg_to_num(dd)?;
7286 let (vd, d) = encode_dreg(dd_num);
7287 let rn = reg_to_bits(&addr.base);
7288
7289 let offset = addr.offset;
7290 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7291 let abs_offset = offset.unsigned_abs();
7292 let imm8 = (abs_offset / 4) & 0xFF;
7293
7294 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
7295}
7296
7297fn encode_vmov_core_dreg(
7301 to_dreg: bool,
7302 dreg: &VfpReg,
7303 core_lo: &Reg,
7304 core_hi: &Reg,
7305) -> Result<u32> {
7306 let d_num = vfp_dreg_to_num(dreg)?;
7307 let (vm, m) = encode_dreg(d_num);
7308 let rt = reg_to_bits(core_lo);
7309 let rt2 = reg_to_bits(core_hi);
7310
7311 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
7312 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
7313}
7314
7315fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
7317 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
7318 let hw2 = (instr & 0xFFFF) as u16;
7319 let mut bytes = hw1.to_le_bytes().to_vec();
7320 bytes.extend_from_slice(&hw2.to_le_bytes());
7321 bytes
7322}
7323
7324fn qreg_to_num(reg: &QReg) -> u32 {
7330 match reg {
7331 QReg::Q0 => 0,
7332 QReg::Q1 => 1,
7333 QReg::Q2 => 2,
7334 QReg::Q3 => 3,
7335 QReg::Q4 => 4,
7336 QReg::Q5 => 5,
7337 QReg::Q6 => 6,
7338 QReg::Q7 => 7,
7339 }
7340}
7341
7342fn mve_size_bits(size: &MveSize) -> u32 {
7344 match size {
7345 MveSize::S8 => 0b00,
7346 MveSize::S16 => 0b01,
7347 MveSize::S32 => 0b10,
7348 }
7349}
7350
7351fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7355 let d = qreg_to_num(qd) * 2;
7356 let n = qreg_to_num(qn) * 2;
7357 let m = qreg_to_num(qm) * 2;
7358
7359 let vd = d & 0xF;
7364 let d_bit = (d >> 4) & 1;
7365 let vn = n & 0xF;
7366 let n_bit = (n >> 4) & 1;
7367 let vm = m & 0xF;
7368 let m_bit = (m >> 4) & 1;
7369
7370 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
7371}
7372
7373fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
7375 encode_mve_3reg(base, qd, qn, qm)
7376}
7377
7378fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
7381 let qd_enc = qreg_to_num(qd) * 2;
7382 let rn = reg_to_bits(&addr.base);
7383 let offset = addr.offset;
7384 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7385 let abs_offset = offset.unsigned_abs();
7386 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
7390 | (u_bit << 23)
7391 | ((qd_enc >> 4) << 22)
7392 | (rn << 16)
7393 | ((qd_enc & 0xF) << 12)
7394 | (imm7 & 0x7F)
7395}
7396
7397fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
7399 let qd_enc = qreg_to_num(qd) * 2;
7400 let rn = reg_to_bits(&addr.base);
7401 let offset = addr.offset;
7402 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
7403 let abs_offset = offset.unsigned_abs();
7404 let imm7 = (abs_offset / 4) & 0x7F;
7405
7406 0xED000E80
7407 | (u_bit << 23)
7408 | ((qd_enc >> 4) << 22)
7409 | (rn << 16)
7410 | ((qd_enc & 0xF) << 12)
7411 | (imm7 & 0x7F)
7412}
7413
7414impl ArmEncoder {
7415 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
7417 let mut result = Vec::new();
7418 let qd_num = qreg_to_num(qd);
7419
7420 for i in 0..4 {
7422 let word = u32::from_le_bytes([
7423 bytes[i * 4],
7424 bytes[i * 4 + 1],
7425 bytes[i * 4 + 2],
7426 bytes[i * 4 + 3],
7427 ]);
7428 let lo16 = word & 0xFFFF;
7429 let hi16 = (word >> 16) & 0xFFFF;
7430
7431 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7433 if hi16 != 0 {
7435 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7436 }
7437
7438 let s_num = qd_num * 4 + i as u32;
7440 let (vn, n) = encode_sreg(s_num);
7441 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
7442 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7443 }
7444
7445 Ok(result)
7446 }
7447
7448 fn encode_thumb_mve_lane_wise_f32_binop(
7450 &self,
7451 qd: &QReg,
7452 qn: &QReg,
7453 qm: &QReg,
7454 vfp_base: u32,
7455 ) -> Result<Vec<u8>> {
7456 let mut result = Vec::new();
7457 let qd_num = qreg_to_num(qd);
7458 let qn_num = qreg_to_num(qn);
7459 let qm_num = qreg_to_num(qm);
7460
7461 for i in 0..4u32 {
7463 let sd = qd_num * 4 + i;
7464 let sn = qn_num * 4 + i;
7465 let sm = qm_num * 4 + i;
7466
7467 let (vd, d) = encode_sreg(sd);
7468 let (vn, n) = encode_sreg(sn);
7469 let (vm, m) = encode_sreg(sm);
7470
7471 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7472 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7473 }
7474
7475 Ok(result)
7476 }
7477
7478 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
7480 let mut result = Vec::new();
7481 let qd_num = qreg_to_num(qd);
7482 let qm_num = qreg_to_num(qm);
7483
7484 for i in 0..4u32 {
7486 let sd = qd_num * 4 + i;
7487 let sm = qm_num * 4 + i;
7488
7489 let (vd, d) = encode_sreg(sd);
7490 let (vm, m) = encode_sreg(sm);
7491
7492 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7493 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
7494 }
7495
7496 Ok(result)
7497 }
7498}
7499
7500#[cfg(test)]
7501mod tests {
7502 use super::*;
7503
7504 #[test]
7505 fn test_encoder_creation() {
7506 let encoder_arm = ArmEncoder::new_arm32();
7507 assert!(!encoder_arm.thumb_mode);
7508
7509 let encoder_thumb = ArmEncoder::new_thumb2();
7510 assert!(encoder_thumb.thumb_mode);
7511 }
7512
7513 #[test]
7525 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
7526 use synth_synthesis::{ArmOp, Condition, Reg};
7527 let enc = ArmEncoder::new_thumb2();
7528 let bytes = enc
7529 .encode(&ArmOp::I64SetCond {
7530 rd: Reg::R8,
7531 rn_lo: Reg::R2,
7532 rn_hi: Reg::R3,
7533 rm_lo: Reg::R6,
7534 rm_hi: Reg::R7,
7535 cond: Condition::EQ,
7536 })
7537 .unwrap();
7538 let halfwords: Vec<u16> = bytes
7541 .chunks(2)
7542 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7543 .collect();
7544 assert!(
7545 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
7546 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
7547 );
7548 assert!(
7549 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
7550 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
7551 );
7552
7553 let bytes_z = enc
7554 .encode(&ArmOp::I64SetCondZ {
7555 rd: Reg::R8,
7556 rn_lo: Reg::R2,
7557 rn_hi: Reg::R3,
7558 })
7559 .unwrap();
7560 let hw_z: Vec<u16> = bytes_z
7561 .chunks(2)
7562 .map(|c| u16::from_le_bytes([c[0], c[1]]))
7563 .collect();
7564 assert!(
7565 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
7566 "SetCondZ high rd MOV.W: {hw_z:04x?}"
7567 );
7568 assert!(
7570 hw_z.contains(&(0xF1B0 | 8)),
7571 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
7572 );
7573 }
7574
7575 #[test]
7576 fn test_encode_setcond_high_reg_uses_mov_w_204() {
7577 use synth_synthesis::{ArmOp, Condition, Reg};
7578 let enc = ArmEncoder::new_thumb2();
7579 let hi = enc
7581 .encode(&ArmOp::SetCond {
7582 rd: Reg::R12,
7583 cond: Condition::NE,
7584 })
7585 .unwrap();
7586 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
7587 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
7589 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
7590 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
7591 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
7592 let lo = enc
7594 .encode(&ArmOp::SetCond {
7595 rd: Reg::R0,
7596 cond: Condition::NE,
7597 })
7598 .unwrap();
7599 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
7600 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
7601 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
7602 }
7603
7604 #[test]
7608 fn test_encode_umull_209b() {
7609 use synth_synthesis::{ArmOp, Reg};
7610 let op = ArmOp::Umull {
7611 rdlo: Reg::R4,
7612 rdhi: Reg::R5,
7613 rn: Reg::R0,
7614 rm: Reg::R3,
7615 };
7616 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
7618 assert_eq!(
7619 t,
7620 vec![0xA0, 0xFB, 0x03, 0x45],
7621 "umull r4,r5,r0,r3 (T2): {t:02x?}"
7622 );
7623 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
7625 assert_eq!(
7626 a,
7627 0xE085_4390u32.to_le_bytes().to_vec(),
7628 "umull (A32): {a:02x?}"
7629 );
7630 }
7631
7632 #[test]
7639 fn test_encode_arm32_indexed_load_keeps_index_206() {
7640 use synth_synthesis::{ArmOp, MemAddr, Reg};
7641 let enc = ArmEncoder::new_arm32();
7642 let bytes = enc
7644 .encode(&ArmOp::Ldr {
7645 rd: Reg::R0,
7646 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
7647 })
7648 .unwrap();
7649 assert_eq!(
7650 bytes.len(),
7651 8,
7652 "expected ADD ip + LDR (2 words): {bytes:02x?}"
7653 );
7654 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7655 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7656 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
7658 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
7660 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
7662 }
7663
7664 #[test]
7670 fn test_encode_arm32_call_indirect_is_real_call_594() {
7671 use synth_synthesis::{ArmOp, Reg};
7672 let enc = ArmEncoder::new_arm32();
7673 let bytes = enc
7674 .encode(&ArmOp::CallIndirect {
7675 rd: Reg::R0,
7676 type_idx: 0,
7677 table_index_reg: Reg::R0,
7678 })
7679 .unwrap();
7680 assert_eq!(
7681 bytes.len(),
7682 12,
7683 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
7684 );
7685 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7686 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
7687 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
7688 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
7690 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
7692 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
7694 assert!(
7696 !bytes
7697 .chunks_exact(4)
7698 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
7699 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
7700 );
7701
7702 let bytes = enc
7704 .encode(&ArmOp::CallIndirect {
7705 rd: Reg::R0,
7706 type_idx: 0,
7707 table_index_reg: Reg::R4,
7708 })
7709 .unwrap();
7710 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
7711 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
7712 }
7713
7714 #[test]
7730 fn test_encode_thumb_call_indirect_lsl2_597() {
7731 use synth_synthesis::{ArmOp, Reg};
7732 let enc = ArmEncoder::new_thumb2();
7733 let bytes = enc
7734 .encode(&ArmOp::CallIndirect {
7735 rd: Reg::R0,
7736 type_idx: 0,
7737 table_index_reg: Reg::R0,
7738 })
7739 .unwrap();
7740 assert_eq!(
7741 bytes,
7742 vec![0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
7743 "Thumb-2 CallIndirect: mov.w ip,r0,LSL#2; ldr.w ip,[r11,ip]; blx ip: {bytes:02x?}"
7744 );
7745 assert_ne!(
7747 &bytes[0..4],
7748 &[0x4F, 0xEA, 0x20, 0x0C],
7749 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
7750 );
7751
7752 let bytes = enc
7754 .encode(&ArmOp::CallIndirect {
7755 rd: Reg::R0,
7756 type_idx: 0,
7757 table_index_reg: Reg::R4,
7758 })
7759 .unwrap();
7760 assert_eq!(
7761 &bytes[0..4],
7762 &[0x4F, 0xEA, 0x84, 0x0C],
7763 "mov.w ip, r4, LSL #2: {bytes:02x?}"
7764 );
7765 }
7766
7767 #[test]
7774 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
7775 let encoder = ArmEncoder::new_thumb2();
7776
7777 let code = encoder
7779 .encode(&ArmOp::Add {
7780 rd: Reg::R12,
7781 rn: Reg::R12,
7782 op2: Operand2::Reg(Reg::R0),
7783 })
7784 .unwrap();
7785 assert_eq!(
7787 code,
7788 vec![0x0C, 0xEB, 0x00, 0x0C],
7789 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
7790 );
7791 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
7793
7794 let lo = encoder
7796 .encode(&ArmOp::Add {
7797 rd: Reg::R1,
7798 rn: Reg::R2,
7799 op2: Operand2::Reg(Reg::R3),
7800 })
7801 .unwrap();
7802 assert_eq!(
7803 lo.len(),
7804 2,
7805 "low-reg ADD should remain 16-bit, got {lo:02X?}"
7806 );
7807 }
7808
7809 #[test]
7812 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
7813 let encoder = ArmEncoder::new_thumb2();
7814
7815 let adds = encoder
7817 .encode(&ArmOp::Adds {
7818 rd: Reg::R10,
7819 rn: Reg::R10,
7820 op2: Operand2::Reg(Reg::R8),
7821 })
7822 .unwrap();
7823 assert_eq!(
7824 adds,
7825 vec![0x1A, 0xEB, 0x08, 0x0A],
7826 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
7827 );
7828
7829 let subs = encoder
7831 .encode(&ArmOp::Subs {
7832 rd: Reg::R10,
7833 rn: Reg::R10,
7834 op2: Operand2::Reg(Reg::R8),
7835 })
7836 .unwrap();
7837 assert_eq!(
7838 subs,
7839 vec![0xBA, 0xEB, 0x08, 0x0A],
7840 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
7841 );
7842 }
7843
7844 #[test]
7847 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
7848 let encoder = ArmEncoder::new_thumb2();
7849
7850 let cmn = encoder
7852 .encode(&ArmOp::Cmn {
7853 rn: Reg::R10,
7854 op2: Operand2::Reg(Reg::R8),
7855 })
7856 .unwrap();
7857 assert_eq!(
7858 cmn,
7859 vec![0x1A, 0xEB, 0x08, 0x0F],
7860 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
7861 );
7862
7863 let lo = encoder
7865 .encode(&ArmOp::Cmn {
7866 rn: Reg::R1,
7867 op2: Operand2::Reg(Reg::R2),
7868 })
7869 .unwrap();
7870 assert_eq!(
7871 lo.len(),
7872 2,
7873 "low-reg CMN should remain 16-bit, got {lo:02X?}"
7874 );
7875 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
7876 }
7877
7878 #[test]
7882 fn test_encode_pc_operand_returns_err_not_panic_185() {
7883 let encoder = ArmEncoder::new_thumb2();
7884 for op in [
7885 ArmOp::Sdiv {
7886 rd: Reg::PC,
7887 rn: Reg::R0,
7888 rm: Reg::R1,
7889 },
7890 ArmOp::Udiv {
7891 rd: Reg::R0,
7892 rn: Reg::PC,
7893 rm: Reg::R1,
7894 },
7895 ArmOp::Sdiv {
7896 rd: Reg::R0,
7897 rn: Reg::R1,
7898 rm: Reg::PC,
7899 },
7900 ] {
7901 let r = encoder.encode(&op);
7902 assert!(
7903 r.is_err(),
7904 "encode({op:?}) must return Err for a PC operand, got {r:?}"
7905 );
7906 }
7907 assert!(
7909 encoder
7910 .encode(&ArmOp::Sdiv {
7911 rd: Reg::R0,
7912 rn: Reg::R1,
7913 rm: Reg::R2
7914 })
7915 .is_ok()
7916 );
7917 }
7918
7919 #[test]
7920 fn test_encode_nop_arm32() {
7921 let encoder = ArmEncoder::new_arm32();
7922 let code = encoder.encode(&ArmOp::Nop).unwrap();
7923
7924 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
7927
7928 #[test]
7929 fn test_encode_nop_thumb() {
7930 let encoder = ArmEncoder::new_thumb2();
7931 let code = encoder.encode(&ArmOp::Nop).unwrap();
7932
7933 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
7936
7937 #[test]
7938 fn test_encode_mov_immediate_arm32() {
7939 let encoder = ArmEncoder::new_arm32();
7940 let op = ArmOp::Mov {
7941 rd: Reg::R0,
7942 op2: Operand2::Imm(42),
7943 };
7944
7945 let code = encoder.encode(&op).unwrap();
7946 assert_eq!(code.len(), 4);
7947
7948 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7950 assert_eq!(instr & 0x0E000000, 0x02000000); }
7952
7953 #[test]
7954 fn test_encode_add_registers_arm32() {
7955 let encoder = ArmEncoder::new_arm32();
7956 let op = ArmOp::Add {
7957 rd: Reg::R0,
7958 rn: Reg::R1,
7959 op2: Operand2::Reg(Reg::R2),
7960 };
7961
7962 let code = encoder.encode(&op).unwrap();
7963 assert_eq!(code.len(), 4);
7964
7965 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
7966 assert_eq!(instr & 0x0FE00000, 0x00800000);
7968 }
7969
7970 #[test]
7974 fn test_encode_add_imm_large_350() {
7975 let enc = ArmEncoder::new_thumb2();
7976
7977 let small = enc
7979 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
7980 .unwrap();
7981 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
7982
7983 fn movx_imm16(b: &[u8]) -> u32 {
7985 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
7986 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
7987 let imm4 = hw1 & 0xF;
7988 let i = (hw1 >> 10) & 1;
7989 let imm3 = (hw2 >> 12) & 0x7;
7990 let imm8 = hw2 & 0xFF;
7991 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
7992 }
7993 fn movx_rd(b: &[u8]) -> u32 {
7994 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
7995 }
7996
7997 let seq = enc
8000 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
8001 .unwrap();
8002 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
8003 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
8005 assert_eq!(movx_rd(&seq[0..4]), 12);
8006 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
8007 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
8009 assert_eq!(movx_rd(&seq[4..8]), 12);
8010 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
8011 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
8013 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
8014 assert_eq!(add1 & 0xFFF0, 0xEB00);
8015 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
8020 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
8021 70000
8022 );
8023
8024 let seq16 = enc
8026 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
8027 .unwrap();
8028 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
8029 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
8030 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
8035 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
8036 .unwrap();
8037 assert_eq!(inplace.len(), 12);
8038 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
8039 assert_eq!(
8040 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
8041 0x12345
8042 );
8043 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
8045 assert_eq!(ip_add2 & 0xF, 12);
8046 assert_eq!((ip_add2 >> 8) & 0xF, 5);
8047 }
8048
8049 #[test]
8057 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
8058 let enc = ArmEncoder::new_thumb2();
8059 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
8061 assert!(
8062 r.is_err(),
8063 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
8064 );
8065 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
8069 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
8070 }
8071
8072 #[test]
8081 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
8082 let enc = ArmEncoder::new_arm32();
8083 let bad = enc.encode(&ArmOp::Add {
8084 rd: Reg::R0,
8085 rn: Reg::R1,
8086 op2: Operand2::Imm(0x1FF),
8087 });
8088 assert!(
8089 bad.is_err(),
8090 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
8091 to 0xFF), got {bad:?}"
8092 );
8093 let ok = enc.encode(&ArmOp::Add {
8095 rd: Reg::R0,
8096 rn: Reg::R1,
8097 op2: Operand2::Imm(0xFF),
8098 });
8099 assert!(
8100 ok.is_ok(),
8101 "0xFF is a valid rotated immediate, must stay Ok"
8102 );
8103 }
8104
8105 #[test]
8106 fn test_encode_ldr_arm32() {
8107 let encoder = ArmEncoder::new_arm32();
8108 let op = ArmOp::Ldr {
8109 rd: Reg::R0,
8110 addr: MemAddr::imm(Reg::R1, 4),
8111 };
8112
8113 let code = encoder.encode(&op).unwrap();
8114 assert_eq!(code.len(), 4);
8115
8116 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8117 assert_eq!(instr & 0x00100000, 0x00100000);
8119 }
8120
8121 #[test]
8122 fn test_encode_str_arm32() {
8123 let encoder = ArmEncoder::new_arm32();
8124 let op = ArmOp::Str {
8125 rd: Reg::R0,
8126 addr: MemAddr::imm(Reg::SP, 0),
8127 };
8128
8129 let code = encoder.encode(&op).unwrap();
8130 assert_eq!(code.len(), 4);
8131 }
8132
8133 #[test]
8134 fn test_encode_branch_arm32() {
8135 let encoder = ArmEncoder::new_arm32();
8136 let op = ArmOp::Bl {
8137 label: "main".to_string(),
8138 };
8139
8140 let code = encoder.encode(&op).unwrap();
8141 assert_eq!(code.len(), 4);
8142
8143 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8144 assert_eq!(instr & 0x0F000000, 0x0B000000);
8146 }
8147
8148 #[test]
8158 fn test_encode_thumb_bl_placeholder_addend_167_174() {
8159 let encoder = ArmEncoder::new_thumb2();
8160 let op = ArmOp::Bl {
8161 label: "callee".to_string(),
8162 };
8163
8164 let code = encoder.encode(&op).unwrap();
8165 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
8166
8167 let hw1 = u16::from_le_bytes([code[0], code[1]]);
8168 let hw2 = u16::from_le_bytes([code[2], code[3]]);
8169 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
8170 assert_eq!(
8171 hw2, 0xFFFE,
8172 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
8173 );
8174 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
8175 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
8176 }
8177
8178 #[test]
8179 fn test_encode_sequence() {
8180 let encoder = ArmEncoder::new_arm32();
8181 let ops = vec![
8182 ArmOp::Mov {
8183 rd: Reg::R0,
8184 op2: Operand2::Imm(42),
8185 },
8186 ArmOp::Mov {
8187 rd: Reg::R1,
8188 op2: Operand2::Imm(10),
8189 },
8190 ArmOp::Add {
8191 rd: Reg::R2,
8192 rn: Reg::R0,
8193 op2: Operand2::Reg(Reg::R1),
8194 },
8195 ];
8196
8197 let code = encoder.encode_sequence(&ops).unwrap();
8198 assert_eq!(code.len(), 12); }
8200
8201 #[test]
8202 fn test_reg_to_bits() {
8203 assert_eq!(reg_to_bits(&Reg::R0), 0);
8204 assert_eq!(reg_to_bits(&Reg::R7), 7);
8205 assert_eq!(reg_to_bits(&Reg::SP), 13);
8206 assert_eq!(reg_to_bits(&Reg::LR), 14);
8207 assert_eq!(reg_to_bits(&Reg::PC), 15);
8208 }
8209
8210 #[test]
8211 fn test_encode_bitwise_operations() {
8212 let encoder = ArmEncoder::new_arm32();
8213
8214 let and_op = ArmOp::And {
8215 rd: Reg::R0,
8216 rn: Reg::R1,
8217 op2: Operand2::Reg(Reg::R2),
8218 };
8219 let and_code = encoder.encode(&and_op).unwrap();
8220 assert_eq!(and_code.len(), 4);
8221
8222 let orr_op = ArmOp::Orr {
8223 rd: Reg::R0,
8224 rn: Reg::R1,
8225 op2: Operand2::Reg(Reg::R2),
8226 };
8227 let orr_code = encoder.encode(&orr_op).unwrap();
8228 assert_eq!(orr_code.len(), 4);
8229
8230 let eor_op = ArmOp::Eor {
8231 rd: Reg::R0,
8232 rn: Reg::R1,
8233 op2: Operand2::Reg(Reg::R2),
8234 };
8235 let eor_code = encoder.encode(&eor_op).unwrap();
8236 assert_eq!(eor_code.len(), 4);
8237 }
8238
8239 #[test]
8242 fn test_encode_sdiv_thumb2() {
8243 let encoder = ArmEncoder::new_thumb2();
8244 let op = ArmOp::Sdiv {
8245 rd: Reg::R0,
8246 rn: Reg::R1,
8247 rm: Reg::R2,
8248 };
8249
8250 let code = encoder.encode(&op).unwrap();
8251 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
8258 assert_eq!(code[1], 0xFB);
8259 assert_eq!(code[2], 0xF2);
8260 assert_eq!(code[3], 0xF0);
8261 }
8262
8263 #[test]
8264 fn test_encode_udiv_thumb2() {
8265 let encoder = ArmEncoder::new_thumb2();
8266 let op = ArmOp::Udiv {
8267 rd: Reg::R0,
8268 rn: Reg::R1,
8269 rm: Reg::R2,
8270 };
8271
8272 let code = encoder.encode(&op).unwrap();
8273 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
8278 assert_eq!(code[1], 0xFB);
8279 assert_eq!(code[2], 0xF2);
8280 assert_eq!(code[3], 0xF0);
8281 }
8282
8283 #[test]
8284 fn test_encode_mul_thumb2() {
8285 let encoder = ArmEncoder::new_thumb2();
8286 let op = ArmOp::Mul {
8287 rd: Reg::R0,
8288 rn: Reg::R1,
8289 rm: Reg::R2,
8290 };
8291
8292 let code = encoder.encode(&op).unwrap();
8293 assert_eq!(code.len(), 4); }
8295
8296 #[test]
8297 fn test_encode_and_thumb2() {
8298 let encoder = ArmEncoder::new_thumb2();
8299 let op = ArmOp::And {
8300 rd: Reg::R0,
8301 rn: Reg::R1,
8302 op2: Operand2::Reg(Reg::R2),
8303 };
8304
8305 let code = encoder.encode(&op).unwrap();
8306 assert_eq!(code.len(), 4); }
8308
8309 #[test]
8310 fn test_encode_lsl_thumb2_low_regs() {
8311 let encoder = ArmEncoder::new_thumb2();
8312 let op = ArmOp::Lsl {
8313 rd: Reg::R0,
8314 rn: Reg::R1,
8315 shift: 5,
8316 };
8317
8318 let code = encoder.encode(&op).unwrap();
8319 assert_eq!(code.len(), 2); }
8321
8322 #[test]
8323 fn test_encode_clz_thumb2() {
8324 let encoder = ArmEncoder::new_thumb2();
8325 let op = ArmOp::Clz {
8326 rd: Reg::R0,
8327 rm: Reg::R1,
8328 };
8329
8330 let code = encoder.encode(&op).unwrap();
8331 assert_eq!(code.len(), 4); }
8333
8334 #[test]
8335 fn test_encode_bx_thumb2() {
8336 let encoder = ArmEncoder::new_thumb2();
8337 let op = ArmOp::Bx { rm: Reg::LR };
8338
8339 let code = encoder.encode(&op).unwrap();
8340 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
8344 }
8345
8346 #[test]
8351 fn test_encode_f32_abs_arm32() {
8352 let encoder = ArmEncoder::new_arm32();
8353 let op = ArmOp::F32Abs {
8354 sd: VfpReg::S0,
8355 sm: VfpReg::S2,
8356 };
8357 let code = encoder.encode(&op).unwrap();
8358 assert_eq!(code.len(), 4); }
8360
8361 #[test]
8362 fn test_encode_f32_neg_arm32() {
8363 let encoder = ArmEncoder::new_arm32();
8364 let op = ArmOp::F32Neg {
8365 sd: VfpReg::S0,
8366 sm: VfpReg::S2,
8367 };
8368 let code = encoder.encode(&op).unwrap();
8369 assert_eq!(code.len(), 4);
8370 }
8371
8372 #[test]
8373 fn test_encode_f32_sqrt_arm32() {
8374 let encoder = ArmEncoder::new_arm32();
8375 let op = ArmOp::F32Sqrt {
8376 sd: VfpReg::S0,
8377 sm: VfpReg::S2,
8378 };
8379 let code = encoder.encode(&op).unwrap();
8380 assert_eq!(code.len(), 4);
8381 }
8382
8383 #[test]
8384 fn test_encode_f32_ceil_arm32() {
8385 let encoder = ArmEncoder::new_arm32();
8386 let op = ArmOp::F32Ceil {
8387 sd: VfpReg::S0,
8388 sm: VfpReg::S2,
8389 };
8390 let code = encoder.encode(&op).unwrap();
8391 assert_eq!(code.len(), 36);
8393 }
8394
8395 #[test]
8396 fn test_encode_f32_floor_thumb2() {
8397 let encoder = ArmEncoder::new_thumb2();
8398 let op = ArmOp::F32Floor {
8399 sd: VfpReg::S0,
8400 sm: VfpReg::S2,
8401 };
8402 let code = encoder.encode(&op).unwrap();
8403 assert_eq!(code.len(), 36);
8405 }
8406
8407 #[test]
8408 fn test_encode_f32_min_arm32() {
8409 let encoder = ArmEncoder::new_arm32();
8410 let op = ArmOp::F32Min {
8411 sd: VfpReg::S0,
8412 sn: VfpReg::S2,
8413 sm: VfpReg::S4,
8414 };
8415 let code = encoder.encode(&op).unwrap();
8416 assert_eq!(code.len(), 16); }
8418
8419 #[test]
8420 fn test_encode_f32_max_thumb2() {
8421 let encoder = ArmEncoder::new_thumb2();
8422 let op = ArmOp::F32Max {
8423 sd: VfpReg::S0,
8424 sn: VfpReg::S2,
8425 sm: VfpReg::S4,
8426 };
8427 let code = encoder.encode(&op).unwrap();
8428 assert_eq!(code.len(), 18);
8430 }
8431
8432 #[test]
8433 fn test_encode_f32_copysign_arm32() {
8434 let encoder = ArmEncoder::new_arm32();
8435 let op = ArmOp::F32Copysign {
8436 sd: VfpReg::S0,
8437 sn: VfpReg::S2,
8438 sm: VfpReg::S4,
8439 };
8440 let code = encoder.encode(&op).unwrap();
8441 assert_eq!(code.len(), 24);
8443 }
8444
8445 #[test]
8450 fn test_encode_f64_add_arm32() {
8451 let encoder = ArmEncoder::new_arm32();
8452 let op = ArmOp::F64Add {
8453 dd: VfpReg::D0,
8454 dn: VfpReg::D1,
8455 dm: VfpReg::D2,
8456 };
8457 let code = encoder.encode(&op).unwrap();
8458 assert_eq!(code.len(), 4);
8459 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8461 assert_eq!((instr >> 8) & 0xF, 0xB); }
8463
8464 #[test]
8465 fn test_encode_f64_sub_thumb2() {
8466 let encoder = ArmEncoder::new_thumb2();
8467 let op = ArmOp::F64Sub {
8468 dd: VfpReg::D0,
8469 dn: VfpReg::D1,
8470 dm: VfpReg::D2,
8471 };
8472 let code = encoder.encode(&op).unwrap();
8473 assert_eq!(code.len(), 4); }
8475
8476 #[test]
8477 fn test_encode_f64_mul_arm32() {
8478 let encoder = ArmEncoder::new_arm32();
8479 let op = ArmOp::F64Mul {
8480 dd: VfpReg::D0,
8481 dn: VfpReg::D1,
8482 dm: VfpReg::D2,
8483 };
8484 let code = encoder.encode(&op).unwrap();
8485 assert_eq!(code.len(), 4);
8486 }
8487
8488 #[test]
8489 fn test_encode_f64_div_arm32() {
8490 let encoder = ArmEncoder::new_arm32();
8491 let op = ArmOp::F64Div {
8492 dd: VfpReg::D0,
8493 dn: VfpReg::D1,
8494 dm: VfpReg::D2,
8495 };
8496 let code = encoder.encode(&op).unwrap();
8497 assert_eq!(code.len(), 4);
8498 }
8499
8500 #[test]
8501 fn test_encode_f64_abs_arm32() {
8502 let encoder = ArmEncoder::new_arm32();
8503 let op = ArmOp::F64Abs {
8504 dd: VfpReg::D0,
8505 dm: VfpReg::D2,
8506 };
8507 let code = encoder.encode(&op).unwrap();
8508 assert_eq!(code.len(), 4);
8509 }
8510
8511 #[test]
8512 fn test_encode_f64_neg_arm32() {
8513 let encoder = ArmEncoder::new_arm32();
8514 let op = ArmOp::F64Neg {
8515 dd: VfpReg::D0,
8516 dm: VfpReg::D2,
8517 };
8518 let code = encoder.encode(&op).unwrap();
8519 assert_eq!(code.len(), 4);
8520 }
8521
8522 #[test]
8523 fn test_encode_f64_sqrt_arm32() {
8524 let encoder = ArmEncoder::new_arm32();
8525 let op = ArmOp::F64Sqrt {
8526 dd: VfpReg::D0,
8527 dm: VfpReg::D2,
8528 };
8529 let code = encoder.encode(&op).unwrap();
8530 assert_eq!(code.len(), 4);
8531 }
8532
8533 #[test]
8534 fn test_encode_f64_load_arm32() {
8535 let encoder = ArmEncoder::new_arm32();
8536 let op = ArmOp::F64Load {
8537 dd: VfpReg::D0,
8538 addr: MemAddr::imm(Reg::R0, 8),
8539 };
8540 let code = encoder.encode(&op).unwrap();
8541 assert_eq!(code.len(), 4);
8542 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8543 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
8546
8547 #[test]
8548 fn test_encode_f64_store_thumb2() {
8549 let encoder = ArmEncoder::new_thumb2();
8550 let op = ArmOp::F64Store {
8551 dd: VfpReg::D0,
8552 addr: MemAddr::imm(Reg::SP, 0),
8553 };
8554 let code = encoder.encode(&op).unwrap();
8555 assert_eq!(code.len(), 4);
8556 }
8557
8558 #[test]
8559 fn test_encode_f64_compare_arm32() {
8560 let encoder = ArmEncoder::new_arm32();
8561 let op = ArmOp::F64Eq {
8562 rd: Reg::R0,
8563 dn: VfpReg::D0,
8564 dm: VfpReg::D1,
8565 };
8566 let code = encoder.encode(&op).unwrap();
8567 assert_eq!(code.len(), 16); }
8569
8570 #[test]
8571 fn test_encode_f64_compare_thumb2() {
8572 let encoder = ArmEncoder::new_thumb2();
8573 let op = ArmOp::F64Lt {
8574 rd: Reg::R0,
8575 dn: VfpReg::D0,
8576 dm: VfpReg::D1,
8577 };
8578 let code = encoder.encode(&op).unwrap();
8579 assert_eq!(code.len(), 14);
8581 }
8582
8583 #[test]
8584 fn test_encode_f64_const_arm32() {
8585 let encoder = ArmEncoder::new_arm32();
8586 let op = ArmOp::F64Const {
8587 dd: VfpReg::D0,
8588 value: 3.125,
8589 };
8590 let code = encoder.encode(&op).unwrap();
8591 assert_eq!(code.len(), 20);
8593 }
8594
8595 #[test]
8596 fn test_encode_f64_const_thumb2() {
8597 let encoder = ArmEncoder::new_thumb2();
8598 let op = ArmOp::F64Const {
8599 dd: VfpReg::D0,
8600 value: 2.5,
8601 };
8602 let code = encoder.encode(&op).unwrap();
8603 assert_eq!(code.len(), 20);
8605 }
8606
8607 #[test]
8608 fn test_encode_f64_convert_i32s_arm32() {
8609 let encoder = ArmEncoder::new_arm32();
8610 let op = ArmOp::F64ConvertI32S {
8611 dd: VfpReg::D0,
8612 rm: Reg::R0,
8613 };
8614 let code = encoder.encode(&op).unwrap();
8615 assert_eq!(code.len(), 8);
8617 }
8618
8619 #[test]
8620 fn test_encode_f64_promote_f32_arm32() {
8621 let encoder = ArmEncoder::new_arm32();
8622 let op = ArmOp::F64PromoteF32 {
8623 dd: VfpReg::D0,
8624 sm: VfpReg::S0,
8625 };
8626 let code = encoder.encode(&op).unwrap();
8627 assert_eq!(code.len(), 4); }
8629
8630 #[test]
8631 fn test_encode_f64_promote_f32_thumb2() {
8632 let encoder = ArmEncoder::new_thumb2();
8633 let op = ArmOp::F64PromoteF32 {
8634 dd: VfpReg::D0,
8635 sm: VfpReg::S0,
8636 };
8637 let code = encoder.encode(&op).unwrap();
8638 assert_eq!(code.len(), 4);
8639 }
8640
8641 #[test]
8642 fn test_encode_i32_trunc_f64s_arm32() {
8643 let encoder = ArmEncoder::new_arm32();
8644 let op = ArmOp::I32TruncF64S {
8645 rd: Reg::R0,
8646 dm: VfpReg::D0,
8647 };
8648 let code = encoder.encode(&op).unwrap();
8649 assert_eq!(code.len(), 8);
8651 }
8652
8653 #[test]
8654 fn test_encode_f64_reinterpret_i64_arm32() {
8655 let encoder = ArmEncoder::new_arm32();
8656 let op = ArmOp::F64ReinterpretI64 {
8657 dd: VfpReg::D0,
8658 rmlo: Reg::R0,
8659 rmhi: Reg::R1,
8660 };
8661 let code = encoder.encode(&op).unwrap();
8662 assert_eq!(code.len(), 4); }
8664
8665 #[test]
8666 fn test_encode_i64_reinterpret_f64_thumb2() {
8667 let encoder = ArmEncoder::new_thumb2();
8668 let op = ArmOp::I64ReinterpretF64 {
8669 rdlo: Reg::R0,
8670 rdhi: Reg::R1,
8671 dm: VfpReg::D0,
8672 };
8673 let code = encoder.encode(&op).unwrap();
8674 assert_eq!(code.len(), 4);
8675 }
8676
8677 #[test]
8678 fn test_encode_f64_trunc_thumb2() {
8679 let encoder = ArmEncoder::new_thumb2();
8680 let op = ArmOp::F64Trunc {
8681 dd: VfpReg::D0,
8682 dm: VfpReg::D1,
8683 };
8684 let code = encoder.encode(&op).unwrap();
8685 assert_eq!(code.len(), 8);
8687 }
8688
8689 #[test]
8690 fn test_encode_f64_min_arm32() {
8691 let encoder = ArmEncoder::new_arm32();
8692 let op = ArmOp::F64Min {
8693 dd: VfpReg::D0,
8694 dn: VfpReg::D1,
8695 dm: VfpReg::D2,
8696 };
8697 let code = encoder.encode(&op).unwrap();
8698 assert_eq!(code.len(), 16);
8700 }
8701
8702 #[test]
8703 fn test_f64_cp11_encoding() {
8704 let encoder = ArmEncoder::new_arm32();
8706
8707 let code = encoder
8709 .encode(&ArmOp::F64Add {
8710 dd: VfpReg::D0,
8711 dn: VfpReg::D0,
8712 dm: VfpReg::D0,
8713 })
8714 .unwrap();
8715 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8716 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
8717
8718 let code = encoder
8720 .encode(&ArmOp::F32Add {
8721 sd: VfpReg::S0,
8722 sn: VfpReg::S0,
8723 sm: VfpReg::S0,
8724 })
8725 .unwrap();
8726 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8727 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
8728 }
8729
8730 #[test]
8731 fn test_dreg_encoding_higher_registers() {
8732 let encoder = ArmEncoder::new_arm32();
8733
8734 let op = ArmOp::F64Add {
8736 dd: VfpReg::D15,
8737 dn: VfpReg::D14,
8738 dm: VfpReg::D13,
8739 };
8740 let code = encoder.encode(&op).unwrap();
8741 assert_eq!(code.len(), 4);
8742
8743 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8745 assert_eq!((instr >> 8) & 0xF, 0xB); }
8747
8748 #[test]
8753 fn test_encode_label_emits_no_bytes() {
8754 let encoder = ArmEncoder::new_thumb2();
8755 let op = ArmOp::Label {
8756 name: ".Lblock_end_0".to_string(),
8757 };
8758 let code = encoder.encode(&op).unwrap();
8759 assert!(code.is_empty(), "Label should emit zero bytes");
8760
8761 let encoder32 = ArmEncoder::new_arm32();
8762 let code32 = encoder32.encode(&op).unwrap();
8763 assert!(
8764 code32.is_empty(),
8765 "Label should emit zero bytes in ARM32 too"
8766 );
8767 }
8768
8769 #[test]
8770 fn test_encode_bcc_eq_thumb2() {
8771 use synth_synthesis::Condition;
8772 let encoder = ArmEncoder::new_thumb2();
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(), 2); assert_eq!(code, vec![0x00, 0xD0]);
8782 }
8783
8784 #[test]
8785 fn test_encode_bcc_ne_thumb2() {
8786 use synth_synthesis::Condition;
8787 let encoder = ArmEncoder::new_thumb2();
8788 let op = ArmOp::Bcc {
8789 cond: Condition::NE,
8790 label: "target".to_string(),
8791 };
8792 let code = encoder.encode(&op).unwrap();
8793 assert_eq!(code.len(), 2);
8794
8795 assert_eq!(code, vec![0x00, 0xD1]);
8797 }
8798
8799 #[test]
8800 fn test_encode_bcc_arm32() {
8801 use synth_synthesis::Condition;
8802 let encoder = ArmEncoder::new_arm32();
8803 let op = ArmOp::Bcc {
8804 cond: Condition::EQ,
8805 label: "target".to_string(),
8806 };
8807 let code = encoder.encode(&op).unwrap();
8808 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
8811 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
8815
8816 #[test]
8817 fn test_encode_udf_thumb2() {
8818 let encoder = ArmEncoder::new_thumb2();
8819 let op = ArmOp::Udf { imm: 0 };
8820 let code = encoder.encode(&op).unwrap();
8821 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
8825 }
8826
8827 #[test]
8828 fn test_encode_nop_thumb2() {
8829 let encoder = ArmEncoder::new_thumb2();
8830 let op = ArmOp::Nop;
8831 let code = encoder.encode(&op).unwrap();
8832 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
8836 }
8837
8838 #[test]
8843 fn test_encode_i64_add_thumb2() {
8844 let encoder = ArmEncoder::new_thumb2();
8845 let op = ArmOp::I64Add {
8846 rdlo: Reg::R0,
8847 rdhi: Reg::R1,
8848 rnlo: Reg::R0,
8849 rnhi: Reg::R1,
8850 rmlo: Reg::R2,
8851 rmhi: Reg::R3,
8852 };
8853 let code = encoder.encode(&op).unwrap();
8854 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
8856 }
8857
8858 #[test]
8859 fn test_encode_i64_sub_thumb2() {
8860 let encoder = ArmEncoder::new_thumb2();
8861 let op = ArmOp::I64Sub {
8862 rdlo: Reg::R0,
8863 rdhi: Reg::R1,
8864 rnlo: Reg::R0,
8865 rnhi: Reg::R1,
8866 rmlo: Reg::R2,
8867 rmhi: Reg::R3,
8868 };
8869 let code = encoder.encode(&op).unwrap();
8870 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
8872 }
8873
8874 #[test]
8875 fn test_encode_i64_and_thumb2() {
8876 let encoder = ArmEncoder::new_thumb2();
8877 let op = ArmOp::I64And {
8878 rdlo: Reg::R0,
8879 rdhi: Reg::R1,
8880 rnlo: Reg::R0,
8881 rnhi: Reg::R1,
8882 rmlo: Reg::R2,
8883 rmhi: Reg::R3,
8884 };
8885 let code = encoder.encode(&op).unwrap();
8886 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
8888 }
8889
8890 #[test]
8891 fn test_encode_i64_or_thumb2() {
8892 let encoder = ArmEncoder::new_thumb2();
8893 let op = ArmOp::I64Or {
8894 rdlo: Reg::R0,
8895 rdhi: Reg::R1,
8896 rnlo: Reg::R0,
8897 rnhi: Reg::R1,
8898 rmlo: Reg::R2,
8899 rmhi: Reg::R3,
8900 };
8901 let code = encoder.encode(&op).unwrap();
8902 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
8903 }
8904
8905 #[test]
8906 fn test_encode_i64_xor_thumb2() {
8907 let encoder = ArmEncoder::new_thumb2();
8908 let op = ArmOp::I64Xor {
8909 rdlo: Reg::R0,
8910 rdhi: Reg::R1,
8911 rnlo: Reg::R0,
8912 rnhi: Reg::R1,
8913 rmlo: Reg::R2,
8914 rmhi: Reg::R3,
8915 };
8916 let code = encoder.encode(&op).unwrap();
8917 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
8918 }
8919
8920 #[test]
8921 fn test_encode_i64_const_small_thumb2() {
8922 let encoder = ArmEncoder::new_thumb2();
8923 let op = ArmOp::I64Const {
8925 rdlo: Reg::R0,
8926 rdhi: Reg::R1,
8927 value: 42,
8928 };
8929 let code = encoder.encode(&op).unwrap();
8930 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
8932 }
8933
8934 #[test]
8935 fn test_encode_i64_const_large_thumb2() {
8936 let encoder = ArmEncoder::new_thumb2();
8937 let op = ArmOp::I64Const {
8939 rdlo: Reg::R0,
8940 rdhi: Reg::R1,
8941 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
8942 };
8943 let code = encoder.encode(&op).unwrap();
8944 assert_eq!(
8946 code.len(),
8947 16,
8948 "I64Const with large value should be 16 bytes"
8949 );
8950 }
8951
8952 #[test]
8953 fn test_encode_i64_extend_i32_s_thumb2() {
8954 let encoder = ArmEncoder::new_thumb2();
8955 let op = ArmOp::I64ExtendI32S {
8956 rdlo: Reg::R0,
8957 rdhi: Reg::R1,
8958 rn: Reg::R0,
8959 };
8960 let code = encoder.encode(&op).unwrap();
8961 assert_eq!(
8963 code.len(),
8964 4,
8965 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
8966 );
8967 }
8968
8969 #[test]
8970 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
8971 let encoder = ArmEncoder::new_thumb2();
8972 let op = ArmOp::I64ExtendI32S {
8973 rdlo: Reg::R0,
8974 rdhi: Reg::R1,
8975 rn: Reg::R2,
8976 };
8977 let code = encoder.encode(&op).unwrap();
8978 assert!(
8980 code.len() >= 6,
8981 "I64ExtendI32S (diff reg) should be at least 6 bytes"
8982 );
8983 }
8984
8985 #[test]
8986 fn test_encode_i64_extend_i32_u_thumb2() {
8987 let encoder = ArmEncoder::new_thumb2();
8988 let op = ArmOp::I64ExtendI32U {
8989 rdlo: Reg::R0,
8990 rdhi: Reg::R1,
8991 rn: Reg::R0,
8992 };
8993 let code = encoder.encode(&op).unwrap();
8994 assert_eq!(
8996 code.len(),
8997 2,
8998 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
8999 );
9000 }
9001
9002 #[test]
9003 fn test_encode_i32_wrap_i64_nop_thumb2() {
9004 let encoder = ArmEncoder::new_thumb2();
9005 let op = ArmOp::I32WrapI64 {
9007 rd: Reg::R0,
9008 rnlo: Reg::R0,
9009 };
9010 let code = encoder.encode(&op).unwrap();
9011 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
9012 assert_eq!(code, vec![0x00, 0xBF]); }
9014
9015 #[test]
9016 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
9017 let encoder = ArmEncoder::new_thumb2();
9018 let op = ArmOp::I32WrapI64 {
9019 rd: Reg::R2,
9020 rnlo: Reg::R0,
9021 };
9022 let code = encoder.encode(&op).unwrap();
9023 assert!(
9025 code.len() >= 2,
9026 "I32WrapI64 diff reg should emit at least 2 bytes"
9027 );
9028 }
9029
9030 #[test]
9031 fn test_encode_i64_eqz_thumb2() {
9032 let encoder = ArmEncoder::new_thumb2();
9033 let op = ArmOp::I64Eqz {
9034 rd: Reg::R0,
9035 rnlo: Reg::R0,
9036 rnhi: Reg::R1,
9037 };
9038 let code = encoder.encode(&op).unwrap();
9039 assert!(
9041 code.len() >= 6,
9042 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
9043 );
9044 }
9045
9046 #[test]
9047 fn test_encode_i64_eq_thumb2() {
9048 let encoder = ArmEncoder::new_thumb2();
9049 let op = ArmOp::I64Eq {
9050 rd: Reg::R0,
9051 rnlo: Reg::R0,
9052 rnhi: Reg::R1,
9053 rmlo: Reg::R2,
9054 rmhi: Reg::R3,
9055 };
9056 let code = encoder.encode(&op).unwrap();
9057 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
9059 }
9060
9061 #[test]
9062 fn test_encode_i64_ldr_thumb2() {
9063 let encoder = ArmEncoder::new_thumb2();
9064 let op = ArmOp::I64Ldr {
9065 rdlo: Reg::R0,
9066 rdhi: Reg::R1,
9067 addr: MemAddr::imm(Reg::SP, 0),
9068 };
9069 let code = encoder.encode(&op).unwrap();
9070 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
9072 }
9073
9074 #[test]
9075 fn test_372_i64_ldr_indexed_materializes_address() {
9076 let encoder = ArmEncoder::new_thumb2();
9081 let indexed = encoder
9082 .encode(&ArmOp::I64Ldr {
9083 rdlo: Reg::R0,
9084 rdhi: Reg::R1,
9085 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
9086 })
9087 .unwrap();
9088 assert_eq!(
9090 &indexed[0..4],
9091 &[0x0b, 0xeb, 0x00, 0x0c],
9092 "indexed I64Ldr must start with ADD.W ip, base, index"
9093 );
9094 let frame = encoder
9095 .encode(&ArmOp::I64Ldr {
9096 rdlo: Reg::R0,
9097 rdhi: Reg::R1,
9098 addr: MemAddr::imm(Reg::SP, 8),
9099 })
9100 .unwrap();
9101 assert_ne!(
9103 &frame[0..2],
9104 &[0x0b, 0xeb],
9105 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
9106 );
9107 }
9108
9109 #[test]
9110 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
9111 let encoder = ArmEncoder::new_thumb2();
9117 let ld = encoder
9120 .encode(&ArmOp::I64Ldr {
9121 rdlo: Reg::R0,
9122 rdhi: Reg::R1,
9123 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9124 })
9125 .expect("large-offset i64.load must lower, not skip");
9126 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
9128 assert_ne!(
9131 &ld[0..2],
9132 &[0x0b, 0xeb],
9133 "must materialize the large offset"
9134 );
9135 assert_eq!(
9137 &ld[4..20],
9138 &[
9139 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
9144 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
9145 );
9146
9147 let st = encoder
9149 .encode(&ArmOp::I64Str {
9150 rdlo: Reg::R2,
9151 rdhi: Reg::R3,
9152 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
9153 })
9154 .expect("large-offset i64.store must lower, not skip");
9155 assert_eq!(st.len(), 20);
9156 assert_eq!(
9157 &st[4..20],
9158 &[
9159 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
9164 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
9165 );
9166
9167 let small = encoder
9171 .encode(&ArmOp::I64Ldr {
9172 rdlo: Reg::R0,
9173 rdhi: Reg::R1,
9174 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
9175 })
9176 .unwrap();
9177 assert_eq!(
9178 &small[0..4],
9179 &[0x0b, 0xeb, 0x00, 0x0c],
9180 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
9181 );
9182 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
9183 }
9184
9185 #[test]
9186 fn test_encode_i64_str_thumb2() {
9187 let encoder = ArmEncoder::new_thumb2();
9188 let op = ArmOp::I64Str {
9189 rdlo: Reg::R0,
9190 rdhi: Reg::R1,
9191 addr: MemAddr::imm(Reg::SP, 0),
9192 };
9193 let code = encoder.encode(&op).unwrap();
9194 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
9196 }
9197
9198 #[test]
9199 fn test_encode_i64_all_comparisons_thumb2() {
9200 let encoder = ArmEncoder::new_thumb2();
9201
9202 let ops = vec![
9203 ArmOp::I64Ne {
9204 rd: Reg::R0,
9205 rnlo: Reg::R0,
9206 rnhi: Reg::R1,
9207 rmlo: Reg::R2,
9208 rmhi: Reg::R3,
9209 },
9210 ArmOp::I64LtS {
9211 rd: Reg::R0,
9212 rnlo: Reg::R0,
9213 rnhi: Reg::R1,
9214 rmlo: Reg::R2,
9215 rmhi: Reg::R3,
9216 },
9217 ArmOp::I64LtU {
9218 rd: Reg::R0,
9219 rnlo: Reg::R0,
9220 rnhi: Reg::R1,
9221 rmlo: Reg::R2,
9222 rmhi: Reg::R3,
9223 },
9224 ArmOp::I64LeS {
9225 rd: Reg::R0,
9226 rnlo: Reg::R0,
9227 rnhi: Reg::R1,
9228 rmlo: Reg::R2,
9229 rmhi: Reg::R3,
9230 },
9231 ArmOp::I64LeU {
9232 rd: Reg::R0,
9233 rnlo: Reg::R0,
9234 rnhi: Reg::R1,
9235 rmlo: Reg::R2,
9236 rmhi: Reg::R3,
9237 },
9238 ArmOp::I64GtS {
9239 rd: Reg::R0,
9240 rnlo: Reg::R0,
9241 rnhi: Reg::R1,
9242 rmlo: Reg::R2,
9243 rmhi: Reg::R3,
9244 },
9245 ArmOp::I64GtU {
9246 rd: Reg::R0,
9247 rnlo: Reg::R0,
9248 rnhi: Reg::R1,
9249 rmlo: Reg::R2,
9250 rmhi: Reg::R3,
9251 },
9252 ArmOp::I64GeS {
9253 rd: Reg::R0,
9254 rnlo: Reg::R0,
9255 rnhi: Reg::R1,
9256 rmlo: Reg::R2,
9257 rmhi: Reg::R3,
9258 },
9259 ArmOp::I64GeU {
9260 rd: Reg::R0,
9261 rnlo: Reg::R0,
9262 rnhi: Reg::R1,
9263 rmlo: Reg::R2,
9264 rmhi: Reg::R3,
9265 },
9266 ];
9267
9268 for op in &ops {
9269 let code = encoder.encode(op).unwrap();
9270 assert!(
9271 code.len() >= 8,
9272 "i64 comparison {:?} should emit at least 8 bytes, got {}",
9273 op,
9274 code.len()
9275 );
9276 }
9277 }
9278
9279 #[test]
9280 fn test_encode_i64_const_zero_thumb2() {
9281 let encoder = ArmEncoder::new_thumb2();
9282 let op = ArmOp::I64Const {
9283 rdlo: Reg::R0,
9284 rdhi: Reg::R1,
9285 value: 0,
9286 };
9287 let code = encoder.encode(&op).unwrap();
9288 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
9290 }
9291
9292 #[test]
9293 fn test_encode_i64_const_negative_one_thumb2() {
9294 let encoder = ArmEncoder::new_thumb2();
9295 let op = ArmOp::I64Const {
9296 rdlo: Reg::R0,
9297 rdhi: Reg::R1,
9298 value: -1, };
9300 let code = encoder.encode(&op).unwrap();
9301 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
9303 }
9304
9305 #[test]
9310 fn test_encode_ldrb_arm32() {
9311 let encoder = ArmEncoder::new_arm32();
9312 let op = ArmOp::Ldrb {
9313 rd: Reg::R0,
9314 addr: MemAddr::imm(Reg::R1, 4),
9315 };
9316 let code = encoder.encode(&op).unwrap();
9317 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
9318 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9320 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
9321 }
9322
9323 #[test]
9324 fn test_encode_strb_arm32() {
9325 let encoder = ArmEncoder::new_arm32();
9326 let op = ArmOp::Strb {
9327 rd: Reg::R0,
9328 addr: MemAddr::imm(Reg::R1, 0),
9329 };
9330 let code = encoder.encode(&op).unwrap();
9331 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
9332 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9334 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
9335 }
9336
9337 #[test]
9338 fn test_encode_ldrh_arm32() {
9339 let encoder = ArmEncoder::new_arm32();
9340 let op = ArmOp::Ldrh {
9341 rd: Reg::R0,
9342 addr: MemAddr::imm(Reg::R1, 2),
9343 };
9344 let code = encoder.encode(&op).unwrap();
9345 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
9346 }
9347
9348 #[test]
9349 fn test_encode_strh_arm32() {
9350 let encoder = ArmEncoder::new_arm32();
9351 let op = ArmOp::Strh {
9352 rd: Reg::R0,
9353 addr: MemAddr::imm(Reg::R1, 0),
9354 };
9355 let code = encoder.encode(&op).unwrap();
9356 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
9357 }
9358
9359 #[test]
9360 fn test_encode_ldrsb_arm32() {
9361 let encoder = ArmEncoder::new_arm32();
9362 let op = ArmOp::Ldrsb {
9363 rd: Reg::R0,
9364 addr: MemAddr::imm(Reg::R1, 0),
9365 };
9366 let code = encoder.encode(&op).unwrap();
9367 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
9368 }
9369
9370 #[test]
9371 fn test_encode_ldrsh_arm32() {
9372 let encoder = ArmEncoder::new_arm32();
9373 let op = ArmOp::Ldrsh {
9374 rd: Reg::R0,
9375 addr: MemAddr::imm(Reg::R1, 0),
9376 };
9377 let code = encoder.encode(&op).unwrap();
9378 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
9379 }
9380
9381 #[test]
9382 fn test_encode_ldrb_thumb2_16bit() {
9383 let encoder = ArmEncoder::new_thumb2();
9384 let op = ArmOp::Ldrb {
9385 rd: Reg::R0,
9386 addr: MemAddr::imm(Reg::R1, 4),
9387 };
9388 let code = encoder.encode(&op).unwrap();
9389 assert_eq!(
9391 code.len(),
9392 2,
9393 "Thumb-2 LDRB with small offset should be 16-bit"
9394 );
9395 }
9396
9397 #[test]
9398 fn test_encode_ldrb_thumb2_32bit() {
9399 let encoder = ArmEncoder::new_thumb2();
9400 let op = ArmOp::Ldrb {
9401 rd: Reg::R0,
9402 addr: MemAddr::imm(Reg::R1, 100), };
9404 let code = encoder.encode(&op).unwrap();
9405 assert_eq!(
9406 code.len(),
9407 4,
9408 "Thumb-2 LDRB with large offset should be 32-bit"
9409 );
9410 }
9411
9412 #[test]
9413 fn test_encode_strb_thumb2_16bit() {
9414 let encoder = ArmEncoder::new_thumb2();
9415 let op = ArmOp::Strb {
9416 rd: Reg::R0,
9417 addr: MemAddr::imm(Reg::R1, 10),
9418 };
9419 let code = encoder.encode(&op).unwrap();
9420 assert_eq!(
9421 code.len(),
9422 2,
9423 "Thumb-2 STRB with small offset should be 16-bit"
9424 );
9425 }
9426
9427 #[test]
9428 fn test_encode_ldrh_thumb2_16bit() {
9429 let encoder = ArmEncoder::new_thumb2();
9430 let op = ArmOp::Ldrh {
9431 rd: Reg::R0,
9432 addr: MemAddr::imm(Reg::R1, 4), };
9434 let code = encoder.encode(&op).unwrap();
9435 assert_eq!(
9436 code.len(),
9437 2,
9438 "Thumb-2 LDRH with small aligned offset should be 16-bit"
9439 );
9440 }
9441
9442 #[test]
9443 fn test_encode_strh_thumb2_16bit() {
9444 let encoder = ArmEncoder::new_thumb2();
9445 let op = ArmOp::Strh {
9446 rd: Reg::R0,
9447 addr: MemAddr::imm(Reg::R1, 4),
9448 };
9449 let code = encoder.encode(&op).unwrap();
9450 assert_eq!(
9451 code.len(),
9452 2,
9453 "Thumb-2 STRH with small aligned offset should be 16-bit"
9454 );
9455 }
9456
9457 #[test]
9458 fn test_encode_ldrsb_thumb2() {
9459 let encoder = ArmEncoder::new_thumb2();
9460 let op = ArmOp::Ldrsb {
9461 rd: Reg::R0,
9462 addr: MemAddr::imm(Reg::R1, 0),
9463 };
9464 let code = encoder.encode(&op).unwrap();
9465 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
9467 }
9468
9469 #[test]
9470 fn test_encode_ldrsh_thumb2() {
9471 let encoder = ArmEncoder::new_thumb2();
9472 let op = ArmOp::Ldrsh {
9473 rd: Reg::R0,
9474 addr: MemAddr::imm(Reg::R1, 0),
9475 };
9476 let code = encoder.encode(&op).unwrap();
9477 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
9478 }
9479
9480 #[test]
9481 fn test_encode_memory_size_thumb2() {
9482 let encoder = ArmEncoder::new_thumb2();
9483 let op = ArmOp::MemorySize { rd: Reg::R0 };
9484 let code = encoder.encode(&op).unwrap();
9485 assert!(!code.is_empty(), "MemorySize should produce code");
9487 }
9488
9489 #[test]
9490 fn test_encode_memory_grow_thumb2() {
9491 let encoder = ArmEncoder::new_thumb2();
9492 let op = ArmOp::MemoryGrow {
9493 rd: Reg::R0,
9494 rn: Reg::R0,
9495 };
9496 let code = encoder.encode(&op).unwrap();
9497 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
9498 }
9499
9500 #[test]
9501 fn test_encode_subword_reg_offset_thumb2() {
9502 let encoder = ArmEncoder::new_thumb2();
9503
9504 let op = ArmOp::Ldrb {
9506 rd: Reg::R0,
9507 addr: MemAddr::reg(Reg::R1, Reg::R2),
9508 };
9509 let code = encoder.encode(&op).unwrap();
9510 assert_eq!(
9511 code.len(),
9512 4,
9513 "Thumb-2 LDRB with reg offset should be 32-bit"
9514 );
9515
9516 let op = ArmOp::Strb {
9518 rd: Reg::R0,
9519 addr: MemAddr::reg(Reg::R1, Reg::R2),
9520 };
9521 let code = encoder.encode(&op).unwrap();
9522 assert_eq!(
9523 code.len(),
9524 4,
9525 "Thumb-2 STRB with reg offset should be 32-bit"
9526 );
9527
9528 let op = ArmOp::Ldrh {
9530 rd: Reg::R0,
9531 addr: MemAddr::reg(Reg::R1, Reg::R2),
9532 };
9533 let code = encoder.encode(&op).unwrap();
9534 assert_eq!(
9535 code.len(),
9536 4,
9537 "Thumb-2 LDRH with reg offset should be 32-bit"
9538 );
9539
9540 let op = ArmOp::Strh {
9542 rd: Reg::R0,
9543 addr: MemAddr::reg(Reg::R1, Reg::R2),
9544 };
9545 let code = encoder.encode(&op).unwrap();
9546 assert_eq!(
9547 code.len(),
9548 4,
9549 "Thumb-2 STRH with reg offset should be 32-bit"
9550 );
9551 }
9552
9553 #[test]
9554 fn test_encode_subword_reg_imm_offset_thumb2() {
9555 let encoder = ArmEncoder::new_thumb2();
9556
9557 let op = ArmOp::Ldrb {
9559 rd: Reg::R0,
9560 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
9561 };
9562 let code = encoder.encode(&op).unwrap();
9563 assert_eq!(
9565 code.len(),
9566 8,
9567 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
9568 );
9569 }
9570
9571 #[test]
9576 fn test_encode_mve_addi32_thumb2() {
9577 let encoder = ArmEncoder::new_thumb2();
9578 let op = ArmOp::MveAddI {
9579 qd: QReg::Q0,
9580 qn: QReg::Q1,
9581 qm: QReg::Q2,
9582 size: MveSize::S32,
9583 };
9584 let code = encoder.encode(&op).unwrap();
9585 assert_eq!(
9586 code.len(),
9587 4,
9588 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
9589 );
9590 }
9591
9592 #[test]
9593 fn test_encode_mve_subi16_thumb2() {
9594 let encoder = ArmEncoder::new_thumb2();
9595 let op = ArmOp::MveSubI {
9596 qd: QReg::Q0,
9597 qn: QReg::Q1,
9598 qm: QReg::Q2,
9599 size: MveSize::S16,
9600 };
9601 let code = encoder.encode(&op).unwrap();
9602 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
9603 }
9604
9605 #[test]
9606 fn test_encode_mve_muli8_thumb2() {
9607 let encoder = ArmEncoder::new_thumb2();
9608 let op = ArmOp::MveMulI {
9609 qd: QReg::Q0,
9610 qn: QReg::Q1,
9611 qm: QReg::Q2,
9612 size: MveSize::S8,
9613 };
9614 let code = encoder.encode(&op).unwrap();
9615 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
9616 }
9617
9618 #[test]
9619 fn test_encode_mve_bitwise_thumb2() {
9620 let encoder = ArmEncoder::new_thumb2();
9621
9622 let ops = vec![
9623 ArmOp::MveAnd {
9624 qd: QReg::Q0,
9625 qn: QReg::Q1,
9626 qm: QReg::Q2,
9627 },
9628 ArmOp::MveOrr {
9629 qd: QReg::Q0,
9630 qn: QReg::Q1,
9631 qm: QReg::Q2,
9632 },
9633 ArmOp::MveEor {
9634 qd: QReg::Q0,
9635 qn: QReg::Q1,
9636 qm: QReg::Q2,
9637 },
9638 ArmOp::MveBic {
9639 qd: QReg::Q0,
9640 qn: QReg::Q1,
9641 qm: QReg::Q2,
9642 },
9643 ];
9644 for op in ops {
9645 let code = encoder.encode(&op).unwrap();
9646 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
9647 }
9648 }
9649
9650 #[test]
9651 fn test_encode_mve_mvn_thumb2() {
9652 let encoder = ArmEncoder::new_thumb2();
9653 let op = ArmOp::MveMvn {
9654 qd: QReg::Q0,
9655 qm: QReg::Q1,
9656 };
9657 let code = encoder.encode(&op).unwrap();
9658 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
9659 }
9660
9661 #[test]
9662 fn test_encode_mve_load_store_thumb2() {
9663 let encoder = ArmEncoder::new_thumb2();
9664
9665 let load = ArmOp::MveLoad {
9666 qd: QReg::Q0,
9667 addr: MemAddr::imm(Reg::R0, 16),
9668 };
9669 let code = encoder.encode(&load).unwrap();
9670 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
9671
9672 let store = ArmOp::MveStore {
9673 qd: QReg::Q1,
9674 addr: MemAddr::imm(Reg::R1, 0),
9675 };
9676 let code = encoder.encode(&store).unwrap();
9677 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
9678 }
9679
9680 #[test]
9681 fn test_encode_mve_const_thumb2() {
9682 let encoder = ArmEncoder::new_thumb2();
9683 let op = ArmOp::MveConst {
9684 qd: QReg::Q0,
9685 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
9686 };
9687 let code = encoder.encode(&op).unwrap();
9688 assert!(
9691 code.len() >= 24,
9692 "MVE const should produce multiple instructions"
9693 );
9694 }
9695
9696 #[test]
9697 fn test_encode_mve_dup_thumb2() {
9698 let encoder = ArmEncoder::new_thumb2();
9699 let op = ArmOp::MveDup {
9700 qd: QReg::Q0,
9701 rn: Reg::R0,
9702 size: MveSize::S32,
9703 };
9704 let code = encoder.encode(&op).unwrap();
9705 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
9706 }
9707
9708 #[test]
9709 fn test_encode_mve_extract_lane_thumb2() {
9710 let encoder = ArmEncoder::new_thumb2();
9711 let op = ArmOp::MveExtractLane {
9712 rd: Reg::R0,
9713 qn: QReg::Q1,
9714 lane: 2,
9715 size: MveSize::S32,
9716 };
9717 let code = encoder.encode(&op).unwrap();
9718 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
9719 }
9720
9721 #[test]
9722 fn test_encode_mve_insert_lane_thumb2() {
9723 let encoder = ArmEncoder::new_thumb2();
9724 let op = ArmOp::MveInsertLane {
9725 qd: QReg::Q0,
9726 rn: Reg::R1,
9727 lane: 3,
9728 size: MveSize::S32,
9729 };
9730 let code = encoder.encode(&op).unwrap();
9731 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
9732 }
9733
9734 #[test]
9735 fn test_encode_mve_addf32_thumb2() {
9736 let encoder = ArmEncoder::new_thumb2();
9737 let op = ArmOp::MveAddF32 {
9738 qd: QReg::Q0,
9739 qn: QReg::Q1,
9740 qm: QReg::Q2,
9741 };
9742 let code = encoder.encode(&op).unwrap();
9743 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
9744 }
9745
9746 #[test]
9747 fn test_encode_mve_divf32_thumb2() {
9748 let encoder = ArmEncoder::new_thumb2();
9749 let op = ArmOp::MveDivF32 {
9750 qd: QReg::Q0,
9751 qn: QReg::Q1,
9752 qm: QReg::Q2,
9753 };
9754 let code = encoder.encode(&op).unwrap();
9755 assert_eq!(
9757 code.len(),
9758 16,
9759 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
9760 );
9761 }
9762
9763 #[test]
9764 fn test_encode_mve_sqrtf32_thumb2() {
9765 let encoder = ArmEncoder::new_thumb2();
9766 let op = ArmOp::MveSqrtF32 {
9767 qd: QReg::Q0,
9768 qm: QReg::Q1,
9769 };
9770 let code = encoder.encode(&op).unwrap();
9771 assert_eq!(
9773 code.len(),
9774 16,
9775 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
9776 );
9777 }
9778
9779 #[test]
9780 fn test_encode_mve_negf32_thumb2() {
9781 let encoder = ArmEncoder::new_thumb2();
9782 let op = ArmOp::MveNegF32 {
9783 qd: QReg::Q0,
9784 qm: QReg::Q1,
9785 };
9786 let code = encoder.encode(&op).unwrap();
9787 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
9788 }
9789
9790 #[test]
9791 fn test_encode_mve_absf32_thumb2() {
9792 let encoder = ArmEncoder::new_thumb2();
9793 let op = ArmOp::MveAbsF32 {
9794 qd: QReg::Q0,
9795 qm: QReg::Q1,
9796 };
9797 let code = encoder.encode(&op).unwrap();
9798 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
9799 }
9800
9801 #[test]
9816 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
9817 let encoder = ArmEncoder::new_thumb2();
9818 let op = ArmOp::And {
9819 rd: Reg::R2,
9820 rn: Reg::R0,
9821 op2: Operand2::Imm(0x7e),
9822 };
9823 let code = encoder.encode(&op).unwrap();
9824 assert_eq!(
9825 code,
9826 vec![0x00, 0xf0, 0x7e, 0x02],
9827 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
9828 );
9829 }
9830
9831 #[test]
9838 fn try_thumb_expand_imm_encodes_modified_immediates() {
9839 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
9841 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);
9849 assert_eq!(try_thumb_expand_imm(0x12345), None);
9850 }
9851
9852 #[test]
9857 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
9858 let encoder = ArmEncoder::new_thumb2();
9859 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
9861 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
9862 assert!(
9864 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
9865 "cmp #0x101 must error, not compare the wrong constant"
9866 );
9867 assert!(
9868 encoder
9869 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
9870 .is_err()
9871 );
9872 assert!(
9873 encoder
9874 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
9875 .is_err()
9876 );
9877 assert!(
9879 encoder
9880 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
9881 .is_ok()
9882 );
9883 }
9884
9885 #[test]
9888 fn mla_thumb2_encodes_correctly() {
9889 let encoder = ArmEncoder::new_thumb2();
9890 let code = encoder
9891 .encode(&ArmOp::Mla {
9892 rd: Reg::R2,
9893 rn: Reg::R3,
9894 rm: Reg::R4,
9895 ra: Reg::R8,
9896 })
9897 .unwrap();
9898 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
9900 }
9901
9902 #[test]
9907 fn ldst_imm12_offset_errors_when_out_of_range() {
9908 let encoder = ArmEncoder::new_thumb2();
9909 assert!(
9911 encoder
9912 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
9913 .is_ok()
9914 );
9915 assert!(
9917 encoder
9918 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
9919 .is_err(),
9920 "ldr offset 4096 must error, not wrap to 0"
9921 );
9922 assert!(
9923 encoder
9924 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
9925 .is_err()
9926 );
9927 assert!(
9928 encoder
9929 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
9930 .is_err()
9931 );
9932 assert!(
9933 encoder
9934 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
9935 .is_err()
9936 );
9937 }
9938
9939 #[test]
9946 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
9947 let encoder = ArmEncoder::new_thumb2();
9948 assert_eq!(
9950 encoder
9951 .encode(&ArmOp::Add {
9952 rd: Reg::SP,
9953 rn: Reg::SP,
9954 op2: Operand2::Imm(256),
9955 })
9956 .unwrap(),
9957 vec![0x0d, 0xf2, 0x00, 0x1d],
9958 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
9959 );
9960 assert_eq!(
9962 encoder
9963 .encode(&ArmOp::Sub {
9964 rd: Reg::SP,
9965 rn: Reg::SP,
9966 op2: Operand2::Imm(256),
9967 })
9968 .unwrap(),
9969 vec![0xad, 0xf2, 0x00, 0x1d],
9970 );
9971 assert!(
9973 encoder
9974 .encode(&ArmOp::Add {
9975 rd: Reg::SP,
9976 rn: Reg::SP,
9977 op2: Operand2::Imm(5000),
9978 })
9979 .is_err(),
9980 "add #5000 must error (no single ADDW), not mis-encode"
9981 );
9982 }
9983
9984 #[test]
9989 fn and_cmn_immediate_thumb_expand_else_error() {
9990 let encoder = ArmEncoder::new_thumb2();
9991 assert_eq!(
9993 encoder
9994 .encode(&ArmOp::And {
9995 rd: Reg::R2,
9996 rn: Reg::R0,
9997 op2: Operand2::Imm(0x7e),
9998 })
9999 .unwrap(),
10000 vec![0x00, 0xf0, 0x7e, 0x02],
10001 );
10002 assert!(
10004 encoder
10005 .encode(&ArmOp::And {
10006 rd: Reg::R2,
10007 rn: Reg::R0,
10008 op2: Operand2::Imm(0xff00ff00u32 as i32),
10009 })
10010 .is_ok()
10011 );
10012 assert!(
10014 encoder
10015 .encode(&ArmOp::And {
10016 rd: Reg::R2,
10017 rn: Reg::R0,
10018 op2: Operand2::Imm(0x101),
10019 })
10020 .is_err()
10021 );
10022 assert!(
10023 encoder
10024 .encode(&ArmOp::Cmn {
10025 rn: Reg::R0,
10026 op2: Operand2::Imm(0x101),
10027 })
10028 .is_err(),
10029 "CMN #0x101 must error, not emit a NOP"
10030 );
10031 }
10032
10033 #[test]
10037 fn orr_eor_immediate_encode_in_byte_range_else_error() {
10038 let encoder = ArmEncoder::new_thumb2();
10039 assert_eq!(
10041 encoder
10042 .encode(&ArmOp::Orr {
10043 rd: Reg::R2,
10044 rn: Reg::R0,
10045 op2: Operand2::Imm(0x7e),
10046 })
10047 .unwrap(),
10048 vec![0x40, 0xf0, 0x7e, 0x02],
10049 );
10050 assert_eq!(
10052 encoder
10053 .encode(&ArmOp::Eor {
10054 rd: Reg::R2,
10055 rn: Reg::R0,
10056 op2: Operand2::Imm(0x7e),
10057 })
10058 .unwrap(),
10059 vec![0x80, 0xf0, 0x7e, 0x02],
10060 );
10061 assert!(
10063 encoder
10064 .encode(&ArmOp::Orr {
10065 rd: Reg::R2,
10066 rn: Reg::R0,
10067 op2: Operand2::Imm(0x140),
10068 })
10069 .is_err(),
10070 "ORR #0x140 must error, not emit a NOP"
10071 );
10072 }
10073
10074 #[test]
10075 fn test_encode_mve_different_qregs() {
10076 let encoder = ArmEncoder::new_thumb2();
10077
10078 let op1 = ArmOp::MveAddI {
10080 qd: QReg::Q0,
10081 qn: QReg::Q0,
10082 qm: QReg::Q0,
10083 size: MveSize::S32,
10084 };
10085 let op2 = ArmOp::MveAddI {
10086 qd: QReg::Q3,
10087 qn: QReg::Q5,
10088 qm: QReg::Q7,
10089 size: MveSize::S32,
10090 };
10091 let code1 = encoder.encode(&op1).unwrap();
10092 let code2 = encoder.encode(&op2).unwrap();
10093 assert_ne!(
10094 code1, code2,
10095 "Different Q-registers should produce different encodings"
10096 );
10097 }
10098
10099 #[test]
10100 fn test_encode_mve_arm32_nop() {
10101 let encoder = ArmEncoder::new_arm32();
10103 let op = ArmOp::MveAddI {
10104 qd: QReg::Q0,
10105 qn: QReg::Q1,
10106 qm: QReg::Q2,
10107 size: MveSize::S32,
10108 };
10109 let code = encoder.encode(&op).unwrap();
10110 assert_eq!(code.len(), 4, "ARM32 MVE should be 4 bytes (NOP)");
10111 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10113 assert_eq!(instr, 0xE1A00000, "ARM32 MVE should encode as NOP");
10114 }
10115}