From f4b345ecd78bebb21f73353923bf35844c0f9acd Mon Sep 17 00:00:00 2001 From: Rangel Ivanov Date: Sun, 12 Apr 2020 11:46:44 +0300 Subject: [PATCH 01/44] build/lattice/trellis.py: Add 12k device nextpnr adds the --12k option which is the same like the --25k but with the correct idcode for the 12k devices Signed-off-by: Rangel Ivanov --- litex/build/lattice/trellis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 154e751dd..a9ae49be4 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -97,6 +97,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", From c57e438df6e6f932df4228bf5df669897fd67ec7 Mon Sep 17 00:00:00 2001 From: Rangel Ivanov Date: Sun, 12 Apr 2020 11:51:08 +0300 Subject: [PATCH 02/44] boards/targets/ulx3s.py: Update --device option help message Signed-off-by: Rangel Ivanov --- litex/boards/targets/ulx3s.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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", From 4fe31f0760ca98994d4b8c9b867cfff686412c7d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 12 Apr 2020 16:34:33 +0200 Subject: [PATCH 03/44] cores: add External Memory Interface (EMIF) Wishbone bridge. Useful to interface Processors/DSPs with LiteX. EMIF is generally used on Texas Instrument DSPs. --- litex/soc/cores/emif.py | 150 ++++++++++++++++++++++++++++++++++++++++ test/test_emif.py | 91 ++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 litex/soc/cores/emif.py create mode 100644 test/test_emif.py 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/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)]) From 97d0c525ee239be435a0a19be4155405595b3b7d Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Sun, 12 Apr 2020 10:29:13 -0700 Subject: [PATCH 04/44] Remove trailing whitespace. --- litex/build/sim/core/modules.c | 4 ++-- .../build/sim/core/modules/clocker/clocker.c | 4 ++-- .../sim/core/modules/serial2tcp/serial2tcp.c | 24 +++++++++---------- litex/build/sim/core/pads.c | 6 ++--- litex/build/sim/core/parse.c | 10 ++++---- 5 files changed, 24 insertions(+), 24 deletions(-) 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)); From a8bf02167aa26934aa64605c6f12bc7142cd2313 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 12 Apr 2020 19:46:56 +0200 Subject: [PATCH 05/44] litex_setup: raise exception on update if repository has been been initialized. --- litex_setup.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/litex_setup.py b/litex_setup.py index 60582955e..991c23ac4 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -85,14 +85,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:]: @@ -120,6 +121,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)) From ded10c89dc1d609af3b6e142eb0130489aaa9dec Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 14 Apr 2020 12:38:02 +0200 Subject: [PATCH 06/44] build/sim/core/Makefile: add -p to mkdir modules. --- litex/build/sim/core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From d44fe18bd9e7c21b755b814d5be715928cd6fb64 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 14 Apr 2020 17:34:57 +0200 Subject: [PATCH 07/44] stream/AsyncFIFO: add default depth (useful when used for CDC). --- litex/soc/interconnect/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From 77a05b78e81af7fb2ca992ae8b6b5bd550310ec8 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Tue, 14 Apr 2020 21:43:58 +0200 Subject: [PATCH 08/44] soc_core: Fix region type generation Include information about being a linker region. --- litex/soc/integration/soc_core.py | 2 ++ 1 file changed, 2 insertions(+) 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) From 5e149ceda2e60ffce2740f8ef60f66428bbba449 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 15 Apr 2020 08:59:03 +0200 Subject: [PATCH 09/44] build/generic_programmer: add automatic search/download of flash_proxy in repositories if not available locally. --- litex/build/generic_programmer.py | 34 ++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/litex/build/generic_programmer.py b/litex/build/generic_programmer.py index ac22c74f2..2fb344443 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 +import requests from litex.build import tools @@ -12,25 +15,46 @@ 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 + 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 From 2d018826532e486b94615c6b9cee4f16a924dba2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 15 Apr 2020 09:27:26 +0200 Subject: [PATCH 10/44] setup.py/install_requires: add requests. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 46f8b6eeb..a52d0acd8 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( test_suite="test", license="BSD", python_requires="~=3.6", - install_requires=["migen", "pyserial"], + install_requires=["migen", "pyserial", "requests"], packages=find_packages(exclude=("test*", "sim*", "doc*")), include_package_data=True, entry_points={ From c9ab59398922d0c63743f97c432f9f310d1b317c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 15 Apr 2020 19:30:23 +0200 Subject: [PATCH 11/44] bios/sdram/ECP5: set ERR_DDRPHY_BITSLIP to 4. Bitslip software control is now used on ECP5 to move dqs_read. --- litex/soc/software/bios/sdram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index c0fec2544..d79bb1542 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -249,7 +249,7 @@ void sdrwr(char *startaddr) #define NBMODULES DFII_PIX_DATA_BYTES/2 #elif defined (ECP5DDRPHY) #define ERR_DDRPHY_DELAY 8 -#define ERR_DDRPHY_BITSLIP 1 +#define ERR_DDRPHY_BITSLIP 4 #define NBMODULES DFII_PIX_DATA_BYTES/4 #else #define ERR_DDRPHY_DELAY 32 From c0c5ae558ace64d37741c135af0d5c7be05c23c8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Apr 2020 08:44:36 +0200 Subject: [PATCH 12/44] build/generic_programmer: move requests import to do it only when needed. --- litex/build/generic_programmer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/build/generic_programmer.py b/litex/build/generic_programmer.py index 2fb344443..394440300 100644 --- a/litex/build/generic_programmer.py +++ b/litex/build/generic_programmer.py @@ -5,7 +5,7 @@ import os import sys -import requests + from litex.build import tools @@ -38,6 +38,7 @@ class GenericProgrammer: 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)) From 3915ed97607ab1fce9bd8637063329da07edf020 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Apr 2020 10:22:43 +0200 Subject: [PATCH 13/44] litex_sim: add phytype to PhySettings. --- litex/tools/litex_sim.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 1efea94d3..8ac544fcb 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, From c0f3710d66715f61cfed4a8cfdddfe7387ce907d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Apr 2020 10:23:31 +0200 Subject: [PATCH 14/44] bios/sdram: update/simplify with new exported LiteDRAM parameters. --- litex/soc/software/bios/main.c | 2 +- litex/soc/software/bios/sdram.c | 146 +++++++++++++++----------------- litex/soc/software/bios/sdram.h | 6 -- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index dff353586..0d2e6d863 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -475,7 +475,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 diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index d79bb1542..53333cd84 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 @@ -114,7 +114,7 @@ void sdrrdbuf(int dq) step = DFII_PIX_DATA_BYTES/2; } - for(p=0;p 32 show = (j%16 == 0); #endif for (k=0; k<128; k++) { @@ -368,7 +353,7 @@ int write_level(void) cdelay(10); csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[0], buf, DFII_PIX_DATA_BYTES); - if (buf[NBMODULES-1-i] != 0) + if (buf[SDRAM_PHY_MODULES-1-i] != 0) one_count++; else zero_count++; @@ -420,7 +405,7 @@ int write_level(void) sdrwloff(); ok = 1; - for(i=NBMODULES-1;i>=0;i--) { + for(i=SDRAM_PHY_MODULES-1;i>=0;i--) { if(delays[i] < 0) ok = 0; } @@ -428,7 +413,7 @@ int write_level(void) return ok; } -#endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */ +#endif /* SDRAM_PHY_WRITE_LEVELING_CAPABLE */ static void read_delay_rst(int module) { /* sel module */ @@ -440,7 +425,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 +442,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 +477,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 +554,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 +564,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 +633,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,7 +904,7 @@ int memtest(void) #ifdef CSR_SDRAM_BASE -#ifdef CSR_DDRPHY_BASE +#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE) int sdrlevel(void) { int module; @@ -930,25 +915,26 @@ int sdrlevel(void) sdrsw(); - for(module=0; module Date: Thu, 16 Apr 2020 11:26:59 +0200 Subject: [PATCH 15/44] targets: manual define of the SDRAM PHY no longer needed. --- litex/boards/targets/kcu105.py | 1 - litex/boards/targets/versa_ecp5.py | 1 - 2 files changed, 2 deletions(-) diff --git a/litex/boards/targets/kcu105.py b/litex/boards/targets/kcu105.py index 6e90ec47b..74023f67c 100755 --- a/litex/boards/targets/kcu105.py +++ b/litex/boards/targets/kcu105.py @@ -67,7 +67,6 @@ class BaseSoC(SoCCore): iodelay_clk_freq = 200e6, cmd_latency = 0) 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/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, From b0f8ee987667e4517574ff590f5baff336bfb9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Fri, 17 Apr 2020 14:52:53 +0200 Subject: [PATCH 16/44] litex_sim: add option to create SDRAM module from SPD data --- litex/tools/litex_sim.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 8ac544fcb..7a526f83a 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -166,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() @@ -182,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, @@ -285,6 +289,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") @@ -323,6 +328,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}) From 08e4dc02ecdcc28aedda868c4871cb9c2f3bf251 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 17 Apr 2020 21:30:33 +0200 Subject: [PATCH 17/44] tools/remote/etherbone: update import. --- litex/tools/remote/etherbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 56e1528455464572226ddd99663b17559eca4bc0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 18 Apr 2020 11:38:24 +0200 Subject: [PATCH 18/44] platforms/de0nano: swap serial tx/rx to ease use of cheap FT232 based cables. --- litex/boards/platforms/de0nano.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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")), From 2d25bcb09c20d6838ad3619288562624e298eeb0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 08:41:17 +0200 Subject: [PATCH 19/44] lattice/common: add LatticeiCE40DDRInput, LatticeiCE40SDROutput and LatticeiCE40SDRInput. --- litex/build/lattice/common.py | 71 ++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index 929aaadfa..25076d802 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 @@ -142,10 +142,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,7 +160,7 @@ 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): @@ -162,7 +168,7 @@ class LatticeiCE40TristateImpl(Module): if nbits == 1: self.specials += [ Instance("SB_IO", - p_PIN_TYPE = C(0b101001, 6), + p_PIN_TYPE = C(0b101001, 6), # PIN_OUTPUT_TRISTATE + PIN_INPUT io_PACKAGE_PIN = io, i_OUTPUT_ENABLE = oe, i_D_OUT_0 = o, @@ -173,7 +179,7 @@ class LatticeiCE40TristateImpl(Module): for bit in range(nbits): self.specials += [ Instance("SB_IO", - p_PIN_TYPE = C(0b101001, 6), + p_PIN_TYPE = C(0b101001, 6), # PIN_OUTPUT_TRISTATE + PIN_INPUT io_PACKAGE_PIN = io[bit], i_OUTPUT_ENABLE = oe, i_D_OUT_0 = o[bit], @@ -193,16 +199,15 @@ 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 @@ -215,14 +220,13 @@ class LatticeiCE40DifferentialOutput: 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_PIN_TYPE = C(0b010000, 6), # PIN_OUTPUT_DDR p_IO_STANDARD = "SB_LVCMOS", io_PACKAGE_PIN = o, i_CLOCK_ENABLE = 1, @@ -239,11 +243,50 @@ 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 LatticeiCE40SDROutput: + @staticmethod + def lower(dr): + return LatticeiCE40DDROutputImpl(dr.i, 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 Trellis Special Overrides ------------------------------------------------------------------ lattice_ice40_special_overrides = { AsyncResetSynchronizer: LatticeiCE40AsyncResetSynchronizer, Tristate: LatticeiCE40Tristate, DifferentialOutput: LatticeiCE40DifferentialOutput, - DDROutput: LatticeiCE40DDROutput + DDROutput: LatticeiCE40DDROutput, + DDRInput: LatticeiCE40DDRInput, + SDROutput: LatticeiCE40SDROutput, + SDRInput: LatticeiCE40SDRInput, } From 2031f28057a8b776ea7b63a688f69599451e47f0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 08:45:32 +0200 Subject: [PATCH 20/44] lattice/common: cleanup instances, simplify tritates. --- litex/build/lattice/common.py | 114 ++++++++++++---------------------- 1 file changed, 40 insertions(+), 74 deletions(-) diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index 25076d802..e147c4231 100644 --- a/litex/build/lattice/common.py +++ b/litex/build/lattice/common.py @@ -99,27 +99,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 @@ -143,10 +130,10 @@ class LatticeiCE40AsyncResetSynchronizerImpl(Module): rst1 = Signal() self.specials += [ Instance("SB_DFFS", - i_D= 0, - i_S= async_reset, - i_C= cd.clk, - o_Q= rst1), + i_D = 0, + i_S = async_reset, + i_C = cd.clk, + o_Q = rst1), Instance("SB_DFFS", i_D = rst1, i_S = async_reset, @@ -165,28 +152,14 @@ class LatticeiCE40AsyncResetSynchronizer: 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), # PIN_OUTPUT_TRISTATE + PIN_INPUT - 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), # PIN_OUTPUT_TRISTATE + PIN_INPUT - 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 @@ -203,9 +176,7 @@ class LatticeiCE40DifferentialOutputImpl(Module): 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), # PIN_OUTPUT p_IO_STANDARD = "SB_LVCMOS", @@ -214,7 +185,6 @@ class LatticeiCE40DifferentialOutputImpl(Module): ) ] - class LatticeiCE40DifferentialOutput: @staticmethod def lower(dr): @@ -224,18 +194,16 @@ class LatticeiCE40DifferentialOutput: class LatticeiCE40DDROutputImpl(Module): def __init__(self, i1, i2, o, clk): - 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 - ) - ] + 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: @@ -247,17 +215,15 @@ class LatticeiCE40DDROutput: 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 - ) - ] + 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: From 65e6ddc6cde21a327bdb00142dc12b638402a149 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 10:13:28 +0200 Subject: [PATCH 21/44] lattice/common: add LatticeECP5DDRInput. --- litex/build/lattice/common.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index e147c4231..543ea5dd0 100644 --- a/litex/build/lattice/common.py +++ b/litex/build/lattice/common.py @@ -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 ---------------------------------------------------------------------------- @@ -120,6 +137,7 @@ lattice_ecp5_trellis_special_overrides = { Tristate: LatticeECP5TrellisTristate, SDRInput: LatticeECP5SDRInput, SDROutput: LatticeECP5SDROutput, + DDRInput: LatticeECP5DDRInput, DDROutput: LatticeECP5DDROutput } From 69462e66690b606183caa410783402df721d8d86 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 10:33:22 +0200 Subject: [PATCH 22/44] build/xilinx/common: add 7-Series/Ultrascale SDROutput/Input. --- litex/build/xilinx/common.py | 38 ++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index 7507264b8..53b165070 100644 --- a/litex/build/xilinx/common.py +++ b/litex/build/xilinx/common.py @@ -275,11 +275,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 +339,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 ---------------------------------------------------------------------------------------- From 1457c32052b71fc056523f2cbeeefc44c028d765 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 10:41:50 +0200 Subject: [PATCH 23/44] xilinx/common: use a common SDRTristate implementation for Spartan6, 7-Series and Ultrascale. --- litex/build/xilinx/common.py | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index 53b165070..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 ------------------------------------------------------------------------------- From fc434af949be567af7294e1951a68dc16e33e7ef Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 11:50:55 +0200 Subject: [PATCH 24/44] build/lattice/common: add specific LatticeiCE40SDROutputImpl/LatticeiCE40SDRTristateImpl (thanks @tnt). --- litex/build/lattice/common.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index 543ea5dd0..fbb446db8 100644 --- a/litex/build/lattice/common.py +++ b/litex/build/lattice/common.py @@ -251,10 +251,22 @@ class LatticeiCE40DDRInput: # 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 LatticeiCE40DDROutputImpl(dr.i, dr.i, dr.o, dr.clk) + return LatticeiCE40SDROutputImpl(dr.i, dr.o, dr.clk) # iCE40 SDR Input ---------------------------------------------------------------------------------- @@ -263,6 +275,25 @@ class LatticeiCE40SDRInput: 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 = { @@ -273,4 +304,5 @@ lattice_ice40_special_overrides = { DDRInput: LatticeiCE40DDRInput, SDROutput: LatticeiCE40SDROutput, SDRInput: LatticeiCE40SDRInput, + SDRTristate: LatticeiCE40SDRTristate, } From 6bb22dfe6b8f4b9550c9b2b169228c9c991fa78f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 12:20:23 +0200 Subject: [PATCH 25/44] cores/spi: simplify. --- litex/soc/cores/spi.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/litex/soc/cores/spi.py b/litex/soc/cores/spi.py index 8cf7ceb50..fdf263e75 100644 --- a/litex/soc/cores/spi.py +++ b/litex/soc/cores/spi.py @@ -98,30 +98,31 @@ class SPIMaster(Module, AutoCSR): # Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) --------------- mosi_data = Signal(data_width) - self.sync += \ + self.sync += [ If(self.start, mosi_data.eq(self.mosi) ).Elif(clk_rise & shift, - mosi_data.eq(Cat(Signal(), mosi_data[:-1])) + mosi_data.eq(Cat(Signal(), mosi_data)) ).Elif(clk_fall, pads.mosi.eq(mosi_data[-1]) ) + ] # 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=[ From 0b3c4b50fa99cd92ba83ea64a1386b94195a35d4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 13:15:07 +0200 Subject: [PATCH 26/44] soc/cores/spi: add optional aligned mode. In aligned mode, MOSI and MISO bits are located on the LSBs and first transmitted MOSI bit is length - 1 bit. --- litex/soc/cores/spi.py | 17 ++++++++++------- test/test_spi.py | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/litex/soc/cores/spi.py b/litex/soc/cores/spi.py index fdf263e75..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,15 +97,17 @@ 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) + # 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)) - ).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]) ) ] 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) From 22c3923644e9804183217cf8de80c42721860fed Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 23 Apr 2020 08:04:04 +0200 Subject: [PATCH 27/44] initial SERV integration. --- litex/soc/cores/cpu/__init__.py | 18 +++-- litex/soc/cores/cpu/serv/__init__.py | 1 + litex/soc/cores/cpu/serv/core.py | 91 ++++++++++++++++++++++ litex/soc/integration/soc_core.py | 3 + litex/soc/software/bios/boot-helper-serv.S | 4 + litex/soc/software/bios/main.c | 2 + litex/soc/software/bios/sdram.c | 2 + litex/soc/software/include/base/irq.h | 10 +++ litex/soc/software/libbase/crt0-serv.S | 63 +++++++++++++++ litex/soc/software/libbase/system.c | 4 + 10 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 litex/soc/cores/cpu/serv/__init__.py create mode 100644 litex/soc/cores/cpu/serv/core.py create mode 100644 litex/soc/software/bios/boot-helper-serv.S create mode 100644 litex/soc/software/libbase/crt0-serv.S 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..8128fda5a --- /dev/null +++ b/litex/soc/cores/cpu/serv/core.py @@ -0,0 +1,91 @@ +# This file is Copyright (c) 2020 Florent Kermarrec + +# 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 = [self.ibus, dbus] + self.interrupt = Signal(32) + + # # # + + self.cpu_params = dict( + # clock / reset + i_clk = ClockSignal(), + i_i_rst = ResetSignal(), + + # timer irq + i_i_timer_irq = 0, + + # ibus + o_o_ibus_adr = 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 = 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), + 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_top", **self.cpu_params) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 3eb0016c7..ab8704ced 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -132,6 +132,9 @@ class SoCCore(LiteXSoC): self.cpu_type = cpu_type self.cpu_variant = cpu_variant + if cpu_type == "serv": + self.add_constant("UART_POLLING") # FIXME: use UART in polling mode for SERV bringup + self.integrated_rom_size = integrated_rom_size self.integrated_rom_initialized = integrated_rom_init != [] self.integrated_sram_size = integrated_sram_size 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/main.c b/litex/soc/software/bios/main.c index 0d2e6d863..1d68210c9 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -647,6 +647,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 53333cd84..de49a942d 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -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 diff --git a/litex/soc/software/include/base/irq.h b/litex/soc/software/include/base/irq.h index 7ff9b4033..00dad8a2b 100644 --- a/litex/soc/software/include/base/irq.h +++ b/litex/soc/software/include/base/irq.h @@ -75,6 +75,8 @@ static inline unsigned int irq_getie(void) return 0; // FIXME #elif defined (__blackparrot__) return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;//TODO +#elif defined (__serv__) + return 0; /* FIXME */ #else #error Unsupported architecture #endif @@ -104,6 +106,8 @@ static inline void irq_setie(unsigned int ie) // FIXME #elif defined (__blackparrot__) if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);//TODO:BP +#elif defined (__serv__) + /* FIXME */ #else #error Unsupported architecture #endif @@ -135,6 +139,8 @@ static inline unsigned int irq_getmask(void) return 0; // FIXME #elif defined (__blackparrot__) //TODO:BP +#elif defined (__serv__) + return 0; /* FIXME */ #else #error Unsupported architecture #endif @@ -160,6 +166,8 @@ static inline void irq_setmask(unsigned int mask) // FIXME #elif defined (__blackparrot__) //TODO:BP +#elif defined (__serv__) + /* FIXME */ #else #error Unsupported architecture #endif @@ -189,6 +197,8 @@ static inline unsigned int irq_pending(void) return 0; // FIXME #elif defined (__blackparrot__) return csr_readl(PLIC_PENDING) >> 1;//TODO:BP +#elif defined (__serv__) + return 0;/* FIXME */ #else #error Unsupported architecture #endif 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 From ab92e81e3103d3de6a643949570adaab70d2d981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Thu, 23 Apr 2020 13:52:28 +0200 Subject: [PATCH 28/44] bios/sdram: add automatic cdly calibration during write leveling --- litex/soc/software/bios/main.c | 6 + litex/soc/software/bios/sdram.c | 200 ++++++++++++++++++++++++++------ litex/soc/software/bios/sdram.h | 1 + 3 files changed, 169 insertions(+), 38 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 0d2e6d863..423d4f28d 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"); @@ -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(); diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index 53333cd84..ff094bd0e 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -310,7 +310,7 @@ static void write_delay_inc(int module) { ddrphy_dly_sel_write(0); } -int write_level(void) +static int write_level_scan(int *delays, int show) { int i, j, k; @@ -322,20 +322,17 @@ int write_level(void) int one_window_start, one_window_best_start; int one_window_count, one_window_best_count; - int delays[SDRAM_PHY_MODULES]; - unsigned char buf[DFII_PIX_DATA_BYTES]; int ok; err_ddrphy_wdly = SDRAM_PHY_DELAYS - ddrphy_half_sys8x_taps_read(); - printf("Write leveling:\n"); - sdrwlon(); cdelay(100); for(i=0;i 32 - show = (j%16 == 0); + show_iter = (j%16 == 0) && show; #endif for (k=0; k<128; k++) { ddrphy_wlevel_strobe_write(1); @@ -362,19 +359,20 @@ int write_level(void) taps_scan[j] = 1; else taps_scan[j] = 0; - if (show) + if (show_iter) printf("%d", taps_scan[j]); write_delay_inc(i); cdelay(10); } - printf("|"); + if (show) + printf("|"); /* find longer 1 window and set delay at the 0/1 transition */ one_window_active = 0; one_window_start = 0; one_window_count = 0; one_window_best_start = 0; - one_window_best_count = 0; + one_window_best_count = -1; delays[i] = -1; for(j=0;j 0 && one_window_best_start > 0) { + delays[i] = one_window_best_start; - /* configure write delay */ - write_delay_rst(i); - for(j=0; j 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); + } + } + + /* re-run write leveling the final time */ + if (!write_level_scan(delays, 1)) + return 0; + + return best_cdly >= 0; +} + + #endif /* SDRAM_PHY_WRITE_LEVELING_CAPABLE */ static void read_delay_rst(int module) { @@ -905,7 +1007,8 @@ int memtest(void) #ifdef CSR_SDRAM_BASE #if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE) -int sdrlevel(void) + +static void read_leveling(void) { int module; int bitslip; @@ -913,23 +1016,6 @@ int sdrlevel(void) int best_score; int best_bitslip; - sdrsw(); - - for(module=0; module Date: Sat, 25 Apr 2020 11:00:21 +0200 Subject: [PATCH 29/44] bios/sdram: review/cleanup Command/Clock calibration, set window at the start instead of middle. Working on KC705 that previously required manual adjustment. --- litex/soc/software/bios/sdram.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index ff094bd0e..eca275d96 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -441,21 +441,19 @@ static void write_level_cdly_range(unsigned int *best_error, int *best_cdly, } delay_mean /= SDRAM_PHY_MODULES; - /* we want it to be in the middle */ - int ideal_delay = (SDRAM_PHY_DELAYS - ddrphy_half_sys8x_taps_read()) / 2; + /* we want it to be at the start */ + int ideal_delay = 1; int error = ideal_delay - delay_mean; if (error < 0) error *= -1; if (error < *best_error) { - printf("+"); *best_cdly = cdly; *best_error = error; - } else { - printf("-"); } + printf("1"); } else { - printf("."); + printf("0"); } } } @@ -469,14 +467,17 @@ int write_level(void) int cdly_range_end; int cdly_range_step; - printf("cdly scan: "); + 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 = 512; - cdly_range_step = 64; + 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, @@ -507,6 +508,8 @@ int write_level(void) } } + printf("Data scan:\n"); + /* re-run write leveling the final time */ if (!write_level_scan(delays, 1)) return 0; From 038e1bc048731e55856999622c3a2c7ff45bb050 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 25 Apr 2020 11:03:04 +0200 Subject: [PATCH 30/44] targets/kc705: manual DDRPHY_CMD_DELAY no longer needed. --- litex/boards/targets/kc705.py | 1 - 1 file changed, 1 deletion(-) 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"), From 85a059bf773f9224bdd7106dbc5c8639d20d3af2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 25 Apr 2020 12:11:10 +0200 Subject: [PATCH 31/44] bios/sdram: add some margin on cdly ideal_delay, do the read_leveling even if write_leveling is not optimal. We need to provide enough information to ease support and understand the issue. The write leveling/read leveling are doing there best to calibrate the DRAM correctly and memtest gives the final result. --- litex/soc/software/bios/sdram.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index eca275d96..ff4e8f40f 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -442,7 +442,7 @@ static void write_level_cdly_range(unsigned int *best_error, int *best_cdly, delay_mean /= SDRAM_PHY_MODULES; /* we want it to be at the start */ - int ideal_delay = 1; + int ideal_delay = 4*SDRAM_PHY_DELAYS/32; int error = ideal_delay - delay_mean; if (error < 0) error *= -1; @@ -1069,13 +1069,11 @@ int sdrlevel(void) #ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE printf("Write leveling:\n"); if (_write_level_cdly_scan) { - if(!write_level()) - return 0; + write_level(); } else { /* use only the current cdly */ int delays[SDRAM_PHY_MODULES]; - if (!write_level_scan(delays, 1)) - return 0; + write_level_scan(delays, 1); } #endif From 43e1a5d67d8d15cb1f2b17ab98a55b07622d6efd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 25 Apr 2020 12:12:27 +0200 Subject: [PATCH 32/44] targets/kcu105: use cmd_latency=1. --- litex/boards/targets/kcu105.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/boards/targets/kcu105.py b/litex/boards/targets/kcu105.py index 74023f67c..b632b16cc 100755 --- a/litex/boards/targets/kcu105.py +++ b/litex/boards/targets/kcu105.py @@ -65,7 +65,7 @@ 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_DEBUG") self.add_sdram("sdram", From 96e7e6e89a7972a43f5808d8b76691bfa1169bea Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 25 Apr 2020 12:51:33 +0200 Subject: [PATCH 33/44] bios/sdram: reduce number of scan loops during cdly scan to speed it up. --- litex/soc/software/bios/sdram.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index ff4e8f40f..00c540ae3 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -310,7 +310,7 @@ static void write_delay_inc(int module) { ddrphy_dly_sel_write(0); } -static int write_level_scan(int *delays, int show) +static int write_level_scan(int *delays, int loops, int show) { int i, j, k; @@ -345,7 +345,7 @@ static int write_level_scan(int *delays, int show) #if SDRAM_PHY_DELAYS > 32 show_iter = (j%16 == 0) && show; #endif - for (k=0; k<128; k++) { + for (k=0; k= 0; @@ -1073,7 +1073,7 @@ int sdrlevel(void) } else { /* use only the current cdly */ int delays[SDRAM_PHY_MODULES]; - write_level_scan(delays, 1); + write_level_scan(delays, 128, 1); } #endif From 2efd939d06ba7903892fc5a742838b49ab1728fb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 26 Apr 2020 16:26:15 +0200 Subject: [PATCH 34/44] serv: fix ibus/dbus byte/word addressing inconsistency, add missing ibus.sel (thanks @GregDavill). --- litex/soc/cores/cpu/serv/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 8128fda5a..ab73cea22 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -36,7 +36,7 @@ class SERV(CPU): self.reset = Signal() self.ibus = ibus = wishbone.Interface() self.dbus = dbus = wishbone.Interface() - self.buses = [self.ibus, dbus] + self.buses = [ibus, dbus] self.interrupt = Signal(32) # # # @@ -50,14 +50,13 @@ class SERV(CPU): i_i_timer_irq = 0, # ibus - o_o_ibus_adr = ibus.adr, + 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 = dbus.adr, + 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, @@ -67,6 +66,7 @@ class SERV(CPU): ) self.comb += [ ibus.stb.eq(ibus.cyc), + ibus.sel.eq(0xf), dbus.stb.eq(dbus.cyc), ] From 1f9db583fd47c82d42e51058774d3654fae16883 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 26 Apr 2020 21:05:47 +0200 Subject: [PATCH 35/44] serv/cores: fix verilog top level (use serv_rf_top instead of serv_top), working :). --- litex/soc/cores/cpu/serv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index ab73cea22..e24853c4a 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -88,4 +88,4 @@ class SERV(CPU): def do_finalize(self): assert hasattr(self, "reset_address") - self.specials += Instance("serv_top", **self.cpu_params) + self.specials += Instance("serv_rf_top", **self.cpu_params) From 71778ad226858624494419b5b1cc538e91a7194a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 10:27:44 +0200 Subject: [PATCH 36/44] serv: update copyrights (Greg Davill found the typos/issues). --- litex/soc/cores/cpu/serv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index e24853c4a..4cda01d80 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -1,5 +1,5 @@ # This file is Copyright (c) 2020 Florent Kermarrec - +# This file is Copyright (c) 2020 Greg Davill # License: BSD import os From 642c4b303606e13f2d4c8ced0e78a4b651f482b9 Mon Sep 17 00:00:00 2001 From: Greg Davill Date: Mon, 27 Apr 2020 20:10:25 +0930 Subject: [PATCH 37/44] build/trellis: add verilog_read -defer option to yosys script --- litex/build/lattice/trellis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index a9ae49be4..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}", ] From c4c891dec51a77560f8660967f6666b170b517dc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 13:17:53 +0200 Subject: [PATCH 38/44] build/icestorm: add verilog_read -defer option to yosys script (changes similar the ones applied to trellis). --- litex/build/lattice/icestorm.py | 3 +++ 1 file changed, 3 insertions(+) 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", ] From fb9e369a193ba43a46d0e5651859b1809e8ab9b6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 13:26:45 +0200 Subject: [PATCH 39/44] serv: connect reset. --- litex/soc/cores/cpu/serv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 4cda01d80..c919fb532 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -44,7 +44,7 @@ class SERV(CPU): self.cpu_params = dict( # clock / reset i_clk = ClockSignal(), - i_i_rst = ResetSignal(), + i_i_rst = ResetSignal() | self.reset, # timer irq i_i_timer_irq = 0, From 1d1a4ecd28aeb3196e7ae2adeb97e25204613a3a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 13:46:12 +0200 Subject: [PATCH 40/44] software/irq: cleanup and make explicit that irqs are not supported with Microwatt and SERV, fix compilation warning. --- litex/soc/software/bios/isr.c | 6 ++--- litex/soc/software/include/base/irq.h | 32 +++++++++++++-------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/litex/soc/software/bios/isr.c b/litex/soc/software/bios/isr.c index 971bd37b6..f33cdac43 100644 --- a/litex/soc/software/bios/isr.c +++ b/litex/soc/software/bios/isr.c @@ -8,7 +8,7 @@ #include #include - + #if defined(__blackparrot__) /*TODO: Update this function for BP*/ // void isr(void); @@ -21,7 +21,7 @@ void isr(void) onetime++; } } -#elif defined(__rocket__) +#elif defined(__rocket__) void plic_init(void); void plic_init(void) { @@ -65,7 +65,7 @@ void isr(void) void isr(void); void isr(void) { - unsigned int irqs; + __attribute__((unused)) unsigned int irqs; irqs = irq_pending() & irq_getmask(); diff --git a/litex/soc/software/include/base/irq.h b/litex/soc/software/include/base/irq.h index 00dad8a2b..6a2f73944 100644 --- a/litex/soc/software/include/base/irq.h +++ b/litex/soc/software/include/base/irq.h @@ -72,11 +72,11 @@ static inline unsigned int irq_getie(void) #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 + return 0; /* No interrupt support on Microwatt */ +#elif defined (__blackparrot__) + return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; /* FIXME */ #elif defined (__serv__) - return 0; /* FIXME */ + return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -103,11 +103,11 @@ static inline void irq_setie(unsigned int ie) #elif defined (__rocket__) if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); #elif defined (__microwatt__) - // FIXME + /* No interrupt support on Microwatt */ #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 */ #elif defined (__serv__) - /* FIXME */ + /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -136,11 +136,11 @@ static inline unsigned int irq_getmask(void) #elif defined (__rocket__) return *((unsigned int *)PLIC_ENABLED) >> 1; #elif defined (__microwatt__) - return 0; // FIXME + return 0; /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) - //TODO:BP -#elif defined (__serv__) return 0; /* FIXME */ +#elif defined (__serv__) + return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -163,11 +163,11 @@ static inline void irq_setmask(unsigned int mask) #elif defined (__rocket__) *((unsigned int *)PLIC_ENABLED) = mask << 1; #elif defined (__microwatt__) - // FIXME + /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) - //TODO:BP -#elif defined (__serv__) /* FIXME */ +#elif defined (__serv__) + /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -194,11 +194,11 @@ static inline unsigned int irq_pending(void) #elif defined (__rocket__) return *((unsigned int *)PLIC_PENDING) >> 1; #elif defined (__microwatt__) - return 0; // FIXME + return 0; /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) - return csr_readl(PLIC_PENDING) >> 1;//TODO:BP + return csr_readl(PLIC_PENDING) >> 1; /* FIXME */ #elif defined (__serv__) - return 0;/* FIXME */ + return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif From 9460e048ec782900c3199ebded0e57128c8216ac Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 15:08:48 +0200 Subject: [PATCH 41/44] tools/litex_sim: use similar analyzer configuration than wiki. --- litex/tools/litex_sim.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 7a526f83a..987681d33 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -270,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 -------------------------------------------------------------------------------------------- From 3892d7a90a7c57bd58321f444c51dfae95d9f106 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Sat, 25 Apr 2020 23:22:38 +0200 Subject: [PATCH 42/44] bios: print memory usage Print memory usage during the compilation of bios.elf. --- litex/soc/software/bios/Makefile | 1 + litex/soc/software/memusage.py | 63 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 litex/soc/software/memusage.py 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/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() From 4dece4ce24972fb2652ee6183bed1cec9ab40672 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 19:06:16 +0200 Subject: [PATCH 43/44] soc/cpu: simplify integration of CPU without interrupts (and automatically use UART_POLLING mode in this case). --- litex/soc/cores/cpu/serv/core.py | 1 - litex/soc/integration/soc.py | 16 +++++++++++----- litex/soc/integration/soc_core.py | 3 --- litex/soc/software/bios/boot.c | 3 +++ litex/soc/software/bios/isr.c | 14 ++++++++++---- litex/soc/software/bios/main.c | 3 ++- litex/soc/software/include/base/irq.h | 25 +++++-------------------- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index c919fb532..4fb2f0a49 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -37,7 +37,6 @@ class SERV(CPU): self.ibus = ibus = wishbone.Interface() self.dbus = dbus = wishbone.Interface() self.buses = [ibus, dbus] - self.interrupt = Signal(32) # # # 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 ab8704ced..3eb0016c7 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -132,9 +132,6 @@ class SoCCore(LiteXSoC): self.cpu_type = cpu_type self.cpu_variant = cpu_variant - if cpu_type == "serv": - self.add_constant("UART_POLLING") # FIXME: use UART in polling mode for SERV bringup - self.integrated_rom_size = integrated_rom_size self.integrated_rom_initialized = integrated_rom_init != [] self.integrated_sram_size = integrated_sram_size 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 f33cdac43..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 +void isr(void); + +#ifdef CONFIG_CPU_HAS_INTERRUPT #if defined(__blackparrot__) /*TODO: Update this function for BP*/ // - -void isr(void); void isr(void) { static int onetime = 0; @@ -36,7 +38,6 @@ void plic_init(void) *((unsigned int *)PLIC_THRSHLD) = 0; } -void isr(void); void isr(void) { unsigned int claim; @@ -62,7 +63,6 @@ void isr(void) } } #else -void isr(void); void isr(void) { __attribute__((unused)) unsigned int irqs; @@ -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 08fc6faa9..b6501edbb 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -616,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"); diff --git a/litex/soc/software/include/base/irq.h b/litex/soc/software/include/base/irq.h index 6a2f73944..9fd8e1805 100644 --- a/litex/soc/software/include/base/irq.h +++ b/litex/soc/software/include/base/irq.h @@ -7,6 +7,9 @@ extern "C" { #include #include +#include + +#ifdef CONFIG_CPU_HAS_INTERRUPT #ifdef __picorv32__ // PicoRV32 has a very limited interrupt support, implemented via custom @@ -71,12 +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; /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; /* FIXME */ -#elif defined (__serv__) - return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -102,12 +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__) - /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); /* FIXME */ -#elif defined (__serv__) - /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -135,12 +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; /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) return 0; /* FIXME */ -#elif defined (__serv__) - return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -162,12 +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__) - /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) /* FIXME */ -#elif defined (__serv__) - /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -193,12 +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; /* No interrupt support on Microwatt */ #elif defined (__blackparrot__) return csr_readl(PLIC_PENDING) >> 1; /* FIXME */ -#elif defined (__serv__) - return 0; /* No interrupt support on SERV */ #else #error Unsupported architecture #endif @@ -208,4 +191,6 @@ static inline unsigned int irq_pending(void) } #endif +#endif + #endif /* __IRQ_H */ From f71014b9fb09ae649c1aa58e9575b995eaa9702d Mon Sep 17 00:00:00 2001 From: shuffle2 Date: Mon, 27 Apr 2020 11:14:18 -0700 Subject: [PATCH 44/44] diamond: fix include paths include paths given via tcl script need semicolon separators and forward slash as directory separator (even on windows) --- litex/build/lattice/diamond.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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))