Merge branch 'master' into litex-sm2py

This commit is contained in:
enjoy-digital 2020-04-27 22:24:10 +02:00 committed by GitHub
commit 317ea7edd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1095 additions and 330 deletions

View File

@ -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")),

View File

@ -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"),

View File

@ -65,9 +65,8 @@ class BaseSoC(SoCCore):
memtype = "DDR4",
sys_clk_freq = sys_clk_freq,
iodelay_clk_freq = 200e6,
cmd_latency = 0)
cmd_latency = 1)
self.add_csr("ddrphy")
self.add_constant("USDDRPHY")
self.add_constant("USDDRPHY_DEBUG")
self.add_sdram("sdram",
phy = self.ddrphy,

View File

@ -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",

View File

@ -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,

View File

@ -1,8 +1,11 @@
# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import os, sys
import os
import sys
from litex.build import tools
@ -12,25 +15,47 @@ class GenericProgrammer:
self.flash_proxy_dirs = [
"~/.migen", "/usr/local/share/migen", "/usr/share/migen",
"~/.mlabs", "/usr/local/share/mlabs", "/usr/share/mlabs",
"~/.litex", "/usr/local/share/litex", "/usr/share/litex"]
"~/.litex", "/usr/local/share/litex", "/usr/share/litex"
]
self.flash_proxy_repos = [
"https://github.com/quartiq/bscan_spi_bitstreams/raw/master/",
]
self.flash_proxy_local = "flash_proxies"
def set_flash_proxy_dir(self, flash_proxy_dir):
if flash_proxy_dir is not None:
self.flash_proxy_dirs = [flash_proxy_dir]
def find_flash_proxy(self):
# Search in installed flash_proxy_directories
for d in self.flash_proxy_dirs:
fulldir = os.path.abspath(os.path.expanduser(d))
fulldir = os.path.abspath(os.path.expanduser(d))
fullname = tools.cygpath(os.path.join(fulldir, self.flash_proxy_basename))
if os.path.exists(fullname):
return fullname
# Search in local flash_proxy directory
fullname = tools.cygpath(os.path.join(self.flash_proxy_local, self.flash_proxy_basename))
if os.path.exists(fullname):
return fullname
# Search in repositories and download it
import requests
os.makedirs(self.flash_proxy_local, exist_ok=True)
for d in self.flash_proxy_repos:
fullname = tools.cygpath(os.path.join(self.flash_proxy_local, self.flash_proxy_basename))
try:
r = requests.get(d + self.flash_proxy_basename)
with open(fullname, "wb") as f:
f.write(r.content)
return fullname
except:
pass
raise OSError("Failed to find flash proxy bitstream")
# must be overloaded by specific programmer
# Must be overloaded by specific programmer
def load_bitstream(self, bitstream_file):
raise NotImplementedError
# must be overloaded by specific programmer
# Must be overloaded by specific programmer
def flash(self, address, data_file):
raise NotImplementedError

View File

@ -1,4 +1,4 @@
# This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2017 William D. Jones <thor0505@comcast.net>
# This file is Copyright (c) 2019 David Shah <dave@ds0.me>
# License: BSD
@ -69,6 +69,22 @@ class LatticeECP5SDROutput:
def lower(dr):
return LatticeECP5SDROutputImpl(dr.i, dr.o, dr.clk)
# ECP5 DDR Input -----------------------------------------------------------------------------------
class LatticeECP5DDRInputImpl(Module):
def __init__(self, i, o1, o2, clk):
self.specials += Instance("IDDRX1F",
i_SCLK = clk,
i_D = i,
o_Q0 = o1,
o_Q1 = o2,
)
class LatticeECP5DDRInput:
@staticmethod
def lower(dr):
return LatticeECP5DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk)
# ECP5 DDR Output ----------------------------------------------------------------------------------
class LatticeECP5DDROutputImpl(Module):
@ -91,7 +107,8 @@ lattice_ecp5_special_overrides = {
AsyncResetSynchronizer: LatticeECP5AsyncResetSynchronizer,
SDRInput: LatticeECP5SDRInput,
SDROutput: LatticeECP5SDROutput,
DDROutput: LatticeECP5DDROutput
DDRInput: LatticeECP5DDRInput,
DDROutput: LatticeECP5DDROutput,
}
# ECP5 Trellis Tristate ----------------------------------------------------------------------------
@ -99,27 +116,14 @@ lattice_ecp5_special_overrides = {
class LatticeECP5TrellisTristateImpl(Module):
def __init__(self, io, o, oe, i):
nbits, sign = value_bits_sign(io)
if nbits == 1:
self.specials += [
Instance("TRELLIS_IO",
p_DIR = "BIDIR",
i_B = io,
i_I = o,
o_O = i,
i_T = ~oe
)
]
else:
for bit in range(nbits):
self.specials += [
Instance("TRELLIS_IO",
p_DIR="BIDIR",
i_B = io[bit],
i_I = o[bit],
o_O = i[bit],
i_T = ~oe
)
]
for bit in range(nbits):
self.specials += Instance("TRELLIS_IO",
p_DIR = "BIDIR",
i_B = io[bit] if nbits > 1 else io,
i_I = o[bit] if nbits > 1 else o,
o_O = i[bit] if nbits > 1 else i,
i_T = ~oe
)
class LatticeECP5TrellisTristate(Module):
@staticmethod
@ -133,6 +137,7 @@ lattice_ecp5_trellis_special_overrides = {
Tristate: LatticeECP5TrellisTristate,
SDRInput: LatticeECP5SDRInput,
SDROutput: LatticeECP5SDROutput,
DDRInput: LatticeECP5DDRInput,
DDROutput: LatticeECP5DDROutput
}
@ -142,10 +147,16 @@ class LatticeiCE40AsyncResetSynchronizerImpl(Module):
def __init__(self, cd, async_reset):
rst1 = Signal()
self.specials += [
Instance("SB_DFFS", i_D=0, i_S=async_reset,
i_C=cd.clk, o_Q=rst1),
Instance("SB_DFFS", i_D=rst1, i_S=async_reset,
i_C=cd.clk, o_Q=cd.rst)
Instance("SB_DFFS",
i_D = 0,
i_S = async_reset,
i_C = cd.clk,
o_Q = rst1),
Instance("SB_DFFS",
i_D = rst1,
i_S = async_reset,
i_C = cd.clk,
o_Q = cd.rst)
]
@ -154,33 +165,19 @@ class LatticeiCE40AsyncResetSynchronizer:
def lower(dr):
return LatticeiCE40AsyncResetSynchronizerImpl(dr.cd, dr.async_reset)
# iCE40 Trellis Tristate ---------------------------------------------------------------------------
# iCE40 Tristate -----------------------------------------------------------------------------------
class LatticeiCE40TristateImpl(Module):
def __init__(self, io, o, oe, i):
nbits, sign = value_bits_sign(io)
if nbits == 1:
self.specials += [
Instance("SB_IO",
p_PIN_TYPE = C(0b101001, 6),
io_PACKAGE_PIN = io,
i_OUTPUT_ENABLE = oe,
i_D_OUT_0 = o,
o_D_IN_0 = i
)
]
else:
for bit in range(nbits):
self.specials += [
Instance("SB_IO",
p_PIN_TYPE = C(0b101001, 6),
io_PACKAGE_PIN = io[bit],
i_OUTPUT_ENABLE = oe,
i_D_OUT_0 = o[bit],
o_D_IN_0 = i[bit]
)
]
for bit in range(nbits):
self.specials += Instance("SB_IO",
p_PIN_TYPE = C(0b101001, 6), # PIN_OUTPUT_TRISTATE + PIN_INPUT
io_PACKAGE_PIN = io[bit] if nbits > 1 else io,
i_OUTPUT_ENABLE = oe,
i_D_OUT_0 = o[bit] if nbits > 1 else o,
o_D_IN_0 = i[bit] if nbits > 1 else i,
)
class LatticeiCE40Tristate(Module):
@staticmethod
@ -193,45 +190,38 @@ class LatticeiCE40DifferentialOutputImpl(Module):
def __init__(self, i, o_p, o_n):
self.specials += [
Instance("SB_IO",
p_PIN_TYPE = C(0b011000, 6),
p_PIN_TYPE = C(0b011000, 6), # PIN_OUTPUT
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = o_p,
i_D_OUT_0 = i
)
]
self.specials += [
),
Instance("SB_IO",
p_PIN_TYPE = C(0b011000, 6),
p_PIN_TYPE = C(0b011000, 6), # PIN_OUTPUT
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = o_n,
i_D_OUT_0 = ~i
)
]
class LatticeiCE40DifferentialOutput:
@staticmethod
def lower(dr):
return LatticeiCE40DifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
# iCE40 DDR Output ---------------------------------------------------------------------------------
class LatticeiCE40DDROutputImpl(Module):
def __init__(self, i1, i2, o, clk):
self.specials += [
Instance("SB_IO",
p_PIN_TYPE = C(0b010000, 6),
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = o,
i_CLOCK_ENABLE = 1,
i_OUTPUT_CLK = clk,
i_OUTPUT_ENABLE = 1,
i_D_OUT_0 = i1,
i_D_OUT_1 = i2
)
]
self.specials += Instance("SB_IO",
p_PIN_TYPE = C(0b010000, 6), # PIN_OUTPUT_DDR
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = o,
i_CLOCK_ENABLE = 1,
i_OUTPUT_CLK = clk,
i_OUTPUT_ENABLE = 1,
i_D_OUT_0 = i1,
i_D_OUT_1 = i2
)
class LatticeiCE40DDROutput:
@ -239,11 +229,80 @@ class LatticeiCE40DDROutput:
def lower(dr):
return LatticeiCE40DDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk)
# iCE40 DDR Input ----------------------------------------------------------------------------------
class LatticeiCE40DDRInputImpl(Module):
def __init__(self, i, o1, o2, clk):
self.specials += Instance("SB_IO",
p_PIN_TYPE = C(0b000000, 6), # PIN_INPUT_DDR
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = i,
i_CLOCK_ENABLE = 1,
i_INPUT_CLK = clk,
o_D_IN_0 = o1,
o_D_IN_1 = o2
)
class LatticeiCE40DDRInput:
@staticmethod
def lower(dr):
return LatticeiCE40DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk)
# iCE40 SDR Output ---------------------------------------------------------------------------------
class LatticeiCE40SDROutputImpl(Module):
def __init__(self, i, o, clk):
self.specials += Instance("SB_IO",
p_PIN_TYPE = C(0b010100, 6), # PIN_OUTPUT_REGISTERED
p_IO_STANDARD = "SB_LVCMOS",
io_PACKAGE_PIN = o,
i_CLOCK_ENABLE = 1,
i_OUTPUT_CLK = clk,
i_OUTPUT_ENABLE = 1,
i_D_OUT_0 = i
)
class LatticeiCE40SDROutput:
@staticmethod
def lower(dr):
return LatticeiCE40SDROutputImpl(dr.i, dr.o, dr.clk)
# iCE40 SDR Input ----------------------------------------------------------------------------------
class LatticeiCE40SDRInput:
@staticmethod
def lower(dr):
return LatticeiCE40DDRInputImpl(dr.i, dr.o, Signal(), dr.clk)
# iCE40 SDR Tristate -------------------------------------------------------------------------------
class LatticeiCE40SDRTristateImpl(Module):
def __init__(self, io, o, oe, i, clk):
self.specials += Instance("SB_IO",
p_PIN_TYPE = C(0b110100, 6), # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED + PIN_INPUT_REGISTERED
io_PACKAGE_PIN = io,
i_INPUT_CLK = clk,
i_OUTPUT_CLK = clk,
i_OUTPUT_ENABLE = oe,
i_D_OUT_0 = o,
o_D_IN_0 = i,
)
class LatticeiCE40SDRTristate(Module):
@staticmethod
def lower(dr):
return LatticeiCE40SDRTristateImpl(dr.io, dr.o, dr.oe, dr.i, dr.clk)
# iCE40 Trellis Special Overrides ------------------------------------------------------------------
lattice_ice40_special_overrides = {
AsyncResetSynchronizer: LatticeiCE40AsyncResetSynchronizer,
Tristate: LatticeiCE40Tristate,
DifferentialOutput: LatticeiCE40DifferentialOutput,
DDROutput: LatticeiCE40DDROutput
DDROutput: LatticeiCE40DDROutput,
DDRInput: LatticeiCE40DDRInput,
SDROutput: LatticeiCE40SDROutput,
SDRInput: LatticeiCE40SDRInput,
SDRTristate: LatticeiCE40SDRTristate,
}

View File

@ -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))
self.false_paths.add((from_, to))

View File

@ -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",
]

View File

@ -49,7 +49,10 @@ def _build_lpf(named_sc, named_pc, build_name):
# Yosys/Nextpnr Helpers/Templates ------------------------------------------------------------------
_yosys_template = [
"verilog_defaults -push",
"verilog_defaults -add -defer",
"{read_files}",
"verilog_defaults -pop",
"attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0",
"synth_ecp5 -abc9 {nwl} -json {build_name}.json -top {build_name}",
]
@ -97,6 +100,7 @@ def nextpnr_ecp5_parse_device(device):
return (family, size, speed_grade, package)
nextpnr_ecp5_architectures = {
"lfe5u-12f" : "12k",
"lfe5u-25f" : "25k",
"lfe5u-45f" : "45k",
"lfe5u-85f" : "85k",

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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));

View File

@ -1,5 +1,5 @@
# This file is Copyright (c) 2014-2015 Sebastien Bourdeauducq <sb@m-labs.hk>
# This file is Copyright (c) 2014-2018 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2016-2018 Robert Jordens <jordens@gmail.com>
# This file is Copyright (c) 2015 William D. Jones <thor0505@comcast.net>
# License: BSD
@ -127,6 +127,27 @@ class XilinxDifferentialOutput:
def lower(dr):
return XilinxDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
# Common SDRTristate -------------------------------------------------------------------------------
class XilinxSDRTristateImpl(Module):
def __init__(self, io, o, oe, i, clk):
_o = Signal()
_oe_n = Signal()
_i = Signal()
self.specials += SDROutput(o, _o)
self.specials += SDROutput(~oe, _oe_n)
self.specials += SDRInput(_i, i)
self.specials += Instance("IOBUF",
io_IO = io,
o_O = _i,
i_I = _o,
i_T = _oe_n,
)
class XilinxSDRTristate:
@staticmethod
def lower(dr):
return XilinxSDRTristateImpl(dr.io, dr.o, dr.oe, dr.i, dr.clk)
# Common Special Overrides -------------------------------------------------------------------------
@ -135,6 +156,7 @@ xilinx_special_overrides = {
AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
DifferentialInput: XilinxDifferentialInput,
DifferentialOutput: XilinxDifferentialOutput,
SDRTristate: XilinxSDRTristate,
}
# Spartan6 DDROutput -------------------------------------------------------------------------------
@ -201,28 +223,6 @@ class XilinxSDRInputS6:
def lower(dr):
return XilinxDDRInputImplS6(dr.i, dr.o, Signal(), dr.clk)
# Spartan6 SDRTristate -----------------------------------------------------------------------------
class XilinxSDRTristateImplS6(Module):
def __init__(self, io, o, oe, i, clk):
_o = Signal()
_oe_n = Signal()
_i = Signal()
self.specials += SDROutput(o, _o)
self.specials += SDROutput(~oe, _oe_n)
self.specials += SDRInput(_i, i)
self.specials += Instance("IOBUF",
io_IO = io,
o_O = _i,
i_I = _o,
i_T = _oe_n,
)
class XilinxSDRTristateS6:
@staticmethod
def lower(dr):
return XilinxSDRTristateImplS6(dr.io, dr.o, dr.oe, dr.i, dr.clk)
# Spartan6 Special Overrides -----------------------------------------------------------------------
xilinx_s6_special_overrides = {
@ -230,7 +230,6 @@ xilinx_s6_special_overrides = {
DDRInput: XilinxDDRInputS6,
SDROutput: XilinxSDROutputS6,
SDRInput: XilinxSDRInputS6,
SDRTristate: XilinxSDRTristateS6,
}
# 7-Series DDROutput -------------------------------------------------------------------------------
@ -275,11 +274,28 @@ class XilinxDDRInputS7:
def lower(dr):
return XilinxDDRInputImplS7(dr.i, dr.o1, dr.o2, dr.clk)
# 7-Series SDROutput -------------------------------------------------------------------------------
class XilinxSDROutputS7:
@staticmethod
def lower(dr):
return XilinxDDROutputImplS7(dr.i, dr.i, dr.o, dr.clk)
# 7-Series SDRInput --------------------------------------------------------------------------------
class XilinxSDRInputS7:
@staticmethod
def lower(dr):
return XilinxDDRInputImplS7(dr.i, dr.o, Signal(), dr.clk)
# 7-Series Special Overrides -----------------------------------------------------------------------
xilinx_s7_special_overrides = {
DDROutput: XilinxDDROutputS7,
DDRInput: XilinxDDRInputS7
DDRInput: XilinxDDRInputS7,
SDROutput: XilinxSDROutputS7,
SDRInput: XilinxSDRInputS7,
}
# Ultrascale DDROutput -----------------------------------------------------------------------------
@ -322,11 +338,28 @@ class XilinxDDRInputUS:
def lower(dr):
return XilinxDDRInputImplUS(dr.i, dr.o1, dr.o2, dr.clk)
# Ultrascale SDROutput -----------------------------------------------------------------------------
class XilinxSDROutputUS:
@staticmethod
def lower(dr):
return XilinxDDROutputImplUS(dr.i, dr.i, dr.o, dr.clk)
# Ultrascale SDRInput ------------------------------------------------------------------------------
class XilinxSDRInputUS:
@staticmethod
def lower(dr):
return XilinxDDRInputImplUS(dr.i, dr.o, Signal(), dr.clk)
# Ultrascale Specials Overrides --------------------------------------------------------------------
xilinx_us_special_overrides = {
DDROutput: XilinxDDROutputUS,
DDRInput: XilinxDDRInputUS
DDRInput: XilinxDDRInputUS,
SDROutput: XilinxSDROutputUS,
SDRInput: XilinxSDRInputUS,
}
# Yosys Run ----------------------------------------------------------------------------------------

View File

@ -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 ---------------------------------------------------------------

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.serv.core import SERV

View File

@ -0,0 +1,90 @@
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2020 Greg Davill <greg.davill@gmail.com>
# License: BSD
import os
from migen import *
from litex.soc.interconnect import wishbone
from litex.soc.cores.cpu import CPU
CPU_VARIANTS = ["standard"]
class SERV(CPU):
name = "serv"
data_width = 32
endianness = "little"
gcc_triple = ("riscv64-unknown-elf", "riscv32-unknown-elf", "riscv-none-embed",
"riscv64-linux", "riscv-sifive-elf", "riscv64-none-elf")
linker_output_format = "elf32-littleriscv"
io_regions = {0x80000000: 0x80000000} # origin, length
@property
def gcc_flags(self):
flags = "-march=rv32i "
flags += "-mabi=ilp32 "
flags += "-D__serv__ "
return flags
def __init__(self, platform, variant="standard"):
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
self.platform = platform
self.variant = variant
self.reset = Signal()
self.ibus = ibus = wishbone.Interface()
self.dbus = dbus = wishbone.Interface()
self.buses = [ibus, dbus]
# # #
self.cpu_params = dict(
# clock / reset
i_clk = ClockSignal(),
i_i_rst = ResetSignal() | self.reset,
# timer irq
i_i_timer_irq = 0,
# ibus
o_o_ibus_adr = Cat(Signal(2), ibus.adr),
o_o_ibus_cyc = ibus.cyc,
i_i_ibus_rdt = ibus.dat_r,
i_i_ibus_ack = ibus.ack,
# dbus
o_o_dbus_adr = Cat(Signal(2), dbus.adr),
o_o_dbus_dat = dbus.dat_w,
o_o_dbus_sel = dbus.sel,
o_o_dbus_we = dbus.we,
o_o_dbus_cyc = dbus.cyc,
i_i_dbus_rdt = dbus.dat_r,
i_i_dbus_ack = dbus.ack,
)
self.comb += [
ibus.stb.eq(ibus.cyc),
ibus.sel.eq(0xf),
dbus.stb.eq(dbus.cyc),
]
# add verilog sources
self.add_sources(platform)
def set_reset_address(self, reset_address):
assert not hasattr(self, "reset_address")
self.reset_address = reset_address
self.cpu_params.update(p_RESET_PC=reset_address)
@staticmethod
def add_sources(platform):
# FIXME: add SERV as submodule
os.system("git clone https://github.com/olofk/serv")
vdir = os.path.join("serv", "rtl")
platform.add_source_dir(vdir)
platform.add_verilog_include_path(vdir)
def do_finalize(self):
assert hasattr(self, "reset_address")
self.specials += Instance("serv_rf_top", **self.cpu_params)

150
litex/soc/cores/emif.py Normal file
View File

@ -0,0 +1,150 @@
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# 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")
)
)

View File

@ -17,7 +17,8 @@ class SPIMaster(Module, AutoCSR):
configurable data_width and frequency.
"""
pads_layout = [("clk", 1), ("cs_n", 1), ("mosi", 1), ("miso", 1)]
def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True):
def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True, mode="raw"):
assert mode in ["raw", "aligned"]
if pads is None:
pads = Record(self.pads_layout)
if not hasattr(pads, "cs_n"):
@ -96,32 +97,35 @@ class SPIMaster(Module, AutoCSR):
for i in range(len(pads.cs_n)):
self.comb += pads.cs_n[i].eq(~self.cs[i] | ~xfer)
# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ---------------
mosi_data = Signal(data_width)
self.sync += \
# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ----------------
mosi_data = Array(self.mosi[i] for i in range(data_width))
mosi_bit = Signal(max=data_width)
self.sync += [
If(self.start,
mosi_data.eq(self.mosi)
mosi_bit.eq(self.length - 1 if mode == "aligned" else data_width - 1),
).Elif(clk_rise & shift,
mosi_data.eq(Cat(Signal(), mosi_data[:-1]))
).Elif(clk_fall,
pads.mosi.eq(mosi_data[-1])
mosi_bit.eq(mosi_bit - 1)
),
If(clk_fall,
pads.mosi.eq(mosi_data[mosi_bit])
)
]
# Master In Slave Out (MISO) capture (captured on spi_clk rising edge) --------------------
miso = Signal()
miso_data = self.miso
self.sync += \
If(shift,
If(clk_rise,
If(self.loopback,
miso.eq(pads.mosi)
).Else(
miso.eq(pads.miso)
)
).Elif(clk_fall,
miso_data.eq(Cat(miso, miso_data[:-1]))
self.sync += [
If(clk_rise & shift,
If(self.loopback,
miso.eq(pads.mosi)
).Else(
miso.eq(pads.miso)
)
),
If(clk_fall & shift,
miso_data.eq(Cat(miso, miso_data))
)
]
def add_csr(self):
self._control = CSRStorage(fields=[

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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 $< $@

View File

@ -0,0 +1,4 @@
.section .text, "ax", @progbits
.global boot_helper
boot_helper:
jr x13

View File

@ -18,6 +18,7 @@
#include <generated/mem.h>
#include <generated/csr.h>
#include <generated/soc.h>
#ifdef CSR_ETHMAC_BASE
#include <net/microudp.h>
@ -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();

View File

@ -4,14 +4,16 @@
#include <generated/csr.h>
#include <generated/soc.h>
#include <irq.h>
#include <uart.h>
#include <stdio.h>
#if defined(__blackparrot__) /*TODO: Update this function for BP*/ //
void isr(void);
#ifdef CONFIG_CPU_HAS_INTERRUPT
#if defined(__blackparrot__) /*TODO: Update this function for BP*/ //
void isr(void)
{
static int onetime = 0;
@ -21,7 +23,7 @@ void isr(void)
onetime++;
}
}
#elif defined(__rocket__)
#elif defined(__rocket__)
void plic_init(void);
void plic_init(void)
{
@ -36,7 +38,6 @@ void plic_init(void)
*((unsigned int *)PLIC_THRSHLD) = 0;
}
void isr(void);
void isr(void)
{
unsigned int claim;
@ -62,10 +63,9 @@ void isr(void)
}
}
#else
void isr(void);
void isr(void)
{
unsigned int irqs;
__attribute__((unused)) unsigned int irqs;
irqs = irq_pending() & irq_getmask();
@ -75,3 +75,9 @@ void isr(void)
#endif
}
#endif
#else
void isr(void){};
#endif

View File

@ -394,6 +394,7 @@ static void help(void)
puts("sdram_cal - run SDRAM calibration");
puts("sdram_mpr - read SDRAM MPR");
puts("sdram_mrwr reg value - write SDRAM mode registers");
puts("sdram_cdly_scan enabled - enable/disable cdly scan");
#endif
#ifdef CSR_SPISDCARD_BASE
puts("spisdcardboot - boot from SDCard via SPI hardware bitbang");
@ -475,7 +476,7 @@ static void do_command(char *c)
else if(strcmp(token, "sdrwr") == 0) sdrwr(get_token(&c));
#ifdef CSR_DDRPHY_BASE
else if(strcmp(token, "sdrinit") == 0) sdrinit();
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
else if(strcmp(token, "sdrwlon") == 0) sdrwlon();
else if(strcmp(token, "sdrwloff") == 0) sdrwloff();
#endif
@ -506,6 +507,11 @@ static void do_command(char *c)
sdrmrwr(reg, value);
sdrhw();
}
else if(strcmp(token, "sdram_cdly_scan") == 0) {
unsigned int enabled;
enabled = atoi(get_token(&c));
sdr_cdly_scan(enabled);
}
#endif
#ifdef CSR_SPISDCARD_BASE
else if(strcmp(token, "spisdcardboot") == 0) spisdcardboot();
@ -610,9 +616,10 @@ int main(int i, char **c)
{
char buffer[64];
int sdr_ok;
#ifdef CONFIG_CPU_HAS_INTERRUPT
irq_setmask(0);
irq_setie(1);
#endif
uart_init();
printf("\n");
@ -647,6 +654,8 @@ int main(int i, char **c)
printf("RocketRV64[imac]");
#elif __blackparrot__
printf("BlackParrotRV64[ia]");
#elif __serv__
printf("SERV");
#else
printf("Unknown");
#endif

View File

@ -1,5 +1,5 @@
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
// This file is Copyright (c) 2013-2019 Florent Kermarrec <florent@enjoy-digital.fr>
// This file is Copyright (c) 2013-2020 Florent Kermarrec <florent@enjoy-digital.fr>
// This file is Copyright (c) 2018 Chris Ballance <chris.ballance@physics.ox.ac.uk>
// This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
// This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
@ -48,6 +48,8 @@ __attribute__((unused)) static void cdelay(int i)
__asm__ volatile("nop");
#elif defined (__blackparrot__)
__asm__ volatile("nop");
#elif defined (__serv__)
__asm__ volatile("nop");
#else
#error Unsupported architecture
#endif
@ -114,7 +116,7 @@ void sdrrdbuf(int dq)
step = DFII_PIX_DATA_BYTES/2;
}
for(p=0;p<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
buf, DFII_PIX_DATA_BYTES);
for(i=first_byte;i<DFII_PIX_DATA_BYTES;i+=step)
@ -161,8 +163,8 @@ void sdrrderr(char *count)
char *c;
int _count;
int i, j, p;
unsigned char prev_data[DFII_NPHASES][DFII_PIX_DATA_BYTES];
unsigned char errs[DFII_NPHASES][DFII_PIX_DATA_BYTES];
unsigned char prev_data[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
unsigned char errs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
unsigned char new_data[DFII_PIX_DATA_BYTES];
if(*count == 0) {
@ -175,7 +177,7 @@ void sdrrderr(char *count)
return;
}
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
for(i=0;i<DFII_PIX_DATA_BYTES;i++)
errs[p][i] = 0;
@ -184,14 +186,14 @@ void sdrrderr(char *count)
sdram_dfii_pird_baddress_write(0);
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15);
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
prev_data[p], DFII_PIX_DATA_BYTES);
for(j=0;j<_count;j++) {
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15);
for(p=0;p<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
new_data, DFII_PIX_DATA_BYTES);
for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
@ -202,11 +204,11 @@ void sdrrderr(char *count)
}
}
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
for(i=0;i<DFII_PIX_DATA_BYTES;i++)
printf("%02x", errs[p][i]);
printf("\n");
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
for(i=0;i<DFII_PIX_DATA_BYTES;i++)
printf("%2x", DFII_PIX_DATA_BYTES/2 - 1 - (i % (DFII_PIX_DATA_BYTES/2)));
printf("\n");
@ -229,7 +231,7 @@ void sdrwr(char *startaddr)
return;
}
for(p=0;p<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
for(i=0;i<DFII_PIX_DATA_BYTES;i++)
buf[i] = 0x10*p + i;
csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
@ -243,20 +245,6 @@ void sdrwr(char *startaddr)
#ifdef CSR_DDRPHY_BASE
#if defined (USDDRPHY)
#define ERR_DDRPHY_DELAY 512
#define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_BYTES/2
#elif defined (ECP5DDRPHY)
#define ERR_DDRPHY_DELAY 8
#define ERR_DDRPHY_BITSLIP 1
#define NBMODULES DFII_PIX_DATA_BYTES/4
#else
#define ERR_DDRPHY_DELAY 32
#define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_BYTES/2
#endif
#if defined(DDRPHY_CMD_DELAY) || defined(USDDRPHY_DEBUG)
void ddrphy_cdly(unsigned int delay) {
printf("Setting clk/cmd delay to %d taps\n", delay);
@ -275,8 +263,7 @@ void ddrphy_cdly(unsigned int delay) {
}
#endif
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
void sdrwlon(void)
{
sdram_dfii_pi0_address_write(DDRX_MR1 | (1 << 7));
@ -294,7 +281,7 @@ void sdrwloff(void)
}
static void write_delay_rst(int module) {
#ifdef USDDRPHY
#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
int i;
#endif
@ -304,7 +291,7 @@ static void write_delay_rst(int module) {
/* rst delay */
ddrphy_wdly_dq_rst_write(1);
ddrphy_wdly_dqs_rst_write(1);
#ifdef USDDRPHY /* need to init manually on Ultrascale */
#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
for(i=0; i<ddrphy_half_sys8x_taps_read(); i++)
ddrphy_wdly_dqs_inc_write(1);
#endif
@ -325,32 +312,29 @@ static void write_delay_inc(int module) {
ddrphy_dly_sel_write(0);
}
int write_level(void)
static int write_level_scan(int *delays, int loops, int show)
{
int i, j, k;
int err_ddrphy_wdly;
unsigned char taps_scan[ERR_DDRPHY_DELAY];
unsigned char taps_scan[SDRAM_PHY_DELAYS];
int one_window_active;
int one_window_start, one_window_best_start;
int one_window_count, one_window_best_count;
int delays[NBMODULES];
unsigned char buf[DFII_PIX_DATA_BYTES];
int ok;
err_ddrphy_wdly = ERR_DDRPHY_DELAY - ddrphy_half_sys8x_taps_read();
printf("Write leveling:\n");
err_ddrphy_wdly = SDRAM_PHY_DELAYS - ddrphy_half_sys8x_taps_read();
sdrwlon();
cdelay(100);
for(i=0;i<NBMODULES;i++) {
printf("m%d: |", i);
for(i=0;i<SDRAM_PHY_MODULES;i++) {
if (show)
printf("m%d: |", i);
/* rst delay */
write_delay_rst(i);
@ -359,16 +343,16 @@ int write_level(void)
for(j=0;j<err_ddrphy_wdly;j++) {
int zero_count = 0;
int one_count = 0;
int show = 1;
#ifdef USDDRPHY
show = (j%16 == 0);
int show_iter = show;
#if SDRAM_PHY_DELAYS > 32
show_iter = (j%16 == 0) && show;
#endif
for (k=0; k<128; k++) {
for (k=0; k<loops; k++) {
ddrphy_wlevel_strobe_write(1);
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++;
@ -377,19 +361,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<err_ddrphy_wdly;j++) {
if (one_window_active) {
@ -408,19 +393,23 @@ int write_level(void)
}
}
}
delays[i] = one_window_best_start;
/* succeed only if the start of a 1s window has been found */
if (one_window_best_count > 0 && one_window_best_start > 0) {
delays[i] = one_window_best_start;
/* configure write delay */
write_delay_rst(i);
for(j=0; j<delays[i]; j++)
write_delay_inc(i);
printf(" delay: %02d\n", delays[i]);
/* configure write delay */
write_delay_rst(i);
for(j=0; j<delays[i]; j++)
write_delay_inc(i);
}
if (show)
printf(" delay: %02d\n", delays[i]);
}
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 +417,110 @@ int write_level(void)
return ok;
}
#endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */
static void write_level_cdly_range(unsigned int *best_error, int *best_cdly,
int cdly_start, int cdly_stop, int cdly_step)
{
int cdly;
int cdly_actual = 0;
int delays[SDRAM_PHY_MODULES];
/* scan through the range */
ddrphy_cdly_rst_write(1);
for (cdly = cdly_start; cdly < cdly_stop; cdly += cdly_step) {
/* increment cdly to current value */
while (cdly_actual < cdly) {
ddrphy_cdly_inc_write(1);
cdelay(10);
cdly_actual++;
}
/* write level using this delay */
if (write_level_scan(delays, 8, 0)) {
/* use the mean of delays for error calulation */
int delay_mean = 0;
for (int i=0; i < SDRAM_PHY_MODULES; ++i) {
delay_mean += delays[i];
}
delay_mean /= SDRAM_PHY_MODULES;
/* we want it to be at the start */
int ideal_delay = 4*SDRAM_PHY_DELAYS/32;
int error = ideal_delay - delay_mean;
if (error < 0)
error *= -1;
if (error < *best_error) {
*best_cdly = cdly;
*best_error = error;
}
printf("1");
} else {
printf("0");
}
}
}
int write_level(void)
{
int delays[SDRAM_PHY_MODULES];
unsigned int best_error = ~0u;
int best_cdly = -1;
int cdly_range_start;
int cdly_range_end;
int cdly_range_step;
printf("Command/Clk scan:\n");
/* Center write leveling by varying cdly. Searching through all possible
* values is slow, but we can use a simple optimization method of iterativly
* scanning smaller ranges with decreasing step */
cdly_range_start = 0;
cdly_range_end = SDRAM_PHY_DELAYS;
if (SDRAM_PHY_DELAYS > 32)
cdly_range_step = SDRAM_PHY_DELAYS/8;
else
cdly_range_step = 1;
while (cdly_range_step > 0) {
printf("|");
write_level_cdly_range(&best_error, &best_cdly,
cdly_range_start, cdly_range_end, cdly_range_step);
/* small optimization - stop if we have zero error */
if (best_error == 0)
break;
/* use best result as the middle of next range */
cdly_range_start = best_cdly - cdly_range_step;
cdly_range_end = best_cdly + cdly_range_step + 1;
if (cdly_range_start < 0)
cdly_range_start = 0;
if (cdly_range_end > 512)
cdly_range_end = 512;
cdly_range_step /= 4;
}
printf("| best: %d\n", best_cdly);
/* if we found any working delay then set it */
if (best_cdly >= 0) {
ddrphy_cdly_rst_write(1);
for (int i = 0; i < best_cdly; ++i) {
ddrphy_cdly_inc_write(1);
cdelay(10);
}
}
printf("Data scan:\n");
/* re-run write leveling the final time */
if (!write_level_scan(delays, 128, 1))
return 0;
return best_cdly >= 0;
}
#endif /* SDRAM_PHY_WRITE_LEVELING_CAPABLE */
static void read_delay_rst(int module) {
/* sel module */
@ -440,7 +532,7 @@ static void read_delay_rst(int module) {
/* unsel module */
ddrphy_dly_sel_write(0);
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
/* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */
ddrphy_dly_sel_write(0xFF);
ddrphy_dly_sel_write(0);
@ -457,7 +549,7 @@ static void read_delay_inc(int module) {
/* unsel module */
ddrphy_dly_sel_write(0);
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
/* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */
ddrphy_dly_sel_write(0xFF);
ddrphy_dly_sel_write(0);
@ -492,14 +584,14 @@ static void read_bitslip_inc(char m)
static int read_level_scan(int module, int bitslip)
{
unsigned int prv;
unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES];
unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
unsigned char tst[DFII_PIX_DATA_BYTES];
int p, i;
int score;
/* Generate pseudo-random sequence */
prv = 42;
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
prv = 1664525*prv + 1013904223;
prs[p][i] = prv;
@ -512,7 +604,7 @@ static int read_level_scan(int module, int bitslip)
cdelay(15);
/* Write test pattern */
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
prs[p], DFII_PIX_DATA_BYTES);
sdram_dfii_piwr_address_write(0);
@ -526,27 +618,27 @@ static int read_level_scan(int module, int bitslip)
printf("m%d, b%d: |", module, bitslip);
read_delay_rst(module);
for(i=0;i<ERR_DDRPHY_DELAY;i++) {
for(i=0;i<SDRAM_PHY_DELAYS;i++) {
int working = 1;
int show = 1;
#ifdef USDDRPHY
#if SDRAM_PHY_DELAYS > 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<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
/* read back test pattern */
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
tst, DFII_PIX_DATA_BYTES);
/* verify bytes matching current 'module' */
if (prs[p][ NBMODULES-1-module] != tst[ NBMODULES-1-module] ||
prs[p][2*NBMODULES-1-module] != tst[2*NBMODULES-1-module])
if (prs[p][ SDRAM_PHY_MODULES-1-module] != tst[ SDRAM_PHY_MODULES-1-module] ||
prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
working = 0;
}
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
@ -569,7 +661,7 @@ static int read_level_scan(int module, int bitslip)
static void read_level(int module)
{
unsigned int prv;
unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES];
unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
unsigned char tst[DFII_PIX_DATA_BYTES];
int p, i;
int working;
@ -579,7 +671,7 @@ static void read_level(int module)
/* Generate pseudo-random sequence */
prv = 42;
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
prv = 1664525*prv + 1013904223;
prs[p][i] = prv;
@ -592,7 +684,7 @@ static void read_level(int module)
cdelay(15);
/* Write test pattern */
for(p=0;p<DFII_NPHASES;p++)
for(p=0;p<SDRAM_PHY_PHASES;p++)
csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
prs[p], DFII_PIX_DATA_BYTES);
sdram_dfii_piwr_address_write(0);
@ -607,36 +699,36 @@ static void read_level(int module)
delay = 0;
read_delay_rst(module);
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<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
/* read back test pattern */
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
tst, DFII_PIX_DATA_BYTES);
/* verify bytes matching current 'module' */
if (prs[p][ NBMODULES-1-module] != tst[ NBMODULES-1-module] ||
prs[p][2*NBMODULES-1-module] != tst[2*NBMODULES-1-module])
if (prs[p][ SDRAM_PHY_MODULES-1-module] != tst[ SDRAM_PHY_MODULES-1-module] ||
prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
working = 0;
}
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
if(working)
break;
delay++;
if(delay >= ERR_DDRPHY_DELAY)
if(delay >= SDRAM_PHY_DELAYS)
break;
read_delay_inc(module);
}
delay_min = delay;
/* Get a bit further into the working zone */
#ifdef USDDRPHY
#if SDRAM_PHY_DELAYS > 32
for(i=0;i<16;i++) {
delay += 1;
read_delay_inc(module);
@ -648,35 +740,35 @@ static void read_level(int module)
/* Find largest working delay */
while(1) {
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
ddrphy_burstdet_clr_write(1);
#endif
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15);
working = 1;
for(p=0;p<DFII_NPHASES;p++) {
for(p=0;p<SDRAM_PHY_PHASES;p++) {
/* read back test pattern */
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
tst, DFII_PIX_DATA_BYTES);
/* verify bytes matching current 'module' */
if (prs[p][ NBMODULES-1-module] != tst[ NBMODULES-1-module] ||
prs[p][2*NBMODULES-1-module] != tst[2*NBMODULES-1-module])
if (prs[p][ SDRAM_PHY_MODULES-1-module] != tst[ SDRAM_PHY_MODULES-1-module] ||
prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
working = 0;
}
#ifdef ECP5DDRPHY
#ifdef SDRAM_PHY_ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
if(!working)
break;
delay++;
if(delay >= ERR_DDRPHY_DELAY)
if(delay >= SDRAM_PHY_DELAYS)
break;
read_delay_inc(module);
}
delay_max = delay;
if (delay_min >= ERR_DDRPHY_DELAY)
if (delay_min >= SDRAM_PHY_DELAYS)
printf("-");
else
printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2);
@ -919,8 +1011,9 @@ int memtest(void)
#ifdef CSR_SDRAM_BASE
#ifdef CSR_DDRPHY_BASE
int sdrlevel(void)
#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
static void read_leveling(void)
{
int module;
int bitslip;
@ -928,27 +1021,11 @@ int sdrlevel(void)
int best_score;
int best_bitslip;
sdrsw();
for(module=0; module<NBMODULES; module++) {
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
write_delay_rst(module);
#endif
read_delay_rst(module);
read_bitslip_rst(module);
}
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
if(!write_level())
return 0;
#endif
printf("Read leveling:\n");
for(module=0; module<NBMODULES; module++) {
for(module=0; module<SDRAM_PHY_MODULES; module++) {
/* scan possible read windows */
best_score = 0;
best_bitslip = 0;
for(bitslip=0; bitslip<ERR_DDRPHY_BITSLIP; bitslip++) {
for(bitslip=0; bitslip<SDRAM_PHY_BITSLIPS; bitslip++) {
/* compute score */
score = read_level_scan(module, bitslip);
read_level(module);
@ -958,7 +1035,7 @@ int sdrlevel(void)
best_score = score;
}
/* exit */
if (bitslip == ERR_DDRPHY_BITSLIP-1)
if (bitslip == SDRAM_PHY_BITSLIPS-1)
break;
/* increment bitslip */
read_bitslip_inc(module);
@ -974,7 +1051,38 @@ int sdrlevel(void)
read_level(module);
printf("\n");
}
}
int _write_level_cdly_scan = 1;
int sdrlevel(void)
{
int module;
sdrsw();
for(module=0; module<SDRAM_PHY_MODULES; module++) {
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
write_delay_rst(module);
#endif
read_delay_rst(module);
read_bitslip_rst(module);
}
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
printf("Write leveling:\n");
if (_write_level_cdly_scan) {
write_level();
} else {
/* use only the current cdly */
int delays[SDRAM_PHY_MODULES];
write_level_scan(delays, 128, 1);
}
#endif
#ifdef SDRAM_PHY_READ_LEVELING_CAPABLE
printf("Read leveling:\n");
read_leveling();
#endif
return 1;
}
@ -991,13 +1099,15 @@ int sdrinit(void)
init_sequence();
#ifdef CSR_DDRPHY_BASE
#if CSR_DDRPHY_EN_VTC_ADDR
ddrphy_en_vtc_write(0);
#endif
#ifdef DDRPHY_CMD_DELAY
ddrphy_cdly(DDRPHY_CMD_DELAY);
#endif
#if CSR_DDRPHY_EN_VTC_ADDR
ddrphy_en_vtc_write(0);
#endif
#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
sdrlevel();
#endif
#if CSR_DDRPHY_EN_VTC_ADDR
ddrphy_en_vtc_write(1);
#endif
@ -1067,8 +1177,8 @@ void sdrmpr(void)
printf("Read SDRAM MPR...\n");
/* rst phy */
for(module=0; module<NBMODULES; module++) {
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
for(module=0; module<SDRAM_PHY_MODULES; module++) {
#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
write_delay_rst(module);
#endif
read_delay_rst(module);
@ -1082,13 +1192,13 @@ void sdrmpr(void)
sdrmpron(MPR0_SEL);
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15);
for (module=0; module < NBMODULES; module++) {
for (module=0; module < SDRAM_PHY_MODULES; module++) {
printf("m%d: ", module);
for(phase=0; phase<DFII_NPHASES; phase++) {
for(phase=0; phase<SDRAM_PHY_PHASES; phase++) {
csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[phase],
buf, DFII_PIX_DATA_BYTES);
printf("%d", buf[ NBMODULES-module-1] & 0x1);
printf("%d", buf[2*NBMODULES-module-1] & 0x1);
printf("%d", buf[ SDRAM_PHY_MODULES-module-1] & 0x1);
printf("%d", buf[2*SDRAM_PHY_MODULES-module-1] & 0x1);
}
printf("\n");
}
@ -1098,7 +1208,12 @@ void sdrmpr(void)
sdrhw();
}
#endif
void sdr_cdly_scan(int enabled)
{
printf("Turning cdly scan %s\n", enabled ? "ON" : "OFF");
_write_level_cdly_scan = enabled;
}
#endif
#endif

View File

@ -11,17 +11,11 @@ void sdrrd(char *startaddr, char *dq);
void sdrrderr(char *count);
void sdrwr(char *startaddr);
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
void sdrwlon(void);
void sdrwloff(void);
int write_level(void);
#endif
#ifdef CSR_DDRPHY_BASE
void sdrwlon(void);
void sdrwloff(void);
int sdrlevel(void);
#endif
int memtest_silent(void);
int memtest(void);
@ -35,6 +29,7 @@ void ddrphy_cdly(unsigned int delay);
void sdrcal(void);
void sdrmrwr(char reg, int value);
void sdrmpr(void);
void sdr_cdly_scan(int enabled);
#endif
#endif /* __SDRAM_H */

View File

@ -7,6 +7,9 @@ extern "C" {
#include <system.h>
#include <generated/csr.h>
#include <generated/soc.h>
#ifdef CONFIG_CPU_HAS_INTERRUPT
#ifdef __picorv32__
// PicoRV32 has a very limited interrupt support, implemented via custom
@ -71,10 +74,8 @@ static inline unsigned int irq_getie(void)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
#elif defined (__rocket__)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
#elif defined (__microwatt__)
return 0; // FIXME
#elif defined (__blackparrot__)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;//TODO
#elif defined (__blackparrot__)
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0; /* FIXME */
#else
#error Unsupported architecture
#endif
@ -100,10 +101,8 @@ static inline void irq_setie(unsigned int ie)
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
#elif defined (__rocket__)
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
#elif defined (__microwatt__)
// FIXME
#elif defined (__blackparrot__)
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);//TODO:BP
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE); /* FIXME */
#else
#error Unsupported architecture
#endif
@ -131,10 +130,8 @@ static inline unsigned int irq_getmask(void)
return mask;
#elif defined (__rocket__)
return *((unsigned int *)PLIC_ENABLED) >> 1;
#elif defined (__microwatt__)
return 0; // FIXME
#elif defined (__blackparrot__)
//TODO:BP
return 0; /* FIXME */
#else
#error Unsupported architecture
#endif
@ -156,10 +153,8 @@ static inline void irq_setmask(unsigned int mask)
asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
#elif defined (__rocket__)
*((unsigned int *)PLIC_ENABLED) = mask << 1;
#elif defined (__microwatt__)
// FIXME
#elif defined (__blackparrot__)
//TODO:BP
/* FIXME */
#else
#error Unsupported architecture
#endif
@ -185,10 +180,8 @@ static inline unsigned int irq_pending(void)
return pending;
#elif defined (__rocket__)
return *((unsigned int *)PLIC_PENDING) >> 1;
#elif defined (__microwatt__)
return 0; // FIXME
#elif defined (__blackparrot__)
return csr_readl(PLIC_PENDING) >> 1;//TODO:BP
return csr_readl(PLIC_PENDING) >> 1; /* FIXME */
#else
#error Unsupported architecture
#endif
@ -198,4 +191,6 @@ static inline unsigned int irq_pending(void)
}
#endif
#endif
#endif /* __IRQ_H */

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
# This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
# 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()

View File

@ -141,6 +141,7 @@ def get_sdram_phy_settings(memtype, data_width, clk_freq):
}
return PhySettings(
phytype = "SDRAMPHYModel",
memtype = memtype,
databits = data_width,
dfi_databits = data_width if memtype == "SDR" else 2*data_width,
@ -165,6 +166,7 @@ class SimSoC(SoCSDRAM):
sdram_module = "MT48LC16M16",
sdram_init = [],
sdram_data_width = 32,
sdram_spd_data = None,
sdram_verbosity = 0,
**kwargs):
platform = Platform()
@ -181,9 +183,12 @@ class SimSoC(SoCSDRAM):
# SDRAM ------------------------------------------------------------------------------------
if with_sdram:
sdram_clk_freq = int(100e6) # FIXME: use 100MHz timings
sdram_module_cls = getattr(litedram_modules, sdram_module)
sdram_rate = "1:{}".format(sdram_module_nphases[sdram_module_cls.memtype])
sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate)
if sdram_spd_data is None:
sdram_module_cls = getattr(litedram_modules, sdram_module)
sdram_rate = "1:{}".format(sdram_module_nphases[sdram_module_cls.memtype])
sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate)
else:
sdram_module = litedram_modules.SDRAMModule.from_spd_data(sdram_spd_data, sdram_clk_freq)
phy_settings = get_sdram_phy_settings(
memtype = sdram_module.memtype,
data_width = sdram_data_width,
@ -265,10 +270,19 @@ class SimSoC(SoCSDRAM):
# Analyzer ---------------------------------------------------------------------------------
if with_analyzer:
analyzer_signals = [
self.cpu.ibus,
self.cpu.dbus
self.cpu.ibus.stb,
self.cpu.ibus.cyc,
self.cpu.ibus.adr,
self.cpu.ibus.we,
self.cpu.ibus.ack,
self.cpu.ibus.sel,
self.cpu.ibus.dat_w,
self.cpu.ibus.dat_r,
]
self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 512)
self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals,
depth = 512,
clock_domain = "sys",
csr_csv = "analyzer.csv")
self.add_csr("analyzer")
# Build --------------------------------------------------------------------------------------------
@ -284,6 +298,7 @@ def main():
parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip")
parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width")
parser.add_argument("--sdram-init", default=None, help="SDRAM init file")
parser.add_argument("--sdram-from-spd-data", default=None, help="Generate SDRAM module based on SPD data from file")
parser.add_argument("--sdram-verbosity", default=0, help="Set SDRAM checker verbosity")
parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support")
parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support")
@ -322,6 +337,9 @@ def main():
soc_kwargs["sdram_module"] = args.sdram_module
soc_kwargs["sdram_data_width"] = int(args.sdram_data_width)
soc_kwargs["sdram_verbosity"] = int(args.sdram_verbosity)
if args.sdram_from_spd_data:
with open(args.sdram_from_spd_data, "rb") as f:
soc_kwargs["sdram_spd_data"] = [int(b) for b in f.read()]
if args.with_ethernet or args.with_etherbone:
sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip})

View File

@ -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

View File

@ -97,14 +97,15 @@ if len(sys.argv) < 2:
if "init" in sys.argv[1:]:
os.chdir(os.path.join(current_path))
for name in repos.keys():
url, need_recursive, need_develop = repos[name]
# clone repo (recursive if needed)
print("[cloning " + name + "]...")
full_url = url + name
opts = "--recursive" if need_recursive else ""
subprocess.check_call(
"git clone " + full_url + " " + opts,
shell=True)
if not os.path.exists(name):
url, need_recursive, need_develop = repos[name]
# clone repo (recursive if needed)
print("[cloning " + name + "]...")
full_url = url + name
opts = "--recursive" if need_recursive else ""
subprocess.check_call(
"git clone " + full_url + " " + opts,
shell=True)
# Repositories installation
if "install" in sys.argv[1:]:
@ -132,6 +133,8 @@ if "install" in sys.argv[1:]:
# Repositories update
if "update" in sys.argv[1:]:
for name in repos.keys():
if not os.path.exists(name):
raise Exception("{} not initialized, please (re)-run init and install first.".format(name))
# update
print("[updating " + name + "]...")
os.chdir(os.path.join(current_path, name))

View File

@ -17,6 +17,7 @@ setup(
install_requires=[
"migen",
"pyserial",
"requests",
"pythondata-software-compiler_rt",
],
packages=find_packages(exclude=("test*", "sim*", "doc*")),

91
test/test_emif.py Normal file
View File

@ -0,0 +1,91 @@
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# 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<<i)
yield pads.addr.eq(addr)
yield pads.data.i.eq((data >> 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<<i)
yield pads.addr.eq(addr)
yield
yield pads.oe_n.eq(0)
for i in range(8):
yield
data >>= 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)])

View File

@ -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)