a51ccf1ae0cbeb39e357516582569588df3d394c
[ieee754fpu.git] / src / add / test_inout_mux_pipe.py
1 """ key strategic example showing how to do multi-input fan-in into a
2 multi-stage pipeline, then multi-output fanout.
3
4 the multiplex ID from the fan-in is passed in to the pipeline, preserved,
5 and used as a routing ID on the fanout.
6 """
7
8 from random import randint
9 from math import log
10 from nmigen import Module, Signal, Cat, Value, Elaboratable
11 from nmigen.compat.sim import run_simulation
12 from nmigen.cli import verilog, rtlil
13
14 from multipipe import CombMultiOutPipeline, CombMuxOutPipe
15 from multipipe import PriorityCombMuxInPipe
16 from singlepipe import SimpleHandshake, RecordObject, Object
17
18
19 class PassData2(RecordObject):
20 def __init__(self):
21 RecordObject.__init__(self)
22 self.mid = Signal(2, reset_less=True)
23 self.idx = Signal(8, reset_less=True)
24 self.data = Signal(16, reset_less=True)
25
26
27 class PassData(Object):
28 def __init__(self):
29 Object.__init__(self)
30 self.mid = Signal(2, reset_less=True)
31 self.idx = Signal(8, reset_less=True)
32 self.data = Signal(16, reset_less=True)
33
34
35
36 class PassThroughStage:
37 def ispec(self):
38 return PassData()
39 def ospec(self):
40 return self.ispec() # same as ospec
41
42 def process(self, i):
43 return i # pass-through
44
45
46
47 class PassThroughPipe(SimpleHandshake):
48 def __init__(self):
49 SimpleHandshake.__init__(self, PassThroughStage())
50
51
52 class InputTest:
53 def __init__(self, dut):
54 self.dut = dut
55 self.di = {}
56 self.do = {}
57 self.tlen = 100
58 for mid in range(dut.num_rows):
59 self.di[mid] = {}
60 self.do[mid] = {}
61 for i in range(self.tlen):
62 self.di[mid][i] = randint(0, 255) + (mid<<8)
63 self.do[mid][i] = self.di[mid][i]
64
65 def send(self, mid):
66 for i in range(self.tlen):
67 op2 = self.di[mid][i]
68 rs = dut.p[mid]
69 yield rs.valid_i.eq(1)
70 yield rs.i_data.data.eq(op2)
71 yield rs.i_data.idx.eq(i)
72 yield rs.i_data.mid.eq(mid)
73 yield
74 o_p_ready = yield rs.ready_o
75 while not o_p_ready:
76 yield
77 o_p_ready = yield rs.ready_o
78
79 print ("send", mid, i, hex(op2))
80
81 yield rs.valid_i.eq(0)
82 # wait random period of time before queueing another value
83 for i in range(randint(0, 3)):
84 yield
85
86 yield rs.valid_i.eq(0)
87 yield
88
89 print ("send ended", mid)
90
91 ## wait random period of time before queueing another value
92 #for i in range(randint(0, 3)):
93 # yield
94
95 #send_range = randint(0, 3)
96 #if send_range == 0:
97 # send = True
98 #else:
99 # send = randint(0, send_range) != 0
100
101 def rcv(self, mid):
102 while True:
103 #stall_range = randint(0, 3)
104 #for j in range(randint(1,10)):
105 # stall = randint(0, stall_range) != 0
106 # yield self.dut.n[0].ready_i.eq(stall)
107 # yield
108 n = self.dut.n[mid]
109 yield n.ready_i.eq(1)
110 yield
111 o_n_valid = yield n.valid_o
112 i_n_ready = yield n.ready_i
113 if not o_n_valid or not i_n_ready:
114 continue
115
116 out_mid = yield n.o_data.mid
117 out_i = yield n.o_data.idx
118 out_v = yield n.o_data.data
119
120 print ("recv", out_mid, out_i, hex(out_v))
121
122 # see if this output has occurred already, delete it if it has
123 assert mid == out_mid, "out_mid %d not correct %d" % (out_mid, mid)
124 assert out_i in self.do[mid], "out_i %d not in array %s" % \
125 (out_i, repr(self.do[mid]))
126 assert self.do[mid][out_i] == out_v # pass-through data
127 del self.do[mid][out_i]
128
129 # check if there's any more outputs
130 if len(self.do[mid]) == 0:
131 break
132 print ("recv ended", mid)
133
134
135 class TestPriorityMuxPipe(PriorityCombMuxInPipe):
136 def __init__(self, num_rows):
137 self.num_rows = num_rows
138 stage = PassThroughStage()
139 PriorityCombMuxInPipe.__init__(self, stage, p_len=self.num_rows)
140
141
142 class OutputTest:
143 def __init__(self, dut):
144 self.dut = dut
145 self.di = []
146 self.do = {}
147 self.tlen = 100
148 for i in range(self.tlen * dut.num_rows):
149 if i < dut.num_rows:
150 mid = i
151 else:
152 mid = randint(0, dut.num_rows-1)
153 data = randint(0, 255) + (mid<<8)
154
155 def send(self):
156 for i in range(self.tlen * dut.num_rows):
157 op2 = self.di[i][0]
158 mid = self.di[i][1]
159 rs = dut.p
160 yield rs.valid_i.eq(1)
161 yield rs.i_data.data.eq(op2)
162 yield rs.i_data.mid.eq(mid)
163 yield
164 o_p_ready = yield rs.ready_o
165 while not o_p_ready:
166 yield
167 o_p_ready = yield rs.ready_o
168
169 print ("send", mid, i, hex(op2))
170
171 yield rs.valid_i.eq(0)
172 # wait random period of time before queueing another value
173 for i in range(randint(0, 3)):
174 yield
175
176 yield rs.valid_i.eq(0)
177
178
179 class TestMuxOutPipe(CombMuxOutPipe):
180 def __init__(self, num_rows):
181 self.num_rows = num_rows
182 stage = PassThroughStage()
183 CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows)
184
185
186 class TestInOutPipe(Elaboratable):
187 def __init__(self, num_rows=4):
188 self.num_rows = num_rows
189 self.inpipe = TestPriorityMuxPipe(num_rows) # fan-in (combinatorial)
190 self.pipe1 = PassThroughPipe() # stage 1 (clock-sync)
191 self.pipe2 = PassThroughPipe() # stage 2 (clock-sync)
192 self.outpipe = TestMuxOutPipe(num_rows) # fan-out (combinatorial)
193
194 self.p = self.inpipe.p # kinda annoying,
195 self.n = self.outpipe.n # use pipe in/out as this class in/out
196 self._ports = self.inpipe.ports() + self.outpipe.ports()
197
198 def elaborate(self, platform):
199 m = Module()
200 m.submodules.inpipe = self.inpipe
201 m.submodules.pipe1 = self.pipe1
202 m.submodules.pipe2 = self.pipe2
203 m.submodules.outpipe = self.outpipe
204
205 m.d.comb += self.inpipe.n.connect_to_next(self.pipe1.p)
206 m.d.comb += self.pipe1.connect_to_next(self.pipe2)
207 m.d.comb += self.pipe2.connect_to_next(self.outpipe)
208
209 return m
210
211 def ports(self):
212 return self._ports
213
214
215 if __name__ == '__main__':
216 dut = TestInOutPipe()
217 vl = rtlil.convert(dut, ports=dut.ports())
218 with open("test_inoutmux_pipe.il", "w") as f:
219 f.write(vl)
220 #run_simulation(dut, testbench(dut), vcd_name="test_inputgroup.vcd")
221
222 test = InputTest(dut)
223 run_simulation(dut, [test.rcv(1), test.rcv(0),
224 test.rcv(3), test.rcv(2),
225 test.send(0), test.send(1),
226 test.send(3), test.send(2),
227 ],
228 vcd_name="test_inoutmux_pipe.vcd")
229