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 data2
= yield rp2
.data_o
99 data
= yield rp1
.data_o
102 # full port read (whole reg)
103 yield dut
.full_rd
.ren
.eq(0xff)
105 yield dut
.full_rd
.ren
.eq(0)
106 data
= yield dut
.full_rd
.data_o
109 # full port read (part reg)
110 yield dut
.full_rd
.ren
.eq(0x1<<5)
112 yield dut
.full_rd
.ren
.eq(0)
113 data
= yield dut
.full_rd
.data_o
116 # full port part-write (part masked reg)
117 yield dut
.full_wr
.wen
.eq(0x1<<1)
118 yield dut
.full_wr
.data_i
.eq(0xe0)
120 yield dut
.full_wr
.wen
.eq(0x0)
122 # full port read (whole reg)
123 yield dut
.full_rd
.ren
.eq(0xff)
125 yield dut
.full_rd
.ren
.eq(0)
126 data
= yield dut
.full_rd
.data_o
130 yield dut
.full_wr
.wen
.eq(0xff)
131 yield dut
.full_wr
.data_i
.eq(0xcafeface)
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 wp
.data_i
.eq(2)
144 yield wp
.wen
.eq(1<<1)
147 yield rp1
.ren
.eq(1<<1)
149 data
= yield rp1
.data_o
153 # full port read (whole reg)
154 yield dut
.full_rd
.ren
.eq(0xff)
156 yield dut
.full_rd
.ren
.eq(0)
157 data
= yield dut
.full_rd
.data_o
160 # simultaneous read/write: full-write, part-write, 3x part-read
161 yield rp1
.ren
.eq(1<<5)
162 yield rp2
.ren
.eq(1<<1)
163 yield rp3
.ren
.eq(1<<3)
164 yield wp
.wen
.eq(1<<3)
165 yield wp
.data_i
.eq(6)
166 yield dut
.full_wr
.wen
.eq((1<<1) |
(1<<5))
167 yield dut
.full_wr
.data_i
.eq((0xa<<(1*4)) |
(0x3<<(5*4)))
169 yield dut
.full_wr
.wen
.eq(0)
174 data1
= yield rp1
.data_o
177 data2
= yield rp2
.data_o
180 data3
= yield rp3
.data_o
186 dut
= VirtualRegPort(32, 8)
187 rp1
= dut
.read_port("read1")
188 rp2
= dut
.read_port("read2")
189 rp3
= dut
.read_port("read3")
190 wp
= dut
.write_port("write")
193 print ("ports", ports
)
194 vl
= rtlil
.convert(dut
, ports
=ports
)
195 with
open("test_virtualregfile.il", "w") as f
:
198 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, rp3
, wp
),
199 vcd_name
='test_regfile_array.vcd')
201 if __name__
== '__main__':