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
):
18 def read_port(self
, name
=None):
19 port
= RecordObject([("ren", 1),
20 ("data_o", self
.width
)],
22 self
._rdports
.append(port
)
25 def write_port(self
, name
=None):
26 port
= RecordObject([("wen", 1),
27 ("data_i", self
.width
)],
29 self
._wrports
.append(port
)
32 def elaborate(self
, platform
):
34 self
.reg
= reg
= Signal(self
.width
, name
="reg")
36 # read ports. has write-through detection (returns data written)
37 for rp
in self
._rdports
:
38 wr_detect
= Signal(reset_less
=False)
40 m
.d
.comb
+= wr_detect
.eq(0)
41 for wp
in self
._wrports
:
43 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
44 m
.d
.comb
+= wr_detect
.eq(1)
45 with m
.If(~wr_detect
):
46 m
.d
.comb
+= rp
.data_o
.eq(reg
)
48 # write ports, don't allow write to address 0 (ignore it)
49 for wp
in self
._wrports
:
51 m
.d
.sync
+= reg
.eq(wp
.data_i
)
56 for p
in self
._rdports
:
58 for p
in self
._wrports
:
65 #print ("treereduce", tree)
66 if not isinstance(tree
, list):
71 return tree
[0].data_o | tree
[1].data_o
72 splitpoint
= len(tree
) // 2
73 return treereduce(tree
[:splitpoint
]) |
treereduce(tree
[splitpoint
:])
76 class RegFileArray(Elaboratable
):
77 """ an array-based register file (register having write-through capability)
78 that has no "address" decoder, instead it has individual write-en
79 and read-en signals (per port).
81 def __init__(self
, width
, depth
):
84 self
.regs
= Array(Register(width
) for _
in range(self
.depth
))
88 def read_port(self
, name
=None):
90 for i
in range(self
.depth
):
91 port
= self
.regs
[i
].read_port(name
)
94 port
= RecordObject([("ren", self
.depth
),
95 ("data_o", self
.width
)], name
)
96 self
._rdports
.append((regs
, port
))
99 def write_port(self
, name
=None):
101 for i
in range(self
.depth
):
102 port
= self
.regs
[i
].write_port(name
)
105 port
= RecordObject([("wen", self
.depth
),
106 ("data_i", self
.width
)])
107 self
._wrports
.append((regs
, port
))
110 def _get_en_sig(self
, port
, typ
):
116 def elaborate(self
, platform
):
118 for i
, reg
in enumerate(self
.regs
):
119 setattr(m
.submodules
, "reg_%d" % i
, reg
)
121 for (regs
, p
) in self
._rdports
:
123 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'ren').eq(p
.ren
)
124 ror
= treereduce(list(regs
))
125 m
.d
.comb
+= p
.data_o
.eq(ror
)
126 for (regs
, p
) in self
._wrports
:
127 m
.d
.comb
+= self
._get
_en
_sig
(regs
, 'wen').eq(p
.wen
)
129 m
.d
.comb
+= r
.data_i
.eq(p
.data_i
)
141 class RegFile(Elaboratable
):
142 def __init__(self
, width
, depth
):
149 bsz
= int(log(self
.width
) / log(2))
150 port
= RecordObject([("raddr", bsz
),
152 ("data_o", self
.width
)])
153 self
._rdports
.append(port
)
156 def write_port(self
):
157 bsz
= int(log(self
.width
) / log(2))
158 port
= RecordObject([("waddr", bsz
),
160 ("data_i", self
.width
)])
161 self
._wrports
.append(port
)
164 def elaborate(self
, platform
):
166 bsz
= int(log(self
.width
) / log(2))
167 regs
= Array(Signal(self
.width
, name
="reg") for _
in range(self
.depth
))
169 # read ports. has write-through detection (returns data written)
170 for rp
in self
._rdports
:
171 wr_detect
= Signal(reset_less
=False)
173 m
.d
.comb
+= wr_detect
.eq(0)
174 for wp
in self
._wrports
:
175 addrmatch
= Signal(reset_less
=False)
176 m
.d
.comb
+= addrmatch
.eq(wp
.waddr
== rp
.raddr
)
177 with m
.If(wp
.wen
& addrmatch
):
178 m
.d
.comb
+= rp
.data_o
.eq(wp
.data_i
)
179 m
.d
.comb
+= wr_detect
.eq(1)
180 with m
.If(~wr_detect
):
181 m
.d
.comb
+= rp
.data_o
.eq(regs
[rp
.raddr
])
183 # write ports, don't allow write to address 0 (ignore it)
184 for wp
in self
._wrports
:
185 with m
.If(wp
.wen
& (wp
.waddr
!= Const(0, bsz
))):
186 m
.d
.sync
+= regs
[wp
.waddr
].eq(wp
.data_i
)
191 yield from self
._rdports
192 yield from self
._wrports
197 if isinstance(r
, RecordObject
):
202 def regfile_sim(dut
, rp
, wp
):
204 yield wp
.data_i
.eq(2)
211 data
= yield rp
.data_o
219 yield wp
.data_i
.eq(6)
220 data
= yield rp
.data_o
225 data
= yield rp
.data_o
229 data
= yield rp
.data_o
235 wp
= dut
.write_port()
236 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
237 with
open("test_regfile.il", "w") as f
:
240 run_simulation(dut
, regfile_sim(dut
, rp
, wp
), vcd_name
='test_regfile.vcd')
242 dut
= RegFileArray(32, 8)
243 rp
= dut
.read_port("read")
244 wp
= dut
.write_port("write")
246 print ("ports", ports
)
247 vl
= rtlil
.convert(dut
, ports
=ports
)
248 with
open("test_regfile_array.il", "w") as f
:
251 #run_simulation(dut, regfile_sim(dut, rp, wp), vcd_name='test_regfile.vcd')
253 if __name__
== '__main__':