From: Luke Kenneth Casson Leighton Date: Sun, 13 Feb 2022 14:13:51 +0000 (+0000) Subject: add MemoryMap to UART16550 (TODO, put that into UART16550 class) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9ba83df4c6fa64600337bfe8af9ad4c5fba5785c;p=ls2.git add MemoryMap to UART16550 (TODO, put that into UART16550 class) --- diff --git a/examples/ls2.py b/examples/ls2.py new file mode 100644 index 0000000..09d4043 --- /dev/null +++ b/examples/ls2.py @@ -0,0 +1,195 @@ +# Copyright (c) 2020 LambdaConcept +# Copyright (c) 2021 Luke Kenneth Casson Leighton +# +# Based on code from LambaConcept, from the gram example which is BSD-2-License +# https://github.com/jeanthom/gram/tree/master/examples +# +# 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 (Module, Elaboratable, DomainRenamer) +from nmigen.lib.cdc import ResetSynchronizer +from nmigen_soc import wishbone, memory +from nmigen_soc.memory import MemoryMap +from nmigen_stdio.serial import AsyncSerial + +from lambdasoc.cpu.minerva import MinervaCPU +from lambdasoc.periph.intc import GenericInterruptController +from lambdasoc.periph.sram import SRAMPeripheral +from lambdasoc.periph.timer import TimerPeripheral +from lambdasoc.periph import Peripheral +from lambdasoc.soc.base import SoC +from soc.bus.uart_16550 import UART16550 # opencores 16550 uart + +from gram.core import gramCore +from gram.phy.ecp5ddrphy import ECP5DDRPHY +from gram.modules import MT41K256M16 +from gram.frontend.wishbone import gramWishbone + +from nmigen_boards.versa_ecp5 import VersaECP5Platform +from nmigen_boards.ulx3s import ULX3S_85F_Platform +from nmigen_boards.arty_a7 import ArtyA7_100Platform +from nmigen_boards.test.blinky import Blinky + +from crg import ECPIX5CRG + +import sys +import os + + +class DDR3SoC(SoC, Elaboratable): + def __init__(self, *, + uart_pins, ddr_pins, + ddrphy_addr, dramcore_addr, + ddr_addr, fw_addr=0x0000_0000, + firmware=None, + clk_freq=40e6): + + # 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, + features={"cti", "bte"}) + + # default firmware name + if firmware is None: + firmware = "firmware/main.bin" + + # set up clock request generator + self.crg = ECPIX5CRG() + + # set up CPU, and interrupt interface + if False: + self.cpu = MinervaCPU(reset_address=0) + 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 + if fw_addr is not None: + self.rom = SRAMPeripheral(size=4096, writable=False) + with open(firmware, "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=fw_addr) # ROM at fw_addr + + # SRAM (read-writeable BRAM) + self.ram = SRAMPeripheral(size=4096) + self._decoder.add(self.ram.bus, addr=0x8000000) # SRAM at 0x8000_000 + + # UART + opencores_16550 = "../../uart16550/rtl/verilog" + pth = os.path.split(__file__)[0] + pth = os.path.join(pth, opencores_16550) + fname = os.path.abspath(pth) + print (fname) + self.uart = UART16550(verilog_src_dir=fname) + umap = MemoryMap(addr_width=7, data_width=8, name="uart_map") + #umap.add_resource(self._mem, name="mem", size=1<<5) + self.uart.bus.memory_map = umap + + 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(clk_freq, "1:2") # match DDR3 ASIC P/N + + 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) + + # 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 = clk_freq + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + + # add the peripherals and clock-reset-generator + m.submodules.sysclk = self.crg + + if hasattr(self, "rom"): + m.submodules.rom = self.rom + m.submodules.ram = self.ram + m.submodules.uart = self.uart + if False: + m.submodules.intc = self.intc + m.submodules.cpu = self.cpu + m.submodules.arbiter = self._arbiter + m.submodules.decoder = self._decoder + m.submodules.ddrphy = self.ddrphy + m.submodules.dramcore = self.dramcore + m.submodules.drambone = self.drambone + + # add blinky lights so we know FPGA is alive + m.submodules.blinky = Blinky() + + # connect the arbiter (of wishbone masters) + # to the decoder (addressing wishbone slaves) + comb += self._arbiter.bus.connect(self._decoder.bus) + + if False: + # wire up the CPU interrupts + comb += self.cpu.ip.eq(self.intc.ip) + + return m + + +if __name__ == "__main__": + + # create a platform selected from the toolchain. defaults to VERSA_ECP5 + # only VERSA_ECP5 will work for now because of the DDR3 module + fpga = "versa_ecp5" + if len(sys.argv) >= 2: + fpga = sys.argv[1] + platform_kls = {'versa_ecp5': VersaECP5Platform, + 'ulx3s': ULX3S_85F_Platform, + 'arty_a7': ArtyA7_100Platform, + }[fpga] + toolchain = {'arty_a7': "yosys_nextpnr", + 'versa_ecp5': 'Trellis', + 'ulx3s': 'Trellis' + }.get(fpga, None) + platform = platform_kls(toolchain=toolchain) + + # select a firmware file + firmware = None + fw_addr = None + if len(sys.argv) >= 3: + firmware = sys.argv[2] + fw_addr = 0x0000_0000 + + # get DDR and UART resource pins + 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) + + # set up the SOC + soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base + dramcore_addr=0x80000000, + ddr_addr=0x10000000, + fw_addr=fw_addr, + ddr_pins=ddr_pins, + uart_pins=uart_pins, + firmware=firmware) + + # build and upload it + platform.build(soc, do_program=True) diff --git a/examples/soc.py b/examples/soc.py deleted file mode 100644 index 54ffdd3..0000000 --- a/examples/soc.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright (c) 2020 LambdaConcept -# Copyright (c) 2021 Luke Kenneth Casson Leighton -# -# Based on code from LambaConcept, from the gram example which is BSD-2-License -# https://github.com/jeanthom/gram/tree/master/examples -# -# Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER -# under EU Grants 871528 and 957073, under the LGPLv3+ License - -from soc.bus.uart_16550 import UART16550 # opencores 16550 uart -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 lambdasoc.cpu.minerva import MinervaCPU -from lambdasoc.periph.intc import GenericInterruptController -from lambdasoc.periph.sram import SRAMPeripheral -from lambdasoc.periph.timer import TimerPeripheral -from lambdasoc.periph import Peripheral -from lambdasoc.soc.base import SoC - -from gram.core import gramCore -from gram.phy.ecp5ddrphy import ECP5DDRPHY -from gram.modules import MT41K256M16 -from gram.frontend.wishbone import gramWishbone - -from nmigen_boards.versa_ecp5 import VersaECP5Platform -from nmigen_boards.ulx3s import ULX3S_85F_Platform -from nmigen_boards.arty_a7 import ArtyA7_100Platform -from nmigen_boards.test.blinky import Blinky - -from crg import ECPIX5CRG - -import sys -import os - - -class DDR3SoC(SoC, Elaboratable): - def __init__(self, *, - uart_pins, ddr_pins, - ddrphy_addr, dramcore_addr, - ddr_addr, fw_addr=0x0000_0000, - firmware=None, - clk_freq=40e6): - - # 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, - features={"cti", "bte"}) - - # default firmware name - if firmware is None: - firmware = "firmware/main.bin" - - # set up clock request generator - self.crg = ECPIX5CRG() - - if False: - # set up CPU, and interrupt interface - self.cpu = MinervaCPU(reset_address=0) - 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 - if fw_addr is not None: - self.rom = SRAMPeripheral(size=4096, writable=False) - with open(firmware, "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=fw_addr) # ROM at fw_addr - - # SRAM (read-writeable BRAM) - self.ram = SRAMPeripheral(size=4096) - self._decoder.add(self.ram.bus, addr=0x8000000) # SRAM at 0x8000_000 - - # UART - opencores_16550 = "../../uart16550/rtl/verilog" - pth = __file__ - print (pth) - self.uart = UART16550(verilog_src_dir=opencores_16550) - 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(clk_freq, "1:2") # match DDR3 ASIC P/N - - 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) - - # 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 = clk_freq - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - - # add the peripherals and clock-reset-generator - m.submodules.sysclk = self.crg - - if hasattr(self, "rom"): - m.submodules.rom = self.rom - m.submodules.ram = self.ram - m.submodules.uart = self.uart - if False: - m.submodules.intc = self.intc - m.submodules.cpu = self.cpu - m.submodules.arbiter = self._arbiter - m.submodules.decoder = self._decoder - m.submodules.ddrphy = self.ddrphy - m.submodules.dramcore = self.dramcore - m.submodules.drambone = self.drambone - - # add blinky lights so we know FPGA is alive - m.submodules.blinky = Blinky() - - # connect the arbiter (of wishbone masters) - # to the decoder (addressing wishbone slaves) - comb += self._arbiter.bus.connect(self._decoder.bus) - - if False: - # wire up the CPU interrupts - comb += self.cpu.ip.eq(self.intc.ip) - - return m - - -if __name__ == "__main__": - - # create a platform selected from the toolchain. defaults to VERSA_ECP5 - # only VERSA_ECP5 will work for now because of the DDR3 module - fpga = "versa_ecp5" - if len(sys.argv) >= 2: - fpga = sys.argv[1] - platform_kls = {'versa_ecp5': VersaECP5Platform, - 'ulx3s': ULX3S_85F_Platform, - 'arty_a7': ArtyA7_100Platform, - }[fpga] - toolchain = {'arty_a7': "yosys_nextpnr", - 'versa_ecp5': 'Trellis', - 'ulx3s': 'Trellis' - }.get(fpga, None) - platform = platform_kls(toolchain=toolchain) - - # select a firmware file - firmware = None - fw_addr = None - if len(sys.argv) >= 3: - firmware = sys.argv[2] - fw_addr = 0x0000_0000 - - # get DDR and UART resource pins - 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) - - # set up the SOC - soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base - dramcore_addr=0x80000000, - ddr_addr=0x10000000, - fw_addr=fw_addr, - ddr_pins=ddr_pins, - uart_pins=uart_pins, - firmware=firmware) - - # build and upload it - platform.build(soc, do_program=True)