1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
import Module
, Signal
, Cat
, Array
, Const
, Repl
, Elaboratable
4 from nmutil
.iocontrol
import RecordObject
5 from nmutil
.nmoperator
import eq
, shape
, cat
8 class Instruction(RecordObject
):
9 def __init__(self
, name
, wid
, opwid
):
10 RecordObject
.__init
__(self
, name
=name
)
11 self
.oper_i
= Signal(opwid
, reset_less
=True)
12 self
.dest_i
= Signal(wid
, reset_less
=True)
13 self
.src1_i
= Signal(wid
, reset_less
=True)
14 self
.src2_i
= Signal(wid
, reset_less
=True)
17 def nq(n_insns
, name
, wid
, opwid
):
19 for i
in range(n_insns
):
20 q
.append(Instruction("%s%d" % (name
, i
), wid
, opwid
))
24 class InstructionQ(Elaboratable
):
25 """ contains a queue of (part-decoded) instructions.
27 it is expected that the user of this queue will simply
28 inspect the queue contents directly, indicating at the start
29 of each clock cycle how many need to be removed.
31 def __init__(self
, wid
, opwid
, iqlen
, n_in
, n_out
):
36 * :wid: register file width
37 * :opwid: operand width
38 * :iqlen: instruction queue length
39 * :n_in: max number of instructions allowed "in"
46 self
.p_add_i
= Signal(max=n_in
) # instructions to add (from data_i)
47 self
.p_ready_o
= Signal() # instructions were added
48 self
.data_i
= Instruction
.nq(n_in
, "data_i", wid
, opwid
)
50 self
.data_o
= Instruction
.nq(n_out
, "data_o", wid
, opwid
)
51 self
.n_sub_i
= Signal(max=n_out
) # number of instructions to remove
52 self
.n_sub_o
= Signal(max=n_out
) # number of instructions removed
54 self
.qsz
= shape(self
.data_o
[0])[0]
55 self
.q
= Signal(iqlen
* self
.qsz
)
56 self
.qlen_o
= Signal(max=iqlen
)
58 def elaborate(self
, platform
):
64 mqlen
= Const(iqlen
, iqlen
*2)
66 start_copy
= Signal(max=iqlen
*2)
67 end_copy
= Signal(max=iqlen
*2)
69 # work out how many can be subtracted from the queue
70 with m
.If(self
.n_sub_i
>= self
.qlen_o
):
71 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
72 with m
.Elif(self
.n_sub_i
):
73 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
75 # work out the start and end of where data can be written
76 comb
+= start_copy
.eq(self
.qlen_o
- self
.n_sub_o
)
77 comb
+= end_copy
.eq(start_copy
+ self
.p_add_i
- 1)
78 comb
+= self
.p_ready_o
.eq(end_copy
< self
.qlen_o
) # ready if room exists
80 # put q (flattened) into output
81 for i
in range(self
.n_out
):
82 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[i
*self
.qsz
:(i
+1)*self
.qsz
])
84 # this is going to be _so_ expensive in terms of gates... *sigh*...
85 with m
.If(self
.p_ready_o
):
86 qsz
= Signal(max=iqlen
* self
.qsz
)
87 comb
+= qsz
.eq(self
.n_sub_o
* Const(self
.qsz
, len(qsz
)))
88 sync
+= self
.q
.eq(self
.q
>> qsz
)
100 for o
in self
.data_o
:
109 def instruction_q_sim(dut
):
110 yield dut
.dest_i
.eq(1)
111 yield dut
.issue_i
.eq(1)
113 yield dut
.issue_i
.eq(0)
115 yield dut
.src1_i
.eq(1)
116 yield dut
.issue_i
.eq(1)
120 yield dut
.issue_i
.eq(0)
122 yield dut
.go_rd_i
.eq(1)
124 yield dut
.go_rd_i
.eq(0)
126 yield dut
.go_wr_i
.eq(1)
128 yield dut
.go_wr_i
.eq(0)
131 def test_instruction_q():
132 dut
= InstructionQ(16, 4, 4, n_in
=2, n_out
=2)
133 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
134 with
open("test_instruction_q.il", "w") as f
:
137 run_simulation(dut
, instruction_q_sim(dut
),
138 vcd_name
='test_instruction_q.vcd')
140 if __name__
== '__main__':