From 0263be25c3a4d9a8702357c306e76074c533c28c Mon Sep 17 00:00:00 2001 From: Joanna Brozek Date: Mon, 18 Nov 2019 18:21:35 +0100 Subject: [PATCH 1/2] third_party: add valentyusb --- .gitmodules | 3 +++ third_party/valentyusb | 1 + 2 files changed, 4 insertions(+) create mode 160000 third_party/valentyusb diff --git a/.gitmodules b/.gitmodules index bd9cc8154..facbc7a5e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,3 +64,6 @@ [submodule "third_party/VexRiscv"] path = third_party/VexRiscv url = https://github.com/SpinalHDL/VexRiscv.git +[submodule "third_party/valentyusb"] + path = third_party/valentyusb + url = https://github.com/im-tomu/valentyusb.git diff --git a/third_party/valentyusb b/third_party/valentyusb new file mode 160000 index 000000000..da4c8c72e --- /dev/null +++ b/third_party/valentyusb @@ -0,0 +1 @@ +Subproject commit da4c8c72eeb22894369b3936abb73f828f222b8e From 7f41d7d40f90760e66b1aee3ed02cb5f3e96330e Mon Sep 17 00:00:00 2001 From: Piotr Binkowski Date: Mon, 25 Nov 2019 15:33:32 +0100 Subject: [PATCH 2/2] targets: add fomu target --- .travis.yml | 1 + gateware/ice40.py | 20 ++++ platforms/fomu.py | 172 ++++++++++++++++++++++++++++++++++ targets/fomu/Makefile.mk | 80 ++++++++++++++++ targets/fomu/base.py | 197 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 470 insertions(+) create mode 100755 platforms/fomu.py create mode 100644 targets/fomu/Makefile.mk create mode 100755 targets/fomu/base.py diff --git a/.travis.yml b/.travis.yml index 33d403c63..90117c150 100644 --- a/.travis.yml +++ b/.travis.yml @@ -106,6 +106,7 @@ env: - C=picorv32.minimal TC="vivado" P=arty T="base net" - C=picorv32.minimal TC="ise" P=matrix_voice T="base" - C=picorv32.minimal TC="ise" P=opsis T="base net" + - C=picorv32.minimal TC="icestorm" P=fomu T="base" F=stub # minerva target - C=minerva TC="vivado" P=arty T="base net" - C=minerva TC="ise" P=opsis T="base net" diff --git a/gateware/ice40.py b/gateware/ice40.py index 64e0bc948..4cf35c3c2 100644 --- a/gateware/ice40.py +++ b/gateware/ice40.py @@ -162,3 +162,23 @@ def __init__(self, pads): o_PWMOUT2 = rgba_pwm[2], o_LEDDON = Signal(), ) + +class SBWarmBoot(Module, AutoCSR): + def __init__(self, parent): + self.ctrl = CSRStorage(size=8) + self.addr = CSRStorage(size=32) + do_reset = Signal() + self.comb += [ + # "Reset Key" is 0xac (0b101011xx) + do_reset.eq(self.ctrl.storage[2] & self.ctrl.storage[3] & ~self.ctrl.storage[4] + & self.ctrl.storage[5] & ~self.ctrl.storage[6] & self.ctrl.storage[7]) + ] + self.specials += Instance("SB_WARMBOOT", + i_S0 = self.ctrl.storage[0], + i_S1 = self.ctrl.storage[1], + i_BOOT = do_reset, + ) + parent.config["BITSTREAM_SYNC_HEADER1"] = 0x7e99aa7e + parent.config["BITSTREAM_SYNC_HEADER2"] = 0x7eaa997e + + diff --git a/platforms/fomu.py b/platforms/fomu.py new file mode 100755 index 000000000..45772cbd1 --- /dev/null +++ b/platforms/fomu.py @@ -0,0 +1,172 @@ +# Support for the Fomu +# More information can be found here https://github.com/im-tomu/foboot.git + +from litex.build.lattice.platform import LatticePlatform +from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal + +_io_evt = [ + ("serial", 0, + Subsignal("rx", Pins("21")), + Subsignal("tx", Pins("13"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + ("usb", 0, + Subsignal("d_p", Pins("34")), + Subsignal("d_n", Pins("37")), + Subsignal("pullup", Pins("35")), + Subsignal("pulldown", Pins("36")), + IOStandard("LVCMOS33") + ), + ("touch", 0, + Subsignal("t1", Pins("48"), IOStandard("LVCMOS33")), + Subsignal("t2", Pins("47"), IOStandard("LVCMOS33")), + Subsignal("t3", Pins("46"), IOStandard("LVCMOS33")), + Subsignal("t4", Pins("45"), IOStandard("LVCMOS33")), + ), + ("pmoda", 0, + Subsignal("p1", Pins("28"), IOStandard("LVCMOS33")), + Subsignal("p2", Pins("27"), IOStandard("LVCMOS33")), + Subsignal("p3", Pins("26"), IOStandard("LVCMOS33")), + Subsignal("p4", Pins("23"), IOStandard("LVCMOS33")), + ), + ("pmodb", 0, + Subsignal("p1", Pins("48"), IOStandard("LVCMOS33")), + Subsignal("p2", Pins("47"), IOStandard("LVCMOS33")), + Subsignal("p3", Pins("46"), IOStandard("LVCMOS33")), + Subsignal("p4", Pins("45"), IOStandard("LVCMOS33")), + ), + ("led", 0, + Subsignal("rgb0", Pins("39"), IOStandard("LVCMOS33")), + Subsignal("rgb1", Pins("40"), IOStandard("LVCMOS33")), + Subsignal("rgb2", Pins("41"), 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")), + Subsignal("wp", Pins("18"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("19"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("14 17 18 19"), IOStandard("LVCMOS33")), + ), + ("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) +] +_io_dvt = [ + ("serial", 0, + Subsignal("rx", Pins("C3")), + Subsignal("tx", Pins("B3"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + ("usb", 0, + Subsignal("d_p", Pins("A1")), + Subsignal("d_n", Pins("A2")), + Subsignal("pullup", Pins("A4")), + IOStandard("LVCMOS33") + ), + ("touch", 0, + Subsignal("t1", Pins("E4"), IOStandard("LVCMOS33")), + Subsignal("t2", Pins("D5"), IOStandard("LVCMOS33")), + Subsignal("t3", Pins("E5"), IOStandard("LVCMOS33")), + Subsignal("t4", Pins("F5"), IOStandard("LVCMOS33")), + ), + ("led", 0, + Subsignal("rgb0", Pins("A5"), IOStandard("LVCMOS33")), + Subsignal("rgb1", Pins("B5"), IOStandard("LVCMOS33")), + Subsignal("rgb2", Pins("C5"), IOStandard("LVCMOS33")), + ), + ("spiflash", 0, + Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")), + Subsignal("wp", Pins("F2"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("B1"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, + Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("F1 E1 F2 B1"), IOStandard("LVCMOS33")), + ), + ("clk48", 0, Pins("F4"), IOStandard("LVCMOS33")) +] +_io_pvt = _io_dvt +_io_hacker = [ + ("serial", 0, + Subsignal("rx", Pins("C3")), + Subsignal("tx", Pins("B3"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + ("usb", 0, + Subsignal("d_p", Pins("A4")), + Subsignal("d_n", Pins("A2")), + Subsignal("pullup", Pins("D5")), + IOStandard("LVCMOS33") + ), + ("touch", 0, + Subsignal("t1", Pins("F4"), IOStandard("LVCMOS33")), + Subsignal("t2", Pins("E5"), IOStandard("LVCMOS33")), + Subsignal("t3", Pins("E4"), IOStandard("LVCMOS33")), + Subsignal("t4", Pins("F2"), IOStandard("LVCMOS33")), + ), + ("led", 0, + Subsignal("rgb0", Pins("A5"), IOStandard("LVCMOS33")), + Subsignal("rgb1", Pins("B5"), IOStandard("LVCMOS33")), + Subsignal("rgb2", Pins("C5"), IOStandard("LVCMOS33")), + ), + ("spiflash", 0, + Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")), + Subsignal("wp", Pins("A1"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("B1"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, + Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("F1 E1"), IOStandard("LVCMOS33")), + ), + ("clk48", 0, Pins("F5"), IOStandard("LVCMOS33")) +] + +_connectors = [] + +class Platform(LatticePlatform): + default_clk_name = "clk48" + default_clk_period = 20.833 + + # From FPGA-TN-02001-30-iCE40-Programming-Configuration.pdf + # Table 9.2. Bitstream Sizes for Different iCE40 FPGA Densities Used to Select a SPI Flash + # iCE40UP 5K; 104161 (bytes); 833288(bits) + # 104161 bytes == 0x196E1 -- Therefore 0x20000 + gateware_size = 0x20000 + # User bitstream starts at 0x40000 in Flash + bootloader_size = 0x40000 + + # FIXME: Create a "spi flash module" object in the same way we have SDRAM + spiflash_model = "n25q32" + spiflash_read_dummy_bits = 8 + spiflash_clock_div = 2 + spiflash_total_size = int((32/8)*1024*1024) # 32Mbit + spiflash_page_size = 256 + spiflash_sector_size = 0x10000 + + def __init__(self, revision="pvt", toolchain="icestorm"): + self.revision = revision + if revision == "evt": + LatticePlatform.__init__(self, "ice40-up5k-sg48", _io_evt, _connectors, toolchain="icestorm") + elif revision == "dvt": + LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_dvt, _connectors, toolchain="icestorm") + elif revision == "pvt": + LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_pvt, _connectors, toolchain="icestorm") + elif revision == "hacker": + LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_hacker, _connectors, toolchain="icestorm") + else: + raise ValueError("Unrecognized reivsion: {}. Known values: evt, dvt, pvt, hacker".format(revision)) + + def create_programmer(self): + raise ValueError("programming is not supported") diff --git a/targets/fomu/Makefile.mk b/targets/fomu/Makefile.mk new file mode 100644 index 000000000..fb496f5c7 --- /dev/null +++ b/targets/fomu/Makefile.mk @@ -0,0 +1,80 @@ +# fomu targets + +ifneq ($(PLATFORM),fomu) + $(error "Platform should be ice40-up5k-uwg30 or ice40-up5k-sg48 when using this file!?") +endif + +PPATH := $(PYTHONPATH) +export PYTHONPATH=$(PPATH):$(TARGET_BUILD_DIR)/../../third_party/valentyusb/ + +# Settings +DEFAULT_TARGET = base +TARGET ?= $(DEFAULT_TARGET) +BAUD ?= 115200 + +# Image +image-flash-$(PLATFORM): + cp $(IMAGE_FILE) $(IMAGE_FILE).dfu + dfu-suffix --pid 1209 --vid 5bf0 --add $(IMAGE_FILE).dfu + dfu-util -D $(IMAGE_FILE).dfu + +# Gateware +gateware-load-$(PLATFORM): + @echo "Fomu 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). +# +# We have to pre-calculate what the image file will end up being, as we are +# included before it has been defined (to get the default target), so we'll +# end up comparing with an empty string/older value from the environment. +# +GATEWARE_BIOS_FILE = $(TARGET_BUILD_DIR)/image-gateware+bios+none.bin +IMAGE_FW_FILE = $(TARGET_BUILD_DIR)/image-gateware+bios+$(FIRMWARE).bin + +gateware-flash-$(PLATFORM): $(GATEWARE_BIOS_FILE) + cp $(GATEWARE_BIOS_FILE) $(GATEWARE_BIOS_FILE).dfu + dfu-suffix --pid 1209 --vid 5bf0 --add $(GATEWARE_BIOS_FILE).dfu + dfu-util -D $(GATEWARE_BIOS_FILE).dfu + +# 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_FW_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 "Fomu doesn't support just flashing firmware, use gateware target instead." + @echo "make image-flash" + @false + +firmware-connect-$(PLATFORM): + @echo "FIXME: Unsupported?." + @false + +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/fomu/base.py b/targets/fomu/base.py new file mode 100755 index 000000000..915cbebc0 --- /dev/null +++ b/targets/fomu/base.py @@ -0,0 +1,197 @@ +import sys +import struct +import os.path +import argparse + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage +from litex.soc.cores import up5kspram + +from valentyusb import usbcore +from valentyusb.usbcore import io as usbio +from valentyusb.usbcore.cpu import epfifo, dummyusb +from valentyusb.usbcore.endpoint import EndpointType + +from gateware import spi_flash, cas + +from targets.utils import define_flash_constants + +class _CRG(Module): + def __init__(self, platform): + clk48_raw = platform.request("clk48") + clk12 = Signal() + + reset_delay = Signal(12, reset=4095) + self.clock_domains.cd_por = ClockDomain() + self.reset = Signal() + + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_usb_12 = ClockDomain() + self.clock_domains.cd_usb_48 = ClockDomain() + + platform.add_period_constraint(self.cd_usb_48.clk, 1e9/48e6) + platform.add_period_constraint(self.cd_sys.clk, 1e9/12e6) + platform.add_period_constraint(self.cd_usb_12.clk, 1e9/12e6) + platform.add_period_constraint(clk48_raw, 1e9/48e6) + + # POR reset logic- POR generated from sys clk, POR logic feeds sys clk + # reset. + self.comb += [ + self.cd_por.clk.eq(self.cd_sys.clk), + self.cd_sys.rst.eq(reset_delay != 0), + self.cd_usb_12.rst.eq(reset_delay != 0), + ] + + # POR reset logic- POR generated from sys clk, POR logic feeds sys clk + # reset. + self.comb += [ + self.cd_usb_48.rst.eq(reset_delay != 0), + ] + + self.comb += self.cd_usb_48.clk.eq(clk48_raw) + + self.specials += Instance( + "SB_PLL40_CORE", + # Parameters + p_DIVR = 0, + p_DIVF = 15, + p_DIVQ = 5, + p_FILTER_RANGE = 1, + p_FEEDBACK_PATH = "SIMPLE", + p_DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED", + p_FDA_FEEDBACK = 15, + p_DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED", + p_FDA_RELATIVE = 0, + p_SHIFTREG_DIV_MODE = 1, + p_PLLOUT_SELECT = "GENCLK_HALF", + p_ENABLE_ICEGATE = 0, + # IO + i_REFERENCECLK = clk48_raw, + o_PLLOUTCORE = clk12, + # o_PLLOUTGLOBAL = clk12, + #i_EXTFEEDBACK, + #i_DYNAMICDELAY, + #o_LOCK, + i_BYPASS = 0, + i_RESETB = 1, + #i_LATCHINPUTVALUE, + #o_SDO, + #i_SDI, + ) + + self.comb += self.cd_sys.clk.eq(clk12) + self.comb += self.cd_usb_12.clk.eq(clk12) + + self.sync.por += \ + If(reset_delay != 0, + reset_delay.eq(reset_delay - 1) + ) + self.specials += AsyncResetSynchronizer(self.cd_por, self.reset) + + +class BaseSoC(SoCCore): + # Create a default CSR map to prevent values from getting reassigned. + # This increases consistency across litex versions. + SoCCore.csr_map = { + "ctrl": 0, # provided by default (optional) + "crg": 1, # user + "uart_phy": 2, # provided by default (optional) + "uart": 3, # provided by default (optional) + "identifier_mem": 4, # provided by default (optional) + "timer0": 5, # provided by default (optional) + "cpu_or_bridge": 8, + "usb": 9, + "picorvspi": 10, + "touch": 11, + "reboot": 12, + "rgb": 13, + "version": 14, + } + + mem_map = { + "rom": 0x00000000, # (default shadow @0x80000000) + "sram": 0x10000000, # (default shadow @0x90000000) + "spiflash": 0x20000000, # (default shadow @0xa0000000) + "main_ram": 0x40000000, # (default shadow @0xc0000000) + "csr": 0xe0000000, # (default shadow @0x60000000) + } + mem_map.update(SoCCore.mem_map) + + def __init__(self, platform, debug=False, **kwargs): + clk_freq = int(12e6) + + if "cpu_type" not in kwargs: + kwargs["cpu_type"] = None + kwargs["cpu_variant"] = None + + if "with_uart" not in kwargs: + kwargs["with_uart"] = False + + if "with_ctrl" not in kwargs: + kwargs["with_ctrl"] = False + + kwargs["integrated_sram_size"] = 0 + + bios_size = kwargs["integrated_rom_size"] + kwargs["integrated_rom_size"] = 0 + kwargs["cpu_reset_address"] = self.mem_map["spiflash"]+platform.bootloader_size+platform.gateware_size + + SoCCore.__init__(self, platform, clk_freq, **kwargs) + + self.submodules.crg = _CRG(platform) + + # SPRAM- UP5K has single port RAM, might as well use it as SRAM to + # free up scarce block RAM. + spram_size = 128*1024 + self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) + self.register_mem("sram", self.mem_map["sram"], self.spram.bus, spram_size) + + # Control and Status + self.submodules.cas = cas.ControlAndStatus(platform, clk_freq) + + # SPI flash peripheral + self.submodules.spiflash = spi_flash.SpiFlashSingle( + platform.request("spiflash"), + dummy=platform.spiflash_read_dummy_bits, + div=platform.spiflash_clock_div) + 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) + + self.add_constant("ROM_DISABLE", 1) + self.add_memory_region( + "rom", kwargs["cpu_reset_address"], bios_size, + type="cached+linker") + self.flash_boot_address = kwargs["cpu_reset_address"]+bios_size + define_flash_constants(self) + + # 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") + + # Add USB pads + usb_pads = platform.request("usb") + usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) + self.submodules.usb = dummyusb.DummyUsb(usb_iobuf, debug=debug) + if debug: + self.add_wb_master(self.usb.debug_bridge.wishbone) + + # For the EVT board, ensure the pulldown pin is tristated as an input + if hasattr(usb_pads, "pulldown"): + pulldown = TSTriple() + self.specials += pulldown.get_tristate(usb_pads.pulldown) + self.comb += pulldown.oe.eq(0) + +SoC = BaseSoC