This commit is contained in:
Sean Cross 2019-04-19 16:47:55 +08:00
commit c780fb22b7
29 changed files with 633 additions and 390 deletions

View file

@ -1,14 +1,14 @@
Unless otherwise noted, LiteX is copyright (C) 2012-2018 Florent Kermarrec. Unless otherwise noted, LiteX is copyright (C) 2012-2019 Florent Kermarrec.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this 1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

2
README
View file

@ -5,7 +5,7 @@
Migen inside Migen inside
Build your hardware, easily! Build your hardware, easily!
Copyright 2012-2018 / EnjoyDigital Copyright 2012-2019 / EnjoyDigital
[> Intro [> Intro
-------- --------

View file

@ -14,6 +14,9 @@ from litex.soc.integration.builder import *
from litedram.modules import EDY4016A from litedram.modules import EDY4016A
from litedram.phy import usddrphy from litedram.phy import usddrphy
from liteeth.phy.ku_1000basex import KU_1000BASEX
from liteeth.core.mac import LiteEthMAC
# CRG ---------------------------------------------------------------------------------------------- # CRG ----------------------------------------------------------------------------------------------
class _CRG(Module): class _CRG(Module):
@ -92,15 +95,61 @@ class BaseSoC(SoCSDRAM):
sdram_module.geom_settings, sdram_module.geom_settings,
sdram_module.timing_settings) sdram_module.timing_settings)
# EthernetSoC ------------------------------------------------------------------------------------------
class EthernetSoC(BaseSoC):
csr_map = {
"ethphy": 18,
"ethmac": 19
}
csr_map.update(BaseSoC.csr_map)
interrupt_map = {
"ethmac": 3,
}
interrupt_map.update(BaseSoC.interrupt_map)
mem_map = {
"ethmac": 0x30000000, # (shadow @0xb0000000)
}
mem_map.update(BaseSoC.mem_map)
def __init__(self, **kwargs):
BaseSoC.__init__(self, **kwargs)
self.comb += self.platform.request("sfp_tx_disable_n", 0).eq(1)
self.submodules.ethphy = KU_1000BASEX(self.crg.cd_clk200.clk,
self.platform.request("sfp", 0), sys_clk_freq=self.clk_freq)
self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32,
interface="wishbone", endianness=self.cpu.endianness)
self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000)
self.crg.cd_sys.clk.attr.add("keep")
self.ethphy.cd_eth_rx.clk.attr.add("keep")
self.ethphy.cd_eth_tx.clk.attr.add("keep")
self.platform.add_period_constraint(self.ethphy.cd_eth_rx.clk, 1e9/125e6)
self.platform.add_period_constraint(self.ethphy.cd_eth_tx.clk, 1e9/125e6)
self.platform.add_false_path_constraints(
self.crg.cd_sys.clk,
self.ethphy.cd_eth_rx.clk,
self.ethphy.cd_eth_tx.clk)
self.platform.add_platform_command("set_property SEVERITY {{Warning}} [get_drc_checks REQP-1753]")
# Build -------------------------------------------------------------------------------------------- # Build --------------------------------------------------------------------------------------------
def main(): def main():
parser = argparse.ArgumentParser(description="LiteX SoC on KCU105") parser = argparse.ArgumentParser(description="LiteX SoC on KCU105")
builder_args(parser) builder_args(parser)
soc_sdram_args(parser) soc_sdram_args(parser)
parser.add_argument("--with-ethernet", action="store_true",
help="enable Ethernet support")
args = parser.parse_args() args = parser.parse_args()
soc = BaseSoC(**soc_sdram_argdict(args)) cls = EthernetSoC if args.with_ethernet else BaseSoC
soc = cls(**soc_sdram_argdict(args))
builder = Builder(soc, **builder_argdict(args)) builder = Builder(soc, **builder_argdict(args))
builder.build() builder.build()

View file

@ -13,7 +13,10 @@ from litex.soc.integration.soc_sdram import *
from litex.soc.integration.builder import * from litex.soc.integration.builder import *
from litedram.modules import MT41K64M16 from litedram.modules import MT41K64M16
from litedram.phy import ECP5DDRPHY, ECP5DDRPHYInit from litedram.phy import ECP5DDRPHY
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
from liteeth.core.mac import LiteEthMAC
# CRG ---------------------------------------------------------------------------------------------- # CRG ----------------------------------------------------------------------------------------------
@ -70,7 +73,7 @@ class BaseSoC(SoCSDRAM):
csr_map.update(SoCSDRAM.csr_map) csr_map.update(SoCSDRAM.csr_map)
def __init__(self, toolchain="diamond", **kwargs): def __init__(self, toolchain="diamond", **kwargs):
platform = versa_ecp5.Platform(toolchain=toolchain) platform = versa_ecp5.Platform(toolchain=toolchain)
sys_clk_freq = int(50e6) sys_clk_freq = int(75e6)
SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq,
integrated_rom_size=0x8000, integrated_rom_size=0x8000,
**kwargs) **kwargs)
@ -84,24 +87,61 @@ class BaseSoC(SoCSDRAM):
platform.request("ddram"), platform.request("ddram"),
sys_clk_freq=sys_clk_freq) sys_clk_freq=sys_clk_freq)
self.add_constant("ECP5DDRPHY", None) self.add_constant("ECP5DDRPHY", None)
ddrphy_init = ECP5DDRPHYInit(self.crg, self.ddrphy) self.comb += crg.stop.eq(self.ddrphy.init.stop)
self.submodules += ddrphy_init
sdram_module = MT41K64M16(sys_clk_freq, "1:2") sdram_module = MT41K64M16(sys_clk_freq, "1:2")
self.register_sdram(self.ddrphy, self.register_sdram(self.ddrphy,
sdram_module.geom_settings, sdram_module.geom_settings,
sdram_module.timing_settings) sdram_module.timing_settings)
# EthernetSoC --------------------------------------------------------------------------------------
class EthernetSoC(BaseSoC):
csr_map = {
"ethphy": 18,
"ethmac": 19
}
csr_map.update(BaseSoC.csr_map)
interrupt_map = {
"ethmac": 3,
}
interrupt_map.update(BaseSoC.interrupt_map)
mem_map = {
"ethmac": 0x30000000, # (shadow @0xb0000000)
}
mem_map.update(BaseSoC.mem_map)
def __init__(self, toolchain="diamond", **kwargs):
BaseSoC.__init__(self, toolchain=toolchain, **kwargs)
self.submodules.ethphy = LiteEthPHYRGMII(
self.platform.request("eth_clocks"),
self.platform.request("eth"))
self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32,
interface="wishbone", endianness=self.cpu.endianness)
self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000)
self.ethphy.crg.cd_eth_rx.clk.attr.add("keep")
self.ethphy.crg.cd_eth_tx.clk.attr.add("keep")
self.platform.add_period_constraint(self.ethphy.crg.cd_eth_rx.clk, 1e9/125e6)
self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk, 1e9/125e6)
# Build -------------------------------------------------------------------------------------------- # Build --------------------------------------------------------------------------------------------
def main(): def main():
parser = argparse.ArgumentParser(description="LiteX SoC on ECP5") parser = argparse.ArgumentParser(description="LiteX SoC on Versa ECP5")
parser.add_argument("--gateware-toolchain", dest="toolchain", default="diamond", parser.add_argument("--gateware-toolchain", dest="toolchain", default="diamond",
help='gateware toolchain to use, diamond (default) or trellis') help='gateware toolchain to use, diamond (default) or trellis')
builder_args(parser) builder_args(parser)
soc_sdram_args(parser) soc_sdram_args(parser)
parser.add_argument("--with-ethernet", action="store_true",
help="enable Ethernet support")
args = parser.parse_args() args = parser.parse_args()
soc = BaseSoC(toolchain=args.toolchain, **soc_sdram_argdict(args)) cls = EthernetSoC if args.with_ethernet else BaseSoC
soc = cls(args.toolchain, **soc_sdram_argdict(args))
builder = Builder(soc, **builder_argdict(args)) builder = Builder(soc, **builder_argdict(args))
builder.build() builder.build()

View file

@ -1,6 +1,9 @@
from migen.fhdl.module import Module from migen.fhdl.module import Module
from migen.fhdl.specials import Instance from migen.fhdl.specials import Instance
from migen.genlib.io import DifferentialInput, DifferentialOutput from migen.genlib.io import DifferentialInput, DifferentialOutput
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.fhdl.structure import *
class AlteraDifferentialInputImpl(Module): class AlteraDifferentialInputImpl(Module):
@ -32,8 +35,29 @@ class AlteraDifferentialOutput:
def lower(dr): def lower(dr):
return AlteraDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n) return AlteraDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
class AlteraAsyncResetSynchronizerImpl(Module):
def __init__(self, cd, async_reset):
if not hasattr(async_reset, "attr"):
i, async_reset = async_reset, Signal()
self.comb += async_reset.eq(i)
rst_meta = Signal()
self.specials += [
Instance("DFF", i_d=0, i_clk=cd.clk, i_clrn=1,
i_prn=async_reset, o_q=rst_meta,
attr={"async_reg", "ars_ff1"}),
Instance("DFF", i_d=rst_meta, i_clk=cd.clk, i_clrn=1,
i_prn=async_reset, o_q=cd.rst,
attr={"async_reg", "ars_ff2"})
]
class AlteraAsyncResetSynchronizer:
@staticmethod
def lower(dr):
return AlteraAsyncResetSynchronizerImpl(dr.cd, dr.async_reset)
altera_special_overrides = { altera_special_overrides = {
DifferentialInput: AlteraDifferentialInput, DifferentialInput: AlteraDifferentialInput,
DifferentialOutput: AlteraDifferentialOutput DifferentialOutput: AlteraDifferentialOutput,
AsyncResetSynchronizer: AlteraAsyncResetSynchronizer
} }

View file

@ -25,3 +25,10 @@ class AlteraPlatform(GenericPlatform):
if hasattr(clk, "p"): if hasattr(clk, "p"):
clk = clk.p clk = clk.p
self.toolchain.add_period_constraint(self, clk, period) self.toolchain.add_period_constraint(self, clk, period)
def add_false_path_constraint(self, from_, to):
if hasattr(from_, "p"):
from_ = from_.p
if hasattr(to, "p"):
to = to.p
self.toolchain.add_false_path_constraint(self, from_, to)

View file

@ -1,8 +1,9 @@
# This file is Copyright (c) 2013 Florent Kermarrec <florent@enjoy-digital.fr> # This file is Copyright (c) 2013-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD # License: BSD
import os import os
import subprocess import subprocess
import math
from migen.fhdl.structure import _Fragment from migen.fhdl.structure import _Fragment
@ -50,7 +51,7 @@ def _format_qsf(signame, pin, others, resname):
return '\n'.join(fmt_c) return '\n'.join(fmt_c)
def _build_qsf(named_sc, named_pc): def _build_qsf(named_sc, named_pc, build_name):
lines = [] lines = []
for sig, pins, others, resname in named_sc: for sig, pins, others, resname in named_sc:
if len(pins) > 1: if len(pins) > 1:
@ -64,10 +65,27 @@ def _build_qsf(named_sc, named_pc):
lines.append("") lines.append("")
lines.append("\n\n".join(named_pc)) lines.append("\n\n".join(named_pc))
lines.append("set_global_assignment -name top_level_entity top") # Set top level name to "build_name" in .qsf file instead always use "top" name
lines.append("set_global_assignment -name top_level_entity " + build_name)
return "\n".join(lines) return "\n".join(lines)
def _build_sdc(clocks, false_paths, vns, build_name):
lines = []
for clk, period in sorted(clocks.items(), key=lambda x: x[0].duid):
lines.append(
"create_clock -name {clk} -period ".format(clk=vns.get_name(clk)) + str(period) +
" [get_ports {{{clk}}}]".format(clk=vns.get_name(clk)))
for from_, to in sorted(false_paths,
key=lambda x: (x[0].duid, x[1].duid)):
lines.append(
"set_false_path "
"-from [get_clocks {{{from_}}}] "
"-to [get_clocks {{{to}}}]".format(
from_=vns.get_name(from_), to=vns.get_name(to)))
tools.write_to_file("{}.sdc".format(build_name), "\n".join(lines))
def _build_files(device, sources, vincpaths, named_sc, named_pc, build_name): def _build_files(device, sources, vincpaths, named_sc, named_pc, build_name):
lines = [] lines = []
for filename, language, library in sources: for filename, language, library in sources:
@ -81,12 +99,13 @@ def _build_files(device, sources, vincpaths, named_sc, named_pc, build_name):
lang=language.upper(), lang=language.upper(),
path=filename.replace("\\", "/"), path=filename.replace("\\", "/"),
lib=library)) lib=library))
lines.append("set_global_assignment -name SDC_FILE {}.sdc".format(build_name))
for path in vincpaths: for path in vincpaths:
lines.append("set_global_assignment -name SEARCH_PATH {}".format( lines.append("set_global_assignment -name SEARCH_PATH {}".format(
path.replace("\\", "/"))) path.replace("\\", "/")))
lines.append(_build_qsf(named_sc, named_pc)) lines.append(_build_qsf(named_sc, named_pc, build_name))
lines.append("set_global_assignment -name DEVICE {}".format(device)) lines.append("set_global_assignment -name DEVICE {}".format(device))
tools.write_to_file("{}.qsf".format(build_name), "\n".join(lines)) tools.write_to_file("{}.qsf".format(build_name), "\n".join(lines))
@ -116,6 +135,10 @@ fi
class AlteraQuartusToolchain: class AlteraQuartusToolchain:
def __init__(self):
self.clocks = dict()
self.false_paths = set()
def build(self, platform, fragment, build_dir="build", build_name="top", def build(self, platform, fragment, build_dir="build", build_name="top",
toolchain_path=None, run=True, **kwargs): toolchain_path=None, run=True, **kwargs):
if toolchain_path is None: if toolchain_path is None:
@ -139,6 +162,8 @@ class AlteraQuartusToolchain:
named_sc, named_sc,
named_pc, named_pc,
build_name) build_name)
_build_sdc(self.clocks, self.false_paths, v_output.ns, build_name)
if run: if run:
_run_quartus(build_name, toolchain_path) _run_quartus(build_name, toolchain_path)
@ -147,12 +172,11 @@ class AlteraQuartusToolchain:
return v_output.ns return v_output.ns
def add_period_constraint(self, platform, clk, period): def add_period_constraint(self, platform, clk, period):
# TODO: handle differential clk if clk in self.clocks:
platform.add_platform_command( raise ValueError("A period constraint already exists")
"set_global_assignment -name duty_cycle 50 -section_id {clk}", period = math.floor(period*1e3)/1e3 # round to lowest picosecond
clk=clk) self.clocks[clk] = period
platform.add_platform_command(
"set_global_assignment -name fmax_requirement \"{freq} MHz\" " def add_false_path_constraint(self, platform, from_, to):
"-section_id {clk}".format(freq=(1. / period) * 1000, if (to, from_) not in self.false_paths:
clk="{clk}"), self.false_paths.add((from_, to))
clk=clk)

View file

@ -143,7 +143,7 @@ class LatticeTrellisToolchain:
self.build_template = [ self.build_template = [
"yosys -q -l {build_name}.rpt {build_name}.ys", "yosys -q -l {build_name}.rpt {build_name}.ys",
"nextpnr-ecp5 --json {build_name}.json --lpf {build_name}.lpf --textcfg {build_name}.config --{architecture} --package {package} --freq {freq_constraint}", "nextpnr-ecp5 --json {build_name}.json --lpf {build_name}.lpf --textcfg {build_name}.config --{architecture} --package {package} --freq {freq_constraint}",
"ecppack {build_name}.config {build_name}.bit" "ecppack {build_name}.config --svf {build_name}.svf --bit {build_name}.bit"
] ]
self.freq_constraints = dict() self.freq_constraints = dict()

View file

@ -23,6 +23,8 @@ def _format_io_constraint(c):
elif isinstance(c, IOStandard): elif isinstance(c, IOStandard):
return "-io_std {} ".format(c.name) return "-io_std {} ".format(c.name)
elif isinstance(c, Misc): elif isinstance(c, Misc):
return "-RES_PULL {} ".format(c.misc)
else:
raise NotImplementedError raise NotImplementedError
@ -183,7 +185,10 @@ def _build_script(build_name, device, toolchain_path, ver=None):
copy_stmt = "copy" copy_stmt = "copy"
fail_stmt = " || exit /b" fail_stmt = " || exit /b"
else: else:
raise NotImplementedError script_ext = ".sh"
build_script_contents = "# Autogenerated by Migen\n\n"
copy_stmt = "cp"
fail_stmt = " || exit 1"
build_script_file = "build_" + build_name + script_ext build_script_file = "build_" + build_name + script_ext
tools.write_to_file(build_script_file, build_script_contents, tools.write_to_file(build_script_file, build_script_contents,

View file

@ -203,7 +203,7 @@ static void cb(int sock, short which, void *arg)
} }
} }
int main() int main(int argc, char *argv[])
{ {
void *vdut=NULL; void *vdut=NULL;
struct timeval tv; struct timeval tv;
@ -224,6 +224,7 @@ int main()
goto out; goto out;
} }
litex_sim_init_cmdargs(argc, argv);
if(RC_OK != (ret = litex_sim_initialize_all(&vdut, base))) if(RC_OK != (ret = litex_sim_initialize_all(&vdut, base)))
{ {
goto out; goto out;

View file

@ -17,6 +17,11 @@ extern "C" void litex_sim_eval(void *vdut)
dut->eval(); dut->eval();
} }
extern "C" void litex_sim_init_cmdargs(int argc, char *argv[])
{
Verilated::commandArgs(argc, argv);
}
extern "C" void litex_sim_init_tracer(void *vdut) extern "C" void litex_sim_init_tracer(void *vdut)
{ {
Vdut *dut = (Vdut*)vdut; Vdut *dut = (Vdut*)vdut;

View file

@ -4,6 +4,7 @@
#define __VERIL_H_ #define __VERIL_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" void litex_sim_init_cmdargs(int argc, char *argv[]);
extern "C" void litex_sim_eval(void *vdut); extern "C" void litex_sim_eval(void *vdut);
extern "C" void litex_sim_init_tracer(void *vdut); extern "C" void litex_sim_init_tracer(void *vdut);
extern "C" void litex_sim_tracer_dump(); extern "C" void litex_sim_tracer_dump();

View file

@ -265,7 +265,7 @@ setattr -set keep 1 a:async_reg=true
synth_xilinx -top top synth_xilinx -top top
write_edif -attrprop {build_name}.edif write_edif -pvector bra -attrprop {build_name}.edif
""".format(build_name=build_name) """.format(build_name=build_name)
ys_name = build_name + ".ys" ys_name = build_name + ".ys"

View file

@ -1,9 +1,10 @@
# This file is Copyright (c) 2014 Florent Kermarrec <florent@enjoy-digital.fr> # This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD # License: BSD
import os import os
import subprocess import subprocess
import sys import sys
import math
from migen.fhdl.structure import _Fragment from migen.fhdl.structure import _Fragment
@ -117,8 +118,9 @@ class XilinxVivadoToolchain:
for filename, language, library in sources: for filename, language, library in sources:
filename_tcl = "{" + filename + "}" filename_tcl = "{" + filename + "}"
tcl.append("add_files " + filename_tcl) tcl.append("add_files " + filename_tcl)
tcl.append("set_property library {} [get_files {}]" if language == "vhdl":
.format(library, filename_tcl)) tcl.append("set_property library {} [get_files {}]"
.format(library, filename_tcl))
for filename in edifs: for filename in edifs:
filename_tcl = "{" + filename + "}" filename_tcl = "{" + filename + "}"
tcl.append("read_edif " + filename_tcl) tcl.append("read_edif " + filename_tcl)
@ -196,23 +198,23 @@ class XilinxVivadoToolchain:
# The asynchronous input to a MultiReg is a false path # The asynchronous input to a MultiReg is a false path
platform.add_platform_command( platform.add_platform_command(
"set_false_path -quiet " "set_false_path -quiet "
"-to [get_nets -filter {{mr_ff == TRUE}}]" "-to [get_nets -quiet -filter {{mr_ff == TRUE}}]"
) )
# The asychronous reset input to the AsyncResetSynchronizer is a false # The asychronous reset input to the AsyncResetSynchronizer is a false
# path # path
platform.add_platform_command( platform.add_platform_command(
"set_false_path -quiet " "set_false_path -quiet "
"-to [get_pins -filter {{REF_PIN_NAME == PRE}} " "-to [get_pins -quiet -filter {{REF_PIN_NAME == PRE}} "
"-of [get_cells -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]" "-of [get_cells -quiet -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]"
) )
# clock_period-2ns to resolve metastability on the wire between the # clock_period-2ns to resolve metastability on the wire between the
# AsyncResetSynchronizer FFs # AsyncResetSynchronizer FFs
platform.add_platform_command( platform.add_platform_command(
"set_max_delay 2 -quiet " "set_max_delay 2 -quiet "
"-from [get_pins -filter {{REF_PIN_NAME == Q}} " "-from [get_pins -quiet -filter {{REF_PIN_NAME == Q}} "
"-of [get_cells -filter {{ars_ff1 == TRUE}}]] " "-of [get_cells -quiet -filter {{ars_ff1 == TRUE}}]] "
"-to [get_pins -filter {{REF_PIN_NAME == D}} " "-to [get_pins -quiet -filter {{REF_PIN_NAME == D}} "
"-of [get_cells -filter {{ars_ff2 == TRUE}}]]" "-of [get_cells -quiet -filter {{ars_ff2 == TRUE}}]]"
) )
def build(self, platform, fragment, build_dir="build", build_name="top", def build(self, platform, fragment, build_dir="build", build_name="top",
@ -250,6 +252,7 @@ class XilinxVivadoToolchain:
def add_period_constraint(self, platform, clk, period): def add_period_constraint(self, platform, clk, period):
if clk in self.clocks: if clk in self.clocks:
raise ValueError("A period constraint already exists") raise ValueError("A period constraint already exists")
period = math.floor(period*1e3)/1e3 # round to lowest picosecond
self.clocks[clk] = period self.clocks[clk] = period
def add_false_path_constraint(self, platform, from_, to): def add_false_path_constraint(self, platform, from_, to):

View file

@ -1,9 +1,4 @@
""" """Clock Abstraction Modules"""
Clock Abstraction Modules
Made in Paris-CDG while waiting a delayed Air-France KLM flight...
"""
from migen import * from migen import *
from migen.genlib.io import DifferentialInput from migen.genlib.io import DifferentialInput
@ -15,13 +10,14 @@ from litex.soc.interconnect.csr import *
def period_ns(freq): def period_ns(freq):
return 1e9/freq return 1e9/freq
# Xilinx / 7-Series # Xilinx / 7-Series --------------------------------------------------------------------------------
class S7Clocking(Module, AutoCSR): class S7Clocking(Module, AutoCSR):
clkfbout_mult_frange = (2, 64+1) clkfbout_mult_frange = (2, 64+1)
clkout_divide_range = (1, 128+1) clkout_divide_range = (1, 128+1)
def __init__(self): def __init__(self, vco_margin=0):
self.vco_margin = vco_margin
self.reset = Signal() self.reset = Signal()
self.locked = Signal() self.locked = Signal()
self.clkin_freq = None self.clkin_freq = None
@ -62,30 +58,32 @@ class S7Clocking(Module, AutoCSR):
def compute_config(self): def compute_config(self):
config = {} config = {}
config["divclk_divide"] = 1 for divclk_divide in range(*self.divclk_divide_range):
for clkfbout_mult in range(*self.clkfbout_mult_frange): config["divclk_divide"] = divclk_divide
all_valid = True for clkfbout_mult in range(*self.clkfbout_mult_frange):
vco_freq = self.clkin_freq*clkfbout_mult all_valid = True
(vco_freq_min, vco_freq_max) = self.vco_freq_range vco_freq = self.clkin_freq*clkfbout_mult/divclk_divide
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: (vco_freq_min, vco_freq_max) = self.vco_freq_range
for n, (clk, f, p, m) in sorted(self.clkouts.items()): if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and
valid = False vco_freq <= vco_freq_max*(1 - self.vco_margin)):
for d in range(*self.clkout_divide_range): for n, (clk, f, p, m) in sorted(self.clkouts.items()):
clk_freq = vco_freq/d valid = False
if abs(clk_freq - f) < f*m: for d in range(*self.clkout_divide_range):
config["clkout{}_freq".format(n)] = clk_freq clk_freq = vco_freq/d
config["clkout{}_divide".format(n)] = d if abs(clk_freq - f) < f*m:
config["clkout{}_phase".format(n)] = p config["clkout{}_freq".format(n)] = clk_freq
valid = True config["clkout{}_divide".format(n)] = d
break config["clkout{}_phase".format(n)] = p
if not valid: valid = True
all_valid = False break
else: if not valid:
all_valid = False all_valid = False
if all_valid: else:
config["vco"] = vco_freq all_valid = False
config["clkfbout_mult"] = clkfbout_mult if all_valid:
return config config["vco"] = vco_freq
config["clkfbout_mult"] = clkfbout_mult
return config
raise ValueError("No PLL config found") raise ValueError("No PLL config found")
def expose_drp(self): def expose_drp(self):
@ -127,6 +125,7 @@ class S7PLL(S7Clocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
S7Clocking.__init__(self) S7Clocking.__init__(self)
self.divclk_divide_range = (1, 56+1)
self.vco_freq_range = { self.vco_freq_range = {
-1: (800e6, 2133e6), -1: (800e6, 2133e6),
-2: (800e6, 1866e6), -2: (800e6, 1866e6),
@ -157,6 +156,7 @@ class S7MMCM(S7Clocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
S7Clocking.__init__(self) S7Clocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (10e6, 800e6), -1: (10e6, 800e6),
-2: (10e6, 933e6), -2: (10e6, 933e6),
@ -204,7 +204,7 @@ class S7IDELAYCTRL(Module):
) )
self.specials += Instance("IDELAYCTRL", i_REFCLK=cd.clk, i_RST=ic_reset) self.specials += Instance("IDELAYCTRL", i_REFCLK=cd.clk, i_RST=ic_reset)
# Xilinx / Ultrascale # Xilinx / Ultrascale ------------------------------------------------------------------------------
# TODO: # TODO:
# - use Ultrascale primitives instead of 7-Series' ones. (Vivado recognize and convert them). # - use Ultrascale primitives instead of 7-Series' ones. (Vivado recognize and convert them).
@ -213,7 +213,8 @@ class USClocking(Module, AutoCSR):
clkfbout_mult_frange = (2, 64+1) clkfbout_mult_frange = (2, 64+1)
clkout_divide_range = (1, 128+1) clkout_divide_range = (1, 128+1)
def __init__(self): def __init__(self, vco_margin=0):
self.vco_margin = vco_margin
self.reset = Signal() self.reset = Signal()
self.locked = Signal() self.locked = Signal()
self.clkin_freq = None self.clkin_freq = None
@ -254,30 +255,32 @@ class USClocking(Module, AutoCSR):
def compute_config(self): def compute_config(self):
config = {} config = {}
config["divclk_divide"] = 1 for divclk_divide in range(*self.divclk_divide_range):
for clkfbout_mult in range(*self.clkfbout_mult_frange): config["divclk_divide"] = divclk_divide
all_valid = True for clkfbout_mult in range(*self.clkfbout_mult_frange):
vco_freq = self.clkin_freq*clkfbout_mult all_valid = True
(vco_freq_min, vco_freq_max) = self.vco_freq_range vco_freq = self.clkin_freq*clkfbout_mult/divclk_divide
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: (vco_freq_min, vco_freq_max) = self.vco_freq_range
for n, (clk, f, p, m) in sorted(self.clkouts.items()): if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and
valid = False vco_freq <= vco_freq_max*(1 - self.vco_margin)):
for d in range(*self.clkout_divide_range): for n, (clk, f, p, m) in sorted(self.clkouts.items()):
clk_freq = vco_freq/d valid = False
if abs(clk_freq - f) < f*m: for d in range(*self.clkout_divide_range):
config["clkout{}_freq".format(n)] = clk_freq clk_freq = vco_freq/d
config["clkout{}_divide".format(n)] = d if abs(clk_freq - f) < f*m:
config["clkout{}_phase".format(n)] = p config["clkout{}_freq".format(n)] = clk_freq
valid = True config["clkout{}_divide".format(n)] = d
break config["clkout{}_phase".format(n)] = p
if not valid: valid = True
all_valid = False break
else: if not valid:
all_valid = False all_valid = False
if all_valid: else:
config["vco"] = vco_freq all_valid = False
config["clkfbout_mult"] = clkfbout_mult if all_valid:
return config config["vco"] = vco_freq
config["clkfbout_mult"] = clkfbout_mult
return config
raise ValueError("No PLL config found") raise ValueError("No PLL config found")
def expose_drp(self): def expose_drp(self):
@ -318,12 +321,12 @@ class USPLL(USClocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
USClocking.__init__(self) USClocking.__init__(self)
self.divclk_divide_range = (1, 56+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (70e6, 800e6), -1: (70e6, 800e6),
-2: (70e6, 933e6), -2: (70e6, 933e6),
-3: (70e6, 1066e6), -3: (70e6, 1066e6),
}[speedgrade] }[speedgrade]
self.vco_freq_range = { self.vco_freq_range = {
-1: (600e6, 1200e6), -1: (600e6, 1200e6),
-2: (600e6, 1335e6), -2: (600e6, 1335e6),
@ -354,12 +357,12 @@ class USMMCM(USClocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
USClocking.__init__(self) USClocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (10e6, 800e6), -1: (10e6, 800e6),
-2: (10e6, 933e6), -2: (10e6, 933e6),
-3: (10e6, 1066e6), -3: (10e6, 1066e6),
}[speedgrade] }[speedgrade]
self.vco_freq_range = { self.vco_freq_range = {
-1: (600e6, 1200e6), -1: (600e6, 1200e6),
-2: (600e6, 1440e6), -2: (600e6, 1440e6),
@ -404,7 +407,7 @@ class USIDELAYCTRL(Module):
i_REFCLK=cd.clk, i_REFCLK=cd.clk,
i_RST=ic_reset) i_RST=ic_reset)
# Lattice / ECP5 # Lattice / ECP5 -----------------------------------------------------------------------------------
# TODO: # TODO:
# - add proper phase support. # - add proper phase support.

View file

@ -16,8 +16,11 @@ class VexRiscv(Module, AutoCSR):
def __init__(self, platform, cpu_reset_address, variant=None): def __init__(self, platform, cpu_reset_address, variant=None):
variant = "std" if variant is None else variant variant = "std" if variant is None else variant
variant = "std_debug" if variant == "debug" else variant variant = "std_debug" if variant == "debug" else variant
variants = ("std", "std_debug", "lite", "lite_debug", "min", "min_debug") variants = ("std", "std_debug", "lite", "lite_debug", "min", "min_debug", "full", "full_debug")
assert variant in variants, "Unsupported variant %s" % variant assert variant in variants, "Unsupported variant %s" % variant
self.platform = platform
self.variant = variant
self.external_variant = None
self.reset = Signal() self.reset = Signal()
self.ibus = ibus = wishbone.Interface() self.ibus = ibus = wishbone.Interface()
self.dbus = dbus = wishbone.Interface() self.dbus = dbus = wishbone.Interface()
@ -60,9 +63,6 @@ class VexRiscv(Module, AutoCSR):
if "debug" in variant: if "debug" in variant:
self.add_debug() self.add_debug()
# add verilog sources
self.add_sources(platform, variant)
def add_debug(self): def add_debug(self):
debug_reset = Signal() debug_reset = Signal()
@ -156,12 +156,20 @@ class VexRiscv(Module, AutoCSR):
"std_debug": "VexRiscv_Debug.v", "std_debug": "VexRiscv_Debug.v",
"lite": "VexRiscv_Lite.v", "lite": "VexRiscv_Lite.v",
"lite_debug": "VexRiscv_LiteDebug.v", "lite_debug": "VexRiscv_LiteDebug.v",
"min": "VexRiscv_Lite.v", "min": "VexRiscv_Min.v",
"min_debug": "VexRiscv_LiteDebug.v", "min_debug": "VexRiscv_MinDebug.v",
"full": "VexRiscv_Full.v",
"full_debug": "VexRiscv_FullDebug.v",
} }
cpu_filename = verilog_variants[variant] cpu_filename = verilog_variants[variant]
vdir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog") vdir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")
platform.add_source(os.path.join(vdir, cpu_filename)) platform.add_source(os.path.join(vdir, cpu_filename))
def use_external_variant(self, variant_filename):
self.external_variant = True
self.platform.add_source(variant_filename)
def do_finalize(self): def do_finalize(self):
if not self.external_variant:
self.add_sources(self.platform, self.variant)
self.specials += Instance("VexRiscv", **self.cpu_params) self.specials += Instance("VexRiscv", **self.cpu_params)

@ -1 +1 @@
Subproject commit d7bbc2c167f1a0886c446d3c305d0ed4388570be Subproject commit ebe4064653bc143bf92a0ccdd1099173620fcbf5

View file

@ -1,5 +1,7 @@
import os
import struct import struct
import inspect import inspect
import json
from operator import itemgetter from operator import itemgetter
from migen import * from migen import *
@ -36,24 +38,43 @@ def mem_decoder(address, start=26, end=29):
def get_mem_data(filename, endianness="big", mem_size=None): def get_mem_data(filename, endianness="big", mem_size=None):
data = [] # create memory regions
with open(filename, "rb") as mem_file: _, ext = os.path.splitext(filename)
while True: if ext == ".json":
w = mem_file.read(4) f = open(filename, "r")
if not w: regions = json.load(f)
break f.close()
if endianness == "little": else:
data.append(struct.unpack("<I", w)[0]) regions = {filename: "0x00000000"}
else:
data.append(struct.unpack(">I", w)[0]) # determine data_size
data_size = len(data)*4 data_size = 0
for filename, base in regions.items():
data_size = max(int(base, 16) + os.path.getsize(filename), data_size)
assert data_size > 0 assert data_size > 0
if mem_size is not None: if mem_size is not None:
assert data_size < mem_size, ( assert data_size < mem_size, (
"file is too big: {}/{} bytes".format( "file is too big: {}/{} bytes".format(
data_size, mem_size)) data_size, mem_size))
return data
# fill data
data = [0]*(data_size//4)
for filename, base in regions.items():
with open(filename, "rb") as f:
i = 0
while True:
w = f.read(4)
if not w:
break
if len(w) != 4:
for i in range(len(w), 4):
w += b'\x00'
if endianness == "little":
data[i] = struct.unpack("<I", w)[0]
else:
data[i] = struct.unpack(">I", w)[0]
i += 1
return data
class ReadOnlyDict(dict): class ReadOnlyDict(dict):
def __readonly__(self, *args, **kwargs): def __readonly__(self, *args, **kwargs):

View file

@ -8,16 +8,29 @@ from litex.soc.integration.cpu_interface import get_csr_header
from litex.soc.interconnect import wishbone from litex.soc.interconnect import wishbone
from litex.soc.interconnect import axi from litex.soc.interconnect import axi
# Record layouts -----------------------------------------------------------------------------------
def axi_fifo_ctrl_layout():
return [
("racount", 3, DIR_M_TO_S),
("rcount", 8, DIR_M_TO_S),
("rdissuecapen", 1, DIR_S_TO_M),
("wacount", 6, DIR_M_TO_S),
("wcount", 8, DIR_M_TO_S),
("wrissuecapen", 1, DIR_S_TO_M),
]
# SoC Zync -----------------------------------------------------------------------------------------
class SoCZynq(SoCCore): class SoCZynq(SoCCore):
SoCCore.mem_map["csr"] = 0x00000000 SoCCore.mem_map["csr"] = 0x00000000
def __init__(self, platform, clk_freq, ps7_name, **kwargs): def __init__(self, platform, clk_freq, ps7_name, **kwargs):
self.ps7_name = ps7_name
SoCCore.__init__(self, platform, clk_freq, cpu_type=None, shadow_base=0x00000000, **kwargs) SoCCore.__init__(self, platform, clk_freq, cpu_type=None, shadow_base=0x00000000, **kwargs)
# PS7 -------------------------------------------------------------------------------------- # PS7 (Minimal) ----------------------------------------------------------------------------
self.axi_gp0 = axi_gp0 = axi.AXIInterface(data_width=32, address_width=32, id_width=12)
ps7_ddram_pads = platform.request("ps7_ddram") ps7_ddram_pads = platform.request("ps7_ddram")
self.specials += Instance(ps7_name, self.ps7_params = dict(
# clk/rst # clk/rst
io_PS_CLK=platform.request("ps7_clk"), io_PS_CLK=platform.request("ps7_clk"),
io_PS_PORB=platform.request("ps7_porb"), io_PS_PORB=platform.request("ps7_porb"),
@ -57,10 +70,17 @@ class SoCZynq(SoCCore):
# fabric clk # fabric clk
o_FCLK_CLK0=ClockSignal("sys"), o_FCLK_CLK0=ClockSignal("sys"),
# axi clk # axi gp0 clk
i_M_AXI_GP0_ACLK=ClockSignal("sys"), i_M_AXI_GP0_ACLK=ClockSignal("sys"),
)
platform.add_ip(os.path.join("ip", ps7_name + ".xci"))
# axi aw # GP0 ------------------------------------------------------------------------------------------
def add_gp0(self):
self.axi_gp0 = axi_gp0 = axi.AXIInterface(data_width=32, address_width=32, id_width=12)
self.ps7_params.update(
# axi gp0 aw
o_M_AXI_GP0_AWVALID=axi_gp0.aw.valid, o_M_AXI_GP0_AWVALID=axi_gp0.aw.valid,
i_M_AXI_GP0_AWREADY=axi_gp0.aw.ready, i_M_AXI_GP0_AWREADY=axi_gp0.aw.ready,
o_M_AXI_GP0_AWADDR=axi_gp0.aw.addr, o_M_AXI_GP0_AWADDR=axi_gp0.aw.addr,
@ -68,39 +88,39 @@ class SoCZynq(SoCCore):
o_M_AXI_GP0_AWLEN=axi_gp0.aw.len, o_M_AXI_GP0_AWLEN=axi_gp0.aw.len,
o_M_AXI_GP0_AWSIZE=axi_gp0.aw.size, o_M_AXI_GP0_AWSIZE=axi_gp0.aw.size,
o_M_AXI_GP0_AWID=axi_gp0.aw.id, o_M_AXI_GP0_AWID=axi_gp0.aw.id,
#o_M_AXI_GP0_AWLOCK =, o_M_AXI_GP0_AWLOCK=axi_gp0.aw.lock,
#o_M_AXI_GP0_AWPROT =, o_M_AXI_GP0_AWPROT=axi_gp0.aw.prot,
#o_M_AXI_GP0_AWCACHE =, o_M_AXI_GP0_AWCACHE=axi_gp0.aw.cache,
#o_M_AXI_GP0_AWQOS =, o_M_AXI_GP0_AWQOS=axi_gp0.aw.qos,
# axi w # axi gp0 w
o_M_AXI_GP0_WVALID=axi_gp0.w.valid, o_M_AXI_GP0_WVALID=axi_gp0.w.valid,
o_M_AXI_GP0_WLAST=axi_gp0.w.last, o_M_AXI_GP0_WLAST=axi_gp0.w.last,
i_M_AXI_GP0_WREADY=axi_gp0.w.ready, i_M_AXI_GP0_WREADY=axi_gp0.w.ready,
#o_M_AXI_GP0_WID=, o_M_AXI_GP0_WID=axi_gp0.w.id,
o_M_AXI_GP0_WDATA=axi_gp0.w.data, o_M_AXI_GP0_WDATA=axi_gp0.w.data,
o_M_AXI_GP0_WSTRB=axi_gp0.w.strb, o_M_AXI_GP0_WSTRB=axi_gp0.w.strb,
# axi b # axi gp0 b
i_M_AXI_GP0_BVALID=axi_gp0.b.valid, i_M_AXI_GP0_BVALID=axi_gp0.b.valid,
o_M_AXI_GP0_BREADY=axi_gp0.b.ready, o_M_AXI_GP0_BREADY=axi_gp0.b.ready,
i_M_AXI_GP0_BID=axi_gp0.b.id, i_M_AXI_GP0_BID=axi_gp0.b.id,
i_M_AXI_GP0_BRESP=axi_gp0.b.resp, i_M_AXI_GP0_BRESP=axi_gp0.b.resp,
# axi ar # axi gp0 ar
o_M_AXI_GP0_ARVALID=axi_gp0.ar.valid, o_M_AXI_GP0_ARVALID=axi_gp0.ar.valid,
i_M_AXI_GP0_ARREADY=axi_gp0.ar.ready, i_M_AXI_GP0_ARREADY=axi_gp0.ar.ready,
o_M_AXI_GP0_ARADDR=axi_gp0.ar.addr, o_M_AXI_GP0_ARADDR=axi_gp0.ar.addr,
o_M_AXI_GP0_ARBURST=axi_gp0.ar.burst, o_M_AXI_GP0_ARBURST=axi_gp0.ar.burst,
o_M_AXI_GP0_ARLEN=axi_gp0.ar.len, o_M_AXI_GP0_ARLEN=axi_gp0.ar.len,
o_M_AXI_GP0_ARID=axi_gp0.ar.id, o_M_AXI_GP0_ARID=axi_gp0.ar.id,
#o_M_AXI_GP0_ARLOCK=, o_M_AXI_GP0_ARLOCK=axi_gp0.ar.lock,
#o_M_AXI_GP0_ARSIZE=, o_M_AXI_GP0_ARSIZE=axi_gp0.ar.size,
#o_M_AXI_GP0_ARPROT=, o_M_AXI_GP0_ARPROT=axi_gp0.ar.prot,
#o_M_AXI_GP0_ARCACHE=, o_M_AXI_GP0_ARCACHE=axi_gp0.ar.cache,
#o_M_AXI_GP0_ARQOS=, o_M_AXI_GP0_ARQOS=axi_gp0.ar.qos,
# axi r # axi gp0 r
i_M_AXI_GP0_RVALID=axi_gp0.r.valid, i_M_AXI_GP0_RVALID=axi_gp0.r.valid,
o_M_AXI_GP0_RREADY=axi_gp0.r.ready, o_M_AXI_GP0_RREADY=axi_gp0.r.ready,
i_M_AXI_GP0_RLAST=axi_gp0.r.last, i_M_AXI_GP0_RLAST=axi_gp0.r.last,
@ -108,13 +128,79 @@ class SoCZynq(SoCCore):
i_M_AXI_GP0_RRESP=axi_gp0.r.resp, i_M_AXI_GP0_RRESP=axi_gp0.r.resp,
i_M_AXI_GP0_RDATA=axi_gp0.r.data, i_M_AXI_GP0_RDATA=axi_gp0.r.data,
) )
platform.add_ip(os.path.join("ip", ps7_name + ".xci"))
# AXI to Wishbone -------------------------------------------------------------------------- # HP0 ------------------------------------------------------------------------------------------
self.wb_gp0 = wb_gp0 = wishbone.Interface()
axi2wishbone = axi.AXI2Wishbone(axi_gp0, wb_gp0, base_address=0x43c00000) def add_hp0(self):
self.axi_hp0 = axi_hp0 = axi.AXIInterface(data_width=64, address_width=32, id_width=6)
self.axi_hp0_fifo_ctrl = axi_hp0_fifo_ctrl = Record(axi_fifo_ctrl_layout())
self.ps7_params.update(
# axi hp0 aw
i_S_AXI_HP0_AWVALID=axi_hp0.aw.valid,
o_S_AXI_HP0_AWREADY=axi_hp0.aw.ready,
i_S_AXI_HP0_AWADDR=axi_hp0.aw.addr,
i_S_AXI_HP0_AWBURST=axi_hp0.aw.burst,
i_S_AXI_HP0_AWLEN=axi_hp0.aw.len,
i_S_AXI_HP0_AWSIZE=axi_hp0.aw.size,
i_S_AXI_HP0_AWID=axi_hp0.aw.id,
i_S_AXI_HP0_AWLOCK=axi_hp0.aw.lock,
i_S_AXI_HP0_AWPROT=axi_hp0.aw.prot,
i_S_AXI_HP0_AWCACHE=axi_hp0.aw.cache,
i_S_AXI_HP0_AWQOS=axi_hp0.aw.qos,
# axi hp0 w
i_S_AXI_HP0_WVALID=axi_hp0.w.valid,
i_S_AXI_HP0_WLAST=axi_hp0.w.last,
o_S_AXI_HP0_WREADY=axi_hp0.w.ready,
i_S_AXI_HP0_WID=axi_hp0.w.id,
i_S_AXI_HP0_WDATA=axi_hp0.w.data,
i_S_AXI_HP0_WSTRB=axi_hp0.w.strb,
# axi hp0 b
o_S_AXI_HP0_BVALID=axi_hp0.b.valid,
i_S_AXI_HP0_BREADY=axi_hp0.b.ready,
o_S_AXI_HP0_BID=axi_hp0.b.id,
o_S_AXI_HP0_BRESP=axi_hp0.b.resp,
# axi hp0 ar
i_S_AXI_HP0_ARVALID=axi_hp0.ar.valid,
o_S_AXI_HP0_ARREADY=axi_hp0.ar.ready,
i_S_AXI_HP0_ARADDR=axi_hp0.ar.addr,
i_S_AXI_HP0_ARBURST=axi_hp0.ar.burst,
i_S_AXI_HP0_ARLEN=axi_hp0.ar.len,
i_S_AXI_HP0_ARID=axi_hp0.ar.id,
i_S_AXI_HP0_ARLOCK=axi_hp0.ar.lock,
i_S_AXI_HP0_ARSIZE=axi_hp0.ar.size,
i_S_AXI_HP0_ARPROT=axi_hp0.ar.prot,
i_S_AXI_HP0_ARCACHE=axi_hp0.ar.cache,
i_S_AXI_HP0_ARQOS=axi_hp0.ar.qos,
# axi hp0 r
o_S_AXI_HP0_RVALID=axi_hp0.r.valid,
i_S_AXI_HP0_RREADY=axi_hp0.r.ready,
o_S_AXI_HP0_RLAST=axi_hp0.r.last,
o_S_AXI_HP0_RID=axi_hp0.r.id,
o_S_AXI_HP0_RRESP=axi_hp0.r.resp,
o_S_AXI_HP0_RDATA=axi_hp0.r.data,
# axi hp0 fifo ctrl
o_S_AXI_HP0_RACOUNT=axi_hp0_fifo_ctrl.racount,
o_S_AXI_HP0_RCOUNT=axi_hp0_fifo_ctrl.rcount,
i_S_AXI_HP0_RDISSUECAP1_EN=axi_hp0_fifo_ctrl.rdissuecapen,
o_S_AXI_HP0_WACOUNT=axi_hp0_fifo_ctrl.wacount,
o_S_AXI_HP0_WCOUNT=axi_hp0_fifo_ctrl.wcount,
i_S_AXI_HP0_WRISSUECAP1_EN=axi_hp0_fifo_ctrl.wrissuecapen
)
def add_axi_to_wishbone(self, axi_port, base_address=0x43c00000):
wb = wishbone.Interface()
axi2wishbone = axi.AXI2Wishbone(axi_port, wb, base_address)
self.submodules += axi2wishbone self.submodules += axi2wishbone
self.add_wb_master(wb_gp0) self.add_wb_master(wb)
def do_finalize(self):
SoCCore.do_finalize(self)
self.specials += Instance(self.ps7_name, **self.ps7_params)
def generate_software_header(self, filename): def generate_software_header(self, filename):
csr_header = get_csr_header(self.get_csr_regions(), csr_header = get_csr_header(self.get_csr_regions(),

View file

@ -0,0 +1,38 @@
from migen import *
from litex.soc.interconnect import stream
# AvalonST to/from Native --------------------------------------------------------------------------
class Native2AvalonST(Module):
def __init__(self, layout, latency=2):
self.sink = sink = stream.Endpoint(layout)
self.source = source = stream.Endpoint(layout)
# # #
_from = sink
for n in range(latency):
_to = stream.Endpoint(layout)
self.sync += _from.connect(_to, omit={"ready"})
if n == 0:
self.sync += _to.valid.eq(sink.valid & source.ready)
_from = _to
self.comb += _to.connect(source, omit={"ready"})
self.comb += sink.ready.eq(source.ready)
class AvalonST2Native(Module):
def __init__(self, layout, latency=2):
self.sink = sink = stream.Endpoint(layout)
self.source = source = stream.Endpoint(layout)
# # #
buf = stream.SyncFIFO(layout, max(latency, 4))
self.submodules += buf
self.comb += [
sink.connect(buf.sink, omit={"ready"}),
sink.ready.eq(source.ready),
buf.source.connect(source)
]

View file

@ -20,26 +20,31 @@ def ax_description(address_width, id_width):
("burst", 2), # Burst type ("burst", 2), # Burst type
("len", 8), # Number of data (-1) transfers (up to 256) ("len", 8), # Number of data (-1) transfers (up to 256)
("size", 4), # Number of bytes (-1) of each data transfer (up to 1024 bits) ("size", 4), # Number of bytes (-1) of each data transfer (up to 1024 bits)
("lock", 2),
("prot", 3),
("cache", 4),
("qos", 4),
("id", id_width) ("id", id_width)
] ]
def w_description(data_width): def w_description(data_width, id_width):
return [ return [
("data", data_width), ("data", data_width),
("strb", data_width//8) ("strb", data_width//8),
("id", id_width)
] ]
def b_description(id_width): def b_description(id_width):
return [ return [
("resp", 2), ("resp", 2),
("id", id_width) ("id", id_width)
] ]
def r_description(data_width, id_width): def r_description(data_width, id_width):
return [ return [
("resp", 2), ("resp", 2),
("data", data_width), ("data", data_width),
("id", id_width) ("id", id_width)
] ]
@ -51,7 +56,7 @@ class AXIInterface(Record):
self.clock_domain = clock_domain self.clock_domain = clock_domain
self.aw = stream.Endpoint(ax_description(address_width, id_width)) self.aw = stream.Endpoint(ax_description(address_width, id_width))
self.w = stream.Endpoint(w_description(data_width)) self.w = stream.Endpoint(w_description(data_width, id_width))
self.b = stream.Endpoint(b_description(id_width)) self.b = stream.Endpoint(b_description(id_width))
self.ar = stream.Endpoint(ax_description(address_width, id_width)) self.ar = stream.Endpoint(ax_description(address_width, id_width))
self.r = stream.Endpoint(r_description(data_width, id_width)) self.r = stream.Endpoint(r_description(data_width, id_width))
@ -60,12 +65,12 @@ class AXIInterface(Record):
class AXI2Wishbone(Module): class AXI2Wishbone(Module):
def __init__(self, axi, wishbone, base_address): def __init__(self, axi, wishbone, base_address):
assert axi.data_width == 32 assert axi.data_width == len(wishbone.dat_r)
assert axi.address_width == 32 assert axi.address_width == len(wishbone.adr) + 2
_data = Signal(axi.data_width) _data = Signal(axi.data_width)
_read_addr = Signal(32) _read_addr = Signal(axi.address_width)
_write_addr = Signal(32) _write_addr = Signal(axi.address_width)
self.comb += _read_addr.eq(axi.ar.addr - base_address) self.comb += _read_addr.eq(axi.ar.addr - base_address)
self.comb += _write_addr.eq(axi.aw.addr - base_address) self.comb += _write_addr.eq(axi.aw.addr - base_address)
@ -78,8 +83,6 @@ class AXI2Wishbone(Module):
NextState("DO-WRITE") NextState("DO-WRITE")
) )
) )
axi_ar_addr = Signal(32)
self.comb += axi_ar_addr.eq(axi.ar.addr - base_address)
fsm.act("DO-READ", fsm.act("DO-READ",
wishbone.stb.eq(1), wishbone.stb.eq(1),
wishbone.cyc.eq(1), wishbone.cyc.eq(1),

View file

@ -186,133 +186,18 @@ static void ident(void)
printf("Ident: %s\n", buffer); printf("Ident: %s\n", buffer);
} }
#ifdef __lm32__
enum {
CSR_IE = 1, CSR_IM, CSR_IP, CSR_ICC, CSR_DCC, CSR_CC, CSR_CFG, CSR_EBA,
CSR_DC, CSR_DEBA, CSR_JTX, CSR_JRX, CSR_BP0, CSR_BP1, CSR_BP2, CSR_BP3,
CSR_WP0, CSR_WP1, CSR_WP2, CSR_WP3,
};
/* processor registers */
static int parse_csr(const char *csr)
{
if(!strcmp(csr, "ie")) return CSR_IE;
if(!strcmp(csr, "im")) return CSR_IM;
if(!strcmp(csr, "ip")) return CSR_IP;
if(!strcmp(csr, "icc")) return CSR_ICC;
if(!strcmp(csr, "dcc")) return CSR_DCC;
if(!strcmp(csr, "cc")) return CSR_CC;
if(!strcmp(csr, "cfg")) return CSR_CFG;
if(!strcmp(csr, "eba")) return CSR_EBA;
if(!strcmp(csr, "dc")) return CSR_DC;
if(!strcmp(csr, "deba")) return CSR_DEBA;
if(!strcmp(csr, "jtx")) return CSR_JTX;
if(!strcmp(csr, "jrx")) return CSR_JRX;
if(!strcmp(csr, "bp0")) return CSR_BP0;
if(!strcmp(csr, "bp1")) return CSR_BP1;
if(!strcmp(csr, "bp2")) return CSR_BP2;
if(!strcmp(csr, "bp3")) return CSR_BP3;
if(!strcmp(csr, "wp0")) return CSR_WP0;
if(!strcmp(csr, "wp1")) return CSR_WP1;
if(!strcmp(csr, "wp2")) return CSR_WP2;
if(!strcmp(csr, "wp3")) return CSR_WP3;
return 0;
}
static void rcsr(char *csr)
{
unsigned int csr2;
register unsigned int value;
if(*csr == 0) {
printf("rcsr <csr>\n");
return;
}
csr2 = parse_csr(csr);
if(csr2 == 0) {
printf("incorrect csr\n");
return;
}
switch(csr2) {
case CSR_IE: asm volatile ("rcsr %0,ie":"=r"(value)); break;
case CSR_IM: asm volatile ("rcsr %0,im":"=r"(value)); break;
case CSR_IP: asm volatile ("rcsr %0,ip":"=r"(value)); break;
case CSR_CC: asm volatile ("rcsr %0,cc":"=r"(value)); break;
case CSR_CFG: asm volatile ("rcsr %0,cfg":"=r"(value)); break;
case CSR_EBA: asm volatile ("rcsr %0,eba":"=r"(value)); break;
case CSR_DEBA: asm volatile ("rcsr %0,deba":"=r"(value)); break;
case CSR_JTX: asm volatile ("rcsr %0,jtx":"=r"(value)); break;
case CSR_JRX: asm volatile ("rcsr %0,jrx":"=r"(value)); break;
default: printf("csr write only\n"); return;
}
printf("%08x\n", value);
}
static void wcsr(char *csr, char *value)
{
char *c;
unsigned int csr2;
register unsigned int value2;
if((*csr == 0) || (*value == 0)) {
printf("wcsr <csr> <address>\n");
return;
}
csr2 = parse_csr(csr);
if(csr2 == 0) {
printf("incorrect csr\n");
return;
}
value2 = strtoul(value, &c, 0);
if(*c != 0) {
printf("incorrect value\n");
return;
}
switch(csr2) {
case CSR_IE: asm volatile ("wcsr ie,%0"::"r"(value2)); break;
case CSR_IM: asm volatile ("wcsr im,%0"::"r"(value2)); break;
case CSR_ICC: asm volatile ("wcsr icc,%0"::"r"(value2)); break;
case CSR_DCC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
case CSR_EBA: asm volatile ("wcsr eba,%0"::"r"(value2)); break;
case CSR_DC: asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
case CSR_DEBA: asm volatile ("wcsr deba,%0"::"r"(value2)); break;
case CSR_JTX: asm volatile ("wcsr jtx,%0"::"r"(value2)); break;
case CSR_JRX: asm volatile ("wcsr jrx,%0"::"r"(value2)); break;
case CSR_BP0: asm volatile ("wcsr bp0,%0"::"r"(value2)); break;
case CSR_BP1: asm volatile ("wcsr bp1,%0"::"r"(value2)); break;
case CSR_BP2: asm volatile ("wcsr bp2,%0"::"r"(value2)); break;
case CSR_BP3: asm volatile ("wcsr bp3,%0"::"r"(value2)); break;
case CSR_WP0: asm volatile ("wcsr wp0,%0"::"r"(value2)); break;
case CSR_WP1: asm volatile ("wcsr wp1,%0"::"r"(value2)); break;
case CSR_WP2: asm volatile ("wcsr wp2,%0"::"r"(value2)); break;
case CSR_WP3: asm volatile ("wcsr wp3,%0"::"r"(value2)); break;
default: printf("csr read only\n"); return;
}
}
#endif /* __lm32__ */
/* Init + command line */ /* Init + command line */
static void help(void) static void help(void)
{ {
puts("LiteX SoC BIOS"); puts("LiteX BIOS, available commands:");
puts("Available commands:");
puts("mr - read address space"); puts("mr - read address space");
puts("mw - write address space"); puts("mw - write address space");
puts("mc - copy address space"); puts("mc - copy address space");
puts("");
puts("crc - compute CRC32 of a part of the address space"); puts("crc - compute CRC32 of a part of the address space");
puts("ident - display identifier"); puts("ident - display identifier");
#ifdef __lm32__ puts("");
puts("rcsr - read processor CSR");
puts("wcsr - write processor CSR");
#endif
#ifdef CSR_CTRL_BASE #ifdef CSR_CTRL_BASE
puts("reboot - reset processor"); puts("reboot - reset processor");
#endif #endif
@ -326,6 +211,7 @@ static void help(void)
#ifdef ROM_BOOT_ADDRESS #ifdef ROM_BOOT_ADDRESS
puts("romboot - boot from embedded rom"); puts("romboot - boot from embedded rom");
#endif #endif
puts("");
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
puts("memtest - run a memory test"); puts("memtest - run a memory test");
#endif #endif
@ -385,11 +271,6 @@ static void do_command(char *c)
else if(strcmp(token, "help") == 0) help(); else if(strcmp(token, "help") == 0) help();
#ifdef __lm32__
else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
#endif
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c)); else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c));
else if(strcmp(token, "sdrsw") == 0) sdrsw(); else if(strcmp(token, "sdrsw") == 0) sdrsw();
@ -399,6 +280,7 @@ static void do_command(char *c)
else if(strcmp(token, "sdrrderr") == 0) sdrrderr(get_token(&c)); else if(strcmp(token, "sdrrderr") == 0) sdrrderr(get_token(&c));
else if(strcmp(token, "sdrwr") == 0) sdrwr(get_token(&c)); else if(strcmp(token, "sdrwr") == 0) sdrwr(get_token(&c));
#ifdef CSR_DDRPHY_BASE #ifdef CSR_DDRPHY_BASE
else if(strcmp(token, "sdrinit") == 0) sdrinit();
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR #ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
else if(strcmp(token, "sdrwlon") == 0) sdrwlon(); else if(strcmp(token, "sdrwlon") == 0) sdrwlon();
else if(strcmp(token, "sdrwloff") == 0) sdrwloff(); else if(strcmp(token, "sdrwloff") == 0) sdrwloff();
@ -406,7 +288,6 @@ static void do_command(char *c)
else if(strcmp(token, "sdrlevel") == 0) sdrlevel(); else if(strcmp(token, "sdrlevel") == 0) sdrlevel();
#endif #endif
else if(strcmp(token, "memtest") == 0) memtest(); else if(strcmp(token, "memtest") == 0) memtest();
else if(strcmp(token, "sdrinit") == 0) sdrinit();
#endif #endif
else if(strcmp(token, "") != 0) else if(strcmp(token, "") != 0)
@ -433,10 +314,10 @@ static void crcbios(void)
length = (unsigned int)&_edata - offset_bios; length = (unsigned int)&_edata - offset_bios;
actual_crc = crc32((unsigned char *)offset_bios, length); actual_crc = crc32((unsigned char *)offset_bios, length);
if(expected_crc == actual_crc) if(expected_crc == actual_crc)
printf("BIOS CRC passed (%08x)\n", actual_crc); printf(" BIOS CRC passed (%08x)\n", actual_crc);
else { else {
printf("BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc); printf(" BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
printf("The system will continue, but expect problems.\n"); printf(" The system will continue, but expect problems.\n");
} }
} }
@ -509,12 +390,22 @@ int main(int i, char **c)
irq_setmask(0); irq_setmask(0);
irq_setie(1); irq_setie(1);
uart_init(); uart_init();
printf("\n"); printf("\n");
printf("\e[1m __ _ __ _ __\e[0m\n"); printf("\e[1m __ _ __ _ __\e[0m\n");
printf("\e[1m / / (_) /____ | |/_/\e[0m\n"); printf("\e[1m / / (_) /____ | |/_/\e[0m\n");
printf("\e[1m / /__/ / __/ -_)> <\e[0m\n"); printf("\e[1m / /__/ / __/ -_)> <\e[0m\n");
printf("\e[1m /____/_/\\__/\\__/_/|_|\e[0m\n"); printf("\e[1m /____/_/\\__/\\__/_/|_|\e[0m\n");
printf("\e[1m SoC BIOS / CPU: "); printf("\n");
printf(" (c) Copyright 2012-2019 Enjoy-Digital\n");
printf(" (c) Copyright 2012-2015 M-Labs Ltd\n");
printf("\n");
printf(" BIOS built on "__DATE__" "__TIME__"\n");
crcbios();
printf("\n");
printf("--============ \e[1mSoC info\e[0m ================--\n");
printf("\e[1mCPU\e[0m: ");
#ifdef __lm32__ #ifdef __lm32__
printf("LM32"); printf("LM32");
#elif __or1k__ #elif __or1k__
@ -528,14 +419,19 @@ int main(int i, char **c)
#else #else
printf("Unknown"); printf("Unknown");
#endif #endif
printf(" / %3dMHz\e[0m\n", SYSTEM_CLOCK_FREQUENCY/1000000); printf(" @ %dMHz\n", SYSTEM_CLOCK_FREQUENCY/1000000);
printf("\e[1mROM\e[0m: %dKB\n", ROM_SIZE/1024);
printf("\e[1mSRAM\e[0m: %dKB\n", SRAM_SIZE/1024);
#ifdef L2_SIZE
printf("\e[1mL2\e[0m: %dKB\n", L2_SIZE/1024);
#endif
#ifdef MAIN_RAM_SIZE
printf("\e[1mMAIN-RAM\e[0m: %dKB\n", MAIN_RAM_SIZE/1024);
#endif
printf("\n");
puts( printf("--========= \e[1mPeripherals init\e[0m ===========--\n");
"(c) Copyright 2012-2018 Enjoy-Digital\n" #ifdef CSR_ETHPHY_CRG_RESET_ADDR
"(c) Copyright 2007-2018 M-Labs Limited\n"
"Built "__DATE__" "__TIME__"\n");
crcbios();
#ifdef CSR_ETHMAC_BASE
eth_init(); eth_init();
#endif #endif
#ifdef CSR_SDRAM_BASE #ifdef CSR_SDRAM_BASE
@ -547,11 +443,17 @@ int main(int i, char **c)
sdr_ok = 1; sdr_ok = 1;
#endif #endif
#endif #endif
if(sdr_ok) if (sdr_ok !=1)
boot_sequence();
else
printf("Memory initialization failed\n"); printf("Memory initialization failed\n");
printf("\n");
if(sdr_ok) {
printf("--========== \e[1mBoot sequence\e[0m =============--\n");
boot_sequence();
printf("\n");
}
printf("--============= \e[1mConsole\e[0m ================--\n");
while(1) { while(1) {
putsnonl("\e[1mBIOS>\e[0m "); putsnonl("\e[1mBIOS>\e[0m ");
readstr(buffer, 64); readstr(buffer, 64);

View file

@ -17,7 +17,7 @@
#define MAIN_RAM_BASE SRAM_BASE #define MAIN_RAM_BASE SRAM_BASE
#endif #endif
static void cdelay(int i) __attribute__((unused)) static void cdelay(int i)
{ {
while(i > 0) { while(i > 0) {
#if defined (__lm32__) #if defined (__lm32__)
@ -210,16 +210,18 @@ void sdrwr(char *startaddr)
#if defined (USDDRPHY) #if defined (USDDRPHY)
#define ERR_DDRPHY_DELAY 512 #define ERR_DDRPHY_DELAY 512
#define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_SIZE/2
#elif defined (ECP5DDRPHY) #elif defined (ECP5DDRPHY)
#define ERR_DDRPHY_DELAY 8 #define ERR_DDRPHY_DELAY 8
#define ERR_DDRPHY_BITSLIP 1
#define NBMODULES DFII_PIX_DATA_SIZE/4
#else #else
#define ERR_DDRPHY_DELAY 32 #define ERR_DDRPHY_DELAY 32
#define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_SIZE/2
#endif #endif
#define ERR_DDRPHY_BITSLIP DFII_NPHASES*2
#define NBMODULES DFII_PIX_DATA_SIZE*DFII_NPHASES/8
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR #ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
void sdrwlon(void) void sdrwlon(void)
@ -461,6 +463,9 @@ static int read_level_scan(int module, int bitslip)
int show = 1; int show = 1;
#ifdef USDDRPHY #ifdef USDDRPHY
show = (j%16 == 0); show = (j%16 == 0);
#endif
#ifdef ECP5DDRPHY
ddrphy_burstdet_clr_write(1);
#endif #endif
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15); cdelay(15);
@ -471,6 +476,10 @@ static int read_level_scan(int module, int bitslip)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
if (show) if (show)
printf("%d", working); printf("%d", working);
score += working; score += working;
@ -526,6 +535,9 @@ static void read_level(int module)
delay = 0; delay = 0;
read_delay_rst(module); read_delay_rst(module);
while(1) { while(1) {
#ifdef ECP5DDRPHY
ddrphy_burstdet_clr_write(1);
#endif
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15); cdelay(15);
working = 1; working = 1;
@ -535,6 +547,10 @@ static void read_level(int module)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
if(working) if(working)
break; break;
delay++; delay++;
@ -557,6 +573,9 @@ static void read_level(int module)
/* Find largest working delay */ /* Find largest working delay */
while(1) { while(1) {
#ifdef ECP5DDRPHY
ddrphy_burstdet_clr_write(1);
#endif
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15); cdelay(15);
working = 1; working = 1;
@ -566,6 +585,10 @@ static void read_level(int module)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) if(MMPTR(sdram_dfii_pix_rddata_addr[p]+4*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY
if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
working = 0;
#endif
if(!working) if(!working)
break; break;
delay++; delay++;

View file

@ -1,11 +0,0 @@
#ifndef __HW_ETHMAC_MEM_H
#define __HW_ETHMAC_MEM_H
#include <generated/mem.h>
#define ETHMAC_RX0_BASE ETHMAC_BASE
#define ETHMAC_RX1_BASE (ETHMAC_BASE+0x0800)
#define ETHMAC_TX0_BASE (ETHMAC_BASE+0x1000)
#define ETHMAC_TX1_BASE (ETHMAC_BASE+0x1800)
#endif

View file

@ -1,4 +1,6 @@
#include <generated/csr.h> #include <generated/csr.h>
#include <generated/mem.h>
#ifdef CSR_ETHMAC_BASE #ifdef CSR_ETHMAC_BASE
#include <stdio.h> #include <stdio.h>
@ -6,7 +8,6 @@
#include <system.h> #include <system.h>
#include <crc.h> #include <crc.h>
#include <hw/flags.h> #include <hw/flags.h>
#include <hw/ethmac_mem.h>
#include <net/microudp.h> #include <net/microudp.h>
@ -110,24 +111,17 @@ struct ethernet_frame {
typedef union { typedef union {
struct ethernet_frame frame; struct ethernet_frame frame;
unsigned char raw[1532]; unsigned char raw[ETHMAC_SLOT_SIZE];
} ethernet_buffer; } ethernet_buffer;
static unsigned int rxslot;
static unsigned int rxlen; static unsigned int rxlen;
static ethernet_buffer *rxbuffer; static ethernet_buffer *rxbuffer;
static ethernet_buffer *rxbuffer0;
static ethernet_buffer *rxbuffer1;
static unsigned int txslot;
static unsigned int txlen; static unsigned int txlen;
static ethernet_buffer *txbuffer; static ethernet_buffer *txbuffer;
static ethernet_buffer *txbuffer0;
static ethernet_buffer *txbuffer1;
static void send_packet(void) static void send_packet(void)
{ {
unsigned int txslot;
#ifndef HW_PREAMBLE_CRC #ifndef HW_PREAMBLE_CRC
unsigned int crc; unsigned int crc;
crc = crc32(&txbuffer->raw[8], txlen-8); crc = crc32(&txbuffer->raw[8], txlen-8);
@ -147,15 +141,13 @@ static void send_packet(void)
printf("\n"); printf("\n");
#endif #endif
ethmac_sram_reader_slot_write(txslot);
ethmac_sram_reader_length_write(txlen); ethmac_sram_reader_length_write(txlen);
while(!(ethmac_sram_reader_ready_read()));
ethmac_sram_reader_start_write(1); ethmac_sram_reader_start_write(1);
txslot = (txslot+1)%2; while(!(ethmac_sram_reader_ready_read()));
if (txslot) txslot = ethmac_sram_reader_slot_read();
txbuffer = txbuffer1; txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot));
else txslot = (txslot+1)%ETHMAC_TX_SLOTS;
txbuffer = txbuffer0; ethmac_sram_reader_slot_write(txslot);
} }
static unsigned char my_mac[6]; static unsigned char my_mac[6];
@ -415,17 +407,6 @@ void microudp_start(const unsigned char *macaddr, unsigned int ip)
ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER); ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER);
ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
rxbuffer0 = (ethernet_buffer *)ETHMAC_RX0_BASE;
rxbuffer1 = (ethernet_buffer *)ETHMAC_RX1_BASE;
txbuffer0 = (ethernet_buffer *)ETHMAC_TX0_BASE;
txbuffer1 = (ethernet_buffer *)ETHMAC_TX1_BASE;
rxslot = 0;
txslot = 0;
rxbuffer = rxbuffer0;
txbuffer = txbuffer0;
for(i=0;i<6;i++) for(i=0;i<6;i++)
my_mac[i] = macaddr[i]; my_mac[i] = macaddr[i];
my_ip = ip; my_ip = ip;
@ -434,18 +415,21 @@ void microudp_start(const unsigned char *macaddr, unsigned int ip)
for(i=0;i<6;i++) for(i=0;i<6;i++)
cached_mac[i] = 0; cached_mac[i] = 0;
ethmac_sram_reader_slot_write(0);
txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * ETHMAC_RX_SLOTS);
rxbuffer = (ethernet_buffer *)ETHMAC_BASE;
rx_callback = (udp_callback)0; rx_callback = (udp_callback)0;
} }
void microudp_service(void) void microudp_service(void)
{ {
unsigned int rxslot;
if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) { if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) {
rxslot = ethmac_sram_writer_slot_read(); rxslot = ethmac_sram_writer_slot_read();
rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot);
rxlen = ethmac_sram_writer_length_read(); rxlen = ethmac_sram_writer_length_read();
if (rxslot)
rxbuffer = rxbuffer1;
else
rxbuffer = rxbuffer0;
process_frame(); process_frame();
ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER);
} }
@ -463,13 +447,12 @@ static void busy_wait(unsigned int ds)
void eth_init(void) void eth_init(void)
{ {
ethphy_crg_reset_write(0); #ifdef CSR_ETHPHY_CRG_RESET_ADDR
busy_wait(2);
/* that pesky ethernet PHY needs two resets at times... */
ethphy_crg_reset_write(1); ethphy_crg_reset_write(1);
busy_wait(2); busy_wait(2);
ethphy_crg_reset_write(0); ethphy_crg_reset_write(0);
busy_wait(2); busy_wait(2);
#endif
} }
#ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR #ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR

1
litex/utils/__init__.py Normal file
View file

@ -0,0 +1 @@

View file

@ -1,5 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse
import sys import sys
import socket import socket
import time import time
@ -10,22 +12,19 @@ from litex.soc.tools.remote.etherbone import EtherboneIPC
class RemoteServer(EtherboneIPC): class RemoteServer(EtherboneIPC):
def __init__(self, comm, port=1234): def __init__(self, comm, bind_ip, bind_port=1234):
self.comm = comm self.comm = comm
self.port = port self.bind_ip = bind_ip
self.bind_port = bind_port
self.lock = False self.lock = False
def open(self): def open(self):
if hasattr(self, "socket"): if hasattr(self, "socket"):
return return
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
for i in range(32): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
try: self.socket.bind((self.bind_ip, self.bind_port))
self.socket.bind(("localhost", self.port + i)) print("tcp port: {:d}".format(self.bind_port))
break
except:
pass
print("tcp port: {:d}".format(self.port + i))
self.socket.listen(1) self.socket.listen(1)
self.comm.open() self.comm.open()
@ -95,46 +94,65 @@ class RemoteServer(EtherboneIPC):
def main(): def main():
print("LiteX remote server") print("LiteX remote server")
if len(sys.argv) < 2 or len(sys.argv) > 4: parser = argparse.ArgumentParser()
print("usages:") # Common arguments
print("litex_server uart [port] [baudrate]") parser.add_argument("--bind-ip", default="localhost",
print("litex_server udp [server] [server_port]") help="Host bind address")
print("litex_server pcie [bar]") parser.add_argument("--bind-port", default=1234,
sys.exit() help="Host bind port")
comm = sys.argv[1]
if comm == "uart": # UART arguments
parser.add_argument("--uart", action="store_true",
help="Select UART interface")
parser.add_argument("--uart-port", default=None,
help="Set UART port")
parser.add_argument("--uart-baudrate", default=115200,
help="Set UART baudrate")
# UDP arguments
parser.add_argument("--udp", action="store_true",
help="Select UDP interface")
parser.add_argument("--udp-ip", default="192.168.1.50",
help="Set UDP remote IP address")
parser.add_argument("--udp-port", default=1234,
help="Set UDP remote port")
# PCIe arguments
parser.add_argument("--pcie", action="store_true",
help="Select PCIe interface")
parser.add_argument("--pcie-bar", default=None,
help="Set PCIe BAR")
args = parser.parse_args()
if args.uart:
from litex.soc.tools.remote import CommUART from litex.soc.tools.remote import CommUART
uart_port = None if args.uart_port is None:
uart_baudrate = 115200 print("Need to specify --uart-port, exiting.")
if len(sys.argv) > 2: exit()
uart_port = sys.argv[2] uart_port = args.uart_port
if len(sys.argv) > 3: uart_baudrate = int(float(args.uart_baudrate))
uart_baudrate = int(float(sys.argv[3]))
print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="") print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="")
comm = CommUART(uart_port, uart_baudrate) comm = CommUART(uart_port, uart_baudrate)
elif comm == "udp": elif args.udp:
from litex.soc.tools.remote import CommUDP from litex.soc.tools.remote import CommUDP
server = "192.168.1.50" udp_ip = args.udp_ip
server_port = 1234 udp_port = int(args.udp_port)
if len(sys.argv) > 2: print("[CommUDP] ip: {} / port: {} / ".format(udp_ip, udp_port), end="")
server = sys.argv[2] comm = CommUDP(udp_ip, udp_port)
if len(sys.argv) > 3: elif args.pcie:
server_port = int(sys.argv[3])
print("[CommUDP] server: {} / port: {} / ".format(server, server_port), end="")
comm = CommUDP(server, server_port)
elif comm == "pcie":
from litex.soc.tools.remote import CommPCIe from litex.soc.tools.remote import CommPCIe
bar = "" pcie_bar = args.pcie_bar
if len(sys.argv) > 2: if args.pcie_bar is None:
bar = sys.argv[2] print("Need to speficy --pcie-bar, exiting.")
if len(sys.argv) > 3: exit()
bar_size = int(sys.argv[3]) print("[CommPCIe] bar: {} / ".format(args.pcie_bar), end="")
print("[CommPCIe] bar: {} / ".format(bar), end="") comm = CommPCIe(args.pcie_bar)
comm = CommPCIe(bar)
else: else:
raise NotImplementedError parser.print_help()
exit()
server = RemoteServer(comm) server = RemoteServer(comm, args.bind_ip, int(args.bind_port))
server.open() server.open()
server.start(4) server.start(4)
try: try:

View file

@ -215,14 +215,20 @@ def main():
sim_config = SimConfig(default_clk="sys_clk") sim_config = SimConfig(default_clk="sys_clk")
sim_config.add_module("serial2console", "serial") sim_config.add_module("serial2console", "serial")
cpu_endianness = "big"
if "cpu_type" in soc_kwargs:
if soc_kwargs["cpu_type"] in ["picorv32", "vexriscv"]:
cpu_endianness = "little"
if args.rom_init: if args.rom_init:
soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init) soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init, cpu_endianness)
if not args.with_sdram: if not args.with_sdram:
soc_kwargs["integrated_main_ram_size"] = 0x10000 soc_kwargs["integrated_main_ram_size"] = 0x10000000 # 256 MB
if args.ram_init is not None: if args.ram_init is not None:
soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init) soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init, cpu_endianness)
soc_kwargs["integrated_main_ram_size"] = max(len(soc_kwargs["integrated_main_ram_init"]), 0x10000)
else: else:
assert args.ram_init is None
soc_kwargs["integrated_main_ram_size"] = 0x0 soc_kwargs["integrated_main_ram_size"] = 0x0
if args.with_ethernet: if args.with_ethernet:
sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": "192.168.1.100"}) sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": "192.168.1.100"})
@ -235,6 +241,8 @@ def main():
with_etherbone=args.with_etherbone, with_etherbone=args.with_etherbone,
with_analyzer=args.with_analyzer, with_analyzer=args.with_analyzer,
**soc_kwargs) **soc_kwargs)
if args.ram_init is not None:
soc.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
builder_kwargs["csr_csv"] = "csr.csv" builder_kwargs["csr_csv"] = "csr.csv"
builder = Builder(soc, **builder_kwargs) builder = Builder(soc, **builder_kwargs)
vns = builder.build(run=False, threads=args.threads, sim_config=sim_config, trace=args.trace) vns = builder.build(run=False, threads=args.threads, sim_config=sim_config, trace=args.trace)

View file

@ -15,6 +15,7 @@ repos = [
("liteusb", ("http://github.com/enjoy-digital/", False, True)), ("liteusb", ("http://github.com/enjoy-digital/", False, True)),
("litedram", ("http://github.com/enjoy-digital/", False, True)), ("litedram", ("http://github.com/enjoy-digital/", False, True)),
("litepcie", ("http://github.com/enjoy-digital/", False, True)), ("litepcie", ("http://github.com/enjoy-digital/", False, True)),
("litesata", ("http://github.com/enjoy-digital/", False, True)),
("litesdcard", ("http://github.com/enjoy-digital/", False, True)), ("litesdcard", ("http://github.com/enjoy-digital/", False, True)),
("liteiclink", ("http://github.com/enjoy-digital/", False, True)), ("liteiclink", ("http://github.com/enjoy-digital/", False, True)),
("litevideo", ("http://github.com/enjoy-digital/", False, True)), ("litevideo", ("http://github.com/enjoy-digital/", False, True)),