Merge branch 'master' of ssh://git.libre-riscv.org:922/soc
[soc.git] / src / soc / scoreboard / instruction_q.py
1 from math import log
2
3 from nmigen.compat.sim import run_simulation
4 from nmigen.cli import verilog, rtlil
5 from nmigen import Module, Signal, Cat, Array, Const, Repl, Elaboratable
6 from nmutil.iocontrol import RecordObject
7 from nmutil.nmoperator import eq, shape, cat
8
9 from soc.decoder.power_decoder2 import Decode2ToExecute1Type
10
11 class Instruction(Decode2ToExecute1Type):
12
13 @staticmethod
14 def _nq(n_insns, name):
15 q = []
16 for i in range(n_insns):
17 q.append(Instruction("%s%d" % (name, i)))
18 return Array(q)
19
20
21 class InstructionQ(Elaboratable):
22 """ contains a queue of (part-decoded) instructions.
23
24 output is copied combinatorially from the front of the queue,
25 for easy access on the clock cycle. only "n_in" instructions
26 are made available this way
27
28 input and shifting occurs on sync.
29 """
30 def __init__(self, wid, opwid, iqlen, n_in, n_out):
31 """ constructor
32
33 Inputs
34
35 * :wid: register file width
36 * :opwid: operand width
37 * :iqlen: instruction queue length
38 * :n_in: max number of instructions allowed "in"
39 """
40 self.iqlen = iqlen
41 self.reg_width = wid
42 self.opwid = opwid
43 self.n_in = n_in
44 self.n_out = n_out
45 mqbits = (int(log(iqlen) / log(2))+2, False)
46
47 self.p_add_i = Signal(mqbits) # instructions to add (from data_i)
48 self.p_ready_o = Signal() # instructions were added
49 self.data_i = Instruction._nq(n_in, "data_i")
50
51 self.data_o = Instruction._nq(n_out, "data_o")
52 self.n_sub_i = Signal(mqbits) # number of instructions to remove
53 self.n_sub_o = Signal(mqbits) # number of instructions removed
54
55 self.qsz = shape(self.data_o[0])[0]
56 q = []
57 for i in range(iqlen):
58 q.append(Signal(self.qsz, name="q%d" % i))
59 self.q = Array(q)
60 self.qlen_o = Signal(mqbits)
61
62 def elaborate(self, platform):
63 m = Module()
64 comb = m.d.comb
65 sync = m.d.sync
66
67 iqlen = self.iqlen
68 mqbits = int(log(iqlen) / log(2))
69
70 left = Signal((mqbits+2, False))
71 spare = Signal((mqbits+2, False))
72 qmaxed = Signal()
73
74 start_q = Signal(mqbits)
75 end_q = Signal(mqbits)
76 mqlen = Const(iqlen, (len(left), False))
77 print ("mqlen", mqlen)
78
79 # work out how many can be subtracted from the queue
80 with m.If(self.n_sub_i):
81 qinmax = Signal()
82 comb += qinmax.eq(self.n_sub_i > self.qlen_o)
83 with m.If(qinmax):
84 comb += self.n_sub_o.eq(self.qlen_o)
85 with m.Else():
86 comb += self.n_sub_o.eq(self.n_sub_i)
87
88 # work out how many new items are going to be in the queue
89 comb += left.eq(self.qlen_o )#- self.n_sub_o)
90 comb += spare.eq(mqlen - self.p_add_i)
91 comb += qmaxed.eq(left <= spare)
92 comb += self.p_ready_o.eq(qmaxed & (self.p_add_i != 0))
93
94 # put q (flattened) into output
95 for i in range(self.n_out):
96 opos = Signal(mqbits)
97 comb += opos.eq(end_q + i)
98 comb += cat(self.data_o[i]).eq(self.q[opos])
99
100 with m.If(self.n_sub_o):
101 # ok now the end's moved
102 sync += end_q.eq(end_q + self.n_sub_o)
103
104 with m.If(self.p_ready_o):
105 # copy in the input... insanely gate-costly... *sigh*...
106 for i in range(self.n_in):
107 with m.If(self.p_add_i > Const(i, len(self.p_add_i))):
108 ipos = Signal(mqbits)
109 comb += ipos.eq(start_q + i) # should roll round
110 sync += self.q[ipos].eq(cat(self.data_i[i]))
111 sync += start_q.eq(start_q + self.p_add_i)
112
113 with m.If(self.p_ready_o):
114 # update the queue length
115 add2 = Signal(mqbits+1)
116 comb += add2.eq(self.qlen_o + self.p_add_i)
117 sync += self.qlen_o.eq(add2 - self.n_sub_o)
118 with m.Else():
119 sync += self.qlen_o.eq(self.qlen_o - self.n_sub_o)
120
121 return m
122
123 def __iter__(self):
124 yield from self.q
125
126 yield self.p_ready_o
127 for o in self.data_i:
128 yield from list(o)
129 yield self.p_add_i
130
131 for o in self.data_o:
132 yield from list(o)
133 yield self.n_sub_i
134 yield self.n_sub_o
135
136 def ports(self):
137 return list(self)
138
139
140 def instruction_q_sim(dut):
141 yield dut.dest_i.eq(1)
142 yield dut.issue_i.eq(1)
143 yield
144 yield dut.issue_i.eq(0)
145 yield
146 yield dut.src1_i.eq(1)
147 yield dut.issue_i.eq(1)
148 yield
149 yield
150 yield
151 yield dut.issue_i.eq(0)
152 yield
153 yield dut.go_rd_i.eq(1)
154 yield
155 yield dut.go_rd_i.eq(0)
156 yield
157 yield dut.go_wr_i.eq(1)
158 yield
159 yield dut.go_wr_i.eq(0)
160 yield
161
162 def test_instruction_q():
163 dut = InstructionQ(16, 4, 4, n_in=2, n_out=2)
164 vl = rtlil.convert(dut, ports=dut.ports())
165 with open("test_instruction_q.il", "w") as f:
166 f.write(vl)
167
168 run_simulation(dut, instruction_q_sim(dut),
169 vcd_name='test_instruction_q.vcd')
170
171 if __name__ == '__main__':
172 test_instruction_q()