Initial commit
* Bare skeleton implementation of everything * Testbench builds with Verilator * Test runs
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
obj_dir
|
||||
runs
|
||||
logs
|
117
Makefile
Normal file
117
Makefile
Normal file
@@ -0,0 +1,117 @@
|
||||
# Logging control
|
||||
LOG_REDIR = >&
|
||||
TIME=/usr/bin/time --format "Elapsed: %E, Memory: %M KB [Swaps %W]"
|
||||
|
||||
# Makefile variables
|
||||
NUM_PROCS=$(shell nproc --all)
|
||||
PROJ_BASE=$(shell pwd)
|
||||
|
||||
# Make and run project
|
||||
UVM_HOME=$(HOME)/git/uvm-verilator
|
||||
PROJ=axi
|
||||
|
||||
SV_OUT=obj_dir/Vuvm_pkg__verFiles.dat
|
||||
SV_BUILD_LOG=logs/$(PROJ)_build_sv.log
|
||||
|
||||
CPP_OUT=$(PROJ).sim
|
||||
CPP_BUILD_LOG=logs/$(PROJ)_build_cpp.log
|
||||
|
||||
SIM_LOG=$(PROJ)_sim.log
|
||||
|
||||
SV_FILES=$(shell ls common/* src/*.sv tb/*.sv)
|
||||
SV_SRC=$(UVM_HOME)/src/uvm_pkg.sv common/common_pkg.sv src/design_pkg.sv tb/tb_types.sv tb/tb_pkg.sv
|
||||
DPI_SRC=$(UVM_HOME)/src/dpi/uvm_dpi.cc
|
||||
DPI_INC=-I/usr/share/verilator/include
|
||||
SV_DEPS=$(SV_FILES)
|
||||
|
||||
CPP_SRC=sim_$(PROJ).cpp
|
||||
|
||||
TIMESCALE= --timescale '1ns/1ns'
|
||||
|
||||
UVM_DEFINES=+define+UVM_NO_DPI \
|
||||
+define+UVM_REPORT_DISABLE_FILE_LINE
|
||||
DISABLED_WARNINGS=-Wno-WIDTHTRUNC -Wno-WIDTHEXPAND \
|
||||
-Wno-CASTCONST -Wno-CONSTRAINTIGN \
|
||||
-Wno-MISINDENT -Wno-REALCVT \
|
||||
-Wno-SYMRSVDWORD -Wno-CASEINCOMPLETE
|
||||
|
||||
BUILD_ARGS=-I$(UVM_HOME)/src -I. \
|
||||
-o $(PROJ).sim \
|
||||
-j $(NUM_PROCS) \
|
||||
--error-limit 10 \
|
||||
--timing $(TIMESCALE) \
|
||||
--trace \
|
||||
+define+SVA_ON \
|
||||
$(UVM_DEFINES) \
|
||||
$(DISABLED_WARNINGS) \
|
||||
+incdir+common +incdir+src +incdir+tb \
|
||||
$(SV_SRC)
|
||||
|
||||
ifndef TEST_NAME
|
||||
TEST_NAME=test_basic
|
||||
endif
|
||||
|
||||
#
|
||||
# Full build to generate testbench executable (Default target)
|
||||
#
|
||||
build: build_cpp
|
||||
@echo "Build done"
|
||||
|
||||
prepare_area:
|
||||
$(info #----------------)
|
||||
$(info # Preparing area)
|
||||
$(info #----------------)
|
||||
@if [ ! -d $(PROJ_BASE)/logs ]; then mkdir -p $(PROJ_BASE)/logs; fi
|
||||
|
||||
#
|
||||
# C code generation from SystemVerilog
|
||||
#
|
||||
build_sv: prepare_area $(SV_OUT)
|
||||
|
||||
$(PROJ_BASE)/logs:
|
||||
@if [ ! -d $(PROJ_BASE)/logs ]; then mkdir -p $(PROJ_BASE)/logs; fi
|
||||
|
||||
$(SV_OUT): $(PROJ_BASE)/logs $(SV_DEPS)
|
||||
$(info #------------)
|
||||
$(info # Building SV)
|
||||
$(info #------------)
|
||||
@verilator --cc $(BUILD_ARGS)
|
||||
|
||||
#
|
||||
# C code build to generate testbench executable
|
||||
#
|
||||
build_cpp: build_sv $(CPP_OUT)
|
||||
|
||||
$(CPP_OUT): $(SV_OUT)
|
||||
$(info #-------------)
|
||||
$(info # Building CPP)
|
||||
$(info #-------------)
|
||||
@verilator --binary $(BUILD_ARGS)
|
||||
|
||||
#
|
||||
# Run just lint to detect syntax errors during development
|
||||
#
|
||||
lint:
|
||||
$(info #--------)
|
||||
$(info # Linting)
|
||||
$(info #--------)
|
||||
@verilator --lint-only $(BUILD_ARGS)
|
||||
|
||||
#
|
||||
# Run test. Use TEST_NAME=<test name> on make line to pick the test
|
||||
#
|
||||
run: $(CPP_OUT)
|
||||
$(info #---------------------)
|
||||
$(info # Running $(TEST_NAME))
|
||||
$(info #---------------------)
|
||||
@if [ ! -d runs/$(TEST_NAME) ]; then mkdir -p runs/$(TEST_NAME); fi
|
||||
@cd runs/$(TEST_NAME) && \
|
||||
$(PROJ_BASE)/obj_dir/$(PROJ).sim +UVM_TESTNAME=$(TEST_NAME) +UVM_CONFIG_DB_TRACE |& tee $(SIM_LOG)
|
||||
notify-send "[$(PROJ)] Test run done"
|
||||
|
||||
#
|
||||
# Remove generated files
|
||||
# - This will not remove 'runs' directory that contains simulation run logs
|
||||
#
|
||||
clean:
|
||||
rm -rf obj_dir logs $(PROJ)*.log
|
122
Makefile.details
Normal file
122
Makefile.details
Normal file
@@ -0,0 +1,122 @@
|
||||
# Logging control
|
||||
ifdef VERBOSE
|
||||
LOG_REDIR = |tee -a
|
||||
TIME=stdbuf -o 0 /usr/bin/time --format "Elapsed: %E, Memory: %M KB [Swaps %W]"
|
||||
else
|
||||
LOG_REDIR = >&
|
||||
TIME=/usr/bin/time --format "Elapsed: %E, Memory: %M KB [Swaps %W]"
|
||||
endif
|
||||
|
||||
# Makefile variables
|
||||
NUM_PROCS=$(shell nproc --all)
|
||||
PROJ_BASE=$(shell pwd)
|
||||
|
||||
# Make and run project
|
||||
UVM_HOME=$(HOME)/git/uvm-verilator
|
||||
PROJ=axi
|
||||
|
||||
SV_OUT=obj_dir/Vuvm_pkg__verFiles.dat
|
||||
SV_BUILD_LOG=logs/$(PROJ)_build_sv.log
|
||||
|
||||
CPP_OUT=$(PROJ).sim
|
||||
CPP_BUILD_LOG=logs/$(PROJ)_build_cpp.log
|
||||
|
||||
SIM_LOG=$(PROJ)_sim.log
|
||||
|
||||
SV_FILES=$(shell ls common/* src/*.sv tb/*.sv)
|
||||
SV_SRC=$(UVM_HOME)/src/uvm_pkg.sv common/common_pkg.sv src/design_pkg.sv tb/tb_types.sv tb/tb_pkg.sv
|
||||
DPI_SRC=$(UVM_HOME)/src/dpi/uvm_dpi.cc
|
||||
DPI_INC=-I/usr/share/verilator/include
|
||||
SV_DEPS=$(SV_FILES)
|
||||
|
||||
CPP_SRC=sim_$(PROJ).cpp
|
||||
|
||||
TIMESCALE= --timescale '1ns/1ns'
|
||||
|
||||
UVM_DEFINES=+define+UVM_NO_DPI \
|
||||
+define+UVM_REPORT_DISABLE_FILE_LINE
|
||||
DISABLED_WARNINGS=-Wno-WIDTHTRUNC -Wno-WIDTHEXPAND \
|
||||
-Wno-CASTCONST -Wno-CONSTRAINTIGN \
|
||||
-Wno-MISINDENT -Wno-REALCVT \
|
||||
-Wno-SYMRSVDWORD -Wno-CASEINCOMPLETE
|
||||
|
||||
BUILD_ARGS=-I$(UVM_HOME)/src -I. \
|
||||
-o $(PROJ).sim \
|
||||
-j $(NUM_PROCS) \
|
||||
--error-limit 10 \
|
||||
--timing $(TIMESCALE) \
|
||||
--trace \
|
||||
+define+SVA_ON \
|
||||
$(UVM_DEFINES) \
|
||||
$(DISABLED_WARNINGS) \
|
||||
+incdir+common +incdir+src +incdir+tb \
|
||||
$(SV_SRC)
|
||||
|
||||
ifndef TEST_NAME
|
||||
TEST_NAME=test_basic
|
||||
endif
|
||||
|
||||
#
|
||||
# Full build to generate testbench executable (Default target)
|
||||
#
|
||||
build: build_cpp
|
||||
@echo "Build done"
|
||||
|
||||
prepare_area:
|
||||
$(info #----------------)
|
||||
$(info # Preparing area)
|
||||
$(info #----------------)
|
||||
@if [ ! -d $(PROJ_BASE)/logs ]; then mkdir -p $(PROJ_BASE)/logs; fi
|
||||
|
||||
#
|
||||
# C code generation from SystemVerilog
|
||||
#
|
||||
build_sv: prepare_area $(SV_OUT)
|
||||
|
||||
$(SV_OUT): $(PROJ_BASE)/logs $(SV_DEPS)
|
||||
$(info #------------)
|
||||
$(info # Building SV)
|
||||
$(info #------------)
|
||||
@$(TIME) verilator --cc $(BUILD_ARGS) $(LOG_REDIR) $(SV_BUILD_LOG) && \
|
||||
tail -1 $(SV_BUILD_LOG)
|
||||
|
||||
#
|
||||
# C code build to generate testbench executable
|
||||
#
|
||||
build_cpp: build_sv $(CPP_OUT)
|
||||
|
||||
$(CPP_OUT): $(SV_OUT)
|
||||
$(info #-------------)
|
||||
$(info # Building CPP)
|
||||
$(info #-------------)
|
||||
@$(TIME) verilator --binary $(BUILD_ARGS) $(LOG_REDIR) $(CPP_BUILD_LOG) && \
|
||||
tail -1 $(CPP_BUILD_LOG) && \
|
||||
notify-send "[$(PROJ)] Build done"
|
||||
|
||||
#
|
||||
# Run just lint to detect syntax errors during development
|
||||
#
|
||||
lint:
|
||||
$(info #--------)
|
||||
$(info # Linting)
|
||||
$(info #--------)
|
||||
@$(TIME) verilator --lint-only $(BUILD_ARGS)
|
||||
|
||||
#
|
||||
# Run test. Use TEST_NAME=<test name> on make line to pick the test
|
||||
#
|
||||
run: $(CPP_OUT)
|
||||
$(info #---------------------)
|
||||
$(info # Running $(TEST_NAME))
|
||||
$(info #---------------------)
|
||||
@if [ ! -d runs/$(TEST_NAME) ]; then mkdir -p runs/$(TEST_NAME); fi
|
||||
@cd runs/$(TEST_NAME) && \
|
||||
$(TIME) $(PROJ_BASE)/obj_dir/$(PROJ).sim +UVM_TESTNAME=$(TEST_NAME) |& tee $(SIM_LOG)
|
||||
@notify-send "[$(PROJ)] Test run done"
|
||||
|
||||
#
|
||||
# Remove generated files
|
||||
# - This will not remove 'runs' directory that contains simulation run logs
|
||||
#
|
||||
clean:
|
||||
rm -rf obj_dir logs $(PROJ)*.log
|
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# AXI Protocol Playground
|
||||
|
||||
## Introduction
|
||||
|
||||
* There is no RTL design here. Just validation components working as both
|
||||
MANAGER and SUBORDINATE parts
|
||||
|
||||
## Dependencies
|
||||
|
||||
* Verilator simulator
|
||||
* UVM that works with Verilator
|
||||
|
||||
```
|
||||
$ cd $UVM_HOME
|
||||
$ git remote -v
|
||||
origin https://github.com/antmicro/uvm-verilator.git (fetch)
|
||||
origin https://github.com/antmicro/uvm-verilator.git (push)
|
||||
$ git branch
|
||||
current-patches
|
||||
* current-patches-2
|
||||
```
|
414
common/axi.intf.sv
Normal file
414
common/axi.intf.sv
Normal file
@@ -0,0 +1,414 @@
|
||||
// Generated AXI Interface
|
||||
// This file is automatically generated by scripts/gen_axi_intf.pl
|
||||
// Do not edit this file directly.
|
||||
//
|
||||
// Interface Name: AXI Signal List
|
||||
interface axi_intf #(
|
||||
parameter ADDR_WIDTH = 1,
|
||||
parameter ARSNOOP_WIDTH = 1,
|
||||
parameter AWCMO_WIDTH = 1,
|
||||
parameter AWSNOOP_WIDTH = 1,
|
||||
parameter BRESP_WIDTH = 1,
|
||||
parameter CEIL_DATA_WIDTH_DIV_128 = 1,
|
||||
parameter CEIL_DATA_WIDTH_DIV_128_TMS_4 = 1,
|
||||
parameter CEIL_DATA_WIDTH_DIV_64 = 1,
|
||||
parameter DATA_WIDTH = 1,
|
||||
parameter DATA_WIDTH_DIV_8 = 1,
|
||||
parameter ID_R_WIDTH = 1,
|
||||
parameter ID_W_WIDTH = 1,
|
||||
parameter LOOP_R_WIDTH = 1,
|
||||
parameter LOOP_W_WIDTH = 1,
|
||||
parameter MECID_WIDTH = 1,
|
||||
parameter MPAM_WIDTH = 1,
|
||||
parameter RCHUNKNUM_WIDTH = 1,
|
||||
parameter RCHUNKSTRB_WIDTH = 1,
|
||||
parameter RRESP_WIDTH = 1,
|
||||
parameter SECSID_WIDTH = 1,
|
||||
parameter SID_WIDTH = 1,
|
||||
parameter SSID_WIDTH = 1,
|
||||
parameter SUBSYSID_WIDTH = 1,
|
||||
parameter SUM_USER_DATA_WIDTH_USER_RESP_WIDTH = 1,
|
||||
parameter USER_DATA_WIDTH = 1,
|
||||
parameter USER_REQ_WIDTH = 1,
|
||||
parameter USER_RESP_WIDTH = 1
|
||||
)
|
||||
|
||||
(
|
||||
input ACLK,
|
||||
input ARESETn
|
||||
);
|
||||
|
||||
// A2.4.1 Clock and reset signals
|
||||
// External signal: ACLK; // External Global clock signal [External]
|
||||
// External signal: ARESETn; // External Global reset signal [External]
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
logic AWVALID; // Valid indicator [Manager]
|
||||
logic AWREADY; // Ready indicator [Subordinate]
|
||||
logic [ID_W_WIDTH-1:0] AWID; // Transaction identifier for the write channels [Manager]
|
||||
logic [ADDR_WIDTH-1:0] AWADDR; // Transaction address [Manager]
|
||||
logic [3:0] AWREGION; // Region identifier [Manager]
|
||||
logic [7:0] AWLEN; // Transaction length [Manager]
|
||||
logic [2:0] AWSIZE; // Transaction size [Manager]
|
||||
logic [1:0] AWBURST; // Burst attribute [Manager]
|
||||
logic AWLOCK; // Exclusive access indicator [Manager]
|
||||
logic [3:0] AWCACHE; // Memory attributes [Manager]
|
||||
logic [2:0] AWPROT; // Access attributes [Manager]
|
||||
logic AWNSE; // Non-secure extension bit for RME [Manager]
|
||||
logic [3:0] AWQOS; // QoS identifier [Manager]
|
||||
logic [USER_REQ_WIDTH-1:0] AWUSER; // User-defined extension to a request [Manager]
|
||||
logic [1:0] AWDOMAIN; // Shareability domain of a request [Manager]
|
||||
logic [AWSNOOP_WIDTH-1:0] AWSNOOP; // Write request opcode [Manager]
|
||||
logic [10:0] AWSTASHNID; // Stash Node ID [Manager]
|
||||
logic AWSTASHNIDEN; // Stash Node ID enable [Manager]
|
||||
logic [4:0] AWSTASHLPID; // Stash Logical Processor ID [Manager]
|
||||
logic AWSTASHLPIDEN; // Stash Logical Processor ID enable [Manager]
|
||||
logic AWTRACE; // Trace signal [Manager]
|
||||
logic [LOOP_W_WIDTH-1:0] AWLOOP; // Loopback signals on the write channels [Manager]
|
||||
logic AWMMUVALID; // MMU signal qualifier [Manager]
|
||||
logic [SECSID_WIDTH-1:0] AWMMUSECSID; // Secure Stream ID [Manager]
|
||||
logic [SID_WIDTH-1:0] AWMMUSID; // StreamID [Manager]
|
||||
logic AWMMUSSIDV; // SubstreamID valid [Manager]
|
||||
logic [SSID_WIDTH-1:0] AWMMUSSID; // SubstreamID [Manager]
|
||||
logic AWMMUATST; // Address translated indicator [Manager]
|
||||
logic [1:0] AWMMUFLOW; // SMMU flow type [Manager]
|
||||
logic [3:0] AWPBHA; // Page-based Hardware Attributes [Manager]
|
||||
logic [3:0] AWNSAID; // Non-secure Access ID [Manager]
|
||||
logic [SUBSYSID_WIDTH-1:0] AWSUBSYSID; // Subsystem ID [Manager]
|
||||
logic [5:0] AWATOP; // Atomic transaction opcode [Manager]
|
||||
logic [MPAM_WIDTH-1:0] AWMPAM; // MPAM information with a request [Manager]
|
||||
logic AWIDUNQ; // Unique ID indicator [Manager]
|
||||
logic [AWCMO_WIDTH-1:0] AWCMO; // CMO type [Manager]
|
||||
logic [1:0] AWTAGOP; // Memory Tag operation for write requests [Manager]
|
||||
logic [MECID_WIDTH-1:0] AWMECID; // Memory Encryption Context identifier [Manager]
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
logic WVALID; // Valid indicator [Manager]
|
||||
logic WREADY; // Ready indicator [Subordinate]
|
||||
logic [DATA_WIDTH-1:0] WDATA; // Write data [Manager]
|
||||
logic [DATA_WIDTH_DIV_8-1:0] WSTRB; // Write data strobes [Manager]
|
||||
logic [CEIL_DATA_WIDTH_DIV_128_TMS_4-1:0] WTAG; // Memory Tag [Manager]
|
||||
logic [CEIL_DATA_WIDTH_DIV_128-1:0] WTAGUPDATE; // Memory Tag update [Manager]
|
||||
logic WLAST; // Last write data [Manager]
|
||||
logic [USER_DATA_WIDTH-1:0] WUSER; // User-defined extension to write data [Manager]
|
||||
logic [CEIL_DATA_WIDTH_DIV_64-1:0] WPOISON; // Poison indicator [Manager]
|
||||
logic WTRACE; // Trace signal [Manager]
|
||||
|
||||
// A2.1.3 Write response channel
|
||||
logic BVALID; // Valid indicator [Subordinate]
|
||||
logic BREADY; // Ready indicator [Manager]
|
||||
logic [ID_W_WIDTH-1:0] BID; // Transaction identifier for the write channels [Subordinate]
|
||||
logic BIDUNQ; // Unique ID indicator [Subordinate]
|
||||
logic [BRESP_WIDTH-1:0] BRESP; // Write response code [Subordinate]
|
||||
logic BCOMP; // Completion response indicator [Subordinate]
|
||||
logic BPERSIST; // Persist response [Subordinate]
|
||||
logic [1:0] BTAGMATCH; // Memory Tag Match response [Subordinate]
|
||||
logic [USER_RESP_WIDTH-1:0] BUSER; // User-defined extension to a write response [Subordinate]
|
||||
logic BTRACE; // Trace signal [Subordinate]
|
||||
logic [LOOP_W_WIDTH-1:0] BLOOP; // Loopback signals on the write channels [Subordinate]
|
||||
logic [1:0] BBUSY; // Busy indicator [Subordinate]
|
||||
|
||||
// A2.2.1 Read request channel
|
||||
logic ARVALID; // Valid indicator [Manager]
|
||||
logic ARREADY; // Ready indicator [Subordinate]
|
||||
logic [ID_R_WIDTH-1:0] ARID; // Transaction identifier for the read channels [Manager]
|
||||
logic [ADDR_WIDTH-1:0] ARADDR; // Transaction address [Manager]
|
||||
logic [3:0] ARREGION; // Region identifier [Manager]
|
||||
logic [7:0] ARLEN; // Transaction length [Manager]
|
||||
logic [2:0] ARSIZE; // Transaction size [Manager]
|
||||
logic [1:0] ARBURST; // Burst attribute [Manager]
|
||||
logic ARLOCK; // Exclusive access indicator [Manager]
|
||||
logic [3:0] ARCACHE; // Memory attributes [Manager]
|
||||
logic [2:0] ARPROT; // Access attributes [Manager]
|
||||
logic ARNSE; // Non-secure extension bit for RME [Manager]
|
||||
logic [3:0] ARQOS; // QoS identifier [Manager]
|
||||
logic [USER_REQ_WIDTH-1:0] ARUSER; // User-defined extension to a request [Manager]
|
||||
logic [1:0] ARDOMAIN; // Shareability domain of a request [Manager]
|
||||
logic [ARSNOOP_WIDTH-1:0] ARSNOOP; // Read request opcode [Manager]
|
||||
logic ARTRACE; // Trace signal [Manager]
|
||||
logic [LOOP_R_WIDTH-1:0] ARLOOP; // Loopback signals on the read channels [Manager]
|
||||
logic ARMMUVALID; // MMU signal qualifier [Manager]
|
||||
logic [SECSID_WIDTH-1:0] ARMMUSECSID; // Secure Stream ID [Manager]
|
||||
logic [SID_WIDTH-1:0] ARMMUSID; // StreamID [Manager]
|
||||
logic ARMMUSSIDV; // SubstreamID valid [Manager]
|
||||
logic [SSID_WIDTH-1:0] ARMMUSSID; // SubstreamID [Manager]
|
||||
logic ARMMUATST; // Address translated indicator [Manager]
|
||||
logic [1:0] ARMMUFLOW; // SMMU flow type [Manager]
|
||||
logic [3:0] ARPBHA; // Page-based Hardware Attributes [Manager]
|
||||
logic [3:0] ARNSAID; // Non-secure Access ID [Manager]
|
||||
logic [SUBSYSID_WIDTH-1:0] ARSUBSYSID; // Subsystem ID [Manager]
|
||||
logic ARCHUNKEN; // Read data chunking enable [Manager]
|
||||
logic ARIDUNQ; // Unique ID indicator [Manager]
|
||||
logic [1:0] ARTAGOP; // Memory Tag operation for read requests [Manager]
|
||||
logic [MECID_WIDTH-1:0] ARMECID; // Memory Encryption Context identifier [Manager]
|
||||
|
||||
// A2.2.2 Read data channel
|
||||
logic RVALID; // Valid indicator [Subordinate]
|
||||
logic RREADY; // Ready indicator [Manager]
|
||||
logic [ID_R_WIDTH-1:0] RID; // Transaction identifier for the read channels [Subordinate]
|
||||
logic RIDUNQ; // Unique ID indicator [Subordinate]
|
||||
logic [DATA_WIDTH-1:0] RDATA; // Read data [Subordinate]
|
||||
logic [CEIL_DATA_WIDTH_DIV_128_TMS_4-1:0] RTAG; // Memory Tag [Subordinate]
|
||||
logic [RRESP_WIDTH-1:0] RRESP; // Read response [Subordinate]
|
||||
logic RLAST; // Last read data [Subordinate]
|
||||
logic [SUM_USER_DATA_WIDTH_USER_RESP_WIDTH-1:0] RUSER; // User-defined extension to read data and response [Subordinate]
|
||||
logic [CEIL_DATA_WIDTH_DIV_64-1:0] RPOISON; // Poison indicator [Subordinate]
|
||||
logic RTRACE; // Trace signal [Subordinate]
|
||||
logic [LOOP_R_WIDTH-1:0] RLOOP; // Loopback signals on the read channels [Subordinate]
|
||||
logic RCHUNKV; // Read data chunking valid [Subordinate]
|
||||
logic [RCHUNKNUM_WIDTH-1:0] RCHUNKNUM; // Read data chunk number [Subordinate]
|
||||
logic [RCHUNKSTRB_WIDTH-1:0] RCHUNKSTRB; // Read data chunk strobe [Subordinate]
|
||||
logic [1:0] RBUSY; // Busy indicator [Subordinate]
|
||||
|
||||
// Modport for Manager role
|
||||
modport MANAGER (
|
||||
|
||||
// A2.4.1 Clock and reset signals
|
||||
input ACLK,
|
||||
input ARESETn,
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
output AWVALID,
|
||||
input AWREADY,
|
||||
output AWID,
|
||||
output AWADDR,
|
||||
output AWREGION,
|
||||
output AWLEN,
|
||||
output AWSIZE,
|
||||
output AWBURST,
|
||||
output AWLOCK,
|
||||
output AWCACHE,
|
||||
output AWPROT,
|
||||
output AWNSE,
|
||||
output AWQOS,
|
||||
output AWUSER,
|
||||
output AWDOMAIN,
|
||||
output AWSNOOP,
|
||||
output AWSTASHNID,
|
||||
output AWSTASHNIDEN,
|
||||
output AWSTASHLPID,
|
||||
output AWSTASHLPIDEN,
|
||||
output AWTRACE,
|
||||
output AWLOOP,
|
||||
output AWMMUVALID,
|
||||
output AWMMUSECSID,
|
||||
output AWMMUSID,
|
||||
output AWMMUSSIDV,
|
||||
output AWMMUSSID,
|
||||
output AWMMUATST,
|
||||
output AWMMUFLOW,
|
||||
output AWPBHA,
|
||||
output AWNSAID,
|
||||
output AWSUBSYSID,
|
||||
output AWATOP,
|
||||
output AWMPAM,
|
||||
output AWIDUNQ,
|
||||
output AWCMO,
|
||||
output AWTAGOP,
|
||||
output AWMECID,
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
output WVALID,
|
||||
input WREADY,
|
||||
output WDATA,
|
||||
output WSTRB,
|
||||
output WTAG,
|
||||
output WTAGUPDATE,
|
||||
output WLAST,
|
||||
output WUSER,
|
||||
output WPOISON,
|
||||
output WTRACE,
|
||||
|
||||
// A2.1.3 Write response channel
|
||||
input BVALID,
|
||||
output BREADY,
|
||||
input BID,
|
||||
input BIDUNQ,
|
||||
input BRESP,
|
||||
input BCOMP,
|
||||
input BPERSIST,
|
||||
input BTAGMATCH,
|
||||
input BUSER,
|
||||
input BTRACE,
|
||||
input BLOOP,
|
||||
input BBUSY,
|
||||
|
||||
// A2.2.1 Read request channel
|
||||
output ARVALID,
|
||||
input ARREADY,
|
||||
output ARID,
|
||||
output ARADDR,
|
||||
output ARREGION,
|
||||
output ARLEN,
|
||||
output ARSIZE,
|
||||
output ARBURST,
|
||||
output ARLOCK,
|
||||
output ARCACHE,
|
||||
output ARPROT,
|
||||
output ARNSE,
|
||||
output ARQOS,
|
||||
output ARUSER,
|
||||
output ARDOMAIN,
|
||||
output ARSNOOP,
|
||||
output ARTRACE,
|
||||
output ARLOOP,
|
||||
output ARMMUVALID,
|
||||
output ARMMUSECSID,
|
||||
output ARMMUSID,
|
||||
output ARMMUSSIDV,
|
||||
output ARMMUSSID,
|
||||
output ARMMUATST,
|
||||
output ARMMUFLOW,
|
||||
output ARPBHA,
|
||||
output ARNSAID,
|
||||
output ARSUBSYSID,
|
||||
output ARCHUNKEN,
|
||||
output ARIDUNQ,
|
||||
output ARTAGOP,
|
||||
output ARMECID,
|
||||
|
||||
// A2.2.2 Read data channel
|
||||
input RVALID,
|
||||
output RREADY,
|
||||
input RID,
|
||||
input RIDUNQ,
|
||||
input RDATA,
|
||||
input RTAG,
|
||||
input RRESP,
|
||||
input RLAST,
|
||||
input RUSER,
|
||||
input RPOISON,
|
||||
input RTRACE,
|
||||
input RLOOP,
|
||||
input RCHUNKV,
|
||||
input RCHUNKNUM,
|
||||
input RCHUNKSTRB,
|
||||
input RBUSY
|
||||
);
|
||||
|
||||
// Modport for Subordinate role
|
||||
modport SUBORDINATE (
|
||||
|
||||
// A2.4.1 Clock and reset signals
|
||||
input ACLK,
|
||||
input ARESETn,
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
input AWVALID,
|
||||
output AWREADY,
|
||||
input AWID,
|
||||
input AWADDR,
|
||||
input AWREGION,
|
||||
input AWLEN,
|
||||
input AWSIZE,
|
||||
input AWBURST,
|
||||
input AWLOCK,
|
||||
input AWCACHE,
|
||||
input AWPROT,
|
||||
input AWNSE,
|
||||
input AWQOS,
|
||||
input AWUSER,
|
||||
input AWDOMAIN,
|
||||
input AWSNOOP,
|
||||
input AWSTASHNID,
|
||||
input AWSTASHNIDEN,
|
||||
input AWSTASHLPID,
|
||||
input AWSTASHLPIDEN,
|
||||
input AWTRACE,
|
||||
input AWLOOP,
|
||||
input AWMMUVALID,
|
||||
input AWMMUSECSID,
|
||||
input AWMMUSID,
|
||||
input AWMMUSSIDV,
|
||||
input AWMMUSSID,
|
||||
input AWMMUATST,
|
||||
input AWMMUFLOW,
|
||||
input AWPBHA,
|
||||
input AWNSAID,
|
||||
input AWSUBSYSID,
|
||||
input AWATOP,
|
||||
input AWMPAM,
|
||||
input AWIDUNQ,
|
||||
input AWCMO,
|
||||
input AWTAGOP,
|
||||
input AWMECID,
|
||||
|
||||
// A2.1.1 Write request channel
|
||||
input WVALID,
|
||||
output WREADY,
|
||||
input WDATA,
|
||||
input WSTRB,
|
||||
input WTAG,
|
||||
input WTAGUPDATE,
|
||||
input WLAST,
|
||||
input WUSER,
|
||||
input WPOISON,
|
||||
input WTRACE,
|
||||
|
||||
// A2.1.3 Write response channel
|
||||
output BVALID,
|
||||
input BREADY,
|
||||
output BID,
|
||||
output BIDUNQ,
|
||||
output BRESP,
|
||||
output BCOMP,
|
||||
output BPERSIST,
|
||||
output BTAGMATCH,
|
||||
output BUSER,
|
||||
output BTRACE,
|
||||
output BLOOP,
|
||||
output BBUSY,
|
||||
|
||||
// A2.2.1 Read request channel
|
||||
input ARVALID,
|
||||
output ARREADY,
|
||||
input ARID,
|
||||
input ARADDR,
|
||||
input ARREGION,
|
||||
input ARLEN,
|
||||
input ARSIZE,
|
||||
input ARBURST,
|
||||
input ARLOCK,
|
||||
input ARCACHE,
|
||||
input ARPROT,
|
||||
input ARNSE,
|
||||
input ARQOS,
|
||||
input ARUSER,
|
||||
input ARDOMAIN,
|
||||
input ARSNOOP,
|
||||
input ARTRACE,
|
||||
input ARLOOP,
|
||||
input ARMMUVALID,
|
||||
input ARMMUSECSID,
|
||||
input ARMMUSID,
|
||||
input ARMMUSSIDV,
|
||||
input ARMMUSSID,
|
||||
input ARMMUATST,
|
||||
input ARMMUFLOW,
|
||||
input ARPBHA,
|
||||
input ARNSAID,
|
||||
input ARSUBSYSID,
|
||||
input ARCHUNKEN,
|
||||
input ARIDUNQ,
|
||||
input ARTAGOP,
|
||||
input ARMECID,
|
||||
|
||||
// A2.2.2 Read data channel
|
||||
output RVALID,
|
||||
input RREADY,
|
||||
output RID,
|
||||
output RIDUNQ,
|
||||
output RDATA,
|
||||
output RTAG,
|
||||
output RRESP,
|
||||
output RLAST,
|
||||
output RUSER,
|
||||
output RPOISON,
|
||||
output RTRACE,
|
||||
output RLOOP,
|
||||
output RCHUNKV,
|
||||
output RCHUNKNUM,
|
||||
output RCHUNKSTRB,
|
||||
output RBUSY
|
||||
);
|
||||
endinterface // axi_intf
|
3
common/common_pkg.sv
Normal file
3
common/common_pkg.sv
Normal file
@@ -0,0 +1,3 @@
|
||||
`include "axi.intf.sv"
|
||||
package common_pkg;
|
||||
endpackage
|
336
scripts/gen_axi_intf.pl
Executable file
336
scripts/gen_axi_intf.pl
Executable file
@@ -0,0 +1,336 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
|
||||
my $app = {};
|
||||
|
||||
get_axi_intf_data($app);
|
||||
augment_intf_data($app);
|
||||
#print Dumper($app->{'intf_data'}); # Debugging output
|
||||
|
||||
gen_intf($app);
|
||||
|
||||
# -----------------
|
||||
# Subroutines
|
||||
# -----------------
|
||||
sub gen_intf {
|
||||
my ($app) = @_;
|
||||
|
||||
print "// Generated AXI Interface\n";
|
||||
print "// This file is automatically generated by $0\n";
|
||||
print "// Do not edit this file directly.\n";
|
||||
print "//\n";
|
||||
print "// Interface Name: $app->{'intf_data'}->{'name'}\n";
|
||||
print "interface axi_intf #(\n";
|
||||
|
||||
my @plines = get_param_lines($app);
|
||||
print join(",\n", @plines);
|
||||
print "\n)\n";
|
||||
my @eplines = get_ext_ports_lines($app);
|
||||
print "\n(\n";
|
||||
print join(",\n", @eplines);
|
||||
print "\n);\n";
|
||||
|
||||
show_interface($app);
|
||||
|
||||
show_modport($app, 'Manager');
|
||||
show_modport($app, 'Subordinate');
|
||||
|
||||
print "endinterface // axi_intf\n";
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub get_param_lines {
|
||||
my ($app) = @_;
|
||||
my @plines;
|
||||
|
||||
foreach my $p (sort { $a cmp $b } keys %{$app->{'intf_data'}->{'params'}}) {
|
||||
my $param_value = $app->{'intf_data'}->{'params'}->{$p}->{'d'};
|
||||
push(@plines, sprintf(" parameter %$app->{'intf_data'}->{'info'}->{'param_width'}s = %d",
|
||||
$p, $param_value));
|
||||
}
|
||||
|
||||
return @plines;
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub get_ext_ports_lines {
|
||||
my ($app) = @_;
|
||||
my @eplines;
|
||||
|
||||
foreach my $p (sort { $a cmp $b } @{$app->{'intf_data'}->{'ext_sigs'}}) {
|
||||
push(@eplines, sprintf(" input %s",
|
||||
$p->{'n'}));
|
||||
}
|
||||
|
||||
return @eplines;
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub show_interface {
|
||||
my ($app) = @_;
|
||||
|
||||
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
||||
print "\n";
|
||||
print " // $section->{'name'}\n";
|
||||
|
||||
# Display signals
|
||||
foreach my $signal (@{$section->{'signals'}}) {
|
||||
if ($signal->{'s'} eq 'External') {
|
||||
printf " // External signal: %-$app->{'intf_data'}->{'info'}->{'sig_width'}s // $signal->{'d'} [$signal->{'s'}]\n",
|
||||
"$signal->{'n'};";
|
||||
} else {
|
||||
printf " logic %$app->{'intf_data'}->{'info'}->{'dim_width'}s %-$app->{'intf_data'}->{'info'}->{'sig_width'}s // $signal->{'d'} [$signal->{'s'}]\n",
|
||||
get_dimension($app, $signal->{'w'}), "$signal->{'n'};";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub show_modport{
|
||||
my ($app, $role) = @_;
|
||||
my $last = 0;
|
||||
|
||||
print "\n";
|
||||
print " // Modport for $role role\n";
|
||||
print " modport " . uc($role) . " (\n";
|
||||
|
||||
my $num_sections = scalar @{$app->{'intf_data'}->{'sections'}};
|
||||
my $section_count = 0;
|
||||
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
||||
print "\n";
|
||||
print " // $section->{'name'}\n";
|
||||
|
||||
$section_count++;
|
||||
|
||||
# Display signals
|
||||
my $num_signals = scalar @{$section->{'signals'}};
|
||||
my $signal_count = 0;
|
||||
foreach my $signal (@{$section->{'signals'}}) {
|
||||
# When role is Manager, signals with 'Manager' source are output, others are input
|
||||
# When role is Subordinate, signals with 'Subordinate' source are output, others are input
|
||||
my $direction = ($role eq 'Global') ? 'input' : ($role eq $signal->{'s'}) ? 'output' : 'input';
|
||||
|
||||
$signal_count++;
|
||||
|
||||
$last = 1 if ($num_signals == $signal_count && $num_sections == $section_count);
|
||||
|
||||
printf " %-8s $signal->{'n'}" . (($last == 1) ? "" : ","). "\n", $direction;
|
||||
}
|
||||
}
|
||||
print " );\n";
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub augment_intf_data {
|
||||
my ($app) = @_;
|
||||
|
||||
# Pretty print widths
|
||||
$app->{'intf_data'}->{'info'}->{'param_width'} = 0;
|
||||
$app->{'intf_data'}->{'info'}->{'dim_width'} = 0;
|
||||
$app->{'intf_data'}->{'info'}->{'sig_width'} = 0;
|
||||
|
||||
# Capture parameters from signals
|
||||
$app->{'intf_data'}->{'params'} = {};
|
||||
# Capture external signals
|
||||
$app->{'intf_data'}->{'ext_sigs'} = [];
|
||||
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
||||
foreach my $signal (@{$section->{'signals'}}) {
|
||||
my $width = $signal->{'w'};
|
||||
if ($width !~ /^\d+$/) {
|
||||
unless (exists $app->{'intf_data'}->{'params'}->{$width}) {
|
||||
$app->{'intf_data'}->{'params'}->{$width} = {
|
||||
'd' => 1, # Default value for the parameter
|
||||
};
|
||||
$app->{'intf_data'}->{'info'}->{'param_width'} = length($width)
|
||||
if (length($width) > $app->{'intf_data'}->{'info'}->{'param_width'});
|
||||
}
|
||||
}
|
||||
if ($signal->{'s'} eq 'External') {
|
||||
push(@{$app->{'intf_data'}->{'ext_sigs'}}, $signal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Find the maximum width of the parameters
|
||||
foreach my $section (@{$app->{'intf_data'}->{'sections'}}) {
|
||||
|
||||
foreach my $signal (@{$section->{'signals'}}) {
|
||||
$app->{'intf_data'}->{'info'}->{'dim_width'} = length(get_dimension($app, $signal->{'w'}))
|
||||
if (length(get_dimension($app, $signal->{'w'})) > $app->{'intf_data'}->{'info'}->{'dim_width'});
|
||||
$app->{'intf_data'}->{'info'}->{'sig_width'} = length($signal->{'n'})
|
||||
if (length($signal->{'n'}) > $app->{'intf_data'}->{'info'}->{'sig_width'});
|
||||
}
|
||||
$app->{'intf_data'}->{'info'}->{'sig_width'} += 1; # Account for the semi-colon
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub get_dimension {
|
||||
my ($app, $width) = @_;
|
||||
|
||||
if ($width =~ /^\d+$/) {
|
||||
if ($width == 1) {
|
||||
return ""; # Single bit width
|
||||
} else {
|
||||
return "[" . ($width-1) . ":0]"; # Specific width
|
||||
}
|
||||
} else {
|
||||
return "[$width-1:0]"; # Width parameter
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------
|
||||
sub get_axi_intf_data {
|
||||
my ($app) = @_;
|
||||
|
||||
$app->{'intf_data'} = {
|
||||
'name' => "AXI Signal List",
|
||||
'sections' =>
|
||||
[
|
||||
{
|
||||
'name' => 'A2.4.1 Clock and reset signals',
|
||||
'signals' => [
|
||||
{ 'n' => 'ACLK', 'w' => '1', 's' => 'External', 'd' => 'External Global clock signal'},
|
||||
{ 'n' => 'ARESETn', 'w' => '1', 's' => 'External', 'd' => 'External Global reset signal'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'name' => 'A2.1.1 Write request channel',
|
||||
'signals' => [
|
||||
# n: name, w: width, s: source, d: description
|
||||
{'n' =>'AWVALID','w' =>'1','s' =>'Manager','d' =>'Valid indicator' },
|
||||
{'n' =>'AWREADY','w' =>'1','s' =>'Subordinate','d' =>'Ready indicator' },
|
||||
{'n' =>'AWID','w' =>'ID_W_WIDTH','s' =>'Manager','d' =>'Transaction identifier for the write channels' },
|
||||
{'n' =>'AWADDR','w' =>'ADDR_WIDTH','s' =>'Manager','d' =>'Transaction address' },
|
||||
{'n' =>'AWREGION','w' =>'4','s' =>'Manager','d' =>'Region identifier' },
|
||||
{'n' =>'AWLEN','w' =>'8','s' =>'Manager','d' =>'Transaction length' },
|
||||
{'n' =>'AWSIZE','w' =>'3','s' =>'Manager','d' =>'Transaction size' },
|
||||
{'n' =>'AWBURST','w' =>'2','s' =>'Manager','d' =>'Burst attribute' },
|
||||
{'n' =>'AWLOCK','w' =>'1','s' =>'Manager','d' =>'Exclusive access indicator' },
|
||||
{'n' =>'AWCACHE','w' =>'4','s' =>'Manager','d' =>'Memory attributes' },
|
||||
{'n' =>'AWPROT','w' =>'3','s' =>'Manager','d' =>'Access attributes' },
|
||||
{'n' =>'AWNSE','w' =>'1','s' =>'Manager','d' =>'Non-secure extension bit for RME' },
|
||||
{'n' =>'AWQOS','w' =>'4','s' =>'Manager','d' =>'QoS identifier' },
|
||||
{'n' =>'AWUSER','w' =>'USER_REQ_WIDTH','s' =>'Manager','d' =>'User-defined extension to a request' },
|
||||
{'n' =>'AWDOMAIN','w' =>'2','s' =>'Manager','d' =>'Shareability domain of a request' },
|
||||
{'n' =>'AWSNOOP','w' =>'AWSNOOP_WIDTH','s' =>'Manager','d' =>'Write request opcode' },
|
||||
{'n' =>'AWSTASHNID','w' =>'11','s' =>'Manager','d' =>'Stash Node ID' },
|
||||
{'n' =>'AWSTASHNIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Node ID enable' },
|
||||
{'n' =>'AWSTASHLPID','w' =>'5','s' =>'Manager','d' =>'Stash Logical Processor ID' },
|
||||
{'n' =>'AWSTASHLPIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Logical Processor ID enable' },
|
||||
{'n' =>'AWTRACE','w' =>'1','s' =>'Manager','d' =>'Trace signal' },
|
||||
{'n' =>'AWLOOP','w' =>'LOOP_W_WIDTH','s' =>'Manager','d' =>'Loopback signals on the write channels' },
|
||||
{'n' =>'AWMMUVALID','w' =>'1','s' =>'Manager','d' =>'MMU signal qualifier' },
|
||||
{'n' =>'AWMMUSECSID','w' =>'SECSID_WIDTH','s' =>'Manager','d' =>'Secure Stream ID' },
|
||||
{'n' =>'AWMMUSID','w' =>'SID_WIDTH','s' =>'Manager','d' =>'StreamID' },
|
||||
{'n' =>'AWMMUSSIDV','w' =>'1','s' =>'Manager','d' =>'SubstreamID valid' },
|
||||
{'n' =>'AWMMUSSID','w' =>'SSID_WIDTH','s' =>'Manager','d' =>'SubstreamID' },
|
||||
{'n' =>'AWMMUATST','w' =>'1','s' =>'Manager','d' =>'Address translated indicator' },
|
||||
{'n' =>'AWMMUFLOW','w' =>'2','s' =>'Manager','d' =>'SMMU flow type' },
|
||||
{'n' =>'AWPBHA','w' =>'4','s' =>'Manager','d' =>'Page-based Hardware Attributes' },
|
||||
{'n' =>'AWNSAID','w' =>'4','s' =>'Manager','d' =>'Non-secure Access ID' },
|
||||
{'n' =>'AWSUBSYSID','w' =>'SUBSYSID_WIDTH','s' =>'Manager','d' =>'Subsystem ID' },
|
||||
{'n' =>'AWATOP','w' =>'6','s' =>'Manager','d' =>'Atomic transaction opcode' },
|
||||
{'n' =>'AWMPAM','w' =>'MPAM_WIDTH','s' =>'Manager','d' =>'MPAM information with a request' },
|
||||
{'n' =>'AWIDUNQ','w' =>'1','s' =>'Manager','d' =>'Unique ID indicator' },
|
||||
{'n' =>'AWCMO','w' =>'AWCMO_WIDTH','s' =>'Manager','d' =>'CMO type' },
|
||||
{'n' =>'AWTAGOP','w' =>'2','s' =>'Manager','d' =>'Memory Tag operation for write requests' },
|
||||
{'n' =>'AWMECID','w' =>'MECID_WIDTH','s' =>'Manager','d' =>'Memory Encryption Context identifier' },
|
||||
]
|
||||
},
|
||||
{
|
||||
'name' => 'A2.1.1 Write request channel',
|
||||
'signals' => [
|
||||
{ 'n' => 'WVALID', 'w' => '1', 's' => 'Manager', 'd' => 'Valid indicator' },
|
||||
{ 'n' => 'WREADY', 'w' => '1', 's' => 'Subordinate', 'd' => 'Ready indicator' },
|
||||
{ 'n' => 'WDATA', 'w' => 'DATA_WIDTH', 's' => 'Manager', 'd' => 'Write data' },
|
||||
{ 'n' => 'WSTRB', 'w' => 'DATA_WIDTH_DIV_8', 's' => 'Manager', 'd' => 'Write data strobes' },
|
||||
{ 'n' => 'WTAG', 'w' => 'CEIL_DATA_WIDTH_DIV_128_TMS_4', 's' => 'Manager', 'd' => 'Memory Tag' },
|
||||
{ 'n' => 'WTAGUPDATE', 'w' => 'CEIL_DATA_WIDTH_DIV_128', 's' => 'Manager', 'd' => 'Memory Tag update' },
|
||||
{ 'n' => 'WLAST', 'w' => '1', 's' => 'Manager', 'd' => 'Last write data' },
|
||||
{ 'n' => 'WUSER', 'w' => 'USER_DATA_WIDTH', 's' => 'Manager', 'd' => 'User-defined extension to write data' },
|
||||
{ 'n' => 'WPOISON', 'w' => 'CEIL_DATA_WIDTH_DIV_64', 's' => 'Manager', 'd' => 'Poison indicator' },
|
||||
{ 'n' => 'WTRACE', 'w' => '1', 's' => 'Manager', 'd' => 'Trace signal' },
|
||||
]
|
||||
},
|
||||
{
|
||||
'name' => 'A2.1.3 Write response channel',
|
||||
'signals' => [
|
||||
{ 'n' => 'BVALID', 'w' => '1', 's' => 'Subordinate', 'd' => 'Valid indicator' },
|
||||
{ 'n' => 'BREADY', 'w' => '1', 's' => 'Manager', 'd' => 'Ready indicator' },
|
||||
{ 'n' => 'BID', 'w' => 'ID_W_WIDTH', 's' => 'Subordinate', 'd' => 'Transaction identifier for the write channels' },
|
||||
{ 'n' => 'BIDUNQ', 'w' => '1', 's' => 'Subordinate', 'd' => 'Unique ID indicator' },
|
||||
{ 'n' => 'BRESP', 'w' => 'BRESP_WIDTH', 's' => 'Subordinate', 'd' => 'Write response code' },
|
||||
{ 'n' => 'BCOMP', 'w' => '1', 's' => 'Subordinate', 'd' => 'Completion response indicator' },
|
||||
{ 'n' => 'BPERSIST', 'w' => '1', 's' => 'Subordinate', 'd' => "Persist response" },
|
||||
{ 'n' => 'BTAGMATCH', 'w' => '2', 's' => 'Subordinate', 'd' => 'Memory Tag Match response' },
|
||||
{ 'n' => 'BUSER', 'w' => 'USER_RESP_WIDTH', 's' => 'Subordinate', 'd' => 'User-defined extension to a write response' },
|
||||
{ 'n' => 'BTRACE', 'w' => '1', 's' => 'Subordinate', 'd' => 'Trace signal' },
|
||||
{ 'n' => 'BLOOP', 'w' => 'LOOP_W_WIDTH', 's' => 'Subordinate', 'd' => 'Loopback signals on the write channels' },
|
||||
{ 'n' => 'BBUSY', 'w' => '2', 's' => 'Subordinate', 'd' => "Busy indicator" },
|
||||
]
|
||||
},
|
||||
{
|
||||
'name' => 'A2.2.1 Read request channel',
|
||||
'signals' => [
|
||||
{ 'n' => 'ARVALID', 'w' => '1', 's' => 'Manager', 'd' => 'Valid indicator' },
|
||||
{ 'n' => 'ARREADY', 'w' => '1', 's' => 'Subordinate', 'd' => 'Ready indicator' },
|
||||
{ 'n' => 'ARID', 'w' => 'ID_R_WIDTH', 's' => 'Manager', 'd' => 'Transaction identifier for the read channels' },
|
||||
{ 'n' => 'ARADDR', 'w' => 'ADDR_WIDTH', 's' => 'Manager', 'd' => 'Transaction address' },
|
||||
{ 'n' => 'ARREGION', 'w' => '4', 's' => 'Manager', 'd' => 'Region identifier' },
|
||||
{ 'n' => 'ARLEN', 'w' => '8', 's' => 'Manager', 'd'=> "Transaction length" },
|
||||
{ 'n' => 'ARSIZE', 'w' => '3', 's' => 'Manager', 'd' => 'Transaction size' },
|
||||
{ 'n' => 'ARBURST', 'w' => '2', 's' => 'Manager', 'd' => 'Burst attribute' },
|
||||
{ 'n' => 'ARLOCK', 'w' => '1', 's' => 'Manager', 'd' => 'Exclusive access indicator' },
|
||||
{ 'n' => 'ARCACHE', 'w' => '4', 's' => 'Manager', 'd' => 'Memory attributes' },
|
||||
{ 'n' => 'ARPROT', 'w' => '3', 's' => 'Manager', 'd' => 'Access attributes' },
|
||||
{ 'n' => 'ARNSE', 'w' => '1', 's' => 'Manager', 'd' => 'Non-secure extension bit for RME' },
|
||||
{ 'n' => 'ARQOS', 'w' => '4', 's' => 'Manager', 'd' => 'QoS identifier' },
|
||||
{ 'n' => 'ARUSER', 'w' => 'USER_REQ_WIDTH', 's' => 'Manager', 'd' => 'User-defined extension to a request' },
|
||||
{ 'n' => 'ARDOMAIN', 'w' => '2', 's' => 'Manager', 'd' => 'Shareability domain of a request' },
|
||||
{ 'n' => 'ARSNOOP', 'w' => 'ARSNOOP_WIDTH', 's' => 'Manager', 'd' => 'Read request opcode' },
|
||||
{ 'n' => 'ARTRACE', 'w' => '1', 's' => 'Manager', 'd' => 'Trace signal' },
|
||||
{ 'n' => 'ARLOOP', 'w' => 'LOOP_R_WIDTH', 's' => 'Manager', 'd' => 'Loopback signals on the read channels' },
|
||||
{ 'n' => 'ARMMUVALID', 'w' => '1', 's' => 'Manager', 'd' => 'MMU signal qualifier' },
|
||||
{ 'n' => 'ARMMUSECSID', 'w' => 'SECSID_WIDTH', 's' => 'Manager', 'd' => 'Secure Stream ID' },
|
||||
{ 'n' => 'ARMMUSID', 'w' => 'SID_WIDTH', 's' => 'Manager', 'd' => 'StreamID' },
|
||||
{ 'n' => 'ARMMUSSIDV', 'w' => '1', 's' => 'Manager', 'd' => 'SubstreamID valid' },
|
||||
{ 'n' => 'ARMMUSSID', 'w' => 'SSID_WIDTH', 's' => 'Manager', 'd' => 'SubstreamID' },
|
||||
{ 'n' => 'ARMMUATST', 'w' => '1', 's' => 'Manager', 'd' => 'Address translated indicator' },
|
||||
{ 'n' => 'ARMMUFLOW', 'w' => '2', 's' => 'Manager', 'd' => 'SMMU flow type' },
|
||||
{ 'n' => 'ARPBHA', 'w' => '4', 's' => 'Manager', 'd' => 'Page-based Hardware Attributes' },
|
||||
{ 'n' => 'ARNSAID', 'w' => '4', 's' => 'Manager', 'd' => 'Non-secure Access ID' },
|
||||
{ 'n' => 'ARSUBSYSID', 'w' => 'SUBSYSID_WIDTH', 's' => 'Manager', 'd' => 'Subsystem ID' },
|
||||
{ 'n' => 'ARCHUNKEN','w' => '1','s' => 'Manager','d' => 'Read data chunking enable'},
|
||||
{ 'n' => 'ARIDUNQ','w' => '1','s' => 'Manager','d' => 'Unique ID indicator'},
|
||||
{ 'n' => 'ARTAGOP','w' => '2','s' => 'Manager','d' => 'Memory Tag operation for read requests'},
|
||||
{ 'n' => 'ARMECID','w' => 'MECID_WIDTH','s' => 'Manager','d' => 'Memory Encryption Context identifier'},
|
||||
]
|
||||
},
|
||||
{
|
||||
'name' => 'A2.2.2 Read data channel',
|
||||
'signals' => [
|
||||
{ 'n' => 'RVALID', 'w' => '1', 's' => 'Subordinate', 'd' => 'Valid indicator' },
|
||||
{ 'n' => 'RREADY', 'w' => '1', 's' => 'Manager', 'd' => 'Ready indicator' },
|
||||
{ 'n' => 'RID', 'w' => 'ID_R_WIDTH', 's' => 'Subordinate', 'd' => 'Transaction identifier for the read channels' },
|
||||
{ 'n' => 'RIDUNQ', 'w' => '1', 's' => 'Subordinate', 'd' => 'Unique ID indicator' },
|
||||
{ 'n' => 'RDATA', 'w' => 'DATA_WIDTH', 's' => 'Subordinate', 'd' => 'Read data' },
|
||||
{ 'n' => 'RTAG', 'w' => 'CEIL_DATA_WIDTH_DIV_128_TMS_4', 's' => 'Subordinate', 'd' => 'Memory Tag' },
|
||||
{ 'n' => 'RRESP', 'w' => 'RRESP_WIDTH', 's' => 'Subordinate', 'd' => 'Read response' },
|
||||
{ 'n' => 'RLAST', 'w' => '1', 's' => 'Subordinate', 'd' => 'Last read data' },
|
||||
{ 'n' => 'RUSER', 'w' => 'SUM_USER_DATA_WIDTH_USER_RESP_WIDTH', 's' => 'Subordinate', 'd' => 'User-defined extension to read data and response' },
|
||||
{ 'n' => 'RPOISON', 'w' => 'CEIL_DATA_WIDTH_DIV_64', 's' => 'Subordinate', 'd' => 'Poison indicator' },
|
||||
{ 'n' => 'RTRACE', 'w' => '1', 's' => 'Subordinate', 'd' => 'Trace signal' },
|
||||
{ 'n' => 'RLOOP', 'w' => 'LOOP_R_WIDTH', 's' => 'Subordinate', 'd' => 'Loopback signals on the read channels' },
|
||||
{ 'n' => 'RCHUNKV','w' => '1', 's' => 'Subordinate', 'd' => 'Read data chunking valid' },
|
||||
{ 'n' => 'RCHUNKNUM', 'w' => 'RCHUNKNUM_WIDTH', 's' => 'Subordinate', 'd' => 'Read data chunk number' },
|
||||
{ 'n' => 'RCHUNKSTRB', 'w' => 'RCHUNKSTRB_WIDTH', 's' => 'Subordinate', 'd' => 'Read data chunk strobe' },
|
||||
{ 'n' => 'RBUSY', 'w' => '2', 's' => 'Subordinate', 'd' => 'Busy indicator' },
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
0
src/design_pkg.sv
Normal file
0
src/design_pkg.sv
Normal file
88
tb/axi_agent.sv
Normal file
88
tb/axi_agent.sv
Normal file
@@ -0,0 +1,88 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// Agent to operate AXI transactions
|
||||
// This agent includes a driver, monitor, and sequencer for AXI transactions
|
||||
// ----------------------------------------------------------------------
|
||||
typedef axi_sequencer;
|
||||
|
||||
class axi_agent extends uvm_agent;
|
||||
agent_type_t agent_type;
|
||||
virtual `AXI_INTF.MANAGER m_if;
|
||||
virtual `AXI_INTF.SUBORDINATE s_if;
|
||||
|
||||
// Declare the sequencer and driver
|
||||
axi_sequencer sequencer;
|
||||
axi_driver driver;
|
||||
axi_monitor monitor;
|
||||
|
||||
`uvm_component_utils_begin(axi_agent)
|
||||
`uvm_field_enum(agent_type_t, agent_type, UVM_DEFAULT)
|
||||
`uvm_component_utils_end
|
||||
|
||||
// --------------------------------------------------
|
||||
// Constructor
|
||||
function new(string name = "axi_agent", uvm_component parent = null);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set agent type
|
||||
function void set_agent_type(agent_type_t atype);
|
||||
agent_type = atype;
|
||||
`uvm_info("set_agent_type", $sformatf("Agent type set to %s", agent_type.name()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Build phase
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
sequencer = axi_sequencer::type_id::create("sequencer", this);
|
||||
driver = axi_driver::type_id::create("driver", this);
|
||||
monitor = axi_monitor::type_id::create("monitor", this);
|
||||
|
||||
// Propagete the agent type to driver and monitor
|
||||
driver.set_agent_type(agent_type);
|
||||
monitor.set_agent_type(agent_type);
|
||||
|
||||
if (agent_type == MANAGER) begin
|
||||
if (!uvm_config_db#(virtual `AXI_INTF.MANAGER)::get(this, "", "axi_dvr_vif", m_if)) begin
|
||||
`uvm_fatal("axi_agent", "AXI agent MANAGER interface not configured")
|
||||
end
|
||||
`uvm_info("axi_agent", $sformatf("Using AXI agent MANAGER interface: axi_dvr_vif"), UVM_LOW)
|
||||
end else begin // if (agent_type == SUBORDINATE) begin
|
||||
if (!uvm_config_db#(virtual `AXI_INTF.SUBORDINATE)::get(this, "", "axi_dvr_vif", s_if)) begin
|
||||
`uvm_fatal("axi_agent", "AXI agent SUBORDINATE interface not configured")
|
||||
end
|
||||
`uvm_info("axi_agent", $sformatf("Using AXI agent SUBORDINATE interface: axi_dvr_vif"), UVM_LOW)
|
||||
end
|
||||
|
||||
driver.set_virtual_intefaces(m_if, s_if);
|
||||
monitor.set_virtual_intefaces(m_if, s_if);
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Connect phase
|
||||
virtual function void connect_phase(uvm_phase phase);
|
||||
// Connect the driver to the sequencer
|
||||
driver.seq_item_port.connect(sequencer.seq_item_export);
|
||||
driver.rsp_port.connect(sequencer.rsp_export);
|
||||
// Connect the monitor to the sequencer
|
||||
// driver.rsp_port.connect(monitor.rsp_export);
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Run phase
|
||||
virtual function void run_phase(uvm_phase phase);
|
||||
`uvm_info("axi_agent", $sformatf("Running AXI agent: %s as %s",
|
||||
get_full_name(), agent_type.name()), UVM_LOW)
|
||||
endfunction
|
||||
endclass : axi_agent
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_sequencer extends uvm_sequencer;
|
||||
|
||||
`uvm_component_utils(axi_sequencer)
|
||||
|
||||
// Constructor
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
endclass : axi_sequencer
|
119
tb/axi_driver.sv
Normal file
119
tb/axi_driver.sv
Normal file
@@ -0,0 +1,119 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// Driver for AXI transactions
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_driver extends uvm_driver; // #(axi_transaction);
|
||||
virtual `AXI_INTF.MANAGER m_if;
|
||||
virtual `AXI_INTF.SUBORDINATE s_if;
|
||||
agent_type_t agent_type;
|
||||
|
||||
`uvm_component_utils(axi_driver)
|
||||
|
||||
// --------------------------------------------------
|
||||
// Constructor
|
||||
function new(string name = "axi_driver", uvm_component parent = null);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set agent type
|
||||
function void set_agent_type(agent_type_t atype);
|
||||
agent_type = atype;
|
||||
`uvm_info("set_agent_type", $sformatf("Agent type set to %s", agent_type.name()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set virtual interfaces
|
||||
function void set_virtual_intefaces(virtual `AXI_INTF.MANAGER m_if_p,
|
||||
virtual `AXI_INTF.SUBORDINATE s_if_p);
|
||||
`uvm_info("set_virtual_intefaces", $sformatf("Setting virtual interfaces"), UVM_LOW)
|
||||
|
||||
m_if = m_if_p;
|
||||
s_if = s_if_p;
|
||||
|
||||
// if (m_if == null && s_if == null) begin
|
||||
// `uvm_fatal("AXI_DRIVER", "Both MANAGER and SUBORDINATE interfaces are null")
|
||||
// end else if ((agent_type == MANAGER) && (m_if == null)) begin
|
||||
// `uvm_error("AXI_DRIVER", $sformatf("MANAGER interface is null"))
|
||||
// end else if ((agent_type == SUBORDINATE) && (s_if == null)) begin
|
||||
// `uvm_error("AXI_DRIVER", $sformatf("SUBORDINATE interface is null"))
|
||||
// end
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Run phase
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
`uvm_info("axi_driver", $sformatf("Running AXI driver: %s as %s",
|
||||
get_full_name(), agent_type.name()), UVM_LOW)
|
||||
|
||||
if (agent_type == MANAGER) begin
|
||||
`uvm_info("axi_driver", $sformatf("Manager agent detected, driving transactions"), UVM_LOW)
|
||||
drive_transactions();
|
||||
end else if (agent_type == SUBORDINATE) begin
|
||||
`uvm_info("axi_driver", $sformatf("Subordinate agent detected, responding to transactions"), UVM_LOW)
|
||||
respond_to_transactions();
|
||||
end else begin
|
||||
`uvm_fatal("AXI_DRIVER", "Unknown agent type")
|
||||
end
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
task drive_transactions();
|
||||
if (m_if == null) begin
|
||||
`uvm_error("AXI_DRIVER", "MANAGER interface is null, cannot drive transactions")
|
||||
end
|
||||
forever begin
|
||||
`uvm_info("axi_driver", $sformatf("Starting to drive transactions for %s (rst_n = %0b)",
|
||||
get_full_name(), m_if.ARESETn), UVM_LOW)
|
||||
|
||||
if (m_if.ARESETn == 0) begin
|
||||
`uvm_info("axi_driver", $sformatf("Waiting for reset to be released (rst_n = %0b)",
|
||||
m_if.ARESETn), UVM_LOW)
|
||||
@(posedge m_if.ARESETn);
|
||||
end
|
||||
|
||||
`uvm_info("axi_driver", $sformatf("Starting to drive transactions for %s (rst_n = %0b)",
|
||||
get_full_name(), m_if.ARESETn), UVM_LOW)
|
||||
|
||||
while (m_if.ARESETn != 0) begin
|
||||
uvm_sequence_item txn;
|
||||
|
||||
`uvm_info("axi_driver", $sformatf("Waiting for next transaction"), UVM_LOW)
|
||||
|
||||
seq_item_port.get_next_item(txn);
|
||||
drive_item(txn);
|
||||
seq_item_port.item_done();
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
task drive_item(uvm_sequence_item txn);
|
||||
axi_transaction req;
|
||||
|
||||
if (!$cast(req, txn)) begin
|
||||
`uvm_fatal("AXI_DRIVER", "Invalid transaction type")
|
||||
end
|
||||
|
||||
`uvm_info("drive_item", $sformatf("Driving AXI transaction:\n%s", req.sprint()), UVM_LOW)
|
||||
@(posedge m_if.ACLK);
|
||||
m_if.AWVALID = 1;
|
||||
m_if.AWADDR = req.addr;
|
||||
@(posedge m_if.ACLK);
|
||||
m_if.WDATA = req.data;
|
||||
m_if.WSTRB = req.strb;
|
||||
`uvm_info("drive_item", $sformatf("Driving AXI transaction done."), UVM_LOW)
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
task respond_to_transactions();
|
||||
forever begin
|
||||
@(posedge s_if.ARESETn);
|
||||
|
||||
while (s_if.ARESETn != 0) begin
|
||||
@(posedge s_if.ACLK);
|
||||
|
||||
@(negedge s_if.ACLK);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
endclass : axi_driver
|
117
tb/axi_monitor.sv
Normal file
117
tb/axi_monitor.sv
Normal file
@@ -0,0 +1,117 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// Monitor for AXI transactions
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_monitor extends uvm_monitor; // #(axi_transaction);
|
||||
virtual `AXI_INTF.MANAGER m_if;
|
||||
virtual `AXI_INTF.SUBORDINATE s_if;
|
||||
agent_type_t agent_type;
|
||||
|
||||
// Declare the analysis export
|
||||
uvm_analysis_port ap;
|
||||
|
||||
// Filehandle for transaction tracker file
|
||||
int trk_file;
|
||||
|
||||
`uvm_component_utils(axi_monitor)
|
||||
|
||||
// --------------------------------------------------
|
||||
// Constructor
|
||||
function new(string name = "axi_monitor", uvm_component parent = null);
|
||||
super.new(name, parent);
|
||||
ap = new("analysis_export", this);
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set agent type
|
||||
function void set_agent_type(agent_type_t atype);
|
||||
agent_type = atype;
|
||||
`uvm_info("set_agent_type", $sformatf("Agent type set to %s", agent_type.name()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Set virtual interfaces
|
||||
function void set_virtual_intefaces(virtual `AXI_INTF.MANAGER m_if_p,
|
||||
virtual `AXI_INTF.SUBORDINATE s_if_p);
|
||||
`uvm_info("set_virtual_intefaces", $sformatf("Setting virtual interfaces"), UVM_LOW)
|
||||
|
||||
m_if = m_if_p;
|
||||
s_if = s_if_p;
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Run phase
|
||||
virtual function void run_phase(uvm_phase phase);
|
||||
// Open transaction log file
|
||||
trk_file = $fopen($sformatf("axi_transactions.%s.log", agent_type.name()), "w");
|
||||
if (trk_file == 0) begin
|
||||
`uvm_error("AXI_MONITOR", "Failed to open transaction log file")
|
||||
end else begin
|
||||
`uvm_info("AXI_MONITOR", "Transaction log file opened successfully", UVM_LOW)
|
||||
end
|
||||
|
||||
// Start monitoring
|
||||
do_monitor();
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Monitor logic to capture transactions
|
||||
virtual task do_monitor();
|
||||
if (agent_type == MANAGER) begin
|
||||
do_manager_monitor();
|
||||
end else if (agent_type == SUBORDINATE) begin
|
||||
do_subordinate_monitor();
|
||||
end else begin
|
||||
`uvm_fatal("AXI_MONITOR", "Unknown agent type")
|
||||
end
|
||||
endtask
|
||||
|
||||
// --------------------------------------------------
|
||||
// Monitor logic for MANAGER agent
|
||||
virtual task do_manager_monitor();
|
||||
// Placeholder for actual monitoring logic
|
||||
// This would typically involve sampling signals and creating transactions
|
||||
forever begin
|
||||
axi_transaction txn;
|
||||
@(posedge m_if.ACLK);
|
||||
|
||||
txn = axi_transaction::type_id::create("txn");
|
||||
|
||||
// Capture transaction details here
|
||||
|
||||
ap.write(txn);
|
||||
write_transaction_to_file(txn);
|
||||
end
|
||||
endtask
|
||||
|
||||
// --------------------------------------------------
|
||||
// Monitor logic for SUBORDINATE agent
|
||||
virtual task do_subordinate_monitor();
|
||||
// Placeholder for actual monitoring logic
|
||||
// This would typically involve sampling signals and creating transactions
|
||||
forever begin
|
||||
axi_transaction txn;
|
||||
@(posedge s_if.ACLK);
|
||||
|
||||
txn = axi_transaction::type_id::create("txn");
|
||||
|
||||
// Capture transaction details here
|
||||
|
||||
ap.write(txn);
|
||||
write_transaction_to_file(txn);
|
||||
end
|
||||
endtask
|
||||
|
||||
// --------------------------------------------------
|
||||
// Report phase
|
||||
virtual function void report_phase(uvm_phase phase);
|
||||
// Report any captured transactions or statistics
|
||||
`uvm_info("axi_monitor", $sformatf("Reporting on %s",
|
||||
get_full_name()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
// --------------------------------------------------
|
||||
// Function to write captured transaction into a file
|
||||
function void write_transaction_to_file(axi_transaction txn);
|
||||
$fwrite(trk_file, "%s\n", txn.sprint());
|
||||
endfunction
|
||||
endclass : axi_monitor
|
43
tb/axi_transaction.sv
Normal file
43
tb/axi_transaction.sv
Normal file
@@ -0,0 +1,43 @@
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_transaction extends uvm_sequence_item;
|
||||
// Declare AXI transaction fields
|
||||
rand axi_transaction_type_t txn_type; // Transaction type (read/write)
|
||||
rand bit [31:0] addr; // Address
|
||||
rand bit [31:0] data; // Data
|
||||
rand bit [3:0] strb; // Byte enable
|
||||
|
||||
`uvm_object_utils_begin(axi_transaction)
|
||||
`uvm_field_enum(axi_transaction_type_t, txn_type, UVM_DEFAULT)
|
||||
`uvm_field_int(addr, UVM_DEFAULT)
|
||||
`uvm_field_int(data, UVM_DEFAULT)
|
||||
`uvm_field_int(strb, UVM_DEFAULT)
|
||||
`uvm_object_utils_end
|
||||
|
||||
// Constructor
|
||||
function new(string name = "axi_transaction");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
// Copy method for cloning
|
||||
virtual function uvm_object clone();
|
||||
axi_transaction copy;
|
||||
copy = axi_transaction::type_id::create(get_name());
|
||||
copy.txn_type = this.txn_type;
|
||||
copy.addr = this.addr;
|
||||
copy.data = this.data;
|
||||
copy.strb = this.strb;
|
||||
return copy;
|
||||
endfunction
|
||||
|
||||
// Comparison method for checking equality
|
||||
virtual function bit compare(uvm_object rhs);
|
||||
axi_transaction other;
|
||||
if (!$cast(other, rhs)) return 0; // Ensure type match
|
||||
return (this.txn_type == other.txn_type) &&
|
||||
(this.addr == other.addr) &&
|
||||
(this.data == other.data) &&
|
||||
(this.strb == other.strb);
|
||||
endfunction
|
||||
|
||||
endclass : axi_transaction
|
||||
|
40
tb/tb_env.sv
Normal file
40
tb/tb_env.sv
Normal file
@@ -0,0 +1,40 @@
|
||||
// Testbench environment for UVM-based verification
|
||||
class tb_env extends uvm_env;
|
||||
|
||||
axi_agent axi_m;
|
||||
axi_agent axi_s;
|
||||
|
||||
`uvm_component_utils(tb_env)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual function void build_phase(uvm_phase phase);
|
||||
axi_m = axi_agent::type_id::create("axi_m", this);
|
||||
axi_s = axi_agent::type_id::create("axi_s", this);
|
||||
|
||||
`uvm_info("tb_env", $sformatf("Building testbench environment: %s", get_full_name()), UVM_LOW)
|
||||
// Set agent types in AXI agents
|
||||
axi_m.set_agent_type(MANAGER);
|
||||
axi_s.set_agent_type(SUBORDINATE);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual function void connect_phase(uvm_phase phase);
|
||||
`uvm_info("tb_env", $sformatf("Connecting testbench environment: %s", get_full_name()), UVM_LOW)
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual function void report_phase(uvm_phase phase);
|
||||
`uvm_info("tb_env", $sformatf("Reporting for testbench environment: %s", get_full_name()), UVM_LOW)
|
||||
// Add any specific report phase tasks here
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function uvm_sequencer_base get_axi_m_sequencer();
|
||||
return axi_m.sequencer;
|
||||
endfunction
|
||||
endclass : tb_env
|
26
tb/tb_intf.sv
Normal file
26
tb/tb_intf.sv
Normal file
@@ -0,0 +1,26 @@
|
||||
// Testbench interface for UVM-based verification environment
|
||||
interface testbench_if (
|
||||
input clk,
|
||||
virtual axi_intf #(.ADDR_WIDTH(`ADDR_WIDTH),
|
||||
.CEIL_DATA_WIDTH_DIV_128(`CEIL_DATA_WIDTH_DIV_128),
|
||||
.CEIL_DATA_WIDTH_DIV_128_TMS_4(`CEIL_DATA_WIDTH_DIV_128_TMS_4),
|
||||
.CEIL_DATA_WIDTH_DIV_64(`CEIL_DATA_WIDTH_DIV_64),
|
||||
.DATA_WIDTH(`DATA_WIDTH),
|
||||
.DATA_WIDTH_DIV_8(`DATA_WIDTH_DIV_8)) m_if,
|
||||
virtual axi_intf #(.ADDR_WIDTH(`ADDR_WIDTH),
|
||||
.CEIL_DATA_WIDTH_DIV_128(`CEIL_DATA_WIDTH_DIV_128),
|
||||
.CEIL_DATA_WIDTH_DIV_128_TMS_4(`CEIL_DATA_WIDTH_DIV_128_TMS_4),
|
||||
.CEIL_DATA_WIDTH_DIV_64(`CEIL_DATA_WIDTH_DIV_64),
|
||||
.DATA_WIDTH(`DATA_WIDTH),
|
||||
.DATA_WIDTH_DIV_8(`DATA_WIDTH_DIV_8)) s_if);
|
||||
|
||||
logic rst_n;
|
||||
|
||||
initial begin
|
||||
forever begin
|
||||
@(clk or rst_n);
|
||||
$monitor("@%6t: %b %b ", $time,
|
||||
rst_n, clk);
|
||||
end
|
||||
end
|
||||
endinterface
|
39
tb/tb_params.sv
Normal file
39
tb/tb_params.sv
Normal file
@@ -0,0 +1,39 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// Tesbench defines
|
||||
// ----------------------------------------------------------------------
|
||||
// List of AXI parameters used in this testbench
|
||||
`define ADDR_WIDTH 32
|
||||
// `define ARSNOOP_WIDTH 1
|
||||
// `define AWCMO_WIDTH 1
|
||||
// `define AWSNOOP_WIDTH 1
|
||||
// `define BRESP_WIDTH 1
|
||||
`define CEIL_DATA_WIDTH_DIV_128 1
|
||||
`define CEIL_DATA_WIDTH_DIV_128_TMS_4 4
|
||||
`define CEIL_DATA_WIDTH_DIV_64 1
|
||||
`define DATA_WIDTH 64
|
||||
`define DATA_WIDTH_DIV_8 8
|
||||
// `define ID_R_WIDTH 1
|
||||
// `define ID_W_WIDTH 1
|
||||
// `define LOOP_R_WIDTH 1
|
||||
// `define LOOP_W_WIDTH 1
|
||||
// `define MECID_WIDTH 1
|
||||
// `define MPAM_WIDTH 1
|
||||
// `define RCHUNKNUM_WIDTH 1
|
||||
// `define RCHUNKSTRB_WIDTH 1
|
||||
// `define RRESP_WIDTH 1
|
||||
// `define SECSID_WIDTH 1
|
||||
// `define SID_WIDTH 1
|
||||
// `define SSID_WIDTH 1
|
||||
// `define SUBSYSID_WIDTH 1
|
||||
// `define SUM_USER_DATA_WIDTH_USER_RESP_WIDTH 1
|
||||
// `define USER_DATA_WIDTH 1
|
||||
// `define USER_REQ_WIDTH 1
|
||||
// `define USER_RESP_WIDTH 1
|
||||
|
||||
// Defines
|
||||
`define AXI_INTF axi_intf #(.ADDR_WIDTH(`ADDR_WIDTH), \
|
||||
.CEIL_DATA_WIDTH_DIV_128(`CEIL_DATA_WIDTH_DIV_128), \
|
||||
.CEIL_DATA_WIDTH_DIV_128_TMS_4(`CEIL_DATA_WIDTH_DIV_128_TMS_4), \
|
||||
.CEIL_DATA_WIDTH_DIV_64(`CEIL_DATA_WIDTH_DIV_64), \
|
||||
.DATA_WIDTH(`DATA_WIDTH), \
|
||||
.DATA_WIDTH_DIV_8(`DATA_WIDTH_DIV_8))
|
25
tb/tb_pkg.sv
Normal file
25
tb/tb_pkg.sv
Normal file
@@ -0,0 +1,25 @@
|
||||
`include "tb_params.sv"
|
||||
`include "tb_intf.sv"
|
||||
package tb_pkg;
|
||||
import uvm_pkg::*;
|
||||
import tb_types::*;
|
||||
|
||||
`include "uvm_macros.svh"
|
||||
|
||||
// Testbench defines
|
||||
// UVM data items
|
||||
`include "axi_transaction.sv"
|
||||
|
||||
// UVM components
|
||||
`include "axi_driver.sv"
|
||||
`include "axi_monitor.sv"
|
||||
`include "axi_agent.sv"
|
||||
`include "tb_env.sv"
|
||||
|
||||
// UVM sequences
|
||||
`include "tb_seq_base.sv"
|
||||
|
||||
// Tests
|
||||
`include "test_base.sv"
|
||||
endpackage
|
||||
`include "tb_top.sv"
|
51
tb/tb_seq_base.sv
Normal file
51
tb/tb_seq_base.sv
Normal file
@@ -0,0 +1,51 @@
|
||||
// Base sequence class for testbench sequences
|
||||
class tb_seq_base extends uvm_sequence;
|
||||
`uvm_object_utils(tb_seq_base)
|
||||
|
||||
// Constructor
|
||||
function new(string name = "tb_seq_base");
|
||||
super.new(name);
|
||||
endfunction
|
||||
endclass : tb_seq_base
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_m_seq_base extends tb_seq_base;
|
||||
tb_env env;
|
||||
|
||||
`uvm_object_utils(axi_m_seq_base)
|
||||
|
||||
// Constructor
|
||||
function new(string name = "axi_m_seq_base");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
// Task to start the sequence
|
||||
virtual task body();
|
||||
bit ok = uvm_config_db#(tb_env)::get(uvm_root::get(), "*", "env", env);
|
||||
endtask
|
||||
endclass : axi_m_seq_base
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
class axi_simple_seq extends axi_m_seq_base;
|
||||
`uvm_object_utils(axi_simple_seq)
|
||||
|
||||
// Constructor
|
||||
function new(string name = "axi_simple_seq");
|
||||
super.new(name);
|
||||
endfunction
|
||||
|
||||
// Task to start the sequence
|
||||
virtual task body();
|
||||
axi_transaction txn;
|
||||
|
||||
super.body();
|
||||
|
||||
`uvm_info("axi_simple_seq", "Starting simple AXI sequence", UVM_LOW)
|
||||
|
||||
`uvm_do(txn, env.get_axi_m_sequencer(), -1, {
|
||||
addr == 32'h0000_0000; // Example address
|
||||
data == 32'hDEAD_BEEF; // Example data
|
||||
strb == 'hf; // Example byte enable
|
||||
});
|
||||
endtask
|
||||
endclass : axi_simple_seq
|
49
tb/tb_top.sv
Normal file
49
tb/tb_top.sv
Normal file
@@ -0,0 +1,49 @@
|
||||
// Testbench top module for UVM-based verification environment
|
||||
import uvm_pkg::*;
|
||||
|
||||
module tb_top (input logic sys_clk);
|
||||
logic clk;
|
||||
logic rst_n;
|
||||
|
||||
// AXI interface for manager and subordinate
|
||||
`AXI_INTF a_if (.ACLK(clk), .ARESETn(rst_n));
|
||||
|
||||
// // Instantiate the UVM testbench interface
|
||||
// testbench_if tb_if (
|
||||
// .clk(clk),
|
||||
// .m_if(m_if),
|
||||
// .s_if(s_if)
|
||||
// );
|
||||
// assign tb_if.rst_n = rst_n;
|
||||
|
||||
// --------------------------------------------------
|
||||
initial begin
|
||||
uvm_config_db#(virtual `AXI_INTF.MANAGER)::set(uvm_root::get(), "uvm_test_top.env.axi_m", "axi_dvr_vif", a_if.MANAGER);
|
||||
uvm_config_db#(virtual `AXI_INTF.SUBORDINATE)::set(uvm_root::get(), "uvm_test_top.env.axi_s", "axi_dvr_vif", a_if.SUBORDINATE);
|
||||
|
||||
run_test();
|
||||
end
|
||||
|
||||
// --------------------------------------------------
|
||||
initial begin
|
||||
$dumpfile("wave.vcd");
|
||||
$dumpvars();
|
||||
end
|
||||
|
||||
// --------------------------------------------------
|
||||
// Clock generation
|
||||
// TODO: Move to interface. Parameterize frequency
|
||||
initial begin
|
||||
clk = 0; // Initialize clock to 0 at time 0
|
||||
forever begin
|
||||
#5ns clk = ~clk; // Toggle clock every 5 ns
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------------------------------------
|
||||
initial begin
|
||||
rst_n = 0;
|
||||
|
||||
#20ns rst_n = 1; // Release reset after 20 ns
|
||||
end
|
||||
endmodule
|
13
tb/tb_types.sv
Normal file
13
tb/tb_types.sv
Normal file
@@ -0,0 +1,13 @@
|
||||
// Types
|
||||
package tb_types;
|
||||
// Agent type
|
||||
typedef enum {
|
||||
MANAGER,
|
||||
SUBORDINATE
|
||||
} agent_type_t;
|
||||
|
||||
typedef enum {
|
||||
AXI_READ,
|
||||
AXI_WRITE
|
||||
} axi_transaction_type_t;
|
||||
endpackage
|
129
tb/test_base.sv
Normal file
129
tb/test_base.sv
Normal file
@@ -0,0 +1,129 @@
|
||||
// Base class for testbench tests
|
||||
class test_base extends uvm_test;
|
||||
`uvm_component_utils(test_base)
|
||||
|
||||
tb_env env;
|
||||
uvm_table_printer tb_printer;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function void build_phase(uvm_phase phase);
|
||||
super.build_phase(phase);
|
||||
|
||||
env = tb_env::type_id::create("env", this);
|
||||
tb_printer = new("tb_printer");
|
||||
|
||||
uvm_config_db#(tb_env)::set(uvm_root::get(), "*", "env", env);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual function void end_of_elaboration_phase(uvm_phase phase);
|
||||
`uvm_info("end_of_elaboration_phase", $sformatf("Testbench topology:\n%s", this.sprint(tb_printer)), UVM_LOW)
|
||||
display_uvm_config_db();
|
||||
display_uvm_config_db("uvm_test_top.env.axi_m");
|
||||
display_uvm_config_db("uvm_test_top.env.axi_s");
|
||||
dump_uvm_config_db();
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual task run_phase(uvm_phase phase);
|
||||
uvm_objection objection;
|
||||
|
||||
objection = phase.get_objection();
|
||||
|
||||
`uvm_info("run_phase", $sformatf("Raising objection"), UVM_LOW)
|
||||
phase.raise_objection(this);
|
||||
|
||||
run_reset_phase(phase);
|
||||
|
||||
run_test_phase(phase);
|
||||
|
||||
run_flush_phase(phase);
|
||||
|
||||
objection.set_drain_time(this, 20);
|
||||
`uvm_info("run_phase", $sformatf("Dropping objection"), UVM_LOW)
|
||||
phase.drop_objection(this);
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual task run_reset_phase(uvm_phase phase);
|
||||
`uvm_info("run_reset_phase", $sformatf("Starting reset"), UVM_LOW)
|
||||
`uvm_info("run_reset_phase", $sformatf("Finishing reset"), UVM_LOW)
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual task run_test_phase(uvm_phase phase);
|
||||
`uvm_warning("run_test_phase", $sformatf("This content is expected to be implemented in specific tests"))
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual task run_flush_phase(uvm_phase phase);
|
||||
`uvm_info("run_flush_phase", $sformatf("Finishing test"), UVM_LOW)
|
||||
endtask
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Function to traverse and display all entries in uvm_config_db
|
||||
function void display_uvm_config_db(string scope = ".*");
|
||||
uvm_resource_pool rp = uvm_resource_pool::get();
|
||||
uvm_resource_types::rsrc_q_t resources;
|
||||
|
||||
// Get all resources from the resource pool
|
||||
resources = rp.lookup_regex(scope, get_full_name());
|
||||
|
||||
rp.print_resources(resources, 1);
|
||||
|
||||
`uvm_info("CONFIG_DB", "Traversing uvm_config_db contents:", UVM_LOW)
|
||||
if (resources.size() == 0) begin
|
||||
`uvm_info("CONFIG_DB", "No entries found in uvm_config_db", UVM_LOW)
|
||||
return;
|
||||
end
|
||||
|
||||
// Iterate through all resources
|
||||
do begin
|
||||
uvm_resource_base r = resources.pop_front();
|
||||
|
||||
if (r == null) begin
|
||||
`uvm_info("CONFIG_DB", "No more resources to process", UVM_LOW)
|
||||
break;
|
||||
end
|
||||
|
||||
`uvm_info("CONFIG_DB", $sformatf("Resource: %s", r.get_name()), UVM_LOW)
|
||||
end while (1);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Function to dump all entries in uvm_config_db
|
||||
function void dump_uvm_config_db();
|
||||
uvm_resource_pool rp = uvm_resource_pool::get();
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
class test_basic extends test_base;
|
||||
`uvm_component_utils(test_basic)
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function new(string name, uvm_component parent);
|
||||
super.new(name, parent);
|
||||
endfunction
|
||||
|
||||
// ------------------------------------------------------------
|
||||
virtual task run_test_phase(uvm_phase phase);
|
||||
axi_simple_seq seq;
|
||||
|
||||
`uvm_info("run_test_phase", $sformatf("Starting stimulus"), UVM_LOW)
|
||||
#100ns;
|
||||
seq = axi_simple_seq::type_id::create("seq");
|
||||
if (seq == null) begin
|
||||
`uvm_fatal("run_test_phase", "Failed to create sequence instance")
|
||||
end
|
||||
seq.start(env.get_axi_m_sequencer());
|
||||
|
||||
`uvm_info("run_test_phase", $sformatf("Finishing stimulus"), UVM_LOW)
|
||||
endtask
|
||||
endclass
|
Reference in New Issue
Block a user