diff --git a/litex/boards/platforms/de0nano.py b/litex/boards/platforms/de0nano.py index 56cc5f164..042a543e5 100644 --- a/litex/boards/platforms/de0nano.py +++ b/litex/boards/platforms/de0nano.py @@ -28,8 +28,10 @@ _io = [ ("sw", 3, Pins("M15"), IOStandard("3.3-V LVTTL")), ("serial", 0, - Subsignal("tx", Pins("B4"), IOStandard("3.3-V LVTTL")), # gpio_05 - Subsignal("rx", Pins("B5"), IOStandard("3.3-V LVTTL")) # gpio_07 + # Compatible with cheap FT232 based cables (ex: Gaoominy 6Pin Ftdi Ft232Rl Ft232) + # GND on JP1 Pin 12. + Subsignal("tx", Pins("B5"), IOStandard("3.3-V LVTTL")), # GPIO_07 (JP1 Pin 10) + Subsignal("rx", Pins("B4"), IOStandard("3.3-V LVTTL")) # GPIO_05 (JP1 Pin 8) ), ("sdram_clock", 0, Pins("R4"), IOStandard("3.3-V LVTTL")), diff --git a/litex/boards/targets/kc705.py b/litex/boards/targets/kc705.py index 35a30c43e..87290e477 100755 --- a/litex/boards/targets/kc705.py +++ b/litex/boards/targets/kc705.py @@ -60,7 +60,6 @@ class BaseSoC(SoCCore): sys_clk_freq = sys_clk_freq, cmd_latency = 1) self.add_csr("ddrphy") - self.add_constant("DDRPHY_CMD_DELAY", 13) self.add_sdram("sdram", phy = self.ddrphy, module = MT8JTF12864(sys_clk_freq, "1:4"), diff --git a/litex/boards/targets/kcu105.py b/litex/boards/targets/kcu105.py index 6e90ec47b..b632b16cc 100755 --- a/litex/boards/targets/kcu105.py +++ b/litex/boards/targets/kcu105.py @@ -65,9 +65,8 @@ class BaseSoC(SoCCore): memtype = "DDR4", sys_clk_freq = sys_clk_freq, iodelay_clk_freq = 200e6, - cmd_latency = 0) + cmd_latency = 1) self.add_csr("ddrphy") - self.add_constant("USDDRPHY") self.add_constant("USDDRPHY_DEBUG") self.add_sdram("sdram", phy = self.ddrphy, diff --git a/litex/boards/targets/ulx3s.py b/litex/boards/targets/ulx3s.py index e42c92b02..a7668e3a9 100755 --- a/litex/boards/targets/ulx3s.py +++ b/litex/boards/targets/ulx3s.py @@ -86,7 +86,7 @@ def main(): parser.add_argument("--gateware-toolchain", dest="toolchain", default="trellis", help="gateware toolchain to use, trellis (default) or diamond") parser.add_argument("--device", dest="device", default="LFE5U-45F", - help="FPGA device, ULX3S can be populated with LFE5U-45F (default) or LFE5U-85F") + help="FPGA device, ULX3S can be populated with LFE5U-12F, LFE5U-25F, LFE5U-45F (default) or LFE5U-85F") parser.add_argument("--sys-clk-freq", default=50e6, help="system clock frequency (default=50MHz)") parser.add_argument("--sdram-module", default="MT48LC16M16", diff --git a/litex/boards/targets/versa_ecp5.py b/litex/boards/targets/versa_ecp5.py index 216d7bb39..49d8a6517 100755 --- a/litex/boards/targets/versa_ecp5.py +++ b/litex/boards/targets/versa_ecp5.py @@ -87,7 +87,6 @@ class BaseSoC(SoCCore): platform.request("ddram"), sys_clk_freq=sys_clk_freq) self.add_csr("ddrphy") - self.add_constant("ECP5DDRPHY") self.comb += self.crg.stop.eq(self.ddrphy.init.stop) self.add_sdram("sdram", phy = self.ddrphy, diff --git a/litex/build/generic_programmer.py b/litex/build/generic_programmer.py index ac22c74f2..394440300 100644 --- a/litex/build/generic_programmer.py +++ b/litex/build/generic_programmer.py @@ -1,8 +1,11 @@ # This file is Copyright (c) 2015 Sebastien Bourdeauducq +# This file is Copyright (c) 2020 Florent Kermarrec # License: BSD -import os, sys +import os +import sys + from litex.build import tools @@ -12,25 +15,47 @@ class GenericProgrammer: self.flash_proxy_dirs = [ "~/.migen", "/usr/local/share/migen", "/usr/share/migen", "~/.mlabs", "/usr/local/share/mlabs", "/usr/share/mlabs", - "~/.litex", "/usr/local/share/litex", "/usr/share/litex"] + "~/.litex", "/usr/local/share/litex", "/usr/share/litex" + ] + self.flash_proxy_repos = [ + "https://github.com/quartiq/bscan_spi_bitstreams/raw/master/", + ] + self.flash_proxy_local = "flash_proxies" def set_flash_proxy_dir(self, flash_proxy_dir): if flash_proxy_dir is not None: self.flash_proxy_dirs = [flash_proxy_dir] def find_flash_proxy(self): + # Search in installed flash_proxy_directories for d in self.flash_proxy_dirs: - fulldir = os.path.abspath(os.path.expanduser(d)) + fulldir = os.path.abspath(os.path.expanduser(d)) fullname = tools.cygpath(os.path.join(fulldir, self.flash_proxy_basename)) if os.path.exists(fullname): return fullname + # Search in local flash_proxy directory + fullname = tools.cygpath(os.path.join(self.flash_proxy_local, self.flash_proxy_basename)) + if os.path.exists(fullname): + return fullname + # Search in repositories and download it + import requests + os.makedirs(self.flash_proxy_local, exist_ok=True) + for d in self.flash_proxy_repos: + fullname = tools.cygpath(os.path.join(self.flash_proxy_local, self.flash_proxy_basename)) + try: + r = requests.get(d + self.flash_proxy_basename) + with open(fullname, "wb") as f: + f.write(r.content) + return fullname + except: + pass raise OSError("Failed to find flash proxy bitstream") - # must be overloaded by specific programmer + # Must be overloaded by specific programmer def load_bitstream(self, bitstream_file): raise NotImplementedError - # must be overloaded by specific programmer + # Must be overloaded by specific programmer def flash(self, address, data_file): raise NotImplementedError diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index 929aaadfa..fbb446db8 100644 --- a/litex/build/lattice/common.py +++ b/litex/build/lattice/common.py @@ -1,4 +1,4 @@ -# This file is Copyright (c) 2015-2019 Florent Kermarrec +# This file is Copyright (c) 2015-2020 Florent Kermarrec # This file is Copyright (c) 2017 William D. Jones # This file is Copyright (c) 2019 David Shah # License: BSD @@ -69,6 +69,22 @@ class LatticeECP5SDROutput: def lower(dr): return LatticeECP5SDROutputImpl(dr.i, dr.o, dr.clk) +# ECP5 DDR Input ----------------------------------------------------------------------------------- + +class LatticeECP5DDRInputImpl(Module): + def __init__(self, i, o1, o2, clk): + self.specials += Instance("IDDRX1F", + i_SCLK = clk, + i_D = i, + o_Q0 = o1, + o_Q1 = o2, + ) + +class LatticeECP5DDRInput: + @staticmethod + def lower(dr): + return LatticeECP5DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk) + # ECP5 DDR Output ---------------------------------------------------------------------------------- class LatticeECP5DDROutputImpl(Module): @@ -91,7 +107,8 @@ lattice_ecp5_special_overrides = { AsyncResetSynchronizer: LatticeECP5AsyncResetSynchronizer, SDRInput: LatticeECP5SDRInput, SDROutput: LatticeECP5SDROutput, - DDROutput: LatticeECP5DDROutput + DDRInput: LatticeECP5DDRInput, + DDROutput: LatticeECP5DDROutput, } # ECP5 Trellis Tristate ---------------------------------------------------------------------------- @@ -99,27 +116,14 @@ lattice_ecp5_special_overrides = { class LatticeECP5TrellisTristateImpl(Module): def __init__(self, io, o, oe, i): nbits, sign = value_bits_sign(io) - if nbits == 1: - self.specials += [ - Instance("TRELLIS_IO", - p_DIR = "BIDIR", - i_B = io, - i_I = o, - o_O = i, - i_T = ~oe - ) - ] - else: - for bit in range(nbits): - self.specials += [ - Instance("TRELLIS_IO", - p_DIR="BIDIR", - i_B = io[bit], - i_I = o[bit], - o_O = i[bit], - i_T = ~oe - ) - ] + for bit in range(nbits): + self.specials += Instance("TRELLIS_IO", + p_DIR = "BIDIR", + i_B = io[bit] if nbits > 1 else io, + i_I = o[bit] if nbits > 1 else o, + o_O = i[bit] if nbits > 1 else i, + i_T = ~oe + ) class LatticeECP5TrellisTristate(Module): @staticmethod @@ -133,6 +137,7 @@ lattice_ecp5_trellis_special_overrides = { Tristate: LatticeECP5TrellisTristate, SDRInput: LatticeECP5SDRInput, SDROutput: LatticeECP5SDROutput, + DDRInput: LatticeECP5DDRInput, DDROutput: LatticeECP5DDROutput } @@ -142,10 +147,16 @@ class LatticeiCE40AsyncResetSynchronizerImpl(Module): def __init__(self, cd, async_reset): rst1 = Signal() self.specials += [ - Instance("SB_DFFS", i_D=0, i_S=async_reset, - i_C=cd.clk, o_Q=rst1), - Instance("SB_DFFS", i_D=rst1, i_S=async_reset, - i_C=cd.clk, o_Q=cd.rst) + Instance("SB_DFFS", + i_D = 0, + i_S = async_reset, + i_C = cd.clk, + o_Q = rst1), + Instance("SB_DFFS", + i_D = rst1, + i_S = async_reset, + i_C = cd.clk, + o_Q = cd.rst) ] @@ -154,33 +165,19 @@ class LatticeiCE40AsyncResetSynchronizer: def lower(dr): return LatticeiCE40AsyncResetSynchronizerImpl(dr.cd, dr.async_reset) -# iCE40 Trellis Tristate --------------------------------------------------------------------------- +# iCE40 Tristate ----------------------------------------------------------------------------------- class LatticeiCE40TristateImpl(Module): def __init__(self, io, o, oe, i): nbits, sign = value_bits_sign(io) - if nbits == 1: - self.specials += [ - Instance("SB_IO", - p_PIN_TYPE = C(0b101001, 6), - io_PACKAGE_PIN = io, - i_OUTPUT_ENABLE = oe, - i_D_OUT_0 = o, - o_D_IN_0 = i - ) - ] - else: - for bit in range(nbits): - self.specials += [ - Instance("SB_IO", - p_PIN_TYPE = C(0b101001, 6), - io_PACKAGE_PIN = io[bit], - i_OUTPUT_ENABLE = oe, - i_D_OUT_0 = o[bit], - o_D_IN_0 = i[bit] - ) - ] - + for bit in range(nbits): + self.specials += Instance("SB_IO", + p_PIN_TYPE = C(0b101001, 6), # PIN_OUTPUT_TRISTATE + PIN_INPUT + io_PACKAGE_PIN = io[bit] if nbits > 1 else io, + i_OUTPUT_ENABLE = oe, + i_D_OUT_0 = o[bit] if nbits > 1 else o, + o_D_IN_0 = i[bit] if nbits > 1 else i, + ) class LatticeiCE40Tristate(Module): @staticmethod @@ -193,45 +190,38 @@ class LatticeiCE40DifferentialOutputImpl(Module): def __init__(self, i, o_p, o_n): self.specials += [ Instance("SB_IO", - p_PIN_TYPE = C(0b011000, 6), + p_PIN_TYPE = C(0b011000, 6), # PIN_OUTPUT p_IO_STANDARD = "SB_LVCMOS", io_PACKAGE_PIN = o_p, i_D_OUT_0 = i - ) - ] - - self.specials += [ + ), Instance("SB_IO", - p_PIN_TYPE = C(0b011000, 6), + p_PIN_TYPE = C(0b011000, 6), # PIN_OUTPUT p_IO_STANDARD = "SB_LVCMOS", io_PACKAGE_PIN = o_n, i_D_OUT_0 = ~i ) ] - class LatticeiCE40DifferentialOutput: @staticmethod def lower(dr): return LatticeiCE40DifferentialOutputImpl(dr.i, dr.o_p, dr.o_n) - # iCE40 DDR Output --------------------------------------------------------------------------------- class LatticeiCE40DDROutputImpl(Module): def __init__(self, i1, i2, o, clk): - self.specials += [ - Instance("SB_IO", - p_PIN_TYPE = C(0b010000, 6), - p_IO_STANDARD = "SB_LVCMOS", - io_PACKAGE_PIN = o, - i_CLOCK_ENABLE = 1, - i_OUTPUT_CLK = clk, - i_OUTPUT_ENABLE = 1, - i_D_OUT_0 = i1, - i_D_OUT_1 = i2 - ) - ] + self.specials += Instance("SB_IO", + p_PIN_TYPE = C(0b010000, 6), # PIN_OUTPUT_DDR + p_IO_STANDARD = "SB_LVCMOS", + io_PACKAGE_PIN = o, + i_CLOCK_ENABLE = 1, + i_OUTPUT_CLK = clk, + i_OUTPUT_ENABLE = 1, + i_D_OUT_0 = i1, + i_D_OUT_1 = i2 + ) class LatticeiCE40DDROutput: @@ -239,11 +229,80 @@ class LatticeiCE40DDROutput: def lower(dr): return LatticeiCE40DDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk) +# iCE40 DDR Input ---------------------------------------------------------------------------------- + +class LatticeiCE40DDRInputImpl(Module): + def __init__(self, i, o1, o2, clk): + self.specials += Instance("SB_IO", + p_PIN_TYPE = C(0b000000, 6), # PIN_INPUT_DDR + p_IO_STANDARD = "SB_LVCMOS", + io_PACKAGE_PIN = i, + i_CLOCK_ENABLE = 1, + i_INPUT_CLK = clk, + o_D_IN_0 = o1, + o_D_IN_1 = o2 + ) + + +class LatticeiCE40DDRInput: + @staticmethod + def lower(dr): + return LatticeiCE40DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk) + +# iCE40 SDR Output --------------------------------------------------------------------------------- + +class LatticeiCE40SDROutputImpl(Module): + def __init__(self, i, o, clk): + self.specials += Instance("SB_IO", + p_PIN_TYPE = C(0b010100, 6), # PIN_OUTPUT_REGISTERED + p_IO_STANDARD = "SB_LVCMOS", + io_PACKAGE_PIN = o, + i_CLOCK_ENABLE = 1, + i_OUTPUT_CLK = clk, + i_OUTPUT_ENABLE = 1, + i_D_OUT_0 = i + ) + +class LatticeiCE40SDROutput: + @staticmethod + def lower(dr): + return LatticeiCE40SDROutputImpl(dr.i, dr.o, dr.clk) + +# iCE40 SDR Input ---------------------------------------------------------------------------------- + +class LatticeiCE40SDRInput: + @staticmethod + def lower(dr): + return LatticeiCE40DDRInputImpl(dr.i, dr.o, Signal(), dr.clk) + +# iCE40 SDR Tristate ------------------------------------------------------------------------------- + +class LatticeiCE40SDRTristateImpl(Module): + def __init__(self, io, o, oe, i, clk): + self.specials += Instance("SB_IO", + p_PIN_TYPE = C(0b110100, 6), # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED + PIN_INPUT_REGISTERED + io_PACKAGE_PIN = io, + i_INPUT_CLK = clk, + i_OUTPUT_CLK = clk, + i_OUTPUT_ENABLE = oe, + i_D_OUT_0 = o, + o_D_IN_0 = i, + ) + +class LatticeiCE40SDRTristate(Module): + @staticmethod + def lower(dr): + return LatticeiCE40SDRTristateImpl(dr.io, dr.o, dr.oe, dr.i, dr.clk) + # iCE40 Trellis Special Overrides ------------------------------------------------------------------ lattice_ice40_special_overrides = { AsyncResetSynchronizer: LatticeiCE40AsyncResetSynchronizer, Tristate: LatticeiCE40Tristate, DifferentialOutput: LatticeiCE40DifferentialOutput, - DDROutput: LatticeiCE40DDROutput + DDROutput: LatticeiCE40DDROutput, + DDRInput: LatticeiCE40DDRInput, + SDROutput: LatticeiCE40SDROutput, + SDRInput: LatticeiCE40SDRInput, + SDRTristate: LatticeiCE40SDRTristate, } diff --git a/litex/build/lattice/diamond.py b/litex/build/lattice/diamond.py index e3f91133f..cf44d096b 100644 --- a/litex/build/lattice/diamond.py +++ b/litex/build/lattice/diamond.py @@ -68,8 +68,8 @@ def _build_tcl(device, sources, vincpaths, build_name): ])) # Add include paths - for path in vincpaths: - tcl.append("prj_impl option {include path} {\"" + path + "\"}") + vincpath = ';'.join(map(lambda x: x.replace('\\', '/'), vincpaths)) + tcl.append("prj_impl option {include path} {\"" + vincpath + "\"}") # Add sources for filename, language, library in sources: @@ -201,4 +201,4 @@ class LatticeDiamondToolchain: from_.attr.add("keep") to.attr.add("keep") if (to, from_) not in self.false_paths: - self.false_paths.add((from_, to)) \ No newline at end of file + self.false_paths.add((from_, to)) diff --git a/litex/build/lattice/icestorm.py b/litex/build/lattice/icestorm.py index a084a9980..2822a9b53 100644 --- a/litex/build/lattice/icestorm.py +++ b/litex/build/lattice/icestorm.py @@ -38,7 +38,10 @@ def _build_pre_pack(vns, clocks): # Yosys/Nextpnr Helpers/Templates ------------------------------------------------------------------ _yosys_template = [ + "verilog_defaults -push", + "verilog_defaults -add -defer", "{read_files}", + "verilog_defaults -pop", "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0", "synth_ice40 {synth_opts} -json {build_name}.json -top {build_name} -dsp", ] diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 154e751dd..fa19b9192 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -49,7 +49,10 @@ def _build_lpf(named_sc, named_pc, build_name): # Yosys/Nextpnr Helpers/Templates ------------------------------------------------------------------ _yosys_template = [ + "verilog_defaults -push", + "verilog_defaults -add -defer", "{read_files}", + "verilog_defaults -pop", "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0", "synth_ecp5 -abc9 {nwl} -json {build_name}.json -top {build_name}", ] @@ -97,6 +100,7 @@ def nextpnr_ecp5_parse_device(device): return (family, size, speed_grade, package) nextpnr_ecp5_architectures = { + "lfe5u-12f" : "12k", "lfe5u-25f" : "25k", "lfe5u-45f" : "45k", "lfe5u-85f" : "85k", diff --git a/litex/build/sim/core/Makefile b/litex/build/sim/core/Makefile index 047423cac..225ff0f21 100644 --- a/litex/build/sim/core/Makefile +++ b/litex/build/sim/core/Makefile @@ -52,7 +52,7 @@ sim: $(OBJS_SIM) | mkdir .PHONY: modules modules: - mkdir modules + mkdir -p modules $(MAKE) -C modules -f $(MOD_DIR)/Makefile .PHONY: clean diff --git a/litex/build/sim/core/modules.c b/litex/build/sim/core/modules.c index 2d12a771f..60bec4c69 100644 --- a/litex/build/sim/core/modules.c +++ b/litex/build/sim/core/modules.c @@ -20,7 +20,7 @@ int litex_sim_register_ext_module(struct ext_module_s *mod) { int ret=RC_OK; struct ext_module_list_s *ml=NULL; - + if(!mod) { eprintf("Invalid arguments\n"); @@ -81,7 +81,7 @@ int litex_sim_load_ext_modules(struct ext_module_list_s **mlist) eprintf("Can't load library %s\n", libdylib_last_error()); goto out; } - + if(!libdylib_find(lib, "litex_sim_ext_module_init")) { ret = RC_ERROR; diff --git a/litex/build/sim/core/modules/clocker/clocker.c b/litex/build/sim/core/modules/clocker/clocker.c index 13d047892..1b2b9db04 100644 --- a/litex/build/sim/core/modules/clocker/clocker.c +++ b/litex/build/sim/core/modules/clocker/clocker.c @@ -60,7 +60,7 @@ static int clocker_new(void **sess, char *args) out: *sess=(void*)s; - return ret; + return ret; } static int clocker_add_pads(void *sess, struct pad_list_s *plist) @@ -74,7 +74,7 @@ static int clocker_add_pads(void *sess, struct pad_list_s *plist) goto out; } pads = plist->pads; - + if(!strcmp(plist->name, "sys_clk")) { litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk); } diff --git a/litex/build/sim/core/modules/serial2tcp/serial2tcp.c b/litex/build/sim/core/modules/serial2tcp/serial2tcp.c index 347c92eb8..82fe4fbab 100644 --- a/litex/build/sim/core/modules/serial2tcp/serial2tcp.c +++ b/litex/build/sim/core/modules/serial2tcp/serial2tcp.c @@ -97,9 +97,9 @@ void read_handler(int fd, short event, void *arg) struct session_s *s = (struct session_s*)arg; char buffer[1024]; ssize_t read_len; - + int i; - + read_len = read(fd, buffer, 1024); for(i = 0; i < read_len; i++) { @@ -118,10 +118,10 @@ static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, { struct session_s *s = (struct session_s*)ctx; struct timeval tv = {1, 0}; - + s->fd = fd; s->ev = event_new(base, fd, EV_READ | EV_PERSIST , event_handler, s); - event_add(s->ev, &tv); + event_add(s->ev, &tv); } static void @@ -159,7 +159,7 @@ static int serial2tcp_new(void **sess, char *args) fprintf(stderr, "Invalid port selected!\n"); goto out; } - + s=(struct session_s*)malloc(sizeof(struct session_s)); if(!s) { ret = RC_NOENMEM; @@ -177,8 +177,8 @@ static int serial2tcp_new(void **sess, char *args) eprintf("Can't bind port %d\n!\n", port); goto out; } - evconnlistener_set_error_cb(listener, accept_error_cb); - + evconnlistener_set_error_cb(listener, accept_error_cb); + out: *sess=(void*)s; return ret; @@ -202,19 +202,19 @@ static int serial2tcp_add_pads(void *sess, struct pad_list_s *plist) litex_sim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid); litex_sim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready); } - + if(!strcmp(plist->name, "sys_clk")) litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk); out: return ret; - + } static int serial2tcp_tick(void *sess) { char c; int ret = RC_OK; - + struct session_s *s = (struct session_s*)sess; if(*s->sys_clk == 0) return RC_OK; @@ -228,7 +228,7 @@ static int serial2tcp_tick(void *sess) goto out; } } - + *s->rx_valid=0; if(s->datalen) { *s->rx=s->databuf[s->data_start]; @@ -236,7 +236,7 @@ static int serial2tcp_tick(void *sess) s->datalen--; *s->rx_valid=1; } - + out: return ret; } diff --git a/litex/build/sim/core/pads.c b/litex/build/sim/core/pads.c index 225a34c3b..c40c3b119 100644 --- a/litex/build/sim/core/pads.c +++ b/litex/build/sim/core/pads.c @@ -17,7 +17,7 @@ int litex_sim_register_pads(struct pad_s *pads, char *interface_name, int index) { ret = RC_INVARG; eprintf("Invalid argument\n"); - goto out; + goto out; } pl = (struct pad_list_s *)malloc(sizeof(struct pad_list_s)); @@ -36,7 +36,7 @@ int litex_sim_register_pads(struct pad_s *pads, char *interface_name, int index) pl->next = padlist; padlist = pl; - + out: return ret; } @@ -45,7 +45,7 @@ int litex_sim_pads_get_list(struct pad_list_s **plist) { int ret=RC_OK; - + if(!plist) { ret = RC_INVARG; diff --git a/litex/build/sim/core/parse.c b/litex/build/sim/core/parse.c index 29d483d0d..6af8a198b 100644 --- a/litex/build/sim/core/parse.c +++ b/litex/build/sim/core/parse.c @@ -99,7 +99,7 @@ static int json_to_interface_list(json_object *interface, struct interface_s **i json_object *obj; json_object *name; json_object *index; - + struct interface_s *t_iface=NULL; if(!interface || !iface) @@ -108,7 +108,7 @@ static int json_to_interface_list(json_object *interface, struct interface_s **i eprintf("Invalid argument\n"); goto out; } - + if(!json_object_is_type(interface, json_type_array)) { ret=RC_JSERROR; @@ -166,7 +166,7 @@ out: static int module_list_free(struct module_s *mod) { - int ret=RC_OK; + int ret=RC_OK; struct module_s *mnext; int i; while(mod) @@ -247,7 +247,7 @@ static int json_to_module_list(json_object *obj, struct module_s **mod) tickfirst=NULL; json_object_object_get_ex(tobj, "tickfirst", &tickfirst); - + if(m) { @@ -275,7 +275,7 @@ static int json_to_module_list(json_object *obj, struct module_s **mod) goto out; } len = 0; - + while(m->iface[len++].name); m->niface= len-1; m->name = strdup(json_object_get_string(name)); diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index 7507264b8..a36b8af41 100644 --- a/litex/build/xilinx/common.py +++ b/litex/build/xilinx/common.py @@ -1,5 +1,5 @@ # This file is Copyright (c) 2014-2015 Sebastien Bourdeauducq -# This file is Copyright (c) 2014-2018 Florent Kermarrec +# This file is Copyright (c) 2014-2020 Florent Kermarrec # This file is Copyright (c) 2016-2018 Robert Jordens # This file is Copyright (c) 2015 William D. Jones # License: BSD @@ -127,6 +127,27 @@ class XilinxDifferentialOutput: def lower(dr): return XilinxDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n) +# Common SDRTristate ------------------------------------------------------------------------------- + +class XilinxSDRTristateImpl(Module): + def __init__(self, io, o, oe, i, clk): + _o = Signal() + _oe_n = Signal() + _i = Signal() + self.specials += SDROutput(o, _o) + self.specials += SDROutput(~oe, _oe_n) + self.specials += SDRInput(_i, i) + self.specials += Instance("IOBUF", + io_IO = io, + o_O = _i, + i_I = _o, + i_T = _oe_n, + ) + +class XilinxSDRTristate: + @staticmethod + def lower(dr): + return XilinxSDRTristateImpl(dr.io, dr.o, dr.oe, dr.i, dr.clk) # Common Special Overrides ------------------------------------------------------------------------- @@ -135,6 +156,7 @@ xilinx_special_overrides = { AsyncResetSynchronizer: XilinxAsyncResetSynchronizer, DifferentialInput: XilinxDifferentialInput, DifferentialOutput: XilinxDifferentialOutput, + SDRTristate: XilinxSDRTristate, } # Spartan6 DDROutput ------------------------------------------------------------------------------- @@ -201,28 +223,6 @@ class XilinxSDRInputS6: def lower(dr): return XilinxDDRInputImplS6(dr.i, dr.o, Signal(), dr.clk) -# Spartan6 SDRTristate ----------------------------------------------------------------------------- - -class XilinxSDRTristateImplS6(Module): - def __init__(self, io, o, oe, i, clk): - _o = Signal() - _oe_n = Signal() - _i = Signal() - self.specials += SDROutput(o, _o) - self.specials += SDROutput(~oe, _oe_n) - self.specials += SDRInput(_i, i) - self.specials += Instance("IOBUF", - io_IO = io, - o_O = _i, - i_I = _o, - i_T = _oe_n, - ) - -class XilinxSDRTristateS6: - @staticmethod - def lower(dr): - return XilinxSDRTristateImplS6(dr.io, dr.o, dr.oe, dr.i, dr.clk) - # Spartan6 Special Overrides ----------------------------------------------------------------------- xilinx_s6_special_overrides = { @@ -230,7 +230,6 @@ xilinx_s6_special_overrides = { DDRInput: XilinxDDRInputS6, SDROutput: XilinxSDROutputS6, SDRInput: XilinxSDRInputS6, - SDRTristate: XilinxSDRTristateS6, } # 7-Series DDROutput ------------------------------------------------------------------------------- @@ -275,11 +274,28 @@ class XilinxDDRInputS7: def lower(dr): return XilinxDDRInputImplS7(dr.i, dr.o1, dr.o2, dr.clk) +# 7-Series SDROutput ------------------------------------------------------------------------------- + +class XilinxSDROutputS7: + @staticmethod + def lower(dr): + return XilinxDDROutputImplS7(dr.i, dr.i, dr.o, dr.clk) + + +# 7-Series SDRInput -------------------------------------------------------------------------------- + +class XilinxSDRInputS7: + @staticmethod + def lower(dr): + return XilinxDDRInputImplS7(dr.i, dr.o, Signal(), dr.clk) + # 7-Series Special Overrides ----------------------------------------------------------------------- xilinx_s7_special_overrides = { DDROutput: XilinxDDROutputS7, - DDRInput: XilinxDDRInputS7 + DDRInput: XilinxDDRInputS7, + SDROutput: XilinxSDROutputS7, + SDRInput: XilinxSDRInputS7, } # Ultrascale DDROutput ----------------------------------------------------------------------------- @@ -322,11 +338,28 @@ class XilinxDDRInputUS: def lower(dr): return XilinxDDRInputImplUS(dr.i, dr.o1, dr.o2, dr.clk) +# Ultrascale SDROutput ----------------------------------------------------------------------------- + +class XilinxSDROutputUS: + @staticmethod + def lower(dr): + return XilinxDDROutputImplUS(dr.i, dr.i, dr.o, dr.clk) + + +# Ultrascale SDRInput ------------------------------------------------------------------------------ + +class XilinxSDRInputUS: + @staticmethod + def lower(dr): + return XilinxDDRInputImplUS(dr.i, dr.o, Signal(), dr.clk) + # Ultrascale Specials Overrides -------------------------------------------------------------------- xilinx_us_special_overrides = { DDROutput: XilinxDDROutputUS, - DDRInput: XilinxDDRInputUS + DDRInput: XilinxDDRInputUS, + SDROutput: XilinxSDROutputUS, + SDRInput: XilinxSDRInputUS, } # Yosys Run ---------------------------------------------------------------------------------------- diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index db9fdab7b..d0b11a50e 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -37,17 +37,19 @@ from litex.soc.cores.cpu.minerva import Minerva from litex.soc.cores.cpu.rocket import RocketRV64 from litex.soc.cores.cpu.microwatt import Microwatt from litex.soc.cores.cpu.blackparrot import BlackParrotRV64 +from litex.soc.cores.cpu.serv import SERV CPUS = { - "None" : CPUNone, - "lm32" : LM32, - "mor1kx" : MOR1KX, - "picorv32" : PicoRV32, - "vexriscv" : VexRiscv, - "minerva" : Minerva, - "rocket" : RocketRV64, - "microwatt" : Microwatt, + "None" : CPUNone, + "lm32" : LM32, + "mor1kx" : MOR1KX, + "picorv32" : PicoRV32, + "vexriscv" : VexRiscv, + "minerva" : Minerva, + "rocket" : RocketRV64, + "microwatt" : Microwatt, "blackparrot" : BlackParrotRV64, + "serv" : SERV } # CPU Variants/Extensions Definition --------------------------------------------------------------- diff --git a/litex/soc/cores/cpu/serv/__init__.py b/litex/soc/cores/cpu/serv/__init__.py new file mode 100644 index 000000000..b46284ac8 --- /dev/null +++ b/litex/soc/cores/cpu/serv/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.serv.core import SERV diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py new file mode 100644 index 000000000..4fb2f0a49 --- /dev/null +++ b/litex/soc/cores/cpu/serv/core.py @@ -0,0 +1,90 @@ +# This file is Copyright (c) 2020 Florent Kermarrec +# This file is Copyright (c) 2020 Greg Davill +# License: BSD + +import os + +from migen import * + +from litex.soc.interconnect import wishbone +from litex.soc.cores.cpu import CPU + + +CPU_VARIANTS = ["standard"] + + +class SERV(CPU): + name = "serv" + data_width = 32 + endianness = "little" + gcc_triple = ("riscv64-unknown-elf", "riscv32-unknown-elf", "riscv-none-embed", + "riscv64-linux", "riscv-sifive-elf", "riscv64-none-elf") + linker_output_format = "elf32-littleriscv" + io_regions = {0x80000000: 0x80000000} # origin, length + + @property + def gcc_flags(self): + flags = "-march=rv32i " + flags += "-mabi=ilp32 " + flags += "-D__serv__ " + return flags + + def __init__(self, platform, variant="standard"): + assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant + self.platform = platform + self.variant = variant + self.reset = Signal() + self.ibus = ibus = wishbone.Interface() + self.dbus = dbus = wishbone.Interface() + self.buses = [ibus, dbus] + + # # # + + self.cpu_params = dict( + # clock / reset + i_clk = ClockSignal(), + i_i_rst = ResetSignal() | self.reset, + + # timer irq + i_i_timer_irq = 0, + + # ibus + o_o_ibus_adr = Cat(Signal(2), ibus.adr), + o_o_ibus_cyc = ibus.cyc, + i_i_ibus_rdt = ibus.dat_r, + i_i_ibus_ack = ibus.ack, + + # dbus + o_o_dbus_adr = Cat(Signal(2), dbus.adr), + o_o_dbus_dat = dbus.dat_w, + o_o_dbus_sel = dbus.sel, + o_o_dbus_we = dbus.we, + o_o_dbus_cyc = dbus.cyc, + i_i_dbus_rdt = dbus.dat_r, + i_i_dbus_ack = dbus.ack, + ) + self.comb += [ + ibus.stb.eq(ibus.cyc), + ibus.sel.eq(0xf), + dbus.stb.eq(dbus.cyc), + ] + + # add verilog sources + self.add_sources(platform) + + def set_reset_address(self, reset_address): + assert not hasattr(self, "reset_address") + self.reset_address = reset_address + self.cpu_params.update(p_RESET_PC=reset_address) + + @staticmethod + def add_sources(platform): + # FIXME: add SERV as submodule + os.system("git clone https://github.com/olofk/serv") + vdir = os.path.join("serv", "rtl") + platform.add_source_dir(vdir) + platform.add_verilog_include_path(vdir) + + def do_finalize(self): + assert hasattr(self, "reset_address") + self.specials += Instance("serv_rf_top", **self.cpu_params) diff --git a/litex/soc/cores/emif.py b/litex/soc/cores/emif.py new file mode 100644 index 000000000..db7c48c81 --- /dev/null +++ b/litex/soc/cores/emif.py @@ -0,0 +1,150 @@ +# This file is Copyright (c) 2020 Florent Kermarrec +# License: BSD + +from migen import * +from migen.genlib.cdc import MultiReg + +from litex.soc.interconnect import wishbone + + +class EMIF(Module): + """External Memory Interface core + + Provides a simple EMIF to Wishbone Master bridge. + """ + def __init__(self, pads): + self.bus = bus = wishbone.Interface() + + # # # + + # Resynchronization ------------------------------------------------------------------------ + cs_n = Signal(reset=1) + oe_n = Signal(reset=1) + we_n = Signal(reset=1) + ba = Signal(2) + addr = Signal(22) + dqm_n = Signal(2) + data = self.add_tristate(pads.data) if not hasattr(pads.data, "oe") else pads.data + data_i = Signal(16) + self.specials += [ + MultiReg(pads.cs_n, cs_n), + MultiReg(pads.oe_n, oe_n), + MultiReg(pads.we_n, we_n), + MultiReg(pads.ba, ba), + MultiReg(pads.addr, addr), + MultiReg(data.i, data_i), + ] + + # EMIF <--> Wishbone ----------------------------------------------------------------------- + access = Signal() + we_n_d = Signal() + oe_n_d = Signal() + self.sync += [ + we_n_d.eq(we_n), + oe_n_d.eq(oe_n), + If(~we_n & we_n_d, + access.eq(1) + ).Elif(~oe_n & oe_n_d, + access.eq(1) + ).Elif(bus.ack, + access.eq(0) + ) + ] + self.comb += [ + bus.stb.eq(~cs_n & access), + bus.cyc.eq(~cs_n & access), + bus.we.eq(~we_n), + bus.adr.eq(addr), + data.oe.eq(~oe_n), + If(ba[1], + bus.dat_w[:16].eq(data_i), + bus.sel[:2].eq(~dqm_n) + ).Else( + bus.dat_w[16:].eq(data_i), + bus.sel[2:].eq(~dqm_n) + ) + ] + self.sync += [ + If(bus.ack, + If(ba[1], + data.o.eq(bus.dat_r[:16]) + ).Else( + data.o.eq(bus.dat_r[16:]) + ) + ) + ] + + def add_tristate(self, pad): + t = TSTriple(len(pad)) + self.specials += t.get_tristate(pad) + return t + + +class EMIF16To32Adapter(Module): + def __init__(self, emif): + self.bus = bus = wishbone.Interface() + + # # # + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + If(emif.bus.stb & emif.bus.cyc, + If(emif.bus.we, + NextState("WRITE0") + ).Else( + NextState("READ") + ) + ) + ) + emif_bus_dat_w = Signal(32) + fsm.act("WRITE0", + emif.bus.ack.eq(1), + If(emif.bus.sel[0], + NextValue(emif_bus_dat_w[8*0:8*1], emif.bus.dat_w[8*0:8*1]) + ), + If(emif.bus.sel[1], + NextValue(emif_bus_dat_w[8*1:8*2], emif.bus.dat_w[8*1:8*2]) + ), + If(emif.bus.sel[2], + NextValue(emif_bus_dat_w[8*2:8*3], emif.bus.dat_w[8*2:8*3]) + ), + If(emif.bus.sel[3], + NextValue(emif_bus_dat_w[8*3:8*4], emif.bus.dat_w[8*3:8*4]) + ), + NextState("WRITE1"), + ) + fsm.act("WRITE1", + bus.stb.eq(emif.bus.stb & emif.bus.cyc), + bus.we.eq(1), + bus.cyc.eq(emif.bus.stb & emif.bus.cyc), + bus.adr.eq(emif.bus.adr), + bus.sel.eq(0b1111), + bus.dat_w.eq(emif_bus_dat_w), + If(emif.bus.sel[0], + bus.dat_w[8*0:8*1].eq(emif.bus.dat_w[8*0:8*1]) + ), + If(emif.bus.sel[1], + bus.dat_w[8*1:8*2].eq(emif.bus.dat_w[8*1:8*2]) + ), + If(emif.bus.sel[2], + bus.dat_w[8*2:8*3].eq(emif.bus.dat_w[8*2:8*3]) + ), + If(emif.bus.sel[3], + bus.dat_w[8*3:8*4].eq(emif.bus.dat_w[8*3:8*4]) + ), + If(bus.stb & bus.ack, + emif.bus.ack.eq(1), + NextState("IDLE") + ) + ) + fsm.act("READ", + bus.stb.eq(1), + bus.we.eq(0), + bus.cyc.eq(1), + bus.adr.eq(emif.bus.adr), + If(bus.ack, + emif.bus.ack.eq(1), + emif.bus.dat_r.eq(bus.dat_r), + NextState("IDLE") + ) + ) diff --git a/litex/soc/cores/spi.py b/litex/soc/cores/spi.py index 8cf7ceb50..fe09f5e9e 100644 --- a/litex/soc/cores/spi.py +++ b/litex/soc/cores/spi.py @@ -17,7 +17,8 @@ class SPIMaster(Module, AutoCSR): configurable data_width and frequency. """ pads_layout = [("clk", 1), ("cs_n", 1), ("mosi", 1), ("miso", 1)] - def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True): + def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True, mode="raw"): + assert mode in ["raw", "aligned"] if pads is None: pads = Record(self.pads_layout) if not hasattr(pads, "cs_n"): @@ -96,32 +97,35 @@ class SPIMaster(Module, AutoCSR): for i in range(len(pads.cs_n)): self.comb += pads.cs_n[i].eq(~self.cs[i] | ~xfer) - # Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) --------------- - mosi_data = Signal(data_width) - self.sync += \ + # Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ---------------- + mosi_data = Array(self.mosi[i] for i in range(data_width)) + mosi_bit = Signal(max=data_width) + self.sync += [ If(self.start, - mosi_data.eq(self.mosi) + mosi_bit.eq(self.length - 1 if mode == "aligned" else data_width - 1), ).Elif(clk_rise & shift, - mosi_data.eq(Cat(Signal(), mosi_data[:-1])) - ).Elif(clk_fall, - pads.mosi.eq(mosi_data[-1]) + mosi_bit.eq(mosi_bit - 1) + ), + If(clk_fall, + pads.mosi.eq(mosi_data[mosi_bit]) ) + ] # Master In Slave Out (MISO) capture (captured on spi_clk rising edge) -------------------- miso = Signal() miso_data = self.miso - self.sync += \ - If(shift, - If(clk_rise, - If(self.loopback, - miso.eq(pads.mosi) - ).Else( - miso.eq(pads.miso) - ) - ).Elif(clk_fall, - miso_data.eq(Cat(miso, miso_data[:-1])) + self.sync += [ + If(clk_rise & shift, + If(self.loopback, + miso.eq(pads.mosi) + ).Else( + miso.eq(pads.miso) ) + ), + If(clk_fall & shift, + miso_data.eq(Cat(miso, miso_data)) ) + ] def add_csr(self): self._control = CSRStorage(fields=[ diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b06abdef7..dcea829aa 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -723,7 +723,7 @@ class SoC(Module): raise self.constants[name] = SoCConstant(value) - def add_config(self, name, value): + def add_config(self, name, value=None): name = "CONFIG_" + name if isinstance(value, str): self.add_constant(name + "_" + value) @@ -784,8 +784,10 @@ class SoC(Module): for n, cpu_bus in enumerate(self.cpu.buses): self.bus.add_master(name="cpu_bus{}".format(n), master=cpu_bus) self.csr.add("cpu", use_loc_if_exists=True) - for name, loc in self.cpu.interrupts.items(): - self.irq.add(name, loc) + if hasattr(self.cpu, "interrupt"): + for name, loc in self.cpu.interrupts.items(): + self.irq.add(name, loc) + self.add_config("CPU_HAS_INTERRUPT") if hasattr(self, "ctrl"): self.comb += self.cpu.reset.eq(self.ctrl.reset) self.add_config("CPU_RESET_ADDR", reset_address) @@ -797,7 +799,8 @@ class SoC(Module): self.check_if_exists(name) setattr(self.submodules, name, Timer()) self.csr.add(name, use_loc_if_exists=True) - self.irq.add(name, use_loc_if_exists=True) + if hasattr(self.cpu, "interrupt"): + self.irq.add(name, use_loc_if_exists=True) # SoC finalization ----------------------------------------------------------------------------- def do_finalize(self): @@ -974,7 +977,10 @@ class LiteXSoC(SoC): 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) + if hasattr(self.cpu, "interrupt"): + self.irq.add("uart", use_loc_if_exists=True) + else: + self.add_constant("UART_POLLING") # Add SDRAM ------------------------------------------------------------------------------------ def add_sdram(self, name, phy, module, origin, size=None, diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index b1209a00d..3eb0016c7 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -244,6 +244,8 @@ class SoCCore(LiteXSoC): for region in self.bus.regions.values(): region.length = region.size region.type = "cached" if region.cached else "io" + if region.linker: + region.type += "+linker" self.csr_regions = self.csr.regions for name, value in self.config.items(): self.add_config(name, value) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 4558ac8c9..f70393aa3 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -228,7 +228,7 @@ class SyncFIFO(_FIFOWrapper): class AsyncFIFO(_FIFOWrapper): - def __init__(self, layout, depth, buffered=False): + def __init__(self, layout, depth=4, buffered=False): assert depth >= 4 _FIFOWrapper.__init__(self, fifo_class = fifo.AsyncFIFOBuffered if buffered else fifo.AsyncFIFO, diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index 66be372c7..12510a712 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -13,6 +13,7 @@ endif OBJECTS=isr.o sdram.o sdcard.o main.o boot-helper-$(CPU).o boot.o all: bios.bin + $(PYTHON) -m litex.soc.software.memusage bios.elf $(CURDIR)/../include/generated/regions.ld $(TRIPLE) %.bin: %.elf $(OBJCOPY) -O binary $< $@ diff --git a/litex/soc/software/bios/boot-helper-serv.S b/litex/soc/software/bios/boot-helper-serv.S new file mode 100644 index 000000000..e8bd5c760 --- /dev/null +++ b/litex/soc/software/bios/boot-helper-serv.S @@ -0,0 +1,4 @@ + .section .text, "ax", @progbits + .global boot_helper +boot_helper: + jr x13 diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index c6c8b9583..08b3be4a8 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -18,6 +18,7 @@ #include #include +#include #ifdef CSR_ETHMAC_BASE #include @@ -38,8 +39,10 @@ static void __attribute__((noreturn)) boot(unsigned long r1, unsigned long r2, u printf("Executing booted program at 0x%08x\n\n", addr); printf("--============= \e[1mLiftoff!\e[0m ===============--\n"); uart_sync(); +#ifdef CONFIG_CPU_HAS_INTERRUPT irq_setmask(0); irq_setie(0); +#endif /* FIXME: understand why flushing icache on Vexriscv make boot fail */ #ifndef __vexriscv__ flush_cpu_icache(); diff --git a/litex/soc/software/bios/isr.c b/litex/soc/software/bios/isr.c index 971bd37b6..0044f3d16 100644 --- a/litex/soc/software/bios/isr.c +++ b/litex/soc/software/bios/isr.c @@ -4,14 +4,16 @@ #include +#include #include #include #include - -#if defined(__blackparrot__) /*TODO: Update this function for BP*/ // - void isr(void); + +#ifdef CONFIG_CPU_HAS_INTERRUPT + +#if defined(__blackparrot__) /*TODO: Update this function for BP*/ // void isr(void) { static int onetime = 0; @@ -21,7 +23,7 @@ void isr(void) onetime++; } } -#elif defined(__rocket__) +#elif defined(__rocket__) void plic_init(void); void plic_init(void) { @@ -36,7 +38,6 @@ void plic_init(void) *((unsigned int *)PLIC_THRSHLD) = 0; } -void isr(void); void isr(void) { unsigned int claim; @@ -62,10 +63,9 @@ void isr(void) } } #else -void isr(void); void isr(void) { - unsigned int irqs; + __attribute__((unused)) unsigned int irqs; irqs = irq_pending() & irq_getmask(); @@ -75,3 +75,9 @@ void isr(void) #endif } #endif + +#else + +void isr(void){}; + +#endif diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index dff353586..b6501edbb 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -394,6 +394,7 @@ static void help(void) puts("sdram_cal - run SDRAM calibration"); puts("sdram_mpr - read SDRAM MPR"); puts("sdram_mrwr reg value - write SDRAM mode registers"); + puts("sdram_cdly_scan enabled - enable/disable cdly scan"); #endif #ifdef CSR_SPISDCARD_BASE puts("spisdcardboot - boot from SDCard via SPI hardware bitbang"); @@ -475,7 +476,7 @@ static void do_command(char *c) else if(strcmp(token, "sdrwr") == 0) sdrwr(get_token(&c)); #ifdef CSR_DDRPHY_BASE else if(strcmp(token, "sdrinit") == 0) sdrinit(); -#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR +#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE else if(strcmp(token, "sdrwlon") == 0) sdrwlon(); else if(strcmp(token, "sdrwloff") == 0) sdrwloff(); #endif @@ -506,6 +507,11 @@ static void do_command(char *c) sdrmrwr(reg, value); sdrhw(); } + else if(strcmp(token, "sdram_cdly_scan") == 0) { + unsigned int enabled; + enabled = atoi(get_token(&c)); + sdr_cdly_scan(enabled); + } #endif #ifdef CSR_SPISDCARD_BASE else if(strcmp(token, "spisdcardboot") == 0) spisdcardboot(); @@ -610,9 +616,10 @@ int main(int i, char **c) { char buffer[64]; int sdr_ok; - +#ifdef CONFIG_CPU_HAS_INTERRUPT irq_setmask(0); irq_setie(1); +#endif uart_init(); printf("\n"); @@ -647,6 +654,8 @@ int main(int i, char **c) printf("RocketRV64[imac]"); #elif __blackparrot__ printf("BlackParrotRV64[ia]"); +#elif __serv__ + printf("SERV"); #else printf("Unknown"); #endif diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index c0fec2544..8d8ddfefe 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -1,5 +1,5 @@ // This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq -// This file is Copyright (c) 2013-2019 Florent Kermarrec +// This file is Copyright (c) 2013-2020 Florent Kermarrec // This file is Copyright (c) 2018 Chris Ballance // This file is Copyright (c) 2018 Dolu1990 // This file is Copyright (c) 2019 Gabriel L. Somlo @@ -48,6 +48,8 @@ __attribute__((unused)) static void cdelay(int i) __asm__ volatile("nop"); #elif defined (__blackparrot__) __asm__ volatile("nop"); +#elif defined (__serv__) + __asm__ volatile("nop"); #else #error Unsupported architecture #endif @@ -114,7 +116,7 @@ void sdrrdbuf(int dq) step = DFII_PIX_DATA_BYTES/2; } - for(p=0;p 32 + show_iter = (j%16 == 0) && show; #endif - for (k=0; k<128; k++) { + for (k=0; k 0 && one_window_best_start > 0) { + delays[i] = one_window_best_start; - /* configure write delay */ - write_delay_rst(i); - for(j=0; j=0;i--) { + for(i=SDRAM_PHY_MODULES-1;i>=0;i--) { if(delays[i] < 0) ok = 0; } @@ -428,7 +417,110 @@ int write_level(void) return ok; } -#endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */ +static void write_level_cdly_range(unsigned int *best_error, int *best_cdly, + int cdly_start, int cdly_stop, int cdly_step) +{ + int cdly; + int cdly_actual = 0; + int delays[SDRAM_PHY_MODULES]; + + /* scan through the range */ + ddrphy_cdly_rst_write(1); + for (cdly = cdly_start; cdly < cdly_stop; cdly += cdly_step) { + /* increment cdly to current value */ + while (cdly_actual < cdly) { + ddrphy_cdly_inc_write(1); + cdelay(10); + cdly_actual++; + } + + /* write level using this delay */ + if (write_level_scan(delays, 8, 0)) { + /* use the mean of delays for error calulation */ + int delay_mean = 0; + for (int i=0; i < SDRAM_PHY_MODULES; ++i) { + delay_mean += delays[i]; + } + delay_mean /= SDRAM_PHY_MODULES; + + /* we want it to be at the start */ + int ideal_delay = 4*SDRAM_PHY_DELAYS/32; + int error = ideal_delay - delay_mean; + if (error < 0) + error *= -1; + + if (error < *best_error) { + *best_cdly = cdly; + *best_error = error; + } + printf("1"); + } else { + printf("0"); + } + } +} + +int write_level(void) +{ + int delays[SDRAM_PHY_MODULES]; + unsigned int best_error = ~0u; + int best_cdly = -1; + int cdly_range_start; + int cdly_range_end; + int cdly_range_step; + + printf("Command/Clk scan:\n"); + + /* Center write leveling by varying cdly. Searching through all possible + * values is slow, but we can use a simple optimization method of iterativly + * scanning smaller ranges with decreasing step */ + cdly_range_start = 0; + cdly_range_end = SDRAM_PHY_DELAYS; + if (SDRAM_PHY_DELAYS > 32) + cdly_range_step = SDRAM_PHY_DELAYS/8; + else + cdly_range_step = 1; + while (cdly_range_step > 0) { + printf("|"); + write_level_cdly_range(&best_error, &best_cdly, + cdly_range_start, cdly_range_end, cdly_range_step); + + /* small optimization - stop if we have zero error */ + if (best_error == 0) + break; + + /* use best result as the middle of next range */ + cdly_range_start = best_cdly - cdly_range_step; + cdly_range_end = best_cdly + cdly_range_step + 1; + if (cdly_range_start < 0) + cdly_range_start = 0; + if (cdly_range_end > 512) + cdly_range_end = 512; + + cdly_range_step /= 4; + } + printf("| best: %d\n", best_cdly); + + /* if we found any working delay then set it */ + if (best_cdly >= 0) { + ddrphy_cdly_rst_write(1); + for (int i = 0; i < best_cdly; ++i) { + ddrphy_cdly_inc_write(1); + cdelay(10); + } + } + + printf("Data scan:\n"); + + /* re-run write leveling the final time */ + if (!write_level_scan(delays, 128, 1)) + return 0; + + return best_cdly >= 0; +} + + +#endif /* SDRAM_PHY_WRITE_LEVELING_CAPABLE */ static void read_delay_rst(int module) { /* sel module */ @@ -440,7 +532,7 @@ static void read_delay_rst(int module) { /* unsel module */ ddrphy_dly_sel_write(0); -#ifdef ECP5DDRPHY +#ifdef SDRAM_PHY_ECP5DDRPHY /* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */ ddrphy_dly_sel_write(0xFF); ddrphy_dly_sel_write(0); @@ -457,7 +549,7 @@ static void read_delay_inc(int module) { /* unsel module */ ddrphy_dly_sel_write(0); -#ifdef ECP5DDRPHY +#ifdef SDRAM_PHY_ECP5DDRPHY /* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */ ddrphy_dly_sel_write(0xFF); ddrphy_dly_sel_write(0); @@ -492,14 +584,14 @@ static void read_bitslip_inc(char m) static int read_level_scan(int module, int bitslip) { unsigned int prv; - unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES]; + unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES]; unsigned char tst[DFII_PIX_DATA_BYTES]; int p, i; int score; /* Generate pseudo-random sequence */ prv = 42; - for(p=0;p 32 show = (i%16 == 0); #endif -#ifdef ECP5DDRPHY +#ifdef SDRAM_PHY_ECP5DDRPHY ddrphy_burstdet_clr_write(1); #endif command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); cdelay(15); - for(p=0;p> module) & 0x1) != 1) working = 0; #endif @@ -569,7 +661,7 @@ static int read_level_scan(int module, int bitslip) static void read_level(int module) { unsigned int prv; - unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES]; + unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES]; unsigned char tst[DFII_PIX_DATA_BYTES]; int p, i; int working; @@ -579,7 +671,7 @@ static void read_level(int module) /* Generate pseudo-random sequence */ prv = 42; - for(p=0;p> module) & 0x1) != 1) working = 0; #endif if(working) break; delay++; - if(delay >= ERR_DDRPHY_DELAY) + if(delay >= SDRAM_PHY_DELAYS) break; read_delay_inc(module); } delay_min = delay; /* Get a bit further into the working zone */ -#ifdef USDDRPHY +#if SDRAM_PHY_DELAYS > 32 for(i=0;i<16;i++) { delay += 1; read_delay_inc(module); @@ -648,35 +740,35 @@ static void read_level(int module) /* Find largest working delay */ while(1) { -#ifdef ECP5DDRPHY +#ifdef SDRAM_PHY_ECP5DDRPHY ddrphy_burstdet_clr_write(1); #endif command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); cdelay(15); working = 1; - for(p=0;p> module) & 0x1) != 1) working = 0; #endif if(!working) break; delay++; - if(delay >= ERR_DDRPHY_DELAY) + if(delay >= SDRAM_PHY_DELAYS) break; read_delay_inc(module); } delay_max = delay; - if (delay_min >= ERR_DDRPHY_DELAY) + if (delay_min >= SDRAM_PHY_DELAYS) printf("-"); else printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2); @@ -919,8 +1011,9 @@ int memtest(void) #ifdef CSR_SDRAM_BASE -#ifdef CSR_DDRPHY_BASE -int sdrlevel(void) +#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE) + +static void read_leveling(void) { int module; int bitslip; @@ -928,27 +1021,11 @@ int sdrlevel(void) int best_score; int best_bitslip; - sdrsw(); - - for(module=0; module #include +#include + +#ifdef CONFIG_CPU_HAS_INTERRUPT #ifdef __picorv32__ // PicoRV32 has a very limited interrupt support, implemented via custom @@ -71,10 +74,8 @@ static inline unsigned int irq_getie(void) return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; #elif defined (__rocket__) return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; -#elif defined (__microwatt__) - return 0; // FIXME -#elif defined (__blackparrot__) - return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;//TODO +#elif defined (__blackparrot__) + return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; /* FIXME */ #else #error Unsupported architecture #endif @@ -100,10 +101,8 @@ static inline void irq_setie(unsigned int ie) if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); #elif defined (__rocket__) if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); -#elif defined (__microwatt__) - // FIXME #elif defined (__blackparrot__) - if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);//TODO:BP + if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); /* FIXME */ #else #error Unsupported architecture #endif @@ -131,10 +130,8 @@ static inline unsigned int irq_getmask(void) return mask; #elif defined (__rocket__) return *((unsigned int *)PLIC_ENABLED) >> 1; -#elif defined (__microwatt__) - return 0; // FIXME #elif defined (__blackparrot__) - //TODO:BP + return 0; /* FIXME */ #else #error Unsupported architecture #endif @@ -156,10 +153,8 @@ static inline void irq_setmask(unsigned int mask) asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask)); #elif defined (__rocket__) *((unsigned int *)PLIC_ENABLED) = mask << 1; -#elif defined (__microwatt__) - // FIXME #elif defined (__blackparrot__) - //TODO:BP + /* FIXME */ #else #error Unsupported architecture #endif @@ -185,10 +180,8 @@ static inline unsigned int irq_pending(void) return pending; #elif defined (__rocket__) return *((unsigned int *)PLIC_PENDING) >> 1; -#elif defined (__microwatt__) - return 0; // FIXME #elif defined (__blackparrot__) - return csr_readl(PLIC_PENDING) >> 1;//TODO:BP + return csr_readl(PLIC_PENDING) >> 1; /* FIXME */ #else #error Unsupported architecture #endif @@ -198,4 +191,6 @@ static inline unsigned int irq_pending(void) } #endif +#endif + #endif /* __IRQ_H */ diff --git a/litex/soc/software/libbase/crt0-serv.S b/litex/soc/software/libbase/crt0-serv.S new file mode 100644 index 000000000..6f6e9e6c0 --- /dev/null +++ b/litex/soc/software/libbase/crt0-serv.S @@ -0,0 +1,63 @@ +#define MIE_MEIE 0x800 + + .global _start +_start: + j reset_vector + +reset_vector: + la sp, _fstack + la t0, trap_vector + csrw mtvec, t0 + + // initialize .bss + la t0, _fbss + la t1, _ebss +1: beq t0, t1, 2f + sw zero, 0(t0) + addi t0, t0, 4 + j 1b +2: + // enable external interrupts + li t0, MIE_MEIE + csrs mie, t0 + + call main +1: j 1b + +trap_vector: + addi sp, sp, -16*4 + sw ra, 0*4(sp) + sw t0, 1*4(sp) + sw t1, 2*4(sp) + sw t2, 3*4(sp) + sw a0, 4*4(sp) + sw a1, 5*4(sp) + sw a2, 6*4(sp) + sw a3, 7*4(sp) + sw a4, 8*4(sp) + sw a5, 9*4(sp) + sw a6, 10*4(sp) + sw a7, 11*4(sp) + sw t3, 12*4(sp) + sw t4, 13*4(sp) + sw t5, 14*4(sp) + sw t6, 15*4(sp) + call isr + lw ra, 0*4(sp) + lw t0, 1*4(sp) + lw t1, 2*4(sp) + lw t2, 3*4(sp) + lw a0, 4*4(sp) + lw a1, 5*4(sp) + lw a2, 6*4(sp) + lw a3, 7*4(sp) + lw a4, 8*4(sp) + lw a5, 9*4(sp) + lw a6, 10*4(sp) + lw a7, 11*4(sp) + lw t3, 12*4(sp) + lw t4, 13*4(sp) + lw t5, 14*4(sp) + lw t6, 15*4(sp) + addi sp, sp, 16*4 + mret diff --git a/litex/soc/software/libbase/system.c b/litex/soc/software/libbase/system.c index e8b3e5055..49d23ac6d 100644 --- a/litex/soc/software/libbase/system.c +++ b/litex/soc/software/libbase/system.c @@ -62,6 +62,8 @@ void flush_cpu_icache(void) #elif defined (__blackparrot__) /* TODO: BP do something useful here! */ asm volatile("nop"); +#elif defined (__serv__) + /* no instruction cache */ #else #error Unsupported architecture #endif @@ -114,6 +116,8 @@ void flush_cpu_dcache(void) #elif defined (__blackparrot__) /* FIXME: do something useful here! */ asm volatile("nop"); +#elif defined (__serv__) + /* no data cache */ #else #error Unsupported architecture #endif diff --git a/litex/soc/software/memusage.py b/litex/soc/software/memusage.py new file mode 100644 index 000000000..3c4dc70a8 --- /dev/null +++ b/litex/soc/software/memusage.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +# This file is Copyright (c) 2020 Franck Jullien +# License: BSD + +import subprocess +import argparse + +def print_usage(bios,regions, triple): + rom_usage = 0 + ram_usage = 0 + + readelf = triple + "-readelf" + + result = subprocess.run([readelf, '-e', '-W', bios], stdout=subprocess.PIPE) + result = result.stdout.decode('utf-8') + result = result.split('\n') + + with open(regions, "r") as regfile: + for line in regfile: + if line == 0: + break + if 'rom' in line: + rom_size = int(line.split(' ')[-1], 16) + if 'sram' in line: + ram_size = int(line.split(' ')[-1], 16) + + for line in result: + if '.text' in line: + if 'PROGBITS' in line: + tokens = list(filter(None,line.split(' '))) + rom_usage += int(tokens[6], 16) + if '.rodata' in line: + if 'PROGBITS' in line: + tokens = list(filter(None,line.split(' '))) + rom_usage += int(tokens[6], 16) + if '.data' in line: + if 'PROGBITS' in line: + tokens = list(filter(None,line.split(' '))) + rom_usage += int(tokens[6], 16) + if '.commands' in line: + if 'PROGBITS' in line: + tokens = list(filter(None,line.split(' '))) + rom_usage += int(tokens[6], 16) + if '.bss' in line: + if 'NOBITS' in line: + tokens = list(filter(None,line.split(' '))) + ram_usage += int(tokens[6], 16) + + print("\nROM usage: {:.2f}KiB \t({:.2f}%)".format(rom_usage / 1024.0, rom_usage / rom_size * 100.0)) + print("RAM usage: {:.2f}KiB \t({:.2f}%)\n".format(ram_usage / 1024.0, ram_usage / ram_size * 100.0)) + +def main(): + parser = argparse.ArgumentParser(description="Print bios memory usage") + parser.add_argument("input", help="input file") + parser.add_argument("regions", help="regions definitions") + parser.add_argument("triple", help="toolchain triple") + args = parser.parse_args() + print_usage(args.input, args.regions, args.triple) + + +if __name__ == "__main__": + main() diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 1efea94d3..987681d33 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -141,6 +141,7 @@ def get_sdram_phy_settings(memtype, data_width, clk_freq): } return PhySettings( + phytype = "SDRAMPHYModel", memtype = memtype, databits = data_width, dfi_databits = data_width if memtype == "SDR" else 2*data_width, @@ -165,6 +166,7 @@ class SimSoC(SoCSDRAM): sdram_module = "MT48LC16M16", sdram_init = [], sdram_data_width = 32, + sdram_spd_data = None, sdram_verbosity = 0, **kwargs): platform = Platform() @@ -181,9 +183,12 @@ class SimSoC(SoCSDRAM): # SDRAM ------------------------------------------------------------------------------------ if with_sdram: sdram_clk_freq = int(100e6) # FIXME: use 100MHz timings - sdram_module_cls = getattr(litedram_modules, sdram_module) - sdram_rate = "1:{}".format(sdram_module_nphases[sdram_module_cls.memtype]) - sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate) + if sdram_spd_data is None: + sdram_module_cls = getattr(litedram_modules, sdram_module) + sdram_rate = "1:{}".format(sdram_module_nphases[sdram_module_cls.memtype]) + sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate) + else: + sdram_module = litedram_modules.SDRAMModule.from_spd_data(sdram_spd_data, sdram_clk_freq) phy_settings = get_sdram_phy_settings( memtype = sdram_module.memtype, data_width = sdram_data_width, @@ -265,10 +270,19 @@ class SimSoC(SoCSDRAM): # Analyzer --------------------------------------------------------------------------------- if with_analyzer: analyzer_signals = [ - self.cpu.ibus, - self.cpu.dbus + self.cpu.ibus.stb, + self.cpu.ibus.cyc, + self.cpu.ibus.adr, + self.cpu.ibus.we, + self.cpu.ibus.ack, + self.cpu.ibus.sel, + self.cpu.ibus.dat_w, + self.cpu.ibus.dat_r, ] - self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 512) + self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, + depth = 512, + clock_domain = "sys", + csr_csv = "analyzer.csv") self.add_csr("analyzer") # Build -------------------------------------------------------------------------------------------- @@ -284,6 +298,7 @@ def main(): parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip") parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width") parser.add_argument("--sdram-init", default=None, help="SDRAM init file") + parser.add_argument("--sdram-from-spd-data", default=None, help="Generate SDRAM module based on SPD data from file") parser.add_argument("--sdram-verbosity", default=0, help="Set SDRAM checker verbosity") parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support") parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") @@ -322,6 +337,9 @@ def main(): soc_kwargs["sdram_module"] = args.sdram_module soc_kwargs["sdram_data_width"] = int(args.sdram_data_width) soc_kwargs["sdram_verbosity"] = int(args.sdram_verbosity) + if args.sdram_from_spd_data: + with open(args.sdram_from_spd_data, "rb") as f: + soc_kwargs["sdram_spd_data"] = [int(b) for b in f.read()] if args.with_ethernet or args.with_etherbone: sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip}) diff --git a/litex/tools/remote/etherbone.py b/litex/tools/remote/etherbone.py index ec63645f2..43af3dc3b 100644 --- a/litex/tools/remote/etherbone.py +++ b/litex/tools/remote/etherbone.py @@ -5,7 +5,7 @@ import math import struct -from litex.soc.interconnect.stream_packet import HeaderField, Header +from litex.soc.interconnect.packet import HeaderField, Header etherbone_magic = 0x4e6f diff --git a/litex_setup.py b/litex_setup.py index 82259f1a1..9e5a085df 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -97,14 +97,15 @@ if len(sys.argv) < 2: if "init" in sys.argv[1:]: os.chdir(os.path.join(current_path)) for name in repos.keys(): - url, need_recursive, need_develop = repos[name] - # clone repo (recursive if needed) - print("[cloning " + name + "]...") - full_url = url + name - opts = "--recursive" if need_recursive else "" - subprocess.check_call( - "git clone " + full_url + " " + opts, - shell=True) + if not os.path.exists(name): + url, need_recursive, need_develop = repos[name] + # clone repo (recursive if needed) + print("[cloning " + name + "]...") + full_url = url + name + opts = "--recursive" if need_recursive else "" + subprocess.check_call( + "git clone " + full_url + " " + opts, + shell=True) # Repositories installation if "install" in sys.argv[1:]: @@ -132,6 +133,8 @@ if "install" in sys.argv[1:]: # Repositories update if "update" in sys.argv[1:]: for name in repos.keys(): + if not os.path.exists(name): + raise Exception("{} not initialized, please (re)-run init and install first.".format(name)) # update print("[updating " + name + "]...") os.chdir(os.path.join(current_path, name)) diff --git a/setup.py b/setup.py index 496c65d64..7429e9203 100755 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ setup( install_requires=[ "migen", "pyserial", + "requests", "pythondata-software-compiler_rt", ], packages=find_packages(exclude=("test*", "sim*", "doc*")), diff --git a/test/test_emif.py b/test/test_emif.py new file mode 100644 index 000000000..c7793f4a2 --- /dev/null +++ b/test/test_emif.py @@ -0,0 +1,91 @@ +# This file is Copyright (c) 2020 Florent Kermarrec +# License: BSD + +import unittest + +from migen import * + +from litex.soc.interconnect import wishbone + +from litex.soc.cores.emif import EMIF + + +class EMIFPads: + def __init__(self): + self.cs_n = Signal(reset=1) + self.we_n = Signal(reset=1) + self.oe_n = Signal(reset=1) + self.wait_n = Signal(reset=1) + self.ba = Signal(2) + self.addr = Signal(22) + self.dqm_n = Signal(2) + self.data = Record([("oe", 1), ("o", 16), ("i", 16)]) + + +def emif_write(pads, addr, data, release_cs=True): + for i in range(2): + yield pads.cs_n.eq(0) + yield pads.we_n.eq(1) + yield pads.oe_n.eq(1) + yield pads.ba.eq(1<> 16*i) & 0xffff) + yield + yield pads.we_n.eq(0) + for i in range(8): + yield + yield pads.we_n.eq(1) + yield + yield pads.cs_n.eq(release_cs) + yield + + +def emif_read(pads, addr, release_cs=True, release_oe=True): + data = 0 + for i in range(2): + yield pads.cs_n.eq(0) + yield pads.we_n.eq(1) + yield pads.oe_n.eq(release_oe) + yield pads.ba.eq(1<>= 16 + data |= (yield pads.data.o) << 16 + yield pads.oe_n.eq(release_oe) + yield + yield pads.cs_n.eq(release_cs) + yield + return data + + +class TestEMIF(unittest.TestCase): + def test_emif(self): + pads = EMIFPads() + def generator(dut): + # Test writes/reads with cs release between accesses + yield from emif_write(pads, 0, 0xdeadbeef, True) + yield from emif_write(pads, 1, 0x12345678, True) + yield from emif_write(pads, 2, 0x5aa55aa5, True) + self.assertEqual((yield from emif_read(pads, 0, True)), 0xdeadbeef) + self.assertEqual((yield from emif_read(pads, 1, True)), 0x12345678) + self.assertEqual((yield from emif_read(pads, 2, True)), 0x5aa55aa5) + + # Test writes/reads without cs release between accesses + yield from emif_write(pads, 0, 0xdeadbeef, False) + yield from emif_write(pads, 1, 0x12345678, False) + yield from emif_write(pads, 2, 0x5aa55aa5, False) + self.assertEqual((yield from emif_read(pads, 0, False)), 0xdeadbeef) + self.assertEqual((yield from emif_read(pads, 1, False)), 0x12345678) + self.assertEqual((yield from emif_read(pads, 2, False)), 0x5aa55aa5) + + class DUT(Module): + def __init__(self, pads): + emif = EMIF(pads) + self.submodules += emif + mem = wishbone.SRAM(16, bus=emif.bus) + self.submodules += mem + dut = DUT(pads) + run_simulation(dut, [generator(dut)]) diff --git a/test/test_spi.py b/test/test_spi.py index 1cfffd57e..92d1ad827 100644 --- a/test/test_spi.py +++ b/test/test_spi.py @@ -13,7 +13,7 @@ class TestSPI(unittest.TestCase): spi_master = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6) self.assertEqual(hasattr(spi_master, "pads"), 1) - def test_spi_master_xfer_loopback(self): + def test_spi_master_xfer_loopback_32b_32b(self): def generator(dut): yield dut.loopback.eq(1) yield dut.mosi.eq(0xdeadbeef) @@ -29,6 +29,22 @@ class TestSPI(unittest.TestCase): dut = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6, with_csr=False) run_simulation(dut, generator(dut)) + def test_spi_master_xfer_loopback_32b_16b(self): + def generator(dut): + yield dut.loopback.eq(1) + yield dut.mosi.eq(0xbeef) + yield dut.length.eq(16) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + yield + while (yield dut.done) == 0: + yield + self.assertEqual((yield dut.miso), 0xbeef) + + dut = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6, with_csr=False, mode="aligned") + run_simulation(dut, generator(dut)) + def test_spi_slave_syntax(self): spi_slave = SPISlave(pads=None, data_width=32) self.assertEqual(hasattr(spi_slave, "pads"), 1)