Only Imported FPGetOp
[ieee754fpu.git] / a36447fc
1 \e[33mcommit f02c6f4bbf463472d3d68e52bd5ededd3c937f58\e[m\e[33m (\e[m\e[1;36mHEAD -> \e[m\e[1;32mmaster\e[m\e[33m, \e[m\e[1;31morigin/master\e[m\e[33m, \e[m\e[1;31morigin/HEAD\e[m\e[33m)\e[m
2 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 Date: Fri Mar 15 12:37:14 2019 +0000
4
5 add parallel InputGroup unit test
6
7 \e[33mcommit b13c8a7a5368a53bedc71e5b8969c721103144c4\e[m
8 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
9 Date: Fri Mar 15 10:59:44 2019 +0000
10
11 rename BufPipe example to ExampleBufPipe
12
13 \e[33mcommit a36447fcd4d4f049b7127e1fc02dc1390d05fa75\e[m
14 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
15 Date: Fri Mar 15 09:59:07 2019 +0000
16
17 instantiate 2 FPGetOp instances and use them. a little awkwardly.
18
19 \e[33mcommit 092d2d78fa19a5c73863cb89c5d680cbd2afe027\e[m
20 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
21 Date: Fri Mar 15 09:33:44 2019 +0000
22
23 update comments
24
25 \e[33mcommit 8989cd3452869d43a8a3655acffd3eb3288f5d9a\e[m
26 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
27 Date: Fri Mar 15 09:22:58 2019 +0000
28
29 remove unnecessary code
30
31 \e[33mcommit b90c533476affe63a34292bfe54dde62a105bed8\e[m
32 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
33 Date: Fri Mar 15 08:47:21 2019 +0000
34
35 add extra comment block explaining pipe stage example
36
37 \e[33mcommit 28a8ede4a797a76e83410fb42a9aaa02b44fb2ef\e[m
38 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
39 Date: Fri Mar 15 08:37:18 2019 +0000
40
41 inverted busy signal and named it "ready"
42
43 \e[33mcommit 0ebc09c0a7b74e4807ccdb60ca0a10cbb605666a\e[m
44 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
45 Date: Fri Mar 15 08:29:56 2019 +0000
46
47 rename stb to "valid"
48
49 \e[33mcommit 0bfbc8ff919f0cd9c7f01b4c711b1b91a53ad480\e[m
50 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
51 Date: Fri Mar 15 08:28:18 2019 +0000
52
53 create classes for STB/BUSY, split in from out
54
55 \e[33mcommit ca218a65dc9af73965a5c4f105a780ed04b588e0\e[m
56 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
57 Date: Fri Mar 15 00:31:30 2019 +0000
58
59 add use of FPState, not being used yet
60
61 \e[33mcommit ce7a1d5c48e987cbfb40236f13b17ffcea55b585\e[m
62 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
63 Date: Thu Mar 14 13:32:06 2019 +0000
64
65 split pipeline test into 2 functions, one send, one receive
66
67 \e[33mcommit 481d00c37b31e7908e624235e6e9c93b12baeebb\e[m
68 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
69 Date: Thu Mar 14 06:33:10 2019 +0000
70
71 got fpdiv up and running again
72
73 \e[33mcommit 286fdefc4bbe8c7b4bb34ae33b513e8bb81b3d7e\e[m
74 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
75 Date: Thu Mar 14 05:41:02 2019 +0000
76
77 forgot to add submodules
78
79 \e[33mcommit 43c53078d577aa33d28ba0eb2af782b7d348a517\e[m
80 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
81 Date: Thu Mar 14 05:09:36 2019 +0000
82
83 got rounding working again for fmul
84
85 \e[33mcommit 892d640f8224e6a52907c6899ab6ab671f5f53af\e[m
86 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
87 Date: Thu Mar 14 04:42:53 2019 +0000
88
89 remove extra arg from old roundz function
90
91 \e[33mcommit ccd4d65a7bd2985edb5547daf7df623cda5ab9da\e[m
92 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
93 Date: Thu Mar 14 04:33:01 2019 +0000
94
95 make a bit of a mess of the unit tests, getting mul up and running again
96 taking a copy (sigh) of the old version of check_case and get_case
97
98 \e[33mcommit 9b9732e1c96d085bc9c7b696e7c86dd0c4a4ae49\e[m
99 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
100 Date: Thu Mar 14 04:17:28 2019 +0000
101
102 get roundz working again, needed for mul stage
103
104 \e[33mcommit 38452d7fb64752a897b26e1da96a27d3a5979a76\e[m
105 Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
106 Date: Thu Mar 14 04:16:28 2019 +0000
107
108 add new FPNormaliseSingleMod, not tested
109 \e[1mdiff --git a/src/add/example_buf_pipe.py b/src/add/example_buf_pipe.py\e[m
110 \e[1mindex 6678a67..00eecc3 100644\e[m
111 \e[1m--- a/src/add/example_buf_pipe.py\e[m
112 \e[1m+++ b/src/add/example_buf_pipe.py\e[m
113 \e[36m@@ -12,12 +12,12 @@\e[m
114 where data will flow on *every* clock when the conditions are right.\e[m
115 \e[m
116 input acceptance conditions are when:\e[m
117 \e[31m- * incoming previous-stage strobe (i_p_stb) is HIGH\e[m
118 \e[31m- * outgoing previous-stage busy (o_p_busy) is LOW\e[m
119 \e[32m+\e[m\e[32m * incoming previous-stage strobe (i.p_valid) is HIGH\e[m
120 \e[32m+\e[m\e[32m * outgoing previous-stage ready (o.p_ready) is LOW\e[m
121 \e[m
122 output transmission conditions are when:\e[m
123 \e[31m- * outgoing next-stage strobe (o_n_stb) is HIGH\e[m
124 \e[31m- * outgoing next-stage busy (i_n_busy) is LOW\e[m
125 \e[32m+\e[m\e[32m * outgoing next-stage strobe (o.n_valid) is HIGH\e[m
126 \e[32m+\e[m\e[32m * outgoing next-stage ready (i.n_ready) is LOW\e[m
127 \e[m
128 the tricky bit is when the input has valid data and the output is not\e[m
129 ready to accept it. if it wasn't for the clock synchronisation, it\e[m
130 \e[36m@@ -33,7 +33,7 @@\e[m
131 we now effectively have *two* possible pieces of data to "choose" from:\e[m
132 the buffered data, and the incoming data. the decision as to which\e[m
133 to process and output is based on whether we are in "stall" or not.\e[m
134 \e[31m- i.e. when the next stage is no longer busy, the output comes from\e[m
135 \e[32m+\e[m\e[32m i.e. when the next stage is no longer ready, the output comes from\e[m
136 the buffer if a stall had previously occurred, otherwise it comes\e[m
137 direct from processing the input.\e[m
138 \e[m
139 \e[36m@@ -69,7 +69,17 @@\e[m \e[mclass ExampleStage:\e[m
140 \e[m
141 def __init__(self):\e[m
142 """ i_data can be a DIFFERENT type from everything else\e[m
143 \e[31m- o_data, r_data and result must be of the same type\e[m
144 \e[32m+\e[m\e[32m o_data, r_data and result are best of the same type.\e[m
145 \e[32m+\e[m\e[32m however this is not strictly necessary. an intermediate\e[m
146 \e[32m+\e[m\e[32m transformation process could hypothetically be applied, however\e[m
147 \e[32m+\e[m\e[32m it is result and r_data that definitively need to be of the same\e[m
148 \e[32m+\e[m\e[32m (intermediary) type, as it is both result and r_data that\e[m
149 \e[32m+\e[m\e[32m are transferred into o_data:\e[m
150 \e[32m+\e[m
151 \e[32m+\e[m\e[32m i_data -> process() -> result --> o_data\e[m
152 \e[32m+\e[m\e[32m | ^\e[m
153 \e[32m+\e[m\e[32m | |\e[m
154 \e[32m+\e[m\e[32m +-> r_data -+\e[m
155 """\e[m
156 self.i_data = Signal(16)\e[m
157 self.r_data = Signal(16)\e[m
158 \e[36m@@ -83,7 +93,9 @@\e[m \e[mclass ExampleStage:\e[m
159 return self.result.eq(self.i_data + 1)\e[m
160 \e[m
161 def update_buffer(self):\e[m
162 \e[31m- """ copies the result into the intermediate register r_data\e[m
163 \e[32m+\e[m\e[32m """ copies the result into the intermediate register r_data,\e[m
164 \e[32m+\e[m\e[32m which will need to be outputted on a subsequent cycle\e[m
165 \e[32m+\e[m\e[32m prior to allowing "normal" operation.\e[m
166 """\e[m
167 return self.r_data.eq(self.result)\e[m
168 \e[m
169 \e[36m@@ -100,88 +112,98 @@\e[m \e[mclass ExampleStage:\e[m
170 def ports(self):\e[m
171 return [self.i_data, self.o_data]\e[m
172 \e[m
173 \e[32m+\e[m\e[32mclass IOAckIn:\e[m
174 \e[32m+\e[m
175 \e[32m+\e[m\e[32m def __init__(self):\e[m
176 \e[32m+\e[m\e[32m self.p_valid = Signal() # >>in - comes in from PREVIOUS stage\e[m
177 \e[32m+\e[m\e[32m self.n_ready = Signal() # in<< - comes in from the NEXT stage\e[m
178 \e[32m+\e[m
179 \e[32m+\e[m
180 \e[32m+\e[m\e[32mclass IOAckOut:\e[m
181 \e[32m+\e[m
182 \e[32m+\e[m\e[32m def __init__(self):\e[m
183 \e[32m+\e[m\e[32m self.n_valid = Signal() # out>> - goes out to the NEXT stage\e[m
184 \e[32m+\e[m\e[32m self.p_ready = Signal() # <<out - goes out to the PREVIOUS stage\e[m
185 \e[32m+\e[m
186 \e[m
187 class BufferedPipeline:\e[m
188 """ buffered pipeline stage\e[m
189 \e[m
190 \e[31m- stage-1 i_p_stb >>in stage o_n_stb out>> stage+1\e[m
191 \e[31m- stage-1 o_p_busy <<out stage i_n_busy <<in stage+1\e[m
192 \e[31m- stage-1 i_data >>in stage o_data out>> stage+1\e[m
193 \e[32m+\e[m\e[32m stage-1 i.p_valid >>in stage o.n_valid out>> stage+1\e[m
194 \e[32m+\e[m\e[32m stage-1 o.p_ready <<out stage i.n_ready <<in stage+1\e[m
195 \e[32m+\e[m\e[32m stage-1 i_data >>in stage o_data out>> stage+1\e[m
196 | |\e[m
197 +-------> process\e[m
198 | |\e[m
199 +-- r_data ---+\e[m
200 """\e[m
201 def __init__(self):\e[m
202 \e[31m- # input: strobe comes in from previous stage, busy comes in from next\e[m
203 \e[31m- #self.i_p_rst = Signal() # >>in - comes in from PREVIOUS stage\e[m
204 \e[31m- self.i_p_stb = Signal() # >>in - comes in from PREVIOUS stage\e[m
205 \e[31m- self.i_n_busy = Signal() # in<< - comes in from the NEXT stage\e[m
206 \e[32m+\e[m\e[32m # input: strobe comes in from previous stage, ready comes in from next\e[m
207 \e[32m+\e[m\e[32m self.i = IOAckIn()\e[m
208 \e[32m+\e[m\e[32m #self.i.p_valid = Signal() # >>in - comes in from PREVIOUS stage\e[m
209 \e[32m+\e[m\e[32m #self.i.n_ready = Signal() # in<< - comes in from the NEXT stage\e[m
210 \e[m
211 \e[31m- # output: strobe goes out to next stage, busy comes in from previous\e[m
212 \e[31m- self.o_n_stb = Signal() # out>> - goes out to the NEXT stage\e[m
213 \e[31m- self.o_p_busy = Signal() # <<out - goes out to the PREVIOUS stage\e[m
214 \e[32m+\e[m\e[32m # output: strobe goes out to next stage, ready comes in from previous\e[m
215 \e[32m+\e[m\e[32m self.o = IOAckOut()\e[m
216 \e[32m+\e[m\e[32m #self.o.n_valid = Signal() # out>> - goes out to the NEXT stage\e[m
217 \e[32m+\e[m\e[32m #self.o.p_ready = Signal() # <<out - goes out to the PREVIOUS stage\e[m
218 \e[m
219 def elaborate(self, platform):\e[m
220 m = Module()\e[m
221 \e[m
222 # establish some combinatorial temporaries\e[m
223 \e[31m- o_p_busyn = Signal(reset_less=True)\e[m
224 \e[31m- o_n_stbn = Signal(reset_less=True)\e[m
225 \e[31m- i_n_busyn = Signal(reset_less=True)\e[m
226 \e[31m- i_p_stb_o_p_busyn = Signal(reset_less=True)\e[m
227 \e[31m- m.d.comb += [i_n_busyn.eq(~self.i_n_busy),\e[m
228 \e[31m- o_n_stbn.eq(~self.o_n_stb),\e[m
229 \e[31m- o_p_busyn.eq(~self.o_p_busy),\e[m
230 \e[31m- i_p_stb_o_p_busyn.eq(self.i_p_stb & o_p_busyn),\e[m
231 \e[32m+\e[m\e[32m o_n_validn = Signal(reset_less=True)\e[m
232 \e[32m+\e[m\e[32m i_p_valid_o_p_ready = Signal(reset_less=True)\e[m
233 \e[32m+\e[m\e[32m m.d.comb += [o_n_validn.eq(~self.o.n_valid),\e[m
234 \e[32m+\e[m\e[32m i_p_valid_o_p_ready.eq(self.i.p_valid & self.o.p_ready),\e[m
235 ]\e[m
236 \e[m
237 # store result of processing in combinatorial temporary\e[m
238 \e[31m- with m.If(self.i_p_stb): # input is valid: process it\e[m
239 \e[32m+\e[m\e[32m with m.If(self.i.p_valid): # input is valid: process it\e[m
240 m.d.comb += self.stage.process()\e[m
241 # if not in stall condition, update the temporary register\e[m
242 \e[31m- with m.If(o_p_busyn): # not stalled\e[m
243 \e[32m+\e[m\e[32m with m.If(self.o.p_ready): # not stalled\e[m
244 m.d.sync += self.stage.update_buffer()\e[m
245 \e[m
246 \e[31m- #with m.If(self.i_p_rst): # reset\e[m
247 \e[31m- # m.d.sync += self.o_n_stb.eq(0)\e[m
248 \e[31m- # m.d.sync += self.o_p_busy.eq(0)\e[m
249 \e[31m- with m.If(i_n_busyn): # next stage is not busy\e[m
250 \e[31m- with m.If(o_p_busyn): # not stalled\e[m
251 \e[32m+\e[m\e[32m #with m.If(self.i.p_rst): # reset\e[m
252 \e[32m+\e[m\e[32m # m.d.sync += self.o.n_valid.eq(0)\e[m
253 \e[32m+\e[m\e[32m # m.d.sync += self.o.p_ready.eq(0)\e[m
254 \e[32m+\e[m\e[32m with m.If(self.i.n_ready): # next stage is ready\e[m
255 \e[32m+\e[m\e[32m with m.If(self.o.p_ready): # not stalled\e[m
256 # nothing in buffer: send (processed) input direct to output\e[m
257 \e[31m- m.d.sync += [self.o_n_stb.eq(self.i_p_stb),\e[m
258 \e[32m+\e[m\e[32m m.d.sync += [self.o.n_valid.eq(self.i.p_valid),\e[m
259 self.stage.update_output(),\e[m
260 ]\e[m
261 \e[31m- with m.Else(): # o_p_busy is true, and something is in our buffer.\e[m
262 \e[32m+\e[m\e[32m with m.Else(): # o.p_ready is false, and something is in buffer.\e[m
263 # Flush the [already processed] buffer to the output port.\e[m
264 \e[31m- m.d.sync += [self.o_n_stb.eq(1),\e[m
265 \e[32m+\e[m\e[32m m.d.sync += [self.o.n_valid.eq(1),\e[m
266 self.stage.flush_buffer(),\e[m
267 # clear stall condition, declare register empty.\e[m
268 \e[31m- self.o_p_busy.eq(0),\e[m
269 \e[32m+\e[m\e[32m self.o.p_ready.eq(1),\e[m
270 ]\e[m
271 \e[31m- # ignore input, since o_p_busy is also true.\e[m
272 \e[32m+\e[m\e[32m # ignore input, since o.p_ready is also false.\e[m
273 \e[m
274 \e[31m- # (i_n_busy) is true here: next stage is busy\e[m
275 \e[31m- with m.Elif(o_n_stbn): # next stage being told "not busy"\e[m
276 \e[31m- m.d.sync += [self.o_n_stb.eq(self.i_p_stb),\e[m
277 \e[31m- self.o_p_busy.eq(0), # Keep the buffer empty\e[m
278 \e[32m+\e[m\e[32m # (i.n_ready) is false here: next stage is ready\e[m
279 \e[32m+\e[m\e[32m with m.Elif(o_n_validn): # next stage being told "ready"\e[m
280 \e[32m+\e[m\e[32m m.d.sync += [self.o.n_valid.eq(self.i.p_valid),\e[m
281 \e[32m+\e[m\e[32m self.o.p_ready.eq(1), # Keep the buffer empty\e[m
282 # set the output data (from comb result)\e[m
283 self.stage.update_output(),\e[m
284 ]\e[m
285 \e[31m- # (i_n_busy) and (o_n_stb) both true:\e[m
286 \e[31m- with m.Elif(i_p_stb_o_p_busyn):\e[m
287 \e[31m- # If next stage *is* busy, and not stalled yet, accept input\e[m
288 \e[31m- m.d.sync += self.o_p_busy.eq(self.i_p_stb & self.o_n_stb)\e[m
289 \e[32m+\e[m\e[32m # (i.n_ready) false and (o.n_valid) true:\e[m
290 \e[32m+\e[m\e[32m with m.Elif(i_p_valid_o_p_ready):\e[m
291 \e[32m+\e[m\e[32m # If next stage *is* ready, and not stalled yet, accept input\e[m
292 \e[32m+\e[m\e[32m m.d.sync += self.o.p_ready.eq(~(self.i.p_valid & self.o.n_valid))\e[m
293 \e[m
294 return m\e[m
295 \e[m
296 def ports(self):\e[m
297 \e[31m- return [self.i_p_stb, self.i_n_busy,\e[m
298 \e[31m- self.o_n_stb, self.o_p_busy,\e[m
299 \e[32m+\e[m\e[32m return [self.i.p_valid, self.i.n_ready,\e[m
300 \e[32m+\e[m\e[32m self.o.n_valid, self.o.p_ready,\e[m
301 ]\e[m
302 \e[m
303 \e[m
304 \e[31m-class BufPipe(BufferedPipeline):\e[m
305 \e[32m+\e[m\e[32mclass ExampleBufPipe(BufferedPipeline):\e[m
306 \e[m
307 def __init__(self):\e[m
308 BufferedPipeline.__init__(self)\e[m
309 \e[1mdiff --git a/src/add/fmul.py b/src/add/fmul.py\e[m
310 \e[1mindex 130d49e..5b6da94 100644\e[m
311 \e[1m--- a/src/add/fmul.py\e[m
312 \e[1m+++ b/src/add/fmul.py\e[m
313 \e[36m@@ -2,7 +2,8 @@\e[m \e[mfrom nmigen import Module, Signal, Cat, Mux, Array, Const\e[m
314 from nmigen.cli import main, verilog\e[m
315 \e[m
316 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase\e[m
317 \e[31m-from nmigen_add_experiment import FPState\e[m
318 \e[32m+\e[m\e[32m+from nmigen_add_experiment import FPState, FPGetOp\e[m
319 \e[32m+\e[m
320 \e[m
321 class FPMUL(FPBase):\e[m
322 \e[m
323 \e[1mdiff --git a/src/add/nmigen_div_experiment.py b/src/add/nmigen_div_experiment.py\e[m
324 \e[1mindex ff4c966..e074c5c 100644\e[m
325 \e[1m--- a/src/add/nmigen_div_experiment.py\e[m
326 \e[1m+++ b/src/add/nmigen_div_experiment.py\e[m
327 \e[36m@@ -6,6 +6,7 @@\e[m \e[mfrom nmigen import Module, Signal, Const, Cat\e[m
328 from nmigen.cli import main, verilog\e[m
329 \e[m
330 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase\e[m
331 \e[32m+\e[m\e[32mfrom nmigen_add_experiment import FPState, FPGetOp\e[m
332 \e[m
333 class Div:\e[m
334 def __init__(self, width):\e[m
335 \e[36m@@ -36,6 +37,12 @@\e[m \e[mclass FPDIV(FPBase):\e[m
336 self.in_b = FPOp(width)\e[m
337 self.out_z = FPOp(width)\e[m
338 \e[m
339 \e[32m+\e[m\e[32m self.states = []\e[m
340 \e[32m+\e[m
341 \e[32m+\e[m\e[32m def add_state(self, state):\e[m
342 \e[32m+\e[m\e[32m self.states.append(state)\e[m
343 \e[32m+\e[m\e[32m return state\e[m
344 \e[32m+\e[m
345 def get_fragment(self, platform=None):\e[m
346 """ creates the HDL code-fragment for FPDiv\e[m
347 """\e[m
348 \e[36m@@ -59,14 +66,26 @@\e[m \e[mclass FPDIV(FPBase):\e[m
349 # ******\e[m
350 # gets operand a\e[m
351 \e[m
352 \e[32m+\e[m\e[32m geta = FPGetOp("get_a", "get_b", self.in_a, self.width)\e[m
353 \e[32m+\e[m\e[32m geta.setup(m, self.in_a)\e[m
354 \e[32m+\e[m
355 with m.State("get_a"):\e[m
356 \e[31m- self.get_op(m, self.in_a, a, "get_b")\e[m
357 \e[32m+\e[m\e[32m geta.action(m)\e[m
358 \e[32m+\e[m\e[32m with m.If(geta.out_decode):\e[m
359 \e[32m+\e[m\e[32m m.d.sync += a.decode(self.in_a.v)\e[m
360 \e[32m+\e[m\e[32m #self.get_op(m, self.in_a, a, "get_b")\e[m
361 \e[m
362 # ******\e[m
363 # gets operand b\e[m
364 \e[m
365 \e[32m+\e[m\e[32m getb = FPGetOp("get_b", "special_cases", self.in_b, self.width)\e[m
366 \e[32m+\e[m\e[32m getb.setup(m, self.in_b)\e[m
367 \e[32m+\e[m
368 with m.State("get_b"):\e[m
369 \e[31m- self.get_op(m, self.in_b, b, "special_cases")\e[m
370 \e[32m+\e[m\e[32m getb.action(m)\e[m
371 \e[32m+\e[m\e[32m with m.If(getb.out_decode):\e[m
372 \e[32m+\e[m\e[32m m.d.sync += b.decode(self.in_b.v)\e[m
373 \e[32m+\e[m\e[32m #self.get_op(m, self.in_b, b, "special_cases")\e[m
374 \e[m
375 # ******\e[m
376 # special cases: NaNs, infs, zeros, denormalised\e[m
377 \e[1mdiff --git a/src/add/test_buf_pipe.py b/src/add/test_buf_pipe.py\e[m
378 \e[1mindex 8590cca..fa23eac 100644\e[m
379 \e[1m--- a/src/add/test_buf_pipe.py\e[m
380 \e[1m+++ b/src/add/test_buf_pipe.py\e[m
381 \e[36m@@ -1,86 +1,90 @@\e[m
382 from nmigen import Module, Signal\e[m
383 from nmigen.compat.sim import run_simulation\e[m
384 \e[31m-from example_buf_pipe import BufPipe\e[m
385 \e[32m+\e[m\e[32mfrom example_buf_pipe import ExampleBufPipe\e[m
386 from random import randint\e[m
387 \e[m
388 \e[m
389 \e[31m-def check_o_n_stb(dut, val):\e[m
390 \e[31m- o_n_stb = yield dut.o_n_stb\e[m
391 \e[31m- assert o_n_stb == val\e[m
392 \e[32m+\e[m\e[32mdef check_o_n_valid(dut, val):\e[m
393 \e[32m+\e[m\e[32m o_n_valid = yield dut.o.n_valid\e[m
394 \e[32m+\e[m\e[32m assert o_n_valid == val\e[m
395 \e[32m+\e[m
396 \e[32m+\e[m\e[32mdef check_o_n_valid2(dut, val):\e[m
397 \e[32m+\e[m\e[32m o_n_valid = yield dut.o_n_valid\e[m
398 \e[32m+\e[m\e[32m assert o_n_valid == val\e[m
399 \e[m
400 \e[m
401 def testbench(dut):\e[m
402 #yield dut.i_p_rst.eq(1)\e[m
403 \e[31m- yield dut.i_n_busy.eq(1)\e[m
404 \e[31m- yield dut.o_p_busy.eq(1)\e[m
405 \e[32m+\e[m\e[32m yield dut.i.n_ready.eq(0)\e[m
406 \e[32m+\e[m\e[32m yield dut.o.p_ready.eq(0)\e[m
407 yield\e[m
408 yield\e[m
409 #yield dut.i_p_rst.eq(0)\e[m
410 \e[31m- yield dut.i_n_busy.eq(0)\e[m
411 \e[32m+\e[m\e[32m yield dut.i.n_ready.eq(1)\e[m
412 yield dut.stage.i_data.eq(5)\e[m
413 \e[31m- yield dut.i_p_stb.eq(1)\e[m
414 \e[32m+\e[m\e[32m yield dut.i.p_valid.eq(1)\e[m
415 yield\e[m
416 \e[m
417 yield dut.stage.i_data.eq(7)\e[m
418 \e[31m- yield from check_o_n_stb(dut, 0) # effects of i_p_stb delayed\e[m
419 \e[32m+\e[m\e[32m yield from check_o_n_valid(dut, 0) # effects of i_p_valid delayed\e[m
420 yield\e[m
421 \e[31m- yield from check_o_n_stb(dut, 1) # ok *now* i_p_stb effect is felt\e[m
422 \e[32m+\e[m\e[32m yield from check_o_n_valid(dut, 1) # ok *now* i_p_valid effect is felt\e[m
423 \e[m
424 yield dut.stage.i_data.eq(2)\e[m
425 yield\e[m
426 \e[31m- yield dut.i_n_busy.eq(1) # begin going into "stall" (next stage says busy)\e[m
427 \e[32m+\e[m\e[32m yield dut.i.n_ready.eq(0) # begin going into "stall" (next stage says ready)\e[m
428 yield dut.stage.i_data.eq(9)\e[m
429 yield\e[m
430 \e[31m- yield dut.i_p_stb.eq(0)\e[m
431 \e[32m+\e[m\e[32m yield dut.i.p_valid.eq(0)\e[m
432 yield dut.stage.i_data.eq(12)\e[m
433 yield\e[m
434 yield dut.stage.i_data.eq(32)\e[m
435 \e[31m- yield dut.i_n_busy.eq(0)\e[m
436 \e[32m+\e[m\e[32m yield dut.i.n_ready.eq(1)\e[m
437 yield\e[m
438 \e[31m- yield from check_o_n_stb(dut, 1) # buffer still needs to output\e[m
439 \e[32m+\e[m\e[32m yield from check_o_n_valid(dut, 1) # buffer still needs to output\e[m
440 yield\e[m
441 \e[31m- yield from check_o_n_stb(dut, 1) # buffer still needs to output\e[m
442 \e[32m+\e[m\e[32m yield from check_o_n_valid(dut, 1) # buffer still needs to output\e[m
443 yield\e[m
444 \e[31m- yield from check_o_n_stb(dut, 0) # buffer outputted, *now* we're done.\e[m
445 \e[32m+\e[m\e[32m yield from check_o_n_valid(dut, 0) # buffer outputted, *now* we're done.\e[m
446 yield\e[m
447 \e[m
448 \e[m
449 def testbench2(dut):\e[m
450 \e[31m- #yield dut.i_p_rst.eq(1)\e[m
451 \e[31m- yield dut.i_n_busy.eq(1)\e[m
452 \e[31m- #yield dut.o_p_busy.eq(1)\e[m
453 \e[32m+\e[m\e[32m #yield dut.i.p_rst.eq(1)\e[m
454 \e[32m+\e[m\e[32m yield dut.i_n_ready.eq(0)\e[m
455 \e[32m+\e[m\e[32m #yield dut.o.p_ready.eq(0)\e[m
456 yield\e[m
457 yield\e[m
458 \e[31m- #yield dut.i_p_rst.eq(0)\e[m
459 \e[31m- yield dut.i_n_busy.eq(0)\e[m
460 \e[32m+\e[m\e[32m #yield dut.i.p_rst.eq(0)\e[m
461 \e[32m+\e[m\e[32m yield dut.i_n_ready.eq(1)\e[m
462 yield dut.i_data.eq(5)\e[m
463 \e[31m- yield dut.i_p_stb.eq(1)\e[m
464 \e[32m+\e[m\e[32m yield dut.i_p_valid.eq(1)\e[m
465 yield\e[m
466 \e[m
467 yield dut.i_data.eq(7)\e[m
468 \e[31m- yield from check_o_n_stb(dut, 0) # effects of i_p_stb delayed 2 clocks\e[m
469 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 0) # effects of i_p_valid delayed 2 clocks\e[m
470 yield\e[m
471 \e[31m- yield from check_o_n_stb(dut, 0) # effects of i_p_stb delayed 2 clocks\e[m
472 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 0) # effects of i_p_valid delayed 2 clocks\e[m
473 \e[m
474 yield dut.i_data.eq(2)\e[m
475 yield\e[m
476 \e[31m- yield from check_o_n_stb(dut, 1) # ok *now* i_p_stb effect is felt\e[m
477 \e[31m- yield dut.i_n_busy.eq(1) # begin going into "stall" (next stage says busy)\e[m
478 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 1) # ok *now* i_p_valid effect is felt\e[m
479 \e[32m+\e[m\e[32m yield dut.i_n_ready.eq(0) # begin going into "stall" (next stage says ready)\e[m
480 yield dut.i_data.eq(9)\e[m
481 yield\e[m
482 \e[31m- yield dut.i_p_stb.eq(0)\e[m
483 \e[32m+\e[m\e[32m yield dut.i_p_valid.eq(0)\e[m
484 yield dut.i_data.eq(12)\e[m
485 yield\e[m
486 yield dut.i_data.eq(32)\e[m
487 \e[31m- yield dut.i_n_busy.eq(0)\e[m
488 \e[32m+\e[m\e[32m yield dut.i_n_ready.eq(1)\e[m
489 yield\e[m
490 \e[31m- yield from check_o_n_stb(dut, 1) # buffer still needs to output\e[m
491 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 1) # buffer still needs to output\e[m
492 yield\e[m
493 \e[31m- yield from check_o_n_stb(dut, 1) # buffer still needs to output\e[m
494 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 1) # buffer still needs to output\e[m
495 yield\e[m
496 \e[31m- yield from check_o_n_stb(dut, 1) # buffer still needs to output\e[m
497 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 1) # buffer still needs to output\e[m
498 yield\e[m
499 \e[31m- yield from check_o_n_stb(dut, 0) # buffer outputted, *now* we're done.\e[m
500 \e[32m+\e[m\e[32m yield from check_o_n_valid2(dut, 0) # buffer outputted, *now* we're done.\e[m
501 yield\e[m
502 yield\e[m
503 yield\e[m
504 \e[36m@@ -104,28 +108,28 @@\e[m \e[mclass Test3:\e[m
505 send = True\e[m
506 else:\e[m
507 send = randint(0, send_range) != 0\e[m
508 \e[31m- o_p_busy = yield self.dut.o_p_busy\e[m
509 \e[31m- if o_p_busy:\e[m
510 \e[32m+\e[m\e[32m o_p_ready = yield self.dut.o.p_ready\e[m
511 \e[32m+\e[m\e[32m if not o_p_ready:\e[m
512 yield\e[m
513 continue\e[m
514 if send and self.i != len(self.data):\e[m
515 \e[31m- yield self.dut.i_p_stb.eq(1)\e[m
516 \e[32m+\e[m\e[32m yield self.dut.i.p_valid.eq(1)\e[m
517 yield self.dut.stage.i_data.eq(self.data[self.i])\e[m
518 self.i += 1\e[m
519 else:\e[m
520 \e[31m- yield self.dut.i_p_stb.eq(0)\e[m
521 \e[32m+\e[m\e[32m yield self.dut.i.p_valid.eq(0)\e[m
522 yield\e[m
523 \e[m
524 def rcv(self):\e[m
525 while self.o != len(self.data):\e[m
526 stall_range = randint(0, 3)\e[m
527 for j in range(randint(1,10)):\e[m
528 \e[31m- stall = randint(0, stall_range) == 0\e[m
529 \e[31m- yield self.dut.i_n_busy.eq(stall)\e[m
530 \e[32m+\e[m\e[32m stall = randint(0, stall_range) != 0\e[m
531 \e[32m+\e[m\e[32m yield self.dut.i.n_ready.eq(stall)\e[m
532 yield\e[m
533 \e[31m- o_n_stb = yield self.dut.o_n_stb\e[m
534 \e[31m- i_n_busy = yield self.dut.i_n_busy\e[m
535 \e[31m- if not o_n_stb or i_n_busy:\e[m
536 \e[32m+\e[m\e[32m o_n_valid = yield self.dut.o.n_valid\e[m
537 \e[32m+\e[m\e[32m i_n_ready = yield self.dut.i.n_ready\e[m
538 \e[32m+\e[m\e[32m if not o_n_valid or not i_n_ready:\e[m
539 continue\e[m
540 o_data = yield self.dut.stage.o_data\e[m
541 assert o_data == self.data[self.o] + 1, \\e[m
542 \e[36m@@ -144,21 +148,21 @@\e[m \e[mdef testbench4(dut):\e[m
543 i = 0\e[m
544 o = 0\e[m
545 while True:\e[m
546 \e[31m- stall = randint(0, 3) == 0\e[m
547 \e[32m+\e[m\e[32m stall = randint(0, 3) != 0\e[m
548 send = randint(0, 5) != 0\e[m
549 \e[31m- yield dut.i_n_busy.eq(stall)\e[m
550 \e[31m- o_p_busy = yield dut.o_p_busy\e[m
551 \e[31m- if not o_p_busy:\e[m
552 \e[32m+\e[m\e[32m yield dut.i_n_ready.eq(stall)\e[m
553 \e[32m+\e[m\e[32m o_p_ready = yield dut.o_p_ready\e[m
554 \e[32m+\e[m\e[32m if o_p_ready:\e[m
555 if send and i != len(data):\e[m
556 \e[31m- yield dut.i_p_stb.eq(1)\e[m
557 \e[32m+\e[m\e[32m yield dut.i_p_valid.eq(1)\e[m
558 yield dut.i_data.eq(data[i])\e[m
559 i += 1\e[m
560 else:\e[m
561 \e[31m- yield dut.i_p_stb.eq(0)\e[m
562 \e[32m+\e[m\e[32m yield dut.i_p_valid.eq(0)\e[m
563 yield\e[m
564 \e[31m- o_n_stb = yield dut.o_n_stb\e[m
565 \e[31m- i_n_busy = yield dut.i_n_busy\e[m
566 \e[31m- if o_n_stb and not i_n_busy:\e[m
567 \e[32m+\e[m\e[32m o_n_valid = yield dut.o_n_valid\e[m
568 \e[32m+\e[m\e[32m i_n_ready = yield dut.i_n_ready\e[m
569 \e[32m+\e[m\e[32m if o_n_valid and i_n_ready:\e[m
570 o_data = yield dut.o_data\e[m
571 assert o_data == data[o] + 2, "%d-%d data %x not match %x\n" \\e[m
572 % (i, o, o_data, data[o])\e[m
573 \e[36m@@ -167,26 +171,26 @@\e[m \e[mdef testbench4(dut):\e[m
574 break\e[m
575 \e[m
576 \e[m
577 \e[31m-class BufPipe2:\e[m
578 \e[32m+\e[m\e[32mclass ExampleBufPipe2:\e[m
579 """\e[m
580 connect these: ------|---------------|\e[m
581 v v\e[m
582 \e[31m- i_p_stb >>in pipe1 o_n_stb out>> i_p_stb >>in pipe2\e[m
583 \e[31m- o_p_busy <<out pipe1 i_n_busy <<in o_p_busy <<out pipe2\e[m
584 \e[32m+\e[m\e[32m i_p_valid >>in pipe1 o_n_valid out>> i_p_valid >>in pipe2\e[m
585 \e[32m+\e[m\e[32m o_p_ready <<out pipe1 i_n_ready <<in o_p_ready <<out pipe2\e[m
586 stage.i_data >>in pipe1 o_data out>> stage.i_data >>in pipe2\e[m
587 """\e[m
588 def __init__(self):\e[m
589 \e[31m- self.pipe1 = BufPipe()\e[m
590 \e[31m- self.pipe2 = BufPipe()\e[m
591 \e[32m+\e[m\e[32m self.pipe1 = ExampleBufPipe()\e[m
592 \e[32m+\e[m\e[32m self.pipe2 = ExampleBufPipe()\e[m
593 \e[m
594 # input\e[m
595 \e[31m- self.i_p_stb = Signal() # >>in - comes in from PREVIOUS stage\e[m
596 \e[31m- self.i_n_busy = Signal() # in<< - comes in from the NEXT stage\e[m
597 \e[32m+\e[m\e[32m self.i_p_valid = Signal() # >>in - comes in from PREVIOUS stage\e[m
598 \e[32m+\e[m\e[32m self.i_n_ready = Signal() # in<< - comes in from the NEXT stage\e[m
599 self.i_data = Signal(32) # >>in - comes in from the PREVIOUS stage\e[m
600 \e[m
601 # output\e[m
602 \e[31m- self.o_n_stb = Signal() # out>> - goes out to the NEXT stage\e[m
603 \e[31m- self.o_p_busy = Signal() # <<out - goes out to the PREVIOUS stage\e[m
604 \e[32m+\e[m\e[32m self.o_n_valid = Signal() # out>> - goes out to the NEXT stage\e[m
605 \e[32m+\e[m\e[32m self.o_p_ready = Signal() # <<out - goes out to the PREVIOUS stage\e[m
606 self.o_data = Signal(32) # out>> - goes out to the NEXT stage\e[m
607 \e[m
608 def elaborate(self, platform):\e[m
609 \e[36m@@ -194,37 +198,37 @@\e[m \e[mclass BufPipe2:\e[m
610 m.submodules.pipe1 = self.pipe1\e[m
611 m.submodules.pipe2 = self.pipe2\e[m
612 \e[m
613 \e[31m- # connect inter-pipe input/output stb/busy/data\e[m
614 \e[31m- m.d.comb += self.pipe2.i_p_stb.eq(self.pipe1.o_n_stb)\e[m
615 \e[31m- m.d.comb += self.pipe1.i_n_busy.eq(self.pipe2.o_p_busy)\e[m
616 \e[32m+\e[m\e[32m # connect inter-pipe input/output valid/ready/data\e[m
617 \e[32m+\e[m\e[32m m.d.comb += self.pipe2.i.p_valid.eq(self.pipe1.o.n_valid)\e[m
618 \e[32m+\e[m\e[32m m.d.comb += self.pipe1.i.n_ready.eq(self.pipe2.o.p_ready)\e[m
619 m.d.comb += self.pipe2.stage.i_data.eq(self.pipe1.stage.o_data)\e[m
620 \e[m
621 # inputs/outputs to the module: pipe1 connections here (LHS)\e[m
622 \e[31m- m.d.comb += self.pipe1.i_p_stb.eq(self.i_p_stb)\e[m
623 \e[31m- m.d.comb += self.o_p_busy.eq(self.pipe1.o_p_busy)\e[m
624 \e[32m+\e[m\e[32m m.d.comb += self.pipe1.i.p_valid.eq(self.i_p_valid)\e[m
625 \e[32m+\e[m\e[32m m.d.comb += self.o_p_ready.eq(self.pipe1.o.p_ready)\e[m
626 m.d.comb += self.pipe1.stage.i_data.eq(self.i_data)\e[m
627 \e[m
628 # now pipe2 connections (RHS)\e[m
629 \e[31m- m.d.comb += self.o_n_stb.eq(self.pipe2.o_n_stb)\e[m
630 \e[31m- m.d.comb += self.pipe2.i_n_busy.eq(self.i_n_busy)\e[m
631 \e[32m+\e[m\e[32m m.d.comb += self.o_n_valid.eq(self.pipe2.o.n_valid)\e[m
632 \e[32m+\e[m\e[32m m.d.comb += self.pipe2.i.n_ready.eq(self.i_n_ready)\e[m
633 m.d.comb += self.o_data.eq(self.pipe2.stage.o_data)\e[m
634 \e[m
635 return m\e[m
636 \e[m
637 if __name__ == '__main__':\e[m
638 print ("test 1")\e[m
639 \e[31m- dut = BufPipe()\e[m
640 \e[32m+\e[m\e[32m dut = ExampleBufPipe()\e[m
641 run_simulation(dut, testbench(dut), vcd_name="test_bufpipe.vcd")\e[m
642 \e[m
643 print ("test 2")\e[m
644 \e[31m- dut = BufPipe2()\e[m
645 \e[32m+\e[m\e[32m dut = ExampleBufPipe2()\e[m
646 run_simulation(dut, testbench2(dut), vcd_name="test_bufpipe2.vcd")\e[m
647 \e[m
648 print ("test 3")\e[m
649 \e[31m- dut = BufPipe()\e[m
650 \e[32m+\e[m\e[32m dut = ExampleBufPipe()\e[m
651 test = Test3(dut)\e[m
652 run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe3.vcd")\e[m
653 \e[m
654 print ("test 4")\e[m
655 \e[31m- dut = BufPipe2()\e[m
656 \e[32m+\e[m\e[32m dut = ExampleBufPipe2()\e[m
657 run_simulation(dut, testbench4(dut), vcd_name="test_bufpipe4.vcd")\e[m
658 \e[1mdiff --git a/src/add/test_inputgroup.py b/src/add/test_inputgroup.py\e[m
659 \e[1mindex ca8523d..bb68861 100644\e[m
660 \e[1m--- a/src/add/test_inputgroup.py\e[m
661 \e[1m+++ b/src/add/test_inputgroup.py\e[m
662 \e[36m@@ -99,9 +99,81 @@\e[m \e[mdef testbench(dut):\e[m
663 assert out_mid == 3, "out mid %d" % out_mid\e[m
664 \e[m
665 \e[m
666 \e[32m+\e[m\e[32mclass InputTest:\e[m
667 \e[32m+\e[m\e[32m def __init__(self, dut):\e[m
668 \e[32m+\e[m\e[32m self.dut = dut\e[m
669 \e[32m+\e[m\e[32m self.di = {}\e[m
670 \e[32m+\e[m\e[32m self.do = {}\e[m
671 \e[32m+\e[m\e[32m self.tlen = 10\e[m
672 \e[32m+\e[m\e[32m for mid in range(dut.num_rows):\e[m
673 \e[32m+\e[m\e[32m self.di[mid] = {}\e[m
674 \e[32m+\e[m\e[32m self.do[mid] = {}\e[m
675 \e[32m+\e[m\e[32m for i in range(self.tlen):\e[m
676 \e[32m+\e[m\e[32m self.di[mid][i] = randint(0, 100)\e[m
677 \e[32m+\e[m\e[32m self.do[mid][i] = self.di[mid][i]\e[m
678 \e[32m+\e[m
679 \e[32m+\e[m\e[32m def send(self, mid):\e[m
680 \e[32m+\e[m\e[32m for i in range(self.tlen):\e[m
681 \e[32m+\e[m\e[32m op2 = self.di[mid][i]\e[m
682 \e[32m+\e[m\e[32m rs = dut.rs[mid]\e[m
683 \e[32m+\e[m\e[32m ack = yield rs.ack\e[m
684 \e[32m+\e[m\e[32m while not ack:\e[m
685 \e[32m+\e[m\e[32m yield\e[m
686 \e[32m+\e[m\e[32m ack = yield rs.ack\e[m
687 \e[32m+\e[m\e[32m yield rs.in_op[0].eq(i)\e[m
688 \e[32m+\e[m\e[32m yield rs.in_op[1].eq(op2)\e[m
689 \e[32m+\e[m\e[32m yield rs.stb.eq(0b11) # strobe indicate 1st op ready\e[m
690 \e[32m+\e[m\e[32m ack = yield rs.ack\e[m
691 \e[32m+\e[m\e[32m while ack:\e[m
692 \e[32m+\e[m\e[32m yield\e[m
693 \e[32m+\e[m\e[32m ack = yield rs.ack\e[m
694 \e[32m+\e[m\e[32m yield rs.stb.eq(0)\e[m
695 \e[32m+\e[m
696 \e[32m+\e[m\e[32m # wait random period of time before queueing another value\e[m
697 \e[32m+\e[m\e[32m for i in range(randint(0, 12)):\e[m
698 \e[32m+\e[m\e[32m yield\e[m
699 \e[32m+\e[m
700 \e[32m+\e[m\e[32m def recv(self):\e[m
701 \e[32m+\e[m\e[32m while True:\e[m
702 \e[32m+\e[m\e[32m stb = yield dut.out_op.stb\e[m
703 \e[32m+\e[m\e[32m yield dut.out_op.ack.eq(0)\e[m
704 \e[32m+\e[m\e[32m while not stb:\e[m
705 \e[32m+\e[m\e[32m yield\e[m
706 \e[32m+\e[m\e[32m stb = yield dut.out_op.stb\e[m
707 \e[32m+\e[m
708 \e[32m+\e[m\e[32m yield dut.out_op.ack.eq(1)\e[m
709 \e[32m+\e[m\e[32m stb = yield dut.out_op.stb\e[m
710 \e[32m+\e[m\e[32m while stb:\e[m
711 \e[32m+\e[m\e[32m yield\e[m
712 \e[32m+\e[m\e[32m stb = yield dut.out_op.stb\e[m
713 \e[32m+\e[m\e[32m mid = yield dut.mid\e[m
714 \e[32m+\e[m\e[32m out_i = yield dut.out_op.v[0]\e[m
715 \e[32m+\e[m\e[32m out_v = yield dut.out_op.v[1]\e[m
716 \e[32m+\e[m
717 \e[32m+\e[m\e[32m # see if this output has occurred already, delete it if it has\e[m
718 \e[32m+\e[m\e[32m assert out_i in self.do[mid]\e[m
719 \e[32m+\e[m\e[32m assert self.do[mid][out_i] == out_v\e[m
720 \e[32m+\e[m\e[32m del self.do[mid][out_i]\e[m
721 \e[32m+\e[m
722 \e[32m+\e[m\e[32m # check if there's any more outputs\e[m
723 \e[32m+\e[m\e[32m zerolen = True\e[m
724 \e[32m+\e[m\e[32m for (k, v) in self.do.items():\e[m
725 \e[32m+\e[m\e[32m if v:\e[m
726 \e[32m+\e[m\e[32m zerolen = False\e[m
727 \e[32m+\e[m\e[32m if zerolen:\e[m
728 \e[32m+\e[m\e[32m break\e[m
729 \e[32m+\e[m
730 if __name__ == '__main__':\e[m
731 dut = InputGroup(width=32)\e[m
732 vl = rtlil.convert(dut, ports=dut.ports())\e[m
733 with open("test_inputgroup.il", "w") as f:\e[m
734 f.write(vl)\e[m
735 run_simulation(dut, testbench(dut), vcd_name="test_inputgroup.vcd")\e[m
736 \e[32m+\e[m
737 \e[32m+\e[m\e[32m dut = InputGroup(width=16)\e[m
738 \e[32m+\e[m\e[32m test = InputTest(dut)\e[m
739 \e[32m+\e[m\e[32m run_simulation(dut, [test.send(3), test.send(2),\e[m
740 \e[32m+\e[m\e[32m test.send(1), test.send(0),\e[m
741 \e[32m+\e[m\e[32m test.recv()],\e[m
742 \e[32m+\e[m\e[32m vcd_name="test_inputgroup_parallel.vcd")\e[m
743 \e[41m+\e[m