Example #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"))
Example #2
0
    def __init__(self, spi=None, bits=32):
        self.jtag = mg.Record([
            ("sel", 1),
            ("shift", 1),
            ("capture", 1),
            ("tck", 1),
            ("tdi", 1),
            ("tdo", 1),
        ])
        self.cs_n = mg.TSTriple()
        self.clk = mg.TSTriple()
        self.mosi = mg.TSTriple()
        self.miso = mg.TSTriple()

        # # #

        self.cs_n.o.reset = mg.Constant(1)
        self.submodules.fsm = fsm = mg.FSM("IDLE")
        en = mg.Signal()
        bits = mg.Signal(bits, reset_less=True)
        head = mg.Signal(max=len(bits), reset=len(bits) - 1)
        self.clock_domains.cd_sys = mg.ClockDomain()
        self.clock_domains.cd_rise = mg.ClockDomain(reset_less=True)
        if spi is not None:
            self.specials += [
                self.cs_n.get_tristate(spi.cs_n),
                self.mosi.get_tristate(spi.mosi),
                self.miso.get_tristate(spi.miso),
            ]
            if hasattr(spi, "clk"):  # 7 Series drive it fixed
                self.specials += self.clk.get_tristate(spi.clk)
        self.comb += [
            en.eq(self.jtag.sel & self.jtag.shift),
            self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture),
            self.cd_sys.clk.eq(~self.jtag.tck),
            self.cd_rise.clk.eq(self.jtag.tck),
            self.cs_n.oe.eq(en),
            self.clk.oe.eq(en),
            self.mosi.oe.eq(en),
            self.miso.oe.eq(0),
            self.clk.o.eq(self.jtag.tck & ~self.cs_n.o),
            self.mosi.o.eq(self.jtag.tdi),
        ]
        # Some (Xilinx) bscan cells register TDO (from the fabric) on falling
        # TCK and output it (externally).
        # SPI requires sampling on rising CLK. This leads to one cycle of
        # latency.
        self.sync.rise += self.jtag.tdo.eq(self.miso.i)
        fsm.act("IDLE", mg.If(self.jtag.tdi, mg.NextState("HEAD")))
        fsm.act("HEAD", mg.If(head == 0, mg.NextState("XFER")))
        fsm.act(
            "XFER",
            mg.If(bits == 0, mg.NextState("IDLE")),
            self.cs_n.o.eq(0),
        )
        self.sync += [
            mg.If(fsm.ongoing("HEAD"), bits.eq(mg.Cat(self.jtag.tdi, bits)),
                  head.eq(head - 1)),
            mg.If(fsm.ongoing("XFER"), bits.eq(bits - 1))
        ]
Example #3
0
    def __init__(self, buf_width=8, buf_depth=16, buf_afull=5):

        # write port
        self.wr_valid_in = migen.Signal(1)
        self.wr_data_in = migen.Signal(buf_width)
        self.wr_ready_out = migen.Signal(1)

        # read port
        self.rd_data_out = migen.Signal(buf_width)
        self.rd_valid_out = migen.Signal(1)
        self.rd_ready_in = migen.Signal(1)

        self.num_fifo_elements = migen.Signal(
            math.ceil(math.log2(buf_depth)) + 1)

        # Create port map
        wr_itf = {
            self.wr_valid_in, self.wr_data_in, self.wr_ready_out,
            self.num_fifo_elements
        }
        rd_iff = {self.rd_data_out, self.rd_valid_out, self.rd_ready_in}
        self.ios = set(wr_itf) | set(rd_iff)

        # internals
        self.cnt = migen.Signal(math.ceil(math.log2(buf_depth)) + 1)
        self.almost_full = migen.Signal(1)

        ####

        # fifo submodule
        self.submodules.fifo = fifo = SyncFIFO(buf_width, buf_depth)

        self.comb += [
            migen.If(  # write logic
                fifo.writable & self.wr_valid_in & ~self.almost_full,
                fifo.we.eq(1), fifo.din.eq(self.wr_data_in)),
            migen.If(  # read logic
                fifo.readable & self.rd_ready_in, fifo.re.eq(1),
                self.rd_data_out.eq(fifo.dout)),
            migen.If(  # assert rd valid if fifo is not empty
                fifo.readable, self.rd_valid_out.eq(1))
        ]

        # element counter
        self.sync += [
            migen.If(fifo.we & (~fifo.re), self.cnt.eq(self.cnt + 1)).Elif(
                fifo.re & (~fifo.we),
                self.cnt.eq(self.cnt - 1)).Else(self.cnt.eq(self.cnt))
        ]

        # almost full
        self.comb += [
            migen.If((self.cnt >= buf_depth - buf_afull),
                     self.almost_full.eq(1)).Else(self.almost_full.eq(0)),
            self.wr_ready_out.eq(~self.almost_full),  # back-pressure
            self.num_fifo_elements.eq(self.cnt)  # usedw
        ]
Example #4
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)
            )
        )
Example #5
0
 def exec_stmts(stmts):
     results = []
     for stmt in stmts:
         # now execute the statements
         if stmt[0] == "comb" or stmt[0] == "sync":
             # we need to evalue x.eq(y)
             # so do x and y first
             makeload(stmt[1])  # after a little hack
             x, y = ast_eval(stmt[1]), ast_eval(stmt[2])
             # now execute x.eq(y) and save the result
             if fsm is None or stmt[0] == "comb":
                 results.append((stmt[0], x.eq(y)))
             else:
                 # sync with FSM requires a special object
                 results.append((stmt[0], migen.genlib.fsm.NextValue(x, y)))
         elif stmt[0] == "if":
             # execute the predicate
             pred = ast_eval(stmt[2])
             # get results of substatements
             if_true = tuple(r[1] for r in exec_stmts(stmt[3]))
             if_false = tuple(r[1] for r in exec_stmts(stmt[4]))
             the_if = migen.If(pred, *if_true)
             if len(if_false) > 0:
                 the_if = the_if.Else(*if_false)
             results.append((stmt[1], the_if))
         elif stmt[0] == "next_state":
             # the result is just a next state marker
             results.append(
                 (None, migen.genlib.fsm.NextState(ast_eval(stmt[1]))))
     return results
Example #6
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)
            )
        )
Example #7
0
    def migen_body(self, template):
        # inputs and 1 output
        in1 = template.add_pa_in_port('in1', DOptional(int))
        out1 = template.add_pa_out_port('out1', DOptional(int))

        # Counter
        self.incremented = migen.Signal(10)

        # for instance, at this clock the node is ready to input
        self.comb += in1.ready.eq(1)

        self.sync += migen.If(
            out1.ready == 1,
            migen.If(in1.valid,
                     out1.data.eq(self.incremented),
                     out1.valid.eq(0x1),
                     self.incremented.eq(in1.data+1)
                     ).Else(out1.valid.eq(0))
        )
Example #8
0
 def patch_csrs(self):
     for csr in self.dut.get_csrs():
         if isinstance(csr, CSRStorage) and hasattr(csr, "dat_w"):
             self.dut.sync += [
                 migen.If(csr.we,
                     csr.storage.eq(csr.dat_w),
                     csr.re.eq(1),
                 ).Else(
                     csr.re.eq(0),
                 )
             ]
Example #9
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))
Example #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)
            )
        )
    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))
    def __init__(self, spi=None, bits=32):
        self.jtag = mg.Record([
            ("sel", 1),
            ("shift", 1),
            ("capture", 1),
            ("tck", 1),
            ("tdi", 1),
            ("tdo", 1),
        ])
        self.cs_n = mg.TSTriple()
        self.clk = mg.TSTriple()
        self.mosi = mg.TSTriple()
        self.miso = mg.TSTriple()

        # # #

        self.cs_n.o.reset = mg.Constant(1)
        self.mosi.o.reset_less = True
        bits = mg.Signal(bits, reset_less=True)
        head = mg.Signal(max=len(bits), reset=len(bits) - 1)
        self.clock_domains.cd_sys = mg.ClockDomain()
        self.submodules.fsm = mg.FSM("IDLE")
        if spi is not None:
            self.specials += [
                self.cs_n.get_tristate(spi.cs_n),
                self.mosi.get_tristate(spi.mosi),
                self.miso.get_tristate(spi.miso),
            ]
            if hasattr(spi, "clk"):  # 7 Series drive it fixed
                self.specials += self.clk.get_tristate(spi.clk)
                # self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o)
        self.comb += [
            self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture),
            self.cd_sys.clk.eq(self.jtag.tck),
            self.cs_n.oe.eq(self.jtag.sel),
            self.clk.oe.eq(self.jtag.sel),
            self.mosi.oe.eq(self.jtag.sel),
            self.miso.oe.eq(0),
            # Do not suppress CLK toggles outside CS_N asserted.
            # Xilinx USRCCLK0 requires three dummy cycles to do anything
            # https://www.xilinx.com/support/answers/52626.html
            # This is fine since CS_N changes only on falling CLK.
            self.clk.o.eq(~self.jtag.tck),
            self.jtag.tdo.eq(self.miso.i),
        ]
        # Latency calculation (in half cycles):
        # 0 (falling TCK, rising CLK):
        #   JTAG adapter: set TDI
        # 1 (rising TCK, falling CLK):
        #   JTAG2SPI: sample TDI -> set MOSI
        #   SPI: set MISO
        # 2 (falling TCK, rising CLK):
        #   SPI: sample MOSI
        #   JTAG2SPI (BSCAN primitive): sample MISO -> set TDO
        # 3 (rising TCK, falling CLK):
        #   JTAG adapter: sample TDO
        self.fsm.act(
            "IDLE",
            mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift,
                  mg.NextState("HEAD")))
        self.fsm.act("HEAD", mg.If(head == 0, mg.NextState("XFER")))
        self.fsm.act(
            "XFER",
            mg.If(bits == 0, mg.NextState("IDLE")),
        )
        self.sync += [
            self.mosi.o.eq(self.jtag.tdi),
            self.cs_n.o.eq(~self.fsm.ongoing("XFER")),
            mg.If(self.fsm.ongoing("HEAD"),
                  bits.eq(mg.Cat(self.jtag.tdi, bits)), head.eq(head - 1)),
            mg.If(self.fsm.ongoing("XFER"), bits.eq(bits - 1))
        ]