Skip to content
Snippets Groups Projects
Commit 76a32ba8 authored by Owen Kirby's avatar Owen Kirby
Browse files

Add Logicbone ECP5 board

The Logicbone is an Open Source development board for the Lattice ECP5
being developed at https://github.com/oskirby/logicbone
parent 0ecb8609
No related branches found
No related tags found
No related merge requests found
# This file is Copyright (c) 2020 Owen Kirby <oskirby@gmail.com>
# License: BSD
#
# Logicbone ECP5:
# - Design files: https://github.com/oskirby/logicbone
# - Bootloader: https://github.com/oskirby/tinydfu-bootloader
#
from litex.build.generic_platform import *
from litex.build.lattice import LatticePlatform
from litex.build.dfu import DFUProg
# IOs ----------------------------------------------------------------------------------------------
_io_rev0 = [
("refclk", 0, Pins("M19"), IOStandard("LVCMOS18")),
("rst_n", 0, Pins("C17"), IOStandard("LVCMOS33")),
("user_btn", 0, Pins("U2"), IOStandard("LVCMOS33")),
("user_led", 0, Pins("D16"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("C15"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("C13"), IOStandard("LVCMOS33")),
("user_led", 3, Pins("B13"), IOStandard("LVCMOS33")),
("ddram", 0,
Subsignal("a", Pins(
"D5 F4 B3 F3 E5 C3 C4 A5",
"A3 B5 G3 F5 D2 A4 D3 E3"),
IOStandard("SSTL135_I")),
Subsignal("ba", Pins("B4 H5 N2"), IOStandard("SSTL135_I")),
Subsignal("ras_n", Pins("L1"), IOStandard("SSTL135_I")),
Subsignal("cas_n", Pins("M1"), IOStandard("SSTL135_I")),
Subsignal("we_n", Pins("E4"), IOStandard("SSTL135_I")),
Subsignal("cs_n", Pins("M3"), IOStandard("SSTL135_I")),
#Subsignal("dm", Pins("L4 J5"), IOStandard("SSTL135_I")),
Subsignal("dm", Pins("L5 H3"), IOStandard("SSTL135_I")), # HACK: I broke the DM pins, so we'll use some NC pins instead.
Subsignal("dq", Pins(
"G2 K1 F1 K3 H2 J3 G1 H1",
"B1 E1 A2 F2 C1 E2 C2 D1"),
IOStandard("SSTL135_I"),
Misc("TERMINATION=75")),
Subsignal("dqs_p", Pins("K2 H4"), IOStandard("SSTL135D_I"),
Misc("TERMINATION=OFF"),
Misc("DIFFRESISTOR=100")),
Subsignal("clk_p", Pins("M4"), IOStandard("SSTL135D_I")),
Subsignal("cke", Pins("K4"), IOStandard("SSTL135_I")),
Subsignal("odt", Pins("C5"), IOStandard("SSTL135_I")),
Subsignal("reset_n", Pins("P1"), IOStandard("SSTL135_I")),
Misc("SLEWRATE=FAST"),
),
("usb", 0,
Subsignal("d_p", Pins("B12")),
Subsignal("d_n", Pins("C12")),
Subsignal("pullup", Pins("C16")),
IOStandard("LVCMOS33")
),
("serial", 0,
Subsignal("rx", Pins("B6"), IOStandard("LVCMOS33")),
Subsignal("tx", Pins("A7"), IOStandard("LVCMOS33")),
),
("spiflash4x", 0,
Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")),
#Subsignal("clk", Pins("U3"), IOStandard("LVCMOS33")), # Note: CLK is bound using USRMCLK block
Subsignal("dq", Pins("W2 V2 Y2 W1"), IOStandard("LVCMOS33")),
),
("spiflash", 0,
Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")),
#Subsignal("clk", Pins("U3"), IOStandard("LVCMOS33")), # Note: CLK is bound using USRMCLK block
Subsignal("miso", Pins("V2"), IOStandard("LVCMOS33")),
Subsignal("mosi", Pins("W2"), IOStandard("LVCMOS33")),
Subsignal("wp", Pins("Y2"), IOStandard("LVCMOS33")),
Subsignal("hold", Pins("W1"), IOStandard("LVCMOS33")),
),
("sdcard", 0,
Subsignal("clk", Pins("E11")),
Subsignal("cmd", Pins("D15"), Misc("PULLMODE=UP")),
Subsignal("data", Pins("D13 E13 E15 E14"), Misc("PULLMODE=UP")),
Subsignal("cd", Pins("D14"), Misc("PULLMODE=UP")),
IOStandard("LVCMOS33"), Misc("SLEW=FAST")
),
("spisdcard", 0,
Subsignal("clk", Pins("E11")),
Subsignal("mosi", Pins("D15"), Misc("PULLMODE=UP")),
Subsignal("cs_n", Pins("E14"), Misc("PULLMODE=UP")),
Subsignal("miso", Pins("D13"), Misc("PULLMODE=UP")),
Misc("SLEW=FAST"),
IOStandard("LVCMOS33"),
),
("i2c", 0,
Subsignal("sda", Pins("V1")),
Subsignal("scl", Pins("U1")),
IOStandard("LVCMOS33")
),
("eth_clocks", 0,
Subsignal("tx", Pins("A15")),
Subsignal("rx", Pins("B18")),
Subsignal("ref", Pins("A19")),
IOStandard("LVCMOS33")
),
("eth", 0,
#Subsignal("rst_n", Pins("U17")), # Stolen for SYS_RESETn on prototypes.
Subsignal("int_n", Pins("B20"), Misc("PULLMODE=UP")), # HACK: Should have a pullup on the board.
Subsignal("mdio", Pins("B19"), Misc("PULLMODE=UP")), # HACK: Should have a pullup on the board.
Subsignal("mdc", Pins("D12")),
Subsignal("tx_ctl", Pins("B15")),
Subsignal("tx_data", Pins("A12 A13 C14 A14")),
Subsignal("rx_ctl", Pins("A18")),
Subsignal("rx_data", Pins("B17 A17 B16 A16")),
IOStandard("LVCMOS33")
),
]
# Connectors ---------------------------------------------------------------------------------------
_connectors_rev0 = [
("P8",
"None", # No pin 0
"None", "None", # GND
"C20", "D19", # P8_LVDS1
"D20", "E19", # P8_LVDS2
"E20", "F19", # P8_LVDS3
"F20", "G20", # P8_LVDS4
"None", "None",
"None", "None",
"None", "None",
"None", "None",
"None", "None",
"None", "None",
"G19", "H20", # P8_LVDS5
"J20", "K20", # P8_LVDS6
"C18", "D17", # P8_LVDS7
"D18", "E17", # P8_LVDS8
"E18", "F18", # P8_LVDS9
"F17", "G18", # P8_LVDS10
"E16", "F16", # P8_LVDS11
"G16", "H16", # P8_LVDS12
"J17", "J16", # P8_LVDS13
"H18", "H17", # P8_LVDS14
"J19", "K19", # P8_LVDS15
"J18", "K18"), # P8_LVDS16
("P9",
"None", # No pin 0
"None", "None", # GND
"None", "None", # VCC3V3
"None", "None", # CAPE_5V
"None", "None", # VBUS
"None", "None", # PWR_BUTTON, SYS_RESETn
"A11", "B11", # GPIO11, GPIO12
"A10", "C10", # GPIO13, GPIO14
"A9", "B9", # GPIO15, GPIO16
"C11", "A8", # GPIO17, GPIO18
"None", "None", # I2C Bus
"D9", "C8", # GPIO21, GPIO22
"B8", "A7", # GPIO23, GPIO24
"A6", "B6", # GPIO25, GPIO26
"D8", "C7", # GPIO27, P9_SPI_CSEL
"D7", "C6", # P9_SPI_D0, P9_SPI_D1
"D6", "None", # P9_SPI_SCLK, VADC
"None", "None", # AIN4, GNDA
"None", "None", # AIN6, AIN5
"None", "None", # AIN2, AIN3
"None", "None", # AIN0, AIN1
"B10", "E10", # CLKOUT, GPIO42
"None", "None", # GND
"None", "None") # GND
]
# Platform -----------------------------------------------------------------------------------------
class Platform(LatticePlatform):
default_clk_name = "refclk"
default_clk_period = 1e9/25e6
def __init__(self, revision="rev0", device="45F", **kwargs):
assert revision in ["rev0"]
self.revision = revision
io = {"rev0": _io_rev0 }[revision]
connectors = {"rev0": _connectors_rev0 }[revision]
LatticePlatform.__init__(self, f"LFE5UM5G-{device}-8BG381C", io, connectors, **kwargs)
def create_programmer(self):
return DFUProg(vid="1d50", pid="6130")
def do_finalize(self, fragment):
LatticePlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request("refclk", loose=True), 1e9/25e6)
self.add_period_constraint(self.lookup_request("eth_clocks:rx", loose=True), 1e9/125e6)
#!/usr/bin/env python3
# This file is Copyright (c) 2020 Owen Kirby <oskirby@gmail.com>
# License: BSD
import os
import sys
import argparse
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex_boards.platforms import logicbone
from litex.build.lattice.trellis import trellis_args, trellis_argdict
from litex.soc.cores.clock import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.soc_sdram import *
from litex.soc.integration.builder import *
from litex.soc.cores.led import LedChaser
from litedram.modules import MT41K512M16
from litedram.phy import ECP5DDRPHY
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
# _CRG ---------------------------------------------------------------------------------------------
class _CRG(Module):
def __init__(self, platform, sys_clk_freq, with_usb_pll=False):
self.clock_domains.cd_init = ClockDomain()
self.clock_domains.cd_por = ClockDomain(reset_less=True)
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys2x = ClockDomain()
self.clock_domains.cd_sys2x_i = ClockDomain(reset_less=True)
self.clock_domains.cd_sys2x_eb = ClockDomain(reset_less=True)
self.clock_domains.cd_clk10 = ClockDomain()
# # #
self.stop = Signal()
# Clk / Rst
clk25 = platform.request("refclk")
# Power on reset
por_count = Signal(16, reset=2**16-1)
por_done = Signal()
self.comb += self.cd_por.clk.eq(ClockSignal())
self.comb += por_done.eq(por_count == 0)
self.sync.por += If(~por_done, por_count.eq(por_count - 1))
# PLL
sys2x_clk_ecsout = Signal()
self.submodules.pll = pll = ECP5PLL()
pll.register_clkin(clk25, 25e6)
pll.create_clkout(self.cd_sys2x_i, 2*sys_clk_freq)
pll.create_clkout(self.cd_init, 24e6)
pll.create_clkout(self.cd_clk10, 10e6)
self.specials += [
Instance("ECLKBRIDGECS",
i_CLK0 = self.cd_sys2x_i.clk,
i_SEL = 0,
o_ECSOUT = sys2x_clk_ecsout),
Instance("ECLKSYNCB",
i_ECLKI = sys2x_clk_ecsout,
i_STOP = self.stop,
o_ECLKO = self.cd_sys2x.clk),
Instance("CLKDIVF",
p_DIV = "2.0",
i_ALIGNWD = 0,
i_CLKI = self.cd_sys2x.clk,
i_RST = self.cd_sys2x.rst,
o_CDIVX = self.cd_sys.clk),
AsyncResetSynchronizer(self.cd_init, ~por_done | ~pll.locked),
AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked),
AsyncResetSynchronizer(self.cd_clk10, ~por_done | ~pll.locked)
]
# USB PLL
if with_usb_pll:
self.clock_domains.cd_usb_12 = ClockDomain()
self.clock_domains.cd_usb_48 = ClockDomain()
usb_pll = ECP5PLL()
self.submodules += usb_pll
usb_pll.register_clkin(clk25, 25e6)
usb_pll.create_clkout(self.cd_usb_48, 48e6)
usb_pll.create_clkout(self.cd_usb_12, 12e6)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, revision="rev0", device="45F", sdram_device="MT41K512M16",
with_ethernet=False,
sys_clk_freq=int(75e6), toolchain="trellis", **kwargs):
platform = logicbone.Platform(revision=revision, device=device ,toolchain=toolchain)
# Serial -----------------------------------------------------------------------------------
if kwargs["uart_name"] == "usb_acm":
# FIXME: do proper install of ValentyUSB.
os.system("git clone https://github.com/gregdavill/valentyusb -b hw_cdc_eptri")
sys.path.append("valentyusb")
# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs)
# CRG --------------------------------------------------------------------------------------
with_usb_pll = kwargs.get("uart_name", None) == "usb_acm"
self.submodules.crg = _CRG(platform, sys_clk_freq, with_usb_pll)
# DDR3 SDRAM -------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
available_sdram_modules = {
"MT41K512M16": MT41K512M16,
#"AS4C1GM8": AS4C1GM8, ## Too many rows, seems to break things.
}
sdram_module = available_sdram_modules.get(sdram_device)
self.submodules.ddrphy = ECP5DDRPHY(
platform.request("ddram"),
sys_clk_freq=sys_clk_freq)
self.add_csr("ddrphy")
self.comb += self.crg.stop.eq(self.ddrphy.init.stop)
self.add_sdram("sdram",
phy = self.ddrphy,
module = sdram_module(sys_clk_freq, "1:2"),
origin = self.mem_map["main_ram"],
size = kwargs.get("max_sdram_size", 0x40000000),
l2_cache_size = kwargs.get("l2_size", 8192),
l2_cache_min_data_width = kwargs.get("min_l2_data_width", 128),
l2_cache_reverse = True
)
# Ethernet ---------------------------------------------------------------------------------
if with_ethernet:
self.submodules.ethphy = LiteEthPHYRGMII(
clock_pads = self.platform.request("eth_clocks"),
pads = self.platform.request("eth"))
self.add_csr("ethphy")
self.add_ethernet(phy=self.ethphy)
# Leds -------------------------------------------------------------------------------------
self.submodules.leds = LedChaser(
pads = Cat(*[platform.request("user_led", i) for i in range(4)]),
sys_clk_freq = sys_clk_freq)
self.add_csr("leds")
# Build --------------------------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Logicbone")
parser.add_argument("--build", action="store_true", help="Build bitstream")
parser.add_argument("--load", action="store_true", help="Load bitstream")
parser.add_argument("--toolchain", default="trellis", help="Gateware toolchain to use, trellis (default) or diamond")
builder_args(parser)
soc_sdram_args(parser)
trellis_args(parser)
parser.add_argument("--sys-clk-freq", default=75e6, help="System clock frequency (default=75MHz)")
parser.add_argument("--device", default="45F", help="ECP5 device (default=45F)")
parser.add_argument("--sdram-device", default="MT41K512M16", help="ECP5 device (default=MT41K512M16)")
parser.add_argument("--with-ethernet", action="store_true", help="enable Ethernet support")
parser.add_argument("--with-sdcard", action="store_true", help="enable SDCard support")
args = parser.parse_args()
soc = BaseSoC(
toolchain = args.toolchain,
revision = args.revision,
device = args.device,
sdram_device = args.sdram_device,
with_ethernet=args.with_ethernet,
sys_clk_freq = int(float(args.sys_clk_freq)),
**soc_sdram_argdict(args))
if args.with_sdcard:
soc.add_sdcard()
builder = Builder(soc, **builder_argdict(args))
builder_kargs = trellis_argdict(args) if args.toolchain == "trellis" else {}
builder.build(**builder_kargs, 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()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment