Add Logicbone ECP5 board
The Logicbone is an Open Source development board for the Lattice ECP5 being developed at https://github.com/oskirby/logicbone
This commit is contained in:
parent
0ecb8609b3
commit
76a32ba8ec
|
@ -0,0 +1,195 @@
|
|||
# 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)
|
|
@ -0,0 +1,186 @@
|
|||
#!/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()
|
Loading…
Reference in New Issue