3434#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
3535
3636#include "py/mpstate.h"
37- #include "py/persistentcode.h"
3837#include "py/asmthumb.h"
3938
4039#define UNSIGNED_FIT5 (x ) ((uint32_t)(x) < 32)
4645#define SIGNED_FIT12 (x ) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
4746#define SIGNED_FIT23 (x ) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000)
4847
49- #if MICROPY_EMIT_THUMB_ARMV7M
5048// Note: these actually take an imm12 but the high-bit is not encoded here
5149#define OP_ADD_W_RRI_HI (reg_src ) (0xf200 | (reg_src))
5250#define OP_ADD_W_RRI_LO (reg_dest , imm11 ) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff))
5856
5957#define OP_LDRH_W_HI (reg_base ) (0xf8b0 | (reg_base))
6058#define OP_LDRH_W_LO (reg_dest , imm12 ) ((reg_dest) << 12 | (imm12))
61- #endif
6259
6360static inline byte * asm_thumb_get_cur_to_write_bytes (asm_thumb_t * as , int n ) {
6461 return mp_asm_base_get_cur_to_write_bytes (& as -> base , n );
@@ -161,43 +158,43 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
161158 }
162159 asm_thumb_op16 (as , OP_PUSH_RLIST_LR (reglist ));
163160 if (stack_adjust > 0 ) {
164- #if MICROPY_EMIT_THUMB_ARMV7M
165- if (UNSIGNED_FIT7 (stack_adjust )) {
166- asm_thumb_op16 (as , OP_SUB_SP (stack_adjust ));
161+ if (asm_thumb_allow_armv7m (as )) {
162+ if (UNSIGNED_FIT7 (stack_adjust )) {
163+ asm_thumb_op16 (as , OP_SUB_SP (stack_adjust ));
164+ } else {
165+ asm_thumb_op32 (as , OP_SUB_W_RRI_HI (ASM_THUMB_REG_SP ), OP_SUB_W_RRI_LO (ASM_THUMB_REG_SP , stack_adjust * 4 ));
166+ }
167167 } else {
168- asm_thumb_op32 (as , OP_SUB_W_RRI_HI (ASM_THUMB_REG_SP ), OP_SUB_W_RRI_LO (ASM_THUMB_REG_SP , stack_adjust * 4 ));
169- }
170- #else
171- int adj = stack_adjust ;
172- // we don't expect the stack_adjust to be massive
173- while (!UNSIGNED_FIT7 (adj )) {
174- asm_thumb_op16 (as , OP_SUB_SP (127 ));
175- adj -= 127 ;
168+ int adj = stack_adjust ;
169+ // we don't expect the stack_adjust to be massive
170+ while (!UNSIGNED_FIT7 (adj )) {
171+ asm_thumb_op16 (as , OP_SUB_SP (127 ));
172+ adj -= 127 ;
173+ }
174+ asm_thumb_op16 (as , OP_SUB_SP (adj ));
176175 }
177- asm_thumb_op16 (as , OP_SUB_SP (adj ));
178- #endif
179176 }
180177 as -> push_reglist = reglist ;
181178 as -> stack_adjust = stack_adjust ;
182179}
183180
184181void asm_thumb_exit (asm_thumb_t * as ) {
185182 if (as -> stack_adjust > 0 ) {
186- #if MICROPY_EMIT_THUMB_ARMV7M
187- if (UNSIGNED_FIT7 (as -> stack_adjust )) {
188- asm_thumb_op16 (as , OP_ADD_SP (as -> stack_adjust ));
183+ if (asm_thumb_allow_armv7m (as )) {
184+ if (UNSIGNED_FIT7 (as -> stack_adjust )) {
185+ asm_thumb_op16 (as , OP_ADD_SP (as -> stack_adjust ));
186+ } else {
187+ asm_thumb_op32 (as , OP_ADD_W_RRI_HI (ASM_THUMB_REG_SP ), OP_ADD_W_RRI_LO (ASM_THUMB_REG_SP , as -> stack_adjust * 4 ));
188+ }
189189 } else {
190- asm_thumb_op32 (as , OP_ADD_W_RRI_HI (ASM_THUMB_REG_SP ), OP_ADD_W_RRI_LO (ASM_THUMB_REG_SP , as -> stack_adjust * 4 ));
191- }
192- #else
193- int adj = as -> stack_adjust ;
194- // we don't expect the stack_adjust to be massive
195- while (!UNSIGNED_FIT7 (adj )) {
196- asm_thumb_op16 (as , OP_ADD_SP (127 ));
197- adj -= 127 ;
190+ int adj = as -> stack_adjust ;
191+ // we don't expect the stack_adjust to be massive
192+ while (!UNSIGNED_FIT7 (adj )) {
193+ asm_thumb_op16 (as , OP_ADD_SP (127 ));
194+ adj -= 127 ;
195+ }
196+ asm_thumb_op16 (as , OP_ADD_SP (adj ));
198197 }
199- asm_thumb_op16 (as , OP_ADD_SP (adj ));
200- #endif
201198 }
202199 asm_thumb_op16 (as , OP_POP_RLIST_PC (as -> push_reglist ));
203200}
@@ -251,27 +248,19 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
251248 asm_thumb_op16 (as , 0x4600 | op_lo );
252249}
253250
254- #if MICROPY_EMIT_THUMB_ARMV7M
255-
256251// if loading lo half with movw, the i16 value will be zero extended into the r32 register!
257- size_t asm_thumb_mov_reg_i16 (asm_thumb_t * as , uint mov_op , uint reg_dest , int i16_src ) {
252+ void asm_thumb_mov_reg_i16 (asm_thumb_t * as , uint mov_op , uint reg_dest , int i16_src ) {
258253 assert (reg_dest < ASM_THUMB_REG_R15 );
259- size_t loc = mp_asm_base_get_code_pos (& as -> base );
260254 // mov[wt] reg_dest, #i16_src
261255 asm_thumb_op32 (as , mov_op | ((i16_src >> 1 ) & 0x0400 ) | ((i16_src >> 12 ) & 0xf ), ((i16_src << 4 ) & 0x7000 ) | (reg_dest << 8 ) | (i16_src & 0xff ));
262- return loc ;
263256}
264257
265- #else
266-
267- void asm_thumb_mov_rlo_i16 (asm_thumb_t * as , uint rlo_dest , int i16_src ) {
258+ static void asm_thumb_mov_rlo_i16 (asm_thumb_t * as , uint rlo_dest , int i16_src ) {
268259 asm_thumb_mov_rlo_i8 (as , rlo_dest , (i16_src >> 8 ) & 0xff );
269260 asm_thumb_lsl_rlo_rlo_i5 (as , rlo_dest , rlo_dest , 8 );
270261 asm_thumb_add_rlo_i8 (as , rlo_dest , i16_src & 0xff );
271262}
272263
273- #endif
274-
275264#define OP_B_N (byte_offset ) (0xe000 | (((byte_offset) >> 1) & 0x07ff))
276265
277266bool asm_thumb_b_n_label (asm_thumb_t * as , uint label ) {
@@ -295,14 +284,12 @@ bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) {
295284 if (!wide ) {
296285 asm_thumb_op16 (as , OP_BCC_N (cond , rel ));
297286 return as -> base .pass != MP_ASM_PASS_EMIT || SIGNED_FIT9 (rel );
298- } else {
299- #if MICROPY_EMIT_THUMB_ARMV7M
287+ } else if (asm_thumb_allow_armv7m (as )) {
300288 asm_thumb_op32 (as , OP_BCC_W_HI (cond , rel ), OP_BCC_W_LO (rel ));
301289 return true;
302- # else
290+ } else {
303291 // this method should not be called for ARMV6M
304292 return false;
305- #endif
306293 }
307294}
308295
@@ -323,45 +310,44 @@ size_t asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
323310
324311 size_t loc = mp_asm_base_get_code_pos (& as -> base );
325312
326- #if MICROPY_EMIT_THUMB_ARMV7M
327- asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVW , reg_dest , i32 );
328- asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVT , reg_dest , i32 >> 16 );
329- #else
330- // should only be called with lo reg for ARMV6M
331- assert (reg_dest < ASM_THUMB_REG_R8 );
332-
333- // sanity check that generated code is aligned
334- assert (!as -> base .code_base || !(3u & (uintptr_t )as -> base .code_base ));
335-
336- // basically:
337- // (nop)
338- // ldr reg_dest, _data
339- // b 1f
340- // _data: .word i32
341- // 1:
342- if (as -> base .code_offset & 2u ) {
343- asm_thumb_op16 (as , ASM_THUMB_OP_NOP );
313+ if (asm_thumb_allow_armv7m (as )) {
314+ asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVW , reg_dest , i32 );
315+ asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVT , reg_dest , i32 >> 16 );
316+ } else {
317+ // should only be called with lo reg for ARMV6M
318+ assert (reg_dest < ASM_THUMB_REG_R8 );
319+
320+ // sanity check that generated code is aligned
321+ assert (!as -> base .code_base || !(3u & (uintptr_t )as -> base .code_base ));
322+
323+ // basically:
324+ // (nop)
325+ // ldr reg_dest, _data
326+ // b 1f
327+ // _data: .word i32
328+ // 1:
329+ if (as -> base .code_offset & 2u ) {
330+ asm_thumb_op16 (as , ASM_THUMB_OP_NOP );
331+ }
332+ asm_thumb_ldr_rlo_pcrel_i8 (as , reg_dest , 0 );
333+ asm_thumb_op16 (as , OP_B_N (2 ));
334+ asm_thumb_op16 (as , i32 & 0xffff );
335+ asm_thumb_op16 (as , i32 >> 16 );
344336 }
345- asm_thumb_ldr_rlo_pcrel_i8 (as , reg_dest , 0 );
346- asm_thumb_op16 (as , OP_B_N (2 ));
347- asm_thumb_op16 (as , i32 & 0xffff );
348- asm_thumb_op16 (as , i32 >> 16 );
349- #endif
350337
351338 return loc ;
352339}
353340
354341void asm_thumb_mov_reg_i32_optimised (asm_thumb_t * as , uint reg_dest , int i32 ) {
355342 if (reg_dest < 8 && UNSIGNED_FIT8 (i32 )) {
356343 asm_thumb_mov_rlo_i8 (as , reg_dest , i32 );
357- } else {
358- #if MICROPY_EMIT_THUMB_ARMV7M
344+ } else if (asm_thumb_allow_armv7m (as )) {
359345 if (UNSIGNED_FIT16 (i32 )) {
360346 asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVW , reg_dest , i32 );
361347 } else {
362348 asm_thumb_mov_reg_i32 (as , reg_dest , i32 );
363349 }
364- # else
350+ } else {
365351 uint rlo_dest = reg_dest ;
366352 assert (rlo_dest < ASM_THUMB_REG_R8 ); // should never be called for ARMV6M
367353
@@ -389,7 +375,6 @@ void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) {
389375 if (negate ) {
390376 asm_thumb_neg_rlo_rlo (as , rlo_dest , rlo_dest );
391377 }
392- #endif
393378 }
394379}
395380
@@ -432,27 +417,25 @@ void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) {
432417 mp_uint_t dest = get_label_dest (as , label );
433418 mp_int_t rel = dest - as -> base .code_offset ;
434419 rel |= 1 ; // to stay in Thumb state when jumping to this address
435- # if MICROPY_EMIT_THUMB_ARMV7M
436- rel -= 6 + 4 ; // adjust for mov_reg_i16, sxth_rlo_rlo and then PC+4 prefetch of add_reg_reg
437- asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVW , rlo_dest , rel ); // 4 bytes
438- asm_thumb_sxth_rlo_rlo (as , rlo_dest , rlo_dest ); // 2 bytes
439- # else
440- rel -= 8 + 4 ; // adjust for four instructions and then PC+4 prefetch of add_reg_reg
441- // 6 bytes
442- asm_thumb_mov_rlo_i16 (as , rlo_dest , rel );
443- // 2 bytes - not always needed, but we want to keep the size the same
444- asm_thumb_sxth_rlo_rlo (as , rlo_dest , rlo_dest );
445- #endif
420+ if ( asm_thumb_allow_armv7m ( as )) {
421+ rel -= 6 + 4 ; // adjust for mov_reg_i16, sxth_rlo_rlo and then PC+4 prefetch of add_reg_reg
422+ asm_thumb_mov_reg_i16 (as , ASM_THUMB_OP_MOVW , rlo_dest , rel ); // 4 bytes
423+ asm_thumb_sxth_rlo_rlo (as , rlo_dest , rlo_dest ); // 2 bytes
424+ } else {
425+ rel -= 8 + 4 ; // adjust for four instructions and then PC+4 prefetch of add_reg_reg
426+ // 6 bytes
427+ asm_thumb_mov_rlo_i16 (as , rlo_dest , rel );
428+ // 2 bytes - not always needed, but we want to keep the size the same
429+ asm_thumb_sxth_rlo_rlo (as , rlo_dest , rlo_dest );
430+ }
446431 asm_thumb_add_reg_reg (as , rlo_dest , ASM_THUMB_REG_R15 ); // 2 bytes
447432}
448433
449- #if MICROPY_EMIT_THUMB_ARMV7M
434+ // ARMv7-M only
450435static inline void asm_thumb_ldr_reg_reg_i12 (asm_thumb_t * as , uint reg_dest , uint reg_base , uint word_offset ) {
451436 asm_thumb_op32 (as , OP_LDR_W_HI (reg_base ), OP_LDR_W_LO (reg_dest , word_offset * 4 ));
452437}
453- #endif
454438
455- #if !MICROPY_EMIT_THUMB_ARMV7M
456439// emits code for: reg_dest = reg_base + offset << offset_shift
457440static void asm_thumb_add_reg_reg_offset (asm_thumb_t * as , uint reg_dest , uint reg_base , uint offset , uint offset_shift ) {
458441 if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 ) {
@@ -479,37 +462,31 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re
479462 assert (0 ); // should never be called for ARMV6M
480463 }
481464}
482- #endif
483465
484466void asm_thumb_ldr_reg_reg_i12_optimised (asm_thumb_t * as , uint reg_dest , uint reg_base , uint word_offset ) {
485467 if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5 (word_offset )) {
486468 asm_thumb_ldr_rlo_rlo_i5 (as , reg_dest , reg_base , word_offset );
487- } else {
488- #if MICROPY_EMIT_THUMB_ARMV7M
469+ } else if (asm_thumb_allow_armv7m (as )) {
489470 asm_thumb_ldr_reg_reg_i12 (as , reg_dest , reg_base , word_offset );
490- # else
471+ } else {
491472 asm_thumb_add_reg_reg_offset (as , reg_dest , reg_base , word_offset - 31 , 2 );
492473 asm_thumb_ldr_rlo_rlo_i5 (as , reg_dest , reg_dest , 31 );
493- #endif
494474 }
495475}
496476
497- #if MICROPY_EMIT_THUMB_ARMV7M
477+ // ARMv7-M only
498478static inline void asm_thumb_ldrh_reg_reg_i12 (asm_thumb_t * as , uint reg_dest , uint reg_base , uint uint16_offset ) {
499479 asm_thumb_op32 (as , OP_LDRH_W_HI (reg_base ), OP_LDRH_W_LO (reg_dest , uint16_offset * 2 ));
500480}
501- #endif
502481
503482void asm_thumb_ldrh_reg_reg_i12_optimised (asm_thumb_t * as , uint reg_dest , uint reg_base , uint uint16_offset ) {
504483 if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5 (uint16_offset )) {
505484 asm_thumb_ldrh_rlo_rlo_i5 (as , reg_dest , reg_base , uint16_offset );
506- } else {
507- #if MICROPY_EMIT_THUMB_ARMV7M
485+ } else if (asm_thumb_allow_armv7m (as )) {
508486 asm_thumb_ldrh_reg_reg_i12 (as , reg_dest , reg_base , uint16_offset );
509- # else
487+ } else {
510488 asm_thumb_add_reg_reg_offset (as , reg_dest , reg_base , uint16_offset - 31 , 1 );
511489 asm_thumb_ldrh_rlo_rlo_i5 (as , reg_dest , reg_dest , 31 );
512- #endif
513490 }
514491}
515492
@@ -521,20 +498,21 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) {
521498 mp_uint_t dest = get_label_dest (as , label );
522499 mp_int_t rel = dest - as -> base .code_offset ;
523500 rel -= 4 ; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
501+
524502 if (dest != (mp_uint_t )- 1 && rel <= -4 ) {
525503 // is a backwards jump, so we know the size of the jump on the first pass
526504 // calculate rel assuming 12 bit relative jump
527505 if (SIGNED_FIT12 (rel )) {
528506 asm_thumb_op16 (as , OP_B_N (rel ));
529- } else {
530- goto large_jump ;
507+ return ;
531508 }
532- } else {
533- // is a forwards jump, so need to assume it's large
534- large_jump :
535- #if MICROPY_EMIT_THUMB_ARMV7M
509+ }
510+
511+ // is a large backwards jump, or a forwards jump (that must be assumed large)
512+
513+ if (asm_thumb_allow_armv7m (as )) {
536514 asm_thumb_op32 (as , OP_BW_HI (rel ), OP_BW_LO (rel ));
537- # else
515+ } else {
538516 if (SIGNED_FIT12 (rel )) {
539517 // this code path has to be the same number of instructions irrespective of rel
540518 asm_thumb_op16 (as , OP_B_N (rel ));
@@ -545,32 +523,31 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) {
545523 mp_raise_NotImplementedError (MP_ERROR_TEXT ("native method too big" ));
546524 }
547525 }
548- #endif
549526 }
550527}
551528
552529void asm_thumb_bcc_label (asm_thumb_t * as , int cond , uint label ) {
553530 mp_uint_t dest = get_label_dest (as , label );
554531 mp_int_t rel = dest - as -> base .code_offset ;
555532 rel -= 4 ; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
533+
556534 if (dest != (mp_uint_t )- 1 && rel <= -4 ) {
557535 // is a backwards jump, so we know the size of the jump on the first pass
558536 // calculate rel assuming 9 bit relative jump
559537 if (SIGNED_FIT9 (rel )) {
560538 asm_thumb_op16 (as , OP_BCC_N (cond , rel ));
561- } else {
562- goto large_jump ;
539+ return ;
563540 }
564- } else {
565- // is a forwards jump, so need to assume it's large
566- large_jump :
567- #if MICROPY_EMIT_THUMB_ARMV7M
541+ }
542+
543+ // is a large backwards jump, or a forwards jump (that must be assumed large)
544+
545+ if (asm_thumb_allow_armv7m (as )) {
568546 asm_thumb_op32 (as , OP_BCC_W_HI (cond , rel ), OP_BCC_W_LO (rel ));
569- # else
547+ } else {
570548 // reverse the sense of the branch to jump over a longer branch
571549 asm_thumb_op16 (as , OP_BCC_N (cond ^ 1 , 0 ));
572550 asm_thumb_b_label (as , label );
573- #endif
574551 }
575552}
576553
0 commit comments