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
47e1b85d
Commit
47e1b85d
authored
Apr 08, 2014
by
Damien George
Browse files
py: Improve inline assembler; add a few more opcodes.
parent
495d781a
Changes
3
Hide whitespace changes
Inline
Side-by-side
py/asmthumb.c
View file @
47e1b85d
...
...
@@ -275,6 +275,12 @@ 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_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
void
asm_thumb_add_reg_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
)
{
asm_thumb_write_op16
(
as
,
OP_ADD_REG_REG_REG
(
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))
void
asm_thumb_subs_rlo_rlo_i3
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src
,
int
i3_src
)
{
...
...
@@ -283,6 +289,12 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int
asm_thumb_write_op16
(
as
,
OP_SUBS_RLO_RLO_I3
(
rlo_dest
,
rlo_src
,
i3_src
));
}
#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a))
void
asm_thumb_cmp_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_a
,
uint
rlo_b
)
{
asm_thumb_write_op16
(
as
,
OP_CMP_REG_REG
(
rlo_a
,
rlo_b
));
}
#define OP_CMP_RLO_I8(rlo, i8) (0x2800 | ((rlo) << 8) | (i8))
void
asm_thumb_cmp_rlo_i8
(
asm_thumb_t
*
as
,
uint
rlo
,
int
i8
)
{
...
...
@@ -290,6 +302,10 @@ 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
));
}
void
asm_thumb_ite_ge
(
asm_thumb_t
*
as
)
{
asm_thumb_write_op16
(
as
,
0xbfac
);
}
#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff))
void
asm_thumb_b_n
(
asm_thumb_t
*
as
,
int
label
)
{
...
...
@@ -360,22 +376,6 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
asm_thumb_write_op16
(
as
,
OP_ADD_REG_SP_OFFSET
(
rlo_dest
,
word_offset
));
}
#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
void
asm_thumb_add_reg_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
)
{
asm_thumb_write_op16
(
as
,
OP_ADD_REG_REG_REG
(
rlo_dest
,
rlo_src_a
,
rlo_src_b
));
}
#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a))
void
asm_thumb_cmp_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_a
,
uint
rlo_b
)
{
asm_thumb_write_op16
(
as
,
OP_CMP_REG_REG
(
rlo_a
,
rlo_b
));
}
void
asm_thumb_ite_ge
(
asm_thumb_t
*
as
)
{
asm_thumb_write_op16
(
as
,
0xbfac
);
}
// this could be wrong, because it should have a range of +/- 16MiB...
#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))
#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff))
...
...
py/asmthumb.h
View file @
47e1b85d
...
...
@@ -62,8 +62,11 @@ 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_reg_reg_reg
(
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_ite_ge
(
asm_thumb_t
*
as
);
void
asm_thumb_b_n
(
asm_thumb_t
*
as
,
int
label
);
void
asm_thumb_bcc_n
(
asm_thumb_t
*
as
,
int
cond
,
int
label
);
...
...
@@ -73,10 +76,6 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src);
void
asm_thumb_mov_reg_local
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
int
local_num
);
// convenience
void
asm_thumb_mov_reg_local_addr
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
int
local_num
);
// convenience
void
asm_thumb_add_reg_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_dest
,
uint
rlo_src_a
,
uint
rlo_src_b
);
// convenience ?
void
asm_thumb_cmp_reg_reg
(
asm_thumb_t
*
as
,
uint
rlo_a
,
uint
rlo_b
);
// convenience ?
void
asm_thumb_ite_ge
(
asm_thumb_t
*
as
);
// convenience ?
void
asm_thumb_b_label
(
asm_thumb_t
*
as
,
int
label
);
// convenience ?
void
asm_thumb_bcc_label
(
asm_thumb_t
*
as
,
int
cc
,
int
label
);
// convenience: picks narrow or wide branch
void
asm_thumb_bl_ind
(
asm_thumb_t
*
as
,
void
*
fun_ptr
,
uint
fun_id
,
uint
reg_temp
);
// convenience ?
...
...
py/emitinlinethumb.c
View file @
47e1b85d
...
...
@@ -81,45 +81,36 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr
asm_thumb_label_assign
(
emit
->
as
,
label_num
);
}
STATIC
bool
check_n_arg
(
qstr
op
,
int
n_args
,
int
wanted_n_args
)
{
if
(
wanted_n_args
==
n_args
)
{
return
true
;
}
else
{
printf
(
"SyntaxError: '%s' expects %d arguments'
\n
"
,
qstr_str
(
op
),
wanted_n_args
);
return
false
;
}
}
STATIC
uint
get_arg_rlo
(
qstr
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_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
"
,
qstr_str
(
op
)
,
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
"
,
qstr_str
(
op
)
,
wanted_arg_num
);
printf
(
"SyntaxError: '%s' expects a register in position %d
\n
"
,
op
,
wanted_arg_num
);
return
0
;
}
return
reg_str
[
1
]
-
'0'
;
}
STATIC
int
get_arg_i
(
qst
r
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
,
int
fit_mask
)
{
STATIC
int
get_arg_i
(
const
cha
r
*
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
"
,
qstr_str
(
op
)
,
wanted_arg_num
);
printf
(
"SyntaxError: '%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
"
,
qstr_str
(
op
)
,
i
,
fit_mask
);
printf
(
"SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x
\n
"
,
op
,
i
,
fit_mask
);
return
0
;
}
return
i
;
}
STATIC
int
get_arg_label
(
emit_inline_asm_t
*
emit
,
qst
r
op
,
mp_parse_node_t
*
pn_args
,
int
wanted_arg_num
)
{
STATIC
int
get_arg_label
(
emit_inline_asm_t
*
emit
,
const
cha
r
*
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
"
,
qstr_str
(
op
)
,
wanted_arg_num
);
printf
(
"SyntaxError: '%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
]);
...
...
@@ -135,6 +126,24 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_a
return
0
;
}
typedef
struct
_cc_name_t
{
byte
cc
;
byte
name
[
2
];
}
cc_name_t
;
STATIC
const
cc_name_t
cc_name_table
[]
=
{
{
THUMB_CC_EQ
,
"eq"
},
{
THUMB_CC_NE
,
"ne"
},
{
THUMB_CC_CS
,
"cs"
},
{
THUMB_CC_CC
,
"cc"
},
{
THUMB_CC_MI
,
"mi"
},
{
THUMB_CC_PL
,
"pl"
},
{
THUMB_CC_VS
,
"vs"
},
{
THUMB_CC_VC
,
"vc"
},
{
THUMB_CC_HI
,
"hi"
},
{
THUMB_CC_LS
,
"ls"
},
{
THUMB_CC_GE
,
"ge"
},
{
THUMB_CC_LT
,
"lt"
},
{
THUMB_CC_GT
,
"gt"
},
{
THUMB_CC_LE
,
"le"
},
};
STATIC
void
emit_inline_thumb_op
(
emit_inline_asm_t
*
emit
,
qstr
op
,
int
n_args
,
mp_parse_node_t
*
pn_args
)
{
// TODO perhaps make two tables:
// one_args =
...
...
@@ -146,60 +155,86 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
// three_args =
// "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3
// 1 arg
if
(
strcmp
(
qstr_str
(
op
),
"b"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
1
))
{
return
;
}
int
label_num
=
get_arg_label
(
emit
,
op
,
pn_args
,
0
);
// TODO check that this succeeded, ie branch was within range
asm_thumb_b_n
(
emit
->
as
,
label_num
);
}
else
if
(
strcmp
(
qstr_str
(
op
),
"bgt"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
1
))
{
return
;
}
int
label_num
=
get_arg_label
(
emit
,
op
,
pn_args
,
0
);
// TODO check that this succeeded, ie branch was within range
asm_thumb_bcc_n
(
emit
->
as
,
THUMB_CC_GT
,
label_num
);
// 2 args
}
else
if
(
strcmp
(
qstr_str
(
op
),
"movs"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
2
))
{
return
;
const
char
*
op_str
=
qstr_str
(
op
);
uint
op_len
=
strlen
(
op_str
);
if
(
n_args
==
0
)
{
if
(
strcmp
(
op_str
,
"ite.ge"
)
==
0
)
{
// TODO correct name for this op?
asm_thumb_ite_ge
(
emit
->
as
);
}
else
{
goto
unknown_op
;
}
uint
rlo_dest
=
get_arg_rlo
(
op
,
pn_args
,
0
);
int
i_src
=
get_arg_i
(
op
,
pn_args
,
1
,
0xff
);
asm_thumb_movs_rlo_i8
(
emit
->
as
,
rlo_dest
,
i_src
);
}
else
if
(
strcmp
(
qstr_str
(
op
),
"movw"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
2
))
{
return
;
}
else
if
(
n_args
==
1
)
{
if
(
strcmp
(
op_str
,
"b"
)
==
0
)
{
int
label_num
=
get_arg_label
(
emit
,
op_str
,
pn_args
,
0
);
// TODO check that this succeeded, ie branch was within range
asm_thumb_b_n
(
emit
->
as
,
label_num
);
}
else
if
(
op_str
[
0
]
==
'b'
&&
op_len
==
3
)
{
uint
cc
=
-
1
;
for
(
uint
i
=
0
;
i
<
(
sizeof
cc_name_table
)
/
(
sizeof
cc_name_table
[
0
]);
i
++
)
{
if
(
op_str
[
1
]
==
cc_name_table
[
i
].
name
[
0
]
&&
op_str
[
2
]
==
cc_name_table
[
i
].
name
[
1
])
{
cc
=
cc_name_table
[
i
].
cc
;
}
}
if
(
cc
==
-
1
)
{
goto
unknown_op
;
}
int
label_num
=
get_arg_label
(
emit
,
op_str
,
pn_args
,
0
);
// TODO check that this succeeded, ie branch was within range
asm_thumb_bcc_n
(
emit
->
as
,
cc
,
label_num
);
}
else
{
goto
unknown_op
;
}
uint
rlo_dest
=
get_arg_rlo
(
op
,
pn_args
,
0
);
// TODO can be reg lo or hi
int
i_src
=
get_arg_i
(
op
,
pn_args
,
1
,
0xffff
);
asm_thumb_movw_reg_i16
(
emit
->
as
,
rlo_dest
,
i_src
);
}
else
if
(
strcmp
(
qstr_str
(
op
),
"cmp"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
2
))
{
return
;
}
else
if
(
n_args
==
2
)
{
if
(
strcmp
(
op_str
,
"mov"
)
==
0
)
{
uint
rlo_dest
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
uint
rlo_src
=
get_arg_rlo
(
op_str
,
pn_args
,
1
);
asm_thumb_mov_reg_reg
(
emit
->
as
,
rlo_dest
,
rlo_src
);
}
else
if
(
strcmp
(
op_str
,
"movs"
)
==
0
)
{
uint
rlo_dest
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
int
i_src
=
get_arg_i
(
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
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_movw_reg_i16
(
emit
->
as
,
rlo_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
);
}
else
if
(
strcmp
(
op_str
,
"cmp"
)
==
0
)
{
uint
rlo
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
int
i8
=
get_arg_i
(
op_str
,
pn_args
,
1
,
0xff
);
asm_thumb_cmp_rlo_i8
(
emit
->
as
,
rlo
,
i8
);
}
else
{
goto
unknown_op
;
}
uint
rlo
=
get_arg_rlo
(
op
,
pn_args
,
0
);
int
i8
=
get_arg_i
(
op
,
pn_args
,
1
,
0xff
);
asm_thumb_cmp_rlo_i8
(
emit
->
as
,
rlo
,
i8
);
// 3 args
}
else
if
(
strcmp
(
qstr_str
(
op
),
"subs"
)
==
0
)
{
if
(
!
check_n_arg
(
op
,
n_args
,
3
))
{
return
;
}
else
if
(
n_args
==
3
)
{
if
(
strcmp
(
op_str
,
"add"
)
==
0
)
{
uint
rlo_dest
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
uint
rlo_src_a
=
get_arg_rlo
(
op_str
,
pn_args
,
1
);
uint
rlo_src_b
=
get_arg_rlo
(
op_str
,
pn_args
,
2
);
asm_thumb_add_reg_reg_reg
(
emit
->
as
,
rlo_dest
,
rlo_src_a
,
rlo_src_b
);
}
else
if
(
strcmp
(
op_str
,
"subs"
)
==
0
)
{
uint
rlo_dest
=
get_arg_rlo
(
op_str
,
pn_args
,
0
);
uint
rlo_src
=
get_arg_rlo
(
op_str
,
pn_args
,
1
);
int
i3_src
=
get_arg_i
(
op_str
,
pn_args
,
2
,
0x7
);
asm_thumb_subs_rlo_rlo_i3
(
emit
->
as
,
rlo_dest
,
rlo_src
,
i3_src
);
}
else
{
goto
unknown_op
;
}
uint
rlo_dest
=
get_arg_rlo
(
op
,
pn_args
,
0
);
uint
rlo_src
=
get_arg_rlo
(
op
,
pn_args
,
1
);
int
i3_src
=
get_arg_i
(
op
,
pn_args
,
2
,
0x7
);
asm_thumb_subs_rlo_rlo_i3
(
emit
->
as
,
rlo_dest
,
rlo_src
,
i3_src
);
// unknown op
}
else
{
printf
(
"SyntaxError: unsupported ARM Thumb instruction '%s'
\n
"
,
qstr_str
(
op
));
return
;
goto
unknown_op
;
}
return
;
unknown_op:
printf
(
"SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments
\n
"
,
op_str
,
n_args
);
}
const
emit_inline_asm_method_table_t
emit_inline_thumb_method_table
=
{
...
...
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