コード例 #1
0
    def migen_body(self, template):

        inp = template.add_pa_in_port('inp', dl.Optional(int))
        trigger = template.add_pa_in_port('trigger', dl.Optional(int))
        out = template.add_pa_out_port('out', int)

        # Declare input and output ports always happy to receive/transmit data
        self.comb += (
            inp.ready.eq(1),
            trigger.ready.eq(1),
            out.ready.eq(1),
        )

        commander_fsm = migen.FSM(reset_state="IDLE")
        self.submodules.commander_fsm = commander_fsm

        commander_fsm.act("IDLE",
                          migen.If(inp.valid == 1, migen.NextState("LOADING")))

        commander_fsm.act(
            "LOADING",
            migen.If(trigger.valid & trigger.data == 1,
                     migen.NextState("RETURN")).Else(
                         migen.NextValue(out.data, out.data + inp.data), ))

        commander_fsm.act("RETURN", migen.NextValue(out.valid, 1),
                          migen.NextState("IDLE"))
コード例 #2
0
    def migen_body(self, template):
        # Input/Outputs start here:

        # 2 inputs and 2 outputs.
        #
        # This block group ports which will be accessed by migen, using
        # the protocol adapters.
        # in_ports and out_ports implement a similar logic based on 3
        # signals, ready, valid and data.
        # An input can be received when the ready signal is = '1'.
        # data contains the value of the message that we are receiving
        # and can considered sensible only when valid = '1', i.e. when
        # a new data has been received on the pa_input_port.
        # The opposite logic holds true for the outputs.
        in1 = template.add_pa_in_port('in1', dl.Optional(int))
        in2 = template.add_pa_in_port('in2', dl.Optional(int))
        out1 = template.add_pa_out_port('out1', int)
        out2 = template.add_pa_out_port('out2', int)

        # The main migen logic starts here:

        # Everything below is just an example that show different routines.

        # Add a 32-bit counter (0-2**32-1) which will increment at each clock
        # cycle.
        self.counter = migen.Signal(32)
        self.sync += self.counter.eq(self.counter + 1)

        # Add a condition when in_ports are ready.
        self.comb += migen.If(
            self.counter >= 3,
            in1.ready.eq(1),
            in2.ready.eq(1)
        )

        # Pretend that we do a useful calculations.
        # Here we first check that the outputs are ready.
        # Then wait for the counter to reach 100.
        # And write outputs.
        # Note that the output should be marked as valid.
        self.comb += migen.If(
            (out1.ready & out2.ready) == 1,
            migen.If(
                self.counter == 5,
                out1.data.eq(in1.data + in2.data),
                out2.data.eq(self.counter),
                out1.valid.eq(in1.valid & in2.valid),
                out2.valid.eq(in1.valid & in2.valid)
            ).Else(
                out1.valid.eq(0),
                out2.valid.eq(0)
            )
        )
コード例 #3
0
    def migen_body(self, template):
        """ This is the body of the migen node connecting
        the pulser and timestamper as 2 submodules.
        """

        # Node inputs
        self.reset = template.add_pa_in_port('reset', dl.Optional(int))
        self.photon = template.add_pa_in_port('photon', dl.Optional(int))

        # Node outputs
        self.time = template.add_pa_out_port('time', dl.UInt())
        self.error = template.add_pa_out_port('error', dl.Int())

        self.rf_trigger = Signal(1)
        self.pmt_trigger = Signal(1)
        self.hit_channels = Signal(2)
        self.clock = Signal(TIME_RES)

        ###

        self.comb += [
            self.hit_channels.eq(self.pmt_trigger + 2 * self.rf_trigger),
            self.photon.ready.eq(1),
        ]

        # error management ( if photon is outside valid range)
        self.sync += [
            If(
                self.photon.valid & ((self.photon.data < 1) |
                                     (self.photon.data > TIME_RES - 1)),
                self.error.data.eq(1), self.error.valid.eq(1)).Elif(
                    self.photon.valid, self.error.data.eq(0),
                    self.error.valid.eq(1)).Else(
                        self.error.data.eq(self.error.data),
                        self.error.valid.eq(0))
        ]

        self.pulser_inst = TimestamperModel.Pulser(self.reset,
                                                   self.pmt_trigger,
                                                   self.rf_trigger,
                                                   self.photon, self.clock)

        self.timestamper_inst = TimestamperModel.Timestamper(
            self.hit_channels, self.time, self.reset, self.clock)

        self.submodules += [self.timestamper_inst, self.pulser_inst]
コード例 #4
0
    def multi_count_print_exit(self,
                               x: dl.Optional(int),
                               y: dl.Optional(int),
                               z: dl.Optional(bool)):
        """Count and store messages until we receive self.max_count many, then 
        print all stores and exit.
        """
        if x is not None:
            self.x_store.append(x)
            self.curr_count += 1

        if y is not None:
            self.y_store.append(y)
            self.curr_count += 1

        if z is not None:
            self.z_store.append(z)
            self.curr_count += 1

        if self.curr_count >= self.max_count:
            print(self.x_store)
            print(self.y_store)
            print(self.z_store)
            raise DeltaRuntimeExit
コード例 #5
0
    def migen_body(self, template):
        start = template.add_pa_in_port('start', dl.Optional(int))
        out_a = template.add_pa_out_port('out_a', int)
        out_b = template.add_pa_out_port('out_b', int)
        # This will need to be converted to boolean when migen nodes support
        # boolean
        self.cnt = migen.Signal(10)

        self.comb += (out_a.ready.eq(1), out_b.ready.eq(1), start.ready.eq(1))
        self.sync += migen.If(self.cnt & 0x1, out_a.valid.eq(start.data),
                              out_b.valid.eq(0)).Else(
                                  out_a.valid.eq(0),
                                  out_b.valid.eq(start.data))
        self.sync += (self.cnt.eq(self.cnt + 1), out_a.data.eq(self.cnt),
                      out_b.data.eq(self.cnt))
コード例 #6
0
    def migen_body(self, template):
        # We are using a Optional here because the code should run
        # no matter the input. If you were to use an int (so a
        # not-optional input) we would stall the migen simulation until
        # an input is received. In this example, we have a cyclical graph
        # in which the hardware node (migenNode) must produce an output
        # (a reset signal) no matter the input.
        pulse_in = template.add_pa_in_port('pulse_in', dl.Optional(int))
        reset_out = template.add_pa_out_port('reset_out', int)

        # Constants
        self.NUM_CLOCKS = 5
        # We set the lowest NUM_CLOCKS bits of INIT_VAL to be '1's
        self.INIT_VAL = 2**self.NUM_CLOCKS-1

        # Signal that generates a pulse of length NUM_CLOCKS
        self.shaper = migen.Signal(self.NUM_CLOCKS+1)

        # When I receive a reset signal -> initialise the shaper to contain
        # N '1's.
        # If I haven't received one just shift the value to the left
        # 01111 -> 00111. I will use the lowest bit for the reset_out signal
        # This equates to seconding N times a '1' after receiving a pulse_in
        # followed by '0'. Note: the sync construct instructs migen that the
        # logic contained within the block is sequential - i.e. it can only
        # change on a clock transaction (from low to high).
        self.sync += (
            migen.If(
                (pulse_in.valid == 1) & (pulse_in.data == 1),
                self.shaper.eq(self.INIT_VAL)
            ).Else(
                self.shaper.eq(self.shaper >> 1)
            )
        )

        # Always generating an output
        self.sync += (reset_out.data.eq(self.shaper[0]))

        # Always ready to receive a reset, always generating an output.
        # Note: comb (combinatorial logic) is executed instantaneously
        # when inputs change. In this example, inputs for the
        # reset_out.valid is a constant 1 so it is always = 1.
        # If it was a signal the value of reset_out.valid would change
        # together with the input signal.
        self.comb += (reset_out.valid.eq(1),
                      pulse_in.ready.eq(1),
                      reset_out.ready.eq(1))
コード例 #7
0
    def test_interactive_node_with_only_optional_input(self):
        """Test that an interactive node with an only optional input and no
        outputs or outputs that can be reached only in a special case wouldn't
        block the simulation.

        This is implemented via addition of a 1 ns wait when a node attempts
        to receive an input and it's trivial.

        Note that non-interactive nodes with such behaviour won't block as
        they always call ``send``.
        """

        @dl.Interactive(inputs=[('a', dl.Optional(int))])
        def node_to_investigate(node):
            while True:
                a = node.receive('a')
                if a is not None:
                    STORE.append(a)
                    raise dl.DeltaRuntimeExit

        @dl.Interactive(outputs=[('output', int)])
        def rest_of_graph(node):
            """This node imitates the rest of the graph that does some
            computations and occasionally provides an input."""
            i = 0
            while True:
                i += 1
                a = 40
                b = 2
                a, b = b, a
                if i % 1000 == 0:
                    node.send(10)
                else:
                    node.send(None)

        with dl.DeltaGraph() as graph:
            opt_input = rest_of_graph.call()
            node_to_investigate.call(a=opt_input)

        start_time = time.time()
        dl.DeltaPySimulator(graph).run()
        total_time = time.time() - start_time

        self.assertEqual(STORE, [10])
        self.assertLessEqual(total_time, 1)
コード例 #8
0
    def migen_body(self, template):
        # I/O:
        i1 = template.add_pa_in_port("i1", dl.Optional(int))
        o1 = template.add_pa_out_port("o1", int)

        # LOGIC:
        self.counter = migen.Signal(1000)
        self.sync += self.counter.eq(self.counter + 1)

        # Two memories for testing
        self.specials.mem1 = mem1 = migen.Memory(32, 100, init=[5, 15, 32])
        read_port1 = mem1.get_port()
        self.specials.mem2 = mem2 = migen.Memory(32, 100, init=[2, 4, 6, 8])
        read_port2 = mem2.get_port()
        self.specials += read_port1
        self.specials += read_port2
        self.mem_out1 = migen.Signal(32)
        self.mem_out2 = migen.Signal(32)

        self.sync += (read_port1.adr.eq(self.counter),
                      self.mem_out1.eq(read_port1.dat_r))

        self.sync += (read_port2.adr.eq(self.counter),
                      self.mem_out2.eq(read_port2.dat_r))

        # DEBUGGING:
        # add any signal you want to see in debugging and printing format
        # (in_ports, out_ports, inputs, output are added by default):
        self.debug_signals = {'counter': (self.counter, '05b')}

        self.comb += migen.If(
            self.counter >= 5,
            i1.ready.eq(1)
        )

        self.comb += migen.If(
            o1.ready == 1,
            migen.If(
                self.counter == 10,
                o1.data.eq(self.counter+i1.data),
                o1.valid.eq(1)
            ).Else(
                o1.valid.eq(0)
            )
        )
コード例 #9
0
def interact(a: int,
             b: dl.Optional(int) = None,
             node: dl.PythonNode = None) -> int:
    """Node that will set up an interactive console.

    The user will be able to see local variables, arguments and globals.

    Through the node object, they can also send & receive messages.

    Args:
        a : int
            An argument the user can access (either 1 or 2 to distinguish
            the two nodes)
        b : int
            An argument sent from one node to the other
    """
    c = 9
    d = 10
    if b == -1:
        raise dl.DeltaRuntimeExit
    code.interact(banner=f"{a}",
                  local=dict(globals(), **locals()),
                  exitmsg=f"Exiting {a}")
コード例 #10
0
    def migen_body(self, template):
        # I/O:
        i1 = template.add_pa_in_port("i1", dl.Optional(int))
        o1 = template.add_pa_out_port("o1", int)

        self.comb += (
            i1.ready.eq(1),
        )

        started = migen.Signal(1)

        self.sync += migen.If(
            i1.valid == 1,
            o1.valid.eq(1),
            o1.data.eq(i1.data+1)
        ).Else(
            o1.data.eq(0),
            migen.If(started == 0,
                     o1.valid.eq(1),
                     started.eq(1)
                     ).Else(
                o1.valid.eq(0)
            )
        )
コード例 #11
0
        n1 = node.receive('n1')
        n2 = node.receive('n2')
        node.send(n1 + n2)


@dl.Interactive([('n1', int), ('n2', int)], [('output', int)])
def add_interactive_loop_staggerd(node):
    while True:
        n1 = node.receive('n1')
        n2 = node.receive('n2')
        n1 += node.receive('n1')
        n2 += node.receive('n2')
        node.send(n1 + n2)


@dl.Interactive([('n1', dl.Optional(int)), ('n2', int)], [('output', int)])
def add_interactive_loop_optional(node):
    while True:
        n1 = node.receive('n1')
        n2 = node.receive('n2')
        if n1:
            node.send(n1 + n2)
        else:
            node.send(n2)


# Increment: 1 input, 1 output


@dl.DeltaBlock(allow_const=True)
def increment_const(val: int) -> int:
コード例 #12
0
 def migen_body(self, template):
     template.add_pa_in_port('i', dl.Optional(dl.Int(dl.Size(8))))
コード例 #13
0
    def migen_body(self, template):

        _TIME_RES = 32
        # Node inputs
        self.time_in = template.add_pa_in_port('time_in',
                                               dl.Optional(dl.UInt()))

        # Node outputs
        self.time_out = template.add_pa_out_port('time_out', dl.UInt())
        self.counter_reset = template.add_pa_out_port('counter_reset',
                                                      dl.Int())

        # Internal signals
        self.pmt_reg = Signal(_TIME_RES)
        self.rf_reg = Signal(_TIME_RES)
        self.pmt_trig = Signal(1)
        self.rf_trig = Signal(1)

        self.submodules.fsm = FSM(reset_state="RESET_COUNTER")

        self.sync += [
            If(
                self.pmt_trig,
                self.pmt_reg.eq(self.time_in.data),
            ).Elif(self.fsm.ongoing("RESET_COUNTER"),
                   self.pmt_reg.eq(0)).Else(self.pmt_reg.eq(self.pmt_reg)),
            If(
                self.rf_trig,
                self.rf_reg.eq(self.time_in.data),
            ).Elif(self.fsm.ongoing("RESET_COUNTER"),
                   self.rf_reg.eq(0)).Else(self.rf_reg.eq(self.rf_reg))
        ]
        """FSM
        The FSM is used to control the readouts from the HPTDC chip and
        generate a time signal for the accumulator

        RESET_COUNTER
        This is the dinitial state of the FSM at the start of the experiment.
        It resets the "coarse counter" of the HPTDC chip to establish a TO
        time reference.

        WAIT_FOR_PMT
        This state holds until the PMT timestamp is available at the HPTDC
        chip readout (first data_ready sync pulse)

        WAIT_FOR_RF
        This state holds until the RMT timestamp is available at the HPTDC
        chip readout (second data_ready sync pulse)

        SEND_TIME
        In this state, the difference between t_PMT and t_RF is derived and
        sent to the accumulator.

        WAIT_ACC_LATENCY
        This state is used to wait for any delays on inter-node communication
        """

        self.fsm.act(
            "RESET_COUNTER",
            self.pmt_trig.eq(0),
            self.rf_trig.eq(0),
            self.time_in.ready.eq(1),
            self.counter_reset.data.eq(1),  # reset counters
            self.counter_reset.valid.eq(1),
            NextState("WAIT_FOR_PMT"))

        self.fsm.act(
            "WAIT_FOR_PMT", self.counter_reset.data.eq(0),
            self.time_in.ready.eq(1),
            If(self.time_in.valid, self.pmt_trig.eq(1),
               NextState("WAIT_FOR_RF")))

        self.fsm.act(
            "WAIT_FOR_RF", self.time_in.ready.eq(1),
            If(self.time_in.valid, self.rf_trig.eq(1), NextState("SEND_TIME")))

        self.fsm.act("SEND_TIME", self.time_in.ready.eq(1),
                     self.time_out.data.eq(self.rf_reg - self.pmt_reg),
                     self.time_out.valid.eq(1), NextState("WAIT_ACC_LATENCY"))

        self.fsm.act("WAIT_ACC_LATENCY",
                     If(self.time_in.valid == 0, NextState("RESET_COUNTER")))
コード例 #14
0
 def test_node(a: dl.Optional(int)) -> dl.Void:
     pass
コード例 #15
0
def add_optional(n1: dl.Optional(int), n2: int) -> int:
    if n1:
        return n1 + n2
    else:
        return n2
コード例 #16
0
 def migen_body(self, template):
     template.add_pa_in_port('a', dl.Optional(int))
     template.add_pa_out_port('x', int)
     template.add_pa_out_port('y', int)
コード例 #17
0
ファイル: comb_tree.py プロジェクト: riverlane/deltalanguage
    def migen_body(self, template):

        # generics
        N_BITS = template.generics["N_BITS"]  # 1-64
        N_INPUTS = template.generics["N_INPUTS"]
        TREE_DEPTH = int(ceil(log2(N_INPUTS)))

        # inputs
        self.d_in = template.add_pa_in_port(
            'd_in', dl.Optional(dl.Int(dl.Size(N_BITS * N_INPUTS))))
        self.cmd = template.add_pa_in_port('cmd', dl.Optional(dl.Int()))

        # outputs
        self.d_out = template.add_pa_out_port('d_out', dl.Int())
        self.err = template.add_pa_out_port('error', dl.Int())

        # input length correction [need a power of 2 sized tree]
        N_INPUTS_CORR = pow(2, TREE_DEPTH)

        # internals

        # correct the size of the input tree to be a power of 2
        # and register the inputs
        self.d_in_full_reg = Signal(N_INPUTS_CORR * N_BITS)
        self.d_in_valid_reg = Signal(1)
        self.cmd_data_reg = Signal(8)
        self.cmd_valid_reg = Signal(1)

        # register outputs
        self.d_out_data_reg = Signal(N_BITS + TREE_DEPTH)
        self.d_out_valid_reg = Signal(1)
        self.err_data_reg = Signal(1)
        self.err_valid_reg = Signal(1)

        # create the 2D array of data [INPUTS x TREE_DEPTH] to route
        # all the core units in an iterative way. The number of bits is incremented
        # at each stage to account for the carry in additions.
        self.d_pipe = Array(
            Array(Signal(N_BITS + b) for a in range(N_INPUTS_CORR))
            for b in range(TREE_DEPTH + 1))

        # create the 2D array of error signals.
        self.e_pipe = Array(
            Array(Signal(N_BITS) for a in range(N_INPUTS_CORR))
            for b in range(TREE_DEPTH))

        ###

        # correct input vector length to match a power of 2.
        # fill non-provided inputs with 0's (affects mean and minimum)
        self.sync += [
            self.d_in_full_reg.eq(self.d_in.data),
            self.d_in_valid_reg.eq(self.d_in.valid),
            self.cmd_data_reg.eq(self.cmd.data),
            self.cmd_valid_reg.eq(self.cmd.valid)
        ]

        # wiring inputs to the first stage of the tree
        for i in range(N_INPUTS_CORR):
            self.comb += [
                self.d_pipe[0][i].eq(self.d_in_full_reg[N_BITS * i:N_BITS *
                                                        (i + 1)])
            ]

        # instantiation of the core units.
        for j in range(TREE_DEPTH):
            for i in range(int(N_INPUTS_CORR / (pow(2, j + 1)))):
                self.submodules += CoreUnit(self.d_pipe[j][2 * i],
                                            self.d_pipe[j][2 * i + 1],
                                            self.d_pipe[j + 1][i],
                                            self.cmd_data_reg,
                                            self.e_pipe[j][i], N_BITS)

                # error signal propagation. If any of the single units have
                # a high error signal, the error is propagated to the node's output.
                self.comb += [
                    If(self.e_pipe[j][i] == 1, self.err_data_reg.eq(1))
                ]

        self.comb += [
            self.d_in.ready.eq(1),
            self.cmd.ready.eq(1),
            self.d_out_data_reg.eq(self.d_pipe[TREE_DEPTH][0]),
            If(self.d_in_valid_reg, self.err_valid_reg.eq(1),
               self.d_out_valid_reg.eq(1)).Else(self.err_valid_reg.eq(0))
        ]

        self.sync += [
            self.d_out.data.eq(self.d_out_data_reg),
            self.d_out.valid.eq(self.d_out_valid_reg),
            self.err.data.eq(self.err_data_reg),
            self.err.valid.eq(self.err_valid_reg)
        ]
コード例 #18
0
 def migen_body(self, template):
     template.add_pa_in_port('in1', dl.Optional(int))
コード例 #19
0
from matplotlib import ticker
from progress.bar import Bar
import time
import math
import random
import numpy as np
import logging

import deltalanguage as dl

TIME_RES = 30


@dl.Interactive(inputs=[('new_time', dl.UInt()), ('DAC_status', int),
                        ('DAC_voltage', int),
                        ('experiment_start', dl.Optional(bool))],
                outputs=[('DAC_command', int), ('DAC_param', int),
                         ('photon', int), ('reset', int)])
def accumulator(node):
    """ Accumulator Node

    This node collects times sent from the counter FPGA node and issues
    commands to the DAC controller.

    This allows the node to collect data, fit to the data and feedback to the
    experiment. The process can loop until some minimum threshold is reached,
    allowing full automation of micromotion compensation.

    Inputs:
        - new_time: Time from Counter node
        - DAC_status: DAC status from DAC node
コード例 #20
0
def mix_optional(n1: dl.Optional(int), n2: int) -> int:
    if n1:
        return n1 + n2, n1 * n2
    else:
        return n2, n2
コード例 #21
0
        sys_clk += 1

        if sys_clk == 100:
            node.send(pmt_trigger=False, rf_trigger=True)
            # The nodes are asynchronous, time is random even if fixed here
            photon = random.randrange(10, 99)
            sys_clk = 0

        elif photon == sys_clk:
            node.send(pmt_trigger=True, rf_trigger=False)

        else:
            node.send(pmt_trigger=False, rf_trigger=False)


@dl.Interactive([('pmt', dl.Optional(bool)), ('rf', dl.Optional(bool))], int)
def counter(node):
    """ counter
    The counter node receives the 2 trigger pulses from hardware and counts the
    time between the pulses. The unit of time in a real system will be clock
    ticks from the fastest clock available!
    """

    while True:
        if node.receive('pmt') is True:
            start = time.time()  # record the time when the photon arrived
            while node.receive('rf') is not True:  # Hold until RF trigger
                pass

            # Calculate time between triggers
            cnt = (time.time() - start)