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
34 def elaborate(self
, platform
):
35 m
= super().elaborate(platform
)
38 # for internal use only.
39 wr_regs
= self
.write_reg_port(f
"w")
40 rd_regs
= self
.read_reg_port(f
"r")
42 # connect up full read port
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)
49 comb
+= rfull
.data_o
.eq(Cat(*l
)) # we like Cat on lists
50 comb
+= Cat(*le
).eq(rfull
.ren
)
52 # connect up full write port
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)
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
)
66 yield from super().__iter
__()
67 yield from self
.full_wr
68 yield from self
.full_rd
71 def regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
):
78 yield rp1
.ren
.eq(1<<1)
80 data
= yield rp1
.data_o
84 # simultaneous read/write - should be pass-thru
85 yield rp1
.ren
.eq(1<<5)
86 yield rp2
.ren
.eq(1<<1)
93 data1
= yield rp1
.data_o
95 assert data1
== 6, data1
96 data2
= yield rp2
.data_o
98 assert data2
== 2, data2
100 data
= yield rp1
.data_o
103 # full port read (whole reg)
104 yield dut
.full_rd
.ren
.eq(0xff)
106 yield dut
.full_rd
.ren
.eq(0)
107 data
= yield dut
.full_rd
.data_o
110 # full port read (part reg)
111 yield dut
.full_rd
.ren
.eq(0x1<<5)
113 yield dut
.full_rd
.ren
.eq(0)
114 data
= yield dut
.full_rd
.data_o
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)
121 yield dut
.full_wr
.wen
.eq(0x0)
123 # full port read (whole reg)
124 yield dut
.full_rd
.ren
.eq(0xff)
126 yield dut
.full_rd
.ren
.eq(0)
127 data
= yield dut
.full_rd
.data_o
131 yield dut
.full_wr
.wen
.eq(0xff)
132 yield dut
.full_wr
.data_i
.eq(0xcafeface)
134 yield dut
.full_wr
.wen
.eq(0x0)
136 # full port read (whole reg)
137 yield dut
.full_rd
.ren
.eq(0xff)
139 yield dut
.full_rd
.ren
.eq(0)
140 data
= yield dut
.full_rd
.data_o
144 yield wp
.data_i
.eq(2)
145 yield wp
.wen
.eq(1<<1)
148 yield rp1
.ren
.eq(1<<1)
150 data
= yield rp1
.data_o
154 # full port read (whole reg)
155 yield dut
.full_rd
.ren
.eq(0xff)
157 yield dut
.full_rd
.ren
.eq(0)
158 data
= yield dut
.full_rd
.data_o
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)))
170 yield dut
.full_wr
.wen
.eq(0)
175 data1
= yield rp1
.data_o
178 data2
= yield rp2
.data_o
181 data3
= yield rp3
.data_o
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")
194 print ("ports", ports
)
195 vl
= rtlil
.convert(dut
, ports
=ports
)
196 with
open("test_virtualregfile.il", "w") as f
:
199 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
),
200 vcd_name
='test_regfile_array.vcd')
202 if __name__
== '__main__':