merge most of misoc 54e1ef82 and migen e93d0601 changes
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Jan 2017 00:33:48 +0000 (01:33 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Jan 2017 02:55:00 +0000 (03:55 +0100)
41 files changed:
litex/boards/targets/kc705.py
litex/boards/targets/nexys_video.py
litex/build/altera/quartus.py
litex/build/tools.py
litex/build/xilinx/common.py
litex/build/xilinx/ise.py
litex/build/xilinx/platform.py
litex/build/xilinx/vivado.py
litex/gen/__init__.py
litex/gen/fhdl/bitcontainer.py
litex/gen/fhdl/decorators.py
litex/gen/fhdl/simplify.py
litex/gen/fhdl/specials.py
litex/gen/fhdl/structure.py
litex/gen/fhdl/verilog.py
litex/gen/fhdl/visit.py
litex/gen/genlib/cdc.py
litex/gen/genlib/fifo.py
litex/gen/genlib/fsm.py
litex/gen/genlib/io.py
litex/gen/sim/core.py
litex/soc/integration/builder.py
litex/soc/integration/cpu_interface.py
litex/soc/integration/soc_core.py
litex/soc/integration/soc_sdram.py
litex/soc/interconnect/csr.py
litex/soc/interconnect/csr_bus.py
litex/soc/interconnect/csr_eventmanager.py
litex/soc/interconnect/wishbone.py
litex/soc/software/bios/boot.c
litex/soc/software/bios/boot.h
litex/soc/software/bios/main.c
litex/soc/software/include/base/inttypes.h
litex/soc/software/include/base/math.h [new file with mode: 0644]
litex/soc/software/include/base/stddef.h
litex/soc/software/include/base/stdlib.h
litex/soc/software/include/dyld/dyld.h
litex/soc/software/include/fdlibm/fdlibm.h [new file with mode: 0644]
litex/soc/software/libbase/crt0-or1k.S
litex/soc/software/libbase/exception.c
litex/soc/software/libbase/vsnprintf.c

index 9139be8e085d61952781c774c6da30427a3346bb..c889d49efe2e4b3d18d04686b1dde6a0fc6bec2b 100755 (executable)
@@ -131,12 +131,21 @@ class MiniSoC(BaseSoC):
     def __init__(self, *args, **kwargs):
         BaseSoC.__init__(self, *args, **kwargs)
 
-        self.submodules.ethphy = LiteEthPHY(self.platform.request("eth_clocks"),
+        eth_clocks = self.platform.request("eth_clocks")
+        self.submodules.ethphy = LiteEthPHY(eth_clocks,
                                             self.platform.request("eth"), clk_freq=self.clk_freq)
         self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone")
         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.crg.cd_eth_tx.clk.attr.add("keep")
+        # period constraints are required here because of vivado
+        self.platform.add_period_constraint(self.crg.cd_sys.clk, 8.0)
+        self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk, 8.0)
+        self.platform.add_false_path_constraints(
+            self.crg.cd_sys.clk,
+            self.ethphy.crg.cd_eth_tx.clk, eth_clocks.rx)
 
 def soc_kc705_args(parser):
     soc_sdram_args(parser)
index 810f594da5f26c260ae266c4324c0615ef9b67cc..3d52befd9e5f996f3fca02d653b163513edc3612 100755 (executable)
@@ -4,7 +4,6 @@ import os
 
 from litex.gen import *
 from litex.gen.genlib.resetsync import AsyncResetSynchronizer
-from litex.gen.fhdl.specials import Keep
 
 from litex.boards.platforms import nexys_video
 
index e7a27622d913b32ae17fab23e5e5f7c55a0493f9..af34b2eb47d09be0fcac308dfbafaf08ef0cfb03 100644 (file)
@@ -100,6 +100,7 @@ quartus_map --read_settings_files=on --write_settings_files=off {build_name} -c
 quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
 quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
 quartus_sta {build_name} -c {build_name}
+quartus_cpf -c {build_name}.sof {build_name}.rbf
 
 """.format(build_name=build_name)  # noqa
     build_script_file = "build_" + build_name + ".sh"
@@ -115,7 +116,7 @@ class AlteraQuartusToolchain:
     def build(self, platform, fragment, build_dir="build", build_name="top",
               toolchain_path="/opt/Altera", run=True, **kwargs):
         cwd = os.getcwd()
-        tools.mkdir_noerror(build_dir)
+        os.makedirs(build_dir, exist_ok=True)
         os.chdir(build_dir)
 
         if not isinstance(fragment, _Fragment):
index 34c054b16ec69a25122780bde7d9f0d56b0b5e02..f585f018b7781f2dc93d29ea7d3806c4a2f1a8cd 100644 (file)
@@ -1,13 +1,9 @@
 import os
 import struct
 from distutils.version import StrictVersion
-
-
-def mkdir_noerror(d):
-    try:
-        os.mkdir(d)
-    except OSError:
-        pass
+import re
+import subprocess
+import sys
 
 
 def language_by_filename(name):
@@ -23,9 +19,6 @@ def write_to_file(filename, contents, force_unix=False):
     newline = None
     if force_unix:
         newline = "\n"
-    if os.path.exists(filename):
-        if open(filename, "r", newline=newline).read() == contents:
-            return
     with open(filename, "w", newline=newline) as f:
         f.write(contents)
 
@@ -43,3 +36,25 @@ def versions(path):
             yield StrictVersion(n)
         except ValueError:
             continue
+
+
+def sub_rules(lines, rules, max_matches=1):
+    for line in lines:
+        n = max_matches
+        for pattern, color in rules:
+            line, m = re.subn(pattern, color, line, n)
+            n -= m
+            if not n:
+                break
+        yield line
+
+
+def subprocess_call_filtered(command, rules, *, max_matches=1, **kwargs):
+    proc = subprocess.Popen(command, stdout=subprocess.PIPE,
+                            universal_newlines=True, bufsize=1,
+                            **kwargs)
+    with proc:
+        for line in sub_rules(iter(proc.stdout.readline, ""),
+                              rules, max_matches):
+            sys.stdout.write(line)
+    return proc.returncode
index dcd47b25f65a8113bc7897d8e590542a6811b364..3728a531f282e2dfb612866012385f494b7cc829 100644 (file)
@@ -1,11 +1,15 @@
 import os
 import sys
-from distutils.version import StrictVersion
+try:
+    import colorama
+    colorama.init()  # install escape sequence translation on Windows
+    _have_colorama = True
+except ImportError:
+    _have_colorama = False
 
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.specials import Instance
 from litex.gen.fhdl.module import Module
-from litex.gen.fhdl.specials import SynthesisDirective
 from litex.gen.genlib.cdc import *
 from litex.gen.genlib.resetsync import AsyncResetSynchronizer
 from litex.gen.genlib.io import *
@@ -13,6 +17,20 @@ from litex.gen.genlib.io import *
 from litex.build import tools
 
 
+colors = []
+if _have_colorama:
+    colors += [
+        ("^ERROR:.*$", colorama.Fore.RED + colorama.Style.BRIGHT +
+         r"\g<0>" + colorama.Style.RESET_ALL),
+        ("^CRITICAL WARNING:.*$", colorama.Fore.RED +
+         r"\g<0>" + colorama.Style.RESET_ALL),
+        ("^WARNING:.*$", colorama.Fore.YELLOW +
+         r"\g<0>" + colorama.Style.RESET_ALL),
+        ("^INFO:.*$", colorama.Fore.GREEN +
+         r"\g<0>" + colorama.Style.RESET_ALL),
+    ]
+
+
 def settings(path, ver=None, sub=None):
     if ver is None:
         vers = list(tools.versions(path))
@@ -42,52 +60,18 @@ def settings(path, ver=None, sub=None):
     raise OSError("no Xilinx tools settings file found")
 
 
-class XilinxNoRetimingVivadoImpl(Module):
-    def __init__(self, reg):
-        pass # No equivalent in Vivado
-
-
-class XilinxNoRetimingVivado:
-    @staticmethod
-    def lower(dr):
-        return XilinxNoRetimingVivadoImpl(dr.reg)
-
-
-class XilinxNoRetimingISEImpl(Module):
-    def __init__(self, reg):
-        self.specials += SynthesisDirective("attribute register_balancing of {r} is no", r=reg)
-
-
-class XilinxNoRetimingISE:
-    @staticmethod
-    def lower(dr):
-        return XilinxNoRetimingISEImpl(dr.reg)
-
-
-class XilinxMultiRegVivadoImpl(MultiRegImpl):
+class XilinxMultiRegImpl(MultiRegImpl):
     def __init__(self, *args, **kwargs):
         MultiRegImpl.__init__(self, *args, **kwargs)
-        for reg in self.regs:
-            reg.attribute += " SHIFT_EXTRACT=\"NO\", ASYNC_REG=\"TRUE\","
+        for r in self.regs:
+            r.attr.add("async_reg")
+            r.attr.add("no_shreg_extract")
 
 
-class XilinxMultiRegVivado:
+class XilinxMultiReg:
     @staticmethod
     def lower(dr):
-        return XilinxMultiRegVivadoImpl(dr.i, dr.o, dr.odomain, dr.n)
-
-
-class XilinxMultiRegISEImpl(MultiRegImpl):
-    def __init__(self, *args, **kwargs):
-        MultiRegImpl.__init__(self, *args, **kwargs)
-        self.specials += [SynthesisDirective("attribute shreg_extract of {r} is no", r=r)
-            for r in self.regs]
-
-
-class XilinxMultiRegISE:
-    @staticmethod
-    def lower(dr):
-        return XilinxMultiRegISEImpl(dr.i, dr.o, dr.odomain, dr.n)
+        return XilinxMultiRegImpl(dr.i, dr.o, dr.odomain, dr.n)
 
 
 class XilinxAsyncResetSynchronizerImpl(Module):
@@ -99,6 +83,8 @@ class XilinxAsyncResetSynchronizerImpl(Module):
             Instance("FDPE", p_INIT=1, i_D=rst1, i_PRE=async_reset,
                 i_CE=1, i_C=cd.clk, o_Q=cd.rst)
         ]
+        rst1.attr.add("async_reg")
+        cd.rst.attr.add("async_reg")
 
 
 class XilinxAsyncResetSynchronizer:
@@ -145,6 +131,7 @@ class XilinxDDROutput:
 
 
 xilinx_special_overrides = {
+    MultiReg:               XilinxMultiReg,
     AsyncResetSynchronizer: XilinxAsyncResetSynchronizer,
     DifferentialInput:      XilinxDifferentialInput,
     DifferentialOutput:     XilinxDifferentialOutput,
@@ -152,18 +139,6 @@ xilinx_special_overrides = {
 }
 
 
-xilinx_vivado_special_overrides = {
-    NoRetiming:             XilinxNoRetimingVivado,
-    MultiReg:               XilinxMultiRegVivado
-}
-
-
-xilinx_ise_special_overrides = {
-    NoRetiming:             XilinxNoRetimingISE,
-    MultiReg:               XilinxMultiRegISE
-}
-
-
 class XilinxDDROutputImplS7(Module):
     def __init__(self, i1, i2, o, clk):
         self.specials += Instance("ODDR",
index 656ed010803c3c544f7cc1d2f47baad7f38b048d..19bbe9ef4b8b577602d01ae1c058c5936219df8f 100644 (file)
@@ -88,39 +88,48 @@ def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
         script_ext = ".bat"
         shell = ["cmd", "/c"]
         build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
+        fail_stmt = " || exit /b"
     else:
         source_cmd = "source "
         script_ext = ".sh"
         shell = ["bash"]
         build_script_contents = "# Autogenerated by LiteX\nset -e\n"
+        fail_stmt = ""
     if source:
         settings = common.settings(ise_path, ver, "ISE_DS")
         build_script_contents += source_cmd + settings + "\n"
 
     ext = "ngc"
     build_script_contents += """
-xst -ifn {build_name}.xst
+xst -ifn {build_name}.xst{fail_stmt}
 """
 
     build_script_contents += """
-ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd
-map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf
-par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf
-bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit
+ngdbuild {ngdbuild_opt} -uc {build_name}.ucf {build_name}.{ext} {build_name}.ngd{fail_stmt}
+map {map_opt} -o {build_name}_map.ncd {build_name}.ngd {build_name}.pcf{fail_stmt}
+par {par_opt} {build_name}_map.ncd {build_name}.ncd {build_name}.pcf{fail_stmt}
+bitgen {bitgen_opt} {build_name}.ncd {build_name}.bit{fail_stmt}
 """
     build_script_contents = build_script_contents.format(build_name=build_name,
             ngdbuild_opt=ngdbuild_opt, bitgen_opt=bitgen_opt, ext=ext,
-            par_opt=par_opt, map_opt=map_opt)
+            par_opt=par_opt, map_opt=map_opt, fail_stmt=fail_stmt)
     build_script_contents += ise_commands.format(build_name=build_name)
     build_script_file = "build_" + build_name + script_ext
     tools.write_to_file(build_script_file, build_script_contents, force_unix=False)
     command = shell + [build_script_file]
-    r = subprocess.call(command)
+    r = tools.subprocess_call_filtered(command, common.colors)
     if r != 0:
         raise OSError("Subprocess failed")
 
 
 class XilinxISEToolchain:
+    attr_translate = {
+        "keep": ("keep", "true"),
+        "no_retiming": ("register_balancing", "no"),
+        "async_reg": None,
+        "no_shreg_extract": ("shreg_extract", "no")
+    }
+
     def __init__(self):
         self.xst_opt = """-ifmt MIXED
 -use_new_parser yes
@@ -150,7 +159,7 @@ class XilinxISEToolchain:
         ngdbuild_opt = self.ngdbuild_opt
         vns = None
 
-        tools.mkdir_noerror(build_dir)
+        os.makedirs(build_dir, exist_ok=True)
         cwd = os.getcwd()
         os.chdir(build_dir)
         try:
index 8a6251868ad656d6a8f67df7beb01b9bff5c7231..04c8b4187d9231ea81fd8d9b79d065cb1ac4c8c9 100644 (file)
@@ -18,12 +18,10 @@ class XilinxPlatform(GenericPlatform):
         so = dict(common.xilinx_special_overrides)
         if self.device[:3] == "xc7":
             so.update(common.xilinx_s7_special_overrides)
-        if self.toolchain == "ise":
-            so.update(common.xilinx_vivado_special_overrides)
-        else:
-            so.update(common.xilinx_ise_special_overrides)
         so.update(special_overrides)
-        return GenericPlatform.get_verilog(self, *args, special_overrides=so, **kwargs)
+        return GenericPlatform.get_verilog(self, *args,
+            special_overrides=so, attr_translate=self.toolchain.attr_translate, **kwargs)
+
 
     def build(self, *args, **kwargs):
         return self.toolchain.build(self, *args, **kwargs)
index 4d9a8d2b8cf5712c5aaa8008ddf8cacb6a1c6f50..fb0932bc73de804e8ee6c1917386855eaa9d79b7 100644 (file)
@@ -56,28 +56,35 @@ def _run_vivado(build_name, vivado_path, source, ver=None):
         build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n"
         build_script_file = "build_" + build_name + ".bat"
         tools.write_to_file(build_script_file, build_script_contents)
-        r = subprocess.call([build_script_file])
+        command = build_script_file
     else:
         build_script_contents = "# Autogenerated by LiteX\nset -e\n"
-        if vivado_path is None:
-            vivado_path = "/opt/Xilinx/Vivado"
         settings = common.settings(vivado_path, ver)
         build_script_contents += "source " + settings + "\n"
         build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n"
         build_script_file = "build_" + build_name + ".sh"
         tools.write_to_file(build_script_file, build_script_contents)
-        r = subprocess.call(["bash", build_script_file])
-
+        command = ["bash", build_script_file]
+    r = tools.subprocess_call_filtered(command, common.colors)
     if r != 0:
         raise OSError("Subprocess failed")
 
 
 class XilinxVivadoToolchain:
+    attr_translate = {
+        "keep": ("dont_touch", "true"),
+        "no_retiming": ("dont_touch", "true"),
+        "async_reg": ("async_reg", "true"),
+        "no_shreg_extract": None
+    }
+
     def __init__(self):
         self.bitstream_commands = []
         self.additional_commands = []
         self.pre_synthesis_commands = []
         self.with_phys_opt = False
+        self.clocks = dict()
+        self.false_paths = set()
 
     def _build_batch(self, platform, sources, build_name):
         tcl = []
@@ -103,7 +110,7 @@ class XilinxVivadoToolchain:
         tcl.append("route_design")
         tcl.append("report_route_status -file {}_route_status.rpt".format(build_name))
         tcl.append("report_drc -file {}_drc.rpt".format(build_name))
-        tcl.append("report_timing_summary -max_paths 10 -file {}_timing.rpt".format(build_name))
+        tcl.append("report_timing_summary -datasheet -max_paths 10 -file {}_timing.rpt".format(build_name))
         tcl.append("report_power -file {}_power.rpt".format(build_name))
         for bitstream_command in self.bitstream_commands:
             tcl.append(bitstream_command.format(build_name=build_name))
@@ -113,15 +120,35 @@ class XilinxVivadoToolchain:
         tcl.append("quit")
         tools.write_to_file(build_name + ".tcl", "\n".join(tcl))
 
+    def _convert_clocks(self, platform):
+        for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid):
+            platform.add_platform_command(
+                "create_clock -name {clk} -period " + str(period) +
+                " [get_nets {clk}]", clk=clk)
+        for from_, to in sorted(self.false_paths,
+                                key=lambda x: (x[0].duid, x[1].duid)):
+            if (from_ not in self.clocks
+                    or to not in self.clocks):
+                raise ValueError("Vivado requires period "
+                                 "constraints on all clocks used in false paths")
+            platform.add_platform_command(
+                "set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]",
+                from_=from_, to=to)
+
+        # make sure add_*_constraint cannot be used again
+        del self.clocks
+        del self.false_paths
+
     def build(self, platform, fragment, build_dir="build", build_name="top",
             toolchain_path=None, source=True, run=True, **kwargs):
-        tools.mkdir_noerror(build_dir)
+        os.makedirs(build_dir, exist_ok=True)
         cwd = os.getcwd()
         os.chdir(build_dir)
 
         if not isinstance(fragment, _Fragment):
             fragment = fragment.get_fragment()
         platform.finalize(fragment)
+        self._convert_clocks(platform)
         v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
         named_sc, named_pc = platform.resolve_signals(v_output.ns)
         v_file = build_name + ".v"
@@ -137,11 +164,9 @@ class XilinxVivadoToolchain:
         return v_output.ns
 
     def add_period_constraint(self, platform, clk, period):
-        platform.add_platform_command(
-            "create_clock -name {clk} -period " + str(period) +
-            " [get_nets {clk}]", clk=clk)
+        if clk in self.clocks:
+            raise ValueError("A period constraint already exists")
+        self.clocks[clk] = period
 
     def add_false_path_constraint(self, platform, from_, to):
-        platform.add_platform_command(
-            "set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]",
-            from_=from_, to=to)
+        self.false_paths.add((from_, to))
index 264a79e20c6eb72b755fa9cbedd329266b59239e..2cd38253440795d5f8f6cc3e1d48a1ffb4d2d037 100644 (file)
@@ -3,6 +3,7 @@ from litex.gen.fhdl.module import *
 from litex.gen.fhdl.specials import *
 from litex.gen.fhdl.bitcontainer import *
 from litex.gen.fhdl.decorators import *
+from litex.gen.fhdl.simplify import *
 
 from litex.gen.sim import *
 
index 11a3ede7fa927d5a764aaef6993b0b6ee91d35b6..e7894bce0da58ec044c44259818d7f7285566112 100644 (file)
@@ -5,12 +5,10 @@ __all__ = ["log2_int", "bits_for", "value_bits_sign"]
 
 
 def log2_int(n, need_pow2=True):
-    l = 1
-    r = 0
-    while l < n:
-        l *= 2
-        r += 1
-    if need_pow2 and l != n:
+    if n == 0:
+        return 0
+    r = (n - 1).bit_length()
+    if need_pow2 and (1 << r) != n:
         raise ValueError("Not a power of 2")
     return r
 
@@ -26,6 +24,21 @@ def bits_for(n, require_sign_bit=False):
     return r
 
 
+def _bitwise_binary_bits_sign(a, b):
+    if not a[1] and not b[1]:
+        # both operands unsigned
+        return max(a[0], b[0]), False
+    elif a[1] and b[1]:
+        # both operands signed
+        return max(a[0], b[0]), True
+    elif not a[1] and b[1]:
+        # first operand unsigned (add sign bit), second operand signed
+        return max(a[0] + 1, b[0]), True
+    else:
+        # first signed, second operand unsigned (add sign bit)
+        return max(a[0], b[0] + 1), True
+
+
 def value_bits_sign(v):
     """Bit length and signedness of a value.
 
@@ -53,18 +66,13 @@ def value_bits_sign(v):
     elif isinstance(v, f._Operator):
         obs = list(map(value_bits_sign, v.operands))
         if v.op == "+" or v.op == "-":
-            if not obs[0][1] and not obs[1][1]:
-                # both operands unsigned
-                return max(obs[0][0], obs[1][0]) + 1, False
-            elif obs[0][1] and obs[1][1]:
-                # both operands signed
-                return max(obs[0][0], obs[1][0]) + 1, True
-            elif not obs[0][1] and obs[1][1]:
-                # first operand unsigned (add sign bit), second operand signed
-                return max(obs[0][0] + 1, obs[1][0]) + 1, True
-            else:
-                # first signed, second operand unsigned (add sign bit)
-                return max(obs[0][0], obs[1][0] + 1) + 1, True
+            if len(obs) == 1:
+                if v.op == "-" and not obs[0][1]:
+                    return obs[0][0] + 1, True
+                else:
+                    return obs[0]
+            n, s = _bitwise_binary_bits_sign(*obs)
+            return n + 1, s
         elif v.op == "*":
             if not obs[0][1] and not obs[1][1]:
                 # both operands unsigned
@@ -88,23 +96,14 @@ def value_bits_sign(v):
                 extra = 0
             return obs[0][0] + extra, obs[0][1]
         elif v.op == "&" or v.op == "^" or v.op == "|":
-            if not obs[0][1] and not obs[1][1]:
-                # both operands unsigned
-                return max(obs[0][0], obs[1][0]), False
-            elif obs[0][1] and obs[1][1]:
-                # both operands signed
-                return max(obs[0][0], obs[1][0]), True
-            elif not obs[0][1] and obs[1][1]:
-                # first operand unsigned (add sign bit), second operand signed
-                return max(obs[0][0] + 1, obs[1][0]), True
-            else:
-                # first signed, second operand unsigned (add sign bit)
-                return max(obs[0][0], obs[1][0] + 1), True
-        elif v.op == "<" or v.op == "<=" or v.op == "==" or v.op == "!=" \
-          or v.op == ">" or v.op == ">=":
-              return 1, False
+            return _bitwise_binary_bits_sign(*obs)
+        elif (v.op == "<" or v.op == "<=" or v.op == "==" or v.op == "!=" or
+              v.op == ">" or v.op == ">="):
+            return 1, False
         elif v.op == "~":
             return obs[0]
+        elif v.op == "m":
+            return _bitwise_binary_bits_sign(obs[1], obs[2])
         else:
             raise TypeError
     elif isinstance(v, f._Slice):
index 59444eaf3fdd81c036bed8ba612e8467a41d6a89..347eaaa1aac5887c35d1e214c44ad3b3b41cfa58 100644 (file)
@@ -28,7 +28,8 @@ class ModuleTransformer:
                 return f
 
         Wrapped.__name__ = victim.__name__
-        # "{}_{}".format(self.__class__.__name__, victim.__name__)
+        Wrapped.__doc__ = victim.__doc__
+        Wrapped.__module__ = victim.__module__
         return Wrapped
 
     def wrap_instance(self, victim):
index 5f31a470b7d8282897713b6813dcdd067c9adc58..864ab37ebf4226663d0ac1cb09175e63c63aaeb1 100644 (file)
@@ -2,6 +2,7 @@ from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.specials import Memory, _MemoryPort, WRITE_FIRST, NO_CHANGE
 from litex.gen.fhdl.decorators import ModuleTransformer
 from litex.gen.util.misc import gcd_multiple
+from litex.gen.fhdl.bitcontainer import log2_int
 
 
 class FullMemoryWE(ModuleTransformer):
@@ -10,13 +11,11 @@ class FullMemoryWE(ModuleTransformer):
 
     def transform_fragment(self, i, f):
         newspecials = set()
-        replaced_ports = set()
 
         for orig in f.specials:
             if not isinstance(orig, Memory):
                 newspecials.add(orig)
                 continue
-
             global_granularity = gcd_multiple([p.we_granularity if p.we_granularity else orig.width for p in orig.ports])
             if global_granularity == orig.width:
                 newspecials.add(orig)  # nothing to do
@@ -46,13 +45,11 @@ class FullMemoryWE(ModuleTransformer):
                             clock_domain=port.clock.cd)
                         newmem.ports.append(newport)
                         newspecials.add(newport)
-
-                for port in orig.ports:
-                    replaced_ports.add(port)
                 self.replacements[orig] = newmems
 
-        newspecials -= replaced_ports
         f.specials = newspecials
+        for oldmem in self.replacements.keys():
+            f.specials -= set(oldmem.ports)
 
 
 class MemoryToArray(ModuleTransformer):
@@ -111,7 +108,7 @@ class MemoryToArray(ModuleTransformer):
                             m = i*port.we_granularity
                             M = (i+1)*port.we_granularity
                             sync.append(If(port.we[i],
-                                        storage[port.adr][m:M].eq(port.dat_w)))
+                                        storage[port.adr][m:M].eq(port.dat_w[m:M])))
                     else:
                         sync.append(If(port.we,
                                        storage[port.adr].eq(port.dat_w)))
@@ -120,3 +117,88 @@ class MemoryToArray(ModuleTransformer):
 
         newspecials -= processed_ports
         f.specials = newspecials
+
+
+class SplitMemory(ModuleTransformer):
+    """Split memories with depths that are not powers of two into smaller
+    power-of-two memories.
+
+    This prevents toolchains from rounding up and wasting resources."""
+
+    def transform_fragment(self, i, f):
+        old_specials, f.specials = f.specials, set()
+        old_ports = set()
+
+        for old in old_specials:
+            if not isinstance(old, Memory):
+                f.specials.add(old)
+                continue
+            try:
+                log2_int(old.depth, need_pow2=True)
+                f.specials.add(old)
+            except ValueError:
+                new, comb, sync = self._split_mem(old)
+                old_ports |= set(old.ports)
+                f.specials.update(new)
+                f.comb += comb
+                for cd, sy in sync.items():
+                    s = f.sync.setdefault(cd, [])
+                    s += sy
+        f.specials -= old_ports
+
+    def _split_mem(self, mem):
+        depths = [1 << i for i in range(log2_int(mem.depth, need_pow2=False))
+                  if mem.depth & (1 << i)]
+        depths.reverse()
+        inits = None
+        if mem.init is not None:
+            inits = list(mem.init)
+        mems = []
+        for i, depth in enumerate(depths):
+            init = None
+            if inits is not None:
+                init = inits[:depth]
+                del inits[:depth]
+            name = "{}_part{}".format(mem.name_override, i)
+            mems.append(Memory(width=mem.width, depth=depth,
+                               init=init, name=name))
+        ports = []
+        comb = []
+        sync = {}
+        for port in mem.ports:
+            p, c, s = self._split_port(port, mems)
+            ports += p
+            comb += c
+            sy = sync.setdefault(port.clock.cd, [])
+            sy += s
+        return mems + ports, comb, sync
+
+    def _split_port(self, port, mems):
+        ports = [mem.get_port(write_capable=port.we is not None,
+                              async_read=port.async_read,
+                              has_re=port.re is not None,
+                              we_granularity=port.we_granularity,
+                              mode=port.mode,
+                              clock_domain=port.clock.cd)
+                 for mem in mems]
+
+        sel = Signal(max=len(ports), reset=len(ports) - 1)
+        sel_r = Signal.like(sel)
+        eq = sel_r.eq(sel)
+        if port.re is not None:
+            eq = If(port.re, eq)
+        comb, sync = [], []
+        if port.async_read:
+            comb += [eq]
+        else:
+            sync += [eq]
+        comb += reversed([If(~port.adr[len(p.adr)], sel.eq(i))
+                          for i, p in enumerate(ports)])
+        comb += [p.adr.eq(port.adr) for p in ports]
+        comb.append(port.dat_r.eq(Array([p.dat_r for p in ports])[sel_r]))
+        if port.we is not None:
+            comb.append(Array([p.we for p in ports])[sel].eq(port.we))
+            comb += [p.dat_w.eq(port.dat_w) for p in ports]
+        if port.re is not None:
+            comb += [p.re.eq(port.re) for p in ports]
+        return ports, comb, sync
index d4fc2bf1ec8bed289f238e01fbe0bbe32ba35caf..5520f8938e957c9b01709083c6d9737a2f4e90bf 100644 (file)
@@ -111,7 +111,12 @@ class Instance(Special):
         self.items = list(items)
         self.synthesis_directive = synthesis_directive
         for k, v in sorted(kwargs.items(), key=itemgetter(0)):
-            item_type, item_name = k.split("_", maxsplit=1)
+            try:
+                item_type, item_name = k.split("_", maxsplit=1)
+            except ValueError:
+                raise TypeError("Wrong format for value '" + str(k) +
+                                "', format should be 'type_name'")
+
             item_class = {
                 "i": Instance.Input,
                 "o": Instance.Output,
@@ -277,7 +282,7 @@ class Memory(Special):
         data_regs = {}
         for port in memory.ports:
             if not port.async_read:
-                if port.mode == WRITE_FIRST and port.we is not None:
+                if port.mode == WRITE_FIRST:
                     adr_reg = Signal(name_override="memadr")
                     r += "reg [" + str(adrbits-1) + ":0] " \
                         + gn(adr_reg) + ";\n"
@@ -303,11 +308,11 @@ class Memory(Special):
                     r += "\tif (" + gn(port.we) + ")\n"
                     r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n"
             if not port.async_read:
-                if port.mode == WRITE_FIRST and port.we is not None:
+                if port.mode == WRITE_FIRST:
                     rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n"
                 else:
                     bassign = gn(data_regs[id(port)]) + " <= " + gn(memory) + "[" + gn(port.adr) + "];\n"
-                    if port.mode == READ_FIRST or port.we is None:
+                    if port.mode == READ_FIRST:
                         rd = "\t" + bassign
                     elif port.mode == NO_CHANGE:
                         rd = "\tif (!" + gn(port.we) + ")\n" \
@@ -323,7 +328,7 @@ class Memory(Special):
             if port.async_read:
                 r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n"
             else:
-                if port.mode == WRITE_FIRST and port.we is not None:
+                if port.mode == WRITE_FIRST:
                     r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(adr_regs[id(port)]) + "];\n"
                 else:
                     r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n"
@@ -340,21 +345,3 @@ class Memory(Special):
             r += "end\n\n"
 
         return r
-
-
-class SynthesisDirective(Special):
-    def __init__(self, template, **signals):
-        Special.__init__(self)
-        self.template = template
-        self.signals = signals
-
-    @staticmethod
-    def emit_verilog(directive, ns, add_data_file):
-        name_dict = dict((k, ns.get_name(sig)) for k, sig in directive.signals.items())
-        formatted = directive.template.format(**name_dict)
-        return "// synthesis " + formatted + "\n"
-
-
-class Keep(SynthesisDirective):
-    def __init__(self, signal):
-        SynthesisDirective.__init__(self, "attribute keep of {s} is true", s=signal)
index 96c2fb27be465d655724b703d96f4a6ddc505274..9dc922dc7339bfdbdb66f303227eb41c1d63c8de 100644 (file)
@@ -1,5 +1,6 @@
 import builtins as _builtins
 import collections as _collections
+import re as _re
 
 from litex.gen.fhdl import tracer as _tracer
 from litex.gen.util.misc import flat_iteration as _flat_iteration
@@ -136,7 +137,8 @@ def wrap(value):
     if isinstance(value, (bool, int)):
         value = Constant(value)
     if not isinstance(value, _Value):
-        raise TypeError("Object is not a Migen value")
+        raise TypeError("Object '{}' of type {} is not a Migen value"
+                        .format(value, type(value)))
     return value
 
 
@@ -310,12 +312,20 @@ class Signal(_Value):
         determined by the integer range given by `min` (inclusive,
         defaults to 0) and `max` (exclusive, defaults to 2).
     related : Signal or None
+    attr : set of synthesis attributes
     """
-    def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_override=None, min=None, max=None, related=None, attribute=""):
+    _name_re = _re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
+
+    def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_override=None, min=None, max=None, related=None, attr=None):
         from litex.gen.fhdl.bitcontainer import bits_for
 
         _Value.__init__(self)
 
+        for n in [name, name_override]:
+            if n is not None and not self._name_re.match(n):
+                raise ValueError("Signal name {} is not a valid Python identifier"
+                                 .format(repr(n)))
+
         # determine number of bits and signedness
         if bits_sign is None:
             if min is None:
@@ -332,15 +342,19 @@ class Signal(_Value):
                 self.nbits, self.signed = bits_sign
             else:
                 self.nbits, self.signed = bits_sign, False
+        if isinstance(reset, (bool, int)):
+            reset = Constant(reset, (self.nbits, self.signed))
         if not isinstance(self.nbits, int) or self.nbits <= 0:
             raise ValueError("Signal width must be a strictly positive integer")
+        if attr is None:
+            attr = set()
 
         self.variable = variable  # deprecated
         self.reset = reset
         self.name_override = name_override
         self.backtrace = _tracer.trace_back(name)
         self.related = related
-        self.attribute = attribute
+        self.attr = attr
 
     def __setattr__(self, k, v):
         if k == "reset":
@@ -526,7 +540,7 @@ class Case(_Statement):
         for k, v in cases.items():
             if isinstance(k, (bool, int)):
                 k = Constant(k)
-            if (not isinstance(k, Constant) 
+            if (not isinstance(k, Constant)
                     and not (isinstance(k, str) and k == "default")):
                 raise TypeError("Case object is not a Migen constant")
             if not isinstance(v, _collections.Iterable):
index 4a647dd1bcd8abbf273602d68f4dcc6622573c8f..1fb6024b37d0fbc0372816dce7f270a9646f159f 100644 (file)
@@ -116,9 +116,7 @@ def _printexpr(ns, node):
 
 
 def _printnode(ns, at, level, node):
-    if node is None:
-        return ""
-    elif isinstance(node, Display):
+    if isinstance(node, Display):
         s = "\"" + node.s + "\\r\""
         for arg in node.args:
             s += ", "
@@ -176,8 +174,30 @@ def _list_comb_wires(f):
             r |= g[0]
     return r
 
+def _printattr(sig, attr_translate):
+    r = ""
+    firsta = True
+    for attr in sorted(sig.attr,
+                       key=lambda x: ("", x) if isinstance(x, str) else x):
+        if isinstance(attr, tuple):
+            # platform-dependent attribute
+            attr_name, attr_value = attr
+        else:
+            # translated attribute
+            at = attr_translate[attr]
+            if at is None:
+                continue
+            attr_name, attr_value = at
+        if not firsta:
+            r += ", "
+        firsta = False
+        r += attr_name + " = \"" + attr_value + "\""
+    if r:
+        r = "(* " + r + " *)"
+    return r
 
-def _printheader(f, ios, name, ns,
+
+def _printheader(f, ios, name, ns, attr_translate,
                  reg_initialization):
     sigs = list_signals(f) | list_special_ios(f, True, True, True)
     special_outs = list_special_ios(f, False, True, True)
@@ -190,6 +210,9 @@ def _printheader(f, ios, name, ns,
         if not firstp:
             r += ",\n"
         firstp = False
+        attr = _printattr(sig, attr_translate)
+        if attr:
+            r += "\t" + attr
         if sig in inouts:
             r += "\tinout " + _printsig(ns, sig)
         elif sig in targets:
@@ -201,6 +224,9 @@ def _printheader(f, ios, name, ns,
             r += "\tinput " + _printsig(ns, sig)
     r += "\n);\n\n"
     for sig in sorted(sigs - ios, key=lambda x: x.duid):
+        attr = _printattr(sig, attr_translate)
+        if attr:
+            r += attr + " "
         if sig in wires:
             r += "wire " + _printsig(ns, sig) + ";\n"
         else:
@@ -219,15 +245,19 @@ def _printcomb(f, ns,
     r = ""
     if f.comb:
         if dummy_signal:
-            # Generate a dummy event to get the simulator
-            # to run the combinatorial process once at the beginning.
+            explanation = """
+// Adding a dummy event (using a dummy signal 'dummy_s') to get the simulator
+// to run the combinatorial process once at the beginning.
+"""
             syn_off = "// synthesis translate_off\n"
             syn_on = "// synthesis translate_on\n"
             dummy_s = Signal(name_override="dummy_s")
+            r += explanation
             r += syn_off
             r += "reg " + _printsig(ns, dummy_s) + ";\n"
             r += "initial " + ns.get_name(dummy_s) + " <= 1'd0;\n"
             r += syn_on
+            r += "\n"
 
         groups = group_by_targets(f.comb)
 
@@ -280,8 +310,14 @@ def _printspecials(overrides, specials, ns, add_data_file):
     return r
 
 
+class DummyAttrTranslate:
+    def __getitem__(self, k):
+        return (k, "true")
+
+
 def convert(f, ios=None, name="top",
   special_overrides=dict(),
+  attr_translate=DummyAttrTranslate(),
   create_clock_domains=True,
   display_run=False,
   reg_initialization=True,
@@ -323,7 +359,7 @@ def convert(f, ios=None, name="top",
     r.ns = ns
 
     src = "/* Machine-generated using LiteX gen */\n"
-    src += _printheader(f, ios, name, ns,
+    src += _printheader(f, ios, name, ns, attr_translate,
                         reg_initialization=reg_initialization)
     src += _printcomb(f, ns,
                       display_run=display_run,
index 84bb8adc5d71b0c0819e02e01163c9fe0fda9822..676ceb965ee1c5b544442ef950257847e218743d 100644 (file)
@@ -38,7 +38,7 @@ class NodeVisitor:
             self.visit_clock_domains(node)
         elif isinstance(node, _ArrayProxy):
             self.visit_ArrayProxy(node)
-        elif node is not None:
+        else:
             self.visit_unknown(node)
 
     def visit_Constant(self, node):
@@ -140,10 +140,8 @@ class NodeTransformer:
             return self.visit_clock_domains(node)
         elif isinstance(node, _ArrayProxy):
             return self.visit_ArrayProxy(node)
-        elif node is not None:
-            return self.visit_unknown(node)
         else:
-            return None
+            return self.visit_unknown(node)
 
     def visit_Constant(self, node):
         return node
index 6bac9e0003430498db835989423354d6414e4532..72efb03f74d63a8b5837b10f2d490cd0d00e5de6 100644 (file)
@@ -1,3 +1,7 @@
+"""
+Clock domain crossing module
+"""
+
 from litex.gen.fhdl.structure import *
 from litex.gen.fhdl.module import Module
 from litex.gen.fhdl.specials import Special, Memory
@@ -6,17 +10,6 @@ from litex.gen.genlib.misc import WaitTimer
 from litex.gen.genlib.resetsync import AsyncResetSynchronizer
 
 
-class NoRetiming(Special):
-    def __init__(self, reg):
-        Special.__init__(self)
-        self.reg = reg
-
-    # do nothing
-    @staticmethod
-    def lower(dr):
-        return Module()
-
-
 class MultiRegImpl(Module):
     def __init__(self, i, o, odomain, n):
         self.i = i
@@ -34,7 +27,8 @@ class MultiRegImpl(Module):
             sd += reg.eq(src)
             src = reg
         self.comb += self.o.eq(src)
-        self.specials += [NoRetiming(reg) for reg in self.regs]
+        for reg in self.regs:
+            reg.attr.add("no_retiming")
 
 
 class MultiReg(Special):
@@ -114,6 +108,7 @@ class BusSynchronizer(Module):
             ibuffer = Signal(width)
             obuffer = Signal(width)
             sync_i += If(self._pong.o, ibuffer.eq(self.i))
+            ibuffer.attr.add("no_retiming")
             self.specials += MultiReg(ibuffer, obuffer, odomain)
             sync_o += If(self._ping.o, self.o.eq(obuffer))
 
index 167f96437e2491da1160cac1496817db4f092009..f24449ffaa05296a2eaf432281e56a15a4e78792 100644 (file)
@@ -3,7 +3,7 @@ from litex.gen.fhdl.module import Module
 from litex.gen.fhdl.specials import Memory
 from litex.gen.fhdl.bitcontainer import log2_int
 from litex.gen.fhdl.decorators import ClockDomainsRenamer
-from litex.gen.genlib.cdc import NoRetiming, MultiReg, GrayCounter
+from litex.gen.genlib.cdc import MultiReg, GrayCounter
 
 
 def _inc(signal, modulo):
@@ -177,15 +177,11 @@ class AsyncFIFO(Module, _FIFOInterface):
         ]
 
         produce_rdomain = Signal(depth_bits+1)
-        self.specials += [
-            NoRetiming(produce.q),
-            MultiReg(produce.q, produce_rdomain, "read")
-        ]
+        produce.q.attr.add("no_retiming")
+        self.specials += MultiReg(produce.q, produce_rdomain, "read")
         consume_wdomain = Signal(depth_bits+1)
-        self.specials += [
-            NoRetiming(consume.q),
-            MultiReg(consume.q, consume_wdomain, "write")
-        ]
+        consume.q.attr.add("no_retiming")
+        self.specials += MultiReg(consume.q, consume_wdomain, "write")
         if depth_bits == 1:
             self.comb += self.writable.eq((produce.q[-1] == consume_wdomain[-1])
                 | (produce.q[-2] == consume_wdomain[-2]))
index de20e745d205615a52db3e1c4556e43e013ea855..044b95d9320749fd2ed5db7e22100995975bcc35 100644 (file)
@@ -40,7 +40,7 @@ def _target_eq(a, b):
     elif ty == _Slice:
         return (_target_eq(a.value, b.value)
                     and a.start == b.start
-                    and a.end == b.end)
+                    and a.stop == b.stop)
     elif ty == _ArrayProxy:
         return (all(_target_eq(x, y) for x, y in zip(a.choices, b.choices))
                     and _target_eq(a.key, b.key))
@@ -82,8 +82,47 @@ class _LowerNext(NodeTransformer):
         else:
             return node
 
-
 class FSM(Module):
+    """
+    Finite state machine
+
+    Any Python objects can be used as states, e.g. strings.
+
+    Parameters
+    ----------
+    reset_state
+        Reset state. Defaults to the first added state.
+
+    Examples
+    --------
+
+    >>> self.active = Signal()
+    >>> self.bitno = Signal(3)
+    >>>
+    >>> fsm = FSM(reset_state="START")
+    >>> self.submodules += fsm
+    >>>
+    >>> fsm.act("START",
+    ...     self.active.eq(1),
+    ...     If(strobe,
+    ...         NextState("DATA")
+    ...     )
+    ... )
+    >>> fsm.act("DATA",
+    ...     self.active.eq(1),
+    ...     If(strobe,
+    ...         NextValue(self.bitno, self.bitno + 1)
+    ...         If(self.bitno == 7,
+    ...             NextState("END")
+    ...         )
+    ...     )
+    ... )
+    >>> fsm.act("END",
+    ...     self.active.eq(0),
+    ...     NextState("STOP")
+    ... )
+
+    """
     def __init__(self, reset_state=None):
         self.actions = OrderedDict()
         self.state_aliases = dict()
@@ -95,6 +134,16 @@ class FSM(Module):
         self.after_leaving_signals = OrderedDict()
 
     def act(self, state, *statements):
+        """
+        Schedules `statements` to be executed in `state`. Statements may include:
+
+            * combinatorial statements of form `a.eq(b)`, equivalent to
+              `self.comb += a.eq(b)` when the FSM is in the given `state`;
+            * synchronous statements of form `NextValue(a, b)`, equivalent to
+              `self.sync += a.eq(b)` when the FSM is in the given `state`;
+            * a statement of form `NextState(new_state)`, selecting the next state;
+            * `If`, `Case`, etc.
+        """
         if self.finalized:
             raise FinalizeError
         if self.reset_state is None:
@@ -119,6 +168,10 @@ class FSM(Module):
             self.state_aliases[name] = target
 
     def ongoing(self, state):
+        """
+        Returns a signal that has the value 1 when the FSM is in the given `state`,
+        and 0 otherwise.
+        """
         is_ongoing = Signal()
         self.act(state, is_ongoing.eq(1))
         return is_ongoing
index 5c441e664fababa4cd5f3a97f8d7aa90512d0b11..a30218ca4bb901d836c1252428a142e829e422c5 100644 (file)
@@ -38,6 +38,8 @@ class DifferentialOutput(Special):
 
 
 class CRG(Module):
+    """ Clock and Reset Generator """
+
     def __init__(self, clk, rst=0):
         self.clock_domains.cd_sys = ClockDomain()
         self.clock_domains.cd_por = ClockDomain(reset_less=True)
index 27e8f13fb32714d1e65702a70b9acc21de1d2efb..c23c2a65dd6c5a4430fdadf6f947d3fbb79fc355 100644 (file)
@@ -11,7 +11,9 @@ from litex.gen.fhdl.bitcontainer import value_bits_sign
 from litex.gen.fhdl.tools import (list_targets, list_signals,
                               insert_resets, lower_specials)
 from litex.gen.fhdl.simplify import MemoryToArray
-from litex.gen.fhdl.specials import _MemoryLocation, _MemoryPort
+from litex.gen.fhdl.specials import _MemoryLocation
+from litex.gen.fhdl.module import Module
+from litex.gen.genlib.resetsync import AsyncResetSynchronizer
 from litex.gen.sim.vcd import VCDWriter, DummyVCDWriter
 
 
@@ -39,7 +41,7 @@ class TimeManager:
             else:
                 high = False
             self.clocks[k] = ClockState(high, half_period, half_period - phase)
-
+    
     def tick(self):
         rising = set()
         falling = set()
@@ -62,14 +64,14 @@ str2op = {
     "+": operator.add,
     "-": operator.sub,
     "*": operator.mul,
-
+    
     ">>>": operator.rshift,
     "<<<": operator.lshift,
-
+    
     "&": operator.and_,
     "^": operator.xor,
     "|": operator.or_,
-
+    
     "<": operator.lt,
     "<=": operator.le,
     "==": operator.eq,
@@ -144,8 +146,8 @@ class Evaluator:
             v = self.eval(node.v, postcommit) & (2**nbits - 1)
             return sum(v << i*nbits for i in range(node.n))
         elif isinstance(node, _ArrayProxy):
-            return self.eval(node.choices[self.eval(node.key, postcommit)],
-                             postcommit)
+            idx = min(len(node.choices) - 1, self.eval(node.key, postcommit))
+            return self.eval(node.choices[idx], postcommit)
         elif isinstance(node, _MemoryLocation):
             array = self.replaced_memories[node.memory]
             return self.eval(array[self.eval(node.index, postcommit)], postcommit)
@@ -183,7 +185,8 @@ class Evaluator:
             full_value |= value << node.start
             self.assign(node.value, full_value)
         elif isinstance(node, _ArrayProxy):
-            self.assign(node.choices[self.eval(node.key)], value)
+            idx = min(len(node.choices) - 1, self.eval(node.key))
+            self.assign(node.choices[idx], value)
         elif isinstance(node, _MemoryLocation):
             array = self.replaced_memories[node.memory]
             self.assign(array[self.eval(node.index)], value)
@@ -218,9 +221,24 @@ class Evaluator:
                 raise NotImplementedError
 
 
+class DummyAsyncResetSynchronizerImpl(Module):
+    def __init__(self, cd, async_reset):
+        # TODO: asynchronous set
+        # This naive implementation has a minimum reset pulse
+        # width requirement of one clock period in cd.
+        self.comb += cd.rst.eq(async_reset)
+
+
+class DummyAsyncResetSynchronizer:
+    @staticmethod
+    def lower(dr):
+        return DummyAsyncResetSynchronizerImpl(dr.cd, dr.async_reset)
+
+
 # TODO: instances via Iverilog/VPI
 class Simulator:
-    def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None):
+    def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None,
+                 special_overrides={}):
         if isinstance(fragment_or_module, _Fragment):
             self.fragment = fragment_or_module
         else:
@@ -229,16 +247,11 @@ class Simulator:
         mta = MemoryToArray()
         mta.transform_fragment(None, self.fragment)
 
-        fs, lowered = lower_specials(overrides={}, specials=self.fragment.specials)
+        overrides = {AsyncResetSynchronizer: DummyAsyncResetSynchronizer}
+        overrides.update(special_overrides)
+        fs, lowered = lower_specials(overrides=overrides, specials=self.fragment.specials)
         self.fragment += fs
         self.fragment.specials -= lowered
-        # FIXME: Remaining replaced ports workaround
-        remaining_memory_ports = set()
-        for s in self.fragment.specials:
-            if isinstance(s, _MemoryPort):
-                remaining_memory_ports.add(s)
-        self.fragment.specials -= remaining_memory_ports
-        # FIXME: Remaining replaced ports workaround
         if self.fragment.specials:
             raise ValueError("Could not lower all specials", self.fragment.specials)
 
index dac60305cc6c4239e0a4cb975c1614f90e9fb23d..2f1af0fdd2c8a94dd97fa7ece23e160b915964cd 100644 (file)
@@ -3,7 +3,6 @@ import subprocess
 import struct
 import shutil
 
-from litex.build.tools import write_to_file
 from litex.soc.integration import cpu_interface, soc_sdram, sdram_init
 
 
@@ -11,10 +10,9 @@ __all__ = ["soc_software_packages", "soc_directory",
            "Builder", "builder_args", "builder_argdict"]
 
 
-# in build order (for dependencies)
 soc_software_packages = [
-    "libbase",
     "libcompiler_rt",
+    "libbase",
     "libnet",
     "bios"
 ]
@@ -47,10 +45,11 @@ class Builder:
 
         self.software_packages = []
         for name in soc_software_packages:
-            self.add_software_package(
-                name, os.path.join(soc_directory, "software", name))
+            self.add_software_package(name)
 
-    def add_software_package(self, name, src_dir):
+    def add_software_package(self, name, src_dir=None):
+        if src_dir is None:
+            src_dir = os.path.join(soc_directory, "software", name)
         self.software_packages.append((name, src_dir))
 
     def _generate_includes(self):
@@ -67,38 +66,30 @@ class Builder:
         buildinc_dir = os.path.join(self.output_dir, "software", "include")
         generated_dir = os.path.join(buildinc_dir, "generated")
         os.makedirs(generated_dir, exist_ok=True)
-
-        variables_contents = []
-        def define(k, v):
-            variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
-        for k, v in cpu_interface.get_cpu_mak(cpu_type):
-            define(k, v)
-        define("SOC_DIRECTORY", soc_directory)
-        define("BUILDINC_DIRECTORY", buildinc_dir)
-        for name, src_dir in self.software_packages:
-            define(name.upper() + "_DIRECTORY", src_dir)
-        write_to_file(
-            os.path.join(generated_dir, "variables.mak"),
-            "".join(variables_contents))
-
-        write_to_file(
-            os.path.join(generated_dir, "output_format.ld"),
-            cpu_interface.get_linker_output_format(cpu_type))
-        write_to_file(
-            os.path.join(generated_dir, "regions.ld"),
-            cpu_interface.get_linker_regions(memory_regions))
-
-        write_to_file(
-            os.path.join(generated_dir, "mem.h"),
-            cpu_interface.get_mem_header(memory_regions, flash_boot_address))
-        write_to_file(
-            os.path.join(generated_dir, "csr.h"),
-            cpu_interface.get_csr_header(csr_regions, constants))
+        with open(os.path.join(generated_dir, "variables.mak"), "w") as f:
+            def define(k, v):
+                f.write("{}={}\n".format(k, _makefile_escape(v)))
+            for k, v in cpu_interface.get_cpu_mak(cpu_type):
+                define(k, v)
+            define("SOC_DIRECTORY", soc_directory)
+            define("BUILDINC_DIRECTORY", buildinc_dir)
+            f.write("export BUILDINC_DIRECTORY\n")
+            for name, src_dir in self.software_packages:
+                define(name.upper() + "_DIRECTORY", src_dir)
+
+        with open(os.path.join(generated_dir, "output_format.ld"), "w") as f:
+            f.write(cpu_interface.get_linker_output_format(cpu_type))
+        with open(os.path.join(generated_dir, "regions.ld"), "w") as f:
+            f.write(cpu_interface.get_linker_regions(memory_regions))
+
+        with open(os.path.join(generated_dir, "mem.h"), "w") as f:
+            f.write(cpu_interface.get_mem_header(memory_regions, flash_boot_address))
+        with open(os.path.join(generated_dir, "csr.h"), "w") as f:
+            f.write(cpu_interface.get_csr_header(csr_regions, constants))
 
         if sdram_phy_settings is not None:
-            write_to_file(
-                os.path.join(generated_dir, "sdram_phy.h"),
-                sdram_init.get_sdram_phy_header(sdram_phy_settings))
+            with open(os.path.join(generated_dir, "sdram_phy.h"), "w") as f:
+                f.write(sdram_init.get_sdram_phy_header(sdram_phy_settings))
 
     def _generate_csr_csv(self):
         memory_regions = self.soc.get_memory_regions()
@@ -107,9 +98,8 @@ class Builder:
 
         csr_dir = os.path.dirname(self.csr_csv)
         os.makedirs(csr_dir, exist_ok=True)
-        write_to_file(
-            self.csr_csv,
-            cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
+        with open(self.csr_csv, "w") as f:
+            f.write(cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
 
     def _prepare_software(self):
         for name, src_dir in self.software_packages:
index 2f25e1523cc6c8e6f257a2f8044067baaac91842..650ddbb8a238730c8429b440d608d83833fb96b0 100644 (file)
@@ -11,28 +11,18 @@ cpu_endianness = {
 }
 
 def get_cpu_mak(cpu):
-    clang = os.getenv("CLANG", "")
-    if clang != "":
-        clang = bool(int(clang))
-    else:
-        clang = None
     if cpu == "lm32":
-        assert not clang, "lm32 not supported with clang."
         triple = "lm32-elf"
         cpuflags = "-mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled"
+        clang = ""
     elif cpu == "or1k":
-        # default to CLANG unless told otherwise
-        if clang is None:
-           clang = True
-        triple = "or1k-elf"
-        cpuflags = "-mhard-mul -mhard-div -mror"
-        if clang:
-            triple = "or1k-linux"
-            cpuflags += "-mffl1 -maddc"
+        triple = "or1k-linux"
+        cpuflags = "-mhard-mul -mhard-div -mror -mffl1 -maddc"
+        clang = "1"
     elif cpu == "riscv32":
-        assert not clang, "riscv32 not supported with clang."
         triple = "riscv32-unknown-elf"
         cpuflags = "-mno-save-restore"
+        clang = "0"
     else:
         raise ValueError("Unsupported CPU type: "+cpu)
     return [
@@ -40,7 +30,7 @@ def get_cpu_mak(cpu):
         ("CPU", cpu),
         ("CPUFLAGS", cpuflags),
         ("CPUENDIANNESS", cpu_endianness[cpu]),
-        ("CLANG", str(0 if clang is None else int(clang)))
+        ("CLANG", clang)
     ]
 
 
@@ -71,7 +61,7 @@ def get_mem_header(regions, flash_boot_address):
     return r
 
 
-def _get_rw_functions(reg_name, reg_base, nwords, busword, read_only, with_access_functions):
+def _get_rw_functions_c(reg_name, reg_base, nwords, busword, read_only, with_access_functions):
     r = ""
 
     r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n"
@@ -124,18 +114,23 @@ def get_csr_header(regions, constants, with_access_functions=True):
             r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n"
             for csr in obj:
                 nr = (csr.size + busword - 1)//busword
-                r += _get_rw_functions(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus), with_access_functions)
+                r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus), with_access_functions)
                 origin += 4*nr
 
     r += "\n/* constants */\n"
     for name, value in constants:
-        r += "#define " + name
-        if value is not None:
-            if isinstance(value, str):
-                r +=  " \"" + value + "\""
-            else:
-                r += " " + str(value)
-        r += "\n"
+        if value is None:
+            r += "#define "+name+"\n"
+            continue
+        if isinstance(value, str):
+            value = "\"" + value + "\""
+            ctype = "const char *"
+        else:
+            value = str(value)
+            ctype = "int"
+        r += "#define "+name+" "+value+"\n"
+        r += "static inline "+ctype+" "+name.lower()+"_read(void) {\n"
+        r += "\treturn "+value+";\n}\n"
 
     r += "\n#endif\n"
     return r
index 8e3f7a2247ee43ab778207cb6945a635479a9c17..df54355f1acf8bb34ef6c2356ce09ba67e741081 100644 (file)
@@ -175,6 +175,14 @@ class SoCCore(Module):
         r += self._constants
         return r
 
+    def get_csr_dev_address(self, name, memory):
+        if memory is not None:
+            name = name + "_" + memory.name_override
+        try:
+            return self.csr_map[name]
+        except ValueError:
+            return None
+
     def do_finalize(self):
         registered_mems = {regions[0] for regions in self._memory_regions}
         if self.cpu_type is not None:
@@ -189,7 +197,7 @@ class SoCCore(Module):
 
             # CSR
             self.submodules.csrbankarray = csr_bus.CSRBankArray(self,
-                lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
+                self.get_csr_dev_address,
                 data_width=self.csr_data_width, address_width=self.csr_address_width)
             self.submodules.csrcon = csr_bus.Interconnect(
                 self.wishbone2csr.csr, self.csrbankarray.get_buses())
index efc1c810d0485c9b79bb37062a732a4e204a3da2..4969bd598d6c7086a30d35db0e809d48652e4dce 100644 (file)
@@ -62,7 +62,7 @@ class SoCSDRAM(SoCCore):
         main_ram_size = 2**(geom_settings.bankbits +
                             geom_settings.rowbits +
                             geom_settings.colbits)*sdram_width//8
-        # XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories.
+        # TODO: modify mem_map to allow larger memories.
         main_ram_size = min(main_ram_size, 256*1024*1024)
         self.add_constant("L2_SIZE", self.l2_size)
 
index c4458cdeb327516b5e3aa27c82c469eefd40b2d5..b34802fcdba7c0925dc43da92a1f4fb1b45f7bf2 100644 (file)
@@ -1,3 +1,29 @@
+"""
+Configuration and Status Registers
+**********************************
+
+The lowest-level description of a register is provided by the ``CSR`` class,
+which maps to the value at a single address on the target bus. Also provided
+are helper classes for dealing with values larger than the CSR buses data
+width.
+
+ * ``CSRConstant``, for constant values.
+ * ``CSRStatus``, for providing information to the CPU.
+ * ``CSRStorage``, for allowing control via the CPU.
+
+Generating register banks
+=========================
+A module can provide bus-independent CSRs by implementing a ``get_csrs`` method
+that returns a list of instances of the classes described above.
+
+Similarly, bus-independent memories can be returned as a list by a
+``get_memories`` method.
+
+To avoid listing those manually, a module can inherit from the ``AutoCSR``
+class, which provides ``get_csrs`` and ``get_memories`` methods that scan for
+CSR and memory attributes and return their list.
+"""
+
 from litex.gen import *
 from litex.gen.util.misc import xdir
 from litex.gen.fhdl.tracer import get_obj_var_name
@@ -12,13 +38,69 @@ class _CSRBase(DUID):
         self.size = size
 
 
+class CSRConstant(DUID):
+    """Register which contains a constant value.
+
+    Useful for providing information on how a HDL was instantiated to firmware
+    running on the device.
+    """
+
+    def __init__(self, value, bits_sign=None, name=None):
+        DUID.__init__(self)
+        self.value = Constant(value, bits_sign)
+        self.name = get_obj_var_name(name)
+        if self.name is None:
+            raise ValueError("Cannot extract CSR name from code, need to specify.")
+
+    def read(self):
+        """Read method for simulation."""
+        return self.value.value
+
+
 class CSR(_CSRBase):
+    """Basic CSR register.
+
+    Parameters
+    ----------
+    size : int
+        Size of the CSR register in bits.
+        Must be less than CSR bus width!
+
+    name : string
+        Provide (or override the name) of the CSR register.
+
+    Attributes
+    ----------
+    r : Signal(size), out
+        Contains the data written from the bus interface.
+        ``r`` is only valid when ``re`` is high.
+
+    re : Signal(), out
+        The strobe signal for ``r``.
+        It is active for one cycle, after or during a write from the bus.
+
+    w : Signal(size), in
+        The value to be read from the bus.
+        Must be provided at all times.
+    """
+
     def __init__(self, size=1, name=None):
         _CSRBase.__init__(self, size, name)
         self.re = Signal(name=self.name + "_re")
         self.r = Signal(self.size, name=self.name + "_r")
         self.w = Signal(self.size, name=self.name + "_w")
 
+    def read(self):
+        """Read method for simulation."""
+        return (yield self.w)
+
+    def write(self, value):
+        """Write method for simulation."""
+        yield self.r.eq(value)
+        yield self.re.eq(1)
+        yield
+        yield self.re.eq(0)
+
 
 class _CompoundCSR(_CSRBase, Module):
     def __init__(self, size, name):
@@ -35,6 +117,39 @@ class _CompoundCSR(_CSRBase, Module):
 
 
 class CSRStatus(_CompoundCSR):
+    """Status Register.
+
+    The ``CSRStatus`` class is meant to be used as a status register that is
+    read-only from the CPU.
+
+    The user design is expected to drive its ``status`` signal.
+
+    The advantage of using ``CSRStatus`` instead of using ``CSR`` and driving
+    ``w`` is that the width of ``CSRStatus`` can be arbitrary.
+
+    Status registers larger than the bus word width are automatically broken
+    down into several ``CSR`` registers to span several addresses.
+
+    *Be careful, though:* the atomicity of reads is not guaranteed.
+
+    Parameters
+    ----------
+    size : int
+        Size of the CSR register in bits.
+        Can be bigger than the CSR bus width.
+
+    reset : string
+        Value of the register after reset.
+
+    name : string
+        Provide (or override the name) of the ``CSRStatus`` register.
+
+    Attributes
+    ----------
+    status : Signal(size), in
+        The value of the CSRStatus register.
+    """
+
     def __init__(self, size=1, reset=0, name=None):
         _CompoundCSR.__init__(self, size, name)
         self.status = Signal(self.size, reset=reset)
@@ -47,8 +162,65 @@ class CSRStatus(_CompoundCSR):
             self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits])
             self.simple_csrs.append(sc)
 
+    def read(self):
+        """Read method for simulation."""
+        return (yield self.status)
+
 
 class CSRStorage(_CompoundCSR):
+    """Control Register.
+
+    The ``CSRStorage`` class provides a memory location that can be read and
+    written by the CPU, and read and optionally written by the design.
+
+    It can span several CSR addresses.
+
+    Parameters
+    ----------
+    size : int
+        Size of the CSR register in bits.
+        Can be bigger than the CSR bus width.
+
+    reset : string
+        Value of the register after reset.
+
+    atomic_write : bool
+        Provide an mechanism for atomic CPU writes is provided.
+        When enabled, writes to the first CSR addresses go to a back-buffer
+        whose contents are atomically copied to the main buffer when the last
+        address is written.
+
+    write_from_dev : bool
+        Allow the design to update the CSRStorage value.
+        *Warning*: The atomicity of reads by the CPU is not guaranteed.
+
+    alignment_bits : int
+        ???
+
+    name : string
+        Provide (or override the name) of the ``CSRStatus`` register.
+
+    Attributes
+    ----------
+    storage_full : Signal(size), out
+        ???
+
+    storage : Signal(size), out
+        Signal providing the value of the ``CSRStorage`` object.
+
+    re : Signal(), in
+        The strobe signal indicating a write to the ``CSRStorage`` register.
+        It is active for one cycle, after or during a write from the bus.
+
+    we : Signal(), out
+        Only available when ``write_from_dev == True``
+        ???
+
+    dat_w : Signal(), out
+        Only available when ``write_from_dev == True``
+        ???
+    """
+
     def __init__(self, size=1, reset=0, atomic_write=False, write_from_dev=False, alignment_bits=0, name=None):
         _CompoundCSR.__init__(self, size, name)
         self.alignment_bits = alignment_bits
@@ -90,6 +262,17 @@ class CSRStorage(_CompoundCSR):
                 self.sync += If(sc.re, self.storage_full[lo:hi].eq(sc.r))
         self.sync += self.re.eq(sc.re)
 
+    def read(self):
+        """Read method for simulation."""
+        return (yield self.storage) << self.alignment_bits
+
+    def write(self, value):
+        """Write method for simulation."""
+        yield self.storage.eq(value >> self.alignment_bits)
+        yield self.re.eq(1)
+        yield
+        yield self.re.eq(0)
+
 
 def csrprefix(prefix, csrs, done):
     for csr in csrs:
@@ -129,8 +312,20 @@ def _make_gatherer(method, cls, prefix_cb):
 
 
 class AutoCSR:
+    """MixIn to provide bus independent access to CSR registers.
+
+    A module can inherit from the ``AutoCSR`` class, which provides
+    ``get_csrs``, ``get_memories`` and ``get_constants`` methods that scan for
+    CSR and memory attributes and return their list.
+
+    If the module has child objects that implement ``get_csrs``,
+    ``get_memories`` or ``get_constants``, they will be called by the
+    ``AutoCSR`` methods and their CSR and memories added to the lists returned,
+    with the child objects' names as prefixes.
+    """
     get_memories = _make_gatherer("get_memories", Memory, memprefix)
     get_csrs = _make_gatherer("get_csrs", _CSRBase, csrprefix)
+    get_constants = _make_gatherer("get_constants", CSRConstant, csrprefix)
 
 
 class GenericBank(Module):
index 1281992753eba3395989c39caecbee259932060b..86a9dad4586485bea97325c58b436305c17acb79 100644 (file)
@@ -1,3 +1,11 @@
+"""
+CSR-2 bus
+=========
+
+The CSR-2 bus is a low-bandwidth, resource-sensitive bus designed for accessing
+the configuration and status registers of cores from software.
+"""
+
 from litex.gen import *
 from litex.gen.genlib.record import *
 from litex.gen.genlib.misc import chooser
@@ -20,6 +28,24 @@ class Interface(Record):
         Record.__init__(self, set_layout_parameters(_layout,
             data_width=data_width, address_width=address_width))
 
+    @classmethod
+    def like(self, other):
+        return Interface(len(other.dat_w),
+                         len(other.adr))
+
+    def write(self, adr, dat):
+        yield self.adr.eq(adr)
+        yield self.dat_w.eq(dat)
+        yield self.we.eq(1)
+        yield
+        yield self.we.eq(0)
+
+    def read(self, adr):
+        yield self.adr.eq(adr)
+        yield
+        yield
+        return (yield self.dat_r)
+
 
 class Interconnect(Module):
     def __init__(self, master, slaves):
@@ -144,6 +170,7 @@ class CSRBankArray(Module):
     def scan(self, ifargs, ifkwargs):
         self.banks = []
         self.srams = []
+        self.constants = []
         for name, obj in xdir(self.source, True):
             if hasattr(obj, "get_csrs"):
                 csrs = obj.get_csrs()
@@ -165,6 +192,9 @@ class CSRBankArray(Module):
                     self.submodules += mmap
                     csrs += mmap.get_csrs()
                     self.srams.append((name, memory, mapaddr, mmap))
+            if hasattr(obj, "get_constants"):
+                for constant in obj.get_constants():
+                    self.constants.append((name, constant))
             if csrs:
                 mapaddr = self.address_map(name, None)
                 if mapaddr is None:
index 12b85a0a94f2a6bb1714c6aef6600d5e4752227f..07a32c336df630461f5a32ae12a2dc8ebd89840f 100644 (file)
@@ -1,3 +1,8 @@
+"""
+The event manager provides a systematic way to generate standard interrupt
+controllers.
+"""
+
 from functools import reduce
 from operator import or_
 
@@ -8,16 +13,44 @@ from litex.soc.interconnect.csr import *
 
 
 class _EventSource(DUID):
+    """Base class for EventSources.
+
+    Attributes
+    ----------
+    trigger : Signal(), in
+        Signal which interfaces with the user design.
+
+    status : Signal(), out
+        Contains the current level of the trigger signal.
+        This value ends up in the ``status`` register.
+
+    pending : Signal(), out
+        A trigger event has occurred and not yet cleared.
+        This value ends up in the ``pending`` register.
+
+    clear : Signal(), in
+        Clear after a trigger event.
+        Ignored by some event sources.
+    """
+
     def __init__(self):
         DUID.__init__(self)
-        self.status = Signal()  # value in the status register
-        self.pending = Signal()  # value in the pending register + assert irq if unmasked
-        self.trigger = Signal()  # trigger signal interface to the user design
-        self.clear = Signal()  # clearing attempt by W1C to pending register, ignored by some event sources
+        self.status = Signal()
+        self.pending = Signal()
+        self.trigger = Signal()
+        self.clear = Signal()
 
 
-# set on a positive trigger pulse
 class EventSourcePulse(Module, _EventSource):
+    """EventSource which triggers on a pulse.
+
+    The event stays asserted after the ``trigger`` signal goes low, and until
+    software acknowledges it.
+
+    An example use is to pulse ``trigger`` high for 1 cycle after the reception
+    of a character in a UART.
+    """
+
     def __init__(self):
         _EventSource.__init__(self)
         self.comb += self.status.eq(0)
@@ -27,8 +60,12 @@ class EventSourcePulse(Module, _EventSource):
         ]
 
 
-# set on the falling edge of the trigger, status = trigger
 class EventSourceProcess(Module, _EventSource):
+    """EventSource which triggers on a falling edge.
+
+    The purpose of this event source is to monitor the status of processes and
+    generate an interrupt on their completion.
+    """
     def __init__(self):
         _EventSource.__init__(self)
         self.comb += self.status.eq(self.trigger)
@@ -40,8 +77,13 @@ class EventSourceProcess(Module, _EventSource):
         ]
 
 
-# all status set by external trigger
 class EventSourceLevel(Module, _EventSource):
+    """EventSource which trigger contains the instantaneous state of the event.
+
+    It must be set and released by the user design. For example, a DMA
+    controller with several slots can use this event source to signal that one
+    or more slots require CPU attention.
+    """
     def __init__(self):
         _EventSource.__init__(self)
         self.comb += [
@@ -51,6 +93,31 @@ class EventSourceLevel(Module, _EventSource):
 
 
 class EventManager(Module, AutoCSR):
+    """Provide an IRQ and CSR registers for a set of event sources.
+
+    Each event source is assigned one bit in each of those registers.
+
+    Attributes
+    ----------
+    irq : Signal(), out
+        A signal which is driven high whenever there is a pending and unmasked
+        event.
+        It is typically connected to an interrupt line of a CPU.
+
+    status : CSR(n), read-only
+        Contains the current level of the trigger line of
+        ``EventSourceProcess`` and ``EventSourceLevel`` sources.
+        It is always 0 for ``EventSourcePulse``
+
+    pending : CSR(n), read-write
+        Contains the currently asserted events. Writing 1 to the bit assigned
+        to an event clears it.
+
+    enable : CSR(n), read-write
+        Defines which asserted events will cause the ``irq`` line to be
+        asserted.
+    """
+
     def __init__(self):
         self.irq = Signal()
 
@@ -81,6 +148,8 @@ class EventManager(Module, AutoCSR):
 
 
 class SharedIRQ(Module):
+    """Allow an IRQ signal to be shared between multiple EventManager objects."""
+
     def __init__(self, *event_managers):
         self.irq = Signal()
         self.comb += self.irq.eq(reduce(or_, [ev.irq for ev in event_managers]))
index 73ba6e0ba5b320c6c126c95f2a9158cd83c3206f..2f2798c7b00c6370506a420de199af9f6a2aff2c 100644 (file)
@@ -9,14 +9,7 @@ from litex.gen.genlib.fsm import FSM, NextState
 
 from litex.soc.interconnect import csr
 
-# TODO: rewrite without FlipFlop and Counter
-@ResetInserter()
-@CEInserter()
-class FlipFlop(Module):
-    def __init__(self, *args, **kwargs):
-        self.d = Signal(*args, **kwargs)
-        self.q = Signal(*args, **kwargs)
-        self.sync += self.q.eq(self.d)
+# TODO: rewrite without FlipFlop
 
 
 _layout = [
@@ -40,6 +33,10 @@ class Interface(Record):
             data_width=data_width,
             sel_width=data_width//8))
 
+    @staticmethod
+    def like(other):
+        return Interface(len(other.dat_w))
+
     def _do_transaction(self):
         yield self.cyc.eq(1)
         yield self.stb.eq(1)
@@ -465,7 +462,7 @@ class Cache(Module):
         self.master = master
         self.slave = slave
 
-        ###
+        # # #
 
         dw_from = len(master.dat_r)
         dw_to = len(slave.dat_r)
index f7c0150b76270a35c7ea86b4b92b6e4ad998895b..e0ff8ba95b0445325daae01b7e331d07e4fb41d7 100644 (file)
@@ -27,6 +27,12 @@ static void __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, uns
        while(1);
 }
 
+enum {
+       ACK_TIMEOUT,
+       ACK_CANCELLED,
+       ACK_OK
+};
+
 static int check_ack(void)
 {
        int recognized;
@@ -42,10 +48,12 @@ static int check_ack(void)
                if(uart_read_nonblock()) {
                        char c;
                        c = uart_read();
+                       if((c == 'Q') || (c == '\e'))
+                               return ACK_CANCELLED;
                        if(c == str[recognized]) {
                                recognized++;
                                if(recognized == SFL_MAGIC_LEN)
-                                       return 1;
+                                       return ACK_OK;
                        } else {
                                if(c == str[0])
                                        recognized = 1;
@@ -55,30 +63,39 @@ static int check_ack(void)
                }
                timer0_update_value_write(1);
        }
-       return 0;
+       return ACK_TIMEOUT;
 }
 
 #define MAX_FAILED 5
 
-void serialboot(void)
+/* Returns 1 if other boot methods should be tried */
+int serialboot(void)
 {
        struct sfl_frame frame;
        int failed;
        unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
        static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
        const char *c;
+       int ack_status;
 
        printf("Booting from serial...\n");
+       printf("Press Q or ESC to abort boot completely.\n");
 
        c = str;
        while(*c) {
                uart_write(*c);
                c++;
        }
-       if(!check_ack()) {
+       ack_status = check_ack();
+       if(ack_status == ACK_TIMEOUT) {
                printf("Timeout\n");
-               return;
+               return 1;
        }
+       if(ack_status == ACK_CANCELLED) {
+               printf("Cancelled\n");
+               return 0;
+       }
+       /* assume ACK_OK */
 
        failed = 0;
        cmdline_adr = initrdstart_adr = initrdend_adr = 0;
@@ -102,7 +119,7 @@ void serialboot(void)
                        failed++;
                        if(failed == MAX_FAILED) {
                                printf("Too many consecutive errors, aborting");
-                               return;
+                               return 1;
                        }
                        uart_write(SFL_ACK_CRCERROR);
                        continue;
@@ -113,7 +130,7 @@ void serialboot(void)
                        case SFL_CMD_ABORT:
                                failed = 0;
                                uart_write(SFL_ACK_SUCCESS);
-                               return;
+                               return 1;
                        case SFL_CMD_LOAD: {
                                char *writepointer;
 
@@ -168,12 +185,13 @@ void serialboot(void)
                                failed++;
                                if(failed == MAX_FAILED) {
                                        printf("Too many consecutive errors, aborting");
-                                       return;
+                                       return 1;
                                }
                                uart_write(SFL_ACK_UNKNOWN);
                                break;
                }
        }
+       return 1;
 }
 
 #ifdef CSR_ETHMAC_BASE
index aa9cd88ad2757fc73846590932e2e606fe3feeff..65dcf4574b9d7b68007f4f919ee834fb6d6632d5 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __BOOT_H
 #define __BOOT_H
 
-void serialboot(void);
+int serialboot(void);
 void netboot(void);
 void flashboot(void);
 void romboot(void);
index 8b93392b39b737615e17f4bbb2688e09c35223e5..0bdffdf1894c46602e3e8876a8f3cf011bbe0333 100644 (file)
@@ -458,69 +458,9 @@ static void readstr(char *s, int size)
        }
 }
 
-static int test_user_abort(void)
-{
-       char c;
-
-       printf("Automatic boot in 2 seconds...\n");
-       printf("Q/ESC: abort boot\n");
-#ifdef FLASH_BOOT_ADDRESS
-       printf("F:     boot from flash\n");
-#endif
-       printf("S:     boot from serial\n");
-#ifdef CSR_ETHMAC_BASE
-       printf("N:     boot from network\n");
-#endif
-#ifdef ROM_BOOT_ADDRESS
-       printf("R:     boot from embedded ROM\n");
-#endif
-       timer0_en_write(0);
-       timer0_reload_write(0);
-#ifndef TEST_USER_ABORT_DELAY
-       timer0_load_write(SYSTEM_CLOCK_FREQUENCY*2);
-#else
-       timer0_load_write(TEST_USER_ABORT_DELAY);
-#endif
-       timer0_en_write(1);
-       timer0_update_value_write(1);
-       while(timer0_value_read()) {
-               if(readchar_nonblock()) {
-                       c = readchar();
-                       if((c == 'Q')||(c == 'q')||(c == '\e')) {
-                               puts("Aborted");
-                               return 0;
-                       }
-#ifdef FLASH_BOOT_ADDRESS
-                       if((c == 'F')||(c == 'f')) {
-                               flashboot();
-                               return 0;
-                       }
-#endif
-                       if((c == 'S')||(c == 's')) {
-                               serialboot();
-                               return 0;
-                       }
-#ifdef CSR_ETHMAC_BASE
-                       if((c == 'N')||(c == 'n')) {
-                               netboot();
-                               return 0;
-                       }
-#endif
-#ifdef ROM_BOOT_ADDRESS
-                       if((c == 'R')||(c == 'r')) {
-                               romboot();
-                               return 0;
-                       }
-#endif
-               }
-               timer0_update_value_write(1);
-       }
-       return 1;
-}
-
 static void boot_sequence(void)
 {
-       if(test_user_abort()) {
+       if(serialboot()) {
 #ifdef FLASH_BOOT_ADDRESS
                flashboot();
 #endif
@@ -557,10 +497,9 @@ int main(int i, char **c)
        printf("(unknown)\n");
 #endif
        puts(
-       "(c) Copyright 2012-2016 Enjoy-Digital\n"
-       "(c) Copyright 2007-2016 M-Labs Limited\n"
+       "(c) Copyright 2012-2017 Enjoy-Digital\n"
+       "(c) Copyright 2007-2017 M-Labs Limited\n"
        "Built "__DATE__" "__TIME__"\n");
-
        crcbios();
 #ifdef CSR_ETHMAC_BASE
        eth_init();
index 9e4534c254e8728dfa7ecd438758c403c25ad4c6..4afd04b62fded7d59b1ac351f7929349188ce520 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __INTTYPES_H
 #define __INTTYPES_H
 
+#include <stdint.h>
+
 # if __WORDSIZE == 64
 #  define __PRI64_PREFIX        "l"
 #  define __PRIPTR_PREFIX       "l"
diff --git a/litex/soc/software/include/base/math.h b/litex/soc/software/include/base/math.h
new file mode 100644 (file)
index 0000000..f13bf6c
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __MATH_H
+#define __MATH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../fdlibm/fdlibm.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATH_H */
index d1afa95ec9322aca02074844c12a190f7470f64a..4f9a211f799744f18f054dc47f4301886e7760ce 100644 (file)
@@ -14,7 +14,7 @@ extern "C" {
 typedef unsigned long size_t;
 typedef long ptrdiff_t;
 
-#define offsetof(s,m) (size_t)&(((s *)0)->m)
+#define offsetof(type, member) __builtin_offsetof(type, member)
 
 #ifdef __cplusplus
 }
index 4b9bd0492bed5bcd3b2da2b0655802141a8714df..448b2f6700cabe602a02f23b76cce88bba4dc8fb 100644 (file)
@@ -74,6 +74,7 @@ void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, con
 char *getenv(const char *name);
 
 void *malloc(size_t size);
+void *calloc(size_t nmemb, size_t size);
 void free(void *ptr);
 void *realloc(void *ptr, size_t size);
 
index 6bd55be7da0acfb54f806a53027c2b151b326627..5d3e6f340022e428e75223df790e549020113938 100644 (file)
@@ -5,7 +5,6 @@
 
 struct dyld_info {
     Elf32_Addr base;
-    const void *init;
     const char *strtab;
     const Elf32_Sym *symtab;
     struct {
@@ -21,7 +20,7 @@ extern "C" {
 #endif
 
 int dyld_load(const void *shlib, Elf32_Addr base,
-              Elf32_Addr (*resolve_import)(const char *),
+              Elf32_Addr (*resolve)(void *, const char *), void *resolve_data,
               struct dyld_info *info, const char **error_out);
 void *dyld_lookup(const char *symbol, struct dyld_info *info);
 
diff --git a/litex/soc/software/include/fdlibm/fdlibm.h b/litex/soc/software/include/fdlibm/fdlibm.h
new file mode 100644 (file)
index 0000000..60a8df6
--- /dev/null
@@ -0,0 +1,216 @@
+
+/* @(#)fdlibm.h 1.5 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Sometimes it's necessary to define __LITTLE_ENDIAN explicitly
+   but these catch some common cases. */
+
+#if defined(i386) || defined(i486) || \
+  defined(intel) || defined(x86) || defined(i86pc) || \
+  defined(__alpha) || defined(__osf__)
+#define __LITTLE_ENDIAN
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+#define __HIp(x) *(1+(int*)x)
+#define __LOp(x) *(int*)x
+#else
+#define __HI(x) *(int*)&x
+#define __LO(x) *(1+(int*)&x)
+#define __HIp(x) *(int*)x
+#define __LOp(x) *(1+(int*)x)
+#endif
+
+#ifdef __STDC__
+#define __P(p)  p
+#else
+#define __P(p)  ()
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+
+extern int signgam;
+
+#define MAXFLOAT  ((float)3.40282346638528860e+38)
+
+enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix};
+
+#define _LIB_VERSION_TYPE enum fdversion
+#define _LIB_VERSION _fdlib_version
+
+/* if global variable _LIB_VERSION is not desirable, one may
+ * change the following to be a constant by:
+ *  #define _LIB_VERSION_TYPE const enum version
+ * In that case, after one initializes the value _LIB_VERSION (see
+ * s_lib_version.c) during compile time, it cannot be modified
+ * in the middle of a program
+ */
+extern  _LIB_VERSION_TYPE  _LIB_VERSION;
+
+#define _IEEE_  fdlibm_ieee
+#define _SVID_  fdlibm_svid
+#define _XOPEN_ fdlibm_xopen
+#define _POSIX_ fdlibm_posix
+
+struct exception {
+  int type;
+  char *name;
+  double arg1;
+  double arg2;
+  double retval;
+};
+
+#define HUGE    MAXFLOAT
+
+/*
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS   1.41484755040568800000e+16
+
+#define DOMAIN    1
+#define SING    2
+#define OVERFLOW  3
+#define UNDERFLOW 4
+#define TLOSS   5
+#define PLOSS   6
+
+/*
+ * ANSI/POSIX
+ */
+extern double acos __P((double));
+extern double asin __P((double));
+extern double atan __P((double));
+extern double atan2 __P((double, double));
+extern double cos __P((double));
+extern double sin __P((double));
+extern double tan __P((double));
+
+extern double cosh __P((double));
+extern double sinh __P((double));
+extern double tanh __P((double));
+
+extern double exp __P((double));
+extern double frexp __P((double, int *));
+extern double ldexp __P((double, int));
+extern double log __P((double));
+extern double log10 __P((double));
+extern double modf __P((double, double *));
+
+extern double pow __P((double, double));
+extern double sqrt __P((double));
+
+extern double ceil __P((double));
+extern double fabs __P((double));
+extern double floor __P((double));
+extern double fmod __P((double, double));
+
+extern double erf __P((double));
+extern double erfc __P((double));
+extern double gamma __P((double));
+extern double hypot __P((double, double));
+extern int isnan __P((double));
+extern int finite __P((double));
+extern double j0 __P((double));
+extern double j1 __P((double));
+extern double jn __P((int, double));
+extern double lgamma __P((double));
+extern double y0 __P((double));
+extern double y1 __P((double));
+extern double yn __P((int, double));
+
+extern double acosh __P((double));
+extern double asinh __P((double));
+extern double atanh __P((double));
+extern double cbrt __P((double));
+extern double logb __P((double));
+extern double nextafter __P((double, double));
+extern double remainder __P((double, double));
+#ifdef _SCALB_INT
+extern double scalb __P((double, int));
+#else
+extern double scalb __P((double, double));
+#endif
+
+extern int matherr __P((struct exception *));
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand __P((double));
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign __P((double, double));
+extern int ilogb __P((double));
+extern double rint __P((double));
+extern double scalbn __P((double, int));
+
+/*
+ * BSD math library entry points
+ */
+extern double expm1 __P((double));
+extern double log1p __P((double));
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r __P((double, int *));
+extern double lgamma_r __P((double, int *));
+#endif  /* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));
+extern double __ieee754_acos __P((double));
+extern double __ieee754_acosh __P((double));
+extern double __ieee754_log __P((double));
+extern double __ieee754_atanh __P((double));
+extern double __ieee754_asin __P((double));
+extern double __ieee754_atan2 __P((double,double));
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_lgamma __P((double));
+extern double __ieee754_gamma __P((double));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern int    __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int    __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*));
index 33807f87b2a9d55ab05c0840d28543605779cafe..5db4142af20dd385ab303846ff1c335827d88cd9 100644 (file)
@@ -202,6 +202,8 @@ _exception_handler:
     l.mfspr r5, r0, SPR_EPCR_BASE
     /* Extract exception effective address */
     l.mfspr r6, r0, SPR_EEAR_BASE
+    /* Extract exception SR */
+    l.mfspr r7, r0, SPR_ESR_BASE
     /* Call exception handler with the link address as argument */
     l.jal   exception_handler
      l.nop
index 542001ad87c6dab8a4a2064c78645c3504916eea..b758e58eecfb52a5636fd485235cc996bddcb3a6 100644 (file)
+#include <generated/csr.h>
+#include <stdio.h>
+#include <stdarg.h>
+
 void isr(void);
 
 #ifdef __or1k__
 
+#include <hw/flags.h>
+
 #define EXTERNAL_IRQ 0x8
 
+static void emerg_printf(const char *fmt, ...)
+{
+       char buf[512];
+       va_list args;
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       char *p = buf;
+       while(*p) {
+               while(uart_txfull_read());
+               uart_rxtx_write(*p++);
+       }
+}
+
+static char emerg_getc()
+{
+       while(uart_rxempty_read());
+       char c = uart_rxtx_read();
+       uart_ev_pending_write(UART_EV_RX);
+       return c;
+}
+
+static const char hex[] = "0123456789abcdef";
+
+static void gdb_send(const char *txbuf)
+{
+       unsigned char cksum = 0;
+       const char *p = txbuf;
+       while(*p) cksum += *p++;
+       emerg_printf("+$%s#%c%c", txbuf, hex[cksum >> 4], hex[cksum & 0xf]);
+}
+
+static void gdb_recv(char *rxbuf, size_t size)
+{
+       size_t pos = (size_t)-1;
+       for(;;) {
+               char c = emerg_getc();
+               if(c == '$')
+                       pos = 0;
+               else if(c == '#')
+                       return;
+               else if(pos < size - 1) {
+                       rxbuf[pos++] = c;
+                       rxbuf[pos] = 0;
+               }
+       }
+}
+
+static void gdb_stub(unsigned long pc, unsigned long sr,
+                     unsigned long r1, unsigned long *regs)
+{
+       gdb_send("S05");
+
+       char buf[385];
+       for(;;) {
+               gdb_recv(buf, sizeof(buf));
+
+               switch(buf[0]) {
+                       case '?': {
+                               snprintf(buf, sizeof(buf), "S05");
+                               break;
+                       }
+
+                       case 'g': {
+                               snprintf(buf, sizeof(buf),
+                                        "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
+                                        "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x"
+                                        "%08x%08x%08x",
+                                        0,        r1,       regs[2],  regs[3],  regs[4],  regs[5],  regs[6],  regs[7],
+                                        regs[8],  regs[9],  regs[10], regs[11], regs[12], regs[13], regs[14], regs[15],
+                                        regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23],
+                                        regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31],
+                                        pc-4,     pc,       sr);
+                               break;
+                       }
+
+                       case 'm': {
+                               unsigned long addr, len;
+                               char *endptr = &buf[0];
+                               addr  = strtoul(endptr + 1, &endptr, 16);
+                               len   = strtoul(endptr + 1, &endptr, 16);
+                               unsigned char *ptr = (unsigned char *)addr;
+                               if(len > sizeof(buf) / 2) len = sizeof(buf) / 2;
+                               for(size_t i = 0; i < len; i++) {
+                                       buf[i*2  ] = hex[ptr[i] >> 4];
+                                       buf[i*2+1] = hex[ptr[i] & 15];
+                                       buf[i*2+2] = 0;
+                               }
+                               break;
+                       }
+
+                       case 'p': {
+                               unsigned long reg, value;
+                               char *endptr = &buf[0];
+                               reg   = strtoul(endptr + 1, &endptr, 16);
+                               if(reg == 0)
+                                       value = 0;
+                               else if(reg == 1)
+                                       value = r1;
+                               else if(reg >= 2 && reg <= 31)
+                                       value = regs[reg];
+                               else if(reg == 33)
+                                       value = pc;
+                               else if(reg == 34)
+                                       value = sr;
+                               else {
+                                       snprintf(buf, sizeof(buf), "E01");
+                                       break;
+                               }
+                               snprintf(buf, sizeof(buf), "%08x", value);
+                               break;
+                       }
+
+                       case 'P': {
+                               unsigned long reg, value;
+                               char *endptr = &buf[0];
+                               reg   = strtoul(endptr + 1, &endptr, 16);
+                               value = strtoul(endptr + 1, &endptr, 16);
+                               if(reg == 0)
+                                       /* ignore */;
+                               else if(reg == 1)
+                                       r1 = value;
+                               else if(reg >= 2 && reg <= 31)
+                                       regs[reg] = value;
+                               else if(reg == 33)
+                                       pc = value;
+                               else if(reg == 34)
+                                       sr = value;
+                               else {
+                                       snprintf(buf, sizeof(buf), "E01");
+                                       break;
+                               }
+                               snprintf(buf, sizeof(buf), "OK");
+                               break;
+                       }
+
+                       case 'c': {
+                               if(buf[1] != '\0') {
+                                       snprintf(buf, sizeof(buf), "E01");
+                                       break;
+                               }
+                               return;
+                       }
+
+                       default:
+                               snprintf(buf, sizeof(buf), "");
+                               break;
+               }
+
+               do {
+                       gdb_send(buf);
+               } while(emerg_getc() == '-');
+       }
+}
+
 void exception_handler(unsigned long vect, unsigned long *regs,
-                       unsigned long pc, unsigned long ea);
+                       unsigned long pc, unsigned long ea, unsigned long sr);
 void exception_handler(unsigned long vect, unsigned long *regs,
-                       unsigned long pc, unsigned long ea)
+                       unsigned long pc, unsigned long ea, unsigned long sr)
 {
        if(vect == EXTERNAL_IRQ) {
                isr();
        } else {
-               /* Unhandled exception */
-               for(;;);
+               emerg_printf("\n *** Unhandled exception %d *** \n", vect);
+               emerg_printf("   pc  %08x sr  %08x ea  %08x\n",
+                            pc, sr, ea);
+               unsigned long r1 = (unsigned long)regs + 4*32;
+               regs -= 2;
+               emerg_printf("   r0  %08x r1  %08x r2  %08x r3  %08x\n",
+                            0, r1, regs[2], regs[3]);
+               emerg_printf("   r4  %08x r5  %08x r6  %08x r7  %08x\n",
+                            regs[4], regs[5], regs[6], regs[7]);
+               emerg_printf("   r8  %08x r9  %08x r10 %08x r11 %08x\n",
+                            regs[8], regs[9], regs[10], regs[11]);
+               emerg_printf("   r12 %08x r13 %08x r14 %08x r15 %08x\n",
+                            regs[12], regs[13], regs[14], regs[15]);
+               emerg_printf("   r16 %08x r17 %08x r18 %08x r19 %08x\n",
+                            regs[16], regs[17], regs[18], regs[19]);
+               emerg_printf("   r20 %08x r21 %08x r22 %08x r23 %08x\n",
+                            regs[20], regs[21], regs[22], regs[23]);
+               emerg_printf("   r24 %08x r25 %08x r26 %08x r27 %08x\n",
+                            regs[24], regs[25], regs[26], regs[27]);
+               emerg_printf("   r28 %08x r29 %08x r30 %08x r31 %08x\n",
+                            regs[28], regs[29], regs[30], regs[31]);
+               emerg_printf(" stack:\n");
+               unsigned long *sp = (unsigned long *)r1;
+               for(unsigned long spoff = 0; spoff < 16; spoff += 4) {
+                       emerg_printf("   %08x:", &sp[spoff]);
+                       for(unsigned long spoff2 = 0; spoff2 < 4; spoff2++) {
+                               emerg_printf(" %08x", sp[spoff + spoff2]);
+                       }
+                       emerg_printf("\n");
+               }
+               emerg_printf(" waiting for gdb... ");
+               gdb_stub(pc, sr, r1, regs);
        }
 }
 #endif
index 2192974dc546d73173c966e6d57e0fa72f006edc..e056d328bf589279d380b799fba304088f22d2c5 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
+#include <math.h>
 
 /**
  * vsnprintf - Format a string and place it in a buffer
@@ -109,7 +110,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                /* get the precision */
                precision = -1;
                if (*fmt == '.') {
-                       ++fmt;  
+                       ++fmt;
                        if (isdigit(*fmt))
                                precision = skip_atoi(&fmt);
                        else if (*fmt == '*') {
@@ -195,51 +196,40 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 #ifndef NO_FLOAT
                        case 'g':
                        case 'f': {
-                               int m;
-                               double f;
-                               int integer;
-                               
+                         double f, g;
+
                                f = va_arg(args, double);
                                if(f < 0.0) {
-                                       *str = '-';
+                                       if(str < end)
+                                               *str = '-';
                                        str++;
                                        f = -f;
                                }
 
-                               integer = f;
-                               if(integer > 0) {
-                                       m = 1;
-                                       while(integer > (m*10)) m *= 10;
-                                       while((m >= 1) && (str < end)) {
-                                               int n;
-                                               n = integer/m;
-                                               *str = '0' + n;
-                                               str++;
-                                               f = f - m*n;
-                                               integer = integer - m*n;
-                                               m /= 10;
-                                       }
-                               } else if(str < end) {
-                                       *str = '0';
+                               g = pow(10.0, floor(log10(f)));
+                               if(g < 1.0) {
+                                       if(str < end)
+                                               *str = '0';
                                        str++;
                                }
-
-                               if(str < end) {
-                                       *str = '.';
+                               while(g >= 1.0) {
+                                       if(str < end)
+                                               *str = '0' + fmod(f/g, 10.0);
                                        str++;
+                                       g /= 10.0;
                                }
 
-                               for(i=0;i<6;i++) {
-                                       int n;
+                               if(str < end)
+                                       *str = '.';
+                               str++;
 
-                                       f = f*10.0;
-                                       n = f;
-                                       f = f - n;
-                                       if(str >= end) break;
-                                       *str = '0' + n;
+                               for(i=0;i<6;i++) {
+                                       f = fmod(f*10.0, 10.0);
+                                       if(str < end)
+                                               *str = '0' + f;
                                        str++;
                                }
-                               
+
                                continue;
                        }
 #endif