4dec3cf21adbc6a7c72c077a92dc3a1585531c51
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
9 from soc
.decoder
.power_decoder2
import Decode2ToExecute1Type
12 class Instruction(Decode2ToExecute1Type
):
15 def _nq(n_insns
, name
):
17 for i
in range(n_insns
):
18 q
.append(Instruction("%s%d" % (name
, i
)))
22 class InstructionQ(Elaboratable
):
23 """ contains a queue of (part-decoded) instructions.
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
29 input and shifting occurs on sync.
32 def __init__(self
, wid
, opwid
, iqlen
, n_in
, n_out
):
37 * :wid: register file width
38 * :opwid: operand width
39 * :iqlen: instruction queue length
40 * :n_in: max number of instructions allowed "in"
47 mqbits
= (int(log(iqlen
) / log(2))+2, False)
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")
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
57 self
.qsz
= shape(self
.data_o
[0])[0]
59 for i
in range(iqlen
):
60 q
.append(Signal(self
.qsz
, name
="q%d" % i
))
62 self
.qlen_o
= Signal(mqbits
)
64 def elaborate(self
, platform
):
70 mqbits
= int(log(iqlen
) / log(2))
72 left
= Signal((mqbits
+2, False))
73 spare
= Signal((mqbits
+2, False))
76 start_q
= Signal(mqbits
)
77 end_q
= Signal(mqbits
)
78 mqlen
= Const(iqlen
, (len(left
), False))
81 # work out how many can be subtracted from the queue
82 with m
.If(self
.n_sub_i
):
84 comb
+= qinmax
.eq(self
.n_sub_i
> self
.qlen_o
)
86 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
88 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
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))
96 # put q (flattened) into output
97 for i
in range(self
.n_out
):
99 comb
+= opos
.eq(end_q
+ i
)
100 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[opos
])
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
)
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
)
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
)
121 sync
+= self
.qlen_o
.eq(self
.qlen_o
- self
.n_sub_o
)
129 for o
in self
.data_i
:
133 for o
in self
.data_o
:
142 def instruction_q_sim(dut
):
143 yield dut
.dest_i
.eq(1)
144 yield dut
.issue_i
.eq(1)
146 yield dut
.issue_i
.eq(0)
148 yield dut
.src1_i
.eq(1)
149 yield dut
.issue_i
.eq(1)
153 yield dut
.issue_i
.eq(0)
155 yield dut
.go_rd_i
.eq(1)
157 yield dut
.go_rd_i
.eq(0)
159 yield dut
.go_wr_i
.eq(1)
161 yield dut
.go_wr_i
.eq(0)
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
:
171 run_simulation(dut
, instruction_q_sim(dut
),
172 vcd_name
='test_instruction_q.vcd')
175 if __name__
== '__main__':