From 28fb85f4fb261885c83eea7b963273b2346852cb Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Fri, 27 Oct 2023 16:13:29 +0200 Subject: [PATCH] tracer: Update tracer to the multiprotocol version of iDMA (#8) * Add a tracer for the DMA #8 --- Bender.yml | 1 + idma.mk | 35 +++++- requirements.txt | 1 + src/db/idma_axi.yml | 10 ++ src/db/idma_axi_lite.yml | 10 ++ src/db/idma_axi_stream.yml | 11 ++ src/db/idma_init.yml | 9 ++ src/db/idma_obi.yml | 11 ++ src/db/idma_tilelink.yml | 10 ++ src/include/idma/tpl/tracer.svh.tpl | 30 +++++ src/include/idma/tracer.svh | 101 ----------------- target/rtl/.gitignore | 1 + target/rtl/tpl/Bender.yml.tpl | 1 + test/frontend/tb_idma_desc64_bench.sv | 156 ++++++-------------------- test/frontend/tb_idma_desc64_top.sv | 2 +- test/future/idma_tb_per2axi.sv | 4 +- test/tb_idma_nd_backend.sv | 27 ++++- test/tpl/tb_idma_backend.sv.tpl | 20 +++- util/gen_idma.py | 5 +- util/mario/synth.py | 2 +- util/mario/tracer.py | 132 ++++++++++++++++++++++ util/trace_idma.py | 74 +++++++++--- 22 files changed, 399 insertions(+), 254 deletions(-) create mode 100644 src/include/idma/tpl/tracer.svh.tpl delete mode 100644 src/include/idma/tracer.svh create mode 100644 util/mario/tracer.py diff --git a/Bender.yml b/Bender.yml index 342c867b..7c8dbd29 100644 --- a/Bender.yml +++ b/Bender.yml @@ -19,6 +19,7 @@ dependencies: export_include_dirs: - src/include + - target/rtl/include sources: # Source files grouped in levels. Files in level 0 have no dependencies on files in this diff --git a/idma.mk b/idma.mk index 0db0a202..acd88d62 100644 --- a/idma.mk +++ b/idma.mk @@ -68,9 +68,11 @@ IDMA_GEN := $(IDMA_UTIL_DIR)/gen_idma.py IDMA_GEN_SRC := $(IDMA_UTIL_DIR)/mario/backend.py \ $(IDMA_UTIL_DIR)/mario/bender.py \ $(IDMA_UTIL_DIR)/mario/database.py \ + $(IDMA_UTIL_DIR)/mario/frontend.py \ $(IDMA_UTIL_DIR)/mario/legalizer.py \ $(IDMA_UTIL_DIR)/mario/synth.py \ $(IDMA_UTIL_DIR)/mario/testbench.py \ + $(IDMA_UTIL_DIR)/mario/tracer.py \ $(IDMA_UTIL_DIR)/mario/transport_layer.py \ $(IDMA_UTIL_DIR)/mario/util.py \ $(IDMA_UTIL_DIR)/mario/wave.py @@ -112,12 +114,18 @@ $(IDMA_RTL_DIR)/tb_idma_backend_%.sv: $(IDMA_GEN) $(IDMA_RTL_DIR)/idma_backend_% $(IDMA_VSIM_DIR)/wave/backend_%.do: $(IDMA_GEN) $(IDMA_RTL_DIR)/tb_idma_backend_%.sv $(IDMA_VSIM_DIR)/wave/tpl/backend.do.tpl $(call idma_gen,vsim_wave,$(IDMA_VSIM_DIR)/wave/tpl/backend.do.tpl,$(IDMA_DB_FILES),$*,,$@) +$(IDMA_RTL_DIR)/include/idma/tracer.svh: $(IDMA_GEN) $(IDMA_GEN_SRC) $(IDMA_ROOT)/src/include/idma/tpl/tracer.svh.tpl $(IDMA_DB_FILES) $(IDMA_ROOT)/idma.mk + mkdir -p $(IDMA_RTL_DIR)/include/idma + $(call idma_gen,tracer,$(IDMA_ROOT)/src/include/idma/tpl/tracer.svh.tpl,$(IDMA_DB_FILES),$(IDMA_BACKEND_IDS),$(IDMA_FE_IDS),$@) + idma_rtl_clean: rm -f $(IDMA_RTL_DIR)/Bender.yml rm -f $(IDMA_RTL_DIR)/*.sv rm -f $(IDMA_VSIM_DIR)/wave/*.do + rm -f $(IDMA_RTL_DIR)/include/idma/tracer.svh # assemble the required files +IDMA_RTL_ALL += $(IDMA_RTL_DIR)/include/idma/tracer.svh IDMA_RTL_ALL += $(foreach X,$(IDMA_RTL_FILES),$(foreach Y,$(IDMA_BACKEND_IDS),$X_$Y.sv)) IDMA_TB_ALL += $(foreach Y,$(IDMA_BACKEND_IDS),$(IDMA_RTL_DIR)/tb_idma_backend_$Y.sv) IDMA_TB_ALL += $(foreach Y,$(IDMA_BACKEND_IDS),$(IDMA_VSIM_DIR)/wave/backend_$Y.do) @@ -263,12 +271,12 @@ idma_sim_clean: rm -f $(IDMA_VSIM_DIR)/dma_transfers.txt rm -f $(IDMA_VSIM_DIR)/transcript rm -f $(IDMA_VSIM_DIR)/wlf* - rm -f $(IDMA_VSIM_DIR)/logs/wlf* - rm -f $(IDMA_VSIM_DIR)/logs/*.wlf + rm -f $(IDMA_VSIM_DIR)/*.wlf rm -f $(IDMA_VSIM_DIR)/*.vstf rm -f $(IDMA_VSIM_DIR)/*.vcd rm -f $(IDMA_VSIM_DIR)/modelsim.ini - rm -f $(IDMA_VSIM_DIR)/logs/*vsim.log + rm -f $(IDMA_VSIM_DIR)/*.log + rm -f $(IDMA_VSIM_DIR)/*.txt # -------------- @@ -312,7 +320,8 @@ idma_vcs_clean: rm -rf $(IDMA_VCS_DIR)/bin rm -f $(IDMA_VCS_DIR)/ucli.key rm -f $(IDMA_VCS_DIR)/vc_hdrs.h - rm -f $(IDMA_VCS_DIR)/logs/*.vcs.log + rm -f $(IDMA_VCS_DIR)/*.log + rm -f $(IDMA_VCS_DIR)/*.txt # -------------- @@ -346,6 +355,22 @@ idma_verilator_clean: rm -rf $(IDMA_VLT_DIR) +# --------------- +# Trace +# --------------- + +.PHONY: idma_trace_clean + +IDMA_TRACE := $(IDMA_UTIL_DIR)/trace_idma.py + +%_trace.rpt: $(IDMA_TRACE) $(IDMA_DB_FILES) %.txt + $(PYTHON) $(IDMA_TRACE) --db $(IDMA_DB_FILES) --trace $*.txt > $@ + +idma_trace_clean: + rm -f $(IDMA_VSIM_DIR)/*_trace.rpt + rm -f $(IDMA_VCS_DIR)/*_trace.rpt + + # --------------- # Doc # --------------- @@ -385,7 +410,7 @@ idma_nonfree_clean: .PHONY: idma_clean_all idma_clean idma_misc_clean -idma_clean_all idma_clean: idma_rtl_clean idma_reg_clean idma_morty_clean idma_sim_clean idma_vcs_clean idma_verilator_clean idma_spinx_doc_clean +idma_clean_all idma_clean: idma_rtl_clean idma_reg_clean idma_morty_clean idma_sim_clean idma_vcs_clean idma_verilator_clean idma_spinx_doc_clean idma_trace_clean idma_misc_clean: rm -rf scripts/__pycache__ diff --git a/requirements.txt b/requirements.txt index 3bef2fab..1bfe7864 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ sphinx-rtd-theme recommonmark sphinxcontrib-svg2pdfconverter pylint +flatdict diff --git a/src/db/idma_axi.yml b/src/db/idma_axi.yml index 1d308ea3..91b2c0a9 100644 --- a/src/db/idma_axi.yml +++ b/src/db/idma_axi.yml @@ -224,3 +224,13 @@ synth_wrapper_assign_read: | assign axi_read_rsp.r.last = axi_r_last_i; assign axi_read_rsp.r.user = axi_r_user_i; assign axi_read_rsp.r_valid = axi_r_valid_i; +trace_signals: + read: + rsp: + valid: axi_read_rsp_i.r_valid + ready: axi_read_req_o.r_ready + write: + req: + valid: axi_write_req_o.w_valid + ready: axi_write_rsp_i.w_ready + strobe: axi_write_req_o.w.strb diff --git a/src/db/idma_axi_lite.yml b/src/db/idma_axi_lite.yml index bd6e42f1..0f40fe08 100644 --- a/src/db/idma_axi_lite.yml +++ b/src/db/idma_axi_lite.yml @@ -157,3 +157,13 @@ synth_wrapper_assign_read: | assign axi_lite_read_rsp.r.data = axi_lite_r_data_i; assign axi_lite_read_rsp.r.resp = axi_lite_r_resp_i; assign axi_lite_read_rsp.r_valid = axi_lite_r_valid_i; +trace_signals: + read: + rsp: + valid: axi_lite_read_rsp_i.r_valid + ready: axi_lite_read_req_o.r_ready + write: + req: + valid: axi_lite_write_req_o.w_valid + ready: axi_lite_write_rsp_i.w_ready + strobe: axi_lite_write_req_o.w.strb diff --git a/src/db/idma_axi_stream.yml b/src/db/idma_axi_stream.yml index b19ca710..04cb6e33 100644 --- a/src/db/idma_axi_stream.yml +++ b/src/db/idma_axi_stream.yml @@ -320,3 +320,14 @@ synth_wrapper_assign_write: | assign axi_stream_write_tvalid_o = axi_stream_write_req.tvalid; assign axi_stream_write_rsp.tready = axi_stream_write_tready_i; +trace_signals: + read: + rsp: + valid: axi_stream_read_rsp_i.tvalid + ready: axi_stream_read_req_o.tready + strobe: axi_stream_read_rsp_i.t.strb + write: + req: + valid: axi_stream_write_req_o.tvalid + ready: axi_stream_write_rsp_i.tready + strobe: axi_stream_write_req_o.t.strb diff --git a/src/db/idma_init.yml b/src/db/idma_init.yml index 58fc51d9..bc30c5bc 100644 --- a/src/db/idma_init.yml +++ b/src/db/idma_init.yml @@ -100,3 +100,12 @@ synth_wrapper_assign_read: | assign init_read_rsp.rsp_valid = init_read_rsp_valid_i; assign init_read_rsp.rsp_chan.init_value = init_read_rsp_init_value_i; assign init_read_rsp_ready_o = init_read_req.rsp_ready; +trace_signals: + read: + req: + valid: init_read_req_o.req_valid + config: init_read_req_o.req_chan.cfg + ready: init_read_rsp_i.req_ready + rsp: + valid: init_read_rsp_i.rsp_valid + ready: init_read_req_o.rsp_ready diff --git a/src/db/idma_obi.yml b/src/db/idma_obi.yml index 4a7d7aa4..cc577031 100644 --- a/src/db/idma_obi.yml +++ b/src/db/idma_obi.yml @@ -161,3 +161,14 @@ synth_wrapper_assign_read: | assign obi_read_rsp.r_valid = obi_read_rsp_r_valid_i; assign obi_read_rsp.r.rdata = obi_read_rsp_r_rdata_i; assign obi_read_rsp.r.rid = obi_read_rsp_r_rid_i; +trace_signals: + read: + rsp: + valid: obi_read_req_o.r_valid + ready: obi_read_rsp_i.r_ready + write: + req: + valid: obi_write_req_o.a_req + ready: obi_write_rsp_i.a_gnt + strobe: obi_write_req_o.a.be + write_en: obi_write_req_o.a.we diff --git a/src/db/idma_tilelink.yml b/src/db/idma_tilelink.yml index 4edf7d9e..273fed38 100644 --- a/src/db/idma_tilelink.yml +++ b/src/db/idma_tilelink.yml @@ -241,3 +241,13 @@ synth_wrapper_assign_read: | assign tilelink_read_rsp.d.denied = tilelink_read_rsp_d_denied_i; assign tilelink_read_rsp.d.data = tilelink_read_rsp_d_data_i; assign tilelink_read_rsp.d.corrupt = tilelink_read_rsp_d_corrupt_i; +trace_signals: + read: + rsp: + valid: tilelink_read_rsp_i.d_valid + ready: tilelink_read_req_o.d_ready + write: + req: + valid: tilelink_write_req_o.a_valid + ready: tilelink_write_rsp_i.a_ready + strobe: tilelink_write_req_o.a.mask diff --git a/src/include/idma/tpl/tracer.svh.tpl b/src/include/idma/tpl/tracer.svh.tpl new file mode 100644 index 00000000..457c5d91 --- /dev/null +++ b/src/include/idma/tpl/tracer.svh.tpl @@ -0,0 +1,30 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Authors: +// - Thomas Benz + +// Macro holding all the resources for the iDMA backend tracer +`ifndef IDMA_TRACER_SVH_ +`define IDMA_TRACER_SVH_ + +// largest type to trace +`define IDMA_TRACER_MAX_TYPE_WIDTH 1024 +`define IDMA_TRACER_MAX_TYPE logic [`IDMA_TRACER_MAX_TYPE_WIDTH-1:0] + +// string assembly function +`define IDMA_TRACER_STR_ASSEMBLY(__dict, __cond) <%text>\ + if(__cond) begin <%text>\ + trace = $sformatf("%s'%s':{", trace, `"__dict`"); <%text>\ + foreach(__dict``[key]) trace = $sformatf("%s'%s': 0x%0x,", trace, key, __dict``[key]); <%text>\ + trace = $sformatf("%s},", trace); <%text>\ + end + +// helper to clear a condition +`define IDMA_TRACER_CLEAR_COND(__cond) <%text>\ + if(__cond) begin <%text>\ + __cond = ~__cond; <%text>\ + end +${body} +`endif diff --git a/src/include/idma/tracer.svh b/src/include/idma/tracer.svh deleted file mode 100644 index d8f6740d..00000000 --- a/src/include/idma/tracer.svh +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 -// -// Thomas Benz - -// Macro holding all the resources for the iDMA backend tracer -`ifndef IDMA_TRACER_SVH_ -`define IDMA_TRACER_SVH_ - -// largest type to trace -`define IDMA_TRACER_MAX_TYPE_WIDTH 1024 -`define IDMA_TRACER_MAX_TYPE logic [`IDMA_TRACER_MAX_TYPE_WIDTH-1:0] - -// string assembly function -`define IDMA_TRACER_STR_ASSEMBLY(__dict, __cond) \ - if(__cond) begin \ - trace = $sformatf("%s'%s':{", trace, `"__dict`"); \ - foreach(__dict``[key]) trace = $sformatf("%s'%s': 0x%0x,", trace, key, __dict``[key]); \ - trace = $sformatf("%s},", trace); \ - end - -// helper to clear a condition -`define IDMA_TRACER_CLEAR_COND(__cond) \ - if(__cond) begin \ - __cond = ~__cond; \ - end - -// The tracer for the iDMA -`define IDMA_TRACER(__backend_inst, __out_f_name) \ -`ifndef SYNTHESYS \ -`ifndef VERILATOR \ - initial begin : inital_tracer \ - automatic bit first_iter = 1; \ - automatic integer tf; \ - automatic `IDMA_TRACER_MAX_TYPE cnst [string]; \ - automatic `IDMA_TRACER_MAX_TYPE meta [string]; \ - automatic `IDMA_TRACER_MAX_TYPE busy [string]; \ - automatic `IDMA_TRACER_MAX_TYPE axib [string]; \ - automatic string trace; \ - #0; \ - tf = $fopen(__out_f_name, "w"); \ - $display("[Tracer] Logging iDMA backend %s to %s", `"__backend_inst`", __out_f_name); \ - forever begin \ - @(posedge __backend_inst``.clk_i); \ - if(__backend_inst``.rst_ni & |__backend_inst``.busy_o) begin \ - /* Trace */ \ - trace = "{"; \ - /* Constants */ \ - cnst = '{ \ - "inst" : `"__backend_inst`", \ - "data_width" : __backend_inst``.DataWidth, \ - "addr_width" : __backend_inst``.AddrWidth, \ - "user_width" : __backend_inst``.UserWidth, \ - "axi_id_width" : __backend_inst``.AxiIdWidth, \ - "num_ax_in_flight" : __backend_inst``.NumAxInFlight, \ - "buffer_depth" : __backend_inst``.BufferDepth, \ - "tf_len_width" : __backend_inst``.TFLenWidth, \ - "mem_sys_depth" : __backend_inst``.MemSysDepth, \ - "rw_coupling_avail" : __backend_inst``.RAWCouplingAvail, \ - "mask_invalid_data" : __backend_inst``.MaskInvalidData, \ - "hardware_legalizer" : __backend_inst``.HardwareLegalizer, \ - "reject_zero_transfers" : __backend_inst``.RejectZeroTransfers, \ - "error_cap" : __backend_inst``.ErrorCap, \ - "print_fifo_info" : __backend_inst``.PrintFifoInfo \ - }; \ - meta = '{ \ - "time" : $time() \ - }; \ - busy = '{ \ - "buffer" : __backend_inst``.busy_o.buffer_busy, \ - "r_dp" : __backend_inst``.busy_o.r_dp_busy, \ - "w_dp" : __backend_inst``.busy_o.w_dp_busy, \ - "r_leg" : __backend_inst``.busy_o.r_leg_busy, \ - "w_leg" : __backend_inst``.busy_o.w_leg_busy, \ - "eh_fsm" : __backend_inst``.busy_o.eh_fsm_busy, \ - "eh_cnt" : __backend_inst``.busy_o.eh_cnt_busy, \ - "raw_coupler" : __backend_inst``.busy_o.raw_coupler_busy \ - }; \ - axib = '{ \ - "w_valid" : __backend_inst``.axi_req_o.w_valid, \ - "w_ready" : __backend_inst``.axi_rsp_i.w_ready, \ - "w_strb" : __backend_inst``.axi_req_o.w.strb, \ - "r_valid" : __backend_inst``.axi_rsp_i.r_valid, \ - "r_ready" : __backend_inst``.axi_req_o.r_ready \ - }; \ - /* Assembly */ \ - `IDMA_TRACER_STR_ASSEMBLY(cnst, first_iter); \ - `IDMA_TRACER_STR_ASSEMBLY(meta, 1); \ - `IDMA_TRACER_STR_ASSEMBLY(busy, 1); \ - `IDMA_TRACER_STR_ASSEMBLY(axib, 1); \ - `IDMA_TRACER_CLEAR_COND(first_iter); \ - /* Commit */ \ - $fwrite(tf, $sformatf("%s}\n", trace)); \ - end \ - end \ - end \ -`endif \ -`endif - -`endif diff --git a/target/rtl/.gitignore b/target/rtl/.gitignore index 9eddf5ef..a2e0e0a0 100644 --- a/target/rtl/.gitignore +++ b/target/rtl/.gitignore @@ -1,3 +1,4 @@ Bender.yml +include *.sv *.hjson diff --git a/target/rtl/tpl/Bender.yml.tpl b/target/rtl/tpl/Bender.yml.tpl index b449aee0..03641b51 100644 --- a/target/rtl/tpl/Bender.yml.tpl +++ b/target/rtl/tpl/Bender.yml.tpl @@ -16,6 +16,7 @@ dependencies: export_include_dirs: - ../../src/include - ../../test + - include sources: # Source files grouped in levels. Files in level 0 have no dependencies on files in this diff --git a/test/frontend/tb_idma_desc64_bench.sv b/test/frontend/tb_idma_desc64_bench.sv index 73191aa7..8283d3be 100644 --- a/test/frontend/tb_idma_desc64_bench.sv +++ b/test/frontend/tb_idma_desc64_bench.sv @@ -47,6 +47,7 @@ module tb_idma_desc64_bench parameter bit RejectZeroTransfers = 1, parameter bit ErrorHandling = 1, parameter bit IdealMemory = 1, + parameter bit DmaTracing = 1, parameter int unsigned Seed = 1337 ) (); localparam time PERIOD = 10ns; @@ -97,7 +98,7 @@ module tb_idma_desc64_bench // set seed initial begin - int drop = $urandom(Seed); + automatic int drop = $urandom(Seed); end class stimulus_t; @@ -296,131 +297,40 @@ module tb_idma_desc64_bench .busy_o ( busy ) ); - // Read Write Join - axi_rw_join #( - .axi_req_t ( axi_req_t ), - .axi_resp_t ( axi_resp_t ) - ) i_axi_rw_join ( - .clk_i ( clk ), - .rst_ni ( rst_n ), - .slv_read_req_i ( axi_read_req ), - .slv_read_resp_o ( axi_read_rsp ), - .slv_write_req_i ( axi_write_req ), - .slv_write_resp_o ( axi_write_rsp ), - .mst_req_o ( dma_be_master_request ), - .mst_resp_i ( dma_be_master_response ) - ); - - string trace_file; - initial begin - void'($value$plusargs("trace_file=%s", trace_file)); - end - `ifndef SYNTHESYS - `ifndef VERILATOR - initial begin : inital_tracer - automatic bit first_iter = 1'b1; - automatic int unsigned skipped_transfers = 0; - automatic int unsigned recorded_transfers = 0; - automatic integer tf; - automatic `IDMA_TRACER_MAX_TYPE cnst [string]; - automatic `IDMA_TRACER_MAX_TYPE meta [string]; - automatic `IDMA_TRACER_MAX_TYPE busy [string]; - automatic `IDMA_TRACER_MAX_TYPE axib [string]; - automatic string trace; - #0; - tf = $fopen(trace_file, "w"); - $display("[Tracer] Logging iDMA backend %s to %s", "i_idma_backend", trace_file); - forever begin - @(posedge i_idma_backend.clk_i); - if (i_idma_backend.rst_ni & irq) begin - skipped_transfers += 1; - if (skipped_transfers > TransfersToSkip) begin - break; - end - end - end - forever begin - @(posedge i_idma_backend.clk_i); - if (irq) begin - recorded_transfers += 1; - if (recorded_transfers >= TransfersToSkip / 2) begin - break; + + //-------------------------------------- + // DMA Tracer + //-------------------------------------- + // only activate tracer if requested + if (DmaTracing) begin + // fetch the name of the trace file from CMD line + string trace_file; + initial begin + void'($value$plusargs("trace_file=%s", trace_file)); end - end - /* Trace */ - trace = "{"; - /* Constants */ - cnst = '{ - "inst" : "i_idma_backend", - "data_width" : i_idma_backend.DataWidth, - "addr_width" : i_idma_backend.AddrWidth, - "user_width" : i_idma_backend.UserWidth, - "axi_id_width" : i_idma_backend.AxiIdWidth, - "num_ax_in_flight" : i_idma_backend.NumAxInFlight, - "buffer_depth" : i_idma_backend.BufferDepth, - "tf_len_width" : i_idma_backend.TFLenWidth, - "mem_sys_depth" : i_idma_backend.MemSysDepth, - "rw_coupling_avail" : i_idma_backend.RAWCouplingAvail, - "mask_invalid_data" : i_idma_backend.MaskInvalidData, - "hardware_legalizer" : i_idma_backend.HardwareLegalizer, - "reject_zero_transfers" : i_idma_backend.RejectZeroTransfers, - "error_cap" : i_idma_backend.ErrorCap, - "print_fifo_info" : i_idma_backend.PrintFifoInfo - }; - meta = '{ - "time" : $time() - }; - busy = '{ - "buffer" : i_idma_backend.busy_o.buffer_busy, - "r_dp" : i_idma_backend.busy_o.r_dp_busy, - "w_dp" : i_idma_backend.busy_o.w_dp_busy, - "r_leg" : i_idma_backend.busy_o.r_leg_busy, - "w_leg" : i_idma_backend.busy_o.w_leg_busy, - "eh_fsm" : i_idma_backend.busy_o.eh_fsm_busy, - "eh_cnt" : i_idma_backend.busy_o.eh_cnt_busy, - "raw_coupler" : i_idma_backend.busy_o.raw_coupler_busy - }; - axib = '{ - "w_valid" : i_idma_backend.axi_write_req_o.w_valid, - "w_ready" : i_idma_backend.axi_write_rsp_i.w_ready, - "w_strb" : i_idma_backend.axi_write_req_o.w.strb, - "r_valid" : i_idma_backend.axi_read_rsp_i.r_valid, - "r_ready" : i_idma_backend.axi_read_req_o.r_ready - }; - if ($isunknown(axib["w_ready"]) || $isunknown(axib["r_valid"])) begin - $fatal("UNKNOWN AXI STATE, THIS SHOULD NEVER HAPPEN!"); - end - /* Assembly */ - `IDMA_TRACER_STR_ASSEMBLY(cnst, first_iter); - `IDMA_TRACER_STR_ASSEMBLY(meta, 1); - `IDMA_TRACER_STR_ASSEMBLY(busy, 1); - `IDMA_TRACER_STR_ASSEMBLY(axib, 1); - `IDMA_TRACER_CLEAR_COND(first_iter); - /* Commit */ - $fwrite(tf, $sformatf("%s}\n", trace)); + // attach the tracer + `IDMA_TRACER_RW_AXI(i_idma_backend, trace_file); end - end -`endif -`endif - - /* - axi_cut #( - .aw_chan_t (axi_aw_chan_t), - .w_chan_t (axi_w_chan_t), - .b_chan_t (axi_b_chan_t), - .ar_chan_t (axi_ar_chan_t), - .r_chan_t (axi_r_chan_t), - .axi_req_t (axi_req_t), - .axi_resp_t(axi_resp_t) - ) i_axi_cut ( - .clk_i (clk), - .rst_ni (rst_n), - .slv_req_i (dma_be_cut_req), - .slv_resp_o (dma_be_cut_resp), - .mst_req_o (dma_be_master_request), - .mst_resp_i (dma_be_master_response) + + + //-------------------------------------- + // TB connections + //-------------------------------------- + + // Read Write Join + axi_rw_join #( + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_resp_t ) + ) i_axi_rw_join ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .slv_read_req_i ( axi_read_req ), + .slv_read_resp_o ( axi_read_rsp ), + .slv_write_req_i ( axi_write_req ), + .slv_write_resp_o ( axi_write_rsp ), + .mst_req_o ( dma_be_master_request ), + .mst_resp_i ( dma_be_master_response ) ); - */ // AXI mux axi_mux #( diff --git a/test/frontend/tb_idma_desc64_top.sv b/test/frontend/tb_idma_desc64_top.sv index cde305f2..9391b0d4 100644 --- a/test/frontend/tb_idma_desc64_top.sv +++ b/test/frontend/tb_idma_desc64_top.sv @@ -64,7 +64,7 @@ module tb_idma_desc64_top // set seed initial begin - int drop = $urandom(Seed); + automatic int drop = $urandom(Seed); end class stimulus_t; diff --git a/test/future/idma_tb_per2axi.sv b/test/future/idma_tb_per2axi.sv index 4487068a..e79a1066 100644 --- a/test/future/idma_tb_per2axi.sv +++ b/test/future/idma_tb_per2axi.sv @@ -123,10 +123,10 @@ module idma_tb_fifo_v2 #( input logic pop_i ); logic [ADDR_DEPTH-1:0] usage; - if (DEPTH == 0) begin + if (DEPTH == 0) begin : proc_depth_zero assign alm_full_o = 1'b0; assign alm_empty_o = 1'b0; - end else begin + end else begin : proc_depth_larger_zero assign alm_full_o = (usage >= ALM_FULL_TH[ADDR_DEPTH-1:0]); assign alm_empty_o = (usage <= ALM_EMPTY_TH[ADDR_DEPTH-1:0]); end diff --git a/test/tb_idma_nd_backend.sv b/test/tb_idma_nd_backend.sv index 2c467c39..02741080 100644 --- a/test/tb_idma_nd_backend.sv +++ b/test/tb_idma_nd_backend.sv @@ -8,6 +8,7 @@ `timescale 1ns/1ns `include "axi/typedef.svh" +`include "idma/tracer.svh" `include "idma/typedef.svh" // Protocol testbench defines @@ -34,7 +35,8 @@ module tb_idma_nd_backend import idma_pkg::*; #( parameter bit HardwareLegalizer = 1, parameter bit RejectZeroTransfers = 1, parameter bit ErrorHandling = 1, - parameter bit IdealMemory = 1 + parameter bit IdealMemory = 1, + parameter bit DmaTracing = 1 ); // timing parameters @@ -422,6 +424,26 @@ module tb_idma_nd_backend import idma_pkg::*; #( .busy_o ( busy ) ); + + //-------------------------------------- + // DMA Tracer + //-------------------------------------- + // only activate tracer if requested + if (DmaTracing) begin + // fetch the name of the trace file from CMD line + string trace_file; + initial begin + void'($value$plusargs("trace_file=%s", trace_file)); + end + // attach the tracer + `IDMA_TRACER_RW_AXI(i_idma_backend, trace_file); + end + + + //-------------------------------------- + // TB connections + //-------------------------------------- + // Read Write Join axi_rw_join #( .axi_req_t ( axi_req_t ), @@ -437,9 +459,6 @@ module tb_idma_nd_backend import idma_pkg::*; #( .mst_resp_i ( axi_rsp ) ); - //-------------------------------------- - // TB connections - //-------------------------------------- // connect virtual driver interface to structs assign nd_req = idma_nd_dv.req; assign nd_req_valid = idma_nd_dv.req_valid; diff --git a/test/tpl/tb_idma_backend.sv.tpl b/test/tpl/tb_idma_backend.sv.tpl index e09c260e..3c3154b4 100644 --- a/test/tpl/tb_idma_backend.sv.tpl +++ b/test/tpl/tb_idma_backend.sv.tpl @@ -7,6 +7,7 @@ `timescale 1ns/1ns `include "axi/typedef.svh" +`include "idma/tracer.svh" `include "idma/typedef.svh" // Protocol testbench defines @@ -53,7 +54,8 @@ module tb_idma_backend_${name_uniqueifier} import idma_pkg::*; #( %endif parameter bit HardwareLegalizer = 1, parameter bit RejectZeroTransfers = 1, - parameter bit ErrorHandling = 0 + parameter bit ErrorHandling = 0, + parameter bit DmaTracing = 1 ); // timing parameters @@ -590,6 +592,22 @@ ${p}_${database[p]['write_meta_channel']}_width\ .busy_o ( busy ) ); + + //-------------------------------------- + // DMA Tracer + //-------------------------------------- + // only activate tracer if requested + if (DmaTracing) begin + // fetch the name of the trace file from CMD line + string trace_file; + initial begin + void'($value$plusargs("trace_file=%s", trace_file)); + end + // attach the tracer + `IDMA_TRACER_${name_uniqueifier.upper()}(i_idma_backend, trace_file); + end + + //-------------------------------------- // TB connections //-------------------------------------- diff --git a/util/gen_idma.py b/util/gen_idma.py index cbf78711..faffb2e4 100644 --- a/util/gen_idma.py +++ b/util/gen_idma.py @@ -22,9 +22,10 @@ from mario.synth import render_synth_wrapper from mario.testbench import render_testbench from mario.frontend import render_reg_hjson, render_reg_top +from mario.tracer import render_tracer GENABLE_ENTITIES = ['transport', 'legalizer', 'backend', 'vsim_wave', 'testbench', 'synth_wrapper', - 'bender', 'reg_top', 'reg_hjson'] + 'bender', 'reg_top', 'reg_hjson', 'tracer'] EPILOG = ''' The iDMA configuration ID is composed of a underscore-separated list of specifiers and protocols. @@ -73,6 +74,8 @@ def main(): print(render_reg_hjson(frontend_ids, args.tpl)) elif args.entity == 'reg_top': print(render_reg_top(frontend_ids, args.tpl)) + elif args.entity == 'tracer': + print(render_tracer(protocol_ids, protocol_db, args.tpl)) else: return 1 diff --git a/util/mario/synth.py b/util/mario/synth.py index b83479f9..2baa2c4a 100644 --- a/util/mario/synth.py +++ b/util/mario/synth.py @@ -36,7 +36,7 @@ def render_synth_wrapper(prot_ids: dict, db: dict, tpl_file: str) -> str: db[rp]['synth_wrapper_assign_read'] =\ ' ' + db[rp]['synth_wrapper_assign_read'].replace('\n', '\n ') - for wp in used_read_prots: + for wp in used_write_prots: db[wp]['synth_wrapper_ports_write'] =\ ' ' + db[wp]['synth_wrapper_ports_write'].replace('\n', '\n ') db[wp]['synth_wrapper_assign_write'] =\ diff --git a/util/mario/tracer.py b/util/mario/tracer.py new file mode 100644 index 00000000..493be78d --- /dev/null +++ b/util/mario/tracer.py @@ -0,0 +1,132 @@ +#!/usr/env python3 +# Copyright 2022 ETH Zurich and University of Bologna. +# Solderpad Hardware License, Version 0.51, see LICENSE for details. +# SPDX-License-Identifier: SHL-0.51 + +# Authors: +# - Tobias Senti +# - Thomas Benz + +""" MARIO tracer interaction""" +import flatdict +from mako.template import Template + +TRACER_BODY = ''' +// The tracer for the ${identifier} iDMA +`define IDMA_TRACER_${identifier_cap}(__backend_inst, __out_f) <%text>\\ +`ifndef SYNTHESYS <%text>\\ +`ifndef VERILATOR <%text>\\ + initial begin : inital_tracer_${identifier} <%text>\\ + automatic bit first_iter = 1; <%text>\\ + automatic integer tf; <%text>\\ + automatic `IDMA_TRACER_MAX_TYPE cnst [string]; <%text>\\ + automatic `IDMA_TRACER_MAX_TYPE meta [string]; <%text>\\ + automatic `IDMA_TRACER_MAX_TYPE busy [string]; <%text>\\ + automatic `IDMA_TRACER_MAX_TYPE bus [string]; <%text>\\ + automatic string trace; <%text>\\ + #0; <%text>\\ + tf = $fopen(__out_f, "w"); <%text>\\ + $display("[iDMA Tracer] Logging %s to %s", `"__backend_inst`", __out_f); <%text>\\ + forever begin <%text>\\ + @(posedge __backend_inst``.clk_i); <%text>\\ + if(__backend_inst``.rst_ni & |__backend_inst``.busy_o) begin <%text>\\ + /* Trace */ <%text>\\ + trace = "{"; <%text>\\ + /* Constants */ <%text>\\ + cnst = '{ <%text>\\ + "inst" : `"__backend_inst`", <%text>\\ + "identifier" : "${identifier}", <%text>\\ + "data_width" : __backend_inst``.DataWidth, <%text>\\ + "addr_width" : __backend_inst``.AddrWidth, <%text>\\ + "user_width" : __backend_inst``.UserWidth, <%text>\\ + "axi_id_width" : __backend_inst``.AxiIdWidth, <%text>\\ + "num_ax_in_flight" : __backend_inst``.NumAxInFlight, <%text>\\ + "buffer_depth" : __backend_inst``.BufferDepth, <%text>\\ + "tf_len_width" : __backend_inst``.TFLenWidth, <%text>\\ + "mem_sys_depth" : __backend_inst``.MemSysDepth, <%text>\\ + "combined_shifter" : __backend_inst``.CombinedShifter, <%text>\\ + "rw_coupling_avail" : __backend_inst``.RAWCouplingAvail, <%text>\\ + "mask_invalid_data" : __backend_inst``.MaskInvalidData, <%text>\\ + "hardware_legalizer" : __backend_inst``.HardwareLegalizer, <%text>\\ + "reject_zero_tfs" : __backend_inst``.RejectZeroTransfers, <%text>\\ + "error_cap" : __backend_inst``.ErrorCap, <%text>\\ + "print_fifo_info" : __backend_inst``.PrintFifoInfo <%text>\\ + }; <%text>\\ + meta = '{ <%text>\\ + "time" : $time() <%text>\\ + }; <%text>\\ + busy = '{ <%text>\\ + "buffer" : __backend_inst``.busy_o.buffer_busy, <%text>\\ + "r_dp" : __backend_inst``.busy_o.r_dp_busy, <%text>\\ + "w_dp" : __backend_inst``.busy_o.w_dp_busy, <%text>\\ + "r_leg" : __backend_inst``.busy_o.r_leg_busy, <%text>\\ + "w_leg" : __backend_inst``.busy_o.w_leg_busy, <%text>\\ + "eh_fsm" : __backend_inst``.busy_o.eh_fsm_busy, <%text>\\ + "eh_cnt" : __backend_inst``.busy_o.eh_cnt_busy, <%text>\\ + "raw_coupler" : __backend_inst``.busy_o.raw_coupler_busy <%text>\\ + }; <%text>\\ + bus = '{ <%text>\\ +${signals} + }; <%text>\\ + /* Assembly */ <%text>\\ + `IDMA_TRACER_STR_ASSEMBLY(cnst, first_iter); <%text>\\ + `IDMA_TRACER_STR_ASSEMBLY(meta, 1); <%text>\\ + `IDMA_TRACER_STR_ASSEMBLY(busy, 1); <%text>\\ + `IDMA_TRACER_STR_ASSEMBLY(bus, 1); <%text>\\ + `IDMA_TRACER_CLEAR_COND(first_iter); <%text>\\ + /* Commit */ <%text>\\ + $fwrite(tf, $sformatf("%s}<%text>\\n", trace)); <%text>\\ + end <%text>\\ + end <%text>\\ + end <%text>\\ +`endif <%text>\\ +`endif +''' + + +def render_tracer(prot_ids: dict, db: dict, tpl_file: str) -> str: + """Generate racer""" + tracer_body = '' + + with open(tpl_file, 'r', encoding='utf-8') as templ_file: + tracer_tpl = templ_file.read() + + # render for every is + for prot_id in prot_ids: + + # signals + signals = '' + + # handle read ports + for read_prot in prot_ids[prot_id]['ar']: + sig_dict = flatdict.FlatDict(db[read_prot]['trace_signals']['read'], delimiter='_') + for signal in sig_dict: + signals += ' ' + signals += f'"{read_prot}_{signal}": __backend_inst``.{sig_dict[signal]}' + signals += ', \\\n' + + for write_prot in prot_ids[prot_id]['aw']: + sig_dict = flatdict.FlatDict(db[write_prot]['trace_signals']['write'], delimiter='_') + for signal in sig_dict: + signals += ' ' + signals += f'"{write_prot}_{signal}": __backend_inst``.{sig_dict[signal]}' + signals += ', \\\n' + + # post-processing + signals = signals[:-4] + ' \\' + + context_body = { + 'identifier': prot_id, + 'identifier_cap': prot_id.upper(), + 'signals': signals + } + + # render + tracer_body += Template(TRACER_BODY).render(**context_body) + + # render tracer context + context = { + 'body': tracer_body + } + + return Template(tracer_tpl).render(**context) diff --git a/util/trace_idma.py b/util/trace_idma.py index ad57b213..50ac8c08 100644 --- a/util/trace_idma.py +++ b/util/trace_idma.py @@ -1,21 +1,24 @@ #!/usr/bin/env python3 -# Copyright 2022 ETH Zurich and University of Bologna. +# Copyright 2023 ETH Zurich and University of Bologna. # Solderpad Hardware License, Version 0.51, see LICENSE for details. # SPDX-License-Identifier: SHL-0.51 -# Author: Thomas Benz +# Authors: +# - Thomas Benz """Functions used to parse and evaluate iDMA trace files.""" +import argparse import ast import sys from pprint import pprint as pp +from mario.database import read_database +from mario.util import prepare_ids def strb_to_bytes(strobe: int) -> int: """Returns the amount of valid bytes in a strobe value""" res = 0 - # iterate over strobe for byte_en in str(bin(strobe))[2:]: if byte_en == '1': @@ -29,7 +32,6 @@ def read_trace(fn: str) -> list: # resulting list of trace events trace = [] - # read and parse file with open(fn, 'r', encoding='utf8') as tf: for line in tf: @@ -42,10 +44,14 @@ def read_trace(fn: str) -> list: def extract_parameter(trace: list) -> dict: """Extracts the parameter of the DMA backend the run resulted from""" - return trace[0]['cnst'] + if len(trace) > 0 and 'cnst' in trace[0]: + return trace[0]['cnst'] + else: + print('Trace file is empty or constant header is malformed') + sys.exit(0) -def get_global_utilization(trace: list, data_width: int) -> list: +def get_global_utilization(trace: list, params: dict, be_info: dict) -> list: """Calculates the global utilization [read, write] of the DMA""" read_data = 0 # in bytes @@ -53,21 +59,59 @@ def get_global_utilization(trace: list, data_width: int) -> list: for ele in trace: # add read contribution - if ele['axib']['r_ready'] and ele['axib']['r_valid']: - read_data += data_width // 8 + for read_prot in be_info['read_prots']: + if ele['bus'][f'{read_prot}_rsp_ready'] and ele['bus'][f'{read_prot}_rsp_valid']: + read_data += params['data_width'] // 8 # add write contribution - if ele['axib']['w_ready'] and ele['axib']['w_valid']: - write_data += strb_to_bytes(ele['axib']['w_strb']) + for write_prot in be_info['write_prots']: + if ele['bus'][f'{write_prot}_req_ready'] and ele['bus'][f'{write_prot}_req_valid']: + write_data += strb_to_bytes(ele['bus'][f'{write_prot}_req_strobe']) # calculate maximum possible amount of data - max_data = len(trace) * data_width // 8 + max_data = len(trace) * params['data_width'] // 8 return [read_data / max_data, write_data / max_data] +def main(): + # Parse Arguments + parser = argparse.ArgumentParser( + prog='trace_idma', + description='Trace iDMA files to analyze them.' + ) + parser.add_argument('--db', dest='db', nargs='*', required=True, help='Database files') + parser.add_argument('--trace', dest='trace_file', required=True, help='Trace file') + args = parser.parse_args() + + # get database to fetch interface names + database = read_database(args.db) + + # read trace, fetch parameters + idma_trace = read_trace(args.trace_file) + params = extract_parameter(idma_trace) + + # fetch and parse identifier + id = bytes.fromhex(hex(params['identifier'])[2:]).decode("ASCII") + read_prots = prepare_ids([id])[id]['ar'] + write_prots = prepare_ids([id])[id]['aw'] + read_sigs = [database[r]['trace_signals']['read'] for r in read_prots] + write_sigs = [database[w]['trace_signals']['write'] for w in write_prots] + + # pack data + be_info = { + 'read_prots': read_prots, + 'write_prots': write_prots, + 'read_sigs': read_sigs, + 'write_sigs': write_sigs + } + + # get utilization + pp(get_global_utilization(idma_trace, params, be_info)) + + # no issues + return 0 + + if __name__ == '__main__': - _, filename = sys.argv - idma_trace = read_trace(filename) - idma_data_width = extract_parameter(idma_trace)['data_width'] - pp(get_global_utilization(idma_trace, idma_data_width)) + sys.exit(main())