blob: d3dae867e69075e1e42a5ec92dbbe67fcd6e941c [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
from .flags import FlagGroups
from .wsr import WSRFile
class CSRFile:
'''A model of the CSR file'''
def __init__(self) -> None:
self.flags = FlagGroups()
self._known_indices = set()
self._known_indices.add(0x7c0) # FG0
self._known_indices.add(0x7c1) # FG1
self._known_indices.add(0x7c8) # FLAGS
for idx in range(0x7d0, 0x7d8):
self._known_indices.add(idx) # MODi
self._known_indices.add(0x7d8) # RND_PREFETCH
self._known_indices.add(0xfc0) # RND
self._known_indices.add(0xfc1) # URND
@staticmethod
def _get_field(field_idx: int, field_size: int, val: int) -> int:
mask = (1 << field_size) - 1
return (val >> (field_size * field_idx)) & mask
@staticmethod
def _set_field(field_idx: int, field_size: int, field_val: int,
old_val: int) -> int:
assert 0 <= field_val < (1 << field_size)
mask = (1 << field_size) - 1
shift = field_size * field_idx
return (old_val & ~(mask << shift)) | (field_val << shift)
def check_idx(self, idx: int) -> bool:
'''Return True if idx points to a valid CSR; False otherwise.'''
return idx in self._known_indices
def read_unsigned(self, wsrs: WSRFile, idx: int) -> int:
if 0x7c0 <= idx <= 0x7c1:
# FG0/FG1
fg = idx - 0x7c0
return self._get_field(fg, 4, self.flags.read_unsigned())
if idx == 0x7c8:
# FLAGS register
return self.flags.read_unsigned()
if 0x7d0 <= idx <= 0x7d7:
# MOD0 .. MOD7. MODi is bits [32*(i+1)-1..32*i]
mod_n = idx - 0x7d0
return self._get_field(mod_n, 32, wsrs.MOD.read_unsigned())
if idx == 0x7d8:
# RND_PREFETCH register
return 0
if idx == 0xfc0:
# RND register
return wsrs.RND.read_u32()
if idx == 0xfc1:
# URND register
return wsrs.URND.read_u32()
raise RuntimeError('Unknown CSR index: {:#x}'.format(idx))
def write_unsigned(self, wsrs: WSRFile, idx: int, value: int) -> None:
assert 0 <= value < (1 << 32)
if 0x7c0 <= idx <= 0x7c1:
# FG0/FG1
fg = idx - 0x7c0
old = self.flags.read_unsigned()
self.flags.write_unsigned(self._set_field(fg, 4, value & 0xf, old))
return
if idx == 0x7c8:
# FLAGS register
self.flags.write_unsigned(value)
return
if 0x7d0 <= idx <= 0x7d7:
# MOD0 .. MOD7. MODi is bits [32*(i+1)-1..32*i]. read,modify,write.
mod_n = idx - 0x7d0
old = wsrs.MOD.read_unsigned()
wsrs.MOD.write_unsigned(self._set_field(mod_n, 32, value, old))
return
if idx == 0x7d8:
# RND_PREFETCH
wsrs.RND.request_value()
return
if idx == 0xfc0:
# RND register (which ignores writes)
return
if idx == 0xfc1:
# URND register (which ignores writes)
return
raise RuntimeError('Unknown CSR index: {:#x}'.format(idx))
def wipe(self) -> None:
self.flags.write_unsigned(0)