Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / scoreboard / mem_dependence_cell.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3 from nmigen import Module, Signal, Elaboratable, Cat, Repl
4 from nmutil.latch import SRLatch
5
6
7 class MemDepRow(Elaboratable):
8 """ implements 1st phase Memory Depencency cell
9 """
10 def __init__(self, n_reg):
11 self.n_reg = n_reg
12 # inputs
13 self.ld_i = Signal(n_reg, reset_less=True) # Dest in (top)
14 self.st_i = Signal(n_reg, reset_less=True) # oper1 in (top)
15 self.issue_i = Signal(reset_less=True) # Issue in (top)
16
17 self.st_pend_i = Signal(n_reg, reset_less=True) # Read pend in (top)
18 self.ld_pend_i = Signal(n_reg, reset_less=True) # Write pend in (top)
19 self.v_st_rsel_o = Signal(n_reg, reset_less=True) # Read pend out (bot)
20 self.v_ld_rsel_o = Signal(n_reg, reset_less=True) # Write pend out (bot)
21
22 self.go_ld_i = Signal(reset_less=True) # Go Write in (left)
23 self.go_st_i = Signal(reset_less=True) # Go Read in (left)
24 self.go_die_i = Signal(reset_less=True) # Go Die in (left)
25
26 # for Register File Select Lines (vertical)
27 self.ld_rsel_o = Signal(n_reg, reset_less=True) # dest reg sel (bot)
28 self.st_rsel_o = Signal(n_reg, reset_less=True) # src1 reg sel (bot)
29
30 # for Function Unit "forward progress" (horizontal)
31 self.ld_fwd_o = Signal(n_reg, reset_less=True) # dest FU fw (right)
32 self.st_fwd_o = Signal(n_reg, reset_less=True) # src1 FU fw (right)
33
34 def elaborate(self, platform):
35 m = Module()
36 m.submodules.ld_c = ld_c = SRLatch(sync=False, llen=self.n_reg)
37 m.submodules.st_c = st_c = SRLatch(sync=False, llen=self.n_reg)
38
39 # connect go_rd / go_wr (dest->wr, src->rd)
40 ld_die = Signal(reset_less=True)
41 st_die = Signal(reset_less=True)
42 m.d.comb += ld_die.eq(self.go_ld_i | self.go_die_i)
43 m.d.comb += st_die.eq(self.go_st_i | self.go_die_i)
44 m.d.comb += ld_c.r.eq(Repl(ld_die, self.n_reg))
45 m.d.comb += st_c.r.eq(Repl(st_die, self.n_reg))
46
47 # connect input reg bit (unary)
48 i_ext = Repl(self.issue_i, self.n_reg)
49 m.d.comb += ld_c.s.eq(i_ext & self.ld_i)
50 m.d.comb += st_c.s.eq(i_ext & self.st_i)
51
52 # connect up hazard checks: read-after-write and write-after-read
53 m.d.comb += self.ld_fwd_o.eq(ld_c.q & self.st_pend_i)
54 m.d.comb += self.st_fwd_o.eq(st_c.q & self.ld_pend_i)
55
56 # connect reg-sel outputs
57 st_ext = Repl(self.go_st_i, self.n_reg)
58 ld_ext = Repl(self.go_ld_i, self.n_reg)
59 m.d.comb += self.ld_rsel_o.eq(ld_c.qlq & ld_ext)
60 m.d.comb += self.st_rsel_o.eq(st_c.qlq & st_ext)
61
62 # to be accumulated to indicate if register is in use (globally)
63 # after ORing, is fed back in to st_pend_i / ld_pend_i
64 m.d.comb += self.v_st_rsel_o.eq(st_c.qlq)
65 m.d.comb += self.v_ld_rsel_o.eq(ld_c.qlq)
66
67 return m
68
69 def __iter__(self):
70 yield self.ld_i
71 yield self.st_i
72 yield self.st_pend_i
73 yield self.ld_pend_i
74 yield self.issue_i
75 yield self.go_ld_i
76 yield self.go_st_i
77 yield self.go_die_i
78 yield self.v_ld_rsel_o
79 yield self.v_st_rsel_o
80 yield self.ld_rsel_o
81 yield self.st_rsel_o
82 yield self.ld_fwd_o
83 yield self.st_fwd_o
84
85 def ports(self):
86 return list(self)
87
88
89 def dcell_sim(dut):
90 yield dut.ld_i.eq(1)
91 yield dut.issue_i.eq(1)
92 yield
93 yield dut.issue_i.eq(0)
94 yield
95 yield dut.st_i.eq(1)
96 yield dut.issue_i.eq(1)
97 yield
98 yield
99 yield
100 yield dut.issue_i.eq(0)
101 yield
102 yield dut.go_st_i.eq(1)
103 yield
104 yield dut.go_st_i.eq(0)
105 yield
106 yield dut.go_ld_i.eq(1)
107 yield
108 yield dut.go_ld_i.eq(0)
109 yield
110
111 def test_dcell():
112 dut = MemDepRow(4)
113 vl = rtlil.convert(dut, ports=dut.ports())
114 with open("test_mem_drow.il", "w") as f:
115 f.write(vl)
116
117 run_simulation(dut, dcell_sim(dut), vcd_name='test_mem_dcell.vcd')
118
119 if __name__ == '__main__':
120 test_dcell()