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"
47 self
.p_add_i
= Signal(max=n_in
) # 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", wid
, opwid
)
51 self
.data_o
= Instruction
.nq(n_out
, "data_o", wid
, opwid
)
52 self
.n_sub_i
= Signal(max=n_out
) # number of instructions to remove
53 self
.n_sub_o
= Signal(max=n_out
) # 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(max=iqlen
)
62 def elaborate(self
, platform
):
68 mqlen
= Const(iqlen
, iqlen
+1)
70 start_copy
= Signal(max=iqlen
*2)
71 end_copy
= Signal(max=iqlen
*2)
73 # work out how many can be subtracted from the queue
74 with m
.If(self
.n_sub_i
>= self
.qlen_o
):
75 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
76 with m
.Elif(self
.n_sub_i
):
77 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
79 # work out the start and end of where data can be written
80 comb
+= start_copy
.eq(self
.qlen_o
- self
.n_sub_o
)
81 comb
+= end_copy
.eq(start_copy
+ self
.p_add_i
)
82 comb
+= self
.p_ready_o
.eq((end_copy
< self
.qlen_o
) & self
.p_add_i
)
84 # put q (flattened) into output
85 for i
in range(self
.n_out
):
86 comb
+= cat(self
.data_o
[i
]).eq(self
.q
[i
])
88 # this is going to be _so_ expensive in terms of gates... *sigh*...
89 with m
.If(self
.p_ready_o
):
90 for i
in range(iqlen
-1):
91 cfrom
= Signal(max=iqlen
*2)
92 cto
= Signal(max=iqlen
*2)
93 comb
+= cfrom
.eq(Const(i
, iqlen
+1) + start_copy
)
94 comb
+= cto
.eq(Const(i
, iqlen
+1) + end_copy
)
95 with m
.If((cfrom
< mqlen
) & (cto
< mqlen
)):
96 sync
+= self
.q
[cto
].eq(self
.q
[cfrom
])
98 for i
in range(self
.n_in
):
99 with m
.If(self
.p_add_i
< i
):
100 idx
= Signal(max=iqlen
)
101 comb
+= idx
.eq(start_copy
+ i
)
102 sync
+= self
.q
[idx
].eq(cat(self
.data_i
[i
]))
110 for o
in self
.data_i
:
114 for o
in self
.data_o
:
123 def instruction_q_sim(dut
):
124 yield dut
.dest_i
.eq(1)
125 yield dut
.issue_i
.eq(1)
127 yield dut
.issue_i
.eq(0)
129 yield dut
.src1_i
.eq(1)
130 yield dut
.issue_i
.eq(1)
134 yield dut
.issue_i
.eq(0)
136 yield dut
.go_rd_i
.eq(1)
138 yield dut
.go_rd_i
.eq(0)
140 yield dut
.go_wr_i
.eq(1)
142 yield dut
.go_wr_i
.eq(0)
145 def test_instruction_q():
146 dut
= InstructionQ(16, 4, 4, n_in
=2, n_out
=2)
147 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
148 with
open("test_instruction_q.il", "w") as f
:
151 run_simulation(dut
, instruction_q_sim(dut
),
152 vcd_name
='test_instruction_q.vcd')
154 if __name__
== '__main__':