1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
4 from nmigen
import Cat
, Const
, Array
, Signal
, Elaboratable
, Module
5 from nmutil
.iocontrol
import RecordObject
8 from functools
import reduce
12 class Register(Elaboratable
):
13 def __init__(self
, width
, writethru
=False):
15 self
.writethru
= writethru
19 def read_port(self
, name
=None):
20 port
= RecordObject([("ren", 1),
21 ("data_o", self
.width
)],
23 self
._rdports
.append(port
)
26 def write_port(self
, name
=None):
27 port
= RecordObject([("wen", 1),
28 ("data_i", self
.width
)],
30 self
._wrports
.append(port
)
33 def elaborate(self
, platform
):
35 self
.reg
= reg
= Signal(self
.width
, name
="reg")
37 # read ports. has write-through detection (returns data written)
38 for rp
in self
._rdports
:
41 wr_detect
= Signal(reset_less
=False)
42 m
.d
.comb
+= wr_detect
.eq(0)
43 for wp
in self
._wrports
:
45 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
46 m
.d
.comb
+= wr_detect
.eq(1)
47 with m
.If(~wr_detect
):
48 m
.d
.comb
+= rp
.data_o
.eq(reg
)
50 m
.d
.comb
+= rp
.data_o
.eq(reg
)
52 # write ports, don't allow write to address 0 (ignore it)
53 for wp
in self
._wrports
:
55 m
.d
.sync
+= reg
.eq(wp
.data_i
)
60 for p
in self
._rdports
:
62 for p
in self
._wrports
:
69 #print ("treereduce", tree)
70 if not isinstance(tree
, list):
75 return tree
[0].data_o | tree
[1].data_o
76 splitpoint
= len(tree
) // 2
77 return treereduce(tree
[:splitpoint
]) |
treereduce(tree
[splitpoint
:])
80 class RegFileArray(Elaboratable
):
81 """ an array-based register file (register having write-through capability)
82 that has no "address" decoder, instead it has individual write-en
83 and read-en signals (per port).
85 def __init__(self
, width
, depth
):
88 self
.regs
= Array(Register(width
) for _
in range(self
.depth
))
92 def read_port(self
, name
=None):
94 for i
in range(self
.depth
):
95 port
= self
.regs
[i
].read_port(name
)
98 port
= RecordObject([("ren", self
.depth
),
99 ("data_o", self
.width
)], name
)
100 self
._rdports
.append((regs
, port
))
103 def write_port(self
, name
=None):
105 for i
in range(self
.depth
):
106 port
= self
.regs
[i
].write_port(name
)
109 port
= RecordObject([("wen", self
.depth
),
110 ("data_i", self
.width
)])
111 self
._wrports
.append((regs
, port
))
114 def _get_en_sig(self
, port
, typ
):
120 def elaborate(self
, platform
):
122 for i
, reg
in enumerate(self
.regs
):
123 setattr(m
.submodules
, "reg_%d" % i
, reg
)
125 for (regs
, p
) in self
._rdports
:
127 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'ren').eq(p
.ren
)
128 ror
= treereduce(list(regs
))
129 m
.d
.comb
+= p
.data_o
.eq(ror
)
130 for (regs
, p
) in self
._wrports
:
131 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'wen').eq(p
.wen
)
133 m
.d
.comb
+= r
.data_i
.eq(p
.data_i
)
145 class RegFile(Elaboratable
):
146 def __init__(self
, width
, depth
):
153 bsz
= int(log(self
.width
) / log(2))
154 port
= RecordObject([("raddr", bsz
),
156 ("data_o", self
.width
)])
157 self
._rdports
.append(port
)
160 def write_port(self
):
161 bsz
= int(log(self
.width
) / log(2))
162 port
= RecordObject([("waddr", bsz
),
164 ("data_i", self
.width
)])
165 self
._wrports
.append(port
)
168 def elaborate(self
, platform
):
170 bsz
= int(log(self
.width
) / log(2))
171 regs
= Array(Signal(self
.width
, name
="reg") for _
in range(self
.depth
))
173 # read ports. has write-through detection (returns data written)
174 for rp
in self
._rdports
:
175 wr_detect
= Signal(reset_less
=False)
177 m
.d
.comb
+= wr_detect
.eq(0)
178 for wp
in self
._wrports
:
179 addrmatch
= Signal(reset_less
=False)
180 m
.d
.comb
+= addrmatch
.eq(wp
.waddr
== rp
.raddr
)
181 with m
.If(wp
.wen
& addrmatch
):
182 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
183 m
.d
.comb
+= wr_detect
.eq(1)
184 with m
.If(~wr_detect
):
185 m
.d
.comb
+= rp
.data_o
.eq(regs
[rp
.raddr
])
187 # write ports, don't allow write to address 0 (ignore it)
188 for wp
in self
._wrports
:
189 with m
.If(wp
.wen
& (wp
.waddr
!= Const(0, bsz
))):
190 m
.d
.sync
+= regs
[wp
.waddr
].eq(wp
.data_i
)
195 yield from self
._rdports
196 yield from self
._wrports
201 if isinstance(r
, RecordObject
):
206 def regfile_sim(dut
, rp
, wp
):
208 yield wp
.data_i
.eq(2)
215 data
= yield rp
.data_o
223 yield wp
.data_i
.eq(6)
224 data
= yield rp
.data_o
229 data
= yield rp
.data_o
233 data
= yield rp
.data_o
236 def regfile_array_sim(dut
, rp1
, rp2
, wp
):
237 yield wp
.data_i
.eq(2)
238 yield wp
.wen
.eq(1<<1)
241 yield rp1
.ren
.eq(1<<1)
243 data
= yield rp1
.data_o
247 yield rp1
.ren
.eq(1<<5)
248 yield rp2
.ren
.eq(1<<1)
249 yield wp
.wen
.eq(1<<5)
250 yield wp
.data_i
.eq(6)
251 data
= yield rp1
.data_o
257 data1
= yield rp1
.data_o
259 data2
= yield rp2
.data_o
263 data
= yield rp1
.data_o
269 wp
= dut
.write_port()
270 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
271 with
open("test_regfile.il", "w") as f
:
274 run_simulation(dut
, regfile_sim(dut
, rp
, wp
), vcd_name
='test_regfile.vcd')
276 dut
= RegFileArray(32, 8)
277 rp1
= dut
.read_port("read1")
278 rp2
= dut
.read_port("read2")
279 wp
= dut
.write_port("write")
281 print ("ports", ports
)
282 vl
= rtlil
.convert(dut
, ports
=ports
)
283 with
open("test_regfile_array.il", "w") as f
:
286 run_simulation(dut
, regfile_array_sim(dut
, rp1
, rp2
, wp
),
287 vcd_name
='test_regfile_array.vcd')
289 if __name__
== '__main__':