From 5451131e1a80aea08767b24fa39efee0da6d3947 Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sun, 24 Aug 2025 11:27:11 -0700 Subject: [PATCH] Interface clean up. WA for verilator tracing --- Makefile | 5 ++ axi.gtkw | 47 +++++++++++ scripts/gen_axi_intf.pl | 31 ++++++++ src/axi/axi_monitor.sv | 3 +- tb/tb_intf.sv | 38 +++++---- tb/tb_top.sv | 28 +------ tb/verilator_trace_workaround.svh | 124 ++++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 43 deletions(-) create mode 100644 axi.gtkw create mode 100644 tb/verilator_trace_workaround.svh diff --git a/Makefile b/Makefile index aa773d5..a1d8a82 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,9 @@ CPP_SRC=sim_$(PROJ).cpp TIMESCALE= --timescale '1ns/1ns' +ifndef VERI_TRACE_DIS +TB_DEFINES=+define+VERI_TRACE_EN +endif UVM_DEFINES=+define+UVM_NO_DPI \ +define+UVM_REPORT_DISABLE_FILE_LINE DISABLED_WARNINGS=-Wno-WIDTHTRUNC -Wno-WIDTHEXPAND \ @@ -41,7 +44,9 @@ BUILD_ARGS=-I$(UVM_HOME)/src -I. \ --error-limit 10 \ --timing $(TIMESCALE) \ --trace \ + --top tb_top \ +define+SVA_ON \ + $(TB_DEFINES) \ $(UVM_DEFINES) \ $(DISABLED_WARNINGS) \ +incdir+common +incdir+src/axi +incdir+tb \ diff --git a/axi.gtkw b/axi.gtkw new file mode 100644 index 0000000..2f0673a --- /dev/null +++ b/axi.gtkw @@ -0,0 +1,47 @@ +[*] +[*] GTKWave Analyzer v3.3.124 (w)1999-2025 BSI +[*] Sun Aug 24 18:22:14 2025 +[*] +[dumpfile] "/home/mahesh/dev/sv/axipg/runs/test_basic/wave.vcd" +[dumpfile_mtime] "Sun Aug 24 18:18:15 2025" +[dumpfile_size] 19493 +[savefile] "/home/mahesh/dev/sv/axipg/axi.gtkw" +[timestart] 0 +[size] 1388 1348 +[pos] -1 -1 +*-6.502242 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] tb_top. +[sst_width] 290 +[signals_width] 126 +[sst_expanded] 1 +[sst_vpaned_height] 417 +@28 +tb_top.t_if.ARESETn +tb_top.t_if.ACLK +tb_top.t_if.ARVALID +tb_top.t_if.ARREADY +@22 +tb_top.t_if.ARADDR[31:0] +tb_top.t_if.ARLEN[7:0] +@200 +- +@28 +tb_top.t_if.AWVALID +tb_top.t_if.AWREADY +@22 +tb_top.t_if.AWADDR[31:0] +tb_top.t_if.AWLEN[7:0] +@200 +- +@28 +tb_top.t_if.WVALID +tb_top.t_if.WREADY +@22 +tb_top.t_if.WSTRB[7:0] +tb_top.t_if.WDATA[63:0] +@28 +tb_top.t_if.WLAST +@200 +- +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/scripts/gen_axi_intf.pl b/scripts/gen_axi_intf.pl index 9efbf85..937504b 100755 --- a/scripts/gen_axi_intf.pl +++ b/scripts/gen_axi_intf.pl @@ -38,6 +38,8 @@ sub gen_intf { show_modport($app, 'Subordinate'); print "endinterface // axi_intf\n"; + + show_trace_interface_driver($app); } # ----------------- @@ -88,6 +90,35 @@ sub show_interface { } } +# ----------------- +sub show_trace_interface_driver { + my ($app) = @_; + + print qq{ +`ifdef VERI_TRACE_EN + // -------------------------------------------------- + // Work around Verilator's lack of support for virutal interface tracing + `AXI_INTF t_if (.ACLK(clk), .ARESETn(rst_n)); +}; + foreach my $section (@{$app->{'intf_data'}->{'sections'}}) { + 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 " always @(a_if.$signal->{'n'}) t_if.$signal->{'n'} <= a_if.$signal->{'n'};\n"; + } + } + } + + print qq{ +`endif +}; +} + # ----------------- sub show_modport{ my ($app, $role) = @_; diff --git a/src/axi/axi_monitor.sv b/src/axi/axi_monitor.sv index bdf7d2d..b80c503 100644 --- a/src/axi/axi_monitor.sv +++ b/src/axi/axi_monitor.sv @@ -32,7 +32,7 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction); // -------------------------------------------------- // Set virtual interfaces function void set_virtual_interfaces(virtual `AXI_INTF.MANAGER m_if_p, - virtual `AXI_INTF.SUBORDINATE s_if_p); + virtual `AXI_INTF.SUBORDINATE s_if_p); `uvm_info("set_virtual_interfaces", $sformatf("Setting virtual interfaces"), UVM_LOW) m_if = m_if_p; @@ -68,7 +68,6 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction); $fwrite(trk_file, "AXI monitor (%0s Mode)\n", agent_type.name()); $fwrite(trk_file, "--------------------------------------------------\n"); - forever begin @(posedge mon_if.ACLK); if (mon_if.ARESETn != 0) begin diff --git a/tb/tb_intf.sv b/tb/tb_intf.sv index 75d3855..c5d3f78 100644 --- a/tb/tb_intf.sv +++ b/tb/tb_intf.sv @@ -1,26 +1,30 @@ // 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); + output clk, + output rst_n +); - logic rst_n; + logic clk_w; + logic rst_n_w; + assign clk = clk_w; + assign rst_n = rst_n_w; + + // -------------------------------------------------- + // Clock generation initial begin + clk_w = 0; // Initialize clock to 0 at time 0 forever begin - @(clk or rst_n); - $monitor("@%6t: %b %b ", $time, - rst_n, clk); + #5ns clk_w = ~clk_w; // Toggle clock every 5 ns end end + + // -------------------------------------------------- + // Initial reset + initial begin + rst_n_w = 0; + + repeat(20) @(posedge clk_w); + rst_n_w = 1; // Release reset after 20 clocks + end endinterface diff --git a/tb/tb_top.sv b/tb/tb_top.sv index d453c91..35066e6 100644 --- a/tb/tb_top.sv +++ b/tb/tb_top.sv @@ -5,22 +5,17 @@ module tb_top (input logic sys_clk); logic clk; logic rst_n; + // Testbench interface to controll clocks, reset, etc. + testbench_if tb_if(.clk(clk), .rst_n(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); uvm_config_db#(virtual `AXI_INTF)::set(uvm_root::get(), "uvm_test_top.env", "axi_mon_vif", a_if); + uvm_config_db#(virtual testbench_if)::set(uvm_root::get(), "uvm_test_top.env", "tb_vif", tb_if); run_test(); end @@ -31,20 +26,5 @@ module tb_top (input logic sys_clk); $dumpvars(0, "tb_top"); 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 +`include "verilator_trace_workaround.svh" endmodule diff --git a/tb/verilator_trace_workaround.svh b/tb/verilator_trace_workaround.svh new file mode 100644 index 0000000..fcfca78 --- /dev/null +++ b/tb/verilator_trace_workaround.svh @@ -0,0 +1,124 @@ +// Issue #5044: Wires driven through virtual interface traced improperly +// https://github.com/verilator/verilator/issues/5044 +`ifdef VERI_TRACE_EN + // -------------------------------------------------- + // Work around Verilator's lack of support for virutal interface tracing + `AXI_INTF t_if (.ACLK(clk), .ARESETn(rst_n)); + // 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 + always @(a_if.AWVALID) t_if.AWVALID <= a_if.AWVALID; + always @(a_if.AWREADY) t_if.AWREADY <= a_if.AWREADY; + always @(a_if.AWID) t_if.AWID <= a_if.AWID; + always @(a_if.AWADDR) t_if.AWADDR <= a_if.AWADDR; + always @(a_if.AWREGION) t_if.AWREGION <= a_if.AWREGION; + always @(a_if.AWLEN) t_if.AWLEN <= a_if.AWLEN; + always @(a_if.AWSIZE) t_if.AWSIZE <= a_if.AWSIZE; + always @(a_if.AWBURST) t_if.AWBURST <= a_if.AWBURST; + always @(a_if.AWLOCK) t_if.AWLOCK <= a_if.AWLOCK; + always @(a_if.AWCACHE) t_if.AWCACHE <= a_if.AWCACHE; + always @(a_if.AWPROT) t_if.AWPROT <= a_if.AWPROT; + always @(a_if.AWNSE) t_if.AWNSE <= a_if.AWNSE; + always @(a_if.AWQOS) t_if.AWQOS <= a_if.AWQOS; + always @(a_if.AWUSER) t_if.AWUSER <= a_if.AWUSER; + always @(a_if.AWDOMAIN) t_if.AWDOMAIN <= a_if.AWDOMAIN; + always @(a_if.AWSNOOP) t_if.AWSNOOP <= a_if.AWSNOOP; + always @(a_if.AWSTASHNID) t_if.AWSTASHNID <= a_if.AWSTASHNID; + always @(a_if.AWSTASHNIDEN) t_if.AWSTASHNIDEN <= a_if.AWSTASHNIDEN; + always @(a_if.AWSTASHLPID) t_if.AWSTASHLPID <= a_if.AWSTASHLPID; + always @(a_if.AWSTASHLPIDEN) t_if.AWSTASHLPIDEN <= a_if.AWSTASHLPIDEN; + always @(a_if.AWTRACE) t_if.AWTRACE <= a_if.AWTRACE; + always @(a_if.AWLOOP) t_if.AWLOOP <= a_if.AWLOOP; + always @(a_if.AWMMUVALID) t_if.AWMMUVALID <= a_if.AWMMUVALID; + always @(a_if.AWMMUSECSID) t_if.AWMMUSECSID <= a_if.AWMMUSECSID; + always @(a_if.AWMMUSID) t_if.AWMMUSID <= a_if.AWMMUSID; + always @(a_if.AWMMUSSIDV) t_if.AWMMUSSIDV <= a_if.AWMMUSSIDV; + always @(a_if.AWMMUSSID) t_if.AWMMUSSID <= a_if.AWMMUSSID; + always @(a_if.AWMMUATST) t_if.AWMMUATST <= a_if.AWMMUATST; + always @(a_if.AWMMUFLOW) t_if.AWMMUFLOW <= a_if.AWMMUFLOW; + always @(a_if.AWPBHA) t_if.AWPBHA <= a_if.AWPBHA; + always @(a_if.AWNSAID) t_if.AWNSAID <= a_if.AWNSAID; + always @(a_if.AWSUBSYSID) t_if.AWSUBSYSID <= a_if.AWSUBSYSID; + always @(a_if.AWATOP) t_if.AWATOP <= a_if.AWATOP; + always @(a_if.AWMPAM) t_if.AWMPAM <= a_if.AWMPAM; + always @(a_if.AWIDUNQ) t_if.AWIDUNQ <= a_if.AWIDUNQ; + always @(a_if.AWCMO) t_if.AWCMO <= a_if.AWCMO; + always @(a_if.AWTAGOP) t_if.AWTAGOP <= a_if.AWTAGOP; + always @(a_if.AWMECID) t_if.AWMECID <= a_if.AWMECID; + // A2.1.1 Write request channel + always @(a_if.WVALID) t_if.WVALID <= a_if.WVALID; + always @(a_if.WREADY) t_if.WREADY <= a_if.WREADY; + always @(a_if.WDATA) t_if.WDATA <= a_if.WDATA; + always @(a_if.WSTRB) t_if.WSTRB <= a_if.WSTRB; + always @(a_if.WTAG) t_if.WTAG <= a_if.WTAG; + always @(a_if.WTAGUPDATE) t_if.WTAGUPDATE <= a_if.WTAGUPDATE; + always @(a_if.WLAST) t_if.WLAST <= a_if.WLAST; + always @(a_if.WUSER) t_if.WUSER <= a_if.WUSER; + always @(a_if.WPOISON) t_if.WPOISON <= a_if.WPOISON; + always @(a_if.WTRACE) t_if.WTRACE <= a_if.WTRACE; + // A2.1.3 Write response channel + always @(a_if.BVALID) t_if.BVALID <= a_if.BVALID; + always @(a_if.BREADY) t_if.BREADY <= a_if.BREADY; + always @(a_if.BID) t_if.BID <= a_if.BID; + always @(a_if.BIDUNQ) t_if.BIDUNQ <= a_if.BIDUNQ; + always @(a_if.BRESP) t_if.BRESP <= a_if.BRESP; + always @(a_if.BCOMP) t_if.BCOMP <= a_if.BCOMP; + always @(a_if.BPERSIST) t_if.BPERSIST <= a_if.BPERSIST; + always @(a_if.BTAGMATCH) t_if.BTAGMATCH <= a_if.BTAGMATCH; + always @(a_if.BUSER) t_if.BUSER <= a_if.BUSER; + always @(a_if.BTRACE) t_if.BTRACE <= a_if.BTRACE; + always @(a_if.BLOOP) t_if.BLOOP <= a_if.BLOOP; + always @(a_if.BBUSY) t_if.BBUSY <= a_if.BBUSY; + // A2.2.1 Read request channel + always @(a_if.ARVALID) t_if.ARVALID <= a_if.ARVALID; + always @(a_if.ARREADY) t_if.ARREADY <= a_if.ARREADY; + always @(a_if.ARID) t_if.ARID <= a_if.ARID; + always @(a_if.ARADDR) t_if.ARADDR <= a_if.ARADDR; + always @(a_if.ARREGION) t_if.ARREGION <= a_if.ARREGION; + always @(a_if.ARLEN) t_if.ARLEN <= a_if.ARLEN; + always @(a_if.ARSIZE) t_if.ARSIZE <= a_if.ARSIZE; + always @(a_if.ARBURST) t_if.ARBURST <= a_if.ARBURST; + always @(a_if.ARLOCK) t_if.ARLOCK <= a_if.ARLOCK; + always @(a_if.ARCACHE) t_if.ARCACHE <= a_if.ARCACHE; + always @(a_if.ARPROT) t_if.ARPROT <= a_if.ARPROT; + always @(a_if.ARNSE) t_if.ARNSE <= a_if.ARNSE; + always @(a_if.ARQOS) t_if.ARQOS <= a_if.ARQOS; + always @(a_if.ARUSER) t_if.ARUSER <= a_if.ARUSER; + always @(a_if.ARDOMAIN) t_if.ARDOMAIN <= a_if.ARDOMAIN; + always @(a_if.ARSNOOP) t_if.ARSNOOP <= a_if.ARSNOOP; + always @(a_if.ARTRACE) t_if.ARTRACE <= a_if.ARTRACE; + always @(a_if.ARLOOP) t_if.ARLOOP <= a_if.ARLOOP; + always @(a_if.ARMMUVALID) t_if.ARMMUVALID <= a_if.ARMMUVALID; + always @(a_if.ARMMUSECSID) t_if.ARMMUSECSID <= a_if.ARMMUSECSID; + always @(a_if.ARMMUSID) t_if.ARMMUSID <= a_if.ARMMUSID; + always @(a_if.ARMMUSSIDV) t_if.ARMMUSSIDV <= a_if.ARMMUSSIDV; + always @(a_if.ARMMUSSID) t_if.ARMMUSSID <= a_if.ARMMUSSID; + always @(a_if.ARMMUATST) t_if.ARMMUATST <= a_if.ARMMUATST; + always @(a_if.ARMMUFLOW) t_if.ARMMUFLOW <= a_if.ARMMUFLOW; + always @(a_if.ARPBHA) t_if.ARPBHA <= a_if.ARPBHA; + always @(a_if.ARNSAID) t_if.ARNSAID <= a_if.ARNSAID; + always @(a_if.ARSUBSYSID) t_if.ARSUBSYSID <= a_if.ARSUBSYSID; + always @(a_if.ARCHUNKEN) t_if.ARCHUNKEN <= a_if.ARCHUNKEN; + always @(a_if.ARIDUNQ) t_if.ARIDUNQ <= a_if.ARIDUNQ; + always @(a_if.ARTAGOP) t_if.ARTAGOP <= a_if.ARTAGOP; + always @(a_if.ARMECID) t_if.ARMECID <= a_if.ARMECID; + // A2.2.2 Read data channel + always @(a_if.RVALID) t_if.RVALID <= a_if.RVALID; + always @(a_if.RREADY) t_if.RREADY <= a_if.RREADY; + always @(a_if.RID) t_if.RID <= a_if.RID; + always @(a_if.RIDUNQ) t_if.RIDUNQ <= a_if.RIDUNQ; + always @(a_if.RDATA) t_if.RDATA <= a_if.RDATA; + always @(a_if.RTAG) t_if.RTAG <= a_if.RTAG; + always @(a_if.RRESP) t_if.RRESP <= a_if.RRESP; + always @(a_if.RLAST) t_if.RLAST <= a_if.RLAST; + always @(a_if.RUSER) t_if.RUSER <= a_if.RUSER; + always @(a_if.RPOISON) t_if.RPOISON <= a_if.RPOISON; + always @(a_if.RTRACE) t_if.RTRACE <= a_if.RTRACE; + always @(a_if.RLOOP) t_if.RLOOP <= a_if.RLOOP; + always @(a_if.RCHUNKV) t_if.RCHUNKV <= a_if.RCHUNKV; + always @(a_if.RCHUNKNUM) t_if.RCHUNKNUM <= a_if.RCHUNKNUM; + always @(a_if.RCHUNKSTRB) t_if.RCHUNKSTRB <= a_if.RCHUNKSTRB; + always @(a_if.RBUSY) t_if.RBUSY <= a_if.RBUSY; + +`endif