49f68b0ac94ed91c2e47c0eecc53cf8aad83625f
[riscv-isa-sim.git] / id_regs.py
1 #!/usr/bin/env python
2 # Copyright (C) 2018 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3
4 """ identify registers used in riscv/insns/*.h and create code
5 that can be used in spike at runtime
6
7 the design of spike assumes that once an opcode is identified,
8 the role of decoding the instruction is implicitly rolled into
9 and included inside the function that emulates that opcode.
10
11 however there may be circumstances where the behaviour of an
12 instruction has to change depending on "tags" associated with
13 the registers (security extensions, simple-v extension).
14
15 therefore this code walks the instruction implementations
16 in riscv/insns/*.h looking for register usage patterns.
17 the resultant table can be used *prior* to the emulation,
18 without having to manually maintain such a table.
19 """
20
21 import os
22 import sys
23
24 insns_dir = "./riscv/insns"
25 def list_insns():
26 if len(sys.argv) == 2:
27 fullfname = sys.argv[1]
28 pth, fname = os.path.split(fullfname)
29 insn = fname[:-2]
30 return [(fullfname, insn)]
31
32 res = []
33 for fname in os.listdir(insns_dir):
34 if not fname.endswith(".h"):
35 continue
36 if fname.startswith("regs_"):
37 continue
38 insn = fname[:-2]
39 res.append((os.path.join(insns_dir, fname), insn))
40 return res
41
42 cintpatterns = [ 'WRITE_RVC_RS1S', 'WRITE_RVC_RS2S',
43 'RVC_RS1', 'RVC_RS2', 'RVC_RS1S', 'RVC_RS2S', ]
44 cfloatpatterns = [ 'WRITE_RVC_FRS2S', 'RVC_FRS2 ', 'RVC_FRS2S ']
45 intpatterns = ['WRITE_RD' , 'RS1', 'RS2', 'RS3']
46 floatpatterns = ['WRITE_FRD', 'FRS1', 'FRS2', 'FRS3']
47 patterns = intpatterns + floatpatterns
48 patterns += cintpatterns
49 patterns += cfloatpatterns
50
51 allfloats = floatpatterns + cfloatpatterns
52 floatmask = (1<<len(allfloats)-1)
53 allints = intpatterns + cintpatterns[2:]
54
55 skip = '#define USING_NOREGS\n' \
56 '#define REGS_PATTERN 0x0\n'
57
58 # this matches the order of the 4 predication arguments to
59 drlookup = { 'rd': 0, 'frd': 0, 'rs1': 1, 'rs2': 2, 'rs3': 3,
60 'rvc_rs1': 1, 'rvc_rs1s': 1,
61 'rvc_rs2': 2, 'rvc_rs2s': 2,
62 'rvc_frs2': 2, 'rvc_frs2s': 2,
63 }
64
65 def find_registers(fname, twin_predication):
66 # HACK! macro-skipping of instructions too painful
67 for notparallel in ['csr', 'lui', 'c_j', 'wfi', 'auipc',
68 'dret', 'uret', 'mret', 'sret',
69 'lr_d', 'lr_w', 'sc_d', 'sc_w']:
70 if notparallel in fname:
71 return skip
72 res = []
73 regs = []
74 isintfloat = 0x0 + floatmask << len(allints)
75 with open(fname) as f:
76 f = f.read()
77 dest_reg = None
78 for pattern in patterns:
79 x = f.find(pattern)
80 if x == -1:
81 continue
82 if pattern.startswith('R') and x != 0 and f[x-1] == 'F':
83 # botch-job/hack: RS1 also matches against FRS1 (etc.)
84 # check letter before match: if "F", skip it.
85 continue
86 if pattern.startswith('R') and x != 0 and f[x-1] == '_':
87 # RS1 also matches against RVC_RS1 (etc.)
88 # check letter before match: if "_", skip it.
89 continue
90 if pattern.startswith('FR') and x != 0 and f[x-1] == '_':
91 # RS1 also matches against RVC_FRS1 (etc.)
92 # check letter before match: if "_", skip it.
93 continue
94 if 'RVC_' in pattern and f[x+len(pattern)] == 'S':
95 # RVC_RS2S also matches against RVC_RS2 (etc.)
96 # check letter at end of match: if "S", skip it.
97 continue
98 p = pattern
99 if p.startswith('WRITE_'):
100 p = p[6:]
101 dest_reg = p
102 if pattern in allints:
103 idx = allints.index(pattern)
104 isintfloat += 1 << idx
105 if pattern in allfloats:
106 idx = allfloats.index(pattern)
107 isintfloat &= ~(1 << (idx+len(allints)))
108 regs.append(p)
109 res.append('#define USING_REG_%s' % p)
110 if dest_reg:
111 dr = dest_reg
112 fdest = False
113 if dest_reg.startswith('RVC_F'):
114 fdest = True
115 dr = 'RVC_' + dest_reg[5:]
116 if dest_reg == 'FRD':
117 fdest = True
118 dr = 'RD'
119 dridx = drlookup[dest_reg.lower()]
120 res.append('#define DEST_REG %s' % dr.lower())
121 res.append('#define _DEST_REG _%s' % dr.lower())
122 res.append('#define DEST_PREDINT %d' % (0 if fdest else 1))
123 if not res:
124 return skip
125 res.append('#define REGS_PATTERN 0x%x' % isintfloat)
126
127 predargs = ['dest_pred'] * 4
128 if twin_predication:
129 found = None
130 for search in ['rs1', 'rs2', 'rs3', 'rvc_rs1', 'rvc_rs1s',
131 'rvc_rs2', 'rvc_rs2s',
132 'frs1', 'frs2', 'frs3',
133 'rvc_frs2', 'rvc_frs2s']:
134 if search.upper() in regs:
135 found = search
136 if found:
137 predargs[drlookup[found]] = 'src_pred'
138 fsrc = 'f' in found
139 found = found.replace('f', '')
140 res.append('#define SRC_PREDINT %d' % (0 if fsrc else 1))
141 res.append('#define SRC_REG %s' % found)
142
143 res.append('#define PRED_ARGS %s' % ','.join(predargs))
144
145 return '\n'.join(res)
146
147 if __name__ == '__main__':
148 files = list_insns()
149 for (fname, insn) in files:
150 regsname = "regs_%s.h" % insn
151 regsname = os.path.join(insns_dir, regsname)
152 twin_predication = False
153 with open(regsname, "w") as f:
154 txt = "\n#define INSN_%s\n" % insn.upper()
155 # help identify type of register
156 if insn in ['beq', 'bne', 'blt', 'bltu', 'bge', 'bgeu']:
157 txt += "#define INSN_TYPE_BRANCH\n"
158 if insn in ['lb', 'lbu', 'lw', 'lwu', 'ld', 'ldu']:
159 twin_predication = True
160 txt += "#define INSN_TYPE_LOAD\n"
161 elif insn in ['c_lwsp', 'c_ldsp', 'c_lqsp', 'c_flwsp', 'c_fldsp']:
162 txt += "\n#define INSN_TYPE_C_STACK_LD\n"
163 elif insn in ['c_swsp', 'c_sdsp', 'c_sqsp', 'c_fswsp', 'c_fsdsp']:
164 txt += "\n#define INSN_TYPE_C_STACK_ST\n"
165 elif insn in ['c_lw', 'c_ld', 'c_lq', 'c_flw', 'c_fld']:
166 txt += "\n#define INSN_TYPE_C_LD\n"
167 twin_predication = True
168 elif insn in ['c_sw', 'c_sd', 'c_sq', 'c_fsw', 'c_fsd']:
169 txt += "\n#define INSN_TYPE_C_ST\n"
170 twin_predication = True
171 elif insn in ['c_beqz', 'c_bnez']:
172 txt += "\n#define INSN_TYPE_C_BRANCH\n"
173 elif insn in ['c_mv']:
174 twin_predication = True
175 elif insn.startswith("c_"):
176 txt += "#define INSN_TYPE_C\n"
177 elif insn.startswith("fmv") or \
178 insn.startswith("fcvt") or \
179 insn.startswith("fsgn"):
180 txt += "#define INSN_TYPE_FP_DUALOP\n"
181 elif insn.startswith("feq") or \
182 insn.startswith("flt") or \
183 insn.startswith("fle"):
184 txt += "#define INSN_TYPE_FP_BRANCH\n"
185 if twin_predication:
186 txt += "\n#define INSN_CATEGORY_TWINPREDICATION\n"
187 txt += find_registers(fname, twin_predication)
188 f.write(txt)