97463b6a606072281749ce77ae32da6fee1cbf05
[openpower-isa.git] / src / openpower / 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 openpower.decoder.power_enums import get_csv, find_wiki_dir
6 from openpower.util import log
7 import os
8
9 # identifies register by type
10 def is_CR_3bit(regname):
11 return regname in ['BF', 'BFA', 'BFB']
12
13 def is_CR_5bit(regname):
14 return regname in ['BA', 'BB', 'BC', 'BI', 'BT']
15
16 def is_GPR(regname):
17 return regname in ['RA', 'RB', 'RC', 'RS', 'RT']
18
19 def is_FPR(regname):
20 return regname in ['FRA', 'FRB', 'FRC', 'FRS', 'FRT']
21
22 def get_regtype(regname):
23 if is_CR_3bit(regname):
24 return "CR_3bit"
25 if is_CR_5bit(regname):
26 return "CR_5bit"
27 if is_GPR(regname):
28 return "GPR"
29 if is_FPR(regname):
30 return "FPR"
31
32
33 def decode_extra(rm, prefix=''):
34 # first turn the svp64 rm into a "by name" dict, recording
35 # which position in the RM EXTRA it goes into
36 # also: record if the src or dest was a CR, for sanity-checking
37 # (elwidth overrides on CRs are banned)
38 dest_reg_cr, src_reg_cr = False, False
39 svp64_srcreg_byname = {}
40 svp64_destreg_byname = {}
41 log ("decode_extra RM", rm)
42 for i in range(4):
43 rfield = rm[prefix+str(i)]
44 if not rfield or rfield == '0':
45 continue
46 log ("EXTRA field", i, rfield)
47 rfield = rfield.split(";") # s:RA;d:CR1 etc.
48 for r in rfield:
49 rtype = r[0]
50 # TODO: ignoring s/d makes it impossible to do
51 # LD/ST-with-update.
52 r = r[2:] # ignore s: and d:
53 if rtype == 'd':
54 svp64_destreg_byname[r] = i # dest reg in EXTRA position 0-3
55 else:
56 svp64_srcreg_byname[r] = i # src reg in EXTRA position 0-3
57 # check the regtype (if CR, record that)
58 regtype = get_regtype(r)
59 if regtype in ['CR_3bit', 'CR_5bit']:
60 if rtype == 'd':
61 dest_reg_cr = True
62 if rtype == 's':
63 src_reg_cr = True
64
65 return dest_reg_cr, src_reg_cr, svp64_srcreg_byname, svp64_destreg_byname
66
67
68 # gets SVP64 ReMap information
69 class SVP64RM:
70 def __init__(self, microwatt_format=False):
71 """SVP64RM: gets micro-opcode information
72
73 microwatt_format: moves RS to in1 (to match decode1.vhdl)
74 """
75 self.instrs = {}
76 self.svp64_instrs = {}
77 pth = find_wiki_dir()
78 for fname in os.listdir(pth):
79 if fname.startswith("RM") or fname.startswith("LDSTRM"):
80 for entry in get_csv(fname):
81 entry['insn'] = entry['insn'].split("=")[-1]
82 if microwatt_format:
83 # move RS from position 1 to position 3, to match
84 # microwatt decode1.vhdl format
85 if entry['in1'] == 'RS' and entry['in3'] == 'NONE':
86 entry['in1'] = 'NONE'
87 entry['in3'] = 'RS'
88 self.instrs[entry['insn']] = entry
89
90
91 def get_svp64_csv(self, fname):
92 # first get the v3.0B entries
93 v30b = get_csv(fname)
94
95 # now add the RM fields (for each instruction)
96 for entry in v30b:
97 # FP entries have a format NN/NN=insn
98 entry['comment'] = entry['comment'].split("=")[-1]
99 # *sigh* create extra field "out2" based on LD/ST update
100 # KEEP TRACK HERE https://bugs.libre-soc.org/show_bug.cgi?id=619
101 entry['out2'] = 'NONE'
102 if entry['upd'] == '1':
103 entry['out2'] = 'RA'
104
105 # dummy (blank) fields, first
106 entry.update({'EXTRA0': '0', 'EXTRA1': '0', 'EXTRA2': '0',
107 'EXTRA3': '0',
108 'SV_mode': 'NONE',
109 'SV_Ptype': 'NONE', 'SV_Etype': 'NONE',
110 'sv_cr_in': 'NONE', 'sv_cr_out': 'NONE'})
111 for fname in ['in1', 'in2', 'in3', 'out', 'out2']:
112 entry['sv_%s' % fname] = 'NONE'
113
114 # is this SVP64-augmented?
115 asmcode = entry['comment']
116 if asmcode not in self.instrs:
117 continue
118
119 # start updating the fields, merge relevant info
120 svp64 = self.instrs[asmcode]
121 for k, v in {'EXTRA0': '0', 'EXTRA1': '1', 'EXTRA2': '2',
122 'EXTRA3': '3',
123 'SV_mode': 'mode',
124 'SV_Ptype': 'Ptype', 'SV_Etype': 'Etype'}.items():
125 entry[k] = svp64[v]
126
127 # hmm, we need something more useful: a cross-association
128 # of the in1/2/3 and CR in/out with the EXTRA0-3 fields
129 decode = decode_extra(entry, "EXTRA")
130 dest_reg_cr, src_reg_cr, svp64_src, svp64_dest = decode
131
132 # now examine in1/2/3/out, create sv_in1/2/3/out
133 for fname in ['in1', 'in2', 'in3', 'out', 'out2']:
134 regfield = entry[fname]
135 extra_index = None
136 if regfield == 'RA_OR_ZERO':
137 regfield = 'RA'
138 log (asmcode, regfield, fname, svp64_dest, svp64_src)
139 # find the reg in the SVP64 extra map
140 if (fname in ['out', 'out2'] and regfield in svp64_dest):
141 extra_index = svp64_dest[regfield]
142 if (fname not in ['out', 'out2'] and regfield in svp64_src):
143 extra_index = svp64_src[regfield]
144 # ta-daa, we know in1/2/3/out's bit-offset
145 if extra_index is not None:
146 entry['sv_%s' % fname] = "Idx"+str(extra_index)
147
148 # TODO: CRs a little tricky, the power_enums.CRInSel is a bit odd.
149 # ignore WHOLE_REG for now
150 cr_in = entry['CR in']
151 extra_index = 'NONE'
152 if cr_in in svp64_src:
153 entry['sv_cr_in'] = "Idx"+str(svp64_src[cr_in])
154 elif cr_in == 'BA_BB':
155 index1 = svp64_src.get('BA', None)
156 index2 = svp64_src.get('BB', None)
157 entry['sv_cr_in'] = "Idx_%d_%d" % (index1, index2)
158 elif cr_in == 'BFA_BFB_BF':
159 index1 = svp64_src.get('BFA', None)
160 index2 = svp64_src.get('BFB', None)
161 index3 = svp64_src.get('BF', None)
162 entry['sv_cr_in'] = "Idx_%d_%d_%d" % (index1, index2, index3)
163
164 # CRout a lot easier. ignore WHOLE_REG for now
165 cr_out = entry['CR out']
166 extra_index = svp64_dest.get(cr_out, None)
167 if extra_index is not None:
168 entry['sv_cr_out'] = 'Idx%d' % extra_index
169
170 # more enum-friendly Ptype names. should have done this in
171 # sv_analysis.py, oh well
172 if entry['SV_Ptype'] == '1P':
173 entry['SV_Ptype'] = 'P1'
174 if entry['SV_Ptype'] == '2P':
175 entry['SV_Ptype'] = 'P2'
176 self.svp64_instrs[asmcode] = entry
177
178 return v30b
179
180 if __name__ == '__main__':
181 isa = SVP64RM()
182 minor_31 = isa.get_svp64_csv("minor_31.csv")
183 for entry in minor_31:
184 if entry['comment'].startswith('ldu'):
185 print ("entry", entry)
186 minor_19 = isa.get_svp64_csv("minor_19.csv")
187 for entry in minor_19:
188 if entry['comment'].startswith('cr'):
189 print (entry)
190 minor_31 = isa.get_svp64_csv("minor_31.csv")
191 for entry in minor_31:
192 if entry['comment'].startswith('cmp'):
193 print ("cmp", entry)