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.
@@ -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())