This commit is contained in:
Florent Kermarrec 2015-09-07 12:44:47 +02:00
parent e49a3c20c8
commit 8e8cc8e5a6
36 changed files with 0 additions and 3102 deletions

View File

@ -1,28 +0,0 @@
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.

View File

@ -1,89 +0,0 @@
__ _ __ __ _________
/ / (_) /____ / / / / __/ _ )
/ /__/ / __/ -_) /_/ /\ \/ _ |
/____/_/\__/\__/\____/___/____/
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

View File

@ -1,61 +0,0 @@
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)

View File

@ -1,31 +0,0 @@
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))

View File

@ -1,291 +0,0 @@
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))

View File

@ -1,33 +0,0 @@
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)

View File

@ -1,158 +0,0 @@
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)

View File

@ -1,140 +0,0 @@
#!/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)

View File

@ -1,45 +0,0 @@
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

View File

@ -1,8 +0,0 @@
LITEUSBDIR=../../software
dll:
cd $(LITEUSBDIR)/ftdi/windows && make all
cp $(LITEUSBDIR)/ftdi/libftdicom.dll libftdicom.dll
clean:
rm -f libftdicom.dll

View File

@ -1,31 +0,0 @@
#!/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)

View File

@ -1,11 +0,0 @@
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()

View File

@ -1,102 +0,0 @@
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),
]

View File

@ -1,35 +0,0 @@
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)
]

View File

@ -1,9 +0,0 @@
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)

View File

@ -1,319 +0,0 @@
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)

View File

@ -1,14 +0,0 @@
[> 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

View File

@ -1,364 +0,0 @@
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)

View File

@ -1,81 +0,0 @@
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)

View File

@ -1,548 +0,0 @@
/*
* 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);
}

View File

@ -1,133 +0,0 @@
/*
* 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 */

View File

@ -1,35 +0,0 @@
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)

View File

@ -1,12 +0,0 @@
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

View File

@ -1,81 +0,0 @@
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)

View File

@ -1,13 +0,0 @@
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

View File

@ -1,16 +0,0 @@
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

View File

@ -1,148 +0,0 @@
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()

View File

@ -1,139 +0,0 @@
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()

View File

@ -1,127 +0,0 @@
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()