├── .gitignore ├── Makefile ├── README.md ├── README.ru.md ├── apb_iso_all_random_reset_test.py ├── apb_iso_base_test.py ├── apb_iso_client.py ├── apb_iso_cov_collector.py ├── apb_iso_env.py ├── apb_iso_env_cfg.py ├── apb_iso_pkg.py ├── apb_iso_pyuvm_utils.py ├── apb_iso_scoreboard.py ├── apb_iso_server_test.py ├── apb_master_agent.py ├── apb_master_agent_cfg.py ├── apb_master_driver.py ├── apb_master_driver_item.py ├── apb_master_random_sequence.py ├── apb_memory_random_responce_sequence.py ├── apb_monitor.py ├── apb_monitor_item.py ├── apb_slave_agent.py ├── apb_slave_agent_cfg.py ├── apb_slave_driver.py ├── apb_slave_driver_item.py ├── apb_slave_sequencer.py ├── lpi_master_agent.py ├── lpi_master_agent_cfg.py ├── lpi_master_driver.py ├── lpi_master_sequence_param.py ├── lpi_monitor.py ├── lpi_q_item.py ├── requirements.txt ├── reset_agent.py ├── reset_agent_cfg.py ├── reset_driver.py ├── reset_driver_item.py ├── reset_monitor.py ├── reset_monitor_item.py ├── reset_sequence_param.py └── rtl ├── apb_isolator_top.sv └── apb_isolator_top_wrapper.sv /.gitignore: -------------------------------------------------------------------------------- 1 | sim_build 2 | venv 3 | __pycache__ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CWD=$(shell pwd) 2 | SIM ?= icarus #Verilator don't supported 3 | TEST_NAME ?= apb_iso_all_random_reset_test 4 | VERILOG_SOURCES =$(CWD)/rtl/apb_isolator_top_wrapper.sv \ 5 | $(CWD)/rtl/apb_isolator_top.sv 6 | MODULE := $(TEST_NAME) 7 | TOPLEVEL = apb_isolator_top_wrapper 8 | PLUSARGS ?=+APB_ISO_ADDR_WIDTH=32 +APB_ISO_DATA_WIDTH=32 +num_pkts=5 +has_cov=0 +loglvl=DEBUG +pydebug=0 9 | WAVES ?= 1 10 | COCOTB_HDL_TIMEUNIT = 1ns 11 | COCOTB_HDL_TIMEPRECISION = 1ps 12 | include $(shell cocotb-config --makefiles)/Makefile.sim 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Translations 2 | - [Russian](README.ru.md) 3 | - [English](README.md) 4 | 5 | # Example of using PyUVM for digital design verification 6 | 7 | 8 | The tested digital RTL design is an isolator (LPI q-channel based) for the AMBA APB3 protocol bus (rtl/apb_isolator_top.sv). 9 | 10 | **The composition of the PyUVM verification environment:** 11 | 12 | -apb_iso_base_test - basic test 13 | -apb_iso_env_cfg - environment configuration 14 | -apb_iso_env - environment 15 | -dut_reset_agent - agent for the DUT process 16 | -uvm_sequencer 17 | -reset_driver 18 | -reset_monitor 19 | -slv_reset_agent - agent for resetting the slave APB3 20 | -uvm_sequencer 21 | -reset_driver 22 | -reset_monitor 23 | -mst_reset_agent - agent for resetting master APB3 24 | -uvm_sequencer 25 | -reset_driver 26 | -reset_monitor 27 | -lpi_master_agent - LPI_Q channel interface management agent 28 | -uvm_sequencer 29 | -lpi_master_driver 30 | -lpi_monitor 31 | -apb_master_agent - APB3 Master bus management agent 32 | -uvm_sequencer 33 | -apb_master_driver 34 | -apb_monitor 35 | -apb_slave_agent - APB3 slave bus management agent 36 | -apb_slave_sequencer - non-standard sequencer, memory support is implemented 37 | -apb_slave_driver 38 | -uvm_tlm_fifo 39 | -apb_monitor 40 | -apb_iso_scoreboard - golden model 41 | -apb_iso_cov_collector - functional coverage collector (using cocotb-coverage) 42 | 43 | **Verification environment scheme on PyUVM:** 44 | ![image](https://github.com/hurisson/pyuvm_primer/assets/61613953/28a63384-993e-4527-86e8-48837aa27078) 45 | 46 | Each agent of the verification environment is assigned its own signals in the RTL wrapper (rtl/apb_isolator_top_wrapper.sv). This allows you to instantiate many identical agents in an environment. The names of the signals comparable to them are indexed by the serial number of the agent creation. 47 | 48 | 49 | **Used frameworks in the environment:** 50 | 51 | | Framework | Link | 52 | | ------------- | ------------- | 53 | | cocotb | https://github.com/cocotb/cocotb | 54 | | PyUVM | https://github.com/pyuvm/pyuvm | 55 | | pyvsc (constraint, randomize) | https://github.com/fvutils/pyvsc | 56 | | cocotb_coverage (functional coverage) | https://cocotb-coverage.readthedocs.io/en/latest/ | 57 | | debugpy (Python debugger in vscode) |https://github.com/microsoft/debugpy | 58 | 59 | Setup this frameworks using python venv: 60 | 61 | ```bash 62 | [user@pc /../pyuvm_primer]$ python -m venv venv 63 | [user@pc /../pyuvm_primer]$ source ./venv/bin/activate 64 | [user@pc /../pyuvm_primer]$ pip install -r ./requirements.txt 65 | ``` 66 | 67 | **Documentation of the standarts:** 68 | | Standart | Link | 69 | | ------------- | ------------- | 70 | | APB3 | https://web.eecs.umich.edu/~prabal/teaching/eecs373-f12/readings/ARM_AMBA3_APB.pdf | 71 | | LPI q-channel | https://developer.arm.com/documentation/ihi0068/latest/| 72 | 73 | 74 | **Start testing:** 75 | 76 | ```bash 77 | [user@pc /../pyuvm_primer]$ make 78 | ``` 79 | 80 | Available Makefile Options: 81 | 82 | | Option | Description | 83 | | ------------- | ------------- | 84 | | SIM | Default - icarus. Support Synopsys, Cadence. With Verilator don't work in this env, because X-state checking. | 85 | | TEST_NAME | Default - apb_iso_all_random_reset_test. Available variant - apb_iso_server_test | 86 | | PLUSARGS | +APB_ISO_ADDR_WIDTH=32 (APB address width) +APB_ISO_DATA_WIDTH=32 (APB data width) +num_pkts=1000 (iterations in apb_iso_all_random_reset_test) +has_cov=0 (coverage enable) +loglvl=DEBUG(log level) +pydebug=0 (python debug enable ) | 87 | | WAVES | Default - 1. Support dump timing diagrams in vcd format | 88 | | COCOTB_HDL_TIMEUNIT | Default 1ns| 89 | | COCOTB_HDL_TIMEPRECISION | Default 1ps| 90 | 91 | 92 | **Using client-server testing:** 93 | 94 | ![image](https://github.com/hurisson/pyuvm_primer/assets/61613953/fe3a494f-29d3-42c8-8697-d0e3ef2f2732) 95 | 96 | In the test apb_iso_server_test.py the server is instantiated in run_phase. The server is waiting for the client to connect (apb_uart_client.py ) and commands from him. Simple commands such as starting a coroutine reset, random transaction on the master bus, and completing the simulation are implemented. 97 | 98 | 99 | ![2024-05-2413-32-26-ezgif com-video-to-gif-converter](https://github.com/hurisson/pyuvm_primer/assets/61613953/2ac04e2b-83e9-463f-8928-9b20b272e524) 100 | -------------------------------------------------------------------------------- /README.ru.md: -------------------------------------------------------------------------------- 1 | # Переводы 2 | - [Русский](README.ru.md) 3 | - [Английский](README.md) 4 | 5 | # Пример использования PyUVM для верификации цифрового дизайна: 6 | Тестируемый цифровой дизайн RTL - изолятор (на основе LPI q-channel) для шины протокола семейства AMBA APB3 (rtl/apb_isolator_top.sv). 7 | 8 | **Состав верификационного окружения PyUVM:** 9 | 10 | -apb_iso_base_test - базовый тест 11 | -apb_iso_env_cfg - конфигурация окружения 12 | -apb_iso_env - окружение 13 | -dut_reset_agent - агент для сроса DUT 14 | -uvm_sequencer 15 | -reset_driver 16 | -reset_monitor 17 | -slv_reset_agent - агент для сброса slave APB3 18 | -uvm_sequencer 19 | -reset_driver 20 | -reset_monitor 21 | -mst_reset_agent - агент для сброса master APB3 22 | -uvm_sequencer 23 | -reset_driver 24 | -reset_monitor 25 | -lpi_master_agent - агент управления интерфейсом LPI q-channel 26 | -uvm_sequencer 27 | -lpi_master_driver 28 | -lpi_monitor 29 | -apb_master_agent - агент управления шиной мастера APB3 30 | -uvm_sequencer 31 | -apb_master_driver 32 | -apb_monitor 33 | -apb_slave_agent - агент управления шиной слейва APB3 34 | -apb_slave_sequencer - нестандартный секвенсор, реализована поддержка памяти 35 | -apb_slave_driver 36 | -uvm_tlm_fifo 37 | -apb_monitor 38 | -apb_iso_scoreboard - модуль сравнения транзакций (golden model) 39 | -apb_iso_cov_collector - сборщик функционального покрытия (используя cocotb-coverage) 40 | **Схема верификационного окружения PyUVM:** 41 | ![image](https://github.com/hurisson/pyuvm_primer/assets/61613953/28a63384-993e-4527-86e8-48837aa27078) 42 | 43 | Для каждого агента верификационного окружения назначаются свои сигналы во враппере RTL (rtl/apb_isolator_top_wrapper.sv). Это позволяет инстацировать множество одинаковых агентов в окружении. Названия сопоставимых им сигналов индексируются по порядковму номеру создания агента. 44 | 45 | **Используемые фреймворки в окружении:** 46 | 47 | 48 | | Фреймворк | Ссылка | 49 | | ------------- | ------------- | 50 | | cocotb | https://github.com/cocotb/cocotb | 51 | | PyUVM | https://github.com/pyuvm/pyuvm | 52 | | pyvsc (constraint, randomize) | https://github.com/fvutils/pyvsc | 53 | | cocotb_coverage (функциональное покрытие, рандомизация) | https://cocotb-coverage.readthedocs.io/en/latest/ | 54 | | debugpy (Отладчик Python в среде vscode) |https://github.com/microsoft/debugpy | 55 | 56 | Установите данные фреймворки используя python venv: 57 | 58 | ```bash 59 | [user@pc /../pyuvm_primer]$ python -m venv venv 60 | [user@pc /../pyuvm_primer]$ source ./venv/bin/activate 61 | [user@pc /../pyuvm_primer]$ pip install -r ./requirements.txt 62 | ``` 63 | 64 | **Документация на протоколы:** 65 | 66 | | Протокол | Ссылка | 67 | | ------------- | ------------- | 68 | | APB3 | https://web.eecs.umich.edu/~prabal/teaching/eecs373-f12/readings/ARM_AMBA3_APB.pdf | 69 | | LPI q-channel | https://developer.arm.com/documentation/ihi0068/latest/| 70 | 71 | 72 | 73 | 74 | 75 | **Запуск тестирования:** 76 | 77 | 78 | 79 | ```bash 80 | [user@pc /../pyuvm_primer]$ make 81 | ``` 82 | 83 | 84 | Доступные опции Makefile: 85 | 86 | | Опция | Описание | 87 | | ------------- | ------------- | 88 | | SIM | По умолчанию - icarus. Поддержка Synopsys, Cadence. С Verilator не работает - по причине проверки X состояний. | 89 | | TEST_NAME | По умолчанию - apb_iso_all_random_reset_test. Доступный вариант - apb_iso_server_test | 90 | | PLUSARGS | +APB_ISO_ADDR_WIDTH=32 (ширина шинны адреса APB) +APB_ISO_DATA_WIDTH=32 (ширина шины данных APB) +num_pkts=1000 (кол-во итераций в тесте apb_iso_all_random_reset_test) +has_cov=0 (опция включения покрытия) +loglvl=DEBUG(уровень логирования) +pydebug=0 (включение опции отладки) | 91 | | WAVES | По умолчанию - 1. Поддержка дампа временных диаграмм | 92 | | COCOTB_HDL_TIMEUNIT | По умолчанию 1ns| 93 | | COCOTB_HDL_TIMEPRECISION | По умолчанию 1ps| 94 | 95 | 96 | **Использование клиент-серверного тестирования:** 97 | ![image](https://github.com/hurisson/pyuvm_primer/assets/61613953/fe3a494f-29d3-42c8-8697-d0e3ef2f2732) 98 | 99 | 100 | 101 | В тесте apb_iso_server_test.py инстанцируется сервер в run_phase. Сервер ожидает подключение клиента (apb_uart_client.py) и команд от него. Реализованы простые команды типа запуска корутин сброса, рандомной транзации по master-шине, а также завершения симуляции. 102 | 103 | ![2024-05-2413-32-26-ezgif com-video-to-gif-converter](https://github.com/hurisson/pyuvm_primer/assets/61613953/2ac04e2b-83e9-463f-8928-9b20b272e524) 104 | 105 | 106 | -------------------------------------------------------------------------------- /apb_iso_all_random_reset_test.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | 4 | @test() 5 | class apb_iso_all_random_reset_test(apb_iso_base_test): 6 | 7 | async def all_reset(self): 8 | rst_task_dut = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.dut_reset_agent.reset_seqr)) 9 | rst_task_mst = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.mst_reset_agent.reset_seqr)) 10 | rst_task_slv = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.slv_reset_agent.reset_seqr)) 11 | await cocotb.triggers.Combine(rst_task_dut, rst_task_mst, rst_task_slv) 12 | 13 | async def reset_action(self): 14 | while True: 15 | await self.reset_seq.start(self.env.mst_reset_agent.reset_seqr) 16 | 17 | async def apb_mst_trn_task(self, min_delay_trn, max_delay_trn): 18 | while True: 19 | wdt_delay = random.randint(min_delay_trn, max_delay_trn) 20 | await cocotb.triggers.Timer(wdt_delay, "ns") 21 | await cocotb.start_soon(apb_master_random_sequence("apb_master_stimulus").start(self.env.apb_master_agent.apb_master_seqr)) 22 | 23 | async def lpi_trn_task_after_reset(self): 24 | await cocotb.triggers.Combine(cocotb.triggers.RisingEdge(cocotb.top.rst_vip_m0_reset), cocotb.triggers.RisingEdge(cocotb.top.rst_vip_m1_reset)) 25 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.NO_REQUEST, pre_delay_clk = 0, post_delay_clk = 20).start(self.env.lpi_master_agent.sequencer)) 26 | 27 | async def rst_apb_slv_mst_in_iso_state_task(self, min_delay_trn, max_delay_trn): 28 | wdt_delay = random.randint(min_delay_trn, max_delay_trn) 29 | await cocotb.triggers.Timer(wdt_delay, "ns") 30 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.REQUEST, pre_delay_clk = 0, post_delay_clk = 0).start(self.env.lpi_master_agent.sequencer)) 31 | while (cocotb.top.lpi_vip_m0_qacceptn.value == 1): 32 | await cocotb.triggers.FallingEdge(cocotb.top.lpi_vip_m0_qacceptn) 33 | await cocotb.start_soon(reset_sequence_param("rst_param_stim_slv", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 50, clk_cycles_after = 20).start(self.env.slv_reset_agent.reset_seqr)) 34 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.NO_REQUEST, pre_delay_clk = 0, post_delay_clk = 40).start(self.env.lpi_master_agent.sequencer)) 35 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.REQUEST, pre_delay_clk = 0, post_delay_clk = 0).start(self.env.lpi_master_agent.sequencer)) 36 | while (cocotb.top.lpi_vip_m0_qacceptn.value == 1): 37 | await cocotb.triggers.FallingEdge(cocotb.top.lpi_vip_m0_qacceptn) 38 | await cocotb.start_soon(reset_sequence_param("rst_param_stim_mst", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 40, clk_cycles_after = 30).start(self.env.mst_reset_agent.reset_seqr)) 39 | 40 | async def run_phase(self): 41 | # Break into debugger for user control 42 | # breakpoint() # or debugpy.breakpoint() on 3.6 and below 43 | try: 44 | is_debug = int(cocotb.plusargs["pydebug"]) 45 | except KeyError: 46 | is_debug = 0 47 | 48 | if (is_debug): 49 | listen_host, listen_port = debugpy.listen(("localhost", 5679)) 50 | debugpy.wait_for_client() 51 | 52 | self.raise_objection() 53 | cocotb.start_soon(self.apb_slave_responce()) 54 | self.start_clock("cocotb_clock") 55 | 56 | max_duration_rst = 30 57 | min_duration_rst = 20 58 | min_delay_trn = 0 59 | max_delay_trn = 2000 60 | 61 | try: 62 | num_pkts = int(cocotb.plusargs["num_pkts"]) 63 | except KeyError: 64 | num_pkts = 1 65 | 66 | for i in range(num_pkts): 67 | self.logger.info("System cold-reset init") 68 | await cocotb.start_soon(self.all_reset()) 69 | self.logger.info("System hot-reset init") 70 | duration_reset_slv = random.randint(min_duration_rst, max_duration_rst) 71 | duration_reset_mst = random.randint(min_duration_rst, max_duration_rst) 72 | duration_reset_dut = random.randint(min_duration_rst, max_duration_rst) 73 | rst_task_dut = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = duration_reset_dut, clk_cycles_after = 0).start(self.env.dut_reset_agent.reset_seqr)) 74 | rst_task_mst = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = duration_reset_mst, clk_cycles_after = 0).start(self.env.mst_reset_agent.reset_seqr)) 75 | rst_task_slv = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = duration_reset_slv, clk_cycles_after = 0).start(self.env.slv_reset_agent.reset_seqr)) 76 | await cocotb.triggers.First(rst_task_dut, rst_task_mst, rst_task_slv) 77 | await cocotb.triggers.First(cocotb.start_soon(self.apb_mst_trn_task(min_delay_trn, max_delay_trn)), cocotb.start_soon(self.lpi_trn_task_after_reset())) 78 | await cocotb.triggers.Timer(max_delay_trn, "ns") 79 | #Separate reset for Slave and Master 80 | await cocotb.start_soon(self.all_reset()) 81 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.NO_REQUEST, pre_delay_clk = 0, post_delay_clk = 20).start(self.env.lpi_master_agent.sequencer)) 82 | await cocotb.triggers.First(cocotb.start_soon(self.apb_mst_trn_task(min_delay_trn, max_delay_trn / 4)), cocotb.start_soon(self.rst_apb_slv_mst_in_iso_state_task(min_delay_trn + 1, max_delay_trn * 2))) 83 | await cocotb.triggers.Timer(max_delay_trn, "ns") 84 | await cocotb.triggers.ClockCycles(cocotb.top.cocotb_clock, 10) 85 | self.drop_objection() 86 | 87 | def final_phase(self): 88 | uvm_factory().print(1) 89 | -------------------------------------------------------------------------------- /apb_iso_base_test.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class apb_iso_base_test(uvm_test): 4 | """ 5 | Base test for the module 6 | """ 7 | 8 | def __init__(self, name, parent): 9 | super().__init__(name, parent) 10 | 11 | def build_phase(self): 12 | self.env = apb_iso_env("apb_iso_env", self) 13 | self.cfg = apb_iso_env_cfg("apb_iso_env_cfg") 14 | self.apb_memory_random_responce_sequence = apb_memory_random_responce_sequence.create("slave_stimulus") 15 | self.cfg.build() 16 | ConfigDB().set(self, "apb_iso_env", "apb_iso_env_cfg", self.cfg) 17 | 18 | def start_clock(self, name): 19 | sig = getattr(cocotb.top, name) 20 | clock = cocotb.clock.Clock(sig, 42, units="ns") 21 | cocotb.start_soon(clock.start(start_high=False)) 22 | 23 | async def apb_slave_responce(self): 24 | while True: 25 | await self.apb_memory_random_responce_sequence.start(self.env.apb_slave_agent.apb_slave_sequencer) 26 | 27 | def end_of_elaboration_phase(self): 28 | try: 29 | self.set_logging_level_hier(cocotb.plusargs["loglvl"]) 30 | except KeyError: 31 | self.set_logging_level_hier(INFO) 32 | 33 | async def run_phase(self): 34 | self.raise_objection() 35 | cocotb.start_soon(self.apb_slave_responce()) 36 | self.start_clock("cocotb_clock") 37 | await cocotb.triggers.ClockCycles(cocotb.top.cocotb_clock, 2) 38 | await cocotb.triggers.ClockCycles(cocotb.top.cocotb_clock, 10) 39 | self.drop_objection() 40 | 41 | async def run(self): 42 | raise NotImplementedError() 43 | -------------------------------------------------------------------------------- /apb_iso_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 4 | client.connect(("127.0.0.1", 15259)) 5 | 6 | while True: 7 | data = client.recv(1024) 8 | print(data.decode("utf-8")) 9 | break 10 | 11 | while True: 12 | msg = input().encode("utf-8") 13 | client.send(msg) 14 | if msg == b'FINISH': 15 | break -------------------------------------------------------------------------------- /apb_iso_cov_collector.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | 4 | class apb_iso_cov_collector(uvm_component): 5 | 6 | class uvm_AnalysisImp(uvm_analysis_export): 7 | def __init__(self, name, parent, write_fn): 8 | super().__init__(name, parent) 9 | self.write_fn = write_fn 10 | 11 | def write(self, tt): 12 | self.write_fn(tt) 13 | 14 | def __init__(self, name, parent): 15 | super().__init__(name, parent) 16 | self.analysis_export_master = self.uvm_AnalysisImp("analysis_export_master", 17 | self, 18 | self.write_master_cov) 19 | 20 | self.analysis_export_slave = self.uvm_AnalysisImp("analysis_export_slave", 21 | self, 22 | self.write_slave_cov) 23 | 24 | self.analysis_export_lpi = self.uvm_AnalysisImp("analysis_export_lpi", 25 | self, 26 | self.write_lpi_cov) 27 | 28 | self.analysis_export_dut_rst = self.uvm_AnalysisImp("analysis_export_dut_rst", 29 | self, 30 | self.write_dut_rst_cov) 31 | 32 | self.analysis_export_master_rst = self.uvm_AnalysisImp("analysis_export_master_rst", 33 | self, 34 | self.write_master_rst_cov) 35 | 36 | self.analysis_export_slave_rst = self.uvm_AnalysisImp("analysis_export_slave_rst", 37 | self, 38 | self.write_slave_rst_cov) 39 | 40 | self.ready = CocotbEvent() 41 | 42 | 43 | def write_master_cov(self, master_item): 44 | self.sample_mst_trn(self.lpi_state, master_item.direction, master_item.pslverr_enable, 45 | int(master_item.pstrb), master_item.pprot0, master_item.pprot1, master_item.pprot2) 46 | 47 | def write_slave_cov(self, slave_item): 48 | self.sample_slv_trn(self.lpi_state, slave_item.direction, slave_item.pslverr_enable, 49 | int(slave_item.pstrb), slave_item.pprot0, slave_item.pprot1, slave_item.pprot2) 50 | 51 | def write_lpi_cov(self, lpi_item): 52 | self.lpi_state = lpi_item.get_lpi_state() 53 | 54 | def write_dut_rst_cov(self, dut_rst_item): 55 | self.sample_rst_dut(dut_rst_item.rst_st.name) 56 | if dut_rst_item.rst_st == rst_state.RST_ASSERT: 57 | self.get_dut_rst = 1 58 | self.ready.set() 59 | self.ready.clear() 60 | 61 | def write_master_rst_cov(self, master_rst_item): 62 | self.sample_rst_mst(master_rst_item.rst_st.name) 63 | if master_rst_item.rst_st == rst_state.RST_ASSERT: 64 | self.get_master_rst = 1 65 | self.ready.set() 66 | self.ready.clear() 67 | 68 | def write_slave_rst_cov(self, slave_rst_item): 69 | self.sample_rst_slv(slave_rst_item.rst_st.name) 70 | if slave_rst_item.rst_st == rst_state.RST_ASSERT: 71 | self.get_slave_rst = 1 72 | self.ready.set() 73 | self.ready.clear() 74 | 75 | async def run_phase(self): 76 | self.lpi_state = lpi_q_state_e.Q_STOPPED 77 | while True: 78 | await self.ready.wait() 79 | await cocotb.triggers.Timer(1.0, "ns") 80 | if (self.get_master_rst == 1 and self.get_slave_rst == 1 and self.get_dut_rst == 1): 81 | get_all_reset = 1 82 | self.general_rst_on_all_components_cg_sample(get_all_reset, self.lpi_state) 83 | self.get_master_rst = 0 84 | self.get_slave_rst = 0 85 | self.get_dut_rst = 0 86 | 87 | def final_phase(self): 88 | coverage_db.report_coverage(self.logger.info, bins=True) 89 | coverage_db.export_to_xml(filename="coverage.xml") 90 | coverage_db.export_to_yaml(filename="coverage.yml") 91 | 92 | @CoverPoint("apb_iso_top.apb_master.lpi_state.qstate_cp", 93 | xf = lambda x, y, z, a, b, c, d : x, 94 | bins = [lpi_q_state_e.Q_RUN.name, lpi_q_state_e.Q_REQUEST.name, lpi_q_state_e.Q_STOPPED.name, lpi_q_state_e.Q_EXIT.name]) 95 | @CoverPoint("apb_iso_top.apb_master.direction", 96 | xf = lambda x, y, z, a, b, c, d : y, 97 | bins = [0, 1], 98 | bins_labels = ["READ", "WRITE"]) 99 | @CoverPoint("apb_iso_top.apb_master.responce", 100 | xf = lambda x, y, z, a, b, c, d : z, 101 | bins = [0, 1], 102 | bins_labels = ["OKAY", "ERROR"]) 103 | @CoverPoint("apb_iso_top.apb_master.pstrb", 104 | xf = lambda x, y, z, a, b, c, d :a, 105 | bins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) 106 | @CoverPoint("apb_iso_top.apb_master.pprot0", 107 | xf = lambda x, y, z, a, b, c, d :b, 108 | bins = [apb_pprot0.NORMAL.name, apb_pprot0.PRIVILEGED.name]) 109 | @CoverPoint("apb_iso_top.apb_master.pprot1", 110 | xf = lambda x, y, z, a, b, c, d :c, 111 | bins = [apb_pprot1.SECURE.name, apb_pprot1.NON_SECURE.name]) 112 | @CoverPoint("apb_iso_top.apb_master.pprot2", 113 | xf = lambda x, y, z, a, b, c, d :d, 114 | bins = [apb_pprot2.DATA.name, apb_pprot2.INSTRUCTION.name]) 115 | @CoverCross("apb_iso_top.apb_master.qstate_cp_X_status_tr_cp", 116 | items = ["apb_iso_top.apb_master.lpi_state.qstate_cp", "apb_iso_top.apb_master.direction"]) 117 | def sample_mst_trn(self, x, y, z, a, b, c, d): 118 | pass 119 | 120 | @CoverPoint("apb_iso_top.apb_slave.lpi_state.qstate_cp", 121 | xf = lambda x, y, z, a, b, c, d : x, 122 | bins = [lpi_q_state_e.Q_RUN.name, lpi_q_state_e.Q_REQUEST.name, lpi_q_state_e.Q_STOPPED.name, lpi_q_state_e.Q_EXIT.name]) 123 | @CoverPoint("apb_iso_top.apb_slave.direction", 124 | xf = lambda x, y, z, a, b, c, d : y, 125 | bins = [0, 1], 126 | bins_labels = ["READ", "WRITE"]) 127 | @CoverPoint("apb_iso_top.apb_slave.responce", 128 | xf = lambda x, y, z, a, b, c, d : z, 129 | bins = [0, 1], 130 | bins_labels = ["OKAY", "ERROR"]) 131 | @CoverPoint("apb_iso_top.apb_slave.pstrb", 132 | xf = lambda x, y, z, a, b, c, d :a, 133 | bins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) 134 | @CoverPoint("apb_iso_top.apb_slave.pprot0", 135 | xf = lambda x, y, z, a, b, c, d :b, 136 | bins = [apb_pprot0.NORMAL.name, apb_pprot0.PRIVILEGED.name]) 137 | @CoverPoint("apb_iso_top.apb_slave.pprot1", 138 | xf = lambda x, y, z, a, b, c, d :c, 139 | bins = [apb_pprot1.SECURE.name, apb_pprot1.NON_SECURE.name]) 140 | @CoverPoint("apb_iso_top.apb_slave.pprot2", 141 | xf = lambda x, y, z, a, b, c, d :d, 142 | bins = [apb_pprot2.DATA.name, apb_pprot2.INSTRUCTION.name]) 143 | @CoverCross("apb_iso_top.apb_slave.qstate_cp_X_status_tr_cp", 144 | items = ["apb_iso_top.apb_slave.lpi_state.qstate_cp", "apb_iso_top.apb_master.direction"]) 145 | def sample_slv_trn(self, x, y, z, a, b, c, d): 146 | pass 147 | 148 | @CoverPoint("apb_iso_top.reset_dut", bins = [rst_state.RST_ASSERT.name, rst_state.RST_DEASSERT.name]) 149 | def sample_rst_dut(self, a): 150 | pass 151 | 152 | @CoverPoint("apb_iso_top.reset_mst", bins = [rst_state.RST_ASSERT.name, rst_state.RST_DEASSERT.name]) 153 | def sample_rst_mst(self, a): 154 | pass 155 | 156 | @CoverPoint("apb_iso_top.reset_slv", bins = [rst_state.RST_ASSERT.name, rst_state.RST_DEASSERT.name]) 157 | def sample_rst_slv(self, a): 158 | pass 159 | 160 | @CoverPoint("apb_iso_top.covercross.get_all_reset", 161 | xf = lambda x, y: x, 162 | bins = [1], 163 | bins_labels = ["ALL_RESET"] 164 | ) 165 | @CoverPoint("apb_iso_top.covercross.lpi_state", 166 | xf = lambda x, y: y, 167 | bins = [lpi_q_state_e.Q_RUN.name, lpi_q_state_e.Q_REQUEST.name, lpi_q_state_e.Q_STOPPED.name, lpi_q_state_e.Q_EXIT.name] 168 | ) 169 | 170 | @CoverCross( 171 | name = "apb_iso_top.covercross.get_all_reset_lpi_state", 172 | items = ["apb_iso_top.covercross.get_all_reset", "apb_iso_top.covercross.lpi_state"] 173 | ) 174 | def general_rst_on_all_components_cg_sample (self, get_all_reset, lpi_state): 175 | pass 176 | -------------------------------------------------------------------------------- /apb_iso_env.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_iso_env (uvm_env): 3 | """Instantiate components""" 4 | def build_phase(self): 5 | 6 | self.apb_iso_env_cfg = ConfigDB().get(self, "", "apb_iso_env_cfg") 7 | 8 | if (self.apb_iso_env_cfg.has_scoreboard): 9 | self.scoreboard = apb_iso_scoreboard.create("apb_iso_scoreboard", self) 10 | 11 | if (self.apb_iso_env_cfg.has_cov): 12 | self.cov_collector = apb_iso_cov_collector.create("apb_iso_cov_collector", self) 13 | 14 | if (self.apb_iso_env_cfg.has_dut_reset_master_agent): 15 | self.dut_reset_agent = reset_agent.create("dut_reset_agent", self) 16 | ConfigDB().set(self, "dut_reset_agent", "cfg", self.apb_iso_env_cfg.dut_reset_agent_cfg) 17 | 18 | if (self.apb_iso_env_cfg.has_slv_reset_master_agent): 19 | self.slv_reset_agent = reset_agent.create("slv_reset_agent", self) 20 | ConfigDB().set(self, "slv_reset_agent", "cfg", self.apb_iso_env_cfg.slv_reset_agent_cfg) 21 | 22 | if (self.apb_iso_env_cfg.has_mst_reset_master_agent): 23 | self.mst_reset_agent = reset_agent.create("mst_reset_agent", self) 24 | ConfigDB().set(self, "mst_reset_agent", "cfg", self.apb_iso_env_cfg.mst_reset_agent_cfg) 25 | 26 | if (self.apb_iso_env_cfg.has_lpi_master_agent): 27 | self.lpi_master_agent = lpi_master_agent.create("lpi_master_agent", self) 28 | ConfigDB().set(self, "lpi_master_agent", "cfg", self.apb_iso_env_cfg.lpi_master_agent_cfg) 29 | 30 | if (self.apb_iso_env_cfg.has_master_apb_agent): 31 | self.apb_master_agent = apb_master_agent.create("apb_master_agent", self) 32 | ConfigDB().set(self, "apb_master_agent", "cfg", self.apb_iso_env_cfg.apb_master_agent_cfg) 33 | 34 | if (self.apb_iso_env_cfg.has_slave_apb_agent): 35 | self.apb_slave_agent = apb_slave_agent.create("apb_slave_agent", self) 36 | ConfigDB().set(self, "apb_slave_agent", "cfg", self.apb_iso_env_cfg.apb_slave_agent_cfg) 37 | 38 | def connect_phase(self): 39 | if (self.apb_iso_env_cfg.has_scoreboard): 40 | 41 | if (self.apb_iso_env_cfg.has_dut_reset_master_agent): 42 | self.dut_reset_agent.monitor.ap.connect(self.scoreboard.dut_fifo_reset.analysis_export) 43 | 44 | if (self.apb_iso_env_cfg.has_slv_reset_master_agent): 45 | self.slv_reset_agent.monitor.ap.connect(self.scoreboard.slv_fifo_reset.analysis_export) 46 | 47 | if (self.apb_iso_env_cfg.has_mst_reset_master_agent): 48 | self.mst_reset_agent.monitor.ap.connect(self.scoreboard.mst_fifo_reset.analysis_export) 49 | 50 | if (self.apb_iso_env_cfg.has_lpi_master_agent): 51 | self.lpi_master_agent.monitor.ap.connect(self.scoreboard.lpi_fifo_trans.analysis_export) 52 | 53 | if (self.apb_iso_env_cfg.has_master_apb_agent): 54 | self.apb_master_agent.monitor.ap.connect(self.scoreboard.mst_fifo_trans.analysis_export) 55 | 56 | if (self.apb_iso_env_cfg.has_slave_apb_agent): 57 | self.apb_slave_agent.monitor.ap.connect(self.scoreboard.slv_fifo_trans.analysis_export) 58 | 59 | if (self.apb_iso_env_cfg.has_cov): 60 | if (self.apb_iso_env_cfg.has_dut_reset_master_agent): 61 | self.dut_reset_agent.monitor.ap.connect(self.cov_collector.analysis_export_dut_rst) 62 | 63 | if (self.apb_iso_env_cfg.has_slv_reset_master_agent): 64 | self.slv_reset_agent.monitor.ap.connect(self.cov_collector.analysis_export_slave_rst) 65 | 66 | if (self.apb_iso_env_cfg.has_mst_reset_master_agent): 67 | self.mst_reset_agent.monitor.ap.connect(self.cov_collector.analysis_export_master_rst) 68 | 69 | if (self.apb_iso_env_cfg.has_lpi_master_agent): 70 | self.lpi_master_agent.monitor.ap.connect(self.cov_collector.analysis_export_lpi) 71 | 72 | if (self.apb_iso_env_cfg.has_master_apb_agent): 73 | self.apb_master_agent.monitor.ap.connect(self.cov_collector.analysis_export_master) 74 | 75 | if (self.apb_iso_env_cfg.has_slave_apb_agent): 76 | self.apb_slave_agent.monitor.ap.connect(self.cov_collector.analysis_export_slave) 77 | -------------------------------------------------------------------------------- /apb_iso_env_cfg.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class apb_iso_env_cfg (uvm_object): 4 | def __init__(self, name): 5 | super().__init__(name) 6 | self.has_scoreboard = 1 7 | self.has_master_apb_agent = 1 8 | self.has_slave_apb_agent = 1 9 | self.has_lpi_master_agent = 1 10 | self.has_reset_master_agent = 1 11 | self.has_dut_reset_master_agent = 1 12 | self.has_slv_reset_master_agent = 1 13 | self.has_mst_reset_master_agent = 1 14 | self.is_active = 1 15 | try: 16 | self.has_cov = int(cocotb.plusargs["has_cov"]) 17 | except KeyError: 18 | self.has_cov = 0 19 | 20 | def build(self): 21 | if (self.has_dut_reset_master_agent): 22 | self.build_dut_reset_agent_cfg() 23 | 24 | if (self.has_slv_reset_master_agent): 25 | self.build_slv_reset_agent_cfg() 26 | 27 | if (self.has_mst_reset_master_agent): 28 | self.build_mst_reset_agent_cfg() 29 | 30 | if (self.has_lpi_master_agent): 31 | self.build_lpi_master_agent_cfg() 32 | 33 | if (self.has_master_apb_agent): 34 | self.build_master_apb_agent_cfg() 35 | 36 | if (self.has_slave_apb_agent): 37 | self.build_slave_apb_agent_cfg() 38 | 39 | def build_dut_reset_agent_cfg(self): 40 | self.dut_reset_agent_cfg = reset_agent_cfg("dut_reset_agent_cfg") 41 | self.dut_reset_agent_cfg.active_level = reset_level.LOW_LEVEL 42 | self.dut_reset_agent_cfg.is_active = self.is_active 43 | 44 | def build_slv_reset_agent_cfg(self): 45 | self.slv_reset_agent_cfg = reset_agent_cfg("slv_reset_agent_cfg") 46 | self.slv_reset_agent_cfg.active_level = reset_level.LOW_LEVEL 47 | self.slv_reset_agent_cfg.is_active = self.is_active 48 | 49 | def build_mst_reset_agent_cfg(self): 50 | self.mst_reset_agent_cfg = reset_agent_cfg("mst_reset_agent_cfg") 51 | self.mst_reset_agent_cfg.active_level = reset_level.LOW_LEVEL 52 | self.mst_reset_agent_cfg.is_active = self.is_active 53 | 54 | def build_lpi_master_agent_cfg(self): 55 | self.lpi_master_agent_cfg = lpi_master_agent_cfg("lpi_master_agent_cfg") 56 | self.lpi_master_agent_cfg.is_active = self.is_active 57 | self.lpi_master_agent_cfg.randomize() 58 | with self.lpi_master_agent_cfg.randomize_with() as it: 59 | it.qreqn_state_during_rst == 0 60 | 61 | def build_master_apb_agent_cfg(self): 62 | self.apb_master_agent_cfg = apb_master_agent_cfg("apb_master_agent_cfg") 63 | self.apb_master_agent_cfg.is_active = self.is_active 64 | self.apb_master_agent_cfg.fix_pready_timeout = 10 65 | 66 | def build_slave_apb_agent_cfg(self): 67 | self.apb_slave_agent_cfg = apb_slave_agent_cfg("apb_slave_agent_cfg") 68 | self.apb_slave_agent_cfg.is_active = self.is_active 69 | self.apb_slave_agent_cfg.randomize() 70 | -------------------------------------------------------------------------------- /apb_iso_pkg.py: -------------------------------------------------------------------------------- 1 | import debugpy 2 | import cocotb 3 | import cocotb.clock 4 | import cocotb.triggers 5 | import cocotb.binary 6 | import enum 7 | import logging 8 | import sys 9 | import random 10 | import os 11 | import socket 12 | import time 13 | import vsc 14 | from cocotb_coverage.coverage import * 15 | from pyuvm import * 16 | from apb_iso_pyuvm_utils import * 17 | from reset_agent_cfg import * 18 | from lpi_master_agent_cfg import * 19 | from apb_master_agent_cfg import * 20 | from apb_slave_agent_cfg import * 21 | from apb_iso_env_cfg import * 22 | from apb_master_agent_cfg import * 23 | from apb_master_driver_item import * 24 | from apb_master_driver import * 25 | from apb_monitor_item import * 26 | from apb_monitor import * 27 | from apb_master_agent import * 28 | from apb_slave_driver_item import * 29 | from apb_slave_sequencer import * 30 | from apb_slave_driver import * 31 | from apb_slave_agent import * 32 | from lpi_q_item import * 33 | from lpi_master_driver import * 34 | from lpi_monitor import * 35 | from lpi_master_agent import * 36 | from apb_memory_random_responce_sequence import * 37 | from pathlib import Path 38 | from apb_iso_cov_collector import * 39 | from apb_iso_scoreboard import * 40 | from reset_driver_item import * 41 | from reset_driver import * 42 | from reset_monitor_item import * 43 | from reset_monitor import * 44 | from reset_agent import * 45 | from apb_iso_env import * 46 | from lpi_master_sequence_param import * 47 | from apb_master_random_sequence import * 48 | from reset_sequence_param import * 49 | from apb_iso_base_test import * 50 | -------------------------------------------------------------------------------- /apb_iso_pyuvm_utils.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | @enum.unique 4 | class lpi_q_req_e(enum.IntEnum): 5 | REQUEST = 0 6 | NO_REQUEST = 1 7 | 8 | @enum.unique 9 | class lpi_q_resp_e(enum.IntEnum): 10 | IDLE = 0 11 | ACCEPT = 1 12 | DENY = 2 13 | 14 | @enum.unique 15 | class lpi_q_active_e(enum.IntEnum): 16 | NOT_ACTIVE = 0 17 | ACTIVE = 1 18 | 19 | @enum.unique 20 | class lpi_q_state_e(enum.IntEnum): 21 | Q_RUN = 0 22 | Q_REQUEST = 1 23 | Q_STOPPED = 2 24 | Q_EXIT = 3 25 | Q_DENIED = 4 26 | Q_CONTINUE = 5 27 | ILLEGAL = 6 28 | 29 | 30 | @enum.unique 31 | class reset_action(enum.IntEnum): 32 | """Legal ops for the reset driver item""" 33 | RST_PULSE = 1 34 | DEASSERT = 2 35 | 36 | @enum.unique 37 | class reset_level(enum.IntEnum): 38 | LOW_LEVEL = 0 39 | HIGH_LEVEL = 1 40 | 41 | @enum.unique 42 | class apb_direction(enum.IntEnum): 43 | READ = 0 44 | WRITE = 1 45 | 46 | @enum.unique 47 | class apb_pprot0(enum.IntEnum): 48 | NORMAL = 0 49 | PRIVILEGED = 1 50 | 51 | @enum.unique 52 | class apb_pprot1(enum.IntEnum): 53 | SECURE = 0 54 | NON_SECURE = 1 55 | 56 | @enum.unique 57 | class apb_state(enum.IntEnum): 58 | IDLE = 0 59 | SETUP = 1 60 | ACCESS = 2 61 | ABORTED = 3 62 | 63 | @enum.unique 64 | class apb_pprot2(enum.IntEnum): 65 | DATA = 0 66 | INSTRUCTION = 1 67 | 68 | @enum.unique 69 | class rst_state(enum.IntEnum): 70 | """Legal ops for the reset monitor item""" 71 | RST_ASSERT = 0 72 | RST_DEASSERT = 1 73 | -------------------------------------------------------------------------------- /apb_iso_scoreboard.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_iso_scoreboard (uvm_component): 3 | def __init__(self, name, parent): 4 | super().__init__(name, parent) 5 | self.passed = None 6 | self.apb_slv_trn = None 7 | 8 | def build_phase(self): 9 | self.dut_fifo_reset = uvm_tlm_analysis_fifo("dut_fifo_reset", self) 10 | self.slv_fifo_reset = uvm_tlm_analysis_fifo("slv_fifo_reset", self) 11 | self.mst_fifo_reset = uvm_tlm_analysis_fifo("mst_fifo_reset", self) 12 | self.mst_fifo_trans = uvm_tlm_analysis_fifo("mst_fifo_trans", self) 13 | self.slv_fifo_trans = uvm_tlm_analysis_fifo("slv_fifo_trans", self) 14 | self.lpi_fifo_trans = uvm_tlm_analysis_fifo("lpi_fifo_trans", self) 15 | 16 | async def get_lpi_trn(self): 17 | while True: 18 | self.lpi_trn = await self.lpi_fifo_trans.get() 19 | 20 | async def get_apb_slv_trn(self): 21 | while True: 22 | self.apb_slv_trn = await self.slv_fifo_trans.get() 23 | self.logger.debug(f"Get apb-slv trans{self.apb_slv_trn}") 24 | self.got_slv_trn_flag = 1 25 | 26 | async def get_rst_dut_trn(self): 27 | while True: 28 | self.rst_dut_trn = await self.dut_fifo_reset.get() 29 | 30 | async def get_rst_slv_trn(self): 31 | while True: 32 | self.rst_slv_trn = await self.slv_fifo_reset.get() 33 | 34 | async def check_trn(self, mst_trn, slv_trn): 35 | if (self.lpi_trn.state_resp == lpi_q_resp_e.IDLE): 36 | if (self.got_slv_trn_flag == 0 and self.rst_slv_trn.rst_st != rst_state.RST_ASSERT): 37 | self.logger.error(f"Slave transaction was skipped") 38 | raise RuntimeError(f"{self.get_full_name()} : Slave transaction was skipped") 39 | self.got_slv_trn_flag = 0 40 | if (slv_trn.curr_state != apb_state.ABORTED.name): 41 | if (mst_trn != slv_trn): 42 | self.logger.error(f"slave and master transactions are different") 43 | raise RuntimeError(f"{self.get_full_name()} : slave and master transactions are different") 44 | elif (self.lpi_trn.state_resp == lpi_q_resp_e.ACCEPT and mst_trn.curr_state != apb_state.ABORTED.name): 45 | if (self.got_slv_trn_flag == 1): 46 | self.logger.error(f"Extra slave transaction was received") 47 | raise RuntimeError(f"Extra slave transaction was received") 48 | if (mst_trn.pslverr_enable != 1): 49 | self.logger.error(f"The interface was not isolated") 50 | raise RuntimeError(f"The interface was not isolated") 51 | 52 | async def run_phase (self): 53 | self.got_slv_trn_flag = 0 54 | t1 = cocotb.start_soon(self.get_apb_slv_trn()) 55 | t2 = cocotb.start_soon(self.get_lpi_trn()) 56 | t3 = cocotb.start_soon(self.get_rst_dut_trn()) 57 | t4 = cocotb.start_soon(self.get_rst_slv_trn()) 58 | cocotb.triggers.Combine(t1, t2, t3, t4) 59 | while True: 60 | self.apb_mst_trn = await self.mst_fifo_trans.get() 61 | self.logger.debug(f"Get apb-mst trans{self.apb_mst_trn}") 62 | await cocotb.triggers.Timer(1.0, "ns") 63 | await self.check_trn(self.apb_mst_trn, self.apb_slv_trn) 64 | -------------------------------------------------------------------------------- /apb_iso_server_test.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | @test() 4 | class apb_iso_server_test(apb_iso_base_test): 5 | 6 | async def all_reset(self): 7 | rst_task_dut = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.dut_reset_agent.reset_seqr)) 8 | rst_task_mst = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.mst_reset_agent.reset_seqr)) 9 | rst_task_slv = cocotb.start_soon(reset_sequence_param("rst_param_stim", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 20, clk_cycles_after = 20).start(self.env.slv_reset_agent.reset_seqr)) 10 | await cocotb.triggers.Combine(rst_task_dut, rst_task_mst, rst_task_slv) 11 | 12 | async def reset_action(self): 13 | while True: 14 | await self.reset_seq.start(self.env.mst_reset_agent.reset_seqr) 15 | 16 | async def apb_mst_trn_task(self, min_delay_trn, max_delay_trn): 17 | while True: 18 | wdt_delay = random.randint(min_delay_trn, max_delay_trn) 19 | await cocotb.triggers.Timer(wdt_delay, "ns") 20 | await cocotb.start_soon(apb_master_random_sequence("apb_master_stimulus").start(self.env.apb_master_agent.apb_master_seqr)) 21 | 22 | async def lpi_trn_task_after_reset(self): 23 | while (cocotb.top.rst_vip_m0_reset.value == 0 or cocotb.top.rst_vip_m1_reset.value == 0): 24 | await cocotb.triggers.First(cocotb.triggers.Edge(cocotb.top.rst_vip_m0_reset), cocotb.triggers.Edge(cocotb.top.rst_vip_m1_reset)) 25 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.NO_REQUEST, pre_delay_clk = 0, post_delay_clk = 20).start(self.env.lpi_master_agent.sequencer)) 26 | 27 | async def rst_apb_slv_mst_in_iso_state_task(self, min_delay_trn, max_delay_trn): 28 | wdt_delay = random.randint(min_delay_trn, max_delay_trn) 29 | await cocotb.triggers.Timer(wdt_delay, "ns") 30 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.REQUEST, pre_delay_clk = 0, post_delay_clk = 0).start(self.env.lpi_master_agent.sequencer)) 31 | while (cocotb.top.lpi_vip_m0_qacceptn.value == 1): 32 | await cocotb.triggers.FallingEdge(cocotb.top.lpi_vip_m0_qacceptn) 33 | await cocotb.start_soon(reset_sequence_param("rst_param_stim_slv", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 50, clk_cycles_after = 20).start(self.env.slv_reset_agent.reset_seqr)) 34 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.NO_REQUEST, pre_delay_clk = 0, post_delay_clk = 40).start(self.env.lpi_master_agent.sequencer)) 35 | await cocotb.start_soon(lpi_master_sequence_param("lpi_param_stim", state_req = lpi_q_req_e.REQUEST, pre_delay_clk = 0, post_delay_clk = 0).start(self.env.lpi_master_agent.sequencer)) 36 | while (cocotb.top.lpi_vip_m0_qacceptn.value == 1): 37 | await cocotb.triggers.FallingEdge(cocotb.top.lpi_vip_m0_qacceptn) 38 | await cocotb.start_soon(reset_sequence_param("rst_param_stim_mst", item_type = reset_action.RST_PULSE, clk_cycles_before = 0, clk_cycles_duration = 40, clk_cycles_after = 30).start(self.env.mst_reset_agent.reset_seqr)) 39 | 40 | async def run_phase(self): 41 | self.raise_objection() 42 | cocotb.start_soon(self.apb_slave_responce()) 43 | self.start_clock("cocotb_clock") 44 | 45 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 46 | server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 47 | server.bind(("127.0.0.1", 15259)) 48 | server.listen(1) 49 | conn, _ = server.accept() 50 | conn.send("APB_ISO_SERVER IS CONNECTED".encode("utf-8")) 51 | conn.setblocking(False) 52 | while True: 53 | try: 54 | hdr = conn.recv(1024) 55 | except: 56 | await cocotb.triggers.RisingEdge(cocotb.top.cocotb_clock) 57 | continue 58 | if (hdr.decode("utf-8") == "RESET ALL"): 59 | await cocotb.start_soon(self.all_reset()) 60 | conn.send("System reset".encode("utf-8")) 61 | elif (hdr.decode("utf-8") == "APB TRANS"): 62 | await cocotb.start_soon(apb_master_random_sequence("apb_master_stimulus").start(self.env.apb_master_agent.apb_master_seqr)) 63 | conn.send("APB-tran complete".encode("utf-8")) 64 | elif (hdr.decode("utf-8") == "FINISH"): 65 | break 66 | hdr = "" 67 | await cocotb.triggers.RisingEdge(cocotb.top.cocotb_clock) 68 | 69 | self.drop_objection() 70 | -------------------------------------------------------------------------------- /apb_master_agent.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_master_agent(uvm_agent): 3 | num_id = 0 4 | def __init__(self, name, parent, *args, **kwargs): 5 | apb_master_agent.num_id += 1 6 | self.num_id = apb_master_agent.num_id 7 | super().__init__(name, parent) 8 | 9 | def build_phase(self): 10 | self.cfg = ConfigDB().get(self, "", "cfg") 11 | if (self.cfg.is_active): 12 | self.apb_master_seqr = uvm_sequencer("apb_master_seqr", self) 13 | self.driver = apb_master_driver("apb_master_driver", self, num_id = self.num_id) 14 | self.monitor = apb_monitor("apb_monitor", self, is_master = 1, num_id = self.num_id) 15 | self.monitor.set_cfg(self.cfg) 16 | 17 | def connect_phase(self): 18 | if (self.cfg.is_active): 19 | self.driver.seq_item_port.connect(self.apb_master_seqr.seq_item_export) 20 | -------------------------------------------------------------------------------- /apb_master_agent_cfg.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_master_agent_cfg(uvm_object): 3 | def __init__(self, name): 4 | super().__init__(name) 5 | self.is_active = 0 6 | self.has_cov = 0 7 | self.fix_pready_timeout = 10 8 | self.print_debug_info = 0 #ToDo 9 | -------------------------------------------------------------------------------- /apb_master_driver.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class apb_master_driver(uvm_driver): 4 | 5 | def __init__(self, *args, **kwargs): 6 | self.num_id = kwargs["num_id"] 7 | del kwargs["num_id"] 8 | super().__init__(*args, **kwargs) 9 | 10 | def connect_phase(self): 11 | pre_index = "apb" + "_vip_" + "m" + str(self.num_id - 1) + "_" 12 | self.paddr = getattr(cocotb.top, (pre_index + "paddr")) 13 | self.psel = getattr(cocotb.top, (pre_index + "psel")) 14 | self.pprot = getattr(cocotb.top, (pre_index + "pprot")) 15 | self.penable = getattr(cocotb.top, (pre_index + "penable")) 16 | self.pwrite = getattr(cocotb.top, (pre_index + "pwrite")) 17 | self.pwdata = getattr(cocotb.top, (pre_index + "pwdata")) 18 | self.pstrb = getattr(cocotb.top, (pre_index + "pstrb")) 19 | self.pready = getattr(cocotb.top, (pre_index + "pready")) 20 | self.prdata = getattr(cocotb.top, (pre_index + "prdata")) 21 | self.pslverr = getattr(cocotb.top, (pre_index + "pslverr")) 22 | self.pclk = getattr(cocotb.top, (pre_index + "pclk")) 23 | self.presetn = getattr(cocotb.top, (pre_index + "presetn")) 24 | 25 | def __sign_zero_init(self): 26 | self.penable.value = 0 27 | self.paddr.value = 0 28 | self.psel.value = 0 29 | self.pwrite.value = 0 30 | self.pwdata.value = 0 31 | self.pstrb.value = 0 32 | self.pprot.value = 0 33 | 34 | def __init_flag_to_zero(self): 35 | self.__flag_transaction_started = 0 36 | self.__flag_transaction_completed = 0 37 | 38 | async def __main_task(self): 39 | while True: 40 | item = await self.seq_item_port.get_next_item() 41 | self.__flag_transaction_completed = 0 42 | self.__flag_transaction_started = 1 43 | await cocotb.triggers.ClockCycles(self.pclk, 1 + item.num_idle_cycles) 44 | if item.direction == apb_direction.WRITE: 45 | self.pwrite.value = apb_direction.WRITE 46 | assert item.data is not None 47 | self.pwdata.value = item.data 48 | self.pstrb.value = item.pstrb 49 | elif item.direction == apb_direction.READ: 50 | self.pwrite.value = apb_direction.READ 51 | self.pwdata.value = 0 52 | self.pstrb.value = 0 53 | else: 54 | raise RuntimeError("Unknown direction-field in item '{}'", item.direction) 55 | assert item.addr is not None 56 | assert item.pprot2 is not None 57 | assert item.pprot1 is not None 58 | assert item.pprot0 is not None 59 | assert item.pstrb is not None 60 | self.paddr.value = item.addr 61 | self.pprot.value = int ((str(item.pprot2.value) + str(item.pprot1.value) + str(item.pprot0.value)),2) 62 | self.psel.value = 1 63 | await cocotb.triggers.ClockCycles(self.pclk, 1) 64 | self.penable.value = 1 65 | await cocotb.triggers.ClockCycles(self.pclk, 1) 66 | while self.pready.value == 0: 67 | await cocotb.triggers.ClockCycles(self.pclk, 1) 68 | self.seq_item_port.item_done() 69 | self.__flag_transaction_completed = 1 70 | self.__flag_transaction_started = 0 71 | self.__sign_zero_init() 72 | 73 | async def __rst_task(self): 74 | await cocotb.triggers.FallingEdge(self.presetn) 75 | self.rst_assert = 1 76 | self.__sign_zero_init() 77 | 78 | async def run_phase(self): 79 | if (cocotb.SIM_NAME != "Verilator"): #x = 0 Verilator features 80 | await cocotb.triggers.FallingEdge(self.presetn) 81 | self.__sign_zero_init() 82 | while True: 83 | await cocotb.triggers.RisingEdge(self.presetn) 84 | self.rst_assert = 0 85 | self.__flag_transaction_completed = 0 86 | self.__flag_transaction_started = 0 87 | main_task = cocotb.start_soon(self.__main_task()) 88 | await cocotb.triggers.First(main_task, cocotb.start_soon(self.__rst_task())) 89 | main_task.kill() 90 | if(self.__flag_transaction_completed == 0 and self.__flag_transaction_started == 1 ): 91 | self.seq_item_port.item_done() 92 | -------------------------------------------------------------------------------- /apb_master_driver_item.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | @vsc.randobj 3 | class apb_master_driver_item(uvm_sequence_item): 4 | 5 | def __init__(self): 6 | super().__init__("apb_master_driver_item") 7 | 8 | try: 9 | data_width = int(cocotb.plusargs["APB_ISO_ADDR_WIDTH"]) 10 | except: 11 | data_width = 32 12 | 13 | try: 14 | addr_width = int(cocotb.plusargs["APB_ISO_ADDR_WIDTH"]) 15 | except: 16 | addr_width = 32 17 | 18 | self.addr = vsc.rand_bit_t(addr_width) 19 | self.data = vsc.rand_bit_t(data_width) 20 | self.direction = vsc.rand_enum_t(apb_direction) 21 | self.pstrb = vsc.rand_bit_t(data_width // 8) 22 | self.pprot0 = vsc.rand_enum_t(apb_pprot0) 23 | self.pprot1 = vsc.rand_enum_t(apb_pprot1) 24 | self.pprot2 = vsc.rand_enum_t(apb_pprot2) 25 | self.num_idle_cycles = vsc.uint32_t() 26 | self.max_num_idle_cycles = 5 27 | 28 | @vsc.constraint 29 | def addr_alligned_constr(self): 30 | self.addr[1:0] == 0 31 | 32 | @vsc.constraint 33 | def pstrb_constr(self): 34 | with vsc.if_then(self.direction == apb_direction.WRITE): 35 | self.pstrb > 0 36 | with vsc.if_then(self.direction == apb_direction.READ): 37 | self.pstrb == 0 38 | 39 | @vsc.constraint 40 | def num_idle_cycle_constr(self): 41 | self.num_idle_cycles in vsc.rangelist(vsc.rng(0,self.max_num_idle_cycles)) 42 | 43 | def __eq__(self, other): 44 | pass 45 | 46 | def __str__(self): 47 | return self.__class__.__name__ 48 | -------------------------------------------------------------------------------- /apb_master_random_sequence.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_master_random_sequence(uvm_sequence): 3 | 4 | def __init__(self, name): 5 | super().__init__(name) 6 | 7 | async def body(self): 8 | item = apb_master_driver_item() 9 | item.randomize() 10 | await self.start_item(item) 11 | await self.finish_item(item) 12 | -------------------------------------------------------------------------------- /apb_memory_random_responce_sequence.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_memory_random_responce_sequence(uvm_sequence): 3 | 4 | def __init__(self, name): 5 | super().__init__(name) 6 | 7 | async def body(self): 8 | self.sequencer.pslverr = random.randint(0, 1) 9 | self.sequencer.num_wait_cycles = random.randint(0, 5) 10 | await self.sequencer.get_ready() 11 | item = self.sequencer.build_item 12 | await self.start_item(item) 13 | await self.finish_item(item) 14 | -------------------------------------------------------------------------------- /apb_monitor.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class apb_monitor(uvm_component): 4 | """ 5 | APB master-interface monitor 6 | """ 7 | def __init__(self, *args, **kwargs): 8 | self.is_master = kwargs["is_master"] 9 | self.num_id = kwargs["num_id"] 10 | del kwargs ["is_master"] 11 | del kwargs ["num_id"] 12 | super().__init__(*args, **kwargs) 13 | 14 | def build_phase(self): 15 | self.ap = uvm_analysis_port("ap", self) 16 | if not self.is_master: 17 | self.mon_trans_port_put = uvm_blocking_put_port("mon_trans_port_put", self) 18 | 19 | def connect_phase(self): 20 | if self.is_master: 21 | pre_index = "apb" + "_vip_" + "m" + str(self.num_id - 1) + "_" 22 | else: 23 | pre_index = "apb" + "_vip_" + "s" + str(self.num_id - 1) + "_" 24 | self.paddr = getattr(cocotb.top, (pre_index + "paddr")) 25 | self.psel = getattr(cocotb.top, (pre_index + "psel")) 26 | self.pprot = getattr(cocotb.top, (pre_index + "pprot")) 27 | self.penable = getattr(cocotb.top, (pre_index + "penable")) 28 | self.pwrite = getattr(cocotb.top, (pre_index + "pwrite")) 29 | self.pwdata = getattr(cocotb.top, (pre_index + "pwdata")) 30 | self.pstrb = getattr(cocotb.top, (pre_index + "pstrb")) 31 | self.pready = getattr(cocotb.top, (pre_index + "pready")) 32 | self.prdata = getattr(cocotb.top, (pre_index + "prdata")) 33 | self.pslverr = getattr(cocotb.top, (pre_index + "pslverr")) 34 | self.pclk = getattr(cocotb.top, (pre_index + "pclk")) 35 | self.presetn = getattr(cocotb.top, (pre_index + "presetn")) 36 | 37 | def set_cfg(self, cfg): 38 | self.__cfg = cfg 39 | 40 | async def run_phase(self): 41 | if not self.is_master: 42 | fix_pready_timeout = 500000 43 | else: 44 | fix_pready_timeout = self.__cfg.fix_pready_timeout 45 | send_trans = 0 46 | if (cocotb.SIM_NAME != "Verilator"): #x = 0 Verilator features 47 | await cocotb.triggers.RisingEdge(self.presetn) 48 | await cocotb.triggers.RisingEdge(self.presetn) 49 | else: 50 | await cocotb.triggers.RisingEdge(self.presetn) 51 | tr = apb_monitor_item() 52 | tr.curr_state = apb_state.IDLE.name 53 | wdt_timeout = 0 54 | while True: 55 | await cocotb.triggers.First(cocotb.triggers.RisingEdge(self.pclk), cocotb.triggers.FallingEdge(self.presetn)) 56 | if (self.presetn.value == 0): 57 | if (tr.curr_state == apb_state.SETUP.name or tr.curr_state == apb_state.ACCESS.name): 58 | tr.curr_state = apb_state.ABORTED.name 59 | tr.end_time = cocotb.utils.get_sim_time(units='ns') 60 | if (send_trans == 0 ): 61 | self.ap.write(apb_monitor_item(tr.direction, tr.data, tr.address, tr.pprot0, tr.pprot1, tr.pprot2, tr.pslverr_enable, tr.pstrb, tr.curr_state, tr.begin_time, tr.end_time)) 62 | send_trans = 1 63 | tr.curr_state = apb_state.IDLE.name 64 | else: 65 | tr.curr_state = apb_state.IDLE.name 66 | send_trans = 0 67 | elif (self.psel.value == 0 and self.penable.value == 0): 68 | if (tr.curr_state == apb_state.ACCESS.name): 69 | tr.curr_state = apb_state.IDLE.name 70 | send_trans = 0 71 | elif (tr.curr_state == apb_state.IDLE.name): 72 | pass 73 | else: 74 | self.logger.error(f"Violation of APB state transitions in {tr.curr_state.name}") 75 | assert False, "Violation of state transitions in SETUP-state" 76 | elif (self.psel.value == 1 and self.penable.value == 0): 77 | if (tr.curr_state == apb_state.IDLE.name or tr.curr_state == apb_state.ACCESS.name ): 78 | tr.curr_state = apb_state.SETUP.name 79 | else: 80 | self.logger.error(f"Violation of APB state transitions") 81 | assert False, "Violation of state transitions in SETUP-state" 82 | send_trans = 0 83 | tr.begin_time = cocotb.utils.get_sim_time(units='ns') 84 | tr.address = hex(self.paddr.value) 85 | tr.direction = self.pwrite.value 86 | tr.data = self.pwdata.value 87 | tr.pstrb = self.pstrb.value 88 | if tr.direction == apb_direction.READ.name: 89 | assert self.pwdata.value == 0, "PWDATA must be zero for READ-transaction" 90 | assert self.pstrb.value == 0, "PSTRB must be zero for READ-transaction" 91 | tr.pprot0 = apb_pprot0(self.pprot.value & 0b001).name 92 | tr.pprot1 = apb_pprot1((self.pprot.value & 0b010) >> 1).name 93 | tr.pprot2 = apb_pprot2((self.pprot.value & 0b100) >> 2).name 94 | if not self.is_master: 95 | if (self.__cfg.is_active): 96 | await self.mon_trans_port_put.put(apb_monitor_item(tr.direction, tr.data, tr.address, tr.pprot0, tr.pprot1, tr.pprot2, tr.pslverr_enable, tr.pstrb, tr.curr_state, tr.begin_time, tr.end_time)) 97 | elif (self.psel.value == 1 and self.penable.value == 1): 98 | if tr.curr_state == apb_state.SETUP.name: 99 | tr.curr_state = apb_state.ACCESS.name 100 | assert tr.address == hex(self.paddr.value), "PADDR change value in SETUP_to_ACCESS cycle" 101 | if (tr.direction == apb_direction.WRITE.name): 102 | assert tr.data == self.pwdata.value, "PWDATA change value in SETUP_to_ACCESS cycle" 103 | assert tr.direction == self.pwrite.value,"PWRITE change value in SETUP_to_ACCESS cycle" 104 | assert tr.pprot0 == apb_pprot0(self.pprot.value & 0b001).name, "PPROT0 change value in SETUP_to_ACCESS cycle" 105 | assert tr.pprot1 == apb_pprot1((self.pprot.value & 0b010) >> 1).name, "PPROT1 change value in SETUP_to_ACCESS cycle" 106 | assert tr.pprot2 == apb_pprot2((self.pprot.value & 0b100) >> 2).name, "PPROT2 change value in SETUP_to_ACCESS cycle" 107 | assert tr.pstrb == self.pstrb.value, "PPROT2 change value in SETUP_to_ACCESS cycle" 108 | if self.pready.value: 109 | tr.end_time = cocotb.utils.get_sim_time(units='ns') 110 | if (tr.direction == apb_direction.READ.name): 111 | tr.data = self.prdata.value 112 | tr.pslverr_enable = self.pslverr.value 113 | send_trans = 1 114 | self.ap.write(apb_monitor_item(tr.direction, tr.data, tr.address, tr.pprot0, tr.pprot1, tr.pprot2, tr.pslverr_enable, tr.pstrb, tr.curr_state, tr.begin_time, tr.end_time)) 115 | wdt_timeout = 0 116 | elif tr.curr_state == apb_state.ACCESS.name: 117 | if (wdt_timeout < fix_pready_timeout): 118 | if self.pready.value: 119 | wdt_timeout = 0 120 | tr.end_time = cocotb.utils.get_sim_time(units='ns') 121 | if (tr.direction == apb_direction.READ): 122 | tr.data = self.prdata.value 123 | tr.pslverr_enable = self.pslverr.value 124 | send_trans = 1 125 | self.ap.write(apb_monitor_item(tr.direction, tr.data, tr.address, tr.pprot0, tr.pprot1, tr.pprot2, tr.pslverr_enable, tr.pstrb, tr.curr_state, tr.begin_time, tr.end_time)) 126 | else: 127 | wdt_timeout += 1 128 | else: 129 | self.logger.error(f"TIMEOUT of PREADY, timeout set {fix_pready_timeout} clock cycles") 130 | assert False, "TIMEOUT of PREADY in APB-bus" 131 | else: 132 | self.logger.error(tr.curr_state) 133 | self.logger.error(f"Violation of APB state transitions") 134 | assert False, "Violation of state transitions in SETUP-state" 135 | -------------------------------------------------------------------------------- /apb_monitor_item.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_monitor_item(uvm_sequence_item): 3 | """ 4 | APB-common monitor item 5 | """ 6 | 7 | def __init__(self, direction = None, data = None, address = None, pprot0 = None, pprot1 = None, pprot2 = None, pslverr_enable = None, pstrb = None, curr_state = None, begin_time = None, end_time = None): 8 | super().__init__("apb_monitor_item") 9 | self.direction = direction 10 | self.data = data 11 | self.address = address 12 | self.pslverr_enable = pslverr_enable 13 | self.pstrb = pstrb 14 | self.pprot0 = pprot0 15 | self.pprot1 = pprot1 16 | self.pprot2 = pprot2 17 | self.curr_state = curr_state 18 | self.begin_time = begin_time 19 | self.end_time = end_time 20 | 21 | def __eq__(self, other): 22 | return (self.direction == other.direction and 23 | self.data == other.data and 24 | self.address == other.address and 25 | self.pslverr_enable == other.pslverr_enable and 26 | self.pstrb == other.pstrb and 27 | self.pprot0 == other.pprot0 and 28 | self.pprot1 == other.pprot1 and 29 | self.pprot2 == other.pprot2 and 30 | self.curr_state == other.curr_state) 31 | 32 | def __str__(self): 33 | return ((f"\nName: {self.get_full_name()} \ 34 | \nADDR: {self.address} \ 35 | \nDATA: {hex(self.data)} \ 36 | \nDIRECTION: {apb_direction(self.direction).name} \ 37 | \nSLV_ERR: {self.pslverr_enable} \ 38 | \nPSTRB: {self.pstrb} \ 39 | \nPPROT_0: {self.pprot0} \ 40 | \nPPROT_1: {self.pprot1} \ 41 | \nPPROT_2: {self.pprot2} \ 42 | \nSTATE: {self.curr_state} \ 43 | \nBEGIN_TIME: {self.begin_time} \ 44 | \nEND_TINE: {self.end_time}")) 45 | -------------------------------------------------------------------------------- /apb_slave_agent.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_slave_agent(uvm_agent): 3 | num_id = 0 4 | def __init__(self, name, parent, *args, **kwargs): 5 | apb_slave_agent.num_id += 1 6 | self.num_id = apb_slave_agent.num_id 7 | super().__init__(name, parent) 8 | 9 | def build_phase(self): 10 | self.cfg = ConfigDB().get(self, "", "cfg") 11 | if (self.cfg.is_active): 12 | self.apb_slave_sequencer = apb_slave_sequencer("apb_slave_sequencer", self) 13 | self.driver = apb_slave_driver("apb_slave_driver", self, num_id = self.num_id) 14 | self.driver.set_cfg(self.cfg) 15 | self.fifo = uvm_tlm_fifo("fifo", self) 16 | self.monitor = apb_monitor("apb_monitor", self, is_master = 0, num_id = self.num_id) 17 | self.monitor.set_cfg(self.cfg) 18 | 19 | def connect_phase(self): 20 | if (self.cfg.is_active): 21 | self.driver.seq_item_port.connect(self.apb_slave_sequencer.seq_item_export) 22 | self.apb_slave_sequencer.mon_trans_port_get.connect(self.fifo.get_export) 23 | self.monitor.mon_trans_port_put.connect(self.fifo.put_export) 24 | -------------------------------------------------------------------------------- /apb_slave_agent_cfg.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | @vsc.randobj 3 | class apb_slave_agent_cfg(uvm_object): 4 | def __init__(self, name): 5 | super().__init__(name) 6 | self.is_active = 0 7 | self.has_cov = 0 8 | self.pready_default = vsc.rand_bit_t() 9 | self.print_debug_info = 0 #ToDo 10 | -------------------------------------------------------------------------------- /apb_slave_driver.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_slave_driver(uvm_driver): 3 | """ 4 | Seqr <---> Driver 5 | Monitor <--^ 6 | """ 7 | def __init__(self, *args, **kwargs): 8 | self.num_id = kwargs["num_id"] 9 | del kwargs["num_id"] 10 | super().__init__(*args, **kwargs) 11 | 12 | def connect_phase(self): 13 | pre_index = "apb" + "_vip_" + "s" + str(self.num_id - 1) + "_" 14 | self.pready = getattr(cocotb.top, (pre_index + "pready")) 15 | self.prdata = getattr(cocotb.top, (pre_index + "prdata")) 16 | self.pslverr = getattr(cocotb.top, (pre_index + "pslverr")) 17 | self.presetn = getattr(cocotb.top, (pre_index + "presetn")) 18 | self.pclk = getattr(cocotb.top, (pre_index + "pclk")) 19 | 20 | def zero_init(self): 21 | self.pready.value = 0 22 | self.prdata.value = 0 23 | self.pslverr.value = 0 24 | 25 | def set_cfg(self, cfg): 26 | self.__cfg = cfg 27 | 28 | def __sign_default_init(self): 29 | self.pready.value = self.__cfg.pready_default 30 | self.prdata.value = 0 31 | self.pslverr.value = 0 32 | 33 | def __sign_reset_init(self): 34 | self.pready.value = 0 35 | self.prdata.value = 0 36 | self.pslverr.value = 0 37 | 38 | 39 | def __init_flag_to_zero(self): 40 | self.__flag_transaction_started = 0 #private 41 | self.__flag_transaction_completed = 0 #private 42 | 43 | 44 | async def __main_task(self): 45 | while True: 46 | item = await self.seq_item_port.get_next_item() #ToDo 47 | self.__flag_transaction_started = 1 48 | self.__flag_transaction_completed = 0 49 | if (item.num_wait_cycles > 0): 50 | self.pready.value = 0 51 | for i in range(item.num_wait_cycles): 52 | await cocotb.triggers.RisingEdge(self.pclk) 53 | self.pready.value = 1 54 | if item.direction == apb_direction.WRITE: 55 | self.prdata.value = 0 56 | elif item.error == 1: 57 | self.prdata.value = 0 58 | else: 59 | self.prdata.value = item.data 60 | self.pslverr.value = item.error 61 | await cocotb.triggers.RisingEdge(self.pclk) 62 | self.__sign_default_init() 63 | self.seq_item_port.item_done() 64 | self.__flag_transaction_completed = 1 65 | self.__flag_transaction_started = 0 66 | 67 | 68 | async def __rst_task(self): 69 | await cocotb.triggers.FallingEdge(self.presetn) 70 | self.rst_assert = 1 71 | self.__sign_reset_init() 72 | 73 | async def run_phase(self): 74 | if (cocotb.SIM_NAME != "Verilator"): #x = 0 Verilator features 75 | await cocotb.triggers.FallingEdge(self.presetn) 76 | self.__sign_reset_init() 77 | self.__init_flag_to_zero() 78 | while True: 79 | await cocotb.triggers.RisingEdge(self.presetn) 80 | self.__sign_default_init() 81 | self.__init_flag_to_zero() 82 | self.rst_assert = 0 83 | t1 = cocotb.start_soon(self.__main_task()) 84 | await cocotb.triggers.First(t1, cocotb.start_soon(self.__rst_task())) 85 | t1.kill() 86 | if(self.__flag_transaction_completed == 0 and self.__flag_transaction_started == 1): 87 | self.seq_item_port.item_done() 88 | -------------------------------------------------------------------------------- /apb_slave_driver_item.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class apb_slave_driver_item(uvm_sequence_item): 3 | """ 4 | APB-Slave driver item 5 | """ 6 | def __init__(self, data = None, error = None, num_wait_cycles = None, direction = None): 7 | super().__init__("apb_slave_driver_item") 8 | self.data = data 9 | self.error = error 10 | self.direction = direction 11 | self.num_wait_cycles = num_wait_cycles 12 | 13 | def randomize(self): 14 | self.randomize_resp() 15 | self.randomize_data() 16 | 17 | def randomize_resp(self): 18 | slv_err = "" 19 | slv_err += random.choice(["0", "1"]) 20 | self.error = int(slv_err,2) 21 | 22 | def randomize_data(self): 23 | data = "" 24 | for i in range(int(cocotb.plusargs["APB_ISO_DATA_WIDTH"])): 25 | data += random.choice(["0", "1"]) 26 | self.data = int(data, 2) 27 | 28 | def __eq__(self, other): 29 | pass 30 | 31 | def __str__(self): 32 | return self.__class__.__name__ 33 | -------------------------------------------------------------------------------- /apb_slave_sequencer.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class apb_slave_sequencer(uvm_sequencer): 4 | 5 | def __init__(self, name, parent): 6 | super().__init__(name, parent) 7 | self.apb_slave_memory = dict() 8 | self.ready = CocotbEvent() 9 | self.pslverr = 0 10 | self.num_wait_cycles = 0 11 | 12 | def build_phase(self): 13 | super().build_phase() 14 | self.mon_trans_port_get = uvm_blocking_get_port("mon_trans_port_get", self) 15 | 16 | 17 | async def run_phase(self): 18 | while True: 19 | get_item = await self.mon_trans_port_get.get() 20 | mask_wr_data = "" 21 | wr_data = get_item.data 22 | self.build_item = apb_slave_driver_item() 23 | if self.pslverr == 0: 24 | if (get_item.direction == apb_direction.WRITE): 25 | if get_item.address in self.apb_slave_memory: 26 | mem_data = str(bin(self.apb_slave_memory[get_item.address])) 27 | mem_data = mem_data.replace("0b","") 28 | else: 29 | self.build_item.randomize() 30 | mem_data = str(bin(self.build_item.data)) 31 | mem_data = mem_data.replace("0b","") 32 | for i in range((int(get_item.pstrb).bit_length())): 33 | if (get_item.pstrb >> i) & 1: 34 | mask_wr_data = "11111111" + mask_wr_data 35 | if (i == 0): 36 | mem_data = mem_data[:-8*(i+1)] + "00000000" 37 | else: 38 | mem_data = mem_data[:-8*(i+1)] + "00000000" + mem_data[-8*i:] 39 | else: 40 | mask_wr_data = "00000000" + mask_wr_data 41 | wr_data = (wr_data & int(mask_wr_data, 2)) | int(mem_data, 2) 42 | self.apb_slave_memory[get_item.address] = wr_data 43 | else: 44 | if get_item.address in self.apb_slave_memory: 45 | self.build_item.data = self.apb_slave_memory[get_item.address] 46 | else: 47 | self.build_item.randomize() 48 | self.apb_slave_memory[get_item.address] = self.build_item.data 49 | self.build_item.error = self.pslverr 50 | self.build_item.num_wait_cycles = self.num_wait_cycles 51 | self.build_item.direction = get_item.direction 52 | self.ready.set() 53 | self.ready.clear() 54 | next_item = await self.seq_q.get() 55 | self.logger.debug(f"Sequence item {next_item} started") 56 | await self.seq_item_export.put_req(next_item) 57 | 58 | async def get_ready(self): 59 | await self.ready.wait() 60 | 61 | def final_phase(self): 62 | file_name = (str(self.get_full_name()) + "_mem.txt") 63 | with open(file_name,'w') as out: 64 | for addr, data in self.apb_slave_memory.items(): 65 | out.write('MEM_ADDR | {}| DATA | {}|\n'.format(addr, hex(data))) 66 | out.close() 67 | -------------------------------------------------------------------------------- /lpi_master_agent.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class lpi_master_agent(uvm_agent): 4 | num_id = 0 5 | def __init__(self, name, parent, *args, **kwargs): 6 | lpi_master_agent.num_id +=1 7 | self.num_id = lpi_master_agent.num_id 8 | super().__init__(name, parent) 9 | 10 | def build_phase(self): 11 | super().build_phase() 12 | self.cfg = ConfigDB().get(self, "", "cfg") 13 | if (self.cfg.is_active): 14 | self.sequencer = uvm_sequencer("lpi_master_seqr", self) 15 | self.driver = lpi_master_driver("lpi_master_driver", self, num_id = self.num_id) 16 | self.driver.set_cfg(self.cfg) 17 | self.monitor = lpi_monitor("lpi_monitor", self, num_id = self.num_id) 18 | self.monitor.set_cfg(self.cfg) 19 | 20 | def connect_phase(self): 21 | if (self.cfg.is_active): 22 | self.driver.seq_item_port.connect(self.sequencer.seq_item_export) 23 | -------------------------------------------------------------------------------- /lpi_master_agent_cfg.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | @vsc.randobj 4 | class lpi_master_agent_cfg (uvm_object): 5 | def __init__(self, name): 6 | super().__init__(name) 7 | self.is_active = 0 8 | self.print_debug_info = 0 #ToDo 9 | self.qreqn_state_during_rst = vsc.rand_bit_t() -------------------------------------------------------------------------------- /lpi_master_driver.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class lpi_master_driver(uvm_driver): 4 | 5 | def __init__(self, *args, **kwargs): 6 | self.num_id = kwargs["num_id"] 7 | del kwargs["num_id"] 8 | self.__flag_transaction_completed = 0 9 | self.__flag_transaction_started = 0 10 | super().__init__(*args, **kwargs) 11 | 12 | def connect_phase (self): 13 | pre_index = "lpi" + "_vip_" + "m" + str(self.num_id - 1) + "_" 14 | self.qreqn = getattr(cocotb.top, (pre_index + "qreqn")) 15 | self.qclk = getattr(cocotb.top, (pre_index + "qclk")) 16 | self.qreset = getattr(cocotb.top, (pre_index + "qreset")) 17 | 18 | def __init_flag_to_zero(self): 19 | self.__flag_transaction_started = 0 #private 20 | self.__flag_transaction_completed = 0 #private 21 | 22 | def set_cfg(self, cfg): 23 | self.__cfg = cfg 24 | 25 | async def __main_task(self): 26 | while True: 27 | item = await self.seq_item_port.get_next_item() #ToDo 28 | self.__flag_transaction_started = 1 29 | await cocotb.triggers.ClockCycles(self.qclk, 1 + item.pre_delay_clk) 30 | if item.state_req == lpi_q_req_e.REQUEST: 31 | self.qreqn.value = 0 32 | elif item.state_req == lpi_q_req_e.NO_REQUEST: 33 | self.qreqn.value = 1 34 | else: 35 | raise RuntimeError("Unknown switch case-statement: '{}'" , item.state_req) 36 | await cocotb.triggers.ClockCycles(self.qclk, item.post_delay_clk) 37 | self.seq_item_port.item_done() 38 | self.__flag_transaction_completed = 1 39 | self.__init_flag_to_zero() 40 | 41 | async def __rst_task(self): 42 | await cocotb.triggers.RisingEdge(self.qreset) 43 | self.qreqn.value = self.__cfg.qreqn_state_during_rst 44 | 45 | async def run_phase(self): 46 | await cocotb.triggers.RisingEdge(self.qreset) 47 | self.qreqn.value = 0 48 | await cocotb.triggers.FallingEdge(self.qreset) 49 | while True: 50 | first_task = cocotb.start_soon(self.__main_task()) 51 | second_task = cocotb.start_soon(self.__rst_task()) 52 | await cocotb.triggers.First(first_task, second_task) 53 | if(self.__flag_transaction_started == 1 and ~self.__flag_transaction_completed == 1): 54 | seq_item_port.item_done() 55 | self.__init_flag_to_zero() 56 | -------------------------------------------------------------------------------- /lpi_master_sequence_param.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class lpi_master_sequence_param(uvm_sequence): 3 | def __init__(self, name, pre_delay_clk, post_delay_clk, state_req): 4 | super().__init__(name) 5 | self.pre_delay_clk = pre_delay_clk 6 | self.post_delay_clk = post_delay_clk 7 | self.state_req = state_req 8 | async def body(self): 9 | item = lpi_q_item(state_req = self.state_req, pre_delay_clk = self.pre_delay_clk, post_delay_clk = self.post_delay_clk) 10 | await self.start_item(item) 11 | await self.finish_item(item) 12 | -------------------------------------------------------------------------------- /lpi_monitor.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class lpi_monitor(uvm_component): 4 | """ 5 | LPI monitor 6 | """ 7 | def __init__(self, *args, **kwargs): 8 | self.num_id = kwargs["num_id"] 9 | del kwargs ["num_id"] 10 | super().__init__(*args, **kwargs) 11 | 12 | def build_phase(self): 13 | self.ap = uvm_analysis_port("ap", self) 14 | 15 | def connect_phase(self): 16 | pre_index = "lpi" + "_vip_" + "m" + str(self.num_id - 1) + "_" 17 | self.qclk = getattr(cocotb.top, (pre_index + "qclk")) 18 | self.qreset = getattr(cocotb.top, (pre_index + "qreset")) 19 | self.qreqn = getattr(cocotb.top, (pre_index + "qreqn")) 20 | self.qacceptn = getattr(cocotb.top, (pre_index + "qacceptn")) 21 | self.qdeny = getattr(cocotb.top, (pre_index + "qdeny")) 22 | self.qactive = getattr(cocotb.top, (pre_index + "qactive")) 23 | 24 | def set_cfg(self, cfg): 25 | self.__cfg = cfg 26 | 27 | async def __main_task(self): 28 | while True: 29 | await cocotb.triggers.First(cocotb.triggers.Edge(self.qreqn), cocotb.triggers.Edge(self.qacceptn), cocotb.triggers.Edge(self.qdeny), cocotb.triggers.Edge(self.qactive)) 30 | await cocotb.triggers.FallingEdge(self.qclk) 31 | if (self.qreset.value == 0): 32 | bus_item = lpi_q_item() 33 | if (self.qreqn.value): 34 | bus_item.state_req = lpi_q_req_e.NO_REQUEST 35 | else: 36 | bus_item.state_req = lpi_q_req_e.REQUEST 37 | if (self.qacceptn.value == 0 and self.qdeny.value == 0): 38 | bus_item.state_resp = lpi_q_resp_e.ACCEPT 39 | elif (self.qacceptn.value == 1 and self.qdeny.value == 1): 40 | bus_item.state_resp = lpi_q_resp_e.DENY 41 | elif (self.qacceptn.value == 1 and self.qdeny.value == 0): 42 | bus_item.state_resp = lpi_q_resp_e.IDLE 43 | elif (self.qacceptn.value == 0 and self.qdeny.value == 1): 44 | self.logger.error(f"Violation of LPI state transitions - qacceptn = 0 and qdeny = 1") 45 | assert False, "Violation of LPI state transitions" 46 | if (self.qactive): 47 | bus_item.state_active = lpi_q_active_e.ACTIVE 48 | else: 49 | bus_item.state_active = lpi_q_active_e.NOT_ACTIVE 50 | self.ap.write(bus_item) 51 | 52 | async def __rst_task(self): 53 | await cocotb.triggers.RisingEdge(self.qreset) 54 | await cocotb.triggers.FallingEdge(self.qclk) 55 | bus_item_after_rst = lpi_q_item() 56 | if (self.qreqn.value): 57 | bus_item_after_rst.state_req = lpi_q_req_e.NO_REQUEST 58 | else: 59 | bus_item_after_rst.state_req = lpi_q_req_e.REQUEST 60 | if (self.qacceptn.value == 0 and self.qdeny.value == 0): 61 | bus_item_after_rst.state_resp = lpi_q_resp_e.ACCEPT 62 | elif (self.qacceptn.value == 1 and self.qdeny.value == 1): 63 | bus_item_after_rst.state_resp = lpi_q_resp_e.DENY 64 | elif (self.qacceptn.value == 1 and self.qdeny.value == 0): 65 | bus_item_after_rst.state_resp = lpi_q_resp_e.IDLE 66 | elif (self.qacceptn.value == 0 and self.qdeny.value == 1): 67 | self.logger.error(f"Violation of LPI state transitions - qacceptn = 0 and qdeny = 1") 68 | assert False, "Violation of LPI state transitions" 69 | if (self.qactive.value): 70 | bus_item_after_rst.state_active = lpi_q_active_e.ACTIVE 71 | else: 72 | bus_item_after_rst.state_active = lpi_q_active_e.NOT_ACTIVE 73 | self.ap.write(bus_item_after_rst) 74 | 75 | async def run_phase(self): 76 | while True: 77 | try: 78 | state_x = str(self.qreset.value) 79 | except ValueError: 80 | state_x = "x" 81 | if (state_x != "x"): 82 | await cocotb.triggers.FallingEdge(self.qreset) 83 | first_task = cocotb.start_soon(self.__main_task()) 84 | second_task = cocotb.start_soon(self.__rst_task()) 85 | await cocotb.triggers.First(first_task, second_task) 86 | else: 87 | await cocotb.triggers.RisingEdge(self.qclk) 88 | -------------------------------------------------------------------------------- /lpi_q_item.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | @vsc.randobj 3 | class lpi_q_item(uvm_sequence_item): 4 | """ 5 | LPI-Master driver item 6 | """ 7 | def __init__(self, pre_delay_clk = 0, post_delay_clk = 0, state_req = None, state_resp = None, state_active = None): 8 | super().__init__("lpi_q_item") 9 | self.pre_delay_clk = pre_delay_clk 10 | self.post_delay_clk = post_delay_clk 11 | self.state_req = state_req 12 | self.state_resp = state_resp 13 | self.state_active = state_active 14 | 15 | def randomize(self): 16 | self.__randomize_req() 17 | 18 | def __randomize_req(self): 19 | self.state_req = random.choice(list(state_req)) 20 | 21 | def __eq__(self, other): 22 | pass 23 | 24 | def __str__(self): 25 | return self.__class__.__name__ 26 | 27 | def get_lpi_state(self): 28 | if (self.state_req == lpi_q_req_e.NO_REQUEST and self.state_resp == lpi_q_resp_e.IDLE): 29 | return lpi_q_state_e.Q_RUN.name 30 | elif (self.state_req == lpi_q_req_e.REQUEST and self.state_resp == lpi_q_resp_e.IDLE): 31 | return lpi_q_state_e.Q_REQUEST.name 32 | elif (self.state_req == lpi_q_req_e.REQUEST and self.state_resp == lpi_q_resp_e.ACCEPT): 33 | return lpi_q_state_e.Q_STOPPED.name 34 | elif (self.state_req == lpi_q_req_e.NO_REQUEST and self.state_resp == lpi_q_resp_e.ACCEPT): 35 | return lpi_q_state_e.Q_EXIT.name 36 | elif (self.state_req == lpi_q_req_e.REQUEST and self.state_resp == lpi_q_resp_e.DENY): 37 | return lpi_q_state_e.Q_DENIED.name 38 | elif (self.state_req == lpi_q_req_e.NO_REQUEST and self.state_resp == lpi_q_resp_e.DENY): 39 | return lpi_q_state_e.Q_CONTINUE.name 40 | else: 41 | return lpi_q_state_e.ILLEGAL.name 42 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cocotb 2 | pyuvm 3 | pyvsc 4 | debugpy 5 | cocotb-coverage -------------------------------------------------------------------------------- /reset_agent.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class reset_agent(uvm_agent): 4 | num_id = 0 5 | def __init__(self, name, parent, *args, **kwargs): 6 | reset_agent.num_id += 1 7 | self.num_id = reset_agent.num_id 8 | super().__init__(name, parent) 9 | 10 | 11 | def build_phase(self): 12 | self.cfg = ConfigDB().get(self, "", "cfg") 13 | if (self.cfg.is_active): 14 | self.reset_seqr = uvm_sequencer.create("reset_seqr", self) 15 | self.driver = reset_driver("reset_driver", self, num_id = self.num_id) 16 | self.driver.set_cfg(self.cfg) 17 | self.monitor = reset_monitor("reset_monitor", self, num_id = self.num_id) 18 | 19 | def connect_phase(self): 20 | if (self.cfg.is_active): 21 | self.driver.seq_item_port.connect(self.reset_seqr.seq_item_export) 22 | -------------------------------------------------------------------------------- /reset_agent_cfg.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class reset_agent_cfg (uvm_object): 3 | def __init__(self, name): 4 | super().__init__(name) 5 | self.active_level = 0 6 | self.is_active = 0 7 | -------------------------------------------------------------------------------- /reset_driver.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class reset_driver(uvm_driver): 4 | def __init__(self, *args, **kwargs): 5 | self.num_id = kwargs["num_id"] 6 | del kwargs["num_id"] 7 | super().__init__(*args, **kwargs) 8 | 9 | def connect_phase(self): 10 | pre_index = "rst" + "_vip_"+ "m" + str(self.num_id - 1) + "_" 11 | self.clk = getattr(cocotb.top, (pre_index + "clk")) 12 | self.rst = getattr(cocotb.top, (pre_index + "reset")) 13 | 14 | async def run_phase(self): 15 | active_level = cocotb.binary.BinaryValue(value=self.__cfg.active_level, bigEndian=True, n_bits=1) 16 | await cocotb.triggers.RisingEdge(self.clk) 17 | self.rst.value = int(~active_level, 2) 18 | while True: 19 | item = await self.seq_item_port.get_next_item() 20 | if item.item_type == reset_action.RST_PULSE: 21 | await cocotb.triggers.ClockCycles(self.clk, 1 + item.clk_cycles_before) 22 | self.rst.value = int(active_level) 23 | await cocotb.triggers.ClockCycles(self.clk, item.clk_cycles_duration) 24 | self.rst.value = int(~active_level, 2) 25 | await cocotb.triggers.ClockCycles(self.clk, item.clk_cycles_after) 26 | else: 27 | raise RuntimeError("Unknown item '{}'" , item.item_type) 28 | self.seq_item_port.item_done() 29 | 30 | def set_cfg(self, cfg): 31 | self.__cfg = cfg 32 | -------------------------------------------------------------------------------- /reset_driver_item.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | class reset_driver_item(uvm_sequence_item): 3 | def __init__(self, item_type, clk_cycles_before = 0, clk_cycles_duration = 0, clk_cycles_after = 0): 4 | super().__init__("reset_driver_item") 5 | self.item_type = item_type 6 | self.clk_cycles_after = clk_cycles_after 7 | self.clk_cycles_before = clk_cycles_before 8 | self.clk_cycles_duration = clk_cycles_duration 9 | 10 | def randomize(self): 11 | pass 12 | 13 | def __eq__(self, other): 14 | pass 15 | 16 | def __str__(self): 17 | return self.__class__.__name__ 18 | -------------------------------------------------------------------------------- /reset_monitor.py: -------------------------------------------------------------------------------- 1 | from apb_iso_pkg import * 2 | 3 | class reset_monitor(uvm_component): 4 | """ 5 | Reset monitor 6 | """ 7 | 8 | def __init__(self, *args, **kwargs): 9 | self.num_id = kwargs["num_id"] 10 | del kwargs["num_id"] 11 | super().__init__(*args, **kwargs) 12 | 13 | def connect_phase(self): 14 | pre_index = "rst" + "_vip_"+ "m" + str(self.num_id - 1) + "_" 15 | self.clk = getattr(cocotb.top, (pre_index + "clk")) 16 | self.rst = getattr(cocotb.top, (pre_index + "reset")) 17 | 18 | def build_phase(self): 19 | self.ap = uvm_analysis_port("ap", self) 20 | 21 | async def run_phase(self): 22 | await cocotb.triggers.Edge(self.rst) 23 | while True: 24 | await cocotb.triggers.Edge(self.rst) 25 | if self.rst.value: 26 | rst_st = rst_state.RST_ASSERT 27 | else: 28 | rst_st = rst_state.RST_DEASSERT 29 | time_assert = cocotb.utils.get_sim_time(units='ns') 30 | self.ap.write(reset_monitor_item(rst_st, time_assert)) 31 | -------------------------------------------------------------------------------- /reset_monitor_item.py: -------------------------------------------------------------------------------- 1 | 2 | from apb_iso_pkg import * 3 | class reset_monitor_item(uvm_sequence_item): 4 | """ 5 | Reset monitor item 6 | """ 7 | def __init__(self, rst_st, time_assert): 8 | super().__init__("reset_monitor_item") 9 | self.rst_st = rst_st 10 | self.time_assert = time_assert 11 | 12 | def randomize(self): 13 | pass 14 | 15 | def __eq__(self, other): 16 | pass 17 | 18 | def __str__(self): 19 | return self.get_full_name() 20 | -------------------------------------------------------------------------------- /reset_sequence_param.py: -------------------------------------------------------------------------------- 1 | 2 | from apb_iso_pkg import * 3 | class reset_sequence_param(uvm_sequence): 4 | def __init__(self, name, item_type, clk_cycles_before, clk_cycles_duration, clk_cycles_after): 5 | super().__init__(name) 6 | self.item_type = item_type 7 | self.clk_cycles_after = clk_cycles_after 8 | self.clk_cycles_before = clk_cycles_before 9 | self.clk_cycles_duration = clk_cycles_duration 10 | 11 | async def body(self): 12 | item = reset_driver_item(self.item_type, self.clk_cycles_before, self.clk_cycles_duration, self.clk_cycles_after) 13 | await self.start_item(item) 14 | await self.finish_item(item) -------------------------------------------------------------------------------- /rtl/apb_isolator_top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | module apb_isolator_top 3 | #( 4 | parameter 5 | AW = 20 , 6 | DW = 32 7 | ) 8 | ( 9 | 10 | input wire pclk_i , 11 | input wire presetn_i , 12 | 13 | input wire qreqn_i , 14 | output wire qacceptn_o , 15 | output wire qdeny_o , 16 | output wire qactive_o , 17 | 18 | input wire [AW -1:0] s_paddr_i , 19 | input wire [3 -1:0] s_pprot_i , 20 | input wire s_psel_i , 21 | input wire s_penable_i , 22 | input wire s_pwrite_i , 23 | input wire [DW -1:0] s_pwdata_i , 24 | input wire [DW/8 -1:0] s_pstrb_i , 25 | output wire s_pready_o , 26 | output wire [DW -1:0] s_prdata_o , 27 | output wire s_pslverr_o , 28 | 29 | output wire [AW -1:0] m_paddr_o , 30 | output wire [3 -1:0] m_pprot_o , 31 | output wire m_psel_o , 32 | output wire m_penable_o , 33 | output wire m_pwrite_o , 34 | output wire [DW -1:0] m_pwdata_o , 35 | output wire [DW/8 -1:0] m_pstrb_o , 36 | input wire m_pready_i , 37 | input wire [DW -1:0] m_prdata_i , 38 | input wire m_pslverr_i 39 | 40 | ); 41 | 42 | wire presetn_l ; 43 | wire qreqn_l ; 44 | reg qactive_l ; 45 | reg iso_l ; 46 | 47 | assign qacceptn_o = iso_l ? { {1'b0}} : 1'b1 ; 48 | assign qdeny_o = 1'b0 ; 49 | assign qactive_o = qactive_l ; 50 | assign m_paddr_o = iso_l ? {AW {1'b0}} : s_paddr_i ; 51 | assign m_pprot_o = iso_l ? {3 {1'b0}} : s_pprot_i ; 52 | assign m_psel_o = iso_l ? { {1'b0}} : s_psel_i ; 53 | assign m_penable_o = iso_l ? { {1'b0}} : s_penable_i ; 54 | assign m_pwrite_o = iso_l ? { {1'b0}} : s_pwrite_i ; 55 | assign m_pwdata_o = iso_l ? {DW {1'b0}} : s_pwdata_i ; 56 | assign m_pstrb_o = iso_l ? {DW/8{1'b0}} : s_pstrb_i ; 57 | assign s_pready_o = iso_l ? { {1'b1}} : m_pready_i ; 58 | assign s_prdata_o = iso_l ? {DW {1'b0}} : m_prdata_i ; 59 | assign s_pslverr_o = iso_l ? { {1'b1}} : m_pslverr_i ; 60 | 61 | always @(posedge pclk_i or negedge presetn_l) 62 | begin 63 | if (~presetn_l) qactive_l <= 1'b0 ; 64 | else qactive_l <= s_psel_i ; 65 | end 66 | always @(posedge pclk_i or negedge presetn_l) 67 | begin 68 | if (~presetn_l) iso_l <= 1'b1 ; 69 | else 70 | begin 71 | if (qreqn_l == iso_l) 72 | begin 73 | if (~s_psel_i || (s_penable_i && s_pready_o)) iso_l <= ~iso_l ; 74 | end 75 | end 76 | end 77 | 78 | assign presetn_l = presetn_i; 79 | assign qreqn_l = qreqn_i; 80 | 81 | endmodule 82 | -------------------------------------------------------------------------------- /rtl/apb_isolator_top_wrapper.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | module apb_isolator_top_wrapper 3 | #( 4 | parameter 5 | AW = 32, 6 | DW = 32 7 | )(); 8 | 9 | wire cocotb_clock ; 10 | 11 | // LPI VIP master[0] wires 12 | wire lpi_vip_m0_qreqn ; 13 | wire lpi_vip_m0_qacceptn ; 14 | wire lpi_vip_m0_qdeny ; 15 | wire lpi_vip_m0_qactive ; 16 | wire lpi_vip_m0_qreset ; 17 | wire lpi_vip_m0_qclk ; 18 | 19 | // APB VIP slave wires 20 | wire [AW -1:0] apb_vip_s0_paddr ; 21 | wire [3 -1:0] apb_vip_s0_pprot ; 22 | wire apb_vip_s0_psel ; 23 | wire apb_vip_s0_penable ; 24 | wire apb_vip_s0_pwrite ; 25 | wire [DW -1:0] apb_vip_s0_pwdata ; 26 | wire [DW/8 -1:0] apb_vip_s0_pstrb ; 27 | wire apb_vip_s0_pready ; 28 | wire [DW -1:0] apb_vip_s0_prdata ; 29 | wire apb_vip_s0_pslverr ; 30 | wire apb_vip_s0_pclk ; 31 | wire apb_vip_s0_presetn ; 32 | 33 | //APB VIP master wires 34 | wire [AW -1:0] apb_vip_m0_paddr ; 35 | wire [3 -1:0] apb_vip_m0_pprot ; 36 | wire apb_vip_m0_psel ; 37 | wire apb_vip_m0_penable ; 38 | wire apb_vip_m0_pwrite ; 39 | wire [DW -1:0] apb_vip_m0_pwdata ; 40 | wire [DW/8 -1:0] apb_vip_m0_pstrb ; 41 | wire apb_vip_m0_pready ; 42 | wire [DW -1:0] apb_vip_m0_prdata ; 43 | wire apb_vip_m0_pslverr ; 44 | wire apb_vip_m0_pclk ; 45 | wire apb_vip_m0_presetn ; 46 | 47 | //RST VIP master[0] wires 48 | wire rst_vip_m0_clk; 49 | wire rst_vip_m0_reset; 50 | 51 | //RST VIP master[1] wires 52 | wire rst_vip_m1_clk; 53 | wire rst_vip_m1_reset; 54 | 55 | //RST VIP master[2] wires 56 | wire rst_vip_m2_clk; 57 | wire rst_vip_m2_reset; 58 | 59 | // clk & rst connect to APB-master[0] VIP 60 | assign apb_vip_m0_pclk = cocotb_clock; 61 | assign apb_vip_m0_presetn = rst_vip_m2_reset; 62 | 63 | // clk & rst connect to APB-slave[0] VIP 64 | assign apb_vip_s0_pclk = cocotb_clock; 65 | assign apb_vip_s0_presetn = rst_vip_m1_reset; 66 | 67 | // clk connect to RST-master[0] VIP 68 | assign rst_vip_m0_clk = cocotb_clock; 69 | 70 | // clk connect to RST-master[1] VIP 71 | assign rst_vip_m1_clk = cocotb_clock; 72 | 73 | // clk connect to RST-master[2] VIP 74 | assign rst_vip_m2_clk = cocotb_clock; 75 | 76 | // clk connect to RST-master[2] VIP 77 | assign lpi_vip_m0_qreset = ~rst_vip_m0_reset; 78 | assign lpi_vip_m0_qclk = cocotb_clock; 79 | 80 | apb_isolator_top 81 | #( 82 | .AW (AW) , 83 | .DW (DW) 84 | ) 85 | dut 86 | 87 | ( 88 | .pclk_i (cocotb_clock) , 89 | .presetn_i (rst_vip_m0_reset) , 90 | .qreqn_i (lpi_vip_m0_qreqn), 91 | .qacceptn_o (lpi_vip_m0_qacceptn), 92 | .qdeny_o (lpi_vip_m0_qdeny), 93 | .qactive_o (lpi_vip_m0_qactive), 94 | .s_paddr_i (apb_vip_m0_paddr), 95 | .s_pprot_i (apb_vip_m0_pprot), 96 | .s_psel_i (apb_vip_m0_psel), 97 | .s_penable_i (apb_vip_m0_penable), 98 | .s_pwrite_i (apb_vip_m0_pwrite), 99 | .s_pwdata_i (apb_vip_m0_pwdata), 100 | .s_pstrb_i (apb_vip_m0_pstrb), 101 | .s_pready_o (apb_vip_m0_pready), 102 | .s_prdata_o (apb_vip_m0_prdata), 103 | .s_pslverr_o (apb_vip_m0_pslverr), 104 | 105 | .m_paddr_o (apb_vip_s0_paddr), 106 | .m_pprot_o (apb_vip_s0_pprot), 107 | .m_psel_o (apb_vip_s0_psel), 108 | .m_penable_o (apb_vip_s0_penable), 109 | .m_pwrite_o (apb_vip_s0_pwrite), 110 | .m_pwdata_o (apb_vip_s0_pwdata), 111 | .m_pstrb_o (apb_vip_s0_pstrb), 112 | .m_pready_i (apb_vip_s0_pready), 113 | .m_prdata_i (apb_vip_s0_prdata), 114 | .m_pslverr_i (apb_vip_s0_pslverr) 115 | ); 116 | 117 | endmodule 118 | --------------------------------------------------------------------------------