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
10 class Instruction(RecordObject
):
11 def __init__(self
, name
, wid
, opwid
):
12 RecordObject
.__init
__(self
, name
=name
)
13 self
.oper_i
= Signal(opwid
, reset_less
=True)
14 self
.dest_i
= Signal(wid
, reset_less
=True)
15 self
.src1_i
= Signal(wid
, reset_less
=True)
16 self
.src2_i
= Signal(wid
, reset_less
=True)
19 def nq(n_insns
, name
, wid
, opwid
):
21 for i
in range(n_insns
):
22 q
.append(Instruction("%s%d" % (name
, i
), wid
, opwid
))
26 class InstructionQ(Elaboratable
):
27 """ contains a queue of (part-decoded) instructions.
29 output is copied combinatorially from the front of the queue,
30 for easy access on the clock cycle. only "n_in" instructions
31 are made available this way
33 input and shifting occurs on sync.
35 def __init__(self
, wid
, opwid
, iqlen
, n_in
, n_out
):
40 * :wid: register file width
41 * :opwid: operand width
42 * :iqlen: instruction queue length
43 * :n_in: max number of instructions allowed "in"
50 mqbits
= (int(log(iqlen
) / log(2))+2, False)
52 self
.p_add_i
= Signal(mqbits
) # instructions to add (from data_i)
53 self
.p_ready_o
= Signal() # instructions were added
54 self
.data_i
= Instruction
.nq(n_in
, "data_i", wid
, opwid
)
56 self
.data_o
= Instruction
.nq(n_out
, "data_o", wid
, opwid
)
57 self
.n_sub_i
= Signal(mqbits
) # number of instructions to remove
58 self
.n_sub_o
= Signal(mqbits
) # number of instructions removed
60 self
.qsz
= shape(self
.data_o
[0])[0]
62 for i
in range(iqlen
):
63 q
.append(Signal(self
.qsz
, name
="q%d" % i
))
65 self
.qlen_o
= Signal(mqbits
)
67 def elaborate(self
, platform
):
73 mqbits
= int(log(iqlen
) / log(2))
75 left
= Signal((mqbits
+2, False))
76 spare
= Signal((mqbits
+2, False))
79 start_q
= Signal(mqbits
)
80 end_q
= Signal(mqbits
)
81 mqlen
= Const(iqlen
, (len(left
), False))
82 print ("mqlen", mqlen
)
84 # work out how many can be subtracted from the queue
85 with m
.If(self
.n_sub_i
):
87 comb
+= qinmax
.eq(self
.n_sub_i
> self
.qlen_o
)
89 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
91 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
93 # work out how many new items are going to be in the queue
94 comb
+= left
.eq(self
.qlen_o
)#- self.n_sub_o)
95 comb
+= spare
.eq(mqlen
- self
.p_add_i
)
96 comb
+= qmaxed
.eq(left
<= spare
)
97 comb
+= self
.p_ready_o
.eq(qmaxed
& (self
.p_add_i
!= 0))
99 # put q (flattened) into output
100 for i
in range(self
.n_out
):
101 opos
= Signal(mqbits
)
102 comb
+= opos
.eq(end_q
+ i
)
103 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[opos
])
105 with m
.If(self
.n_sub_o
):
106 # ok now the end's moved
107 sync
+= end_q
.eq(end_q
+ self
.n_sub_o
)
109 with m
.If(self
.p_ready_o
):
110 # copy in the input... insanely gate-costly... *sigh*...
111 for i
in range(self
.n_in
):
112 with m
.If(self
.p_add_i
> Const(i
, len(self
.p_add_i
))):
113 ipos
= Signal(mqbits
)
114 comb
+= ipos
.eq(start_q
+ i
) # should roll round
115 sync
+= self
.q
[ipos
].eq(cat(self
.data_i
[i
]))
116 sync
+= start_q
.eq(start_q
+ self
.p_add_i
)
118 with m
.If(self
.p_ready_o
):
119 # update the queue length
120 add2
= Signal(mqbits
+1)
121 comb
+= add2
.eq(self
.qlen_o
+ self
.p_add_i
)
122 sync
+= self
.qlen_o
.eq(add2
- self
.n_sub_o
)
124 sync
+= self
.qlen_o
.eq(self
.qlen_o
- self
.n_sub_o
)
132 for o
in self
.data_i
:
136 for o
in self
.data_o
:
145 def instruction_q_sim(dut
):
146 yield dut
.dest_i
.eq(1)
147 yield dut
.issue_i
.eq(1)
149 yield dut
.issue_i
.eq(0)
151 yield dut
.src1_i
.eq(1)
152 yield dut
.issue_i
.eq(1)
156 yield dut
.issue_i
.eq(0)
158 yield dut
.go_rd_i
.eq(1)
160 yield dut
.go_rd_i
.eq(0)
162 yield dut
.go_wr_i
.eq(1)
164 yield dut
.go_wr_i
.eq(0)
167 def test_instruction_q():
168 dut
= InstructionQ(16, 4, 4, n_in
=2, n_out
=2)
169 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
170 with
open("test_instruction_q.il", "w") as f
:
173 run_simulation(dut
, instruction_q_sim(dut
),
174 vcd_name
='test_instruction_q.vcd')
176 if __name__
== '__main__':