8000 Tease apart decoding of instruction and printing. Add unit tests. · Plaque-fcc/micropython-esp32-ulp@e4b34e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit e4b34e2

Browse files
committed
Tease apart decoding of instruction and printing. Add unit tests.
1 parent 8325c2b commit e4b34e2

File tree

4 files changed

+160
-9
lines changed

4 files changed

+160
-9
lines changed

tests/00_unit_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
set -e
66

7-
for file in opcodes assemble link util preprocess definesdb; do
7+
for file in opcodes assemble link util preprocess definesdb disassemble; do
88
echo testing $file...
99
micropython $file.py
1010
done

tests/disassemble.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from tools.disassemble import decode_instruction
2+
import esp32_ulp.opcodes as opcodes
3+
import ubinascii
4+
5+
tests = []
6+
7+
8+
def test(param):
9+
tests.append(param)
10+
11+
12+
def hex_to_int(sequence):
13+
byte_sequence = ubinascii.unhexlify(sequence)
14+
return int.from_bytes(byte_sequence, 'little')
15+
16+
17+
def assert_decode(sequence, expected_struct, expected_name):
18+
i = hex_to_int(sequence)
19+
20+
ins, name = decode_instruction(i)
21+
22+
assert ins is expected_struct, 'incorrect instruction struct'
23+
assert name == expected_name, '%s != %s' % (name, expected_name)
24+
25+
26+
def assert_decode_exception(sequence, expected_message):
27+
i = hex_to_int(sequence)
28+
29+
try:
30+
decode_instruction(i)
31+
except Exception as e:
32+
assert str(e) == expected_message, str(e)
33+
raised = True
34+
else:
35+
raised = False
36+
37+
assert raised, 'Exception not raised'
38+
39+
40+
@test
41+
def test_unknown_instruction():
42+
assert_decode_exception("10000001", 'Unknown instruction')
43+
44+
45+
# All hex sequences were generated using our assembler.
46+
# Note: disassembled instructions always show field values according
47+
# to what is actually encoded into the binary instruction, not as per
48+
# original assembly code.
49+
# For example in JUMP instructions in the source code one would
50+
# specify jump offsets in bytes (e.g. 4 bytes) but in the actual
51+
# instruction offset encoded in the binary instruction will be in
52+
# words (1 word = 4 bytes).
53+
# The disassembled instructions would therefore show as "JUMP 1"
54+
# for what was originally "JUMP 4" in the source code.@test
55+
@test
56+
def test_all_instructions():
57+
# OPCODE_WR_REG = 1
58+
assert_decode("00000010", opcodes._wr_reg, 'REG_WR 0x0, 0, 0, 0')
59+
60+
# OPCODE_RD_REG = 2
61+
assert_decode("00000020", opcodes._rd_reg, 'REG_RD 0x0, 0, 0')
62+
63+
# OPCODE_I2C = 3
64+
assert_decode("00000030", opcodes._i2c, 'I2C_RD 0, 0, 0, 0')
65+
assert_decode("00000038", opcodes._i2c, 'I2C_WR 0, 0, 0, 0')
66+
67+
# OPCODE_DELAY = 4
68+
assert_decode("00000040", opcodes._delay, 'NOP')
69+
assert_decode("01000040", opcodes._delay, 'WAIT 1')
70+
71+
# OPCODE_ADC = 5
72+
assert_decode("00000050", opcodes._adc, 'ADC r0, 0, 0')
73+
74+
# OPCODE_ST = 6
75+
assert_decode("00000068", opcodes._st, 'ST r0, r0, 0')
76+
77+
# OPCODE_ALU = 7, SUB_OPCODE_ALU_REG
78+
assert_decode("00000070", opcodes._alu_reg, 'ADD r0, r0, r0')
79+
assert_decode("00002070", opcodes._alu_reg, 'SUB r0, r0, r0')
80+
assert_decode("00004070", opcodes._alu_reg, 'AND r0, r0, r0')
81+
assert_decode("00006070", opcodes._alu_reg, 'OR r0, r0, r0')
82+
assert_decode("00008070", opcodes._alu_reg, "MOVE r0, r0")
83+
assert_decode("0000a070", opcodes._alu_reg, 'LSH r0, r0, r0')
84+
assert_decode("0000c070", opcodes._alu_reg, 'RSH r0, r0, r0')
85+
86+
# OPCODE_ALU = 7, SUB_OPCODE_ALU_IMM
87+
assert_decode("00000072", opcodes._alu_imm, 'ADD r0, r0, 0')
88+
assert_decode("00002072", opcodes._alu_imm, 'SUB r0, r0, 0')
89+
assert_decode("00004072", opcodes._alu_imm, 'AND r0, r0, 0')
90+
assert_decode("00006072", opcodes._alu_imm, 'OR r0, r0, 0')
91+
assert_decode("00008072", opcodes._alu_imm, "MOVE r0, 0")
92+
assert_decode("0000a072", opcodes._alu_imm, 'LSH r0, r0, 0')
93+
assert_decode("0000c072", opcodes._alu_imm, 'RSH r0, r0, 0')
94+
95+
# OPCODE_ALU = 7, SUB_OPCODE_ALU_CNT
96+
assert_decode("00004074", opcodes._alu_cnt, 'STAGE_RST')
97+
assert_decode("00000074", opcodes._alu_cnt, 'STAGE_INC 0')
98+
assert_decode("00002074", opcodes._alu_cnt, 'STAGE_DEC 0')
99+
100+
# OPCODE_BRANCH = 8, SUB_OPCODE_BX (IMM)
101+
assert_decode("00000080", opcodes._bx, 'JUMP 0')
102+
assert_decode("00004080", opcodes._bx, 'JUMP 0, EQ')
103+
assert_decode("00008080", opcodes._bx, 'JUMP 0, OV')
104+
105+
# OPCODE_BRANCH = 8, SUB_OPCODE_BX (REG)
106+
assert_decode("00002080", opcodes._bx, 'JUMP r0')
107+
assert_decode("00006080", opcodes._bx, 'JUMP r0, EQ')
108+
assert_decode("0000a080", opcodes._bx, 'JUMP r0, OV')
109+
110+
# OPCODE_BRANCH = 8, SUB_OPCODE_BR
111+
assert_decode("00000082", opcodes._br, 'JUMPR 0, 0, LT')
112+
assert_decode("00000182", opcodes._br, 'JUMPR 0, 0, GE')
113+
114+
# OPCODE_BRANCH = 8, SUB_OPCODE_BX
115+
assert_decode("00000084", opcodes._bs, 'JUMPS 0, 0, LT')
116+
assert_decode("00800084", opcodes._bs, 'JUMPS 0, 0, GE')
117+
assert_decode("00000184", opcodes._bs, 'JUMPS 0, 0, LE')
118+
119+
# OPCODE_END = 9, SUB_OPCODE_END
120+
assert_decode("01000090", opcodes._end, 'WAKE')
121+
122+
# OPCODE_END = 9, SUB_OPCODE_SLEEP
123+
assert_decode("00000092", opcodes._sleep, 'SLEEP 0')
124+
125+
# OPCODE_TSENS = 10
126+
assert_decode("000000a0", opcodes._tsens, 'TSENS r0, 0')
127+
128+
# OPCODE_HALT = 11
129+
assert_decode("000000b0", opcodes._halt, 'HALT')
130+
131+
# OPCODE_LD = 13
132+
assert_decode("000000d0", opcodes._ld, 'LD r0, r0, 0')
133+
134+
135+
if __name__ == '__main__':
136+
# run all methods marked with @test
137+
for t in tests:
138+
t()

tests/tools

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../tools

tools/disassemble.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
opcodes.SUB_OPCODE_ALU_REG: (
2929
'ALU_REG',
3030
opcodes._alu_reg,
31-
lambda op: '%s r%s, r%s, r%s' % (alu_ops[op.sel], op.dreg, op.sreg, op.treg)
31+
lambda op: '%s r%s, r%s' % (alu_ops[op.sel], op.dreg, op.sreg) if op.sel == opcodes.ALU_SEL_MOV
32+
else '%s r%s, r%s, r%s' % (alu_ops[op.sel], op.dreg, op.sreg, op.treg)
3233
),
3334
}),
3435
opcodes.OPCODE_BRANCH: ('BRANCH', opcodes._bx, {
@@ -91,13 +92,10 @@ def decode_instruction(i):
9192
ins = opcodes._end
9293
ins.all = i # abuse a struct to get opcode
9394

94-
print(ubinascii.hexlify(i.to_bytes(4, 'little')))
95-
9695
params = lookup.get(ins.opcode, None)
9796

9897
if not params:
99-
print('Unknown instruction')
100-
return
98+
raise Exception('Unknown instruction')
10199

102100
if len(params) == 3:
103101
name, ins, third = params
@@ -116,6 +114,18 @@ def decode_instruction(i):
116114
name, ins = params
117115
ins.all = i
118116

117+
return ins, name
118+
119+
120+
def decode_instruction_and_print(i):
121+
print(ubinascii.hexlify(i.to_bytes(4, 'little')))
122+
123+
try:
124+
ins, name = decode_instruction(i)
125+
except Exception as e:
126+
print(e)
127+
return
128+
119129
print(name)
120130

121131
possible_fields = (
@@ -132,12 +142,14 @@ def decode_instruction(i):
132142
except KeyError:
133143
continue
134144
extra = ''
135-
if field == 'sel':
145+
if field == 'sel': # ALU
136146
if ins.sub_opcode == opcodes.SUB_OPCODE_ALU_CNT:
137147
extra = ' (%s)' % alu_cnt_ops[val]
138148
else:
139149
extra = ' (%s)' % alu_ops[val]
140-
elif field == 'cmp':
150+
elif field == 'type': # JUMP
151+
extra = ' (%s)' % jump_types[val]
152+
elif field == 'cmp': # JUMPR/JUMPS
141153
extra = ' (%s)' % cmp_ops[val]
142154
print(" {:10} = {:3}{}".format(field, val, extra))
143155

@@ -153,7 +165,7 @@ def disassemble_manually(byte_sequence_string):
153165
for instruction in list:
154166
byte_sequence = ubinascii.unhexlify(instruction.replace(' ',''))
155167
i = int.from_bytes(byte_sequence, 'little')
156-
decode_instruction(i)
168+
decode_instruction_and_print(i)
157169

158170

159171
def print_help():

0 commit comments

Comments
 (0)
0