Skip to content
Snippets Groups Projects
signal_flow_graph.py 8.87 KiB
Newer Older
  • Learn to ignore specific revisions
  • Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    from typing import Optional
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    from b_asic import (
        SFG,
        AbstractOperation,
        Addition,
        Butterfly,
        Constant,
        ConstantMultiplication,
        Delay,
        Input,
        Name,
        Output,
    
    Frans Skarman's avatar
    Frans Skarman committed
        Signal,
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        SignalSourceProvider,
        TypeName,
    )
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and two outputs.
    
             .               .
        in1-------+  +--------->out1
             .    |  |       .
             .    v  |       .
             .   add1+--+    .
             .    ^     |    .
             .    |     v    .
        in2+------+    add2---->out2
           | .          ^    .
           | .          |    .
           +------------+    .
             .               .
        out1 = in1 + in2
        out2 = in1 + 2 * in2
        """
        in1 = Input("IN1")
        in2 = Input("IN2")
        add1 = Addition(in1, in2, "ADD1")
        add2 = Addition(add1, in2, "ADD2")
        out1 = Output(add1, "OUT1")
        out2 = Output(add2, "OUT2")
        return SFG(inputs=[in1, in2], outputs=[out1, out2])
    
    
    @pytest.fixture
    def sfg_two_inputs_two_outputs_independent():
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and two outputs, where the first output only depends
    
        on the first input and the second output only depends on the second input.
             .               .
        in1-------------------->out1
             .               .
             .               .
             .      c1--+    .
             .          |    .
             .          v    .
        in2------+     add1---->out2
             .   |      ^    .
             .   |      |    .
             .   +------+    .
             .               .
        out1 = in1
        out2 = in2 + 3
        """
        in1 = Input("IN1")
        in2 = Input("IN2")
        c1 = Constant(3, "C1")
        add1 = Addition(in2, c1, "ADD1")
        out1 = Output(in1, "OUT1")
        out2 = Output(add1, "OUT2")
        return SFG(inputs=[in1, in2], outputs=[out1, out2])
    
    
    @pytest.fixture
    def sfg_two_inputs_two_outputs_independent_with_cmul():
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and two outputs, where the first output only depends
    
        on the first input and the second output only depends on the second input.
            .                 .
        in1--->cmul1--->cmul2--->out1
            .                 .
            .                 .
            .  c1             .
            .   |             .
            .   v             .
        in2--->add1---->cmul3--->out2
            .                 .
        """
        in1 = Input("IN1")
        in2 = Input("IN2")
        c1 = Constant(3, "C1")
    
        add1 = Addition(in2, c1, "ADD1", 7, execution_time=2)
        cmul3 = ConstantMultiplication(2, add1, "CMUL3", 3, execution_time=1)
        cmul1 = ConstantMultiplication(5, in1, "CMUL1", 5, execution_time=3)
        cmul2 = ConstantMultiplication(4, cmul1, "CMUL2", 4, execution_time=1)
    
        out1 = Output(cmul2, "OUT1")
        out2 = Output(cmul3, "OUT2")
        return SFG(inputs=[in1, in2], outputs=[out1, out2])
    
    
    @pytest.fixture
    def sfg_nested():
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and one output.
    
        out1 = in1 + (in1 + in1 * in2) * (in1 + in2 * (in1 + in1 * in2))
        """
        mac_in1 = Input()
        mac_in2 = Input()
        mac_in3 = Input()
        mac_out1 = Output(mac_in1 + mac_in2 * mac_in3)
        MAC = SFG(inputs=[mac_in1, mac_in2, mac_in3], outputs=[mac_out1])
    
        in1 = Input()
        in2 = Input()
        mac1 = MAC(in1, in1, in2)
        mac2 = MAC(in1, in2, mac1)
        mac3 = MAC(in1, mac1, mac2)
        out1 = Output(mac3)
        return SFG(inputs=[in1, in2], outputs=[out1])
    
    
    @pytest.fixture
    def sfg_delay():
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with one input and one output.
    
        out1 = in1'
        """
        in1 = Input()
        t1 = Delay(in1)
        out1 = Output(t1)
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        return SFG(inputs=[in1], outputs=[out1])
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and one output.
    
        data_out = (data_in' + data_in) * (1 - reset)
        """
        data_in = Input()
        reset = Input()
        t = Delay()
        t << (t + data_in) * (1 - reset)
        data_out = Output(t)
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        return SFG(inputs=[data_in, reset], outputs=[data_out])
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        Valid SFG with two inputs and one output.
    
             .                .
        in1----->add1-----+----->out1
             .    ^       |   .
             .    |       |   .
             .    +--t1<--+   .
             .                .
        """
        in1 = Input()
        t1 = Delay()
        add1 = in1 + t1
        t1 << add1
        out1 = Output(add1)
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        return SFG(inputs=[in1], outputs=[out1])
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        A valid SFG that is used as a filter in the first lab for TSTE87.
    
             .                 .
             .   +--cmul1<--+  .
             .   |          |  .
             .   v          |  .
        in1---->add1----->t1+---->out1
             .                 .
        """
        in1 = Input("IN1")
        cmul1 = ConstantMultiplication(0.5, name="CMUL1")
        add1 = Addition(in1, cmul1, "ADD1")
        add1.input(1).signals[0].name = "S2"
        t1 = Delay(add1, name="T1")
        cmul1.input(0).connect(t1, "S1")
        out1 = Output(t1, "OUT1")
        return SFG(inputs=[in1], outputs=[out1], name="simple_filter")
    
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    
    
    @pytest.fixture
    def sfg_custom_operation():
        """A valid SFG containing a custom operation."""
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    
    
        class CustomOperation(AbstractOperation):
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            def __init__(
                self, src0: Optional[SignalSourceProvider] = None, name: Name = ""
            ):
                super().__init__(
                    input_count=1, output_count=2, name=name, input_sources=[src0]
                )
    
            @classmethod
            def type_name(self) -> TypeName:
                return "custom"
    
            def evaluate(self, a):
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
                return a * 2, 2**a
    
    
        in1 = Input()
        custom1 = CustomOperation(in1)
        out1 = Output(custom1.output(0))
        out2 = Output(custom1.output(1))
        return SFG(inputs=[in1], outputs=[out1, out2])
    
    
    @pytest.fixture
    def precedence_sfg_delays():
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
        """
        A sfg with delays and interesting layout for precedence list generation.
    
             .                                          .
        IN1>--->C0>--->ADD1>--->Q1>---+--->A0>--->ADD4>--->OUT1
             .           ^            |            ^    .
             .           |            T1           |    .
             .           |            |            |    .
             .         ADD2<---<B1<---+--->A1>--->ADD3  .
             .           ^            |            ^    .
             .           |            T2           |    .
             .           |            |            |    .
             .           +-----<B2<---+--->A2>-----+    .
        """
        in1 = Input("IN1")
        c0 = ConstantMultiplication(5, in1, "C0")
        add1 = Addition(c0, None, "ADD1")
        # Not sure what operation "Q" is supposed to be in the example
        Q1 = ConstantMultiplication(1, add1, "Q1")
        T1 = Delay(Q1, 0, "T1")
        T2 = Delay(T1, 0, "T2")
        b2 = ConstantMultiplication(2, T2, "B2")
        b1 = ConstantMultiplication(3, T1, "B1")
        add2 = Addition(b1, b2, "ADD2")
        add1.input(1).connect(add2)
        a1 = ConstantMultiplication(4, T1, "A1")
        a2 = ConstantMultiplication(6, T2, "A2")
        add3 = Addition(a1, a2, "ADD3")
        a0 = ConstantMultiplication(7, Q1, "A0")
        add4 = Addition(a0, add3, "ADD4")
        out1 = Output(add4, "OUT1")
    
        return SFG(inputs=[in1], outputs=[out1], name="SFG")
    
    
    @pytest.fixture
    def precedence_sfg_delays_and_constants():
        in1 = Input("IN1")
        c0 = ConstantMultiplication(5, in1, "C0")
        add1 = Addition(c0, None, "ADD1")
        # Not sure what operation "Q" is supposed to be in the example
        Q1 = ConstantMultiplication(1, add1, "Q1")
        T1 = Delay(Q1, 0, "T1")
        const1 = Constant(10, "CONST1")  # Replace T2 delay with a constant
        b2 = ConstantMultiplication(2, const1, "B2")
        b1 = ConstantMultiplication(3, T1, "B1")
        add2 = Addition(b1, b2, "ADD2")
        add1.input(1).connect(add2)
        a1 = ConstantMultiplication(4, T1, "A1")
        a2 = ConstantMultiplication(10, const1, "A2")
        add3 = Addition(a1, a2, "ADD3")
        a0 = ConstantMultiplication(7, Q1, "A0")
        # Replace ADD4 with a butterfly to test multiple output ports
        bfly1 = Butterfly(a0, add3, "BFLY1")
        out1 = Output(bfly1.output(0), "OUT1")
        Output(bfly1.output(1), "OUT2")
    
        return SFG(inputs=[in1], outputs=[out1], name="SFG")
    
    Frans Skarman's avatar
    Frans Skarman committed
    
    
    @pytest.fixture
    def sfg_two_tap_fir():
        # Inputs:
        in1 = Input(name="in1")
    
        # Outputs:
        out1 = Output(name="out1")
    
        # Operations:
        t1 = Delay(initial_value=0, name="t1")
        cmul1 = ConstantMultiplication(
            value=0.5, name="cmul1", latency_offsets={'in0': None, 'out0': None}
        )
        add1 = Addition(
            name="add1", latency_offsets={'in0': None, 'in1': None, 'out0': None}
        )
        cmul2 = ConstantMultiplication(
            value=0.5, name="cmul2", latency_offsets={'in0': None, 'out0': None}
        )
    
        # Signals:
    
        Signal(source=t1.output(0), destination=cmul1.input(0))
        Signal(source=in1.output(0), destination=t1.input(0))
        Signal(source=in1.output(0), destination=cmul2.input(0))
        Signal(source=cmul1.output(0), destination=add1.input(0))
        Signal(source=add1.output(0), destination=out1.input(0))
        Signal(source=cmul2.output(0), destination=add1.input(1))
        return SFG(inputs=[in1], outputs=[out1], name='twotapfir')