move all source directories to soc so that "import soc.scoreboard" etc is used
[soc.git] / src / soc / decoder / power_fields.py
diff --git a/src/soc/decoder/power_fields.py b/src/soc/decoder/power_fields.py
new file mode 100644 (file)
index 0000000..3457331
--- /dev/null
@@ -0,0 +1,242 @@
+from collections import OrderedDict, namedtuple
+
+
+class BitRange(OrderedDict):
+    """BitRange: remaps from straight indices (0,1,2..) to bit numbers
+    """
+    def __getitem__(self, subscript):
+        if isinstance(subscript, slice):
+            return list(self)[subscript]
+        else:
+            return self[subscript]
+
+def decode_instructions(form):
+    res = {}
+    accum = []
+    for l in form:
+        if l.strip().startswith("Formats"):
+            l = l.strip().split(":")[-1]
+            l = l.replace(" ", "")
+            l = l.split(",")
+            for fmt in l:
+                if fmt not in res:
+                    res[fmt] = [accum[0]]
+                else:
+                    res[fmt].append(accum[0])
+            accum = []
+        else:
+            accum.append(l.strip())
+    return res
+
+def decode_form_header(hdr):
+    res = {}
+    count = 0
+    hdr = hdr.strip()
+    print (hdr.split('|'))
+    for f in hdr.split("|"):
+        if not f:
+            continue
+        if f[0].isdigit():
+            idx = int(f.strip().split(' ')[0])
+            res[count] = idx
+        count += len(f) + 1
+    return res
+
+def find_unique(d, key):
+    if key not in d:
+        return key
+    idx = 1
+    while "%s_%d" % (key, idx) in d:
+        idx += 1
+    return "%s_%d" % (key, idx)
+
+
+def decode_line(header, line):
+    line = line.strip()
+    res = {}
+    count = 0
+    print ("line", line)
+    prev_fieldname = None
+    for f in line.split("|"):
+        if not f:
+            continue
+        end = count + len(f) + 1
+        fieldname = f.strip()
+        if not fieldname or fieldname.startswith('/'):
+            if prev_fieldname is not None:
+                res[prev_fieldname] = (res[prev_fieldname], header[count])
+                prev_fieldname = None
+            count = end
+            continue
+        bitstart = header[count]
+        if prev_fieldname is not None:
+            res[prev_fieldname] = (res[prev_fieldname], bitstart)
+        res[fieldname] = bitstart
+        count = end
+        prev_fieldname = fieldname
+    res[prev_fieldname] = (bitstart, 32)
+    return res
+
+
+def decode_form(form):
+    header = decode_form_header(form[0])
+    res = []
+    print ("header", header)
+    for line in form[1:]:
+        dec = decode_line(header, line)
+        if dec:
+            res.append(dec)
+    fields = {}
+    falternate = {}
+    for l in res:
+        for k, (start,end) in l.items():
+            if k in fields:
+                if (start, end) == fields[k]:
+                    continue # already in and matching for this Form
+                if k in falternate:
+                    alternate = "%s_%d" % (k, falternate[k])
+                    if (start, end) == fields[alternate]:
+                        continue
+                falternate[k] = fidx = falternate.get(k, 0) + 1
+                fields["%s_%d" % (k, fidx)] = (start, end)
+            else:
+                fields[k] = (start, end)
+    return fields
+
+
+class DecodeFields:
+
+    def __init__(self, bitkls=BitRange, bitargs=(), fname="fields.txt"):
+        self.bitkls = bitkls
+        self.bitargs = bitargs
+        self.fname = fname
+
+    def create_specs(self):
+        self.forms, self.instrs = self.decode_fields()
+        self.form_names = forms = self.instrs.keys()
+        for form in forms:
+            fields = self.instrs[form]
+            fk = fields.keys()
+            Fields = namedtuple("Fields", fk)
+            instr = Fields(**fields)
+            setattr(self, "Form%s" % form, instr)
+        # now add in some commonly-used fields (should be done automatically)
+        # note that these should only be ones which are the same on all Forms
+        # note: these are from microwatt insn_helpers.vhdl
+        self.RS = self.FormX.RS
+        self.RT = self.FormX.RT
+        self.RA = self.FormX.RA
+        self.RB = self.FormX.RB
+        self.SI = self.FormD.SI
+        self.UI = self.FormD.UI
+        self.L = self.FormD.L
+        self.SH32 = self.FormM.SH
+        self.sh = self.FormMD.sh
+        self.MB32 = self.FormM.MB
+        self.ME32 = self.FormM.ME
+        self.LI = self.FormI.LI
+        self.LK = self.FormI.LK
+        self.AA = self.FormB.AA
+        self.Rc = self.FormX.Rc
+        self.OE = self.FormXO.Rc
+        self.BD = self.FormB.BD
+        self.BF = self.FormX.BF
+        self.CR = self.FormXL.XO # used by further mcrf decoding
+        self.BB = self.FormXL.BB
+        self.BA = self.FormXL.BA
+        self.BT = self.FormXL.BT
+        self.FXM = self.FormXFX.FXM
+        self.BO = self.FormXL.BO
+        self.BI = self.FormXL.BI
+        self.BH = self.FormXL.BH
+        self.D = self.FormD.D
+        self.DS = self.FormDS.DS
+        self.TO = self.FormX.TO
+        self.BC = self.FormA.BC
+        self.SH = self.FormX.SH
+        self.ME = self.FormM.ME
+        self.MB = self.FormM.MB
+        self.SPR = self.FormXFX.SPR
+
+    def decode_fields(self):
+        with open(self.fname) as f:
+            txt = f.readlines()
+        forms = {}
+        reading_data = False
+        for l in txt:
+            print ("line", l)
+            l = l.strip()
+            if len(l) == 0:
+                continue
+            if reading_data:
+                if l[0] == '#':
+                    reading_data = False
+                else:
+                    forms[heading].append(l)
+            if not reading_data:
+                assert l[0] == '#'
+                heading = l[1:].strip()
+                #if heading.startswith('1.6.28'): # skip instr fields for now
+                    #break
+                heading = heading.split(' ')[-1]
+                print ("heading", heading)
+                reading_data = True
+                forms[heading] = []
+
+        res = {}
+        inst = {}
+
+        for hdr, form in forms.items():
+            print ("heading", hdr)
+            if heading == 'Fields':
+                i = decode_instructions(form)
+                for form, field in i.items():
+                    inst[form] = self.decode_instruction_fields(field)
+            #else:
+            #    res[hdr] = decode_form(form)
+        return res, inst
+
+    def decode_instruction_fields(self, fields):
+        res = {}
+        for field in fields:
+            f, spec = field.strip().split(" ")
+            d = self.bitkls(*self.bitargs)
+            idx = 0
+            for s in spec[1:-1].split(","):
+                s = s.split(':')
+                if len(s) == 1:
+                    d[idx] = int(s[0])
+                    idx += 1
+                else:
+                    start = int(s[0])
+                    end = int(s[1])
+                    while start <= end:
+                        d[idx] = start
+                        idx += 1
+                        start += 1
+            f = f.replace(",", "_")
+            unique = find_unique(res, f)
+            res[unique] = d
+
+        return res
+
+if __name__ == '__main__':
+    dec = DecodeFields()
+    dec.create_specs()
+    forms, instrs = dec.forms, dec.instrs
+    for hdr, form in forms.items():
+        print ()
+        print (hdr)
+        for k, v in form.items():
+            #print ("line", l)
+            #for k, v in l.items():
+            print ("%s: %d-%d" % (k, v[0], v[1]))
+    for form, field in instrs.items():
+        print ()
+        print (form)
+        for f, vals in field.items():
+            print ("    ", f, vals)
+    print (dec.FormX)
+    print (dec.FormX.A)
+    print (dir(dec.FormX))
+    print (dec.FormX._fields)