Beispiel #1
0
    def __init__(self, platform, *args, **kwargs):
        BaseSoC.__init__(self, platform, *args, **kwargs)

        encoder_port = self.sdram.crossbar.get_port()
        self.submodules.encoder_reader = EncoderDMAReader(encoder_port)
        self.add_csr("encoder_reader")
        encoder_cdc = stream.AsyncFIFO([("data", 128)], 4)
        encoder_cdc = ClockDomainsRenamer({"write": "sys",
                                           "read": "encoder"})(encoder_cdc)
        encoder_buffer = ClockDomainsRenamer("encoder")(EncoderBuffer())
        encoder = Encoder(platform)
        encoder_streamer = USBStreamer(platform, platform.request("fx2"))
        self.submodules += encoder_cdc, encoder_buffer, encoder, encoder_streamer
        self.add_csr("encoder")

        self.comb += [
            self.encoder_reader.source.connect(encoder_cdc.sink),
            encoder_cdc.source.connect(encoder_buffer.sink),
            encoder_buffer.source.connect(encoder.sink),
            encoder.source.connect(encoder_streamer.sink)
        ]
        self.add_wb_slave(self.mem_map["encoder"], encoder.bus)
        self.add_memory_region("encoder",
            self.mem_map["encoder"], 0x2000, type="io")

        self.platform.add_period_constraint(encoder_streamer.cd_usb.clk, 10.0)

        encoder_streamer.cd_usb.clk.attr.add("keep")
        self.crg.cd_encoder.clk.attr.add("keep")
        self.platform.add_false_path_constraints(
            self.crg.cd_sys.clk,
            self.crg.cd_encoder.clk,
            encoder_streamer.cd_usb.clk)
Beispiel #2
0
    def __init__(self, width, depth):
        super().__init__(width, depth)

        ###

        depth_bits = log2_int(depth, True)

        produce = ClockDomainsRenamer("write")(GrayCounter(depth_bits + 1))
        consume = ClockDomainsRenamer("read")(GrayCounter(depth_bits + 1))
        self.submodules += produce, consume
        self.comb += [
            produce.ce.eq(self.writable & self.we),
            consume.ce.eq(self.readable & self.re)
        ]

        produce_rdomain = Signal(depth_bits + 1)
        produce.q.attr.add("no_retiming")
        self.specials += MultiReg(produce.q, produce_rdomain, "read")
        consume_wdomain = Signal(depth_bits + 1)
        consume.q.attr.add("no_retiming")
        self.specials += MultiReg(consume.q, consume_wdomain, "write")
        if depth_bits == 1:
            self.comb += self.writable.eq(
                (produce.q[-1] == consume_wdomain[-1]) |
                (produce.q[-2] == consume_wdomain[-2]))
        else:
            self.comb += [
                self.writable.eq(
                    (produce.q[-1] == consume_wdomain[-1]) |
                    (produce.q[-2] == consume_wdomain[-2]) |
                    (produce.q[:-2] != consume_wdomain[:-2]))
            ]
        self.comb += self.readable.eq(consume.q != produce_rdomain)

        storage = Memory(self.width, depth)
        self.specials += storage
        wrport = storage.get_port(write_capable=True, clock_domain="write")
        self.specials += wrport
        self.comb += [
            wrport.adr.eq(produce.q_binary[:-1]),
            wrport.dat_w.eq(self.din),
            wrport.we.eq(produce.ce)
        ]
        rdport = storage.get_port(clock_domain="read")
        self.specials += rdport
        self.comb += [
            rdport.adr.eq(consume.q_next_binary[:-1]),
            self.dout.eq(rdport.dat_r)
        ]
Beispiel #3
0
    def __init__(self, width, idomain, odomain, timeout=128):
        self.i = Signal(width)
        self.o = Signal(width, reset_less=True)

        if width == 1:
            self.specials += MultiReg(self.i, self.o, odomain)
        else:
            sync_i = getattr(self.sync, idomain)
            sync_o = getattr(self.sync, odomain)

            starter = Signal(reset=1)
            sync_i += starter.eq(0)
            self.submodules._ping = PulseSynchronizer(idomain, odomain)
            self.submodules._pong = PulseSynchronizer(odomain, idomain)
            self.submodules._timeout = ClockDomainsRenamer(idomain)(
                WaitTimer(timeout))
            self.comb += [
                self._timeout.wait.eq(~self._ping.i),
                self._ping.i.eq(starter | self._pong.o | self._timeout.done),
                self._pong.i.eq(self._ping.i)
            ]

            ibuffer = Signal(width, reset_less=True)
            obuffer = Signal(width)  # registered reset_less by MultiReg
            sync_i += If(self._pong.o, ibuffer.eq(self.i))
            ibuffer.attr.add("no_retiming")
            self.specials += MultiReg(ibuffer, obuffer, odomain)
            sync_o += If(self._ping.o, self.o.eq(obuffer))
    def __init__(self, width, idomain, odomain, timeout=128):
        self.i = Signal(width)
        self.o = Signal(width, reset_less=True)

        if width == 1:
            self.specials += MultiReg(self.i, self.o, odomain)
        else:
            sync_i = getattr(self.sync, idomain)
            sync_o = getattr(self.sync, odomain)

            starter = Signal(reset=1)
            sync_i += starter.eq(0)
            self.submodules._ping = PulseSynchronizer(idomain, odomain)
            # Extra flop on i->o to avoid race between data and request
            # https://github.com/m-labs/nmigen/pull/40#issuecomment-484166790
            ping_o = Signal()
            sync_o += ping_o.eq(self._ping.o)
            self.submodules._pong = PulseSynchronizer(odomain, idomain)
            self.submodules._timeout = ClockDomainsRenamer(idomain)(
                WaitTimer(timeout))
            self.comb += [
                self._timeout.wait.eq(~self._ping.i),
                self._ping.i.eq(starter | self._pong.o | self._timeout.done),
                self._pong.i.eq(ping_o)
            ]

            ibuffer = Signal(width, reset_less=True)
            obuffer = Signal(width)  # registered reset_less by MultiReg
            sync_i += If(self._pong.o, ibuffer.eq(self.i))
            ibuffer.attr.add("no_retiming")
            self.specials += MultiReg(ibuffer, obuffer, odomain)
            sync_o += If(ping_o, self.o.eq(obuffer))
Beispiel #5
0
 def add_udp_loopback(self, portnum, dw, depth, name=None):
     port = self.eth_core.udp.crossbar.get_port(portnum, dw, cd="sys2x_i")
     buf = ClockDomainsRenamer("sys2x_i")(stream.SyncFIFO(eth_udp_user_description(dw), depth//(dw//8), buffered=True))
     if name is None:
         self.submodules += buf
     else:
         setattr(self.submodules, name, buf)
     self.comb += Port.connect(port, buf)
Beispiel #6
0
    def __init__(self, sd_linklayer, pins):
        self._latch = CSRStorage(len(pins))

        self.clock_domains.cd_sd = ClockDomain(reset_less=True)
        self.comb += self.cd_sd.clk.eq(sd_linklayer.cd_sd.clk)

        sdcd_latch = Signal(len(pins))
        self.specials += MultiReg(self._latch.storage, sdcd_latch, odomain="sd", n=3)

        # Output circuit itself is entirely in SD clock domain
        self.submodules.drv = ClockDomainsRenamer("sd")(
           SDTriggerOutputDriver(pins, sdcd_latch, sd_linklayer.data_out_done))
Beispiel #7
0
    def __init__(self, sys_clk_freq=int(75e6), toolchain="trellis", **kwargs):
        BaseSoC.__init__(self, toolchain=toolchain, **kwargs)

        # Ethernet ---------------------------------------------------------------------------------
        # phy
        self.submodules.ethphy = ClockDomainsRenamer("sys2x_i")(LiteEthPHYRGMII(
            self.platform.request("eth_clocks"),
            self.platform.request("eth")))
        self.add_csr("ethphy")
        
        self.submodules.eth_core = ClockDomainsRenamer("sys2x_i")(LiteEthUDPIPCore(
            phy         = self.ethphy,
            mac_address = 0x10e2d5000001,
            ip_address  = "192.168.1.50",
            clk_freq    = int(2*sys_clk_freq),
            with_icmp   = True))

        self.add_udp_loopback(8000, 32, 128, "loopback_32")

        # etherbone - TODO, doesn't work yet
        # self.submodules.etherbone = LiteEthEtherbone(self.eth_core.udp, 1234)
        # self.add_wb_master(self.etherbone.wishbone.bus)

        # litescope - TODO, needs etherbone to work first
        # analyzer_signals = [
        #     self.loopback_32.sink
        # ]
        # self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 4096, csr_csv="tools/analyzer.csv")
        # self.add_csr("analyzer")
        
        # timing constraints
        self.platform.add_period_constraint(self.ethphy.crg.cd_eth_rx.clk, 1e9/125e6)
        self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk, 1e9/125e6)
        self.platform.add_false_path_constraints(
            self.crg.cd_sys.clk,
            self.ethphy.crg.cd_eth_rx.clk,
            self.ethphy.crg.cd_eth_tx.clk)
Beispiel #8
0
    def __init__(self, platform, boot_source="rand",
                 debug=None, bios_file=None,
                 use_dsp=False, placer="heap", output_dir="build",
                 pnr_seed=0,
                 warmboot_offsets=None,
                 **kwargs):
        # Disable integrated RAM as we'll add it later
        self.integrated_sram_size = 0

        self.output_dir = output_dir

        clk_freq = int(12e6)
        self.submodules.crg = _CRG(platform)

        SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, with_uart=False, **kwargs)

        usb_debug = False
        if debug is not None:
            if debug == "uart":
                from litex.soc.cores.uart import UARTWishboneBridge
                self.submodules.uart_bridge = UARTWishboneBridge(platform.request("serial"), clk_freq, baudrate=115200)
                self.add_wb_master(self.uart_bridge.wishbone)
            elif debug == "usb":
                usb_debug = True
            elif debug == "spi":
                import spibone
                # Add SPI Wishbone bridge
                debug_device = [
                    ("spidebug", 0,
                        Subsignal("mosi", Pins("dbg:0")),
                        Subsignal("miso", Pins("dbg:1")),
                        Subsignal("clk",  Pins("dbg:2")),
                        Subsignal("cs_n", Pins("dbg:3")),
                    )
                ]
                platform.add_extension(debug_device)
                spi_pads = platform.request("spidebug")
                self.submodules.spibone = ClockDomainsRenamer("usb_12")(spibone.SpiWishboneBridge(spi_pads, wires=4))
                self.add_wb_master(self.spibone.wishbone)
            if hasattr(self, "cpu") and not isinstance(self.cpu, CPUNone):
                self.cpu.use_external_variant("rtl/VexRiscv_Fomu_Debug.v")
                os.path.join(output_dir, "gateware")
                self.register_mem("vexriscv_debug", 0xf00f0000, self.cpu.debug_bus, 0x100)
        else:
            if hasattr(self, "cpu") and not isinstance(self.cpu, CPUNone):
                self.cpu.use_external_variant("rtl/VexRiscv_Fomu.v")

        # SPRAM- UP5K has single port RAM, might as well use it as SRAM to
        # free up scarce block RAM.
        spram_size = 128*1024
        self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size)
        self.register_mem("sram", self.mem_map["sram"], self.spram.bus, spram_size)

        # Add a Messible for device->host communications
        self.submodules.messible = Messible()

        if boot_source == "rand":
            kwargs['cpu_reset_address'] = 0
            bios_size = 0x2000
            self.submodules.random_rom = RandomFirmwareROM(bios_size)
            self.add_constant("ROM_DISABLE", 1)
            self.register_rom(self.random_rom.bus, bios_size)
        elif boot_source == "bios":
            kwargs['cpu_reset_address'] = 0
            if bios_file is None:
                self.integrated_rom_size = bios_size = 0x2000
                self.submodules.rom = wishbone.SRAM(bios_size, read_only=True, init=[])
                self.register_rom(self.rom.bus, bios_size)
            else:
                bios_size = 0x2000
                self.submodules.firmware_rom = FirmwareROM(bios_size, bios_file)
                self.add_constant("ROM_DISABLE", 1)
                self.register_rom(self.firmware_rom.bus, bios_size)

        elif boot_source == "spi":
            kwargs['cpu_reset_address'] = 0
            self.integrated_rom_size = bios_size = 0x2000
            gateware_size = 0x1a000
            self.flash_boot_address = self.mem_map["spiflash"] + gateware_size
            self.submodules.rom = wishbone.SRAM(bios_size, read_only=True, init=[])
            self.register_rom(self.rom.bus, bios_size)
        else:
            raise ValueError("unrecognized boot_source: {}".format(boot_source))

        # The litex SPI module supports memory-mapped reads, as well as a bit-banged mode
        # for doing writes.
        spi_pads = platform.request("spiflash4x")
        self.submodules.lxspi = spi_flash.SpiFlashDualQuad(spi_pads, dummy=platform.spi_dummy, endianness="little")
        self.register_mem("spiflash", self.mem_map["spiflash"], self.lxspi.bus, size=platform.spi_size)

        # Add USB pads, as well as the appropriate USB controller.  If no CPU is
        # present, use the DummyUsb controller.
        usb_pads = platform.request("usb")
        usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup)
        if hasattr(self, "cpu") and not isinstance(self.cpu, CPUNone):
            self.submodules.usb = eptri.TriEndpointInterface(usb_iobuf, debug=usb_debug)
        else:
            self.submodules.usb = dummyusb.DummyUsb(usb_iobuf, debug=usb_debug)

        if usb_debug:
            self.add_wb_master(self.usb.debug_bridge.wishbone)
        # For the EVT board, ensure the pulldown pin is tristated as an input
        if hasattr(usb_pads, "pulldown"):
            pulldown = TSTriple()
            self.specials += pulldown.get_tristate(usb_pads.pulldown)
            self.comb += pulldown.oe.eq(0)

        # Add GPIO pads for the touch buttons
        platform.add_extension(TouchPads.touch_device)
        self.submodules.touch = TouchPads(platform.request("touch_pads"))

        # Allow the user to reboot the ICE40.  Additionally, connect the CPU
        # RESET line to a register that can be modified, to allow for
        # us to debug programs even during reset.
        self.submodules.reboot = SBWarmBoot(self, warmboot_offsets)
        if hasattr(self, "cpu") and not isinstance(self.cpu, CPUNone):
            self.cpu.cpu_params.update(
                i_externalResetVector=self.reboot.addr.storage,
            )

        self.submodules.rgb = SBLED(platform.revision, platform.request("rgb_led"))
        self.submodules.version = Version(platform.revision, self, pnr_seed, models=[
                ("0x45", "E", "Fomu EVT"),
                ("0x44", "D", "Fomu DVT"),
                ("0x50", "P", "Fomu PVT (production)"),
                ("0x48", "H", "Fomu Hacker"),
                ("0x3f", "?", "Unknown model"),
            ])

        # Override default LiteX's yosys/build templates
        assert hasattr(platform.toolchain, "yosys_template")
        assert hasattr(platform.toolchain, "build_template")
        platform.toolchain.yosys_template = [
            "{read_files}",
            "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0",
            "synth_ice40 -json {build_name}.json -top {build_name}",
        ]
        platform.toolchain.build_template = [
            "yosys -q -l {build_name}.rpt {build_name}.ys",
            "nextpnr-ice40 --json {build_name}.json --pcf {build_name}.pcf --asc {build_name}.txt \
            --pre-pack {build_name}_pre_pack.py --{architecture} --package {package}",
            "icepack {build_name}.txt {build_name}.bin"
        ]

        # Add "-relut -dffe_min_ce_use 4" to the synth_ice40 command.
        # The "-reult" adds an additional LUT pass to pack more stuff in,
        # and the "-dffe_min_ce_use 4" flag prevents Yosys from generating a
        # Clock Enable signal for a LUT that has fewer than 4 flip-flops.
        # This increases density, and lets us use the FPGA more efficiently.
        platform.toolchain.yosys_template[2] += " -relut -abc2 -dffe_min_ce_use 4 -relut"
        if use_dsp:
            platform.toolchain.yosys_template[2] += " -dsp"

        # Disable final deep-sleep power down so firmware words are loaded
        # onto softcore's address bus.
        platform.toolchain.build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"

        # Allow us to set the nextpnr seed
        platform.toolchain.build_template[1] += " --seed " + str(pnr_seed)

        if placer is not None:
            platform.toolchain.build_template[1] += " --placer {}".format(placer)
    def __init__(self, usb_iobuf):
        self.bus = wishbone.Interface()

        # create a new custom CSR bus
        self.submodules.csr = WB2CSR(self.bus)
        csr_cpu = self.csr.csr

        self.submodules.usb = usb = ClockDomainsRenamer({'sys': 'usb_12'})(
            eptri.TriEndpointInterface(usb_iobuf, debug=False))
        csrs = self.usb.get_csrs()
        # create a CSRBank for the eptri CSRs
        self.submodules.csr_bank = ClockDomainsRenamer({'sys': 'usb_12'
                                                        })(CSRBank(csrs, 0))
        csr_usb12 = self.csr_bank.bus

        if hasattr(usb, 'debug_bridge'):
            self.debug_bridge = usb.debug_bridge.wishbone

        # patch these two CSRs together with an Async FIFO
        _layout = [("adr", 32), ("dat_w", 32), ("we", 1)]

        self.submodules.fifo = fifo = ClockDomainsRenamer({
            'write': 'sys',
            'read': 'usb_12'
        })(AsyncFIFO(_layout, 64, False))

        bus_adr = Signal(32)

        self.comb += [
            # Data into FIFO
            fifo.sink.adr.eq(csr_cpu.adr),
            fifo.sink.dat_w.eq(csr_cpu.dat_w),
            fifo.sink.we.eq(csr_cpu.we),
            fifo.sink.valid.eq(self.csr.en),

            # Always clear FIFO on clock cycle
            fifo.source.ready.eq(1),
            If(
                fifo.source.valid,
                csr_usb12.dat_w.eq(fifo.source.dat_w),
                csr_usb12.adr.eq(fifo.source.adr),
                bus_adr.eq(fifo.source.adr),
                csr_usb12.we.eq(fifo.source.we),
            ),
        ]

        self.submodules.fifo_r = fifo_r = ClockDomainsRenamer({
            'write': 'usb_12',
            'read': 'sys'
        })(AsyncFIFO([("adr", 32), ("dat_r", 32)], 64, False))

        valid = Signal()
        source_adr = Signal(32)

        self.sync.usb_12 += [
            valid.eq(fifo.source.valid & ~csr_usb12.we),
            source_adr.eq(bus_adr)
        ]

        self.comb += [
            # Data into FIFO
            fifo_r.sink.dat_r.eq(csr_usb12.dat_r),
            fifo_r.sink.adr.eq(source_adr),
            fifo_r.sink.valid.eq(valid),
            fifo_r.source.ready.eq(1),
        ]

        self.sync += [
            self.csr.ack.eq(0),
            If(
                fifo_r.source.valid,
                self.csr.ack.eq(self.bus.adr[:14] == fifo_r.source.adr),
                csr_cpu.dat_r.eq(fifo_r.source.dat_r),
            ),
        ]

        # Patch interrupt through
        self.irq = Signal()
        self.specials += MultiReg(usb.ev.irq, self.irq)
    def __init__(self, pads, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
        half_rate_phy = S6HalfRateDDRPHY(pads, "DDR3", rd_bitslip, wr_bitslip,
                                         dqs_ddr_alignment)
        self.submodules += ClockDomainsRenamer("sys2x")(half_rate_phy)

        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        nphases = 4

        self.settings = PhySettings(memtype="DDR3",
                                    dfi_databits=2 * databits,
                                    nranks=nranks,
                                    nphases=nphases,
                                    rdphase=0,
                                    wrphase=1,
                                    rdcmdphase=1,
                                    wrcmdphase=0,
                                    cl=5,
                                    cwl=6,
                                    read_latency=6 // 2 + 1,
                                    write_latency=2 // 2)

        self.dfi = Interface(addressbits, bankbits, nranks, 2 * databits,
                             nphases)
        self.clk8x_wr_strb = half_rate_phy.clk4x_wr_strb
        self.clk8x_rd_strb = half_rate_phy.clk4x_rd_strb

        # sys_clk      : system clk, used for dfi interface
        # sys2x_clk    : 2x system clk
        sd_sys = getattr(self.sync, "sys")
        sd_sys2x = getattr(self.sync, "sys2x")

        # select active sys2x phase
        # sys_clk   ----____----____
        # phase_sel 0   1   0   1
        phase_sel = Signal()
        phase_sys2x = Signal.like(phase_sel)
        phase_sys = Signal.like(phase_sys2x)

        sd_sys += phase_sys.eq(phase_sys2x)

        sd_sys2x += [
            If(
                phase_sys2x == phase_sys,
                phase_sel.eq(0),
            ).Else(phase_sel.eq(~phase_sel)),
            phase_sys2x.eq(~phase_sel)
        ]

        # DFI adaptation

        # Commands and writes
        dfi_omit = set(["rddata", "rddata_valid", "wrdata_en"])
        self.comb += [
            If(
                ~phase_sel,
                self.dfi.phases[0].connect(half_rate_phy.dfi.phases[0],
                                           omit=dfi_omit),
                self.dfi.phases[1].connect(half_rate_phy.dfi.phases[1],
                                           omit=dfi_omit),
            ).Else(
                self.dfi.phases[2].connect(half_rate_phy.dfi.phases[0],
                                           omit=dfi_omit),
                self.dfi.phases[3].connect(half_rate_phy.dfi.phases[1],
                                           omit=dfi_omit),
            ),
        ]
        wr_data_en = self.dfi.phases[
            self.settings.wrphase].wrdata_en & ~phase_sel
        wr_data_en_d = Signal()
        sd_sys2x += wr_data_en_d.eq(wr_data_en)
        self.comb += half_rate_phy.dfi.phases[
            half_rate_phy.settings.wrphase].wrdata_en.eq(wr_data_en
                                                         | wr_data_en_d)

        # Reads
        rddata = Array(Signal(2 * databits) for i in range(2))
        rddata_valid = Signal(2)

        for i in range(2):
            sd_sys2x += [
                rddata_valid[i].eq(half_rate_phy.dfi.phases[i].rddata_valid),
                rddata[i].eq(half_rate_phy.dfi.phases[i].rddata)
            ]

        sd_sys += [
            self.dfi.phases[0].rddata.eq(rddata[0]),
            self.dfi.phases[0].rddata_valid.eq(rddata_valid[0]),
            self.dfi.phases[1].rddata.eq(rddata[1]),
            self.dfi.phases[1].rddata_valid.eq(rddata_valid[1]),
            self.dfi.phases[2].rddata.eq(half_rate_phy.dfi.phases[0].rddata),
            self.dfi.phases[2].rddata_valid.eq(
                half_rate_phy.dfi.phases[0].rddata_valid),
            self.dfi.phases[3].rddata.eq(half_rate_phy.dfi.phases[1].rddata),
            self.dfi.phases[3].rddata_valid.eq(
                half_rate_phy.dfi.phases[1].rddata_valid)
        ]
Beispiel #11
0
    def __init__(self):
        self.specials += self.data_t

        self.isRxCmd = Signal()
        self.rx_data = Signal(8)
        rx_fifo_we = Signal()
        self.debug = Signal(8)

        past_rx_cmd = Signal(8)
        current_rx_cmd = Signal(8)

        # ULPI Register Write signals. USB clock domain
        ulpi_reg_wr_addr = Signal(6)
        ulpi_reg_wr_data = Signal(8)
        ulpi_reg_wr_trig = Signal()
        ulpi_reg_wr_busy = Signal()
        ulpi_reg_wr_done = Signal()
        ulpi_reg_wr_queue = Signal()

        # ULPI Register Read signals. USB clock domain
        ulpi_reg_rd_addr = Signal(6)
        ulpi_reg_rd_data = Signal(8)
        ulpi_reg_rd_trig = Signal()
        ulpi_reg_rd_busy = Signal()
        ulpi_reg_rd_done = Signal()
        ulpi_reg_rd_queue = Signal()

        self.sync.usb += [
            If(ulpi_reg_wr_trig, ulpi_reg_wr_queue.eq(1)),
            If(ulpi_reg_rd_trig, ulpi_reg_rd_queue.eq(1)),
        ]

        fsm = self.fsm = ClockDomainsRenamer("usb")(FSM(reset_state="RESET"))
        self.submodules += fsm

        fsm.act(
            "RESET",
            If(
                ~self.dir,
                NextValue(self.data_t.o, 0x00),
                NextState("IDLE"),
            ))

        fsm.act(
            "IDLE",
            If(
                self.dir,  # & self.nxt,
                NextState("RX")).Elif(
                    ulpi_reg_wr_queue,
                    NextState("REG_WR_CMD"),
                    NextValue(
                        self.data_t.o,
                        Cat(ulpi_reg_wr_addr, Constant(value=2, bits_sign=2))),
                    NextValue(ulpi_reg_wr_queue, 0),
                    NextValue(ulpi_reg_wr_busy, 1),
                    NextValue(ulpi_reg_wr_done, 0),
                ).Elif(
                    ulpi_reg_rd_queue,
                    NextState("REG_RD_CMD"),
                    NextValue(
                        self.data_t.o,
                        Cat(ulpi_reg_rd_addr, Constant(value=3, bits_sign=2))),
                    NextValue(ulpi_reg_rd_queue, 0),
                    NextValue(ulpi_reg_rd_busy, 1),
                    NextValue(ulpi_reg_rd_done, 0),
                ))

        fsm.act(
            "RX", NextValue(self.isRxCmd, 0x0),
            If(
                self.dir & ~self.nxt,
                NextValue(self.rx_data, self.data_t.i),
                NextValue(self.isRxCmd, 0x1),
            ).Elif(self.dir & self.nxt, NextValue(self.rx_data,
                                                  self.data_t.i)).Elif(
                                                      ~self.dir & ~self.nxt,
                                                      NextState("IDLE"),
                                                  ))

        fsm.act(
            "REG_WR_CMD",
            If(
                ~self.dir & self.nxt,
                NextState("REG_WR_DATA"),
                NextValue(self.data_t.o, ulpi_reg_wr_data),
            ).Elif(
                self.dir,  # & self.nxt,
                NextState(
                    "RX"),  # Reg write aborted during Reg Write TXCMD cycle
                NextValue(self.data_t.o, 0x00),
            ))

        fsm.act(
            "REG_WR_DATA",
            If(
                ~self.dir & self.nxt,
                NextState("REG_WR_STP"),
                NextValue(self.stp, 1),
            ).Elif(
                self.dir & self.nxt,
                NextState("RX"),  # Reg write aborted during write data cycle
            ),
            NextValue(self.data_t.o, 0x00),
        )

        fsm.act(
            "REG_WR_STP",
            If(
                ~self.dir & ~self.nxt,
                NextState("IDLE"),
            ).Elif(
                self.dir & self.nxt,
                NextState(
                    "RX"
                ),  # Register write followed immediately by a USB receive during stp assertion
            ),
            NextValue(self.data_t.o, 0x00),
            NextValue(ulpi_reg_wr_busy, 0),
            NextValue(ulpi_reg_wr_done, 1),
        )

        fsm.act(
            "REG_RD_CMD",
            If(
                self.nxt & ~self.dir,
                NextState("REG_RD_TURNAROUND"),
            ).Elif(
                self.nxt & self.
                dir,  # Reg read aborted by PHY during TX_CMD due to receive
                NextState("RX"),
                NextValue(self.data_t.o, 0x00),
            ),
        )

        fsm.act(
            "REG_RD_TURNAROUND",
            If(
                self.dir & self.
                nxt,  # Reg read aborted by PHY during turnaround due to receive
                NextState("RX")).Elif(
                    self.dir & ~self.nxt,
                    NextState("REG_RD_DATA"),
                ),
            NextValue(self.data_t.o, 0x00),
        )

        fsm.act(
            "REG_RD_DATA",
            If(
                self.dir & ~self.nxt,
                NextState("RX"),
                NextValue(ulpi_reg_rd_data, self.data_t.i),
                NextValue(ulpi_reg_rd_busy, 0),
                NextValue(ulpi_reg_rd_done, 1),
            ))

        self.sync.usb += [
            If(self.dir & ~self.nxt & fsm.ongoing("RX"),
               past_rx_cmd.eq(current_rx_cmd),
               current_rx_cmd.eq(self.data_t.i))
        ]

        se0 = Signal()
        j_state = Signal()
        k_state = Signal()
        se1 = Signal()

        squelch = Signal()
        n_squelch = Signal()
        FULL_SPEED = 0
        HIGH_SPEED = 1
        mode = FULL_SPEED  # 0: Full Speed, 1: High Speed
        self.comb += [
            se0.eq((current_rx_cmd[0:2] == 0b00) & (mode == FULL_SPEED)),
            j_state.eq((current_rx_cmd[0:2] == 0b01) & (mode == FULL_SPEED)),
            k_state.eq((current_rx_cmd[0:2] == 0b10) & (mode == FULL_SPEED)),
            se1.eq((current_rx_cmd[0:2] == 0b11) & (mode == FULL_SPEED)),
            squelch.eq((current_rx_cmd[0:2] == 0b00) & (mode == HIGH_SPEED)),
            n_squelch.eq((current_rx_cmd[0:2] == 0b01) & (mode == HIGH_SPEED)),
        ]

        rx_fifo = self.rx_fifo = ClockDomainsRenamer("usb")(
            SyncFIFO(9, 20480)
        )  # ClockDomainsRenamer({"write": "usb", "read": "sys"})(AsyncFIFO(9, 2048))
        self.submodules += rx_fifo
        self.sync.usb += [
            self.stp.eq(
                0
            ),  # ~rx_fifo.writable)  # No need to stop. Always receive unless FIFO full. FIXME stp
            rx_fifo.we.eq(
                rx_fifo_we
            )  # Delay we assertion since we are delaying data too in fsm's NextValue
        ]

        self.comb += [
            self.data_t.oe.eq(~self.dir),  # Tristate output enable
            rx_fifo_we.eq(fsm.ongoing("RX") & self.dir & rx_fifo.writable),
            rx_fifo.din.eq(Cat(self.rx_data, self.isRxCmd)),
            # rx_fifo.we.eq(fsm.ongoing("RX") & self.dir & rx_fifo.writable)
        ]

        self.attach_axi_slave(16)

        self.comb += [
            self.axi_reg[0].data_r.eq(
                Cat(rx_fifo.dout[:8], Constant(0, bits_sign=23),
                    rx_fifo.dout[8])),
            self.axi_reg[0].readable.eq(rx_fifo.readable),
            rx_fifo.re.eq(self.axi_reg[0].re),
            self.axi_reg[1].data_r.eq(rx_fifo.readable),

            # ULPI Register
            ulpi_reg_wr_addr.eq(self.axi_reg[2].data_w[0:6]),
            ulpi_reg_wr_data.eq(self.axi_reg[3].data_w[0:8]),
            ulpi_reg_wr_trig.eq(self.get_rising_edge(
                self.axi_reg[4].data_w[0])),
            self.axi_reg[5].data_r.eq(Cat(ulpi_reg_wr_busy, ulpi_reg_wr_done)),
            ulpi_reg_rd_addr.eq(self.axi_reg[6].data_w[0:6]),
            self.axi_reg[7].data_r.eq(ulpi_reg_rd_data),
            ulpi_reg_rd_trig.eq(self.get_rising_edge(
                self.axi_reg[8].data_w[0])),
            self.axi_reg[9].data_r.eq(Cat(ulpi_reg_rd_busy, ulpi_reg_rd_done)),
        ]

        self.comb += [self.axi_reg[i].writable.eq(1) for i in range(16)]

        # self.comb += [
        #     self.debug.eq(Cat(ulpi_reg_rd_busy, ulpi_reg_rd_done, ulpi_reg_rd_trig, ulpi_reg_rd_queue, ulpi_reg_wr_busy, ulpi_reg_wr_done, ulpi_reg_wr_trig, ulpi_reg_wr_queue))
        # ]
        self.sync.usb += [
            If(ulpi_reg_wr_trig, self.debug[0].eq(1)),
            If(ulpi_reg_rd_trig, self.debug[1].eq(1)),
        ]
Beispiel #12
0
def export_async(config, filename='top'):
    print("Adding async FIFOs to external network interfaces")

    m = [
        Core(
            config, i * config.addresslayout.num_pe_per_fpga,
            min((i + 1) * config.addresslayout.num_pe_per_fpga,
                config.addresslayout.num_pe))
        for i in range(config.addresslayout.num_fpga)
    ]

    for core in m:
        core.clock_domains.cd_sys = ClockDomain(reset_less=True)
        core.clock_domains.cd_ext = ClockDomain(reset_less=True)
        core.submodules.asyncfifos_in = [
            ClockDomainsRenamer({
                "write": "ext",
                "read": "sys"
            })(AsyncFIFOBuffered(width=layout_len(
                core.network.external_network_interface_in[j].layout),
                                 depth=16))
            for j in range(config.addresslayout.num_channels)
        ]
        core.submodules.asyncfifos_out = [
            ClockDomainsRenamer({
                "write": "sys",
                "read": "ext"
            })(AsyncFIFOBuffered(width=layout_len(
                core.network.external_network_interface_in[j].layout),
                                 depth=16))
            for j in range(config.addresslayout.num_channels)
        ]
        core.external_network_interface_in = [
            NetworkInterface(name="ext_network_in",
                             **config.addresslayout.get_params())
            for _ in range(config.addresslayout.num_channels)
        ]
        core.external_network_interface_out = [
            NetworkInterface(name="ext_network_out",
                             **config.addresslayout.get_params())
            for _ in range(config.addresslayout.num_channels)
        ]
        for j in range(config.addresslayout.num_channels):
            core.comb += [
                core.asyncfifos_in[j].din.eq(
                    core.external_network_interface_in[j].raw_bits()),
                core.asyncfifos_in[j].we.eq(
                    core.external_network_interface_in[j].valid),
                core.external_network_interface_in[j].ack.eq(
                    core.asyncfifos_in[j].writable)
            ]
            core.comb += [
                core.network.external_network_interface_in[j].raw_bits().eq(
                    core.asyncfifos_in[j].dout),
                core.network.external_network_interface_in[j].valid.eq(
                    core.asyncfifos_in[j].readable),
                core.asyncfifos_in[j].re.eq(
                    core.network.external_network_interface_in[j].ack)
            ]
            core.comb += [
                core.asyncfifos_out[j].din.eq(
                    core.network.external_network_interface_out[j].raw_bits()),
                core.asyncfifos_out[j].we.eq(
                    core.network.external_network_interface_out[j].valid),
                core.network.external_network_interface_out[j].ack.eq(
                    core.asyncfifos_out[j].writable)
            ]
            core.comb += [
                core.external_network_interface_out[j].raw_bits().eq(
                    core.asyncfifos_out[j].dout),
                core.external_network_interface_out[j].valid.eq(
                    core.asyncfifos_out[j].readable),
                core.asyncfifos_out[j].re.eq(
                    core.external_network_interface_out[j].ack)
            ]

    for i in range(config.addresslayout.num_fpga):
        iname = filename + "_" + str(i)
        os.makedirs(iname, exist_ok=True)
        with cd(iname):

            ios = {
                m[i].start, m[i].done, m[i].cycle_count,
                m[i].total_num_messages, m[i].level, m[i].kernel_error,
                m[i].cd_sys.clk, m[i].cd_ext.clk
            }

            for j in range(config.addresslayout.num_channels):
                ios |= set(m[i].external_network_interface_in[j].flatten())
                ios |= set(m[i].external_network_interface_out[j].flatten())

            # debug signals
            for a in m[i].network.arbiter:
                ios.add(a.barriercounter.all_messages_recvd)
                ios.add(a.barriercounter.all_barriers_recvd)
                # ios |= set(a.barriercounter.barrier_from_pe)
                # ios |= set(a.barriercounter.num_from_pe)
                # ios |= set(a.barriercounter.num_expected_from_pe)
            ios.add(m[i].network.local_network_round)

            verilog.convert(m[i], name="top", ios=ios).write(iname + ".v")