1 """VirtualRegPort - terrible name for a complex register class
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.
11 from nmigen
.compat
.sim
import run_simulation
12 from nmigen
.cli
import verilog
, rtlil
14 from nmigen
import Cat
, Const
, Array
, Signal
, Elaboratable
, Module
15 from nmutil
.iocontrol
import RecordObject
17 from soc
.regfile
.regfile
import RegFileArray
20 class VirtualRegPort(RegFileArray
):
21 def __init__(self
, bitwidth
, n_regs
):
22 self
.bitwidth
= bitwidth
24 self
.regwidth
= regwidth
= bitwidth
// n_regs
25 super().__init
__(self
.regwidth
, n_regs
)
27 # "full" depth variant of the "external" port
28 self
.full_wr
= RecordObject([("wen", n_regs
),
29 ("data_i", bitwidth
)], # *full* wid
31 self
.full_rd
= RecordObject([("ren", n_regs
),
32 ("data_o", bitwidth
)], # *full* wid
35 def elaborate(self
, platform
):
36 m
= super().elaborate(platform
)
39 # for internal use only.
40 wr_regs
= self
.write_reg_port(f
"w")
41 rd_regs
= self
.read_reg_port(f
"r")
43 # connect up full read port
46 # wire up the enable signals and chain-accumulate the data
47 l
= map(lambda port
: port
.data_o
, rd_regs
) # get port data(s)
48 le
= map(lambda port
: port
.ren
, rd_regs
) # get port ren(s)
50 comb
+= rfull
.data_o
.eq(Cat(*l
)) # we like Cat on lists
51 comb
+= Cat(*le
).eq(rfull
.ren
)
53 # connect up full write port
56 # wire up the enable signals from the large (full) port
57 l
= map(lambda port
: port
.data_i
, wr_regs
)
58 le
= map(lambda port
: port
.wen
, wr_regs
) # get port wen(s)
60 # get list of all data_i (and wens) and assign to them via Cat
61 comb
+= Cat(*l
).eq(wfull
.data_i
)
62 comb
+= Cat(*le
).eq(wfull
.wen
)
67 yield from super().__iter
__()
68 yield from self
.full_wr
69 yield from self
.full_rd
72 def regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
):
75 yield wp
.wen
.eq(1 << 1)
79 yield rp1
.ren
.eq(1 << 1)
81 data
= yield rp1
.data_o
85 # simultaneous read/write - should be pass-thru
86 yield rp1
.ren
.eq(1 << 5)
87 yield rp2
.ren
.eq(1 << 1)
88 yield wp
.wen
.eq(1 << 5)
94 data1
= yield rp1
.data_o
96 assert data1
== 6, data1
97 data2
= yield rp2
.data_o
99 assert data2
== 2, data2
101 data
= yield rp1
.data_o
104 # full port read (whole reg)
105 yield dut
.full_rd
.ren
.eq(0xff)
107 yield dut
.full_rd
.ren
.eq(0)
108 data
= yield dut
.full_rd
.data_o
111 # full port read (part reg)
112 yield dut
.full_rd
.ren
.eq(0x1 << 5)
114 yield dut
.full_rd
.ren
.eq(0)
115 data
= yield dut
.full_rd
.data_o
118 # full port part-write (part masked reg)
119 yield dut
.full_wr
.wen
.eq(0x1 << 1)
120 yield dut
.full_wr
.data_i
.eq(0xe0)
122 yield dut
.full_wr
.wen
.eq(0x0)
124 # full port read (whole reg)
125 yield dut
.full_rd
.ren
.eq(0xff)
127 yield dut
.full_rd
.ren
.eq(0)
128 data
= yield dut
.full_rd
.data_o
132 yield dut
.full_wr
.wen
.eq(0xff)
133 yield dut
.full_wr
.data_i
.eq(0xcafeface)
135 yield dut
.full_wr
.wen
.eq(0x0)
137 # full port read (whole reg)
138 yield dut
.full_rd
.ren
.eq(0xff)
140 yield dut
.full_rd
.ren
.eq(0)
141 data
= yield dut
.full_rd
.data_o
145 yield wp
.data_i
.eq(2)
146 yield wp
.wen
.eq(1 << 1)
149 yield rp1
.ren
.eq(1 << 1)
151 data
= yield rp1
.data_o
155 # full port read (whole reg)
156 yield dut
.full_rd
.ren
.eq(0xff)
158 yield dut
.full_rd
.ren
.eq(0)
159 data
= yield dut
.full_rd
.data_o
162 # simultaneous read/write: full-write, part-write, 3x part-read
163 yield rp1
.ren
.eq(1 << 5)
164 yield rp2
.ren
.eq(1 << 1)
165 yield rp3
.ren
.eq(1 << 3)
166 yield wp
.wen
.eq(1 << 3)
167 yield wp
.data_i
.eq(6)
168 yield dut
.full_wr
.wen
.eq((1 << 1) |
(1 << 5))
169 yield dut
.full_wr
.data_i
.eq((0xa << (1*4)) |
(0x3 << (5*4)))
171 yield dut
.full_wr
.wen
.eq(0)
176 data1
= yield rp1
.data_o
179 data2
= yield rp2
.data_o
182 data3
= yield rp3
.data_o
188 dut
= VirtualRegPort(32, 8)
189 rp1
= dut
.read_port("read1")
190 rp2
= dut
.read_port("read2")
191 rp3
= dut
.read_port("read3")
192 wp
= dut
.write_port("write")
195 print("ports", ports
)
196 vl
= rtlil
.convert(dut
, ports
=ports
)
197 with
open("test_virtualregfile.il", "w") as f
:
200 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
),
201 vcd_name
='test_regfile_array.vcd')
204 if __name__
== '__main__':