debugging decoding of SPRs (fast)
[soc.git] / src / soc / regfile / virtual_port.py
1 """VirtualRegPort - terrible name for a complex register class
2
3 This Register file has a "virtual" port on it which is effectively
4 the ability to read and write to absolutely every bit in the regfile
5 at once. This is achieved by having N actual read and write ports
6 if there are N registers. That results in a staggeringly high gate count
7 with full crossbars, so attempting to do use this for anything other
8 than really small registers (XER, CR) is a seriously bad idea.
9 """
10
11 from nmigen.compat.sim import run_simulation
12 from nmigen.cli import verilog, rtlil
13
14 from nmigen import Cat, Const, Array, Signal, Elaboratable, Module
15 from nmutil.iocontrol import RecordObject
16
17 from soc.regfile.regfile import RegFileArray
18
19
20 class VirtualRegPort(RegFileArray):
21 def __init__(self, bitwidth, n_regs):
22 self.bitwidth = bitwidth
23 self.nregs = n_regs
24 self.regwidth = regwidth = bitwidth // n_regs
25 super().__init__(self.regwidth, n_regs)
26
27 # "full" depth variant of the "external" port
28 self.full_wr = RecordObject([("wen", n_regs),
29 ("data_i", bitwidth)], # *full* wid
30 name="full_wr")
31 self.full_rd = RecordObject([("ren", n_regs),
32 ("data_o", bitwidth)], # *full* wid
33 name="full_rd")
34 def elaborate(self, platform):
35 m = super().elaborate(platform)
36 comb = m.d.comb
37
38 # for internal use only.
39 wr_regs = self.write_reg_port(f"w")
40 rd_regs = self.read_reg_port(f"r")
41
42 # connect up full read port
43 rfull = self.full_rd
44
45 # wire up the enable signals and chain-accumulate the data
46 l = map(lambda port: port.data_o, rd_regs) # get port data(s)
47 le = map(lambda port: port.ren, rd_regs) # get port ren(s)
48
49 comb += rfull.data_o.eq(Cat(*l)) # we like Cat on lists
50 comb += Cat(*le).eq(rfull.ren)
51
52 # connect up full write port
53 wfull = self.full_wr
54
55 # wire up the enable signals from the large (full) port
56 l = map(lambda port: port.data_i, wr_regs)
57 le = map(lambda port: port.wen, wr_regs) # get port wen(s)
58
59 # get list of all data_i (and wens) and assign to them via Cat
60 comb += Cat(*l).eq(wfull.data_i)
61 comb += Cat(*le).eq(wfull.wen)
62
63 return m
64
65 def __iter__(self):
66 yield from super().__iter__()
67 yield from self.full_wr
68 yield from self.full_rd
69
70
71 def regfile_array_sim(dut, rp1, rp2, rp3, wp):
72 # part-port write
73 yield wp.data_i.eq(2)
74 yield wp.wen.eq(1<<1)
75 yield
76 yield wp.wen.eq(0)
77 # part-port read
78 yield rp1.ren.eq(1<<1)
79 yield
80 data = yield rp1.data_o
81 print (data)
82 assert data == 2
83
84 # simultaneous read/write - should be pass-thru
85 yield rp1.ren.eq(1<<5)
86 yield rp2.ren.eq(1<<1)
87 yield wp.wen.eq(1<<5)
88 yield wp.data_i.eq(6)
89 yield
90 yield wp.wen.eq(0)
91 yield rp1.ren.eq(0)
92 yield rp2.ren.eq(0)
93 data1 = yield rp1.data_o
94 print (data1)
95 assert data1 == 6, data1
96 data2 = yield rp2.data_o
97 print (data2)
98 assert data2 == 2, data2
99 yield
100 data = yield rp1.data_o
101 print (data)
102
103 # full port read (whole reg)
104 yield dut.full_rd.ren.eq(0xff)
105 yield
106 yield dut.full_rd.ren.eq(0)
107 data = yield dut.full_rd.data_o
108 print (hex(data))
109
110 # full port read (part reg)
111 yield dut.full_rd.ren.eq(0x1<<5)
112 yield
113 yield dut.full_rd.ren.eq(0)
114 data = yield dut.full_rd.data_o
115 print (hex(data))
116
117 # full port part-write (part masked reg)
118 yield dut.full_wr.wen.eq(0x1<<1)
119 yield dut.full_wr.data_i.eq(0xe0)
120 yield
121 yield dut.full_wr.wen.eq(0x0)
122
123 # full port read (whole reg)
124 yield dut.full_rd.ren.eq(0xff)
125 yield
126 yield dut.full_rd.ren.eq(0)
127 data = yield dut.full_rd.data_o
128 print (hex(data))
129
130 # full port write
131 yield dut.full_wr.wen.eq(0xff)
132 yield dut.full_wr.data_i.eq(0xcafeface)
133 yield
134 yield dut.full_wr.wen.eq(0x0)
135
136 # full port read (whole reg)
137 yield dut.full_rd.ren.eq(0xff)
138 yield
139 yield dut.full_rd.ren.eq(0)
140 data = yield dut.full_rd.data_o
141 print (hex(data))
142
143 # part write
144 yield wp.data_i.eq(2)
145 yield wp.wen.eq(1<<1)
146 yield
147 yield wp.wen.eq(0)
148 yield rp1.ren.eq(1<<1)
149 yield
150 data = yield rp1.data_o
151 print (hex(data))
152 assert data == 2
153
154 # full port read (whole reg)
155 yield dut.full_rd.ren.eq(0xff)
156 yield
157 yield dut.full_rd.ren.eq(0)
158 data = yield dut.full_rd.data_o
159 print (hex(data))
160
161 # simultaneous read/write: full-write, part-write, 3x part-read
162 yield rp1.ren.eq(1<<5)
163 yield rp2.ren.eq(1<<1)
164 yield rp3.ren.eq(1<<3)
165 yield wp.wen.eq(1<<3)
166 yield wp.data_i.eq(6)
167 yield dut.full_wr.wen.eq((1<<1) | (1<<5))
168 yield dut.full_wr.data_i.eq((0xa<<(1*4)) | (0x3<<(5*4)))
169 yield
170 yield dut.full_wr.wen.eq(0)
171 yield wp.wen.eq(0)
172 yield rp1.ren.eq(0)
173 yield rp2.ren.eq(0)
174 yield rp3.ren.eq(0)
175 data1 = yield rp1.data_o
176 print (hex(data1))
177 assert data1 == 0x3
178 data2 = yield rp2.data_o
179 print (hex(data2))
180 assert data2 == 0xa
181 data3 = yield rp3.data_o
182 print (hex(data3))
183 assert data3 == 0x6
184
185
186 def test_regfile():
187 dut = VirtualRegPort(32, 8)
188 rp1 = dut.read_port("read1")
189 rp2 = dut.read_port("read2")
190 rp3 = dut.read_port("read3")
191 wp = dut.write_port("write")
192
193 ports=dut.ports()
194 print ("ports", ports)
195 vl = rtlil.convert(dut, ports=ports)
196 with open("test_virtualregfile.il", "w") as f:
197 f.write(vl)
198
199 run_simulation(dut, regfile_array_sim(dut, rp1, rp2, rp3, wp),
200 vcd_name='test_regfile_array.vcd')
201
202 if __name__ == '__main__':
203 test_regfile()
204
205