from nmigen import Module, Signal, Mux
+from nmigen.hdl.rec import Record
from nmigen.compat.sim import run_simulation
from nmigen.cli import verilog, rtlil
from example_buf_pipe import ExampleBufPipe, ExampleBufPipeAdd
-from example_buf_pipe import ExampleCombPipe, CombPipe
-from example_buf_pipe import PrevControl, NextControl
+from example_buf_pipe import ExampleCombPipe, CombPipe, ExampleStageCls
+from example_buf_pipe import PrevControl, NextControl, BufferedPipeline
+from example_buf_pipe import StageChain
+
from random import randint
"%d-%d data %x not match %x\n" \
% (i, o, o_data, expected)
+def data_dict():
+ data = []
+ for i in range(num_tests):
+ data.append({'src1': randint(0, 1<<16-1),
+ 'src2': randint(0, 1<<16-1)})
+ return data
+
+
class Test5:
- def __init__(self, dut, resultfn):
+ def __init__(self, dut, resultfn, data=None):
self.dut = dut
self.resultfn = resultfn
- self.data = []
- for i in range(num_tests):
- self.data.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
+ if data:
+ self.data = data
+ else:
+ self.data = []
+ for i in range(num_tests):
+ self.data.append((randint(0, 1<<16-1), randint(0, 1<<16-1)))
self.i = 0
self.o = 0
i_n_ready = yield self.dut.n.i_ready
if not o_n_valid or not i_n_ready:
continue
- o_data = yield self.dut.n.o_data
+ if isinstance(self.dut.n.o_data, Record):
+ o_data = {}
+ dod = self.dut.n.o_data
+ for k, v in dod.fields.items():
+ o_data[k] = yield v
+ else:
+ o_data = yield self.dut.n.o_data
self.resultfn(o_data, self.data[self.o], self.i, self.o)
self.o += 1
if self.o == len(self.data):
return m
+
+class ExampleBufPipeChain2(BufferedPipeline):
+ """ connects two stages together as a *single* combinatorial stage.
+ """
+ def __init__(self):
+ stage1 = ExampleStageCls()
+ stage2 = ExampleStageCls()
+ combined = StageChain([stage1, stage2])
+ BufferedPipeline.__init__(self, combined)
+
+
+def data_chain2():
+ data = []
+ for i in range(num_tests):
+ data.append(randint(0, 1<<16-2))
+ return data
+
+
+def test9_resultfn(o_data, expected, i, o):
+ res = expected + 2
+ assert o_data == res, \
+ "%d-%d data %x not match %s\n" \
+ % (i, o, o_data, repr(expected))
+
+
class SetLessThan:
def __init__(self, width, signed):
self.src1 = Signal((width, signed))
% (i, o, o_data, repr(expected))
-num_tests = 1000
+class ExampleAddRecordStage:
+ """ example use of a Record
+ """
+
+ record_spec = [('src1', 16), ('src2', 16)]
+ def ispec(self):
+ """ returns a tuple of input signals which will be the incoming data
+ """
+ return Record(self.record_spec)
+
+ def ospec(self):
+ return Record(self.record_spec)
+
+ def process(self, i):
+ """ process the input data (sums the values in the tuple) and returns it
+ """
+ return {'src1': i.src1 + 1,
+ 'src2': i.src2 + 1}
+
+
+class ExampleAddRecordPipe(CombPipe):
+ """ an example of how to use the combinatorial pipeline.
+ """
+
+ def __init__(self):
+ stage = ExampleAddRecordStage()
+ CombPipe.__init__(self, stage)
+
+
+def test7_resultfn(o_data, expected, i, o):
+ res = (expected['src1'] + 1, expected['src2'] + 1)
+ assert o_data['src1'] == res[0] and o_data['src2'] == res[1], \
+ "%d-%d data %s not match %s\n" \
+ % (i, o, repr(o_data), repr(expected))
+
+
+class Example2OpClass:
+ """ an example of a class used to store 2 operands.
+ requires an eq function, to conform with the pipeline stage API
+ """
+
+ def __init__(self):
+ self.op1 = Signal(16)
+ self.op2 = Signal(16)
+
+ def eq(self, i):
+ return [self.op1.eq(i.op1), self.op2.eq(i.op2)]
+
+
+class ExampleAddClassStage:
+ """ an example of how to use the buffered pipeline, as a class instance
+ """
+
+ def ispec(self):
+ """ returns an instance of an Example2OpClass.
+ """
+ return Example2OpClass()
+
+ def ospec(self):
+ """ returns an output signal which will happen to contain the sum
+ of the two inputs
+ """
+ return Signal(16)
+
+ def process(self, i):
+ """ process the input data (sums the values in the tuple) and returns it
+ """
+ return i.op1 + i.op2
+
+
+class ExampleBufPipeAddClass(BufferedPipeline):
+ """ an example of how to use the buffered pipeline, using a class instance
+ """
+
+ def __init__(self):
+ addstage = ExampleAddClassStage()
+ BufferedPipeline.__init__(self, addstage)
+
+
+class TestInputAdd:
+ """ the eq function, called by set_input, needs an incoming object
+ that conforms to the Example2OpClass.eq function requirements
+ easiest way to do that is to create a class that has the exact
+ same member layout (self.op1, self.op2) as Example2OpClass
+ """
+ def __init__(self, op1, op2):
+ self.op1 = op1
+ self.op2 = op2
+
+
+def test8_resultfn(o_data, expected, i, o):
+ res = expected.op1 + expected.op2 # these are a TestInputAdd instance
+ assert o_data == res, \
+ "%d-%d data %x not match %s\n" \
+ % (i, o, o_data, repr(expected))
+
+def data_2op():
+ data = []
+ for i in range(num_tests):
+ data.append(TestInputAdd(randint(0, 1<<16-1), randint(0, 1<<16-1)))
+ return data
+
+
+num_tests = 100
if __name__ == '__main__':
print ("test 1")
with open("test_ltcomb_pipe.il", "w") as f:
f.write(vl)
+ print ("test 7")
+ dut = ExampleAddRecordPipe()
+ data=data_dict()
+ test = Test5(dut, test7_resultfn, data=data)
+ run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
+
+ ports = [dut.p.i_valid, dut.n.i_ready,
+ dut.n.o_valid, dut.p.o_ready,
+ dut.p.i_data.src1, dut.p.i_data.src2,
+ dut.n.o_data.src1, dut.n.o_data.src2]
+ vl = rtlil.convert(dut, ports=ports)
+ with open("test_recordcomb_pipe.il", "w") as f:
+ f.write(vl)
+
+ print ("test 8")
+ dut = ExampleBufPipeAddClass()
+ data=data_2op()
+ test = Test5(dut, test8_resultfn, data=data)
+ run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe8.vcd")
+
+ print ("test 9")
+ dut = ExampleBufPipeChain2()
+ ports = [dut.p.i_valid, dut.n.i_ready,
+ dut.n.o_valid, dut.p.o_ready] + \
+ [dut.p.i_data] + [dut.n.o_data]
+ vl = rtlil.convert(dut, ports=ports)
+ with open("test_bufpipechain2.il", "w") as f:
+ f.write(vl)
+
+ data = data_chain2()
+ test = Test5(dut, test9_resultfn, data=data)
+ run_simulation(dut, [test.send, test.rcv],
+ vcd_name="test_bufpipechain2.vcd")
+