X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Flitex%2Fflorent%2Fls180soc.py;h=cd8119ebba7ce080cf17a6c147db92edbedd27f5;hb=5b4254bea20b8562872cc94b889fd0e18e0a41e1;hp=877abf020f6d4e059b9ff6e6cedb68688024b11b;hpb=0b7dc18b6f8205c0ae21f18713c66c374163614a;p=soc.git diff --git a/src/soc/litex/florent/ls180soc.py b/src/soc/litex/florent/ls180soc.py index 877abf02..cd8119eb 100755 --- a/src/soc/litex/florent/ls180soc.py +++ b/src/soc/litex/florent/ls180soc.py @@ -2,8 +2,11 @@ import os import argparse +from functools import reduce +from operator import or_ -from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState) +from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState, + Cat, Record, ClockSignal, wrap, ResetInserter) from litex.build.generic_platform import Pins, Subsignal from litex.build.sim import SimPlatform @@ -18,11 +21,13 @@ from litex.soc.integration.common import get_mem_data from litedram import modules as litedram_modules from litedram.phy.model import SDRAMPHYModel -from litedram.phy.gensdrphy import GENSDRPHY, HalfRateGENSDRPHY - -from litex.soc.cores.gpio import GPIOInOut, GPIOIn, GPIOOut#, GPIOTristate +#from litedram.phy.gensdrphy import GENSDRPHY, HalfRateGENSDRPHY +from litedram.common import PHYPadsCombiner, PhySettings +from litedram.phy.dfi import Interface as DFIInterface from litex.soc.cores.spi import SPIMaster from litex.soc.cores.pwm import PWM +from litex.soc.cores.bitbang import I2CMaster +from litex.soc.cores import uart from litex.tools.litex_sim import sdram_module_nphases, get_sdram_phy_settings @@ -39,8 +44,196 @@ from microwatt import Microwatt from litex.soc.integration.soc import SoCCSRHandler SoCCSRHandler.supported_address_width.append(12) +# GPIO Tristate ------------------------------------------------------- +# doesn't work properly. +#from litex.soc.cores.gpio import GPIOTristate +from litex.soc.interconnect.csr import CSRStorage, CSRStatus +from migen.genlib.cdc import MultiReg + +# Imports +from litex.soc.interconnect import wishbone +from litesdcard.phy import (SDPHY, SDPHYClocker, + SDPHYInit, SDPHYCMDW, SDPHYCMDR, + SDPHYDATAW, SDPHYDATAR, + _sdpads_layout) +from litesdcard.core import SDCore +from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA +from litex.build.io import SDROutput, SDRInput + + +class GPIOTristateASIC(Module, AutoCSR): + def __init__(self, pads): + nbits = len(pads.oe) # hack + self._oe = CSRStorage(nbits, description="GPIO Tristate(s) Control.") + self._in = CSRStatus(nbits, description="GPIO Input(s) Status.") + self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.") + + # # # + + _pads = Record( (("i", nbits), + ("o", nbits), + ("oe", nbits))) + self.comb += _pads.i.eq(pads.i) + self.comb += pads.o.eq(_pads.o) + self.comb += pads.oe.eq(_pads.oe) + + self.comb += _pads.oe.eq(self._oe.storage) + self.comb += _pads.o.eq(self._out.storage) + for i in range(nbits): + self.specials += MultiReg(_pads.i[i], self._in.status[i]) + +# SDCard PHY IO ------------------------------------------------------- + +class SDRPad(Module): + def __init__(self, pad, name, o, oe, i): + clk = ClockSignal() + _o = getattr(pad, "%s_o" % name) + _oe = getattr(pad, "%s_oe" % name) + _i = getattr(pad, "%s_i" % name) + self.specials += SDROutput(clk=clk, i=oe, o=_oe) + for j in range(len(_o)): + self.specials += SDROutput(clk=clk, i=o[j], o=_o[j]) + self.specials += SDRInput(clk=clk, i=_i[j], o=i[j]) + + +class SDPHYIOGen(Module): + def __init__(self, clocker, sdpads, pads): + # Rst + if hasattr(pads, "rst"): + self.comb += pads.rst.eq(0) + + # Clk + self.specials += SDROutput( + clk = ClockSignal(), + i = ~clocker.clk & sdpads.clk, + o = pads.clk + ) + + # Cmd + c = sdpads.cmd + self.submodules.sd_cmd = SDRPad(pads, "cmd", c.o, c.oe, c.i) + + # Data + d = sdpads.data + self.submodules.sd_data = SDRPad(pads, "data", d.o, d.oe, d.i) + + +class SDPHY(Module, AutoCSR): + def __init__(self, pads, device, sys_clk_freq, + cmd_timeout=10e-3, data_timeout=10e-3): + self.card_detect = CSRStatus() # Assume SDCard is present if no cd pin. + self.comb += self.card_detect.status.eq(getattr(pads, "cd", 0)) + + self.submodules.clocker = clocker = SDPHYClocker() + self.submodules.init = init = SDPHYInit() + self.submodules.cmdw = cmdw = SDPHYCMDW() + self.submodules.cmdr = cmdr = SDPHYCMDR(sys_clk_freq, + cmd_timeout, cmdw) + self.submodules.dataw = dataw = SDPHYDATAW() + self.submodules.datar = datar = SDPHYDATAR(sys_clk_freq, + data_timeout) + + # # # + + self.sdpads = sdpads = Record(_sdpads_layout) + + # IOs + sdphy_cls = SDPHYIOGen + self.submodules.io = sdphy_cls(clocker, sdpads, pads) + + # Connect pads_out of submodules to physical pads -------------- + pl = [init, cmdw, cmdr, dataw, datar] + self.comb += [ + sdpads.clk.eq( reduce(or_, [m.pads_out.clk for m in pl])), + sdpads.cmd.oe.eq( reduce(or_, [m.pads_out.cmd.oe for m in pl])), + sdpads.cmd.o.eq( reduce(or_, [m.pads_out.cmd.o for m in pl])), + sdpads.data.oe.eq(reduce(or_, [m.pads_out.data.oe for m in pl])), + sdpads.data.o.eq( reduce(or_, [m.pads_out.data.o for m in pl])), + ] + for m in pl: + self.comb += m.pads_out.ready.eq(self.clocker.ce) + + # Connect physical pads to pads_in of submodules --------------- + for m in pl: + self.comb += m.pads_in.valid.eq(self.clocker.ce) + self.comb += m.pads_in.cmd.i.eq(sdpads.cmd.i) + self.comb += m.pads_in.data.i.eq(sdpads.data.i) + + # Speed Throttling ------------------------------------------- + self.comb += clocker.stop.eq(dataw.stop | datar.stop) + + +# Generic SDR PHY --------------------------------------------------------- + +class GENSDRPHY(Module): + def __init__(self, pads, cl=2, cmd_latency=1): + pads = PHYPadsCombiner(pads) + addressbits = len(pads.a) + bankbits = len(pads.ba) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + databits = len(pads.dq_i) + assert cl in [2, 3] + assert databits%8 == 0 + + # PHY settings ---------------------------------------------------- + self.settings = PhySettings( + phytype = "GENSDRPHY", + memtype = "SDR", + databits = databits, + dfi_databits = databits, + nranks = nranks, + nphases = 1, + rdphase = 0, + wrphase = 0, + rdcmdphase = 0, + wrcmdphase = 0, + cl = cl, + read_latency = cl + cmd_latency, + write_latency = 0 + ) + + # DFI Interface --------------------------------------------------- + self.dfi = dfi = DFIInterface(addressbits, bankbits, nranks, databits) + + # # # + + # Iterate on pads groups ------------------------------------------ + for pads_group in range(len(pads.groups)): + pads.sel_group(pads_group) + + # Addresses and Commands -------------------------------------- + p0 = dfi.p0 + self.specials += [SDROutput(i=p0.address[i], o=pads.a[i]) + for i in range(len(pads.a))] + self.specials += [SDROutput(i=p0.bank[i], o=pads.ba[i]) + for i in range(len(pads.ba))] + self.specials += SDROutput(i=p0.cas_n, o=pads.cas_n) + self.specials += SDROutput(i=p0.ras_n, o=pads.ras_n) + self.specials += SDROutput(i=p0.we_n, o=pads.we_n) + if hasattr(pads, "cke"): + for i in range(len(pads.cke)): + self.specials += SDROutput(i=p0.cke[i], o=pads.cke[i]) + if hasattr(pads, "cs_n"): + for i in range(len(pads.cs_n)): + self.specials += SDROutput(i=p0.cs_n[i], o=pads.cs_n[i]) -# LibreSoCSim ----------------------------------------------------------------- + # DQ/DM Data Path ------------------------------------------------- + + d = dfi.p0 + wren = [] + self.submodules.dq = SDRPad(pads, "dq", d.wrdata, d.wrdata_en, d.rddata) + + if hasattr(pads, "dm"): + for i in range(len(pads.dm)): + self.specials += SDROutput(i=d.wrdata_mask[i], o=pads.dm[i]) + + # DQ/DM Control Path ---------------------------------------------- + rddata_en = Signal(cl + cmd_latency) + self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en)) + self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1]) + + +# LibreSoC 180nm ASIC ------------------------------------------------------- class LibreSoCSim(SoCCore): def __init__(self, cpu="libresoc", debug=False, with_sdram=True, @@ -59,7 +252,7 @@ class LibreSoCSim(SoCCore): uart_name = "sim" elif platform == 'ls180': platform = LS180Platform() - uart_name = "serial" + uart_name = "uart" #cpu_data_width = 32 cpu_data_width = 64 @@ -100,7 +293,8 @@ class LibreSoCSim(SoCCore): cpu_variant = variant, csr_data_width = 8, l2_size = 0, - uart_name = uart_name, + with_uart = False, + uart_name = None, with_sdram = with_sdram, sdram_module = sdram_module, sdram_data_width = sdram_data_width, @@ -145,7 +339,7 @@ class LibreSoCSim(SoCCore): memtype = sdram_module.memtype, data_width = sdram_data_width, clk_freq = sdram_clk_freq) - #sdrphy_cls = HalfRateGENSDRPHY + #sdrphy_cls = HalfRateGENSDRPHY sdrphy_cls = GENSDRPHY self.submodules.sdrphy = sdrphy_cls(platform.request("sdram")) #self.submodules.sdrphy = sdrphy_cls(sdram_module, @@ -156,7 +350,7 @@ class LibreSoCSim(SoCCore): phy = self.sdrphy, module = sdram_module, origin = self.mem_map["main_ram"], - size = 0x40000000, + size = 0x80000000, l2_cache_size = 0, # 8192 l2_cache_min_data_width = 128, l2_cache_reverse = True @@ -169,16 +363,41 @@ class LibreSoCSim(SoCCore): self.add_constant("MEMTEST_ADDR_DEBUG", 1) self.add_constant("MEMTEST_DATA_DEBUG", 1) - # GPIOs - #platform.add_extension([("gpio_in", 0, Pins(8))]) - self.submodules.gpio_in = GPIOIn(platform.request("gpio_in")) - self.add_csr("gpio_in") - self.submodules.gpio_out = GPIOIn(platform.request("gpio_out")) - self.add_csr("gpio_out") - - if False: - self.submodules.gpio = GPIOTristate(platform.request("gpio")) - self.add_csr("gpio") + # SDRAM clock + sys_clk = ClockSignal() + sdr_clk = platform.request("sdram_clock") + #self.specials += DDROutput(1, 0, , sdram_clk) + self.specials += SDROutput(clk=sys_clk, i=sys_clk, o=sdr_clk) + + # UART + uart_core_pads = self.cpu.cpupads['uart'] + self.submodules.uart_phy = uart.UARTPHY( + pads = uart_core_pads, + clk_freq = self.sys_clk_freq, + baudrate = 115200) + self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy, + tx_fifo_depth = 16, + rx_fifo_depth = 16)) + # "real" pads connect to C4M JTAG iopad + uart_pads = platform.request(uart_name) # "real" (actual) pin + uart_io_pads = self.cpu.iopads['uart'] # C4M JTAG pads + self.comb += uart_pads.tx.eq(uart_io_pads.tx) + self.comb += uart_io_pads.rx.eq(uart_pads.rx) + + self.csr.add("uart_phy", use_loc_if_exists=True) + self.csr.add("uart", use_loc_if_exists=True) + self.irq.add("uart", use_loc_if_exists=True) + + # GPIOs (bi-directional) + gpio_core_pads = self.cpu.cpupads['gpio'] + self.submodules.gpio = GPIOTristateASIC(gpio_core_pads) + self.add_csr("gpio") + + gpio_pads = platform.request("gpio") # "real" (actual) pins + gpio_io_pads = self.cpu.iopads['gpio'] # C4M JTAG pads + self.comb += gpio_io_pads.i.eq(gpio_pads.i) + self.comb += gpio_pads.o.eq(gpio_io_pads.o) + self.comb += gpio_pads.oe.eq(gpio_io_pads.oe) # SPI Master self.submodules.spi_master = SPIMaster( @@ -199,12 +418,58 @@ class LibreSoCSim(SoCCore): self.comb += self.cpu.jtag_tdi.eq(jtagpads.tdi) self.comb += jtagpads.tdo.eq(self.cpu.jtag_tdo) + # NC - allows some iopads to be connected up + # sigh, just do something, anything, to stop yosys optimising these out + nc_pads = platform.request("nc") + num_nc = len(nc_pads) + self.nc = Signal(num_nc) + self.comb += self.nc.eq(nc_pads) + self.dummy = Signal(num_nc) + for i in range(num_nc): + self.sync += self.dummy[i].eq(self.nc[i] | self.cpu.interrupt[0]) + # PWM for i in range(2): name = "pwm%d" % i setattr(self.submodules, name, PWM(platform.request("pwm", i))) self.add_csr(name) + if False: # TODO: convert to _i _o _oe + # I2C Master + self.submodules.i2c = I2CMaster(platform.request("i2c")) + self.add_csr("i2c") + + # SDCard ----------------------------------------------------- + + # Emulator / Pads + sdcard_pads = self.platform.request("sdcard") + + # Core + self.submodules.sdphy = SDPHY(sdcard_pads, + self.platform.device, self.clk_freq) + self.submodules.sdcore = SDCore(self.sdphy) + self.add_csr("sdphy") + self.add_csr("sdcore") + + # Block2Mem DMA + bus = wishbone.Interface(data_width=self.bus.data_width, + adr_width=self.bus.address_width) + self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, + endianness=self.cpu.endianness) + self.comb += self.sdcore.source.connect(self.sdblock2mem.sink) + dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus + dma_bus.add_master("sdblock2mem", master=bus) + self.add_csr("sdblock2mem") + + # Mem2Block DMA + bus = wishbone.Interface(data_width=self.bus.data_width, + adr_width=self.bus.address_width) + self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, + endianness=self.cpu.endianness) + self.comb += self.sdmem2block.source.connect(self.sdcore.sink) + dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus + dma_bus.add_master("sdmem2block", master=bus) + self.add_csr("sdmem2block") # Debug --------------------------------------------------------------- if not debug: @@ -493,7 +758,6 @@ def main(): if args.platform == 'ls180': soc = LibreSoCSim(cpu=args.cpu, debug=args.debug, platform=args.platform) - soc.add_sdcard() soc.add_spi_sdcard() builder = Builder(soc, compile_gateware = True) builder.build(run = True)