# Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
# under EU Grants 871528 and 957073, under the LGPLv3+ License
-
-from nmigen import *
+from nmigen import (Module, Elaboratable, DomainRenamer)
from nmigen.lib.cdc import ResetSynchronizer
from nmigen_soc import wishbone, memory
from nmigen_stdio.serial import AsyncSerial
from nmigen_boards.versa_ecp5 import VersaECP5Platform
from uartbridge import UARTBridge
-from crg import *
+from crg import ECPIX5CRG
+
class DDR3SoC(SoC, Elaboratable):
def __init__(self, *,
uart_pins, ddr_pins,
ddrphy_addr, dramcore_addr,
- ddr_addr):
- self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
+ ddr_addr,
+ firmware=None,
+ clk_freq=10e6):
+
+ # set up wishbone bus arbiter and decoder. arbiter routes,
+ # decoder maps local-relative addressed satellites to global addresses
+ self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32,
+ granularity=8,
features={"cti", "bte"})
- self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
+ self._decoder = wishbone.Decoder(addr_width=30, data_width=32,
+ granularity=8,
features={"cti", "bte"})
- freq = 100e6
+ # default firmware name
+ if firmware is None:
+ firmware = "firmware/main.bin"
+ # set up clock request generator, CPU, and interrupt interface
self.crg = ECPIX5CRG()
-
self.cpu = MinervaCPU(reset_address=0)
- self._arbiter.add(self.cpu.ibus)
- self._arbiter.add(self.cpu.dbus)
+ self._arbiter.add(self.cpu.ibus) # I-Cache Master
+ self._arbiter.add(self.cpu.dbus) # D-Cache Master. TODO JTAG master
self.intc = GenericInterruptController(width=len(self.cpu.ip))
+ # SRAM (but actually a ROM, for firmware), at address 0x0
self.rom = SRAMPeripheral(size=4096, writable=False)
- with open("firmware/main.bin", "rb") as f:
+ with open(, "rb") as f:
words = iter(lambda: f.read(self.cpu.data_width // 8), b'')
bios = [int.from_bytes(w, self.cpu.byteorder) for w in words]
self.rom.init = bios
- self._decoder.add(self.rom.bus, addr=0)
+ self._decoder.add(self.rom.bus, addr=0) # ROM is at 0x0000_0000
+ # SRAM (read-writeable BRAM)
self.ram = SRAMPeripheral(size=4096)
- self._decoder.add(self.ram.bus, addr=0x1000)
+ self._decoder.add(self.ram.bus, addr=0x8000000) # SRAM at 0x8000_000
+ # UART
self.uart_phy = AsyncSerial(data_bits=8,
- divisor=int(freq//115200),
+ divisor=int(clk_freq//115200),
pins=uart_pins)
self.uart = AsyncSerialPeripheral(core=self.uart_phy)
- self._decoder.add(self.uart.bus, addr=0x2000)
+ self._decoder.add(self.uart.bus, addr=0xc0002000) # 16550 UART address
-
+ # DRAM Module
self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins,
sys_clk_freq=100e6))
self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
- ddrmodule = MT41K256M16(freq, "1:2")
+ ddrmodule = MT41K256M16(clk_freq, "1:2") # match DDR3 ASIC P/N
- self.dramcore = DomainRenamer("dramsync")(gramCore(
- phy=self.ddrphy,
- geom_settings=ddrmodule.geom_settings,
- timing_settings=ddrmodule.timing_settings,
- clk_freq=freq))
+ drs = DomainRenamer("dramsync")
+ dramcore = gramCore(phy=self.ddrphy,
+ geom_settings=ddrmodule.geom_settings,
+ timing_settings=ddrmodule.timing_settings,
+ clk_freq=clk_freq)
+ self.dramcore = drs(dramcore)
self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
- self.drambone = DomainRenamer("dramsync")(gramWishbone(self.dramcore))
+ # map the DRAM onto Wishbone
+ self.drambone = drs(gramWishbone(self.dramcore))
self._decoder.add(self.drambone.bus, addr=ddr_addr)
self.memory_map = self._decoder.bus.memory_map
- self.clk_freq = freq
+ self.clk_freq = clk_freq
def elaborate(self, platform):
m = Module()
+ comb = m.d.comb
+ # add the peripherals and clock-reset-generator
m.submodules.sysclk = self.crg
-
+
m.submodules.rom = self.rom
m.submodules.ram = self.ram
m.submodules.uart = self.uart
m.submodules.dramcore = self.dramcore
m.submodules.drambone = self.drambone
- m.d.comb += [
- self._arbiter.bus.connect(self._decoder.bus),
- self.cpu.ip.eq(self.intc.ip),
- ]
+ # connect the arbiter (of wishbone masters)
+ # to the decoder (addressing wishbone slaves)
+ comb += self._arbiter.bus.connect(self._decoder.bus)
+
+ # wire up the CPU interrupts
+ comb += self.cpu.ip.eq(self.intc.ip)
return m
if __name__ == "__main__":
platform = VersaECP5Platform()
- ddr_pins = platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"},
- xdr={"clk":4, "a":4, "ba":4, "clk_en":4, "odt":4, "ras":4, "cas":4, "we":4})
+ ddr_pins = platform.request("ddr3", 0,
+ dir={"dq":"-", "dqs":"-"},
+ xdr={"clk":4, "a":4, "ba":4, "clk_en":4,
+ "odt":4, "ras":4, "cas":4, "we":4})
uart_pins = platform.request("uart", 0)
- soc = DDR3SoC(ddrphy_addr=0x00008000, dramcore_addr=0x00009000,
- ddr_addr=0x10000000, ddr_pins=ddr_pins, uart_pins=uart_pins)
+ soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base
+ dramcore_addr=0x40000000,
+ ddr_addr=0x10000000,
+ ddr_pins=ddr_pins,
+ uart_pins=uart_pins)
platform.build(soc, do_program=True)