diff --git a/README.md b/README.md index 9ee9625..ad87308 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Some of the suported boards, see yours? Give LiteX-Boards a try! ├── adi_adrv2crr_fmc ├── adi_plutosdr ├── alchitry_au + ├── alchitry_cu ├── alchitry_mojo ├── aliexpress_xc7k420t ├── alinx_ax7010 diff --git a/litex_boards/platforms/alchitry_cu.py b/litex_boards/platforms/alchitry_cu.py new file mode 100644 index 0000000..3d332e8 --- /dev/null +++ b/litex_boards/platforms/alchitry_cu.py @@ -0,0 +1,78 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2023 Nimalan M +# SPDX-License-Identifier: BSD-2-Clause + +# The Alchitry Cu is FPGA Development board +# by SparkFun - https://www.sparkfun.com/products/16526. +# +# It has a Lattice ICE40HX8K-CB132IC and can be programmed +# with the Icestorm toolchain +# Schematic - https://cdn.sparkfun.com/assets/2/6/e/5/e/alchitry_cu_sch_update.pdf + +from litex.build.generic_platform import * +from litex.build.lattice import LatticeiCE40Platform +from litex.build.lattice.programmer import IceStormProgrammer + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("clk100", 0, Pins("P7"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("P8"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("J11"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("K11"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("K12"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("K14"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("L12"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("L14"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("M12"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("N14"), IOStandard("LVCMOS33")), + + # Serial + ("serial", 0, + Subsignal("rx", Pins("P14")), + Subsignal("tx", Pins("M9")), + IOStandard("LVCMOS33") + ), + + # Onboard QWIIC + ("i2c", 0, + Subsignal("scl", Pins("A4")), + Subsignal("sda", Pins("A3")), + IOStandard("LVCMOS33"), + ), + + # SPIFlash X25XXSMD1 + ("spiflash", 0, + Subsignal("mosi", Pins("M11")), + Subsignal("miso", Pins("P11")), + Subsignal("clk", Pins("P12")), + Subsignal("cs_n", Pins("P13")), + IOStandard("LVCMOS33") + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(LatticeiCE40Platform): + default_clk_name = "clk100" + default_clk_period = 1e9/100e6 + + def __init__(self, toolchain="icestorm", **kwargs): + LatticeiCE40Platform.__init__(self, "ice40-hx8k-cb132", _io, _connectors, toolchain=toolchain) + + def create_programmer(self): + return IceStormProgrammer() + + def do_finalize(self, fragment): + LatticeiCE40Platform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6) + diff --git a/litex_boards/targets/alchitry_cu.py b/litex_boards/targets/alchitry_cu.py new file mode 100644 index 0000000..7c7d92b --- /dev/null +++ b/litex_boards/targets/alchitry_cu.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2023 Nimalan M +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from litex.gen import * + +from litex_boards.platforms import alchitry_cu + +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.builder import * +from litex.soc.cores.clock import iCE40PLL +from litex.soc.cores.led import LedChaser + +from migen.genlib.resetsync import AsyncResetSynchronizer + +kB = 1024 +mB = 1024*kB + + +# CRG ------------------------------------------------------------------------------------------- + +class _CRG(LiteXModule): + def __init__(self, platform, sys_clk_freq): + self.rst = Signal() + self.cd_sys = ClockDomain() + self.cd_por = ClockDomain() + + # Clk/Rst + clk100 = platform.request("clk100") + rst_n = platform.request("cpu_reset") + + # 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)) + + self.pll = pll = iCE40PLL(primitive="SB_PLL40_CORE") + self.comb += pll.reset.eq(~rst_n) # FIXME: Add proper iCE40PLL reset support and add back | self.rst. + pll.register_clkin(clk100, 100e6) + pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked) + platform.add_period_constraint(self.cd_sys.clk, 1e9/sys_clk_freq) + +# BaseSoC ----------------------------------------------------------------------------------------- + +class BaseSoC(SoCCore): + def __init__(self, + bios_flash_offset, + sys_clk_freq=50e6, + with_led_chaser = True, + **kwargs): + # Create our platform (fpga interface) + platform = alchitry_cu.Platform() + + # Disable Integrated ROM since too large for iCE40. + kwargs["integrated_rom_size"] = 0 + + # SoC with CPU + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Alchitry Cu", + **kwargs) + + # CRG + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # SPI Flash -------------------------------------------------------------------------------- + from litespi.modules import W25Q32 + from litespi.opcodes import SpiNorFlashOpCodes as Codes + self.add_spi_flash(mode="1x", module=W25Q32(Codes.READ_1_1_1), with_master=False) + + # Add ROM linker region -------------------------------------------------------------------- + self.bus.add_region("rom", SoCRegion( + origin = self.bus.regions["spiflash"].origin + bios_flash_offset, + size = 256*kB, + linker = True) + ) + self.cpu.set_reset_address(self.bus.regions["rom"].origin) + + # Led + if with_led_chaser: + self.submodules.leds = LedChaser(pads=platform.request_all("user_led"), sys_clk_freq=sys_clk_freq) + +# Flash -------------------------------------------------------------------------------------------- + +def flash(build_dir, build_name, bios_flash_offset): + from litex.build.lattice.programmer import IceStormProgrammer + prog = IceStormProgrammer() + prog.flash(bios_flash_offset, f"{build_dir}/software/bios/bios.bin") + prog.flash(0x00000000, f"{build_dir}/gateware/{build_name}.bin") + +# Build -------------------------------------------------------------------------------------------- + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=alchitry_cu.Platform, description="LiteX SoC on Alchitry Cu") + parser.add_target_argument("--flash", action="store_true", help="Flash Bitstream and BIOS.") + parser.add_target_argument("--bios-flash-offset", default="0x040000", help="BIOS offset in SPI Flash (default: 0x40000)") + parser.add_target_argument("--sys-clk-freq", default=50e6, type=float, help="System clock frequency (default: 50MHz)") + parser.add_target_argument("--with-led-chaser", action="store_true", help="Enable LED Chaser.") + args = parser.parse_args() + + soc = BaseSoC( + bios_flash_offset = int(args.bios_flash_offset, 0), + sys_clk_freq = args.sys_clk_freq, + **parser.soc_argdict + ) + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + + if args.flash: + flash(builder.output_dir, soc.build_name, args.bios_flash_offset) + + +if __name__ == "__main__": + main()