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
, insn
, twin_predication
, immed_offset
, is_branch
):
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 'c_addi4spn', 'c_addi16sp']:
71 if notparallel
in fname
:
75 isintfloat
= 0x0 + floatmask
<< len(allints
)
76 with
open(fname
) as f
:
79 for pattern
in patterns
:
83 if pattern
.startswith('R') and x
!= 0 and f
[x
-1] == 'F':
84 # botch-job/hack: RS1 also matches against FRS1 (etc.)
85 # check letter before match: if "F", skip it.
87 if pattern
.startswith('R') and x
!= 0 and f
[x
-1] == '_':
88 # RS1 also matches against RVC_RS1 (etc.)
89 # check letter before match: if "_", skip it.
91 if pattern
.startswith('FR') and x
!= 0 and f
[x
-1] == '_':
92 # RS1 also matches against RVC_FRS1 (etc.)
93 # check letter before match: if "_", skip it.
95 if 'RVC_' in pattern
and f
[x
+len(pattern
)] == 'S':
96 # RVC_RS2S also matches against RVC_RS2 (etc.)
97 # check letter at end of match: if "S", skip it.
100 if p
.startswith('WRITE_'):
103 if pattern
in allints
:
104 idx
= allints
.index(pattern
)
105 isintfloat
+= 1 << idx
106 if pattern
in allfloats
:
107 idx
= allfloats
.index(pattern
)
108 isintfloat
&= ~
(1 << (idx
+len(allints
)))
110 res
.append('#define USING_REG_%s' % p
)
114 if dest_reg
.startswith('RVC_F'):
116 dr
= 'RVC_' + dest_reg
[5:]
117 if dest_reg
== 'FRD':
120 dridx
= drlookup
[dest_reg
.lower()]
121 res
.append('#define DEST_REG %s' % dr
.lower())
122 res
.append('#define _DEST_REG _%s' % dr
.lower())
123 res
.append('#define DEST_PREDINT %d' % (0 if fdest
else 1))
126 res
.append('#define REGS_PATTERN 0x%x' % isintfloat
)
128 predargs
= ['dest_pred'] * 4
129 if immed_offset
: # C.LWSP
130 if immed_offset
== 'LD':
131 predargs
.append('&src_pred')
133 predargs
.append('&dest_pred')
134 fsrc
= insn
in ['c_flwsp', 'c_fldsp']
135 c_sp_width
= {'c_lwsp': 4, 'c_ldsp': 8, 'c_lqsp': 16,
136 'c_flwsp': 4, 'c_fldsp': 8,
137 'c_swsp': 4, 'c_sdsp': 8, 'c_sqsp': 16,
138 'c_fswsp': 4, 'c_fsdsp': 8}
139 iwidth
= c_sp_width
[insn
]
140 res
.append('#define IMMEDWIDTH %d' % (iwidth
))
141 if immed_offset
== 'LD':
142 res
.append('#define SRC_PREDINT %d' % (0 if fsrc
else 1))
144 res
.append('#define DEST_PREDINT %d' % (0 if fsrc
else 1))
148 for search
in ['rs1', 'rs2', 'rs3', 'rvc_rs1', 'rvc_rs1s',
149 'rvc_rs2', 'rvc_rs2s',
150 'frs1', 'frs2', 'frs3',
151 'rvc_frs2', 'rvc_frs2s']:
152 if search
.upper() in regs
:
155 predargs
[drlookup
[found
]] = 'src_pred'
157 found
= found
.replace('f', '')
158 res
.append('#define SRC_PREDINT %d' % (0 if fsrc
else 1))
159 res
.append('#define SRC_REG %s' % found
)
161 if len(predargs
) == 4:
162 predargs
.append('NULL')
164 res
.append('#define PRED_ARGS %s' % ','.join(predargs
))
166 for i
in range(len(predargs
)):
167 offsargs
.append(predargs
[i
].replace('pred', 'offs').replace("&", ''))
168 res
.append('#define OFFS_ARGS %s' % ','.join(offsargs
))
170 return '\n'.join(res
)
172 if __name__
== '__main__':
174 for (fname
, insn
) in files
:
175 regsname
= "regs_%s.h" % insn
176 regsname
= os
.path
.join(insns_dir
, regsname
)
177 twin_predication
= False
180 with
open(regsname
, "w") as f
:
181 txt
= "\n#define INSN_%s\n" % insn
.upper()
182 # help identify type of register
183 if insn
in ['beq', 'bne', 'blt', 'bltu', 'bge', 'bgeu']:
184 txt
+= "#define INSN_TYPE_BRANCH\n"
185 is_branch
= 'STD' # standard branch
186 if insn
in ['lb', 'lbu', 'lw', 'lwu', 'ld', 'ldu']:
187 twin_predication
= True
188 txt
+= "#define INSN_TYPE_LOAD\n"
189 elif insn
in ['c_lwsp', 'c_ldsp', 'c_lqsp', 'c_flwsp', 'c_fldsp']:
190 twin_predication
= True
192 txt
+= "\n#define INSN_TYPE_C_STACK_LD\n"
193 elif insn
in ['c_swsp', 'c_sdsp', 'c_sqsp', 'c_fswsp', 'c_fsdsp']:
194 twin_predication
= True
196 txt
+= "\n#define INSN_TYPE_C_STACK_ST\n"
197 elif insn
in ['c_lw', 'c_ld', 'c_lq', 'c_flw', 'c_fld']:
198 txt
+= "\n#define INSN_TYPE_C_LD\n"
199 twin_predication
= True
200 elif insn
in ['c_sw', 'c_sd', 'c_sq', 'c_fsw', 'c_fsd']:
201 txt
+= "\n#define INSN_TYPE_C_ST\n"
202 twin_predication
= True
203 elif insn
in ['c_beqz', 'c_bnez']:
204 txt
+= "\n#define INSN_TYPE_C_BRANCH\n"
205 elif insn
in ['c_mv']:
206 twin_predication
= True
207 elif insn
.startswith("c_"):
208 txt
+= "#define INSN_TYPE_C\n"
209 elif insn
.startswith("fmv") or \
210 insn
.startswith("fcvt") or \
211 insn
.startswith("fsgn"):
212 txt
+= "#define INSN_TYPE_FP_DUALOP\n"
213 elif insn
.startswith("feq") or \
214 insn
.startswith("flt") or \
215 insn
.startswith("fle"):
216 txt
+= "#define INSN_TYPE_FP_BRANCH\n"
218 txt
+= "\n#define INSN_CATEGORY_TWINPREDICATION\n"
219 txt
+= find_registers(fname
, insn
, twin_predication
,
220 immed_offset
, is_branch
)