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
.opim_i
= Signal(1, reset_less
=True) # src2 is an immediate
15 self
.imm_i
= Signal(wid
, reset_less
=True)
16 self
.dest_i
= Signal(wid
, reset_less
=True)
17 self
.src1_i
= Signal(wid
, reset_less
=True)
18 self
.src2_i
= Signal(wid
, reset_less
=True)
21 def nq(n_insns
, name
, wid
, opwid
):
23 for i
in range(n_insns
):
24 q
.append(Instruction("%s%d" % (name
, i
), wid
, opwid
))
28 class InstructionQ(Elaboratable
):
29 """ contains a queue of (part-decoded) instructions.
31 output is copied combinatorially from the front of the queue,
32 for easy access on the clock cycle. only "n_in" instructions
33 are made available this way
35 input and shifting occurs on sync.
37 def __init__(self
, wid
, opwid
, iqlen
, n_in
, n_out
):
42 * :wid: register file width
43 * :opwid: operand width
44 * :iqlen: instruction queue length
45 * :n_in: max number of instructions allowed "in"
52 mqbits
= (int(log(iqlen
) / log(2))+2, False)
54 self
.p_add_i
= Signal(mqbits
) # instructions to add (from data_i)
55 self
.p_ready_o
= Signal() # instructions were added
56 self
.data_i
= Instruction
.nq(n_in
, "data_i", wid
, opwid
)
58 self
.data_o
= Instruction
.nq(n_out
, "data_o", wid
, opwid
)
59 self
.n_sub_i
= Signal(mqbits
) # number of instructions to remove
60 self
.n_sub_o
= Signal(mqbits
) # number of instructions removed
62 self
.qsz
= shape(self
.data_o
[0])[0]
64 for i
in range(iqlen
):
65 q
.append(Signal(self
.qsz
, name
="q%d" % i
))
67 self
.qlen_o
= Signal(mqbits
)
69 def elaborate(self
, platform
):
75 mqbits
= int(log(iqlen
) / log(2))
77 left
= Signal((mqbits
+2, False))
78 spare
= Signal((mqbits
+2, False))
81 start_q
= Signal(mqbits
)
82 end_q
= Signal(mqbits
)
83 mqlen
= Const(iqlen
, (len(left
), False))
84 print ("mqlen", mqlen
)
86 # work out how many can be subtracted from the queue
87 with m
.If(self
.n_sub_i
):
89 comb
+= qinmax
.eq(self
.n_sub_i
> self
.qlen_o
)
91 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
93 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
95 # work out how many new items are going to be in the queue
96 comb
+= left
.eq(self
.qlen_o
)#- self.n_sub_o)
97 comb
+= spare
.eq(mqlen
- self
.p_add_i
)
98 comb
+= qmaxed
.eq(left
<= spare
)
99 comb
+= self
.p_ready_o
.eq(qmaxed
& (self
.p_add_i
!= 0))
101 # put q (flattened) into output
102 for i
in range(self
.n_out
):
103 opos
= Signal(mqbits
)
104 comb
+= opos
.eq(end_q
+ i
)
105 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[opos
])
107 with m
.If(self
.n_sub_o
):
108 # ok now the end's moved
109 sync
+= end_q
.eq(end_q
+ self
.n_sub_o
)
111 with m
.If(self
.p_ready_o
):
112 # copy in the input... insanely gate-costly... *sigh*...
113 for i
in range(self
.n_in
):
114 with m
.If(self
.p_add_i
> Const(i
, len(self
.p_add_i
))):
115 ipos
= Signal(mqbits
)
116 comb
+= ipos
.eq(start_q
+ i
) # should roll round
117 sync
+= self
.q
[ipos
].eq(cat(self
.data_i
[i
]))
118 sync
+= start_q
.eq(start_q
+ self
.p_add_i
)
120 with m
.If(self
.p_ready_o
):
121 # update the queue length
122 add2
= Signal(mqbits
+1)
123 comb
+= add2
.eq(self
.qlen_o
+ self
.p_add_i
)
124 sync
+= self
.qlen_o
.eq(add2
- self
.n_sub_o
)
126 sync
+= self
.qlen_o
.eq(self
.qlen_o
- self
.n_sub_o
)
134 for o
in self
.data_i
:
138 for o
in self
.data_o
:
147 def instruction_q_sim(dut
):
148 yield dut
.dest_i
.eq(1)
149 yield dut
.issue_i
.eq(1)
151 yield dut
.issue_i
.eq(0)
153 yield dut
.src1_i
.eq(1)
154 yield dut
.issue_i
.eq(1)
158 yield dut
.issue_i
.eq(0)
160 yield dut
.go_rd_i
.eq(1)
162 yield dut
.go_rd_i
.eq(0)
164 yield dut
.go_wr_i
.eq(1)
166 yield dut
.go_wr_i
.eq(0)
169 def test_instruction_q():
170 dut
= InstructionQ(16, 4, 4, n_in
=2, n_out
=2)
171 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
172 with
open("test_instruction_q.il", "w") as f
:
175 run_simulation(dut
, instruction_q_sim(dut
),
176 vcd_name
='test_instruction_q.vcd')
178 if __name__
== '__main__':