git.s-ol.nu subv / f899824
revert to code detection by segment s-ol 30 days ago
5 changed file(s) with 61 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
8383 def elf(iter):
8484 segments = []
8585 segment = None
86 for line in iter:
86 for _, line in iter:
8787 if line['type'] == 'segment':
8888 (name, addr) = line['segment']
8989 segment = { 'name': name, 'addr': addr, 'content': [] }
9090 segments.append(segment)
91 elif line['type'] == 'data':
91 elif line['type'] == 'instr':
9292 if segment == None:
9393 raise ValueError("label or code outside of segment!")
9494
95 segment['content'] += line['data']
95 segment['content'] += line['instr']
9696 else:
9797 raise ValueError("elf input should contain only segments and data!")
9898
283283
284284 @subv.with_parsed_lines
285285 def format(iter):
286 for line in iter:
287 if line['type'] == 'instr':
286 for segment, line in iter:
287 if line['type'] == 'instr' and segment == 'code':
288288 op = line['instr'][0]
289289 assert len(op) == 2, 'instruction without op label: {}'.format(op)
290290
296296 raise ValueError("opcode {} doesn't match label {} (expected {})"
297297 .format(op, label, expected))
298298
299 formatted = formatter(line['instr'])
300 formatted[0] = (*formatted[0], label)
301 line['instr'] = formatted
299 line['instr'] = formatter(line['instr'])
302300 line = yield subv.format(line)
303301 else:
304302 line = yield line['raw']
6363
6464 @subv.with_parsed_lines
6565 def pack(iter):
66 segment = None
67
6866 out = []
6967 buf = bits.empty
7068
7270 tmp = out[:]
7371 out.clear()
7472 return {
75 'type': 'data',
76 'data': tmp,
73 'type': 'instr',
74 'instr': tmp,
7775 'comment': None,
7876 }
7977
80 for line in iter:
81 if line['type'] == 'data':
82 for part in line['data']:
83 buf = bits.concat(buf, bits.from_part(part))
84 while buf[1] >= 8:
85 byte = bits.slice(buf, 7, 0)
86 buf = bits.slice(buf, buf[1] - 1, 8, allow_empty=True)
87 out.append(byte[:1])
88
89 if len(out) == 4:
90 yield subv.format(flush_bytes())
91 else:
78 last_segment = None
79 for segment, line in iter:
80 if last_segment != segment:
9281 assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment)
9382 if out:
9483 yield subv.format(flush_bytes())
9584
96 if line['type'] == 'segment':
97 segment = line['segment'][0]
85 if line['type'] == 'instr':
86 for part in line['instr']:
87 buf = bits.concat(buf, bits.from_part(part))
88 else:
9889 yield line['raw']
90
91 while buf[1] >= 8:
92 byte = bits.slice(buf, 7, 0)
93 buf = bits.slice(buf, buf[1] - 1, 8, allow_empty=True)
94 out.append(byte[:1])
95
96 if len(out) == 4:
97 yield subv.format(flush_bytes())
98
99 last_segment = segment
99100
100101 assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment)
101102
126126 >>> classify('$some:label:')
127127 'label'
128128 >>> classify('ff/op 0/subop/add 1/rd/x1 label[11:0]/imm12')
129 'data'
129 'instr'
130130 >>> classify('ff/8 0/3 2/5')
131 'data'
131 'instr'
132132 """
133133 if line == '':
134134 return 'empty'
137137 elif line.endswith(':'): # label
138138 return 'label'
139139 else:
140 return 'data'
140 return 'instr'
141141
142142 def parse(line):
143143 """ clean, classify and parse lines.
156156 parsed = parse_segment(clean)
157157 elif type == 'label':
158158 parsed = parse_label(clean)
159 elif type == 'data':
159 elif type == 'instr':
160160 parsed = parse_instr(clean)
161 if len(parsed[0]) > 1 and not num.match(parsed[0][-1]):
162 type = 'instr'
163161 else:
164162 parsed = None
165163
296294 def __init__(self, stream):
297295 self.stream = stream
298296 self.iter = enumerate(self.stream, start=1)
299 self.i, self.raw_line, self.line = 0, None, None
297 self.i, self.raw_line = 0, None
298 self.line, self.segment = None, None
300299
301300 def __iter__(self):
302301 return self
306305 self.line = None
307306 try:
308307 self.line = parse(self.raw_line)
308 if self.line['type'] == 'segment':
309 self.segment = self.line['segment'][0]
309310 except Exception as e:
310311 raise self.exception("failed to parse line") from e
311 return self.line
312 return (self.segment, self.line)
312313
313314 def exception(self, msg):
314315 if self.line:
6363 (2, 2)
6464 >>> observe(('label[31:0]', 'off32'), 1000, {'label': 1234})
6565 (234, 32)
66 >>> observe(('label[31:12]', 'off32'), 1000, {'label': 1234})
67 (0, 20)
66 >>> observe(('label[31:12]', 'off32'), 1000, {'label': 0x10fff})
67 (16, 20)
6868 >>> observe(('label[31:0]', 'off32'), 2000, {'label': 1000})
6969 (4294966296, 32)
7070
9494 queue = []
9595 map = {}
9696 addr, bits = -1, 0
97 for line in iter:
97 for segment, line in iter:
9898 line['addr'] = addr
9999 queue.append(line)
100100
101101 # step forward addr
102102 type = line['type']
103103 if type == 'segment':
104 segment, addr = line['segment']
105 bits = 0
104 addr, bits = line['segment'][1], 0
106105 elif type == 'label':
107106 assert bits == 0, "label isn't byte aligned"
108107 map[line['label']] = addr
109 elif type == 'data':
110 for part in line['data']:
111 bits += int(part[1])
112
113 if bits >= 8:
114 addr += bits // 8
115 bits = bits % 8
116108 elif type == 'instr':
117 assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits)
118 assert addr % 2 == 0, "instruction isn't 2-byte aligned"
119
120 bits = 0
121 for part in line['instr']:
122 if subv.is_reference(part):
123 ref = subv.parse_reference(part)
124 bits += ref['size']
125 else:
109 if segment == 'data':
110 for part in line['instr']:
126111 bits += int(part[1])
127112
128 assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits)
129 addr += bits // 8
130 bits = 0
113 if bits >= 8:
114 addr += bits // 8
115 bits = bits % 8
116 elif segment == 'code':
117 assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits)
118 assert addr % 2 == 0, "instruction isn't 2-byte aligned"
119
120 bits = 0
121 for part in line['instr']:
122 if subv.is_reference(part):
123 ref = subv.parse_reference(part)
124 bits += ref['size']
125 else:
126 bits += int(part[1])
127
128 assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits)
129 addr += bits // 8
130 bits = 0
131 else:
132 raise ValueError("unknown segment '{}'".format(segment))
131133
132134 for line in queue:
133135 type = line['type']
134 if type == 'instr' or type == 'data':
136 if type == 'instr':
135137 instr = []
136138 if type == 'instr':
137139 # strip label from opcode