add regfile.py
[soc.git] / src / regfile / regfile.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3
4 from nmigen import Const, Array, Signal, Elaboratable, Module
5 from nmutil.iocontrol import RecordObject
6
7 from math import log
8
9
10 class RegFile(Elaboratable):
11 def __init__(self, width, depth):
12 self.width = width
13 self.depth = depth
14 self._rdports = []
15 self._wrports = []
16
17 def read_port(self):
18 bsz = int(log(self.width) / log(2))
19 port = RecordObject([("raddr", bsz),
20 ("ren", 1),
21 ("data_o", self.width)])
22 self._rdports.append(port)
23 return port
24
25 def write_port(self):
26 bsz = int(log(self.width) / log(2))
27 port = RecordObject([("waddr", bsz),
28 ("wen", 1),
29 ("data_i", self.width)])
30 self._wrports.append(port)
31 return port
32
33 def elaborate(self, platform):
34 m = Module()
35 bsz = int(log(self.width) / log(2))
36 regs = Array(Signal(self.width, name="reg") for _ in range(self.depth))
37
38 # read ports. has write-through detection (returns data written)
39 for rp in self._rdports:
40 wr_detect = Signal(reset_less=False)
41 with m.If(rp.ren):
42 m.d.comb += wr_detect.eq(0)
43 for wp in self._wrports:
44 addrmatch = Signal(reset_less=False)
45 m.d.comb += addrmatch.eq(wp.waddr == rp.raddr)
46 with m.If(wp.wen & addrmatch):
47 m.d.comb += rp.data_o.eq(wp.data_i)
48 m.d.comb += wr_detect.eq(1)
49 with m.If(~wr_detect):
50 m.d.comb += rp.data_o.eq(regs[rp.raddr])
51
52 # write ports, don't allow write to address 0 (ignore it)
53 for wp in self._wrports:
54 with m.If(wp.wen & (wp.waddr != Const(0, bsz))):
55 m.d.sync += regs[wp.waddr].eq(wp.data_i)
56
57 return m
58
59 def __iter__(self):
60 yield from self._rdports
61 yield from self._wrports
62
63 def ports(self):
64 res = list(self)
65 for r in res:
66 if isinstance(r, RecordObject):
67 yield from r
68 else:
69 yield r
70
71 def regfile_sim(dut, rp, wp):
72 yield wp.waddr.eq(1)
73 yield wp.data_i.eq(2)
74 yield wp.wen.eq(1)
75 yield
76 yield wp.wen.eq(0)
77 yield rp.ren.eq(1)
78 yield rp.raddr.eq(1)
79 yield
80 data = yield rp.data_o
81 print (data)
82 assert data == 2
83
84 yield wp.waddr.eq(5)
85 yield rp.raddr.eq(5)
86 yield rp.ren.eq(1)
87 yield wp.wen.eq(1)
88 yield wp.data_i.eq(6)
89 data = yield rp.data_o
90 print (data)
91 yield
92 yield wp.wen.eq(0)
93 yield rp.ren.eq(0)
94 data = yield rp.data_o
95 print (data)
96 assert data == 6
97 yield
98 data = yield rp.data_o
99 print (data)
100
101 def test_regfile():
102 dut = RegFile(32, 8)
103 rp = dut.read_port()
104 wp = dut.write_port()
105 vl = rtlil.convert(dut, ports=dut.ports())
106 with open("test_regfile.il", "w") as f:
107 f.write(vl)
108
109 run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regfile.vcd')
110
111 if __name__ == '__main__':
112 test_regfile()