diff --git a/platforms/icebreaker.py b/platforms/icebreaker.py index 69e1f3424..74cbc1f8c 100644 --- a/platforms/icebreaker.py +++ b/platforms/icebreaker.py @@ -4,16 +4,27 @@ _io = [ - ("user_led_n", 0, Pins("11"), IOStandard("LVCMOS33")), - ("user_led_n", 1, Pins("37"), IOStandard("LVCMOS33")), - # Color-specific aliases - ("user_ledr_n", 0, Pins("11"), IOStandard("LVCMOS33")), - ("user_ledg_n", 0, Pins("37"), IOStandard("LVCMOS33")), - ("user_btn_n", 0, Pins("10"), IOStandard("LVCMOS33")), + # HACK: Use icefeather pins + ("user_led_n", 0, Pins("47"), IOStandard("LVCMOS33")), + ("user_led", 0, Pins("41"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("40"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("39"), IOStandard("LVCMOS33")), + # RGB LED + ("user_ledr_n", 0, Pins("41"), IOStandard("LVCMOS33")), + ("user_ledg_n", 0, Pins("40"), IOStandard("LVCMOS33")), + ("user_ledb_n", 0, Pins("39"), IOStandard("LVCMOS33")), + ("user_btn_n", 0, Pins("2"), IOStandard("LVCMOS33")), + + # HACK: Replace UART with icefeather pins + #("serial", 0, + # Subsignal("rx", Pins("6")), + # Subsignal("tx", Pins("9"), Misc("PULLUP")), + # IOStandard("LVCMOS33") + #), ("serial", 0, - Subsignal("rx", Pins("6")), - Subsignal("tx", Pins("9"), Misc("PULLUP")), + Subsignal("rx", Pins("23")), + Subsignal("tx", Pins("21"), Misc("PULLUP")), IOStandard("LVCMOS33") ), @@ -36,35 +47,9 @@ ] _connectors = [ - ("PMOD1A", "4 2 47 45 3 48 46 44"), - ("PMOD1B", "43 38 34 31 42 36 32 28"), - ("PMOD2", "27 25 21 19 26 23 20 18"), ("RGBLED", "39 40 41"), ] -# The attached LED/button section can be either used standalone or as a PMOD. -# Attach to platform using: -# plat.add_extension(break_off_pmod) -# pmod_btn = plat.request("user_btn") -break_off_pmod = [ - ("user_btn", 0, Pins("PMOD2:6"), IOStandard("LVCMOS33")), - ("user_btn", 1, Pins("PMOD2:3"), IOStandard("LVCMOS33")), - ("user_btn", 2, Pins("PMOD2:7"), IOStandard("LVCMOS33")), - - ("user_led", 0, Pins("PMOD2:4"), IOStandard("LVCMOS33")), - ("user_led", 1, Pins("PMOD2:0"), IOStandard("LVCMOS33")), - ("user_led", 2, Pins("PMOD2:1"), IOStandard("LVCMOS33")), - ("user_led", 3, Pins("PMOD2:5"), IOStandard("LVCMOS33")), - ("user_led", 4, Pins("PMOD2:2"), IOStandard("LVCMOS33")), - - # Color-specific aliases - ("user_ledr", 0, Pins("PMOD2:4"), IOStandard("LVCMOS33")), - ("user_ledg", 0, Pins("PMOD2:0"), IOStandard("LVCMOS33")), - ("user_ledg", 1, Pins("PMOD2:1"), IOStandard("LVCMOS33")), - ("user_ledg", 2, Pins("PMOD2:5"), IOStandard("LVCMOS33")), - ("user_ledg", 3, Pins("PMOD2:2"), IOStandard("LVCMOS33")) -] - rgb_led = [ ("rgbled", 0, Subsignal("rgb0", Pins("RGBLED:0")), diff --git a/platforms/icefeather.py b/platforms/icefeather.py new file mode 100644 index 000000000..1ec9bb26c --- /dev/null +++ b/platforms/icefeather.py @@ -0,0 +1,74 @@ +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform +from litex.build.lattice.programmer import IceStormProgrammer + + +_io = [ + ("user_led_n", 0, Pins("47"), IOStandard("LVCMOS33")), + # RGB LED + ("user_ledr_n", 0, Pins("41"), IOStandard("LVCMOS33")), + ("user_ledg_n", 0, Pins("40"), IOStandard("LVCMOS33")), + ("user_ledb_n", 0, Pins("39"), IOStandard("LVCMOS33")), + ("user_btn_n", 0, Pins("2"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("rx", Pins("23")), + Subsignal("tx", Pins("21"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + + ("spiflash", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")), + # TODO: Do not need these + Subsignal("wp", Pins("12"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("13"), IOStandard("LVCMOS33")), + ), + + ("spiflash4x", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + # TODO: Find out quad-spi pins + Subsignal("dq", Pins("14 17 12 13"), IOStandard("LVCMOS33")), + ), + + ("clk12", 0, Pins("35"), IOStandard("LVCMOS33")) +] + +_connectors = [ + ("RGBLED", "6 4 3"), +] + +rgb_led = [ + ("rgbled", 0, + Subsignal("rgb0", Pins("RGBLED:0")), + Subsignal("rgb1", Pins("RGBLED:1")), + Subsignal("rgb2", Pins("RGBLED:2")), + IOStandard("LVCMOS33") + ), +] + + +class Platform(LatticePlatform): + default_clk_name = "clk12" + default_clk_period = 83.333 + + gateware_size = 0x20000 + + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + spiflash_model = "n25q128" + spiflash_read_dummy_bits = 8 + spiflash_clock_div = 2 + spiflash_total_size = int((128/8)*1024*1024) # 128Mbit + spiflash_page_size = 256 + # Winbond calls 32kb/64kb sectors "blocks". + spiflash_sector_size = 0x10000 + + def __init__(self): + LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, + toolchain="icestorm") + + def create_programmer(self): + return IceStormProgrammer() diff --git a/scripts/download-env.sh b/scripts/download-env.sh index bb77de0ac..752910cbf 100755 --- a/scripts/download-env.sh +++ b/scripts/download-env.sh @@ -438,7 +438,7 @@ if [ "$PLATFORM" = "tinyfpga_bx" ]; then fi # iceprog compatible platforms -if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then +if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "icefeather" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then echo echo "Installing iceprog (tool for FTDI)" conda install iceprog diff --git a/scripts/enter-env.sh b/scripts/enter-env.sh index 17d41c9a9..88bddf2a4 100755 --- a/scripts/enter-env.sh +++ b/scripts/enter-env.sh @@ -361,7 +361,7 @@ if [ "$PLATFORM" = "tinyfpga_bx" ]; then fi # iceprog compatible platforms -if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then +if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "icefeather" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then diff --git a/targets/icebreaker/base.py b/targets/icebreaker/base.py index bc86a0852..c279e66e9 100644 --- a/targets/icebreaker/base.py +++ b/targets/icebreaker/base.py @@ -74,7 +74,6 @@ def __init__(self, platform, **kwargs): # Assume user still has LEDs/Buttons still attached to the PCB or as # a PMOD; pinout is identical either way. - platform.add_extension(icebreaker.break_off_pmod) clk_freq = int(12e6) kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size diff --git a/targets/icefeather/Makefile.mk b/targets/icefeather/Makefile.mk new file mode 100644 index 000000000..19873b780 --- /dev/null +++ b/targets/icefeather/Makefile.mk @@ -0,0 +1,66 @@ +# ice40_up5k targets + +ifneq ($(PLATFORM),icefeather) + $(error "Platform should be icefeather when using this file!?") +endif + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): + iceprog $(IMAGE_FILE) + +# Gateware +gateware-load-$(PLATFORM): + @echo "icefeather doesn't support loading, use the flash target instead." + @echo "make gateware-flash" + @false + +# As with Mimasv2, if the user asks to flash the gateware only, the BIOS must +# be sent as well (because the BIOS is too big to fit into the bitstream). +GATEWARE_BIOS_FILE = $(TARGET_BUILD_DIR)/image-gateware+bios+none.bin + +gateware-flash-$(PLATFORM): $(GATEWARE_BIOS_FILE) + iceprog $(GATEWARE_BIOS_FILE) + +# To avoid duplicating the mkimage.py call here, if the user has not +# already built a image-gateware+bios+none.bin, we call make recursively +# to build one here, with the FIRMWARE=none override. +# +ifneq ($(GATEWARE_BIOS_FILE),$(IMAGE_FILE)) +$(GATEWARE_BIOS_FILE): $(GATEWARE_FILEBASE).bin $(BIOS_FILE) mkimage.py + FIRMWARE=none make image +endif + +# Firmware +firmware-load-$(PLATFORM): + @echo "Unsupported." + @false + +firmware-flash-$(PLATFORM): + @echo "icefeather doesn't support just flashing firmware, use image target instead." + @echo "make image-flash" + @false + +firmware-connect-$(PLATFORM): + flterm --port=$(COMM_PORT) --speed=$(BAUD) + +firmware-clear-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +# Bios +bios-flash-$(PLATFORM): + @echo "Unsupported." + @false + +# Extra commands +help-$(PLATFORM): + @true + +reset-$(PLATFORM): + @echo "Unsupported." + @false diff --git a/targets/icefeather/base.py b/targets/icefeather/base.py new file mode 100644 index 000000000..bdb7c91dc --- /dev/null +++ b/targets/icefeather/base.py @@ -0,0 +1,118 @@ +import sys +import struct +import os.path +import argparse + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.build.generic_platform import Pins, Subsignal, IOStandard +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage + +from gateware import ice40 +from gateware import cas +from gateware import spi_flash + +from targets.utils import define_flash_constants +from platforms import icefeather + +class _CRG(Module): + def __init__(self, platform): + clk12 = platform.request("clk12") + + self.clock_domains.cd_sys = ClockDomain() + self.reset = Signal() + + # FIXME: Use PLL, increase system clock to 32 MHz, pending nextpnr + # fixes. + self.comb += self.cd_sys.clk.eq(clk12) + + # POR reset logic- POR generated from sys clk, POR logic feeds sys clk + # reset. + reset = self.reset | ~platform.request("user_btn_n") + self.clock_domains.cd_por = ClockDomain() + reset_delay = Signal(12, reset=4095) + self.comb += [ + self.cd_por.clk.eq(self.cd_sys.clk), + self.cd_sys.rst.eq(reset_delay != 0) + ] + self.sync.por += \ + If(reset_delay != 0, + reset_delay.eq(reset_delay - 1) + ) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + + +class BaseSoC(SoCCore): + mem_map = {**SoCCore.mem_map, **{ + "spiflash": 0xa0000000, + }} + + def __init__(self, platform, **kwargs): + # disable SRAM, it'll be added later + kwargs['integrated_sram_size'] = 0x0 + + # disable ROM, it'll be added later + kwargs['integrated_rom_size'] = 0x0 + + # FIXME: Force either lite or minimal variants of CPUs; full is too big. + + # Assume user still has LEDs/Buttons still attached to the PCB or as + # a PMOD; pinout is identical either way. + clk_freq = int(12e6) + + kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size + SoCCore.__init__(self, platform, clk_freq, **kwargs) + + self.submodules.crg = _CRG(platform) + self.platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq) + + # Control and Status + self.submodules.cas = cas.ControlAndStatus(platform, clk_freq) + self.add_csr("cas") + + # SPI flash peripheral + # TODO: Inferred tristate not currently supported by nextpnr; upgrade + # to spiflash4x when possible. + self.submodules.spiflash = spi_flash.SpiFlashSingle( + platform.request("spiflash"), + dummy=platform.spiflash_read_dummy_bits, + div=platform.spiflash_clock_div, + endianness=self.cpu.endianness) + self.add_csr("spiflash") + self.add_constant("SPIFLASH_PAGE_SIZE", platform.spiflash_page_size) + self.add_constant("SPIFLASH_SECTOR_SIZE", platform.spiflash_sector_size) + self.register_mem("spiflash", self.mem_map["spiflash"], + self.spiflash.bus, size=platform.spiflash_total_size) + + # rgb led connector + platform.add_extension(icefeather.rgb_led) + self.submodules.rgbled = ice40.LED(platform.request("rgbled", 0)) + self.add_csr("rgbled") + + bios_size = 0x8000 + self.add_constant("ROM_DISABLE", 1) + self.add_memory_region( + "rom", kwargs['cpu_reset_address'], bios_size, + type="cached+linker") + self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size + define_flash_constants(self) + + # SPRAM- UP5K has single port RAM, might as well use it as SRAM to + # free up scarce block RAM. + self.submodules.spram = ice40.SPRAM(size=128*1024) + self.register_mem("sram", self.mem_map["sram"], self.spram.bus, 0x20000) + + # We don't have a DRAM, so use the remaining SPI flash for user + # program. + self.add_memory_region("user_flash", + self.flash_boot_address, + # Leave a grace area- possible one-by-off bug in add_memory_region? + # Possible fix: addr < origin + length - 1 + platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100, + type="cached+linker") + + +SoC = BaseSoC