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
11 class Instruction(Decode2ToExecute1Type
):
14 def _nq(n_insns
, name
):
16 for i
in range(n_insns
):
17 q
.append(Instruction("%s%d" % (name
, i
)))
21 class InstructionQ(Elaboratable
):
22 """ contains a queue of (part-decoded) instructions.
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
28 input and shifting occurs on sync.
30 def __init__(self
, wid
, opwid
, iqlen
, n_in
, n_out
):
35 * :wid: register file width
36 * :opwid: operand width
37 * :iqlen: instruction queue length
38 * :n_in: max number of instructions allowed "in"
45 mqbits
= (int(log(iqlen
) / log(2))+2, False)
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")
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
55 self
.qsz
= shape(self
.data_o
[0])[0]
57 for i
in range(iqlen
):
58 q
.append(Signal(self
.qsz
, name
="q%d" % i
))
60 self
.qlen_o
= Signal(mqbits
)
62 def elaborate(self
, platform
):
68 mqbits
= int(log(iqlen
) / log(2))
70 left
= Signal((mqbits
+2, False))
71 spare
= Signal((mqbits
+2, False))
74 start_q
= Signal(mqbits
)
75 end_q
= Signal(mqbits
)
76 mqlen
= Const(iqlen
, (len(left
), False))
77 print ("mqlen", mqlen
)
79 # work out how many can be subtracted from the queue
80 with m
.If(self
.n_sub_i
):
82 comb
+= qinmax
.eq(self
.n_sub_i
> self
.qlen_o
)
84 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
86 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
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))
94 # put q (flattened) into output
95 for i
in range(self
.n_out
):
97 comb
+= opos
.eq(end_q
+ i
)
98 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[opos
])
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
)
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
)
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
)
119 sync
+= self
.qlen_o
.eq(self
.qlen_o
- self
.n_sub_o
)
127 for o
in self
.data_i
:
131 for o
in self
.data_o
:
140 def instruction_q_sim(dut
):
141 yield dut
.dest_i
.eq(1)
142 yield dut
.issue_i
.eq(1)
144 yield dut
.issue_i
.eq(0)
146 yield dut
.src1_i
.eq(1)
147 yield dut
.issue_i
.eq(1)
151 yield dut
.issue_i
.eq(0)
153 yield dut
.go_rd_i
.eq(1)
155 yield dut
.go_rd_i
.eq(0)
157 yield dut
.go_wr_i
.eq(1)
159 yield dut
.go_wr_i
.eq(0)
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
:
168 run_simulation(dut
, instruction_q_sim(dut
),
169 vcd_name
='test_instruction_q.vcd')
171 if __name__
== '__main__':