+++ /dev/null
-Unless otherwise noted, LiteUSB is copyright (C) 2015 Florent Kermarrec.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-Other authors retain ownership of their contributions. If a submission can
-reasonably be considered independently copyrightable, it's yours and we
-encourage you to claim it with appropriate copyright notices. This submission
-then falls under the "otherwise noted" category. All submissions are strongly
-encouraged to use the two-clause BSD license reproduced above.
+++ /dev/null
- __ _ __ __ _________
- / / (_) /____ / / / / __/ _ )
- / /__/ / __/ -_) /_/ /\ \/ _ |
- /____/_/\__/\__/\____/___/____/
-
- Copyright 2015 / EnjoyDigital / M-Labs Ltd
-
- A small footprint and configurable USB core
- powered by Migen
-
-[> Doc
----------
-XXX
-
-[> Intro
----------
-LiteUSB provides a small footprint and configurable USB core.
-
-LiteUSB is part of MiSoC libraries whose aims are to lower entry level of
-complex FPGA cores by providing simple, elegant and efficient implementations
-ofcomponents used in today's SoC such as Ethernet, SATA, PCIe, SDRAM Controller...
-
-The core uses simple and specific streaming buses and will provides in the future
-adapters to use standardized AXI or Avalon-ST streaming buses.
-
-Since Python is used to describe the HDL, the core is highly and easily
-configurable.
-
-LiteUSB uses technologies developed in partnership with M-Labs Ltd:
- - Migen enables generating HDL with Python in an efficient way.
- - MiSoC provides the basic blocks to build a powerful and small footprint SoC.
-
-LiteUSB can be used as MiSoC library or can be integrated with your standard
-design flow by generating the verilog rtl that you will use as a standard core.
-
-[> Features
------------
-- FTDI2232 slave fifo core (DMA, virtual TTY) + host software
-
-[> Possible improvements
--------------------------
-- add Cypress FX2 support
-- add Cypress FX3 support
-- add USB3 transceiver support and use Daisho's USB3 stack?
-- ... See below Support and consulting :)
-
-If you want to support these features, please contact us at florent [AT]
-enjoy-digital.fr. You can also contact our partner on the public mailing list
-devel [AT] lists.m-labs.hk.
-
-
-[> Getting started
-------------------
-XXX
-
-[> Simulations:
-XXX
-
-[> Tests :
-XXX
-
-[> License
------------
-LiteUSB is released under the very permissive two-clause BSD license. Under
-the terms of this license, you are authorized to use LiteUSB for closed-source
-proprietary designs.
-Even though we do not require you to do so, those things are awesome, so please
-do them if possible:
- - tell us that you are using LiteUSB
- - cite LiteUSB in publications related to research it has helped
- - send us feedback and suggestions for improvements
- - send us bug reports when something goes wrong
- - send us the modifications and improvements you have done to LiteUSB.
-
-[> Support and consulting
---------------------------
-We love open-source hardware and like sharing our designs with others.
-
-LiteUSB is mainly developed and maintained by EnjoyDigital.
-
-If you would like to know more about LiteUSB or if you are already a happy
-user and would like to extend it for your needs, EnjoyDigital can provide standard
-commercial support as well as consulting services.
-
-So feel free to contact us, we'd love to work with you! (and eventually shorten
-the list of the possible improvements :)
-
-[> Contact
-E-mail: florent [AT] enjoy-digital.fr
\ No newline at end of file
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.fsm import *
-from migen.actorlib.fifo import *
-from migen.flow.actor import EndpointDescription
-from migen.actorlib.packet import *
-from migen.actorlib.structuring import Pipeline
-
-
-packet_header_length = 9
-packet_header_fields = {
- "preamble": HeaderField(0, 0, 32),
- "dst": HeaderField(4, 0, 8),
- "length": HeaderField(5, 0, 32)
-}
-packet_header = Header(packet_header_fields,
- packet_header_length,
- swap_field_bytes=True)
-
-
-def phy_description(dw):
- payload_layout = [("data", dw)]
- return EndpointDescription(payload_layout, packetized=False)
-
-
-def packet_description(dw):
- param_layout = packet_header.get_layout()
- payload_layout = [
- ("data", dw),
- ("error", dw//8)
- ]
- return EndpointDescription(payload_layout, param_layout, packetized=True)
-
-
-def user_description(dw):
- param_layout = [
- ("dst", 8),
- ("length", 32)
- ]
- payload_layout = [
- ("data", dw),
- ("error", dw//8)
- ]
- return EndpointDescription(payload_layout, param_layout, packetized=True)
-
-
-class LiteUSBMasterPort:
- def __init__(self, dw):
- self.source = Source(user_description(dw))
- self.sink = Sink(user_description(dw))
-
-
-class LiteUSBSlavePort:
- def __init__(self, dw, tag):
- self.sink = Sink(user_description(dw))
- self.source = Source(user_description(dw))
- self.tag = tag
-
-
-class LiteUSBUserPort(LiteUSBSlavePort):
- def __init__(self, dw, tag):
- LiteUSBSlavePort.__init__(self, dw, tag)
+++ /dev/null
-from misoclib.com.liteusb.common import *
-from misoclib.com.liteusb.core.packet import LiteUSBPacketizer, LiteUSBDepacketizer
-from misoclib.com.liteusb.core.crc import LiteUSBCRC32Inserter, LiteUSBCRC32Checker
-from misoclib.com.liteusb.core.crossbar import LiteUSBCrossbar
-
-class LiteUSBCore(Module):
- def __init__(self, phy, clk_freq, with_crc=True):
- rx_pipeline = [phy]
- tx_pipeline = [phy]
-
- # depacketizer / packetizer
- self.submodules.depacketizer = LiteUSBDepacketizer(clk_freq)
- self.submodules.packetizer = LiteUSBPacketizer()
- rx_pipeline += [self.depacketizer]
- tx_pipeline += [self.packetizer]
-
- if with_crc:
- # crc checker / inserter
- self.submodules.crc_rx = LiteUSBCRC32Checker()
- self.submodules.crc_tx = LiteUSBCRC32Inserter()
- rx_pipeline += [self.crc_rx]
- tx_pipeline += [self.crc_tx]
-
- # crossbar
- self.submodules.crossbar = LiteUSBCrossbar()
- rx_pipeline += [self.crossbar.master]
- tx_pipeline += [self.crossbar.master]
-
- # graph
- self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
- self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline))
+++ /dev/null
-from collections import OrderedDict
-from migen.fhdl.std import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.record import *
-from migen.genlib.misc import chooser, optree
-from migen.flow.actor import Sink, Source
-from migen.actorlib.fifo import SyncFIFO
-
-from misoclib.com.liteusb.common import *
-
-
-class CRCEngine(Module):
- """Cyclic Redundancy Check Engine
-
- Compute next CRC value from last CRC value and data input using
- an optimized asynchronous LFSR.
-
- Parameters
- ----------
- dat_width : int
- Width of the data bus.
- width : int
- Width of the CRC.
- polynom : int
- Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
-
- Attributes
- ----------
- d : in
- Data input.
- last : in
- last CRC value.
- next :
- next CRC value.
- """
- def __init__(self, dat_width, width, polynom):
- self.data = Signal(dat_width)
- self.last = Signal(width)
- self.next = Signal(width)
-
- # # #
-
- def _optimize_eq(l):
- """
- Replace even numbers of XORs in the equation
- with an equivalent XOR
- """
- d = OrderedDict()
- for e in l:
- if e in d:
- d[e] += 1
- else:
- d[e] = 1
- r = []
- for key, value in d.items():
- if value%2 != 0:
- r.append(key)
- return r
-
- # compute and optimize CRC's LFSR
- curval = [[("state", i)] for i in range(width)]
- for i in range(dat_width):
- feedback = curval.pop() + [("din", i)]
- for j in range(width-1):
- if (polynom & (1<<(j+1))):
- curval[j] += feedback
- curval[j] = _optimize_eq(curval[j])
- curval.insert(0, feedback)
-
- # implement logic
- for i in range(width):
- xors = []
- for t, n in curval[i]:
- if t == "state":
- xors += [self.last[n]]
- elif t == "din":
- xors += [self.data[n]]
- self.comb += self.next[i].eq(optree("^", xors))
-
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class CRC32(Module):
- """IEEE 802.3 CRC
-
- Implement an IEEE 802.3 CRC generator/checker.
-
- Parameters
- ----------
- dat_width : int
- Width of the data bus.
-
- Attributes
- ----------
- d : in
- Data input.
- value : out
- CRC value (used for generator).
- error : out
- CRC error (used for checker).
- """
- width = 32
- polynom = 0x04C11DB7
- init = 2**width-1
- check = 0xC704DD7B
-
- def __init__(self, dat_width):
- self.data = Signal(dat_width)
- self.value = Signal(self.width)
- self.error = Signal()
-
- # # #
-
- self.submodules.engine = CRCEngine(dat_width, self.width, self.polynom)
- reg = Signal(self.width, reset=self.init)
- self.sync += reg.eq(self.engine.next)
- self.comb += [
- self.engine.data.eq(self.data),
- self.engine.last.eq(reg),
-
- self.value.eq(~reg[::-1]),
- self.error.eq(self.engine.next != self.check)
- ]
-
-
-class CRCInserter(Module):
- """CRC Inserter
-
- Append a CRC at the end of each packet.
-
- Parameters
- ----------
- layout : layout
- Layout of the dataflow.
-
- Attributes
- ----------
- sink : in
- Packets input without CRC.
- source : out
- Packets output with CRC.
- """
- def __init__(self, crc_class, layout):
- self.sink = sink = Sink(layout)
- self.source = source = Source(layout)
- self.busy = Signal()
-
- # # #
-
- dw = flen(sink.data)
- crc = crc_class(dw)
- fsm = FSM(reset_state="IDLE")
- self.submodules += crc, fsm
-
- fsm.act("IDLE",
- crc.reset.eq(1),
- sink.ack.eq(1),
- If(sink.stb & sink.sop,
- sink.ack.eq(0),
- NextState("COPY"),
- )
- )
- fsm.act("COPY",
- crc.ce.eq(sink.stb & source.ack),
- crc.data.eq(sink.data),
- Record.connect(sink, source),
- source.eop.eq(0),
- If(sink.stb & sink.eop & source.ack,
- NextState("INSERT"),
- )
- )
- ratio = crc.width//dw
- if ratio > 1:
- cnt = Signal(max=ratio, reset=ratio-1)
- cnt_done = Signal()
- fsm.act("INSERT",
- source.stb.eq(1),
- chooser(crc.value, cnt, source.data, reverse=True),
- If(cnt_done,
- source.eop.eq(1),
- If(source.ack, NextState("IDLE"))
- )
- )
- self.comb += cnt_done.eq(cnt == 0)
- self.sync += \
- If(fsm.ongoing("IDLE"),
- cnt.eq(cnt.reset)
- ).Elif(fsm.ongoing("INSERT") & ~cnt_done,
- cnt.eq(cnt - source.ack)
- )
- else:
- fsm.act("INSERT",
- source.stb.eq(1),
- source.eop.eq(1),
- source.data.eq(crc.value),
- If(source.ack, NextState("IDLE"))
- )
- self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
-
-
-class LiteUSBCRC32Inserter(CRCInserter):
- def __init__(self):
- CRCInserter.__init__(self, CRC32, user_description(8))
-
-
-class CRCChecker(Module):
- """CRC Checker
-
- Check CRC at the end of each packet.
-
- Parameters
- ----------
- layout : layout
- Layout of the dataflow.
-
- Attributes
- ----------
- sink : in
- Packets input with CRC.
- source : out
- Packets output without CRC and "error" set to 0
- on eop when CRC OK / set to 1 when CRC KO.
- """
- def __init__(self, crc_class, layout):
- self.sink = sink = Sink(layout)
- self.source = source = Source(layout)
- self.busy = Signal()
-
- # # #
-
- dw = flen(sink.data)
- crc = crc_class(dw)
- self.submodules += crc
- ratio = crc.width//dw
-
- error = Signal()
- fifo = InsertReset(SyncFIFO(layout, ratio + 1))
- self.submodules += fifo
-
- fsm = FSM(reset_state="RESET")
- self.submodules += fsm
-
- fifo_in = Signal()
- fifo_out = Signal()
- fifo_full = Signal()
-
- self.comb += [
- fifo_full.eq(fifo.fifo.level == ratio),
- fifo_in.eq(sink.stb & (~fifo_full | fifo_out)),
- fifo_out.eq(source.stb & source.ack),
-
- Record.connect(sink, fifo.sink),
- fifo.sink.stb.eq(fifo_in),
- self.sink.ack.eq(fifo_in),
-
- source.stb.eq(sink.stb & fifo_full),
- source.sop.eq(fifo.source.sop),
- source.eop.eq(sink.eop),
- fifo.source.ack.eq(fifo_out),
- source.payload.eq(fifo.source.payload),
-
- source.error.eq(sink.error | crc.error),
- ]
-
- fsm.act("RESET",
- crc.reset.eq(1),
- fifo.reset.eq(1),
- NextState("IDLE"),
- )
- fsm.act("IDLE",
- crc.data.eq(sink.data),
- If(sink.stb & sink.sop & sink.ack,
- crc.ce.eq(1),
- NextState("COPY")
- )
- )
- fsm.act("COPY",
- crc.data.eq(sink.data),
- If(sink.stb & sink.ack,
- crc.ce.eq(1),
- If(sink.eop,
- NextState("RESET")
- )
- )
- )
- self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
-
-
-class LiteUSBCRC32Checker(CRCChecker):
- def __init__(self):
- CRCChecker.__init__(self, CRC32, user_description(8))
+++ /dev/null
-from collections import OrderedDict
-
-from misoclib.com.liteusb.common import *
-
-class LiteUSBCrossbar(Module):
- def __init__(self):
- self.users = OrderedDict()
- self.master = LiteUSBMasterPort(8)
- self.dispatch_param = "dst"
-
- def get_port(self, dst):
- port = LiteUSBUserPort(8, dst)
- if dst in self.users.keys():
- raise ValueError("Destination {0:#x} already assigned".format(dst))
- self.users[dst] = port
- return port
-
- def do_finalize(self):
- # TX arbitrate
- sinks = [port.sink for port in self.users.values()]
- self.submodules.arbiter = Arbiter(sinks, self.master.source)
-
- # RX dispatch
- sources = [port.source for port in self.users.values()]
- self.submodules.dispatcher = Dispatcher(self.master.sink,
- sources,
- one_hot=True)
- cases = {}
- cases["default"] = self.dispatcher.sel.eq(0)
- for i, (k, v) in enumerate(self.users.items()):
- cases[k] = self.dispatcher.sel.eq(2**i)
- self.comb += \
- Case(getattr(self.master.sink, self.dispatch_param), cases)
+++ /dev/null
-from misoclib.com.liteusb.common import *
-from migen.actorlib.structuring import Pack, Unpack
-from migen.genlib.misc import WaitTimer
-
-class LiteUSBPacketizer(Module):
- def __init__(self):
- self.sink = sink = Sink(user_description(8))
- self.source = source = Source(phy_description(8))
-
- # # #
-
- # Packet description
- # - preamble : 4 bytes
- # - dst : 1 byte
- # - length : 4 bytes
- # - payload
- header = [
- # preamble
- 0x5A,
- 0xA5,
- 0x5A,
- 0xA5,
- # dst
- sink.dst,
- # length
- sink.length[24:32],
- sink.length[16:24],
- sink.length[8:16],
- sink.length[0:8],
- ]
-
- header_unpack = Unpack(len(header), phy_description(8))
- self.submodules += header_unpack
-
- for i, byte in enumerate(header):
- chunk = getattr(header_unpack.sink.payload, "chunk" + str(i))
- self.comb += chunk.data.eq(byte)
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- fsm.act("IDLE",
- If(sink.stb & sink.sop,
- NextState("INSERT_HEADER")
- )
- )
-
- fsm.act("INSERT_HEADER",
- header_unpack.sink.stb.eq(1),
- source.stb.eq(1),
- source.data.eq(header_unpack.source.data),
- header_unpack.source.ack.eq(source.ack),
- If(header_unpack.sink.ack,
- NextState("COPY")
- )
- )
-
- fsm.act("COPY",
- source.stb.eq(sink.stb),
- source.data.eq(sink.data),
- sink.ack.eq(source.ack),
- If(source.ack & sink.eop,
- NextState("IDLE")
- )
- )
-
-
-class LiteUSBDepacketizer(Module):
- def __init__(self, clk_freq, timeout=10):
- self.sink = sink = Sink(phy_description(8))
- self.source = source = Source(user_description(8))
-
- # # #
-
- # Packet description
- # - preamble : 4 bytes
- # - dst : 1 byte
- # - length : 4 bytes
- # - payload
- preamble = Array(Signal(8) for i in range(4))
-
- header = [
- # dst
- source.dst,
- # length
- source.length[24:32],
- source.length[16:24],
- source.length[8:16],
- source.length[0:8],
- ]
-
- header_pack = InsertReset(Pack(phy_description(8), len(header)))
- self.submodules += header_pack
-
- for i, byte in enumerate(header):
- chunk = getattr(header_pack.source.payload, "chunk" + str(i))
- self.comb += byte.eq(chunk.data)
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- self.comb += preamble[0].eq(sink.data)
- for i in range(1, 4):
- self.sync += If(sink.stb & sink.ack,
- preamble[i].eq(preamble[i-1])
- )
- fsm.act("IDLE",
- sink.ack.eq(1),
- If((preamble[3] == 0x5A) &
- (preamble[2] == 0xA5) &
- (preamble[1] == 0x5A) &
- (preamble[0] == 0xA5) &
- sink.stb,
- NextState("RECEIVE_HEADER")
- ),
- header_pack.source.ack.eq(1),
- )
-
- self.submodules.timer = WaitTimer(clk_freq*timeout)
- self.comb += self.timer.wait.eq(~fsm.ongoing("IDLE"))
-
- fsm.act("RECEIVE_HEADER",
- header_pack.sink.stb.eq(sink.stb),
- header_pack.sink.payload.eq(sink.payload),
- If(self.timer.done,
- NextState("IDLE")
- ).Elif(header_pack.source.stb,
- NextState("COPY")
- ).Else(
- sink.ack.eq(1)
- )
- )
-
- self.comb += header_pack.reset.eq(self.timer.done)
-
- sop = Signal()
- eop = Signal()
- cnt = Signal(32)
-
- fsm.act("COPY",
- source.stb.eq(sink.stb),
- source.sop.eq(sop),
- source.eop.eq(eop),
- source.data.eq(sink.data),
- sink.ack.eq(source.ack),
- If((source.stb & source.ack & eop) | self.timer.done,
- NextState("IDLE")
- )
- )
-
- self.sync += \
- If(fsm.ongoing("IDLE"),
- cnt.eq(0)
- ).Elif(source.stb & source.ack,
- cnt.eq(cnt + 1)
- )
- self.comb += sop.eq(cnt == 0)
- self.comb += eop.eq(cnt == source.length - 1)
+++ /dev/null
-#!/usr/bin/env python3
-
-import sys
-import os
-import argparse
-import subprocess
-import struct
-import importlib
-
-from mibuild.tools import write_to_file
-from migen.util.misc import autotype
-from migen.fhdl import verilog, edif
-from migen.fhdl.structure import _Fragment
-from migen.bank.description import CSRStatus
-from mibuild import tools
-from mibuild.xilinx.common import *
-
-from misoclib.soc import cpuif
-#from misoclib.lit.liteusb.common import *
-
-
-def _import(default, name):
- return importlib.import_module(default + "." + name)
-
-
-def _get_args():
- parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
- description="""\
-LiteUSB - based on Migen.
-
-This program builds and/or loads LiteUSB components.
-One or several actions can be specified:
-
-clean delete previous build(s).
-build-rtl build verilog rtl.
-build-bitstream build-bitstream build FPGA bitstream.
-build-csr-csv save CSR map into CSV file.
-
-load-bitstream load bitstream into volatile storage.
-
-all clean, build-csr-csv, build-bitstream, load-bitstream.
-""")
-
- parser.add_argument("-t", "--target", default="simple", help="Core type to build")
- parser.add_argument("-s", "--sub-target", default="", help="variant of the Core type to build")
- parser.add_argument("-p", "--platform", default=None, help="platform to build for")
- parser.add_argument("-Ot", "--target-option", default=[], nargs=2, action="append", help="set target-specific option")
- parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option")
- parser.add_argument("-Ob", "--build-option", default=[], nargs=2, action="append", help="set build option")
- parser.add_argument("--csr_csv", default="./test/csr.csv", help="CSV file to save the CSR map into")
-
- parser.add_argument("action", nargs="+", help="specify an action")
-
- return parser.parse_args()
-
-# Note: misoclib need to be installed as a python library
-
-if __name__ == "__main__":
- args = _get_args()
-
- # create top-level Core object
- target_module = _import("targets", args.target)
- if args.sub_target:
- top_class = getattr(target_module, args.sub_target)
- else:
- top_class = target_module.default_subtarget
-
- if args.platform is None:
- if hasattr(top_class, "default_platform"):
- platform_name = top_class.default_platform
- else:
- raise ValueError("Target has no default platform, specify a platform with -p your_platform")
- else:
- platform_name = args.platform
- platform_module = _import("mibuild.platforms", platform_name)
- platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option)
- platform = platform_module.Platform(**platform_kwargs)
-
- build_name = top_class.__name__.lower() + "-" + platform_name
- top_kwargs = dict((k, autotype(v)) for k, v in args.target_option)
- soc = top_class(platform, **top_kwargs)
- soc.finalize()
- memory_regions = soc.get_memory_regions()
- csr_regions = soc.get_csr_regions()
-
- # decode actions
- action_list = ["clean", "build-csr-csv", "build-bitstream", "load-bitstream", "all"]
- actions = {k: False for k in action_list}
- for action in args.action:
- if action in actions:
- actions[action] = True
- else:
- print("Unknown action: "+action+". Valid actions are:")
- for a in action_list:
- print(" "+a)
- sys.exit(1)
-
- print("""
- __ _ __ __ _________
- / / (_) /____ / / / / __/ _ )
- / /__/ / __/ -_) /_/ /\ \/ _ |
- /____/_/\__/\__/\____/___/____/
-
-
- A small footprint and configurable USB core
- powered by Migen
-
-====== Building parameters: ======
-System Clk: {} MHz
-===============================""".format(
- soc.clk_freq/1000000))
-
- # dependencies
- if actions["all"]:
- actions["build-csr-csv"] = True
- actions["build-bitstream"] = True
- actions["load-bitstream"] = True
-
- if actions["build-bitstream"]:
- actions["build-csr-csv"] = True
- actions["build-bitstream"] = True
- actions["load-bitstream"] = True
-
- if actions["clean"]:
- subprocess.call(["rm", "-rf", "build/*"])
-
- if actions["build-csr-csv"]:
- csr_csv = cpuif.get_csr_csv(csr_regions)
- write_to_file(args.csr_csv, csr_csv)
-
- if actions["build-bitstream"]:
- build_kwargs = dict((k, autotype(v)) for k, v in args.build_option)
- vns = platform.build(soc, build_name=build_name, **build_kwargs)
- if hasattr(soc, "do_exit") and vns is not None:
- if hasattr(soc.do_exit, '__call__'):
- soc.do_exit(vns)
-
- if actions["load-bitstream"]:
- prog = platform.create_programmer()
- prog.load_bitstream("build/" + build_name + platform.bitstream_ext)
+++ /dev/null
-from migen.genlib.io import CRG
-from migen.actorlib.fifo import SyncFIFO
-
-from misoclib.soc import SoC
-
-from misoclib.com.liteusb.common import *
-from misoclib.com.liteusb.phy.ft245 import FT245PHY
-from misoclib.com.liteusb.core import LiteUSBCore
-from misoclib.com.liteusb.frontend.wishbone import LiteUSBWishboneBridge
-
-from misoclib.com.gpio import GPIOOut
-
-class LiteUSBSoC(SoC):
- csr_map = {}
- csr_map.update(SoC.csr_map)
-
- usb_map = {
- "bridge": 0
- }
-
- def __init__(self, platform):
- clk_freq = int((1/(platform.default_clk_period))*1000000000)
- SoC.__init__(self, platform, clk_freq,
- cpu_type="none",
- with_csr=True, csr_data_width=32,
- with_uart=False,
- with_identifier=True,
- with_timer=False
- )
- self.submodules.crg = CRG(platform.request(platform.default_clk_name))
-
- self.submodules.usb_phy = FT245PHY(platform.request("usb_fifo"), self.clk_freq)
- self.submodules.usb_core = LiteUSBCore(self.usb_phy, self.clk_freq, with_crc=False)
-
-
- # Wishbone Bridge
- usb_bridge_port = self.usb_core.crossbar.get_port(self.usb_map["bridge"])
- self.add_cpu_or_bridge(LiteUSBWishboneBridge(usb_bridge_port, self.clk_freq))
- self.add_wb_master(self.cpu_or_bridge.wishbone)
-
- # Leds
- leds = Cat(iter([platform.request("user_led", i) for i in range(8)]))
- self.submodules.leds = GPIOOut(leds)
-
-default_subtarget = LiteUSBSoC
+++ /dev/null
-LITEUSBDIR=../../software
-
-dll:
- cd $(LITEUSBDIR)/ftdi/windows && make all
- cp $(LITEUSBDIR)/ftdi/libftdicom.dll libftdicom.dll
-
-clean:
- rm -f libftdicom.dll
+++ /dev/null
-#!/usr/bin/env python3
-import argparse
-import importlib
-
-FTDI_INTERFACE_A = 1
-FTDI_INTERFACE_B = 2
-
-def _get_args():
- parser = argparse.ArgumentParser()
- parser.add_argument("--tag", default=0, help="USB channel tag")
- parser.add_argument("--busword", default=32, help="CSR busword")
-
- parser.add_argument("test", nargs="+", help="specify a test")
-
- return parser.parse_args()
-
-if __name__ == "__main__":
- args = _get_args()
- from misoclib.com.liteusb.software.wishbone import LiteUSBWishboneDriver
- wb = LiteUSBWishboneDriver("ft2232h", FTDI_INTERFACE_B, "asynchronous",
- tag=int(args.tag),
- busword=int(args.busword),
- addrmap="./csr.csv",
- debug=False)
-
- def _import(name):
- return importlib.import_module(name)
-
- for test in args.test:
- t = _import(test)
- t.main(wb)
+++ /dev/null
-def main(wb):
- wb.open()
- regs = wb.regs
- # # #
- for i in range(64):
- wb.regs.leds_out.write(i)
- print("sysid : 0x{:04x}".format(regs.identifier_sysid.read()))
- print("revision : 0x{:04x}".format(regs.identifier_revision.read()))
- print("frequency : {}MHz".format(int(regs.identifier_frequency.read()/1000000)))
- # # #
- wb.close()
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.flow.network import *
-from migen.actorlib import structuring, spi
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.genlib.record import Record
-
-from misoclib.mem.sdram.frontend import dma_lasmi
-from misoclib.com.liteusb.common import *
-
-
-class LiteUSBDMAWriter(Module, AutoCSR):
- def __init__(self, lasmim):
- self.sink = sink = Sink(user_description(8))
-
- # Pack data
- pack_factor = lasmim.dw//8
- pack = structuring.Pack(phy_description(8), pack_factor, reverse=True)
- cast = structuring.Cast(pack.source.payload.layout, lasmim.dw)
-
- # DMA
- writer = dma_lasmi.Writer(lasmim)
- self._reset = CSR()
- self.dma = InsertReset(spi.DMAWriteController(writer, mode=spi.MODE_SINGLE_SHOT))
- self.comb += self.dma.reset.eq(self._reset.r & self._reset.re)
-
- # Remove sop/eop/length/dst fields from payload
- self.comb += [
- pack.sink.stb.eq(sink.stb),
- pack.sink.payload.eq(sink.payload),
- sink.ack.eq(pack.sink.ack)
- ]
-
- # Graph
- g = DataFlowGraph()
- g.add_pipeline(pack, cast, self.dma)
- self.submodules += CompositeActor(g)
-
- # IRQ
- self.submodules.ev = EventManager()
- self.ev.done = EventSourcePulse()
- self.ev.finalize()
- self.comb += self.ev.done.trigger.eq(sink.stb & sink.eop)
-
- # CRC
- self._crc_failed = CSRStatus()
- self.sync += \
- If(sink.stb & sink.eop,
- self._crc_failed.status.eq(sink.error)
- )
-
-
-class LiteUSBDMAReader(Module, AutoCSR):
- def __init__(self, lasmim, tag):
- self.source = source = Source(user_description(8))
-
- reader = dma_lasmi.Reader(lasmim)
- self.dma = spi.DMAReadController(reader, mode=spi.MODE_SINGLE_SHOT)
-
- pack_factor = lasmim.dw//8
- packed_dat = structuring.pack_layout(8, pack_factor)
- cast = structuring.Cast(lasmim.dw, packed_dat)
- unpack = structuring.Unpack(pack_factor, phy_description(8), reverse=True)
-
- # Graph
- cnt = Signal(32)
- self.sync += \
- If(self.dma.generator._shoot.re,
- cnt.eq(0)
- ).Elif(source.stb & source.ack,
- cnt.eq(cnt + 1)
- )
- g = DataFlowGraph()
- g.add_pipeline(self.dma, cast, unpack)
- self.submodules += CompositeActor(g)
- self.comb += [
- source.stb.eq(unpack.source.stb),
- source.sop.eq(cnt == 0),
- source.eop.eq(cnt == (self.dma.length*pack_factor-1)),
- source.length.eq(self.dma.length*pack_factor),
- source.data.eq(unpack.source.data),
- source.dst.eq(tag),
- unpack.source.ack.eq(source.ack)
- ]
-
- # IRQ
- self.submodules.ev = EventManager()
- self.ev.done = EventSourcePulse()
- self.ev.finalize()
- self.comb += self.ev.done.trigger.eq(source.stb & source.eop)
-
-
-class LiteUSBDMA(Module, AutoCSR):
- def __init__(self, port, lasmim_dma_wr, lasmim_dma_rd):
- self.submodules.writer = LiteUSBDMAWriter(lasmim_dma_wr)
- self.submodules.reader = LiteUSBDMAReader(lasmim_dma_rd, port.tag)
- self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev)
- self.comb += [
- Record.connect(port.source, self.writer.sink),
- Record.connect(self.reader.source, port.sink),
- ]
+++ /dev/null
-from migen.fhdl.std import *
-
-from misoclib.com.liteusb.common import *
-from misoclib.com.uart import UART
-
-class LiteUSBUARTPHY:
- def __init__(self):
- self.sink = Sink([("data", 8)])
- self.source = Source([("data", 8)])
-
-class LiteUSBUART(UART):
- def __init__(self, port,
- tx_fifo_depth=16,
- rx_fifo_depth=16):
-
- phy = LiteUSBUARTPHY()
- UART.__init__(self, phy, tx_fifo_depth, rx_fifo_depth)
-
- # TX
- self.comb += [
- port.sink.stb.eq(phy.sink.stb),
- port.sink.sop.eq(1),
- port.sink.eop.eq(1),
- port.sink.length.eq(1),
- port.sink.dst.eq(port.tag),
- port.sink.data.eq(phy.sink.data),
- phy.sink.ack.eq(port.sink.ack)
- ]
-
- # RX
- self.comb += [
- phy.source.stb.eq(port.source.stb),
- phy.source.data.eq(port.source.data),
- port.source.ack.eq(phy.source.ack)
- ]
+++ /dev/null
-from migen.fhdl.std import *
-
-from misoclib.com.liteusb.common import *
-from misoclib.tools.wishbone import WishboneStreamingBridge
-
-class LiteUSBWishboneBridge(WishboneStreamingBridge):
- def __init__(self, port, clk_freq):
- WishboneStreamingBridge.__init__(self, port, clk_freq)
- self.comb += port.sink.dst.eq(port.tag)
+++ /dev/null
-import math
-
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
-from migen.fhdl.specials import *
-from migen.genlib.cdc import MultiReg
-
-from misoclib.com.liteusb.common import *
-
-
-def anti_starvation(module, timeout):
- en = Signal()
- max_time = Signal()
- if timeout:
- t = timeout - 1
- time = Signal(max=t+1)
- module.comb += max_time.eq(time == 0)
- module.sync += If(~en,
- time.eq(t)
- ).Elif(~max_time,
- time.eq(time - 1)
- )
- else:
- module.comb += max_time.eq(0)
- return en, max_time
-
-
-class FT245PHYSynchronous(Module):
- def __init__(self, pads, clk_freq,
- fifo_depth=32,
- read_time=128,
- write_time=128):
- dw = flen(pads.data)
-
- # read fifo (FTDI --> SoC)
- read_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth),
- {"write": "usb", "read": "sys"})
- read_buffer = RenameClockDomains(SyncFIFO(phy_description(8), 4),
- {"sys": "usb"})
- self.comb += read_buffer.source.connect(read_fifo.sink)
-
- # write fifo (SoC --> FTDI)
- write_fifo = RenameClockDomains(AsyncFIFO(phy_description(8), fifo_depth),
- {"write": "sys", "read": "usb"})
-
- self.submodules += read_fifo, read_buffer, write_fifo
-
- # sink / source interfaces
- self.sink = write_fifo.sink
- self.source = read_fifo.source
-
- # read / write arbitration
- wants_write = Signal()
- wants_read = Signal()
-
- txe_n = Signal()
- rxf_n = Signal()
-
- self.comb += [
- txe_n.eq(pads.txe_n),
- rxf_n.eq(pads.rxf_n),
- wants_write.eq(~txe_n & write_fifo.source.stb),
- wants_read.eq(~rxf_n & read_fifo.sink.ack),
- ]
-
- read_time_en, max_read_time = anti_starvation(self, read_time)
- write_time_en, max_write_time = anti_starvation(self, write_time)
-
- data_w_accepted = Signal(reset=1)
-
- fsm = FSM(reset_state="READ")
- self.submodules += RenameClockDomains(fsm, {"sys": "usb"})
-
- fsm.act("READ",
- read_time_en.eq(1),
- If(wants_write,
- If(~wants_read | max_read_time,
- NextState("RTW")
- )
- )
- )
- fsm.act("RTW",
- NextState("WRITE")
- )
- fsm.act("WRITE",
- write_time_en.eq(1),
- If(wants_read,
- If(~wants_write | max_write_time,
- NextState("WTR")
- )
- ),
- write_fifo.source.ack.eq(wants_write & data_w_accepted)
- )
- fsm.act("WTR",
- NextState("READ")
- )
-
- # databus tristate
- data_w = Signal(dw)
- data_r = Signal(dw)
- data_oe = Signal()
- self.specials += Tristate(pads.data, data_w, data_oe, data_r)
-
- # read / write actions
- pads.oe_n.reset = 1
- pads.rd_n.reset = 1
- pads.wr_n.reset = 1
-
- self.sync.usb += [
- If(fsm.ongoing("READ"),
- data_oe.eq(0),
-
- pads.oe_n.eq(0),
- pads.rd_n.eq(~wants_read),
- pads.wr_n.eq(1)
-
- ).Elif(fsm.ongoing("WRITE"),
- data_oe.eq(1),
-
- pads.oe_n.eq(1),
- pads.rd_n.eq(1),
- pads.wr_n.eq(~wants_write),
-
- data_w_accepted.eq(~txe_n)
-
- ).Else(
- data_oe.eq(1),
-
- pads.oe_n.eq(~fsm.ongoing("WTR")),
- pads.rd_n.eq(1),
- pads.wr_n.eq(1)
- ),
- read_buffer.sink.stb.eq(~pads.rd_n & ~rxf_n),
- read_buffer.sink.data.eq(data_r),
- If(~txe_n & data_w_accepted,
- data_w.eq(write_fifo.source.data)
- )
- ]
-
-
-class FT245PHYAsynchronous(Module):
- def __init__(self, pads, clk_freq,
- fifo_depth=32,
- read_time=128,
- write_time=128):
- dw = flen(pads.data)
- self.clk_freq = clk_freq
-
- # timings
- tRD = self.ns(30) # RD# active pulse width (t4)
- tRDDataSetup = self.ns(14) # RD# to DATA (t3)
- tWRDataSetup = self.ns(5) # DATA to WR# active setup time (t8)
- tWR = self.ns(30) # WR# active pulse width (t10)
- tMultiReg = 2
-
- # read fifo (FTDI --> SoC)
- read_fifo = SyncFIFO(phy_description(8), fifo_depth)
-
- # write fifo (SoC --> FTDI)
- write_fifo = SyncFIFO(phy_description(8), fifo_depth)
-
- self.submodules += read_fifo, write_fifo
-
- # sink / source interfaces
- self.sink = write_fifo.sink
- self.source = read_fifo.source
-
- # read / write arbitration
- wants_write = Signal()
- wants_read = Signal()
-
- txe_n = Signal()
- rxf_n = Signal()
-
- self.specials += [
- MultiReg(pads.txe_n, txe_n),
- MultiReg(pads.rxf_n, rxf_n)
- ]
-
- self.comb += [
- wants_write.eq(~txe_n & write_fifo.source.stb),
- wants_read.eq(~rxf_n & read_fifo.sink.ack),
- ]
-
- read_time_en, max_read_time = anti_starvation(self, read_time)
- write_time_en, max_write_time = anti_starvation(self, write_time)
-
- fsm = FSM(reset_state="READ")
- self.submodules += fsm
-
- read_done = Signal()
- write_done = Signal()
- commuting = Signal()
-
- fsm.act("READ",
- read_time_en.eq(1),
- If(wants_write & read_done,
- If(~wants_read | max_read_time,
- commuting.eq(1),
- NextState("RTW")
- )
- )
- )
- fsm.act("RTW",
- NextState("WRITE")
- )
- fsm.act("WRITE",
- write_time_en.eq(1),
- If(wants_read & write_done,
- If(~wants_write | max_write_time,
- commuting.eq(1),
- NextState("WTR")
- )
- )
- )
- fsm.act("WTR",
- NextState("READ")
- )
-
- # databus tristate
- data_w = Signal(dw)
- data_r_async = Signal(dw)
- data_r = Signal(dw)
- data_oe = Signal()
- self.specials += [
- Tristate(pads.data, data_w, data_oe, data_r_async),
- MultiReg(data_r_async, data_r)
- ]
-
-
- # read actions
- pads.rd_n.reset = 1
-
- read_fsm = FSM(reset_state="IDLE")
- read_counter = Counter(8)
- self.submodules += read_fsm, read_counter
-
- read_fsm.act("IDLE",
- read_done.eq(1),
- read_counter.reset.eq(1),
- If(fsm.ongoing("READ") & wants_read,
- If(~commuting,
- NextState("PULSE_RD_N")
- )
- )
- )
- read_fsm.act("PULSE_RD_N",
- pads.rd_n.eq(0),
- read_counter.ce.eq(1),
- If(read_counter.value == max((tRD-1), (tRDDataSetup + tMultiReg -1)),
- NextState("ACQUIRE_DATA")
- )
- )
- read_fsm.act("ACQUIRE_DATA",
- read_fifo.sink.stb.eq(1),
- read_fifo.sink.data.eq(data_r),
- NextState("WAIT_RXF_N")
- )
- read_fsm.act("WAIT_RXF_N",
- If(rxf_n,
- NextState("IDLE")
- )
- )
-
- # write actions
- pads.wr_n.reset = 1
-
- write_fsm = FSM(reset_state="IDLE")
- write_counter = Counter(8)
- self.submodules += write_fsm, write_counter
-
- write_fsm.act("IDLE",
- write_done.eq(1),
- write_counter.reset.eq(1),
- If(fsm.ongoing("WRITE") & wants_write,
- If(~commuting,
- NextState("SET_DATA")
- )
- )
- )
- write_fsm.act("SET_DATA",
- data_oe.eq(1),
- data_w.eq(write_fifo.source.data),
- write_counter.ce.eq(1),
- If(write_counter.value == (tWRDataSetup-1),
- write_counter.reset.eq(1),
- NextState("PULSE_WR_N")
- )
- )
- write_fsm.act("PULSE_WR_N",
- data_oe.eq(1),
- data_w.eq(write_fifo.source.data),
- pads.wr_n.eq(0),
- write_counter.ce.eq(1),
- If(write_counter.value == (tWR-1),
- NextState("WAIT_TXE_N")
- )
- )
- write_fsm.act("WAIT_TXE_N",
- If(txe_n,
- write_fifo.source.ack.eq(1),
- NextState("IDLE")
- )
- )
-
- def ns(self, t, margin=True):
- clk_period_ns = 1000000000/self.clk_freq
- if margin:
- t += clk_period_ns/2
- return math.ceil(t/clk_period_ns)
-
-
-def FT245PHY(pads, *args, **kwargs):
- # autodetect PHY
- if hasattr(pads, "oe_n"):
- return FT245PHYSynchronous(pads, *args, **kwargs)
- else:
- return FT245PHYAsynchronous(pads, *args, **kwargs)
+++ /dev/null
-[> Libftdicom
-------------------------------
-
-[> Windows build
---------------------------
-1. Install MinGW32
-2. Download libusbx windows binaries (tested version: libusbx-1.0.17-win)
-3. Put libusb-1.0.dll.a in mingw lib directory
-4. Download Zadig and use WinUSB driver for Interface A and Interface B
-5. make all in libftdicom/win
-
-[> Linux build
---------------------------
-1. make all in libftdicom/linux
\ No newline at end of file
+++ /dev/null
-import platform
-import ctypes
-import os
-import time
-import queue
-import threading
-
-if platform.system() == "Windows":
- libftdicom = ctypes.cdll.LoadLibrary("./libftdicom.dll")
-else:
- libftdicom = ctypes.cdll.LoadLibrary("./libftdicom.so")
-
-
-class FTDI_Device(ctypes.Structure):
- _fields_ = [
- ('_1', ctypes.c_void_p),
- ('_2', ctypes.c_void_p),
- ]
-
-pFTDI_Device = ctypes.POINTER(FTDI_Device)
-
-# FTDIDevice_Open
-FTDIDevice_Open = libftdicom.FTDIDevice_Open
-FTDIDevice_Open.argtypes = [
- pFTDI_Device, # Dev
- ctypes.c_int # Interface
- ]
-FTDIDevice_Open.restype = ctypes.c_int
-
-# FTDIDevice_Close
-FTDIDevice_Close = libftdicom.FTDIDevice_Close
-FTDIDevice_Close.argtypes = [pFTDI_Device]
-
-FTDIDevice_SetMode = libftdicom.FTDIDevice_SetMode
-FTDIDevice_SetMode.argtypes = [
- pFTDI_Device, # Dev
- ctypes.c_int, # Interface
- ctypes.c_int, # Mode
- ctypes.c_char, # PinDirection
- ctypes.c_char, # baudrate
- ]
-
-
-FTDIDevice_Write = libftdicom.FTDIDevice_Write
-FTDIDevice_Write.argtypes = [
- pFTDI_Device, # Dev
- ctypes.c_int, # Interface
- ctypes.c_char_p, # Buf
- ctypes.c_size_t, # N
- ctypes.c_bool, # async
- ]
-FTDIDevice_Write.restype = ctypes.c_int
-
-p_cb_StreamCallback = ctypes.CFUNCTYPE(
- ctypes.c_int, # retval
- ctypes.POINTER(ctypes.c_uint8), # buf
- ctypes.c_int, # length
- ctypes.c_void_p, # progress
- ctypes.c_void_p) # userdata
-
-FTDIDevice_ReadStream = libftdicom.FTDIDevice_ReadStream
-FTDIDevice_ReadStream.argtypes = [
- pFTDI_Device, # dev
- ctypes.c_int, # interface
- p_cb_StreamCallback, # callback
- ctypes.c_void_p, # userdata
- ctypes.c_int, # packetsPerTransfer
- ctypes.c_int, # numTransfers
- ]
-FTDIDevice_ReadStream.restype = ctypes.c_int
-
-FTDI_INTERFACE_A = 1
-FTDI_INTERFACE_B = 2
-
-FTDI_BITMODE_SYNC_FIFO = (1 << 6)
-
-
-class FTDIDevice:
- def __init__(self, interface, mode):
- self.__is_open = False
- self._dev = FTDI_Device()
- self.interface = interface
- self.mode = mode
-
- def __del__(self):
- if self.__is_open:
- self.__is_open = False
- FTDIDevice_Close(self._dev)
-
- def open(self):
- err = FTDIDevice_Open(self._dev, self.interface)
- if err:
- return err
- else:
- self.__is_open = True
-
- if self.mode == "synchronous":
- err = FTDIDevice_SetMode(self._dev, interface, FTDI_BITMODE_SYNC_FIFO, 0xFF, 0)
-
- return err
-
- def write(self, intf, buf, async=False):
- if not isinstance(buf, bytes):
- raise TypeError("buf must be bytes")
-
- return FTDIDevice_Write(self._dev, intf, buf, len(buf), async)
-
- def read(self, intf, n):
- buf = []
-
- def callback(b, prog):
- buf.extend(b)
- return int(len(buf) >= n)
-
- self.read_async(intf, callback, 4, 4)
-
- return buf
-
- def read_async(self, intf, callback, packetsPerTransfer, numTransfers):
- def callback_wrapper(buf, ll, prog, user):
- if ll:
- b = ctypes.string_at(buf, ll)
- else:
- b = b''
- return callback(b, prog)
-
- cb = p_cb_StreamCallback(callback_wrapper)
-
- return FTDIDevice_ReadStream(self._dev, intf, cb,
- None, packetsPerTransfer, numTransfers)
-
-
-class ProtocolError(Exception):
- pass
-
-
-class TimeoutError(Exception):
- pass
-
-
-INCOMPLETE = -1
-UNMATCHED = 0
-class BaseService:
- def match_identifier(self, byt):
- r = True
- r = r and (byt[0] == 0x5A)
- r = r and (byt[1] == 0xA5)
- r = r and (byt[2] == 0x5A)
- r = r and (byt[3] == 0xA5)
- r = r and (byt[4] == self.tag)
- return r
-
- def get_needed_size_for_identifier(self):
- return self.NEEDED_FOR_SIZE
-
- def present_bytes(self, b):
- if len(b) < self.get_needed_size_for_identifier():
- return INCOMPLETE
-
- if not self.match_identifier(b):
- return UNMATCHED
-
- size = self.get_packet_size(b)
-
- if len(b) < size:
- return INCOMPLETE
-
- self.consume(b[:size])
-
- return size
-
-
-class UART:
- class __UARTService(BaseService):
- NEEDED_FOR_SIZE = 9
-
- def __init__(self, tag):
- self.tag = tag
- self.q = queue.Queue()
-
- def get_packet_size(self, buf):
- payload_size = buf[5] << 24
- payload_size |= buf[6] << 16
- payload_size |= buf[7] << 8
- payload_size |= buf[8] << 0
- return 9 + payload_size
-
- def consume(self, buf):
- for value in buf[9:]:
- self.q.put(value)
-
- def __init__(self, tag):
- self.tag = tag
- self.service = UART.__UARTService(self.tag)
-
- def do_read(self, timeout=None):
- try:
- resp = self.service.q.get(True, timeout)
- except queue.Empty:
- return -1
- return resp
-
- def do_write(self, data):
- if isinstance(data, int):
- data = [data]
- msg = [0x5A, 0xA5, 0x5A, 0xA5]
- msg.append(self.tag)
- length = len(data)
- msg.append((length >> 24) & 0xff)
- msg.append((length >> 16) & 0xff)
- msg.append((length >> 8) & 0xff)
- msg.append((length >> 0) & 0xff)
- for value in data:
- msg.append(value&0xff)
- self.service.write(bytes(msg))
-
-
-class DMA:
- class __DMAService(BaseService):
- NEEDED_FOR_SIZE = 9
-
- def __init__(self, tag):
- self.tag = tag
- self.q = queue.Queue()
-
- def get_packet_size(self, buf):
- payload_size = buf[5] << 24
- payload_size |= buf[6] << 16
- payload_size |= buf[7] << 8
- payload_size |= buf[8] << 0
- return 9 + payload_size
-
- def consume(self, buf):
- self.q.put(buf[9:])
-
- def __init__(self, tag):
- self.tag = tag
- self.service = DMA.__DMAService(self.tag)
-
- def do_read(self, timeout=None):
- try:
- resp = list(self.service.q.get(True, timeout))
- except queue.Empty:
- raise TimeoutError("DMA read timed out")
- return resp
-
- def do_write(self, data):
- length = len(data)
- msg = [0x5A, 0xA5, 0x5A, 0xA5, self.tag,
- (length & 0xff000000) >> 24,
- (length & 0x00ff0000) >> 16,
- (length & 0x0000ff00) >> 8,
- (length & 0x000000ff) >> 0]
- msg += data
- self.service.write(bytes(msg))
-
-
-class FTDIComDevice:
- def __init__(self, interface, mode, uart_tag=0, dma_tag=1, verbose=False):
- self.__is_open = False
-
- self.interface = interface
- self.mode = mode
-
- self.dev = FTDIDevice(interface, mode)
- self.verbose = verbose
-
- self.uart = UART(uart_tag)
- self.dma = DMA(dma_tag)
-
- self.__services = [self.uart.service, self.dma.service]
-
- # Inject a write function into the services
- for service in self.__services:
- def write(msg):
- if self.verbose:
- print("< %s" % " ".join("%02x" % i for i in msg))
-
- self.dev.write(self.interface, msg, async=False)
-
- service.write = write
-
- def __comms(self):
- self.__buf = b""
-
- def callback(b, prog):
- try:
- if self.verbose and b:
- print("> %s" % " ".join("%02x" % i for i in b))
-
- self.__buf += b
-
- incomplete = False
-
- while self.__buf and not incomplete:
- for service in self.__services:
- code = service.present_bytes(self.__buf)
- if code == INCOMPLETE:
- incomplete = True
- break
- elif code:
- self.__buf = self.__buf[code:]
- break
- else:
- self.__buf = self.__buf[1:]
-
- return int(self.__comm_term)
- except Exception as e:
- self.__comm_term = True
- self.__comm_exc = e
- return 1
-
- while not self.__comm_term:
- self.dev.read_async(self.interface, callback, 8, 16)
-
- if self.__comm_exc:
- raise self.__comm_exc
-
- def __del__(self):
- if self.__is_open:
- self.close()
-
- def open(self):
- if self.__is_open:
- raise ValueError("FTDICOMDevice doubly opened")
-
- stat = self.dev.open()
- if stat:
- print("USB: Error opening device\n")
- return stat
-
- self.commthread = threading.Thread(target=self.__comms, daemon=True)
- self.__comm_term = False
- self.__comm_exc = None
-
- self.commthread.start()
-
- self.__comm_term = False
- self.__is_open = True
-
- def close(self):
- if not self.__is_open:
- raise ValueError("FTDICOMDevice doubly closed")
-
- self.__comm_term = True
- self.commthread.join()
-
- self.__is_open = False
-
- def uartflush(self, timeout=0.25):
- while (self.uartread(timeout) != -1):
- pass
-
- def uartread(self, timeout=None):
- return self.uart.do_read(timeout)
-
- def uartwrite(self, data):
- return self.uart.do_write(data)
-
- def dmaread(self):
- return self.dma.do_read()
-
- def dmawrite(self, data):
- return self.dma.do_write(data)
+++ /dev/null
-import platform
-import os
-import sys
-import time
-import threading
-
-# XXX FTDI Communication POC
-
-sys.path.append("../")
-from ftdi import FTDIComDevice, FTDI_INTERFACE_B
-
-def uart_console(ftdi_com):
- def read():
- while True:
- print(chr(ftdi_com.uartread()), end="")
-
- readthread = threading.Thread(target=read, daemon=True)
- readthread.start()
-
- def write():
- while True:
- for e in input():
- c = ord(e)
- ftdi_com.uartwrite(c)
- ftdi_com.uartwrite(ord("\n"))
-
-
- writethread = threading.Thread(target=write, daemon=True)
- writethread.start()
-
-
-def uart_virtual(ftdi_com):
- import pty, serial
- master, slave = pty.openpty()
- s_name = os.ttyname(slave)
- ser = serial.Serial(s_name)
-
- def read():
- while True:
- s = ftdi_com.uartread()
- s = bytes(chr(s).encode('utf-8'))
- os.write(master, s)
-
- readthread = threading.Thread(target=read, daemon=True)
- readthread.start()
-
- def write():
- while True:
- for c in list(os.read(master, 100)):
- ftdi_com.uartwrite(c)
-
- writethread = threading.Thread(target=write, daemon=True)
- writethread.start()
-
- return s_name
-
-
-ftdi_map = {
- "uart": 0,
- "dma": 1
-}
-ftdi_com = FTDIComDevice(FTDI_INTERFACE_B,
- mode="asynchronous",
- uart_tag=ftdi_map["uart"],
- dma_tag=ftdi_map["dma"],
- verbose=False)
-ftdi_com.open()
-# test DMA
-for i in range(256):
- ftdi_com.dmawrite([i])
- print("%02x" %(ftdi_com.dmaread()[0]), end="")
- sys.stdout.flush()
-print("")
-# test UART
-if platform.system() == "Windows":
- uart_console(ftdi_com) # redirect uart to console since pty does not exist on Windows platforms
-else:
- s_name = uart_virtual(ftdi_com)
- print(s_name)
-while True:
- time.sleep(1)
+++ /dev/null
-/*
- * fastftdi.c - A minimal FTDI FT2232H interface for which supports bit-bang
- * mode, but focuses on very high-performance support for
- * synchronous FIFO mode. Requires libusb-1.0
- *
- * Copyright (C) 2009 Micah Elizabeth Scott
- * Copyright (C) 2015 Florent Kermarrec
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include "fastftdi.h"
-
-#if defined _WIN32 || defined _WIN64
- #include <time.h>
- #include <sys/timeb.h>
- int gettimeofday (struct timeval *tp, void *tz)
- {
- struct _timeb timebuffer;
- _ftime (&timebuffer);
- tp->tv_sec = timebuffer.time;
- tp->tv_usec = timebuffer.millitm * 1000;
- return 0;
- }
-#endif
-
-typedef struct {
- FTDIStreamCallback *callback;
- void *userdata;
- int result;
- FTDIProgressInfo progress;
-} FTDIStreamState;
-
-static int
-DeviceInit(FTDIDevice *dev, FTDIInterface interface)
-{
- int err;
-
- if (libusb_kernel_driver_active(dev->handle, (interface-1)) == 1) {
- if ((err = libusb_detach_kernel_driver(dev->handle, (interface-1)))) {
- perror("Error detaching kernel driver");
- return err;
- }
- }
-
- if ((err = libusb_set_configuration(dev->handle, 1))) {
- perror("Error setting configuration");
- return err;
- }
-
- if ((err = libusb_claim_interface(dev->handle, (interface-1)))) {
- perror("Error claiming interface");
- return err;
- }
-
- return 0;
-}
-
-
-int
-FTDIDevice_Open(FTDIDevice *dev, FTDIInterface interface)
-{
- int err;
-
- memset(dev, 0, sizeof *dev);
-
- if ((err = libusb_init(&dev->libusb))) {
- return err;
- }
-
- libusb_set_debug(dev->libusb, 0);
-
-
- if (!dev->handle) {
- dev->handle = libusb_open_device_with_vid_pid(dev->libusb,
- FTDI_VENDOR,
- FTDI_PRODUCT_FT2232H);
- }
-
- if (!dev->handle) {
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return DeviceInit(dev, interface);
-}
-
-
-void
-FTDIDevice_Close(FTDIDevice *dev)
-{
- libusb_close(dev->handle);
- libusb_exit(dev->libusb);
-}
-
-
-int
-FTDIDevice_Reset(FTDIDevice *dev, FTDIInterface interface)
-{
- int err;
-
- err = libusb_reset_device(dev->handle);
- if (err)
- return err;
-
- return DeviceInit(dev, interface);
-}
-
-
-int
-FTDIDevice_SetMode(FTDIDevice *dev, FTDIInterface interface,
- FTDIBitmode mode, uint8_t pinDirections,
- int baudRate)
-{
- int err;
-
- err = libusb_control_transfer(dev->handle,
- LIBUSB_REQUEST_TYPE_VENDOR
- | LIBUSB_RECIPIENT_DEVICE
- | LIBUSB_ENDPOINT_OUT,
- FTDI_SET_BITMODE_REQUEST,
- pinDirections | (mode << 8),
- interface,
- NULL, 0,
- FTDI_COMMAND_TIMEOUT);
- if (err)
- return err;
-
- if (baudRate) {
- int divisor;
-
- if (mode == FTDI_BITMODE_BITBANG)
- baudRate <<= 2;
-
- divisor = 240000000 / baudRate;
- if (divisor < 1 || divisor > 0xFFFF) {
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- err = libusb_control_transfer(dev->handle,
- LIBUSB_REQUEST_TYPE_VENDOR
- | LIBUSB_RECIPIENT_DEVICE
- | LIBUSB_ENDPOINT_OUT,
- FTDI_SET_BAUD_REQUEST,
- divisor,
- interface,
- NULL, 0,
- FTDI_COMMAND_TIMEOUT);
- if (err)
- return err;
- }
-
- return err;
-}
-
-
-/*
- * Internal callback for cleaning up async writes.
- */
-
-static void
-WriteAsyncCallback(struct libusb_transfer *transfer)
-{
- free(transfer->buffer);
- libusb_free_transfer(transfer);
-}
-
-
-/*
- * Write to an FTDI interface, either synchronously or asynchronously.
- * Async writes have no completion callback, they finish 'eventually'.
- */
-
-int
-FTDIDevice_Write(FTDIDevice *dev, FTDIInterface interface,
- uint8_t *data, size_t length, bool async)
-{
- int err;
-
- if (async) {
- struct libusb_transfer *transfer = libusb_alloc_transfer(0);
-
- if (!transfer) {
- return LIBUSB_ERROR_NO_MEM;
- }
-
- libusb_fill_bulk_transfer(transfer, dev->handle, FTDI_EP_OUT(interface),
- malloc(length), length, (libusb_transfer_cb_fn) WriteAsyncCallback, 0, 0);
-
- if (!transfer->buffer) {
- libusb_free_transfer(transfer);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- memcpy(transfer->buffer, data, length);
- err = libusb_submit_transfer(transfer);
-
- } else {
- int transferred;
- err = libusb_bulk_transfer(dev->handle, FTDI_EP_OUT(interface),
- data, length, &transferred,
- FTDI_COMMAND_TIMEOUT);
- }
-
- if (err < 0)
- return err;
- else
- return 0;
-}
-
-
-int
-FTDIDevice_WriteByteSync(FTDIDevice *dev, FTDIInterface interface, uint8_t byte)
-{
- return FTDIDevice_Write(dev, interface, &byte, sizeof byte, false);
-}
-
-
-int
-FTDIDevice_ReadByteSync(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte)
-{
- /*
- * This is a simplified synchronous read, intended for bit-banging mode.
- * Ignores the modem/buffer status bytes, returns just the data.
- *
- */
-
- uint8_t packet[3];
- int transferred, err;
-
- err = libusb_bulk_transfer(dev->handle, FTDI_EP_IN(interface),
- packet, sizeof packet, &transferred,
- FTDI_COMMAND_TIMEOUT);
- if (err < 0) {
- return err;
- }
- if (transferred != sizeof packet) {
- return -1;
- }
-
- if (byte) {
- *byte = packet[sizeof packet - 1];
- }
-
- return 0;
-}
-
-
-/*
- * Internal callback for one transfer's worth of stream data.
- * Split it into packets and invoke the callbacks.
- */
-
-static void
-ReadStreamCallback(struct libusb_transfer *transfer)
-{
- FTDIStreamState *state = transfer->user_data;
-
- if (state->result == 0) {
- if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
-
- int i;
- uint8_t *ptr = transfer->buffer;
- int length = transfer->actual_length;
- int numPackets = (length + FTDI_PACKET_SIZE - 1) >> FTDI_LOG_PACKET_SIZE;
-
- for (i = 0; i < numPackets; i++) {
- int payloadLen;
- int packetLen = length;
-
- if (packetLen > FTDI_PACKET_SIZE)
- packetLen = FTDI_PACKET_SIZE;
-
- payloadLen = packetLen - FTDI_HEADER_SIZE;
- state->progress.current.totalBytes += payloadLen;
-
- state->result = state->callback(ptr + FTDI_HEADER_SIZE, payloadLen,
- NULL, state->userdata);
- if (state->result)
- break;
-
- ptr += packetLen;
- length -= packetLen;
- }
-
- } else {
- state->result = LIBUSB_ERROR_IO;
- }
- }
-
- if (state->result == 0) {
- transfer->status = -1;
- state->result = libusb_submit_transfer(transfer);
- }
-}
-
-
-static double
-TimevalDiff(const struct timeval *a, const struct timeval *b)
-{
- return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
-}
-
-
-/*
- * Use asynchronous transfers in libusb-1.0 for high-performance
- * streaming of data from a device interface back to the PC. This
- * function continuously transfers data until either an error occurs
- * or the callback returns a nonzero value. This function returns
- * a libusb error code or the callback's return value.
- *
- * For every contiguous block of received data, the callback will
- * be invoked.
- */
-
-int
-FTDIDevice_ReadStream(FTDIDevice *dev, FTDIInterface interface,
- FTDIStreamCallback *callback, void *userdata,
- int packetsPerTransfer, int numTransfers)
-{
- struct libusb_transfer **transfers;
- FTDIStreamState state = { callback, userdata };
- int bufferSize = packetsPerTransfer * FTDI_PACKET_SIZE;
- int xferIndex;
- int err = 0;
-
- /*
- * Set up all transfers
- */
-
- transfers = calloc(numTransfers, sizeof *transfers);
- if (!transfers) {
- err = LIBUSB_ERROR_NO_MEM;
- goto cleanup;
- }
-
- for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) {
- struct libusb_transfer *transfer;
-
- transfer = libusb_alloc_transfer(0);
- transfers[xferIndex] = transfer;
- if (!transfer) {
- err = LIBUSB_ERROR_NO_MEM;
- goto cleanup;
- }
-
- libusb_fill_bulk_transfer(transfer, dev->handle, FTDI_EP_IN(interface),
- malloc(bufferSize), bufferSize, (libusb_transfer_cb_fn) ReadStreamCallback,
- &state, 0);
-
- if (!transfer->buffer) {
- err = LIBUSB_ERROR_NO_MEM;
- goto cleanup;
- }
-
- transfer->status = -1;
- err = libusb_submit_transfer(transfer);
- if (err)
- goto cleanup;
- }
-
- /*
- * Run the transfers, and periodically assess progress.
- */
-
- gettimeofday(&state.progress.first.time, NULL);
-
- do {
- FTDIProgressInfo *progress = &state.progress;
- const double progressInterval = 0.1;
- struct timeval timeout = { 0, 10000 };
- struct timeval now;
-
- int err = libusb_handle_events_timeout(dev->libusb, &timeout);
- if (!state.result) {
- state.result = err;
- }
-
- // If enough time has elapsed, update the progress
- gettimeofday(&now, NULL);
- if (TimevalDiff(&now, &progress->current.time) >= progressInterval) {
-
- progress->current.time = now;
-
- if (progress->prev.totalBytes) {
- // We have enough information to calculate rates
-
- double currentTime;
-
- progress->totalTime = TimevalDiff(&progress->current.time,
- &progress->first.time);
- currentTime = TimevalDiff(&progress->current.time,
- &progress->prev.time);
-
- progress->totalRate = progress->current.totalBytes / progress->totalTime;
- progress->currentRate = (progress->current.totalBytes -
- progress->prev.totalBytes) / currentTime;
- }
-
- state.result = state.callback(NULL, 0, progress, state.userdata);
- progress->prev = progress->current;
- }
- } while (!state.result);
-
- /*
- * Cancel any outstanding transfers, and free memory.
- */
-
- cleanup:
- if (transfers) {
- bool done_cleanup = false;
- while (!done_cleanup)
- {
- done_cleanup = true;
-
- for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) {
- struct libusb_transfer *transfer = transfers[xferIndex];
-
- if (transfer) {
- // If a transfer is in progress, cancel it
- if (transfer->status == -1) {
- libusb_cancel_transfer(transfer);
-
- // And we need to wait until we get a clean sweep
- done_cleanup = false;
-
- // If a transfer is complete or cancelled, nuke it
- } else if (transfer->status == 0 ||
- transfer->status == LIBUSB_TRANSFER_CANCELLED) {
- free(transfer->buffer);
- libusb_free_transfer(transfer);
- transfers[xferIndex] = NULL;
- }
- }
- }
-
- // pump events
- struct timeval timeout = { 0, 10000 };
- libusb_handle_events_timeout(dev->libusb, &timeout);
- }
- free(transfers);
- }
-
- if (err)
- return err;
- else
- return state.result;
-}
-
-/* MPSSE mode support -- see
- * http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
- */
-
-int
-FTDIDevice_MPSSE_Enable(FTDIDevice *dev, FTDIInterface interface)
-{
- int err;
-
- /* Reset interface */
-
- err = FTDIDevice_SetMode(dev, interface, FTDI_BITMODE_RESET, 0, 0);
- if (err)
- return err;
-
- /* Enable MPSSE mode */
-
- err = FTDIDevice_SetMode(dev, interface, FTDI_BITMODE_MPSSE,
- FTDI_SET_BITMODE_REQUEST, 0);
-
- return err;
-}
-
-int
-FTDIDevice_MPSSE_SetDivisor(FTDIDevice *dev, FTDIInterface interface,
- uint8_t ValueL, uint8_t ValueH)
-{
- uint8_t buf[3] = {FTDI_MPSSE_SETDIVISOR, 0, 0};
-
- buf[1] = ValueL;
- buf[2] = ValueH;
-
- return FTDIDevice_Write(dev, interface, buf, 3, false);
-}
-
-int
-FTDIDevice_MPSSE_SetLowByte(FTDIDevice *dev, FTDIInterface interface, uint8_t data, uint8_t dir)
-{
- uint8_t buf[3] = {FTDI_MPSSE_SETLOW, 0, 0};
-
- buf[1] = data;
- buf[2] = dir;
-
- return FTDIDevice_Write(dev, interface, buf, 3, false);
-}
-
-int
-FTDIDevice_MPSSE_SetHighByte(FTDIDevice *dev, FTDIInterface interface, uint8_t data, uint8_t dir)
-{
- uint8_t buf[3] = {FTDI_MPSSE_SETHIGH, 0, 0};
-
- buf[1] = data;
- buf[2] = dir;
-
- return FTDIDevice_Write(dev, interface, buf, 3, false);
-}
-
-int
-FTDIDevice_MPSSE_GetLowByte(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte)
-{
- int err;
-
- err = FTDIDevice_WriteByteSync(dev, interface, FTDI_MPSSE_GETLOW);
- if (err)
- return err;
-
- return FTDIDevice_ReadByteSync(dev, interface, byte);
-}
-
-int
-FTDIDevice_MPSSE_GetHighByte(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte)
-{
- int err;
-
- err = FTDIDevice_WriteByteSync(dev, interface, FTDI_MPSSE_GETHIGH);
- if (err)
- return err;
-
- return FTDIDevice_ReadByteSync(dev, interface, byte);
-}
+++ /dev/null
-/*
- * fastftdi.h - A minimal FTDI FT232H interface for Linux which supports
- * bit-bang mode, but focuses on very high-performance support
- * for synchronous FIFO mode.
- *
- * Copyright (C) 2009 Micah Elizabeth Scott
- * Copyright (C) 2015 Florent Kermarrec
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef __FASTFTDI_H
-#define __FASTFTDI_H
-
-#include <libusb.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef enum {
- FTDI_BITMODE_RESET = 0,
- FTDI_BITMODE_BITBANG = 1 << 0,
- FTDI_BITMODE_MPSSE = 1 << 1,
- FTDI_BITMODE_SYNC_BITBANG = 1 << 2,
- FTDI_BITMODE_MCU = 1 << 3,
- FTDI_BITMODE_OPTO = 1 << 4,
- FTDI_BITMODE_CBUS = 1 << 5,
- FTDI_BITMODE_SYNC_FIFO = 1 << 6,
-} FTDIBitmode;
-
-typedef enum {
- FTDI_MPSSE_SETLOW = 0x80,
- FTDI_MPSSE_SETHIGH = 0x82,
- FTDI_MPSSE_GETLOW = 0x81,
- FTDI_MPSSE_GETHIGH = 0x83,
- FTDI_MPSSE_SETDIVISOR = 0x86,
-} FTDIMPSSEOpcode;
-
-typedef enum {
- FTDI_INTERFACE_A = 1,
- FTDI_INTERFACE_B = 2,
-} FTDIInterface;
-
-typedef struct {
- libusb_context *libusb;
- libusb_device_handle *handle;
-} FTDIDevice;
-
-typedef struct {
- struct {
- uint64_t totalBytes;
- struct timeval time;
- } first, prev, current;
-
- double totalTime;
- double totalRate;
- double currentRate;
-} FTDIProgressInfo;
-
-
-/*
- * USB Constants
- */
-
-#define FTDI_VENDOR 0x0403
-#define FTDI_PRODUCT_FT2232H 0x6010
-
-#define FTDI_COMMAND_TIMEOUT 1000
-
-#define FTDI_SET_BAUD_REQUEST 0x03
-#define FTDI_SET_BITMODE_REQUEST 0x0B
-
-#define FTDI_EP_IN(i) (0x81 + (i-1)*2)
-#define FTDI_EP_OUT(i) (0x02 + (i-1)*2)
-
-#define FTDI_PACKET_SIZE 512 // Specific to FT2232H
-#define FTDI_LOG_PACKET_SIZE 9 // 512 == 1 << 9
-#define FTDI_HEADER_SIZE 2
-
-typedef int (FTDIStreamCallback)(uint8_t *buffer, int length,
- FTDIProgressInfo *progress, void *userdata);
-
-
-/*
- * Public Functions
- */
-
-int FTDIDevice_Open(FTDIDevice *dev, FTDIInterface interface);
-void FTDIDevice_Close(FTDIDevice *dev);
-int FTDIDevice_Reset(FTDIDevice *dev, FTDIInterface interface);
-
-int FTDIDevice_SetMode(FTDIDevice *dev, FTDIInterface interface,
- FTDIBitmode mode, uint8_t pinDirections,
- int baudRate);
-
-int FTDIDevice_Write(FTDIDevice *dev, FTDIInterface interface,
- uint8_t *data, size_t length, bool async);
-
-int FTDIDevice_WriteByteSync(FTDIDevice *dev, FTDIInterface interface, uint8_t byte);
-int FTDIDevice_ReadByteSync(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte);
-
-int FTDIDevice_ReadStream(FTDIDevice *dev, FTDIInterface interface,
- FTDIStreamCallback *callback, void *userdata,
- int packetsPerTransfer, int numTransfers);
-
-int FTDIDevice_MPSSE_Enable(FTDIDevice *dev, FTDIInterface interface);
-int FTDIDevice_MPSSE_SetDivisor(FTDIDevice *dev, FTDIInterface interface,
- uint8_t ValueL, uint8_t ValueH);
-
-int FTDIDevice_MPSSE_SetLowByte(FTDIDevice *dev, FTDIInterface interface,
- uint8_t data, uint8_t dir);
-int FTDIDevice_MPSSE_SetHighByte(FTDIDevice *dev, FTDIInterface interface,
- uint8_t data, uint8_t dir);
-
-int FTDIDevice_MPSSE_GetLowByte(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte);
-int FTDIDevice_MPSSE_GetHighByte(FTDIDevice *dev, FTDIInterface interface, uint8_t *byte);
-
-#endif /* __FASTFTDI_H */
+++ /dev/null
-UNAME := $(shell uname)
-
-LIBNAME := libftdicom
-
-
-# Load libusb via pkg-config
-PACKAGES := libusb-1.0
-CFLAGS += $(shell pkg-config --cflags $(PACKAGES))
-LDFLAGS += $(shell pkg-config --libs $(PACKAGES))
-
-# Large file support
-CFLAGS += $(shell getconf LFS_CFLAGS)
-
-CFLAGS += -fPIC
-
-SO := $(LIBNAME).so
-SO_LDFLAGS := $(LDFLAGS) -shared
-
-# Local headers
-CFLAGS += -I../include
-
-SO_OBJS := ../fastftdi.o
-
-CFLAGS += -O3 -g --std=c99
-
-all: $(SO)
- cp libftdicom.so ../libftdicom.so
-
-$(SO): $(SO_OBJS)
- cc -o $@ $^ $(SO_LDFLAGS)
-
-*.o: *.h Makefile
-
-clean:
- rm -f $(SO) $(OBJS) $(SO_OBJS)
+++ /dev/null
-CC=gcc
-CFLAGS_DLL =-Wall -O0 -g -shared -Wl,--subsystem,windows -DDLL
-LIBS= -lusb-1.0
-
-all: libftdicom.dll
- cp libftdicom.dll ../libftdicom.dll
-
-libftdicom.dll: ../fastftdi.c
- $(CC) -o $@ $(CFLAGS_DLL) $^ $(LIBS)
-
-clean:
- rm -f libftdicom.dll ../libftdicom.dll
+++ /dev/null
-from misoclib.tools.litescope.software.driver.reg import *
-from misoclib.com.liteusb.software.ftdi import FTDIComDevice
-
-class LiteUSBWishboneDriverFTDI:
- cmds = {
- "write": 0x01,
- "read": 0x02
- }
- def __init__(self, interface, mode, tag, addrmap=None, busword=8, debug=False):
- self.interface = interface
- self.mode = mode
- self.tag = tag
- self.debug = debug
- self.com = FTDIComDevice(self.interface,
- mode=mode,
- uart_tag=tag,
- dma_tag=16, # XXX FIXME
- verbose=debug)
- if addrmap is not None:
- self.regs = build_map(addrmap, busword, self.read, self.write)
-
- def open(self):
- self.com.open()
-
- def close(self):
- self.com.close()
-
- def read(self, addr, burst_length=1):
- datas = []
- msg = []
- self.com.uartflush()
- msg.append(self.cmds["read"])
- msg.append(burst_length)
- word_addr = addr//4
- msg.append((word_addr >> 24) & 0xff)
- msg.append((word_addr >> 16) & 0xff)
- msg.append((word_addr >> 8) & 0xff)
- msg.append((word_addr >> 0) & 0xff)
- self.com.uartwrite(msg)
- for i in range(burst_length):
- data = 0
- for k in range(4):
- data = data << 8
- data |= self.com.uartread()
- if self.debug:
- print("RD {:08X} @ {:08X}".format(data, addr + 4*i))
- datas.append(data)
- if burst_length == 1:
- return datas[0]
- else:
- return datas
-
- def write(self, addr, data):
- if isinstance(data, list):
- burst_length = len(data)
- else:
- burst_length = 1
- data = [data]
- msg = []
- msg.append(self.cmds["write"])
- msg.append(burst_length)
- word_addr = addr//4
- msg.append((word_addr >> 24) & 0xff)
- msg.append((word_addr >> 16) & 0xff)
- msg.append((word_addr >> 8) & 0xff)
- msg.append((word_addr >> 0) & 0xff)
- for i in range(len(data)):
- dat = data[i]
- for j in range(4):
- msg.append((dat >> 24) & 0xff)
- dat = dat << 8
- if self.debug:
- print("WR {:08X} @ {:08X}".format(data[i], addr + 4*i))
- self.com.uartwrite(msg)
-
-
-def LiteUSBWishboneDriver(chip="ft2232h", *args, **kwargs):
- drivers = {
- "ft2232h": LiteUSBWishboneDriverFTDI
- }
- return drivers[chip](*args, **kwargs)
+++ /dev/null
-MSCDIR = ../../
-PYTHON = python3
-
-CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
-
-ft245_sync_tb:
- $(CMD) ft245_sync_tb.py
-
-ft245_async_tb:
- $(CMD) ft245_async_tb.py
-
-core_tb:
- $(CMD) core_tb.py
+++ /dev/null
-import random
-
-def randn(max_n):
- return random.randint(0, max_n-1)
-
-
-class RandRun:
- def __init__(self, level=0):
- self.run = True
- self.level = level
-
- def do_simulation(self, selfp):
- self.run = True
- n = randn(100)
- if n < self.level:
- self.run = False
+++ /dev/null
-import binascii
-
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.fhdl.specials import *
-
-from migen.sim.generic import run_simulation
-
-from misoclib.com.liteusb.common import *
-from misoclib.com.liteusb.core import LiteUSBCore
-from misoclib.com.liteusb.test.common import *
-
-# XXX for now use it from liteeth to avoid duplication
-from misoclib.com.liteeth.test.common import *
-
-def crc32(l):
- crc = []
- crc_bytes = split_bytes(binascii.crc32(bytes(l)), 4, "little")
- for byte in crc_bytes:
- crc.append(int(byte))
- return crc
-
-
-class USBPacket(Packet):
- def __init__(self, init=[]):
- Packet.__init__(self, init)
- self.crc_error = False
-
- def check_remove_crc(self):
- if comp(self[-4:], crc32(self[:-4])):
- for i in range(4):
- self.pop()
- return False
- else:
- return True
-
- def decode_remove_header(self):
- header = []
- for byte in self[:packet_header.length]:
- header.append(self.pop(0))
- for k, v in sorted(packet_header.fields.items()):
- setattr(self, k, get_field_data(v, header))
-
- def decode(self):
- # XXX Header should be protected by CRC
- self.decode_remove_header()
- self.crc_error = self.check_remove_crc()
- if self.crc_error:
- raise ValueError # XXX handle this properly
-
- def encode_header(self):
- header = 0
- for k, v in sorted(packet_header.fields.items()):
- value = merge_bytes(split_bytes(getattr(self, k),
- math.ceil(v.width/8)),
- "little")
- header += (value << v.offset+(v.byte*8))
- for d in split_bytes(header, packet_header.length):
- self.insert(0, d)
-
- def insert_crc(self):
- for d in crc32(self):
- self.append(d)
-
- def encode(self):
- # XXX Header should be protected by CRC
- self.insert_crc()
- self.encode_header()
-
- def __repr__(self):
- r = "--------\n"
- for k in sorted(packet_header.fields.keys()):
- r += k + " : 0x{:0x}\n".format(getattr(self, k))
- r += "payload: "
- for d in self:
- r += "{:02x}".format(d)
- return r
-
-
-class PHYModel(Module):
- def __init__(self):
- self.sink = Sink(phy_description(8))
- self.source = Source(phy_description(8))
-
-class TB(Module):
- def __init__(self):
- self.submodules.phy = PHYModel()
- self.submodules.core = LiteUSBCore(self.phy)
-
- self.submodules.phy_streamer = PacketStreamer(phy_description(8))
- self.submodules.phy_streamer_randomizer = AckRandomizer(phy_description(8), level=0)
-
- self.submodules.phy_logger_randomizer = AckRandomizer(phy_description(8), level=0)
- self.submodules.phy_logger = PacketLogger(phy_description(8))
-
- self.submodules.core_streamer = PacketStreamer(user_description(8))
- self.submodules.core_streamer_randomizer = AckRandomizer(user_description(8), level=10)
-
- self.submodules.core_logger = PacketLogger(user_description(8))
- self.submodules.core_logger_randomizer = AckRandomizer(user_description(8), level=10)
-
-
- user_port = self.core.crossbar.get_port(0x12)
-
-
- self.comb += [
- Record.connect(self.phy_streamer.source, self.phy_streamer_randomizer.sink),
- Record.connect(self.phy_streamer_randomizer.source, self.phy.source),
-
- Record.connect(self.core_streamer.source, self.core_streamer_randomizer.sink),
- Record.connect(self.core_streamer_randomizer.source, user_port.sink),
-
- Record.connect(user_port.source, self.core_logger_randomizer.sink),
- Record.connect(self.core_logger_randomizer.source, self.core_logger.sink),
-
- Record.connect(self.phy.sink, self.phy_logger_randomizer.sink),
- Record.connect(self.phy_logger_randomizer.source, self.phy_logger.sink)
- ]
-
- def gen_simulation(self, selfp):
- packet = USBPacket([i for i in range(128)])
- packet.preamble = 0x5AA55AA5
- packet.dst = 0x12
- packet.length = 128 + 4
- packet.encode()
- yield from self.phy_streamer.send(packet)
- for i in range(32):
- yield
- print(self.core_logger.packet)
-
- selfp.core_streamer.source.dst = 0x12
- selfp.core_streamer.source.length = 128 + 4
- packet = Packet([i for i in range(128)])
- yield from self.core_streamer.send(packet)
- for i in range(32):
- yield
- for d in self.phy_logger.packet:
- print("%02x" %d, end="")
- print("")
- packet = USBPacket(self.phy_logger.packet)
- packet.decode()
- print(packet)
-
-def main():
- run_simulation(TB(), ncycles=2000, vcd_name="my.vcd", keep_files=True)
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.fhdl.specials import *
-
-from migen.sim.generic import run_simulation
-
-from misoclib.com.liteusb.common import *
-from misoclib.com.liteusb.phy.ft245 import FT245PHYAsynchronous
-from misoclib.com.liteusb.test.common import *
-
-# XXX for now use it from liteeth to avoid duplication
-from misoclib.com.liteeth.test.common import *
-
-class FT245AsynchronousModel(Module):
- def __init__(self, clk_freq, rd_data):
- self.clk_freq = clk_freq
- self.rd_data = [0] + rd_data
- self.rd_idx = 0
-
- # timings
- self.tRDInactive = self.ns(49) # RXF# inactive after RD# cycle
- self.tWRInactive = self.ns(49) # TXE# inactive after WR# cycle
-
- # pads
- self.data = Signal(8)
- self.rxf_n = Signal(reset=1)
- self.txe_n = Signal(reset=1)
- self.rd_n = Signal(reset=1)
- self.wr_n = Signal(reset=1)
-
- self.init = True
- self.wr_data = []
- self.wait_wr_n = False
- self.rd_done = 0
-
-
- self.data_w = Signal(8)
- self.data_r = Signal(8)
-
- self.specials += Tristate(self.data, self.data_r, ~self.rd_n, self.data_w)
-
- self.last_wr_n = 1
- self.last_rd_n = 1
-
- self.wr_delay = 0
- self.rd_delay = 0
-
- def wr_sim(self, selfp):
- if self.wr_delay:
- selfp.txe_n = 1
- self.wr_delay = self.wr_delay - 1
- else:
- if (not selfp.wr_n and self.last_wr_n) and not selfp.txe_n:
- self.wr_data.append(selfp.data_w)
- self.wr_delay = self.tWRInactive
- self.last_wr_n = selfp.wr_n
-
- selfp.txe_n = 0
-
- def rd_sim(self, selfp):
- if self.rd_delay:
- selfp.rxf_n = 1
- self.rd_delay = self.rd_delay - 1
- else:
- rxf_n = selfp.rxf_n
- if self.rd_idx < len(self.rd_data)-1:
- self.rd_done = selfp.rxf_n
- selfp.rxf_n = 0
- else:
- selfp.rxf_n = self.rd_done
-
- if not selfp.rd_n and self.last_rd_n:
- if self.rd_idx < len(self.rd_data)-1:
- self.rd_idx += not rxf_n
- selfp.data_r = self.rd_data[self.rd_idx]
- self.rd_done = 1
- if selfp.rd_n and not self.last_rd_n:
- self.rd_delay = self.tRDInactive
-
- self.last_rd_n = selfp.rd_n
-
- def do_simulation(self, selfp):
- if self.init:
- selfp.rxf_n = 0
- self.wr_data = []
- self.init = False
- self.wr_sim(selfp)
- self.rd_sim(selfp)
-
- def ns(self, t, margin=True):
- clk_period_ns = 1000000000/self.clk_freq
- if margin:
- t += clk_period_ns/2
- return math.ceil(t/clk_period_ns)
-
-
-test_packet = [i%256 for i in range(128)]
-
-
-class TB(Module):
- def __init__(self):
- clk_freq = 50*1000000
- self.submodules.model = FT245AsynchronousModel(clk_freq, test_packet)
- self.submodules.phy = FT245PHYAsynchronous(self.model, clk_freq)
-
- self.submodules.streamer = PacketStreamer(phy_description(8))
- self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10)
-
- self.submodules.logger_randomizer = AckRandomizer(phy_description(8), level=10)
- self.submodules.logger = PacketLogger(phy_description(8))
-
- self.comb += [
- Record.connect(self.streamer.source, self.streamer_randomizer.sink),
- self.phy.sink.stb.eq(self.streamer_randomizer.source.stb),
- self.phy.sink.data.eq(self.streamer_randomizer.source.data),
- self.streamer_randomizer.source.ack.eq(self.phy.sink.ack),
-
- self.logger_randomizer.sink.stb.eq(self.phy.source.stb),
- self.logger_randomizer.sink.data.eq(self.phy.source.data),
- self.phy.source.ack.eq(self.logger_randomizer.sink.ack),
- Record.connect(self.logger_randomizer.source, self.logger.sink)
- ]
-
- def gen_simulation(self, selfp):
- yield from self.streamer.send(Packet(test_packet))
- for i in range(4000):
- yield
- s, l, e = check(test_packet, self.model.wr_data)
- print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
-
- s, l, e = check(test_packet, self.logger.packet)
- print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
-
-
-def main():
- run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True)
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.fhdl.specials import *
-
-from migen.sim.generic import run_simulation
-
-from misoclib.com.liteusb.common import *
-from misoclib.com.liteusb.phy.ft245 import FT245PHYSynchronous
-from misoclib.com.liteusb.test.common import *
-
-# XXX for now use it from liteeth to avoid duplication
-from misoclib.com.liteeth.test.common import *
-
-class FT245SynchronousModel(Module, RandRun):
- def __init__(self, rd_data):
- RandRun.__init__(self, 10)
- self.rd_data = [0] + rd_data
- self.rd_idx = 0
-
- # pads
- self.data = Signal(8)
- self.rxf_n = Signal(reset=1)
- self.txe_n = Signal(reset=1)
- self.rd_n = Signal(reset=1)
- self.wr_n = Signal(reset=1)
- self.oe_n = Signal(reset=1)
- self.siwua = Signal()
- self.pwren_n = Signal(reset=1)
-
- self.init = True
- self.wr_data = []
- self.wait_wr_n = False
- self.rd_done = 0
-
-
- self.data_w = Signal(8)
- self.data_r = Signal(8)
-
- self.specials += Tristate(self.data, self.data_r, ~self.oe_n, self.data_w)
-
- def wr_sim(self, selfp):
- if not selfp.wr_n and not selfp.txe_n:
- self.wr_data.append(selfp.data_w)
- self.wait_wr_n = False
-
- if not self.wait_wr_n:
- if self.run:
- selfp.txe_n = 1
- else:
- if selfp.txe_n:
- self.wait_wr_n = True
- selfp.txe_n = 0
-
- def rd_sim(self, selfp):
- rxf_n = selfp.rxf_n
- if self.run:
- if self.rd_idx < len(self.rd_data)-1:
- self.rd_done = selfp.rxf_n
- selfp.rxf_n = 0
- else:
- selfp.rxf_n = self.rd_done
- else:
- selfp.rxf_n = self.rd_done
-
- if not selfp.rd_n and not selfp.oe_n:
- if self.rd_idx < len(self.rd_data)-1:
- self.rd_idx += not rxf_n
- selfp.data_r = self.rd_data[self.rd_idx]
- self.rd_done = 1
-
- def do_simulation(self, selfp):
- RandRun.do_simulation(self, selfp)
- if self.init:
- selfp.rxf_n = 0
- self.wr_data = []
- self.init = False
- self.wr_sim(selfp)
- self.rd_sim(selfp)
-
-test_packet = [i%256 for i in range(512)]
-
-
-class TB(Module):
- def __init__(self):
- self.submodules.model = FT245SynchronousModel(test_packet)
- self.submodules.phy = FT245PHYSynchronous(self.model)
-
- self.submodules.streamer = PacketStreamer(phy_description(8))
- self.submodules.streamer_randomizer = AckRandomizer(phy_description(8), level=10)
-
- self.submodules.logger_randomizer = AckRandomizer(phy_description(8), level=10)
- self.submodules.logger = PacketLogger(phy_description(8))
-
- self.comb += [
- Record.connect(self.streamer.source, self.streamer_randomizer.sink),
- self.phy.sink.stb.eq(self.streamer_randomizer.source.stb),
- self.phy.sink.data.eq(self.streamer_randomizer.source.data),
- self.streamer_randomizer.source.ack.eq(self.phy.sink.ack),
-
- self.logger_randomizer.sink.stb.eq(self.phy.source.stb),
- self.logger_randomizer.sink.data.eq(self.phy.source.data),
- self.phy.source.ack.eq(self.logger_randomizer.sink.ack),
- Record.connect(self.logger_randomizer.source, self.logger.sink)
- ]
-
- # Use sys_clk as ftdi_clk in simulation
- self.comb += [
- ClockSignal("ftdi").eq(ClockSignal()),
- ResetSignal("ftdi").eq(ResetSignal())
- ]
-
- def gen_simulation(self, selfp):
- yield from self.streamer.send(Packet(test_packet))
- for i in range(2000):
- yield
- s, l, e = check(test_packet, self.model.wr_data)
- print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
-
- s, l, e = check(test_packet, self.logger.packet[1:])
- print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
-
-
-def main():
- run_simulation(TB(), ncycles=8000, vcd_name="my.vcd", keep_files=True)
-
-if __name__ == "__main__":
- main()
\ No newline at end of file