riscv-formal-nmigen/rvfi/cores/minerva/units/debug/regfile.py

96 lines
3.1 KiB
Python

from nmigen import *
from nmigen.hdl.rec import *
from .dmi import *
__all__ = ["DebugRegisterFile"]
class DmiOp:
NOP = 0
READ = 1
WRITE = 2
reg_map = {
DebugReg.DMSTATUS: dmstatus_layout,
DebugReg.DMCONTROL: dmcontrol_layout,
DebugReg.HARTINFO: flat_layout,
DebugReg.ABSTRACTCS: abstractcs_layout,
DebugReg.COMMAND: command_layout,
DebugReg.SBCS: sbcs_layout,
DebugReg.SBADDRESS0: flat_layout,
DebugReg.SBDATA0: flat_layout,
DebugReg.DATA0: flat_layout,
DebugReg.HALTSUM0: flat_layout,
DebugReg.HALTSUM1: flat_layout,
}
class DebugRegisterFile(Elaboratable):
def __init__(self, dmi):
self.dmi = dmi
self.ports = dict()
def reg_port(self, addr, name=None, src_loc_at=0):
if addr not in reg_map:
raise ValueError("Unknown register {:x}.".format(addr))
if addr in self.ports:
raise ValueError("Register {:x} has already been allocated.".format(addr))
layout = [f[:2] for f in reg_map[addr]]
port = Record([("r", layout), ("w", layout), ("update", 1), ("capture", 1)],
name=name, src_loc_at=1 + src_loc_at)
for name, shape, mode, reset in reg_map[addr]:
getattr(port.r, name).reset = reset
getattr(port.w, name).reset = reset
self.ports[addr] = port
return port
def elaborate(self, platform):
m = Module()
def do_read(addr, port):
rec = Record(port.w.layout)
m.d.sync += self.dmi.r.data.eq(rec)
for name, shape, mode, reset in reg_map[addr]:
dst = getattr(rec, name)
src = getattr(port.w, name)
if mode in {RegMode.R, RegMode.RW, RegMode.RW1C}:
m.d.comb += dst.eq(src)
else:
m.d.comb += dst.eq(Const(0))
m.d.sync += port.capture.eq(1)
def do_write(addr, port):
rec = Record(port.r.layout)
m.d.comb += rec.eq(self.dmi.w.data)
for name, shape, mode, reset in reg_map[addr]:
dst = getattr(port.r, name)
src = getattr(rec, name)
if mode in {RegMode.W, RegMode.RW}:
m.d.sync += dst.eq(src)
elif mode is RegMode.W1:
m.d.sync += dst.eq(getattr(port.w, name) | src)
elif mode is RegMode.RW1C:
m.d.sync += dst.eq(getattr(port.w, name) & ~src)
m.d.sync += port.update.eq(1)
with m.If(self.dmi.update):
with m.Switch(self.dmi.w.addr):
for addr, port in self.ports.items():
with m.Case(addr):
with m.If(self.dmi.w.op == DmiOp.READ):
do_read(addr, port)
with m.Elif(self.dmi.w.op == DmiOp.WRITE):
do_write(addr, port)
for port in self.ports.values():
with m.If(port.update):
m.d.sync += port.update.eq(0)
with m.If(port.capture):
m.d.sync += port.capture.eq(0)
return m