cocotbext-spi


Namecocotbext-spi JSON
Version 0.4.0 PyPI version JSON
download
home_page
SummarySPI modules for cocotb
upload_time2023-10-05 17:30:54
maintainer
docs_urlNone
author
requires_python>=3.7
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SPI Interface for Cocotb

[![Regression Tests](https://github.com/schang412/cocotbext-spi/actions/workflows/regression-tests.yml/badge.svg)](https://github.com/schang412/cocotbext-spi/actions/workflows/regression-tests.yml)
[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)

GitHub repository: https://github.com/schang412/cocotbext-spi

## Introduction

SPI simulation framework for [cocotb](https://github.com/cocotb/cocotb).

## Installation

Installation from pip (release version, stable):
```bash
pip install cocotbext-spi
```

Installation from git (latest development version, potentially unstable):
```bash
pip install https://github.com/schang412/cocotbext-spi/archive/main.zip
```

Installation for active development:
```bash
git clone https://github.com/schang412/cocotbext-spi
pip install -e cocotbext-spi
```

## Documentation and Usage

See the `tests` directory for complete testbenches using these modules.

### SPI Signals

The SPI bus signals are bundled together into a `SpiBus` class.

If the port instantiations look like:
```verilog
module my_module(
    input  wire sclk, 
    input  wire mosi,
    output wire miso,
    input  wire cs,  // active-low
)
```
The `SpiBus` class can be created as:
```python
from cocotbext.spi import SpiBus
spi_bus = SpiBus.from_entity(dut)
```

If there is some prefix, the `from_prefix` class method may be used:
```verilog
module my_module(
    input  wire spi0_sclk, 
    input  wire spi0_mosi,
    output wire spi0_miso,
    input  wire spi0_cs,  // active-low
)
```
```python
spi_bus = SpiBus.from_prefix(dut, "spi0")
```

If the chip select has been renamed for clarity:
```verilog
module my_module(
    input  wire spi0_sclk, 
    input  wire spi0_mosi,
    output wire spi0_miso,
    input  wire spi0_ncs,  // active-low
)
```
```python
spi_bus = SpiBus.from_prefix(dut, "spi0", cs_name="ncs")
```

### SPI Config

SPI Configuration parameters are bundled together into a `SpiConfig` class.

To create the object simply call it like a class and pass in arguments:
```python
from cocotbext.spi import SpiConfig

spi_config = SpiConfig(
    word_width = 16,        # number of bits in a SPI transaction
    sclk_freq  = 25e6,      # clock rate in Hz
    cpol       = False,     # clock idle polarity
    cpha       = True,      # clock phase (CPHA=True means data sampled on second edge)
    msb_first  = True,      # the order that bits are clocked onto the wire
    data_output_idle = 1,   # the idle value of the MOSI or MISO line
    frame_spacing_ns = 1,   # the spacing between frames that the master waits for or the slave obeys
                            #       the slave should raise SpiFrameError if this is not obeyed.
    ignore_rx_value = None, # MISO value that should be ignored when received
    cs_active_low = True    # the chip select is active low
)
```

All parameters are optional, and the defaults are shown above.

### SPI Master

The `SpiMaster` class acts as an SPI Master endpoint.

To use this class, import it, configure it, and connect to the dut.

```python
from cocotbext.spi import SpiMaster, SpiBus, SpiConfig

spi_bus = SpiBus.from_entity(dut)

spi_config = SpiConfig(
    word_width = 16,     # all parameters optional
    sclk_freq  = 25e6,   # these are the defaults
    cpol       = False,
    cpha       = True,
    msb_first  = True,
    cs_active_low = True # optional (assumed True)
)

spi_master = SpiMaster(spi_bus, spi_config)
```

To send data into a design with `SpiMaster`, call `write()` or `write_nowait()`. Accepted data types are iterables of ints including lists, bytes, bytearrays, etc. Optionally, call wait() to wait for the transmit operation to complete. We can take a look at the data received back with `read()` or `read_nowait()`

```python
# TX/RX transaction example
spi_master.write_nowait([0xFFFF])
await spi_master.wait()
read_bytes = await spi_master.read()
print(read_bytes)

# we can alternatively call (which has equivalent functionality)
await spi_master.write([0xFFFF])
read_bytes = await spi_masetr.read()
```

#### Constructor Parameters
- `bus`: SpiBus
- `config`: SpiConfig

#### Methods
- `write(data)`: send data (blocking)
- `write_nowait(data)`: send data (non-blocking)
- `read(count=-1)`: read count bytes from buffer, reading whole buffer by default (blocking)
- `read_nowait(count=-1)`: read count bytes from buffer, reading whole buffer by default (non-blocking)
- `count_tx()`: returns the number of items in the transmit queue
- `count_rx()`: returns the number of items in the receive queue
- `empty_tx()`: returns True if the transmit queue is empty
- `empty_rx()`: returns True if the receive queue is empty
- `idle()`: returns True if the transmit and receive buffers are empty
- `clear()`: drop all data in the queue

### SPI Slave

The `SpiSlaveBase` acts as an abstract class for a SPI Slave Endpoint.

To use this class, import it and inherit it. Then use the subclass as the slave and connect it to the dut.

```python
from cocotbext.spi import SpiMaster, SpiBus, SpiConfig

class SimpleSpiSlave(SpiSlaveBase):
    def __init__(self, bus):
        self._config = SpiConfig()
        self.content = 0
        super().__init__(bus)

    async def get_content(self):
        await self.idle.wait()
        return self.content

    async def _transaction(self, frame_start, frame_end):
        await frame_start
        self.idle.clear()

        self.content = int(await self._shift(16, tx_word=(0xAAAA)))

        await frame_end

spi_slave = SimpleSpiSlave(SpiBus.from_entity(dut))
```

#### Implementation

All SPI Slave Classes should:
- inherit the SpiSlaveBase class
- define `self._config` adjust the values for:
    - `word_width`
    - `cpha`
    - `cpol`
    - `msb_first`
    - `frame_spacing_ns`
- implement a `_transaction` coroutine
    - the coroutine should take 3 arguments, self, frame_start and frame_end
    - the coroutine should await frame_start at the transaction start, and frame_end when done.
        - frame_start and frame_end are Rising and Falling edges of the chip select based on the chip select polarity
    - when the coroutine receives a frame_start signal, it should clear the `self.idle` Event.
        - `self.idle` is automatically set when `_transaction` returns
- when implementing a method to read the class contents, make sure to await the `self.idle`, otherwise the data may not be up to date because the device is in the middle of a transaction.


#### Simulated Devices

This framework includes some SPI Slave devices built in. A list of supported devices can be found in `cocotbext/spi/devices` and are sorted by vendor.

To use these devices, you can simply import them.

```python
from cocotbext.spi.devices.TI import DRV8306

spi_slave = DRV8306(SpiBus.from_entity(dut, cs_name="ncs"))
```

To submit a new device, make a pull request.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "cocotbext-spi",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "",
    "author_email": "Spencer Chang <spencer@sycee.xyz>",
    "download_url": "https://files.pythonhosted.org/packages/6f/29/6f38dfbaff47ae64cca6a342334e3a9c322556325333189662e895dcc1b7/cocotbext-spi-0.4.0.tar.gz",
    "platform": null,
    "description": "# SPI Interface for Cocotb\n\n[![Regression Tests](https://github.com/schang412/cocotbext-spi/actions/workflows/regression-tests.yml/badge.svg)](https://github.com/schang412/cocotbext-spi/actions/workflows/regression-tests.yml)\n[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)\n\nGitHub repository: https://github.com/schang412/cocotbext-spi\n\n## Introduction\n\nSPI simulation framework for [cocotb](https://github.com/cocotb/cocotb).\n\n## Installation\n\nInstallation from pip (release version, stable):\n```bash\npip install cocotbext-spi\n```\n\nInstallation from git (latest development version, potentially unstable):\n```bash\npip install https://github.com/schang412/cocotbext-spi/archive/main.zip\n```\n\nInstallation for active development:\n```bash\ngit clone https://github.com/schang412/cocotbext-spi\npip install -e cocotbext-spi\n```\n\n## Documentation and Usage\n\nSee the `tests` directory for complete testbenches using these modules.\n\n### SPI Signals\n\nThe SPI bus signals are bundled together into a `SpiBus` class.\n\nIf the port instantiations look like:\n```verilog\nmodule my_module(\n    input  wire sclk, \n    input  wire mosi,\n    output wire miso,\n    input  wire cs,  // active-low\n)\n```\nThe `SpiBus` class can be created as:\n```python\nfrom cocotbext.spi import SpiBus\nspi_bus = SpiBus.from_entity(dut)\n```\n\nIf there is some prefix, the `from_prefix` class method may be used:\n```verilog\nmodule my_module(\n    input  wire spi0_sclk, \n    input  wire spi0_mosi,\n    output wire spi0_miso,\n    input  wire spi0_cs,  // active-low\n)\n```\n```python\nspi_bus = SpiBus.from_prefix(dut, \"spi0\")\n```\n\nIf the chip select has been renamed for clarity:\n```verilog\nmodule my_module(\n    input  wire spi0_sclk, \n    input  wire spi0_mosi,\n    output wire spi0_miso,\n    input  wire spi0_ncs,  // active-low\n)\n```\n```python\nspi_bus = SpiBus.from_prefix(dut, \"spi0\", cs_name=\"ncs\")\n```\n\n### SPI Config\n\nSPI Configuration parameters are bundled together into a `SpiConfig` class.\n\nTo create the object simply call it like a class and pass in arguments:\n```python\nfrom cocotbext.spi import SpiConfig\n\nspi_config = SpiConfig(\n    word_width = 16,        # number of bits in a SPI transaction\n    sclk_freq  = 25e6,      # clock rate in Hz\n    cpol       = False,     # clock idle polarity\n    cpha       = True,      # clock phase (CPHA=True means data sampled on second edge)\n    msb_first  = True,      # the order that bits are clocked onto the wire\n    data_output_idle = 1,   # the idle value of the MOSI or MISO line\n    frame_spacing_ns = 1,   # the spacing between frames that the master waits for or the slave obeys\n                            #       the slave should raise SpiFrameError if this is not obeyed.\n    ignore_rx_value = None, # MISO value that should be ignored when received\n    cs_active_low = True    # the chip select is active low\n)\n```\n\nAll parameters are optional, and the defaults are shown above.\n\n### SPI Master\n\nThe `SpiMaster` class acts as an SPI Master endpoint.\n\nTo use this class, import it, configure it, and connect to the dut.\n\n```python\nfrom cocotbext.spi import SpiMaster, SpiBus, SpiConfig\n\nspi_bus = SpiBus.from_entity(dut)\n\nspi_config = SpiConfig(\n    word_width = 16,     # all parameters optional\n    sclk_freq  = 25e6,   # these are the defaults\n    cpol       = False,\n    cpha       = True,\n    msb_first  = True,\n    cs_active_low = True # optional (assumed True)\n)\n\nspi_master = SpiMaster(spi_bus, spi_config)\n```\n\nTo send data into a design with `SpiMaster`, call `write()` or `write_nowait()`. Accepted data types are iterables of ints including lists, bytes, bytearrays, etc. Optionally, call wait() to wait for the transmit operation to complete. We can take a look at the data received back with `read()` or `read_nowait()`\n\n```python\n# TX/RX transaction example\nspi_master.write_nowait([0xFFFF])\nawait spi_master.wait()\nread_bytes = await spi_master.read()\nprint(read_bytes)\n\n# we can alternatively call (which has equivalent functionality)\nawait spi_master.write([0xFFFF])\nread_bytes = await spi_masetr.read()\n```\n\n#### Constructor Parameters\n- `bus`: SpiBus\n- `config`: SpiConfig\n\n#### Methods\n- `write(data)`: send data (blocking)\n- `write_nowait(data)`: send data (non-blocking)\n- `read(count=-1)`: read count bytes from buffer, reading whole buffer by default (blocking)\n- `read_nowait(count=-1)`: read count bytes from buffer, reading whole buffer by default (non-blocking)\n- `count_tx()`: returns the number of items in the transmit queue\n- `count_rx()`: returns the number of items in the receive queue\n- `empty_tx()`: returns True if the transmit queue is empty\n- `empty_rx()`: returns True if the receive queue is empty\n- `idle()`: returns True if the transmit and receive buffers are empty\n- `clear()`: drop all data in the queue\n\n### SPI Slave\n\nThe `SpiSlaveBase` acts as an abstract class for a SPI Slave Endpoint.\n\nTo use this class, import it and inherit it. Then use the subclass as the slave and connect it to the dut.\n\n```python\nfrom cocotbext.spi import SpiMaster, SpiBus, SpiConfig\n\nclass SimpleSpiSlave(SpiSlaveBase):\n    def __init__(self, bus):\n        self._config = SpiConfig()\n        self.content = 0\n        super().__init__(bus)\n\n    async def get_content(self):\n        await self.idle.wait()\n        return self.content\n\n    async def _transaction(self, frame_start, frame_end):\n        await frame_start\n        self.idle.clear()\n\n        self.content = int(await self._shift(16, tx_word=(0xAAAA)))\n\n        await frame_end\n\nspi_slave = SimpleSpiSlave(SpiBus.from_entity(dut))\n```\n\n#### Implementation\n\nAll SPI Slave Classes should:\n- inherit the SpiSlaveBase class\n- define `self._config` adjust the values for:\n    - `word_width`\n    - `cpha`\n    - `cpol`\n    - `msb_first`\n    - `frame_spacing_ns`\n- implement a `_transaction` coroutine\n    - the coroutine should take 3 arguments, self, frame_start and frame_end\n    - the coroutine should await frame_start at the transaction start, and frame_end when done.\n        - frame_start and frame_end are Rising and Falling edges of the chip select based on the chip select polarity\n    - when the coroutine receives a frame_start signal, it should clear the `self.idle` Event.\n        - `self.idle` is automatically set when `_transaction` returns\n- when implementing a method to read the class contents, make sure to await the `self.idle`, otherwise the data may not be up to date because the device is in the middle of a transaction.\n\n\n#### Simulated Devices\n\nThis framework includes some SPI Slave devices built in. A list of supported devices can be found in `cocotbext/spi/devices` and are sorted by vendor.\n\nTo use these devices, you can simply import them.\n\n```python\nfrom cocotbext.spi.devices.TI import DRV8306\n\nspi_slave = DRV8306(SpiBus.from_entity(dut, cs_name=\"ncs\"))\n```\n\nTo submit a new device, make a pull request.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "SPI modules for cocotb",
    "version": "0.4.0",
    "project_urls": {
        "repository": "https://github.com/schang412/cocotbext-spi"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "38735d9fc9e6251a8435e385d1f8611dbfab264388c7daa9f392661d8fecd78d",
                "md5": "4a8529d54acfbb3bf2f5258dc9ffa7fb",
                "sha256": "6daa4db2a2c4ec18cece00d3517f258ffc710e982776e4cb885cc82421c5bb89"
            },
            "downloads": -1,
            "filename": "cocotbext_spi-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4a8529d54acfbb3bf2f5258dc9ffa7fb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 20113,
            "upload_time": "2023-10-05T17:30:53",
            "upload_time_iso_8601": "2023-10-05T17:30:53.020179Z",
            "url": "https://files.pythonhosted.org/packages/38/73/5d9fc9e6251a8435e385d1f8611dbfab264388c7daa9f392661d8fecd78d/cocotbext_spi-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6f296f38dfbaff47ae64cca6a342334e3a9c322556325333189662e895dcc1b7",
                "md5": "931df386c759e7ba89d2a4e8201ca878",
                "sha256": "3c2339e7dea6c7d6a70df7017526db39c7d87628af6e5f2a480ae37a5c4b992d"
            },
            "downloads": -1,
            "filename": "cocotbext-spi-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "931df386c759e7ba89d2a4e8201ca878",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 29637,
            "upload_time": "2023-10-05T17:30:54",
            "upload_time_iso_8601": "2023-10-05T17:30:54.675640Z",
            "url": "https://files.pythonhosted.org/packages/6f/29/6f38dfbaff47ae64cca6a342334e3a9c322556325333189662e895dcc1b7/cocotbext-spi-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-10-05 17:30:54",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "schang412",
    "github_project": "cocotbext-spi",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "cocotbext-spi"
}
        
Elapsed time: 0.12906s