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