split out register decode from issue unit
[soc.git] / src / 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, Record, Elaboratable
4 from nmigen.lib.coding import Decoder
5
6 from .shadow_fn import ShadowFn
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(max=wid, reset_less=True) # Dest R# in
22 self.src1_i = Signal(max=wid, reset_less=True) # oper1 R# in
23 self.src2_i = Signal(max=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 IssueUnit(Elaboratable):
60 """ implements 11.4.14 issue unit, p50
61
62 Inputs
63
64 * :wid: register file width
65 * :n_insns: number of instructions in this issue unit.
66 """
67 def __init__(self, wid, n_insns):
68 self.reg_width = wid
69 self.n_insns = n_insns
70
71 # inputs
72 self.store_i = Signal(reset_less=True) # instruction is a store
73 self.dest_i = Signal(wid, reset_less=True) # Dest R in (unary)
74
75 self.g_wr_pend_i = Signal(wid, reset_less=True) # write pending vector
76
77 self.insn_i = Array(Signal(reset_less=True, name="insn_i") \
78 for i in range(n_insns))
79 self.busy_i = Array(Signal(reset_less=True, name="busy_i") \
80 for i in range(n_insns))
81
82 # outputs
83 self.fn_issue_o = Array(Signal(reset_less=True, name="fn_issue_o") \
84 for i in range(n_insns))
85 self.g_issue_o = Signal(reset_less=True)
86
87 def elaborate(self, platform):
88 m = Module()
89
90 if self.n_insns == 0:
91 return m
92
93 # temporaries
94 waw_stall = Signal(reset_less=True)
95 fu_stall = Signal(reset_less=True)
96 pend = Signal(self.reg_width, reset_less=True)
97
98 # dest decoder: write-pending
99 m.d.comb += pend.eq(self.dest_i & self.g_wr_pend_i & (~self.store_i))
100 m.d.comb += waw_stall.eq(pend.bool())
101
102 ib_l = []
103 for i in range(self.n_insns):
104 ib_l.append(self.insn_i[i] & self.busy_i[i])
105 m.d.comb += fu_stall.eq(Cat(*ib_l).bool())
106 m.d.comb += self.g_issue_o.eq(~(waw_stall | fu_stall))
107 for i in range(self.n_insns):
108 m.d.comb += self.fn_issue_o[i].eq(self.g_issue_o & self.insn_i[i])
109
110 return m
111
112 def __iter__(self):
113 yield self.store_i
114 yield self.dest_i
115 yield self.src1_i
116 yield self.src2_i
117 yield self.g_wr_pend_i
118 yield from self.insn_i
119 yield from self.busy_i
120 yield from self.fn_issue_o
121 yield self.g_issue_o
122
123 def ports(self):
124 return list(self)
125
126
127 class IntFPIssueUnit(Elaboratable):
128 def __init__(self, wid, n_int_insns, n_fp_insns):
129 self.i = IssueUnit(wid, n_int_insns)
130 self.f = IssueUnit(wid, n_fp_insns)
131 self.issue_o = Signal(reset_less=True)
132
133 # some renames
134 self.int_write_pending_i = self.i.g_wr_pend_i
135 self.fp_write_pending_i = self.f.g_wr_pend_i
136 self.int_write_pending_i.name = 'int_write_pending_i'
137 self.fp_write_pending_i.name = 'fp_write_pending_i'
138
139 def elaborate(self, platform):
140 m = Module()
141 m.submodules.intissue = self.i
142 m.submodules.fpissue = self.f
143
144 m.d.comb += self.issue_o.eq(self.i.g_issue_o | self.f.g_issue_o)
145
146 return m
147
148 def ports(self):
149 yield self.issue_o
150 yield from self.i
151 yield from self.f
152
153
154 def issue_unit_sim(dut):
155 yield dut.dest_i.eq(1)
156 yield dut.issue_i.eq(1)
157 yield
158 yield dut.issue_i.eq(0)
159 yield
160 yield dut.src1_i.eq(1)
161 yield dut.issue_i.eq(1)
162 yield
163 yield
164 yield
165 yield dut.issue_i.eq(0)
166 yield
167 yield dut.go_rd_i.eq(1)
168 yield
169 yield dut.go_rd_i.eq(0)
170 yield
171 yield dut.go_wr_i.eq(1)
172 yield
173 yield dut.go_wr_i.eq(0)
174 yield
175
176 def test_issue_unit():
177 dut = IssueUnit(32, 3)
178 vl = rtlil.convert(dut, ports=dut.ports())
179 with open("test_issue_unit.il", "w") as f:
180 f.write(vl)
181
182 dut = IntFPIssueUnit(32, 3, 3)
183 vl = rtlil.convert(dut, ports=dut.ports())
184 with open("test_intfp_issue_unit.il", "w") as f:
185 f.write(vl)
186
187 run_simulation(dut, issue_unit_sim(dut), vcd_name='test_issue_unit.vcd')
188
189 if __name__ == '__main__':
190 test_issue_unit()