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
, rd2
=False):
22 self
.bitwidth
= bitwidth
24 self
.rd2
= rd2
# eurgh hack
25 self
.regwidth
= regwidth
= bitwidth
// n_regs
26 super().__init
__(self
.regwidth
, n_regs
)
28 # "full" depth variant of the "external" port
29 self
.full_wr
= RecordObject([("wen", n_regs
),
30 ("data_i", bitwidth
)], # *full* wid
32 self
.full_rd
= RecordObject([("ren", n_regs
),
33 ("data_o", bitwidth
)], # *full* wid
37 self
.full_rd2
= RecordObject([("ren", n_regs
),
38 ("data_o", bitwidth
)], # *full* wid
41 def connect_full_rd(self
, m
, rfull
, name
):
43 rd_regs
= self
.read_reg_port(name
)
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 def elaborate(self
, platform
):
53 m
= super().elaborate(platform
)
56 # for internal use only.
57 wr_regs
= self
.write_reg_port(f
"w")
59 # connect up full read port
60 self
.connect_full_rd(m
, self
.full_rd
, "r")
62 self
.connect_full_rd(m
, self
.full_rd2
, "r2")
64 # connect up full write port
67 # wire up the enable signals from the large (full) port
68 l
= map(lambda port
: port
.data_i
, wr_regs
)
69 le
= map(lambda port
: port
.wen
, wr_regs
) # get port wen(s)
71 # get list of all data_i (and wens) and assign to them via Cat
72 comb
+= Cat(*l
).eq(wfull
.data_i
)
73 comb
+= Cat(*le
).eq(wfull
.wen
)
78 yield from super().__iter
__()
79 yield from self
.full_wr
80 yield from self
.full_rd
83 def regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
):
86 yield wp
.wen
.eq(1 << 1)
90 yield rp1
.ren
.eq(1 << 1)
92 data
= yield rp1
.data_o
96 # simultaneous read/write - should be pass-thru
97 yield rp1
.ren
.eq(1 << 5)
98 yield rp2
.ren
.eq(1 << 1)
99 yield wp
.wen
.eq(1 << 5)
100 yield wp
.data_i
.eq(6)
105 data1
= yield rp1
.data_o
107 assert data1
== 6, data1
108 data2
= yield rp2
.data_o
110 assert data2
== 2, data2
112 data
= yield rp1
.data_o
115 # full port read (whole reg)
116 yield dut
.full_rd
.ren
.eq(0xff)
118 yield dut
.full_rd
.ren
.eq(0)
119 data
= yield dut
.full_rd
.data_o
122 # full port read (part reg)
123 yield dut
.full_rd
.ren
.eq(0x1 << 5)
125 yield dut
.full_rd
.ren
.eq(0)
126 data
= yield dut
.full_rd
.data_o
129 # full port part-write (part masked reg)
130 yield dut
.full_wr
.wen
.eq(0x1 << 1)
131 yield dut
.full_wr
.data_i
.eq(0xe0)
133 yield dut
.full_wr
.wen
.eq(0x0)
135 # full port read (whole reg)
136 yield dut
.full_rd
.ren
.eq(0xff)
138 yield dut
.full_rd
.ren
.eq(0)
139 data
= yield dut
.full_rd
.data_o
143 yield dut
.full_wr
.wen
.eq(0xff)
144 yield dut
.full_wr
.data_i
.eq(0xcafeface)
146 yield dut
.full_wr
.wen
.eq(0x0)
148 # full port read (whole reg)
149 yield dut
.full_rd
.ren
.eq(0xff)
151 yield dut
.full_rd
.ren
.eq(0)
152 data
= yield dut
.full_rd
.data_o
156 yield wp
.data_i
.eq(2)
157 yield wp
.wen
.eq(1 << 1)
160 yield rp1
.ren
.eq(1 << 1)
162 data
= yield rp1
.data_o
166 # full port read (whole reg)
167 yield dut
.full_rd
.ren
.eq(0xff)
169 yield dut
.full_rd
.ren
.eq(0)
170 data
= yield dut
.full_rd
.data_o
173 # simultaneous read/write: full-write, part-write, 3x part-read
174 yield rp1
.ren
.eq(1 << 5)
175 yield rp2
.ren
.eq(1 << 1)
176 yield rp3
.ren
.eq(1 << 3)
177 yield wp
.wen
.eq(1 << 3)
178 yield wp
.data_i
.eq(6)
179 yield dut
.full_wr
.wen
.eq((1 << 1) |
(1 << 5))
180 yield dut
.full_wr
.data_i
.eq((0xa << (1*4)) |
(0x3 << (5*4)))
182 yield dut
.full_wr
.wen
.eq(0)
187 data1
= yield rp1
.data_o
190 data2
= yield rp2
.data_o
193 data3
= yield rp3
.data_o
199 dut
= VirtualRegPort(32, 8)
200 rp1
= dut
.read_port("read1")
201 rp2
= dut
.read_port("read2")
202 rp3
= dut
.read_port("read3")
203 wp
= dut
.write_port("write")
206 print("ports", ports
)
207 vl
= rtlil
.convert(dut
, ports
=ports
)
208 with
open("test_virtualregfile.il", "w") as f
:
211 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
),
212 vcd_name
='test_regfile_array.vcd')
215 if __name__
== '__main__':