rename PLRU modules to avoid conflict in microwatt
[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, cachetype, n_plrus, n_bits):
59 self.cachetype = cachetype
60 self.n_plrus = n_plrus
61 self.n_bits = n_bits
62 self.valid = Signal()
63 self.way = Signal(n_bits)
64 self.index = Signal(n_plrus.bit_length())
65 self.isel = Signal(n_plrus.bit_length())
66 self.o_index = Signal(n_bits)
67
68 def elaborate(self, platform):
69 """Generate TLB PLRUs
70 """
71 m = Module()
72 comb = m.d.comb
73
74 if self.n_plrus == 0:
75 return m
76
77 # Binary-to-Unary one-hot, enabled by valid
78 m.submodules.te = te = Decoder(self.n_plrus)
79 comb += te.n.eq(~self.valid)
80 comb += te.i.eq(self.index)
81
82 out = Array(Signal(self.n_bits, name="plru_out%d" % x) \
83 for x in range(self.n_plrus))
84
85 for i in range(self.n_plrus):
86 # PLRU interface
87 name = "%s_plru_%d" % (self.cachetype, i)
88 m.submodules[name] = plru = PLRU(self.n_bits)
89
90 comb += plru.acc_en.eq(te.o[i])
91 comb += plru.acc_i.eq(self.way)
92 comb += out[i].eq(plru.lru_o)
93
94 # select output based on index
95 comb += self.o_index.eq(out[self.isel])
96
97 return m
98
99 def ports(self):
100 return [self.valid, self.way, self.index, self.isel, self.o_index]
101
102
103 if __name__ == '__main__':
104 dut = PLRU(2)
105 vl = rtlil.convert(dut, ports=dut.ports())
106 with open("test_plru.il", "w") as f:
107 f.write(vl)
108
109
110 dut = PLRUs("testing", 4, 2)
111 vl = rtlil.convert(dut, ports=dut.ports())
112 with open("test_plrus.il", "w") as f:
113 f.write(vl)
114
115