Skip to content

Commit

Permalink
platforms: Add icebreaker platform with base target. Micropython boots.
Browse files Browse the repository at this point in the history
  • Loading branch information
cr1901 committed Nov 20, 2018
1 parent 0fa0a09 commit c8f6793
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Expand Up @@ -66,10 +66,12 @@ env:
# lm32 lite
- C=lm32.lite P=ice40_hx8k_b_evn T="base" F=stub
- C=lm32.lite P=ice40_up5k_b_evn T="base" F=stub
- C=lm32.lite P=icebreaker T="base" F=stub
- C=lm32.lite P=tinyfpga_bx T="base" F=stub
# lm32 minimal
- C=lm32.minimal P=ice40_hx8k_b_evn T="base" F=stub
- C=lm32.minimal P=ice40_up5k_b_evn T="base" F=stub
- C=lm32.minimal P=icebreaker T="base" F=stub
- C=lm32.minimal P=tinyfpga_bx T="base" F=stub
# or1k base targets
- C=or1k P=arty T="base net"
Expand Down
88 changes: 88 additions & 0 deletions platforms/icebreaker.py
@@ -0,0 +1,88 @@
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("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")),

("serial", 0,
Subsignal("rx", Pins("6")),
Subsignal("tx", Pins("9"), 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")),
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")),
Subsignal("dq", Pins("14 17 12 13"), IOStandard("LVCMOS33")),
),

("clk12", 0, Pins("35"), IOStandard("LVCMOS33"))
]

_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")
]

# 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"))
]


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()
66 changes: 66 additions & 0 deletions targets/icebreaker/Makefile.mk
@@ -0,0 +1,66 @@
# ice40_hx8k_b_evn targets

ifneq ($(PLATFORM),icebreaker)
$(error "Platform should be icebreaker 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 "icebreaker 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 "icebreaker 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
129 changes: 129 additions & 0 deletions targets/icebreaker/base.py
@@ -0,0 +1,129 @@
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 gateware import up5kspram
from gateware import cas
from gateware import spi_flash

from targets.utils import csr_map_update
from platforms import icebreaker


# Alternate serial port, using the second 6-pin PMOD port. Follows Digilent
# PMOD Specification Type 4, so e.g. PMOD USBUART can be used.
pmod_serial = [
("serial", 0,
Subsignal("rx", Pins("PMOD:6")),
Subsignal("tx", Pins("PMOD:5")),
Subsignal("rts", Pins("PMOD:4")),
Subsignal("cts", Pins("PMOD:7")),
IOStandard("LVCMOS33"),
),
]

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):
csr_peripherals = (
"spiflash",
"cas",
)
csr_map_update(SoCCore.csr_map, csr_peripherals)

mem_map = {
"spiflash": 0x20000000, # (default shadow @0xa0000000)
}
mem_map.update(SoCCore.mem_map)

def __init__(self, platform, **kwargs):
if 'integrated_rom_size' not in kwargs:
kwargs['integrated_rom_size']=0
if 'integrated_sram_size' not in kwargs:
kwargs['integrated_sram_size']=0

# 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.
platform.add_extension(icebreaker.break_off_pmod)
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)

# 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)
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)

bios_size = 0x8000
self.add_constant("ROM_DISABLE", 1)
self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size)
self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size

# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM.
self.submodules.spram = up5kspram.Up5kSPRAM(size=128*1024)
self.register_mem("sram", 0x10000000, 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)

# Disable final deep-sleep power down so firmware words are loaded
# onto softcore's address bus.
platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin"
platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"

SoC = BaseSoC

0 comments on commit c8f6793

Please sign in to comment.