From a157ebebb30118995bada5d4f9cfb3368a66c0bf Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sat, 22 Jul 2023 19:04:43 +0300 Subject: [PATCH] Correct decoding of esp32s2 negative LD/ST offsets 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. --- tests/fixtures/all_opcodes-v.esp32s2.lst | 46 +++++++++++++++++++++--- tests/fixtures/all_opcodes.esp32s2.S | 6 ++++ tests/fixtures/all_opcodes.esp32s2.lst | 8 +++-- tools/decode_s2.py | 23 +++++++++--- 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/tests/fixtures/all_opcodes-v.esp32s2.lst b/tests/fixtures/all_opcodes-v.esp32s2.lst index 43126de..a2ebb15 100644 --- a/tests/fixtures/all_opcodes-v.esp32s2.lst +++ b/tests/fixtures/all_opcodes-v.esp32s2.lst @@ -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) ---------------------------------------- @@ -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 -00f8 fecadec0 +0104 00000000 +0108 fecadec0 diff --git a/tests/fixtures/all_opcodes.esp32s2.S b/tests/fixtures/all_opcodes.esp32s2.S index 5e5dea0..7483840 100644 --- a/tests/fixtures/all_opcodes.esp32s2.S +++ b/tests/fixtures/all_opcodes.esp32s2.S @@ -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 diff --git a/tests/fixtures/all_opcodes.esp32s2.lst b/tests/fixtures/all_opcodes.esp32s2.lst index d3d6d10..5de1704 100644 --- a/tests/fixtures/all_opcodes.esp32s2.lst +++ b/tests/fixtures/all_opcodes.esp32s2.lst @@ -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 -00f8 fecadec0 +0104 00000000 +0108 fecadec0 diff --git a/tools/decode_s2.py b/tools/decode_s2.py index 2b6d440..de3b3c7 100644 --- a/tools/decode_s2.py +++ b/tools/decode_s2.py @@ -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: ( @@ -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: ( @@ -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('') @@ -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))