1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
import Module
, Const
, Signal
, Array
, Cat
, Elaboratable
5 from regfile
.regfile
import RegFileArray
, treereduce
6 from scoreboard
.fn_unit
import IntFnUnit
, FPFnUnit
, LDFnUnit
, STFnUnit
7 from scoreboard
.fu_fu_matrix
import FUFUDepMatrix
8 from scoreboard
.fu_reg_matrix
import FURegDepMatrix
9 from scoreboard
.global_pending
import GlobalPending
10 from scoreboard
.group_picker
import GroupPicker
11 from scoreboard
.issue_unit
import IntFPIssueUnit
, RegDecode
13 from compalu
import ComputationUnitNoDelay
15 from alu_hier
import ALU
16 from nmutil
.latch
import SRLatch
18 from random
import randint
20 class CompUnits(Elaboratable
):
22 def __init__(self
, rwid
, n_units
):
25 * :rwid: bit width of register file(s) - both FP and INT
26 * :n_units: number of ALUs
28 self
.n_units
= n_units
31 self
.issue_i
= Signal(n_units
, reset_less
=True)
32 self
.go_rd_i
= Signal(n_units
, reset_less
=True)
33 self
.go_wr_i
= Signal(n_units
, reset_less
=True)
34 self
.busy_o
= Signal(n_units
, reset_less
=True)
35 self
.req_rel_o
= Signal(n_units
, reset_less
=True)
37 self
.dest_o
= Signal(rwid
, reset_less
=True)
38 self
.src1_data_i
= Signal(rwid
, reset_less
=True)
39 self
.src2_data_i
= Signal(rwid
, reset_less
=True)
41 def elaborate(self
, platform
):
47 m
.submodules
.comp1
= comp1
= ComputationUnitNoDelay(self
.rwid
, 1, add
)
48 m
.submodules
.comp2
= comp2
= ComputationUnitNoDelay(self
.rwid
, 1, sub
)
49 int_alus
= [comp1
, comp2
]
51 m
.d
.comb
+= comp1
.oper_i
.eq(Const(0)) # temporary/experiment: op=add
52 m
.d
.comb
+= comp2
.oper_i
.eq(Const(1)) # temporary/experiment: op=sub
60 req_rel_l
.append(alu
.req_rel_o
)
61 go_wr_l
.append(alu
.go_wr_i
)
62 go_rd_l
.append(alu
.go_rd_i
)
63 issue_l
.append(alu
.issue_i
)
64 busy_l
.append(alu
.busy_o
)
65 m
.d
.comb
+= self
.req_rel_o
.eq(Cat(*req_rel_l
))
66 m
.d
.comb
+= self
.busy_o
.eq(Cat(*busy_l
))
67 m
.d
.comb
+= Cat(*go_wr_l
).eq(self
.go_wr_i
)
68 m
.d
.comb
+= Cat(*go_rd_l
).eq(self
.go_rd_i
)
69 m
.d
.comb
+= Cat(*issue_l
).eq(self
.issue_i
)
71 # connect data register input/output
73 # merge (OR) all integer FU / ALU outputs to a single value
74 # bit of a hack: treereduce needs a list with an item named "dest_o"
75 dest_o
= treereduce(int_alus
)
76 m
.d
.comb
+= self
.dest_o
.eq(dest_o
)
78 for i
, alu
in enumerate(int_alus
):
79 m
.d
.comb
+= alu
.src1_i
.eq(self
.src1_data_i
)
80 m
.d
.comb
+= alu
.src2_i
.eq(self
.src2_data_i
)
85 class FunctionUnits(Elaboratable
):
87 def __init__(self
, n_regs
, n_int_alus
):
89 self
.n_int_alus
= n_int_alus
91 self
.dest_i
= Signal(n_regs
, reset_less
=True) # Dest R# in
92 self
.src1_i
= Signal(n_regs
, reset_less
=True) # oper1 R# in
93 self
.src2_i
= Signal(n_regs
, reset_less
=True) # oper2 R# in
95 self
.dest_rsel_o
= Signal(n_regs
, reset_less
=True) # dest reg (bot)
96 self
.src1_rsel_o
= Signal(n_regs
, reset_less
=True) # src1 reg (bot)
97 self
.src2_rsel_o
= Signal(n_regs
, reset_less
=True) # src2 reg (bot)
99 self
.req_rel_i
= Signal(n_int_alus
, reset_less
= True)
100 self
.g_int_rd_pend_o
= Signal(n_regs
, reset_less
=True)
101 self
.g_int_wr_pend_o
= Signal(n_regs
, reset_less
=True)
102 self
.readable_o
= Signal(n_int_alus
, reset_less
=True)
103 self
.writable_o
= Signal(n_int_alus
, reset_less
=True)
105 self
.go_rd_i
= Signal(n_int_alus
, reset_less
=True)
106 self
.go_wr_i
= Signal(n_int_alus
, reset_less
=True)
107 self
.req_rel_o
= Signal(n_int_alus
, reset_less
=True)
108 self
.fn_issue_i
= Signal(n_int_alus
, reset_less
=True)
110 def elaborate(self
, platform
):
113 n_int_fus
= self
.n_int_alus
115 # Integer FU-FU Dep Matrix
116 intfudeps
= FUFUDepMatrix(n_int_fus
, n_int_fus
)
117 m
.submodules
.intfudeps
= intfudeps
118 # Integer FU-Reg Dep Matrix
119 intregdeps
= FURegDepMatrix(n_int_fus
, self
.n_regs
)
120 m
.submodules
.intregdeps
= intregdeps
122 m
.d
.comb
+= self
.g_int_rd_pend_o
.eq(intregdeps
.rd_pend_o
)
123 m
.d
.comb
+= self
.g_int_wr_pend_o
.eq(intregdeps
.wr_pend_o
)
125 m
.d
.comb
+= intfudeps
.rd_pend_i
.eq(self
.g_int_rd_pend_o
)
126 m
.d
.comb
+= intfudeps
.wr_pend_i
.eq(self
.g_int_wr_pend_o
)
128 m
.d
.sync
+= intfudeps
.issue_i
.eq(self
.fn_issue_i
)
129 m
.d
.sync
+= intfudeps
.go_rd_i
.eq(self
.go_rd_i
)
130 m
.d
.sync
+= intfudeps
.go_wr_i
.eq(self
.go_wr_i
)
131 m
.d
.comb
+= self
.readable_o
.eq(intfudeps
.readable_o
)
132 m
.d
.comb
+= self
.writable_o
.eq(intfudeps
.writable_o
)
134 # Connect function issue / arrays, and dest/src1/src2
135 m
.d
.comb
+= intregdeps
.dest_i
.eq(self
.dest_i
)
136 m
.d
.comb
+= intregdeps
.src1_i
.eq(self
.src1_i
)
137 m
.d
.comb
+= intregdeps
.src2_i
.eq(self
.src2_i
)
139 m
.d
.comb
+= intregdeps
.go_rd_i
.eq(self
.go_rd_i
)
140 m
.d
.comb
+= intregdeps
.go_wr_i
.eq(self
.go_wr_i
)
141 m
.d
.comb
+= intregdeps
.issue_i
.eq(self
.fn_issue_i
)
143 m
.d
.comb
+= self
.dest_rsel_o
.eq(intregdeps
.dest_rsel_o
)
144 m
.d
.comb
+= self
.src1_rsel_o
.eq(intregdeps
.src1_rsel_o
)
145 m
.d
.comb
+= self
.src2_rsel_o
.eq(intregdeps
.src2_rsel_o
)
150 class Scoreboard(Elaboratable
):
151 def __init__(self
, rwid
, n_regs
):
154 * :rwid: bit width of register file(s) - both FP and INT
155 * :n_regs: depth of register file(s) - number of FP and INT regs
161 self
.intregs
= RegFileArray(rwid
, n_regs
)
162 self
.fpregs
= RegFileArray(rwid
, n_regs
)
165 self
.int_store_i
= Signal(reset_less
=True) # instruction is a store
166 self
.int_dest_i
= Signal(max=n_regs
, reset_less
=True) # Dest R# in
167 self
.int_src1_i
= Signal(max=n_regs
, reset_less
=True) # oper1 R# in
168 self
.int_src2_i
= Signal(max=n_regs
, reset_less
=True) # oper2 R# in
170 self
.issue_o
= Signal(reset_less
=True) # instruction was accepted
172 def elaborate(self
, platform
):
175 m
.submodules
.intregs
= self
.intregs
176 m
.submodules
.fpregs
= self
.fpregs
179 int_dest
= self
.intregs
.write_port("dest")
180 int_src1
= self
.intregs
.read_port("src1")
181 int_src2
= self
.intregs
.read_port("src2")
183 fp_dest
= self
.fpregs
.write_port("dest")
184 fp_src1
= self
.fpregs
.read_port("src1")
185 fp_src2
= self
.fpregs
.read_port("src2")
187 # Int ALUs and Comp Units
189 m
.submodules
.cu
= cu
= CompUnits(self
.rwid
, n_int_alus
)
192 m
.submodules
.intfus
= intfus
= FunctionUnits(self
.n_regs
, n_int_alus
)
194 # Count of number of FUs
195 n_int_fus
= n_int_alus
196 n_fp_fus
= 0 # for now
198 # Integer Priority Picker 1: Adder + Subtractor
199 intpick1
= GroupPicker(2) # picks between add and sub
200 m
.submodules
.intpick1
= intpick1
203 regdecode
= RegDecode(self
.n_regs
)
204 m
.submodules
.regdecode
= regdecode
205 issueunit
= IntFPIssueUnit(self
.n_regs
, n_int_fus
, n_fp_fus
)
206 m
.submodules
.issueunit
= issueunit
209 # ok start wiring things together...
210 # "now hear de word of de looord... dem bones dem bones dem dryy bones"
211 # https://www.youtube.com/watch?v=pYb8Wm6-QfA
215 # Issue Unit is where it starts. set up some in/outs for this module
217 m
.d
.comb
+= [issueunit
.i
.store_i
.eq(self
.int_store_i
),
218 regdecode
.dest_i
.eq(self
.int_dest_i
),
219 regdecode
.src1_i
.eq(self
.int_src1_i
),
220 regdecode
.src2_i
.eq(self
.int_src2_i
),
221 regdecode
.enable_i
.eq(1),
222 issueunit
.i
.dest_i
.eq(regdecode
.dest_o
),
223 self
.issue_o
.eq(issueunit
.issue_o
)
225 self
.int_insn_i
= issueunit
.i
.insn_i
# enabled by instruction decode
227 # connect global rd/wr pending vectors
228 m
.d
.comb
+= issueunit
.i
.g_wr_pend_i
.eq(intfus
.g_int_wr_pend_o
)
229 # TODO: issueunit.f (FP)
231 # and int function issue / busy arrays, and dest/src1/src2
232 m
.d
.comb
+= intfus
.dest_i
.eq(regdecode
.dest_o
)
233 m
.d
.comb
+= intfus
.src1_i
.eq(regdecode
.src1_o
)
234 m
.d
.comb
+= intfus
.src2_i
.eq(regdecode
.src2_o
)
236 fn_issue_o
= issueunit
.i
.fn_issue_o
238 m
.d
.comb
+= intfus
.fn_issue_i
.eq(fn_issue_o
)
239 # XXX sync, so as to stop a simulation infinite loop
240 m
.d
.sync
+= issueunit
.i
.busy_i
.eq(cu
.busy_o
)
243 # connect fu-fu matrix
246 # Group Picker... done manually for now. TODO: cat array of pick sigs
247 go_rd_o
= intpick1
.go_rd_o
248 go_wr_o
= intpick1
.go_wr_o
249 go_rd_i
= intfus
.go_rd_i
250 go_wr_i
= intfus
.go_wr_i
251 m
.d
.comb
+= go_rd_i
[0:2].eq(go_rd_o
[0:2]) # add rd
252 m
.d
.comb
+= go_wr_i
[0:2].eq(go_wr_o
[0:2]) # add wr
256 m
.d
.sync
+= intpick1
.go_rd_i
[0:2].eq(~go_rd_i
[0:2])
257 m
.d
.comb
+= intpick1
.req_rel_i
[0:2].eq(cu
.req_rel_o
[0:2])
258 int_readable_o
= intfus
.readable_o
259 int_writable_o
= intfus
.writable_o
260 m
.d
.comb
+= intpick1
.readable_i
[0:2].eq(int_readable_o
[0:2])
261 m
.d
.comb
+= intpick1
.writable_i
[0:2].eq(int_writable_o
[0:2])
264 # Connect Register File(s)
266 print ("intregdeps wen len", len(intfus
.dest_rsel_o
))
267 m
.d
.sync
+= int_dest
.wen
.eq(intfus
.dest_rsel_o
)
268 m
.d
.comb
+= int_src1
.ren
.eq(intfus
.src1_rsel_o
)
269 m
.d
.comb
+= int_src2
.ren
.eq(intfus
.src2_rsel_o
)
271 # connect ALUs to regfule
272 m
.d
.comb
+= int_dest
.data_i
.eq(cu
.dest_o
)
273 m
.d
.comb
+= cu
.src1_data_i
.eq(int_src1
.data_o
)
274 m
.d
.comb
+= cu
.src2_data_i
.eq(int_src2
.data_o
)
276 # connect ALU Computation Units
277 m
.d
.sync
+= cu
.go_rd_i
[0:2].eq(go_rd_o
[0:2])
278 m
.d
.sync
+= cu
.go_wr_i
[0:2].eq(go_wr_o
[0:2])
279 m
.d
.sync
+= cu
.issue_i
[0:2].eq(fn_issue_o
[0:2])
285 yield from self
.intregs
286 yield from self
.fpregs
287 yield self
.int_store_i
288 yield self
.int_dest_i
289 yield self
.int_src1_i
290 yield self
.int_src2_i
292 #yield from self.int_src1
293 #yield from self.int_dest
294 #yield from self.int_src1
295 #yield from self.int_src2
296 #yield from self.fp_dest
297 #yield from self.fp_src1
298 #yield from self.fp_src2
307 def __init__(self
, rwidth
, nregs
):
309 self
.regs
= [0] * nregs
311 def op(self
, op
, src1
, src2
, dest
):
312 src1
= self
.regs
[src1
]
313 src2
= self
.regs
[src2
]
315 val
= (src1
+ src2
) & ((1<<(self
.rwidth
))-1)
317 val
= (src1
- src2
) & ((1<<(self
.rwidth
))-1)
318 self
.regs
[dest
] = val
320 def setval(self
, dest
, val
):
321 self
.regs
[dest
] = val
324 for i
, val
in enumerate(self
.regs
):
325 reg
= yield dut
.intregs
.regs
[i
].reg
326 okstr
= "OK" if reg
== val
else "!ok"
327 print("reg %d expected %x received %x %s" % (i
, val
, reg
, okstr
))
329 def check(self
, dut
):
330 for i
, val
in enumerate(self
.regs
):
331 reg
= yield dut
.intregs
.regs
[i
].reg
333 print("reg %d expected %x received %x\n" % (i
, val
, reg
))
334 yield from self
.dump(dut
)
337 def int_instr(dut
, alusim
, op
, src1
, src2
, dest
):
338 for i
in range(len(dut
.int_insn_i
)):
339 yield dut
.int_insn_i
[i
].eq(0)
340 yield dut
.int_dest_i
.eq(dest
)
341 yield dut
.int_src1_i
.eq(src1
)
342 yield dut
.int_src2_i
.eq(src2
)
343 yield dut
.int_insn_i
[op
].eq(1)
344 alusim
.op(op
, src1
, src2
, dest
)
347 def print_reg(dut
, rnums
):
350 reg
= yield dut
.intregs
.regs
[rnum
].reg
351 rs
.append("%x" % reg
)
352 rnums
= map(str, rnums
)
353 print ("reg %s: %s" % (','.join(rnums
), ','.join(rs
)))
356 def scoreboard_sim(dut
, alusim
):
357 yield dut
.int_store_i
.eq(0)
359 for i
in range(1, dut
.n_regs
):
360 yield dut
.intregs
.regs
[i
].reg
.eq(i
*2)
361 alusim
.setval(i
, i
*2)
368 src1
= randint(1, dut
.n_regs
-1)
369 src2
= randint(1, dut
.n_regs
-1)
371 dest
= randint(1, dut
.n_regs
-1)
373 if dest
not in [src1
, src2
]:
381 instrs
.append((src1
, src2
, dest
, op
))
384 instrs
.append((2, 3, 3, 0))
385 instrs
.append((5, 3, 3, 1))
388 instrs
.append((7, 2, 6, 1))
389 instrs
.append((3, 7, 1, 1))
390 instrs
.append((2, 2, 3, 1))
392 for i
, (src1
, src2
, dest
, op
) in enumerate(instrs
):
394 print ("instr %d: %d %d %d %d\n" % (i
, op
, src1
, src2
, dest
))
395 yield from int_instr(dut
, alusim
, op
, src1
, src2
, dest
)
396 yield from print_reg(dut
, [3,4,5])
399 issue_o
= yield dut
.issue_o
401 yield from print_reg(dut
, [3,4,5])
402 for i
in range(len(dut
.int_insn_i
)):
403 yield dut
.int_insn_i
[i
].eq(0)
406 yield from print_reg(dut
, [3,4,5])
410 yield from print_reg(dut
, [3,4,5])
412 yield from print_reg(dut
, [3,4,5])
417 yield from alusim
.check(dut
)
418 yield from alusim
.dump(dut
)
421 def explore_groups(dut
):
422 from nmigen
.hdl
.ir
import Fragment
423 from nmigen
.hdl
.xfrm
import LHSGroupAnalyzer
425 fragment
= dut
.elaborate(platform
=None)
426 fr
= Fragment
.get(fragment
, platform
=None)
428 groups
= LHSGroupAnalyzer()(fragment
._statements
)
433 def test_scoreboard():
434 dut
= Scoreboard(32, 8)
435 alusim
= RegSim(32, 8)
436 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
437 with
open("test_scoreboard6600.il", "w") as f
:
440 run_simulation(dut
, scoreboard_sim(dut
, alusim
),
441 vcd_name
='test_scoreboard6600.vcd')
444 if __name__
== '__main__':