add QMTech 5CEFA5 Cyclone V board support

This commit is contained in:
Hans Baier 2023-04-06 18:20:22 +07:00
parent ae3d5d599b
commit 43ce24dcb3
2 changed files with 350 additions and 0 deletions

View File

@ -0,0 +1,164 @@
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2023 Hans Baier <hansfbaier@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
from litex.build.generic_platform import *
from litex.build.altera import AlteraPlatform
from litex.build.altera.programmer import USBBlaster
# IOs ----------------------------------------------------------------------------------------------
_io = [
# Clk
("clk50", 0, Pins("M9"), IOStandard("3.3-V LVCMOS")),
# Button
("key", 0, Pins("J17"), IOStandard("3.3-V LVCMOS")),
("key", 1, Pins("E16"), IOStandard("3.3-V LVCMOS")),
# SPIFlash (MT25QL128ABA)
("spiflash", 0,
# clk
Subsignal("cs_n", Pins("R4")),
Subsignal("clk", Pins("V3")),
Subsignal("mosi", Pins("AB4")),
Subsignal("miso", Pins("AB3")),
IOStandard("3.3-V LVCMOS"),
),
# SDR SDRAM
("sdram_clock", 0, Pins("G18"), IOStandard("3.3-V LVCMOS")),
("sdram", 0,
Subsignal("a", Pins(
# A0 A1 A2 A3 A4 A5 A6 A7
"M18 M20 M16 L17 L19 L18 K16 K17",
# A8 A9 A10 A11 A12
"J18 J19 N19 H18 H20")),
Subsignal("ba", Pins("P19 P18")),
Subsignal("cs_n", Pins("P17")),
Subsignal("cke", Pins("G17")),
Subsignal("ras_n", Pins("P16")),
Subsignal("cas_n", Pins("T19")),
Subsignal("we_n", Pins("U20")),
Subsignal("dq", Pins(
"AA22 AB22 Y22 Y21 W22 W21 V21 U22 M21 M22 T22 R21 R22 P22 N20 N21 ",
"K22 K21 J22 J21 H21 G22 G21 F22 E22 E20 D22 D21 C21 B22 A22 B21")),
Subsignal("dm", Pins("U21 L22 K20 E21")),
IOStandard("3.3-V LVCMOS")
),
]
# 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 U6 and J3 is U5
_connectors = [
("J2", {
# odd row even row
7: "AB21", 8: "AB20",
9: "Y19", 10: "Y20",
11: "AA20", 12: "AA19",
13: "W19", 14: "V20",
15: "AB18", 16: "AB17",
17: "U17", 18: "U16",
19: "R16", 20: "R17",
21: "T15", 22: "R15",
23: "R14", 24: "P14",
25: "AA15", 26: "AB15",
27: "T13", 28: "T12",
29: "R11", 30: "R10",
31: "AA13", 32: "AA14",
33: "Y15", 34: "Y14",
35: "AB12", 36: "AB13",
37: "AB11", 38: "AB10",
39: "V10", 40: "V9",
41: "U12", 42: "U11",
43: "R9", 44: "T10",
45: "T8", 46: "T7",
47: "N8", 48: "P8",
49: "M7", 50: "M6",
51: "N6", 52: "P6",
53: "R5", 54: "R6",
55: "AB8", 56: "AA8 ",
57: "AB7", 58: "AA7",
59: "AB5", 60: "AB6",
}),
("J3", {
# odd row even row
7: "F19", 8: "F18",
9: "E19", 10: "D19",
11: "C20", 12: "B20",
13: "A20", 14: "A19",
15: "C19", 16: "C18",
17: "A18", 18: "A17",
19: "B18", 20: "B17",
21: "B16", 22: "C16",
23: "C15", 24: "B15",
25: "E15", 26: "F15",
27: "A15", 28: "A14",
29: "B13", 30: "A13",
31: "B12", 32: "A12",
33: "G15", 34: "F14",
35: "H13", 36: "G13",
37: "D12", 38: "E12",
39: "H11", 40: "G12",
41: "A10", 42: "A9",
43: "J9", 44: "H9",
45: "E9", 46: "D9",
47: "H8", 48: "G8",
49: "L7", 50: "K7",
51: "J7", 52: "J8",
53: "A8", 54: "A7",
55: "B6", 56: "B7",
57: "C6", 58: "D6",
59: "A5", 60: "B5",
})
]
# Platform -----------------------------------------------------------------------------------------
class Platform(AlteraPlatform):
default_clk_name = "clk50"
default_clk_period = 1e9/50e6
core_resources = [
("user_led", 0, Pins("V19"), IOStandard("3.3-V LVCMOS")),
("user_led", 1, Pins("T20"), IOStandard("3.3-V LVCMOS")),
("serial", 0,
Subsignal("tx", Pins("J3:7"), IOStandard("3.3-V LVCMOS")),
Subsignal("rx", Pins("J3:8"), IOStandard("3.3-V LVCMOS"))
),
]
def __init__(self, toolchain="quartus", with_daughterboard=False):
device = "5CEFA5F23I7"
io = _io
connectors = _connectors
if with_daughterboard:
from litex_boards.platforms.qmtech_daughterboard import QMTechDaughterboard
daughterboard = QMTechDaughterboard(IOStandard("3.3-V LVCMOS"))
io += daughterboard.io
connectors += daughterboard.connectors
else:
io += self.core_resources
AlteraPlatform.__init__(self, device, io, connectors, toolchain=toolchain)
if with_daughterboard:
# ethernet takes the config pin, so make it available
self.add_platform_command("set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION \"USE AS REGULAR IO\"")
# Generate PLL clock in STA
self.toolchain.additional_sdc_commands.append("derive_pll_clocks")
# Calculates clock uncertainties
self.toolchain.additional_sdc_commands.append("derive_clock_uncertainty")
def create_programmer(self):
return USBBlaster()
def do_finalize(self, fragment):
AlteraPlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6)

View File

@ -0,0 +1,186 @@
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2023 Hans Baier <hansfbaier@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
#
# Note: The CPU actually runs at over 100MHz, but the SDRAM only works up to 75MHz
from migen import *
from litex.gen import *
from litex.build.io import DDROutput
from litex_boards.platforms import qmtech_5cefa5
from litex.soc.cores.clock import CycloneVPLL
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.cores.led import LedChaser
from litedram.modules import W9825G6KH6
from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY
from litex.soc.cores.video import VideoVGAPHY
from liteeth.phy.mii import LiteEthPHYMII
# CRG ----------------------------------------------------------------------------------------------
class _CRG(LiteXModule):
def __init__(self, platform, sys_clk_freq, with_ethernet, with_vga, sdram_rate="1:1"):
self.rst = Signal()
self.cd_sys = ClockDomain()
if sdram_rate == "1:2":
self.cd_sys2x = ClockDomain()
self.cd_sys2x_ps = ClockDomain()
else:
self.cd_sys_ps = ClockDomain()
if with_ethernet:
self.cd_eth = ClockDomain()
if with_vga:
self.cd_vga = ClockDomain()
# # #
# Clk / Rst
clk50 = platform.request("clk50")
# PLL
self.pll = pll = CycloneVPLL(speedgrade="-C8")
self.comb += pll.reset.eq(self.rst)
pll.register_clkin(clk50, 50e6)
pll.create_clkout(self.cd_sys, sys_clk_freq)
if sdram_rate == "1:2":
pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq)
# theoretically 90 degrees, but increase to relax timing
pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=180)
else:
pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=45)
if with_ethernet:
pll.create_clkout(self.cd_eth, 25e6)
if with_vga:
pll.create_clkout(self.cd_vga, 40e6)
# SDRAM clock
sdram_clk = ClockSignal("sys2x_ps" if sdram_rate == "1:2" else "sys_ps")
self.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, sys_clk_freq=80e6, with_daughterboard=False,
with_ethernet = False,
with_etherbone = False,
eth_ip = "192.168.1.50",
eth_dynamic_ip = False,
with_led_chaser = True,
with_video_terminal = False,
with_video_framebuffer = False,
sdram_rate = "1:1",
**kwargs):
platform = qmtech_5cefa5.Platform(with_daughterboard=with_daughterboard)
# CRG --------------------------------------------------------------------------------------
self.crg = _CRG(platform, sys_clk_freq,
with_ethernet = with_ethernet or with_etherbone,
with_vga = with_video_terminal or with_video_framebuffer,
sdram_rate = sdram_rate
)
# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, sys_clk_freq,
ident = "LiteX SoC on QMTECH 5CEFA5" + (" + Daughterboard" if with_daughterboard else ""),
**kwargs)
# SDR SDRAM --------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
sdrphy_cls = HalfRateGENSDRPHY if sdram_rate == "1:2" else GENSDRPHY
self.sdrphy = sdrphy_cls(platform.request("sdram"), sys_clk_freq)
self.add_sdram("sdram",
phy = self.sdrphy,
module = W9825G6KH6(sys_clk_freq, sdram_rate),
l2_cache_size = kwargs.get("l2_size", 8192)
)
# Ethernet / Etherbone ---------------------------------------------------------------------
if with_ethernet or with_etherbone:
self.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)
# Video ------------------------------------------------------------------------------------
if with_video_terminal or with_video_framebuffer:
self.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 -------------------------------------------------------------------------------------
if with_led_chaser:
self.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
# Build --------------------------------------------------------------------------------------------
def main():
from litex.build.parser import LiteXArgumentParser
parser = LiteXArgumentParser(platform=qmtech_5cefa5.Platform, description="LiteX SoC on QMTECH 5CEFA5.")
parser.add_target_argument("--sys-clk-freq", default=80e6, type=float, help="System clock frequency.")
parser.add_target_argument("--sdram-rate", default="1:1", help="SDRAM Rate (1:1 Full Rate or 1:2 Half Rate).")
parser.add_target_argument("--with-daughterboard", action="store_true", help="Board plugged into the QMTech daughterboard.")
ethopts = parser.target_group.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_target_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address.")
parser.add_target_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting.")
sdopts = parser.target_group.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_target_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).")
viopts = parser.target_group.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).")
args = parser.parse_args()
soc = BaseSoC(
sys_clk_freq = 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,
with_video_terminal = args.with_video_terminal,
with_video_framebuffer = args.with_video_framebuffer,
with_spi_flash = args.with_spi_flash,
sdram_rate = args.sdram_rate,
**parser.soc_argdict
)
if args.with_spi_sdcard:
soc.add_spi_sdcard()
if args.with_sdcard:
soc.add_sdcard()
builder = Builder(soc, **parser.builder_argdict)
if args.build:
builder.build(**parser.toolchain_argdict)
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
if __name__ == "__main__":
main()