avl-riscv-coverage 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- avl_riscv_coverage/__init__.py +24 -0
- avl_riscv_coverage/__main__.py +185 -0
- avl_riscv_coverage/_coverage.py +32 -0
- avl_riscv_coverage/_elf.py +154 -0
- avl_riscv_coverage/_instr.py +78 -0
- avl_riscv_coverage/_isa.py +523 -0
- avl_riscv_coverage/_spike.py +54 -0
- avl_riscv_coverage/_trace.py +54 -0
- avl_riscv_coverage/coverage_packages/_compression.py +23 -0
- avl_riscv_coverage/coverage_packages/_jump.py +40 -0
- avl_riscv_coverage/coverage_packages/_opcodes.py +25 -0
- avl_riscv_coverage/instr_dict.json +15741 -0
- avl_riscv_coverage-0.0.1.dist-info/METADATA +177 -0
- avl_riscv_coverage-0.0.1.dist-info/RECORD +17 -0
- avl_riscv_coverage-0.0.1.dist-info/WHEEL +4 -0
- avl_riscv_coverage-0.0.1.dist-info/entry_points.txt +3 -0
- avl_riscv_coverage-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
ISA: dict[str, Encoding] = {}
|
|
6
|
+
"""
|
|
7
|
+
Dictionary of all instruction encodings based on the reference instr_dict.json.
|
|
8
|
+
Filtered based on supported base and extensions
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
class Encoding:
|
|
12
|
+
|
|
13
|
+
# Integer Registers
|
|
14
|
+
_int_regs_ : list[str] = [
|
|
15
|
+
'zero', 'ra', 'sp', 'gp', 'tp', 't0', 't1', 't2',
|
|
16
|
+
's0', 's1', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5',
|
|
17
|
+
'a6', 'a7', 's2', 's3', 's4', 's5', 's6', 's7',
|
|
18
|
+
's8', 's9', 's10', 's11', 't3', 't4', 't5', 't6'
|
|
19
|
+
]
|
|
20
|
+
"""List of ABI integer registers"""
|
|
21
|
+
|
|
22
|
+
# Floating-Point Registers
|
|
23
|
+
_fp_regs_ : list[str]= [
|
|
24
|
+
'ft0', 'ft1', 'ft2', 'ft3', 'ft4', 'ft5', 'ft6', 'ft7',
|
|
25
|
+
'fs0', 'fs1', 'fa0', 'fa1', 'fa2', 'fa3', 'fa4', 'fa5',
|
|
26
|
+
'fa6', 'fa7', 'fs2', 'fs3', 'fs4', 'fs5', 'fs6', 'fs7',
|
|
27
|
+
'fs8', 'fs9', 'fs10', 'fs11', 'ft8', 'ft9', 'ft10', 'ft11'
|
|
28
|
+
]
|
|
29
|
+
"""List of ABI floating point registers"""
|
|
30
|
+
|
|
31
|
+
# Additional register categorization
|
|
32
|
+
_compressed_regs_ = [
|
|
33
|
+
# Both integer and FP compressed registers
|
|
34
|
+
'rd_p',
|
|
35
|
+
'rs1_p',
|
|
36
|
+
'rs2_p',
|
|
37
|
+
'rd_rs1_p',
|
|
38
|
+
'c_sreg1',
|
|
39
|
+
'c_sreg2',
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
_full_width_regs_ = [
|
|
43
|
+
# All full 5-bit registers (integer, FP, vector)
|
|
44
|
+
'rd',
|
|
45
|
+
'rs1',
|
|
46
|
+
'rs2',
|
|
47
|
+
'rs3',
|
|
48
|
+
'rd_n0',
|
|
49
|
+
'rs1_n0',
|
|
50
|
+
'rd_rs1_n0',
|
|
51
|
+
'rd_n2',
|
|
52
|
+
'c_rs1_n0',
|
|
53
|
+
'c_rs2',
|
|
54
|
+
'c_rs2_n0',
|
|
55
|
+
'vd',
|
|
56
|
+
'vs1',
|
|
57
|
+
'vs2',
|
|
58
|
+
'vs3',
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
# Signed Immediates
|
|
62
|
+
_signed_imms_ = [
|
|
63
|
+
# Standard signed immediates
|
|
64
|
+
'imm12',
|
|
65
|
+
'imm12hi', # S-type split (needs reconstruction)
|
|
66
|
+
'imm12lo', # S-type split (needs reconstruction)
|
|
67
|
+
'imm20', # U-type (technically unsigned but often treated as signed)
|
|
68
|
+
'imm5', # 5-bit signed
|
|
69
|
+
'bimm12hi', # B-type split (needs reconstruction)
|
|
70
|
+
'bimm12lo', # B-type split (needs reconstruction)
|
|
71
|
+
'jimm20', # J-type (needs special reconstruction)
|
|
72
|
+
|
|
73
|
+
# Compressed signed immediates
|
|
74
|
+
'c_imm12',
|
|
75
|
+
'c_imm6hi', # Split (needs reconstruction)
|
|
76
|
+
'c_imm6lo', # Split (needs reconstruction)
|
|
77
|
+
'c_nzimm6hi', # Split non-zero (needs reconstruction)
|
|
78
|
+
'c_nzimm6lo', # Split non-zero (needs reconstruction)
|
|
79
|
+
'c_nzimm10hi', # Split (needs reconstruction)
|
|
80
|
+
'c_nzimm10lo', # Split (needs reconstruction)
|
|
81
|
+
'c_nzimm18hi', # Split LUI (needs reconstruction)
|
|
82
|
+
'c_nzimm18lo', # Split LUI (needs reconstruction)
|
|
83
|
+
'c_bimm9hi', # Split branch (needs reconstruction)
|
|
84
|
+
'c_bimm9lo', # Split branch (needs reconstruction)
|
|
85
|
+
|
|
86
|
+
# Vector signed immediate
|
|
87
|
+
'simm5',
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# Unsigned Immediates
|
|
91
|
+
_unsigned_imms_ = [
|
|
92
|
+
# Shift amounts
|
|
93
|
+
'shamtw', # 5-bit word shift
|
|
94
|
+
'shamtd', # 6-bit double-word shift
|
|
95
|
+
'bs', # Bit select position
|
|
96
|
+
|
|
97
|
+
# CSR
|
|
98
|
+
'csr', # 12-bit CSR address
|
|
99
|
+
|
|
100
|
+
# Fence
|
|
101
|
+
'pred', # Fence predecessor
|
|
102
|
+
'succ', # Fence successor
|
|
103
|
+
'fm', # Fence mode
|
|
104
|
+
|
|
105
|
+
# Atomic
|
|
106
|
+
'aq', # Acquire bit
|
|
107
|
+
'rl', # Release bit
|
|
108
|
+
|
|
109
|
+
# Floating-point
|
|
110
|
+
'rm', # Rounding mode
|
|
111
|
+
|
|
112
|
+
# Bit manipulation
|
|
113
|
+
'rnum', # Rotate amount
|
|
114
|
+
|
|
115
|
+
# Vector unsigned immediates
|
|
116
|
+
'zimm5',
|
|
117
|
+
'zimm6hi', # Split (needs reconstruction)
|
|
118
|
+
'zimm6lo', # Split (needs reconstruction)
|
|
119
|
+
'zimm10',
|
|
120
|
+
'zimm11',
|
|
121
|
+
'vm', # Vector mask bit
|
|
122
|
+
|
|
123
|
+
# Compressed unsigned immediates
|
|
124
|
+
'c_nzuimm6hi', # Split (needs reconstruction)
|
|
125
|
+
'c_nzuimm6lo', # Split (needs reconstruction)
|
|
126
|
+
'c_nzuimm10',
|
|
127
|
+
'c_uimm1',
|
|
128
|
+
'c_uimm2',
|
|
129
|
+
'c_uimm7hi', # Split (needs reconstruction)
|
|
130
|
+
'c_uimm7lo', # Split (needs reconstruction)
|
|
131
|
+
'c_uimm8hi', # Split (needs reconstruction)
|
|
132
|
+
'c_uimm8lo', # Split (needs reconstruction)
|
|
133
|
+
'c_uimm8sp_s',
|
|
134
|
+
'c_uimm8sphi', # Split (needs reconstruction)
|
|
135
|
+
'c_uimm8splo', # Split (needs reconstruction)
|
|
136
|
+
'c_uimm9sp_s',
|
|
137
|
+
'c_uimm9sphi', # Split (needs reconstruction)
|
|
138
|
+
'c_uimm9splo', # Split (needs reconstruction)
|
|
139
|
+
'c_spimm', # Zcmp stack pointer immediate
|
|
140
|
+
'c_rlist', # Zcmp register list (encoded value)
|
|
141
|
+
'c_index', # Custom/extension index
|
|
142
|
+
|
|
143
|
+
# Memory operation types (custom/Zacas)
|
|
144
|
+
'c_mop_t',
|
|
145
|
+
'mop_r_t_21_20',
|
|
146
|
+
'mop_r_t_27_26',
|
|
147
|
+
'mop_r_t_30',
|
|
148
|
+
'mop_rr_t_27_26',
|
|
149
|
+
'mop_rr_t_30',
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
# Split immediates that need reconstruction
|
|
153
|
+
_split_immediates_ = {
|
|
154
|
+
# Format: 'combined_name': ['hi_part', 'lo_part']
|
|
155
|
+
'imm12': ['imm12hi', 'imm12lo'], # S-type store
|
|
156
|
+
'bimm12': ['bimm12hi', 'bimm12lo'], # B-type branch
|
|
157
|
+
'c_imm6': ['c_imm6hi', 'c_imm6lo'],
|
|
158
|
+
'c_nzimm6': ['c_nzimm6hi', 'c_nzimm6lo'],
|
|
159
|
+
'c_nzimm10': ['c_nzimm10hi', 'c_nzimm10lo'],
|
|
160
|
+
'c_nzimm18': ['c_nzimm18hi', 'c_nzimm18lo'],
|
|
161
|
+
'c_bimm9': ['c_bimm9hi', 'c_bimm9lo'],
|
|
162
|
+
'c_nzuimm6': ['c_nzuimm6hi', 'c_nzuimm6lo'],
|
|
163
|
+
'c_uimm7': ['c_uimm7hi', 'c_uimm7lo'],
|
|
164
|
+
'c_uimm8': ['c_uimm8hi', 'c_uimm8lo'],
|
|
165
|
+
'c_uimm8sp': ['c_uimm8sphi', 'c_uimm8splo'],
|
|
166
|
+
'c_uimm9sp': ['c_uimm9sphi', 'c_uimm9splo'],
|
|
167
|
+
'zimm6': ['zimm6hi', 'zimm6lo'], # Vector
|
|
168
|
+
}
|
|
169
|
+
_field_positions_ = {
|
|
170
|
+
# Atomic memory ordering
|
|
171
|
+
'aq': (26, 26),
|
|
172
|
+
'rl': (25, 25),
|
|
173
|
+
|
|
174
|
+
# Branch immediates (split)
|
|
175
|
+
'bimm12hi': (31, 25),
|
|
176
|
+
'bimm12lo': (11, 7),
|
|
177
|
+
|
|
178
|
+
# Bit manipulation
|
|
179
|
+
'bs': (25, 20),
|
|
180
|
+
|
|
181
|
+
# Compressed branch immediate (split)
|
|
182
|
+
'c_bimm9hi': (12, 10),
|
|
183
|
+
'c_bimm9lo': (6, 2),
|
|
184
|
+
|
|
185
|
+
# Compressed jump immediate
|
|
186
|
+
'c_imm12': (12, 2),
|
|
187
|
+
|
|
188
|
+
# Compressed signed immediate (split)
|
|
189
|
+
'c_imm6hi': (12, 12),
|
|
190
|
+
'c_imm6lo': (6, 2),
|
|
191
|
+
|
|
192
|
+
# Compressed custom fields
|
|
193
|
+
'c_index': (12, 10), # Adjust as needed for your extension
|
|
194
|
+
'c_mop_t': (12, 10), # Adjust as needed for your extension
|
|
195
|
+
|
|
196
|
+
# Compressed non-zero signed immediate (split)
|
|
197
|
+
'c_nzimm10hi': (12, 12),
|
|
198
|
+
'c_nzimm10lo': (6, 2),
|
|
199
|
+
|
|
200
|
+
# Compressed non-zero LUI immediate (split)
|
|
201
|
+
'c_nzimm18hi': (12, 12),
|
|
202
|
+
'c_nzimm18lo': (6, 2),
|
|
203
|
+
|
|
204
|
+
# Compressed non-zero 6-bit signed immediate (split)
|
|
205
|
+
'c_nzimm6hi': (12, 12),
|
|
206
|
+
'c_nzimm6lo': (6, 2),
|
|
207
|
+
|
|
208
|
+
# Compressed non-zero unsigned immediate
|
|
209
|
+
'c_nzuimm10': (12, 2),
|
|
210
|
+
|
|
211
|
+
# Compressed non-zero unsigned 6-bit immediate (split)
|
|
212
|
+
'c_nzuimm6hi': (12, 12),
|
|
213
|
+
'c_nzuimm6lo': (6, 2),
|
|
214
|
+
|
|
215
|
+
# Compressed register list
|
|
216
|
+
'c_rlist': (7, 4), # Adjust as needed for Zcmp
|
|
217
|
+
|
|
218
|
+
# Compressed registers (non-zero)
|
|
219
|
+
'c_rs1_n0': (11, 7),
|
|
220
|
+
'c_rs2': (6, 2),
|
|
221
|
+
'c_rs2_n0': (6, 2),
|
|
222
|
+
|
|
223
|
+
# Compressed stack pointer immediate
|
|
224
|
+
'c_spimm': (12, 2), # Adjust as needed for Zcmp
|
|
225
|
+
|
|
226
|
+
# Compressed save/restore registers
|
|
227
|
+
'c_sreg1': (9, 7), # Adjust as needed for Zcmp
|
|
228
|
+
'c_sreg2': (4, 2), # Adjust as needed for Zcmp
|
|
229
|
+
|
|
230
|
+
# Compressed small unsigned immediates
|
|
231
|
+
'c_uimm1': (12, 12), # Single bit
|
|
232
|
+
'c_uimm2': (6, 5), # 2 bits
|
|
233
|
+
|
|
234
|
+
# Compressed unsigned 7-bit immediate (split)
|
|
235
|
+
'c_uimm7hi': (12, 12),
|
|
236
|
+
'c_uimm7lo': (6, 2),
|
|
237
|
+
|
|
238
|
+
# Compressed unsigned 8-bit immediate (split)
|
|
239
|
+
'c_uimm8hi': (12, 10),
|
|
240
|
+
'c_uimm8lo': (6, 2),
|
|
241
|
+
|
|
242
|
+
# Compressed stack-relative store
|
|
243
|
+
'c_uimm8sp_s': (12, 2),
|
|
244
|
+
|
|
245
|
+
# Compressed stack-relative unsigned 8-bit (split)
|
|
246
|
+
'c_uimm8sphi': (12, 10),
|
|
247
|
+
'c_uimm8splo': (6, 5),
|
|
248
|
+
|
|
249
|
+
# Compressed stack-relative store 9-bit
|
|
250
|
+
'c_uimm9sp_s': (12, 2),
|
|
251
|
+
|
|
252
|
+
# Compressed stack-relative unsigned 9-bit (split)
|
|
253
|
+
'c_uimm9sphi': (12, 10),
|
|
254
|
+
'c_uimm9splo': (6, 4),
|
|
255
|
+
|
|
256
|
+
# CSR
|
|
257
|
+
'csr': (31, 20),
|
|
258
|
+
|
|
259
|
+
# Fence mode
|
|
260
|
+
'fm': (31, 28),
|
|
261
|
+
|
|
262
|
+
# Standard immediates
|
|
263
|
+
'imm12': (31, 20),
|
|
264
|
+
'imm12hi': (31, 25),
|
|
265
|
+
'imm12lo': (11, 7),
|
|
266
|
+
'imm20': (31, 12),
|
|
267
|
+
'imm5': (24, 20),
|
|
268
|
+
|
|
269
|
+
# Jump immediate
|
|
270
|
+
'jimm20': (31, 12),
|
|
271
|
+
|
|
272
|
+
# Memory operation type fields (custom/Zacas)
|
|
273
|
+
'mop_r_t_21_20': (21, 20),
|
|
274
|
+
'mop_r_t_27_26': (27, 26),
|
|
275
|
+
'mop_r_t_30': (30, 30),
|
|
276
|
+
'mop_rr_t_27_26': (27, 26),
|
|
277
|
+
'mop_rr_t_30': (30, 30),
|
|
278
|
+
|
|
279
|
+
# Fence
|
|
280
|
+
'pred': (27, 24),
|
|
281
|
+
'succ': (23, 20),
|
|
282
|
+
|
|
283
|
+
# Standard registers
|
|
284
|
+
'rd': (11, 7),
|
|
285
|
+
'rd_n0': (11, 7),
|
|
286
|
+
'rd_n2': (11, 7),
|
|
287
|
+
'rd_p': (9, 7),
|
|
288
|
+
'rd_rs1_n0': (11, 7),
|
|
289
|
+
'rd_rs1_p': (9, 7),
|
|
290
|
+
|
|
291
|
+
# Floating-point rounding mode
|
|
292
|
+
'rm': (14, 12),
|
|
293
|
+
|
|
294
|
+
# Rotate amount
|
|
295
|
+
'rnum': (23, 20),
|
|
296
|
+
|
|
297
|
+
# Source registers
|
|
298
|
+
'rs1': (19, 15),
|
|
299
|
+
'rs1_n0': (19, 15),
|
|
300
|
+
'rs1_p': (9, 7),
|
|
301
|
+
'rs2': (24, 20),
|
|
302
|
+
'rs2_p': (4, 2),
|
|
303
|
+
'rs3': (31, 27),
|
|
304
|
+
|
|
305
|
+
# Shift amounts
|
|
306
|
+
'shamtd': (25, 20),
|
|
307
|
+
'shamtw': (24, 20),
|
|
308
|
+
|
|
309
|
+
# Vector signed 5-bit immediate
|
|
310
|
+
'simm5': (19, 15),
|
|
311
|
+
|
|
312
|
+
# Vector registers
|
|
313
|
+
'vd': (11, 7),
|
|
314
|
+
'vm': (25, 25),
|
|
315
|
+
'vs1': (19, 15),
|
|
316
|
+
'vs2': (24, 20),
|
|
317
|
+
'vs3': (11, 7),
|
|
318
|
+
|
|
319
|
+
# Vector zero-extended immediates
|
|
320
|
+
'zimm10': (29, 20),
|
|
321
|
+
'zimm11': (30, 20),
|
|
322
|
+
'zimm5': (19, 15),
|
|
323
|
+
|
|
324
|
+
# Vector 6-bit zero-extended immediate (split)
|
|
325
|
+
'zimm6hi': (26, 26),
|
|
326
|
+
'zimm6lo': (19, 15),
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
def __init__(self, mnemonic : str, match : int, mask : int, size : int, base : str, extensions : list[str]) -> None:
|
|
330
|
+
"""
|
|
331
|
+
Constructor
|
|
332
|
+
|
|
333
|
+
:param mnemonic: Instruction mnemonic
|
|
334
|
+
:type encode: str
|
|
335
|
+
:param match: Opcode encoding bits
|
|
336
|
+
:type match: int
|
|
337
|
+
:param mask: Opcode encoding bit mask
|
|
338
|
+
:type mask: int
|
|
339
|
+
:param size: Instruction size in bytes
|
|
340
|
+
:type size: int
|
|
341
|
+
:param base: Instruction base (i.e. RV32/RV64)
|
|
342
|
+
:type base: str
|
|
343
|
+
:param extensions: List of extensions
|
|
344
|
+
:type extensions: list[str]
|
|
345
|
+
"""
|
|
346
|
+
self.mnemonic = mnemonic
|
|
347
|
+
self.match = match
|
|
348
|
+
self.mask = mask
|
|
349
|
+
self.size = size
|
|
350
|
+
self.base = base
|
|
351
|
+
self.extensions = extensions
|
|
352
|
+
self.operands = {}
|
|
353
|
+
|
|
354
|
+
def __str__(self) -> str:
|
|
355
|
+
"""
|
|
356
|
+
Return a string representation of the Encoding.
|
|
357
|
+
|
|
358
|
+
:return: String representation of the Encoding.
|
|
359
|
+
:rtype: str
|
|
360
|
+
"""
|
|
361
|
+
s = "="*70 + "\n"
|
|
362
|
+
for k,v in self.__dict__.items():
|
|
363
|
+
if isinstance(v, list):
|
|
364
|
+
s += f"{k:<16} : {','.join(v)}\n"
|
|
365
|
+
else:
|
|
366
|
+
s += f"{k:<16} : {v}\n"
|
|
367
|
+
s += "="*70 + "\n"
|
|
368
|
+
return s
|
|
369
|
+
|
|
370
|
+
@classmethod
|
|
371
|
+
def get_mnemonic(self, encoding : int) -> str:
|
|
372
|
+
"""
|
|
373
|
+
Extract Mnemoic from the encoding
|
|
374
|
+
|
|
375
|
+
:param encoding: Post masking encoding
|
|
376
|
+
:type encoding: int
|
|
377
|
+
:return: String mnemonic
|
|
378
|
+
:rtype: str
|
|
379
|
+
"""
|
|
380
|
+
|
|
381
|
+
for mnemonic, instr_data in ISA.items():
|
|
382
|
+
# Check if instruction matches
|
|
383
|
+
if (encoding & instr_data.mask) == instr_data.match:
|
|
384
|
+
return mnemonic
|
|
385
|
+
|
|
386
|
+
raise ValueError(f"Failed to get mnemonic for {encoding:x}")
|
|
387
|
+
|
|
388
|
+
@classmethod
|
|
389
|
+
def get_encoding(self, encoding : int) -> Encoding:
|
|
390
|
+
"""
|
|
391
|
+
Extract Mnemoic from the encoding
|
|
392
|
+
|
|
393
|
+
:param encoding: Post masking encoding
|
|
394
|
+
:type encoding: int
|
|
395
|
+
:return: Encoding object
|
|
396
|
+
:rtype: Encoding
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
mnemonic = Encoding.get_mnemonic(encoding)
|
|
400
|
+
return ISA[mnemonic]
|
|
401
|
+
|
|
402
|
+
@classmethod
|
|
403
|
+
def get_operand(self, encoding : int, name : str) -> int:
|
|
404
|
+
"""
|
|
405
|
+
Extract operand value from encoding
|
|
406
|
+
|
|
407
|
+
:param encoding: Post masking encoding
|
|
408
|
+
:type encoding: int
|
|
409
|
+
:param name: name of operand
|
|
410
|
+
:type name: str
|
|
411
|
+
:return: Operand Value
|
|
412
|
+
:rtype: int
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
fp = Encoding._field_positions_[name]
|
|
416
|
+
|
|
417
|
+
nb = fp[0] - fp[1] + 1
|
|
418
|
+
mask = (1 << nb) -1
|
|
419
|
+
shift = fp[1]
|
|
420
|
+
|
|
421
|
+
return (encoding >> shift) & mask
|
|
422
|
+
|
|
423
|
+
def _analyze_operand(self, name : str) -> None:
|
|
424
|
+
"""
|
|
425
|
+
Anyalyse operands
|
|
426
|
+
|
|
427
|
+
:param name: Operand name
|
|
428
|
+
:type name: str
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
# === REGULAR INTEGER REGISTER OPERANDS ===
|
|
432
|
+
if name in Encoding._full_width_regs_:
|
|
433
|
+
if name.endswith("_n0"):
|
|
434
|
+
return {
|
|
435
|
+
"type": "reg",
|
|
436
|
+
"min": 1,
|
|
437
|
+
"max": 32,
|
|
438
|
+
}
|
|
439
|
+
else:
|
|
440
|
+
return {
|
|
441
|
+
"type": "reg",
|
|
442
|
+
"min": 0,
|
|
443
|
+
"max": 32,
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
# === COMPRESSED REGISTER OPERANDS ===
|
|
447
|
+
if name in Encoding._compressed_regs_:
|
|
448
|
+
return {
|
|
449
|
+
"type": "int_reg",
|
|
450
|
+
"min": 8,
|
|
451
|
+
"max": 15,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
# === SIGNED IMMEDIATE OPERANDS ===
|
|
455
|
+
if name in Encoding._signed_imms_:
|
|
456
|
+
num_bits = Encoding._field_positions_[name][0] - Encoding._field_positions_[name][1] + 1
|
|
457
|
+
max_value = (1 << (num_bits - 1)) - 1
|
|
458
|
+
min_value = -(1 << num_bits -1)
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
"type": "imm",
|
|
462
|
+
"min": min_value,
|
|
463
|
+
"max": max_value,
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
# === UNSIGNED IMMEDIATE OPERANDS ===
|
|
467
|
+
if name in Encoding._unsigned_imms_:
|
|
468
|
+
num_bits = Encoding._field_positions_[name][0] - Encoding._field_positions_[name][1] + 1
|
|
469
|
+
max_value = (1 << num_bits) - 1
|
|
470
|
+
min_value = 0
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
"type": "imm",
|
|
474
|
+
"min": min_value,
|
|
475
|
+
"max": max_value,
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
# === UNKNOWN OPERAND ===
|
|
479
|
+
raise ValueError(f"Unknown operand : {name}")
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def extract_isa(ref : str) -> None:
|
|
483
|
+
"""
|
|
484
|
+
Extract ISAs from instr_dict.json
|
|
485
|
+
|
|
486
|
+
:param ref: Location of instr_dict.json
|
|
487
|
+
:type ref: str
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
# Read reference json
|
|
491
|
+
with open(ref) as f:
|
|
492
|
+
ref = json.load(f)
|
|
493
|
+
|
|
494
|
+
# Process instructions
|
|
495
|
+
for k,v in ref.items():
|
|
496
|
+
mnemonic = k.replace("_", ".")
|
|
497
|
+
base = list(set([e.split("_", 1)[0].upper() for e in v["extension"]]))
|
|
498
|
+
assert len(base) == 1
|
|
499
|
+
extensions = [e.split("_", 1)[1].upper() for e in v["extension"]]
|
|
500
|
+
|
|
501
|
+
# Extract match and mask
|
|
502
|
+
match = int(v["match"], 16)
|
|
503
|
+
mask = int(v["mask"], 16)
|
|
504
|
+
|
|
505
|
+
# Extract operands
|
|
506
|
+
operands = v["variable_fields"]
|
|
507
|
+
|
|
508
|
+
# Extract size (compressed)
|
|
509
|
+
size = 2 if not v["encoding"].endswith("11") else 4
|
|
510
|
+
|
|
511
|
+
enc = Encoding(mnemonic, match, mask, size, base[0], extensions)
|
|
512
|
+
for o in operands:
|
|
513
|
+
enc.operands[o] = enc._analyze_operand(o)
|
|
514
|
+
ISA[mnemonic] = enc
|
|
515
|
+
|
|
516
|
+
# Create an entry for unknow
|
|
517
|
+
ISA[None] = Encoding(None, 0, 0, 4, "RV", [])
|
|
518
|
+
|
|
519
|
+
__all__ = [
|
|
520
|
+
"ISA",
|
|
521
|
+
"Encoding",
|
|
522
|
+
"extract_isa",
|
|
523
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from ._elf import INSTRUCTIONS
|
|
5
|
+
from ._trace import TRACE, Trace
|
|
6
|
+
|
|
7
|
+
_pattern_ = re.compile(
|
|
8
|
+
r"core\s+(\d+):\s*0x([0-9a-fA-F]+)\s*\(0x([0-9a-fA-F]+)\)"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
def parse_spike_log(fname : str) -> None:
|
|
12
|
+
"""
|
|
13
|
+
Parse spike log to generate linked list of Trace
|
|
14
|
+
elements
|
|
15
|
+
|
|
16
|
+
:param fname: Filename of trace to parse
|
|
17
|
+
:type fname: str
|
|
18
|
+
"""
|
|
19
|
+
prev = {}
|
|
20
|
+
try:
|
|
21
|
+
with open(fname) as f:
|
|
22
|
+
for line in f:
|
|
23
|
+
m = _pattern_.search(line)
|
|
24
|
+
if m:
|
|
25
|
+
core, pc, _instr = m.groups()
|
|
26
|
+
|
|
27
|
+
core = int(core)
|
|
28
|
+
pc = int(pc, 16)
|
|
29
|
+
|
|
30
|
+
# Find instruction (based on pc)
|
|
31
|
+
instr = INSTRUCTIONS.get(pc, None)
|
|
32
|
+
|
|
33
|
+
if instr is None:
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
# Create Trace (instructions in execution order)
|
|
37
|
+
trace = Trace(instr)
|
|
38
|
+
|
|
39
|
+
# Create the Linked list
|
|
40
|
+
if core not in TRACE:
|
|
41
|
+
TRACE[core] = trace
|
|
42
|
+
|
|
43
|
+
# Link
|
|
44
|
+
if core in prev and prev[core] is not None:
|
|
45
|
+
prev[core].link(trace)
|
|
46
|
+
prev[core] = trace
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"Failed to parse {fname} : {e}")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"parse_spike_log",
|
|
54
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from ._instr import Instruction
|
|
2
|
+
|
|
3
|
+
TRACE = {}
|
|
4
|
+
"""
|
|
5
|
+
Dict of double-linked-lists of Trace elements. Indexed by CPUID
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
class Trace:
|
|
9
|
+
def __init__(self, instr : Instruction) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Constructor
|
|
12
|
+
|
|
13
|
+
:param instr: Executed Instruction
|
|
14
|
+
:type instr: Instruction
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
self.instr = instr
|
|
18
|
+
self.prev = None
|
|
19
|
+
self.next = None
|
|
20
|
+
|
|
21
|
+
def __str__(self) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Return a string representation of the Instruction.
|
|
24
|
+
|
|
25
|
+
:return: String representation of the Instruction.
|
|
26
|
+
:rtype: str
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
s = f"{self.prev.instr}" if self.prev is not None else "None"
|
|
30
|
+
s += " -> "
|
|
31
|
+
s += f"\033[31m{self.instr}\033[0m" if self.instr is not None else "None"
|
|
32
|
+
s += " -> "
|
|
33
|
+
s += f"{self.next.instr}" if self.next is not None else "None"
|
|
34
|
+
|
|
35
|
+
return s
|
|
36
|
+
|
|
37
|
+
def link(self, next : Instruction | None) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Create 2 way link to next instruction (if you can)
|
|
40
|
+
|
|
41
|
+
Next / Prev refers to location in trace (i.e. executed instruction +/- one instruction)
|
|
42
|
+
not location in program
|
|
43
|
+
|
|
44
|
+
:param next: Next executed instruction
|
|
45
|
+
:type next: Instruction
|
|
46
|
+
"""
|
|
47
|
+
if next is not None:
|
|
48
|
+
self.next = next
|
|
49
|
+
self.next.prev = self
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
"TRACE",
|
|
53
|
+
"Trace",
|
|
54
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import avl
|
|
2
|
+
from avl_riscv_coverage._coverage import COVERPACKAGES, CoverPackage
|
|
3
|
+
from avl_riscv_coverage._elf import EXTENSIONS
|
|
4
|
+
from avl_riscv_coverage._trace import Trace
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Compression(CoverPackage):
|
|
8
|
+
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
super().__init__("Compression")
|
|
11
|
+
|
|
12
|
+
self.compressed = False
|
|
13
|
+
self.cg = avl.Covergroup("compression", None)
|
|
14
|
+
cp = self.cg.add_coverpoint("compression", lambda: self.compressed)
|
|
15
|
+
cp.add_bin("compressed", True)
|
|
16
|
+
cp.add_bin("not compressed", False)
|
|
17
|
+
|
|
18
|
+
def sample(self, trace : Trace) -> None:
|
|
19
|
+
self.compressed = trace.instr.encoding.size == 2
|
|
20
|
+
self.cg.sample()
|
|
21
|
+
|
|
22
|
+
if "C" in EXTENSIONS:
|
|
23
|
+
COVERPACKAGES.append(Compression())
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import avl
|
|
2
|
+
from avl_riscv_coverage._coverage import COVERPACKAGES, CoverPackage
|
|
3
|
+
from avl_riscv_coverage._elf import EXTENSIONS
|
|
4
|
+
from avl_riscv_coverage._trace import Trace
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Jump(CoverPackage):
|
|
8
|
+
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
super().__init__("Jump")
|
|
11
|
+
|
|
12
|
+
self.mnemonics = ["jal", "jalr"]
|
|
13
|
+
|
|
14
|
+
if "C" in EXTENSIONS:
|
|
15
|
+
self.mnemonics.extend(["c_jal", "c_jalr"])
|
|
16
|
+
|
|
17
|
+
self.mnemonic = None
|
|
18
|
+
self.distance = 0
|
|
19
|
+
|
|
20
|
+
self.cg = avl.Covergroup("jump", None)
|
|
21
|
+
|
|
22
|
+
cp_mnemonic = self.cg.add_coverpoint("mnemonic", lambda: self.mnemonic)
|
|
23
|
+
for m in self.mnemonics:
|
|
24
|
+
cp_mnemonic.add_bin(m, lambda x,m=m: x == m)
|
|
25
|
+
|
|
26
|
+
cp_distance = self.cg.add_coverpoint("distance", lambda: self.distance)
|
|
27
|
+
cp_distance.add_bin("short", range(-64,64), stats=True)
|
|
28
|
+
cp_distance.add_bin("medium", range(-1024,1024), stats=True)
|
|
29
|
+
cp_distance.add_bin("any", lambda x: True, stats=True)
|
|
30
|
+
|
|
31
|
+
self.cg.add_covercross("mnemonicXdistance", cp_mnemonic, cp_distance)
|
|
32
|
+
|
|
33
|
+
def sample(self, trace : Trace) -> None:
|
|
34
|
+
if trace.instr.encoding.mnemonic not in self.mnemonics:
|
|
35
|
+
return
|
|
36
|
+
self.mnemonic = trace.instr.encoding.mnemonic
|
|
37
|
+
self.distance = trace.next.instr.pc - trace.instr.pc
|
|
38
|
+
self.cg.sample()
|
|
39
|
+
|
|
40
|
+
COVERPACKAGES.append(Jump())
|