8000 Add support for assembling new ST and LD instructions of the ESP32-S2/S3 · pidou46/micropython-esp32-ulp@93b18e4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 93b18e4

Browse files
committed
Add support for assembling new ST and LD instructions of the ESP32-S2/S3
For example STL and STH can be used to store to the lower or upper 16-bits of a memory address respectively. (The original ST instruction could only store to the lower 16-bits of a memory address) The following new instructions are now supported: * LDL, LDH * STL, STH, ST32, STI32, STI, STO
1 parent 0db6f60 commit 93b18e4

File tree

3 files changed

+115
-6
lines changed

3 files changed

+115
-6
lines changed

esp32_ulp/opcodes_s2.py

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@
3232

3333
OPCODE_ST = 6
3434
SUB_OPCODE_ST_AUTO = 1
35-
SUB_OPCODE_ST_OFFSET = 3
35+
# Note: SUB_OPCODE_ST_OFFSET should be 3
36+
# But in binutils-gdb they hardcoded the value to 2
37+
# This appears to be a bug, if one looks at the Technical
38+
# Reference Manual of the ESP32-S2.
39+
#
40+
# This issue is reported as a pull-request with fix:
41+
# https://github.com/espressif/binutils-gdb/pull/2
42+
#
43+
# We'll hard code this to 2 for now, until this is resolved in
44+
# binutils-gdb or the Technical Reference Manual is updated.
45+
SUB_OPCODE_ST_OFFSET = 2 # should be 3
3646
SUB_OPCODE_ST = 4
3747

3848
OPCODE_ALU = 7
@@ -467,37 +477,101 @@ def i_adc(reg_dest, adc_idx, mux, _not_used=None):
467477
return _adc.all
468478

469479

470-
def i_st(reg_val, reg_addr, offset): ## FIXME do via i_st_manual
480+
def i_st_manual(reg_val, reg_addr, offset, label, upper, wr_way):
471481
_st.dreg = get_reg(reg_addr)
472482
_st.sreg = get_reg(reg_val)
483+
_st.label = get_imm(label)
484+
_st.upper = upper
485+
_st.wr_way = wr_way
486+
_st.unused1 = 0
487+
_st.offset = get_imm(offset) // 4
488+
_st.unused2 = 0
489+
_st.sub_opcode = SUB_OPCODE_ST
490+
_st.opcode = OPCODE_ST
491+
return _st.all
492+
493+
494+
def i_stl(reg_val, reg_addr, offset, label="0"):
495+
return i_st_manual(reg_val, reg_addr, offset, label, 0, 3 if label=="0" else 1)
496+
497+
498+
def i_sth(reg_val, reg_addr, offset, label="0"):
499+
return i_st_manual(reg_val, reg_addr, offset, label, 1, 3 if label=="0" else 1)
500+
501+
502+
def i_st(reg_val, reg_addr, offset):
503+
return i_stl(reg_val, reg_addr, offset)
504+
505+
506+
def i_st32(reg_val, reg_addr, offset, label):
507+
return i_st_manual(reg_val, reg_addr, offset, label, 0, 0)
508+
509+
510+
def i_st_auto(reg_val, reg_addr, label, wr_way):
511+
_st.dreg = get_reg(reg_addr)
512+
_st.sreg = get_reg(reg_val)
513+
_st.label = get_imm(label)
514+
_st.upper = 0
515+
_st.wr_way = wr_way
516+
_st.unused1 = 0
517+
_st.offset = 0
518+
_st.unused2 = 0
519+
_st.sub_opcode = SUB_OPCODE_ST_AUTO
520+
_st.opcode = OPCODE_ST
521+
return _st.all
522+
523+
524+
def i_sto(offset):
525+
_st.dreg = 0
526+
_st.sreg = 0
473527
_st.label = 0
474528
_st.upper = 0
475-
_st.wr_way = 3
529+
_st.wr_way = 0
476530
_st.unused1 = 0
477531
_st.offset = get_imm(offset) // 4
478532
_st.unused2 = 0
479-
_st.sub_opcode = SUB_OPCODE_ST
533+
_st.sub_opcode = SUB_OPCODE_ST_OFFSET
480534
_st.opcode = OPCODE_ST
481535
return _st.all
482536

483537

538+
def i_sti(reg_val, reg_addr, label="0"):
539+
return i_st_auto(reg_val, reg_addr, label, 3 if label=="0" else 1)
540+
541+
542+
def i_sti32(reg_val, reg_addr, label):
543+
return i_st_auto(reg_val, reg_addr, label, 0)
544+
545+
484546
def i_halt():
485547
_halt.unused = 0
486548
_halt.opcode = OPCODE_HALT
487549
return _halt.all
488550

489551

490-
def i_ld(reg_dest, reg_addr, offset): ## FIXME do via i_ld_manual
552+
def i_ld_manual(reg_dest, reg_addr, offset, rd_upper):
491553
_ld.dreg = get_reg(reg_dest)
492554
_ld.sreg = get_reg(reg_addr)
493555
_ld.unused1 = 0
494556
_ld.offset = get_imm(offset) // 4
495557
_ld.unused2 = 0
496-
_ld.rd_upper = 0
558+
_ld.rd_upper = rd_upper
497559
_ld.opcode = OPCODE_LD
498560
return _ld.all
499561

500562

563+
def i_ldl(reg_dest, reg_addr, offset):
564+
return i_ld_manual(reg_dest, reg_addr, offset, 0)
565+
566+
567+
def i_ldh(reg_dest, reg_addr, offset):
568+
return i_ld_manual(reg_dest, reg_addr, offset, 1)
569+
570+
571+
def i_ld(reg_dest, reg_add F438 r, offset):
572+
return i_ldl(reg_dest, reg_addr, offset)
573+
574+
501575
def i_move(reg_dest, reg_imm_src):
502576
# this is the only ALU instruction with 2 args: move r0, r1
503577
dest = get_reg(reg_dest)

tests/01_compat_tests.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ run_tests_for_cpu() {
1717
for src_file in $(ls -1 compat/*.S); do
1818
src_name="${src_file%.S}"
1919

20+
# files with a cpu encoded into their name are only run for that cpu
21+
if [[ $src_file =~ \.esp32\. && $cpu != esp32 ]] || [[ $src_file =~ \.esp32s2?\. && $cpu != esp32s2 ]]; then
22+
continue
23+
fi
2024
echo "Testing $src_file"
2125
echo -e "\tBuilding using micropython-esp32-ulp ($cpu)"
2226
ulp_file="${src_name}.ulp"

tests/compat/loadstore.esp32s2.S

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.set offs, 0x20
2+
.set lab1, 0x01
3+
4+
.text
5+
LDL R1, R2, 0x20
6+
LDL R1, R2, offs
7+
LDH R1, R2, 0x20
8+
LDH R1, R2, offs
9+
10+
STL R1, R2, 0x20
11+
STL R1, R2, offs
12+
STL R1, R2, offs, 1
13+
STL R1, R2, offs, lab1
14+
15+
STH R1, R2, 0x20
16+
STH R1, R2, offs
17+
STH R1, R2, offs, 1
18+
STH R1, R2, offs, lab1
19+
20+
ST32 R1, R2, 0x10, 1
21+
ST32 R1, R2, offs, lab1
22+
23+
STI32 R1, R2, 1
24+
STI32 R1, R2, lab1
25+
26+
STI R1, R2
27+
STI R1, R2, 1
28+
STI R1, R2, lab1
29+
30+
STO 0x20
31+
STO offs

0 commit comments

Comments
 (0)
0