blob: c5902ef2ca3f61a9c5f9cb3c3eea01bc0b8d4474 [file]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
from typing import List
from .reg import Reg, RegFile
class GPRs(RegFile):
'''The narrow OTBN register file'''
def __init__(self) -> None:
super().__init__('x', 32, 32)
# The call stack for x1 and its pending updates. self.callstack is
# never empty and (after commit) the tail always matches
# self._registers[1].read_unsigned() (pushing from the right)
self._callstack = [0] # type: List[int]
self._callstack_pop = False
def mark_read(self, idx: int) -> None:
super().mark_read(idx)
if idx == 1:
self._callstack_pop = True
def get_reg(self, idx: int) -> Reg:
# If idx == 0, this is a zeros register that should ignore writes.
# Return a fresh Reg with no parent, so writes to it have no effect.
if idx == 0:
return Reg(None, 0, 32, 0)
return super().get_reg(idx)
def post_insn(self) -> None:
'''Update call stack after instruction execution but before commit
This is not idempotent: call it exactly once.
'''
callstack_push = 1 in self._pending_writes
# If we read from the call stack, we have popped from it. (Even if the
# stack is empty, we treat this as a logical pop. We need to decide
# what happens here: see issue #3239).
if self._callstack_pop:
if len(self._callstack) > 1:
self._callstack.pop()
# Write the new head of the call stack to the relevant register,
# unless x1 has a pending write (which means that we had an
# instruction like "addi x1, x1, 0", so the pop happened logically
# before the push)
if not callstack_push:
self._registers[1].write_unsigned(self._callstack[-1])
# If there is a pending write to x1 (which wasn't caused by the
# callstack pop code just above) then callstack_push will be true. In
# that case, we should push the new value onto the call stack.
if callstack_push:
new_x1 = self._registers[1].read_next()
assert new_x1 is not None
self._callstack.append(new_x1)
def commit(self) -> None:
self._callstack_pop = False
super().commit()