This commit is contained in:
Florent Kermarrec 2015-09-07 11:11:43 +02:00
parent bedf3ed9a6
commit 35e3853f6e
56 changed files with 0 additions and 4124 deletions

1
README
View file

@ -29,7 +29,6 @@
and logic, etc.
* Possibility to encapsulate legacy Verilog/VHDL code.
* Complex FPGA cores that can be used integrated in MiSoC or standalone:
- LitePcie: a small footprint and configuragle PCIe core
- LiteEth: a small footprint and configurable Ethernet core
- LiteSATA: a small footprint and configurable SATA core
- LiteScope: a small footprint and configurable logic analyzer core

View file

@ -1,28 +0,0 @@
Unless otherwise noted, LitePCIe 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,123 +0,0 @@
__ _ __ ___ _________
/ / (_) /____ / _ \/ ___/ _/__
/ /__/ / __/ -_) ___/ /___/ // -_)
/____/_/\__/\__/_/ \___/___/\__/
Copyright 2015 / EnjoyDigital / M-Labs Ltd
A small footprint and configurable PCIe core
with MMAP interface and scatter-gather DMA
developed by EnjoyDigital
[> Doc
---------
XXX
[> Intro
---------
LitePCIe provides a small footprint and configurable PCIe gen1/2 core.
LitePCIe 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.
LitePCIe 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.
LitePCIe 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
-----------
- 7-Series Artix7/Kintex7 PHY (up to PCIe Gen2 X2)
- Scatter-gather DMA
- Wishbone bridge
- Linux driver with DMA loopback demo and Sysfs
[> Possibles improvements
-------------------------
- add standardized interfaces (AXI, Avalon-ST)
- add support for PCIe Gen2 X4 and X8 on 7-Series
- clean up 7-Series wrappers
- add Altera/Lattice support
- ... 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
------------------
1. Install Python3 and your vendor's software
2. Obtain Migen and install it:
git clone https://github.com/m-labs/migen
cd migen
python3 setup.py install
cd ..
3. Obtain MiSoC:
git clone https://github.com/m-labs/misoc --recursive
4. Build and load PCIe DMA loopback design (only for KC705 for now):
go to misoclib/com/litepcie/example_designs/
run ./make.py all load-bitstream
5. Build and load Linux Driver:
go to misoclib/com/litepcie/software/linux/kernel
make all
./init.sh
5. Build and load Linux utilities:
go to misoclib/com/litepcie/software/linux/user
make all
./litepcie_util dma_loopback_test
[> Simulations:
Simulations are available in misoclib/com/litepcie/test:
- wishbone_tb
- dma_tb
To run a simulation, move to misoclib/com/litepcie/test/ and run:
make simulation_name
[> Tests :
A DMA loopback example with Wishbone over Sysfs is provided.
Please go to Getting Started section to see how to run the tests.
[> License
-----------
LitePCIe is released under the very permissive two-clause BSD license. Under
the terms of this license, you are authorized to use LiteEth 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 LitePCIe
- cite LitePCIe 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 LitePCIe.
[> Support and consulting
--------------------------
We love open-source hardware and like sharing our designs with others.
LitePCIe is mainly developed and maintained by EnjoyDigital.
If you would like to know more about LitePCIe 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,67 +0,0 @@
from migen.fhdl.std import *
from migen.genlib.record import *
from migen.genlib.misc import reverse_bytes
from migen.flow.actor import *
from migen.actorlib.packet import Arbiter, Dispatcher
KB = 1024
MB = 1024*KB
GB = 1024*MB
def get_bar_mask(size):
mask = 0
found = 0
for i in range(32):
if size%2:
found = 1
if found:
mask |= (1 << i)
size = size >> 1
return mask
def phy_layout(dw):
layout = [
("dat", dw),
("be", dw//8)
]
return EndpointDescription(layout, packetized=True)
def request_layout(dw):
layout = [
("we", 1),
("adr", 32),
("len", 10),
("req_id", 16),
("tag", 8),
("dat", dw),
("channel", 8), # for routing
("user_id", 8) # for packet identification
]
return EndpointDescription(layout, packetized=True)
def completion_layout(dw):
layout = [
("adr", 32),
("len", 10),
("last", 1),
("req_id", 16),
("cmp_id", 16),
("err", 1),
("tag", 8),
("dat", dw),
("channel", 8), # for routing
("user_id", 8) # for packet identification
]
return EndpointDescription(layout, packetized=True)
def interrupt_layout():
return [("dat", 8)]
def dma_layout(dw):
layout = [("data", dw)]
return EndpointDescription(layout, packetized=True)

View file

@ -1,40 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.record import *
from misoclib.com.litepcie.core.packet.depacketizer import Depacketizer
from misoclib.com.litepcie.core.packet.packetizer import Packetizer
from misoclib.com.litepcie.core.switch.crossbar import Crossbar
class Endpoint(Module):
def __init__(self, phy, max_pending_requests=4, with_reordering=False):
self.phy = phy
self.max_pending_requests = max_pending_requests
# # #
# TLP Packetizer / Depacketizer
depacketizer = Depacketizer(phy.dw, phy.bar0_mask)
packetizer = Packetizer(phy.dw)
self.submodules += depacketizer, packetizer
self.comb += [
phy.source.connect(depacketizer.sink),
packetizer.source.connect(phy.sink)
]
# Crossbar
self.crossbar = crossbar = Crossbar(phy.dw, max_pending_requests, with_reordering)
self.submodules += crossbar
# (Slave) HOST initiates the transactions
self.comb += [
Record.connect(depacketizer.req_source, crossbar.phy_slave.sink),
Record.connect(crossbar.phy_slave.source, packetizer.cmp_sink)
]
# (Master) FPGA initiates the transactions
self.comb += [
Record.connect(crossbar.phy_master.source, packetizer.req_sink),
Record.connect(depacketizer.cmp_source, crossbar.phy_master.sink)
]

View file

@ -1,26 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from misoclib.com.litepcie.common import *
class InterruptController(Module, AutoCSR):
def __init__(self, n_irqs=32):
self.irqs = Signal(n_irqs)
self.source = Source(interrupt_layout())
self._enable = CSRStorage(n_irqs)
self._clear = CSR(n_irqs)
self._vector = CSRStatus(n_irqs)
# # #
enable = self._enable.storage
clear = Signal(n_irqs)
self.comb += If(self._clear.re, clear.eq(self._clear.r))
# memorize and clear irqs
vector = self._vector.status
self.sync += vector.eq(~clear & (vector | self.irqs))
self.comb += self.source.stb.eq((vector & enable) != 0)

View file

@ -1,117 +0,0 @@
from migen.fhdl.std import *
from migen.genlib.record import *
from migen.flow.actor import EndpointDescription, Sink, Source
from migen.actorlib.packet import HeaderField, Header
from misoclib.com.litepcie.common import *
# constants
fmt_type_dict = {
"mem_rd32": 0b0000000,
"mem_wr32": 0b1000000,
"mem_rd64": 0b0100000,
"mem_wr64": 0b1100000,
"cpld": 0b1001010,
"cpl": 0b0001010
}
cpl_dict = {
"sc": 0b000,
"ur": 0b001,
"crs": 0b010,
"ca": 0b011
}
max_request_size = 512
# headers
tlp_common_header_length = 16
tlp_common_header_fields = {
"fmt": HeaderField(0*4, 29, 2),
"type": HeaderField(0*4, 24, 5),
}
tlp_common_header = Header(tlp_common_header_fields,
tlp_common_header_length,
swap_field_bytes=False)
tlp_request_header_length = 16
tlp_request_header_fields = {
"fmt": HeaderField(0*4, 29, 2),
"type": HeaderField(0*4, 24, 5),
"tc": HeaderField(0*4, 20, 3),
"td": HeaderField(0*4, 15, 1),
"ep": HeaderField(0*4, 14, 1),
"attr": HeaderField(0*4, 12, 2),
"length": HeaderField(0*4, 0, 10),
"requester_id": HeaderField(1*4, 16, 16),
"tag": HeaderField(1*4, 8, 8),
"last_be": HeaderField(1*4, 4, 4),
"first_be": HeaderField(1*4, 0, 4),
"address": HeaderField(2*4, 2, 30),
}
tlp_request_header = Header(tlp_request_header_fields,
tlp_request_header_length,
swap_field_bytes=False)
tlp_completion_header_length = 16
tlp_completion_header_fields = {
"fmt": HeaderField(0*4, 29, 2),
"type": HeaderField(0*4, 24, 5),
"tc": HeaderField(0*4, 20, 3),
"td": HeaderField(0*4, 15, 1),
"ep": HeaderField(0*4, 14, 1),
"attr": HeaderField(0*4, 12, 2),
"length": HeaderField(0*4, 0, 10),
"completer_id": HeaderField(1*4, 16, 16),
"status": HeaderField(1*4, 13, 3),
"bcm": HeaderField(1*4, 12, 1),
"byte_count": HeaderField(1*4, 0, 12),
"requester_id": HeaderField(2*4, 16, 16),
"tag": HeaderField(2*4, 8, 8),
"lower_address": HeaderField(2*4, 0, 7),
}
tlp_completion_header = Header(tlp_completion_header_fields,
tlp_completion_header_length,
swap_field_bytes=False)
# layouts
def tlp_raw_layout(dw):
layout = [
("header", 4*32),
("dat", dw),
("be", dw//8)
]
return EndpointDescription(layout, packetized=True)
def tlp_common_layout(dw):
layout = tlp_common_header.get_layout() + [
("dat", dw),
("be", dw//8)
]
return EndpointDescription(layout, packetized=True)
def tlp_request_layout(dw):
layout = tlp_request_header.get_layout() + [
("dat", dw),
("be", dw//8)
]
return EndpointDescription(layout, packetized=True)
def tlp_completion_layout(dw):
layout = tlp_completion_header.get_layout() + [
("dat", dw),
("be", dw//8)
]
return EndpointDescription(layout, packetized=True)

View file

@ -1,160 +0,0 @@
from migen.fhdl.std import *
from migen.actorlib.structuring import *
from migen.genlib.fsm import FSM, NextState
from misoclib.com.litepcie.core.packet.common import *
class HeaderExtracter(Module):
def __init__(self, dw):
self.sink = Sink(phy_layout(dw))
self.source = Source(tlp_raw_layout(dw))
###
sink, source = self.sink, self.source
sop = Signal()
shift = Signal()
sink_dat_r = Signal(dw)
sink_be_r = Signal(dw//8)
fsm = FSM(reset_state="HEADER1")
self.submodules += fsm
fsm.act("HEADER1",
sink.ack.eq(1),
If(sink.stb,
shift.eq(1),
NextState("HEADER2")
)
)
fsm.act("HEADER2",
sink.ack.eq(1),
If(sink.stb,
shift.eq(1),
If(sink.eop,
sink.ack.eq(0),
NextState("TERMINATE"),
).Else(
NextState("COPY")
)
)
)
self.sync += [
If(shift, self.source.header.eq(Cat(self.source.header[64:], sink.dat))),
If(sink.stb & sink.ack,
sink_dat_r.eq(sink.dat),
sink_be_r.eq(sink.be)
)
]
fsm.act("COPY",
sink.ack.eq(source.ack),
source.stb.eq(sink.stb),
source.sop.eq(sop),
source.eop.eq(sink.eop),
source.dat.eq(Cat(reverse_bytes(sink_dat_r[32:]), reverse_bytes(sink.dat[:32]))),
source.be.eq(Cat(freversed(sink_be_r[4:]), freversed(sink.be[:4]))),
If(source.stb & source.ack & source.eop,
NextState("HEADER1")
)
)
self.sync += \
If(fsm.before_entering("COPY"),
sop.eq(1)
).Elif(source.stb & source.ack,
sop.eq(0)
)
fsm.act("TERMINATE",
sink.ack.eq(source.ack),
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(1),
source.dat.eq(reverse_bytes(sink.dat[32:])),
source.be.eq(freversed(sink.be[4:])),
If(source.stb & source.ack & source.eop,
NextState("HEADER1")
)
)
class Depacketizer(Module):
def __init__(self, dw, address_mask=0):
self.sink = Sink(phy_layout(dw))
self.req_source = Source(request_layout(dw))
self.cmp_source = Source(completion_layout(dw))
###
# extract raw header
header_extracter = HeaderExtracter(dw)
self.submodules += header_extracter
self.comb += Record.connect(self.sink, header_extracter.sink)
header = header_extracter.source.header
# dispatch data according to fmt/type
dispatch_source = Source(tlp_common_layout(dw))
dispatch_sinks = [Sink(tlp_common_layout(dw)) for i in range(2)]
self.comb += [
dispatch_source.stb.eq(header_extracter.source.stb),
header_extracter.source.ack.eq(dispatch_source.ack),
dispatch_source.sop.eq(header_extracter.source.sop),
dispatch_source.eop.eq(header_extracter.source.eop),
dispatch_source.dat.eq(header_extracter.source.dat),
dispatch_source.be.eq(header_extracter.source.be),
tlp_common_header.decode(header, dispatch_source)
]
self.submodules.dispatcher = Dispatcher(dispatch_source, dispatch_sinks)
fmt_type = Cat(dispatch_source.type, dispatch_source.fmt)
self.comb += \
If((fmt_type == fmt_type_dict["mem_rd32"]) | (fmt_type == fmt_type_dict["mem_wr32"]),
self.dispatcher.sel.eq(0),
).Elif((fmt_type == fmt_type_dict["cpld"]) | (fmt_type == fmt_type_dict["cpl"]),
self.dispatcher.sel.eq(1),
)
# decode TLP request and format local request
tlp_req = Source(tlp_request_layout(dw))
self.comb += Record.connect(dispatch_sinks[0], tlp_req)
self.comb += tlp_request_header.decode(header, tlp_req)
req_source = self.req_source
self.comb += [
req_source.stb.eq(tlp_req.stb),
req_source.we.eq(tlp_req.stb & (Cat(tlp_req.type, tlp_req.fmt) == fmt_type_dict["mem_wr32"])),
tlp_req.ack.eq(req_source.ack),
req_source.sop.eq(tlp_req.sop),
req_source.eop.eq(tlp_req.eop),
req_source.adr.eq(Cat(Signal(2), tlp_req.address & (~address_mask))),
req_source.len.eq(tlp_req.length),
req_source.req_id.eq(tlp_req.requester_id),
req_source.tag.eq(tlp_req.tag),
req_source.dat.eq(tlp_req.dat),
]
# decode TLP completion and format local completion
tlp_cmp = Source(tlp_completion_layout(dw))
self.comb += Record.connect(dispatch_sinks[1], tlp_cmp)
self.comb += tlp_completion_header.decode(header, tlp_cmp)
cmp_source = self.cmp_source
self.comb += [
cmp_source.stb.eq(tlp_cmp.stb),
tlp_cmp.ack.eq(cmp_source.ack),
cmp_source.sop.eq(tlp_cmp.sop),
cmp_source.eop.eq(tlp_cmp.eop),
cmp_source.len.eq(tlp_cmp.length),
cmp_source.last.eq(tlp_cmp.length == (tlp_cmp.byte_count[2:])),
cmp_source.adr.eq(tlp_cmp.lower_address),
cmp_source.req_id.eq(tlp_cmp.requester_id),
cmp_source.cmp_id.eq(tlp_cmp.completer_id),
cmp_source.err.eq(tlp_cmp.status != 0),
cmp_source.tag.eq(tlp_cmp.tag),
cmp_source.dat.eq(tlp_cmp.dat)
]

View file

@ -1,187 +0,0 @@
from migen.fhdl.std import *
from migen.actorlib.structuring import *
from migen.genlib.fsm import FSM, NextState
from migen.genlib.misc import chooser
from misoclib.com.litepcie.core.packet.common import *
class HeaderInserter(Module):
def __init__(self, dw):
self.sink = sink = Sink(tlp_raw_layout(dw))
self.source = source = Source(phy_layout(dw))
###
fsm = FSM(reset_state="HEADER1")
self.submodules += fsm
sink_dat_r = Signal(dw)
sink_eop_r = Signal()
self.sync += \
If(sink.stb & sink.ack,
sink_dat_r.eq(sink.dat),
sink_eop_r.eq(sink.eop)
)
fsm.act("HEADER1",
sink.ack.eq(1),
If(sink.stb & sink.sop,
sink.ack.eq(0),
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(0),
source.dat.eq(sink.header[:64]),
source.be.eq(0xff),
If(source.stb & source.ack,
NextState("HEADER2"),
)
)
)
fsm.act("HEADER2",
source.stb.eq(1),
source.sop.eq(0),
source.eop.eq(sink.eop),
source.dat.eq(Cat(sink.header[64:96], reverse_bytes(sink.dat[:32]))),
source.be.eq(Cat(Signal(4, reset=0xf), freversed(sink.be[:4]))),
If(source.stb & source.ack,
sink.ack.eq(1),
If(source.eop,
NextState("HEADER1")
).Else(
NextState("COPY")
)
)
)
fsm.act("COPY",
source.stb.eq(sink.stb | sink_eop_r),
source.sop.eq(0),
source.eop.eq(sink_eop_r),
source.dat.eq(Cat(reverse_bytes(sink_dat_r[32:64]), reverse_bytes(sink.dat[:32]))),
If(sink_eop_r,
source.be.eq(0x0f)
).Else(
source.be.eq(0xff)
),
If(source.stb & source.ack,
sink.ack.eq(~sink_eop_r),
If(source.eop,
NextState("HEADER1")
)
)
)
class Packetizer(Module):
def __init__(self, dw):
self.req_sink = req_sink = Sink(request_layout(dw))
self.cmp_sink = cmp_sink = Sink(completion_layout(dw))
self.source = Source(phy_layout(dw))
###
# format TLP request and encode it
tlp_req = Sink(tlp_request_layout(dw))
self.comb += [
tlp_req.stb.eq(req_sink.stb),
req_sink.ack.eq(tlp_req.ack),
tlp_req.sop.eq(req_sink.sop),
tlp_req.eop.eq(req_sink.eop),
If(req_sink.we,
Cat(tlp_req.type, tlp_req.fmt).eq(fmt_type_dict["mem_wr32"])
).Else(
Cat(tlp_req.type, tlp_req.fmt).eq(fmt_type_dict["mem_rd32"])
),
tlp_req.tc.eq(0),
tlp_req.td.eq(0),
tlp_req.ep.eq(0),
tlp_req.attr.eq(0),
tlp_req.length.eq(req_sink.len),
tlp_req.requester_id.eq(req_sink.req_id),
tlp_req.tag.eq(req_sink.tag),
If(req_sink.len > 1,
tlp_req.last_be.eq(0xf)
).Else(
tlp_req.last_be.eq(0x0)
),
tlp_req.first_be.eq(0xf),
tlp_req.address.eq(req_sink.adr[2:]),
tlp_req.dat.eq(req_sink.dat),
If(req_sink.we,
tlp_req.be.eq(0xff)
).Else(
tlp_req.be.eq(0x00)
),
]
tlp_raw_req = Sink(tlp_raw_layout(dw))
self.comb += [
tlp_raw_req.stb.eq(tlp_req.stb),
tlp_req.ack.eq(tlp_raw_req.ack),
tlp_raw_req.sop.eq(tlp_req.sop),
tlp_raw_req.eop.eq(tlp_req.eop),
tlp_request_header.encode(tlp_req, tlp_raw_req.header),
tlp_raw_req.dat.eq(tlp_req.dat),
tlp_raw_req.be.eq(tlp_req.be),
]
# format TLP completion and encode it
tlp_cmp = Sink(tlp_completion_layout(dw))
self.comb += [
tlp_cmp.stb.eq(cmp_sink.stb),
cmp_sink.ack.eq(tlp_cmp.ack),
tlp_cmp.sop.eq(cmp_sink.sop),
tlp_cmp.eop.eq(cmp_sink.eop),
tlp_cmp.tc.eq(0),
tlp_cmp.td.eq(0),
tlp_cmp.ep.eq(0),
tlp_cmp.attr.eq(0),
tlp_cmp.length.eq(cmp_sink.len),
tlp_cmp.completer_id.eq(cmp_sink.cmp_id),
If(cmp_sink.err,
Cat(tlp_cmp.type, tlp_cmp.fmt).eq(fmt_type_dict["cpl"]),
tlp_cmp.status.eq(cpl_dict["ur"])
).Else(
Cat(tlp_cmp.type, tlp_cmp.fmt).eq(fmt_type_dict["cpld"]),
tlp_cmp.status.eq(cpl_dict["sc"])
),
tlp_cmp.bcm.eq(0),
tlp_cmp.byte_count.eq(cmp_sink.len*4),
tlp_cmp.requester_id.eq(cmp_sink.req_id),
tlp_cmp.tag.eq(cmp_sink.tag),
tlp_cmp.lower_address.eq(cmp_sink.adr),
tlp_cmp.dat.eq(cmp_sink.dat),
tlp_cmp.be.eq(0xff)
]
tlp_raw_cmp = Sink(tlp_raw_layout(dw))
self.comb += [
tlp_raw_cmp.stb.eq(tlp_cmp.stb),
tlp_cmp.ack.eq(tlp_raw_cmp.ack),
tlp_raw_cmp.sop.eq(tlp_cmp.sop),
tlp_raw_cmp.eop.eq(tlp_cmp.eop),
tlp_completion_header.encode(tlp_cmp, tlp_raw_cmp.header),
tlp_raw_cmp.dat.eq(tlp_cmp.dat),
tlp_raw_cmp.be.eq(tlp_cmp.be),
]
# arbitrate
tlp_raw = Sink(tlp_raw_layout(dw))
self.submodules.arbitrer = Arbiter([tlp_raw_req, tlp_raw_cmp], tlp_raw)
# insert header
header_inserter = HeaderInserter(dw)
self.submodules += header_inserter
self.comb += [
Record.connect(tlp_raw, header_inserter.sink),
Record.connect(header_inserter.source, self.source)
]

View file

@ -1,34 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from misoclib.com.litepcie.common import *
class SlaveInternalPort:
def __init__(self, dw, address_decoder=None):
self.address_decoder = address_decoder
self.sink = Sink(completion_layout(dw))
self.source = Source(request_layout(dw))
class MasterInternalPort:
def __init__(self, dw, channel=None, write_only=False, read_only=False):
self.channel = channel
self.write_only = write_only
self.read_only = read_only
self.sink = Sink(request_layout(dw))
self.source = Source(completion_layout(dw))
class SlavePort:
def __init__(self, port):
self.address_decoder = port.address_decoder
self.sink = port.source
self.source = port.sink
class MasterPort:
def __init__(self, port):
self.channel = port.channel
self.sink = port.source
self.source = port.sink

View file

@ -1,120 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.switch.common import *
from misoclib.com.litepcie.core.switch.request_controller import RequestController
class Crossbar(Module, AutoCSR):
def __init__(self, dw, max_pending_requests, with_reordering=False):
self.dw = dw
self.max_pending_requests = max_pending_requests
self.with_reordering = with_reordering
self.master = MasterInternalPort(dw)
self.slave = SlaveInternalPort(dw)
self.phy_master = MasterPort(self.master)
self.phy_slave = SlavePort(self.slave)
self.user_masters = []
self.user_masters_channel = 0
self.user_slaves = []
def get_slave_port(self, address_decoder):
s = SlaveInternalPort(self.dw, address_decoder)
self.user_slaves.append(s)
return SlavePort(s)
def get_master_port(self, write_only=False, read_only=False):
m = MasterInternalPort(self.dw, self.user_masters_channel, write_only, read_only)
self.user_masters_channel += 1
self.user_masters.append(m)
return MasterPort(m)
def filter_masters(self, write_only, read_only):
masters = []
for m in self.user_masters:
if m.write_only == write_only and m.read_only == read_only:
masters.append(m)
return masters
def slave_dispatch_arbitrate(self, slaves, slave):
# dispatch
s_sources = [s.source for s in slaves]
s_dispatcher = Dispatcher(slave.source, s_sources, one_hot=True)
self.submodules += s_dispatcher
for i, s in enumerate(slaves):
self.comb += s_dispatcher.sel[i].eq(s.address_decoder(slave.source.adr))
# arbitrate
s_sinks = [s.sink for s in slaves]
s_arbiter = Arbiter(s_sinks, slave.sink)
self.submodules += s_arbiter
def master_arbitrate_dispatch(self, masters, master):
# arbitrate
m_sinks = [m.sink for m in masters]
m_arbiter = Arbiter(m_sinks, master.sink)
self.submodules += m_arbiter
# dispatch
m_sources = [m.source for m in masters]
m_dispatcher = Dispatcher(master.source, m_sources)
self.submodules += m_dispatcher
self.comb += m_dispatcher.sel.eq(master.source.channel)
def do_finalize(self):
# Slave path
# Dispatch request to user sources (according to address decoder)
# Arbitrate completion from user sinks
if self.user_slaves != []:
self.slave_dispatch_arbitrate(self.user_slaves, self.slave)
# Master path
# Abritrate requests from user sinks
# Dispatch completion to user sources (according to channel)
# +-------+
# reqs---> | RD |
# cmps<--- | PORTS |---------+
# +-------+ +---+----+ +----------+
# |Arb/Disp|-->|Controller|--+
# +-------+ +---+----+ +----------+ |
# reqs---> | RW | | |
# cmps<--- | PORTS |---------+ |
# +-------+ +---+----+
# |Arb/Disp|<--> to/from Packetizer/
# +-------+ +---+----+ Depacketizer
# reqs---> | WR | +--------+ |
# cmps<--- | PORTS |-----|Arb/Disp|-----------------+
# +-------+ +--------+
#
# The controller blocks RD requests when the max number of pending
# requests have been sent (max_pending_requests parameters).
# To avoid blocking write_only ports when RD requests are blocked,
# a separate arbitration stage is used.
if self.user_masters != []:
masters = []
# Arbitrate / dispatch read_only / read_write ports
# and insert controller
rd_rw_masters = self.filter_masters(False, True)
rd_rw_masters += self.filter_masters(False, False)
if rd_rw_masters != []:
rd_rw_master = MasterInternalPort(self.dw)
controller = RequestController(self.dw, self.max_pending_requests, self.with_reordering)
self.submodules += controller
self.master_arbitrate_dispatch(rd_rw_masters, controller.master_in)
masters.append(controller.master_out)
# Arbitrate / dispatch write_only ports
wr_masters = self.filter_masters(True, False)
if wr_masters != []:
wr_master = MasterInternalPort(self.dw)
self.master_arbitrate_dispatch(wr_masters, wr_master)
masters.append(wr_master)
# Final Arbitrate / dispatch stage
self.master_arbitrate_dispatch(masters, self.master)

View file

@ -1,175 +0,0 @@
from migen.fhdl.std import *
from migen.actorlib.structuring import *
from migen.genlib.fifo import SyncFIFO
from migen.genlib.fsm import FSM, NextState
from migen.actorlib.fifo import SyncFIFO as SyncFlowFIFO
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.core.switch.common import *
class Reordering(Module):
def __init__(self, dw, max_pending_requests):
self.sink = Sink(completion_layout(dw))
self.source = Source(completion_layout(dw))
self.req_we = Signal()
self.req_tag = Signal(log2_int(max_pending_requests))
# # #
tag_buffer = SyncFIFO(log2_int(max_pending_requests), 2*max_pending_requests)
self.submodules += tag_buffer
self.comb += [
tag_buffer.we.eq(self.req_we),
tag_buffer.din.eq(self.req_tag)
]
reorder_buffers = [SyncFlowFIFO(completion_layout(dw), 2*max_request_size//(dw//8), buffered=True)
for i in range(max_pending_requests)]
self.submodules += iter(reorder_buffers)
# store incoming completion in "sink.tag" buffer
cases = {}
for i in range(max_pending_requests):
cases[i] = [Record.connect(self.sink, reorder_buffers[i].sink)]
cases["default"] = [self.sink.ack.eq(1)]
self.comb += Case(self.sink.tag, cases)
# read buffer according to tag_buffer order
cases = {}
for i in range(max_pending_requests):
cases[i] = [Record.connect(reorder_buffers[i].source, self.source)]
cases["default"] = []
self.comb += [
Case(tag_buffer.dout, cases),
If(self.source.stb & self.source.eop & self.source.last,
tag_buffer.re.eq(self.source.ack)
)
]
class RequestController(Module):
def __init__(self, dw, max_pending_requests, with_reordering=False):
self.master_in = MasterInternalPort(dw)
self.master_out = MasterInternalPort(dw)
# # #
req_sink, req_source = self.master_in.sink, self.master_out.sink
cmp_sink, cmp_source = self.master_out.source, self.master_in.source
tag_fifo = SyncFIFO(log2_int(max_pending_requests), max_pending_requests)
self.submodules += tag_fifo
info_mem = Memory(16, max_pending_requests)
info_mem_wr_port = info_mem.get_port(write_capable=True)
info_mem_rd_port = info_mem.get_port(async_read=False)
self.specials += info_mem, info_mem_wr_port, info_mem_rd_port
req_tag = Signal(max=max_pending_requests)
self.sync += \
If(tag_fifo.re,
req_tag.eq(tag_fifo.dout)
)
# requests mgt
req_fsm = FSM(reset_state="IDLE")
self.submodules += req_fsm
req_fsm.act("IDLE",
req_sink.ack.eq(0),
If(req_sink.stb & req_sink.sop & ~req_sink.we & tag_fifo.readable,
tag_fifo.re.eq(1),
NextState("SEND_READ")
).Elif(req_sink.stb & req_sink.sop & req_sink.we,
NextState("SEND_WRITE")
)
)
req_fsm.act("SEND_READ",
Record.connect(req_sink, req_source),
req_sink.ack.eq(0),
req_source.tag.eq(req_tag),
If(req_source.stb & req_source.eop & req_source.ack,
NextState("UPDATE_INFO_MEM")
)
)
req_fsm.act("SEND_WRITE",
Record.connect(req_sink, req_source),
req_source.tag.eq(32),
If(req_source.stb & req_source.eop & req_source.ack,
NextState("IDLE")
)
)
req_fsm.act("UPDATE_INFO_MEM",
info_mem_wr_port.we.eq(1),
info_mem_wr_port.adr.eq(req_tag),
info_mem_wr_port.dat_w[0:8].eq(req_sink.channel),
info_mem_wr_port.dat_w[8:16].eq(req_sink.user_id),
req_sink.ack.eq(1),
NextState("IDLE")
)
# completions mgt
if with_reordering:
self.submodules.reordering = Reordering(dw, max_pending_requests)
self.comb += [
self.reordering.req_we.eq(info_mem_wr_port.we),
self.reordering.req_tag.eq(info_mem_wr_port.adr),
Record.connect(self.reordering.source, cmp_source)
]
cmp_source = self.reordering.sink
cmp_fsm = FSM(reset_state="INIT")
self.submodules += cmp_fsm
tag_cnt = Signal(max=max_pending_requests)
inc_tag_cnt = Signal()
self.sync += \
If(inc_tag_cnt,
tag_cnt.eq(tag_cnt+1)
)
cmp_fsm.act("INIT",
inc_tag_cnt.eq(1),
tag_fifo.we.eq(1),
tag_fifo.din.eq(tag_cnt),
If(tag_cnt == (max_pending_requests-1),
NextState("IDLE")
)
)
cmp_fsm.act("IDLE",
cmp_sink.ack.eq(1),
info_mem_rd_port.adr.eq(cmp_sink.tag),
If(cmp_sink.stb & cmp_sink.sop,
cmp_sink.ack.eq(0),
NextState("COPY"),
)
)
cmp_fsm.act("COPY",
info_mem_rd_port.adr.eq(cmp_sink.tag),
If(cmp_sink.stb & cmp_sink.eop & cmp_sink.last,
cmp_sink.ack.eq(0),
NextState("UPDATE_TAG_FIFO"),
).Else(
Record.connect(cmp_sink, cmp_source),
If(cmp_sink.stb & cmp_sink.eop & cmp_sink.ack,
NextState("IDLE")
)
),
cmp_source.channel.eq(info_mem_rd_port.dat_r[0:8]),
cmp_source.user_id.eq(info_mem_rd_port.dat_r[8:16]),
)
cmp_fsm.act("UPDATE_TAG_FIFO",
tag_fifo.we.eq(1),
tag_fifo.din.eq(cmp_sink.tag),
info_mem_rd_port.adr.eq(cmp_sink.tag),
Record.connect(cmp_sink, cmp_source),
If(cmp_sink.stb & cmp_sink.ack,
NextState("IDLE")
),
cmp_source.channel.eq(info_mem_rd_port.dat_r[0:8]),
cmp_source.user_id.eq(info_mem_rd_port.dat_r[8:16]),
)

View file

@ -1,148 +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.com.litepcie.common import *
def _import(default, name):
return importlib.import_module(default + "." + name)
def _get_args():
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
LitePCIe - based on Migen.
This program builds and/or loads LitePCIe 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.
build-csr-header save CSR map into C header file.
load-bitstream load bitstream into volatile storage.
all clean, build-csr-csv, build-bitstream, load-bitstream.
""")
parser.add_argument("-t", "--target", default="dma", 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("--csr_csv", default="./test/csr.csv", help="CSV file to save the CSR map into")
parser.add_argument("--csr_header", default="../software/linux/kernel/csr.h", help="C header 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:
platform_name = top_class.default_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-csr-header", "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 PCIe
core powered by Migen
====== Building options: ======
Platform: {}
Target: {}
Subtarget: {}
System Clk: {} MHz
===============================""".format(
platform_name,
args.target,
top_class.__name__,
soc.clk_freq/1000000
)
)
# dependencies
if actions["all"]:
actions["build-csr-csv"] = True
actions["build-csr-header"] = True
actions["build-bitstream"] = True
actions["load-bitstream"] = True
if actions["build-bitstream"]:
actions["build-csr-csv"] = True
actions["build-csr-header"] = 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-csr-header"]:
csr_header = cpuif.get_csr_header(csr_regions, soc.get_constants(), with_access_functions=False)
write_to_file(args.csr_header, csr_header)
if actions["build-bitstream"]:
vns = platform.build(soc, build_name=build_name)
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,99 +0,0 @@
from migen.bus import wishbone
from migen.genlib.io import CRG
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.misc import timeline
from misoclib.soc import SoC
from misoclib.tools.litescope.common import *
from misoclib.com.uart.bridge import UARTWishboneBridge
from misoclib.com.litepcie.phy.s7pciephy import S7PCIEPHY
from misoclib.com.litepcie.core import Endpoint
from misoclib.com.litepcie.core.irq.interrupt_controller import InterruptController
from misoclib.com.litepcie.frontend.dma import DMA
from misoclib.com.litepcie.frontend.wishbone import LitePCIeWishboneBridge
class _CRG(Module, AutoCSR):
def __init__(self, platform):
self.clock_domains.cd_sys = ClockDomain("sys")
self.clock_domains.cd_clk125 = ClockDomain("clk125")
# soft reset generaton
self._soft_rst = CSR()
soft_rst = Signal()
# trigger soft reset 1us after CSR access to terminate
# Wishbone access when reseting from PCIe
self.sync += [
timeline(self._soft_rst.re & self._soft_rst.r, [(125, [soft_rst.eq(1)])]),
]
# sys_clk / sys_rst (from PCIe)
self.comb += self.cd_sys.clk.eq(self.cd_clk125.clk)
self.specials += AsyncResetSynchronizer(self.cd_sys, self.cd_clk125.rst | soft_rst)
# scratch register
self._scratch = CSR(32)
self.sync += If(self._scratch.re, self._scratch.w.eq(self._scratch.r))
class PCIeDMASoC(SoC):
default_platform = "kc705"
csr_map = {
"crg": 16,
"pcie_phy": 17,
"dma": 18,
"irq_controller": 19
}
csr_map.update(SoC.csr_map)
interrupt_map = {
"dma_writer": 0,
"dma_reader": 1
}
interrupt_map.update(SoC.interrupt_map)
mem_map = {
"csr": 0x00000000, # (shadow @0x80000000)
}
mem_map.update(SoC.csr_map)
def __init__(self, platform, with_uart_bridge=True):
clk_freq = 125*1000000
SoC.__init__(self, platform, clk_freq,
cpu_type="none",
shadow_base=0x00000000,
with_csr=True, csr_data_width=32,
with_uart=False,
with_identifier=True,
with_timer=False
)
self.submodules.crg = _CRG(platform)
platform.misoc_path = "../../../../"
# PCIe endpoint
self.submodules.pcie_phy = S7PCIEPHY(platform, link_width=2)
self.submodules.pcie_endpoint = Endpoint(self.pcie_phy, with_reordering=True)
# PCIe Wishbone bridge
self.add_cpu_or_bridge(LitePCIeWishboneBridge(self.pcie_endpoint, lambda a: 1))
self.add_wb_master(self.cpu_or_bridge.wishbone)
# PCIe DMA
self.submodules.dma = DMA(self.pcie_phy, self.pcie_endpoint, with_loopback=True)
self.dma.source.connect(self.dma.sink)
if with_uart_bridge:
self.submodules.uart_bridge = UARTWishboneBridge(platform.request("serial"), clk_freq, baudrate=115200)
self.add_wb_master(self.uart_bridge.wishbone)
# IRQs
self.submodules.irq_controller = InterruptController()
self.comb += self.irq_controller.source.connect(self.pcie_phy.interrupt)
self.interrupts = {
"dma_writer": self.dma.writer.table.irq,
"dma_reader": self.dma.reader.table.irq
}
for k, v in sorted(self.interrupts.items()):
self.comb += self.irq_controller.irqs[self.interrupt_map[k]].eq(v)
default_subtarget = PCIeDMASoC

View file

@ -1,41 +0,0 @@
#!/usr/bin/env python3
import argparse
import importlib
def _get_args():
parser = argparse.ArgumentParser()
parser.add_argument("-b", "--bridge", default="uart", help="Bridge to use")
parser.add_argument("--port", default="2", help="UART port")
parser.add_argument("--baudrate", default=115200, help="UART baudrate")
parser.add_argument("--ip_address", default="192.168.0.42", help="Etherbone IP address")
parser.add_argument("--udp_port", default=20000, help="Etherbone UDP port")
parser.add_argument("--bar", default="/sys/bus/pci/devices/0000:04:00.0/resource0", help="PCIe BAR")
parser.add_argument("--bar_size", default=1*1024*1024, help="PCIe BAR size")
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()
if args.bridge == "uart":
from misoclib.com.uart.software.wishbone import UARTWishboneBridgeDriver
port = args.port if not args.port.isdigit() else int(args.port)
wb = UARTWishboneBridgeDriver(port, args.baudrate, "./csr.csv", int(args.busword), debug=False)
elif args.bridge == "etherbone":
from misoclib.com.liteeth.software.wishbone import LiteETHWishboneDriver
wb = LiteETHWishboneDriver(args.ip_address, int(args.udp_port), "./csr.csv", int(args.busword), debug=False)
elif args.bridge == "pcie":
from misoclib.com.litepcie.software.linux.wishbone import LitePCIeWishboneDriver
wb = LitePCIeWishboneDriver(args.bar, args.bar_size, "./csr.csv", int(args.busword), debug=False)
else:
ValueError("Invalid bridge {}".format(args.bridge))
def _import(name):
return importlib.import_module(name)
for test in args.test:
t = _import(test)
t.main(wb)

View file

@ -1,14 +0,0 @@
def main(wb):
wb.open()
regs = wb.regs
# # #
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)))
print("link up : {}".format(regs.pcie_phy_lnk_up.read()))
print("bus_master_enable : {}".format(regs.pcie_phy_bus_master_enable.read()))
print("msi_enable : {}".format(regs.pcie_phy_msi_enable.read()))
print("max_req_request_size : {}".format(regs.pcie_phy_max_request_size.read()))
print("max_payload_size : {}".format(regs.pcie_phy_max_payload_size.read()))
# # #
wb.close()

View file

@ -1,121 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.actorlib.fifo import SyncFIFO as FIFO
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.frontend.dma.common import *
from misoclib.com.litepcie.frontend.dma.writer import DMAWriter
from misoclib.com.litepcie.frontend.dma.reader import DMAReader
class DMALoopback(Module, AutoCSR):
def __init__(self, dw):
self._enable = CSRStorage()
self.sink = Sink(dma_layout(dw))
self.source = Source(dma_layout(dw))
self.next_source = Source(dma_layout(dw))
self.next_sink = Sink(dma_layout(dw))
# # #
enable = self._enable.storage
self.comb += \
If(enable,
Record.connect(self.sink, self.source)
).Else(
Record.connect(self.sink, self.next_source),
Record.connect(self.next_sink, self.source)
)
class DMASynchronizer(Module, AutoCSR):
def __init__(self, dw):
self._bypass = CSRStorage()
self._enable = CSRStorage()
self.ready = Signal(reset=1)
self.pps = Signal()
self.sink = Sink(dma_layout(dw))
self.source = Source(dma_layout(dw))
self.next_source = Source(dma_layout(dw))
self.next_sink = Sink(dma_layout(dw))
# # #
bypass = self._bypass.storage
enable = self._enable.storage
synced = Signal()
self.sync += \
If(~enable,
synced.eq(0)
).Else(
If(self.ready & self.sink.stb & (self.pps | bypass),
synced.eq(1)
)
)
self.comb += \
If(synced,
Record.connect(self.sink, self.next_source),
Record.connect(self.next_sink, self.source),
).Else(
# Block sink
self.next_source.stb.eq(0),
self.sink.ack.eq(0),
# Ack next_sink
self.source.stb.eq(0),
self.next_sink.ack.eq(1),
)
class DMABuffering(Module, AutoCSR):
def __init__(self, dw, depth):
tx_fifo = FIFO(dma_layout(dw), depth//(dw//8), buffered=True)
rx_fifo = FIFO(dma_layout(dw), depth//(dw//8), buffered=True)
self.submodules += tx_fifo, rx_fifo
self.sink = tx_fifo.sink
self.source = rx_fifo.source
self.next_source = tx_fifo.source
self.next_sink = rx_fifo.sink
class DMA(Module, AutoCSR):
def __init__(self, phy, endpoint,
with_buffering=False, buffering_depth=256*8,
with_loopback=False,
with_synchronizer=False):
# Writer, Reader
self.submodules.writer = DMAWriter(endpoint, endpoint.crossbar.get_master_port(write_only=True))
self.submodules.reader = DMAReader(endpoint, endpoint.crossbar.get_master_port(read_only=True))
self.sink, self.source = self.writer.sink, self.reader.source
# Loopback
if with_loopback:
self.submodules.loopback = DMALoopback(phy.dw)
self.insert_optional_module(self.loopback)
# Synchronizer
if with_synchronizer:
self.submodules.synchronizer = DMASynchronizer(phy.dw)
self.insert_optional_module(self.synchronizer)
# Buffering
if with_buffering:
self.submodules.buffering = DMABuffering(phy.dw, buffering_depth)
self.insert_optional_module(self.buffering)
def insert_optional_module(self, m):
self.comb += [
Record.connect(self.source, m.sink),
Record.connect(m.source, self.sink)
]
self.sink, self.source = m.next_sink, m.next_source

View file

@ -1,164 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
from migen.genlib.fsm import FSM, NextState
from migen.genlib.misc import chooser, displacer
from migen.flow.plumbing import Buffer
from misoclib.com.litepcie.common import *
def descriptor_layout(with_user_id=False):
layout = [
("address", 32),
("length", 16)
]
if with_user_id:
layout += [("user_id", 8)]
return EndpointDescription(layout, packetized=True)
class DMARequestTable(Module, AutoCSR):
def __init__(self, depth):
self.source = source = Source(descriptor_layout())
aw = flen(source.address)
lw = flen(source.length)
self._value = CSRStorage(aw+lw)
self._we = CSR()
self._loop_prog_n = CSRStorage()
self._loop_status = CSRStatus(32)
self._level = CSRStatus(log2_int(depth))
self._flush = CSR()
self.irq = Signal()
# # #
# CSR signals
value = self._value.storage
we = self._we.r & self._we.re
loop_prog_n = self._loop_prog_n.storage
loop_index = self._loop_status.status[:log2_int(depth)]
loop_count = self._loop_status.status[16:]
level = self._level.status
flush = self._flush.r & self._flush.re
# FIFO
# instance
fifo_layout = [("address", aw), ("length", lw), ("start", 1)]
fifo = InsertReset(SyncFIFO(fifo_layout, depth))
self.submodules += fifo
self.comb += [
fifo.reset.eq(flush),
level.eq(fifo.level)
]
# write part
self.sync += [
# in "loop" mode, each data output of the fifo is
# written back
If(loop_prog_n,
fifo.din.address.eq(fifo.dout.address),
fifo.din.length.eq(fifo.dout.length),
fifo.din.start.eq(fifo.dout.start),
fifo.we.eq(fifo.re)
# in "program" mode, fifo input is connected
# to registers
).Else(
fifo.din.address.eq(value[:aw]),
fifo.din.length.eq(value[aw:aw+lw]),
fifo.din.start.eq(~fifo.readable),
fifo.we.eq(we)
)
]
# read part
self.comb += [
source.stb.eq(fifo.readable),
fifo.re.eq(source.stb & source.ack),
source.address.eq(fifo.dout.address),
source.length.eq(fifo.dout.length)
]
# loop_index, loop_count
# used by the software for synchronization in
# "loop" mode
self.sync += \
If(flush,
loop_index.eq(0),
loop_count.eq(0),
).Elif(source.stb & source.ack,
If(fifo.dout.start,
loop_index.eq(0),
loop_count.eq(loop_count+1)
).Else(
loop_index.eq(loop_index+1)
)
)
# IRQ
self.comb += self.irq.eq(source.stb & source.ack)
class DMARequestSplitter(Module, AutoCSR):
def __init__(self, max_size, buffered=True):
self.sink = sink = Sink(descriptor_layout())
if buffered:
self.submodules.buffer = Buffer(descriptor_layout(True))
source = self.buffer.d
self.source = self.buffer.q
else:
self.source = source = Source(descriptor_layout(True))
# # #
offset = Signal(32)
clr_offset = Signal()
inc_offset = Signal()
self.sync += \
If(clr_offset,
offset.eq(0)
).Elif(inc_offset,
offset.eq(offset + max_size)
)
user_id = Signal(8)
self.sync += \
If(sink.stb & sink.ack,
user_id.eq(user_id+1)
)
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
length = Signal(16)
update_length = Signal()
self.sync += If(update_length, length.eq(sink.length))
fsm.act("IDLE",
sink.ack.eq(1),
clr_offset.eq(1),
If(sink.stb,
update_length.eq(1),
sink.ack.eq(0),
NextState("RUN")
)
)
fsm.act("RUN",
source.stb.eq(1),
source.address.eq(sink.address + offset),
source.user_id.eq(user_id),
If((length - offset) > max_size,
source.length.eq(max_size),
inc_offset.eq(source.ack)
).Else(
source.length.eq(length - offset),
If(source.ack,
NextState("ACK")
)
)
)
fsm.act("ACK",
sink.ack.eq(1),
NextState("IDLE")
)

View file

@ -1,79 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.fsm import FSM, NextState
from migen.actorlib.fifo import SyncFIFO as FIFO
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.frontend.dma.common import *
class DMAReader(Module, AutoCSR):
def __init__(self, endpoint, port, table_depth=256):
self.source = Source(dma_layout(endpoint.phy.dw))
self._enable = CSRStorage()
# # #
enable = self._enable.storage
max_words_per_request = max_request_size//(endpoint.phy.dw//8)
max_pending_words = endpoint.max_pending_requests*max_words_per_request
fifo_depth = 2*max_pending_words
# Request generation
# requests from table are splitted in chunks of "max_size"
self.table = table = DMARequestTable(table_depth)
splitter = InsertReset(DMARequestSplitter(endpoint.phy.max_request_size))
self.submodules += table, splitter
self.comb += splitter.reset.eq(~enable)
self.comb += table.source.connect(splitter.sink)
# Request FSM
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
request_ready = Signal()
fsm.act("IDLE",
If(request_ready,
NextState("REQUEST"),
)
)
fsm.act("REQUEST",
port.source.stb.eq(1),
port.source.channel.eq(port.channel),
port.source.user_id.eq(splitter.source.user_id),
port.source.sop.eq(1),
port.source.eop.eq(1),
port.source.we.eq(0),
port.source.adr.eq(splitter.source.address),
port.source.len.eq(splitter.source.length[2:]),
port.source.req_id.eq(endpoint.phy.id),
port.source.dat.eq(0),
If(port.source.ack,
splitter.source.ack.eq(1),
NextState("IDLE"),
)
)
# Data FIFO
# issue read requests when enough space available in fifo
fifo = InsertReset(FIFO(dma_layout(endpoint.phy.dw), fifo_depth, buffered=True))
self.submodules += fifo
self.comb += fifo.reset.eq(~enable)
last_user_id = Signal(8, reset=255)
self.sync += \
If(port.sink.stb & port.sink.sop & port.sink.ack,
last_user_id.eq(port.sink.user_id)
)
self.comb += [
fifo.sink.stb.eq(port.sink.stb),
fifo.sink.sop.eq(port.sink.sop & (port.sink.user_id != last_user_id)),
fifo.sink.data.eq(port.sink.dat),
port.sink.ack.eq(fifo.sink.ack | ~enable),
]
self.comb += Record.connect(fifo.source, self.source)
fifo_ready = fifo.fifo.level < (fifo_depth//2)
self.comb += request_ready.eq(splitter.source.stb & fifo_ready)

View file

@ -1,88 +0,0 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
from migen.genlib.fsm import FSM, NextState
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.frontend.dma.common import *
class DMAWriter(Module, AutoCSR):
def __init__(self, endpoint, port, table_depth=256):
self.sink = sink = Sink(dma_layout(endpoint.phy.dw))
self._enable = CSRStorage()
# # #
enable = self._enable.storage
max_words_per_request = max_request_size//(endpoint.phy.dw//8)
fifo_depth = 4*max_words_per_request
# Data FIFO
# store data until we have enough data to issue a
# write request
fifo = InsertReset(SyncFIFO(endpoint.phy.dw, fifo_depth))
self.submodules += fifo
self.comb += [
fifo.we.eq(sink.stb & enable),
sink.ack.eq(fifo.writable & sink.stb & enable),
fifo.din.eq(sink.data),
fifo.reset.eq(~enable)
]
# Request generation
# requests from table are splitted in chunks of "max_size"
self.table = table = DMARequestTable(table_depth)
splitter = InsertReset(DMARequestSplitter(endpoint.phy.max_payload_size))
self.submodules += table, splitter
self.comb += splitter.reset.eq(~enable)
self.comb += table.source.connect(splitter.sink)
# Request FSM
cnt = Signal(max=(2**flen(endpoint.phy.max_payload_size))/8)
clr_cnt = Signal()
inc_cnt = Signal()
self.sync += \
If(clr_cnt,
cnt.eq(0)
).Elif(inc_cnt,
cnt.eq(cnt + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
request_ready = Signal()
fsm.act("IDLE",
clr_cnt.eq(1),
If(request_ready,
NextState("REQUEST"),
)
)
fsm.act("REQUEST",
inc_cnt.eq(port.source.stb & port.source.ack),
port.source.stb.eq(1),
port.source.channel.eq(port.channel),
port.source.user_id.eq(splitter.source.user_id),
port.source.sop.eq(cnt == 0),
port.source.eop.eq(cnt == splitter.source.length[3:]-1),
port.source.we.eq(1),
port.source.adr.eq(splitter.source.address),
port.source.req_id.eq(endpoint.phy.id),
port.source.tag.eq(0),
port.source.len.eq(splitter.source.length[2:]),
port.source.dat.eq(fifo.dout),
If(port.source.ack,
fifo.re.eq(1),
If(port.source.eop,
splitter.source.ack.eq(1),
NextState("IDLE"),
)
)
)
fifo_ready = fifo.level >= splitter.source.length[3:]
self.sync += request_ready.eq(splitter.source.stb & fifo_ready)

View file

@ -1,67 +0,0 @@
from migen.fhdl.std import *
from migen.genlib.fsm import FSM, NextState
from migen.bus import wishbone
from misoclib.com.litepcie.common import *
class LitePCIeWishboneBridge(Module):
def __init__(self, endpoint, address_decoder):
self.wishbone = wishbone.Interface()
# # #
port = endpoint.crossbar.get_slave_port(address_decoder)
self.submodules.fsm = fsm = FSM()
fsm.act("IDLE",
If(port.sink.stb & port.sink.sop,
If(port.sink.we,
NextState("WRITE"),
).Else(
NextState("READ")
)
).Else(
port.sink.ack.eq(port.sink.stb)
)
)
fsm.act("WRITE",
self.wishbone.adr.eq(port.sink.adr[2:]),
self.wishbone.dat_w.eq(port.sink.dat[:32]),
self.wishbone.sel.eq(0xf),
self.wishbone.stb.eq(1),
self.wishbone.we.eq(1),
self.wishbone.cyc.eq(1),
If(self.wishbone.ack,
port.sink.ack.eq(1),
NextState("IDLE")
)
)
fsm.act("READ",
self.wishbone.adr.eq(port.sink.adr[2:]),
self.wishbone.stb.eq(1),
self.wishbone.we.eq(0),
self.wishbone.cyc.eq(1),
If(self.wishbone.ack,
NextState("COMPLETION")
)
)
self.sync += \
If(self.wishbone.stb & self.wishbone.ack,
port.source.dat.eq(self.wishbone.dat_r),
)
fsm.act("COMPLETION",
port.source.stb.eq(1),
port.source.sop.eq(1),
port.source.eop.eq(1),
port.source.len.eq(1),
port.source.err.eq(0),
port.source.tag.eq(port.sink.tag),
port.source.adr.eq(port.sink.adr),
port.source.cmp_id.eq(endpoint.phy.id),
port.source.req_id.eq(port.sink.req_id),
If(port.source.ack,
port.sink.ack.eq(1),
NextState("IDLE")
)
)

View file

@ -1,2 +0,0 @@
0.9.0

View file

@ -1,163 +0,0 @@
import os
from migen.fhdl.std import *
from migen.bank.description import *
from misoclib.com.litepcie.common import *
def get_gt(device):
if device[:4] == "xc7k":
return "GTX"
elif device[:4] == "xc7a":
return "GTP"
else:
raise ValueError("Unsupported device"+device)
class S7PCIEPHY(Module, AutoCSR):
def __init__(self, platform, dw=64, link_width=2, bar0_size=1*MB):
pads = platform.request("pcie_x"+str(link_width))
device = platform.device
self.dw = dw
self.link_width = link_width
self.sink = Sink(phy_layout(dw))
self.source = Source(phy_layout(dw))
self.interrupt = Sink(interrupt_layout())
self.id = Signal(16)
self.tx_buf_av = Signal(8)
self.tx_terr_drop = Signal()
self.tx_cfg_req = Signal()
self.tx_cfg_gnt = Signal(reset=1)
self.rx_np_ok = Signal(reset=1)
self.rx_np_req = Signal(reset=1)
self.cfg_to_turnoff = Signal()
self._lnk_up = CSRStatus()
self._msi_enable = CSRStatus()
self._bus_master_enable = CSRStatus()
self._max_request_size = CSRStatus(16)
self._max_payload_size = CSRStatus(16)
self.max_request_size = self._max_request_size.status
self.max_payload_size = self._max_payload_size.status
self.bar0_size = bar0_size
self.bar0_mask = get_bar_mask(bar0_size)
# SHARED clock
# In case we want to use the second QPLL of the quad
self.shared_qpll_pd = Signal(reset=1)
self.shared_qpll_rst = Signal(reset=1)
self.shared_qpll_refclk = Signal()
self.shared_qpll_outclk = Signal()
self.shared_qpll_outrefclk = Signal()
self.shared_qpll_lock = Signal()
# # #
clk100 = Signal()
self.specials += Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=pads.clk_p,
i_IB=pads.clk_n,
o_O=clk100,
o_ODIV2=Signal()
)
bus_number = Signal(8)
device_number = Signal(5)
function_number = Signal(3)
command = Signal(16)
dcommand = Signal(16)
self.specials += Instance("pcie_phy",
p_C_DATA_WIDTH=dw,
p_C_PCIE_GT_DEVICE=get_gt(device),
p_C_BAR0=get_bar_mask(self.bar0_size),
i_sys_clk=clk100,
i_sys_rst_n=pads.rst_n,
o_pci_exp_txp=pads.tx_p,
o_pci_exp_txn=pads.tx_n,
i_pci_exp_rxp=pads.rx_p,
i_pci_exp_rxn=pads.rx_n,
o_user_clk=ClockSignal("clk125"),
o_user_reset=ResetSignal("clk125"),
o_user_lnk_up=self._lnk_up.status,
o_tx_buf_av=self.tx_buf_av,
o_tx_terr_drop=self.tx_terr_drop,
o_tx_cfg_req=self.tx_cfg_req,
i_tx_cfg_gnt=self.tx_cfg_gnt,
i_s_axis_tx_tvalid=self.sink.stb,
i_s_axis_tx_tlast=self.sink.eop,
o_s_axis_tx_tready=self.sink.ack,
i_s_axis_tx_tdata=self.sink.dat,
i_s_axis_tx_tkeep=self.sink.be,
i_s_axis_tx_tuser=0,
i_rx_np_ok=self.rx_np_ok,
i_rx_np_req=self.rx_np_req,
o_m_axis_rx_tvalid=self.source.stb,
o_m_axis_rx_tlast=self.source.eop,
i_m_axis_rx_tready=self.source.ack,
o_m_axis_rx_tdata=self.source.dat,
o_m_axis_rx_tkeep=self.source.be,
o_m_axis_rx_tuser=Signal(4),
o_cfg_to_turnoff=self.cfg_to_turnoff,
o_cfg_bus_number=bus_number,
o_cfg_device_number=device_number,
o_cfg_function_number=function_number,
o_cfg_command=command,
o_cfg_dcommand=dcommand,
o_cfg_interrupt_msienable=self._msi_enable.status,
i_cfg_interrupt=self.interrupt.stb,
o_cfg_interrupt_rdy=self.interrupt.ack,
i_cfg_interrupt_di=self.interrupt.dat,
i_SHARED_QPLL_PD=self.shared_qpll_pd,
i_SHARED_QPLL_RST=self.shared_qpll_rst,
i_SHARED_QPLL_REFCLK=self.shared_qpll_refclk,
o_SHARED_QPLL_OUTCLK=self.shared_qpll_outclk,
o_SHARED_QPLL_OUTREFCLK=self.shared_qpll_outrefclk,
o_SHARED_QPLL_LOCK=self.shared_qpll_lock,
)
# id
self.comb += self.id.eq(Cat(function_number, device_number, bus_number))
# config
def convert_size(command, size):
cases = {}
value = 128
for i in range(6):
cases[i] = size.eq(value)
value = value*2
return Case(command, cases)
self.sync += [
self._bus_master_enable.status.eq(command[2]),
convert_size(dcommand[12:15], self.max_request_size),
convert_size(dcommand[5:8], self.max_payload_size)
]
if hasattr(platform, "misoc_path"):
misoc_path = platform.misoc_path
else:
misoc_path = "./"
litepcie_phy_wrapper_path = os.path.join(misoc_path, "extcores", "litepcie_phy_wrappers")
platform.add_source_dir(os.path.join(litepcie_phy_wrapper_path, "xilinx", "7-series", "common"))
if device[:4] == "xc7k":
platform.add_source_dir(os.path.join(litepcie_phy_wrapper_path, "xilinx", "7-series", "kintex7"))
elif device[:4] == "xc7a":
platform.add_source_dir(os.path.join(litepcie_phy_wrapper_path, "xilinx", "7-series", "artix7"))

View file

@ -1,16 +0,0 @@
# Makefile for kernel module
KERNEL_VERSION:=$(shell uname -r)
KERNEL_PATH:=/lib/modules/$(KERNEL_VERSION)/build
obj-m = litepcie.o
litepcie-objs = main.o
all: litepcie.ko
litepcie.ko: main.c
make -C $(KERNEL_PATH) M=$(PWD) modules
clean:
make -C $(KERNEL_PATH) M=$(PWD) clean
rm -f *~

View file

@ -1,9 +0,0 @@
- Use 'make' to build the driver
- Install the driver and create the device with :
./init.sh
- Remove driver with
rmmod litepcie

View file

@ -1,13 +0,0 @@
#ifndef __HW_CONFIG_H
#define __HW_CONFIG_H
/* pci */
#define PCI_FPGA_VENDOR_ID 0x10ee
#define PCI_FPGA_DEVICE_ID 0x7022
#define PCI_FPGA_BAR0_SIZE 0xa000
/* dma */
#define DMA_BUFFER_COUNT 128
#endif /* __HW_CONFIG_H */

View file

@ -1,10 +0,0 @@
#ifndef __HW_FLAGS_H
#define __HW_FLAGS_H
/* dma */
#define DMA_LOOPBACK_ENABLE 0x1
#define DMA_TABLE_LOOP_INDEX 1 << 0
#define DMA_TABLE_LOOP_COUNT 1 << 16
#endif /* __HW_FLAGS_H */

View file

@ -1,7 +0,0 @@
#!/bin/sh
# TODO: use udev instead
insmod litepcie.ko
major=$(awk '/ litepcie$/{print $1}' /proc/devices)
mknod -m 666 /dev/litepcie0 c $major 0

View file

@ -1,50 +0,0 @@
/*
* LitePCIe driver
*
*/
#ifndef _LINUX_LITEPCIE_H
#define _LINUX_LITEPCIE_H
#include <linux/types.h>
struct litepcie_ioctl_mmap_info {
unsigned long reg_offset;
unsigned long reg_size;
unsigned long dma_tx_buf_offset;
unsigned long dma_tx_buf_size;
unsigned long dma_tx_buf_count;
unsigned long dma_rx_buf_offset;
unsigned long dma_rx_buf_size;
unsigned long dma_rx_buf_count;
};
struct litepcie_ioctl_dma_start {
__u32 dma_flags; /* see LITEPCIE_DMA_FLAGS_x */
__u32 tx_buf_size; /* in bytes, must be < dma_buf_pitch. 0 means no TX */
__u32 tx_buf_count;
__u32 rx_buf_size; /* in bytes, must be < dma_buf_pitch. 0 means no RX */
__u32 rx_buf_count;
};
/* if tx_wait is true, wait until the current TX bufffer is
different from tx_buf_num. If tx_wait is false, wait until the
current RX buffer is different from rx_buf_num. Return the last
TX buffer in tx_buf_num and the last RX buffer in
rx_buf_num. */
struct litepcie_ioctl_dma_wait {
__s32 timeout; /* in ms. Return -EAGAIN if timeout occured without event */
__u32 tx_wait;
__u32 tx_buf_num; /* read/write */
__u32 rx_buf_num; /* read/write */
};
#define LITEPCIE_IOCTL 'S'
#define LITEPCIE_IOCTL_GET_MMAP_INFO _IOR(LITEPCIE_IOCTL, 0, struct litepcie_ioctl_mmap_info)
#define LITEPCIE_IOCTL_DMA_START _IOW(LITEPCIE_IOCTL, 1, struct litepcie_ioctl_dma_start)
#define LITEPCIE_IOCTL_DMA_STOP _IO(LITEPCIE_IOCTL, 2)
#define LITEPCIE_IOCTL_DMA_WAIT _IOWR(LITEPCIE_IOCTL, 3, struct litepcie_ioctl_dma_wait)
#endif /* _LINUX_LITEPCIE_H */

View file

@ -1,639 +0,0 @@
/*
* LitePCIe driver
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/mmtimer.h>
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include "litepcie.h"
#include "config.h"
#include "csr.h"
#include "flags.h"
#define LITEPCIE_NAME "litepcie"
#define LITEPCIE_MINOR_COUNT 4
#define DMA_BUFFER_SIZE PAGE_ALIGN(32768)
#define DMA_BUFFER_MAP_SIZE (DMA_BUFFER_SIZE * DMA_BUFFER_COUNT)
#define IRQ_MASK_DMA_READER (1 << DMA_READER_INTERRUPT)
#define IRQ_MASK_DMA_WRITER (1 << DMA_WRITER_INTERRUPT)
typedef struct {
int minor;
struct pci_dev *dev;
phys_addr_t bar0_phys_addr;
uint8_t *bar0_addr; /* virtual address of BAR0 */
uint8_t *dma_tx_bufs[DMA_BUFFER_COUNT];
unsigned long dma_tx_bufs_addr[DMA_BUFFER_COUNT];
uint8_t *dma_rx_bufs[DMA_BUFFER_COUNT];
unsigned long dma_rx_bufs_addr[DMA_BUFFER_COUNT];
uint8_t tx_dma_started;
uint8_t rx_dma_started;
wait_queue_head_t dma_waitqueue;
} LitePCIeState;
static dev_t litepcie_cdev;
static struct cdev litepcie_cdev_struct;
static LitePCIeState *litepcie_minor_table[LITEPCIE_MINOR_COUNT];
static void litepcie_end(struct pci_dev *dev, LitePCIeState *s);
static int litepcie_dma_stop(LitePCIeState *s);
static inline uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr)
{
return readl(s->bar0_addr + addr);
}
static inline void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val)
{
return writel(val, s->bar0_addr + addr);
}
static void litepcie_enable_interrupt(LitePCIeState *s, int irq_num)
{
uint32_t v;
v = litepcie_readl(s, CSR_IRQ_CONTROLLER_ENABLE_ADDR);
v |= (1 << irq_num);
litepcie_writel(s, CSR_IRQ_CONTROLLER_ENABLE_ADDR, v);
}
static void litepcie_disable_interrupt(LitePCIeState *s, int irq_num)
{
uint32_t v;
v = litepcie_readl(s, CSR_IRQ_CONTROLLER_ENABLE_ADDR);
v &= ~(1 << irq_num);
litepcie_writel(s, CSR_IRQ_CONTROLLER_ENABLE_ADDR, v);
}
static int litepcie_open(struct inode *inode, struct file *file)
{
LitePCIeState *s;
int minor;
/* find PCI device */
minor = iminor(inode);
if (minor < 0 || minor >= LITEPCIE_MINOR_COUNT)
return -ENODEV;
s = litepcie_minor_table[minor];
if (!s)
return -ENODEV;
file->private_data = s;
return 0;
}
/* mmap the DMA buffers and registers to user space */
static int litepcie_mmap(struct file *file, struct vm_area_struct *vma)
{
LitePCIeState *s = file->private_data;
unsigned long pfn;
int is_tx, i;
if (vma->vm_pgoff == 0) {
if (vma->vm_end - vma->vm_start != DMA_BUFFER_MAP_SIZE)
return -EINVAL;
is_tx = 1;
goto remap_ram;
} else if (vma->vm_pgoff == (DMA_BUFFER_MAP_SIZE >> PAGE_SHIFT)) {
if (vma->vm_end - vma->vm_start != DMA_BUFFER_MAP_SIZE)
return -EINVAL;
is_tx = 0;
remap_ram:
for(i = 0; i < DMA_BUFFER_COUNT; i++) {
if (is_tx)
pfn = __pa(s->dma_tx_bufs[i]) >> PAGE_SHIFT;
else
pfn = __pa(s->dma_rx_bufs[i]) >> PAGE_SHIFT;
/* Note: the memory is cached, so the user must explicitly
flush the CPU caches on architectures which require it. */
if (remap_pfn_range(vma, vma->vm_start + i * DMA_BUFFER_SIZE, pfn,
DMA_BUFFER_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR LITEPCIE_NAME " remap_pfn_range failed\n");
return -EAGAIN;
}
}
} else if (vma->vm_pgoff == ((2 * DMA_BUFFER_MAP_SIZE) >> PAGE_SHIFT)) {
if (vma->vm_end - vma->vm_start != PCI_FPGA_BAR0_SIZE)
return -EINVAL;
pfn = s->bar0_phys_addr >> PAGE_SHIFT;
/* not cached */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_flags |= VM_IO;
if (io_remap_pfn_range(vma, vma->vm_start, pfn,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) {
printk(KERN_ERR LITEPCIE_NAME " io_remap_pfn_range failed\n");
return -EAGAIN;
}
} else {
return -EINVAL;
}
return 0;
}
static int litepcie_release(struct inode *inode, struct file *file)
{
LitePCIeState *s = file->private_data;
litepcie_dma_stop(s); /* just in case: stop the DMA */
return 0;
}
static irqreturn_t litepcie_interrupt(int irq, void *data)
{
LitePCIeState *s = data;
uint32_t clear_mask, irq_vector;
irq_vector = litepcie_readl(s, CSR_IRQ_CONTROLLER_VECTOR_ADDR);
clear_mask = 0;
if (irq_vector & (IRQ_MASK_DMA_READER | IRQ_MASK_DMA_WRITER)) {
/* wake up processes waiting on dma_wait() */
wake_up_interruptible(&s->dma_waitqueue);
clear_mask |= (IRQ_MASK_DMA_READER | IRQ_MASK_DMA_WRITER);
}
litepcie_writel(s, CSR_IRQ_CONTROLLER_CLEAR_ADDR, clear_mask);
return IRQ_HANDLED;
}
static int litepcie_dma_start(LitePCIeState *s, struct litepcie_ioctl_dma_start *m)
{
int i, val;
if (s->tx_dma_started || s->rx_dma_started)
return -EIO;
if (m->tx_buf_size == 0 && m->rx_buf_size == 0)
return -EINVAL;
/* check alignment (XXX: what is the exact constraint ?) */
if ((m->tx_buf_size & 7) != 0 ||
(m->rx_buf_size & 7) != 0 ||
m->tx_buf_size > DMA_BUFFER_SIZE ||
m->rx_buf_size > DMA_BUFFER_SIZE)
return -EINVAL;
/* check buffer count */
if (m->tx_buf_count > DMA_BUFFER_COUNT)
return -EINVAL;
if (m->rx_buf_count > DMA_BUFFER_COUNT)
return -EINVAL;
val = ((m->dma_flags & DMA_LOOPBACK_ENABLE) != 0);
litepcie_writel(s, CSR_DMA_LOOPBACK_ENABLE_ADDR, val);
/* init DMA write */
if (m->rx_buf_size != 0) {
litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 0);
litepcie_writel(s, CSR_DMA_WRITER_TABLE_FLUSH_ADDR, 1);
litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 0);
for(i = 0; i < m->rx_buf_count; i++) {
litepcie_writel(s, CSR_DMA_WRITER_TABLE_VALUE_ADDR, m->rx_buf_size);
litepcie_writel(s, CSR_DMA_WRITER_TABLE_VALUE_ADDR + 4,
s->dma_rx_bufs_addr[i]);
litepcie_writel(s, CSR_DMA_WRITER_TABLE_WE_ADDR, 1);
}
litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 1);
}
/* init DMA read */
if (m->tx_buf_size != 0) {
litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 0);
litepcie_writel(s, CSR_DMA_READER_TABLE_FLUSH_ADDR, 1);
litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 0);
for(i = 0; i < m->tx_buf_count; i++) {
litepcie_writel(s, CSR_DMA_READER_TABLE_VALUE_ADDR, m->tx_buf_size);
litepcie_writel(s, CSR_DMA_READER_TABLE_VALUE_ADDR + 4,
s->dma_tx_bufs_addr[i]);
litepcie_writel(s, CSR_DMA_READER_TABLE_WE_ADDR, 1);
}
litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 1);
}
/* start DMA */
if (m->rx_buf_size != 0) {
litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 1);
s->rx_dma_started = 1;
}
if (m->tx_buf_size != 0) {
litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 1);
s->tx_dma_started = 1;
}
return 0;
}
static int litepcie_dma_wait(LitePCIeState *s, struct litepcie_ioctl_dma_wait *m)
{
unsigned long timeout;
int ret, last_buf_num;
DECLARE_WAITQUEUE(wait, current);
if (m->tx_wait) {
if (!s->tx_dma_started)
return -EIO;
last_buf_num = m->tx_buf_num;
litepcie_enable_interrupt(s, DMA_READER_INTERRUPT);
} else {
if (!s->rx_dma_started)
return -EIO;
last_buf_num = m->rx_buf_num;
litepcie_enable_interrupt(s, DMA_WRITER_INTERRUPT);
}
add_wait_queue(&s->dma_waitqueue, &wait);
timeout = jiffies + msecs_to_jiffies(m->timeout);
for (;;) {
/* set current buffer */
if (s->tx_dma_started) {
m->tx_buf_num = (litepcie_readl(s, CSR_DMA_READER_TABLE_LOOP_STATUS_ADDR) & 0xffff);
} else {
m->tx_buf_num = 0;
}
if (s->rx_dma_started) {
m->rx_buf_num = (litepcie_readl(s, CSR_DMA_WRITER_TABLE_LOOP_STATUS_ADDR) & 0xfffff);
} else {
m->rx_buf_num = 0;
}
if (m->tx_wait) {
if (m->tx_buf_num != last_buf_num)
break;
} else {
if (m->rx_buf_num != last_buf_num)
break;
}
if ((long)(jiffies - timeout) > 0) {
ret = -EAGAIN;
goto done;
}
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
ret = -EINTR;
goto done;
}
schedule();
}
ret = 0;
done:
if (m->tx_wait) {
litepcie_disable_interrupt(s, DMA_READER_INTERRUPT);
} else {
litepcie_disable_interrupt(s, DMA_WRITER_INTERRUPT);
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&s->dma_waitqueue, &wait);
return ret;
}
static int litepcie_dma_stop(LitePCIeState *s)
{
/* just to be sure, we disable the interrupts */
litepcie_disable_interrupt(s, DMA_READER_INTERRUPT);
litepcie_disable_interrupt(s, DMA_WRITER_INTERRUPT);
s->tx_dma_started = 0;
litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 0);
litepcie_writel(s, CSR_DMA_READER_TABLE_FLUSH_ADDR, 1);
udelay(100);
litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 0);
s->rx_dma_started = 0;
litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 0);
litepcie_writel(s, CSR_DMA_WRITER_TABLE_FLUSH_ADDR, 1);
udelay(100);
litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 0);
return 0;
}
static long litepcie_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
LitePCIeState *s = file->private_data;
long ret;
switch(cmd) {
case LITEPCIE_IOCTL_GET_MMAP_INFO:
{
struct litepcie_ioctl_mmap_info m;
m.dma_tx_buf_offset = 0;
m.dma_tx_buf_size = DMA_BUFFER_SIZE;
m.dma_tx_buf_count = DMA_BUFFER_COUNT;
m.dma_rx_buf_offset = DMA_BUFFER_MAP_SIZE;
m.dma_rx_buf_size = DMA_BUFFER_SIZE;
m.dma_rx_buf_count = DMA_BUFFER_COUNT;
m.reg_offset = 2 * DMA_BUFFER_MAP_SIZE;
m.reg_size = PCI_FPGA_BAR0_SIZE;
if (copy_to_user((void *)arg, &m, sizeof(m))) {
ret = -EFAULT;
break;
}
ret = 0;
}
break;
case LITEPCIE_IOCTL_DMA_START:
{
struct litepcie_ioctl_dma_start m;
if (copy_from_user(&m, (void *)arg, sizeof(m))) {
ret = -EFAULT;
break;
}
ret = litepcie_dma_start(s, &m);
}
break;
case LITEPCIE_IOCTL_DMA_STOP:
{
ret = litepcie_dma_stop(s);
}
break;
case LITEPCIE_IOCTL_DMA_WAIT:
{
struct litepcie_ioctl_dma_wait m;
if (copy_from_user(&m, (void *)arg, sizeof(m))) {
ret = -EFAULT;
break;
}
ret = litepcie_dma_wait(s, &m);
if (ret == 0) {
if (copy_to_user((void *)arg, &m, sizeof(m))) {
ret = -EFAULT;
break;
}
}
}
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
static const struct file_operations litepcie_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = litepcie_ioctl,
.open = litepcie_open,
.release = litepcie_release,
.mmap = litepcie_mmap,
.llseek = no_llseek,
};
static int litepcie_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
LitePCIeState *s = NULL;
uint8_t rev_id;
int ret, minor, i;
printk(KERN_INFO LITEPCIE_NAME " Probing device\n");
/* find available minor */
for(minor = 0; minor < LITEPCIE_MINOR_COUNT; minor++) {
if (!litepcie_minor_table[minor])
break;
}
if (minor == LITEPCIE_MINOR_COUNT) {
printk(KERN_ERR LITEPCIE_NAME " Cannot allocate a minor\n");
ret = -ENODEV;
goto fail1;
}
s = kzalloc(sizeof(LitePCIeState), GFP_KERNEL);
if (!s) {
printk(KERN_ERR LITEPCIE_NAME " Cannot allocate memory\n");
ret = -ENOMEM;
goto fail1;
}
s->minor = minor;
s->dev = dev;
pci_set_drvdata(dev, s);
ret = pci_enable_device(dev);
if (ret != 0) {
printk(KERN_ERR LITEPCIE_NAME " Cannot enable device\n");
goto fail1;
}
/* check device version */
pci_read_config_byte(dev, PCI_REVISION_ID, &rev_id);
if (rev_id != 1) {
printk(KERN_ERR LITEPCIE_NAME " Unsupported device version %d\n", rev_id);
goto fail2;
}
if (pci_request_regions(dev, LITEPCIE_NAME) < 0) {
printk(KERN_ERR LITEPCIE_NAME " Could not request regions\n");
goto fail2;
}
/* check BAR0 config */
if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) {
printk(KERN_ERR LITEPCIE_NAME " Invalid BAR0 config\n");
goto fail3;
}
s->bar0_phys_addr = pci_resource_start(dev, 0);
s->bar0_addr = pci_ioremap_bar(dev, 0);
if (!s->bar0_addr) {
printk(KERN_ERR LITEPCIE_NAME " Could not map BAR0\n");
goto fail3;
}
pci_set_master(dev);
ret = pci_set_dma_mask(dev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_ERR LITEPCIE_NAME " Failed to set DMA mask\n");
goto fail4;
};
ret = pci_enable_msi(dev);
if (ret) {
printk(KERN_ERR LITEPCIE_NAME " Failed to enable MSI\n");
goto fail4;
}
if (request_irq(dev->irq, litepcie_interrupt, IRQF_SHARED, LITEPCIE_NAME, s) < 0) {
printk(KERN_ERR LITEPCIE_NAME " Failed to allocate irq %d\n", dev->irq);
goto fail5;
}
/* soft reset */
litepcie_writel(s, CSR_CRG_SOFT_RST_ADDR, 1);
udelay(5);
/* allocate DMA buffers */
for(i = 0; i < DMA_BUFFER_COUNT; i++) {
s->dma_tx_bufs[i] = kzalloc(DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA32);
if (!s->dma_tx_bufs[i]) {
printk(KERN_ERR LITEPCIE_NAME " Failed to allocate dma_tx_buf\n");
goto fail6;
}
s->dma_tx_bufs_addr[i] = pci_map_single(dev, s->dma_tx_bufs[i],
DMA_BUFFER_SIZE,
DMA_TO_DEVICE);
if (!s->dma_tx_bufs_addr[i]) {
ret = -ENOMEM;
goto fail6;
}
}
for(i = 0; i < DMA_BUFFER_COUNT; i++) {
s->dma_rx_bufs[i] = kzalloc(DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA32);
if (!s->dma_rx_bufs[i]) {
printk(KERN_ERR LITEPCIE_NAME " Failed to allocate dma_rx_buf\n");
goto fail6;
}
s->dma_rx_bufs_addr[i] = pci_map_single(dev, s->dma_rx_bufs[i],
DMA_BUFFER_SIZE,
DMA_FROM_DEVICE);
if (!s->dma_rx_bufs_addr[i]) {
ret = -ENOMEM;
goto fail6;
}
}
init_waitqueue_head(&s->dma_waitqueue);
litepcie_minor_table[minor] = s;
printk(KERN_INFO LITEPCIE_NAME " Assigned to minor %d\n", minor);
return 0;
fail6:
litepcie_end(dev, s);
free_irq(dev->irq, s);
fail5:
pci_disable_msi(dev);
fail4:
pci_iounmap(dev, s->bar0_addr);
fail3:
pci_release_regions(dev);
fail2:
pci_disable_device(dev);
ret = -EIO;
fail1:
kfree(s);
printk(KERN_ERR LITEPCIE_NAME " Error while probing device\n");
return ret;
}
static void litepcie_end(struct pci_dev *dev, LitePCIeState *s)
{
int i;
for(i = 0; i < DMA_BUFFER_COUNT; i++) {
if (s->dma_tx_bufs_addr[i]) {
dma_unmap_single(&dev->dev, s->dma_tx_bufs_addr[i],
DMA_BUFFER_SIZE, DMA_TO_DEVICE);
}
kfree(s->dma_tx_bufs[i]);
}
for(i = 0; i < DMA_BUFFER_COUNT; i++) {
if (s->dma_rx_bufs_addr[i]) {
dma_unmap_single(&dev->dev, s->dma_rx_bufs_addr[i],
DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
}
kfree(s->dma_rx_bufs[i]);
}
}
static void litepcie_pci_remove(struct pci_dev *dev)
{
LitePCIeState *s = pci_get_drvdata(dev);
printk(KERN_INFO LITEPCIE_NAME " Removing device\n");
litepcie_minor_table[s->minor] = NULL;
litepcie_end(dev, s);
free_irq(dev->irq, s);
pci_disable_msi(dev);
pci_iounmap(dev, s->bar0_addr);
pci_disable_device(dev);
pci_release_regions(dev);
kfree(s);
};
static const struct pci_device_id litepcie_pci_ids[] = {
{ PCI_DEVICE(PCI_FPGA_VENDOR_ID, PCI_FPGA_DEVICE_ID), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, litepcie_pci_ids);
static struct pci_driver litepcie_pci_driver = {
.name = LITEPCIE_NAME,
.id_table = litepcie_pci_ids,
.probe = litepcie_pci_probe,
.remove = litepcie_pci_remove,
};
static int __init litepcie_module_init(void)
{
int ret;
ret = pci_register_driver(&litepcie_pci_driver);
if (ret < 0) {
printk(KERN_ERR LITEPCIE_NAME " Error while registering PCI driver\n");
goto fail1;
}
ret = alloc_chrdev_region(&litepcie_cdev, 0, LITEPCIE_MINOR_COUNT, LITEPCIE_NAME);
if (ret < 0) {
printk(KERN_ERR LITEPCIE_NAME " Could not allocate char device\n");
goto fail2;
}
cdev_init(&litepcie_cdev_struct, &litepcie_fops);
ret = cdev_add(&litepcie_cdev_struct, litepcie_cdev, LITEPCIE_MINOR_COUNT);
if (ret < 0) {
printk(KERN_ERR LITEPCIE_NAME " Could not register char device\n");
goto fail3;
}
return 0;
fail3:
unregister_chrdev_region(litepcie_cdev, LITEPCIE_MINOR_COUNT);
fail2:
pci_unregister_driver(&litepcie_pci_driver);
fail1:
return ret;
}
static void __exit litepcie_module_exit(void)
{
cdev_del(&litepcie_cdev_struct);
unregister_chrdev_region(litepcie_cdev, LITEPCIE_MINOR_COUNT);
pci_unregister_driver(&litepcie_pci_driver);
}
module_init(litepcie_module_init);
module_exit(litepcie_module_exit);
MODULE_LICENSE("GPL");

View file

@ -1,19 +0,0 @@
CFLAGS=-O2 -Wall -g -I../kernel -MMD
LDFLAGS=-g
CC=gcc
AR=ar
PROGS=litepcie_util
all: $(PROGS)
litepcie_util: litepcie_util.o litepcie_lib.o
$(CC) $(LDFLAGS) -o $@ $^ -lrt -lm
clean:
rm -f $(PROGS) *.o *.a *.d *~
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
-include $(wildcard *.d)

View file

@ -1,31 +0,0 @@
#include <inttypes.h>
#include <math.h>
#include <immintrin.h>
#ifndef _BOOL_defined
#define _BOOL_defined
#undef FALSE
#undef TRUE
typedef int BOOL;
enum {
FALSE = 0,
TRUE = 1,
};
#endif
static inline int sub_mod_int(int a, int b, int m)
{
a -= b;
if (a < 0)
a += m;
return a;
}
static inline int add_mod_int(int a, int b, int m)
{
a += b;
if (a >= m)
a -= m;
return a;
}

View file

@ -1,182 +0,0 @@
/*
* LitePCIe library
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <time.h>
#include <errno.h>
#include "litepcie.h"
#include "cutils.h"
#include "config.h"
#include "csr.h"
#include "flags.h"
#include "litepcie_lib.h"
/*
TODO:
- DMA overflow/underflow detection
*/
void *litepcie_malloc(int size)
{
return malloc(size);
}
void *litepcie_mallocz(int size)
{
void *ptr;
ptr = litepcie_malloc(size);
if (!ptr)
return NULL;
memset(ptr, 0, size);
return ptr;
}
void litepcie_free(void *ptr)
{
free(ptr);
}
void __attribute__((format(printf, 2, 3))) litepcie_log(LitePCIeState *s, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
/* in ms */
int64_t litepcie_get_time_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (int64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000U);
}
LitePCIeState *litepcie_open(const char *device_name)
{
LitePCIeState *s;
s = litepcie_mallocz(sizeof(LitePCIeState));
if (!s)
return NULL;
s->litepcie_fd = open(device_name, O_RDWR);
if (s->litepcie_fd < 0) {
perror(device_name);
goto fail;
}
/* map the DMA buffers */
if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_GET_MMAP_INFO, &s->mmap_info) != 0) {
perror("LITEPCIE_IOCTL_GET_MMAP_INFO");
exit(1);
}
s->dma_tx_buf = mmap(NULL, s->mmap_info.dma_tx_buf_size *
s->mmap_info.dma_tx_buf_count,
PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd,
s->mmap_info.dma_tx_buf_offset);
if (s->dma_tx_buf == MAP_FAILED) {
perror("mmap1");
exit(1);
}
s->dma_rx_buf = mmap(NULL, s->mmap_info.dma_rx_buf_size *
s->mmap_info.dma_rx_buf_count,
PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd,
s->mmap_info.dma_rx_buf_offset);
if (s->dma_rx_buf == MAP_FAILED) {
perror("mmap2");
exit(1);
}
/* map the registers */
s->reg_buf = mmap(NULL, s->mmap_info.reg_size,
PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd,
s->mmap_info.reg_offset);
if (s->reg_buf == MAP_FAILED) {
perror("mmap2");
exit(1);
}
s->dma_tx_buf_size = s->mmap_info.dma_tx_buf_size;
s->dma_rx_buf_size = s->mmap_info.dma_rx_buf_size;
pthread_mutex_init(&s->fifo_mutex, NULL);
return s;
fail:
litepcie_close(s);
return NULL;
}
void litepcie_dma_start(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback)
{
struct litepcie_ioctl_dma_start dma_start;
if (buf_count > DMA_BUFFER_COUNT) {
litepcie_log(s, "unsupported buf_count\n");
exit(1);
}
s->tx_buf_size = s->rx_buf_size = buf_size;
s->tx_buf_count = s->rx_buf_count = buf_count;
dma_start.dma_flags = 0;
if (is_loopback)
dma_start.dma_flags |= DMA_LOOPBACK_ENABLE;
dma_start.tx_buf_size = s->tx_buf_size;
dma_start.tx_buf_count = s->tx_buf_count;
dma_start.rx_buf_size = s->rx_buf_size;
dma_start.rx_buf_count = s->rx_buf_count;
if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_START, &dma_start) < 0) {
perror("LITEPCIE_IOCTL_DMA_START");
}
}
void litepcie_dma_stop(LitePCIeState *s)
{
if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_STOP, NULL) < 0) {
perror("LITEPCIE_IOCTL_DMA_STOP");
}
}
void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val)
{
*(volatile uint32_t *)(s->reg_buf + addr) = val;
}
uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr)
{
return *(volatile uint32_t *)(s->reg_buf + addr);
}
void litepcie_close(LitePCIeState *s)
{
pthread_mutex_destroy(&s->fifo_mutex);
if (s->dma_tx_buf) {
munmap(s->dma_tx_buf, s->mmap_info.dma_tx_buf_size *
s->mmap_info.dma_tx_buf_count);
}
if (s->dma_rx_buf) {
munmap(s->dma_rx_buf, s->mmap_info.dma_rx_buf_size *
s->mmap_info.dma_rx_buf_count);
}
if (s->reg_buf)
munmap(s->reg_buf, s->mmap_info.reg_size);
if (s->litepcie_fd >= 0)
close(s->litepcie_fd);
litepcie_free(s);
}

View file

@ -1,53 +0,0 @@
/*
* LitePCIe library
*
*/
#ifndef LITEPCIE_LIB_H
#define LITEPCIE_LIB_H
#include <stdarg.h>
#include <pthread.h>
#define LITEPCIE_FILENAME "/dev/litepcie0"
typedef struct {
int litepcie_fd;
struct litepcie_ioctl_mmap_info mmap_info;
uint8_t *dma_tx_buf;
int dma_tx_buf_size;
uint8_t *dma_rx_buf;
int dma_rx_buf_size;
uint8_t *reg_buf;
unsigned int tx_buf_size; /* in bytes */
unsigned int tx_buf_count; /* number of buffers */
unsigned int rx_buf_size; /* in bytes */
unsigned int rx_buf_count; /* number of buffers */
unsigned int tx_buf_len; /* in samples */
unsigned int rx_buf_len; /* in samples */
pthread_mutex_t fifo_mutex;
int64_t rx_timestamp; /* timestamp (in samples) of the current RX buffer */
unsigned int rx_buf_index; /* index of the current RX buffer */
unsigned int rx_buf_next; /* index of the next buffer after the
last received buffer */
BOOL has_rx_timestamp; /* true if received at least one buffer */
int64_t tx_underflow_count; /* TX too late */
int64_t rx_overflow_count; /* RX too late */
} LitePCIeState;
void *litepcie_malloc(int size);
void *litepcie_mallocz(int size);
void litepcie_free(void *ptr);
void __attribute__((format(printf, 2, 3))) litepcie_log(LitePCIeState *s, const char *fmt, ...);
int64_t litepcie_get_time_ms(void);
LitePCIeState *litepcie_open(const char *device_name);
void litepcie_close(LitePCIeState *s);
void litepcie_dma_start(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback);
void litepcie_dma_stop(LitePCIeState *s);
void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val);
uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr);
#endif /* LITEPCIE_LIB_H */

View file

@ -1,259 +0,0 @@
/*
* LitePCIe utilities
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <time.h>
#include "litepcie.h"
#include "cutils.h"
#include "config.h"
#include "csr.h"
#include "flags.h"
#include "litepcie_lib.h"
static inline uint32_t seed_to_data(uint32_t seed)
{
#if 1
/* more random but slower */
return seed * 0x31415976 + 1;
#else
/* simplify debug: just copy the counter */
return seed;
#endif
}
static void write_pn_data(uint32_t *dst, int count, uint32_t *pseed)
{
int i;
uint32_t seed;
seed = *pseed;
for(i = 0; i < count; i++) {
dst[i] = seed_to_data(seed);
seed++;
}
*pseed = seed;
}
/* Return the number of errors */
static int check_pn_data(const uint32_t *tab, int count,
uint32_t *pseed)
{
int i, errors;
uint32_t seed;
errors = 0;
seed = *pseed;
for(i = 0; i < count; i++) {
if (tab[i] != seed_to_data(seed)) {
errors++;
}
seed++;
}
*pseed = seed;
return errors;
}
#define MAX_SHIFT_OFFSET 128
/* test DMA with a buffer size of buf_size bytes in loopback
mode. */
void dma_test(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback)
{
int is_first, tx_buf_num, buf_num_cur, buf_num_next;
struct litepcie_ioctl_dma_wait dma_wait;
int buf_stats_count; /* statistics */
int64_t last_time;
uint32_t tx_seed, rx_seed;
int buf_rx_count, first_rx_buf, rx_errors, shift, d, tx_underflows;
litepcie_dma_start(s, buf_size, buf_count, is_loopback);
is_first = 1;
buf_num_cur = 0; /* next buffer to receive */
/* PN data TX and RX state */
tx_seed = MAX_SHIFT_OFFSET;
rx_seed = 0;
buf_rx_count = 0;
first_rx_buf = 1;
/* statistics */
buf_stats_count = 0;
last_time = litepcie_get_time_ms();
rx_errors = 0;
shift = 0;
tx_underflows = 0;
for(;;) {
/* wait until at least one buffer is received */
dma_wait.timeout = 1000; /* 1 second timeout */
dma_wait.tx_wait = FALSE;
dma_wait.tx_buf_num = -1; /* not used */
if (is_first) {
dma_wait.rx_buf_num = -1; /* don't wait, just get the last
received buffer number */
} else {
dma_wait.rx_buf_num = sub_mod_int(buf_num_cur, 1, buf_count);
}
/* wait until the current buffer number is different from
dma_wait.buf_num */
if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_WAIT, &dma_wait) < 0) {
perror("LITEPCIE_IOCTL_DMA_WAIT");
}
if (is_first) {
buf_num_cur = dma_wait.rx_buf_num;
is_first = 0;
}
buf_num_next = add_mod_int(dma_wait.rx_buf_num, 1, buf_count);
while (buf_num_cur != buf_num_next) {
/* write the TX data 4/10 of a DMA cycle in the future */
tx_buf_num = add_mod_int(buf_num_cur, 4*buf_count/10, buf_count);
d = sub_mod_int(tx_buf_num, buf_num_next, buf_count);
if (d >= (buf_count / 2)) {
/* we are too late in writing data, which necessarily
gives read errors. */
tx_underflows++;
}
write_pn_data((uint32_t *)(s->dma_tx_buf +
tx_buf_num * s->dma_tx_buf_size),
s->tx_buf_size >> 2, &tx_seed);
if (buf_rx_count >= 4*buf_count/10) {
const uint32_t *rx_buf;
int rx_buf_len;
rx_buf = (uint32_t *)(s->dma_rx_buf + buf_num_cur * s->dma_rx_buf_size);
rx_buf_len = s->rx_buf_size >> 2;
if (first_rx_buf) {
uint32_t seed;
/* find the initial shift */
for(shift = 0; shift < 2 * MAX_SHIFT_OFFSET; shift++) {
seed = rx_seed + shift;
rx_errors = check_pn_data(rx_buf, rx_buf_len, &seed);
if (rx_errors <= (rx_buf_len / 2)) {
rx_seed = seed;
break;
}
}
if (shift == 2 * MAX_SHIFT_OFFSET) {
printf("Cannot find initial data\n");
exit(1);
} else {
printf("RX shift = %d\n",
-(shift - MAX_SHIFT_OFFSET));
}
first_rx_buf = 0;
} else {
/* count the number of errors */
rx_errors += check_pn_data(rx_buf, rx_buf_len, &rx_seed);
}
} else {
buf_rx_count++;
}
buf_num_cur = add_mod_int(buf_num_cur, 1, buf_count);
/* statistics */
if (++buf_stats_count == 10000) {
int64_t duration;
duration = litepcie_get_time_ms() - last_time;
printf("%0.1f Gb/sec %0.1f bufs/sec tx_underflows=%d errors=%d\n",
(double)buf_stats_count * buf_size * 8 / ((double)duration * 1e6),
(double)buf_stats_count * 1000 / (double)duration,
tx_underflows, rx_errors);
last_time = litepcie_get_time_ms();
buf_stats_count = 0;
tx_underflows = 0;
rx_errors = 0;
}
}
}
litepcie_dma_stop(s);
}
void dma_loopback_test(void)
{
LitePCIeState *s;
s = litepcie_open(LITEPCIE_FILENAME);
if (!s) {
fprintf(stderr, "Could not init driver\n");
exit(1);
}
dma_test(s, 16*1024, DMA_BUFFER_COUNT, TRUE);
litepcie_close(s);
}
void dump_version(void)
{
LitePCIeState *s;
s = litepcie_open(LITEPCIE_FILENAME);
if (!s) {
fprintf(stderr, "Could not init driver\n");
exit(1);
}
printf("sysid=0x%x\n", litepcie_readl(s, CSR_IDENTIFIER_SYSID_ADDR));
printf("frequency=%d\n", litepcie_readl(s, CSR_IDENTIFIER_FREQUENCY_ADDR));
litepcie_close(s);
}
void help(void)
{
printf("usage: litepcie_util cmd [args...]\n"
"\n"
"available commands:\n"
"dma_loopback_test test DMA loopback operation\n"
"version return fpga version\n"
);
exit(1);
}
int main(int argc, char **argv)
{
const char *cmd;
int c;
for(;;) {
c = getopt(argc, argv, "h");
if (c == -1)
break;
switch(c) {
case 'h':
help();
break;
default:
exit(1);
}
}
if (optind >= argc)
help();
cmd = argv[optind++];
if (!strcmp(cmd, "dma_loopback_test")) {
dma_loopback_test();
} else if (!strcmp(cmd, "version")) {
dump_version();
} else {
help();
}
return 0;
}

View file

@ -1,65 +0,0 @@
import string
import mmap
import sys
from misoclib.tools.litescope.software.driver.reg import *
class LitePCIeWishboneDriverLinux:
def __init__(self, bar, bar_size, addrmap=None, busword=8, debug=False):
self.bar = bar
self.bar_size = bar_size
self.debug = debug
self.f = None
self.mmap = None
self.regs = build_map(addrmap, busword, self.read, self.write)
def open(self):
self.f = open(self.bar, "r+b")
self.f.flush()
self.mmap = mmap.mmap(self.f.fileno(), self.bar_size)
def close(self):
self.mmap.close()
self.f.close()
def read(self, addr, burst_length=1):
datas = []
for i in range(burst_length):
self.mmap.seek(addr + 4*i)
dat = self.mmap.read(4)
val = dat[3] << 24
val |= dat[2] << 16
val |= dat[1] << 8
val |= dat[0] << 0
if self.debug:
print("RD {:08X} @ {:08X}".format(val, addr + 4*i))
datas.append(val)
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]
for i, dat in enumerate(data):
dat_bytes = [0, 0, 0, 0]
dat_bytes[3] = (dat >> 24) & 0xff
dat_bytes[2] = (dat >> 16) & 0xff
dat_bytes[1] = (dat >> 8) & 0xff
dat_bytes[0] = (dat >> 0) & 0xff
self.mmap[addr + 4*i:addr + 4*(i+1)] = bytes(dat_bytes)
if self.debug:
print("WR {:08X} @ {:08X}".format(dat, (addr + i)*4))
def LitePCIeWishboneDriver(*args, **kwargs):
if sys.platform == "win32" or sys.platform == "cygwin":
raise NotImplementedError
else:
return LitePCIeWishboneDriverLinux(*args, **kwargs)

View file

@ -1,10 +0,0 @@
MSCDIR = ../../../../
PYTHON = python3
CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
wishbone_tb:
$(CMD) wishbone_tb.py
dma_tb:
$(CMD) dma_tb.py

View file

@ -1,36 +0,0 @@
import random
def print_with_prefix(s, prefix=""):
if not isinstance(s, str):
s = s.__repr__()
s = s.split("\n")
for l in s:
print(prefix + l)
def seed_to_data(seed, random=True):
if random:
return (seed * 0x31415979 + 1) & 0xffffffff
else:
return seed
def check(ref, res):
if isinstance(ref, int):
return 0, 1, int(ref != res)
else:
shift = 0
while((ref[0] != res[0]) and (len(res) > 1)):
res.pop(0)
shift += 1
length = min(len(ref), len(res))
errors = 0
for i in range(length):
if ref.pop(0) != res.pop(0):
errors += 1
return shift, length, errors
def randn(max_n):
return random.randint(0, max_n-1)

View file

@ -1,177 +0,0 @@
import random
from migen.fhdl.std import *
from migen.sim.generic import run_simulation
from migen.actorlib.structuring import Converter
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core import Endpoint
from misoclib.com.litepcie.core.irq import interrupt_controller
from misoclib.com.litepcie.frontend.dma import writer, reader
from misoclib.com.litepcie.test.common import *
from misoclib.com.litepcie.test.model.host import *
DMA_READER_IRQ = 1
DMA_WRITER_IRQ = 2
root_id = 0x100
endpoint_id = 0x400
max_length = Signal(8, reset=128)
dma_size = 1024
class DMADriver():
def __init__(self, dma, selfp):
self.dma = dma
self.selfp = selfp
def set_prog_mode(self):
dma = getattr(self.selfp, self.dma)
dma.table._loop_prog_n.storage = 0
yield
def set_loop_mode(self):
dma = getattr(self.selfp, self.dma)
dma.table._loop_prog_n.storage = 1
yield
def flush(self):
dma = getattr(self.selfp, self.dma)
dma.table._flush.re = 1
yield
dma.table._flush.re = 0
yield
def program_descriptor(self, address, length):
value = address
value |= (length << 32)
dma = getattr(self.selfp, self.dma)
dma.table._value.storage = value
dma.table._we.r = 1
dma.table._we.re = 1
yield
dma.table._we.re = 0
yield
def enable(self):
dma = getattr(self.selfp, self.dma)
dma._enable.storage = 1
yield
def disable(self):
dma = getattr(self.selfp, self.dma)
dma._enable.storage = 0
yield
class InterruptHandler(Module):
def __init__(self, debug=False):
self.debug = debug
self.sink = Sink(interrupt_layout())
self.dma_writer_irq = 0
def set_tb_selfp(self, tb_selfp):
self.tb_selfp = tb_selfp
def do_simulation(self, selfp):
tb_selfp = self.tb_selfp
tb_selfp.irq_controller._clear.r = 0
tb_selfp.irq_controller._clear.re = 0
selfp.sink.ack = 1
self.dma_writer_irq = 0
if selfp.sink.stb and (selfp.simulator.cycle_counter%4 == 0):
# get vector
irq_vector = tb_selfp.irq_controller._vector.status
# handle irq
if irq_vector & DMA_READER_IRQ:
if self.debug:
print("DMA_READER IRQ : {}".format(tb_selfp.dma_reader.table._index.status))
# clear irq_controller
tb_selfp.irq_controller._clear.re = 1
tb_selfp.irq_controller._clear.r |= DMA_READER_IRQ
if irq_vector & DMA_WRITER_IRQ:
if self.debug:
print("DMA_WRITER IRQ : {}".format(tb_selfp.dma_writer.table._index.status))
# clear irq_controller
tb_selfp.irq_controller._clear.re = 1
tb_selfp.irq_controller._clear.r |= DMA_WRITER_IRQ
self.dma_writer_irq = 1
test_size = 16*1024
class TB(Module):
def __init__(self, with_converter=False):
self.submodules.host = Host(64, root_id, endpoint_id,
phy_debug=False,
chipset_debug=False, chipset_split=True, chipset_reordering=True,
host_debug=True)
self.submodules.endpoint = Endpoint(self.host.phy, max_pending_requests=8, with_reordering=True)
self.submodules.dma_reader = reader.DMAReader(self.endpoint, self.endpoint.crossbar.get_master_port(read_only=True))
self.submodules.dma_writer = writer.DMAWriter(self.endpoint, self.endpoint.crossbar.get_master_port(write_only=True))
if with_converter:
self.submodules.up_converter = Converter(dma_layout(16), dma_layout(64))
self.submodules.down_converter = Converter(dma_layout(64), dma_layout(16))
self.comb += [
self.dma_reader.source.connect(self.down_converter.sink),
self.down_converter.source.connect(self.up_converter.sink),
self.up_converter.source.connect(self.dma_writer.sink)
]
else:
self.comb += self.dma_reader.source.connect(self.dma_writer.sink)
self.submodules.irq_controller = interrupt_controller.InterruptController(2)
self.comb += [
self.irq_controller.irqs[log2_int(DMA_READER_IRQ)].eq(self.dma_reader.table.irq),
self.irq_controller.irqs[log2_int(DMA_WRITER_IRQ)].eq(self.dma_writer.table.irq)
]
self.submodules.irq_handler = InterruptHandler()
self.comb += self.irq_controller.source.connect(self.irq_handler.sink)
def gen_simulation(self, selfp):
self.host.malloc(0x00000000, test_size*2)
self.host.chipset.enable()
host_datas = [seed_to_data(i, True) for i in range(test_size//4)]
self.host.write_mem(0x00000000, host_datas)
dma_reader_driver = DMADriver("dma_reader", selfp)
dma_writer_driver = DMADriver("dma_writer", selfp)
self.irq_handler.set_tb_selfp(selfp)
yield from dma_reader_driver.set_prog_mode()
yield from dma_reader_driver.flush()
for i in range(8):
yield from dma_reader_driver.program_descriptor((test_size//8)*i, test_size//8)
yield from dma_writer_driver.set_prog_mode()
yield from dma_writer_driver.flush()
for i in range(8):
yield from dma_writer_driver.program_descriptor(test_size + (test_size//8)*i, test_size//8)
selfp.irq_controller._enable.storage = DMA_READER_IRQ | DMA_WRITER_IRQ
yield from dma_reader_driver.enable()
yield from dma_writer_driver.enable()
i = 0
while i != 8:
i += self.irq_handler.dma_writer_irq
yield
for i in range(100):
yield
loopback_datas = self.host.read_mem(test_size, test_size)
s, l, e = check(host_datas, loopback_datas)
print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
if __name__ == "__main__":
run_simulation(TB(with_converter=False), ncycles=4000, vcd_name="my.vcd", keep_files=True)

View file

@ -1,142 +0,0 @@
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.test.common import *
from misoclib.com.litepcie.test.model.tlp import *
def print_chipset(s):
print_with_prefix(s, "[CHIPSET] ")
def find_cmp_tags(queue):
tags = []
for tag, dwords in queue:
if tag not in tags:
tags.append(tag)
return tags
def find_first_cmp_msg(queue, msg_tag):
for i, (tag, dwords) in enumerate(queue):
if tag == msg_tag:
return i
# Chipset model
class Chipset(Module):
def __init__(self, phy, root_id, debug=False, with_reordering=False):
self.phy = phy
self.root_id = root_id
self.debug = debug
self.with_reordering = with_reordering
###
self.rd32_data = []
self.cmp_queue = []
self.en = False
def set_host_callback(self, callback):
self.host_callback = callback
def enable(self):
self.en = True
def disable(self):
self.en = False
def wr32(self, adr, data):
wr32 = WR32()
wr32.fmt = 0b10
wr32.type = 0b00000
wr32.length = len(data)
wr32.first_be = 0xf
wr32.address = adr
wr32.requester_id = self.root_id
dwords = wr32.encode_dwords(data)
if self.debug:
print_chipset(">>>>>>>>")
print_chipset(parse_dwords(dwords))
yield from self.phy.send_blocking(dwords)
def rd32(self, adr, length=1):
rd32 = RD32()
rd32.fmt = 0b00
rd32.type = 0b00000
rd32.length = length
rd32.first_be = 0xf
rd32.address = adr
rd32.requester_id = self.root_id
dwords = rd32.encode_dwords()
if self.debug:
print_chipset(">>>>>>>>")
print_chipset(parse_dwords(dwords))
yield from self.phy.send_blocking(dwords)
dwords = None
while dwords is None:
dwords = self.phy.receive()
yield
cpld = CPLD(dwords)
self.rd32_data = cpld.data
if self.debug:
print_chipset("<<<<<<<<")
print_chipset(cpld)
def cmp(self, req_id, data, byte_count=None, lower_address=0, tag=0, with_split=False):
if with_split:
d = random.choice([64, 128, 256])
n = byte_count//d
if n == 0:
self.cmp(req_id, data, byte_count=byte_count, tag=tag)
else:
for i in range(n):
cmp_data = data[i*byte_count//(4*n):(i+1)*byte_count//(4*n)]
self.cmp(req_id, cmp_data, byte_count=byte_count-i*byte_count//n, tag=tag)
else:
if len(data) == 0:
fmt = 0b00
cpl = CPL()
else:
fmt = 0b10
cpl = CPLD()
cpl.fmt = fmt
cpl.type = 0b01010
cpl.length = len(data)
cpl.lower_address = lower_address
cpl.requester_id = req_id
cpl.completer_id = self.root_id
if byte_count is None:
cpl.byte_count = len(data)*4
else:
cpl.byte_count = byte_count
cpl.tag = tag
if len(data) == 0:
dwords = cpl.encode_dwords()
else:
dwords = cpl.encode_dwords(data)
self.cmp_queue.append((tag, dwords))
def cmp_callback(self):
if len(self.cmp_queue):
if self.with_reordering:
tags = find_cmp_tags(self.cmp_queue)
tag = random.choice(tags)
n = find_first_cmp_msg(self.cmp_queue, tag)
tag, dwords = self.cmp_queue.pop(n)
else:
tag, dwords = self.cmp_queue.pop(0)
if self.debug:
print_chipset(">>>>>>>>")
print_chipset(parse_dwords(dwords))
self.phy.send(dwords)
def gen_simulation(self, selfp):
while True:
if self.en:
dwords = self.phy.receive()
if dwords is not None:
msg = parse_dwords(dwords)
if self.debug:
print_chipset(" <<<<<<<< (Callback)")
print_chipset(msg)
self.host_callback(msg)
self.cmp_callback()
yield

View file

@ -1,64 +0,0 @@
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.test.common import *
from misoclib.com.litepcie.test.model.phy import PHY
from misoclib.com.litepcie.test.model.tlp import *
from misoclib.com.litepcie.test.model.chipset import Chipset
def print_host(s):
print_with_prefix(s, "[HOST] ")
# Host model
class Host(Module):
def __init__(self, dw, root_id, endpoint_id, bar0_size=1*MB,
phy_debug=False,
chipset_debug=False, chipset_split=False, chipset_reordering=False,
host_debug=False):
self.debug = host_debug
self.chipset_split = chipset_split
###
self.submodules.phy = PHY(dw, endpoint_id, bar0_size, phy_debug)
self.submodules.chipset = Chipset(self.phy, root_id, chipset_debug, chipset_reordering)
self.chipset.set_host_callback(self.callback)
self.rd32_queue = []
def malloc(self, base, length):
self.base = base
self.buffer = [0]*(length//4)
def write_mem(self, adr, data):
if self.debug:
print_host("Writing {} bytes at 0x{:08x}".format(len(data)*4, adr))
current_adr = (adr-self.base)//4
for i in range(len(data)):
self.buffer[current_adr+i] = data[i]
def read_mem(self, adr, length=1):
if self.debug:
print_host("Reading {} bytes at 0x{:08x}".format(length, adr))
current_adr = (adr-self.base)//4
data = []
for i in range(length//4):
data.append(self.buffer[current_adr+i])
return data
def callback(self, msg):
if isinstance(msg, WR32):
address = msg.address*4
self.write_mem(address, msg.data)
elif isinstance(msg, RD32):
self.rd32_queue.append(msg)
def gen_simulation(self, selfp):
while True:
if len(self.rd32_queue):
msg = self.rd32_queue.pop(0)
address = msg.address*4
length = msg.length*4
data = self.read_mem(address, length)
self.chipset.cmp(msg.requester_id, data, byte_count=length, tag=msg.tag, with_split=self.chipset_split)
else:
yield

View file

@ -1,144 +0,0 @@
import math
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
from misoclib.com.litepcie.test.common import *
def print_chipset(s):
print_with_prefix(s, "[PHY] ")
# PHY Layer model
class PHYPacket():
def __init__(self, dat=[], be=[]):
self.dat = dat
self.be = be
self.start = 1
self.done = 0
class PHYSource(Module):
def __init__(self, dw):
self.source = Source(phy_layout(dw))
###
self.packets = []
self.packet = PHYPacket()
self.packet.done = 1
def send(self, packet):
self.packets.append(packet)
def send_blocking(self, packet):
self.send(packet)
while packet.done == 0:
yield
def do_simulation(self, selfp):
if len(self.packets) and self.packet.done:
self.packet = self.packets.pop(0)
if self.packet.start and not self.packet.done:
selfp.source.stb = 1
selfp.source.sop = 1
selfp.source.dat = self.packet.dat.pop(0)
selfp.source.be = self.packet.be.pop(0)
self.packet.start = 0
elif selfp.source.stb == 1 and selfp.source.ack == 1:
selfp.source.sop = 0
selfp.source.eop = (len(self.packet.dat) == 1)
if len(self.packet.dat) > 0:
selfp.source.stb = 1
selfp.source.dat = self.packet.dat.pop(0)
selfp.source.be = self.packet.be.pop(0)
else:
self.packet.done = 1
selfp.source.stb = 0
class PHYSink(Module):
def __init__(self, dw):
self.sink = Sink(phy_layout(dw))
###
self.packet = PHYPacket()
def receive(self):
self.packet.done = 0
while self.packet.done == 0:
yield
def do_simulation(self, selfp):
self.packet.done = 0
selfp.sink.ack = 1
if selfp.sink.stb == 1 and selfp.sink.sop == 1:
self.packet.start = 1
self.packet.dat = [selfp.sink.dat]
self.packet.be = [selfp.sink.be]
elif selfp.sink.stb:
self.packet.start = 0
self.packet.dat.append(selfp.sink.dat)
self.packet.be.append(selfp.sink.be)
if (selfp.sink.stb == 1 and selfp.sink.eop == 1):
self.packet.done = 1
class PHY(Module):
def __init__(self, dw, id, bar0_size, debug):
self.dw = dw
self.id = id
self.bar0_size = bar0_size
self.bar0_mask = get_bar_mask(bar0_size)
self.max_request_size = 512
self.max_payload_size = 128
self.submodules.phy_source = PHYSource(dw)
self.submodules.phy_sink = PHYSink(dw)
self.source = self.phy_source.source
self.sink = self.phy_sink.sink
def dwords2packet(self, dwords):
ratio = self.dw//32
length = math.ceil(len(dwords)/ratio)
dat = [0]*length
be = [0]*length
for n in range(length):
for i in reversed(range(ratio)):
dat[n] = dat[n] << 32
be[n] = be[n] << 4
try:
dat[n] |= dwords[2*n+i]
be[n] |= 0xF
except:
pass
return dat, be
def send(self, dwords):
dat, be = self.dwords2packet(dwords)
packet = PHYPacket(dat, be)
self.phy_source.send(packet)
def send_blocking(self, dwords):
dat, be = self.dwords2packet(dwords)
packet = PHYPacket(dat, be)
yield from self.phy_source.send_blocking(packet)
def packet2dwords(self, p_dat, p_be):
ratio = self.dw//32
dwords = []
for dat, be in zip(p_dat, p_be):
for i in range(ratio):
dword_be = (be >> (4*i)) & 0xf
dword_dat = (dat >> (32*i)) & 0xffffffff
if dword_be == 0xf:
dwords.append(dword_dat)
return dwords
def receive(self):
if self.phy_sink.packet.done:
self.phy_sink.packet.done = 0
return self.packet2dwords(self.phy_sink.packet.dat, self.phy_sink.packet.be)
else:
return None

View file

@ -1,94 +0,0 @@
from misoclib.com.litepcie.common import *
from misoclib.com.litepcie.core.packet.common import *
# TLP Layer model
def get_field_data(field, dwords):
return (dwords[field.byte//4] >> field.offset) & (2**field.width-1)
tlp_headers_dict = {
"RD32": tlp_request_header,
"WR32": tlp_request_header,
"CPLD": tlp_completion_header,
"CPL": tlp_completion_header
}
class TLP():
def __init__(self, name, dwords=[0, 0, 0]):
self.name = name
self.header = dwords[:3]
self.data = dwords[3:]
self.dwords = self.header + self.data
self.decode_dwords()
def decode_dwords(self):
for k, v in tlp_headers_dict[self.name].fields.items():
setattr(self, k, get_field_data(v, self.header))
def encode_dwords(self, data=[]):
self.header = [0, 0, 0]
for k, v in tlp_headers_dict[self.name].fields.items():
field = tlp_headers_dict[self.name].fields[k]
self.header[field.byte//4] |= (getattr(self, k) << field.offset)
self.data = data
self.dwords = self.header + self.data
return self.dwords
def __repr__(self):
r = self.name + "\n"
r += "--------\n"
for k in sorted(tlp_headers_dict[self.name].keys()):
r += k + " : 0x{:x}".format(getattr(self, k) + "\n")
if len(self.data) != 0:
r += "data:\n"
for d in self.data:
r += "{:08x}\n".format(d)
return r
class RD32(TLP):
def __init__(self, dwords=[0, 0, 0]):
TLP.__init__(self, "RD32", dwords)
class WR32(TLP):
def __init__(self, dwords=[0, 0, 0]):
TLP.__init__(self, "WR32", dwords)
class CPLD(TLP):
def __init__(self, dwords=[0, 0, 0]):
TLP.__init__(self, "CPLD", dwords)
class CPL():
def __init__(self, dwords=[0, 0, 0]):
TLP.__init__(self, "CPL", dwords)
class Unknown():
def __repr__(self):
r = "UNKNOWN\n"
return r
fmt_type_dict = {
fmt_type_dict["mem_rd32"]: (RD32, 3),
fmt_type_dict["mem_wr32"]: (WR32, 4),
fmt_type_dict["cpld"]: (CPLD, 4),
fmt_type_dict["cpl"]: (CPL, 3)
}
def parse_dwords(dwords):
f = get_field_data(tlp_common_header.fields["fmt"], dwords)
t = get_field_data(tlp_common_header.fields["type"], dwords)
fmt_type = (f << 5) | t
try:
tlp, min_len = fmt_type_dict[fmt_type]
if len(dwords) >= min_len:
return tlp(dwords)
else:
return Unknown()
except:
return Unknown()

View file

@ -1,40 +0,0 @@
from migen.fhdl.std import *
from migen.bus import wishbone
from migen.sim.generic import run_simulation
from misoclib.com.litepcie.core import Endpoint
from misoclib.com.litepcie.frontend.bridge.wishbone import WishboneBridge
from misoclib.com.litepcie.test.common import *
from misoclib.com.litepcie.test.model.host import *
root_id = 0x100
endpoint_id = 0x400
class TB(Module):
def __init__(self):
self.submodules.host = Host(64, root_id, endpoint_id,
phy_debug=False,
chipset_debug=False,
host_debug=False)
self.submodules.endpoint = Endpoint(self.host.phy)
self.submodules.wishbone_bridge = WishboneBridge(self.endpoint, lambda a: 1)
self.submodules.sram = wishbone.SRAM(1024, bus=self.wishbone_bridge.wishbone)
def gen_simulation(self, selfp):
wr_datas = [seed_to_data(i, True) for i in range(64)]
for i in range(64):
yield from self.host.chipset.wr32(i, [wr_datas[i]])
rd_datas = []
for i in range(64):
yield from self.host.chipset.rd32(i)
rd_datas.append(self.host.chipset.rd32_data[0])
s, l, e = check(wr_datas, rd_datas)
print("shift " + str(s) + " / length " + str(l) + " / errors " + str(e))
if __name__ == "__main__":
run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)