3 These are not "normal" binary-indexed regfiles (although that is included).
4 They include *unary* indexed regfiles as well as Dependency-tracked ones
5 (SPR files with 1024 registers, only around 4-5 of which need to be active)
6 and special "split" regfiles that have 8R8W for 8 4-bit quantities and a
7 1R1W to read/write *all* 8 4-bit registers in a single one-off 32-bit way.
9 Due to the way that the Dependency Matrices are set up (bit-vectors), the
10 primary focus here is on *unary* indexing.
14 * https://libre-soc.org/3d_gpu/architecture/regfile
15 * https://bugs.libre-soc.org/show_bug.cgi?id=345
16 * https://bugs.libre-soc.org/show_bug.cgi?id=351
17 * https://bugs.libre-soc.org/show_bug.cgi?id=352
20 from nmigen
.compat
.sim
import run_simulation
21 from nmigen
.back
.pysim
import Settle
22 from nmigen
.cli
import verilog
, rtlil
24 from nmigen
import Cat
, Const
, Array
, Signal
, Elaboratable
, Module
25 from nmutil
.iocontrol
import RecordObject
26 from nmutil
.util
import treereduce
27 from nmigen
import Memory
33 class Register(Elaboratable
):
34 def __init__(self
, width
, writethru
=True):
36 self
.writethru
= writethru
40 def read_port(self
, name
=None):
41 port
= RecordObject([("ren", 1),
42 ("data_o", self
.width
)],
44 self
._rdports
.append(port
)
47 def write_port(self
, name
=None):
48 port
= RecordObject([("wen", 1),
49 ("data_i", self
.width
)],
51 self
._wrports
.append(port
)
54 def elaborate(self
, platform
):
56 self
.reg
= reg
= Signal(self
.width
, name
="reg")
58 # read ports. has write-through detection (returns data written)
59 for rp
in self
._rdports
:
60 with m
.If(rp
.ren
== 1):
62 wr_detect
= Signal(reset_less
=False)
63 m
.d
.comb
+= wr_detect
.eq(0)
64 for wp
in self
._wrports
:
66 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
67 m
.d
.comb
+= wr_detect
.eq(1)
68 with m
.If(~wr_detect
):
69 m
.d
.comb
+= rp
.data_o
.eq(reg
)
71 m
.d
.comb
+= rp
.data_o
.eq(reg
)
73 m
.d
.comb
+= rp
.data_o
.eq(0)
75 # write ports, delayed by 1 cycle
76 for wp
in self
._wrports
:
78 m
.d
.sync
+= reg
.eq(wp
.data_i
)
83 for p
in self
._rdports
:
85 for p
in self
._wrports
:
92 def ortreereduce(tree
, attr
="data_o"):
93 return treereduce(tree
, operator
.or_
, lambda x
: getattr(x
, attr
))
96 class RegFileArray(Elaboratable
):
98 """ an array-based register file (register having write-through capability)
99 that has no "address" decoder, instead it has individual write-en
100 and read-en signals (per port).
103 def __init__(self
, width
, depth
):
106 self
.regs
= Array(Register(width
) for _
in range(self
.depth
))
110 def read_reg_port(self
, name
=None):
112 for i
in range(self
.depth
):
113 port
= self
.regs
[i
].read_port("%s%d" % (name
, i
))
117 def write_reg_port(self
, name
=None):
119 for i
in range(self
.depth
):
120 port
= self
.regs
[i
].write_port("%s%d" % (name
, i
))
124 def read_port(self
, name
=None):
125 regs
= self
.read_reg_port(name
)
127 port
= RecordObject([("ren", self
.depth
),
128 ("data_o", self
.width
)], name
)
129 self
._rdports
.append((regs
, port
))
132 def write_port(self
, name
=None):
133 regs
= self
.write_reg_port(name
)
135 port
= RecordObject([("wen", self
.depth
),
136 ("data_i", self
.width
)])
137 self
._wrports
.append((regs
, port
))
140 def _get_en_sig(self
, port
, typ
):
146 def elaborate(self
, platform
):
148 for i
, reg
in enumerate(self
.regs
):
149 setattr(m
.submodules
, "reg_%d" % i
, reg
)
151 for (regs
, p
) in self
._rdports
:
153 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'ren').eq(p
.ren
)
154 ror
= ortreereduce(list(regs
))
155 m
.d
.comb
+= p
.data_o
.eq(ror
)
156 for (regs
, p
) in self
._wrports
:
157 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'wen').eq(p
.wen
)
159 m
.d
.comb
+= r
.data_i
.eq(p
.data_i
)
171 class RegFileMem(Elaboratable
):
173 def __init__(self
, width
, depth
):
174 self
.memory
= Memory(width
=width
, depth
=depth
)
178 def read_port(self
, name
=None):
179 port
= self
._rdports
[name
] = self
.memory
.read_port()
182 def write_port(self
, name
=None):
183 port
= self
._wrports
[name
] = self
.memory
.write_port()
186 def elaborate(self
, platform
):
188 for name
, rp
in self
._rdports
.items():
189 setattr(m
.submodules
, "rp_"+name
, rp
)
190 for name
, wp
in self
._wrports
.items():
191 setattr(m
.submodules
, "wp_"+name
, wp
)
195 class RegFile(Elaboratable
):
197 def __init__(self
, width
, depth
):
203 def read_port(self
, name
=None):
204 bsz
= int(log(self
.width
) / log(2))
205 port
= RecordObject([("raddr", bsz
),
207 ("data_o", self
.width
)], name
=name
)
208 self
._rdports
.append(port
)
211 def write_port(self
, name
=None):
212 bsz
= int(log(self
.width
) / log(2))
213 port
= RecordObject([("waddr", bsz
),
215 ("data_i", self
.width
)], name
=name
)
216 self
._wrports
.append(port
)
219 def elaborate(self
, platform
):
221 bsz
= int(log(self
.width
) / log(2))
222 regs
= Array(Signal(self
.width
, name
="reg") for _
in range(self
.depth
))
224 # read ports. has write-through detection (returns data written)
225 for rp
in self
._rdports
:
226 wr_detect
= Signal(reset_less
=False)
228 m
.d
.comb
+= wr_detect
.eq(0)
229 for wp
in self
._wrports
:
230 addrmatch
= Signal(reset_less
=False)
231 m
.d
.comb
+= addrmatch
.eq(wp
.waddr
== rp
.raddr
)
232 with m
.If(wp
.wen
& addrmatch
):
233 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
234 m
.d
.comb
+= wr_detect
.eq(1)
235 with m
.If(~wr_detect
):
236 m
.d
.comb
+= rp
.data_o
.eq(regs
[rp
.raddr
])
238 # write ports, delayed by one cycle
239 for wp
in self
._wrports
:
241 m
.d
.sync
+= regs
[wp
.waddr
].eq(wp
.data_i
)
246 yield from self
._rdports
247 yield from self
._wrports
252 if isinstance(r
, RecordObject
):
258 def regfile_sim(dut
, rp
, wp
):
260 yield wp
.data_i
.eq(2)
267 data
= yield rp
.data_o
276 yield wp
.data_i
.eq(6)
278 data
= yield rp
.data_o
285 data
= yield rp
.data_o
289 data
= yield rp
.data_o
293 def regfile_array_sim(dut
, rp1
, rp2
, wp
, wp2
):
294 print("regfile_array_sim")
295 yield wp
.data_i
.eq(2)
296 yield wp
.wen
.eq(1 << 1)
299 yield rp1
.ren
.eq(1 << 1)
301 data
= yield rp1
.data_o
306 yield rp1
.ren
.eq(1 << 5)
307 yield rp2
.ren
.eq(1 << 1)
308 yield wp
.wen
.eq(1 << 5)
309 yield wp
.data_i
.eq(6)
311 data
= yield rp1
.data_o
319 data1
= yield rp1
.data_o
322 data2
= yield rp2
.data_o
327 data
= yield rp1
.data_o
335 wp
= dut
.write_port()
336 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
337 with
open("test_regfile.il", "w") as f
:
340 run_simulation(dut
, regfile_sim(dut
, rp
, wp
), vcd_name
='test_regfile.vcd')
342 dut
= RegFileArray(32, 8)
343 rp1
= dut
.read_port("read1")
344 rp2
= dut
.read_port("read2")
345 wp
= dut
.write_port("write")
346 wp2
= dut
.write_port("write2")
348 print("ports", ports
)
349 vl
= rtlil
.convert(dut
, ports
=ports
)
350 with
open("test_regfile_array.il", "w") as f
:
353 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, wp
, wp2
),
354 vcd_name
='test_regfile_array.vcd')
357 if __name__
== '__main__':