Skip to content

Commit

Permalink
Correct decoding of esp32s2 negative LD/ST offsets
Browse files Browse the repository at this point in the history
The ESP32-S2/S3 support a negative offset in ST/LD instructions.
Those offsets are two's-complement encoded into a field that is
11-bits wide.

This change corrects the decoding of negative offsets given the
field width of just 11-bits, rather than relying on the 32 or
64 bits of a MicroPython `int`.

Note 1: Negative offsets used in JUMP instructions are encoded
differently (sign bit + positive value), and their decoding is
already done correctly.

Note 2: The LD/ST instructions in of the ESP32 do not support
negative offsets (according to Espressif tests), so their
decoding remains as is.
  • Loading branch information
wnienhaus committed Aug 31, 2023
1 parent 9bc6fc3 commit a157ebe
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 11 deletions.
46 changes: 42 additions & 4 deletions tests/fixtures/all_opcodes-v.esp32s2.lst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
header
ULP magic : b'ulp\x00' (0x00706c75)
.text offset : 12 (0x0c)
.text size : 244 (0xf4)
.data offset : 256 (0x100)
.text size : 260 (0x104)
.data offset : 272 (0x110)
.data size : 8 (0x08)
.bss size : 0 (0x00)
----------------------------------------
Expand Down Expand Up @@ -527,7 +527,45 @@ ULP magic : b'ulp\x00' (0x00706c75)
label = 0
upper = 0
wr_way = 0
00f4 09e01fd0 LD r1, r2, -8
dreg = 1
offset = -8 (0x7f8)
opcode = 13 (0x0d)
sreg = 2
unused1 = 0
unused2 = 0
rd_upper = 0
00f8 09e01fd8 LDH r1, r2, -8
dreg = 1
offset = -8 (0x7f8)
opcode = 13 (0x0d)
sreg = 2
unused1 = 0
unused2 = 0
rd_upper = 1
00fc 89e11f68 ST r1, r2, -8
dreg = 2
offset = -8 (0x7f8)
opcode = 6
sreg = 1
sub_opcode = 4
unused1 = 0
unused2 = 0
label = 0
upper = 0
wr_way = 3
0100 c9e11f68 STH r1, r2, -8
dreg = 2
offset = -8 (0x7f8)
opcode = 6
sreg = 1
sub_opcode = 4
unused1 = 0
unused2 = 0
label = 0
upper = 1
wr_way = 3
----------------------------------------
.data
00f4 00000000 <empty>
00f8 fecadec0 <non-empty>
0104 00000000 <empty>
0108 fecadec0 <non-empty>
6 changes: 6 additions & 0 deletions tests/fixtures/all_opcodes.esp32s2.S
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ STI32 R1, R2, 0
STI32 R1, R2, 1

STO 0x20

LDL R1, R2, -0x20
LDH R1, R2, -0x20

STL R1, R2, -0x20
STH R1, R2, -0x20
8 changes: 6 additions & 2 deletions tests/fixtures/all_opcodes.esp32s2.lst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
00e8 09000062 STI32 r1, r2, 0
00ec 19000062 STI32 r1, r2, 1
00f0 00200064 STO 8
00f4 09e01fd0 LD r1, r2, -8
00f8 09e01fd8 LDH r1, r2, -8
00fc 89e11f68 ST r1, r2, -8
0100 c9e11f68 STH r1, r2, -8
.data
00f4 00000000 <empty>
00f8 fecadec0 <non-empty>
0104 00000000 <empty>
0108 fecadec0 <non-empty>
23 changes: 18 additions & 5 deletions tools/decode_s2.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
opcodes.OPCODE_LD: (
'LD/LDH',
opcodes._ld,
lambda op: '%s r%s, r%s, %s' % ('LDH' if op.rd_upper else 'LD', op.dreg, op.sreg, op.offset)
lambda op: '%s r%s, r%s, %s' % ('LDH' if op.rd_upper else 'LD', op.dreg, op.sreg, twos_comp(op.offset, 11))
),
opcodes.OPCODE_ST: ('ST', opcodes._st, {
opcodes.SUB_OPCODE_ST_AUTO: (
Expand All @@ -79,14 +79,14 @@
opcodes.SUB_OPCODE_ST_OFFSET: (
'STO',
opcodes._st,
lambda op: 'STO %s' % op.offset
lambda op: 'STO %s' % twos_comp(op.offset, 11)
),
opcodes.SUB_OPCODE_ST: (
'ST/STH/ST32',
opcodes._st,
lambda op: '%s r%s, r%s, %s, %s' % ('STH' if op.upper else 'STL', op.sreg, op.dreg, op.offset, op.label) if op.wr_way and op.label
else '%s r%s, r%s, %s' % ('STH' if op.upper else 'ST', op.sreg, op.dreg, op.offset) if op.wr_way
else 'ST32 r%s, r%s, %s, %s' % (op.sreg, op.dreg, op.offset, op.label)
lambda op: '%s r%s, r%s, %s, %s' % ('STH' if op.upper else 'STL', op.sreg, op.dreg, twos_comp(op.offset, 11), op.label) if op.wr_way and op.label
else '%s r%s, r%s, %s' % ('STH' if op.upper else 'ST', op.sreg, op.dreg, twos_comp(op.offset, 11)) if op.wr_way
else 'ST32 r%s, r%s, %s, %s' % (op.sreg, op.dreg, twos_comp(op.offset, 11), op.label)
)
}),
opcodes.OPCODE_RD_REG: (
Expand All @@ -103,6 +103,16 @@
}


def twos_comp(val, bits):
"""
compute the correct value of a 2's complement
based on the number of bits in the source
"""
if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255
val = val - (1 << bits) # compute negative value
return val


def decode_instruction(i):
if i == 0:
raise Exception('<empty>')
Expand Down Expand Up @@ -167,6 +177,9 @@ def get_instruction_fields(ins):
extra = ' (%s)' % bs_cmp_ops[val]
else:
extra = ' (%s)' % cmp_ops[val]
elif field == 'offset':
if ins.opcode in (opcodes.OPCODE_ST, opcodes.OPCODE_LD):
val = twos_comp(val, 11)

field_details.append((field, val, extra))

Expand Down

0 comments on commit a157ebe

Please sign in to comment.