Apply Kestrel changes to latest LiteX boards upstream tree

parent ef662035
......@@ -3,6 +3,7 @@
#
# Copyright (c) 2017 Sergiusz Bazanski <q3k@q3k.org>
# Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2020-2021 Raptor Engineering, LLC
# SPDX-License-Identifier: BSD-2-Clause
from litex.build.generic_platform import *
......@@ -25,6 +26,7 @@ _io = [
("user_led", 5, Pins("F18"), IOStandard("LVCMOS25")),
("user_led", 6, Pins("E17"), IOStandard("LVCMOS25")),
("user_led", 7, Pins("F16"), IOStandard("LVCMOS25")),
("user_leds", 0, Pins("E16 D17 D18 E18 F17 F18 E17 F16"), IOStandard("LVCMOS25")),
# Switches
("user_dip_btn", 0, Pins("H2"), IOStandard("LVCMOS15")),
......@@ -36,6 +38,25 @@ _io = [
("user_dip_btn", 6, Pins("K19"), IOStandard("LVCMOS25")),
("user_dip_btn", 7, Pins("K20"), IOStandard("LVCMOS25")),
# Alphanumeric display
("alpha_led", 0, Pins("M20"), IOStandard("LVCMOS25")),
("alpha_led", 1, Pins("L18"), IOStandard("LVCMOS25")),
("alpha_led", 2, Pins("M19"), IOStandard("LVCMOS25")),
("alpha_led", 3, Pins("L16"), IOStandard("LVCMOS25")),
("alpha_led", 4, Pins("L17"), IOStandard("LVCMOS25")),
("alpha_led", 5, Pins("M18"), IOStandard("LVCMOS25")),
("alpha_led", 6, Pins("N16"), IOStandard("LVCMOS25")),
("alpha_led", 7, Pins("M17"), IOStandard("LVCMOS25")),
("alpha_led", 8, Pins("N18"), IOStandard("LVCMOS25")),
("alpha_led", 9, Pins("P17"), IOStandard("LVCMOS25")),
("alpha_led", 10, Pins("N17"), IOStandard("LVCMOS25")),
("alpha_led", 11, Pins("P16"), IOStandard("LVCMOS25")),
("alpha_led", 12, Pins("R16"), IOStandard("LVCMOS25")),
("alpha_led", 13, Pins("R17"), IOStandard("LVCMOS25")),
("alpha_led", 14, Pins("U1"), IOStandard("LVCMOS25")),
("alpha_led", 15, Pins("T16"), IOStandard("LVCMOS25")), # Not wired on Versa board, but makes GPIO bank 16 bits. Future expansion?
("alpha_leds", 0, Pins("M20 L18 M19 L16 L17 M18 N16 M17 N18 P17 N17 P16 R16 R17 U1 T16"), IOStandard("LVCMOS25")), # T16 not wired on Versa board, but makes GPIO bank 16 bits. Future expansion?
# Serial
("serial", 0,
Subsignal("rx", Pins("C11"), IOStandard("LVCMOS33")),
......@@ -156,6 +177,68 @@ _io = [
Subsignal("p", Pins("Y7")),
Subsignal("n", Pins("Y8")),
),
("i2c_bus1_master", 0,
Subsignal("sda", Pins("D12"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
Subsignal("scl", Pins("B10"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
),
("i2c_bus2_master", 0,
Subsignal("sda", Pins("C10"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
Subsignal("scl", Pins("A9"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
),
("i2c_bus3_master", 0,
Subsignal("sda", Pins("B17"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
Subsignal("scl", Pins("C17"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
),
("i2c_bus4_master", 0,
Subsignal("sda", Pins("B18"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
Subsignal("scl", Pins("A18"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
),
("openfsi_master", 0,
Subsignal("clock", Pins("B15"), IOStandard("LVCMOS33")),
Subsignal("data", Pins("C15"), IOStandard("LVCMOS33")),
Subsignal("data_direction", Pins("D15"), IOStandard("LVCMOS33")),
),
("hostspiflash4x", 0,
Subsignal("cs_n", Pins("A14")),
Subsignal("clk", Pins("A12")),
Subsignal("dq", Pins("B13 D13 D11 D14")),
IOStandard("LVCMOS33"),
Misc("SLEWRATE=SLOW"),
Misc("DRIVE=16"),
),
("hostlpcslave", 0,
Subsignal("frame_n", Pins("E15"), Misc("PULLMODE=UP")),
Subsignal("reset_n", Pins("B16"), Misc("PULLMODE=UP")),
Subsignal("pwrdn_n", Pins("A16"), Misc("PULLMODE=UP")),
Subsignal("clkrun_n", Pins("D16"), Misc("PULLMODE=UP")),
Subsignal("tpm_gpio0", Pins("A17"), Misc("PULLMODE=UP")),
Subsignal("addrdata", Pins("C14 E13 C13 A13"), Misc("PULLMODE=UP")),
Subsignal("serirq", Pins("E14"), Misc("PULLMODE=UP")),
Subsignal("clk", Pins("B12"), Misc("PULLMODE=NONE")), # Must be PCLK *not* GR_PCLK or (even worse) a general logic I/O! Pullup NONE helps minimize clock distortion / clock failure on heavily loaded clock lines...
IOStandard("LVCMOS33"),
Misc("SLEWRATE=SLOW"),
Misc("DRIVE=16"),
),
("debug_port_2", 0,
Subsignal("led_15", Pins("B19"), IOStandard("LVCMOS33")),
Subsignal("led_14", Pins("B9"), IOStandard("LVCMOS33")),
Subsignal("led_13", Pins("D6"), IOStandard("LVCMOS33")),
Subsignal("led_12", Pins("D7"), IOStandard("LVCMOS33")),
Subsignal("led_11", Pins("B6"), IOStandard("LVCMOS33")),
Subsignal("led_10", Pins("D9"), IOStandard("LVCMOS33")),
Subsignal("led_9", Pins("C8"), IOStandard("LVCMOS33")),
Subsignal("led_8", Pins("E8"), IOStandard("LVCMOS33")),
),
("lpc_debug_mirror_clock", 0, Pins("E12"), IOStandard("LVCMOS33"))
]
# ECP5-hat extension (https://github.com/daveshah1/ecp5-hat) ---------------------------------------
......
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
# This file is part of Kestrel
#
# Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2018-2019 David Shah <dave@ds0.me>
# Copyright (c) 2020-2021 Raptor Engineering, LLC
# SPDX-License-Identifier: BSD-2-Clause
import os
import argparse
import subprocess
import tempfile
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
......@@ -18,6 +21,7 @@ from litex_boards.platforms import versa_ecp5
from litex.build.lattice.trellis import trellis_args, trellis_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.soc_sdram import *
from litex.soc.integration.builder import *
......@@ -28,6 +32,17 @@ from litedram.phy import ECP5DDRPHY
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
# Kestrel-specific peripherals
from tercelspi.tercelspi import TercelSPI
from aquilalpc.aquilalpc import AquilaLPCSlave
from swiftfsi.swiftfsi import OpenFSIMaster
from simplertc.simplertc import SimpleRTCSlave
from opencoresi2c.opencoresi2c import OpenCoresI2CMaster
# Useful constants
kB = 1024
mB = 1024*kB
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
......@@ -79,16 +94,55 @@ class _CRG(Module):
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, sys_clk_freq=int(75e6), device="LFE5UM5G", with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50", eth_phy=0, toolchain="trellis", **kwargs):
mem_map = {
"hostxicsicp" : 0xc3000000,
"hostxicsics" : 0xc3001000,
"ethmac" : 0xc3002000,
"hostspiflashcfg" : 0xc3007000,
"simplertc" : 0xc3008000,
"openfsimaster" : 0xc3009000,
"i2cmaster1" : 0xc300a000,
"i2cmaster2" : 0xc300a020,
"i2cmaster3" : 0xc300a040,
"i2cmaster4" : 0xc300a060,
"hostspiflash" : 0xc4000000,
"hostlpcslave" : 0xcb000000,
}
mem_map.update(SoCCore.mem_map)
interrupt_map = {
"ethmac" : 2,
"hostlpcslave" : 3,
"openfsimaster" : 4,
"i2cmaster1" : 5,
"i2cmaster2" : 6,
"i2cmaster3" : 7,
"i2cmaster4" : 8,
}
interrupt_map.update(SoCCore.interrupt_map)
def __init__(self, sys_clk_freq=int(50e6), device="LFE5UM5G", with_ethernet=False, with_etherbone=False, with_openfsi_master=True, with_hostspiflash=True, with_hostlpcslave=True, with_i2c_masters=True, with_simple_rtc=True, eth_ip="192.168.1.50", eth_phy=0, toolchain="trellis", **kwargs):
platform = versa_ecp5.Platform(toolchain=toolchain, device=device)
# FIXME: adapt integrated rom size for Microwatt
if kwargs.get("cpu_type", None) == "microwatt":
kwargs["integrated_rom_size"] = 0xb000 if with_ethernet else 0x9000
kwargs["integrated_rom_size"] = 0xd000 if with_ethernet else 0xb000
else:
# There are numerous PowerPC-isms scattered throughout the HDL and firmware.
# Even if you get a bistream out with a non-PowerPC CPU, it probably won't
# work, and the firmware almost certainly won't build, let alone function.
#
# If you are an end user or software developer, you probably forgot to pass
# "--cpu-type=microwatt" to the build script.
#
# If you are a developer and are trying to port the Kestrel HDL and firmware
# to a non-PowerPC CPU, you probably know what you're doing and can debug
# whatever you break on your own hardware. Remove this line and keep hacking!
raise OSError("Kestrel HDL and firmware currently require a PowerPC-compatible CPU to function. Did you forget '--cpu-type=microwatt'?")
# SoCCore -----------------------------------------_----------------------------------------
SoCCore.__init__(self, platform, sys_clk_freq,
ident = "LiteX SoC on Versa ECP5",
SoCCore.__init__(self, platform, csr_data_width=32, irq_n_irqs=16, clk_freq=sys_clk_freq,
ident = "Kestrel SoC on Versa ECP5",
ident_version = True,
**kwargs)
......@@ -126,11 +180,187 @@ class BaseSoC(SoCCore):
if with_etherbone:
self.add_etherbone(phy=self.ethphy, ip_address=eth_ip)
# Leds -------------------------------------------------------------------------------------
self.submodules.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
self.add_csr("leds")
# Debug pad locator
debug2_pads = platform.request("debug_port_2")
lpc_debug_mirror_clock_pad = platform.request("lpc_debug_mirror_clock")
# Host SPI Flash (Tercel core) -------------------------------------------------------------
if with_hostspiflash:
hostspiflash4x_pads = platform.request("hostspiflash4x")
self.host_spi_dq_debug = [Signal(), Signal(), Signal(), Signal(), Signal(), Signal()]
self.submodules.hostspiflash = TercelSPI(
platform = platform,
pads = hostspiflash4x_pads,
debug_signals = self.host_spi_dq_debug,
clk_freq = sys_clk_freq,
endianness = self.cpu.endianness,
adr_offset = self.mem_map.get("hostspiflash", None))
self.add_csr("hostspiflash")
hostspiflash_size = 64*mB
hostspiflash_region = SoCRegion(origin=self.mem_map.get("hostspiflash", None), size=hostspiflash_size, cached=False)
self.bus.add_slave(name="hostspiflash", slave=self.hostspiflash.bus, region=hostspiflash_region)
hostspiflashcfg_size = 128
hostspiflashcfg_region = SoCRegion(origin=self.mem_map.get("hostspiflashcfg", None), size=hostspiflashcfg_size, cached=False)
self.bus.add_slave(name="hostspiflashcfg", slave=self.hostspiflash.cfg_bus, region=hostspiflashcfg_region)
# Host LPC Slave (Aquila core) -------------------------------------------------------------
if with_hostlpcslave:
hostlpcslave_pads = platform.request("hostlpcslave")
self.host_lpc_debug = [Signal(), Signal(), Signal(), Signal(), Signal(), Signal(), Signal(), Signal()]
self.host_lpc_clock_mirror = Signal()
self.submodules.hostlpcslave = AquilaLPCSlave(
platform = platform,
pads = hostlpcslave_pads,
debug_signals = self.host_lpc_debug,
lpc_clk_mirror = self.host_lpc_clock_mirror,
endianness = self.cpu.endianness,
adr_offset = self.mem_map.get("hostlpcslave", None))
self.add_csr("hostlpcslave")
hostlpcslave_size = 16*mB
hostlpcslave_region = SoCRegion(origin=self.mem_map.get("hostlpcslave", None), size=hostlpcslave_size, cached=False)
self.bus.add_slave(name="hostlpcslave", slave=self.hostlpcslave.slave_bus, region=hostlpcslave_region)
self.bus.add_master(name="hostlpcslave", master=self.hostlpcslave.master_bus)
# OpenFSI Master ---------------------------------------------------------------------------
if with_openfsi_master:
openfsi_master_pads = platform.request("openfsi_master")
self.submodules.openfsi_master = OpenFSIMaster(
platform = platform,
pads = openfsi_master_pads,
endianness = self.cpu.endianness)
self.add_csr("openfsimaster")
openfsi_master_size = 128
openfsi_master_region = SoCRegion(origin=self.mem_map.get("openfsimaster", None), size=openfsi_master_size, cached=False)
self.bus.add_slave(name="openfsimaster", slave=self.openfsi_master.slave_bus, region=openfsi_master_region)
# Debug hookups...
#self.comb += debug2_pads.led_15.eq(self.host_spi_dq_debug[5])
#self.comb += debug2_pads.led_14.eq(self.host_spi_dq_debug[4])
#self.comb += debug2_pads.led_13.eq(hostspiflash4x_pads.clk)
#self.comb += debug2_pads.led_12.eq(hostspiflash4x_pads.cs_n)
#self.comb += debug2_pads.led_11.eq(self.host_spi_dq_debug[3])
#self.comb += debug2_pads.led_10.eq(self.host_spi_dq_debug[2])
#self.comb += debug2_pads.led_9.eq(self.host_spi_dq_debug[1])
#self.comb += debug2_pads.led_8.eq(self.host_spi_dq_debug[0])
if with_hostlpcslave:
self.comb += debug2_pads.led_15.eq(self.host_lpc_debug[7])
self.comb += debug2_pads.led_14.eq(self.host_lpc_debug[6])
self.comb += debug2_pads.led_13.eq(self.host_lpc_debug[5])
self.comb += debug2_pads.led_12.eq(self.host_lpc_debug[4])
self.comb += debug2_pads.led_11.eq(self.host_lpc_debug[3])
self.comb += debug2_pads.led_10.eq(self.host_lpc_debug[2])
self.comb += debug2_pads.led_9.eq(self.host_lpc_debug[1])
self.comb += debug2_pads.led_8.eq(self.host_lpc_debug[0])
self.comb += lpc_debug_mirror_clock_pad.eq(self.host_lpc_clock_mirror)
# I2C Masters ------------------------------------------------------------------------------
if with_i2c_masters:
i2cmaster1_pads = platform.request("i2c_bus1_master")
self.submodules.i2cmaster1 = OpenCoresI2CMaster(
platform = platform,
pads = i2cmaster1_pads,
clk_freq = sys_clk_freq)
self.add_csr("i2cmaster1")
i2cmaster1_size = 32
i2cmaster1_region = SoCRegion(origin=self.mem_map.get("i2cmaster1", None), size=i2cmaster1_size, cached=False)
self.bus.add_slave(name="i2cmaster1", slave=self.i2cmaster1.bus, region=i2cmaster1_region)
if with_i2c_masters:
i2cmaster2_pads = platform.request("i2c_bus2_master")
self.submodules.i2cmaster2 = OpenCoresI2CMaster(
platform = platform,
pads = i2cmaster2_pads,
clk_freq = sys_clk_freq)
self.add_csr("i2cmaster2")
i2cmaster2_size = 32
i2cmaster2_region = SoCRegion(origin=self.mem_map.get("i2cmaster2", None), size=i2cmaster2_size, cached=False)
self.bus.add_slave(name="i2cmaster2", slave=self.i2cmaster2.bus, region=i2cmaster2_region)
# Not needed for Blackbird / Talos II / Sparrowhawk; save space on the Versa board ECP5 -45 device
#if with_i2c_masters:
#i2cmaster3_pads = platform.request("i2c_bus3_master")
#self.submodules.i2cmaster3 = OpenCoresI2CMaster(
#platform = platform,
#pads = i2cmaster3_pads,
#clk_freq = sys_clk_freq)
#self.add_csr("i2cmaster3")
#i2cmaster3_size = 32
#i2cmaster3_region = SoCRegion(origin=self.mem_map.get("i2cmaster3", None), size=i2cmaster3_size, cached=False)
#self.bus.add_slave(name="i2cmaster3", slave=self.i2cmaster3.bus, region=i2cmaster3_region)
if with_i2c_masters:
i2cmaster4_pads = platform.request("i2c_bus4_master")
self.submodules.i2cmaster4 = OpenCoresI2CMaster(
platform = platform,
pads = i2cmaster4_pads,
clk_freq = sys_clk_freq)
self.add_csr("i2cmaster4")
i2cmaster4_size = 32
i2cmaster4_region = SoCRegion(origin=self.mem_map.get("i2cmaster4", None), size=i2cmaster4_size, cached=False)
self.bus.add_slave(name="i2cmaster4", slave=self.i2cmaster4.bus, region=i2cmaster4_region)
# SimpleRTC --------------------------------------------------------------------------------
if with_simple_rtc:
self.submodules.simple_rtc = SimpleRTCSlave(
platform = platform,
endianness = self.cpu.endianness,
rtc_clk_src = 'sys',
rtc_clk_freq = sys_clk_freq)
self.add_csr("simplertc")
simple_rtc_size = 128
simple_rtc_region = SoCRegion(origin=self.mem_map.get("simplertc", None), size=simple_rtc_size, cached=False)
self.bus.add_slave(name="simplertc", slave=self.simple_rtc.slave_bus, region=simple_rtc_region)
# Discrete LEDs ----------------------------------------------------------------------------
from litex.soc.cores.gpio import GPIOTristate
self.submodules.gpio1 = GPIOTristate(
pads = platform.request("user_leds"))
self.add_csr("gpio1")
# DIP switches -------------------------------------------------------------------------------------
from litex.soc.cores.gpio import GPIOIn
self.submodules.gpio2 = GPIOIn(
pads = Cat(*[platform.request("user_dip_btn", i) for i in range(8)]))
self.add_csr("gpio2")
# Alphanumeric display -----------------------------------------------------------------------------
from litex.soc.cores.gpio import GPIOTristate
self.submodules.gpio3 = GPIOTristate(
pads = platform.request("alpha_leds"))
self.add_csr("gpio3")
def set_gateware_dir(self, gateware_dir):
self.gateware_dir = gateware_dir
def initialize_rom(self, data):
# Save actual expected contents for future use as gateware/rom.init
content = ""
formatter = "{:0" + str(int(self.rom.mem.width / 4)) + "X}\n"
for d in data:
content += formatter.format(d).zfill(int(self.rom.mem.width / 4))
romfile = os.open(os.path.join(self.gateware_dir, "rom_data.init"), os.O_WRONLY | os.O_CREAT)
os.write(romfile, content.encode())
os.close(romfile)
# Generate initial data to allow ecpbram to later stuff the bitstream
(_, path) = tempfile.mkstemp()
subprocess.check_call(["ecpbram", "-g", path, "-w", str(self.rom.mem.width), "-d", str(int(self.integrated_rom_size / 4)), "-s" "0"])
# Convert data to binary
random_file = open(path, 'r')
data = []
random_lines = random_file.readlines()
for line in random_lines:
data.append(int(line, 16))
os.remove(path)
self.rom.mem.init = data
self.rom.mem.name_override = "rom"
# Build --------------------------------------------------------------------------------------------
......@@ -156,15 +386,36 @@ def main():
device = args.device,
with_ethernet = args.with_ethernet,
with_etherbone = args.with_etherbone,
with_hostspiflash = True,
with_hostlpcslave = True,
with_openfsi_master = True,
with_i2c_masters = True,
eth_ip = args.eth_ip,
eth_phy = args.eth_phy,
toolchain = args.toolchain,
**soc_sdram_argdict(args)
)
builder = Builder(soc, **builder_argdict(args))
soc.set_gateware_dir(builder.gateware_dir)
builder_kargs = trellis_argdict(args) if args.toolchain == "trellis" else {}
builder.build(**builder_kargs, run=args.build)
# Stuff the original rom into the fpga
subprocess.check_call(["ecpbram",
"-i", os.path.join(builder.gateware_dir, soc.platform.name + ".config"),
"-o", os.path.join(builder.gateware_dir, soc.platform.name + "_stuffed.config"),
"-f", os.path.join(builder.gateware_dir, "rom.init"),
"-t", os.path.join(builder.gateware_dir, "rom_data.init")])
# Update the svf / bit files
subprocess.check_call(["ecppack",
os.path.join(builder.gateware_dir, soc.platform.name + "_stuffed.config"),
"--svf", os.path.join(builder.gateware_dir, soc.platform.name + ".svf"),
"--bit", os.path.join(builder.gateware_dir, soc.platform.name + ".bit"),
"--bootaddr", "0"])
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".svf"))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment