cocotb 1.9.2__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cocotb might be problematic. Click here for more details.
- cocotb/ANSI.py +92 -0
- cocotb/__init__.py +371 -0
- cocotb/_deprecation.py +36 -0
- cocotb/_py_compat.py +63 -0
- cocotb/_sim_versions.py +145 -0
- cocotb/_vendor/__init__.py +0 -0
- cocotb/_vendor/distutils_version.py +346 -0
- cocotb/_version.py +8 -0
- cocotb/binary.py +858 -0
- cocotb/clock.py +174 -0
- cocotb/config.py +289 -0
- cocotb/decorators.py +332 -0
- cocotb/handle.py +1175 -0
- cocotb/ipython_support.py +92 -0
- cocotb/libs/libcocotb.so +0 -0
- cocotb/libs/libcocotbfli_modelsim.so +0 -0
- cocotb/libs/libcocotbutils.so +0 -0
- cocotb/libs/libcocotbvhpi_aldec.so +0 -0
- cocotb/libs/libcocotbvhpi_ius.so +0 -0
- cocotb/libs/libcocotbvhpi_modelsim.so +0 -0
- cocotb/libs/libcocotbvhpi_nvc.so +0 -0
- cocotb/libs/libcocotbvpi_aldec.so +0 -0
- cocotb/libs/libcocotbvpi_ghdl.so +0 -0
- cocotb/libs/libcocotbvpi_icarus.vpl +0 -0
- cocotb/libs/libcocotbvpi_ius.so +0 -0
- cocotb/libs/libcocotbvpi_modelsim.so +0 -0
- cocotb/libs/libcocotbvpi_vcs.so +0 -0
- cocotb/libs/libcocotbvpi_verilator.so +0 -0
- cocotb/libs/libembed.so +0 -0
- cocotb/libs/libgpi.so +0 -0
- cocotb/libs/libgpilog.so +0 -0
- cocotb/libs/libpygpilog.so +0 -0
- cocotb/log.py +303 -0
- cocotb/memdebug.py +35 -0
- cocotb/outcomes.py +56 -0
- cocotb/queue.py +179 -0
- cocotb/regression.py +933 -0
- cocotb/result.py +209 -0
- cocotb/runner.py +1400 -0
- cocotb/scheduler.py +1099 -0
- cocotb/share/def/.gitignore +2 -0
- cocotb/share/def/README.md +4 -0
- cocotb/share/def/aldec.def +61 -0
- cocotb/share/def/ghdl.def +43 -0
- cocotb/share/def/icarus.def +43 -0
- cocotb/share/def/modelsim.def +137 -0
- cocotb/share/include/cocotb_utils.h +93 -0
- cocotb/share/include/embed.h +56 -0
- cocotb/share/include/exports.h +20 -0
- cocotb/share/include/gpi.h +265 -0
- cocotb/share/include/gpi_logging.h +212 -0
- cocotb/share/include/py_gpi_logging.h +30 -0
- cocotb/share/include/vhpi_user_ext.h +26 -0
- cocotb/share/include/vpi_user_ext.h +55 -0
- cocotb/share/lib/verilator/verilator.cpp +196 -0
- cocotb/share/makefiles/Makefile.deprecations +12 -0
- cocotb/share/makefiles/Makefile.inc +176 -0
- cocotb/share/makefiles/Makefile.sim +113 -0
- cocotb/share/makefiles/simulators/Makefile.activehdl +79 -0
- cocotb/share/makefiles/simulators/Makefile.cvc +94 -0
- cocotb/share/makefiles/simulators/Makefile.ghdl +113 -0
- cocotb/share/makefiles/simulators/Makefile.icarus +111 -0
- cocotb/share/makefiles/simulators/Makefile.ius +125 -0
- cocotb/share/makefiles/simulators/Makefile.modelsim +32 -0
- cocotb/share/makefiles/simulators/Makefile.nvc +64 -0
- cocotb/share/makefiles/simulators/Makefile.questa +171 -0
- cocotb/share/makefiles/simulators/Makefile.riviera +183 -0
- cocotb/share/makefiles/simulators/Makefile.vcs +98 -0
- cocotb/share/makefiles/simulators/Makefile.verilator +86 -0
- cocotb/share/makefiles/simulators/Makefile.xcelium +136 -0
- cocotb/simulator.cpython-313-x86_64-linux-gnu.so +0 -0
- cocotb/task.py +325 -0
- cocotb/triggers.py +1104 -0
- cocotb/types/__init__.py +50 -0
- cocotb/types/array.py +309 -0
- cocotb/types/logic.py +292 -0
- cocotb/types/logic_array.py +298 -0
- cocotb/types/range.py +198 -0
- cocotb/utils.py +698 -0
- cocotb/wavedrom.py +199 -0
- cocotb/xunit_reporter.py +80 -0
- cocotb-1.9.2.dist-info/LICENSE +28 -0
- cocotb-1.9.2.dist-info/METADATA +168 -0
- cocotb-1.9.2.dist-info/RECORD +89 -0
- cocotb-1.9.2.dist-info/WHEEL +6 -0
- cocotb-1.9.2.dist-info/entry_points.txt +2 -0
- cocotb-1.9.2.dist-info/top_level.txt +21 -0
- pygpi/__init__.py +0 -0
- pygpi/entry.py +26 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
2
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
3
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
4
|
+
import IPython
|
|
5
|
+
from IPython.terminal.ipapp import load_default_config
|
|
6
|
+
from IPython.terminal.prompts import Prompts, Token
|
|
7
|
+
|
|
8
|
+
import cocotb
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SimTimePrompt(Prompts):
|
|
12
|
+
"""custom prompt that shows the sim time after a trigger fires"""
|
|
13
|
+
|
|
14
|
+
_show_time = 1
|
|
15
|
+
|
|
16
|
+
def in_prompt_tokens(self, cli=None):
|
|
17
|
+
tokens = super().in_prompt_tokens()
|
|
18
|
+
if self._show_time == self.shell.execution_count:
|
|
19
|
+
tokens = [
|
|
20
|
+
(Token.Comment, f"sim time: {cocotb.utils.get_sim_time()}"),
|
|
21
|
+
(Token.Text, "\n"),
|
|
22
|
+
] + tokens
|
|
23
|
+
return tokens
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _runner(shell, x):
|
|
27
|
+
"""Handler for async functions"""
|
|
28
|
+
ret = cocotb.scheduler._queue_function(x)
|
|
29
|
+
shell.prompts._show_time = shell.execution_count
|
|
30
|
+
return ret
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def embed(user_ns: dict = {}):
|
|
34
|
+
"""
|
|
35
|
+
Start an IPython shell in the current coroutine.
|
|
36
|
+
|
|
37
|
+
Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword
|
|
38
|
+
can be used directly from the shell to wait for triggers.
|
|
39
|
+
The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported.
|
|
40
|
+
|
|
41
|
+
This coroutine will complete only when the user exits the interactive session.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
user_ns:
|
|
45
|
+
The variables to have made available in the shell.
|
|
46
|
+
Passing ``locals()`` is often a good idea.
|
|
47
|
+
``cocotb`` will automatically be included.
|
|
48
|
+
|
|
49
|
+
Notes:
|
|
50
|
+
|
|
51
|
+
If your simulator does not provide an appropriate ``stdin``, you may
|
|
52
|
+
find you cannot type in the resulting shell. Using simulators in batch
|
|
53
|
+
or non-GUI mode may resolve this. This feature is experimental, and
|
|
54
|
+
not all simulators are supported.
|
|
55
|
+
"""
|
|
56
|
+
# ensure cocotb is in the namespace, for convenience
|
|
57
|
+
default_ns = dict(cocotb=cocotb)
|
|
58
|
+
default_ns.update(user_ns)
|
|
59
|
+
|
|
60
|
+
# build the config to enable `await`
|
|
61
|
+
c = load_default_config()
|
|
62
|
+
c.TerminalInteractiveShell.loop_runner = lambda x: _runner(shell, x)
|
|
63
|
+
c.TerminalInteractiveShell.autoawait = True
|
|
64
|
+
# Python3 checks SQLite DB accesses to ensure process ID matches the one that opened the DB and is not propogated
|
|
65
|
+
# because we launch IPython in a different process, this will cause unnecessary warnings, so disable the PID check
|
|
66
|
+
c.HistoryAccessor.connection_options = {"check_same_thread": False}
|
|
67
|
+
# create a shell with access to the dut, and cocotb pre-imported
|
|
68
|
+
shell = IPython.terminal.embed.InteractiveShellEmbed(
|
|
69
|
+
user_ns=default_ns,
|
|
70
|
+
config=c,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# add our custom prompts
|
|
74
|
+
shell.prompts = SimTimePrompt(shell)
|
|
75
|
+
|
|
76
|
+
# start the shell in a background thread
|
|
77
|
+
@cocotb.external
|
|
78
|
+
def run_shell():
|
|
79
|
+
shell()
|
|
80
|
+
|
|
81
|
+
await run_shell()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@cocotb.test()
|
|
85
|
+
async def run_ipython(dut):
|
|
86
|
+
"""A test that launches an interactive Python shell.
|
|
87
|
+
|
|
88
|
+
Do not call this directly - use this as ``make MODULE=cocotb.ipython_support``.
|
|
89
|
+
|
|
90
|
+
Within the shell, a global ``dut`` variable pointing to the design will be present.
|
|
91
|
+
"""
|
|
92
|
+
await embed(user_ns=dict(dut=dut))
|
cocotb/libs/libcocotb.so
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
cocotb/libs/libembed.so
ADDED
|
Binary file
|
cocotb/libs/libgpi.so
ADDED
|
Binary file
|
cocotb/libs/libgpilog.so
ADDED
|
Binary file
|
|
Binary file
|
cocotb/log.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Copyright (c) 2013, 2018 Potential Ventures Ltd
|
|
2
|
+
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
|
12
|
+
# * Neither the name of Potential Ventures Ltd,
|
|
13
|
+
# SolarFlare Communications Inc nor the
|
|
14
|
+
# names of its contributors may be used to endorse or promote products
|
|
15
|
+
# derived from this software without specific prior written permission.
|
|
16
|
+
#
|
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
|
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
Everything related to logging
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import logging
|
|
33
|
+
import os
|
|
34
|
+
import sys
|
|
35
|
+
import typing
|
|
36
|
+
import warnings
|
|
37
|
+
|
|
38
|
+
import cocotb.ANSI as ANSI
|
|
39
|
+
from cocotb import simulator
|
|
40
|
+
from cocotb.utils import get_sim_time, get_time_from_sim_steps, want_color_output
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
_suppress = int(os.environ.get("COCOTB_REDUCED_LOG_FMT", "1"))
|
|
44
|
+
except ValueError:
|
|
45
|
+
_suppress = 1
|
|
46
|
+
|
|
47
|
+
# Column alignment
|
|
48
|
+
_LEVEL_CHARS = len("CRITICAL")
|
|
49
|
+
_RECORD_CHARS = 34
|
|
50
|
+
_FILENAME_CHARS = 20
|
|
51
|
+
_LINENO_CHARS = 4
|
|
52
|
+
_FUNCNAME_CHARS = 31
|
|
53
|
+
|
|
54
|
+
# Custom log level
|
|
55
|
+
logging.TRACE = 5
|
|
56
|
+
logging.addLevelName(5, "TRACE")
|
|
57
|
+
|
|
58
|
+
# Default log level if not overwritten by the user.
|
|
59
|
+
_COCOTB_LOG_LEVEL_DEFAULT = "INFO"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def default_config():
|
|
63
|
+
"""Apply the default cocotb log formatting to the root logger.
|
|
64
|
+
|
|
65
|
+
This hooks up the logger to write to stdout, using either
|
|
66
|
+
:class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending
|
|
67
|
+
on whether colored output is requested. It also adds a
|
|
68
|
+
:class:`SimTimeContextFilter` filter so that
|
|
69
|
+
:attr:`~logging.LogRecord.created_sim_time` is available to the formatter.
|
|
70
|
+
|
|
71
|
+
The logging level for cocotb logs is set based on the
|
|
72
|
+
:envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``.
|
|
73
|
+
|
|
74
|
+
If desired, this logging configuration can be overwritten by calling
|
|
75
|
+
``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by
|
|
76
|
+
manually resetting the root logger instance.
|
|
77
|
+
An example of this can be found in the section on :ref:`rotating-logger`.
|
|
78
|
+
|
|
79
|
+
.. versionadded:: 1.4
|
|
80
|
+
"""
|
|
81
|
+
# construct an appropriate handler
|
|
82
|
+
hdlr = logging.StreamHandler(sys.stdout)
|
|
83
|
+
hdlr.addFilter(SimTimeContextFilter())
|
|
84
|
+
if want_color_output():
|
|
85
|
+
hdlr.setFormatter(SimColourLogFormatter())
|
|
86
|
+
else:
|
|
87
|
+
hdlr.setFormatter(SimLogFormatter())
|
|
88
|
+
|
|
89
|
+
logging.setLoggerClass(SimBaseLog) # For backwards compatibility
|
|
90
|
+
logging.basicConfig()
|
|
91
|
+
logging.getLogger().handlers = [hdlr] # overwrite default handlers
|
|
92
|
+
|
|
93
|
+
# apply level settings for cocotb
|
|
94
|
+
log = logging.getLogger("cocotb")
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# All log levels are upper case, convert the user input for convenience.
|
|
98
|
+
level = os.environ["COCOTB_LOG_LEVEL"].upper()
|
|
99
|
+
except KeyError:
|
|
100
|
+
level = _COCOTB_LOG_LEVEL_DEFAULT
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
log.setLevel(level)
|
|
104
|
+
except ValueError:
|
|
105
|
+
valid_levels = ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE")
|
|
106
|
+
raise ValueError(
|
|
107
|
+
"Invalid log level %r passed through the "
|
|
108
|
+
"COCOTB_LOG_LEVEL environment variable. Valid log "
|
|
109
|
+
"levels: %s" % (level, ", ".join(valid_levels))
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Notify GPI of log level, which it uses as an optimization to avoid
|
|
113
|
+
# calling into Python.
|
|
114
|
+
logging.getLogger("gpi").setLevel(level)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class SimBaseLog(logging.getLoggerClass()):
|
|
118
|
+
"""This class only exists for backwards compatibility"""
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def logger(self):
|
|
122
|
+
warnings.warn(
|
|
123
|
+
"the .logger attribute should not be used now that `SimLog` "
|
|
124
|
+
"returns a native logger instance directly.",
|
|
125
|
+
DeprecationWarning,
|
|
126
|
+
stacklevel=2,
|
|
127
|
+
)
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def colour(self):
|
|
132
|
+
warnings.warn(
|
|
133
|
+
"the .colour attribute may be removed in future, use the "
|
|
134
|
+
"equivalent `cocotb.utils.want_color_output()` instead",
|
|
135
|
+
DeprecationWarning,
|
|
136
|
+
stacklevel=2,
|
|
137
|
+
)
|
|
138
|
+
return want_color_output()
|
|
139
|
+
|
|
140
|
+
def setLevel(self, level: typing.Union[int, str]) -> None:
|
|
141
|
+
super().setLevel(level)
|
|
142
|
+
if self.name == "gpi":
|
|
143
|
+
simulator.log_level(self.getEffectiveLevel())
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# this used to be a class, hence the unusual capitalization
|
|
147
|
+
def SimLog(name, ident=None):
|
|
148
|
+
"""Like logging.getLogger, but append a numeric identifier to the name"""
|
|
149
|
+
if ident is not None:
|
|
150
|
+
name = f"{name}.0x{ident:x}"
|
|
151
|
+
return logging.getLogger(name)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class SimTimeContextFilter(logging.Filter):
|
|
155
|
+
"""
|
|
156
|
+
A filter to inject simulator times into the log records.
|
|
157
|
+
|
|
158
|
+
This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`.
|
|
159
|
+
|
|
160
|
+
This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.
|
|
161
|
+
|
|
162
|
+
.. versionadded:: 1.4
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
# needed to make our docs render well
|
|
166
|
+
def __init__(self):
|
|
167
|
+
""""""
|
|
168
|
+
super().__init__()
|
|
169
|
+
|
|
170
|
+
def filter(self, record):
|
|
171
|
+
try:
|
|
172
|
+
record.created_sim_time = get_sim_time()
|
|
173
|
+
except RecursionError:
|
|
174
|
+
# get_sim_time may try to log - if that happens, we can't
|
|
175
|
+
# attach a simulator time to this message.
|
|
176
|
+
record.created_sim_time = None
|
|
177
|
+
return True
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class SimLogFormatter(logging.Formatter):
|
|
181
|
+
"""Log formatter to provide consistent log message handling.
|
|
182
|
+
|
|
183
|
+
This will only add simulator timestamps if the handler object this
|
|
184
|
+
formatter is attached to has a :class:`SimTimeContextFilter` filter
|
|
185
|
+
attached, which cocotb ensures by default.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
# Removes the arguments from the base class. Docstring needed to make
|
|
189
|
+
# sphinx happy.
|
|
190
|
+
def __init__(self):
|
|
191
|
+
"""Takes no arguments."""
|
|
192
|
+
super().__init__()
|
|
193
|
+
|
|
194
|
+
# Justify and truncate
|
|
195
|
+
@staticmethod
|
|
196
|
+
def ljust(string, chars):
|
|
197
|
+
if len(string) > chars:
|
|
198
|
+
return ".." + string[(chars - 2) * -1 :]
|
|
199
|
+
return string.ljust(chars)
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def rjust(string, chars):
|
|
203
|
+
if len(string) > chars:
|
|
204
|
+
return ".." + string[(chars - 2) * -1 :]
|
|
205
|
+
return string.rjust(chars)
|
|
206
|
+
|
|
207
|
+
def _format(self, level, record, msg, coloured=False):
|
|
208
|
+
sim_time = getattr(record, "created_sim_time", None)
|
|
209
|
+
if sim_time is None:
|
|
210
|
+
sim_time_str = " -.--ns"
|
|
211
|
+
else:
|
|
212
|
+
time_ns = get_time_from_sim_steps(sim_time, "ns")
|
|
213
|
+
sim_time_str = f"{time_ns:6.2f}ns"
|
|
214
|
+
prefix = (
|
|
215
|
+
sim_time_str.rjust(11)
|
|
216
|
+
+ " "
|
|
217
|
+
+ level
|
|
218
|
+
+ " "
|
|
219
|
+
+ self.ljust(record.name, _RECORD_CHARS)
|
|
220
|
+
+ " "
|
|
221
|
+
)
|
|
222
|
+
if not _suppress:
|
|
223
|
+
prefix += (
|
|
224
|
+
self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)
|
|
225
|
+
+ ":"
|
|
226
|
+
+ self.ljust(str(record.lineno), _LINENO_CHARS)
|
|
227
|
+
+ " in "
|
|
228
|
+
+ self.ljust(str(record.funcName), _FUNCNAME_CHARS)
|
|
229
|
+
+ " "
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# these lines are copied from the builtin logger
|
|
233
|
+
if record.exc_info:
|
|
234
|
+
# Cache the traceback text to avoid converting it multiple times
|
|
235
|
+
# (it's constant anyway)
|
|
236
|
+
if not record.exc_text:
|
|
237
|
+
record.exc_text = self.formatException(record.exc_info)
|
|
238
|
+
if record.exc_text:
|
|
239
|
+
if msg[-1:] != "\n":
|
|
240
|
+
msg = msg + "\n"
|
|
241
|
+
msg = msg + record.exc_text
|
|
242
|
+
|
|
243
|
+
prefix_len = len(prefix)
|
|
244
|
+
if coloured:
|
|
245
|
+
prefix_len -= len(level) - _LEVEL_CHARS
|
|
246
|
+
pad = "\n" + " " * (prefix_len)
|
|
247
|
+
return prefix + pad.join(msg.split("\n"))
|
|
248
|
+
|
|
249
|
+
def format(self, record):
|
|
250
|
+
"""Prettify the log output, annotate with simulation time"""
|
|
251
|
+
|
|
252
|
+
msg = record.getMessage()
|
|
253
|
+
level = record.levelname.ljust(_LEVEL_CHARS)
|
|
254
|
+
|
|
255
|
+
return self._format(level, record, msg)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class SimColourLogFormatter(SimLogFormatter):
|
|
259
|
+
"""Log formatter to provide consistent log message handling."""
|
|
260
|
+
|
|
261
|
+
loglevel2colour = {
|
|
262
|
+
logging.TRACE: "%s",
|
|
263
|
+
logging.DEBUG: "%s",
|
|
264
|
+
logging.INFO: "%s",
|
|
265
|
+
logging.WARNING: ANSI.COLOR_WARNING + "%s" + ANSI.COLOR_DEFAULT,
|
|
266
|
+
logging.ERROR: ANSI.COLOR_ERROR + "%s" + ANSI.COLOR_DEFAULT,
|
|
267
|
+
logging.CRITICAL: ANSI.COLOR_CRITICAL + "%s" + ANSI.COLOR_DEFAULT,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
def format(self, record):
|
|
271
|
+
"""Prettify the log output, annotate with simulation time"""
|
|
272
|
+
|
|
273
|
+
msg = record.getMessage()
|
|
274
|
+
|
|
275
|
+
# Need to colour each line in case coloring is applied in the message
|
|
276
|
+
msg = "\n".join(
|
|
277
|
+
[
|
|
278
|
+
SimColourLogFormatter.loglevel2colour.get(record.levelno, "%s") % line
|
|
279
|
+
for line in msg.split("\n")
|
|
280
|
+
]
|
|
281
|
+
)
|
|
282
|
+
level = SimColourLogFormatter.loglevel2colour.get(
|
|
283
|
+
record.levelno, "%s"
|
|
284
|
+
) % record.levelname.ljust(_LEVEL_CHARS)
|
|
285
|
+
|
|
286
|
+
return self._format(level, record, msg, coloured=True)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _filter_from_c(logger_name, level):
|
|
290
|
+
return logging.getLogger(logger_name).isEnabledFor(level)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _log_from_c(logger_name, level, filename, lineno, msg, function_name):
|
|
294
|
+
"""
|
|
295
|
+
This is for use from the C world, and allows us to insert C stack
|
|
296
|
+
information.
|
|
297
|
+
"""
|
|
298
|
+
logger = logging.getLogger(logger_name)
|
|
299
|
+
if logger.isEnabledFor(level):
|
|
300
|
+
record = logger.makeRecord(
|
|
301
|
+
logger.name, level, filename, lineno, msg, None, None, function_name
|
|
302
|
+
)
|
|
303
|
+
logger.handle(record)
|
cocotb/memdebug.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright (c) 2013 Potential Ventures Ltd
|
|
2
|
+
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
|
12
|
+
# * Neither the name of Potential Ventures Ltd,
|
|
13
|
+
# SolarFlare Communications Inc nor the
|
|
14
|
+
# names of its contributors may be used to endorse or promote products
|
|
15
|
+
# derived from this software without specific prior written permission.
|
|
16
|
+
#
|
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
18
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
|
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
26
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
|
|
28
|
+
import cherrypy
|
|
29
|
+
import dowser
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def start(port):
|
|
33
|
+
cherrypy.tree.mount(dowser.Root())
|
|
34
|
+
cherrypy.config.update({"environment": "embedded", "server.socket_port": port})
|
|
35
|
+
cherrypy.engine.start()
|
cocotb/outcomes.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Inspired by https://github.com/python-trio/outcome
|
|
3
|
+
|
|
4
|
+
An outcome is similar to the builtin `concurrent.futures.Future`
|
|
5
|
+
or `asyncio.Future`, but without being tied to a particular task model.
|
|
6
|
+
"""
|
|
7
|
+
import abc
|
|
8
|
+
|
|
9
|
+
from cocotb.utils import remove_traceback_frames
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def capture(fn, *args, **kwargs):
|
|
13
|
+
"""Obtain an `Outcome` representing the result of a function call"""
|
|
14
|
+
try:
|
|
15
|
+
return Value(fn(*args, **kwargs))
|
|
16
|
+
except BaseException as e:
|
|
17
|
+
e = remove_traceback_frames(e, ["capture"])
|
|
18
|
+
return Error(e)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Outcome(metaclass=abc.ABCMeta):
|
|
22
|
+
@abc.abstractmethod
|
|
23
|
+
def send(self, gen):
|
|
24
|
+
"""Send or throw this outcome into a generator"""
|
|
25
|
+
|
|
26
|
+
@abc.abstractmethod
|
|
27
|
+
def get(self, gen):
|
|
28
|
+
"""Get the value of this outcome, or throw its exception"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Value(Outcome):
|
|
32
|
+
def __init__(self, value):
|
|
33
|
+
self.value = value
|
|
34
|
+
|
|
35
|
+
def send(self, gen):
|
|
36
|
+
return gen.send(self.value)
|
|
37
|
+
|
|
38
|
+
def get(self):
|
|
39
|
+
return self.value
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
return f"Value({self.value!r})"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Error(Outcome):
|
|
46
|
+
def __init__(self, error):
|
|
47
|
+
self.error = error
|
|
48
|
+
|
|
49
|
+
def send(self, gen):
|
|
50
|
+
return gen.throw(self.error)
|
|
51
|
+
|
|
52
|
+
def get(self):
|
|
53
|
+
raise self.error
|
|
54
|
+
|
|
55
|
+
def __repr__(self):
|
|
56
|
+
return f"Error({self.error!r})"
|