|
3 | 3 | import os |
4 | 4 | import sys |
5 | 5 | import unittest |
| 6 | +from typing import Callable |
6 | 7 |
|
7 | 8 | import pyrtl |
8 | | -from pyrtl.wire import Const, Output |
9 | 9 | from pyrtl.rtllib import testingutils as utils |
10 | | - |
| 10 | +from pyrtl.wire import Const, Output |
11 | 11 | from .test_transform import NetWireNumTestCases |
12 | 12 |
|
13 | 13 |
|
@@ -733,6 +733,87 @@ def test_nested_elimination(self): |
733 | 733 | pyrtl.working_block().sanity_check() |
734 | 734 |
|
735 | 735 |
|
| 736 | +class TestSynthPasses(unittest.TestCase): |
| 737 | + in0: pyrtl.Input |
| 738 | + in1: pyrtl.Input |
| 739 | + out: pyrtl.Output |
| 740 | + |
| 741 | + def setUp(self): |
| 742 | + pyrtl.reset_working_block() |
| 743 | + self.in0 = pyrtl.Input(bitwidth=5, name='in0') |
| 744 | + self.in1 = pyrtl.Input(bitwidth=5, name='in1') |
| 745 | + self.out = pyrtl.Output(bitwidth=5, name='out') |
| 746 | + |
| 747 | + def check_synth(self, operation: Callable[[int, int], int]): |
| 748 | + """ |
| 749 | + Simulates the current circuit with some test input pairs (in0, in1) and checks the outputs |
| 750 | + against the provided operation. Any synthesis/passes should be run before this gets called. |
| 751 | +
|
| 752 | + :param operation: The operation to test against. This should be a lambda taking an input |
| 753 | + pair (in0, in1) and returning the expected output from this circuit. |
| 754 | + """ |
| 755 | + sim_trace = pyrtl.SimulationTrace() |
| 756 | + sim = pyrtl.Simulation(tracer=sim_trace) |
| 757 | + |
| 758 | + values = [(1, 2), (4, 5), (7, 11)] |
| 759 | + """A list of input pairs (in0, in1) to test on.""" |
| 760 | + |
| 761 | + for in0, in1 in values: |
| 762 | + expected_output = operation(in0, in1) |
| 763 | + sim.step({'in0': in0, 'in1': in1}) |
| 764 | + # compare simulation output to expected output |
| 765 | + self.assertEqual(sim.inspect('out'), expected_output, |
| 766 | + msg=f"Failed on inputs {in0} and {in1}") |
| 767 | + |
| 768 | + def test_nand_synth_and(self): |
| 769 | + self.out <<= self.in0 & self.in1 |
| 770 | + pyrtl.synthesize() |
| 771 | + pyrtl.nand_synth() |
| 772 | + self.check_synth(lambda a, b: a & b) |
| 773 | + |
| 774 | + def test_nand_synth_or(self): |
| 775 | + self.out <<= self.in0 | self.in1 |
| 776 | + pyrtl.synthesize() |
| 777 | + pyrtl.nand_synth() |
| 778 | + self.check_synth(lambda a, b: a | b) |
| 779 | + |
| 780 | + def test_nand_synth_xor(self): |
| 781 | + self.out <<= self.in0 ^ self.in1 |
| 782 | + pyrtl.synthesize() |
| 783 | + pyrtl.nand_synth() |
| 784 | + self.check_synth(lambda a, b: a ^ b) |
| 785 | + |
| 786 | + def test_nand_synth_adder(self): |
| 787 | + self.out <<= self.in0 + self.in1 |
| 788 | + pyrtl.synthesize() |
| 789 | + pyrtl.nand_synth() |
| 790 | + self.check_synth(lambda a, b: a + b) |
| 791 | + |
| 792 | + def test_and_inverter_synth_and(self): |
| 793 | + self.out <<= self.in0 & self.in1 |
| 794 | + pyrtl.synthesize() |
| 795 | + pyrtl.and_inverter_synth() |
| 796 | + self.check_synth(lambda a, b: a & b) |
| 797 | + |
| 798 | + def test_and_inverter_synth_or(self): |
| 799 | + self.out <<= self.in0 | self.in1 |
| 800 | + pyrtl.synthesize() |
| 801 | + pyrtl.and_inverter_synth() |
| 802 | + self.check_synth(lambda a, b: a | b) |
| 803 | + |
| 804 | + def test_and_inverter_synth_xor(self): |
| 805 | + self.out <<= self.in0 ^ self.in1 |
| 806 | + pyrtl.synthesize() |
| 807 | + pyrtl.and_inverter_synth() |
| 808 | + self.check_synth(lambda a, b: a ^ b) |
| 809 | + |
| 810 | + def test_and_inverter_synth_adder(self): |
| 811 | + self.out <<= self.in0 + self.in1 |
| 812 | + pyrtl.synthesize() |
| 813 | + pyrtl.and_inverter_synth() |
| 814 | + self.check_synth(lambda a, b: a + b) |
| 815 | + |
| 816 | + |
736 | 817 | class TestSynthOptTiming(NetWireNumTestCases): |
737 | 818 | def setUp(self): |
738 | 819 | pyrtl.reset_working_block() |
|
0 commit comments