From 213d100860b12430f65320281f523bc327b2d9c8 Mon Sep 17 00:00:00 2001 From: Fabien Date: Tue, 4 May 2021 12:19:21 +0200 Subject: [PATCH] Lattice iCE40 UltraPlus Breakout board (iCE40UP5K-B-EVN) added --- .../platforms/lattice_ice40up5k_evn.py | 131 ++++++++++++++ litex_boards/targets/lattice_ice40up5k_evn.py | 168 ++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 litex_boards/platforms/lattice_ice40up5k_evn.py create mode 100755 litex_boards/targets/lattice_ice40up5k_evn.py diff --git a/litex_boards/platforms/lattice_ice40up5k_evn.py b/litex_boards/platforms/lattice_ice40up5k_evn.py new file mode 100644 index 0000000..c00195a --- /dev/null +++ b/litex_boards/platforms/lattice_ice40up5k_evn.py @@ -0,0 +1,131 @@ +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform +from litex.build.lattice.programmer import IceStormProgrammer + + +_io = [ + # Clk + ("clk12", 0, Pins("35"), IOStandard("LVCMOS33")), + + # LEDs + ("user_led_n", 0, Pins("39"), IOStandard("LVCMOS33")), + ("rgb_led", 0, + Subsignal("r", Pins("41")), + Subsignal("g", Pins("40")), + Subsignal("b", Pins("39")), + IOStandard("LVCMOS33") + ), + + # Buttons + ("user_sw", 0, Pins("23"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("25"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("34"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("43"), IOStandard("LVCMOS33")) +] + +spiflash = [ + # Only usable in PROG FLASH mode and J7 attached (see PCB silkscreen). + ("spiflash", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")), + ), +] + +serial = [ + ("serial", 0, + Subsignal("tx", Pins("J3:0")), + Subsignal("rx", Pins("J3:1")), + IOStandard("LVCMOS33") + ), + ("serial", 1, + Subsignal("tx", Pins("J3:2")), + Subsignal("rx", Pins("J3:3")), + IOStandard("LVCMOS33") + ) +] + + +_connectors = [ + # Many pins on the AARDVARK, PMOD, J52/HEADER A, and J2/HEADER B connectors + # are multiplexed with other I/O or connector pins. For completeness, all + # pins are exposed here except Vdd, NC, and GND. Pin order is as specified + # on the schematic (except for PMOD, which uses Digilent's numbering). + + # AARDVARK connector omitted- although sysCONFIG pins are exposed on this + # header (which can be used as GPIO), it is meant for flashing using an + # external programmer rather than as an I/O port. + + # PMOD connector shares pins with sysCONFIG- make sure to remove jumper + # J7 if using the PMOD. TODO: Perhaps it would be better to split into two + # single 6-pin PMODs. + # + # PMOD pinout (using ICE40 pin names): + # 1, 2, 3, 4- SPI_SS, SPI_SI, SPI_SO, SPI_SCK + # 5, 6, 7, 8- Free + ("PMOD", "16 17 14 15 27 26 32 31"), + #Silk: SS MOSI MISO SCK 38B 39A 43A 42B + + # J52 exposes LEDs and sysCONFIG pins (yet again). Make sure to remove + # jumper J7 if using the PMOD. Pin order is as follows (right to left): + # 12 10 8 6 4 2 + # 11 9 7 5 3 1 + # + # J52's pinout (using ICE40 pin names for SPI flash): + # 1, 2- Vdd + # 3, 4- rgb_led.b, SPI_SI + # 5, 6- rgb_led.g, SPI_SO + # 7, 8- GND, SPI_SCK + # 9, 10- rgb_led.r, SPI_SS + # 11, 12- GND + # 3 4 5 6 8 9 10 + ("J52", "39 17 40 14 15 41 16"), + + # Pin order of J2, and J3 are as follows (left to right/top to bottom): + # 2 4 6 8 10 12 14 16 18 20 + # 1 3 5 7 9 11 13 15 17 19 + # + # J2's pinout is shared by many things. Entire pinout listed follows: + # 1, 2- Vdd + # 3, 4- user_sw0, NC + # 5, 6- user_sw1, NC + # 7, 8- PMOD D5, Free + # 9, 10- PMOD D4, Free + # 11, 12- PMOD D6, Free + # 13, 14- PMOD D7, Free + # 15, 16- Free, 12.00 clock + # 17, 18- user_sw2, GND + # 19, 20- user_sw3, GND + # 3 5 7 8 9 10 11 12 13 14 15 16 17 19 + ("J2", "23 25 26 36 27 42 32 38 31 28 37 35 34 43"), + # Silk:37A 36B 39A 48B 38B 51A 43A 50B 42B 41A 45A_G1 ICE_CLK 44B 49A + # index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + + # Bank2: 4 3 48 45 47 44 46 2 + # Bank1: 12 21 13 20 19 18 11 10 9 6 + # J3's pinout is all Free, except 1 (Vdd) and 19 (GND). + # 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 + ("J3", "12 4 21 3 13 48 20 45 19 47 18 44 11 46 10 2 9 6"), + # Silk:22A 8A 23B 9B 24A 4A 25B_G3 5B 29B 2A 31B 3B_G6 20A 0A 18A 6A 16A 13B + # index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +] + + +class Platform(LatticePlatform): + default_clk_name = "clk12" + default_clk_period = 1e9/12e6 + + def __init__(self): + LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, + toolchain="icestorm") + self.add_extension(serial) + self.add_extension(spiflash) + + def create_programmer(self): + return IceStormProgrammer() + + def do_finalize(self, fragment): + LatticePlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk12", loose=True), 1e9/12e6) + diff --git a/litex_boards/targets/lattice_ice40up5k_evn.py b/litex_boards/targets/lattice_ice40up5k_evn.py new file mode 100755 index 0000000..8adebf7 --- /dev/null +++ b/litex_boards/targets/lattice_ice40up5k_evn.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2019 Sean Cross +# Copyright (c) 2018 David Shah +# Copyright (c) 2020 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import argparse + +target="lattice_ice40up5k_evn" + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import lattice_ice40up5k_evn +from litex.build.lattice.programmer import IceStormProgrammer + +from litex.soc.cores.ram import Up5kSPRAM +from litex.soc.cores.spi_flash import SpiFlash +from litex.soc.cores.clock import iCE40PLL +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser + +kB = 1024 +mB = 1024*kB + + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + assert sys_clk_freq == 12e6 + self.rst = Signal() + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_por = ClockDomain(reset_less=True) + + # # # + + # Clk/Rst + sys = platform.request("clk12") + platform.add_period_constraint(sys, 1e9/12e6) + + # Power On Reset + por_count = Signal(16, reset=2**16-1) + por_done = Signal() + self.comb += self.cd_por.clk.eq(ClockSignal("sys")) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # Sys Clk + self.comb += self.cd_sys.clk.eq(sys) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done) + + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + mem_map = {**SoCCore.mem_map, **{"spiflash": 0x80000000}} + def __init__(self, bios_flash_offset, sys_clk_freq=int(12e6), **kwargs): + platform = lattice_ice40up5k_evn.Platform() + + # Disable Integrated ROM/SRAM since too large for iCE40 and UP5K has specific SPRAM. + kwargs["integrated_sram_size"] = 0 + kwargs["integrated_rom_size"] = 0 + + # Set CPU variant / reset address + kwargs["cpu_reset_address"] = self.mem_map["spiflash"] + bios_flash_offset + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Lattice iCE40UP5k EVN breakout board", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # 128KB SPRAM (used as SRAM) --------------------------------------------------------------- + self.submodules.spram = Up5kSPRAM(size=128*kB) + self.bus.add_slave("sram", self.spram.bus, SoCRegion(size=128*kB)) + + # SPI Flash -------------------------------------------------------------------------------- + self.add_spi_flash(mode="1x", dummy_cycles=8) + # 4x mode is not possible on this board since WP and HOLD pins are not connected to the FPGA + + # Add ROM linker region -------------------------------------------------------------------- + self.bus.add_region("rom", SoCRegion( + origin = self.mem_map["spiflash"] + bios_flash_offset, + size = 32*kB, + linker = True) + ) + + # Leds ------------------------------------------------------------------------------------- + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led_n"), + sys_clk_freq = sys_clk_freq) + + # Add a UART-Wishbone bridge ----------------------------------------- + debug_uart=False + if debug_uart: + # This will add a bridge on the second serial port defined in platform + from litex.soc.cores.uart import UARTWishboneBridge + self.submodules.uart_bridge = UARTWishboneBridge( + platform.request("serial"), + sys_clk_freq, + baudrate=115200) + self.add_wb_master(self.uart_bridge.wishbone) + +# Flash -------------------------------------------------------------------------------------------- + +def flash(bios_flash_offset): + from litex.build.dfu import DFUProg + prog = IceStormProgrammer() + bitstream = open("build/"+target+"/gateware/"+target+".bin", "rb") + bios = open("build/"+target+"/software/bios/bios.bin", "rb") + image = open("build/"+target+"/image.bin", "wb") + # Copy bitstream at 0x00000000 + for i in range(0x00000000, 0x0020000): + b = bitstream.read(1) + if not b: + image.write(0xff.to_bytes(1, "big")) + else: + image.write(b) + # Copy bios at 0x00020000 + for i in range(0x00000000, 0x00010000): + b = bios.read(1) + if not b: + image.write(0xff.to_bytes(1, "big")) + else: + image.write(b) + bitstream.close() + bios.close() + image.close() + print("Flashing bitstream (+bios)") + prog.flash(0x0, "build/"+target+"/image.bin") + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Lattice iCE40UP5k EVN breakout board") + parser.add_argument("--build", action="store_true", help="Build bitstream") + parser.add_argument("--sys-clk-freq", default=12e6, help="System clock frequency (default: 12MHz)") + parser.add_argument("--bios-flash-offset", default=0x20000, help="BIOS offset in SPI Flash (default: 0x20000)") + parser.add_argument("--flash", action="store_true", help="Flash Bitstream") + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + bios_flash_offset = args.bios_flash_offset, + sys_clk_freq = int(float(args.sys_clk_freq)), + **soc_core_argdict(args) + ) + builder = Builder(soc, **builder_argdict(args)) + builder.build(run=args.build) + + if args.flash: + flash(args.bios_flash_offset) + +if __name__ == "__main__": + main()