adb12f47549c549a67799e16d55def375c36d625
[soc.git] / src / scoreboard / shadow.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, Elaboratable
4 from nmigen.lib.coding import Decoder
5
6 from nmutil.latch import SRLatch, latchregister
7
8 from scoreboard.shadow_fn import ShadowFn
9
10
11 class Shadow(Elaboratable):
12 """ implements shadowing 11.5.1, p55
13
14 shadowing can be used for branches as well as exceptions (interrupts),
15 load/store hold (exceptions again), and vector-element predication
16 (once the predicate is known, which it may not be at instruction issue)
17
18 Inputs
19
20 * :wid: register file width
21 * :shadow_wid: number of shadow/fail/good/go_die sets
22 * :n_dests: number of destination regfile(s) (index: rfile_sel_i)
23 * :wr_pend: if true, writable observes the g_wr_pend_i vector
24 otherwise observes g_rd_pend_i
25
26 notes:
27
28 * dest_i / src1_i / src2_i are in *binary*, whereas...
29 * ...g_rd_pend_i / g_wr_pend_i and rd_pend_o / wr_pend_o are UNARY
30 * req_rel_i (request release) is the direct equivalent of pipeline
31 "output valid" (valid_o)
32 * recover is a local python variable (actually go_die_o)
33 * when shadow_wid = 0, recover and shadown are Consts (i.e. do nothing)
34 * wr_pend is set False for the majority of uses: however for
35 use in a STORE Function Unit it is set to True
36 """
37 def __init__(self, shadow_wid=0):
38 self.shadow_wid = shadow_wid
39
40 if shadow_wid:
41 self.issue_i = Signal(reset_less=True)
42 self.shadow_i = Signal(shadow_wid, reset_less=True)
43 self.s_fail_i = Signal(shadow_wid, reset_less=True)
44 self.s_good_i = Signal(shadow_wid, reset_less=True)
45 self.go_die_o = Signal(reset_less=True)
46 self.shadown_o = Signal(reset_less=True)
47 else:
48 self.shadown_o = Const(1)
49 self.go_die_o = Const(0)
50
51 def elaborate(self, platform):
52 m = Module()
53 s_latches = []
54 for i in range(self.shadow_wid):
55 sh = ShadowFn()
56 setattr(m.submodules, "shadow%d" % i, sh)
57 s_latches.append(sh)
58
59 # shadow / recover (optional: shadow_wid > 0)
60 if self.shadow_wid:
61 i_l = []
62 fail_l = []
63 good_l = []
64 shi_l = []
65 sho_l = []
66 rec_l = []
67 # get list of latch signals. really must be a better way to do this
68 for l in s_latches:
69 i_l.append(l.issue_i)
70 shi_l.append(l.shadow_i)
71 fail_l.append(l.s_fail_i)
72 good_l.append(l.s_good_i)
73 sho_l.append(l.shadow_o)
74 rec_l.append(l.recover_o)
75 m.d.comb += Cat(*i_l).eq(self.issue_i)
76 m.d.comb += Cat(*fail_l).eq(self.s_fail_i)
77 m.d.comb += Cat(*good_l).eq(self.s_good_i)
78 m.d.comb += Cat(*shi_l).eq(self.shadow_i)
79 m.d.comb += self.shadown_o.eq(~(Cat(*sho_l).bool()))
80 m.d.comb += self.go_die_o.eq(Cat(*rec_l).bool())
81
82 return m
83
84 def __iter__(self):
85 if self.shadow_wid:
86 yield self.issue_i
87 yield self.shadow_i
88 yield self.s_fail_i
89 yield self.s_good_i
90 yield self.go_die_o
91 yield self.shadown_o
92
93 def ports(self):
94 return list(self)
95
96
97 def shadow_sim(dut):
98 yield dut.dest_i.eq(1)
99 yield dut.issue_i.eq(1)
100 yield
101 yield dut.issue_i.eq(0)
102 yield
103 yield dut.src1_i.eq(1)
104 yield dut.issue_i.eq(1)
105 yield
106 yield
107 yield
108 yield dut.issue_i.eq(0)
109 yield
110 yield dut.go_rd_i.eq(1)
111 yield
112 yield dut.go_rd_i.eq(0)
113 yield
114 yield dut.go_wr_i.eq(1)
115 yield
116 yield dut.go_wr_i.eq(0)
117 yield
118
119 def test_shadow():
120 dut = Shadow(2)
121 vl = rtlil.convert(dut, ports=dut.ports())
122 with open("test_shadow.il", "w") as f:
123 f.write(vl)
124
125 run_simulation(dut, shadow_sim(dut), vcd_name='test_shadow.vcd')
126
127 if __name__ == '__main__':
128 test_shadow()