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'
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
:
65 isintfloat
= 0x0 + floatmask
<< len(allints
)
66 with
open(fname
) as f
:
68 for pattern
in patterns
:
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.
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.
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.
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.
89 if p
.startswith('WRITE_'):
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
)
100 res
.append('#define REGS_PATTERN 0x%x' % isintfloat
)
101 return '\n'.join(res
)
103 if __name__
== '__main__':
105 for (fname
, insn
) in files
:
106 regsname
= "regs_%s.h" % insn
107 regsname
= os
.path
.join(insns_dir
, regsname
)
108 with
open(regsname
, "w") as f
:
109 txt
= find_registers(fname
)
110 txt
+= "\n#define INSN_%s\n" % insn
.upper()
111 # help identify type of register
112 if insn
in ['beq', 'bne', 'blt', 'bltu', 'bge', 'bgeu']:
113 txt
+= "#define INSN_TYPE_BRANCH\n"
114 elif insn
in ['c_ld', 'c_bnez']:
115 txt
+= "\n#define INSN_TYPE_C_BRANCH\n"
116 elif insn
in ['c_lwsp', 'c_ldsp', 'c_lqsp', 'c_flwsp', 'c_fldsp']:
117 txt
+= "\n#define INSN_TYPE_C_STACK_LD\n"
118 elif insn
in ['c_swsp', 'c_sdsp', 'c_sqsp', 'c_fswsp', 'c_fsdsp']:
119 txt
+= "\n#define INSN_TYPE_C_STACK_ST\n"
120 elif insn
in ['c_lw', 'c_ld', 'c_lq', 'c_flw', 'c_fld']:
121 txt
+= "\n#define INSN_TYPE_C_LD\n"
122 elif insn
in ['c_sw', 'c_sd', 'c_sq', 'c_fsw', 'c_fsd']:
123 txt
+= "\n#define INSN_TYPE_C_ST\n"
124 elif insn
in ['c_beqz', 'c_bnez']:
125 txt
+= "\n#define INSN_TYPE_C_BRANCH\n"
126 elif insn
.startswith("c_"):
127 txt
+= "#define INSN_TYPE_C\n"
128 elif insn
.startswith("fmv") or \
129 insn
.startswith("fcvt") or \
130 insn
.startswith("fsgn"):
131 txt
+= "#define INSN_TYPE_FP_DUALOP\n"
132 elif insn
.startswith("feq") or \
133 insn
.startswith("flt") or \
134 insn
.startswith("fle"):
135 txt
+= "#define INSN_TYPE_FP_BRANCH\n"