diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..1a94f0f --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,34 @@ +name: Lint + +on: + push: + branches: + - master + - 'stable/**' + pull_request: + branches: + - master + - 'stable/**' + +jobs: + build: + runs-on: ubuntu-22.04 + + strategy: + matrix: + python-version: + - 3.9 + + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install nox + run: pip install --upgrade nox + + - name: Run nox tests + run: nox -s "lint-${{ matrix.python-version }}" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 34ed916..9560672 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,4 +1,4 @@ -name: Tests +name: Regression Tests on: push: diff --git a/cocotbext/ahb/__init__.py b/cocotbext/ahb/__init__.py index ab16cfe..295a0cd 100644 --- a/cocotbext/ahb/__init__.py +++ b/cocotbext/ahb/__init__.py @@ -2,8 +2,20 @@ # -*- coding: utf-8 -*- # File : __init__.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 02.10.2023 -# Last Modified Date: 07.10.2023 +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + +# Imported all classes in the default constructor to avoid +# specific imports by knowing the folder/files +# ex. without this: +# from cocotbext.ahb.ahb_master import AHBLiteMaster +# from cocotbext.ahb.ahb_bus import AHBBus +# ex. with this: +# from cocotbext.ahb import AHBLiteMaster, AHBBus from .ahb_master import AHBLiteMaster from .ahb_bus import AHBBus + +# Called classes due to flake8 +AHBBus() +AHBLiteMaster() diff --git a/cocotbext/ahb/ahb_bus.py b/cocotbext/ahb/ahb_bus.py index b883e2f..46bfde1 100644 --- a/cocotbext/ahb/ahb_bus.py +++ b/cocotbext/ahb/ahb_bus.py @@ -2,31 +2,31 @@ # -*- coding: utf-8 -*- # File : ahb_bus.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 07.10.2023 -# Last Modified Date: 07.10.2023 -import cocotb +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 from cocotb_bus.drivers import Bus from cocotb.handle import SimHandleBase -from typing import Any, List, Optional, Sequence, Tuple, Union +from typing import Any + class AHBBus(Bus): _signals = ["haddr", "hsize", "htrans", "hwdata", "hrdata", "hwrite", "hready", "hresp"] - _optional_signals = ["hburst","hmastlock", "hprot", "hnonsec", + _optional_signals = ["hburst", "hmastlock", "hprot", "hnonsec", "hexcl", "hmaster", "hexokay", "hsel"] - def __init__(self, entity: SimHandleBase=None, - prefix:str=None, **kwargs: Any): - super().__init__(entity, prefix, self._signals, + def __init__(self, entity: SimHandleBase = None, + prefix: str = None, **kwargs: Any) -> None: + super().__init__(entity, prefix, self._signals, optional_signals=self._optional_signals, **kwargs) self.entity = entity - self.name = prefix if prefix is not None else entity._name+'_ahb_bus' + self.name = prefix if prefix is not None else entity._name+'_ahb_bus' self._data_width = len(self.hwdata) self._addr_width = len(self.haddr) - + @property def data_width(self): return self._data_width @@ -38,7 +38,7 @@ def addr_width(self): @property def hsel_exist(self): return 1 if 'hsel' in self._signals else 0 - + @classmethod def from_entity(cls, entity, **kwargs): return cls(entity, **kwargs) diff --git a/cocotbext/ahb/ahb_master.py b/cocotbext/ahb/ahb_master.py index 38928e7..cba70d3 100644 --- a/cocotbext/ahb/ahb_master.py +++ b/cocotbext/ahb/ahb_master.py @@ -2,36 +2,59 @@ # -*- coding: utf-8 -*- # File : ahb_master.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 01.10.2023 -# Last Modified Date: 07.10.2023 +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + import cocotb +import logging -from .ahb_types import AHBTrans, AHBWrite +from .ahb_types import AHBTrans, AHBWrite, AHBSize from .ahb_bus import AHBBus +from .version import __version__ -from cocotb_bus.drivers import Bus -from cocotb.handle import SimHandleBase from cocotb.triggers import RisingEdge -from typing import Any, List, Optional, Sequence, Tuple, Union -from cocotb.log import SimLog +from typing import Optional, Sequence, Union +from cocotb.types import LogicArray +from cocotb.binary import BinaryValue + class AHBLiteMaster: - def __init__(self, bus: AHBBus, clock: str, reset: str, **kwargs): + def __init__(self, bus: AHBBus, clock: str, reset: str, + timeout: int = 100, def_val: Union[int, str] = 'Z', **kwargs): self.bus = bus - for signal in bus._signals: + self.clk = clock + self.rst = reset + self.def_val = def_val + self.log = logging.getLogger(f"cocotb.{bus._name}.{bus._entity._name}") + self._init_bus() + self.log.info("AHB lite master") + self.log.info("cocotbext-ahb version %s", __version__) + self.log.info("Copyright (c) 2023 Anderson Ignacio da Silva") + self.log.info("https://github.com/aignacio/cocotbext-ahb") + + def _init_bus(self) -> None: + """Initialize the bus with default value.""" + for signal in self.bus._signals: if signal not in ["hready", "hresp", "hrdata"]: + sig = getattr(self.bus, signal) try: - default_value = 0 - getattr(self.bus, signal).setimmediatevalue(default_value) + default_value = self._get_def(len(sig), self.def_val) + sig.setimmediatevalue(default_value) except AttributeError: pass - - def _convert_size(self, value): + + def _get_def(self, width: int = 1, + val: Union[int, str] = 'Z') -> BinaryValue: + """Return a handle obj with the default value""" + return LogicArray([val for _ in range(width)]) + + def _convert_size(self, value) -> AHBTrans: + """Convert byte size into hsize.""" for hsize in AHBSize: if (2**hsize.value) == value: return hsize - raise ValueError(f"No hsize value found for {input_int} number of bytes") + raise ValueError(f"No hsize value found for {value} number of bytes") @staticmethod def _check_size(size: int, data_bus_width: int) -> None: @@ -44,25 +67,28 @@ def _check_size(size: int, data_bus_width: int) -> None: raise ValueError("Size must be a positive power of 2") @cocotb.coroutine - async def write(self, address: int, value: Union[int, Sequence[int]], + async def write(self, address: int, value: Union[int, Sequence[int]], size: Optional[int] = None) -> None: + """Write data in the AHB bus.""" if size is None: - size = len(self.bus.hwdata) // 8 + size = self.bus._data_width//8 else: AHBLiteMaster._check_size(size, len(self.bus.hwdata) // 8) - - await RisingEdge(self.clock) - + + await RisingEdge(self.clk) + # Address phase - self.bus.haddr.value = address + self.bus.haddr.value = address self.bus.htrans.value = AHBTrans(0b10) - self.bus.hsize.value = self._convert_size(size) - self.bus.hwrite.value = AHBWrite(0b1) - await RisingEdge(self.clock) - + self.bus.hsize.value = self._convert_size(size) + self.bus.hwrite.value = AHBWrite(0b1) + await RisingEdge(self.clk) + # Address phase + self._init_bus() # while self.bus.hready.value == 0: - # await RisingEdge(self.clock) + # await RisingEdge(self.clock) # Data phase self.bus.hwdata.value = value - await RisingEdge(self.clock) + await RisingEdge(self.clk) + self._init_bus() diff --git a/cocotbext/ahb/ahb_types.py b/cocotbext/ahb/ahb_types.py index ca0a19a..6c05040 100644 --- a/cocotbext/ahb/ahb_types.py +++ b/cocotbext/ahb/ahb_types.py @@ -2,39 +2,45 @@ # -*- coding: utf-8 -*- # File : ahb_types.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 07.10.2023 -# Last Modified Date: 07.10.2023 +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + import enum + class AHBSize(enum.IntEnum): - BYTE = 0b000 - HWORD = 0b001 - WORD = 0b010 - DWORD = 0b011 - FWORD = 0b100 - EWORD = 0b101 + BYTE = 0b000 + HWORD = 0b001 + WORD = 0b010 + DWORD = 0b011 + FWORD = 0b100 + EWORD = 0b101 + class AHBBurst(enum.IntEnum): - SINGLE = 0b000 - INCR = 0b001 - WRAP4 = 0b010 - INCR4 = 0b011 - WRAP8 = 0b100 - INCR8 = 0b101 - WRAP16 = 0b110 - INCR16 = 0b111 + SINGLE = 0b000 + INCR = 0b001 + WRAP4 = 0b010 + INCR4 = 0b011 + WRAP8 = 0b100 + INCR8 = 0b101 + WRAP16 = 0b110 + INCR16 = 0b111 + class AHBResp(enum.IntEnum): - OKAY = 0b0 - ERROR = 0b1 + OKAY = 0b0 + ERROR = 0b1 + class AHBTrans(enum.IntEnum): - IDLE = 0b00 - BUSY = 0b01 - NONSEQ = 0b10 - SEQ = 0b11 + IDLE = 0b00 + BUSY = 0b01 + NONSEQ = 0b10 + SEQ = 0b11 + class AHBWrite(enum.IntEnum): - WRITE = 0b0 - READ = 0b1 + WRITE = 0b0 + READ = 0b1 diff --git a/noxfile.py b/noxfile.py index 19782f4..2f6d8a9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -2,11 +2,13 @@ # -*- coding: utf-8 -*- # File : noxfile.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 30.09.2023 -# Last Modified Date: 05.10.2023 +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + import nox + @nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10"]) def run(session): session.env['DUT'] = 'ahb_template' @@ -22,3 +24,9 @@ def run(session): 'cocotb >= 1.8.0') session.install("-e", ".") session.run('pytest', '-rP', '-n', 'auto') + + +@nox.session(python=["3.9", "3.10"]) +def lint(session): + session.install('flake8') + session.run('flake8') diff --git a/tests/const.py b/tests/const.py index e2a0cb6..7a4cd58 100644 --- a/tests/const.py +++ b/tests/const.py @@ -2,34 +2,34 @@ # -*- coding: utf-8 -*- # File : const.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 12.07.2023 -# Last Modified Date: 05.10.2023 +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + import os import glob -import copy -import math + class cfg: - RST_CYCLES = 3 - CLK_100MHz = (10, "ns") + RST_CYCLES = 3 + CLK_100MHz = (10, "ns") TIMEOUT_TEST = (CLK_100MHz[0]*200, "ns") TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) - RTL_DIR = os.path.join(TESTS_DIR,"dut") - TOPLEVEL = str(os.getenv("DUT")) + RTL_DIR = os.path.join(TESTS_DIR, "dut") + TOPLEVEL = str(os.getenv("DUT")) SIMULATOR = str(os.getenv("SIM")) - VERILOG_SOURCES = [] # The sequence below matters... - VERILOG_SOURCES += glob.glob(f'{RTL_DIR}**/*.v',recursive=True) + VERILOG_SOURCES = [] # The sequence below matters... + VERILOG_SOURCES += glob.glob(f'{RTL_DIR}**/*.v', recursive=True) EXTRA_ENV = {} EXTRA_ENV['COCOTB_HDL_TIMEPRECISION'] = os.getenv("TIMEPREC") EXTRA_ENV['COCOTB_HDL_TIMEUNIT'] = os.getenv("TIMEUNIT") - TIMESCALE=os.getenv("TIMEUNIT")+'/'+os.getenv("TIMEPREC") + TIMESCALE = os.getenv("TIMEUNIT") + '/' + os.getenv("TIMEPREC") if SIMULATOR == "verilator": - EXTRA_ARGS = ["--trace-fst","--coverage","--coverage-line", - "--coverage-toggle","--trace-structs", - "--Wno-UNOPTFLAT","--Wno-REDEFMACRO"] + EXTRA_ARGS = ["--trace-fst", "--coverage", "--coverage-line", + "--coverage-toggle", "--trace-structs", + "--Wno-UNOPTFLAT", "--Wno-REDEFMACRO"] elif SIMULATOR == "icarus": EXTRA_ARGS = ["WAVES=1"] diff --git a/tests/test_ahb_lite.py b/tests/test_ahb_lite.py index d99e840..87bb2af 100644 --- a/tests/test_ahb_lite.py +++ b/tests/test_ahb_lite.py @@ -2,40 +2,39 @@ # -*- coding: utf-8 -*- # File : test_ahb_lite.py # License : MIT license -# Author : Anderson Ignacio da Silva (aignacio) -# Date : 30.09.2023 -# Last Modified Date: 07.10.2023 -import random +# Author : Anderson I. da Silva (aignacio) +# Date : 08.10.2023 +# Last Modified Date: 08.10.2023 + import cocotb import os -import logging -import pytest -import itertools -import sys -from random import randrange from const import cfg from cocotb_test.simulator import run from cocotb.triggers import ClockCycles -from cocotb.regression import TestFactory from cocotb.clock import Clock from cocotbext.ahb import AHBBus, AHBLiteMaster + @cocotb.coroutine async def setup_dut(dut, cycles): cocotb.start_soon(Clock(dut.hclk, *cfg.CLK_100MHz).start()) dut.hresetn.value = 0 - await ClockCycles(dut.hclk, cycles) + await ClockCycles(dut.hclk, cycles) dut.hresetn.value = 1 + @cocotb.test() async def run_test(dut): - # ahbMaster = AHBBus(dut, "slave") - # ahbMaster1 = AHBBus.from_entity(dut) - ahb_lite_master = AHBLiteMaster(AHBBus.from_prefix(dut, "slave"), dut.hclk, dut.hresetn) - await setup_dut(dut, cfg.RST_CYCLES) - # await ahbMaster.write(0x123,0xdeadbeef) - # await ahbMaster.write(0x456,0xbabebabe) + ahb_lite_master = AHBLiteMaster(AHBBus.from_prefix(dut, "slave"), + dut.hclk, + dut.hresetn, + def_val='X') + await setup_dut(dut, cfg.RST_CYCLES) + await ahb_lite_master.write(0x123, 0xdeadbeef) + await ClockCycles(dut.hclk, 10) + # await ahbMaster.write(0x456,0xbabebabe) + def test_ahb_lite(): """ @@ -44,7 +43,8 @@ def test_ahb_lite(): Test ID: 1 """ module = os.path.splitext(os.path.basename(__file__))[0] - SIM_BUILD = os.path.join(cfg.TESTS_DIR, f"../run_dir/sim_build_{cfg.SIMULATOR}_{module}") + SIM_BUILD = os.path.join(cfg.TESTS_DIR, + f"../run_dir/sim_build_{cfg.SIMULATOR}_{module}") extra_args_sim = cfg.EXTRA_ARGS run(