aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-05-23 09:15:25 +0000
committers-ol <s+removethis@s-ol.nu>2021-05-23 09:15:25 +0000
commitf89982437be8154a9c77527faee2459f0957a450 (patch)
treee977ecdfc81f96d36a5432e5430cfc405e4ce02b
parentlog offending line when errors occur, across all stages (diff)
downloadsubv-f89982437be8154a9c77527faee2459f0957a450.tar.gz
subv-f89982437be8154a9c77527faee2459f0957a450.zip
revert to code detection by segment
-rwxr-xr-xelf.py6
-rwxr-xr-xformat.py8
-rwxr-xr-xpack.py37
-rw-r--r--subv.py17
-rwxr-xr-xsurvey.py52
5 files changed, 61 insertions, 59 deletions
diff --git a/elf.py b/elf.py
index 2759679..a785f79 100755
--- a/elf.py
+++ b/elf.py
@@ -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!")
diff --git a/format.py b/format.py
index aa6c8ba..7798589 100755
--- a/format.py
+++ b/format.py
@@ -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']
diff --git a/pack.py b/pack.py
index 29949b4..f717df4 100755
--- a/pack.py
+++ b/pack.py
@@ -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__':
diff --git a/subv.py b/subv.py
index a280e77..fae4a3e 100644
--- a/subv.py
+++ b/subv.py
@@ -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:
diff --git a/survey.py b/survey.py
index e6beb4b..f8df47d 100755
--- a/survey.py
+++ b/survey.py
@@ -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