Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / experiment / plru.py
1 # based on microwatt plru.vhdl
2
3 from nmigen import Elaboratable, Signal, Array, Module, Mux, Const, Cat
4 from nmigen.cli import rtlil
5 from nmigen.lib.coding import Decoder
6
7
8 class PLRU(Elaboratable):
9
10 def __init__(self, BITS=2):
11 self.BITS = BITS
12 self.acc_i = Signal(BITS)
13 self.acc_en = Signal()
14 self.lru_o = Signal(BITS)
15
16 def elaborate(self, platform):
17 m = Module()
18 comb, sync = m.d.comb, m.d.sync
19
20 tree = Array(Signal(name="tree%d" % i) for i in range(self.BITS))
21
22 # XXX Check if we can turn that into a little ROM instead that
23 # takes the tree bit vector and returns the LRU. See if it's better
24 # in term of FPGA resouces usage...
25 node = Const(0, self.BITS)
26 for i in range(self.BITS):
27 # report "GET: i:" & integer'image(i) & " node:" &
28 # integer'image(node) & " val:" & Signal()'image(tree(node))
29 comb += self.lru_o[self.BITS-1-i].eq(tree[node])
30 if i != self.BITS-1:
31 node_next = Signal(self.BITS)
32 node2 = Signal(self.BITS)
33 comb += node2.eq(node << 1)
34 comb += node_next.eq(Mux(tree[node2], node2+2, node2+1))
35 node = node_next
36
37 with m.If(self.acc_en):
38 node = Const(0, self.BITS)
39 for i in range(self.BITS):
40 # report "GET: i:" & integer'image(i) & " node:" &
41 # integer'image(node) & " val:" & Signal()'image(tree(node))
42 abit = self.acc_i[self.BITS-1-i]
43 sync += tree[node].eq(~abit)
44 if i != self.BITS-1:
45 node_next = Signal(self.BITS)
46 node2 = Signal(self.BITS)
47 comb += node2.eq(node << 1)
48 comb += node_next.eq(Mux(abit, node2+2, node2+1))
49 node = node_next
50
51 return m
52
53 def ports(self):
54 return [self.acc_en, self.lru_o, self.acc_i]
55
56
57 class PLRUs(Elaboratable):
58 def __init__(self, n_plrus, n_bits):
59 self.n_plrus = n_plrus
60 self.n_bits = n_bits
61 self.valid = Signal()
62 self.way = Signal(n_bits)
63 self.index = Signal(n_plrus.bit_length())
64 self.isel = Signal(n_plrus.bit_length())
65 self.o_index = Signal(n_bits)
66
67 def elaborate(self, platform):
68 """Generate TLB PLRUs
69 """
70 m = Module()
71 comb = m.d.comb
72
73 if self.n_plrus == 0:
74 return m
75
76 # Binary-to-Unary one-hot, enabled by valid
77 m.submodules.te = te = Decoder(self.n_plrus)
78 comb += te.n.eq(~self.valid)
79 comb += te.i.eq(self.index)
80
81 out = Array(Signal(self.n_bits, name="plru_out%d" % x) \
82 for x in range(self.n_plrus))
83
84 for i in range(self.n_plrus):
85 # PLRU interface
86 m.submodules["plru_%d" % i] = plru = PLRU(self.n_bits)
87
88 comb += plru.acc_en.eq(te.o[i])
89 comb += plru.acc_i.eq(self.way)
90 comb += out[i].eq(plru.lru_o)
91
92 # select output based on index
93 comb += self.o_index.eq(out[self.isel])
94
95 return m
96
97 def ports(self):
98 return [self.valid, self.way, self.index, self.isel, self.o_index]
99
100
101 if __name__ == '__main__':
102 dut = PLRU(2)
103 vl = rtlil.convert(dut, ports=dut.ports())
104 with open("test_plru.il", "w") as f:
105 f.write(vl)
106
107
108 dut = PLRUs(4, 2)
109 vl = rtlil.convert(dut, ports=dut.ports())
110 with open("test_plrus.il", "w") as f:
111 f.write(vl)
112
113