+def test_alu_parallel():
+ # Compare with the sequential test implementation, above.
+ m = Module()
+ m.submodules.alu = dut = ALU(width=16)
+ write_alu_gtkw("test_alu_parallel.gtkw", sub_module='alu',
+ pysim=is_engine_pysim())
+
+ sim = Simulator(m)
+ sim.add_clock(1e-6)
+
+ def send(a, b, op, inv_a=0):
+ # present input data and assert valid_i
+ yield dut.a.eq(a)
+ yield dut.b.eq(b)
+ yield dut.op.insn_type.eq(op)
+ yield dut.op.invert_in.eq(inv_a)
+ yield dut.p.valid_i.eq(1)
+ yield
+ # wait for ready_o to be asserted
+ while not (yield dut.p.ready_o):
+ yield
+ # clear input data and negate valid_i
+ # if send is called again immediately afterwards, there will be no
+ # visible transition (they will not be negated, after all)
+ yield dut.p.valid_i.eq(0)
+ yield dut.a.eq(0)
+ yield dut.b.eq(0)
+ yield dut.op.insn_type.eq(0)
+ yield dut.op.invert_in.eq(0)
+
+ def receive():
+ # signal readiness to receive data
+ yield dut.n.ready_i.eq(1)
+ yield
+ # wait for valid_o to be asserted
+ while not (yield dut.n.valid_o):
+ yield
+ # read result
+ result = yield dut.o
+ # negate ready_i
+ # if receive is called again immediately afterwards, there will be no
+ # visible transition (it will not be negated, after all)
+ yield dut.n.ready_i.eq(0)
+ return result
+
+ def producer():
+ # send a few test cases, interspersed with wait states
+ # note that, for this test, we do not wait for the result to be ready,
+ # before presenting the next input
+ # 5 + 3
+ yield from send(5, 3, MicrOp.OP_ADD)
+ yield
+ yield
+ # 2 * 3
+ yield from send(2, 3, MicrOp.OP_MUL_L64)
+ # (-5) + 3
+ yield from send(5, 3, MicrOp.OP_ADD, inv_a=1)
+ yield
+ # 5 - 3
+ # note that this is a zero-delay operation
+ yield from send(5, 3, MicrOp.OP_NOP)
+ yield
+ yield
+ # 13 >> 2
+ yield from send(13, 2, MicrOp.OP_SHR)
+
+ def consumer():
+ # receive and check results, interspersed with wait states
+ # the consumer is not in step with the producer, but the
+ # order of the results are preserved
+ yield
+ # 5 + 3 = 8
+ result = yield from receive()
+ assert (result == 8)
+ # 2 * 3 = 6
+ result = yield from receive()
+ assert (result == 6)
+ yield
+ yield
+ # (-5) + 3 = -2
+ result = yield from receive()
+ assert (result == 65533) # unsigned equivalent to -2
+ # 5 - 3 = 2
+ # note that this is a zero-delay operation
+ # this, and the previous result, will be received back-to-back
+ # (check the output waveform to see this)
+ result = yield from receive()
+ assert (result == 2)
+ yield
+ yield
+ # 13 >> 2 = 3
+ result = yield from receive()
+ assert (result == 3)
+
+ sim.add_sync_process(producer)
+ sim.add_sync_process(consumer)
+ sim_writer = sim.write_vcd("test_alu_parallel.vcd")
+ with sim_writer:
+ sim.run()
+
+
+def write_alu_gtkw(gtkw_name, clk_period=1e-6, sub_module=None,
+ pysim=True):
+ """Common function to write the GTKWave documents for this module"""
+ gtkwave_desc = [
+ 'clk',
+ 'i1[15:0]',
+ 'i2[15:0]',
+ 'op__insn_type' if pysim else 'op__insn_type[6:0]',
+ 'op__invert_in',
+ 'valid_i',
+ 'ready_o',
+ 'valid_o',
+ 'ready_i',
+ 'alu_o[15:0]',
+ ]
+ # determine the module name of the DUT
+ module = 'top'
+ if sub_module is not None:
+ module = nmigen_sim_top_module + sub_module
+ vcd_name = gtkw_name.replace('.gtkw', '.vcd')
+ write_gtkw(gtkw_name, vcd_name, gtkwave_desc, module=module,
+ loc=__file__, clk_period=clk_period, base='signed')
+
+