Merge pull request #212 from hansfbaier/qmtech-xc7a35t

add QMTECH XC7A35T core board + daughter board
This commit is contained in:
enjoy-digital 2021-05-07 08:32:16 +02:00 committed by GitHub
commit 2c2a9db3cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 523 additions and 34 deletions

View File

@ -120,7 +120,7 @@ The Colorlight5A is a very nice board to start with, cheap, powerful, easy to us
---------------------
| Name | FPGA Family | FPGA device | Sys-Clk | TTY | RAM | PCIe | Ethernet | Flash | SDCard |
|--------------|---------------------|---------------|---------|------|--------------------|-----------|----------------|-------------|--------|
|----------------|---------------------|---------------|---------|------|--------------------|-----------|----------------|-------------|--------|
| AC701 | Xilinx Artix7 | XC7A200T | 100MHz | FTDI | 64-bit ?MB DDR3 | Gen2 X4 | 1Gbps RGMII | 16MB QSPI | Yes* |
| Aller | Xilinx Artix7 | XC7A200T | 100MHz | PCIe | 16-bit 256MB DDR3 | Gen2 X4 | No | 128MB QSPI | No |
| Arty(A7) | Xilinx Artix7 | XC7A35T | 100MHz | FTDI | 16-bit 256MB DDR3 | No | 100Mbps MII | 16MB QSPI | No |
@ -146,6 +146,7 @@ The Colorlight5A is a very nice board to start with, cheap, powerful, easy to us
| Nereid | Xilinx Kintex7 | XC7K160T | 100MHz | PCIe | 64-bit 4GB DDR3 | Gen2 X4 | No | 16MB QSPI | No |
| Nexys4DDR | Xilinx Artix7 | XC7A100T | 100MHz | FTDI | 16-bit 128MB DDR2 | No | 100Mbps RMII | 16MB QSPI* | Yes |
| Nexys Video | Xilinx Artix7 | XC7A200T | 100MHz | FTDI | 16-bit 512MB DDR3 | No | 1Gbps RMII | 32MB QSPI* | Yes |
| QMTech XC7A35T | Xilinx Artix7 | XC7A35T | 100MHz | FTDI | 16-bit 256MB DDR3 | No | 1Gbps GMII** | 16MB QSPI | Yes**|
| SP605 | Xilinx Spartan6 | XC6SLX45T | 100MHz | FTDI | 16-bit 128MB DDR3* | Gen1 X1* | 1Gbps GMII | 8MB QSPI* | Yes* |
| Tagus | Xilinx Artix7 | XC7A200T | 100MHz | PCIe | 16-bit 256MB DDR3 | Gen2 X1 | 1Gbps-BASE-X* | 16MB QSPI* | No |
| VC707 | Xilinx Virex7 | XC7VX485T | 125MHz | FTDI | 64-bit 1GB DDR3 | Gen3 X8* | 1Gbps GMII | 16MB QSPI* | Yes* |
@ -155,3 +156,4 @@ The Colorlight5A is a very nice board to start with, cheap, powerful, easy to us
| Zybo Z7 | Xilinx ZynqU+ | XC7Z010 | 125MHz | FTDI | 64-bit 1GB DDR4 | No | 1Gbps RGMII* | 64MB QSPI* | Yes* |
\* Present on the board but not yet supported or validated with LiteX.
\*\* available on the daughterboard

View File

@ -0,0 +1,106 @@
from litex.build.generic_platform import Subsignal, Pins, IOStandard, Misc
class QMTechDaughterboard:
"""
the QMTech daughterboard contains standard peripherals
and can be used with a number of different FPGA core boards
source: https://www.aliexpress.com/item/1005001829520314.html
"""
def __init__(self, io_standard) -> None:
"""
because the board can be used with FPGAs core boards from
different vendors, the constructor needs the vendor specific IOStandard
"""
self.io = [
("serial", 0,
Subsignal("rx", Pins("J2:15")),
Subsignal("tx", Pins("J2:16")),
io_standard
),
("user_led", 0, Pins("J2:40"), io_standard),
("user_led", 1, Pins("J2:39"), io_standard),
("user_led", 2, Pins("J2:38"), io_standard),
("user_led", 3, Pins("J2:37"), io_standard),
("user_led", 4, Pins("J2:36"), io_standard),
("user_btn", 0, Pins("J3:7"), io_standard),
("user_btn", 1, Pins("J2:44"), io_standard),
("user_btn", 2, Pins("J2:43"), io_standard),
("user_btn", 3, Pins("J2:42"), io_standard),
("user_btn", 4, Pins("J2:41"), io_standard),
# GMII Ethernet
("eth_clocks", 0,
Subsignal("tx", Pins("J3:22")),
Subsignal("gtx", Pins("J3:29")),
Subsignal("rx", Pins("J3:37")),
io_standard
),
("eth", 0,
# rst is hardwired on the board
#Subsignal("rst_n", Pins("-")),
Subsignal("int_n", Pins("J3:26")),
Subsignal("mdio", Pins("J3:15")),
Subsignal("mdc", Pins("J3:16")),
Subsignal("rx_dv", Pins("J3:42")),
Subsignal("rx_er", Pins("J3:32")),
Subsignal("rx_data", Pins("J3:41 J3:40 J3:39 J3:38 J3:36 J3:35 J3:34 J3:33")),
Subsignal("tx_en", Pins("J3:28")),
Subsignal("tx_er", Pins("J3:17")),
Subsignal("tx_data", Pins("J3:27 J3:25 J3:24 J3:23 J3:21 J3:20 J3:19 J3:18")),
Subsignal("col", Pins("J3:31")),
Subsignal("crs", Pins("J3:30")),
io_standard
),
# Seven Segment
("seven_seg_ctl", 0, Pins("J2:33"), io_standard),
("seven_seg_ctl", 1, Pins("J2:27"), io_standard),
("seven_seg_ctl", 2, Pins("J2:35"), io_standard),
("seven_seg", 0, Pins("J2:31 J2:26 J2:28 J2:32 J2:34 J2:29 J2:25 J2:30"), io_standard),
# VGA
("vga", 0,
Subsignal("hsync_n", Pins("J3:44")),
Subsignal("vsync_n", Pins("J3:43")),
Subsignal("r", Pins("J3:57 J3:56 J3:59 J3:58 J3:60")),
Subsignal("g", Pins("J3:51 J3:50 J3:53 J3:52 J3:54 J3:55")),
Subsignal("b", Pins("J3:46 J3:45 J3:48 J3:47 J3:49")),
io_standard
),
# PullUp resistors are on the board, so we don't need them in the FPGA
("sdcard", 0,
Subsignal("data", Pins("J3:10 J3:9 J3:14 J3:13")),
Subsignal("cmd", Pins("J3:12")),
Subsignal("clk", Pins("J3:11")),
Subsignal("cd", Pins("J3:8")),
Misc("SLEW=FAST"),
io_standard,
),
]
connectors = [
("pmoda", "J2:17 J2:19 J2:21 J2:23 J2:18 J2:20 J2:22 J2:24"), #J10
("pmodb", "J2:7 J2:9 J2:11 J2:13 J2:8 J2:10 J2:12 J2:14"), #J11
("J1", {
3: "J2:60",
4: "J2:59",
5: "J2:58",
6: "J2:57",
7: "J2:56",
8: "J2:55",
9: "J2:54",
10: "J2:53",
11: "J2:52",
12: "J2:51",
13: "J2:50",
14: "J2:49",
15: "J2:48",
16: "J2:47",
17: "J2:46",
18: "J2:45"
}),
]

View File

@ -0,0 +1,179 @@
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2021 Hans Baier <hansfbaier@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
from litex.build.generic_platform import Pins, Subsignal, IOStandard, Misc
from litex.build.xilinx import XilinxPlatform
from litex.build.openocd import OpenOCD
# IOs ----------------------------------------------------------------------------------------------
_io = [
# Clk / Rst
("clk50", 0, Pins("N11"), IOStandard("LVCMOS33")),
# The core board does not have a USB serial on it,
# so you will have to attach an USB to serial adapter
# on these pins
("gpio_serial", 0,
Subsignal("tx", Pins("J2:7")),
Subsignal("rx", Pins("J2:8")),
IOStandard("LVCMOS33")
),
# SPIFlash
# MT25QL128
("spiflash4x", 0, # clock needs to be accessed through STARTUPE2
Subsignal("cs_n", Pins("L12")),
Subsignal("clk", Pins("E8")),
Subsignal("dq", Pins("J13", "J14", "K15", "K16")),
IOStandard("LVCMOS33")
),
# DDR3 SDRAM
# MT41J128M16JT-125K
("ddram", 0,
Subsignal("a", Pins("B14 C8 A14 C14 C9 B10 D9 A12 D8 A13 B12 A9 A8 B11"),
IOStandard("SSTL135")),
Subsignal("ba", Pins("C16 A15 B15"), IOStandard("SSTL135")),
Subsignal("ras_n", Pins("B16"), IOStandard("SSTL135")),
Subsignal("cas_n", Pins("C11"), IOStandard("SSTL135")),
Subsignal("we_n", Pins("C12"), IOStandard("SSTL135")),
# cs_n is hardwired on the board
#Subsignal("cs_n", Pins("-"), IOStandard("SSTL135")),
Subsignal("dm", Pins("F12 H11"), IOStandard("SSTL135")),
Subsignal("dq", Pins(
"F15 F13 E16 D11 E12 E13 D16 E11",
"G12 J16 G16 J15 H14 H12 H16 H13"),
IOStandard("SSTL135"),
Misc("IN_TERM=UNTUNED_SPLIT_40")),
Subsignal("dqs_p", Pins("D14 G14"),
IOStandard("DIFF_SSTL135"),
Misc("IN_TERM=UNTUNED_SPLIT_40")),
Subsignal("dqs_n", Pins("D15 F14"),
IOStandard("DIFF_SSTL135"),
Misc("IN_TERM=UNTUNED_SPLIT_40")),
Subsignal("clk_p", Pins("B9"), IOStandard("DIFF_SSTL135")),
Subsignal("clk_n", Pins("A10"), IOStandard("DIFF_SSTL135")),
Subsignal("cke", Pins("D13"), IOStandard("SSTL135")),
Subsignal("odt", Pins("C13"), IOStandard("SSTL135")),
Subsignal("reset_n", Pins("E15"), IOStandard("SSTL135")),
Misc("SLEW=FAST"),
),
]
# The connectors are named after the daughterboard, not the core board
# because on the different core boards the names vary, but on the
# daughterboard they stay the same, which we need to connect the
# daughterboard peripherals to the core board.
# On this board J2 is U7 and J3 is U8
_connectors = [
("J2", {
# odd row even row
7: "M12", 8: "N13",
9: "N14", 10: "N16",
11: "P15", 12: "P16",
13: "R15", 14: "R16",
15: "T14", 16: "T15",
17: "P13", 18: "P14",
19: "T13", 20: "R13",
21: "T12", 22: "R12",
23: "L13", 24: "N12",
25: "K12", 26: "K13",
27: "P10", 28: "P11",
29: "N9", 30: "P9",
31: "T10", 32: "R11",
33: "T9", 34: "R10",
35: "T8", 36: "R8",
37: "T7", 38: "R7",
39: "T5", 40: "R6",
41: "P6", 42: "R5",
43: "N6", 44: "M6",
45: "L5", 46: "P5",
47: "T4", 48: "T3",
49: "R3", 50: "T2",
51: "R2", 52: "R1",
53: "M5", 54: "N4",
55: "P4", 56: "P3",
57: "N1", 58: "P1",
59: "M2", 60: "M1",
}),
("J3", {
# odd row even row
7: "B7", 8: "A7",
9: "B6", 10: "B5",
11: "E6", 12: "K5",
13: "J5", 14: "J4",
15: "G5", 16: "G4",
17: "C7", 18: "C6",
19: "D6", 20: "D5",
21: "A5", 22: "A4",
23: "B4", 24: "A3",
25: "D4", 26: "C4",
27: "C3", 28: "C2",
29: "B2", 30: "A2",
31: "C1", 32: "B1",
33: "E2", 34: "D1",
35: "E3", 36: "D3",
37: "F5", 38: "E5",
39: "F2", 40: "E1",
41: "F4", 42: "F3",
43: "G2", 44: "G1",
45: "H2", 46: "H1",
47: "K1", 48: "J1",
49: "L3", 50: "L2",
51: "H5", 52: "H4",
53: "J3", 54: "H3",
55: "K3", 56: "K2",
57: "L4", 58: "M4",
59: "N3", 60: "N2",
})
]
# Platform -----------------------------------------------------------------------------------------
class Platform(XilinxPlatform):
default_clk_name = "clk50"
default_clk_period = 1e9/50e6
# these resources conflict with daughterboard resources
# so they are only used if the daughterboard is not present
core_resources = [
("user_led", 0, Pins("E6"), IOStandard("LVCMOS33")),
("cpu_reset", 0, Pins("K5"), IOStandard("LVCMOS33")),
]
def __init__(self, toolchain="vivado", with_daughterboard=False):
device = "xc7a35tftg256-1"
io = _io
connectors = _connectors
if with_daughterboard:
from litex_boards.platforms.qmtech_daughterboard import QMTechDaughterboard
daughterboard = QMTechDaughterboard(IOStandard("LVCMOS33"))
io += daughterboard.io
connectors += daughterboard.connectors
else:
io += self.core_resources
XilinxPlatform.__init__(self, device, io, connectors, toolchain=toolchain)
self.toolchain.bitstream_commands = \
["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"]
self.toolchain.additional_commands = \
["write_cfgmem -force -format bin -interface spix4 -size 16 "
"-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"]
self.add_platform_command("set_property INTERNAL_VREF 0.675 [get_iobanks 15]")
self.add_platform_command("set_property CFGBVS VCCO [current_design]")
self.add_platform_command("set_property CONFIG_VOLTAGE 3.3 [current_design]")
def create_programmer(self):
bscan_spi = "bscan_spi_xc7a35t.bit"
return OpenOCD("openocd_xc7_ft2232.cfg", bscan_spi)
def do_finalize(self, fragment):
XilinxPlatform.do_finalize(self, fragment)
from litex.build.xilinx import symbiflow
self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6)

View File

@ -0,0 +1,201 @@
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2021 Hans Baier <hansfbaier@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
# https://www.aliexpress.com/item/1000006630084.html
import os
import argparse
from migen import *
from litex_boards.platforms import qmtech_xc7a35t
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict
from litex.soc.cores.clock import *
from litex.soc.integration.soc import SoCRegion
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.cores.video import VideoVGAPHY
from litex.soc.cores.led import LedChaser
from litedram.modules import MT41J128M16
from litedram.phy import s7ddrphy
from litespi.modules import MT25QL128
from litespi.opcodes import SpiNorFlashOpCodes as Codes
from litespi.phy.generic import LiteSPIPHY
from litespi import LiteSPI
from liteeth.phy.mii import LiteEthPHYMII
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
def __init__(self, platform, sys_clk_freq, with_ethernet, with_vga):
self.rst = Signal()
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True)
self.clock_domains.cd_idelay = ClockDomain()
self.clock_domains.cd_eth = ClockDomain()
if with_ethernet:
self.clock_domains.cd_eth = ClockDomain()
if with_vga:
self.clock_domains.cd_vga = ClockDomain(reset_less=True)
# # #
self.submodules.pll = pll = S7PLL(speedgrade=-1)
try:
reset_button = platform.request("cpu_reset")
self.comb += pll.reset.eq(~reset_button | self.rst)
except:
self.comb += pll.reset.eq(self.rst)
pll.register_clkin(platform.request("clk50"), 50e6)
pll.create_clkout(self.cd_sys, sys_clk_freq)
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq)
pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90)
pll.create_clkout(self.cd_idelay, 200e6)
if with_ethernet:
pll.create_clkout(self.cd_eth, 25e6)
if with_vga:
pll.create_clkout(self.cd_vga, 40e6)
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst.
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, toolchain="vivado", sys_clk_freq=int(100e6), with_daughterboard=False,
with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50", eth_dynamic_ip=False,
with_video_terminal=False, with_video_framebuffer=False,
ident_version=True, with_jtagbone=True, with_mapped_flash=False, **kwargs):
platform = qmtech_xc7a35t.Platform(toolchain=toolchain, with_daughterboard=with_daughterboard)
# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, sys_clk_freq,
ident = "LiteX SoC on QMTech XC7A35T" + (" + Daughterboard" if with_daughterboard else ""),
ident_version = ident_version,
**kwargs)
# CRG --------------------------------------------------------------------------------------
self.submodules.crg = _CRG(platform, sys_clk_freq, with_ethernet or with_etherbone, with_video_terminal or with_video_framebuffer)
# DDR3 SDRAM -------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
memtype = "DDR3",
nphases = 4,
sys_clk_freq = sys_clk_freq)
self.add_sdram("sdram",
phy = self.ddrphy,
module = MT41J128M16(sys_clk_freq, "1:4"),
l2_cache_size = kwargs.get("l2_size", 8192)
)
# Ethernet / Etherbone ---------------------------------------------------------------------
if with_ethernet or with_etherbone:
self.submodules.ethphy = LiteEthPHYMII(
clock_pads = self.platform.request("eth_clocks"),
pads = self.platform.request("eth"))
if with_ethernet:
self.add_ethernet(phy=self.ethphy, dynamic_ip=eth_dynamic_ip)
if with_etherbone:
self.add_etherbone(phy=self.ethphy, ip_address=eth_ip)
# The daughterboard has the tx clock wired to a non-clock pin, so we can't help it
self.platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets eth_clocks_tx_IBUF]")
# Jtagbone ---------------------------------------------------------------------------------
if with_jtagbone:
self.add_jtagbone()
# Flash (through LiteSPI, experimental).
if with_mapped_flash:
self.submodules.spiflash_phy = LiteSPIPHY(platform.request("spiflash4x"), MT25QL128(Codes.READ_1_1_1))
self.submodules.spiflash_mmap = LiteSPI(self.spiflash_phy, clk_freq=sys_clk_freq, mmap_endianness=self.cpu.endianness)
spiflash_region = SoCRegion(origin=self.mem_map.get("spiflash", None), size=MT25QL128.total_size, cached=False)
self.bus.add_slave(name="spiflash", slave=self.spiflash_mmap.bus, region=spiflash_region)
# Video ------------------------------------------------------------------------------------
if with_video_terminal or with_video_framebuffer:
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
if with_video_terminal:
self.add_video_terminal(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga")
if with_video_framebuffer:
self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga")
# Leds -------------------------------------------------------------------------------------
self.submodules.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
if not with_daughterboard and kwargs["uart_name"] == "serial":
kwargs["uart_name"] = "jtag_serial"
# Build --------------------------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Arty A7")
parser.add_argument("--toolchain", default="vivado", help="Toolchain use to build (default: vivado)")
parser.add_argument("--build", action="store_true", help="Build bitstream")
parser.add_argument("--load", action="store_true", help="Load bitstream")
parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency (default: 100MHz)")
parser.add_argument("--with-daughterboard", action="store_true", help="Whether the core board is plugged into the QMTech daughterboard")
ethopts = parser.add_mutually_exclusive_group()
ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support")
ethopts.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support")
parser.add_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address")
parser.add_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting")
sdopts = parser.add_mutually_exclusive_group()
sdopts.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support")
sdopts.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support")
parser.add_argument("--no-ident-version", action="store_false", help="Disable build time output")
parser.add_argument("--with-jtagbone", action="store_true", help="Enable Jtagbone support")
parser.add_argument("--with-mapped-flash", action="store_true", help="Enable Memory Mapped Flash")
viopts = parser.add_mutually_exclusive_group()
viopts.add_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (VGA)")
viopts.add_argument("--with-video-framebuffer", action="store_true", help="Enable Video Framebuffer (VGA)")
builder_args(parser)
soc_core_args(parser)
vivado_build_args(parser)
args = parser.parse_args()
soc = BaseSoC(
toolchain = args.toolchain,
sys_clk_freq = int(float(args.sys_clk_freq)),
with_daughterboard = args.with_daughterboard,
with_ethernet = args.with_ethernet,
with_etherbone = args.with_etherbone,
eth_ip = args.eth_ip,
eth_dynamic_ip = args.eth_dynamic_ip,
ident_version = args.no_ident_version,
with_jtagbone = args.with_jtagbone,
with_mapped_flash = args.with_mapped_flash,
with_video_terminal = args.with_video_terminal,
with_video_framebuffer = args.with_video_framebuffer,
**soc_core_argdict(args)
)
if args.with_spi_sdcard:
soc.add_spi_sdcard()
if args.with_sdcard:
soc.add_sdcard()
builder = Builder(soc, **builder_argdict(args))
builder_kwargs = vivado_build_argdict(args) if args.toolchain == "vivado" else {}
builder.build(**builder_kwargs, run=args.build)
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit"))
if __name__ == "__main__":
main()

View File

@ -51,6 +51,7 @@ class TestTargets(unittest.TestCase):
platforms.append("acorn")
platforms.append("marblemini")
platforms.append("qmtech_wukong")
platforms.append("qmtech_xc7a35t")
# Xilinx Kintex7
platforms.append("genesys2")