cocotb 1.9.2__cp311-cp311-win32.whl → 2.0.0b1__cp311-cp311-win32.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 → _ANSI.py} +5 -25
- cocotb/__init__.py +76 -332
- cocotb/_base_triggers.py +513 -0
- cocotb/_bridge.py +187 -0
- cocotb/_decorators.py +515 -0
- cocotb/_deprecation.py +3 -3
- cocotb/_exceptions.py +7 -0
- cocotb/_extended_awaitables.py +419 -0
- cocotb/_gpi_triggers.py +382 -0
- cocotb/_init.py +295 -0
- cocotb/_outcomes.py +54 -0
- cocotb/_profiling.py +46 -0
- cocotb/_py_compat.py +100 -29
- cocotb/_scheduler.py +454 -0
- cocotb/_test.py +245 -0
- cocotb/_test_factory.py +309 -0
- cocotb/_test_functions.py +42 -0
- cocotb/_typing.py +7 -0
- cocotb/_utils.py +296 -0
- cocotb/_version.py +3 -7
- cocotb/_xunit_reporter.py +66 -0
- cocotb/clock.py +271 -108
- cocotb/handle.py +1342 -795
- cocotb/libs/cocotb.dll +0 -0
- cocotb/libs/cocotb.exp +0 -0
- cocotb/libs/cocotb.lib +0 -0
- cocotb/libs/cocotbfli_modelsim.dll +0 -0
- cocotb/libs/cocotbfli_modelsim.exp +0 -0
- cocotb/libs/cocotbfli_modelsim.lib +0 -0
- cocotb/libs/cocotbutils.dll +0 -0
- cocotb/libs/cocotbutils.exp +0 -0
- cocotb/libs/cocotbutils.lib +0 -0
- cocotb/libs/cocotbvhpi_aldec.dll +0 -0
- cocotb/libs/cocotbvhpi_aldec.exp +0 -0
- cocotb/libs/cocotbvhpi_aldec.lib +0 -0
- cocotb/libs/cocotbvhpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvhpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvhpi_modelsim.lib +0 -0
- cocotb/libs/cocotbvpi_aldec.dll +0 -0
- cocotb/libs/cocotbvpi_aldec.exp +0 -0
- cocotb/libs/cocotbvpi_aldec.lib +0 -0
- cocotb/libs/cocotbvpi_ghdl.dll +0 -0
- cocotb/libs/cocotbvpi_ghdl.exp +0 -0
- cocotb/libs/cocotbvpi_ghdl.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.exp +0 -0
- cocotb/libs/cocotbvpi_icarus.lib +0 -0
- cocotb/libs/cocotbvpi_icarus.vpl +0 -0
- cocotb/libs/cocotbvpi_modelsim.dll +0 -0
- cocotb/libs/cocotbvpi_modelsim.exp +0 -0
- cocotb/libs/cocotbvpi_modelsim.lib +0 -0
- cocotb/libs/embed.dll +0 -0
- cocotb/libs/embed.exp +0 -0
- cocotb/libs/embed.lib +0 -0
- cocotb/libs/gpi.dll +0 -0
- cocotb/libs/gpi.exp +0 -0
- cocotb/libs/gpi.lib +0 -0
- cocotb/libs/gpilog.dll +0 -0
- cocotb/libs/gpilog.exp +0 -0
- cocotb/libs/gpilog.lib +0 -0
- cocotb/libs/pygpilog.dll +0 -0
- cocotb/libs/pygpilog.exp +0 -0
- cocotb/libs/pygpilog.lib +0 -0
- cocotb/{log.py → logging.py} +105 -110
- cocotb/queue.py +103 -57
- cocotb/regression.py +667 -712
- cocotb/result.py +17 -188
- cocotb/share/def/aldec.exp +0 -0
- cocotb/share/def/aldec.lib +0 -0
- cocotb/share/def/ghdl.exp +0 -0
- cocotb/share/def/ghdl.lib +0 -0
- cocotb/share/def/icarus.exp +0 -0
- cocotb/share/def/icarus.lib +0 -0
- cocotb/share/def/modelsim.def +1 -0
- cocotb/share/def/modelsim.exp +0 -0
- cocotb/share/def/modelsim.lib +0 -0
- cocotb/share/include/cocotb_utils.h +6 -29
- cocotb/share/include/embed.h +5 -28
- cocotb/share/include/gpi.h +137 -92
- cocotb/share/include/gpi_logging.h +221 -142
- cocotb/share/include/py_gpi_logging.h +7 -4
- cocotb/share/include/vpi_user_ext.h +4 -26
- cocotb/share/lib/verilator/verilator.cpp +59 -54
- cocotb/simulator.cp311-win32.exp +0 -0
- cocotb/simulator.cp311-win32.lib +0 -0
- cocotb/simulator.cp311-win32.pyd +0 -0
- cocotb/simulator.pyi +107 -0
- cocotb/task.py +434 -212
- cocotb/triggers.py +55 -1092
- cocotb/types/__init__.py +25 -47
- cocotb/types/_abstract_array.py +151 -0
- cocotb/types/_array.py +264 -0
- cocotb/types/_logic.py +296 -0
- cocotb/types/_logic_array.py +834 -0
- cocotb/types/{range.py → _range.py} +36 -44
- cocotb/types/_resolve.py +76 -0
- cocotb/utils.py +119 -587
- cocotb-2.0.0b1.dist-info/METADATA +60 -0
- cocotb-2.0.0b1.dist-info/RECORD +143 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info}/WHEEL +1 -1
- cocotb-2.0.0b1.dist-info/entry_points.txt +2 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info}/top_level.txt +1 -0
- cocotb_tools/__init__.py +0 -0
- cocotb_tools/_coverage.py +33 -0
- cocotb_tools/_vendor/__init__.py +3 -0
- cocotb_tools/check_results.py +65 -0
- cocotb_tools/combine_results.py +152 -0
- cocotb_tools/config.py +241 -0
- {cocotb → cocotb_tools}/ipython_support.py +29 -22
- cocotb_tools/makefiles/Makefile.deprecations +27 -0
- {cocotb/share → cocotb_tools}/makefiles/Makefile.inc +82 -54
- {cocotb/share → cocotb_tools}/makefiles/Makefile.sim +8 -33
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.activehdl +9 -16
- cocotb_tools/makefiles/simulators/Makefile.cvc +61 -0
- cocotb_tools/makefiles/simulators/Makefile.dsim +39 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.ghdl +13 -42
- cocotb_tools/makefiles/simulators/Makefile.icarus +80 -0
- cocotb_tools/makefiles/simulators/Makefile.ius +93 -0
- cocotb_tools/makefiles/simulators/Makefile.modelsim +9 -0
- cocotb_tools/makefiles/simulators/Makefile.nvc +60 -0
- cocotb_tools/makefiles/simulators/Makefile.questa +29 -0
- cocotb/share/makefiles/simulators/Makefile.questa → cocotb_tools/makefiles/simulators/Makefile.questa-compat +26 -54
- cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun +149 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.riviera +17 -56
- cocotb_tools/makefiles/simulators/Makefile.vcs +65 -0
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.verilator +15 -22
- {cocotb/share → cocotb_tools}/makefiles/simulators/Makefile.xcelium +20 -52
- cocotb_tools/py.typed +0 -0
- {cocotb → cocotb_tools}/runner.py +794 -361
- cocotb/_sim_versions.py → cocotb_tools/sim_versions.py +16 -21
- pygpi/entry.py +34 -17
- pygpi/py.typed +0 -0
- cocotb/binary.py +0 -858
- cocotb/config.py +0 -289
- cocotb/decorators.py +0 -332
- cocotb/memdebug.py +0 -35
- cocotb/outcomes.py +0 -56
- cocotb/scheduler.py +0 -1099
- cocotb/share/makefiles/Makefile.deprecations +0 -12
- cocotb/share/makefiles/simulators/Makefile.cvc +0 -94
- cocotb/share/makefiles/simulators/Makefile.icarus +0 -111
- cocotb/share/makefiles/simulators/Makefile.ius +0 -125
- cocotb/share/makefiles/simulators/Makefile.modelsim +0 -32
- cocotb/share/makefiles/simulators/Makefile.nvc +0 -64
- cocotb/share/makefiles/simulators/Makefile.vcs +0 -98
- cocotb/types/array.py +0 -309
- cocotb/types/logic.py +0 -292
- cocotb/types/logic_array.py +0 -298
- cocotb/wavedrom.py +0 -199
- cocotb/xunit_reporter.py +0 -80
- cocotb-1.9.2.dist-info/METADATA +0 -168
- cocotb-1.9.2.dist-info/RECORD +0 -121
- cocotb-1.9.2.dist-info/entry_points.txt +0 -2
- /cocotb/{_vendor/__init__.py → py.typed} +0 -0
- {cocotb-1.9.2.dist-info → cocotb-2.0.0b1.dist-info/licenses}/LICENSE +0 -0
- {cocotb → cocotb_tools}/_vendor/distutils_version.py +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
2
|
+
# Copyright (c) 2013 Potential Ventures Ltd
|
|
3
|
+
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
4
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
5
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
6
|
+
|
|
7
|
+
import xml.etree.ElementTree as ET
|
|
8
|
+
from typing import Union
|
|
9
|
+
from xml.etree.ElementTree import Element, SubElement
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class XUnitReporter:
|
|
13
|
+
last_testsuite: Element
|
|
14
|
+
last_testcase: Element
|
|
15
|
+
|
|
16
|
+
def __init__(self, filename: str = "results.xml") -> None:
|
|
17
|
+
self.results = Element("testsuites", name="results")
|
|
18
|
+
self.filename = filename
|
|
19
|
+
|
|
20
|
+
def add_testsuite(self, **kwargs: str) -> Element:
|
|
21
|
+
self.last_testsuite = SubElement(self.results, "testsuite", kwargs)
|
|
22
|
+
return self.last_testsuite
|
|
23
|
+
|
|
24
|
+
def add_testcase(
|
|
25
|
+
self, testsuite: Union[Element, None] = None, **kwargs: str
|
|
26
|
+
) -> Element:
|
|
27
|
+
if testsuite is None:
|
|
28
|
+
testsuite = self.last_testsuite
|
|
29
|
+
self.last_testcase = SubElement(testsuite, "testcase", kwargs)
|
|
30
|
+
return self.last_testcase
|
|
31
|
+
|
|
32
|
+
def add_property(
|
|
33
|
+
self, testsuite: Union[Element, None] = None, **kwargs: str
|
|
34
|
+
) -> Element:
|
|
35
|
+
if testsuite is None:
|
|
36
|
+
testsuite = self.last_testsuite
|
|
37
|
+
self.last_property = SubElement(testsuite, "property", kwargs)
|
|
38
|
+
return self.last_property
|
|
39
|
+
|
|
40
|
+
def add_failure(self, testcase: Union[Element, None] = None, **kwargs: str) -> None:
|
|
41
|
+
if testcase is None:
|
|
42
|
+
testcase = self.last_testcase
|
|
43
|
+
SubElement(testcase, "failure", kwargs)
|
|
44
|
+
|
|
45
|
+
def add_skipped(self, testcase: Union[Element, None] = None, **kwargs: str) -> None:
|
|
46
|
+
if testcase is None:
|
|
47
|
+
testcase = self.last_testcase
|
|
48
|
+
SubElement(testcase, "skipped", kwargs)
|
|
49
|
+
|
|
50
|
+
def indent(self, elem: Element, level: int = 0) -> None:
|
|
51
|
+
i = "\n" + level * " "
|
|
52
|
+
if len(elem):
|
|
53
|
+
if not elem.text or not elem.text.strip():
|
|
54
|
+
elem.text = i + " "
|
|
55
|
+
if not elem.tail or not elem.tail.strip():
|
|
56
|
+
elem.tail = i
|
|
57
|
+
for sub_elem in elem:
|
|
58
|
+
self.indent(sub_elem, level + 1)
|
|
59
|
+
if not sub_elem.tail or not sub_elem.tail.strip():
|
|
60
|
+
sub_elem.tail = i
|
|
61
|
+
elif level and (not elem.tail or not elem.tail.strip()):
|
|
62
|
+
elem.tail = i
|
|
63
|
+
|
|
64
|
+
def write(self) -> None:
|
|
65
|
+
self.indent(self.results)
|
|
66
|
+
ET.ElementTree(self.results).write(self.filename, encoding="UTF-8")
|
cocotb/clock.py
CHANGED
|
@@ -1,89 +1,105 @@
|
|
|
1
|
+
# Copyright cocotb contributors
|
|
1
2
|
# Copyright (c) 2013 Potential Ventures Ltd
|
|
2
3
|
# Copyright (c) 2013 SolarFlare Communications Inc
|
|
3
|
-
#
|
|
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.
|
|
4
|
+
# Licensed under the Revised BSD License, see LICENSE for details.
|
|
5
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
27
6
|
|
|
28
7
|
"""A clock class."""
|
|
29
8
|
|
|
30
|
-
import
|
|
9
|
+
import logging
|
|
31
10
|
import warnings
|
|
32
11
|
from decimal import Decimal
|
|
33
|
-
from
|
|
34
|
-
from
|
|
12
|
+
from fractions import Fraction
|
|
13
|
+
from logging import Logger
|
|
14
|
+
from typing import ClassVar, Type, Union
|
|
35
15
|
|
|
36
|
-
|
|
37
|
-
from cocotb.
|
|
38
|
-
|
|
16
|
+
import cocotb
|
|
17
|
+
from cocotb._py_compat import (
|
|
18
|
+
Literal,
|
|
19
|
+
TypeAlias,
|
|
20
|
+
cached_property,
|
|
21
|
+
)
|
|
22
|
+
from cocotb._typing import TimeUnit
|
|
23
|
+
from cocotb.handle import (
|
|
24
|
+
Deposit,
|
|
25
|
+
Force,
|
|
26
|
+
Immediate,
|
|
27
|
+
LogicObject,
|
|
28
|
+
_GPISetAction,
|
|
29
|
+
_trust_inertial,
|
|
30
|
+
)
|
|
31
|
+
from cocotb.simulator import clock_create
|
|
32
|
+
from cocotb.task import Task
|
|
33
|
+
from cocotb.triggers import (
|
|
34
|
+
ClockCycles,
|
|
35
|
+
Event,
|
|
36
|
+
FallingEdge,
|
|
37
|
+
RisingEdge,
|
|
38
|
+
Timer,
|
|
39
|
+
ValueChange,
|
|
40
|
+
)
|
|
41
|
+
from cocotb.utils import get_sim_steps, get_time_from_sim_steps
|
|
39
42
|
|
|
43
|
+
__all__ = ("Clock",)
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
"""Base class to derive from."""
|
|
45
|
+
Impl: TypeAlias = Literal["gpi", "py"]
|
|
43
46
|
|
|
44
|
-
def __init__(self, signal):
|
|
45
|
-
self.signal = signal
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
def log(self):
|
|
49
|
-
return SimLog("cocotb.{}.{}".format(type(self).__qualname__, self.signal._name))
|
|
48
|
+
_valid_impls = ("gpi", "py")
|
|
50
49
|
|
|
51
50
|
|
|
52
|
-
class Clock
|
|
51
|
+
class Clock:
|
|
53
52
|
r"""Simple 50:50 duty cycle clock driver.
|
|
54
53
|
|
|
55
|
-
Instances of this class should call its :meth:`start` method
|
|
56
|
-
and pass the coroutine object to one of the functions in :ref:`task-management`.
|
|
57
|
-
|
|
58
|
-
This will create a clocking task that drives the signal at the
|
|
59
|
-
desired period/frequency.
|
|
60
|
-
|
|
61
|
-
Example:
|
|
62
|
-
|
|
63
54
|
.. code-block:: python
|
|
64
55
|
|
|
65
|
-
c = Clock(dut.clk, 10,
|
|
66
|
-
|
|
56
|
+
c = Clock(dut.clk, 10, "ns")
|
|
57
|
+
c.start()
|
|
67
58
|
|
|
68
59
|
Args:
|
|
69
60
|
signal: The clock pin/signal to be driven.
|
|
70
|
-
period
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
period: The clock period.
|
|
62
|
+
|
|
63
|
+
.. note::
|
|
64
|
+
Must convert to an even number of timesteps.
|
|
65
|
+
unit:
|
|
66
|
+
One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``.
|
|
67
|
+
When *unit* is ``'step'``,
|
|
75
68
|
the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`).
|
|
76
69
|
|
|
70
|
+
.. versionchanged:: 2.0
|
|
71
|
+
Renamed from ``units``.
|
|
72
|
+
|
|
73
|
+
impl:
|
|
74
|
+
One of ``'auto'``, ``'gpi'``, ``'py'``.
|
|
75
|
+
Specify whether the clock is implemented with a :class:`~cocotb.simulator.GpiClock` (faster), or with a Python coroutine.
|
|
76
|
+
When ``'auto'`` is used (default), the fastest implementation that supports your environment and use case is picked.
|
|
77
|
+
|
|
78
|
+
.. versionadded:: 2.0
|
|
79
|
+
|
|
80
|
+
set_action:
|
|
81
|
+
One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`.
|
|
82
|
+
Specify the action to use when setting the clock signal value.
|
|
83
|
+
Defaults to the value of :attr:`default_set_action`.
|
|
84
|
+
|
|
85
|
+
.. versionadded:: 2.0
|
|
86
|
+
|
|
87
|
+
When *impl* is ``'auto'``, if :envvar:`COCOTB_TRUST_INERTIAL_WRITES` is defined,
|
|
88
|
+
the :class:`~cocotb.simulator.GpiClock` implementation will be used.
|
|
89
|
+
Otherwise, the Python coroutine implementation will be used.
|
|
90
|
+
See the environment variable's documentation for more information on the consequences
|
|
91
|
+
of using the simulator's inertial write mechanism.
|
|
92
|
+
|
|
77
93
|
If you need more features like a phase shift and an asymmetric duty cycle,
|
|
78
|
-
it is simple to create your own clock generator (that you then :func
|
|
94
|
+
it is simple to create your own clock generator (that you then :func:`cocotb.start_soon`):
|
|
79
95
|
|
|
80
96
|
.. code-block:: python
|
|
81
97
|
|
|
82
98
|
async def custom_clock():
|
|
83
99
|
# pre-construct triggers for performance
|
|
84
|
-
high_time = Timer(high_delay,
|
|
85
|
-
low_time = Timer(low_delay,
|
|
86
|
-
await Timer(initial_delay,
|
|
100
|
+
high_time = Timer(high_delay, unit="ns")
|
|
101
|
+
low_time = Timer(low_delay, unit="ns")
|
|
102
|
+
await Timer(initial_delay, unit="ns")
|
|
87
103
|
while True:
|
|
88
104
|
dut.clk.value = 1
|
|
89
105
|
await high_time
|
|
@@ -100,75 +116,222 @@ class Clock(BaseClock):
|
|
|
100
116
|
async def custom_clock():
|
|
101
117
|
while True:
|
|
102
118
|
dut.clk.value = 1
|
|
103
|
-
await Timer(high_delay,
|
|
119
|
+
await Timer(high_delay, unit="ns")
|
|
104
120
|
dut.clk.value = 0
|
|
105
|
-
await Timer(low_delay,
|
|
121
|
+
await Timer(low_delay, unit="ns")
|
|
122
|
+
|
|
106
123
|
|
|
107
124
|
high_delay = low_delay = 100
|
|
108
|
-
|
|
109
|
-
await Timer(1000,
|
|
125
|
+
cocotb.start_soon(custom_clock())
|
|
126
|
+
await Timer(1000, unit="ns")
|
|
110
127
|
high_delay = low_delay = 10 # change the clock speed
|
|
111
|
-
await Timer(1000,
|
|
128
|
+
await Timer(1000, unit="ns")
|
|
129
|
+
|
|
130
|
+
.. versionadded:: 1.5
|
|
131
|
+
Support ``'step'`` as the *unit* argument to mean "simulator time step".
|
|
132
|
+
|
|
133
|
+
.. versionremoved:: 2.0
|
|
134
|
+
Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.
|
|
135
|
+
|
|
136
|
+
.. versionchanged:: 2.0
|
|
137
|
+
:meth:`start` now automatically calls :func:`cocotb.start_soon` and stores the Task
|
|
138
|
+
on the Clock object, so that it may later be :meth:`stop`\ ped.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
_impl: Impl
|
|
112
142
|
|
|
113
|
-
|
|
114
|
-
|
|
143
|
+
default_set_action: ClassVar[Union[Type[Immediate], Type[Deposit], Type[Force]]] = (
|
|
144
|
+
Deposit
|
|
145
|
+
)
|
|
146
|
+
"""The default action used to set the clock signal value.
|
|
147
|
+
One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`.
|
|
115
148
|
|
|
116
|
-
..
|
|
117
|
-
Using ``None`` as the *units* argument is deprecated, use ``'step'`` instead.
|
|
149
|
+
.. versionadded:: 2.0
|
|
118
150
|
"""
|
|
119
151
|
|
|
120
152
|
def __init__(
|
|
121
|
-
self,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
153
|
+
self,
|
|
154
|
+
signal: LogicObject,
|
|
155
|
+
period: Union[float, Fraction, Decimal],
|
|
156
|
+
unit: TimeUnit = "step",
|
|
157
|
+
impl: Union[Impl, None] = None,
|
|
158
|
+
*,
|
|
159
|
+
units: None = None,
|
|
160
|
+
set_action: Union[Type[Immediate], Type[Deposit], Type[Force], None] = None,
|
|
161
|
+
) -> None:
|
|
162
|
+
self._signal = signal
|
|
163
|
+
self._period = period
|
|
164
|
+
if units is not None:
|
|
125
165
|
warnings.warn(
|
|
126
|
-
'
|
|
166
|
+
"The 'units' argument has been renamed to 'unit'.",
|
|
127
167
|
DeprecationWarning,
|
|
128
168
|
stacklevel=2,
|
|
129
169
|
)
|
|
130
|
-
|
|
131
|
-
self.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
170
|
+
unit = units
|
|
171
|
+
self._unit: TimeUnit = unit
|
|
172
|
+
if set_action is None:
|
|
173
|
+
set_action = type(self).default_set_action
|
|
174
|
+
if set_action not in (Immediate, Deposit, Force):
|
|
175
|
+
raise TypeError(
|
|
176
|
+
"Invalid value for *set_action*. *set_action* must be one of Immediate, Deposit, or Force"
|
|
177
|
+
)
|
|
178
|
+
self._set_action = set_action
|
|
179
|
+
|
|
180
|
+
if impl is None:
|
|
181
|
+
self._impl = "gpi" if _trust_inertial else "py"
|
|
182
|
+
elif impl in _valid_impls:
|
|
183
|
+
self._impl = impl
|
|
184
|
+
else:
|
|
185
|
+
valid_impls_str = ", ".join([repr(i) for i in _valid_impls])
|
|
186
|
+
raise ValueError(
|
|
187
|
+
f"Invalid clock impl {impl!r}, must be one of: {valid_impls_str}"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
self._task: Union[Task[None], None] = None
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def signal(self) -> LogicObject:
|
|
194
|
+
"""The clock signal being driven."""
|
|
195
|
+
return self._signal
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def period(self) -> Union[float, Fraction, Decimal]:
|
|
199
|
+
"""The clock period (unit-less)."""
|
|
200
|
+
return self._period
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def unit(self) -> TimeUnit:
|
|
204
|
+
"""The unit of the clock period.
|
|
205
|
+
|
|
206
|
+
.. versionadded:: 2.0
|
|
207
|
+
"""
|
|
208
|
+
return self._unit
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def impl(self) -> Impl:
|
|
212
|
+
"""The concrete implementation of the clock used.
|
|
213
|
+
|
|
214
|
+
``"gpi"`` if the clock is implemented in C in the GPI layer,
|
|
215
|
+
or ``"py"`` if the clock is implemented in Python using cocotb Tasks.
|
|
216
|
+
|
|
217
|
+
.. versionadded:: 2.0
|
|
218
|
+
"""
|
|
219
|
+
return self._impl
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def set_action(self) -> Union[Type[Immediate], Type[Deposit], Type[Force]]:
|
|
223
|
+
"""The value setting action used to set the clock signal value.
|
|
224
|
+
|
|
225
|
+
.. versionadded:: 2.0
|
|
226
|
+
"""
|
|
227
|
+
return self._set_action
|
|
228
|
+
|
|
229
|
+
def start(self, start_high: bool = True) -> Task[None]:
|
|
230
|
+
r"""Start driving the clock signal.
|
|
231
|
+
|
|
232
|
+
You can later stop the clock by calling :meth:`stop`.
|
|
142
233
|
|
|
143
234
|
Args:
|
|
144
|
-
|
|
145
|
-
or if ``None`` then cycle the clock forever.
|
|
146
|
-
Note: ``0`` is not the same as ``None``, as ``0`` will cycle no times.
|
|
147
|
-
start_high (bool, optional): Whether to start the clock with a ``1``
|
|
235
|
+
start_high: Whether to start the clock with a ``1``
|
|
148
236
|
for the first half of the period.
|
|
149
237
|
Default is ``True``.
|
|
150
238
|
|
|
151
239
|
.. versionadded:: 1.3
|
|
240
|
+
|
|
241
|
+
Raises:
|
|
242
|
+
RuntimeError: If attempting to start a clock that has already been started.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Object which can be passed to :func:`cocotb.start_soon` or ignored.
|
|
246
|
+
|
|
247
|
+
.. versionremoved:: 2.0
|
|
248
|
+
Removed ``cycles`` arguments for toggling for a finite amount of cycles.
|
|
249
|
+
Use :meth:`stop` to stop a clock from running.
|
|
250
|
+
|
|
251
|
+
.. versionchanged:: 2.0
|
|
252
|
+
Previously, this method returned a :term:`coroutine` which needed to be passed to :func:`cocotb.start_soon`.
|
|
253
|
+
Now the Clock object keeps track of its own driver Task, so this is no longer necessary.
|
|
254
|
+
Simply call ``clock.start()`` to start running the clock.
|
|
152
255
|
"""
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
256
|
+
if self._task is not None:
|
|
257
|
+
raise RuntimeError("Starting clock that has already been started.")
|
|
258
|
+
|
|
259
|
+
period = get_sim_steps(self._period, self._unit)
|
|
260
|
+
t_high = period // 2
|
|
261
|
+
|
|
262
|
+
if self._impl == "gpi":
|
|
263
|
+
clkobj = clock_create(self._signal._handle)
|
|
264
|
+
set_action = {
|
|
265
|
+
Deposit: _GPISetAction.DEPOSIT,
|
|
266
|
+
Immediate: _GPISetAction.NO_DELAY,
|
|
267
|
+
Force: _GPISetAction.FORCE,
|
|
268
|
+
}[self._set_action]
|
|
269
|
+
clkobj.start(period, t_high, start_high, set_action)
|
|
270
|
+
|
|
271
|
+
async def drive() -> None:
|
|
272
|
+
# The clock is meant to toggle forever, so awaiting this should
|
|
273
|
+
# never return by awaiting on Event that's never set.
|
|
274
|
+
e = Event()
|
|
275
|
+
try:
|
|
276
|
+
await e.wait()
|
|
277
|
+
finally:
|
|
278
|
+
clkobj.stop()
|
|
279
|
+
|
|
166
280
|
else:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
281
|
+
|
|
282
|
+
async def drive() -> None:
|
|
283
|
+
timer_high = Timer(t_high)
|
|
284
|
+
timer_low = Timer(period - t_high)
|
|
285
|
+
if start_high:
|
|
286
|
+
self._signal.set(self._set_action(1))
|
|
287
|
+
await timer_high
|
|
288
|
+
while True:
|
|
289
|
+
self._signal.set(self._set_action(0))
|
|
290
|
+
await timer_low
|
|
291
|
+
self._signal.set(self._set_action(1))
|
|
292
|
+
await timer_high
|
|
293
|
+
|
|
294
|
+
self._task = cocotb.start_soon(drive())
|
|
295
|
+
return self._task
|
|
296
|
+
|
|
297
|
+
def stop(self) -> None:
|
|
298
|
+
"""Stop driving the clock signal.
|
|
299
|
+
|
|
300
|
+
You can later start the clock again by calling :meth:`start`.
|
|
301
|
+
|
|
302
|
+
Raises:
|
|
303
|
+
RuntimeError: If attempting to stop a clock that has never been started.
|
|
304
|
+
|
|
305
|
+
.. versionadded:: 2.0
|
|
306
|
+
"""
|
|
307
|
+
if self._task is None:
|
|
308
|
+
raise RuntimeError("Stopping a clock that was never started.")
|
|
309
|
+
self._task.cancel()
|
|
310
|
+
self._task = None
|
|
311
|
+
|
|
312
|
+
async def cycles(
|
|
313
|
+
self,
|
|
314
|
+
num_cycles: int,
|
|
315
|
+
edge_type: Union[
|
|
316
|
+
Type[RisingEdge], Type[FallingEdge], Type[ValueChange]
|
|
317
|
+
] = RisingEdge,
|
|
318
|
+
) -> None:
|
|
319
|
+
"""Wait for a number of clock cycles."""
|
|
320
|
+
# TODO Improve implementation to use a Timer to skip most of the cycles
|
|
321
|
+
await ClockCycles(self._signal, num_cycles, edge_type)
|
|
322
|
+
|
|
323
|
+
def __repr__(self) -> str:
|
|
324
|
+
return self._repr
|
|
325
|
+
|
|
326
|
+
@cached_property
|
|
327
|
+
def _repr(self) -> str:
|
|
328
|
+
freq_mhz = 1 / get_time_from_sim_steps(
|
|
329
|
+
get_sim_steps(self._period, self._unit), "us"
|
|
330
|
+
)
|
|
331
|
+
return f"<{type(self).__qualname__}, {self._signal._path} @ {freq_mhz} MHz>"
|
|
332
|
+
|
|
333
|
+
@cached_property
|
|
334
|
+
def _log(self) -> Logger:
|
|
335
|
+
return logging.getLogger(
|
|
336
|
+
f"cocotb.{type(self).__qualname__}.{self._signal._name}"
|
|
337
|
+
)
|