git.s-ol.nu subv / 12ca589
update all stages to work s-ol 28 days ago
6 changed file(s) with 130 addition(s) and 134 deletion(s). Raw diff Collapse all Expand all
282282 Bitfield(0xa, 8)
283283 """
284284 if self.label not in labels:
285 raise ValueError("label '{}' unresolved".format(self.label))
285 raise ValueError("undefined label '{}'".format(self.label))
286286
287287 value = labels[self.label] + self.offset
288288
403403 val = int(part[0])
404404 size = part[1]
405405 return Bitfield(val, int(size))
406
407 global_slice = slice
408 ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?$')
409 slice_re = re.compile(r'^\[(\d+):(\d+)]$')
410
411 def ref(val, default_slice=None):
412 """ add a default slice spec to labels if missing.
413
414 >>> ref(('label', 'imm12'))
415 LabelRef('label', 0, ('imm', 12), 11:0)
416 >>> ref(('label', 'imm12'), slice(12, 1))
417 LabelRef('label', 0, ('imm', 12), 12:1)
418 >>> ref(('label-4', 'imm12'), slice(12, 1))
419 LabelRef('label', -4, ('imm', 12), 12:1)
420 >>> ref(('label', 'imm12', '[14:3]'), slice(12, 1))
421 LabelRef('label', 0, ('imm', 12), 14:3)
422 >>> ref(('label+4', 'imm12', '[14:3]'), slice(12, 1))
423 LabelRef('label', 4, ('imm', 12), 14:3)
424 >>> ref(('label', 'imm12', '[14:3]'), slice(12, 1))
425 LabelRef('label', 0, ('imm', 12), 14:3)
426 >>> ref(('label', 'imm12', '[31:0]'), slice(11, 0))
427 Traceback (most recent call last):
428 ...
429 AssertionError: expected 12 bit slice, got label/imm12/[31:0]
430 """
431 slice = None
432 if len(val) == 3:
433 label_offset, mode, slice = val
434 elif len(val) == 2:
435 label_offset, mode = val
436 else:
437 raise ValueError("expected label reference, got {}".format(val))
438
439 match = ref_re.match(label_offset)
440 assert match, ValueError("invalid label reference")
441 label, offset = match.group(1), int(match.group(2) or 0)
442
443 if isinstance(slice, str):
444 match = slice_re.match(slice)
445 assert match, ValueError("invalid slice syntax")
446 a, b = match.groups()
447 slice = global_slice(int(a), int(b))
448
449 ref = LabelRef(label, offset, mode, slice or default_slice)
450
451 if default_slice:
452 expected = default_slice.start - default_slice.stop + 1
453 assert expected == ref.size, ValueError("expected {} bit slice, got {}".format(expected, ref))
454
455 return ref
9797 rest = val[size-2:0]
9898 return sign & rest
9999
100 global_slice = slice
101 def default_slice(val, hi, lo):
102 """ add a default slice spec to labels if missing.
103
104 >>> default_slice(('label', 'imm12'), 12, 1)
105 LabelRef('label', 0, ('imm', 12), 12:1)
106 >>> default_slice(('label-4', 'imm12'), 12, 1)
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)
115 Traceback (most recent call last):
116 ...
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))
146 return ref
147
148100 def pack_u(instr):
149101 """ verify & pack U-type instructions.
150102
166118 op = bits.u(subv.untag(op), 7)
167119 rd = bits.u(subv.untag(rd, 'rd'), 5)
168120 if subv.is_reference(imm):
169 imm = default_slice(imm, 31, 12)
121 imm = bits.ref(imm, slice(31, 12))
170122 else:
171123 imm = bits.i(subv.untag(imm, 'imm20'), 20)
172124
187139 rd = bits.u(subv.untag(rd, 'rd'), 5)
188140 rs = bits.u(subv.untag(rs, 'rs'), 5)
189141 if subv.is_reference(imm):
190 imm = default_slice(imm, 11, 0)
142 imm = bits.ref(imm, slice(11, 0))
191143 else:
192144 imm = bits.i(subv.untag(imm, 'imm12'), 12)
193145
209161 rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
210162
211163 if subv.is_reference(imm):
212 imm = default_slice(imm, 11, 0)
164 imm = bits.ref(imm, slice(11, 0))
213165 else:
214166 imm = bits.i(subv.untag(imm, 'off12'), 12)
215167
234186 rd = bits.u(subv.untag(rd, 'rd'), 5)
235187
236188 if subv.is_reference(imm):
237 imm = default_slice(imm, 20, 1)
189 imm = bits.ref(imm, slice(20, 1))
238190 else:
239191 imm = bits.i(subv.untag(imm, 'off20'), 20)
240192
264216 rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
265217
266218 if subv.is_reference(imm):
267 imm = default_slice(imm, 12, 1)
219 imm = bits.ref(imm, slice(12, 1))
268220 else:
269221 imm = bits.i(subv.untag(imm, 'off12'), 12)
270222
1818 ... 23/7 00/5 02/3 05/5 06/5 00/7
1919 ... 13/7 06/5 00/3 00/5 0a/12
2020 ... 23/7 00/5 02/3 05/5 06/5 00/7
21 ... 6f/7 00/5 ff/8 01/1 3e6/10 01/1
21 ... 6f/7 00/5 ff/8 1/1 3e6/10 1/1
2222 ... '''[1:-1]))))
2323 == code 0x80000000
2424 b7 02 01 10
5050 >>> byteify(bits.Bitfield(0x13, 9)),
5151 Traceback (most recent call last):
5252 ...
53 AssertionError: not byte aligned: 0x13'9
53 AssertionError: not byte aligned: 013/9
5454 """
5555 assert word.size % 8 == 0, "not byte aligned: {}".format(word)
5656
367367 return (self.segment, self.line)
368368
369369 def exception(self, msg):
370 stream_name = getattr(self.stream, 'name', '(unnamed)')
370371 if self.line:
371 msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, format(self.line))
372 msg = msg + "\n{}:{}: {}".format(stream_name, self.i, format(self.line))
372373 msg = msg + "\nparsed as {}".format(dump(self.line))
373374 elif self.raw_line:
374 msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, self.raw_line.strip())
375 msg = msg + "\n{}:{}: {}".format(stream_name, self.i, self.raw_line.strip())
375376 return SubVException(msg)
376377
377378 def with_parsed_lines(process_fn):
99 ... # load 0x10010000 (UART0) into t0
1010 ... 37/7 05/5 10010/20
1111 ... # store 0x48 (H) in UART0+0
12 ... 13/7 06/5 00/3 00/5 48/12
13 ... 23/7 00/5 02/3 05/5 06/5 00/7
12 ... 13/7 06/5 0/3 00/5 048/12
13 ... 23/7 00/5 2/3 05/5 06/5 00/7
1414 ... # store 0x65 (e) in UART0+0
15 ... 13/7 06/5 00/3 00/5 65/12
16 ... 23/7 00/5 02/3 05/5 06/5 00/7
15 ... 13/7 06/5 0/3 00/5 065/12
16 ... 23/7 00/5 2/3 05/5 06/5 00/7
1717 ... # store 0x6c (l) in UART0+0
18 ... 13/7 06/5 00/3 00/5 6c/12
19 ... 23/7 00/5 02/3 05/5 06/5 00/7
18 ... 13/7 06/5 0/3 00/5 06c/12
19 ... 23/7 00/5 2/3 05/5 06/5 00/7
2020 ... # store 0x6c (l) in UART0+0
21 ... 13/7 06/5 00/3 00/5 6c/12
22 ... 23/7 00/5 02/3 05/5 06/5 00/7
21 ... 13/7 06/5 0/3 00/5 06c/12
22 ... 23/7 00/5 2/3 05/5 06/5 00/7
2323 ... # store 0x6f (o) in UART0+0
24 ... 13/7 06/5 00/3 00/5 6f/12
25 ... 23/7 00/5 02/3 05/5 06/5 00/7
24 ... 13/7 06/5 0/3 00/5 06f/12
25 ... 23/7 00/5 2/3 05/5 06/5 00/7
2626 ... # store 0x0a (\\\\n) in UART0+0
27 ... 13/7 06/5 00/3 00/5 0a/12
28 ... 23/7 00/5 02/3 05/5 06/5 00/7
27 ... 13/7 06/5 0/3 00/5 00a/12
28 ... 23/7 00/5 2/3 05/5 06/5 00/7
2929 ... # jump back up to the top
30 ... 6f/7 00/5 main[19:12]/off8 main[11:11]/off1 main[10:1]/off10 main[20:20]/off1
30 ... 6f/7 00/5 main/off21/[19:12] main/off21/[11:11] main/off21/[10:1] main/off21/[20:20]
3131 ... '''[1:-1]))))
3232 == code 0x80000000
3333 37/7 05/5 10010/20
4343 23/7 00/5 02/3 05/5 06/5 00/7
4444 13/7 06/5 00/3 00/5 0a/12
4545 23/7 00/5 02/3 05/5 06/5 00/7
46 6f/7 00/5 ff/8 01/1 3e6/10 01/1
46 6f/7 00/5 ff/8 1/1 3e6/10 1/1
4747 """
4848 import subv
4949 import bits
5252 slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$')
5353 field_re = re.compile(r'^(imm|off)(\d+)$')
5454
55 def observe(part, rel_addr, map):
55 def observe(word, pc, map):
5656 """ resolve a label reference.
5757
5858 >>> observe((3, '3'), 0, {})
5959 (3, '3')
60 >>> observe(('label[31:0]', 'imm32'), 0, {'label': 0x1234})
60 >>> observe(('label', 'imm32', '[31:0]'), 0, {'label': 0x1234})
6161 Bitfield(0x1234, 32)
62 >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 0x1234})
62 >>> observe(('label-2', 'imm32', '[31:0]'), 0, {'label': 0x1234})
6363 Bitfield(0x1232, 32)
64 >>> observe(('label[1:0]', 'imm32'), 0, {'label': 0x1236})
64 >>> observe(('label', 'imm32', '[1:0]'), 0, {'label': 0x1236})
6565 Bitfield(0x2, 2)
66 >>> observe(('label[31:0]', 'off32'), 0x1000, {'label': 0x1234})
66 >>> observe(('label', 'off32', '[31:0]'), 0x1000, {'label': 0x1234})
6767 Bitfield(0x234, 32)
68 >>> observe(('label[31:12]', 'off32'), 0x1000, {'label': 0x10fff})
68 >>> observe(('label', 'off32', '[31:12]'), 0x1000, {'label': 0x10fff})
6969 Bitfield(0xf, 20)
70 >>> observe(('label[31:0]', 'off32'), 0x2000, {'label': 0x1000})
70 >>> observe(('label', 'off32', '[31:0]'), 0x2000, {'label': 0x1000})
7171 Bitfield(0xfffff000, 32)
72 >>> observe(('label+4[7:0]', 'off32'), 0x1000, {'label': 0x1234})
72 >>> observe(('label+4', 'off32', '[7:0]'), 0x1000, {'label': 0x1234})
7373 Bitfield(0x38, 8)
74 >>> observe(('label+4[15:8]', 'off32'), 0x1000, {'label': 0x1234})
74 >>> observe(('label+4', 'off32', '[15:8]'), 0x1000, {'label': 0x1234})
7575 Bitfield(0x2, 8)
7676
77 >>> observe(('label[32:0]', 'imm32'), 0, {})
77 >>> observe(('label', 'imm32', '[32:0]'), 0, {})
7878 Traceback (most recent call last):
7979 ...
80 AssertionError: undefined label 'label'
80 ValueError: undefined label 'label'
8181 """
82 if not subv.is_reference(part):
83 return part
82 if not subv.is_reference(word):
83 return word
8484
85 ref = subv.parse_reference(part)
86 assert ref['label'] in map, "undefined label '{}'".format(ref['label'])
87 addr = map[ref['label']]
88
89 if 'offset' in ref:
90 addr += ref['offset']
91
92 # @TODO: the hardcoded 32 here is not right, this is going to blow up
93 # in some circumstances (e.g. a backwards branch 2<<18 bytes away)
94 if ref['mode'] == 'imm':
95 addr = bits.u(addr, 32)
96 else:
97 addr = bits.i(addr - rel_addr, 32)
98
99 return addr[ref['hi']:ref['lo']]
85 word = bits.ref(word)
86 return word.as_value(pc=pc, labels=map)
10087
10188 @subv.with_parsed_lines
10289 def survey(iter):
10390 queue = []
10491 map = {}
105 addr, bits = -1, 0
92 addr, bitcount = -1, 0
10693 for segment, line in iter:
10794 line['addr'] = addr
10895 queue.append(line)
11097 # step forward addr
11198 type = line['type']
11299 if type == 'segment':
113 addr, bits = line['segment'][1], 0
100 addr, bitcount = line['segment'][1], 0
114101 elif type == 'label':
115 assert bits == 0, "label isn't byte aligned"
102 assert bitcount == 0, "label isn't byte aligned"
116103 map[line['label']] = addr
117104 elif type == 'instr':
118105 if segment == 'data':
119106 for part in line['instr']:
120 bits += int(part[1])
107 bitcount += int(part[1])
121108
122 if bits >= 8:
123 addr += bits // 8
124 bits = bits % 8
109 if bitcount >= 8:
110 addr += bitcount // 8
111 bitcount = bitcount % 8
125112 elif segment == 'code':
126 assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits)
113 assert bitcount == 0, "instruction isn't byte aligned ({} bitcount left)".format(8 - bitcount)
127114 assert addr % 2 == 0, "instruction isn't 2-byte aligned"
128115
129 bits = 0
116 bitcount = 0
130117 for part in line['instr']:
131118 if subv.is_reference(part):
132 ref = subv.parse_reference(part)
133 bits += ref['size']
119 ref = bits.ref(part)
120 bitcount += ref.size
134121 else:
135 bits += int(part[1])
122 bitcount += int(part[1])
136123
137 assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits)
138 addr += bits // 8
139 bits = 0
124 assert bitcount % 8 == 0, "instruction size not multiple of 8 bitcount: {}".format(bitcount)
125 addr += bitcount // 8
126 bitcount = 0
140127 else:
141128 raise ValueError("unknown segment '{}'".format(segment))
142129
143 for line in queue:
144 type = line['type']
145 if type == 'instr':
146 instr = []
130 for i, line in enumerate(queue, start=1):
131 try:
132 type = line['type']
147133 if type == 'instr':
148 # strip label from opcode
149 op = line[type].pop(0)
150 instr.append(op[:2])
134 instr = []
135 if type == 'instr':
136 # strip label from opcode
137 op = line[type].pop(0)
138 instr.append(op[:2])
151139
152 for part in line[type]:
153 observed = observe(part, line['addr'], map)
154 instr.append(observed)
155 line[type] = instr
156 yield subv.format(line)
157 elif type == 'segment':
158 yield line['raw']
140 for part in line[type]:
141 observed = observe(part, line['addr'], map)
142 instr.append(observed)
143 line[type] = instr
144 yield subv.format(line)
145 elif type == 'segment':
146 yield line['raw']
147 except Exception as e:
148 msg = "failed to survey line"
149 msg = msg + "\n{}:{}: {}".format('(unknown)', i, subv.format(line))
150 msg = msg + "\nparsed as {}".format(subv.dump(line))
151 raise subv.SubVException(msg) from e
159152
160153 if __name__ == '__main__':
161154 import sys
44
55 # x4 = &message
66 # . load high bits
7 37/lui 4/rd/x4 Message/imm20
7 37/lui 4/rd/x4 Message/imm
88 # . add low bits
9 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/imm12
9 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/imm
1010 print:loop:
1111 # load unsigned byte at x4
1212 03/load 4/subop/lbu 6/rd/t1 4/rs/x4 0/imm12
1313 # break loop if zero
14 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off12
14 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off13
1515 # print char
1616 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
1717 # increment x4
1818 13/opi 0/subop/add 4/rd/x4 4/rs/x4 1/imm12
1919 # jump back up
20 6f/jal 0/rd/x0 print:loop/off20
20 6f/jal 0/rd/x0 print:loop/off21
2121 print:break:
2222
2323 loop:
2424 # infinite loop
25 6f/jal 0/rd/x0 loop/off20
25 6f/jal 0/rd/x0 loop/off21
2626
2727 == data 0x80001000
2828 Message: