git.s-ol.nu subv / 9de28da
use new bits in format.py s-ol 28 days ago
2 changed file(s) with 125 addition(s) and 124 deletion(s). Raw diff Collapse all Expand all
3434 ... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12
3535 ... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
3636 ... # jump back up to the top
37 ... 6f/jal 0/rd/x0 main/off20
37 ... 6f/jal 0/rd/x0 main/off21
3838 ... '''[1:-1]))))
3939 == code 0x80000000
4040 main:
4141 # load 0x10010000 (UART0) into t0
4242 37/7 05/5 10010/20
4343 # store 0x48 (H) in UART0+0
44 13/7 06/5 00/3 00/5 48/12
45 23/7 00/5 02/3 05/5 06/5 00/7
44 13/7 06/5 0/3 00/5 048/12
45 23/7 00/5 2/3 05/5 06/5 00/7
4646 # store 0x65 (e) in UART0+0
47 13/7 06/5 00/3 00/5 65/12
48 23/7 00/5 02/3 05/5 06/5 00/7
47 13/7 06/5 0/3 00/5 065/12
48 23/7 00/5 2/3 05/5 06/5 00/7
4949 # store 0x6c (l) in UART0+0
50 13/7 06/5 00/3 00/5 6c/12
51 23/7 00/5 02/3 05/5 06/5 00/7
50 13/7 06/5 0/3 00/5 06c/12
51 23/7 00/5 2/3 05/5 06/5 00/7
5252 # store 0x6c (l) in UART0+0
53 13/7 06/5 00/3 00/5 6c/12
54 23/7 00/5 02/3 05/5 06/5 00/7
53 13/7 06/5 0/3 00/5 06c/12
54 23/7 00/5 2/3 05/5 06/5 00/7
5555 # store 0x6f (o) in UART0+0
56 13/7 06/5 00/3 00/5 6f/12
57 23/7 00/5 02/3 05/5 06/5 00/7
56 13/7 06/5 0/3 00/5 06f/12
57 23/7 00/5 2/3 05/5 06/5 00/7
5858 # store 0x0a (\\n) in UART0+0
59 13/7 06/5 00/3 00/5 0a/12
60 23/7 00/5 02/3 05/5 06/5 00/7
59 13/7 06/5 0/3 00/5 00a/12
60 23/7 00/5 2/3 05/5 06/5 00/7
6161 # jump back up to the top
62 6f/7 00/5 main[19:12]/off8 main[11:11]/off1 main[10:1]/off10 main[20:20]/off1
62 6f/7 00/5 main/off21/[19:12] main/off21/[11:11] main/off21/[10:1] main/off21/[20:20]
6363 """
6464
65 from operator import __and__
66 from functools import reduce
6765 import subv
6866 import bits
67
68 def _test_format(words):
69 return ' '.join(map(str, words))
6970
7071 def ref_slice(ref, hi, lo):
7172 if hi < lo:
8081 'size': hi - lo + 1,
8182 }
8283
84 def sign_trunc(val, size):
85 """ truncate and sign-shrink a number literal.
86
87 >>> sign_trunc(bits.i(4, 32), 8)
88 Bitfield(0x4, 8)
89 >>> sign_trunc(bits.i(-4, 32), 8)
90 Bitfield(0xfc, 8)
91 >>> sign_trunc(bits.i(0x11ff, 32), 8)
92 Bitfield(0x7f, 8)
93 >>> sign_trunc(bits.i(-0x11ff, 32), 8)
94 Bitfield(0x81, 8)
95 """
96 sign = val[val.size-1]
97 rest = val[size-2:0]
98 return sign & rest
99
100 global_slice = slice
83101 def default_slice(val, hi, lo):
84102 """ add a default slice spec to labels if missing.
85103
86104 >>> default_slice(('label', 'imm12'), 12, 1)
87 ('label[12:1]', 'imm12')
105 LabelRef('label', 0, ('imm', 12), 12:1)
88106 >>> default_slice(('label-4', 'imm12'), 12, 1)
89 ('label-4[12:1]', 'imm12')
90 >>> default_slice(('label[14:3]', 'imm12'), 12, 1)
91 ('label[14:3]', 'imm12')
92 >>> default_slice(('label+4[14:3]', 'imm12'), 12, 1)
93 ('label+4[14:3]', 'imm12')
94 >>> default_slice(('label[14:3]', 'imm12', 'extra'), 12, 1)
95 ('label[14:3]', 'imm12', 'extra')
96 >>> default_slice(('label[31:0]', 'imm12'), 11, 0)
107 LabelRef('label', -4, ('imm', 12), 12:1)
108 >>> default_slice(('label', 'imm12', '[14:3]'), 12, 1)
109 LabelRef('label', 0, ('imm', 12), 14:3)
110 >>> default_slice(('label+4', 'imm12', '[14:3]'), 12, 1)
111 LabelRef('label', 4, ('imm', 12), 14:3)
112 >>> default_slice(('label', 'imm12', '[14:3]'), 12, 1)
113 LabelRef('label', 0, ('imm', 12), 14:3)
114 >>> default_slice(('label', 'imm12', '[31:0]'), 11, 0)
97115 Traceback (most recent call last):
98116 ...
99 AssertionError: expected 12 bit slice, got label[31:0] (32 bit)
100 """
101 parsed = subv.parse_reference(val)
102 if 'hi' not in parsed:
103 parsed['hi'] = hi
104 parsed['lo'] = lo
105 ref = subv.format_reference(parsed)
106
107 p_size = parsed['hi'] - parsed['lo'] + 1
108 assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref[0], p_size)
109
117 AssertionError: expected 12 bit slice, got label/imm12/[31:0]
118 """
119 if len(val) == 3:
120 label_offset, mode, slice = val
121 elif len(val) == 2:
122 label_offset, mode = val
123 slice = global_slice(hi, lo)
124 else:
125 raise ValueError("expected label reference")
126
127 import re
128
129 ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?$')
130 slice_re = re.compile(r'^\[(\d+):(\d+)]$')
131
132 match = ref_re.match(label_offset)
133 assert match, ValueError("invalid label reference")
134 label, offset = match.group(1), int(match.group(2) or 0)
135
136 if isinstance(slice, str):
137 match = slice_re.match(slice)
138 assert match, ValueError("invalid slice syntax")
139 a, b = match.groups()
140 slice = global_slice(int(a), int(b))
141
142 ref = bits.LabelRef(label, offset, mode, slice)
143
144 expected = hi - lo + 1
145 assert expected == ref.size, ValueError("expected {} bit slice, got {}".format(expected, ref))
110146 return ref
111147
112 def slice_bit_or_ref(val, hi, lo):
113 """ bit.slice but for bitfields and label references.
114
115 >>> slice_bit_or_ref(('label[31:0]', 'imm32'), 12, 1)
116 ('label[12:1]', 'imm12')
117 >>> slice_bit_or_ref(('label[31:0]', 'off32'), 11, 0)
118 ('label[11:0]', 'off12')
119 >>> slice_bit_or_ref(('label[31:0]', 'off32'), 31, 12)
120 ('label[31:12]', 'off20')
121 >>> slice_bit_or_ref(('label[11:0]', 'imm12', 'extra'), 15, 4)
148 def pack_u(instr):
149 """ verify & pack U-type instructions.
150
151 >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')]))
152 '37/7 05/5 10010/20'
153
154 >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')]))
155 '37/7 05/5 pos/imm20/[31:12]'
156
157 >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20', '[19:0]')]))
158 '37/7 05/5 pos/imm20/[19:0]'
159
160 >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20', '[31:0]')]))
122161 Traceback (most recent call last):
123162 ...
124 AssertionError: cant slice outside of bounds
125 >>> slice_bit_or_ref(('label', 'imm12'), 12, 1)
126 Traceback (most recent call last):
127 ...
128 AssertionError: cant slice label w/o bounds
129 """
130 if isinstance(val, bits.Bitfield):
131 return val[hi:lo]
132
133 ref = subv.parse_reference(val)
134 assert 'hi' in ref, "cant slice label w/o bounds"
135
136 sz = hi - lo
137 lo = ref['lo'] + lo
138 hi = lo + sz
139 assert hi <= ref['hi'], "cant slice outside of bounds"
140
141 ref['hi'] = hi
142 ref['lo'] = lo
143 ref['size'] = sz + 1
144 main = '{label}[{hi}:{lo}]'.format(**ref)
145 field = '{mode}{size}'.format(**ref)
146 return (main, field, *val[2:])
147
148 def pack_u(instr):
149 """ verify & pack U-type instructions.
150
151 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])
152 [Bitfield(0x37, 7), Bitfield(0x5, 5), Bitfield(0x10010, 20)]
153
154 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])
155 [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[31:12]', 'imm20')]
156
157 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[19:0]', 'imm20')])
158 [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[19:0]', 'imm20')]
159
160 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')])
161 Traceback (most recent call last):
162 ...
163 AssertionError: expected 20 bit slice, got pos[31:0] (32 bit)
163 AssertionError: expected 20 bit slice, got pos/imm20/[31:0]
164164 """
165165 (op, rd, imm) = instr
166166 op = bits.u(subv.untag(op), 7)
175175 def pack_i(instr):
176176 """ verify & pack I-type instructions.
177177
178 >>> reduce(__and__, pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')]))
179 Bitfield(0x26600065, 32)
180
181 >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')])
182 [Bitfield(0x13, 7), Bitfield(0x6, 5), Bitfield(0x0, 3), Bitfield(0x0, 5), ('label[11:0]', 'imm12')]
178 >>> _test_format(pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (0x65, 'imm12')]))
179 '13/7 06/5 0/3 00/5 065/12'
180
181 >>> _test_format(pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')]))
182 '13/7 06/5 0/3 00/5 label/imm12/[11:0]'
183183 """
184184 (op, sub, rd, rs, imm) = instr
185185 op = bits.u(subv.untag(op), 7)
196196 def pack_s(instr):
197197 """ verify & pack S-type instructions.
198198
199 >>> reduce(__and__, pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')]))
200 Bitfield(0x46045300, 32)
201
202 >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')])
203 [Bitfield(0x23, 7), ('home[4:0]', 'off5'), Bitfield(0x2, 3), Bitfield(0x5, 5), Bitfield(0x6, 5), ('home[11:5]', 'off7')]
199 >>> _test_format(pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')]))
200 '23/7 00/5 2/3 05/5 06/5 00/7'
201
202 >>> _test_format(pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')]))
203 '23/7 home/off12/[4:0] 2/3 05/5 06/5 home/off12/[11:5]'
204204 """
205205 (op, sub, rs1, rs2, imm) = instr
206206 op = bits.u(subv.untag(op), 7)
213213 else:
214214 imm = bits.i(subv.untag(imm, 'off12'), 12)
215215
216 imm_lo = slice_bit_or_ref(imm, 4, 0) # + ('off[4:0]',)
217 imm_hi = slice_bit_or_ref(imm, 11, 5) # + ('off[11:5]',)
216 imm_lo = imm[4:0]
217 imm_hi = imm[11:5]
218218 return [op, imm_lo, sub, rs1, rs2, imm_hi]
219219
220220 def pack_j(instr):
221221 """ verify & pack J-type instructions.
222222
223 >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')]))
224 Bitfield(0xde000000, 32)
225
226 >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')]))
227 Bitfield(0xde0ffffd, 32)
228
229 >>> pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')])
230 [Bitfield(0x6f, 7), Bitfield(0x2, 5), ('home[19:12]', 'off8'), ('home[11:11]', 'off1'), ('home[10:1]', 'off10'), ('home[20:20]', 'off1')]
223 >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')]))
224 '6f/7 00/5 00/8 0/1 000/10 0/1'
225
226 >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')]))
227 '6f/7 00/5 ff/8 1/1 3fe/10 1/1'
228
229 >>> _test_format(pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')]))
230 '6f/7 02/5 home/off20/[19:12] home/off20/[11:11] home/off20/[10:1] home/off20/[20:20]'
231231 """
232232 (op, rd, imm) = instr
233233 op = bits.u(subv.untag(op), 7)
238238 else:
239239 imm = bits.i(subv.untag(imm, 'off20'), 20)
240240
241 imm_lo = slice_bit_or_ref(imm, 9, 0) # + ('off[10:1]',)
242 imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',)
243 imm_hi = slice_bit_or_ref(imm, 18, 11) # + ('off[19:12]',)
244 imm_20 = slice_bit_or_ref(imm, 19, 19) # + ('off[20]',)
241 imm_lo = imm[9:0]
242 imm_11 = imm[10]
243 imm_hi = imm[18:11]
244 imm_20 = imm[19]
245245
246246 return [op, rd, imm_hi, imm_11, imm_lo, imm_20]
247247
248248 def pack_b(instr):
249249 """ verify & pack B-type instructions.
250250
251 >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')]))
252 Bitfield(0xc6006000, 32)
253
254 >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')]))
255 Bitfield(0xc7e0607f, 32)
256
257 >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')])
258 [Bitfield(0x63, 7), ('home[11:11]', 'off1'), ('home[4:1]', 'off4'), Bitfield(0x0, 3), Bitfield(0x6, 5), Bitfield(0x0, 5), ('home[10:5]', 'off6'), ('home[12:12]', 'off1')]
251 >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')]))
252 '63/7 0/1 0/4 0/3 06/5 00/5 00/6 0/1'
253
254 >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')]))
255 '63/7 1/1 e/4 0/3 06/5 00/5 3f/6 1/1'
256
257 >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')]))
258 '63/7 home/off12/[11:11] home/off12/[4:1] 0/3 06/5 00/5 home/off12/[10:5] home/off12/[12:12]'
259259 """
260260 (op, sub, rs1, rs2, imm) = instr
261261 op = bits.u(subv.untag(op), 7)
268268 else:
269269 imm = bits.i(subv.untag(imm, 'off12'), 12)
270270
271 imm_lo = slice_bit_or_ref(imm, 3, 0) # + ('off[4:1]',)
272 imm_md = slice_bit_or_ref(imm, 9, 4) # + ('off[10:5]',)
273 imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',)
274 imm_12 = slice_bit_or_ref(imm, 11, 11) # + ('off[12]',)
271 imm_lo = imm[3:0]
272 imm_md = imm[9:4]
273 imm_11 = imm[10]
274 imm_12 = imm[11]
275
275276 return [op, imm_11, imm_lo, sub, rs1, rs2, imm_md, imm_12]
276277
277278 instr_map = {
298298 >>> format_part(('$label:suff', 'tag'))
299299 '$label:suff/tag'
300300 """
301 if isinstance(part, bits.Bitfield):
302 part = ('{:02x}'.format(part.val), part.size)
301 if isinstance(part, bits.WordBase):
302 return str(part)
303303 elif not is_reference(part):
304304 first = '{:02x}'.format(part[0])
305305 part = (first, *part[1:])