From 2e173f9b56a28690c2d95960145e7b5ed6f49179 Mon Sep 17 00:00:00 2001 From: Thomas Benz <tbenz@iis.ee.ethz.ch> 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 | 2 +- test/frontend/tb_idma_desc64_top.sv | 2 +- 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 | 68 ++++++++++--- 21 files changed, 360 insertions(+), 129 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..86802252 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_write_req_o.r_valid + ready: obi_write_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 <tbenz@ethz.ch> + +// 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>\</%text> + if(__cond) begin <%text>\</%text> + trace = $sformatf("%s'%s':{", trace, `"__dict`"); <%text>\</%text> + foreach(__dict``[key]) trace = $sformatf("%s'%s': 0x%0x,", trace, key, __dict``[key]); <%text>\</%text> + trace = $sformatf("%s},", trace); <%text>\</%text> + end + +// helper to clear a condition +`define IDMA_TRACER_CLEAR_COND(__cond) <%text>\</%text> + if(__cond) begin <%text>\</%text> + __cond = ~__cond; <%text>\</%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 <tbenz@ethz.ch> - -// 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..d7f42c3d 100644 --- a/test/frontend/tb_idma_desc64_bench.sv +++ b/test/frontend/tb_idma_desc64_bench.sv @@ -97,7 +97,7 @@ module tb_idma_desc64_bench // set seed initial begin - int drop = $urandom(Seed); + automatic int drop = $urandom(Seed); end class stimulus_t; 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/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 <tsenti@.ethz.ch> +# - Thomas Benz <tbenz@iis.ee.ethz.ch> + +""" 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>\\</%text> +`ifndef SYNTHESYS <%text>\\</%text> +`ifndef VERILATOR <%text>\\</%text> + initial begin : inital_tracer_${identifier} <%text>\\</%text> + automatic bit first_iter = 1; <%text>\\</%text> + automatic integer tf; <%text>\\</%text> + automatic `IDMA_TRACER_MAX_TYPE cnst [string]; <%text>\\</%text> + automatic `IDMA_TRACER_MAX_TYPE meta [string]; <%text>\\</%text> + automatic `IDMA_TRACER_MAX_TYPE busy [string]; <%text>\\</%text> + automatic `IDMA_TRACER_MAX_TYPE bus [string]; <%text>\\</%text> + automatic string trace; <%text>\\</%text> + #0; <%text>\\</%text> + tf = $fopen(__out_f, "w"); <%text>\\</%text> + $display("[iDMA Tracer] Logging %s to %s", `"__backend_inst`", __out_f); <%text>\\</%text> + forever begin <%text>\\</%text> + @(posedge __backend_inst``.clk_i); <%text>\\</%text> + if(__backend_inst``.rst_ni & |__backend_inst``.busy_o) begin <%text>\\</%text> + /* Trace */ <%text>\\</%text> + trace = "{"; <%text>\\</%text> + /* Constants */ <%text>\\</%text> + cnst = '{ <%text>\\</%text> + "inst" : `"__backend_inst`", <%text>\\</%text> + "identifier" : "${identifier}", <%text>\\</%text> + "data_width" : __backend_inst``.DataWidth, <%text>\\</%text> + "addr_width" : __backend_inst``.AddrWidth, <%text>\\</%text> + "user_width" : __backend_inst``.UserWidth, <%text>\\</%text> + "axi_id_width" : __backend_inst``.AxiIdWidth, <%text>\\</%text> + "num_ax_in_flight" : __backend_inst``.NumAxInFlight, <%text>\\</%text> + "buffer_depth" : __backend_inst``.BufferDepth, <%text>\\</%text> + "tf_len_width" : __backend_inst``.TFLenWidth, <%text>\\</%text> + "mem_sys_depth" : __backend_inst``.MemSysDepth, <%text>\\</%text> + "combined_shifter" : __backend_inst``.CombinedShifter, <%text>\\</%text> + "rw_coupling_avail" : __backend_inst``.RAWCouplingAvail, <%text>\\</%text> + "mask_invalid_data" : __backend_inst``.MaskInvalidData, <%text>\\</%text> + "hardware_legalizer" : __backend_inst``.HardwareLegalizer, <%text>\\</%text> + "reject_zero_tfs" : __backend_inst``.RejectZeroTransfers, <%text>\\</%text> + "error_cap" : __backend_inst``.ErrorCap, <%text>\\</%text> + "print_fifo_info" : __backend_inst``.PrintFifoInfo <%text>\\</%text> + }; <%text>\\</%text> + meta = '{ <%text>\\</%text> + "time" : $time() <%text>\\</%text> + }; <%text>\\</%text> + busy = '{ <%text>\\</%text> + "buffer" : __backend_inst``.busy_o.buffer_busy, <%text>\\</%text> + "r_dp" : __backend_inst``.busy_o.r_dp_busy, <%text>\\</%text> + "w_dp" : __backend_inst``.busy_o.w_dp_busy, <%text>\\</%text> + "r_leg" : __backend_inst``.busy_o.r_leg_busy, <%text>\\</%text> + "w_leg" : __backend_inst``.busy_o.w_leg_busy, <%text>\\</%text> + "eh_fsm" : __backend_inst``.busy_o.eh_fsm_busy, <%text>\\</%text> + "eh_cnt" : __backend_inst``.busy_o.eh_cnt_busy, <%text>\\</%text> + "raw_coupler" : __backend_inst``.busy_o.raw_coupler_busy <%text>\\</%text> + }; <%text>\\</%text> + bus = '{ <%text>\\</%text> +${signals} + }; <%text>\\</%text> + /* Assembly */ <%text>\\</%text> + `IDMA_TRACER_STR_ASSEMBLY(cnst, first_iter); <%text>\\</%text> + `IDMA_TRACER_STR_ASSEMBLY(meta, 1); <%text>\\</%text> + `IDMA_TRACER_STR_ASSEMBLY(busy, 1); <%text>\\</%text> + `IDMA_TRACER_STR_ASSEMBLY(bus, 1); <%text>\\</%text> + `IDMA_TRACER_CLEAR_COND(first_iter); <%text>\\</%text> + /* Commit */ <%text>\\</%text> + $fwrite(tf, $sformatf("%s}<%text>\\</%text>n", trace)); <%text>\\</%text> + end <%text>\\</%text> + end <%text>\\</%text> + end <%text>\\</%text> +`endif <%text>\\</%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..d211d2a0 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 <tbenz@iis.ee.ethz.ch> +# Authors: +# - Thomas Benz <tbenz@iis.ee.ethz.ch> """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: @@ -45,7 +47,7 @@ def extract_parameter(trace: list) -> dict: return trace[0]['cnst'] -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 +55,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())