# under EU Grants 871528 and 957073, under the LGPLv3+ License
from nmigen import (Module, Elaboratable, DomainRenamer, Record,
- Signal, Cat, Const, ClockSignal, ResetSignal)
+ Signal, Cat, Const, ClockSignal, ResetSignal,
+ )
from nmigen.build.dsl import Attrs
from nmigen.cli import verilog
from nmigen.lib.cdc import ResetSynchronizer
from nmigen_soc import wishbone, memory
from nmigen_soc.memory import MemoryMap
from nmigen.utils import log2_int
-
+from nmigen_boards.resources.interface import UARTResource
from nmigen_stdio.serial import AsyncSerial
# HyperRAM
from nmigen_boards.ulx3s import ULX3S_85F_Platform
from nmigen_boards.arty_a7 import ArtyA7_100Platform
from nmigen_boards.test.blinky import Blinky
+from nmigen_boards.orangecrab_r0_2 import OrangeCrabR0_2_85k_Platform
from icarusversa import IcarusVersaPlatform
# Clock-Reset Generator (works for all ECP5 platforms)
from ecp5_crg import ECP5CRG
# set up clock request generator
pod_bits = 25
+ sync_bits = 26
+ need_bridge=False
if fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim', 'ulx3s',
- 'orangecrab']:
- if fpga in ['isim']:
- pod_bits = 6
+ 'orangecrab','orangecrab_isim', 'rcs_arctic_tern_bmc_card']:
+ if fpga in ['isim','orangecrab_isim']:
+ pod_bits = 5
+ sync_bits = 6
+ if fpga in ['orangecrab', 'orangecrab_sim',
+ 'rcs_arctic_tern_bmc_card']:
+ need_bridge=True
self.crg = ECP5CRG(clk_freq, dram_clk_freq=dram_clk_freq,
- pod_bits=pod_bits)
+ pod_bits=pod_bits, sync_bits=sync_bits,
+ need_bridge=need_bridge)
if fpga in ['arty_a7']:
self.crg = ArtyA7CRG(clk_freq)
if self.dram_clk_freq is None:
self.dram_clk_freq = clk_freq
- # set up CPU, with 64-to-32-bit downconverters
+ # set up CPU, with 64-to-32-bit downconverters, and a delayed Reset
if add_cpu:
self.cpu = ExternalCore(name="ext_core")
+
cvtdbus = wishbone.Interface(addr_width=30, data_width=32,
granularity=8, features={'stall'})
cvtibus = wishbone.Interface(addr_width=30, data_width=32,
slave_clock_domain="dramsync",
address_width=self.ddrphy.bus.addr_width,
data_width=self.ddrphy.bus.data_width,
- granularity=self.ddrphy.bus.granularity,
- master_features={'stall'})
+ granularity=self.ddrphy.bus.granularity)
self.ddrphy_async_br = pabr
# Set up Wishbone asynchronous bridge
slave_clock_domain="dramsync",
address_width=self.dramcore.bus.addr_width,
data_width=self.dramcore.bus.data_width,
- granularity=self.dramcore.bus.granularity,
- master_features={'stall'})
+ granularity=self.dramcore.bus.granularity)
self.dramcore_async_br = dac
# Set up Wishbone asynchronous bridge
slave_clock_domain="dramsync",
address_width=self.drambone.bus.addr_width,
data_width=self.drambone.bus.data_width,
- granularity=self.drambone.bus.granularity,
- master_features={'stall'})
+ granularity=self.drambone.bus.granularity)
self.drambone_async_br = bab
if ddr_pins is not None:
# additional SRAM at address if DRAM is not also at 0x0
# (TODO, check Flash, and HyperRAM as well)
- if (ddr_pins is None or ddr_addr != 0x0) and fw_addr != 0:
+ if ((ddr_pins is None or ddr_addr != 0x0) and fw_addr != 0 and
+ hyperram_addr[0] != 0x0):
print ("SRAM 0x8000 at address 0x0")
sram_width = 32
self.sram = SRAMPeripheral(size=0x8000,
if spi_0_pins is not None and fpga in ['sim',
'isim',
'rcs_arctic_tern_bmc_card',
+ 'orangecrab',
+ 'orangecrab_isim',
'versa_ecp5',
'versa_ecp5_85',
'arty_a7']:
if fpga in ['versa_ecp5',
'versa_ecp5_85',
'rcs_arctic_tern_bmc_card',
+ 'orangecrab',
+ 'orangecrab_isim',
'isim']:
spi0_is_lattice_ecp5_clk = True
# Ethernet MAC
if ethmac_0_pins is not None and fpga in ['versa_ecp5',
'versa_ecp5_85',
- 'isim']:
+ 'isim']: # not orangecrab
self.eth_irq = IRQLine()
# The OpenCores Ethernet MAC contains two independent Wishbone
# interfaces, a slave (configuration) interface and a master (DMA)
# HyperRAM modules *plural*. Assumes using a Quad PMOD by Piotr
# Esden, sold by 1bitsquared, only doing one CS_N enable at the
# moment
- if hyperram_pins is not None:
- self.hyperram = HyperRAM(io=hyperram_pins, phy_kls=HyperRAMPHY,
- features={'stall'},
- latency=7) # Winbond W956D8MBYA
- self._decoder.add(self.hyperram.bus, addr=hyperram_addr)
+ self.hyperram = []
+ for i, (pins, hraddr) in enumerate(zip(hyperram_pins, hyperram_addr)):
+ hr = HyperRAM(io=pins, phy_kls=HyperRAMPHY,
+ name="hyperram%d" % i,
+ features={'stall'},
+ latency=7) # Winbond W956D8MBYA
+ self._decoder.add(hr.bus, addr=hraddr)
+ self.hyperram.append(hr)
self.memory_map = self._decoder.bus.memory_map
def elaborate(self, platform):
m = Module()
- comb = m.d.comb
+ comb, sync = m.d.comb, m.d.sync
# add the peripherals and clock-reset-generator
if platform is not None and hasattr(self, "crg"):
m.submodules.extcore = self.cpu
m.submodules.dbuscvt = self.dbusdowncvt
m.submodules.ibuscvt = self.ibusdowncvt
- # create stall sigs, assume wishbone classic
- #ibus, dbus = self.cvtibus, self.cvtdbus
- #comb += ibus.stall.eq(ibus.stb & ~ibus.ack)
- #comb += dbus.stall.eq(dbus.stb & ~dbus.ack)
m.submodules.arbiter = self._arbiter
m.submodules.decoder = self._decoder
self.drambone_async_br.add_verilog_source(fname, platform)
# add hyperram module
- if hasattr(self, "hyperram"):
- m.submodules.hyperram = hyperram = self.hyperram
+ for i, hr in enumerate(self.hyperram):
+ m.submodules["hyperram%d" % i] = hr
# grrr, same problem with hyperram: not WB4-pipe compliant
- comb += hyperram.bus.stall.eq(hyperram.bus.cyc & ~hyperram.bus.ack)
- # set 3 top CSn lines to zero for now
+ comb += hr.bus.stall.eq(hr.bus.cyc & ~hr.bus.ack)
+ # reset
if self.fpga == 'arty_a7':
- comb += hyperram.phy.rst_n.eq(ResetSignal())
+ comb += hr.phy.rst_n.eq(ResetSignal())
# add blinky lights so we know FPGA is alive
if platform is not None:
# and at the moment that's just UART tx/rx.
ports = []
ports += [self.uart.tx_o, self.uart.rx_i]
- if hasattr(self, "hyperram"):
- ports += list(self.hyperram.ports())
+ for hr in self.hyperram:
+ ports += list(hr.ports())
if hasattr(self, "ddrphy"):
if hasattr(self.ddrphy, "pads"): # real PHY
ports += list(self.ddrphy.pads.fields.values())
def build_platform(fpga, firmware):
- # create a platform selected from the toolchain.
+ # create a platform selected from the toolchain.
platform_kls = {'versa_ecp5': VersaECP5Platform,
'versa_ecp5_85': VersaECP5Platform85,
'ulx3s': ULX3S_85F_Platform,
+ 'orangecrab': OrangeCrabR0_2_85k_Platform,
'arty_a7': ArtyA7_100Platform,
'isim': IcarusVersaPlatform,
+ 'orangecrab_isim': IcarusVersaPlatform,
+ 'rcs_arctic_tern_bmc_card':None, #TODO
'sim': None,
}[fpga]
toolchain = {'arty_a7': "yosys_nextpnr",
'versa_ecp5': 'Trellis',
'versa_ecp5_85': 'Trellis',
+ 'orangecrab_isim': 'Trellis',
'isim': 'Trellis',
'ulx3s': 'Trellis',
+ 'rcs_arctic_tern_bmc_card': 'Trellis',
'sim': None,
}.get(fpga, None)
dram_cls = {'arty_a7': None,
'versa_ecp5': MT41K64M16,
'versa_ecp5_85': MT41K64M16,
+ 'orangecrab': MT41K64M16,
+ 'orangecrab_isim': MT41K64M16,
#'versa_ecp5': MT41K256M16,
'ulx3s': None,
+ 'rcs_arctic_tern_bmc_card': None, #TODO
'sim': MT41K256M16,
'isim': MT41K64M16,
}.get(fpga, None)
clk_freq = 100e6
dram_clk_freq = clk_freq
if fpga == 'isim':
- clk_freq = 55e6 # below 50 mhz, stops DRAM being enabled
+ clk_freq = 50e6 # below 50 mhz, stops DRAM being enabled
+ #dram_clk_freq = clk_freq
+ dram_clk_freq = 100e6
if fpga == 'versa_ecp5':
- clk_freq = 50e6 # crank right down to test hyperram
- #dram_clk_freq = 100e6
+ clk_freq = 50e6 # crank right down to timing threshold
+ #dram_clk_freq = 55e6
if fpga == 'versa_ecp5_85':
# 50MHz works. 100MHz works. 55MHz does NOT work.
# Stick with multiples of 50MHz...
clk_freq = 50e6
dram_clk_freq = 100e6
if fpga == 'arty_a7':
- clk_freq = 50e6
+ clk_freq = 27.0e6 # urrr "working" with the QSPI core (25 mhz does not)
if fpga == 'ulx3s':
clk_freq = 40.0e6
+ if fpga == 'orangecrab' or fpga=='orangecrab_isim':
+ clk_freq = 50e6
# merge dram_clk_freq with clk_freq if the same
if clk_freq == dram_clk_freq:
dram_clk_freq = None
+ # see if dram can be enabled
+ enable_dram = False
+ if dram_clk_freq is not None and dram_clk_freq >= 50e6:
+ enable_dram = True
+ if dram_clk_freq is None and clk_freq >= 50e6:
+ enable_dram = True
+
# select a firmware address
fw_addr = None
if firmware is not None:
# get UART resource pins
if platform is not None:
+ if fpga=="orangecrab":
+ # assumes an FT232 USB-UART soldered onto these two pins.
+ orangecrab_uart = UARTResource(0, rx="M18", tx="N17")
+ platform.add_resources([orangecrab_uart])
+
uart_pins = platform.request("uart", 0)
else:
uart_pins = Record([('tx', 1), ('rx', 1)], name="uart_0")
# get DDR resource pins, disable if clock frequency is below 50 mhz for now
ddr_pins = None
- if (clk_freq >= 50e6 and platform is not None and
- fpga in ['versa_ecp5', 'versa_ecp5_85', 'arty_a7', 'isim']):
+ if (enable_dram and platform is not None and
+ fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim',
+ 'orangecrab','orangecrab_isim']): # not yet 'arty_a7',
ddr_pins = platform.request("ddr3", 0,
dir={"dq":"-", "dqs":"-"},
xdr={"rst": 4, "clk":4, "a":4,
"ba":4, "clk_en":4,
"odt":4, "ras":4, "cas":4, "we":4,
"cs": 4})
+ print ("ddr pins", ddr_pins)
# Get SPI resource pins
spi_0_pins = None
platform.add_resources(spi_0_ios)
spi_0_pins = platform.request("spi_0", 0)
+ orangecrab_enable_spi = False
+ if orangecrab_enable_spi and platform is not None and \
+ fpga in ['orangecrab']:
+ # spi_flash_mosi <= spi_sdat_o(0) when spi_sdat_oe(0) = '1' else 'Z';
+ # spi_flash_miso <= spi_sdat_o(1) when spi_sdat_oe(1) = '1' else 'Z';
+ # spi_flash_wp_n <= spi_sdat_o(2) when spi_sdat_oe(2) = '1' else 'Z';
+ # spi_flash_hold_n <= spi_sdat_o(3) when spi_sdat_oe(3) = '1' else 'Z';
+ # cs_n="U17", clk="U16", miso="T18", mosi="U18", wp_n="R18", hold_n="N18"
+ # each pin needs a separate direction control
+ spi_0_ios = [
+ Resource("spi_0", 0,
+ Subsignal("dq0", Pins("U18", dir="io")), #mosi
+ Subsignal("dq1", Pins("T18", dir="io")), #miso
+ Subsignal("dq2", Pins("R18", dir="io")), #wp_n
+ Subsignal("dq3", Pins("N18", dir="io")), #hold_n
+ # We use USRMCLK instead for clk
+ # todo: read docs
+ Subsignal("cs_n", Pins("U17", dir="o")),
+ # Subsignal("clk", Pins("U16", dir="o")),
+ Attrs(PULLMODE="NONE", DRIVE="4", IO_TYPE="LVCMOS33"))
+ ]
+ platform.add_resources(spi_0_ios)
+ spi_0_pins = platform.request("spi_0", 0, dir={"cs_n":"o"},
+ xdr={"dq0":1, "dq1": 1,
+ "dq2":1, "dq3": 1,
+ "cs_n":0})
+
print ("spiflash pins", spi_0_pins)
# Get Ethernet RMII resource pins
print ("ethmac pins", ethmac_0_pins)
# Get HyperRAM pins
- hyperram_pins = None
+ hyperram_pins = []
+ hyperram_addr = [0xa000_0000]
if platform is None:
- hyperram_pins = HyperRAMPads()
+ hyperram_pins = [HyperRAMPads()]
elif fpga in ['isim']:
hyperram_ios = HyperRAMResource(0, cs_n="B13",
dq="E14 C10 B10 E12 D12 A9 D11 D14",
rwds="C14", rst_n="E13", ck_p="D13",
attrs=Attrs(IO_TYPE="LVCMOS33"))
platform.add_resources(hyperram_ios)
- hyperram_pins = platform.request("hyperram")
+ hyperram_pins = [platform.request("hyperram")]
print ("isim a7 hyperram", hyperram_ios)
# Digilent Arty A7-100t
elif platform is not None and fpga in ['arty_a7']:
- hyperram_ios = HyperRAMResource(0, cs_n="V12 V14 U12 U14",
+ hyperram_ios = HyperRAMResource(0, cs_n="B11 B18 G13 D13",
+ dq="E15 E16 D15 C15 J15 K15 J18 J17",
+ rwds="K16", rst_n="A18", ck_p="A11",
+ # ck_n="D12" - for later (DDR)
+ attrs=Attrs(IOSTANDARD="LVCMOS33"))
+ platform.add_resources(hyperram_ios)
+ hyperram_ios = HyperRAMResource(1, cs_n="V12 V14 U12 U14",
dq="D4 D3 F4 F3 G2 H2 D2 E2",
rwds="U13", rst_n="T13", ck_p="V10",
# ck_n="V11" - for later (DDR)
attrs=Attrs(IOSTANDARD="LVCMOS33"))
platform.add_resources(hyperram_ios)
- hyperram_pins = platform.request("hyperram")
+ hyperram_pins = [platform.request("hyperram", 0),
+ platform.request("hyperram", 1)]
print ("arty a7 hyperram", hyperram_ios)
+ hyperram_addr=[0x0000_0000, # HYPERRAM_BASE1
+ 0x0200_0000] # HYPERRAM_BASE2
# VERSA ECP5
elif False and platform is not None and fpga in \
['versa_ecp5', 'versa_ecp5_85']:
rwds="C14", rst_n="E13", ck_p="D13",
attrs=Attrs(IO_TYPE="LVCMOS33"))
platform.add_resources(hyperram_ios)
- hyperram_pins = platform.request("hyperram")
+ hyperram_pins = [platform.request("hyperram")]
print ("versa ecp5 hyperram", hyperram_ios)
print ("hyperram pins", hyperram_pins)
spi0_cfg_addr=0xc0006000, # SPI0_CTRL_BASE
eth0_cfg_addr=0xc000c000, # ETH0_CTRL_BASE (4k)
eth0_irqno=1, # ETH0_IRQ number (match microwatt)
- hyperram_addr=0xa0000000, # HYPERRAM_BASE
+ hyperram_addr=hyperram_addr, # determined above
fw_addr=fw_addr,
#fw_addr=None,
ddr_pins=ddr_pins,
if toolchain == 'Trellis':
# add -abc9 option to yosys synth_ecp5
- #os.environ['NMIGEN_synth_opts'] = '-abc9 -nowidelut'
- #os.environ['NMIGEN_synth_opts'] = '-abc9'
- os.environ['NMIGEN_synth_opts'] = '-nowidelut'
+ os.environ['NMIGEN_synth_opts'] = '-abc9' # speed
+ # os.environ['NMIGEN_synth_opts'] = '-nowidelut' # size
+
+ if toolchain == 'yosys_nextpnr':
+ # add --seed 2 to arty a7 compile-time options
+ freq = clk_freq/1e6
+ os.environ['NMIGEN_nextpnr_opts'] = '--seed 3 --freq %.1f' % freq
+ os.environ['NMIGEN_nextpnr_opts'] += ' --timing-allow-fail'
if platform is not None:
# build and upload it
- if fpga == 'isim':
+ if fpga == 'isim' or fpga == 'orangecrab_isim':
platform.build(soc, do_program=False,
do_build=True, build_dir="build_simsoc")
else: