|
11 | 11 | SpeculativeEvaluation,
|
12 | 12 | )
|
13 | 13 |
|
| 14 | + |
14 | 15 | @dataclass(kw_only=True)
|
15 |
| -class InstructionChecker(GenericChecker): |
| 16 | +class InstructionCheckerBase(GenericChecker): |
16 | 17 | instructions: dict[str, Instruction] = field(default_factory=dict)
|
17 | 18 | observers: dict[str, Observer] = field(default_factory=dict)
|
18 | 19 |
|
19 |
| - defined_checks: list[SpeculativeEvaluation] = field(default_factory=list) |
20 |
| - |
21 |
| - registered_checks: ClassVar[list[SpeculativeEvaluation]] = [] |
22 |
| - registered_verilog: ClassVar[list[str]] = [] |
23 | 20 | registered_speculators: ClassVar[dict[str, tuple[SpeculativeObserver, Callable[[Instruction], Optional[str]]]]] = {}
|
24 |
| - registered_hw_traps: ClassVar[dict[str, Callable[[dict[str, Observer]], str]]] = {} |
25 | 21 |
|
26 | 22 | def configure_io(self):
|
27 | 23 | for insn in self.instructions.values():
|
28 | 24 | insn.select_inputs(self.observers.values())
|
29 | 25 | insn.select_outputs([o for o in self.observers.values() if isinstance(o, SpeculativeObserver)])
|
30 | 26 |
|
31 |
| - @classmethod |
32 |
| - def register_check(cls, check: SpeculativeEvaluation): |
33 |
| - cls.registered_checks.append(check) |
34 |
| - |
35 |
| - @classmethod |
36 |
| - def register_verilog(cls, verilog: str): |
37 |
| - cls.registered_verilog.append(verilog) |
38 |
| - |
39 | 27 | @classmethod
|
40 | 28 | def register_speculator(cls,
|
41 | 29 | spec_obs: SpeculativeObserver,
|
42 | 30 | speculator: Callable[[Instruction], Optional[str]],
|
43 | 31 | ):
|
44 | 32 | cls.registered_speculators[spec_obs.name] = (spec_obs, speculator)
|
45 | 33 |
|
46 |
| - @classmethod |
47 |
| - def register_hw_trap(cls, condition: str, handler: Callable[[dict[str, Observer]], str]): |
48 |
| - cls.registered_hw_traps[condition] = handler |
49 |
| - |
50 | 34 | def _v_io(self) -> str:
|
51 | 35 | # macro defined RVFI inputs
|
52 | 36 | return dedent("""\
|
@@ -124,6 +108,47 @@ def _v_instantiation(self) -> str:
|
124 | 108 | v_str += " end"
|
125 | 109 | v_str += "\nend\n"
|
126 | 110 |
|
| 111 | + return v_str |
| 112 | + |
| 113 | + def _v_spec_check(self) -> str: |
| 114 | + raise NotImplementedError() |
| 115 | + |
| 116 | + def _v_body(self) -> str: |
| 117 | + v_str = self._v_format_block(self._v_rvfi_channel()) |
| 118 | + v_str += self._v_format_block(self._v_instantiation()) |
| 119 | + v_str += self._v_format_block(self._v_spec_check()) |
| 120 | + return v_str |
| 121 | + |
| 122 | + def to_verilog(self, xlen: int): |
| 123 | + v_str = "" |
| 124 | + for insn in self.instructions.values(): |
| 125 | + v_str += insn.to_verilog(xlen) + '\n\n' |
| 126 | + return v_str + super().to_verilog() |
| 127 | + |
| 128 | + |
| 129 | +@dataclass(kw_only=True) |
| 130 | +class InstructionChecker(InstructionCheckerBase): |
| 131 | + defined_checks: list[SpeculativeEvaluation] = field(default_factory=list) |
| 132 | + |
| 133 | + registered_checks: ClassVar[list[SpeculativeEvaluation]] = [] |
| 134 | + registered_verilog: ClassVar[list[str]] = [] |
| 135 | + registered_hw_traps: ClassVar[dict[str, Callable[[dict[str, Observer]], str]]] = {} |
| 136 | + |
| 137 | + @classmethod |
| 138 | + def register_check(cls, check: SpeculativeEvaluation): |
| 139 | + cls.registered_checks.append(check) |
| 140 | + |
| 141 | + @classmethod |
| 142 | + def register_verilog(cls, verilog: str): |
| 143 | + cls.registered_verilog.append(verilog) |
| 144 | + |
| 145 | + @classmethod |
| 146 | + def register_hw_trap(cls, condition: str, handler: Callable[[dict[str, Observer]], str]): |
| 147 | + cls.registered_hw_traps[condition] = handler |
| 148 | + |
| 149 | + def _v_instantiation(self) -> str: |
| 150 | + v_str = super()._v_instantiation() |
| 151 | + |
127 | 152 | if self.registered_verilog:
|
128 | 153 | v_str += "\n"
|
129 | 154 | v_str += "\n\n".join(self.registered_verilog)
|
@@ -180,14 +205,42 @@ def _v_spec_check(self) -> str:
|
180 | 205 | )
|
181 | 206 | return v_str
|
182 | 207 |
|
183 |
| - def _v_body(self) -> str: |
184 |
| - v_str = self._v_format_block(self._v_rvfi_channel()) |
185 |
| - v_str += self._v_format_block(self._v_instantiation()) |
186 |
| - v_str += self._v_format_block(self._v_spec_check()) |
187 |
| - return v_str |
188 | 208 |
|
189 |
| - def to_verilog(self, xlen: int): |
| 209 | +@dataclass(kw_only=True) |
| 210 | +class CompleteISAChecker(InstructionCheckerBase): |
| 211 | + valid_opcodes: list[str] = field(default_factory=list) |
| 212 | + extra_valid_checks: list[str] = field(default_factory=list) |
| 213 | + |
| 214 | + def _v_spec_check(self) -> str: |
190 | 215 | v_str = ""
|
191 |
| - for insn in self.instructions.values(): |
192 |
| - v_str += insn.to_verilog(xlen) + '\n\n' |
193 |
| - return v_str + super().to_verilog() |
| 216 | + |
| 217 | + v_str += "wire opcode_valid = " |
| 218 | + if self.valid_opcodes: |
| 219 | + op_checks: list[str] = [] |
| 220 | + for op in self.valid_opcodes: |
| 221 | + if len(op) == 7: |
| 222 | + try: |
| 223 | + int(op, 2) |
| 224 | + except ValueError: |
| 225 | + # not valid binary |
| 226 | + pass |
| 227 | + else: |
| 228 | + op = f"7'b {op}" |
| 229 | + op_checks.append(f"(rvfi.insn[6:0] == {op})") |
| 230 | + v_str += "\n || ".join(op_checks) |
| 231 | + else: |
| 232 | + v_str += "0" |
| 233 | + v_str += ";\n\n" |
| 234 | + |
| 235 | + v_str += "wire extra_valid = " |
| 236 | + v_str += "\n || ".join(f"({check})" for check in self.extra_valid_checks) or "0" |
| 237 | + v_str += ";\n\n" |
| 238 | + |
| 239 | + v_str +=dedent("""\ |
| 240 | + always @* begin |
| 241 | + if (!reset && rvfi.valid && !rvfi.trap && !opcode_valid && !extra_valid) begin |
| 242 | + assert(spec_valid && !spec_trap); |
| 243 | + end |
| 244 | + end""") |
| 245 | + |
| 246 | + return v_str |
0 commit comments