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
8 class IntFnUnit(Elaboratable
):
9 """ implements 11.4.8 integer function unit, p31
10 also implements optional shadowing 11.5.1, p55
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)
18 * req_rel_i (request release) is the direct equivalent of pipeline
20 * recover is a local python variable (actually go_die_o)
21 * when shadow_wid = 0, recover and shadown are Consts
23 def __init__(self
, wid
, shadow_wid
=0):
25 self
.shadow_wid
= shadow_wid
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)
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)
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)
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)
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)
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)
54 def elaborate(self
, platform
):
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
)
62 for i
in range(self
.shadow_wid
):
63 sl
= SRLatch(sync
=False)
64 setattr(m
.submodules
, "shadow%d" % i
, sl
)
67 # shadow / recover (optional: shadow_wid > 0)
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
))
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())
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
)
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
)
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
)
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
)
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())
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
)
128 yield self
.go_write_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
142 def int_fn_unit_sim(dut
):
143 yield dut
.dest_i
.eq(1)
144 yield dut
.issue_i
.eq(1)
146 yield dut
.issue_i
.eq(0)
148 yield dut
.src1_i
.eq(1)
149 yield dut
.issue_i
.eq(1)
153 yield dut
.issue_i
.eq(0)
155 yield dut
.go_read_i
.eq(1)
157 yield dut
.go_read_i
.eq(0)
159 yield dut
.go_write_i
.eq(1)
161 yield dut
.go_write_i
.eq(0)
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
:
170 run_simulation(dut
, int_fn_unit_sim(dut
), vcd_name
='test_int_fn_unit.vcd')
172 if __name__
== '__main__':