Merge branch 'master' into litex-sm2py
This commit is contained in:
commit
317ea7edd1
|
@ -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")),
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 ----------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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 ---------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from litex.soc.cores.cpu.serv.core import SERV
|
|
@ -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)
|
|
@ -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")
|
||||
)
|
||||
)
|
|
@ -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=[
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 $< $@
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.section .text, "ax", @progbits
|
||||
.global boot_helper
|
||||
boot_helper:
|
||||
jr x13
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
1
setup.py
1
setup.py
|
@ -17,6 +17,7 @@ setup(
|
|||
install_requires=[
|
||||
"migen",
|
||||
"pyserial",
|
||||
"requests",
|
||||
"pythondata-software-compiler_rt",
|
||||
],
|
||||
packages=find_packages(exclude=("test*", "sim*", "doc*")),
|
||||
|
|
|
@ -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)])
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue