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
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
.q
= Instruction
.nq(iqlen
, "i", wid
, opwid
)
47 self
.qlen_o
= Signal(max=iqlen
)
49 self
.p_add_i
= Signal(max=n_in
) # instructions to add (from data_i)
50 self
.p_ready_o
= Signal() # instructions were added
51 self
.data_i
= Instruction
.nq(n_in
, "data_i", wid
, opwid
)
53 self
.data_o
= Instruction
.nq(n_out
, "data_o", wid
, opwid
)
54 self
.n_sub_i
= Signal(max=n_out
) # number of instructions to remove
55 self
.n_sub_o
= Signal(max=n_out
) # number of instructions removed
57 def elaborate(self
, platform
):
63 mqlen
= Const(iqlen
, iqlen
*2)
65 start_copy
= Signal(max=iqlen
*2)
66 end_copy
= Signal(max=iqlen
*2)
68 # work out how many can be subtracted from the queue
69 with m
.If(self
.n_sub_i
>= self
.qlen_o
):
70 comb
+= self
.n_sub_o
.eq(self
.qlen_o
)
71 with m
.Elif(self
.n_sub_i
):
72 comb
+= self
.n_sub_o
.eq(self
.n_sub_i
)
74 # work out the start and end of where data can be written
75 comb
+= start_copy
.eq(self
.qlen_o
- self
.n_sub_o
)
76 comb
+= end_copy
.eq(start_copy
+ self
.p_add_i
- 1)
77 comb
+= self
.p_ready_o
.eq(end_copy
< self
.qlen_o
) # ready if room exists
79 # this is going to be _so_ expensive in terms of gates... *sigh*...
80 with m
.If(self
.p_ready_o
):
81 for i
in range(iqlen
):
82 cfrom
= Signal(max=iqlen
*2)
83 cto
= Signal(max=iqlen
*2)
84 comb
+= cfrom
.eq(Const(i
, iqlen
+1) + start_copy
)
85 comb
+= cto
.eq(Const(i
, iqlen
+1) + end_copy
)
86 with m
.If((cfrom
< mqlen
) & (cto
< mqlen
)):
87 sync
+= self
.q
[cto
].oper_i
.eq(self
.q
[cfrom
].oper_i
)
88 sync
+= self
.q
[cto
].dest_i
.eq(self
.q
[cfrom
].dest_i
)
89 sync
+= self
.q
[cto
].src1_i
.eq(self
.q
[cfrom
].src1_i
)
90 sync
+= self
.q
[cto
].src2_i
.eq(self
.q
[cfrom
].src2_i
)
100 for o
in self
.data_i
:
104 for o
in self
.data_o
:
113 def instruction_q_sim(dut
):
114 yield dut
.dest_i
.eq(1)
115 yield dut
.issue_i
.eq(1)
117 yield dut
.issue_i
.eq(0)
119 yield dut
.src1_i
.eq(1)
120 yield dut
.issue_i
.eq(1)
124 yield dut
.issue_i
.eq(0)
126 yield dut
.go_rd_i
.eq(1)
128 yield dut
.go_rd_i
.eq(0)
130 yield dut
.go_wr_i
.eq(1)
132 yield dut
.go_wr_i
.eq(0)
135 def test_instruction_q():
136 dut
= InstructionQ(16, 4, 4, n_in
=2, n_out
=2)
137 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
138 with
open("test_instruction_q.il", "w") as f
:
141 run_simulation(dut
, instruction_q_sim(dut
),
142 vcd_name
='test_instruction_q.vcd')
144 if __name__
== '__main__':