Skip to content

Commit c967c1d

Browse files
committed
fix peripheral register read/write for larger ULP addresses
When register addresses less than or equal to 0x3ff are given to the reg_rd and reg_wr opcodes, these addresses should be used unmodified as the address in the machine instruction. In our implementation we split the 10 bit address field of the machine instruction into two fields, namely "addr" for the lower 8 bits and "periph_sel" for the upper 2 bits. We already had a mechanism for determining the periph_sel part for "full" addresses (e.g. 0x3ff48000), but for direct (ULP) addresses, we always set periph_sel to 0 instead of using the upper 2 bits from the given address. This commit fixes that. Note 1: In binutils-esp32ulp, they don't split the address into these 2 fields but simply put the direct ULP address into a single combined field of 10 bits, which has the same effect. See: https://github.com/espressif/binutils-esp32ulp/blob/249ec34/gas/config/tc-esp32ulp_esp32.c#L145 Note 2: In the "macro approach" in esp-idf for creating ULP code, they also use the split field approach (I assume our implementation is modelled after that) and they also don't handle direct (ULP) addresses correctly (or seemingly at all). See: https://github.com/espressif/esp-idf/blob/9d34a1c/components/ulp/include/esp32/ulp.h#L349 This commit contributes to being able to eventually assemble the esp32ulp_ranges.s test from binutils-esp32ulp. It addresses this line: https://github.com/espressif/binutils-esp32ulp/blob/249ec34/gas/testsuite/gas/esp32ulp/esp32/esp32ulp_ranges.s#L136
1 parent 479f809 commit c967c1d

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

esp32_ulp/opcodes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,10 @@ def i_reg_wr(reg, high_bit, low_bit, val):
379379
reg = get_imm(reg)
380380
if reg <= DR_REG_MAX_DIRECT: # see https://github.com/espressif/binutils-esp32ulp/blob/master/gas/config/tc-esp32ulp_esp32.c
381381
_wr_reg.addr = reg
382+
_wr_reg.periph_sel = reg >> 8
382383
else:
383384
_wr_reg.addr = (reg & 0xff) >> 2
384-
_wr_reg.periph_sel = _soc_reg_to_ulp_periph_sel(reg)
385+
_wr_reg.periph_sel = _soc_reg_to_ulp_periph_sel(reg)
385386
_wr_reg.data = get_imm(val)
386387
_wr_reg.low = get_imm(low_bit)
387388
_wr_reg.high = get_imm(high_bit)
@@ -393,9 +394,10 @@ def i_reg_rd(reg, high_bit, low_bit):
393394
reg = get_imm(reg)
394395
if reg <= DR_REG_MAX_DIRECT: # see https://github.com/espressif/binutils-esp32ulp/blob/master/gas/config/tc-esp32ulp_esp32.c
395396
_rd_reg.addr = reg
397+
_rd_reg.periph_sel = reg >> 8
396398
else:
397399
_rd_reg.addr = (reg & 0xff) >> 2
398-
_rd_reg.periph_sel = _soc_reg_to_ulp_periph_sel(reg)
400+
_rd_reg.periph_sel = _soc_reg_to_ulp_periph_sel(reg)
399401
_rd_reg.unused = 0
400402
_rd_reg.low = get_imm(low_bit)
401403
_rd_reg.high = get_imm(high_bit)

tests/opcodes.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,78 @@ def assert_raises(exception, func, *args):
108108
assert raised
109109

110110

111+
def test_reg_direct_ulp_addressing():
112+
"""
113+
Test direct ULP addressing of peripheral registers
114+
input must be <= 0x3ff (10 bits)
115+
periph_sel == high 2 bits from input
116+
addr == low 8 bits from input
117+
"""
118+
119+
ins = make_ins("""
120+
addr : 8 # Address within either RTC_CNTL, RTC_IO, or SARADC
121+
periph_sel : 2 # Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2)
122+
unused : 8 # Unused
123+
low : 5 # Low bit
124+
high : 5 # High bit
125+
opcode : 4 # Opcode (OPCODE_RD_REG)
126+
""")
127+
128+
ins.all = opcodes.i_reg_rd("0x0", "0", "0")
129+
assert ins.periph_sel == 0
130+
assert ins.addr == 0x0
131+
132+
ins.all = opcodes.i_reg_rd("0x012", "0", "0")
133+
assert ins.periph_sel == 0
134+
assert ins.addr == 0x12
135+
136+
ins.all = opcodes.i_reg_rd("0x123", "0", "0")
137+
assert ins.periph_sel == 1
138+
assert ins.addr == 0x23
139+
140+
ins.all = opcodes.i_reg_rd("0x2ee", "0", "0")
141+
assert ins.periph_sel == 2
142+
assert ins.addr == 0xee
143+
144+
ins.all = opcodes.i_reg_rd("0x3ff", "0", "0")
145+
assert ins.periph_sel == 3
146+
assert ins.addr == 0xff
147+
148+
# anything bigger than 0x3ff must be a valid full address
149+
assert_raises(ValueError, opcodes.i_reg_rd, "0x400", "0", "0")
150+
151+
152+
def test_reg_address_translations():
153+
"""
154+
Test addressing of peripheral registers using full DPORT bus addresses
155+
"""
156+
157+
ins = make_ins("""
158+
addr : 8 # Address within either RTC_CNTL, RTC_IO, or SARADC
159+
periph_sel : 2 # Select peripheral: RTC_CNTL (0), RTC_IO(1), SARADC(2)
160+
unused : 8 # Unused
161+
low : 5 # Low bit
162+
high : 5 # High bit
163+
opcode : 4 # Opcode (OPCODE_RD_REG)
164+
""")
165+
166+
# direct ULP address is derived from full address as follows:
167+
# full:0x3ff484a8 == ulp:(0x3ff484a8-DR_REG_RTCCNTL_BASE) / 4
168+
# full:0x3ff484a8 == ulp:(0x3ff484a8-0x3ff48000) / 4
169+
# full:0x3ff484a8 == ulp:0x4a8 / 4
170+
# full:0x3ff484a8 == ulp:0x12a
171+
# see: https://github.com/espressif/binutils-esp32ulp/blob/249ec34/gas/config/tc-esp32ulp_esp32.c#L149
172+
ins.all = opcodes.i_reg_rd("0x3ff484a8", "0", "0")
173+
assert ins.periph_sel == 1 # high 2 bits of 0x12a
174+
assert ins.addr == 0x2a # low 8 bits of 0x12a
175+
176+
111177
test_make_ins_struct_def()
112178
test_make_ins()
113179
test_arg_qualify()
114180
test_get_reg()
115181
test_get_imm()
116182
test_get_cond()
117-
test_eval_arg()
183+
test_eval_arg()
184+
test_reg_direct_ulp_addressing()
185+
test_reg_address_translations()

0 commit comments

Comments
 (0)