commit 800e9c40080d1b4fc1b2bdb51e20b5f605e8a25a Author: Mahesh Asolkar Date: Sat Aug 23 14:34:23 2025 -0700 Initial commit * Bare skeleton implementation of everything * Testbench builds with Verilator * Test runs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6674592 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +obj_dir +runs +logs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dfa20c4 --- /dev/null +++ b/Makefile @@ -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= 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 diff --git a/Makefile.details b/Makefile.details new file mode 100644 index 0000000..511e938 --- /dev/null +++ b/Makefile.details @@ -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= 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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ca70ae --- /dev/null +++ b/README.md @@ -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 +``` diff --git a/common/axi.intf.sv b/common/axi.intf.sv new file mode 100644 index 0000000..239bde1 --- /dev/null +++ b/common/axi.intf.sv @@ -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 diff --git a/common/common_pkg.sv b/common/common_pkg.sv new file mode 100644 index 0000000..903cdb5 --- /dev/null +++ b/common/common_pkg.sv @@ -0,0 +1,3 @@ +`include "axi.intf.sv" +package common_pkg; +endpackage diff --git a/scripts/gen_axi_intf.pl b/scripts/gen_axi_intf.pl new file mode 100755 index 0000000..9efbf85 --- /dev/null +++ b/scripts/gen_axi_intf.pl @@ -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' }, + ] + }, + ] + } +} diff --git a/src/design_pkg.sv b/src/design_pkg.sv new file mode 100644 index 0000000..e69de29 diff --git a/tb/axi_agent.sv b/tb/axi_agent.sv new file mode 100644 index 0000000..bc243ae --- /dev/null +++ b/tb/axi_agent.sv @@ -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 diff --git a/tb/axi_driver.sv b/tb/axi_driver.sv new file mode 100644 index 0000000..9dd20f2 --- /dev/null +++ b/tb/axi_driver.sv @@ -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 diff --git a/tb/axi_monitor.sv b/tb/axi_monitor.sv new file mode 100644 index 0000000..d9b3a8b --- /dev/null +++ b/tb/axi_monitor.sv @@ -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 diff --git a/tb/axi_transaction.sv b/tb/axi_transaction.sv new file mode 100644 index 0000000..d76597c --- /dev/null +++ b/tb/axi_transaction.sv @@ -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 + diff --git a/tb/tb_env.sv b/tb/tb_env.sv new file mode 100644 index 0000000..54882a2 --- /dev/null +++ b/tb/tb_env.sv @@ -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 diff --git a/tb/tb_intf.sv b/tb/tb_intf.sv new file mode 100644 index 0000000..75d3855 --- /dev/null +++ b/tb/tb_intf.sv @@ -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 diff --git a/tb/tb_params.sv b/tb/tb_params.sv new file mode 100644 index 0000000..7310759 --- /dev/null +++ b/tb/tb_params.sv @@ -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)) diff --git a/tb/tb_pkg.sv b/tb/tb_pkg.sv new file mode 100644 index 0000000..6a54baf --- /dev/null +++ b/tb/tb_pkg.sv @@ -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" diff --git a/tb/tb_seq_base.sv b/tb/tb_seq_base.sv new file mode 100644 index 0000000..b8ecef8 --- /dev/null +++ b/tb/tb_seq_base.sv @@ -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 diff --git a/tb/tb_top.sv b/tb/tb_top.sv new file mode 100644 index 0000000..17447c6 --- /dev/null +++ b/tb/tb_top.sv @@ -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 diff --git a/tb/tb_types.sv b/tb/tb_types.sv new file mode 100644 index 0000000..407fb25 --- /dev/null +++ b/tb/tb_types.sv @@ -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 diff --git a/tb/test_base.sv b/tb/test_base.sv new file mode 100644 index 0000000..3865132 --- /dev/null +++ b/tb/test_base.sv @@ -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