|
7 | 7 | import tempfile
|
8 | 8 | import shutil
|
9 | 9 | import ast
|
| 10 | +import re |
10 | 11 |
|
11 | 12 | from collections import defaultdict
|
12 | 13 |
|
|
17 | 18 | _log = logging.getLogger(__name__)
|
18 | 19 |
|
19 | 20 |
|
| 21 | +def _int(s): |
| 22 | + return int(ast.literal_eval(s)) |
| 23 | + |
| 24 | + |
| 25 | +def _expandWriteVals(ss): |
| 26 | + """Convert string 'n,m,l,k,...' into list of ints [n, m, l, k, ...] |
| 27 | + Raise Exception if not all items separated by commas can be interpreted as integers.""" |
| 28 | + if ',' not in ss: |
| 29 | + return _int(ss) |
| 30 | + vals = [_int(x) for x in ss.split(',')] |
| 31 | + return vals |
| 32 | + |
| 33 | + |
| 34 | +def parseTransaction(xact): |
| 35 | + """ |
| 36 | + Parse transaction string from CLI. Returns (str/int reg, int offset, int/None size, int/None write_val) |
| 37 | + If 'reg' is type int, it is an explicit base address. |
| 38 | + If 'size' is None, size = 1 |
| 39 | + If 'reg' is type str, it is a register name (supposedly). |
| 40 | + If 'size' is None, size = 2**aw (where 'aw' is the 'addr_width' from the romx JSON) |
| 41 | + If 'write_val' is None, it's a read transaction, else it's a write of value 'write_val' |
| 42 | + Viable formats for a transaction (read/write) in string form: |
| 43 | + Example Implied Transaction |
| 44 | + ------------------------------------------- |
| 45 | + regname Read from named register (str) 'regname' |
| 46 | + regaddr Read from explicit address (int) 'regaddr' |
| 47 | + regname=val Write (int) 'val' to named register (str) 'regname' |
| 48 | + regaddr=val Write (int) 'val' to explicit address (int) 'regaddr' |
| 49 | + regname=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at the |
| 50 | + address of named register (str) 'regname' |
| 51 | + regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at |
| 52 | + address (int) 'regaddr' |
| 53 | + regname+offset Read from address = romx['regname']['base_addr'] + (int) 'offset' |
| 54 | + regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset' |
| 55 | + regname:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] |
| 56 | + regaddr:size Read (int) 'size' elements starting from (int) 'regaddr' |
| 57 | + regname+offset=val Write (int) 'val' to address romx['regname']['base_addr'] + (int) 'offset' |
| 58 | + regname+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at |
| 59 | + address romx['regname']['base_addr'] + (int) 'offset' |
| 60 | + regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset' |
| 61 | + regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at |
| 62 | + address (int) 'regaddr' |
| 63 | + regname+offset:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] + \ |
| 64 | + (int) 'offset' |
| 65 | + regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset' |
| 66 | + I'm not sure what use case the "regaddr+offset" syntax supports, but it does no harm to include it. |
| 67 | + NOTE! Deliberately not supporting "regname-offset" (negative offsets) as it's use case is unclear |
| 68 | + and a '_' to '-' typo could potentially collide with legitimate transactions. |
| 69 | + """ |
| 70 | + restr = r"(\w+)\s*([=+:])?\s*([0-9a-fA-Fx,\-]+)?\s*([=:])?\s*([0-9a-fA-Fx,\-]+)?" |
| 71 | + _match = re.match(restr, xact) |
| 72 | + offset = 0 |
| 73 | + wval = None |
| 74 | + size = None |
| 75 | + if _match: |
| 76 | + groups = _match.groups() |
| 77 | + regstr = groups[0] # Always starts with 'regname' or 'regaddr' |
| 78 | + if groups[1] == '=': |
| 79 | + wval = _expandWriteVals(groups[2]) |
| 80 | + elif groups[1] == '+': |
| 81 | + offset = _int(groups[2]) |
| 82 | + elif groups[1] == ':': |
| 83 | + size = _int(groups[2]) |
| 84 | + if groups[3] == '=': |
| 85 | + if groups[1] == '=': |
| 86 | + raise Exception("Malformed transaction: {}".format(xact)) |
| 87 | + wval = _expandWriteVals(groups[4]) |
| 88 | + elif groups[3] == ':': |
| 89 | + if size is not None: |
| 90 | + raise Exception("Malformed transaction: {}".format(xact)) |
| 91 | + size = _int(groups[4]) |
| 92 | + else: |
| 93 | + raise Exception("Failed to match: {}".format(xact)) |
| 94 | + try: |
| 95 | + reg = _int(regstr) |
| 96 | + except ValueError: |
| 97 | + reg = regstr |
| 98 | + if size is None: |
| 99 | + if wval is None: |
| 100 | + size = None |
| 101 | + else: |
| 102 | + size = 0 |
| 103 | + return (reg, offset, size, wval) |
| 104 | + |
| 105 | + |
20 | 106 | def readwrite(args, dev):
|
21 |
| - for pair in args.reg: |
22 |
| - name, _eq, val = pair.partition('=') |
23 |
| - if len(val): |
24 |
| - val = ast.literal_eval(val) |
25 |
| - dev.reg_write([(name, val)]) |
| 107 | + for xact in args.reg: |
| 108 | + reg, offset, size, wvals = parseTransaction(xact) |
| 109 | + if wvals is not None: |
| 110 | + dev.reg_write_offset([(reg, wvals, offset)]) |
26 | 111 | else:
|
27 |
| - value, = dev.reg_read((name,)) |
| 112 | + value, = dev.reg_read_size(((reg, size, offset),)) |
28 | 113 | try:
|
29 | 114 | _ = iter(value)
|
30 |
| - print("%s \t%s" % (name, ' '.join(['%x' % v for v in value]))) |
| 115 | + print("%s \t%s" % (reg, ' '.join(['%x' % v for v in value]))) |
31 | 116 | except TypeError:
|
32 |
| - print("%s \t%08x" % (name, value)) |
| 117 | + print("%s \t%x" % (reg, value)) |
33 | 118 |
|
34 | 119 |
|
35 | 120 | def listreg(args, dev):
|
|
0 commit comments