diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-05-23 09:15:25 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-05-23 09:15:25 +0000 |
| commit | f89982437be8154a9c77527faee2459f0957a450 (patch) | |
| tree | e977ecdfc81f96d36a5432e5430cfc405e4ce02b | |
| parent | log offending line when errors occur, across all stages (diff) | |
| download | subv-f89982437be8154a9c77527faee2459f0957a450.tar.gz subv-f89982437be8154a9c77527faee2459f0957a450.zip | |
revert to code detection by segment
| -rwxr-xr-x | elf.py | 6 | ||||
| -rwxr-xr-x | format.py | 8 | ||||
| -rwxr-xr-x | pack.py | 37 | ||||
| -rw-r--r-- | subv.py | 17 | ||||
| -rwxr-xr-x | survey.py | 52 |
5 files changed, 61 insertions, 59 deletions
@@ -84,16 +84,16 @@ def write_program_header(segment, c, start): def elf(iter): segments = [] segment = None - for line in iter: + for _, line in iter: if line['type'] == 'segment': (name, addr) = line['segment'] segment = { 'name': name, 'addr': addr, 'content': [] } segments.append(segment) - elif line['type'] == 'data': + elif line['type'] == 'instr': if segment == None: raise ValueError("label or code outside of segment!") - segment['content'] += line['data'] + segment['content'] += line['instr'] else: raise ValueError("elf input should contain only segments and data!") @@ -284,8 +284,8 @@ instr_map = { @subv.with_parsed_lines def format(iter): - for line in iter: - if line['type'] == 'instr': + for segment, line in iter: + if line['type'] == 'instr' and segment == 'code': op = line['instr'][0] assert len(op) == 2, 'instruction without op label: {}'.format(op) @@ -297,9 +297,7 @@ def format(iter): raise ValueError("opcode {} doesn't match label {} (expected {})" .format(op, label, expected)) - formatted = formatter(line['instr']) - formatted[0] = (*formatted[0], label) - line['instr'] = formatted + line['instr'] = formatter(line['instr']) line = yield subv.format(line) else: line = yield line['raw'] @@ -64,8 +64,6 @@ def byteify(word): @subv.with_parsed_lines def pack(iter): - segment = None - out = [] buf = bits.empty @@ -73,31 +71,34 @@ def pack(iter): tmp = out[:] out.clear() return { - 'type': 'data', - 'data': tmp, + 'type': 'instr', + 'instr': tmp, 'comment': None, } - for line in iter: - if line['type'] == 'data': - for part in line['data']: - buf = bits.concat(buf, bits.from_part(part)) - while buf[1] >= 8: - byte = bits.slice(buf, 7, 0) - buf = bits.slice(buf, buf[1] - 1, 8, allow_empty=True) - out.append(byte[:1]) - - if len(out) == 4: - yield subv.format(flush_bytes()) - else: + last_segment = None + for segment, line in iter: + if last_segment != segment: assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment) if out: yield subv.format(flush_bytes()) - if line['type'] == 'segment': - segment = line['segment'][0] + if line['type'] == 'instr': + for part in line['instr']: + buf = bits.concat(buf, bits.from_part(part)) + else: yield line['raw'] + while buf[1] >= 8: + byte = bits.slice(buf, 7, 0) + buf = bits.slice(buf, buf[1] - 1, 8, allow_empty=True) + out.append(byte[:1]) + + if len(out) == 4: + yield subv.format(flush_bytes()) + + last_segment = segment + assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment) if __name__ == '__main__': @@ -127,9 +127,9 @@ def classify(line): >>> classify('$some:label:') 'label' >>> classify('ff/op 0/subop/add 1/rd/x1 label[11:0]/imm12') - 'data' + 'instr' >>> classify('ff/8 0/3 2/5') - 'data' + 'instr' """ if line == '': return 'empty' @@ -138,7 +138,7 @@ def classify(line): elif line.endswith(':'): # label return 'label' else: - return 'data' + return 'instr' def parse(line): """ clean, classify and parse lines. @@ -157,10 +157,8 @@ def parse(line): parsed = parse_segment(clean) elif type == 'label': parsed = parse_label(clean) - elif type == 'data': + elif type == 'instr': parsed = parse_instr(clean) - if len(parsed[0]) > 1 and not num.match(parsed[0][-1]): - type = 'instr' else: parsed = None @@ -297,7 +295,8 @@ class LineIterator(object): def __init__(self, stream): self.stream = stream self.iter = enumerate(self.stream, start=1) - self.i, self.raw_line, self.line = 0, None, None + self.i, self.raw_line = 0, None + self.line, self.segment = None, None def __iter__(self): return self @@ -307,9 +306,11 @@ class LineIterator(object): self.line = None try: self.line = parse(self.raw_line) + if self.line['type'] == 'segment': + self.segment = self.line['segment'][0] except Exception as e: raise self.exception("failed to parse line") from e - return self.line + return (self.segment, self.line) def exception(self, msg): if self.line: @@ -64,8 +64,8 @@ def observe(part, rel_addr, map): (2, 2) >>> observe(('label[31:0]', 'off32'), 1000, {'label': 1234}) (234, 32) - >>> observe(('label[31:12]', 'off32'), 1000, {'label': 1234}) - (0, 20) + >>> observe(('label[31:12]', 'off32'), 1000, {'label': 0x10fff}) + (16, 20) >>> observe(('label[31:0]', 'off32'), 2000, {'label': 1000}) (4294966296, 32) @@ -95,44 +95,46 @@ def survey(iter): queue = [] map = {} addr, bits = -1, 0 - for line in iter: + for segment, line in iter: line['addr'] = addr queue.append(line) # step forward addr type = line['type'] if type == 'segment': - segment, addr = line['segment'] - bits = 0 + addr, bits = line['segment'][1], 0 elif type == 'label': assert bits == 0, "label isn't byte aligned" map[line['label']] = addr - elif type == 'data': - for part in line['data']: - bits += int(part[1]) - - if bits >= 8: - addr += bits // 8 - bits = bits % 8 elif type == 'instr': - assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits) - assert addr % 2 == 0, "instruction isn't 2-byte aligned" - - bits = 0 - for part in line['instr']: - if subv.is_reference(part): - ref = subv.parse_reference(part) - bits += ref['size'] - else: + if segment == 'data': + for part in line['instr']: bits += int(part[1]) - assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits) - addr += bits // 8 - bits = 0 + if bits >= 8: + addr += bits // 8 + bits = bits % 8 + elif segment == 'code': + assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits) + assert addr % 2 == 0, "instruction isn't 2-byte aligned" + + bits = 0 + for part in line['instr']: + if subv.is_reference(part): + ref = subv.parse_reference(part) + bits += ref['size'] + else: + bits += int(part[1]) + + assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits) + addr += bits // 8 + bits = 0 + else: + raise ValueError("unknown segment '{}'".format(segment)) for line in queue: type = line['type'] - if type == 'instr' or type == 'data': + if type == 'instr': instr = [] if type == 'instr': # strip label from opcode |
