diff --git a/.gitmodules b/.gitmodules index a142058..53d8113 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,24 +1,24 @@ -[submodule "deps/migen"] - path = deps/migen +[submodule "litex/deps/migen"] + path = litex/deps/migen url = https://github.com/m-labs/migen.git -[submodule "deps/litex"] - path = deps/litex +[submodule "litex/deps/litex"] + path = litex/deps/litex url = https://github.com/enjoy-digital/litex.git -[submodule "deps/litex_boards"] - path = deps/litex_boards +[submodule "litex/deps/litex_boards"] + path = litex/deps/litex_boards url = https://github.com/litex-hub/litex-boards.git -[submodule "deps/litescope"] - path = deps/litescope +[submodule "litex/deps/litescope"] + path = litex/deps/litescope url = https://github.com/enjoy-digital/litescope.git -[submodule "deps/pyserial"] - path = deps/pyserial +[submodule "litex/deps/pyserial"] + path = litex/deps/pyserial url = https://github.com/pyserial/pyserial.git -[submodule "deps/lxsocsupport"] - path = deps/lxsocsupport +[submodule "litex/deps/lxsocsupport"] + path = litex/deps/lxsocsupport url = https://github.com/xobs/lxsocsupport.git -[submodule "deps/valentyusb"] - path = deps/valentyusb +[submodule "litex/deps/valentyusb"] + path = litex/deps/valentyusb url = https://github.com/im-tomu/valentyusb.git -[submodule "deps/litedram"] - path = deps/litedram +[submodule "litex/deps/litedram"] + path = litex/deps/litedram url = https://github.com/enjoy-digital/litedram.git diff --git a/bin/litex_read_verilog b/litex/bin/litex_read_verilog similarity index 100% rename from bin/litex_read_verilog rename to litex/bin/litex_read_verilog diff --git a/bin/litex_server b/litex/bin/litex_server similarity index 100% rename from bin/litex_server rename to litex/bin/litex_server diff --git a/bin/litex_sim b/litex/bin/litex_sim similarity index 100% rename from bin/litex_sim rename to litex/bin/litex_sim diff --git a/bin/litex_simple b/litex/bin/litex_simple similarity index 100% rename from bin/litex_simple rename to litex/bin/litex_simple diff --git a/bin/litex_term b/litex/bin/litex_term similarity index 100% rename from bin/litex_term rename to litex/bin/litex_term diff --git a/bin/mkmscimg b/litex/bin/mkmscimg similarity index 100% rename from bin/mkmscimg rename to litex/bin/mkmscimg diff --git a/deps/litedram b/litex/deps/litedram similarity index 100% rename from deps/litedram rename to litex/deps/litedram diff --git a/deps/litescope b/litex/deps/litescope similarity index 100% rename from deps/litescope rename to litex/deps/litescope diff --git a/deps/litex b/litex/deps/litex similarity index 100% rename from deps/litex rename to litex/deps/litex diff --git a/deps/litex_boards b/litex/deps/litex_boards similarity index 100% rename from deps/litex_boards rename to litex/deps/litex_boards diff --git a/deps/lxsocsupport b/litex/deps/lxsocsupport similarity index 100% rename from deps/lxsocsupport rename to litex/deps/lxsocsupport diff --git a/deps/migen b/litex/deps/migen similarity index 100% rename from deps/migen rename to litex/deps/migen diff --git a/deps/pyserial b/litex/deps/pyserial similarity index 100% rename from deps/pyserial rename to litex/deps/pyserial diff --git a/deps/valentyusb b/litex/deps/valentyusb similarity index 100% rename from deps/valentyusb rename to litex/deps/valentyusb diff --git a/lxbuildenv.py b/litex/lxbuildenv.py similarity index 100% rename from lxbuildenv.py rename to litex/lxbuildenv.py diff --git a/rtl/2-stage-1024-cache.v b/litex/rtl/2-stage-1024-cache.v similarity index 100% rename from rtl/2-stage-1024-cache.v rename to litex/rtl/2-stage-1024-cache.v diff --git a/rtl/spimemio.v b/litex/rtl/spimemio.v similarity index 100% rename from rtl/spimemio.v rename to litex/rtl/spimemio.v diff --git a/litex/workshop.py b/litex/workshop.py new file mode 100644 index 0000000..5a9730f --- /dev/null +++ b/litex/workshop.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "icestorm"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +from litex_boards.partner.platforms.fomu_evt import Platform +from litex_boards.partner.targets.fomu import _CRG + +from litex.soc.integration import SoCCore +from litex.soc.integration.builder import Builder + +from lxsocsupport import up5kspram + +from valentyusb.usbcore import io as usbio +from valentyusb.usbcore.cpu import dummyusb + +import argparse + + +class BaseSoC(SoCCore): + 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, + } + + def __init__(self, platform, output_dir="build", placer=None, pnr_seed=0, use_pll=True, **kwargs): + clk_freq = int(12e6) + self.submodules.crg = _CRG(platform, use_pll=use_pll) + SoCCore.__init__(self, platform, clk_freq, + cpu_type=None, + cpu_variant=None, + integrated_sram_size=0, + with_uart=False, + with_ctrl=False, + **kwargs) + + # UP5K has single port RAM, which is a dedicated 128 kilobyte block. + # Use this as CPU RAM. + spram_size = 128*1024 + self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) + self.register_mem("sram", 0x10000000, self.spram.bus, spram_size) + + # Add USB pads. We use DummyUsb, which simply enumerates as a USB + # device. Then all interaction is done via the wishbone bridge. + 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=True) + self.add_wb_master(self.usb.debug_bridge.wishbone) + + # Add "-relut -dffe_min_ce_use 4" to the synth_ice40 command. + # "-reult" adds an additional LUT pass to pack more stuff in, and + # "-dffe_min_ce_use 4" flag prevents Yosys from generating a + # Clock Enable signal for a LUT that has fewer than 4 flip-flops. + # This increases density, and lets us use the FPGA more efficiently. + platform.toolchain.nextpnr_yosys_template[2] += " -relut -dffe_min_ce_use 4" + + # Allow us to set the nextpnr seed, because some values don't meet timing. + platform.toolchain.nextpnr_build_template[1] += " --seed " + str(pnr_seed) + + # Different placers can improve packing efficiency, however not all placers + # are enabled on all builds of nextpnr-ice40. Let the user override which + # placer they want to use. + if placer is not None: + platform.toolchain.nextpnr_build_template[1] += " --placer {}".format(placer) + +def main(): + parser = argparse.ArgumentParser( + description="Build Fomu Main Gateware") + parser.add_argument( + "--seed", default=0, help="seed to use in nextpnr" + ) + parser.add_argument( + "--placer", choices=["sa", "heap"], help="which placer to use in nextpnr" + ) + parser.add_argument( + "--no-pll", help="disable pll -- this is easier to route, but may not work", action="store_true" + ) + args = parser.parse_args() + + platform = Platform() + soc = BaseSoC(platform, pnr_seed=args.seed, placer=args.placer, use_pll=not args.no_pll) + builder = Builder(soc, + output_dir="build", csr_csv="test/csr.csv", + compile_software=False) + vns = builder.build() + soc.do_exit(vns) + +if __name__ == "__main__": + main() diff --git a/workshop.py b/workshop.py deleted file mode 100644 index e6b6896..0000000 --- a/workshop.py +++ /dev/null @@ -1,366 +0,0 @@ -#!/usr/bin/env python3 -# This variable defines all the external programs that this module -# relies on. lxbuildenv reads this variable in order to ensure -# the build will finish without exiting due to missing third-party -# programs. -LX_DEPENDENCIES = ["riscv", "icestorm"] - -# Import lxbuildenv to integrate the deps/ directory -import lxbuildenv - # "python.autoComplete.extraPaths": [ - # "deps/litescope", - # "deps/litex", - # "deps/litex_boards", - # "deps/lxsocsupport", - # "deps/migen", - # "deps/valentyusb" - # ] - -# Disable pylint's E1101, which breaks completely on migen -#pylint:disable=E1101 - -from migen import Module, Signal, Instance, ClockDomain, If -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.fhdl.specials import TSTriple -from migen.fhdl.bitcontainer import bits_for -from migen.fhdl.structure import ClockSignal, ResetSignal, Replicate, Cat - -from litex_boards.partner.platforms.fomu_pvt import Platform - -from litex.soc.integration import SoCCore -from litex.soc.integration.builder import Builder -from litex.soc.integration.soc_core import csr_map_update -from litex.soc.interconnect import wishbone -from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage - -from lxsocsupport import up5kspram - -from valentyusb import usbcore -from valentyusb.usbcore import io as usbio -from valentyusb.usbcore.cpu import dummyusb - -import argparse - -class _CRG(Module): - def __init__(self, platform, use_pll): - clk48_raw = platform.request("clk48") - clk12_raw = Signal() - clk48 = Signal() - clk12 = Signal() - - reset_delay = Signal(13, 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, 1e9/48e6) - platform.add_period_constraint(clk48_raw, 1e9/48e6) - platform.add_period_constraint(clk12_raw, 1e9/12e6) - - # 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), - ] - - if use_pll: - - # Divide clk48 down to clk12, to ensure they're synchronized. - # By doing this, we avoid needing clock-domain crossing. - clk12_counter = Signal(2) - - self.clock_domains.cd_usb_48_raw = ClockDomain() - - platform.add_period_constraint(self.cd_usb_48_raw.clk, 1e9/48e6) - - # 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_raw.clk.eq(clk48_raw) - self.comb += self.cd_usb_48.clk.eq(clk48) - - self.sync.usb_48_raw += clk12_counter.eq(clk12_counter + 1) - - self.comb += clk12_raw.eq(clk12_counter[1]) - self.specials += Instance( - "SB_GB", - i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw, - o_GLOBAL_BUFFER_OUTPUT=clk12, - ) - - self.specials += Instance( - "SB_PLL40_CORE", - # Parameters - p_DIVR = 0, - p_DIVF = 3, - p_DIVQ = 2, - p_FILTER_RANGE = 1, - p_FEEDBACK_PATH = "PHASE_AND_DELAY", - 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 = "SHIFTREG_0deg", - p_ENABLE_ICEGATE = 0, - # IO - i_REFERENCECLK = clk12, - o_PLLOUTGLOBAL = clk48, - i_BYPASS = 0, - i_RESETB = 1, - ) - else: - self.specials += Instance( - "SB_GB", - i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk48_raw, - o_GLOBAL_BUFFER_OUTPUT=clk48, - ) - self.comb += self.cd_usb_48.clk.eq(clk48) - - clk12_counter = Signal(2) - self.sync.usb_48 += clk12_counter.eq(clk12_counter + 1) - - self.comb += clk12_raw.eq(clk12_counter[1]) - self.specials += Instance( - "SB_GB", - i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw, - o_GLOBAL_BUFFER_OUTPUT=clk12, - ) - - 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 PicoRVSpi(Module, AutoCSR): - def __init__(self, platform, pads, size=2*1024*1024): - self.size = size - - self.bus = bus = wishbone.Interface() - - self.reset = Signal() - - self.cfg1 = CSRStorage(size=8) - self.cfg2 = CSRStorage(size=8) - self.cfg3 = CSRStorage(size=8) - self.cfg4 = CSRStorage(size=8, reset=0x80) - - self.stat1 = CSRStatus(size=8) - self.stat2 = CSRStatus(size=8) - self.stat3 = CSRStatus(size=8) - self.stat4 = CSRStatus(size=8) - - cfg = Signal(32) - cfg_we = Signal(4) - cfg_out = Signal(32) - self.comb += [ - cfg.eq(Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage, self.cfg4.storage)), - cfg_we.eq(Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)), - self.stat1.status.eq(cfg_out[0:8]), - self.stat2.status.eq(cfg_out[8:16]), - self.stat3.status.eq(cfg_out[16:24]), - self.stat4.status.eq(cfg_out[24:32]), - ] - - mosi_pad = TSTriple() - miso_pad = TSTriple() - cs_n_pad = TSTriple() - clk_pad = TSTriple() - wp_pad = TSTriple() - hold_pad = TSTriple() - self.specials += mosi_pad.get_tristate(pads.mosi) - self.specials += miso_pad.get_tristate(pads.miso) - self.specials += cs_n_pad.get_tristate(pads.cs_n) - self.specials += clk_pad.get_tristate(pads.clk) - self.specials += wp_pad.get_tristate(pads.wp) - self.specials += hold_pad.get_tristate(pads.hold) - - reset = Signal() - self.comb += [ - reset.eq(ResetSignal() | self.reset), - cs_n_pad.oe.eq(~reset), - clk_pad.oe.eq(~reset), - ] - - flash_addr = Signal(24) - mem_bits = bits_for(size) - self.comb += flash_addr.eq(bus.adr[0:mem_bits-2] << 2), - - read_active = Signal() - spi_ready = Signal() - self.sync += [ - If(bus.stb & bus.cyc & ~read_active, - read_active.eq(1), - bus.ack.eq(0), - ) - .Elif(read_active & spi_ready, - read_active.eq(0), - bus.ack.eq(1), - ) - .Else( - bus.ack.eq(0), - read_active.eq(0), - ) - ] - - o_rdata = Signal(32) - self.comb += bus.dat_r.eq(o_rdata) - - self.specials += Instance("spimemio", - o_flash_io0_oe = mosi_pad.oe, - o_flash_io1_oe = miso_pad.oe, - o_flash_io2_oe = wp_pad.oe, - o_flash_io3_oe = hold_pad.oe, - - o_flash_io0_do = mosi_pad.o, - o_flash_io1_do = miso_pad.o, - o_flash_io2_do = wp_pad.o, - o_flash_io3_do = hold_pad.o, - o_flash_csb = cs_n_pad.o, - o_flash_clk = clk_pad.o, - - i_flash_io0_di = mosi_pad.i, - i_flash_io1_di = miso_pad.i, - i_flash_io2_di = wp_pad.i, - i_flash_io3_di = hold_pad.i, - - i_resetn = ~reset, - i_clk = ClockSignal(), - - i_valid = bus.stb & bus.cyc, - o_ready = spi_ready, - i_addr = flash_addr, - o_rdata = o_rdata, - - i_cfgreg_we = cfg_we, - i_cfgreg_di = cfg, - o_cfgreg_do = cfg_out, - ) - platform.add_source("rtl/spimemio.v") - -class BaseSoC(SoCCore): - csr_peripherals = [ - "ddrphy", -# "dna", - "xadc", - "cpu_or_bridge", - ] - 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 = { - "spiflash": 0x20000000, # (default shadow @0xa0000000) - } - mem_map.update(SoCCore.mem_map) - - def __init__(self, platform, output_dir="build", placer=None, pnr_seed=0, use_pll=True, **kwargs): - clk_freq = int(12e6) - self.output_dir = output_dir - self.submodules.crg = _CRG(platform, use_pll=use_pll) - SoCCore.__init__(self, platform, clk_freq, - cpu_type=None, cpu_variant=None, - integrated_sram_size=0, with_uart=False, - **kwargs) - - # 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", 0x10000000, self.spram.bus, spram_size) - - # Add a simple bit-banged SPI Flash module based on PicoRVSpi - spi_pads = platform.request("spiflash") - self.submodules.picorvspi = PicoRVSpi(platform, spi_pads) - self.register_mem("spiflash", self.mem_map["spiflash"], - self.picorvspi.bus, size=self.picorvspi.size) - - 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=True) - self.add_wb_master(self.usb.debug_bridge.wishbone) - - if hasattr(self, "cpu"): - self.cpu.use_external_variant("rtl/2-stage-1024-cache.v") - self.copy_memory_file("2-stage-1024-cache.v_toplevel_RegFilePlugin_regFile.bin") - bios_size = 0x8000 - kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size - self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) - self.add_constant("ROM_DISABLE", 1) - self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size - 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) - - # Add "-relut -dffe_min_ce_use 4" to the synth_ice40 command. - # The "-reult" adds an additional LUT pass to pack more stuff in, - # and the "-dffe_min_ce_use 4" flag prevents Yosys from generating a - # Clock Enable signal for a LUT that has fewer than 4 flip-flops. - # This increases density, and lets us use the FPGA more efficiently. - platform.toolchain.nextpnr_yosys_template[2] += " -relut -dffe_min_ce_use 5" - - # Allow us to set the nextpnr seed - platform.toolchain.nextpnr_build_template[1] += " --seed " + str(pnr_seed) - - if placer is not None: - platform.toolchain.nextpnr_build_template[1] += " --placer {}".format(placer) - - def copy_memory_file(self, src): - import os - from shutil import copyfile - if not os.path.exists(self.output_dir): - os.mkdir(self.output_dir) - if not os.path.exists(os.path.join(self.output_dir, "gateware")): - os.mkdir(os.path.join(self.output_dir, "gateware")) - copyfile(os.path.join("rtl", src), os.path.join(self.output_dir, "gateware", src)) - -def main(): - parser = argparse.ArgumentParser( - description="Build Fomu Main Gateware") - parser.add_argument( - "--seed", default=0, help="seed to use in nextpnr" - ) - parser.add_argument( - "--placer", choices=["sa", "heap"], help="which placer to use in nextpnr" - ) - args = parser.parse_args() - - platform = Platform() - soc = BaseSoC(platform, pnr_seed=args.seed, placer=args.placer) - builder = Builder(soc, - output_dir="build", csr_csv="test/csr.csv", - compile_software=False) - vns = builder.build() - soc.do_exit(vns) - -if __name__ == "__main__": - main()