1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
import Module
, Signal
, Cat
, Const
, Repl
, Elaboratable
4 from nmigen
.lib
.coding
import Decoder
6 from nmutil
.picker
import PriorityPicker
9 class RegDecode(Elaboratable
):
10 """ decodes registers into unary
14 * :wid: register file width
16 def __init__(self
, wid
):
20 self
.enable_i
= Signal(reset_less
=True) # enable decoders
21 self
.dest_i
= Signal(range(wid
), reset_less
=True) # Dest R# in
22 self
.src1_i
= Signal(range(wid
), reset_less
=True) # oper1 R# in
23 self
.src2_i
= Signal(range(wid
), reset_less
=True) # oper2 R# in
26 self
.dest_o
= Signal(wid
, reset_less
=True) # Dest unary out
27 self
.src1_o
= Signal(wid
, reset_less
=True) # oper1 unary out
28 self
.src2_o
= Signal(wid
, reset_less
=True) # oper2 unary out
30 def elaborate(self
, platform
):
32 m
.submodules
.dest_d
= dest_d
= Decoder(self
.reg_width
)
33 m
.submodules
.src1_d
= src1_d
= Decoder(self
.reg_width
)
34 m
.submodules
.src2_d
= src2_d
= Decoder(self
.reg_width
)
36 # dest decoder: write-pending
37 for d
, i
, o
in [(dest_d
, self
.dest_i
, self
.dest_o
),
38 (src1_d
, self
.src1_i
, self
.src1_o
),
39 (src2_d
, self
.src2_i
, self
.src2_o
)]:
41 m
.d
.comb
+= d
.n
.eq(~self
.enable_i
)
59 class IssueUnitGroup(Elaboratable
):
60 """ Manages a batch of Computation Units all of which can do the same task
62 A priority picker will allocate one instruction in this cycle based
63 on whether the others are busy.
65 insn_i indicates to this module that there is an instruction to be
66 issued which this group can handle
68 busy_i is a vector of signals that indicate, in this cycle, which
69 of the units are currently busy.
71 busy_o indicates whether it is "safe to proceed" i.e. whether
72 there is a unit here that can *be* issued an instruction
74 fn_issue_o indicates, out of the available (non-busy) units,
75 which one may be selected
77 def __init__(self
, n_insns
):
78 """ Set up inputs and outputs for the Group
82 * :n_insns: number of instructions in this issue unit.
84 self
.n_insns
= n_insns
87 self
.insn_i
= Signal(reset_less
=True, name
="insn_i")
88 self
.busy_i
= Signal(n_insns
, reset_less
=True, name
="busy_i")
91 self
.fn_issue_o
= Signal(n_insns
, reset_less
=True, name
="fn_issue_o")
92 self
.busy_o
= Signal(reset_less
=True)
94 def elaborate(self
, platform
):
100 m
.submodules
.pick
= pick
= PriorityPicker(self
.n_insns
)
103 allissue
= Signal(self
.n_insns
, reset_less
=True)
105 m
.d
.comb
+= allissue
.eq(Repl(self
.insn_i
, self
.n_insns
))
106 # Pick one (and only one) of the units to proceed in this cycle
107 m
.d
.comb
+= pick
.i
.eq(~self
.busy_i
& allissue
)
109 # "Safe to issue" condition is basically when all units are not busy
110 m
.d
.comb
+= self
.busy_o
.eq(~
((~self
.busy_i
).bool()))
112 # Picker only raises one signal, therefore it's also the fn_issue
113 busys
= Repl(~self
.busy_o
, self
.n_insns
)
114 m
.d
.comb
+= self
.fn_issue_o
.eq(pick
.o
& busys
)
121 yield self
.fn_issue_o
128 class IssueUnitArray(Elaboratable
):
129 """ Convenience module that amalgamates the issue and busy signals
131 unit issue_i is to be set externally, at the same time as the
134 def __init__(self
, units
):
136 self
.issue_o
= Signal(reset_less
=True)
139 n_insns
+= len(u
.fn_issue_o
)
140 self
.busy_i
= Signal(n_insns
, reset_less
=True)
141 self
.fn_issue_o
= Signal(n_insns
, reset_less
=True)
142 self
.n_insns
= n_insns
144 def elaborate(self
, platform
):
146 for i
, u
in enumerate(self
.units
):
147 setattr(m
.submodules
, "issue%d" % i
, u
)
153 busy_i
.append(u
.busy_i
)
154 g_issue_o
.append(u
.busy_o
)
155 fn_issue_o
.append(u
.fn_issue_o
)
156 m
.d
.comb
+= self
.issue_o
.eq(~
(Cat(*g_issue_o
).bool()))
157 m
.d
.comb
+= self
.fn_issue_o
.eq(Cat(*fn_issue_o
))
158 m
.d
.comb
+= Cat(*busy_i
).eq(self
.busy_i
)
165 yield self
.fn_issue_o
166 yield from self
.units
170 class IssueUnit(Elaboratable
):
171 """ implements 11.4.14 issue unit, p50
175 * :n_insns: number of instructions in this issue unit.
177 def __init__(self
, n_insns
):
178 self
.n_insns
= n_insns
181 self
.insn_i
= Signal(n_insns
, reset_less
=True, name
="insn_i")
182 self
.busy_i
= Signal(n_insns
, reset_less
=True, name
="busy_i")
185 self
.fn_issue_o
= Signal(n_insns
, reset_less
=True, name
="fn_issue_o")
186 self
.g_issue_o
= Signal(reset_less
=True)
188 def elaborate(self
, platform
):
191 if self
.n_insns
== 0:
195 fu_stall
= Signal(reset_less
=True)
198 for i
in range(self
.n_insns
):
199 ib_l
.append(self
.insn_i
[i
] & self
.busy_i
[i
])
200 m
.d
.comb
+= fu_stall
.eq(Cat(*ib_l
).bool())
201 m
.d
.comb
+= self
.g_issue_o
.eq(~
(fu_stall
))
202 for i
in range(self
.n_insns
):
203 m
.d
.comb
+= self
.fn_issue_o
[i
].eq(self
.g_issue_o
& self
.insn_i
[i
])
210 yield self
.fn_issue_o
217 class IntFPIssueUnit(Elaboratable
):
218 def __init__(self
, n_int_insns
, n_fp_insns
):
219 self
.i
= IssueUnit(n_int_insns
)
220 self
.f
= IssueUnit(n_fp_insns
)
221 self
.issue_o
= Signal(reset_less
=True)
223 def elaborate(self
, platform
):
225 m
.submodules
.intissue
= self
.i
226 m
.submodules
.fpissue
= self
.f
228 m
.d
.comb
+= self
.issue_o
.eq(self
.i
.g_issue_o | self
.f
.g_issue_o
)
238 def issue_unit_sim(dut
):
239 yield dut
.dest_i
.eq(1)
240 yield dut
.issue_i
.eq(1)
242 yield dut
.issue_i
.eq(0)
244 yield dut
.src1_i
.eq(1)
245 yield dut
.issue_i
.eq(1)
249 yield dut
.issue_i
.eq(0)
251 yield dut
.go_rd_i
.eq(1)
253 yield dut
.go_rd_i
.eq(0)
255 yield dut
.go_wr_i
.eq(1)
257 yield dut
.go_wr_i
.eq(0)
260 def test_issue_unit():
261 dut
= IssueUnitGroup(3)
262 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
263 with
open("test_issue_unit_group.il", "w") as f
:
266 dut
= IssueUnit(32, 3)
267 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
268 with
open("test_issue_unit.il", "w") as f
:
271 dut
= IntFPIssueUnit(32, 3, 3)
272 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
273 with
open("test_intfp_issue_unit.il", "w") as f
:
276 run_simulation(dut
, issue_unit_sim(dut
), vcd_name
='test_issue_unit.vcd')
278 if __name__
== '__main__':