@@ -169,12 +169,29 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
169
169
return 0 ;
170
170
}
171
171
172
+ static const int8_t B4CONST [] = {
173
+ -1 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 10 , 12 , 16 , 32 , 64 , 128
174
+ };
175
+
176
+ static mp_int_t encode_b4const (mp_int_t immediate ) {
177
+ for (size_t index = 0 ; index < MP_ARRAY_SIZE (B4CONST ); index ++ ) {
178
+ if (immediate == (mp_int_t )(B4CONST [index ])) {
179
+ return index ;
180
+ }
181
+ }
182
+ return immediate == 256 ? 15 : -1 ;
183
+ }
184
+
172
185
#define RRR (0)
173
186
#define RRI8 (1)
174
187
#define RRI8_B (2)
188
+ #define BRI8 (3)
189
+
190
+ #define UNSIGNED 1
191
+ #define BUILD_BRANCH_IMM (cond ) (2 | ((cond) << 2))
175
192
176
193
typedef struct _opcode_table_3arg_t {
177
- uint16_t name ; // actually a qstr, which should fit in 16 bits
194
+ qstr_short_t name ;
178
195
uint8_t type ;
179
196
uint8_t a0 : 4 ;
180
197
uint8_t a1 : 4 ;
@@ -188,6 +205,13 @@ static const opcode_table_3arg_t opcode_table_3arg[] = {
188
205
{MP_QSTR_add , RRR , 0 , 8 },
189
206
{MP_QSTR_sub , RRR , 0 , 12 },
190
207
{MP_QSTR_mull , RRR , 2 , 8 },
208
+ {MP_QSTR_addx2 , RRR , 0 , 9 },
209
+ {MP_QSTR_addx4 , RRR , 0 , 10 },
210
+ {MP_QSTR_addx8 , RRR , 0 , 11 },
211
+ {MP_QSTR_subx2 , RRR , 0 , 13 },
212
+ {MP_QSTR_subx4 , RRR , 0 , 14 },
213
+ {MP_QSTR_subx8 , RRR , 0 , 15 },
214
+ {MP_QSTR_src , RRR , 1 , 8 },
191
215
192
216
// load/store/addi opcodes: reg, reg, imm
193
217
// upper nibble of type encodes the range of the immediate arg
@@ -209,21 +233,71 @@ static const opcode_table_3arg_t opcode_table_3arg[] = {
209
233
{MP_QSTR_bge , RRI8_B , ASM_XTENSA_CC_GE , 0 },
210
234
{MP_QSTR_bgeu , RRI8_B , ASM_XTENSA_CC_GEU , 0 },
211
235
{MP_QSTR_blt , RRI8_B , ASM_XTENSA_CC_LT , 0 },
236
+ {MP_QSTR_bltu , RRI8_B , ASM_XTENSA_CC_LTU , 0 },
212
237
{MP_QSTR_bnall , RRI8_B , ASM_XTENSA_CC_NALL , 0 },
213
238
{MP_QSTR_bne , RRI8_B , ASM_XTENSA_CC_NE , 0 },
214
239
{MP_QSTR_bnone , RRI8_B , ASM_XTENSA_CC_NONE , 0 },
215
240
};
216
241
242
+ #undef UNSIGNED
243
+
244
+ // The index of the qstrs matches the CCZ condition value to be embedded into the opcode.
245
+ static const qstr_short_t BCCZ_OPCODES [] = { MP_QSTR_beqz , MP_QSTR_bnez , MP_QSTR_bltz , MP_QSTR_bgez };
246
+
247
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
248
+ typedef struct _single_opcode_t {
249
+ qstr_short_t name ;
250
+ uint16_t value ;
251
+ } single_opcode_t ;
252
+
253
+ static const single_opcode_t NOARGS_OPCODES [] = {
254
+ {MP_QSTR_dsync , 0x2030 },
255
+ {MP_QSTR_esync , 0x2020 },
256
+ {MP_QSTR_extw , 0x20D0 },
257
+ {MP_QSTR_ill , 0x0000 },
258
+ {MP_QSTR_isync , 0x2000 },
259
+ {MP_QSTR_memw , 0x20C0 },
260
+ {MP_QSTR_rsync , 0x2010 },
261
+ };
262
+ #endif
263
+
264
+ static void handle_branch_immediate (emit_inline_asm_t * emit , const char * op_str , const uint8_t mn , mp_uint_t reg , mp_parse_node_t * pn_args ) {
265
+ mp_int_t imm = get_arg_i (emit , op_str , pn_args [1 ], -1 , 256 );
266
+ mp_int_t encoded = encode_b4const (imm );
267
+ if (encoded >= 0 ) {
268
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [2 ]);
269
+ asm_xtensa_immediate_branch (& emit -> as , reg , (mp_uint_t )encoded , label , mn );
270
+ return ;
271
+ }
272
+ emit_inline_xtensa_error_exc (emit , mp_obj_new_exception_msg_varg (& mp_type_SyntaxError , MP_ERROR_TEXT ("%d is not a valid immediate" ), imm ));
273
+ }
274
+
217
275
static void emit_inline_xtensa_op (emit_inline_asm_t * emit , qstr op , mp_uint_t n_args , mp_parse_node_t * pn_args ) {
218
276
size_t op_len ;
219
277
const char * op_str = (const char * )qstr_data (op , & op_len );
220
278
221
279
if (n_args == 0 ) {
222
- if (op == MP_QSTR_ret_n ) {
280
+ if (op == MP_QSTR_ret_n || op == MP_QSTR_ret ) {
223
281
asm_xtensa_op_ret_n (& emit -> as );
224
- } else {
225
- goto unknown_op ;
282
+ return ;
283
+ } else if (op == MP_QSTR_nop ) {
284
+ asm_xtensa_op24 (& emit -> as , 0x20F0 );
285
+ return ;
286
+ } else if (op == MP_QSTR_nop_n ) {
287
+ asm_xtensa_op16 (& emit -> as , 0xF03D );
288
+ return ;
289
+ }
290
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
291
+ for (size_t index = 0 ; index < MP_ARRAY_SIZE (NOARGS_OPCODES ); index ++ ) {
292
+ const single_opcode_t * opcode = & NOARGS_OPCODES [index ];
293
+ if (op == opcode -> name ) {
294
+ asm_xtensa_op24 (& emit -> as , opcode -> value );
295
+ return ;
296
+ }
226
297
}
298
+ #endif
299
+
300
+ goto unknown_op ;
227
301
228
302
} else if (n_args == 1 ) {
229
303
if (op == MP_QSTR_callx0 ) {
@@ -235,17 +309,49 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
235
309
} else if (op == MP_QSTR_jx ) {
236
310
uint r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
237
311
asm_xtensa_op_jx (& emit -> as , r0 );
312
+ } else if (op == M
10000
P_QSTR_ssl ) {
313
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
314
+ asm_xtensa_op_ssl (& emit -> as , r0 );
315
+ } else if (op == MP_QSTR_ssr ) {
316
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
317
+ asm_xtensa_op_ssr (& emit -> as , r0 );
318
+ } else if (op == MP_QSTR_ssai ) {
319
+ mp_uint_t sa = get_arg_i (emit , op_str , pn_args [0 ], 0 , 31 );
320
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 4 , 4 , sa & 0x0F , (sa >> 4 ) & 0x01 ));
321
+ } else if (op == MP_QSTR_ssa8b ) {
322
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
323
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 4 , 3 , r0 , 0 ));
324
+ } else if (op == MP_QSTR_ssa8l ) {
325
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
326
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 4 , 2 , r0 , 0 ));
327
+ } else if (op == MP_QSTR_call0 ) {
328
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [0 ]);
329
+ asm_xtensa_call0 (& emit -> as , label );
330
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
331
+ } else if (op == MP_QSTR_fsync ) {
332
+ mp_uint_t imm3 = get_arg_i (emit , op_str , pn_args [0 ], 0 , 7 );
333
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 0 , 2 , 8 | imm3 , 0 ));
334
+ } else if (op == MP_QSTR_ill_n ) {
335
+ asm_xtensa_op16 (& emit -> as , 0xF06D );
336
+ #endif
238
337
} else {
239
338
goto unknown_op ;
240
339
}
241
340
242
341
} else if (n_args == 2 ) {
243
342
uint r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
244
- if (op == MP_QSTR_beqz ) {
245
- int label = get_arg_label (emit , op_str , pn_args [1 ]);
343
+ for (size_t index = 0 ; index < MP_ARRAY_SIZE (BCCZ_OPCODES ); index ++ ) {
344
+ if (op == BCCZ_OPCODES [index ]) {
345
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [1 ]);
346
+ asm_xtensa_bccz_reg_label (& emit -> as , index , r0 , label );
347
+ return ;
348
+ }
349
+ }
350
+ if (op == MP_QSTR_beqz_n ) {
351
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [1 ]);
246
352
asm_xtensa_bccz_reg_label (& emit -> as , ASM_XTENSA_CCZ_EQ , r0 , label );
247
- } else if (op == MP_QSTR_bnez ) {
248
- int label = get_arg_label (emit , op_str , pn_args [1 ]);
353
+ } else if (op == MP_QSTR_bnez_n ) {
354
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [1 ]);
249
355
asm_xtensa_bccz_reg_label (& emit -> as , ASM_XTENSA_CCZ_NE , r0 , label );
250
356
} else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n ) {
251
357
// we emit mov.n for both "mov" and "mov_n" opcodes
@@ -255,7 +361,47 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
255
361
// for convenience we emit l32r if the integer doesn't fit in movi
256
362
uint32_t imm = get_arg_i (emit , op_str , pn_args [1 ], 0 , 0 );
257
363
asm_xtensa_mov_reg_i32 (& emit -> as , r0 , imm );
258
- } else {
364
+ } else if (op == MP_QSTR_abs_ ) {
365
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
366
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 6 , r0 , 1 , r1 ));
367
+ } else if (op == MP_QSTR_neg ) {
368
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
369
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 0 , 6 , r0 , 0 , r1 ));
370
+ } else if (op == MP_QSTR_sll ) {
371
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
372
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 10 , r0 , r1 , 0 ));
373
+ } else if (op == MP_QSTR_sra ) {
374
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
375
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 11 , r0 , 0 , r1 ));
376
+ } else if (op == MP_QSTR_srl ) {
377
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
378
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 9 , r0 , 0 , r1 ));
379
+ } else if (op == MP_QSTR_l32r ) {
380
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [1 ]);
381
+ asm_xtensa_l32r (& emit -> as , r0 , label );
382
+ } else if (op == MP_QSTR_movi_n ) {
383
+ mp_int_t imm = get_arg_i (emit , op_str , pn_args [1 ], -32 , 95 );
384
+ asm_xtensa_op_movi_n (& emit -> as , r0 , imm );
385
+ } else
386
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
387
+ if (op == MP_QSTR_rsr ) {
388
+ mp_uint_t sr = get_arg_i (emit , op_str , pn_args [1 ], 0 , 255 );
389
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RSR (0 , 3 , 0 , sr , r0 ));
390
+ } else if (op == MP_QSTR_rur ) {
391
+ mp_uint_t imm8 = get_arg_i (emit , op_str , pn_args [1 ], 0 , 255 );
392
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 3 , 14 , r0 , (imm8 >> 4 ) & 0x0F , imm8 & 0x0F ));
393
+ } else if (op == MP_QSTR_wsr ) {
394
+ mp_uint_t sr = get_arg_i (emit , op_str , pn_args [1 ], 0 , 255 );
395
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RSR (0 , 3 , 1 , sr , r0 ));
396
+ } else if (op == MP_QSTR_wur ) {
397
+ mp_uint_t sr = get_arg_i (emit , op_str , pn_args [1 ], 0 , 255 );
398
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RSR (0 , 3 , 15 , sr , r0 ));
399
+ } else if (op == MP_QSTR_xsr ) {
400
+ mp_uint_t sr = get_arg_i (emit , op_str , pn_args [1 ], 0 , 255 );
401
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RSR (0 , 1 , 6 , sr , r0 ));
402
+ } else
403
+ #endif
404
+ {
259
405
goto unknown_op ;
260
406
}
261
407
@@ -265,6 +411,10 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
265
411
const opcode_table_3arg_t * o = & opcode_table_3arg [i ];
266
412
if (op == o -> name ) {
267
413
uint r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
414
+ if (o -> type == BRI8 ) {
415
+ handle_branch_immediate (emit , op_str , o -> a0 , r0 , pn_args );
416
+ return ;
417
+ }
268
418
uint r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
269
419
if (o -> type == RRR ) {
270
420
uint r2 = get_arg_reg (emit , op_str , pn_args [2 ]);
@@ -289,7 +439,72 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
289
439
return ;
290
440
}
291
441
}
292
- goto unknown_op ;
442
+
443
+ if (op == MP_QSTR_add_n ) {
444
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
445
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
446
+ mp_uint_t r2 = get_arg_reg (emit , op_str , pn_args [2 ]);
447
+ asm_xtensa_op16 (& emit -> as , ASM_XTENSA_ENCODE_RRRN (10 , r0 , r1 , r2 ));
448
+ } else if (op == MP_QSTR_addi_n ) {
449
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
450
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
451
+ mp_int_t imm4 = get_arg_i (emit , op_str , pn_args [2 ], -1 , 15 );
452
+ asm_xtensa_op16 (& emit -> as , ASM_XTENSA_ENCODE_RRRN (11 , r0 , r1 , (imm4 != 0 ? imm4 : -1 )));
453
+ } else if (op == MP_QSTR_addmi ) {
454
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
455
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
456
+ mp_int_t imm8 = get_arg_i (emit , op_str , pn_args [2 ], -128 * 256 , 127 * 256 );
457
+ if ((imm8 & 0xFF ) != 0 ) {
458
+ emit_inline_xtensa_error_exc (emit , mp_obj_new_exception_msg_varg (& mp_type_SyntaxError , MP_ERROR_TEXT ("%d is not a multiple of %d" ), imm8 , 256 ));
459
+ } else {
460
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRI8 (2 , 13 , r1 , r0 , imm8 >> 8 ));
461
+ }
462
+ } else if (op == MP_QSTR_bbci ) {
463
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
464
+ mp_uint_t bit = get_arg_i (emit , op_str , pn_args [1 ], 0 , 31 );
465
+ mp_int_t label = get_arg_label (emit , op_str , pn_args [2 ]);
466
+ asm_xtensa_bit_branch (& emit -> as , r0 , bit , label , 6 );
467
+ } else if (op == MP_QSTR_bbsi ) {
468
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
469
+ mp_uint_t bit = get_arg_i (emit , op_str , pn_args [1 ], 0 , 31 );
470
+ mp_uint_t label = get_arg_label (emit , op_str , pn_args [2 ]);
471
+ asm_xtensa_bit_branch (& emit -> as , r0 , bit , label , 14 );
472
+ } else if (op == MP_QSTR_slli ) {
473
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
474
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
475
+ mp_uint_t bits = 32 - get_arg_i (emit , op_str , pn_args [2 ], 1 , 31 );
476
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 0 | ((bits >> 4 ) & 0x01 ), r0 , r1 , bits & 0x0F ));
477
+ } else if (op == MP_QSTR_srai ) {
478
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
479
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
480
+ mp_uint_t bits = get_arg_i (emit , op_str , pn_args [2 ], 0 , 31 );
481
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 2 | ((bits >> 4 ) & 0x01 ), r0 , bits & 0x0F , r1 ));
482
+ } else if (op == MP_QSTR_srli ) {
483
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
484
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
485
+ mp_uint_t bits = get_arg_i (emit , op_str , pn_args [2 ], 0 , 15 );
486
+ asm_xtensa_op24 (& emit -> as , ASM_XTENSA_ENCODE_RRR (0 , 1 , 4 , r0 , bits , r1 ));
487
+ } else if (op == MP_QSTR_l32i_n ) {
488
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
489
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
490
+ mp_uint_t imm = get_arg_i (emit , op_str , pn_args [2 ], 0 , 60 );
491
+ if ((imm & 0x03 ) != 0 ) {
492
+ emit_inline_xtensa_error_exc (emit , mp_obj_new_exception_msg_varg (& mp_type_SyntaxError , MP_ERROR_TEXT ("%d is not a multiple of %d" ), imm , 4 ));
493
+ } else {
494
+ asm_xtensa_op_l32i_n (& emit -> as , r0 , r1 , imm >> 2 );
495
+ }
496
+ } else if (op == MP_QSTR_s32i_n ) {
497
+ mp_uint_t r0 = get_arg_reg (emit , op_str , pn_args [0 ]);
498
+ mp_uint_t r1 = get_arg_reg (emit , op_str , pn_args [1 ]);
499
+ mp_uint_t imm = get_arg_i (emit , op_str , pn_args [2 ], 0 , 60 );
500
+ if ((imm & 0x03 ) != 0 ) {
501
+ emit_inline_xtensa_error_exc (emit , mp_obj_new_exception_msg_varg (& mp_type_SyntaxError , MP_ERROR_TEXT ("%d is not a multiple of %d" ), imm , 4 ));
502
+ } else {
503
+ asm_xtensa_op_s32i_n (& emit -> as , r0 , r1 , imm >> 2 );
504
+ }
505
+ } else {
506
+ goto unknown_op ;
507
+ }
293
508
294
509
} else {
295
510
goto unknown_op ;
0 commit comments