start putting LDSTSplitter together
[soc.git] / src / soc / scoreboard / issue_unit.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3 from nmigen import Module, Signal, Cat, Array, Const, Repl, Elaboratable
4 from nmigen.lib.coding import Decoder
5
6 from soc.scoreboard.group_picker import PriorityPicker
7
8
9 class RegDecode(Elaboratable):
10 """ decodes registers into unary
11
12 Inputs
13
14 * :wid: register file width
15 """
16 def __init__(self, wid):
17 self.reg_width = wid
18
19 # inputs
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
24
25 # outputs
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
29
30 def elaborate(self, platform):
31 m = Module()
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)
35
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)]:
40 m.d.comb += d.i.eq(i)
41 m.d.comb += d.n.eq(~self.enable_i)
42 m.d.comb += o.eq(d.o)
43
44 return m
45
46 def __iter__(self):
47 yield self.enable_i
48 yield self.dest_i
49 yield self.src1_i
50 yield self.src2_i
51 yield self.dest_o
52 yield self.src1_o
53 yield self.src2_o
54
55 def ports(self):
56 return list(self)
57
58
59 class IssueUnitGroup(Elaboratable):
60 """ Manages a batch of Computation Units all of which can do the same task
61
62 A priority picker will allocate one instruction in this cycle based
63 on whether the others are busy.
64
65 insn_i indicates to this module that there is an instruction to be
66 issued which this group can handle
67
68 busy_i is a vector of signals that indicate, in this cycle, which
69 of the units are currently busy.
70
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
73
74 fn_issue_o indicates, out of the available (non-busy) units,
75 which one may be selected
76 """
77 def __init__(self, n_insns):
78 """ Set up inputs and outputs for the Group
79
80 Input Parameters
81
82 * :n_insns: number of instructions in this issue unit.
83 """
84 self.n_insns = n_insns
85
86 # inputs
87 self.insn_i = Signal(reset_less=True, name="insn_i")
88 self.busy_i = Signal(n_insns, reset_less=True, name="busy_i")
89
90 # outputs
91 self.fn_issue_o = Signal(n_insns, reset_less=True, name="fn_issue_o")
92 self.busy_o = Signal(reset_less=True)
93
94 def elaborate(self, platform):
95 m = Module()
96
97 if self.n_insns == 0:
98 return m
99
100 m.submodules.pick = pick = PriorityPicker(self.n_insns)
101
102 # temporaries
103 allissue = Signal(self.n_insns, reset_less=True)
104
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)
108
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()))
111
112 # Picker only raises one signal, therefore it's also the fn_issue
113 m.d.comb += self.fn_issue_o.eq(pick.o & Repl(~self.busy_o, self.n_insns))
114
115 return m
116
117 def __iter__(self):
118 yield self.insn_i
119 yield self.busy_i
120 yield self.fn_issue_o
121 yield self.g_issue_o
122
123 def ports(self):
124 return list(self)
125
126
127 class IssueUnitArray(Elaboratable):
128 """ Convenience module that amalgamates the issue and busy signals
129
130 unit issue_i is to be set externally, at the same time as the
131 ALU group oper_i
132 """
133 def __init__(self, units):
134 self.units = units
135 self.issue_o = Signal(reset_less=True)
136 n_insns = 0
137 for u in self.units:
138 n_insns += len(u.fn_issue_o)
139 self.busy_i = Signal(n_insns, reset_less=True)
140 self.fn_issue_o = Signal(n_insns, reset_less=True)
141 self.n_insns = n_insns
142
143 def elaborate(self, platform):
144 m = Module()
145 for i, u in enumerate(self.units):
146 setattr(m.submodules, "issue%d" % i, u)
147
148 g_issue_o = []
149 busy_i = []
150 fn_issue_o = []
151 for u in self.units:
152 busy_i.append(u.busy_i)
153 g_issue_o.append(u.busy_o)
154 fn_issue_o.append(u.fn_issue_o)
155 m.d.comb += self.issue_o.eq(~(Cat(*g_issue_o).bool()))
156 m.d.comb += self.fn_issue_o.eq(Cat(*fn_issue_o))
157 m.d.comb += Cat(*busy_i).eq(self.busy_i)
158
159 return m
160
161 def ports(self):
162 yield self.busy_i
163 yield self.issue_o
164 yield self.fn_issue_o
165 yield from self.units
166
167
168
169 class IssueUnit(Elaboratable):
170 """ implements 11.4.14 issue unit, p50
171
172 Inputs
173
174 * :n_insns: number of instructions in this issue unit.
175 """
176 def __init__(self, n_insns):
177 self.n_insns = n_insns
178
179 # inputs
180 self.insn_i = Signal(n_insns, reset_less=True, name="insn_i")
181 self.busy_i = Signal(n_insns, reset_less=True, name="busy_i")
182
183 # outputs
184 self.fn_issue_o = Signal(n_insns, reset_less=True, name="fn_issue_o")
185 self.g_issue_o = Signal(reset_less=True)
186
187 def elaborate(self, platform):
188 m = Module()
189
190 if self.n_insns == 0:
191 return m
192
193 # temporaries
194 fu_stall = Signal(reset_less=True)
195
196 ib_l = []
197 for i in range(self.n_insns):
198 ib_l.append(self.insn_i[i] & self.busy_i[i])
199 m.d.comb += fu_stall.eq(Cat(*ib_l).bool())
200 m.d.comb += self.g_issue_o.eq(~(fu_stall))
201 for i in range(self.n_insns):
202 m.d.comb += self.fn_issue_o[i].eq(self.g_issue_o & self.insn_i[i])
203
204 return m
205
206 def __iter__(self):
207 yield self.insn_i
208 yield self.busy_i
209 yield self.fn_issue_o
210 yield self.g_issue_o
211
212 def ports(self):
213 return list(self)
214
215
216 class IntFPIssueUnit(Elaboratable):
217 def __init__(self, n_int_insns, n_fp_insns):
218 self.i = IssueUnit(n_int_insns)
219 self.f = IssueUnit(n_fp_insns)
220 self.issue_o = Signal(reset_less=True)
221
222 def elaborate(self, platform):
223 m = Module()
224 m.submodules.intissue = self.i
225 m.submodules.fpissue = self.f
226
227 m.d.comb += self.issue_o.eq(self.i.g_issue_o | self.f.g_issue_o)
228
229 return m
230
231 def ports(self):
232 yield self.issue_o
233 yield from self.i
234 yield from self.f
235
236
237 def issue_unit_sim(dut):
238 yield dut.dest_i.eq(1)
239 yield dut.issue_i.eq(1)
240 yield
241 yield dut.issue_i.eq(0)
242 yield
243 yield dut.src1_i.eq(1)
244 yield dut.issue_i.eq(1)
245 yield
246 yield
247 yield
248 yield dut.issue_i.eq(0)
249 yield
250 yield dut.go_rd_i.eq(1)
251 yield
252 yield dut.go_rd_i.eq(0)
253 yield
254 yield dut.go_wr_i.eq(1)
255 yield
256 yield dut.go_wr_i.eq(0)
257 yield
258
259 def test_issue_unit():
260 dut = IssueUnitGroup(3)
261 vl = rtlil.convert(dut, ports=dut.ports())
262 with open("test_issue_unit_group.il", "w") as f:
263 f.write(vl)
264
265 dut = IssueUnit(32, 3)
266 vl = rtlil.convert(dut, ports=dut.ports())
267 with open("test_issue_unit.il", "w") as f:
268 f.write(vl)
269
270 dut = IntFPIssueUnit(32, 3, 3)
271 vl = rtlil.convert(dut, ports=dut.ports())
272 with open("test_intfp_issue_unit.il", "w") as f:
273 f.write(vl)
274
275 run_simulation(dut, issue_unit_sim(dut), vcd_name='test_issue_unit.vcd')
276
277 if __name__ == '__main__':
278 test_issue_unit()