Merge branch 'master' of git.libre-soc.org:soc
[soc.git] / src / soc / minerva / units / debug / regfile.py
1 from nmigen import Elaboratable, Module, Record, Const
2
3 from .dmi import (DebugReg, DmiOp, RegMode,
4 abstractcs_layout, cmd_access_reg_layout, command_layout,
5 dmcontrol_layout, dmstatus_layout, flat_layout, sbcs_layout)
6
7
8 __all__ = ["DebugRegisterFile"]
9
10
11 class DmiOp:
12 NOP = 0
13 READ = 1
14 WRITE = 2
15
16
17 class DmiResult:
18 OK = 0
19 FAIL = 2
20 BUSY = 3
21
22
23 reg_map = {
24 DebugReg.DMSTATUS: dmstatus_layout,
25 DebugReg.DMCONTROL: dmcontrol_layout,
26 DebugReg.HARTINFO: flat_layout,
27 DebugReg.ABSTRACTCS: abstractcs_layout,
28 DebugReg.COMMAND: command_layout,
29 DebugReg.SBCS: sbcs_layout,
30 DebugReg.SBADDRESS0: flat_layout,
31 DebugReg.SBDATA0: flat_layout,
32 DebugReg.DATA0: flat_layout
33 }
34
35
36 class DebugRegisterFile(Elaboratable):
37 def __init__(self, dmi):
38 self.dmi = dmi
39 self.ports = dict()
40
41 def reg_port(self, addr):
42 if addr not in reg_map:
43 raise ValueError("Unknown register {:x}.".format(addr))
44 if addr in self.ports:
45 raise ValueError("Register {:x} has already been allocated.".format(addr))
46 layout = [f[:2] for f in reg_map[addr]]
47 port = Record([("r", layout), ("w", layout), ("update", 1), ("capture", 1)])
48 for name, shape, mode, reset in reg_map[addr]:
49 getattr(port.r, name).reset = reset
50 getattr(port.w, name).reset = reset
51 self.ports[addr] = port
52 return port
53
54 def elaborate(self, platform):
55 m = Module()
56
57 def do_read(addr, port):
58 rec = Record(port.w.layout)
59 m.d.sync += self.dmi.r.data.eq(rec)
60 for name, shape, mode, reset in reg_map[addr]:
61 dst = getattr(rec, name)
62 src = getattr(port.w, name)
63 if mode in {RegMode.R, RegMode.RW, RegMode.RW1C}:
64 m.d.comb += dst.eq(src)
65 else:
66 m.d.comb += dst.eq(Const(0))
67 m.d.sync += port.capture.eq(1)
68
69 def do_write(addr, port):
70 rec = Record(port.r.layout)
71 m.d.comb += rec.eq(self.dmi.w.data)
72 for name, shape, mode, reset in reg_map[addr]:
73 dst = getattr(port.r, name)
74 src = getattr(rec, name)
75 if mode in {RegMode.W, RegMode.RW}:
76 m.d.sync += dst.eq(src)
77 elif mode is RegMode.W1:
78 m.d.sync += dst.eq(getattr(port.w, name) | src)
79 elif mode is RegMode.RW1C:
80 m.d.sync += dst.eq(getattr(port.w, name) & ~src)
81
82 m.d.sync += port.update.eq(1)
83
84 with m.If(self.dmi.update):
85 with m.Switch(self.dmi.w.addr):
86 for addr, port in self.ports.items():
87 with m.Case(addr):
88 with m.If(self.dmi.w.op == DmiOp.READ):
89 do_read(addr, port)
90 with m.Elif(self.dmi.w.op == DmiOp.WRITE):
91 do_write(addr, port)
92 m.d.sync += self.dmi.r.op.eq(DmiResult.OK)
93 with m.Case():
94 # Invalid register.
95 m.d.sync += self.dmi.r.op.eq(DmiResult.FAIL)
96
97 for port in self.ports.values():
98 with m.If(port.update):
99 m.d.sync += port.update.eq(0)
100 with m.If(port.capture):
101 m.d.sync += port.capture.eq(0)
102
103 return m