From: Sebastien Bourdeauducq Date: Sun, 24 Nov 2013 09:30:02 +0000 (+0100) Subject: modularize SoC integration X-Git-Tag: 24jan2021_ls180~2782 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4a3a1d02e9b2b62072c18480800c14f76fdefc08;p=litex.git modularize SoC integration --- diff --git a/make.py b/make.py index fc8548ff..e051beae 100755 --- a/make.py +++ b/make.py @@ -4,14 +4,14 @@ import argparse, os, importlib, subprocess from mibuild.tools import write_to_file -from misoclib import cpuif +from misoclib.gensoc import cpuif from misoclib.s6ddrphy import initsequence import top, jtag def build(platform_name, build_bitstream, build_header, csr_csv_filename, *soc_args, **soc_kwargs): platform_module = importlib.import_module("mibuild.platforms."+platform_name) platform = platform_module.Platform() - soc = top.SoC(platform, platform_name, *soc_args, **soc_kwargs) + soc = top.SoC(platform, *soc_args, **soc_kwargs) platform.add_platform_command(""" INST "mxcrg/wr_bufpll" LOC = "BUFPLL_X0Y2"; diff --git a/misoclib/cpuif.py b/misoclib/cpuif.py deleted file mode 100644 index 0dcdfc16..00000000 --- a/misoclib/cpuif.py +++ /dev/null @@ -1,72 +0,0 @@ -from migen.bank.description import CSRStatus - -def _get_rw_functions(reg_name, reg_base, size, read_only): - r = "" - - r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n" - r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(size)+"\n" - - if size > 8: - raise NotImplementedError("Register too large") - elif size > 4: - ctype = "unsigned long long int" - elif size > 2: - ctype = "unsigned int" - elif size > 1: - ctype = "unsigned short int" - else: - ctype = "unsigned char" - - r += "static inline "+ctype+" "+reg_name+"_read(void) {\n" - if size > 1: - r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n" - for byte in range(1, size): - r += "\tr <<= 8;\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n" - r += "\treturn r;\n}\n" - else: - r += "\treturn MMPTR("+hex(reg_base)+");\n}\n" - - if not read_only: - r += "static inline void "+reg_name+"_write("+ctype+" value) {\n" - for byte in range(size): - shift = (size-byte-1)*8 - if shift: - value_shifted = "value >> "+str(shift) - else: - value_shifted = "value" - r += "\tMMPTR("+hex(reg_base+4*byte)+") = "+value_shifted+";\n" - r += "}\n" - return r - -def get_csr_header(csr_base, bank_array, interrupt_map): - r = "#ifndef __HW_CSR_H\n#define __HW_CSR_H\n#include \n" - for name, csrs, mapaddr, rmap in bank_array.banks: - r += "\n/* "+name+" */\n" - reg_base = csr_base + 0x800*mapaddr - r += "#define "+name.upper()+"_BASE "+hex(reg_base)+"\n" - for csr in csrs: - nr = (csr.size + 7)//8 - r += _get_rw_functions(name + "_" + csr.name, reg_base, nr, isinstance(csr, CSRStatus)) - reg_base += 4*nr - try: - interrupt_nr = interrupt_map[name] - except KeyError: - pass - else: - r += "#define "+name.upper()+"_INTERRUPT "+str(interrupt_nr)+"\n" - for name, memory, mapaddr, mmap in bank_array.srams: - mem_base = csr_base + 0x800*mapaddr - fullname = name + "_" + memory.name_override - r += "#define "+fullname.upper()+"_BASE "+hex(mem_base)+"\n" - r += "\n#endif\n" - return r - -def get_csr_csv(csr_base, bank_array): - r = "" - for name, csrs, mapaddr, rmap in bank_array.banks: - reg_base = csr_base + 0x800*mapaddr - for csr in csrs: - nr = (csr.size + 7)//8 - r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw") - reg_base += 4*nr - return r diff --git a/misoclib/gensoc/__init__.py b/misoclib/gensoc/__init__.py new file mode 100644 index 00000000..ee2efafa --- /dev/null +++ b/misoclib/gensoc/__init__.py @@ -0,0 +1,128 @@ +from operator import itemgetter +from collections import defaultdict +from math import ceil + +from migen.fhdl.std import * +from migen.bank import csrgen +from migen.bus import wishbone, csr, lasmibus, dfi +from migen.bus import wishbone2lasmi, wishbone2csr + +from misoclib import lm32, uart, dfii, lasmicon, identifier, timer, memtest + +class GenSoC(Module): + csr_base = 0xe0000000 + csr_map = { + "crg": 0, # user + "uart": 1, # provided + "identifier": 2, # provided + "timer0": 3, # provided + "buttons": 4, # user + "leds": 5, # user + } + interrupt_map = { + "uart": 0, + "timer0": 1, + } + known_platform_id = defaultdict(lambda: 0x554E, { + "mixxeo": 0x4D58, + "m1": 0x4D31 + }) + + def __init__(self, platform, clk_freq, sram_size, l2_size=0): + self.clk_freq = clk_freq + self.sram_size = sram_size + self.l2_size = l2_size + + # Wishbone + self.submodules.cpu = lm32.LM32() + self.submodules.sram = wishbone.SRAM(sram_size) + self.submodules.wishbone2csr = wishbone2csr.WB2CSR() + + # rom 0x00000000 (shadow @0x80000000) user + # SRAM/debug 0x10000000 (shadow @0x90000000) provided + # CSR bridge 0x60000000 (shadow @0xe0000000) provided + self._wb_masters = [self.cpu.ibus, self.cpu.dbus] + self._wb_slaves = [ + (lambda a: a[26:29] == 1, self.sram.bus), + (lambda a: a[27:29] == 3, self.wishbone2csr.wishbone) + ] + + # CSR + self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200) + self.submodules.identifier = identifier.Identifier(self.known_platform_id[platform.name], int(clk_freq), + log2_int(l2_size) if l2_size else 0) + self.submodules.timer0 = timer.Timer() + + def add_wb_master(self, wbm): + if self.finalized: + raise FinalizeError + self._wb_masters.append(wbm) + + def add_wb_slave(self, address_decoder, interface): + if self.finalized: + raise FinalizeError + self._wb_slaves.append((address_decoder, interface)) + + def do_finalize(self): + # Wishbone + self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters, + self._wb_slaves, register=True) + + # CSR + self.submodules.csrbankarray = csrgen.BankArray(self, + lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override]) + self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses()) + + # Interrupts + for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)): + if hasattr(self, k): + self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq) + + def ns(self, t, margin=True): + clk_period_ns = 1000000000/self.clk_freq + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) + +class SDRAMSoC(GenSoC): + csr_map = { + "dfii": 6, + "lasmicon": 7, + "memtest_w": 8, + "memtest_r": 9 + } + csr_map.update(GenSoC.csr_map) + + def __init__(self, platform, clk_freq, sram_size, l2_size, with_memtest): + GenSoC.__init__(self, platform, clk_freq, sram_size, l2_size) + self.with_memtest = with_memtest + self._sdram_modules_created = False + + def create_sdram_modules(self, phy_dfi, phy_settings, sdram_geom, sdram_timing): + if self._sdram_modules_created: + raise FinalizeError + self._sdram_modules_created = True + + # DFI + self.submodules.dfii = dfii.DFIInjector(sdram_geom.mux_a, sdram_geom.bank_a, + phy_settings.dfi_d, phy_settings.nphases) + self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, phy_dfi) + + # LASMI + self.submodules.lasmicon = lasmicon.LASMIcon(phy_settings, sdram_geom, sdram_timing) + self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave) + + self.submodules.lasmixbar = lasmibus.Crossbar([self.lasmicon.lasmic], self.lasmicon.nrowbits) + + if self.with_memtest: + self.submodules.memtest_w = memtest.MemtestWriter(self.lasmixbar.get_master()) + self.submodules.memtest_r = memtest.MemtestReader(self.lasmixbar.get_master()) + + # Wishbone bridge: map SDRAM at 0x40000000 (shadow @0xc0000000) + self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(self.l2_size//4, self.lasmixbar.get_master()) + self.add_wb_slave(lambda a: a[27:29] == 2, self.wishbone2lasmi.wishbone) + + def do_finalize(self): + if not self._sdram_modules_created: + raise FinalizeError("Need to call SDRAMSoC.create_sdram_modules()") + GenSoC.do_finalize(self) diff --git a/misoclib/gensoc/cpuif.py b/misoclib/gensoc/cpuif.py new file mode 100644 index 00000000..0dcdfc16 --- /dev/null +++ b/misoclib/gensoc/cpuif.py @@ -0,0 +1,72 @@ +from migen.bank.description import CSRStatus + +def _get_rw_functions(reg_name, reg_base, size, read_only): + r = "" + + r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n" + r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(size)+"\n" + + if size > 8: + raise NotImplementedError("Register too large") + elif size > 4: + ctype = "unsigned long long int" + elif size > 2: + ctype = "unsigned int" + elif size > 1: + ctype = "unsigned short int" + else: + ctype = "unsigned char" + + r += "static inline "+ctype+" "+reg_name+"_read(void) {\n" + if size > 1: + r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n" + for byte in range(1, size): + r += "\tr <<= 8;\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n" + r += "\treturn r;\n}\n" + else: + r += "\treturn MMPTR("+hex(reg_base)+");\n}\n" + + if not read_only: + r += "static inline void "+reg_name+"_write("+ctype+" value) {\n" + for byte in range(size): + shift = (size-byte-1)*8 + if shift: + value_shifted = "value >> "+str(shift) + else: + value_shifted = "value" + r += "\tMMPTR("+hex(reg_base+4*byte)+") = "+value_shifted+";\n" + r += "}\n" + return r + +def get_csr_header(csr_base, bank_array, interrupt_map): + r = "#ifndef __HW_CSR_H\n#define __HW_CSR_H\n#include \n" + for name, csrs, mapaddr, rmap in bank_array.banks: + r += "\n/* "+name+" */\n" + reg_base = csr_base + 0x800*mapaddr + r += "#define "+name.upper()+"_BASE "+hex(reg_base)+"\n" + for csr in csrs: + nr = (csr.size + 7)//8 + r += _get_rw_functions(name + "_" + csr.name, reg_base, nr, isinstance(csr, CSRStatus)) + reg_base += 4*nr + try: + interrupt_nr = interrupt_map[name] + except KeyError: + pass + else: + r += "#define "+name.upper()+"_INTERRUPT "+str(interrupt_nr)+"\n" + for name, memory, mapaddr, mmap in bank_array.srams: + mem_base = csr_base + 0x800*mapaddr + fullname = name + "_" + memory.name_override + r += "#define "+fullname.upper()+"_BASE "+hex(mem_base)+"\n" + r += "\n#endif\n" + return r + +def get_csr_csv(csr_base, bank_array): + r = "" + for name, csrs, mapaddr, rmap in bank_array.banks: + reg_base = csr_base + 0x800*mapaddr + for csr in csrs: + nr = (csr.size + 7)//8 + r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw") + reg_base += 4*nr + return r diff --git a/top.py b/top.py index 50a6502b..ecf3074f 100644 --- a/top.py +++ b/top.py @@ -1,46 +1,12 @@ from fractions import Fraction -from math import ceil -from operator import itemgetter -from collections import defaultdict from migen.fhdl.std import * -from migen.bus import wishbone, csr, lasmibus, dfi -from migen.bus import wishbone2lasmi, wishbone2csr -from migen.bank import csrgen from mibuild.generic_platform import ConstraintError -from misoclib import mxcrg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \ - identifier, timer, minimac3, framebuffer, dvisampler, gpio, memtest +from misoclib import lasmicon, mxcrg, norflash, s6ddrphy, minimac3, framebuffer, dvisampler, gpio +from misoclib.gensoc import SDRAMSoC -clk_freq = (83 + Fraction(1, 3))*1000000 -sram_size = 4096 # in bytes -l2_size = 8192 # in bytes - -clk_period_ns = 1000000000/clk_freq -def ns(t, margin=True): - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) - -sdram_geom = lasmicon.GeomSettings( - bank_a=2, - row_a=13, - col_a=10 -) -sdram_timing = lasmicon.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(15), - tWTR=2, - tREFI=ns(7800, False), - tRFC=ns(70), - - req_queue_size=8, - read_time=32, - write_time=16 -) - -class MXClockPads: +class _MXClockPads: def __init__(self, platform): self.clk50 = platform.request("clk50") self.trigger_reset = 0 @@ -57,129 +23,96 @@ class MXClockPads: self.eth_rx_clk = eth_clocks.rx self.eth_tx_clk = eth_clocks.tx -class SoC(Module): - csr_base = 0xe0000000 +class MiniSoC(SDRAMSoC): csr_map = { - "crg": 0, - "uart": 1, - "dfii": 2, - "identifier": 3, - "timer0": 4, - "minimac": 5, - "fb": 6, - "lasmicon": 7, - "dvisampler0": 8, - "dvisampler0_edid_mem": 9, - "dvisampler1": 10, - "dvisampler1_edid_mem": 11, - "pots": 12, - "buttons": 13, - "leds": 14, - "memtest_w": 15, - "memtest_r": 16 + "minimac": 10, + "fb": 11, + "dvisampler0": 12, + "dvisampler0_edid_mem": 13, + "dvisampler1": 14, + "dvisampler1_edid_mem": 15, } + csr_map.update(SDRAMSoC.csr_map) + interrupt_map = { - "uart": 0, - "timer0": 1, "minimac": 2, "dvisampler0": 3, "dvisampler1": 4, } - known_platform_id = defaultdict(lambda: 0x554E, { - "mixxeo": 0x4D58, - "m1": 0x4D31 - }) + interrupt_map.update(SDRAMSoC.interrupt_map) - def __init__(self, platform, platform_name, with_memtest): - # - # DFI - # - self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), memtype="DDR", nphases=2, cl=3, rd_bitslip=0, wr_bitslip=3, dqs_ddr_alignment="C1") - self.submodules.dfii = dfii.DFIInjector(sdram_geom.mux_a, sdram_geom.bank_a, - self.ddrphy.phy_settings.dfi_d, self.ddrphy.phy_settings.nphases) - self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, self.ddrphy.dfi) + def __init__(self, platform, with_memtest): + SDRAMSoC.__init__(self, platform, + clk_freq=(83 + Fraction(1, 3))*1000000, + sram_size=4096, + l2_size=8192, + with_memtest=with_memtest) - # - # LASMI - # - self.submodules.lasmicon = lasmicon.LASMIcon(self.ddrphy.phy_settings, sdram_geom, sdram_timing) - self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave) + sdram_geom = lasmicon.GeomSettings( + bank_a=2, + row_a=13, + col_a=10 + ) + sdram_timing = lasmicon.TimingSettings( + tRP=self.ns(15), + tRCD=self.ns(15), + tWR=self.ns(15), + tWTR=2, + tREFI=self.ns(7800, False), + tRFC=self.ns(70), - self.submodules.lasmixbar = lasmibus.Crossbar([self.lasmicon.lasmic], self.lasmicon.nrowbits) - lasmim_wb = self.lasmixbar.get_master() - if platform_name == "mixxeo": - lasmim_fb0, lasmim_fb1, lasmim_dvi0, lasmim_dvi1 = (self.lasmixbar.get_master() for i in range(4)) - if platform_name == "m1": - lasmim_fb = self.lasmixbar.get_master() - if with_memtest: - lasmim_mtw, lasmim_mtr = self.lasmixbar.get_master(), self.lasmixbar.get_master() + req_queue_size=8, + read_time=32, + write_time=16 + ) + self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), memtype="DDR", + nphases=2, cl=3, rd_bitslip=0, wr_bitslip=3, dqs_ddr_alignment="C1") + self.create_sdram_modules(self.ddrphy.dfi, self.ddrphy.phy_settings, sdram_geom, sdram_timing) - # - # WISHBONE - # - self.submodules.cpu = lm32.LM32() + # Wishbone self.submodules.norflash = norflash.NorFlash(platform.request("norflash"), 12) - self.submodules.sram = wishbone.SRAM(sram_size) self.submodules.minimac = minimac3.MiniMAC(platform.request("eth")) - self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(l2_size//4, lasmim_wb) - self.submodules.wishbone2csr = wishbone2csr.WB2CSR() - - # norflash 0x00000000 (shadow @0x80000000) - # SRAM/debug 0x10000000 (shadow @0x90000000) - # USB 0x20000000 (shadow @0xa0000000) - # Ethernet 0x30000000 (shadow @0xb0000000) - # SDRAM 0x40000000 (shadow @0xc0000000) - # CSR bridge 0x60000000 (shadow @0xe0000000) - self.submodules.wishbonecon = wishbone.InterconnectShared( - [ - self.cpu.ibus, - self.cpu.dbus - ], [ - (lambda a: a[26:29] == 0, self.norflash.bus), - (lambda a: a[26:29] == 1, self.sram.bus), - (lambda a: a[26:29] == 3, self.minimac.membus), - (lambda a: a[27:29] == 2, self.wishbone2lasmi.wishbone), - (lambda a: a[27:29] == 3, self.wishbone2csr.wishbone) - ], - register=True) + self.add_wb_slave(lambda a: a[26:29] == 0, self.norflash.bus) + self.add_wb_slave(lambda a: a[26:29] == 3, self.minimac.membus) - # # CSR - # - self.submodules.crg = mxcrg.MXCRG(MXClockPads(platform), clk_freq) - self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200) - self.submodules.identifier = identifier.Identifier(self.known_platform_id[platform_name], int(clk_freq), - log2_int(l2_size)) - self.submodules.timer0 = timer.Timer() - if platform_name == "mixxeo": + self.submodules.crg = mxcrg.MXCRG(_MXClockPads(platform), self.clk_freq) + if platform.name == "mixxeo": self.submodules.leds = gpio.GPIOOut(platform.request("user_led")) - self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga_out"), platform.request("dvi_out"), - lasmim_fb0, lasmim_fb1) - self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), lasmim_dvi0) - self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), lasmim_dvi1) - if platform_name == "m1": + if platform.name == "m1": self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) self.submodules.leds = gpio.GPIOOut(Cat(*[platform.request("user_led", i) for i in range(2)])) - self.submodules.fb = framebuffer.Framebuffer(platform.request("vga"), None, lasmim_fb) - if with_memtest: - self.submodules.memtest_w = memtest.MemtestWriter(lasmim_mtw) - self.submodules.memtest_r = memtest.MemtestReader(lasmim_mtr) - self.submodules.csrbankarray = csrgen.BankArray(self, - lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override]) - self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses()) - - # - # Interrupts - # - for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)): - if hasattr(self, k): - self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq) - - # - # Clocking - # + # Clock glue self.comb += [ self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb) ] + +def _get_vga_dvi(platform): + try: + pads_vga = platform.request("vga_out") + except ConstraintError: + pads_vga = None + try: + pads_dvi = platform.request("dvi_out") + except ConstraintError: + pads_dvi = None + return pads_vga, pads_dvi + +class FramebufferSoC(MiniSoC): + def __init__(self, platform, with_memtest): + MiniSoC.__init__(self, platform, with_memtest) + pads_vga, pads_dvi = _get_vga_dvi(platform) + self.submodules.fb = framebuffer.Framebuffer(pads_vga, pads_dvi, self.lasmixbar.get_master()) + +class VideomixerSoC(MiniSoC): + def __init__(self, platform, with_memtest): + MiniSoC.__init__(self, platform, with_memtest) + pads_vga, pads_dvi = _get_vga_dvi(platform) + self.submodules.fb = framebuffer.MixFramebuffer(pads_vga, pads_dvi, + self.lasmixbar.get_master(), self.lasmixbar.get_master()) + self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), self.lasmixbar.get_master()) + self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), self.lasmixbar.get_master()) + +SoC = VideomixerSoC