Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
a26dc509
Commit
a26dc509
authored
Apr 12, 2014
by
Damien George
Browse files
py: Improve inline assembler; improve compiler constant folding.
parent
2813cb60
Changes
7
Hide whitespace changes
Inline
Side-by-side
py/asmthumb.c
View file @
a26dc509
...
...
@@ -275,10 +275,10 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
asm_thumb_write_op16
(
as
,
0x4600
|
op_lo
);
}
#define OP_ADD_R
EG_REG_REG
(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
#define OP_ADD_R
LO_RLO_RLO
(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
void
asm_thumb_add_r
eg_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
)
{
asm_thumb_write_op16
(
as
,
OP_ADD_R
EG_REG_REG
(
rlo_dest
,
rlo_src_a
,
rlo_src_b
));
void
asm_thumb_add_r
lo_rlo_rlo
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
)
{
asm_thumb_write_op16
(
as
,
OP_ADD_R
LO_RLO_RLO
(
rlo_dest
,
rlo_src_a
,
rlo_src_b
));
}
#define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest))
...
...
@@ -302,6 +302,17 @@ void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
asm_thumb_write_op16
(
as
,
OP_CMP_RLO_I8
(
rlo
,
i8
));
}
#define OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
#define OP_STR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6000 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
void
asm_thumb_ldr_rlo_rlo_i5
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_base
,
uint
word_offset
)
{
asm_thumb_write_op16
(
as
,
OP_LDR_RLO_RLO_I5
(
rlo_dest
,
rlo_base
,
word_offset
));
}
void
asm_thumb_str_rlo_rlo_i5
(
asm_thumb_t
*
as
,
uint
rlo_src
,
uint
rlo_base
,
uint
word_offset
)
{
asm_thumb_write_op16
(
as
,
OP_STR_RLO_RLO_I5
(
rlo_src
,
rlo_base
,
word_offset
));
}
void
asm_thumb_ite_ge
(
asm_thumb_t
*
as
)
{
asm_thumb_write_op16
(
as
,
0xbfac
);
}
...
...
@@ -424,7 +435,6 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
#define OP_BLX(reg) (0x4780 | ((reg) << 3))
#define OP_SVC(arg) (0xdf00 | (arg))
#define OP_LDR_FROM_BASE_OFFSET(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
void
asm_thumb_bl_ind
(
asm_thumb_t
*
as
,
void
*
fun_ptr
,
uint
fun_id
,
uint
reg_temp
)
{
/* TODO make this use less bytes
...
...
@@ -442,7 +452,7 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
asm_thumb_mov_reg_i32
(
as
,
reg_temp
,
(
machine_uint_t
)
fun_ptr
);
asm_thumb_write_op16
(
as
,
OP_BLX
(
reg_temp
));
}
else
if
(
1
)
{
asm_thumb_write_op16
(
as
,
OP_LDR_
FROM_BASE_OFFSET
(
reg_temp
,
REG_R7
,
fun_id
));
asm_thumb_write_op16
(
as
,
OP_LDR_
RLO_RLO_I5
(
reg_temp
,
REG_R7
,
fun_id
));
asm_thumb_write_op16
(
as
,
OP_BLX
(
reg_temp
));
}
else
{
// use SVC
...
...
py/asmthumb.h
View file @
a26dc509
...
...
@@ -62,10 +62,12 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src);
void
asm_thumb_movw_reg_i16
(
asm_thumb_t
*
as
,
uint
reg_dest
,
int
i16_src
);
void
asm_thumb_movt_reg_i16
(
asm_thumb_t
*
as
,
uint
reg_dest
,
int
i16_src
);
void
asm_thumb_mov_reg_reg
(
asm_thumb_t
*
as
,
uint
reg_dest
,
uint
reg_src
);
void
asm_thumb_add_r
eg_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
);
void
asm_thumb_add_r
lo_rlo_rlo
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
);
void
asm_thumb_subs_rlo_rlo_i3
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src
,
int
i3_src
);
void
asm_thumb_cmp_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_a
,
uint
rlo_b
);
void
asm_thumb_cmp_rlo_i8
(
asm_thumb_t
*
as
,
uint
rlo
,
int
i8
);
void
asm_thumb_ldr_rlo_rlo_i5
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_base
,
uint
word_offset
);
void
asm_thumb_str_rlo_rlo_i5
(
asm_thumb_t
*
as
,
uint
rlo_src
,
uint
rlo_base
,
uint
word_offset
);
void
asm_thumb_ite_ge
(
asm_thumb_t
*
as
);
void
asm_thumb_b_n
(
asm_thumb_t
*
as
,
uint
label
);
void
asm_thumb_bcc_n
(
asm_thumb_t
*
as
,
int
cond
,
uint
label
);
...
...
py/compile.c
View file @
a26dc509
...
...
@@ -17,6 +17,7 @@
#include
"obj.h"
#include
"compile.h"
#include
"runtime.h"
#include
"builtin.h"
#include
"smallint.h"
// TODO need to mangle __attr names
...
...
@@ -100,17 +101,44 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
pns
->
nodes
[
i
]
=
fold_constants
(
pns
->
nodes
[
i
]);
}
// now try to fold this parse node
switch
(
MP_PARSE_NODE_STRUCT_KIND
(
pns
))
{
case
PN_atom_paren
:
if
(
n
==
1
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
0
]))
{
// (int)
pn
=
pns
->
nodes
[
0
];
}
break
;
case
PN_expr
:
if
(
n
==
2
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
0
])
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
1
]))
{
// int | int
machine_int_t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
machine_int_t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
1
]);
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
|
arg1
);
}
break
;
case
PN_and_expr
:
if
(
n
==
2
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
0
])
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
1
]))
{
// int & int
machine_int_t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
machine_int_t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
1
]);
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
&
arg1
);
}
break
;
case
PN_shift_expr
:
if
(
n
==
3
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
0
])
&&
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
2
]))
{
in
t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
in
t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
2
]);
machine_int_
t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
machine_int_
t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
2
]);
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_DBL_LESS
))
{
#if MICROPY_EMIT_CPYTHON
// can overflow; enabled only to compare with CPython
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
<<
arg1
);
#endif
// int << int
if
(
!
(
arg1
>=
BITS_PER_WORD
||
arg0
>
(
MP_SMALL_INT_MAX
>>
arg1
)
||
arg0
<
(
MP_SMALL_INT_MIN
>>
arg1
)))
{
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
<<
arg1
);
}
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_DBL_MORE
))
{
// int >> int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
>>
arg1
);
}
else
{
// shouldn't happen
...
...
@@ -125,14 +153,17 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
machine_int_t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
2
]);
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_PLUS
))
{
// int + int
arg0
+=
arg1
;
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_MINUS
))
{
// int - int
arg0
-=
arg1
;
}
else
{
// shouldn't happen
assert
(
0
);
}
if
(
MP_PARSE_FITS_SMALL_INT
(
arg0
))
{
//printf("%ld + %ld\n", arg0, arg1);
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg0
);
}
}
...
...
@@ -143,6 +174,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t
arg0
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
0
]);
machine_int_t
arg1
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
2
]);
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_STAR
))
{
// int * int
if
(
!
mp_small_int_mul_overflow
(
arg0
,
arg1
))
{
arg0
*=
arg1
;
if
(
MP_PARSE_FITS_SMALL_INT
(
arg0
))
{
...
...
@@ -150,11 +182,14 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
}
}
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_SLASH
))
{
;
// pass
// int / int
// pass
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_PERCENT
))
{
// int%int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
mp_small_int_modulo
(
arg0
,
arg1
));
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
1
],
MP_TOKEN_OP_DBL_SLASH
))
{
if
(
arg1
!=
0
)
{
// int // int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
mp_small_int_floor_divide
(
arg0
,
arg1
));
}
}
else
{
...
...
@@ -168,10 +203,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if
(
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
1
]))
{
machine_int_t
arg
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pns
->
nodes
[
1
]);
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
0
],
MP_TOKEN_OP_PLUS
))
{
// +int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
arg
);
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
0
],
MP_TOKEN_OP_MINUS
))
{
// -int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
-
arg
);
}
else
if
(
MP_PARSE_NODE_IS_TOKEN_KIND
(
pns
->
nodes
[
0
],
MP_TOKEN_OP_TILDE
))
{
// ~int
pn
=
mp_parse_node_new_leaf
(
MP_PARSE_NODE_SMALL_INT
,
~
arg
);
}
else
{
// shouldn't happen
...
...
@@ -184,7 +222,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if
(
0
)
{
#if MICROPY_EMIT_CPYTHON
}
else
if
(
MP_PARSE_NODE_IS_SMALL_INT
(
pns
->
nodes
[
0
])
&&
MP_PARSE_NODE_IS_NULL
(
pns
->
nodes
[
1
])
&&
!
MP_PARSE_NODE_IS_NULL
(
pns
->
nodes
[
2
]))
{
// int**x
// int
**
x
// can overflow; enabled only to compare with CPython
mp_parse_node_struct_t
*
pns2
=
(
mp_parse_node_struct_t
*
)
pns
->
nodes
[
2
];
if
(
MP_PARSE_NODE_IS_SMALL_INT
(
pns2
->
nodes
[
0
]))
{
...
...
@@ -3121,7 +3159,16 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
for
(
int
i
=
0
;
i
<
num
;
i
++
)
{
assert
(
MP_PARSE_NODE_IS_STRUCT
(
nodes
[
i
]));
mp_parse_node_struct_t
*
pns2
=
(
mp_parse_node_struct_t
*
)
nodes
[
i
];
assert
(
MP_PARSE_NODE_STRUCT_KIND
(
pns2
)
==
PN_expr_stmt
);
if
(
MP_PARSE_NODE_STRUCT_KIND
(
pns2
)
==
PN_pass_stmt
)
{
// no instructions
continue
;
}
else
if
(
MP_PARSE_NODE_STRUCT_KIND
(
pns2
)
==
PN_expr_stmt
)
{
// an instruction; fall through
}
else
{
// not an instruction; error
compile_syntax_error
(
comp
,
nodes
[
i
],
"inline assembler expecting an instruction"
);
return
;
}
assert
(
MP_PARSE_NODE_IS_STRUCT
(
pns2
->
nodes
[
0
]));
assert
(
MP_PARSE_NODE_IS_NULL
(
pns2
->
nodes
[
1
]));
pns2
=
(
mp_parse_node_struct_t
*
)
pns2
->
nodes
[
0
];
...
...
@@ -3152,7 +3199,10 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
}
if
(
comp
->
pass
>
PASS_1
)
{
EMIT_INLINE_ASM
(
end_pass
);
bool
success
=
EMIT_INLINE_ASM
(
end_pass
);
if
(
!
success
)
{
comp
->
had_error
=
true
;
}
}
}
#endif
...
...
@@ -3330,7 +3380,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
comp
->
emit_inline_asm
=
emit_inline_thumb
;
comp
->
emit_inline_asm_method_table
=
&
emit_inline_thumb_method_table
;
compile_scope_inline_asm
(
comp
,
s
,
PASS_2
);
compile_scope_inline_asm
(
comp
,
s
,
PASS_3
);
if
(
!
comp
->
had_error
)
{
compile_scope_inline_asm
(
comp
,
s
,
PASS_3
);
}
#endif
}
else
{
...
...
@@ -3374,7 +3426,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
// compile pass 2 and pass 3
compile_scope
(
comp
,
s
,
PASS_2
);
compile_scope
(
comp
,
s
,
PASS_3
);
if
(
!
comp
->
had_error
)
{
compile_scope
(
comp
,
s
,
PASS_3
);
}
}
}
...
...
py/emit.h
View file @
a26dc509
...
...
@@ -133,7 +133,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t;
typedef
struct
_emit_inline_asm_method_table_t
{
void
(
*
start_pass
)(
emit_inline_asm_t
*
emit
,
pass_kind_t
pass
,
scope_t
*
scope
);
void
(
*
end_pass
)(
emit_inline_asm_t
*
emit
);
bool
(
*
end_pass
)(
emit_inline_asm_t
*
emit
);
int
(
*
count_params
)(
emit_inline_asm_t
*
emit
,
int
n_params
,
mp_parse_node_t
*
pn_params
);
void
(
*
label
)(
emit_inline_asm_t
*
emit
,
uint
label_num
,
qstr
label_id
);
void
(
*
op
)(
emit_inline_asm_t
*
emit
,
qstr
op
,
int
n_args
,
mp_parse_node_t
*
pn_args
);
...
...
py/emitglue.c
View file @
a26dc509
...
...
@@ -185,6 +185,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
#ifdef WRITE_CODE
if
(
fp_write_code
!=
NULL
)
{
fwrite
(
fun_data
,
len
,
1
,
fp_write_code
);
fflush
(
fp_write_code
);
}
#endif
#endif
...
...
py/emitinlinethumb.c
View file @
a26dc509
#include
<stdint.h>
#include
<stdio.h>
#include
<string.h>
#include
<stdarg.h>
#include
<assert.h>
#include
"misc.h"
...
...
@@ -17,13 +18,23 @@
#if MICROPY_EMIT_INLINE_THUMB
struct
_emit_inline_asm_t
{
int
pass
;
uint16_t
pass
;
uint16_t
success
;
scope_t
*
scope
;
uint
max_num_labels
;
qstr
*
label_lookup
;
asm_thumb_t
*
as
;
};
void
emit_inline_thumb_error
(
emit_inline_asm_t
*
emit
,
const
char
*
fmt
,
...)
{
printf
(
"SyntaxError: "
);
emit
->
success
=
false
;
va_list
ap
;
va_start
(
ap
,
fmt
);
vprintf
(
fmt
,
ap
);
va_end
(
ap
);
}
emit_inline_asm_t
*
emit_inline_thumb_new
(
uint
max_num_labels
)
{
emit_inline_asm_t
*
emit
=
m_new_obj
(
emit_inline_asm_t
);
emit
->
max_num_labels
=
max_num_labels
;
...
...
@@ -41,12 +52,13 @@ void emit_inline_thumb_free(emit_inline_asm_t *emit) {
STATIC
void
emit_inline_thumb_start_pass
(
emit_inline_asm_t
*
emit
,
pass_kind_t
pass
,
scope_t
*
scope
)
{
emit
->
pass
=
pass
;
emit
->
success
=
true
;
emit
->
scope
=
scope
;
asm_thumb_start_pass
(
emit
->
as
,
pass
);
asm_thumb_entry
(
emit
->
as
,
0
);
}
STATIC
void
emit_inline_thumb_end_pass
(
emit_inline_asm_t
*
emit
)
{
STATIC
bool
emit_inline_thumb_end_pass
(
emit_inline_asm_t
*
emit
)
{
asm_thumb_exit
(
emit
->
as
);
asm_thumb_end_pass
(
emit
->
as
);
...
...
@@ -54,21 +66,23 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
void
*
f
=
asm_thumb_get_code
(
emit
->
as
);
mp_emit_glue_assign_inline_asm_code
(
emit
->
scope
->
unique_code_id
,
f
,
asm_thumb_get_code_size
(
emit
->
as
),
emit
->
scope
->
num_params
);
}
return
emit
->
success
;
}
STATIC
int
emit_inline_thumb_count_params
(
emit_inline_asm_t
*
emit
,
int
n_params
,
mp_parse_node_t
*
pn_params
)
{
if
(
n_params
>
4
)
{
printf
(
"SyntaxError:
can only have up to 4 parameters to inline thumb assembly
\n
"
);
emit_inline_thumb_error
(
emit
,
"
can only have up to 4 parameters to inline thumb assembly
\n
"
);
return
0
;
}
for
(
int
i
=
0
;
i
<
n_params
;
i
++
)
{
if
(
!
MP_PARSE_NODE_IS_ID
(
pn_params
[
i
]))
{
printf
(
"SyntaxError:
parameter to inline assembler must be an identifier
\n
"
);
emit_inline_thumb_error
(
emit
,
"
parameter to inline assembler must be an identifier
\n
"
);
return
0
;
}
const
char
*
p
=
qstr_str
(
MP_PARSE_NODE_LEAF_ARG
(
pn_params
[
i
]));
if
(
!
(
strlen
(
p
)
==
2
&&
p
[
0
]
==
'r'
&&
p
[
1
]
==
'0'
+
i
))
{
printf
(
"SyntaxError:
parameter %d to inline assembler must be r%d
\n
"
,
i
+
1
,
i
);
emit_inline_thumb_error
(
emit
,
"
parameter %d to inline assembler must be r%d
\n
"
,
i
+
1
,
i
);
return
0
;
}
}
...
...
@@ -81,28 +95,59 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qst
asm_thumb_label_assign
(
emit
->
as
,
label_num
);
}
STATIC
uint
get_arg_rlo
(
const
char
*
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
)
{
if
(
!
MP_PARSE_NODE_IS_ID
(
pn_args
[
wanted_arg_num
]))
{
printf
(
"SyntaxError: '%s' expects a register in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
}
qstr
reg_qstr
=
MP_PARSE_NODE_LEAF_ARG
(
pn_args
[
wanted_arg_num
]);
const
char
*
reg_str
=
qstr_str
(
reg_qstr
);
if
(
!
(
strlen
(
reg_str
)
==
2
&&
reg_str
[
0
]
==
'r'
&&
(
'0'
<=
reg_str
[
1
]
&&
reg_str
[
1
]
<=
'7'
)))
{
printf
(
"SyntaxError: '%s' expects a register in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
typedef
struct
_reg_name_t
{
byte
reg
;
byte
name
[
3
];
}
reg_name_t
;
STATIC
const
reg_name_t
reg_name_table
[]
=
{
{
0
,
"r0
\0
"
},
{
1
,
"r1
\0
"
},
{
2
,
"r2
\0
"
},
{
3
,
"r3
\0
"
},
{
4
,
"r4
\0
"
},
{
5
,
"r5
\0
"
},
{
6
,
"r6
\0
"
},
{
7
,
"r7
\0
"
},
{
8
,
"r8
\0
"
},
{
9
,
"r9
\0
"
},
{
10
,
"r10"
},
{
11
,
"r11"
},
{
12
,
"r12"
},
{
13
,
"r13"
},
{
14
,
"r14"
},
{
15
,
"r15"
},
{
10
,
"sl
\0
"
},
{
11
,
"fp
\0
"
},
{
13
,
"sp
\0
"
},
{
14
,
"lr
\0
"
},
{
15
,
"pc
\0
"
},
};
STATIC
uint
get_arg_reg
(
emit_inline_asm_t
*
emit
,
const
char
*
op
,
mp_parse_node_t
*
pn_args
,
uint
wanted_arg_num
,
uint
max_reg
)
{
if
(
MP_PARSE_NODE_IS_ID
(
pn_args
[
wanted_arg_num
]))
{
qstr
reg_qstr
=
MP_PARSE_NODE_LEAF_ARG
(
pn_args
[
wanted_arg_num
]);
const
char
*
reg_str
=
qstr_str
(
reg_qstr
);
for
(
uint
i
=
0
;
i
<
sizeof
(
reg_name_table
)
/
sizeof
(
reg_name_table
[
0
]);
i
++
)
{
const
reg_name_t
*
r
=
&
reg_name_table
[
i
];
if
(
reg_str
[
0
]
==
r
->
name
[
0
]
&&
reg_str
[
1
]
==
r
->
name
[
1
]
&&
reg_str
[
2
]
==
r
->
name
[
2
]
&&
(
reg_str
[
2
]
==
'\0'
||
reg_str
[
3
]
==
'\0'
))
{
if
(
r
->
reg
>
max_reg
)
{
emit_inline_thumb_error
(
emit
,
"'%s' expects at most r%d in position %d
\n
"
,
op
,
max_reg
,
wanted_arg_num
);
return
0
;
}
else
{
return
r
->
reg
;
}
}
}
}
return
reg_str
[
1
]
-
'0'
;
emit_inline_thumb_error
(
emit
,
"'%s' expects a register in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
}
STATIC
int
get_arg_i
(
const
char
*
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
,
int
fit_mask
)
{
STATIC
int
get_arg_i
(
emit_inline_asm_t
*
emit
,
const
char
*
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
,
int
fit_mask
)
{
if
(
!
MP_PARSE_NODE_IS_SMALL_INT
(
pn_args
[
wanted_arg_num
]))
{
printf
(
"SyntaxError:
'%s' expects an integer in position %d
\n
"
,
op
,
wanted_arg_num
);
emit_inline_thumb_error
(
emit
,
"
'%s' expects an integer in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
}
int
i
=
MP_PARSE_NODE_LEAF_SMALL_INT
(
pn_args
[
wanted_arg_num
]);
if
((
i
&
(
~
fit_mask
))
!=
0
)
{
printf
(
"SyntaxError:
'%s' integer 0x%x does not fit in mask 0x%x
\n
"
,
op
,
i
,
fit_mask
);
emit_inline_thumb_error
(
emit
,
"
'%s' integer 0x%x does not fit in mask 0x%x
\n
"
,
op
,
i
,
fit_mask
);
return
0
;
}
return
i
;
...
...
@@ -110,7 +155,7 @@ STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_nu
STATIC
int
get_arg_label
(
emit_inline_asm_t
*
emit
,
const
char
*
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
)
{
if
(
!
MP_PARSE_NODE_IS_ID
(
pn_args
[
wanted_arg_num
]))
{
printf
(
"SyntaxError:
'%s' expects a label in position %d
\n
"
,
op
,
wanted_arg_num
);
emit_inline_thumb_error
(
emit
,
"
'%s' expects a label in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
}
qstr
label_qstr
=
MP_PARSE_NODE_LEAF_ARG
(
pn_args
[
wanted_arg_num
]);
...
...
@@ -121,7 +166,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
}
// only need to have the labels on the last pass
if
(
emit
->
pass
==
PASS_3
)
{
printf
(
"SyntaxError:
label '%s' not defined
\n
"
,
qstr_str
(
label_qstr
));
emit_inline_thumb_error
(
emit
,
"
label '%s' not defined
\n
"
,
qstr_str
(
label_qstr
));
}
return
0
;
}
...
...
@@ -189,24 +234,31 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
}
else
if
(
n_args
==
2
)
{
if
(
strcmp
(
op_str
,
"mov"
)
==
0
)
{
uint
rlo_dest
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
uint
rlo_src
=
get_arg_r
lo
(
op_str
,
pn_args
,
1
);
uint
rlo_dest
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
uint
rlo_src
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
1
,
7
);
asm_thumb_mov_reg_reg
(
emit
->
as
,
rlo_dest
,
rlo_src
);
}
else
if
(
strcmp
(
op_str
,
"movs"
)
==
0
)
{
uint
rlo_dest
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
int
i_src
=
get_arg_i
(
op_str
,
pn_args
,
1
,
0xff
);
uint
rlo_dest
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
int
i_src
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
1
,
0xff
);
asm_thumb_movs_rlo_i8
(
emit
->
as
,
rlo_dest
,
i_src
);
}
else
if
(
strcmp
(
op_str
,
"movw"
)
==
0
)
{
uint
r
lo
_dest
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
// TODO can be reg lo or hi
int
i_src
=
get_arg_i
(
op_str
,
pn_args
,
1
,
0xffff
);
asm_thumb_movw_reg_i16
(
emit
->
as
,
r
lo
_dest
,
i_src
);
uint
r
eg
_dest
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
15
);
int
i_src
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
1
,
0xffff
);
asm_thumb_movw_reg_i16
(
emit
->
as
,
r
eg
_dest
,
i_src
);
}
else
if
(
strcmp
(
op_str
,
"movt"
)
==
0
)
{
uint
rlo_dest
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
// TODO can be reg lo or hi
int
i_src
=
get_arg_i
(
op_str
,
pn_args
,
1
,
0xffff
);
asm_thumb_movt_reg_i16
(
emit
->
as
,
rlo_dest
,
i_src
);
uint
reg_dest
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
0
,
15
);
int
i_src
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
1
,
0xffff
);
asm_thumb_movt_reg_i16
(
emit
->
as
,
reg_dest
,
i_src
);
}
else
if
(
strcmp
(
op_str
,
"movwt"
)
==
0
)
{
// this is a convenience instruction
// we clear the MSB since it might be set from extracting the small int value
uint
reg_dest
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
0
,
15
);
int
i_src
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
1
,
0xffffffff
);
asm_thumb_movw_reg_i16
(
emit
->
as
,
reg_dest
,
i_src
&
0xffff
);
asm_thumb_movt_reg_i16
(
emit
->
as
,
reg_dest
,
(
i_src
>>
16
)
&
0x7fff
);
}
else
if
(
strcmp
(
op_str
,
"cmp"
)
==
0
)
{
uint
rlo
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
int
i8
=
get_arg_i
(
op_str
,
pn_args
,
1
,
0xff
);
uint
rlo
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
int
i8
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
1
,
0xff
);
asm_thumb_cmp_rlo_i8
(
emit
->
as
,
rlo
,
i8
);
}
else
{
goto
unknown_op
;
...
...
@@ -214,15 +266,26 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
}
else
if
(
n_args
==
3
)
{
if
(
strcmp
(
op_str
,
"add"
)
==
0
)
{
uint
rlo_dest
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
uint
rlo_src_a
=
get_arg_r
lo
(
op_str
,
pn_args
,
1
);
uint
rlo_src_b
=
get_arg_r
lo
(
op_str
,
pn_args
,
2
);
asm_thumb_add_r
eg_reg_reg
(
emit
->
as
,
rlo_dest
,
rlo_src_a
,
rlo_src_b
);
uint
rlo_dest
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
uint
rlo_src_a
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
1
,
7
);
uint
rlo_src_b
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
2
,
7
);
asm_thumb_add_r
lo_rlo_rlo
(
emit
->
as
,
rlo_dest
,
rlo_src_a
,
rlo_src_b
);
}
else
if
(
strcmp
(
op_str
,
"subs"
)
==
0
)
{
uint
rlo_dest
=
get_arg_r
lo
(
op_str
,
pn_args
,
0
);
uint
rlo_src
=
get_arg_r
lo
(
op_str
,
pn_args
,
1
);
int
i3_src
=
get_arg_i
(
op_str
,
pn_args
,
2
,
0x7
);
uint
rlo_dest
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
uint
rlo_src
=
get_arg_r
eg
(
emit
,
op_str
,
pn_args
,
1
,
7
);
int
i3_src
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
2
,
0x7
);
asm_thumb_subs_rlo_rlo_i3
(
emit
->
as
,
rlo_dest
,
rlo_src
,
i3_src
);
}
else
if
(
strcmp
(
op_str
,
"ldr"
)
==
0
)
{
// TODO maybe use ldr(rd, [rb, 4]) syntax?
uint
rlo_dest
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
uint
rlo_base
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
1
,
7
);
int
i5
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
2
,
0x7c
);
asm_thumb_ldr_rlo_rlo_i5
(
emit
->
as
,
rlo_dest
,
rlo_base
,
i5
>>
2
);
}
else
if
(
strcmp
(
op_str
,
"str"
)
==
0
)
{
uint
rlo_src
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
0
,
7
);
uint
rlo_base
=
get_arg_reg
(
emit
,
op_str
,
pn_args
,
1
,
7
);
int
i5
=
get_arg_i
(
emit
,
op_str
,
pn_args
,
2
,
0x7c
);
asm_thumb_str_rlo_rlo_i5
(
emit
->
as
,
rlo_src
,
rlo_base
,
i5
>>
2
);
}
else
{
goto
unknown_op
;
}
...
...
@@ -234,7 +297,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
return
;
unknown_op:
printf
(
"SyntaxError:
unsupported
ARM
Thumb instruction '%s' with %d arguments
\n
"
,
op_str
,
n_args
);
emit_inline_thumb_error
(
emit
,
"
unsupported Thumb instruction '%s' with %d arguments
\n
"
,
op_str
,
n_args
);
}
const
emit_inline_asm_method_table_t
emit_inline_thumb_method_table
=
{
...
...
py/emitnative.c
View file @
a26dc509
...
...
@@ -1058,7 +1058,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
#if N_X64
asm_x64_add_r64_to_r64
(
emit
->
as
,
REG_ARG_3
,
REG_ARG_2
);
#elif N_THUMB
asm_thumb_add_r
eg_reg_reg
(
emit
->
as
,
REG_ARG_2
,
REG_ARG_2
,
REG_ARG_3
);
asm_thumb_add_r
lo_rlo_rlo
(
emit
->
as
,
REG_ARG_2
,
REG_ARG_2
,
REG_ARG_3
);
#endif
emit_post_push_reg
(
emit
,
VTYPE_INT
,
REG_ARG_2
);
}
else
if
(
op
==
MP_BINARY_OP_LESS
)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment