aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-05-29 10:41:25 +0000
committers-ol <s-ol@users.noreply.github.com>2020-05-29 11:49:42 +0000
commit212ea358c73cd5f3c70d143987472327cf15f653 (patch)
treeb8ee641d14ae68c5558341a58e6a825930c7b83d
parentfix permissions (diff)
downloadsubv-212ea358c73cd5f3c70d143987472327cf15f653.tar.gz
subv-212ea358c73cd5f3c70d143987472327cf15f653.zip
new label-slice syntax in format.py; switch to doctest
-rwxr-xr-xformat.py369
-rw-r--r--subv.py38
-rwxr-xr-xsurvey.py3
-rw-r--r--test.subv10
4 files changed, 251 insertions, 169 deletions
diff --git a/format.py b/format.py
index 053e04e..0fed092 100755
--- a/format.py
+++ b/format.py
@@ -1,4 +1,59 @@
#!/usr/bin/env python3
+"""
+>>> from io import StringIO
+>>> # doctest: +REPORT_NDIFF
+... print(subv.join_all(format(StringIO('''
+... == code 0x80000000
+... main:
+... # load 0x10010000 (UART0) into t0
+... 37/lui 5/rd/t0 0x10010/imm20
+... # store 0x48 (H) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # store 0x65 (e) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 65/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # store 0x6c (l) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # store 0x6c (l) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # store 0x6f (o) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6f/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # store 0x0a (\\\\n) in UART0+0
+... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12
+... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
+... # jump back up to the top
+... 6f/jal 0/rd/x0 main/off20
+... '''[1:-1]))))
+== code 0x80000000
+main:
+# load 0x10010000 (UART0) into t0
+37/7 05/5 10010/20
+# store 0x48 (H) in UART0+0
+13/7 06/5 00/3 00/5 48/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# store 0x65 (e) in UART0+0
+13/7 06/5 00/3 00/5 65/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# store 0x6c (l) in UART0+0
+13/7 06/5 00/3 00/5 6c/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# store 0x6c (l) in UART0+0
+13/7 06/5 00/3 00/5 6c/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# store 0x6f (o) in UART0+0
+13/7 06/5 00/3 00/5 6f/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# store 0x0a (\\n) in UART0+0
+13/7 06/5 00/3 00/5 0a/12
+23/7 00/5 02/3 05/5 06/5 00/7
+# jump back up to the top
+6f/7 00/5 main[19:12]/off8 main[11:11]/off1 main[10:1]/off10 main[20:20]/off1
+"""
+
import subv
import bits
@@ -14,85 +69,201 @@ instr_map = {
'jal': ('j', 0x6f),
}
+def ref_slice(ref, hi, lo):
+ if hi < lo:
+ raise ValueError("cant slice reverse range")
+ elif hi >= ref['size']:
+ raise ValueError("cant slice [{}:{}] from {} bit value".format(hi, lo, ref['size']))
+
+ return {
+ **ref,
+ 'hi': hi,
+ 'lo': lo,
+ 'size': hi - lo + 1,
+ }
+
+def default_slice(val, hi, lo):
+ """ ...
+ >>> default_slice(('label', 'imm12'), 12, 1)
+ ('label[12:1]', 'imm12')
+ >>> default_slice(('label[14:3]', 'imm12'), 12, 1)
+ ('label[14:3]', 'imm12')
+ >>> default_slice(('label[14:3]', 'imm12', 'extra'), 12, 1)
+ ('label[14:3]', 'imm12', 'extra')
+ >>> default_slice(('label[31:0]', 'imm12'), 11, 0)
+ Traceback (most recent call last):
+ ...
+ AssertionError: slice doesnt match metadata
+ """
+ parsed = subv.parse_reference(val)
+ if 'hi' not in parsed:
+ parsed['hi'] = hi
+ parsed['lo'] = lo
+
+ p_size = parsed['hi'] - parsed['lo'] + 1
+ assert parsed['size'] == p_size, "slice doesnt match metadata"
+
+ ref = '{label}[{hi}:{lo}]'.format(**parsed)
+ return (ref, *val[1:])
+
+def slice_bit_or_ref(val, hi, lo):
+ """ ...
+ >>> slice_bit_or_ref(('label[31:0]', 'imm32'), 12, 1)
+ ('label[12:1]', 'imm12')
+ >>> slice_bit_or_ref(('label[31:0]', 'off32'), 11, 0)
+ ('label[11:0]', 'off12')
+ >>> slice_bit_or_ref(('label[31:0]', 'off32'), 31, 12)
+ ('label[31:12]', 'off20')
+ >>> slice_bit_or_ref(('label[11:0]', 'imm12', 'extra'), 15, 4)
+ Traceback (most recent call last):
+ ...
+ AssertionError: cant slice outside of bounds
+ >>> slice_bit_or_ref(('label', 'imm12'), 12, 1)
+ Traceback (most recent call last):
+ ...
+ AssertionError: cant slice label w/o bounds
+ """
+ if not isinstance(val[0], str):
+ return bits.slice(val, hi, lo)
+
+ ref = subv.parse_reference(val)
+ assert 'hi' in ref, "cant slice label w/o bounds"
+
+ sz = hi - lo
+ lo = ref['lo'] + lo
+ hi = lo + sz
+ assert hi <= ref['hi'], "cant slice outside of bounds"
+
+ ref['hi'] = hi
+ ref['lo'] = lo
+ ref['size'] = sz + 1
+ main = '{label}[{hi}:{lo}]'.format(**ref)
+ field = '{mode}{size}'.format(**ref)
+ return (main, field, *val[2:])
+
def pack_u(instr):
+ """ verify & pack U-type instructions.
+
+ >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])
+ [(55, 7), (5, 5), (65552, 20)]
+
+ >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])
+ [(55, 7), (5, 5), ('pos[31:12]', 'imm20')]
+
+ >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[19:0]', 'imm20')])
+ [(55, 7), (5, 5), ('pos[19:0]', 'imm20')]
+
+ >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')])
+ Traceback (most recent call last):
+ ...
+ AssertionError: slice doesnt match metadata
+ """
(op, rd, imm) = instr
op = bits.u(subv.untag(op), 7)
rd = bits.u(subv.untag(rd, 'rd'), 5)
- if not subv.is_lref(imm):
+ if subv.is_lref(imm):
+ imm = default_slice(imm, 31, 12)
+ else:
imm = bits.i(subv.untag(imm, 'imm20'), 20)
return [op, rd, imm]
def pack_i(instr):
+ """ verify & pack I-type instructions.
+ >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')])
+ [(19, 7), (6, 5), (0, 3), (0, 5), (101, 12)]
+
+ >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')])
+ [(19, 7), (6, 5), (0, 3), (0, 5), ('label[11:0]', 'imm12')]
+ """
(op, sub, rd, rs, imm) = instr
op = bits.u(subv.untag(op), 7)
sub = bits.u(subv.untag(sub, 'subop'), 3)
rd = bits.u(subv.untag(rd, 'rd'), 5)
rs = bits.u(subv.untag(rs, 'rs'), 5)
- if not subv.is_lref(imm):
+ if subv.is_lref(imm):
+ imm = default_slice(imm, 11, 0)
+ else:
imm = bits.i(subv.untag(imm, 'imm12'), 12)
return [op, rd, sub, rs, imm]
def pack_s(instr):
+ """
+ >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')])
+ [(35, 7), (0, 5), (2, 3), (5, 5), (6, 5), (0, 7)]
+
+ >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')])
+ [(35, 7), ('home[4:0]', 'off5'), (2, 3), (5, 5), (6, 5), ('home[11:5]', 'off7')]
+ """
(op, sub, rs1, rs2, imm) = instr
op = bits.u(subv.untag(op), 7)
sub = bits.u(subv.untag(sub, 'subop'), 3)
rs1 = bits.u(subv.untag(rs1, 'rs'), 5)
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
- if not subv.is_lref(imm):
- imm = bits.i(subv.untag(imm, 'off12'), 12)
- imm_lo = bits.slice(imm, 4, 0)
- imm_hi = bits.slice(imm, 11, 5)
+
+ if subv.is_lref(imm):
+ imm = default_slice(imm, 11, 0)
else:
- label = subv.untag(imm, 'off12')
- imm_lo = (label, 5, 'off12')
- imm_hi = (label, 7, 'off12>>5')
+ imm = bits.i(subv.untag(imm, 'off12'), 12)
+
+ imm_lo = slice_bit_or_ref(imm, 4, 0) # + ('off[4:0]',)
+ imm_hi = slice_bit_or_ref(imm, 11, 5) # + ('off[11:5]',)
return [op, imm_lo, sub, rs1, rs2, imm_hi]
def pack_j(instr):
+ """
+ >>> pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])
+ [(111, 7), (0, 5), (0, 8), (0, 1), (0, 10), (0, 1)]
+
+ >>> pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')])
+ [(111, 7), (0, 5), (255, 8), (1, 1), (1022, 10), (1, 1)]
+
+ >>> pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')])
+ [(111, 7), (2, 5), ('home[19:12]', 'off8'), ('home[11:11]', 'off1'), ('home[10:1]', 'off10'), ('home[20:20]', 'off1')]
+ """
(op, rd, imm) = instr
op = bits.u(subv.untag(op), 7)
rd = bits.u(subv.untag(rd, 'rd'), 5)
- if not subv.is_lref(imm):
- imm = bits.i(subv.untag(imm, 'off21'), 21)
- if imm & 0b1 == 1:
- raise ArgumentError("J-type offsets have to be halfword-aligned")
- imm_lo = bits.slice(imm, 10, 1)
- imm_11 = bits.slice(imm, 11, 11)
- imm_hi = bits.slice(imm, 19, 12)
- imm_20 = bits.slice(imm, 20, 20)
+ if subv.is_lref(imm):
+ imm = default_slice(imm, 20, 1)
else:
- label = subv.untag(imm, 'off21')
- imm_lo = (label, 10, 'off21>>1')
- imm_11 = (label, 1, 'off21>>11')
- imm_hi = (label, 8, 'off21>>12')
- imm_20 = (label, 1, 'off21>>20')
+ imm = bits.i(subv.untag(imm, 'off20'), 20)
+
+ imm_lo = slice_bit_or_ref(imm, 9, 0) # + ('off[10:1]',)
+ imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',)
+ imm_hi = slice_bit_or_ref(imm, 18, 11) # + ('off[19:12]',)
+ imm_20 = slice_bit_or_ref(imm, 19, 19) # + ('off[20]',)
return [op, rd, imm_hi, imm_11, imm_lo, imm_20]
def pack_b(instr):
+ """
+ >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')])
+ [(99, 7), (0, 1), (0, 4), (0, 3), (6, 5), (0, 5), (0, 6), (0, 1)]
+
+ >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')])
+ [(99, 7), (1, 1), (14, 4), (0, 3), (6, 5), (0, 5), (63, 6), (1, 1)]
+
+ >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')])
+ [(99, 7), ('home[11:11]', 'off1'), ('home[4:1]', 'off4'), (0, 3), (6, 5), (0, 5), ('home[10:5]', 'off6'), ('home[12:12]', 'off1')]
+ """
(op, sub, rs1, rs2, imm) = instr
op = bits.u(subv.untag(op), 7)
sub = bits.u(subv.untag(sub, 'subop'), 3)
rs1 = bits.u(subv.untag(rs1, 'rs'), 5)
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
- if not subv.is_lref(imm):
- imm = bits.i(subv.untag(imm, 'off13'), 13)
- if imm & 0b1 == 1:
- raise ArgumentError("B-type offsets have to be halfword-aligned")
- imm_lo = bits.slice(imm, 4, 1)
- imm_md = bits.slice(imm, 10, 5)
- imm_11 = bits.slice(imm, 11, 11)
- imm_12 = bits.lice(imm, 12, 12)
+
+ if subv.is_lref(imm):
+ imm = default_slice(imm, 12, 1)
else:
- label = subv.untag(imm, 'off13')
- imm_lo = (label, 4, 'off13>>1')
- imm_md = (label, 6, 'off13>>5')
- imm_11 = (label, 1, 'off13>>11')
- imm_12 = (label, 1, 'off13>>12')
+ imm = bits.i(subv.untag(imm, 'off12'), 12)
+ imm_lo = slice_bit_or_ref(imm, 3, 0) # + ('off[4:1]',)
+ imm_md = slice_bit_or_ref(imm, 9, 4) # + ('off[10:5]',)
+ imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',)
+ imm_12 = slice_bit_or_ref(imm, 11, 11) # + ('off[12]',)
return [op, imm_11, imm_lo, sub, rs1, rs2, imm_md, imm_12]
def format(iter):
@@ -103,8 +274,7 @@ def format(iter):
if segment == 'code' and line['type'] == 'instr':
instr = line['instr']
op = instr[0]
- if len(op) != 2:
- raise ValueError("instruction without op label")
+ assert len(op) == 2, 'instruction without op label: {}'.format(instr)
(op, label) = op
if label not in instr_map:
@@ -137,128 +307,3 @@ if __name__ == '__main__':
import sys
for line in format(sys.stdin):
print(line)
-
-import unittest
-class TestPackers(unittest.TestCase):
- def test_pack_u(self):
- final = pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])
- self.assertEqual(
- final,
- [(0x37, 7), (0x5, 5), (0x10010, 20)]
- )
- self.assertEqual(bits.concat(*final)[1], 32)
-
- label = pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])
- self.assertEqual(
- label,
- [(0x37, 7), (0x5, 5), ('pos', 'imm20')]
- )
-
- def test_pack_i(self):
- final = pack_i([
- (0x13, 'opi'),
- (0, 'subop', 'add'),
- (6, 'rd', 't1'),
- (0, 'rs', 'x0'),
- (0x65, 'imm12'),
- ])
- self.assertEqual(
- final,
- [(0x13, 7), (6, 5), (0, 3), (0, 5), (0x65, 12)]
- )
- self.assertEqual(bits.concat(*final)[1], 32)
-
- def test_pack_s(self):
- final = pack_s([
- (0x23, 'store'),
- (2, 'subop', 'word'),
- (5, 'rs', 't0'),
- (6, 'rs', 't1'),
- (0, 'off12'),
- ])
- self.assertEqual(
- final,
- [(0x23, 7), (0, 5), (2, 3), (5, 5), (6, 5), (0, 7)]
- )
- self.assertEqual(bits.concat(*final)[1], 32)
-
- label = pack_s([
- (0x23, 'store'),
- (2, 'subop', 'word'),
- (5, 'rs', 't0'),
- (6, 'rs', 't1'),
- ('home', 'off12'),
- ])
- self.assertEqual(label, [
- (0x23, 7),
- ('home', 5, 'off12'),
- (2, 3),
- (5, 5),
- (6, 5),
- ('home', 7, 'off12>>5'),
- ])
-
-class TestE2E(unittest.TestCase):
- def test_e2e(self):
- from io import StringIO
- from textwrap import dedent
- inp = dedent('''\
- == code 0x80000000
- main:
- # load 0x10010000 (UART0) into t0
- 37/lui 5/rd/t0 0x10010/imm20
- # store 0x48 (H) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # store 0x65 (e) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 65/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # store 0x6c (l) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # store 0x6c (l) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # store 0x6f (o) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6f/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # store 0x0a (\\n) in UART0+0
- 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12
- 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
- # jump back up to the top
- 6f/jal 0/rd/x0 main/off21
- ''')
-
- out = dedent('''\
- == code 0x80000000
- main:
- # load 0x10010000 (UART0) into t0
- 37/7 05/5 10010/20
- # store 0x48 (H) in UART0+0
- 13/7 06/5 00/3 00/5 48/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # store 0x65 (e) in UART0+0
- 13/7 06/5 00/3 00/5 65/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # store 0x6c (l) in UART0+0
- 13/7 06/5 00/3 00/5 6c/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # store 0x6c (l) in UART0+0
- 13/7 06/5 00/3 00/5 6c/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # store 0x6f (o) in UART0+0
- 13/7 06/5 00/3 00/5 6f/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # store 0x0a (\\n) in UART0+0
- 13/7 06/5 00/3 00/5 0a/12
- 23/7 00/5 02/3 05/5 06/5 00/7
- # jump back up to the top
- 6f/7 00/5 main/8/off21>>12 main/1/off21>>11 main/10/off21>>1 main/1/off21>>20
- ''')
-
- got = ''
- for line in format(StringIO(inp)):
- got += line + '\n'
-
- self.maxDiff = None
- self.assertEqual(got, out)
diff --git a/subv.py b/subv.py
index b53639d..146d544 100644
--- a/subv.py
+++ b/subv.py
@@ -1,6 +1,8 @@
import re
white = re.compile('[ \t\.\n]+')
hex = re.compile(r'^\-?(0x)?[0-9a-f]+$')
+slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$')
+field_re = re.compile(r'^(imm|off)(\d+)$')
# parsing
@@ -22,6 +24,26 @@ def parse_segment(line):
def parse_label(line):
return line[:-1]
+def parse_reference(part):
+ ref = part[0]
+ field = part[1]
+
+ label, hi, lo = slice_re.match(ref).groups()
+ mode, size = field_re.match(field).groups()
+
+ ref = {
+ 'label': label,
+ 'mode': mode,
+ 'size': int(size),
+ 'meta': part[2:],
+ }
+
+ if hi is not None:
+ ref['hi'] = int(hi)
+ ref['lo'] = int(lo)
+
+ return ref
+
def classify(line):
if line == '':
return 'empty'
@@ -71,7 +93,7 @@ def untag(part, expect=None):
def format_part(part):
if not is_lref(part):
first = '{:02x}'.format(part[0])
- part = (first,) + part[1:]
+ part = (first, *part[1:])
return '/'.join([str(p) for p in part])
def format_instr(inst, comment=None):
@@ -80,6 +102,10 @@ def format_instr(inst, comment=None):
packed = packed + ' # ' + comment
return packed
+def join_all(gen):
+ res = '\n'.join(gen)
+ return res
+
import unittest
class TestParsing(unittest.TestCase):
def test_parse_part(self):
@@ -101,6 +127,16 @@ class TestParsing(unittest.TestCase):
self.assertEqual(parse_part('label:suff/tag*'), ('label:suff', 'tag*'))
self.assertEqual(parse_part('$label:suff/tag*'), ('$label:suff', 'tag*'))
+ def test_parse_reference(self):
+ self.assertEqual(
+ parse_reference(('lbl', 'imm32')),
+ { 'label': 'lbl', 'hi': None, 'lo': None, 'mode': 'imm', 'size': 32, 'meta': () }
+ )
+ self.assertEqual(
+ parse_reference(('x[11:0]', 'off12')),
+ { 'label': 'x', 'hi': 11, 'lo': 0, 'mode': 'off', 'size': 12, 'meta': () }
+ )
+
class TestChecks(unittest.TestCase):
def test_is_lref(self):
self.assertTrue(is_lref(('hello',)))
diff --git a/survey.py b/survey.py
index 442ef11..3ac7e1c 100755
--- a/survey.py
+++ b/survey.py
@@ -3,7 +3,8 @@ import subv
import bits
import re
-tag_re = re.compile(r'^(imm|off)(\d+)(?:>>(\d+))?$')
+slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$')
+field_re = re.compile(r'^(imm|off)(\d+)$')
def scan(iter):
addr = None
diff --git a/test.subv b/test.subv
index 05cb8c1..c3b2e8c 100644
--- a/test.subv
+++ b/test.subv
@@ -5,25 +5,25 @@ main:
# x4 = &message
# . load high bits
- 37/lui 4/rd/x4 Message/20/imm32>>12
+ 37/lui 4/rd/x4 Message/imm20
# . add low bits
- 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/12/imm32
+ 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/imm12
print:loop:
# load unsigned byte at x4
03/load 4/subop/lbu 6/rd/t1 4/rs/x4 0/imm12
# break loop if zero
- 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off13
+ 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off12
# print char
23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
# increment x4
13/opi 0/subop/add 4/rd/x4 4/rs/x4 1/imm12
# jump back up
- 6f/jal 0/rd/x0 print:loop/off21
+ 6f/jal 0/rd/x0 print:loop/off20
print:break:
loop:
# infinite loop
- 6f/jal 0/rd/x0 loop/off21
+ 6f/jal 0/rd/x0 loop/off20
== data 0x80001000
Message: