2 # Copyright (C) 2018 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 """ identify registers used in riscv/insns/*.h and create code
5 that can be used in spike at runtime
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.
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).
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.
24 insns_dir
= "./riscv/insns"
26 if len(sys
.argv
) == 2:
27 fullfname
= sys
.argv
[1]
28 pth
, fname
= os
.path
.split(fullfname
)
30 return [(fullfname
, insn
)]
33 for fname
in os
.listdir(insns_dir
):
34 if not fname
.endswith(".h"):
36 if fname
.startswith("regs_"):
39 res
.append((os
.path
.join(insns_dir
, fname
), insn
))
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
51 allfloats
= floatpatterns
+ cfloatpatterns
52 floatmask
= (1<<len(allfloats
)-1)
53 allints
= intpatterns
+ cintpatterns
[2:]
55 skip
= '#define USING_NOREGS\n' \
56 '#define REGS_PATTERN 0x0\n'
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,
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
:
74 isintfloat
= 0x0 + floatmask
<< len(allints
)
75 with
open(fname
) as f
:
78 for pattern
in patterns
:
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.
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.
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.
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.
99 if p
.startswith('WRITE_'):
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
)))
109 res
.append('#define USING_REG_%s' % p
)
113 if dest_reg
.startswith('RVC_F'):
115 dr
= 'RVC_' + dest_reg
[5:]
116 if dest_reg
== 'FRD':
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))
125 res
.append('#define REGS_PATTERN 0x%x' % isintfloat
)
127 predargs
= ['dest_pred'] * 4
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
:
137 predargs
[drlookup
[found
]] = 'src_pred'
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
)
143 res
.append('#define PRED_ARGS %s' % ','.join(predargs
))
146 offsargs
.append(predargs
[i
].replace('pred', 'offs'))
147 res
.append('#define OFFS_ARGS %s' % ','.join(offsargs
))
149 return '\n'.join(res
)
151 if __name__
== '__main__':
153 for (fname
, insn
) in files
:
154 regsname
= "regs_%s.h" % insn
155 regsname
= os
.path
.join(insns_dir
, regsname
)
156 twin_predication
= False
157 with
open(regsname
, "w") as f
:
158 txt
= "\n#define INSN_%s\n" % insn
.upper()
159 # help identify type of register
160 if insn
in ['beq', 'bne', 'blt', 'bltu', 'bge', 'bgeu']:
161 txt
+= "#define INSN_TYPE_BRANCH\n"
162 if insn
in ['lb', 'lbu', 'lw', 'lwu', 'ld', 'ldu']:
163 twin_predication
= True
164 txt
+= "#define INSN_TYPE_LOAD\n"
165 elif insn
in ['c_lwsp', 'c_ldsp', 'c_lqsp', 'c_flwsp', 'c_fldsp']:
166 txt
+= "\n#define INSN_TYPE_C_STACK_LD\n"
167 elif insn
in ['c_swsp', 'c_sdsp', 'c_sqsp', 'c_fswsp', 'c_fsdsp']:
168 txt
+= "\n#define INSN_TYPE_C_STACK_ST\n"
169 elif insn
in ['c_lw', 'c_ld', 'c_lq', 'c_flw', 'c_fld']:
170 txt
+= "\n#define INSN_TYPE_C_LD\n"
171 twin_predication
= True
172 elif insn
in ['c_sw', 'c_sd', 'c_sq', 'c_fsw', 'c_fsd']:
173 txt
+= "\n#define INSN_TYPE_C_ST\n"
174 twin_predication
= True
175 elif insn
in ['c_beqz', 'c_bnez']:
176 txt
+= "\n#define INSN_TYPE_C_BRANCH\n"
177 elif insn
in ['c_mv']:
178 twin_predication
= True
179 elif insn
.startswith("c_"):
180 txt
+= "#define INSN_TYPE_C\n"
181 elif insn
.startswith("fmv") or \
182 insn
.startswith("fcvt") or \
183 insn
.startswith("fsgn"):
184 txt
+= "#define INSN_TYPE_FP_DUALOP\n"
185 elif insn
.startswith("feq") or \
186 insn
.startswith("flt") or \
187 insn
.startswith("fle"):
188 txt
+= "#define INSN_TYPE_FP_BRANCH\n"
190 txt
+= "\n#define INSN_CATEGORY_TWINPREDICATION\n"
191 txt
+= find_registers(fname
, twin_predication
)