forastero


Nameforastero JSON
Version 1.0 PyPI version JSON
download
home_pageNone
Summarycocotb verification framework with the batteries included
upload_time2024-09-11 10:59:14
maintainerNone
docs_urlNone
authorPeter Birch
requires_python<4.0,>=3.11
licenseApache-2.0
keywords cocotb verification verilog systemverilog
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Forastero

Forastero is a library for writing better testbenches with [cocotb](http://cocotb.org),
taking some inspiration from the
[Unified Verification Methodology (UVM)](https://en.wikipedia.org/wiki/Universal_Verification_Methodology)
but distilling it to just the most useful parts.

For those unfamiliar, [cocotb](http://cocotb.org) is a Python framework for
writing testbenches for hardware designs written in a HDL such as SystemVerilog.
It is agnostic to the simulator being used, working equally well with opensource
and commercial solutions, which is rather unique for the EDA industry.

In some ways Forastero is a spiritual successor to
[cocotb-bus](https://github.com/cocotb/cocotb-bus), which has now fallen out of
active support. Forastero takes much of its inspiration from cocotb-bus, but
takes a different view to how the testbench and its various components interact.

## What makes Forastero different?

### Testbench Class

Forastero provides a way to write testbenches where common drivers and monitors
are defined and attached to the design in a class, rather than as part of each
test sequence. This is subtly different to the recommendations laid out in
[cocotb's documentation](https://docs.cocotb.org/en/stable/quickstart.html), but
leads to less code duplcation and makes it faster to add new tests.

For example, the following code defines a testbench with a driver attached to a
stream input port of the design:

```python
from forastero import BaseBench, IORole

from .stream import StreamInitiator, StreamIO

class Testbench(BaseBench):
    def __init__(self, dut):
        super().__init__(dut, clk=dut.i_clk, rst=dut.i_rst)
        stream_io = StreamIO(dut, "stream", IORole.RESPONDER)
        self.register("stream_init", StreamInitiator(self,
                                                     stream_io,
                                                     self.clk,
                                                     self.rst))
```

Highlighting a few interesting snippets:

 * `Testbench` inherits from `forastero.BaseBench` that provides a baseline
   setup for a testbench;
 * `super().__init__(...)` is called with a handle to the DUT as well as the
   primary clock and reset signals of the design, these are used in standard
   sequences (such as waiting for a test to end) to observe time passing;
 * `StreamIO(...)` wraps multiple signals on the boundary of the design up in
   a single object that can be referenced by drivers and monitors;
 * `self.register("stream_init", StreamInitiator(...))` creates an instance of
   a driver and registers it with the testbench using the name 'stream_init',
   the `StreamIO` object, clock, and reset are passed into the driver.

Forastero has some assumptions of how your design looks, specifically around
how signals are named. It assumes the following naming convention:

 * Ports are prefixed according to their direction with inputs prefixed by `i_`
   and outputs by `o_`;
 * Port names then have a common section depending on their purpose, for example
   all signal relating to the `stream` interface start with either `i_stream_`
   or `o_stream_`;
 * Finally the port name ends with its purpose, for example `i_stream_data`.

Such a design would look like:

```verilog
module arbiter (
      input  logic        i_clk
    , input  logic        i_rst
    , input  logic [31:0] i_stream_data
    , input  logic        i_stream_valid
    , output logic        o_stream_ready
    // ...other signals...
);

// ...implementation...

endmodule : arbiter
```

This style is evidently opinionated, but not without reason as it makes it clear
the exact purpose and direction of any signal within a line without having to
cross-reference the port declaration. If it is not to your taste, the code for
the `BaseIO` object is easily extensible.

### Writing Testcases

cocotb provides the `@cocotb.test()` decorator to distinguish a Python function
as a test, Forastero replaces this with a decorator defined by the testbench
class. For example:

```python
from ..testbench import Testbench

@Testbench.testcase()
async def smoke(tb : Testbench):
    ...
```

As shown above, `@cocotb.test()` is replaced by `@Testbench.testcase()` - this
performs all the same functions but replaces the `dut` argument that cocotb
normally provides with a pointer to an instance of `Testbench` instead. This
decorator does provide some new arguments:

 * `reset` - defaults to `True`, but if set to `False` it will skip the standard
   reset and initialisation preamble of the testbench and immediately start the
   test;
 * `timeout` - sets the maximum number of clock ticks that the testcase can run
   for before the testbench assumes it is a failure and stops it, this defaults
   to `10000`.
 * `shutdown_loops` - overrides the number of loops performed at the end of
   simulation to determine if all monitors, drivers, and scoreboards have
   drained, this defaults to `2`;
 * `shutdown_delay` - overrides the delay between loops of the shutdown sequence,
   this defaults to `100` clock ticks.

## Why the name Forastero?

Forastero is the most commonly grown variety of cacao tree, providing a large
part of the world's supply of cocoa beans. The name was chosen as a bit of a
word play with the 'coco' part of 'cocotb'.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "forastero",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.11",
    "maintainer_email": null,
    "keywords": "cocotb, verification, verilog, systemverilog",
    "author": "Peter Birch",
    "author_email": "peter@lightlogic.co.uk",
    "download_url": "https://files.pythonhosted.org/packages/70/a4/8cd04c768b6f2d0617785583ea0f8456a561f5255d30d07b34ace05f682e/forastero-1.0.tar.gz",
    "platform": null,
    "description": "# Forastero\n\nForastero is a library for writing better testbenches with [cocotb](http://cocotb.org),\ntaking some inspiration from the\n[Unified Verification Methodology (UVM)](https://en.wikipedia.org/wiki/Universal_Verification_Methodology)\nbut distilling it to just the most useful parts.\n\nFor those unfamiliar, [cocotb](http://cocotb.org) is a Python framework for\nwriting testbenches for hardware designs written in a HDL such as SystemVerilog.\nIt is agnostic to the simulator being used, working equally well with opensource\nand commercial solutions, which is rather unique for the EDA industry.\n\nIn some ways Forastero is a spiritual successor to\n[cocotb-bus](https://github.com/cocotb/cocotb-bus), which has now fallen out of\nactive support. Forastero takes much of its inspiration from cocotb-bus, but\ntakes a different view to how the testbench and its various components interact.\n\n## What makes Forastero different?\n\n### Testbench Class\n\nForastero provides a way to write testbenches where common drivers and monitors\nare defined and attached to the design in a class, rather than as part of each\ntest sequence. This is subtly different to the recommendations laid out in\n[cocotb's documentation](https://docs.cocotb.org/en/stable/quickstart.html), but\nleads to less code duplcation and makes it faster to add new tests.\n\nFor example, the following code defines a testbench with a driver attached to a\nstream input port of the design:\n\n```python\nfrom forastero import BaseBench, IORole\n\nfrom .stream import StreamInitiator, StreamIO\n\nclass Testbench(BaseBench):\n    def __init__(self, dut):\n        super().__init__(dut, clk=dut.i_clk, rst=dut.i_rst)\n        stream_io = StreamIO(dut, \"stream\", IORole.RESPONDER)\n        self.register(\"stream_init\", StreamInitiator(self,\n                                                     stream_io,\n                                                     self.clk,\n                                                     self.rst))\n```\n\nHighlighting a few interesting snippets:\n\n * `Testbench` inherits from `forastero.BaseBench` that provides a baseline\n   setup for a testbench;\n * `super().__init__(...)` is called with a handle to the DUT as well as the\n   primary clock and reset signals of the design, these are used in standard\n   sequences (such as waiting for a test to end) to observe time passing;\n * `StreamIO(...)` wraps multiple signals on the boundary of the design up in\n   a single object that can be referenced by drivers and monitors;\n * `self.register(\"stream_init\", StreamInitiator(...))` creates an instance of\n   a driver and registers it with the testbench using the name 'stream_init',\n   the `StreamIO` object, clock, and reset are passed into the driver.\n\nForastero has some assumptions of how your design looks, specifically around\nhow signals are named. It assumes the following naming convention:\n\n * Ports are prefixed according to their direction with inputs prefixed by `i_`\n   and outputs by `o_`;\n * Port names then have a common section depending on their purpose, for example\n   all signal relating to the `stream` interface start with either `i_stream_`\n   or `o_stream_`;\n * Finally the port name ends with its purpose, for example `i_stream_data`.\n\nSuch a design would look like:\n\n```verilog\nmodule arbiter (\n      input  logic        i_clk\n    , input  logic        i_rst\n    , input  logic [31:0] i_stream_data\n    , input  logic        i_stream_valid\n    , output logic        o_stream_ready\n    // ...other signals...\n);\n\n// ...implementation...\n\nendmodule : arbiter\n```\n\nThis style is evidently opinionated, but not without reason as it makes it clear\nthe exact purpose and direction of any signal within a line without having to\ncross-reference the port declaration. If it is not to your taste, the code for\nthe `BaseIO` object is easily extensible.\n\n### Writing Testcases\n\ncocotb provides the `@cocotb.test()` decorator to distinguish a Python function\nas a test, Forastero replaces this with a decorator defined by the testbench\nclass. For example:\n\n```python\nfrom ..testbench import Testbench\n\n@Testbench.testcase()\nasync def smoke(tb : Testbench):\n    ...\n```\n\nAs shown above, `@cocotb.test()` is replaced by `@Testbench.testcase()` - this\nperforms all the same functions but replaces the `dut` argument that cocotb\nnormally provides with a pointer to an instance of `Testbench` instead. This\ndecorator does provide some new arguments:\n\n * `reset` - defaults to `True`, but if set to `False` it will skip the standard\n   reset and initialisation preamble of the testbench and immediately start the\n   test;\n * `timeout` - sets the maximum number of clock ticks that the testcase can run\n   for before the testbench assumes it is a failure and stops it, this defaults\n   to `10000`.\n * `shutdown_loops` - overrides the number of loops performed at the end of\n   simulation to determine if all monitors, drivers, and scoreboards have\n   drained, this defaults to `2`;\n * `shutdown_delay` - overrides the delay between loops of the shutdown sequence,\n   this defaults to `100` clock ticks.\n\n## Why the name Forastero?\n\nForastero is the most commonly grown variety of cacao tree, providing a large\npart of the world's supply of cocoa beans. The name was chosen as a bit of a\nword play with the 'coco' part of 'cocotb'.\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "cocotb verification framework with the batteries included",
    "version": "1.0",
    "project_urls": {
        "Documentation": "http://forastero.intuity.io"
    },
    "split_keywords": [
        "cocotb",
        " verification",
        " verilog",
        " systemverilog"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "db7beb6b7158f3654e1b9a510ccaa7e65f48f469dcf226fc2347293df6225c79",
                "md5": "ead873045757ef1f098be92ce0c8be32",
                "sha256": "ab45aca79b2bb9f4c2ddaed4817d1bff409d857760394fe6d02b207009d3c7a3"
            },
            "downloads": -1,
            "filename": "forastero-1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ead873045757ef1f098be92ce0c8be32",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.11",
            "size": 37916,
            "upload_time": "2024-09-11T10:59:13",
            "upload_time_iso_8601": "2024-09-11T10:59:13.597816Z",
            "url": "https://files.pythonhosted.org/packages/db/7b/eb6b7158f3654e1b9a510ccaa7e65f48f469dcf226fc2347293df6225c79/forastero-1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "70a48cd04c768b6f2d0617785583ea0f8456a561f5255d30d07b34ace05f682e",
                "md5": "b8ca111026f858bf51d823343a93ed0b",
                "sha256": "17855b7ec438decac9644e173a11ea7ecab69636dab8e4c1b3cac3253e9260c7"
            },
            "downloads": -1,
            "filename": "forastero-1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b8ca111026f858bf51d823343a93ed0b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.11",
            "size": 31798,
            "upload_time": "2024-09-11T10:59:14",
            "upload_time_iso_8601": "2024-09-11T10:59:14.982182Z",
            "url": "https://files.pythonhosted.org/packages/70/a4/8cd04c768b6f2d0617785583ea0f8456a561f5255d30d07b34ace05f682e/forastero-1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-11 10:59:14",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "forastero"
}
        
Elapsed time: 0.48191s