mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
Merge branch 'master' of https://github.com/enjoy-digital/litex
This commit is contained in:
commit
c780fb22b7
29 changed files with 633 additions and 390 deletions
6
LICENSE
6
LICENSE
|
@ -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
2
README
|
@ -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
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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):
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
38
litex/soc/interconnect/avalon.py
Normal file
38
litex/soc/interconnect/avalon.py
Normal 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)
|
||||||
|
]
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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
|
|
|
@ -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
1
litex/utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
Loading…
Reference in a new issue