radix: reading first page table entry
[soc.git] / src / soc / decoder / power_svp64.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4
5 from soc.decoder.power_enums import get_csv, find_wiki_dir
6 import os
7
8 # identifies register by type
9 def is_CR_3bit(regname):
10 return regname in ['BF', 'BFA']
11
12 def is_CR_5bit(regname):
13 return regname in ['BA', 'BB', 'BC', 'BI', 'BT']
14
15 def is_GPR(regname):
16 return regname in ['RA', 'RB', 'RC', 'RS', 'RT']
17
18 def get_regtype(regname):
19 if is_CR_3bit(regname):
20 return "CR_3bit"
21 if is_CR_5bit(regname):
22 return "CR_5bit"
23 if is_GPR(regname):
24 return "GPR"
25
26
27 def decode_extra(rm, prefix=''):
28 # first turn the svp64 rm into a "by name" dict, recording
29 # which position in the RM EXTRA it goes into
30 # also: record if the src or dest was a CR, for sanity-checking
31 # (elwidth overrides on CRs are banned)
32 dest_reg_cr, src_reg_cr = False, False
33 svp64_srcreg_byname = {}
34 svp64_destreg_byname = {}
35 for i in range(4):
36 print (rm)
37 rfield = rm[prefix+str(i)]
38 if not rfield or rfield == '0':
39 continue
40 print ("EXTRA field", i, rfield)
41 rfield = rfield.split(";") # s:RA;d:CR1 etc.
42 for r in rfield:
43 rtype = r[0]
44 # TODO: ignoring s/d makes it impossible to do
45 # LD/ST-with-update.
46 r = r[2:] # ignore s: and d:
47 if rtype == 'd':
48 svp64_destreg_byname[r] = i # dest reg in EXTRA position 0-3
49 else:
50 svp64_srcreg_byname[r] = i # src reg in EXTRA position 0-3
51 # check the regtype (if CR, record that)
52 regtype = get_regtype(r)
53 if regtype in ['CR_3bit', 'CR_5bit']:
54 if rtype == 'd':
55 dest_reg_cr = True
56 if rtype == 's':
57 src_reg_cr = True
58
59 return dest_reg_cr, src_reg_cr, svp64_srcreg_byname, svp64_destreg_byname
60
61
62 # gets SVP64 ReMap information
63 class SVP64RM:
64 def __init__(self):
65 self.instrs = {}
66 self.svp64_instrs = {}
67 pth = find_wiki_dir()
68 for fname in os.listdir(pth):
69 if fname.startswith("RM") or fname.startswith("LDSTRM"):
70 for entry in get_csv(fname):
71 self.instrs[entry['insn']] = entry
72
73
74 def get_svp64_csv(self, fname):
75 # first get the v3.0B entries
76 v30b = get_csv(fname)
77
78 # now add the RM fields (for each instruction)
79 for entry in v30b:
80 # dummy (blank) fields, first
81 entry.update({'EXTRA0': '0', 'EXTRA1': '0', 'EXTRA2': '0',
82 'EXTRA3': '0',
83 'SV_Ptype': 'NONE', 'SV_Etype': 'NONE',
84 'sv_cr_in': 'NONE', 'sv_cr_out': 'NONE'})
85 for fname in ['in1', 'in2', 'in3', 'out']:
86 entry['sv_%s' % fname] = 'NONE'
87
88 # is this SVP64-augmented?
89 asmcode = entry['comment']
90 if asmcode not in self.instrs:
91 continue
92
93 # start updating the fields, merge relevant info
94 svp64 = self.instrs[asmcode]
95 for k, v in {'EXTRA0': '0', 'EXTRA1': '1', 'EXTRA2': '2',
96 'EXTRA3': '3',
97 'SV_Ptype': 'Ptype', 'SV_Etype': 'Etype'}.items():
98 entry[k] = svp64[v]
99
100 # hmm, we need something more useful: a cross-association
101 # of the in1/2/3 and CR in/out with the EXTRA0-3 fields
102 decode = decode_extra(entry, "EXTRA")
103 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
104
105 # now examine in1/2/3/out, create sv_in1/2/3/out
106 for fname in ['in1', 'in2', 'in3', 'out']:
107 regfield = entry[fname]
108 extra_index = None
109 if regfield == 'RA_OR_ZERO':
110 regfield = 'RA'
111 print (asmcode, regfield, fname, svp64_dest, svp64_src)
112 # find the reg in the SVP64 extra map
113 if (fname == 'out' and regfield in svp64_dest):
114 extra_index = svp64_dest[regfield]
115 if (fname != 'out' and regfield in svp64_src):
116 extra_index = svp64_src[regfield]
117 # ta-daa, we know in1/2/3/out's bit-offset
118 if extra_index is not None:
119 entry['sv_%s' % fname] = "Idx"+str(extra_index)
120
121 # TODO: CRs a little tricky, the power_enums.CRInSel is a bit odd.
122 # ignore WHOLE_REG for now
123 cr_in = entry['CR in']
124 extra_index = 'NONE'
125 if cr_in in svp64_src:
126 entry['sv_cr_in'] = "Idx"+str(svp64_src[cr_in])
127 elif cr_in == 'BA_BB':
128 index1 = svp64_src.get('BA', None)
129 index2 = svp64_src.get('BB', None)
130 entry['sv_cr_in'] = "Idx_%d_%d" % (index1, index2)
131
132 # CRout a lot easier. ignore WHOLE_REG for now
133 cr_out = entry['CR out']
134 extra_index = svp64_dest.get(cr_out, None)
135 if extra_index is not None:
136 entry['sv_cr_out'] = 'Idx%d' % extra_index
137
138 # more enum-friendly Ptype names. should have done this in
139 # sv_analysis.py, oh well
140 if entry['SV_Ptype'] == '1P':
141 entry['SV_Ptype'] = 'P1'
142 if entry['SV_Ptype'] == '2P':
143 entry['SV_Ptype'] = 'P2'
144 self.svp64_instrs[asmcode] = entry
145
146 return v30b
147
148 if __name__ == '__main__':
149 isa = SVP64RM()
150 minor_30 = isa.get_svp64_csv("minor_30.csv")
151 for entry in minor_30:
152 print (entry)
153 minor_19 = isa.get_svp64_csv("minor_19.csv")
154 for entry in minor_19:
155 if entry['comment'].startswith('cr'):
156 print (entry)
157 minor_31 = isa.get_svp64_csv("minor_31.csv")
158 for entry in minor_31:
159 print (entry)