add in twin-predication identification
[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 def find_registers(fname):
58 # HACK! macro-skipping of instructions too painful
59 for notparallel in ['csr', 'lui', 'c_j', 'wfi', 'auipc',
60 'dret', 'uret', 'mret', 'sret',
61 'lr_d', 'lr_w', 'sc_d', 'sc_w']:
62 if notparallel in fname:
63 return skip
64 res = []
65 isintfloat = 0x0 + floatmask << len(allints)
66 with open(fname) as f:
67 f = f.read()
68 for pattern in patterns:
69 x = f.find(pattern)
70 if x == -1:
71 continue
72 if pattern.startswith('R') and x != 0 and f[x-1] == 'F':
73 # botch-job/hack: RS1 also matches against FRS1 (etc.)
74 # check letter before match: if "F", skip it.
75 continue
76 if pattern.startswith('R') and x != 0 and f[x-1] == '_':
77 # RS1 also matches against RVC_RS1 (etc.)
78 # check letter before match: if "_", skip it.
79 continue
80 if pattern.startswith('FR') and x != 0 and f[x-1] == '_':
81 # RS1 also matches against RVC_FRS1 (etc.)
82 # check letter before match: if "_", skip it.
83 continue
84 if 'RVC_' in pattern and f[x+len(pattern)] == 'S':
85 # RVC_RS2S also matches against RVC_RS2 (etc.)
86 # check letter at end of match: if "S", skip it.
87 continue
88 p = pattern
89 if p.startswith('WRITE_'):
90 p = p[6:]
91 if pattern in allints:
92 idx = allints.index(pattern)
93 isintfloat += 1 << idx
94 if pattern in allfloats:
95 idx = allfloats.index(pattern)
96 isintfloat &= ~(1 << (idx+len(allints)))
97 res.append('#define USING_REG_%s' % p)
98 if not res:
99 return skip
100 res.append('#define REGS_PATTERN 0x%x' % isintfloat)
101 return '\n'.join(res)
102
103 if __name__ == '__main__':
104 files = list_insns()
105 for (fname, insn) in files:
106 regsname = "regs_%s.h" % insn
107 regsname = os.path.join(insns_dir, regsname)
108 twin_predication = False
109 with open(regsname, "w") as f:
110 txt = find_registers(fname)
111 txt += "\n#define INSN_%s\n" % insn.upper()
112 # help identify type of register
113 if insn in ['beq', 'bne', 'blt', 'bltu', 'bge', 'bgeu']:
114 txt += "#define INSN_TYPE_BRANCH\n"
115 if insn in ['lb', 'lbu', 'lw', 'lwu', 'ld', 'ldu']:
116 twin_predication = True
117 txt += "#define INSN_TYPE_LOAD\n"
118 elif insn in ['c_lwsp', 'c_ldsp', 'c_lqsp', 'c_flwsp', 'c_fldsp']:
119 txt += "\n#define INSN_TYPE_C_STACK_LD\n"
120 elif insn in ['c_swsp', 'c_sdsp', 'c_sqsp', 'c_fswsp', 'c_fsdsp']:
121 txt += "\n#define INSN_TYPE_C_STACK_ST\n"
122 elif insn in ['c_lw', 'c_ld', 'c_lq', 'c_flw', 'c_fld']:
123 txt += "\n#define INSN_TYPE_C_LD\n"
124 twin_predication = True
125 elif insn in ['c_sw', 'c_sd', 'c_sq', 'c_fsw', 'c_fsd']:
126 txt += "\n#define INSN_TYPE_C_ST\n"
127 twin_predication = True
128 elif insn in ['c_beqz', 'c_bnez']:
129 txt += "\n#define INSN_TYPE_C_BRANCH\n"
130 elif insn in ['c_mv']:
131 twin_predication = True
132 elif insn.startswith("c_"):
133 txt += "#define INSN_TYPE_C\n"
134 elif insn.startswith("fmv") or \
135 insn.startswith("fcvt") or \
136 insn.startswith("fsgn"):
137 txt += "#define INSN_TYPE_FP_DUALOP\n"
138 elif insn.startswith("feq") or \
139 insn.startswith("flt") or \
140 insn.startswith("fle"):
141 txt += "#define INSN_TYPE_FP_BRANCH\n"
142 if twin_predication:
143 txt += "\n#define INSN_CATEGORY_TWINPREDICATION\n"
144 f.write(txt)