add shadow capability to function unit
[ieee754fpu.git] / src / scoreboard / int_fn_unit.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3 from nmigen import Module, Signal, Cat, Elaboratable
4 from nmutil.latch import SRLatch
5 from nmigen.lib.coding import Decoder
6
7
8 class IntFnUnit(Elaboratable):
9 """ implements 11.4.8 integer function unit, p31
10 also implements optional shadowing 11.5.1, p55
11
12 shadowing can be used for branches as well as exceptions (interrupts),
13 and vector-element predication (once the predicate is known, which it
14 may not be at instruction issue)
15
16 notes:
17
18 * req_rel_i (request release) is the direct equivalent of pipeline
19 "output valid"
20 * recover is a local python variable (actually go_die_o)
21 * when shadow_wid = 0, recover and shadown are Consts
22 """
23 def __init__(self, wid, shadow_wid=0):
24 self.reg_width = wid
25 self.shadow_wid = shadow_wid
26
27 # inputs
28 self.dest_i = Signal(wid, reset_less=True) # Dest in (top)
29 self.src1_i = Signal(wid, reset_less=True) # oper1 in (top)
30 self.src2_i = Signal(wid, reset_less=True) # oper2 in (top)
31 self.issue_i = Signal(reset_less=True) # Issue in (top)
32
33 self.go_write_i = Signal(reset_less=True) # Go Write in (left)
34 self.go_read_i = Signal(reset_less=True) # Go Read in (left)
35 self.req_rel_i = Signal(wid, reset_less=True) # request release (left)
36
37 self.g_rd_pend_i = Signal(wid, reset_less=True) # global rd (right)
38 self.g_wr_pend_i = Signal(wid, reset_less=True) # global wr (right)
39
40 if shadow_wid:
41 self.shadow_i = Signal(shadow_wid, reset_less=True)
42 self.s_fail_i = Signal(shadow_wid, reset_less=True)
43 self.s_good_i = Signal(shadow_wid, reset_less=True)
44 self.go_die_o = Signal(reset_less=True)
45
46 # outputs
47 self.readable_o = Signal(reset_less=True) # Readable out (right)
48 self.writable_o = Signal(reset_less=True) # Writable out (right)
49 self.busy_o = Signal(reset_less=True) # busy out (left)
50
51 self.rd_pend_o = Signal(wid, reset_less=True) # rd pending (right)
52 self.wr_pend_o = Signal(wid, reset_less=True) # wr pending (right)
53
54 def elaborate(self, platform):
55 m = Module()
56 m.submodules.rd_l = rd_l = SRLatch(sync=False)
57 m.submodules.wr_l = wr_l = SRLatch(sync=False)
58 m.submodules.dest_d = dest_d = Decoder(self.reg_width)
59 m.submodules.src1_d = src1_d = Decoder(self.reg_width)
60 m.submodules.src2_d = src2_d = Decoder(self.reg_width)
61 s_latches = []
62 for i in range(self.shadow_wid):
63 sl = SRLatch(sync=False)
64 setattr(m.submodules, "shadow%d" % i, sl)
65 s_latches.append(sl)
66
67 # shadow / recover (optional: shadow_wid > 0)
68 if self.shadow_wid:
69 recover = self.go_die_o
70 si = Signal(self.shadow_wid, reset_less=True)
71 sq = Signal(self.shadow_wid, reset_less=True)
72 shadown = Signal(reset_less=True)
73 recfail = Signal(self.shadow_wid, reset_less=True)
74 l = self.shadow_i & Cat(*([self.issue_i] * self.shadow_wid))
75 q_l = []
76 for i, s in enumerate(l):
77 m.d.comb += s_latches[i].s.eq(s) # issue_i & shadow_i[i]
78 m.d.comb += s_latches[i].r.eq(self.s_good_i[i])
79 q_l.append(s_latches[i].q)
80 m.d.comb += sq.eq(Cat(*q_l))
81 m.d.comb += shadown.eq(~sq.bool())
82 m.d.comb += recfail.eq(sq & self.s_fail_i)
83 m.d.comb += recover.eq(recfail.bool())
84 else:
85 shadown = Const(1)
86 recover = Const(0)
87
88 # go_write latch: reset on go_write HI, set on issue
89 m.d.comb += wr_l.s.eq(self.issue_i)
90 m.d.comb += wr_l.r.eq(self.go_write_i | recover)
91
92 # src1 latch: reset on go_read HI, set on issue
93 m.d.comb += rd_l.s.eq(self.issue_i)
94 m.d.comb += rd_l.r.eq(self.go_read_i | recover)
95
96 # dest decoder: write-pending out
97 m.d.comb += dest_d.i.eq(self.dest_i)
98 m.d.comb += dest_d.n.eq(wr_l.qn) # decode is inverted
99 m.d.comb += self.busy_o.eq(wr_l.q) # busy if set
100 m.d.comb += self.wr_pend_o.eq(dest_d.o)
101
102 # src1/src2 decoder: read-pending out
103 m.d.comb += src1_d.i.eq(self.src1_i)
104 m.d.comb += src1_d.n.eq(rd_l.qn) # decode is inverted
105 m.d.comb += src2_d.i.eq(self.src2_i)
106 m.d.comb += src2_d.n.eq(rd_l.qn) # decode is inverted
107 m.d.comb += self.rd_pend_o.eq(src1_d.o | src2_d.o)
108
109 # readable output signal
110 int_g_wr = Signal(self.reg_width, reset_less=True)
111 m.d.comb += int_g_wr.eq(self.g_wr_pend_i & self.rd_pend_o)
112 m.d.comb += self.readable_o.eq(int_g_wr.bool())
113
114 # writable output signal
115 int_g_rw = Signal(self.reg_width, reset_less=True)
116 g_rw = Signal(reset_less=True)
117 m.d.comb += int_g_rw.eq(self.g_rd_pend_i & self.wr_pend_o)
118 m.d.comb += g_rw.eq(~int_g_rw.bool())
119 m.d.comb += self.writable_o.eq(g_rw & rd_l.q & self.req_rel_i & shadown)
120
121 return m
122
123 def __iter__(self):
124 yield self.dest_i
125 yield self.src1_i
126 yield self.src2_i
127 yield self.issue_i
128 yield self.go_write_i
129 yield self.go_read_i
130 yield self.req_rel_i
131 yield self.g_rd_pend_i
132 yield self.g_wr_pend_i
133 yield self.readable_o
134 yield self.writable_o
135 yield self.rd_pend_o
136 yield self.wr_pend_o
137
138 def ports(self):
139 return list(self)
140
141
142 def int_fn_unit_sim(dut):
143 yield dut.dest_i.eq(1)
144 yield dut.issue_i.eq(1)
145 yield
146 yield dut.issue_i.eq(0)
147 yield
148 yield dut.src1_i.eq(1)
149 yield dut.issue_i.eq(1)
150 yield
151 yield
152 yield
153 yield dut.issue_i.eq(0)
154 yield
155 yield dut.go_read_i.eq(1)
156 yield
157 yield dut.go_read_i.eq(0)
158 yield
159 yield dut.go_write_i.eq(1)
160 yield
161 yield dut.go_write_i.eq(0)
162 yield
163
164 def test_int_fn_unit():
165 dut = IntFnUnit(32, 2)
166 vl = rtlil.convert(dut, ports=dut.ports())
167 with open("test_int_fn_unit.il", "w") as f:
168 f.write(vl)
169
170 run_simulation(dut, int_fn_unit_sim(dut), vcd_name='test_int_fn_unit.vcd')
171
172 if __name__ == '__main__':
173 test_int_fn_unit()