@@ -20,7 +20,6 @@ struct _asm_thumb_t {
2020 byte * code_base ;
2121 byte dummy_data [8 ];
2222
23- int next_label ;
2423 int max_num_labels ;
2524 int * label_offsets ;
2625 int num_locals ;
@@ -65,7 +64,6 @@ void asm_thumb_free(asm_thumb_t *as, bool free_code) {
6564void asm_thumb_start_pass (asm_thumb_t * as , int pass ) {
6665 as -> pass = pass ;
6766 as -> code_offset = 0 ;
68- as -> next_label = 1 ;
6967 if (pass == ASM_THUMB_PASS_2 ) {
7068 memset (as -> label_offsets , -1 , as -> max_num_labels * sizeof (int ));
7169 }
@@ -212,10 +210,6 @@ void asm_thumb_exit(asm_thumb_t *as) {
212210 asm_thumb_write_op16 (as , OP_POP_RLIST_PC (as -> push_reglist ));
213211}
214212
215- int asm_thumb_label_new (asm_thumb_t * as ) {
216- return as -> next_label ++ ;
217- }
218-
219213void asm_thumb_label_assign (asm_thumb_t * as , int label ) {
220214 assert (label < as -> max_num_labels );
221215 if (as -> pass == ASM_THUMB_PASS_2 ) {
@@ -234,43 +228,33 @@ static int get_label_dest(asm_thumb_t *as, int label) {
234228 return as -> label_offsets [label ];
235229}
236230
237- // the i8 value will be zero extended into the r32 register!
238- void asm_thumb_mov_reg_i8 (asm_thumb_t * as , uint rlo_dest , int i8 ) {
231+ #define OP_MOVS_RLO_I8 (rlo_dest , i8_src ) (0x2000 | ((rlo_dest) << 8) | (i8_src))
232+
233+ // the i8_src value will be zero extended into the r32 register!
234+ void asm_thumb_movs_rlo_i8 (asm_thumb_t * as , uint rlo_dest , int i8_src ) {
239235 assert (rlo_dest < REG_R8 );
240- // movs rlo_dest, #i8
241- asm_thumb_write_op16 (as , 0x2000 | (rlo_dest << 8 ) | i8 );
236+ // movs rlo_dest, #i8_src
237+ asm_thumb_write_op16 (as , OP_MOVS_RLO_I8 (rlo_dest , i8_src ) );
242238}
243239
244- // if loading lo half, the i16 value will be zero extended into the r32 register!
245- void asm_thumb_mov_i16_to_reg (asm_thumb_t * as , int i16 , uint reg_dest , bool load_hi_half ) {
240+ #define OP_MOVW (0xf240)
241+ #define OP_MOVT (0xf2c0)
242+
243+ // if loading lo half with movw, the i16 value will be zero extended into the r32 register!
244+ static void asm_thumb_mov_reg_i16 (asm_thumb_t * as , uint mov_op , uint reg_dest , int i16_src ) {
246245 assert (reg_dest < REG_R15 );
247- uint op ;
248- if (load_hi_half ) {
249- // movt reg_dest, #i16
250- op = 0xf2c0 ;
251- } else {
252- // movw reg_dest, #i16
253- op = 0xf240 ;
254- }
255- asm_thumb_write_op32 (as , op | ((i16 >> 1 ) & 0x0400 ) | ((i16 >> 12 ) & 0xf ), ((i16 << 4 ) & 0x7000 ) | (reg_dest << 8 ) | (i16 & 0xff ));
246+ // mov[wt] reg_dest, #i16_src
247+ asm_thumb_write_op32 (as , mov_op | ((i16_src >> 1 ) & 0x0400 ) | ((i16_src >> 12 ) & 0xf ), ((i16_src << 4 ) & 0x7000 ) | (reg_dest << 8 ) | (i16_src & 0xff ));
256248}
257249
258- void asm_thumb_mov_reg_i32 (asm_thumb_t * as , uint reg_dest , machine_uint_t i32 ) {
259- // movw, movt does it in 8 bytes
260- // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
261-
262- asm_thumb_mov_i16_to_reg (as , i32 , reg_dest , false);
263- asm_thumb_mov_i16_to_reg (as , i32 >> 16 , reg_dest , true);
250+ // the i16_src value will be zero extended into the r32 register!
251+ void asm_thumb_movw_reg_i16 (asm_thumb_t * as , uint reg_dest , int i16_src ) {
252+ asm_thumb_mov_reg_i16 (as , OP_MOVW , reg_dest , i16_src );
264253}
265254
266- void asm_thumb_mov_reg_i32_optimised (asm_thumb_t * as , uint reg_dest , int i32 ) {
267- if (reg_dest < 8 && UNSIGNED_FIT8 (i32 )) {
268- asm_thumb_mov_reg_i8 (as , reg_dest , i32 );
269- } else if (UNSIGNED_FIT16 (i32 )) {
270- asm_thumb_mov_i16_to_reg (as , i32 , reg_dest , false);
271- } else {
272- asm_thumb_mov_reg_i32 (as , reg_dest , i32 );
273- }
255+ // the i16_src value will be zero extended into the r32 register!
256+ void asm_thumb_movt_reg_i16 (asm_thumb_t * as , uint reg_dest , int i16_src ) {
257+ asm_thumb_mov_reg_i16 (as , OP_MOVT , reg_dest , i16_src );
274258}
275259
276260void asm_thumb_mov_reg_reg (asm_thumb_t * as , uint reg_dest , uint reg_src ) {
@@ -285,9 +269,69 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
285269 } else {
286270 op_lo |= 0x80 | (reg_dest - 8 );
287271 }
272+ // mov reg_dest, reg_src
288273 asm_thumb_write_op16 (as , 0x4600 | op_lo );
289274}
290275
276+ #define OP_SUBS_RLO_RLO_I3 (rlo_dest , rlo_src , i3_src ) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest))
277+
278+ void asm_thumb_subs_rlo_rlo_i3 (asm_thumb_t * as , uint rlo_dest , uint rlo_src , int i3_src ) {
279+ assert (rlo_dest < REG_R8 );
280+ assert (rlo_src < REG_R8 );
281+ asm_thumb_write_op16 (as , OP_SUBS_RLO_RLO_I3 (rlo_dest , rlo_src , i3_src ));
282+ }
283+
284+ #define OP_CMP_RLO_I8 (rlo , i8 ) (0x2800 | ((rlo) << 8) | (i8))
285+
286+ void asm_thumb_cmp_rlo_i8 (asm_thumb_t * as , uint rlo , int i8 ) {
287+ assert (rlo < REG_R8 );
288+ asm_thumb_write_op16 (as , OP_CMP_RLO_I8 (rlo , i8 ));
289+ }
290+
291+ #define OP_BEQ_N (byte_offset ) (0xd000 | (((byte_offset) >> 1) & 0x00ff))
292+ #define OP_BNE_N (byte_offset ) (0xd100 | (((byte_offset) >> 1) & 0x00ff))
293+ #define OP_BCS_N (byte_offset ) (0xd200 | (((byte_offset) >> 1) & 0x00ff))
294+ #define OP_BCC_N (byte_offset ) (0xd300 | (((byte_offset) >> 1) & 0x00ff))
295+ #define OP_BMI_N (byte_offset ) (0xd400 | (((byte_offset) >> 1) & 0x00ff))
296+ #define OP_BPL_N (byte_offset ) (0xd500 | (((byte_offset) >> 1) & 0x00ff))
297+ #define OP_BVS_N (byte_offset ) (0xd600 | (((byte_offset) >> 1) & 0x00ff))
298+ #define OP_BVC_N (byte_offset ) (0xd700 | (((byte_offset) >> 1) & 0x00ff))
299+ #define OP_BHI_N (byte_offset ) (0xd800 | (((byte_offset) >> 1) & 0x00ff))
300+ #define OP_BLS_N (byte_offset ) (0xd900 | (((byte_offset) >> 1) & 0x00ff))
301+ #define OP_BGE_N (byte_offset ) (0xda00 | (((byte_offset) >> 1) & 0x00ff))
302+ #define OP_BLT_N (byte_offset ) (0xdb00 | (((byte_offset) >> 1) & 0x00ff))
303+ #define OP_BGT_N (byte_offset ) (0xdc00 | (((byte_offset) >> 1) & 0x00ff))
304+ #define OP_BLE_N (byte_offset ) (0xdd00 | (((byte_offset) >> 1) & 0x00ff))
305+
306+ void asm_thumb_bgt_n (asm_thumb_t * as , int label ) {
307+ int dest = get_label_dest (as , label );
308+ int rel = dest - as -> code_offset ;
309+ rel -= 4 ; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
310+ if (SIGNED_FIT9 (rel )) {
311+ asm_thumb_write_op16 (as , OP_BGT_N (rel ));
312+ } else {
313+ printf ("asm_thumb_bgt: branch does not fit in 9 bits\n" );
314+ }
315+ }
316+
317+ void asm_thumb_mov_reg_i32 (asm_thumb_t * as , uint reg_dest , machine_uint_t i32 ) {
318+ // movw, movt does it in 8 bytes
319+ // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
320+
321+ asm_thumb_mov_reg_i16 (as , OP_MOVW , reg_dest , i32 );
322+ asm_thumb_mov_reg_i16 (as , OP_MOVT , reg_dest , i32 >> 16 );
323+ }
324+
325+ void asm_thumb_mov_reg_i32_optimised (asm_thumb_t * as , uint reg_dest , int i32 ) {
326+ if (reg_dest < 8 && UNSIGNED_FIT8 (i32 )) {
327+ asm_thumb_movs_rlo_i8 (as , reg_dest , i32 );
328+ } else if (UNSIGNED_FIT16 (i32 )) {
329+ asm_thumb_mov_reg_i16 (as , OP_MOVW , reg_dest , i32 );
330+ } else {
331+ asm_thumb_mov_reg_i32 (as , reg_dest , i32 );
332+ }
333+ }
334+
291335#define OP_STR_TO_SP_OFFSET (rlo_dest , word_offset ) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
292336#define OP_LDR_FROM_SP_OFFSET (rlo_dest , word_offset ) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
293337
@@ -351,7 +395,6 @@ void asm_thumb_b_label(asm_thumb_t *as, int label) {
351395 }
352396}
353397
354- #define OP_CMP_REG_IMM (rlo , i8 ) (0x2800 | ((rlo) << 8) | (i8))
355398// all these bit arithmetics need coverage testing!
356399#define OP_BEQ (byte_offset ) (0xd000 | (((byte_offset) >> 1) & 0x00ff))
357400#define OP_BEQW_HI (byte_offset ) (0xf000 | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f))
@@ -361,15 +404,15 @@ void asm_thumb_cmp_reg_bz_label(asm_thumb_t *as, uint rlo, int label) {
361404 assert (rlo < REG_R8 );
362405
363406 // compare reg with 0
364- asm_thumb_write_op16 (as , OP_CMP_REG_IMM (rlo , 0 ));
407+ asm_thumb_write_op16 (as , OP_CMP_RLO_I8 (rlo , 0 ));
365408
366409 // branch if equal
367410 int dest = get_label_dest (as , label );
368411 int rel = dest - as -> code_offset ;
369412 rel -= 4 ; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
370413 if (dest >= 0 && rel <= -4 ) {
371414 // is a backwards jump, so we know the size of the jump on the first pass
372- // calculate rel assuming 12 bit relative jump
415+ // calculate rel assuming 9 bit relative jump
373416 if (SIGNED_FIT9 (rel )) {
374417 asm_thumb_write_op16 (as , OP_BEQ (rel ));
375418 } else {
0 commit comments