Basic SoC for Opal Kelly XEM8320

This commit is contained in:
AEW2015 2023-02-28 13:19:12 -07:00
parent f400179b5b
commit e20391d366
3 changed files with 372 additions and 0 deletions

View File

@ -0,0 +1,156 @@
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2022 Andrew Elbert Wilson <Andrew.E.Wilson@ieee.org>
# SPDX-License-Identifier: BSD-2-Clause
from litex.build.generic_platform import *
from litex.build.xilinx import XilinxPlatform, VivadoProgrammer
# IOs ----------------------------------------------------------------------------------------------
_io = [
# Clk / Rst
("sys_clk100", 0,
Subsignal("p", Pins("T24"), IOStandard("LVDS")),
Subsignal("n", Pins("U24"), IOStandard("LVDS"))
),
("ddr_clk100", 0,
Subsignal("p", Pins("AD20"), IOStandard("LVDS")),
Subsignal("n", Pins("AE20"), IOStandard("LVDS"))
),
#NO RESET, maybe use okHOST USB later
#("cpu_reset", 0, Pins("AN8"), IOStandard("LVCMOS18")),
# Leds
("user_led", 0, Pins("G19"), IOStandard("LVCMOS18")),
("user_led", 1, Pins("B16"), IOStandard("LVCMOS18")),
("user_led", 2, Pins("F22"), IOStandard("LVCMOS18")),
("user_led", 3, Pins("E22"), IOStandard("LVCMOS18")),
("user_led", 4, Pins("M24"), IOStandard("LVCMOS18")),
("user_led", 5, Pins("G22"), IOStandard("LVCMOS18")),
# Opal Kelly Host USBC interface
("okHost", 0, # Uses the FrontPanel API
Subsignal("okAA", Pins("T19")),
Subsignal("okHU", Pins("U20 U26 T22")),
Subsignal("okUH", Pins("V23 T23 U22 U25 U21")),
Subsignal("okUHU", Pins("P26 P25 R26 R25 R23 R22 P21 P20",
"R21 R20 P23 N23 T25 N24 N22 V26",
"N19 V21 N21 W20 W26 W19 Y25 Y26",
"Y22 V22 W21 AA23 Y23 AA24 W25 AA25")),
Misc("SLEW=FAST"),
IOStandard("LVCMOS18"),
),
# TODO: Add SMA & SFP+
# DDR4 SDRAM
("ddram", 0,
Subsignal("a", Pins(
"AD18 AE17 AB17 AE18 AD19 AF17 Y17 AE16",
"AA17 AC17 AC19 AC16 AF20 AD16"),
IOStandard("SSTL12_DCI")),
Subsignal("ba", Pins("AC18 AF18"), IOStandard("SSTL12_DCI")),
Subsignal("bg", Pins("AB19"), IOStandard("SSTL12_DCI")),
Subsignal("ras_n", Pins("AA18"), IOStandard("SSTL12_DCI")),
Subsignal("cas_n", Pins("AF19"), IOStandard("SSTL12_DCI")),
Subsignal("we_n", Pins("AA19"), IOStandard("SSTL12_DCI")),
Subsignal("cs_n", Pins("AF22"), IOStandard("SSTL12_DCI")),
Subsignal("act_n", Pins("Y18"), IOStandard("SSTL12_DCI")),
Subsignal("dm", Pins("AE25 AE22"),
IOStandard("POD12_DCI")),
Subsignal("dq", Pins(
"AF24 AB25 AB26 AC24 AF25 AB24 AD24 AD25",
"AB21 AE21 AE23 AD23 AC23 AD21 AC22 AC21"),
IOStandard("POD12_DCI"),
Misc("PRE_EMPHASIS=RDRV_240"),
Misc("EQUALIZATION=EQ_LEVEL2")),
Subsignal("dqs_p", Pins("AC26 AA22"),
IOStandard("DIFF_POD12_DCI"),
Misc("PRE_EMPHASIS=RDRV_240"),
Misc("EQUALIZATION=EQ_LEVEL2")),
Subsignal("dqs_n", Pins("AD26 AB22"),
IOStandard("DIFF_POD12_DCI"),
Misc("PRE_EMPHASIS=RDRV_240"),
Misc("EQUALIZATION=EQ_LEVEL2")),
Subsignal("clk_p", Pins("Y20"), IOStandard("DIFF_SSTL12_DCI")),
Subsignal("clk_n", Pins("Y21"), IOStandard("DIFF_SSTL12_DCI")),
Subsignal("cke", Pins("AA20"), IOStandard("SSTL12_DCI")),
Subsignal("odt", Pins("AB20"), IOStandard("SSTL12_DCI")),
Subsignal("reset_n", Pins("AE26"), IOStandard("LVCMOS12")),
Misc("SLEW=FAST"),
),
]
# Connectors ---------------------------------------------------------------------------------------
# TODO: SYZYGY Connectors & SYZYGY to PMODS!
_connectors = [
("pmod1", "AC14 AC13 AF15 AF14 AF13 AE13 H13 J13"),
("pmod2", "AB15 AB16 W14 J14 AE15 W15 Y15 J15"),
("pmod3", "G14 H14 W13 W12 AA13 Y13 H12 J12"),
("pmod4", "AD14 AD13 W16 AD15 AB14 AA14 Y16 AA15"),
]
def dvi_pmod_io(pmoda,pmodb):
return [
("dvi", 0,
Subsignal("clk", Pins(f"{pmodb}:1")),
Subsignal("de", Pins(f"{pmodb}:6")),
Subsignal("hsync", Pins(f"{pmodb}:3")),
Subsignal("vsync", Pins(f"{pmodb}:7")),
Subsignal("b", Pins(f"{pmoda}:5 {pmoda}:1 {pmoda}:4 {pmoda}:0")),
Subsignal("g", Pins(f"{pmoda}:7 {pmoda}:3 {pmoda}:6 {pmoda}:2")),
Subsignal("r", Pins(f"{pmodb}:2 {pmodb}:5 {pmodb}:4 {pmodb}:0")),
IOStandard("LVCMOS33"),
)
]
_dvi_pmod_io = dvi_pmod_io("pmod2","pmod1") # SDCARD PMOD on JD.
def sdcard_pmod_io(pmod):
return [
# SDCard PMOD:
# - https://store.digilentinc.com/pmod-microsd-microsd-card-slot/
# - https://github.com/antmicro/arty-expansion-board
("spisdcard", 0,
Subsignal("clk", Pins(f"{pmod}:3")),
Subsignal("mosi", Pins(f"{pmod}:1"), Misc("PULLUP True")),
Subsignal("cs_n", Pins(f"{pmod}:0"), Misc("PULLUP True")),
Subsignal("miso", Pins(f"{pmod}:2"), Misc("PULLUP True")),
Misc("SLEW=FAST"),
IOStandard("LVCMOS33"),
),
("sdcard", 0,
Subsignal("data", Pins(f"{pmod}:2 {pmod}:4 {pmod}:5 {pmod}:0"), Misc("PULLUP True")),
Subsignal("cmd", Pins(f"{pmod}:1"), Misc("PULLUP True")),
Subsignal("clk", Pins(f"{pmod}:3")),
Subsignal("cd", Pins(f"{pmod}:6")),
Misc("SLEW=FAST"),
IOStandard("LVCMOS33"),
),
]
_sdcard_pmod_io = sdcard_pmod_io("pmod3") # SDCARD PMOD on JD.
# Platform -----------------------------------------------------------------------------------------
class Platform(XilinxPlatform):
default_clk_name = "sys_clk100"
default_clk_period = 1e9/100e6
def __init__(self, toolchain="vivado"):
XilinxPlatform.__init__(self, "xcau25p-ffvb676-2-e", _io, _connectors, toolchain=toolchain)
def create_programmer(self):
return VivadoProgrammer()
def do_finalize(self, fragment):
XilinxPlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request("sys_clk100", loose=True), 1e9/100e6)
self.add_period_constraint(self.lookup_request("ddr_clk100", loose=True), 1e9/100e6)
self.add_platform_command("set_property INTERNAL_VREF 0.84 [get_iobanks 64]")

View File

@ -0,0 +1,64 @@
interface ftdi
ftdi_vid_pid 0x0403 0x6014
ftdi_channel 0
ftdi_layout_init 0x00e8 0x60eb
reset_config none
#openocd missing support, added to local cfg file
set CHIP XCAU25P
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME xcu
}
# The cvarious chips in the Ultrascale family have different IR length.
# Set $CHIP before including this file to determine the device.
array set _XCU_DATA {
XCAU25P {0x04A64093 6}
}
if { ![info exists CHIP] } {
error "set CHIP to one of "[concat [array names _XCU_DATA]]
}
if { ![llength [array names _XCU_DATA $CHIP]] } {
error "unknown CHIP: "$CHIP
}
set _EXPID [lindex $_XCU_DATA($CHIP) 0]
set _IRLEN [lindex $_XCU_DATA($CHIP) 1]
# the 4 top bits (28:31) are the die stepping/revisions. ignore it.
jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID
pld device virtex2 $_CHIPNAME.tap 1
set XCU_JSHUTDOWN 0x0d
set XCU_JPROGRAM 0x0b
set XCU_JSTART 0x0c
set XCU_BYPASS 0x3f
proc xcu_program {tap} {
global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS
irscan $tap $XCU_JSHUTDOWN
irscan $tap $XCU_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XCU_JSTART
runtest 2000
irscan $tap $XCU_BYPASS
runtest 2000
}
source [find cpld/jtagspi.cfg]
adapter_khz 25000
proc fpga_program {} {
global _CHIPNAME
xc7_program $_CHIPNAME.tap
}

View File

@ -0,0 +1,152 @@
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2022 Andrew Elbert Wilson <Andrew.E.Wilson@ieee.org>
# SPDX-License-Identifier: BSD-2-Clause
import os
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex_boards.platforms import opalkelly_xem8320
from litex.soc.cores.clock import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.cores.led import LedChaser
from litex.soc.cores.video import VideoDVIPHY
from litedram.modules import MT40A512M16
from litedram.phy import usddrphy
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys4x = ClockDomain()
self.clock_domains.cd_idelay = ClockDomain()
self.clock_domains.cd_hdmi = ClockDomain()
self.clock_domains.cd_hdmi5x = ClockDomain()
# # #
clk100 = platform.request("ddr_clk100")
self.submodules.pll = pll = USMMCM(speedgrade=-2)
self.comb += pll.reset.eq(self.rst)
pll.register_clkin(clk100, 100e6)
pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False)
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) #500
pll.create_clkout(self.cd_hdmi, 25e6)
pll.create_clkout(self.cd_hdmi5x, 5*25e6)
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst.
# #option for second MMCM for video clocks
# self.submodules.video_pll = video_pll = USMMCM(speedgrade=-2)
# video_pll.reset.eq(self.rst)
# video_pll.register_clkin(self.cd_sys.clk, sys_clk_freq)
# video_pll.create_clkout(self.cd_hdmi, 25e6)
# video_pll.create_clkout(self.cd_hdmi5x, 5*25e6)
self.submodules.idelayctrl = USIDELAYCTRL(cd_ref=self.cd_sys4x, cd_sys=self.cd_sys)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, sys_clk_freq=int(125e6), with_ethernet=False, with_etherbone=False,
eth_ip="192.168.1.50", with_led_chaser=True,
**kwargs):
platform = opalkelly_xem8320.Platform()
# CRG --------------------------------------------------------------------------------------
self.submodules.crg = _CRG(platform, sys_clk_freq)
kwargs["uart_name"] = "jtag_uart"
# TODO: add okHost FrontPanel API for UART, Data streaing, and Debug
# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on xem8320", **kwargs)
# DDR4 SDRAM -------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
self.submodules.ddrphy = usddrphy.USPDDRPHY(platform.request("ddram"),
memtype = "DDR4",
sys_clk_freq = sys_clk_freq,
iodelay_clk_freq = 500e6)
self.add_sdram("sdram",
phy = self.ddrphy,
module = MT40A512M16(sys_clk_freq, "1:4"),
size = 0x40000000,
l2_cache_size = kwargs.get("l2_size", 8192)
)
# TODO: add SFP+ cages for ethernet
# Ethernet / Etherbone ---------------------------------------------------------------------
# if with_ethernet or with_etherbone:
# self.submodules.ethphy = KU_1000BASEX(self.crg.cd_eth.clk,
# data_pads = self.platform.request("sfp", 0),
# sys_clk_freq = self.clk_freq)
# self.comb += self.platform.request("sfp_tx_disable_n", 0).eq(1)
# self.platform.add_platform_command("set_property SEVERITY {{Warning}} [get_drc_checks REQP-1753]")
# if with_ethernet:
# self.add_ethernet(phy=self.ethphy)
# if with_etherbone:
# self.add_etherbone(phy=self.ethphy, ip_address=eth_ip)
platform.add_extension(opalkelly_xem8320._dvi_pmod_io)
self.submodules.videophy = VideoDVIPHY(platform.request("dvi"), clock_domain="hdmi")
self.add_video_framebuffer(phy=self.videophy, timings="640x480@75Hz", clock_domain="hdmi")
# Leds -------------------------------------------------------------------------------------
if with_led_chaser:
self.submodules.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
# Build --------------------------------------------------------------------------------------------
def main():
from litex.soc.integration.soc import LiteXSoCArgumentParser
parser = LiteXSoCArgumentParser(description="LiteX SoC on XEM8320")
target_group = parser.add_argument_group(title="Target options")
target_group.add_argument("--build", action="store_true", help="Build design.")
target_group.add_argument("--load", action="store_true", help="Load bitstream.")
target_group.add_argument("--sys-clk-freq", default=125e6, help="System clock frequency.")
#ethopts = target_group.add_mutually_exclusive_group()
#ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.")
builder_args(parser)
soc_core_args(parser)
args = parser.parse_args()
soc = BaseSoC(
sys_clk_freq = int(float(args.sys_clk_freq)),
#with_ethernet = args.with_ethernet,
#with_etherbone = args.with_etherbone,
#eth_ip = args.eth_ip,
#with_pcie = args.with_pcie,
#with_sata = args.with_sata,
**soc_core_argdict(args)
)
soc.platform.add_extension(opalkelly_xem8320._sdcard_pmod_io)
soc.add_spi_sdcard()
builder = Builder(soc, **builder_argdict(args))
if args.build:
builder.build()
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
# TODO: add option for FrontPanel Programming
if __name__ == "__main__":
main()