whoops missed some cases in unit test changing ALUHelpers
[soc.git] / src / soc / scoreboard / group_picker.py
1 """Group Picker
2
3 to select an instruction that is permitted to read (or write)
4 based on the Function Unit expressing a *desire* to read (or write).
5
6 The job of the Group Picker is extremely simple yet extremely important.
7 It sits in front of a register file port (read or write) and stops it from
8 being corrupted. It's a "port contention selector", basically.
9
10 The way it works is:
11
12 * Function Units need to read from (or write to) the register file,
13 in order to get (or store) their operands, so they each have a signal,
14 readable (or writable), which "expresses" this need. This is an
15 *unary* encoding.
16
17 * The Function Units also have a signal which indicates that they
18 are requesting "release" of the register file port (this because
19 in the scoreboard, readable/writable can be permanently HI even
20 if the FU is idle, whereas the "release" signal is very specifically
21 only HI if the read (or write) latch is still active)
22
23 * The Group Picker takes this unary encoding of the desire to read
24 (or write) and, on a priority basis, activates one *and only* one
25 of those signals, again as an unary output.
26
27 * Due to the way that the Computation Unit works, that signal (Go_Read
28 or Go_Write) will fire for one (and only one) cycle, and can be used
29 to enable the register file port read (or write) lines. The Go_Read/Wr
30 signal basically loops back to the Computation Unit and resets the
31 "desire-to-read/write-expressing" latch.
32
33 In theory (and in practice!) the following is possible:
34
35 * Separate src1 and src2 Group Pickers. This would allow instructions
36 with only one operand to read to not block up other instructions,
37 and it would also allow 3-operand instructions to be interleaved
38 with 1 and 2 operand instructions.
39
40 * *Multiple* Group Pickers (multi-issue). This would require
41 a corresponding increase in the number of register file ports,
42 either 4R2W (or more) or by "striping" the register file into
43 split banks (a strategy best deployed on Vector Processors)
44 """
45
46 from nmigen.compat.sim import run_simulation
47 from nmigen.cli import verilog, rtlil
48 from nmigen import Module, Signal, Elaboratable, Array
49
50 #from nmutil.picker import MultiPriorityPicker as MPP
51 from nmutil.picker import PriorityPicker
52
53
54 class GroupPicker(Elaboratable):
55 """ implements 10.5 mitch alsup group picker, p27
56 """
57 def __init__(self, wid, n_src, n_dst):
58 self.n_src, self.n_dst = n_src, n_dst
59 self.gp_wid = wid
60
61 # arrays
62 rdr = []
63 rd = []
64 ri = []
65 for i in range(n_src):
66 rdr.append(Signal(wid, name="rdrel%d_i" % i, reset_less=True))
67 rd.append(Signal(wid, name="gord%d_o" % i, reset_less=True))
68 ri.append(Signal(wid, name="readable%d_i" % i, reset_less=True))
69 wrr = []
70 wr = []
71 wi = []
72 for i in range(n_dst):
73 wrr.append(Signal(wid, name="reqrel%d_i" % i, reset_less=True))
74 wr.append(Signal(wid, name="gowr%d_o" % i, reset_less=True))
75 wi.append(Signal(wid, name="writable%d_i" % i, reset_less=True))
76
77 # inputs
78 self.rd_rel_i = Array(rdr) # go read in (top)
79 self.req_rel_i = Array(wrr) # release request in (top)
80 self.readable_i = Array(ri) # readable in (top)
81 self.writable_i = Array(wi) # writable in (top)
82
83 # outputs
84 self.go_rd_o = Array(rd) # go read (bottom)
85 self.go_wr_o = Array(wr) # go write (bottom)
86
87 def elaborate(self, platform):
88 m = Module()
89
90 # combine release (output ready signal) with writeable
91 for i in range(self.n_dst):
92 wpick = PriorityPicker(self.gp_wid)
93 setattr(m.submodules, "wpick%d" % i, wpick)
94 m.d.comb += wpick.i.eq(self.writable_i[i] & self.req_rel_i[i])
95 m.d.comb += self.go_wr_o[i].eq(wpick.o)
96
97 for i in range(self.n_src):
98 rpick = PriorityPicker(self.gp_wid)
99 setattr(m.submodules, "rpick%d" % i, rpick)
100 m.d.comb += rpick.i.eq(self.readable_i[i] & self.rd_rel_i[i])
101 m.d.comb += self.go_rd_o[i].eq(rpick.o)
102
103 return m
104
105 def __iter__(self):
106 yield from self.readable_i
107 yield from self.writable_i
108 yield from self.req_rel_i
109 yield from self.rd_rel_i
110 yield from self.go_rd_o
111 yield from self.go_wr_o
112
113 def ports(self):
114 return list(self)
115
116
117 def grp_pick_sim(dut):
118 yield dut.dest_i.eq(1)
119 yield dut.issue_i.eq(1)
120 yield
121 yield dut.issue_i.eq(0)
122 yield
123 yield dut.src1_i.eq(1)
124 yield dut.issue_i.eq(1)
125 yield
126 yield
127 yield
128 yield dut.issue_i.eq(0)
129 yield
130 yield dut.rd_rel_i.eq(1)
131 yield
132 yield dut.rd_rel_i.eq(0)
133 yield
134 yield dut.go_wr_i.eq(1)
135 yield
136 yield dut.go_wr_i.eq(0)
137 yield
138
139
140 def test_grp_pick():
141 dut = GroupPicker(4, 2, 2)
142 vl = rtlil.convert(dut, ports=dut.ports())
143 with open("test_grp_pick.il", "w") as f:
144 f.write(vl)
145
146 run_simulation(dut, grp_pick_sim(dut), vcd_name='test_grp_pick.vcd')
147
148 if __name__ == '__main__':
149 test_grp_pick()