[otbn] Add support for CSR/WSR instructions to RIG
Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/util/rig/gens/straight_line_insn.py b/hw/ip/otbn/util/rig/gens/straight_line_insn.py
index 5434f18..1d8e838 100644
--- a/hw/ip/otbn/util/rig/gens/straight_line_insn.py
+++ b/hw/ip/otbn/util/rig/gens/straight_line_insn.py
@@ -379,12 +379,16 @@
# Ask the model to try to find a target we can use. If this is a load
# or a CSR operation, it will have to be an address that already has an
# architectural value. If a store, it can be any address in range.
+ #
+ # We cheat a bit for WSR stores. These don't actually load a value, but
+ # we still want to make sure we pick a valid WSR index, so we claim we
+ # loaded one anyway.
lsu_type_to_info = {
'mem-load': ('dmem', True),
'mem-store': ('dmem', False),
'csr': ('csr', True),
'wsr-load': ('wsr', True),
- 'wsr-store': ('wsr', False)
+ 'wsr-store': ('wsr', True)
}
assert set(lsu_type_to_info.keys()) == set(LSUDesc.TYPES)
mem_type, loads_value = lsu_type_to_info[insn.lsu.lsu_type]
diff --git a/hw/ip/otbn/util/rig/model.py b/hw/ip/otbn/util/rig/model.py
index 05797a9..2d542b7 100644
--- a/hw/ip/otbn/util/rig/model.py
+++ b/hw/ip/otbn/util/rig/model.py
@@ -6,7 +6,6 @@
import random
from typing import Dict, List, Optional, Set, Tuple
-from shared.insn_yaml import Insn
from shared.operand import (OperandType,
ImmOperandType, OptionOperandType, RegOperandType)
@@ -49,7 +48,7 @@
self.known_ranges = [] # type: List[Tuple[int, int]]
def touch_range(self, base: int, width: int) -> None:
- '''Mark {base .. base+width} as known'''
+ '''Mark {base .. base + width - 1} as known'''
assert 0 <= width
assert 0 <= base <= self.top_addr - width
for off in range(width):
@@ -349,14 +348,25 @@
self._call_stack = [] # type: List[Optional[int]]
# Known values for memory, keyed by memory type ('dmem', 'csr', 'wsr').
+ csrs = KnownMem(4096)
+ wsrs = KnownMem(4096)
self._known_mem = {
'dmem': KnownMem(dmem_size),
- # TODO: How many CSRs/WSRs? Is that written down somewhere we can
- # extract?
- 'csr': KnownMem(4096),
- 'wsr': KnownMem(4096)
+ 'csr': csrs,
+ 'wsr': wsrs
}
+ # Valid CSRs and WSRs
+ csrs.touch_addr(0x7c0) # FG0
+ csrs.touch_addr(0x7c1) # FG1
+ csrs.touch_addr(0x7c8) # FLAGS
+ csrs.touch_range(0x7d0, 8) # MOD0 - MOD7
+ csrs.touch_addr(0xfc0) # RND
+
+ wsrs.touch_addr(0x0) # MOD
+ wsrs.touch_addr(0x1) # RND
+ wsrs.touch_addr(0x2) # ACC
+
# The current PC (the address of the next instruction that needs
# generating)
self.pc = reset_addr
diff --git a/hw/ip/otbn/util/shared/operand.py b/hw/ip/otbn/util/shared/operand.py
index ef914b8..dc6dd7c 100644
--- a/hw/ip/otbn/util/shared/operand.py
+++ b/hw/ip/otbn/util/shared/operand.py
@@ -168,8 +168,6 @@
TYPE_FMTS = {
'gpr': (5, 'x'),
'wdr': (5, 'w'),
- 'csr': (12, None),
- 'wsr': (8, None)
}
def __init__(self, reg_type: str, is_dest: bool) -> None:
@@ -569,8 +567,6 @@
'grd': ('gpr', True),
'wrs': ('wdr', False),
'wrd': ('wdr', True),
- 'csr': ('csr', True),
- 'wsr': ('wsr', True)
}
reg_match = reg_fmts.get(fmt)
if reg_match is not None:
@@ -582,6 +578,18 @@
reg_type, is_dest = reg_match
return RegOperandType.make(reg_type, is_dest, what, scheme_field)
+ # CSR and WSR indices. These are treated like unsigned immediates, with
+ # width 12 and 8, respectively.
+ xsr_fmts = {
+ 'csr': 12,
+ 'wsr': 8
+ }
+ xsr_match = xsr_fmts.get(fmt)
+ if xsr_match is not None:
+ assert not pc_rel
+ return ImmOperandType.make(xsr_match, 0, 0, False, False,
+ what, scheme_field)
+
# Immediates
for base, signed in [('simm', True), ('uimm', False)]:
# The type of an immediate operand is encoded as