├── .dir-locals.el ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.org ├── ci ├── Jenkinsfile └── run-hw-tests.sh ├── doc └── .gitkeep ├── driver ├── Makefile ├── example_range │ ├── .clang-format │ ├── Makefile │ ├── config.json │ └── range.c ├── lowlevel │ ├── .clang-format │ ├── Makefile │ └── ll_driver.c ├── pulp-notes.org ├── rt │ ├── .clang-format │ ├── Makefile │ ├── config.json │ ├── driver_example.c │ ├── rt_data_trace_debugger.h │ ├── rt_test.c │ ├── rt_trace_debugger.c │ └── rt_trace_debugger.h └── test_interrupt │ ├── .clang-format │ ├── Makefile │ └── interrupt.c ├── include ├── .gitkeep ├── trdb_pkg.sv └── trdb_tb_pkg.sv ├── rtl ├── trace_debugger.sv ├── trace_debugger_stimuli_gen.sv ├── tracer_if.sv ├── tracer_reg_if.sv ├── trdb_align.sv ├── trdb_align8.sv ├── trdb_apb_if.sv ├── trdb_branch_map.sv ├── trdb_filter.sv ├── trdb_lzc.sv ├── trdb_packet_emitter.sv ├── trdb_priority.sv ├── trdb_reg.sv └── trdb_timer.sv ├── src_files.yml ├── tb ├── .gitkeep ├── Makefile ├── driver.svh ├── dummy │ └── apb_bus_if.sv ├── reader.svh ├── response.svh ├── scoreboard.svh ├── scripts │ └── vsim.tcl ├── stimuli.svh ├── stimuli │ └── test ├── trace_debugger_if.sv ├── trace_debugger_wrapper.sv ├── trdb_tb.sv └── trdb_tb_top.sv ├── test-64 └── .gitkeep ├── test └── .gitkeep └── waves └── trace_debugger.tcl /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023 ETH Zurich and University of Bologna. 2 | ;; Solderpad Hardware License, Version 0.51, see LICENSE for details. 3 | ;; SPDX-License-Identifier: SHL-0.51 4 | ;; 5 | ;; Robert Balas 6 | 7 | ;;; Directory Local Variables 8 | ;;; For more information see (info "(emacs) Directory Variables") 9 | 10 | ((nil . ((fill-column . 100))) 11 | (verilog-mode 12 | ;; (verilog-indent-lists quote nil) 13 | ;; (verilog-auto-lineup quote all) 14 | (verilog-cexp-indent . 4) 15 | (verilog-case-indent . 4) 16 | (verilog-indent-level-behavioral . 4) 17 | (verilog-indent-level-declaration . 4) 18 | (verilog-indent-level-module . 4) 19 | (verilog-indent-level . 4))) 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | driver/build* 2 | /change-author.sh 3 | build 4 | TAGS 5 | gmon.out 6 | *.o 7 | *.so 8 | /trdb/scratch 9 | /trdb/trdb 10 | /trdb/tests 11 | work/ 12 | trdb/doc/ 13 | /modelsim.ini 14 | /driver/wave.do 15 | /transcript 16 | /vsim.wlf 17 | /vsim.dbg 18 | /vloggy 19 | *.wlf 20 | *.dbg 21 | *.vstf 22 | .build-rtl 23 | .lib-rtl 24 | .opt-rtl 25 | *.riscv.cvs 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rtl/common_cells"] 2 | path = rtl/common_cells 3 | url = git@github.com:pulp-platform/common_cells.git 4 | [submodule "rtl/tech_cells_generic"] 5 | path = rtl/tech_cells_generic 6 | url = git@github.com:pulp-platform/tech_cells_generic.git 7 | [submodule "trdb"] 8 | path = trdb 9 | url = git@github.com:pulp-platform/trdb.git 10 | [submodule "rtl/axi"] 11 | path = rtl/axi 12 | url = git@github.com:pulp-platform/axi.git 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SOLDERPAD HARDWARE LICENSE version 0.51 2 | 3 | This license is based closely on the Apache License Version 2.0, but is not 4 | approved or endorsed by the Apache Foundation. A copy of the non-modified 5 | Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. 6 | 7 | As this license is not currently OSI or FSF approved, the Licensor permits any 8 | Work licensed under this License, at the option of the Licensee, to be treated 9 | as licensed under the Apache License Version 2.0 (which is so approved). 10 | 11 | This License is licensed under the terms of this License and in particular 12 | clause 7 below (Disclaimer of Warranties) applies in relation to its use. 13 | 14 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 15 | 16 | 1. Definitions. 17 | 18 | "License" shall mean the terms and conditions for use, reproduction, and 19 | distribution as defined by Sections 1 through 9 of this document. 20 | 21 | "Licensor" shall mean the Rights owner or entity authorized by the Rights owner 22 | that is granting the License. 23 | 24 | "Legal Entity" shall mean the union of the acting entity and all other entities 25 | that control, are controlled by, or are under common control with that entity. 26 | For the purposes of this definition, "control" means (i) the power, direct or 27 | indirect, to cause the direction or management of such entity, whether by 28 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 29 | outstanding shares, or (iii) beneficial ownership of such entity. 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising 32 | permissions granted by this License. 33 | 34 | "Rights" means copyright and any similar right including design right (whether 35 | registered or unregistered), semiconductor topography (mask) rights and 36 | database rights (but excluding Patents and Trademarks). 37 | 38 | "Source" form shall mean the preferred form for making modifications, including 39 | but not limited to source code, net lists, board layouts, CAD files, 40 | documentation source, and configuration files. 41 | 42 | "Object" form shall mean any form resulting from mechanical transformation or 43 | translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, the instantiation of a hardware design and 45 | conversions to other media types, including intermediate forms such as 46 | bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask 47 | works). 48 | 49 | "Work" shall mean the work of authorship, whether in Source form or other 50 | Object form, made available under the License, as indicated by a Rights notice 51 | that is included in or attached to the work (an example is provided in the 52 | Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object form, that 55 | is based on (or derived from) the Work and for which the editorial revisions, 56 | annotations, elaborations, or other modifications represent, as a whole, an 57 | original work of authorship. For the purposes of this License, Derivative Works 58 | shall not include works that remain separable from, or merely link (or bind by 59 | name) or physically connect to or interoperate with the interfaces of, the Work 60 | and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any design or work of authorship, including the 63 | original version of the Work and any modifications or additions to that Work or 64 | Derivative Works thereof, that is intentionally submitted to Licensor for 65 | inclusion in the Work by the Rights owner or by an individual or Legal Entity 66 | authorized to submit on behalf of the Rights owner. For the purposes of this 67 | definition, "submitted" means any form of electronic, verbal, or written 68 | communication sent to the Licensor or its representatives, including but not 69 | limited to communication on electronic mailing lists, source code control 70 | systems, and issue tracking systems that are managed by, or on behalf of, the 71 | Licensor for the purpose of discussing and improving the Work, but excluding 72 | communication that is conspicuously marked or otherwise designated in writing 73 | by the Rights owner as "Not a Contribution." 74 | 75 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 76 | of whom a Contribution has been received by Licensor and subsequently 77 | incorporated within the Work. 78 | 79 | 2. Grant of License. Subject to the terms and conditions of this License, each 80 | Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 81 | no-charge, royalty-free, irrevocable license under the Rights to reproduce, 82 | prepare Derivative Works of, publicly display, publicly perform, sublicense, 83 | and distribute the Work and such Derivative Works in Source or Object form and 84 | do anything in relation to the Work as if the Rights did not exist. 85 | 86 | 3. Grant of Patent License. Subject to the terms and conditions of this 87 | License, each Contributor hereby grants to You a perpetual, worldwide, 88 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this 89 | section) patent license to make, have made, use, offer to sell, sell, import, 90 | and otherwise transfer the Work, where such license applies only to those 91 | patent claims licensable by such Contributor that are necessarily infringed by 92 | their Contribution(s) alone or by combination of their Contribution(s) with the 93 | Work to which such Contribution(s) was submitted. If You institute patent 94 | litigation against any entity (including a cross-claim or counterclaim in a 95 | lawsuit) alleging that the Work or a Contribution incorporated within the Work 96 | constitutes direct or contributory patent infringement, then any patent 97 | licenses granted to You under this License for that Work shall terminate as of 98 | the date such litigation is filed. 99 | 100 | 4. Redistribution. You may reproduce and distribute copies of the Work or 101 | Derivative Works thereof in any medium, with or without modifications, and in 102 | Source or Object form, provided that You meet the following conditions: 103 | 104 | You must give any other recipients of the Work or Derivative Works a copy 105 | of this License; and 106 | 107 | You must cause any modified files to carry prominent notices stating that 108 | You changed the files; and 109 | 110 | You must retain, in the Source form of any Derivative Works that You 111 | distribute, all copyright, patent, trademark, and attribution notices from 112 | the Source form of the Work, excluding those notices that do not pertain to 113 | any part of the Derivative Works; and 114 | 115 | If the Work includes a "NOTICE" text file as part of its distribution, then 116 | any Derivative Works that You distribute must include a readable copy of 117 | the attribution notices contained within such NOTICE file, excluding those 118 | notices that do not pertain to any part of the Derivative Works, in at 119 | least one of the following places: within a NOTICE text file distributed as 120 | part of the Derivative Works; within the Source form or documentation, if 121 | provided along with the Derivative Works; or, within a display generated by 122 | the Derivative Works, if and wherever such third-party notices normally 123 | appear. The contents of the NOTICE file are for informational purposes only 124 | and do not modify the License. You may add Your own attribution notices 125 | within Derivative Works that You distribute, alongside or as an addendum to 126 | the NOTICE text from the Work, provided that such additional attribution 127 | notices cannot be construed as modifying the License. You may add Your own 128 | copyright statement to Your modifications and may provide additional or 129 | different license terms and conditions for use, reproduction, or 130 | distribution of Your modifications, or for any such Derivative Works as a 131 | whole, provided Your use, reproduction, and distribution of the Work 132 | otherwise complies with the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 135 | Contribution intentionally submitted for inclusion in the Work by You to the 136 | Licensor shall be under the terms and conditions of this License, without any 137 | additional terms or conditions. Notwithstanding the above, nothing herein shall 138 | supersede or modify the terms of any separate license agreement you may have 139 | executed with Licensor regarding such Contributions. 140 | 141 | 6. Trademarks. This License does not grant permission to use the trade names, 142 | trademarks, service marks, or product names of the Licensor, except as required 143 | for reasonable and customary use in describing the origin of the Work and 144 | reproducing the content of the NOTICE file. 145 | 146 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 147 | writing, Licensor provides the Work (and each Contributor provides its 148 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 149 | KIND, either express or implied, including, without limitation, any warranties 150 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any risks 153 | associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, whether in 156 | tort (including negligence), contract, or otherwise, unless required by 157 | applicable law (such as deliberate and grossly negligent acts) or agreed to in 158 | writing, shall any Contributor be liable to You for damages, including any 159 | direct, indirect, special, incidental, or consequential damages of any 160 | character arising as a result of this License or out of the use or inability to 161 | use the Work (including but not limited to damages for loss of goodwill, work 162 | stoppage, computer failure or malfunction, or any and all other commercial 163 | damages or losses), even if such Contributor has been advised of the 164 | possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 167 | Derivative Works thereof, You may choose to offer, and charge a fee for, 168 | acceptance of support, warranty, indemnity, or other liability obligations 169 | and/or rights consistent with this License. However, in accepting such 170 | obligations, You may act only on Your own behalf and on Your sole 171 | responsibility, not on behalf of any other Contributor, and only if You agree 172 | to indemnify, defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason of your 174 | accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Robert Balas 2 | # Copyright and related rights are licensed under the Solderpad Hardware 3 | # License, Version 0.51 (the "License"); you may not use this file except in 4 | # compliance with the License. You may obtain a copy of the License at 5 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | # or agreed to in writing, software, hardware and materials distributed under 7 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | # specific language governing permissions and limitations under the License. 10 | 11 | # Author: Robert Balas (balasr@student.ethz.ch) 12 | # Description: All in one 13 | 14 | SHELL = /bin/bash 15 | VERILATOR = verilator 16 | 17 | LINTER = $(VERILATOR) --lint-only 18 | MAKE = make 19 | CTAGS = ctags 20 | 21 | VVERSION = "10.7b" 22 | 23 | VLIB = vlib-$(VVERSION) 24 | VWORK = work 25 | 26 | VLOG = vlog-$(VVERSION) 27 | VLOG_FLAGS = -64 -lint #-pedanticerrors 28 | VLOG_LOG = vloggy 29 | 30 | VOPT = vopt-$(VVERSION) 31 | VOPT_FLAGS = -64 -debugdb -fsmdebug +acc -check_synthesis #=mnprft -pedanticerrors 32 | 33 | VSIM = vsim-$(VVERSION) 34 | VSIM_FLAGS = 35 | ALL_VSIM_FLAGS = $(VSIM_FLAGS) -64 36 | VSIM_SCRIPT = tb/scripts/vsim.tcl 37 | 38 | RTLSRC_TB_PKG := $(wildcard include/trdb_tb*.sv) 39 | RTLSRC_TB_TOP := $(wildcard tb/*_top.sv) 40 | RTLSRC_TB := $(wildcard tb/*.sv) \ 41 | $(wildcard tb/dummy/*.sv) 42 | RTLSRC_PKG := $(wildcard include/trdb_pkg.sv) 43 | RTLSRC := $(wildcard rtl/*.sv) \ 44 | $(wildcard rtl/tech_cells_generic/*.sv) \ 45 | $(wildcard rtl/common_cells/*.sv) 46 | 47 | RTLSRC_VLOG_TB_TOP := $(basename $(notdir $(RTLSRC_TB_TOP))) 48 | RTLSRC_VOPT_TB_TOP := $(addsuffix _vopt, $(RTLSRC_VLOG_TB_TOP)) 49 | 50 | DPINAME = trdb/dpi/autogen_trdb_sv.h 51 | DPISRC = $(RTLSRC_TB_PKG) 52 | SV_LIB = trdb/.libs/libtrdb 53 | CFLAGS = -Wall -Wextra -Wno-missing-field-initializers \ 54 | -Wno-unused-function -Wno-missing-braces \ 55 | -O2 -g -fpic \ 56 | -DENABLE_LOGGING -DNDEBUG 57 | 58 | 59 | ALL_TESTS = $(wildcard test/*.cvs) 60 | ALL_TESTS_64 = $(wildcard test-64/*.cvs) 61 | ALL_TEST_RESULTS = $(addsuffix .test, $(basename $(ALL_TESTS))) 62 | ALL_TEST_RESULTS_64 = $(addsuffix .test, $(basename $(ALL_TESTS_64))) 63 | 64 | # rtl related targets 65 | .PHONY: lint 66 | lint: $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) 67 | $(LINTER) -I. -Iinclude/ -Itb/ $(RTLSRC_PKG) $(RTLSRC) \ 68 | $(RTLSRC_TB_PKG) $(RTLSRC_TB) 69 | 70 | 71 | # driver related targets 72 | .PHONY: driver-all 73 | driver-all: check-env 74 | $(MAKE) -C driver/lowlevel all 75 | $(MAKE) -C driver/rt all 76 | 77 | .PHONY: driver-run 78 | driver-run: check-env 79 | $(MAKE) -C driver/lowlevel run 80 | 81 | .PHONY: driver-clean 82 | driver-clean: check-env 83 | $(MAKE) -C driver/lowlevel clean 84 | $(MAKE) -C driver/rt clean 85 | 86 | 87 | # check if environment is setup properly 88 | check-env: 89 | @if test "$(PULP_SDK_HOME)" = "" ; then \ 90 | echo "PULP_SDK_HOME not set"; \ 91 | exit 1; \ 92 | fi 93 | 94 | # make sure that we also compile the library in 64-bit mode if we request it 95 | ifeq ($(findstring +define+TRDB_ARCH64,$(VLOG_FLAGS)),+define+TRDB_ARCH64) 96 | CFLAGS+=-DTRDB_ARCH64 97 | endif 98 | 99 | # c model and decompression tools 100 | $(SV_LIB).so: 101 | cd trdb; \ 102 | autoconf -i; \ 103 | ./configure; \ 104 | $(MAKE) all CFLAGS="$(CFLAGS)"; 105 | 106 | c-all: $(SV_LIB).so 107 | 108 | c-sv-lib: $(SV_LIB).so 109 | 110 | .PHONY: c-clean 111 | c-clean: 112 | $(MAKE) -C trdb clean 113 | 114 | .PHONY: c-docs 115 | c-docs: 116 | $(MAKE) -C trdb doxygen-doc 117 | 118 | # testbench compilation and optimization 119 | .lib-rtl: 120 | $(VLIB) $(VWORK) 121 | touch .lib-rtl 122 | 123 | .build-rtl: .lib-rtl $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) 124 | $(VLOG) -work $(VWORK) $(VLOG_FLAGS) $(RTLSRC_PKG) $(RTLSRC) \ 125 | $(RTLSRC_TB_PKG) $(RTLSRC_TB) 126 | touch .build-rtl 127 | 128 | .opt-rtl: .build-rtl 129 | $(VOPT) -work $(VWORK) $(VOPT_FLAGS) $(RTLSRC_VLOG_TB_TOP) -o \ 130 | $(RTLSRC_VOPT_TB_TOP) 131 | touch .opt-rtl 132 | 133 | vlib: .lib-rtl 134 | vlog: .build-rtl 135 | tb-all: .opt-rtl 136 | 137 | .PHONY: dpiheader 138 | dpiheader: tb-all 139 | $(VLOG) -work $(VWORK) -l $(VLOG_LOG) -dpiheader $(DPINAME) $(DPISRC) 140 | 141 | # run tb and exit 142 | .PHONY: tb-run 143 | tb-run: ALL_VSIM_FLAGS += -c 144 | tb-run: tb-all c-sv-lib 145 | $(VSIM) -work $(VWORK) -sv_lib $(SV_LIB) $(ALL_VSIM_FLAGS) \ 146 | $(RTLSRC_VOPT_TB_TOP) -do 'source $(VSIM_SCRIPT); exit -f' 147 | 148 | # run tb and drop into interactive shell 149 | .PHONY: tb-run-sh 150 | tb-run-sh: ALL_VSIM_FLAGS += -c 151 | tb-run-sh: tb-all c-sv-lib 152 | $(VSIM) -work $(VWORK) -sv_lib $(SV_LIB) $(ALL_VSIM_FLAGS) \ 153 | $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT) 154 | 155 | # run tb with simulator gui 156 | .PHONY: tb-run-gui 157 | tb-run-gui: ALL_VSIM_FLAGS += -gui -debugdb 158 | tb-run-gui: tb-all c-sv-lib 159 | $(VSIM) -work $(VWORK) -sv_lib $(SV_LIB) $(ALL_VSIM_FLAGS) \ 160 | $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT) 161 | 162 | 163 | .PHONY: tb-clean 164 | tb-clean: 165 | if [ -d $(VWORK) ]; then rm -r $(VWORK); fi 166 | rm -f transcript vsim.wlf .build-rtl .opt-rtl .lib-rtl 167 | 168 | generate-tests: 169 | $(MAKE) -C trdb spike-traces-32 170 | cp trdb/riscv-traces-32/*.cvs test/ 171 | 172 | generate-tests-64: 173 | $(MAKE) -C trdb spike-traces-64 174 | cp trdb/riscv-traces-64/*.cvs test-64/ 175 | 176 | test: $(ALL_TEST_RESULTS) 177 | grep -B 2 -A 6 "Simulation Results" test/*.riscv.test \ 178 | | tee test/summary.test 179 | @if [ ! -s test/summary.test ]; then \ 180 | echo "EMPTY RESULTS"; \ 181 | exit 1; \ 182 | elif grep -q "TEST FAIL" test/summary.test; then \ 183 | echo "ATLEAST ONE FAILURE"; \ 184 | exit 1; \ 185 | else \ 186 | echo "ALL TESTS PASSED"; \ 187 | exit 0; \ 188 | fi 189 | 190 | 191 | test-64: VLOG_FLAGS+=+define+TRDB_ARCH64 192 | test-64: CFLAGS+=-DTRDB_ARCH64 193 | test-64: $(ALL_TEST_RESULTS_64) 194 | grep -B 2 -A 6 "Simulation Results" test-64/*.riscv.test \ 195 | | tee test-64/summary.test 196 | @if [ ! -s test-64/summary.test ]; then \ 197 | echo "EMPTY RESULTS"; \ 198 | exit 1; \ 199 | elif grep -q "TEST FAIL" test-64/summary.test; then \ 200 | echo "ATLEAST ONE FAILURE"; \ 201 | exit 1; \ 202 | else \ 203 | echo "ALL TESTS PASSED"; \ 204 | exit 0; \ 205 | fi 206 | 207 | 208 | # we use separate wlf otherwise vsim complains 209 | %.test: %.cvs tb-all c-sv-lib 210 | $(VSIM) -work $(VWORK) -sv_lib $(SV_LIB) $(ALL_VSIM_FLAGS) -c \ 211 | +cvs +implicitret +testname=$< -wlf $@.wlf \ 212 | $(RTLSRC_VOPT_TB_TOP) -do 'source $(VSIM_SCRIPT); exit -f' > $@ 213 | 214 | .PHONY: test-clean 215 | test-clean: 216 | rm -rf test/*.test test/*.wlf test/*.dbg 217 | rm -rf test-64/*.test test-64/*.wlf test-64/*.dbg 218 | 219 | # general targets 220 | .PHONY: TAGS 221 | TAGS: check-env 222 | echo "Generating TAGS for driver..." 223 | echo "Generating TAGS for RTL..." 224 | $(CTAGS) -R -e -h=".c.h.sv.svh" --tag-relative=always \ 225 | --exclude=$(PULP_SDK_HOME) --exclude=trdb/ \ 226 | . $(PULP_PROJECT_HOME) \ 227 | rtl/ tb/ 228 | 229 | .PHONY: docs 230 | docs: c-docs 231 | 232 | .PHONY: all 233 | all: driver-all tb-all c-all 234 | 235 | .PHONY: clean 236 | clean: tb-clean c-clean test-clean 237 | 238 | .PHONY: distclean 239 | distclean: clean 240 | rm -f TAGS 241 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * Trace Debugger For RISC-V Core 2 | ** Overview 3 | An instruction tracer records the sequence of instructions that the CPU 4 | executes. Since the required bandwidth to record every instruction directly and 5 | stream it out through some interface is immense, that's why we employ a few 6 | compression techniques, most notable a method called branch tracing. In branch 7 | tracing we only record changes in the control flow which are unpredictable by 8 | looking at the executed binary. In RISC-V that boils down to branches, jumps 9 | which depends on some registry value and exceptions. Every time the CPU hits 10 | such a discontinuity, we emit a packet which contains enough information to 11 | describe the changes. Such a sequence of packages and the binary which as used 12 | to produced it can be used to reconstruct the original sequence of executed 13 | instructions, as long as we don't have any self-modifying code. 14 | 15 | If one is interested in not only the instructions but also their operand values, 16 | such as the read and written data and their address, then one would have to do 17 | data tracing. Drawbacks are that bandwidth rises dramatically compared to 18 | plain instruction tracing and that the implementation becomes more complicated, 19 | but this solves the self-modying code problem. 20 | 21 | On the PULP platform we rarely deal with the self-modying code issue except for 22 | the interrupt vector table, which gets populated during runtime. This problem 23 | can be solved withouth employing data tracing by emitting additional packets 24 | during an exception, so as to record the first instruction of the exception 25 | handler. 26 | 27 | This project currently contains an instruction tracer for the RISCY core of 28 | the PULP platform (RTL model), a C model of the tracer and C routines to 29 | decompress recorded traces in the packet format. 30 | 31 | ** Packet Format 32 | The used packet format is described [[https://github.com/riscv/riscv-trace-spec][here]]. 33 | 34 | ** Organization of this repository 35 | #+BEGIN_EXAMPLE 36 | . 37 | |-- doc 38 | |-- driver Trace debugger driver for the PULP platform 39 | |-- include 40 | |-- rtl RTL model of the trace debugger 41 | |-- tb Testbench, uses the C model as golden model 42 | |-- trdb Decompression routines and C model 43 | |-- waves 44 | |-- LICENSE 45 | |-- Makefile 46 | |-- README.org This file 47 | `-- src_files.yml Configuration file to use it as an IP in the PULP platform 48 | #+END_EXAMPLE 49 | 50 | ** Checkout, build and running tests 51 | Make sure that the environment variables ~VSIM~ and ~RISCV~ point to your 52 | simulator and RISC-V toolchain respectively. Checkout the repository like 53 | by calling 54 | 55 | #+BEGIN_SRC bash 56 | git clone --recurse https://github.com/pulp-platform/trace_debugger. 57 | #+END_SRC 58 | 59 | Build the tests by calling 60 | 61 | #+BEGIN_SRC bash 62 | make generate-tests-64 63 | #+END_SRC 64 | 65 | This will fetch spike and riscv-tests and put them into ~trdb/~. These are 66 | then run and the instruction traces captured which in turn can be fed to the 67 | rtl testbench by finally calling 68 | 69 | #+BEGIN_SRC bash 70 | make test 71 | #+END_SRC 72 | 73 | If everything works out the test should print =ALL TESTS PASSED=. 74 | 75 | ** TRDB, the trace compression/decompression tool 76 | Trdb is a command line tool which can produce the same output has the 77 | hardware trace debugger given a stimuli file, decompress received packets 78 | given the original binary and also show objdump like disassembly of the 79 | reconstructed instruction sequence. More information on usage and examples 80 | can be found [[https://github.com/pulp-platform/trace_debugger/tree/master/trdb][here]]. 81 | 82 | ** Building the driver for the PULP platform 83 | Make sure you have setup the [[https://github.com/pulp-platform/pulp-sdk][PULP SDK]] as described there and have put in in 84 | your =$PATH$= environment variable. Then run =make driver-all=. 85 | 86 | ** Generating tag files 87 | Run =make TAGS= to generate etag files for emacs. 88 | 89 | ** Building the documentation 90 | There is no documentation for the hardware yet. 91 | -------------------------------------------------------------------------------- /ci/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node ('centos7' + ' && !vm1-centos7'){ 2 | try { 3 | stage('Preparation') { 4 | withEnv(['SPIKE_TEST_TRACES_URL=https://github.com/bluewww/spike-instruction-trace-patch', 5 | 'PATH+WHATEVER=/home/balasr/.local/bin:/home/balasr/.riscv/bin']) { 6 | checkout scm 7 | sh 'git submodule update --init --recursive' 8 | sh "make generate-tests" 9 | sh "make generate-tests-64" 10 | } 11 | } 12 | stage('Build (32-bit)') { 13 | if (isUnix()) { 14 | sh "make clean" 15 | sh "make tb-all" 16 | } else { 17 | echo "unix only" 18 | } 19 | } 20 | stage('Test (32-bit)') { 21 | sh "make -j8 test" 22 | } 23 | 24 | stage('Build (64-bit)') { 25 | if (isUnix()) { 26 | sh "make clean" 27 | sh "make c-sv-lib tb-all VLOG_FLAGS+=+define+TRDB_ARCH64" 28 | } else { 29 | echo "unix only" 30 | } 31 | } 32 | stage('Test (64-bit)') { 33 | sh "make -j8 test-64" 34 | } 35 | 36 | } catch (e) { 37 | currentBuild.result = "FAILED" 38 | echo "SENDING E-MAIL" 39 | notifyFailed() 40 | throw e 41 | } 42 | } 43 | 44 | def notifyFailed() { 45 | emailext ( 46 | subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", 47 | body: """

FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':

48 |

Check console output at "${env.JOB_NAME} [${env.BUILD_NUMBER}]"

""", 49 | recipientProviders: [[$class: 'DevelopersRecipientProvider']] 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /ci/run-hw-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) 5 | 6 | make -C ${ROOT} c-clean c-sv-lib tb-all tb-run 7 | -------------------------------------------------------------------------------- /doc/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/trace_debugger/0df525be5a3856a8af2b99a4396aece3bfd141a9/doc/.gitkeep -------------------------------------------------------------------------------- /driver/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Robert Balas 2 | # Copyright and related rights are licensed under the Solderpad Hardware 3 | # License, Version 0.51 (the "License"); you may not use this file except in 4 | # compliance with the License. You may obtain a copy of the License at 5 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | # or agreed to in writing, software, hardware and materials distributed under 7 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | # specific language governing permissions and limitations under the License. 10 | 11 | # Author: Robert Balas (balasr@student.ethz.ch) 12 | # Description: Build drivers of the trace debugger for the PULP platform 13 | -------------------------------------------------------------------------------- /driver/example_range/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | UseTab: Always 5 | BreakBeforeBraces: Linux 6 | AlwaysBreakBeforeMultilineStrings: true 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortLoopsOnASingleLine: false 9 | AllowShortFunctionsOnASingleLine: false 10 | IndentCaseLabels: false 11 | AlignEscapedNewlinesLeft: false 12 | AlignTrailingComments: true 13 | AllowAllParametersOfDeclarationOnNextLine: false 14 | AlignAfterOpenBracket: true 15 | SpaceAfterCStyleCast: false 16 | MaxEmptyLinesToKeep: 2 17 | BreakBeforeBinaryOperators: NonAssignment 18 | BreakStringLiterals: false 19 | SortIncludes: false 20 | ContinuationIndentWidth: 4 21 | ColumnLimit: 80 -------------------------------------------------------------------------------- /driver/example_range/Makefile: -------------------------------------------------------------------------------- 1 | PULP_APP = range 2 | PULP_APP_FC_SRCS = range.c ../rt/rt_trace_debugger.c 3 | PULP_APP_HOST_SRCS = 4 | PULP_CFLAGS = -O0 -g -mnohwloop 5 | 6 | PULP_USER_CONFIG = $(CURDIR)/config.json 7 | override CONFIG_OPT += runner/peripherals=true 8 | 9 | include $(PULP_SDK_HOME)/install/rules/pulp_rt.mk 10 | #make conf CONFIG_OPT=rt/trace=1 to debug 11 | -------------------------------------------------------------------------------- /driver/example_range/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "devices": { 3 | "spim": { 4 | "type": "spim_verif", 5 | "interface": "spim0", 6 | "cs": 1, 7 | "config": { 8 | "tx_file": { 9 | "path": "tx_spi", 10 | "qpi": "true" 11 | } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /driver/example_range/range.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pulp.h" 3 | #include "rt/rt_api.h" 4 | #include "../rt/rt_trace_debugger.h" 5 | 6 | 7 | int trace_me(int a, int b); 8 | int dont_trace_me(int a, int b, int c); 9 | 10 | int main() 11 | { 12 | /* First configure the SPI device */ 13 | rt_spim_conf_t spi_conf; 14 | /* Get default configuration */ 15 | rt_spim_conf_init(&spi_conf); 16 | /* Set maximum baudrate. Can actually be lower than 17 | * that depending on the best divider found 18 | */ 19 | spi_conf.max_baudrate = 1000000; 20 | /* SPI interface identifier as the Pulp chip can have 21 | * several interfaces 22 | */ 23 | spi_conf.id = 0; 24 | /* Chip select */ 25 | spi_conf.cs = 1; 26 | 27 | /* Then open the device */ 28 | rt_spim_t *spim = rt_spim_open(NULL, &spi_conf, NULL); 29 | if (spim == NULL) 30 | return -1; 31 | 32 | /* setup trace debugger configuration */ 33 | rt_trace_dbg_conf_t trdb_conf; 34 | rt_trace_debugger_conf_init(&trdb_conf); 35 | trdb_conf.buffer_size = 28; 36 | trdb_conf.ctrl_reg = TRDB_ENABLE; /* enable clock */ 37 | 38 | /* and open it */ 39 | rt_trace_dbg_t *trdb = 40 | rt_trace_debugger_open("test000", &trdb_conf, spim, NULL, NULL); 41 | if (!trdb) { 42 | rt_error("[TEST] failed to open trace debugger\n"); 43 | return -1; 44 | } 45 | /* configure range which we want to trace. We looked at the disassembly to 46 | * figure out the boundaries of trace_me(). 47 | */ 48 | rt_trace_debugger_ctrl(TRDB_LOWER_ADDR, 0x1c008eca); 49 | rt_trace_debugger_ctrl(TRDB_HIGHER_ADDR, 0x1c008f0c); 50 | 51 | /* want to trace range */ 52 | rt_trace_debugger_ctrl(TRDB_REG_FILTER, 53 | TRDB_APPLY_FILTERS | TRDB_TRACE_RANGE_EVENT); 54 | 55 | /* enable tracing */ 56 | rt_trace_debugger_ctrl(TRDB_REG_CTRL, TRDB_ENABLE | TRDB_TRACE_ACTIVATED); 57 | 58 | trace_me(0, 5); 59 | dont_trace_me(1, 2, 3); 60 | trace_me(10, 2); 61 | 62 | /* Let's call some functions to generated some code */ 63 | printf("Hello World!\n"); 64 | printf("Memory base address: %x\n", (unsigned int)rt_l2_base()); 65 | printf("Memory CAMERA RX: %x\n", UDMA_CAM_RX_ADDR(0)); 66 | printf("Memory TRACER RX: %x\n", UDMA_TRACER_RX_ADDR(0)); 67 | printf("Whoami: %d\n", (is_fc())); 68 | 69 | /* Run trdb -dSl --bfd driver_example/driver_example -x tx_spi 70 | * to recover trace 71 | */ 72 | 73 | /* TODO: wait for dma to finish, for now we just loop */ 74 | for (;;) { 75 | rt_event_yield(NULL); 76 | } 77 | 78 | rt_trace_debugger_close(trdb, NULL); 79 | rt_spim_close(spim, NULL); 80 | 81 | return 0; 82 | } 83 | 84 | int trace_me(int a, int b) 85 | { 86 | int c = a * b; 87 | int d = c * c; 88 | return a + b + c; 89 | } 90 | 91 | int dont_trace_me(int a, int b, int c) 92 | { 93 | return -a - b - c; 94 | } 95 | -------------------------------------------------------------------------------- /driver/lowlevel/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | UseTab: Always 5 | BreakBeforeBraces: Linux 6 | AlwaysBreakBeforeMultilineStrings: true 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortLoopsOnASingleLine: false 9 | AllowShortFunctionsOnASingleLine: false 10 | IndentCaseLabels: false 11 | AlignEscapedNewlinesLeft: false 12 | AlignTrailingComments: true 13 | AllowAllParametersOfDeclarationOnNextLine: false 14 | AlignAfterOpenBracket: true 15 | SpaceAfterCStyleCast: false 16 | MaxEmptyLinesToKeep: 2 17 | BreakBeforeBinaryOperators: NonAssignment 18 | BreakStringLiterals: false 19 | SortIncludes: false 20 | ContinuationIndentWidth: 4 21 | ColumnLimit: 80 -------------------------------------------------------------------------------- /driver/lowlevel/Makefile: -------------------------------------------------------------------------------- 1 | PULP_APP = ll_driver 2 | PULP_APP_FC_SRCS = ll_driver.c 3 | PULP_APP_HOST_SRCS = ll_driver.c 4 | PULP_CFLAGS = -O3 -g -mnohwloop 5 | 6 | include $(PULP_SDK_HOME)/install/rules/pulp_rt.mk 7 | -------------------------------------------------------------------------------- /driver/lowlevel/ll_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Robert Balas 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Author: Robert Balas (balasr@student.ethz.ch) 17 | * Description: Test the APB interface and UDMA functionality of the trace 18 | * debugger 19 | */ 20 | 21 | #include "pulp.h" 22 | #include 23 | 24 | union uint2ptr{ 25 | unsigned int i; 26 | unsigned int* p; 27 | } conv; 28 | 29 | void write_l2(unsigned int *addr, unsigned int value); 30 | 31 | unsigned int read_l2(unsigned int *addr); 32 | 33 | unsigned int write_and_read_l2(unsigned int *, unsigned int); 34 | 35 | int main() 36 | { 37 | /* activate clk to tracer interface to UDMA*/ 38 | plp_udma_cg_set(plp_udma_cg_get() | (1 << ARCHI_UDMA_TRACER_ID(0))); 39 | 40 | /* the trace debugger registers are mapped to 41 | * `define TRDB_START_ADDR 32'h1A12_0000 42 | * `define TRDB_END_ADDR 32'h1A12_0FFF 43 | * see in periph_bus_defines.sv 44 | */ 45 | 46 | /* allow interrupt by tracer interface to udma */ 47 | soc_eu_fcEventMask_setEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 48 | 49 | /* quickly queue some udma transfer */ 50 | unsigned int size = 32; 51 | unsigned int base = (unsigned int)rt_l2_base(); 52 | plp_udma_enqueue(UDMA_TRACER_RX_ADDR(0), base, size, 53 | UDMA_CHANNEL_CFG_SIZE_32); 54 | 55 | /* This should make the trace debugger start generating packets */ 56 | conv.i = 0x1a120000; 57 | write_l2(conv.p, 1); 58 | 59 | printf("uDMA request @%x:\n", UDMA_TRACER_RX_ADDR(0)); 60 | 61 | 62 | /* Let's call some functions to generated some code */ 63 | printf("Hello World!\n"); 64 | printf("Memory base address: %x\n", (unsigned int)rt_l2_base()); 65 | printf("Memory CAMERA RX: %x\n", UDMA_CAM_RX_ADDR(0)); 66 | printf("Memory TRACER RX: %x\n", UDMA_TRACER_RX_ADDR(0)); 67 | printf("Whoami: %d\n", (is_fc())); 68 | 69 | printf("Wait for interrupt\n"); 70 | wait_soc_event(ARCHI_SOC_EVENT_TRACER_RX(0)); 71 | clear_soc_event(ARCHI_SOC_EVENT_TRACER_RX(0)); 72 | 73 | /* we now dump the memory to check what happened */ 74 | for (unsigned int i = base; i < size + base; i+=4){ 75 | conv.i = i; 76 | printf("mem:%08x\n", read_l2(conv.p)); 77 | } 78 | return 0; 79 | } 80 | 81 | /* Let's just pray that this generated the right code */ 82 | void write_l2(unsigned int *addr, unsigned int value) 83 | { 84 | volatile unsigned int *uint_ptr = addr; 85 | *(uint_ptr) = value; 86 | } 87 | 88 | unsigned int read_l2(unsigned int *addr) 89 | { 90 | volatile unsigned int *uint_ptr = addr; 91 | return *(uint_ptr); 92 | } 93 | 94 | unsigned int write_and_read_l2(unsigned int *addr, unsigned int value) 95 | { 96 | volatile unsigned int *uint_ptr = addr; 97 | *(uint_ptr) = value; 98 | return *(uint_ptr); 99 | } 100 | -------------------------------------------------------------------------------- /driver/pulp-notes.org: -------------------------------------------------------------------------------- 1 | * Notes on using the PULP-SDK 2 | ** Flavours 3 | ~make conf gui=1 CONFIG_OPT=rt/trace=1 gdb=1~ 4 | 5 | ~make conf gui=1 CONFIG_OPT="rt/trace=1 vsim/args=-debugdb" gdb=1~ 6 | 7 | ~make conf gui=1 CONFIG_OPT="rt/trace=1 vsim/args=-debugdb vsim/tcl_args=-fsmdebug" clean all run~ 8 | 9 | ** Memory 10 | + ~0x1c00'0000~ to ~0x1c00'8000~ private bank 0 for fc data 11 | + ~0x1c00'8000~ to ~0x1c01'0000~ private bank 1 for fc code 12 | + ~0x1c01'0000~ to ~0x1c08'0000~ multi-banked area for udma data 13 | + ~rt_l2_base()~ returns ~0x1c01'0000~ 14 | 15 | 16 | ** PULP bridge commands 17 | + ~plpbridge --config build/pulpissimo-riscy/rtl_config.json~ 18 | + ~ +plpbridge --chip=pulpissimo --binary=build/pulpissimo/test/test+ ~ 19 | + ~plpbridge --chip=pulpissimo stop~ 20 | + ~plpbridge --chip=pulpissimo read --addr=0x1c000000 --size=1000~ 21 | + ~plpbridge --chip=pulpissimo write --addr=0x1c000000 --value=0x12345678 --size=1000~ 22 | + ~plpbridge --config build/pulpissimo-riscy/rtl_config.json~ 23 | ** Compiler settings 24 | Run =/home/msc18f22/projects/pulp-sdk/pkg/pulp_riscv_gcc/1.0.5/bin/riscv32-unknown-elf-gcc -march=rv32imcxpulpv2 -Q --help=target= 25 | The following settings are available 26 | + -mComp [disabled] 27 | + -mDIE= 0 28 | + -mEci [disabled] 29 | + -mFC= 0 30 | + -mL1Cl= 0 31 | + -mL1Fc= 0 32 | + -mL2= 0 33 | + -mPE= 0 34 | + -mWci [disabled] 35 | + -mabi= ilp32 36 | + -march= rv32imcxpulpv2 37 | + -mbranch-cost=N 0 38 | + -mchip= [default] 39 | + -mcmodel= medlow 40 | + -mconf= all 41 | + -mcpu= pulpv2 42 | + -mdf [disabled] 43 | + -mdiv [disabled] 44 | + -mexplicit-relocs [disabled] 45 | + -mfdiv [disabled] 46 | + -mfpdouble= double 47 | + -mmemcpy [disabled] 48 | + -mnativeomp [disabled] 49 | + -mnoabs [disabled] 50 | + -mnoaddsubnormround [disabled] 51 | + -mnobitop [disabled] 52 | + -mnoclip [disabled] 53 | + -mnofinduct [disabled] 54 | + -mnohwloop [disabled] 55 | + -mnoindregreg [disabled] 56 | + -mnomac [disabled] 57 | + -mnominmax [disabled] 58 | + -mnomulmacnormround [disabled] 59 | + -mnopartmac [disabled] 60 | + -mnopostmod [disabled] 61 | + -mnosext [disabled] 62 | + -mnoshufflepack [disabled] 63 | + -mnoslet [disabled] 64 | + -mnovect [disabled] 65 | + -mplt [enabled] 66 | + -mreg= 32 67 | + -msave-restore [disabled] 68 | + -msloop [disabled] 69 | + -msmall-data-limit=N 8 70 | + -mstrict-align [disabled] 71 | + -mtune=PROCESSOR 72 | 73 | ** Code fragments on programming the event unit 74 | #+BEGIN_SRC C 75 | printf("UDMA base address: 0x%x\n", ARCHI_SOC_PERIPHERALS_ADDR + ARCHI_UDMA_OFFSET); 76 | printf("hal_udma_channel_base: %d@0x%x\n", 9, hal_udma_channel_base(9)); 77 | printf("hal_udma_channel_base: %d@0x%x\n", 8, hal_udma_channel_base(8)); 78 | printf("hal_udma_channel_base: %d@0x%x\n", 7, hal_udma_channel_base(7)); 79 | printf("hal_udma_channel_base: %d@0x%x\n", 6, hal_udma_channel_base(6)); 80 | printf("hal_udma_channel_base: %d@0x%x\n", 5, hal_udma_channel_base(5)); 81 | printf("hal_udma_channel_base: %d@0x%x\n", 4, hal_udma_channel_base(4)); 82 | printf("hal_udma_channel_base: %d@0x%x\n", 3, hal_udma_channel_base(3)); 83 | printf("hal_udma_channel_base: %d@0x%x\n", 2, hal_udma_channel_base(2)); 84 | printf("hal_udma_channel_base: %d@0x%x\n", 1, hal_udma_channel_base(1)); 85 | printf("hal_udma_channel_base: %d@0x%x\n", 0, hal_udma_channel_base(0)); 86 | //((id)<<4) 87 | // ARCHI_SOC_PERIPHERALS_ADDR + ARCHI_UDMA_OFFSET + 88 | // UDMA_PERIPH_OFFSET(id>>1) + UDMA_CHANNEL_OFFSET(id&1) 89 | // UDMA_PERIPH_AREA_SIZE_LOG2 7 90 | //((id)< 2 | #include "pulp.h" 3 | #include "rt/rt_api.h" 4 | #include "rt_trace_debugger.h" 5 | 6 | 7 | unsigned do_some_computation(unsigned arg0, unsigned arg1, unsigned arg3) 8 | { 9 | unsigned buffer_size = 24; 10 | volatile char buffer[buffer_size]; 11 | 12 | unsigned tmp = arg0 + arg1; 13 | 14 | for (unsigned i = 0; i < buffer_size; i++) { 15 | buffer[i] = 0xff; 16 | } 17 | 18 | return tmp * arg3 - arg0; 19 | } 20 | 21 | int main() 22 | { 23 | 24 | #ifdef __RT_USE_IO 25 | printf("__RT_USE_IO is set\n"); 26 | #else 27 | printf("__RT_USE_IO is NOT set\n"); 28 | #endif 29 | 30 | #ifdef __RT_USE_TRACE 31 | printf("__RT_USE_TRACE is set\n"); 32 | #else 33 | printf("__RT_USE_TRACE is NOT set\n"); 34 | #endif 35 | 36 | /* 37 | * QSPI Setup 38 | */ 39 | rt_spim_conf_t spi_conf; 40 | /* Get default configuration */ 41 | rt_spim_conf_init(&spi_conf); 42 | /* Set maximum baudrate. Can actually be lower than that depending on the 43 | * best divider found 44 | */ 45 | spi_conf.max_baudrate = 1000000000; 46 | /* SPI interface identifier as the Pulp chip can have several interfaces 47 | */ 48 | spi_conf.id = 0; 49 | /* Chip select */ 50 | spi_conf.cs = 1; 51 | /* Then open the device */ 52 | rt_spim_t *spim = rt_spim_open(NULL, &spi_conf, NULL); 53 | if (spim == NULL) 54 | return -1; 55 | 56 | 57 | /* 58 | * Trace Debugger Setup 59 | */ 60 | rt_trace_dbg_conf_t trdb_conf; 61 | rt_trace_debugger_conf_init(&trdb_conf); 62 | trdb_conf.buffer_size = 4 * 1024; 63 | trdb_conf.ctrl_reg = 64 | TRDB_ENABLE | TRDB_TRACE_ACTIVATED; /* enable clock and tracer*/ 65 | /* Open it */ 66 | rt_trace_dbg_t *trdb = 67 | rt_trace_debugger_open("test000", &trdb_conf, spim, NULL, NULL); 68 | if (!trdb) { 69 | rt_error("[TEST] failed to open trace debugger\n"); 70 | return -1; 71 | } 72 | 73 | /* 74 | * Tracing begins ... 75 | */ 76 | 77 | /* Let's call some functions to generated some code */ 78 | printf("Hello World!\n"); 79 | printf("Memory base address: %x\n", (unsigned int)rt_l2_base()); 80 | 81 | int *abuf = rt_alloc(RT_ALLOC_FC_DATA, sizeof(int) * 128); 82 | if (!abuf) { 83 | rt_error("[TEST] out of memory\m"); 84 | return -1; 85 | } 86 | 87 | printf("Memory CAMERA RX: %x\n", UDMA_CAM_RX_ADDR(0)); 88 | printf("Memory TRACER RX: %x\n", UDMA_TRACER_RX_ADDR(0)); 89 | printf("Whoami: %d\n", (is_fc())); 90 | 91 | rt_free(RT_ALLOC_FC_DATA, abuf, sizeof(int) * 128); 92 | 93 | /* infinite loop */ 94 | for (;;) { 95 | rt_event_execute(NULL, 0); 96 | } 97 | rt_trace_debugger_close(trdb, NULL); 98 | 99 | rt_spim_close(spim, NULL); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /driver/rt/rt_data_trace_debugger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Robert Balas 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /* 17 | * Authors: Robert Balas (balasr@student.ethz.ch) 18 | */ 19 | #ifndef __RT_DATA_TRACE_DEBUGGER_H__ 20 | #define __RT_DATA_TRACE_DEBUGGER_H__ 21 | typedef struct { 22 | unsigned int buffer_size; 23 | int dummy; 24 | unsigned int ctrl_reg; 25 | } rt_trace_dbg_conf_t; 26 | 27 | typedef struct { 28 | int channel; 29 | unsigned int buffer_size; 30 | // uint8_t *trace_buffs[2]; 31 | // rt_event_sched_t *sched_i; 32 | } rt_trace_dbg_t; 33 | #endif 34 | -------------------------------------------------------------------------------- /driver/rt/rt_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rt/rt_api.h" 3 | 4 | //#define BUFF_SIZE 8192 5 | #define BUFF_SIZE 128 6 | 7 | static uint8_t *buffers[2]; 8 | 9 | static void end_of_transfer(void *arg) 10 | { 11 | rt_trace(RT_TRACE_DEV_CTRL, "[Trace_DBG] end of transfer, re-enqueue...\n"); 12 | int index = (int)arg; 13 | 14 | for (unsigned int i = 0; i < BUFF_SIZE; i++) { 15 | rt_trace(RT_TRACE_DEV_CTRL, "Mem@%p: 0x%x\n", (buffers[index] + i), 16 | *(buffers[index] + i)); 17 | } 18 | 19 | rt_periph_copy(NULL, 2 * ARCHI_UDMA_TRACER_ID(0), 20 | (unsigned int)buffers[index], BUFF_SIZE, 0, 21 | rt_event_get(NULL, end_of_transfer, (void *)index)); 22 | } 23 | 24 | int main() 25 | { 26 | 27 | #ifdef __RT_USE_IO 28 | printf("__RT_USE_IO is set\n"); 29 | #else 30 | printf("__RT_USE_IO is NOT set\n"); 31 | #endif 32 | 33 | #ifdef __RT_USE_TRACE 34 | printf("__RT_USE_TRACE is set\n"); 35 | #else 36 | printf("__RT_USE_TRACE is NOT set\n"); 37 | #endif 38 | 39 | /* TODO: fix MACRO */ 40 | rt_trace(RT_TRACE_DEV_CTRL, "[TRACE_DBG] Init Tracer\n"); 41 | rt_trace(RT_TRACE_DEV_CTRL, "[TRACE_DBG] rt_event_alloc\n"); 42 | if (rt_event_alloc(NULL, 2)) 43 | return -1; 44 | 45 | rt_trace(RT_TRACE_DEV_CTRL, "[TRACE_DBG] rt_alloc buffer 0\n"); 46 | buffers[0] = rt_alloc(RT_ALLOC_PERIPH, BUFF_SIZE); 47 | if (buffers[0] == NULL) 48 | return -1; 49 | 50 | rt_trace(RT_TRACE_DEV_CTRL, "[TRACE_DBG] rt_alloc buffer 1\n"); 51 | buffers[1] = rt_alloc(RT_ALLOC_PERIPH, BUFF_SIZE); 52 | if (buffers[1] == NULL) 53 | return -1; 54 | 55 | rt_trace(RT_TRACE_DEV_CTRL, "[TRACE_DBG] enable udma channel clock\n"); 56 | plp_udma_cg_set(plp_udma_cg_get() | (1 << ARCHI_UDMA_TRACER_ID(0))); 57 | 58 | rt_trace(RT_TRACE_DEV_CTRL, 59 | "[Trace_DBG] enable udma trace debugger rx event\n"); 60 | soc_eu_fcEventMask_setEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 61 | 62 | 63 | rt_trace(RT_TRACE_DEV_CTRL, "[Trace_DBG] rt_periph_copy start\n"); 64 | 65 | rt_periph_copy(NULL, 2 * ARCHI_UDMA_TRACER_ID(0), (unsigned int)buffers[0], 66 | BUFF_SIZE, 0, 67 | rt_event_get(NULL, end_of_transfer, (void *)0)); 68 | rt_periph_copy(NULL, 2 * ARCHI_UDMA_TRACER_ID(0), (unsigned int)buffers[1], 69 | BUFF_SIZE, 0, 70 | rt_event_get(NULL, end_of_transfer, (void *)1)); 71 | 72 | 73 | rt_trace(RT_TRACE_DEV_CTRL, "[Trace_DBG] yield looping\n"); 74 | while (1) { 75 | rt_event_yield(NULL); 76 | } 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /driver/rt/rt_trace_debugger.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Robert Balas 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Authors: Robert Balas (balasr@student.ethz.ch) 17 | * Description: Driver for the trace debugger unit 18 | */ 19 | 20 | 21 | #include "rt/rt_api.h" 22 | /* TODO: Upstream this*/ 23 | #include "rt_trace_debugger.h" 24 | 25 | /* TODO: should this be allocated in the handler?*/ 26 | /* TODO: is this ok if I allocate resources just like this?*/ 27 | uint8_t *trace_buffs[2]; 28 | unsigned int buffer_size; 29 | unsigned int dummy; 30 | rt_event_sched_t *sched_i; 31 | rt_spim_t *trdb_spi; 32 | 33 | /* for type conversions */ 34 | union uint2ptr { 35 | unsigned int i; 36 | unsigned int *p; 37 | } conv; 38 | 39 | /* just comment this since if its too hard to enable the rt trace */ 40 | #define rt_trace(trace, x...) \ 41 | do { \ 42 | rt_msg(x); \ 43 | } while (0) 44 | 45 | /* we use this for register writes */ 46 | static void write_reg_l2(unsigned int addr, unsigned int value) 47 | { 48 | conv.i = addr; 49 | volatile unsigned int *uint_ptr = conv.p; 50 | *(uint_ptr) = value; 51 | } 52 | 53 | 54 | /* Initialize rt_trace_dbg_conf_t with default values */ 55 | void rt_trace_debugger_conf_init(rt_trace_dbg_conf_t *conf) 56 | { 57 | conf->buffer_size = 128; /* TODO: turn that up */ 58 | conf->dummy = 1; 59 | return; 60 | } 61 | 62 | 63 | void rt_trace_debugger_control(rt_trace_dbg_t *handle) 64 | { 65 | printf("unimplemented\n"); 66 | } 67 | 68 | 69 | /* TODO: this is just for testing, the API should be improved */ 70 | void rt_trace_debugger_ctrl(unsigned int addr, unsigned int value) 71 | { 72 | write_reg_l2(addr, value); 73 | } 74 | 75 | 76 | /* Allocate trace debugger device */ 77 | rt_trace_dbg_t *rt_trace_debugger_open(char *dev_name, 78 | rt_trace_dbg_conf_t *conf, 79 | rt_spim_t *spi, rt_event_sched_t *sched, 80 | rt_event_t *event) 81 | { 82 | /* TODO: open only once */ 83 | if (!conf || !dev_name) 84 | return NULL; 85 | 86 | if (!spi) 87 | return NULL; 88 | trdb_spi = spi; 89 | 90 | /* TODO: do I need to disable irq, what could potentially go wrong? */ 91 | int irq = rt_irq_disable(); 92 | rt_trace(RT_TRACE_DEV_CTRL, 93 | "[TRDB] opening trace debugger device (name: %s)\n", dev_name); 94 | 95 | /* TODO: let's skip that for now */ 96 | /* rt_dev_t *dev = rt_dev_get(dev_name); */ 97 | 98 | buffer_size = conf->buffer_size; 99 | dummy = conf->dummy; 100 | /* TODO: is it ok to hold onto this pointer?*/ 101 | sched_i = sched; 102 | 103 | /* TODO: really alloc enough events */ 104 | if (rt_event_alloc(sched_i, 4)) 105 | goto fail_event; 106 | 107 | rt_trace_dbg_t *tracer = rt_alloc(RT_ALLOC_FC_DATA, sizeof(rt_trace_dbg_t)); 108 | if (!tracer) { 109 | rt_error("[TRDB] failed to allocate rt_trace_dbg_t struct memory\n"); 110 | goto fail_alloc_fc; 111 | } 112 | 113 | tracer->channel = 2 * ARCHI_UDMA_TRACER_ID(0); 114 | tracer->buffer_size = conf->buffer_size; 115 | 116 | /* spi needs 4 byte alignment */ 117 | trace_buffs[0] = rt_alloc_align(RT_ALLOC_PERIPH, buffer_size, 4); 118 | trace_buffs[1] = rt_alloc_align(RT_ALLOC_PERIPH, buffer_size, 4); 119 | if (!trace_buffs[0] || !trace_buffs[1]) { 120 | rt_error("[TRDB] failed to allocate memory for double buffers\n"); 121 | goto fail_alloc_periph; 122 | } 123 | 124 | 125 | /* This handles the udma side, enables the clock for the peripheral and 126 | * enables the event in the event unit 127 | */ 128 | plp_udma_cg_set(plp_udma_cg_get() | (1 << ARCHI_UDMA_TRACER_ID(0))); 129 | soc_eu_fcEventMask_setEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 130 | 131 | /* TODO: don't know if need to propagate rt_periph_copy_t*/ 132 | rt_periph_copy(NULL, 2 * ARCHI_UDMA_TRACER_ID(0), 133 | (unsigned int)trace_buffs[0], buffer_size, 0, 134 | rt_event_get(sched_i, __rt_trace_debugger_eot, (void *)0)); 135 | rt_periph_copy(NULL, 2 * ARCHI_UDMA_TRACER_ID(0), 136 | (unsigned int)trace_buffs[1], buffer_size, 0, 137 | rt_event_get(sched_i, __rt_trace_debugger_eot, (void *)1)); 138 | 139 | /* This applies some desired intial settings */ 140 | write_reg_l2(TRDB_REG_CTRL, conf->ctrl_reg); 141 | 142 | rt_irq_restore(irq); 143 | return tracer; 144 | 145 | fail_alloc_periph: 146 | if (!trace_buffs[0]) 147 | rt_free(RT_ALLOC_PERIPH, trace_buffs[0], buffer_size); 148 | if (!trace_buffs[1]) 149 | rt_free(RT_ALLOC_PERIPH, trace_buffs[1], buffer_size); 150 | rt_free(RT_ALLOC_FC_DATA, tracer, sizeof(rt_trace_dbg_t)); 151 | fail_alloc_fc: 152 | soc_eu_fcEventMask_clearEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 153 | plp_udma_cg_set(plp_udma_cg_get() & ~(1 << ARCHI_UDMA_TRACER_ID(0))); 154 | fail_event: 155 | rt_irq_restore(irq); 156 | return NULL; 157 | } 158 | 159 | 160 | void rt_trace_debugger_close(rt_trace_dbg_t *handle, rt_event_t *event) 161 | { 162 | rt_trace(RT_TRACE_DEV_CTRL, "[TRDB] closing trace debugger\n"); 163 | write_reg_l2(TRDB_REG_CTRL, TRDB_DISABLE); 164 | /* TODO: don't know what to do with event */ 165 | if (!handle) 166 | rt_free(RT_ALLOC_FC_DATA, handle, sizeof(rt_trace_dbg_t)); 167 | if (!trace_buffs[0]) 168 | rt_free(RT_ALLOC_PERIPH, trace_buffs[0], buffer_size); 169 | if (!trace_buffs[1]) 170 | rt_free(RT_ALLOC_PERIPH, trace_buffs[1], buffer_size); 171 | 172 | soc_eu_fcEventMask_clearEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 173 | /* TODO: probably shouldnt kill the transfer like that */ 174 | plp_udma_cg_set(plp_udma_cg_get() & ~(1 << ARCHI_UDMA_TRACER_ID(0))); 175 | rt_trace(RT_TRACE_DEV_CTRL, "[TRDB] closed trace debugger device.\n"); 176 | return; 177 | } 178 | 179 | int buffer_full[2] = {0}; 180 | /* ensure continous transfer */ 181 | void __rt_trace_debugger_eot(void *arg) 182 | { 183 | int index = (int)arg; 184 | int other = (index + 1) % 2; 185 | 186 | buffer_full[index] = 1; 187 | rt_spim_send_qspi(trdb_spi, trace_buffs[index], buffer_size * 8, 188 | RT_SPIM_CS_AUTO, 189 | rt_event_get(sched_i, __rt_spim_eot, (void *)index)); 190 | /* queue for other buffer*/ 191 | rt_periph_copy( 192 | NULL, 2 * ARCHI_UDMA_TRACER_ID(0), (unsigned int)trace_buffs[other], 193 | buffer_size, 0, 194 | rt_event_get(sched_i, __rt_trace_debugger_eot, (void *)other)); 195 | /* printf("trdb: buffer %d is %d\n", index, buffer_full[index]); */ 196 | } 197 | 198 | void __rt_spim_eot(void *arg) 199 | { 200 | buffer_full[(int)arg] = 0; 201 | printf("spim: buffer %d is %d\n", (int)arg, buffer_full[(int)arg]); 202 | } 203 | 204 | /* TODO: make this inline or a macro */ 205 | void rt_trace_debugger_userdata(unsigned int value) 206 | { 207 | write_reg_l2(TRDB_REG_DUMP, value); 208 | } 209 | 210 | void rt_trace_debugger_userdata_time(unsigned int value) 211 | { 212 | write_reg_l2(TRDB_REG_DUMP_WITH_TIME, value); 213 | } 214 | -------------------------------------------------------------------------------- /driver/rt/rt_trace_debugger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Robert Balas 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Authors: Robert Balas (balasr@student.ethz.ch) 17 | * Description: Driver for the trace debugger unit 18 | */ 19 | 20 | #ifndef __RT_TRACE_DEBUGGER_H__ 21 | #define __RT_TRACE_DEBUGGER_H__ 22 | /* TODO: make this include via rt_data.h, like the other drivers do */ 23 | #include "rt_data_trace_debugger.h" 24 | 25 | /* address of memory mapped register and controlflags settings the desired 26 | * bits 27 | */ 28 | #define TRDB_REG_CTRL 0x1a120000 29 | #define TRDB_DISABLE 0 30 | #define TRDB_ENABLE 1 31 | #define TRDB_TRACE_ACTIVATED (1 << 1) 32 | #define TRDB_CLEAR_FIFO (1 << 2) 33 | #define TRDB_FLUSH (1 << 3) 34 | 35 | #define TRDB_REG_STATUS 0x1a120004 36 | #define TRDB_QUALIFIED 1 37 | #define TRDB_PRIV_MATCH (1 << 1) 38 | #define TRDB_RANGE_MATCH (1 << 2) 39 | #define TRDB_FIFO_OVERFLOW (1 << 3) 40 | #define TRDB_EXTERNAL_FIFO_OVERFLOW (1 << 4) 41 | 42 | #define TRDB_REG_FILTER 0x1a120008 43 | #define TRDB_APPLY_FILTERS 1 44 | #define TRDB_TRACE_PRIV (1 << 1) 45 | #define TRDB_WHICH_PRIV (1 << 2) & (1 << 3) //TODO: macros 46 | #define TRDB_TRACE_RANGE_EVENT (1 << 4) 47 | #define TRDB_STOP_EVENT (1 << 6) 48 | 49 | #define TRDB_REG_DUMP 0x1a12000c 50 | #define TRDB_REG_DUMP_WITH_TIME 0x1a120010 51 | 52 | #define TRDB_LOWER_ADDR 0x1a120020 53 | #define TRDB_HIGHER_ADDR 0x1a120024 54 | 55 | 56 | void rt_trace_debugger_conf_init(rt_trace_dbg_conf_t *conf); 57 | rt_trace_dbg_t *rt_trace_debugger_open(char *, rt_trace_dbg_conf_t *, 58 | rt_spim_t *spi, rt_event_sched_t *, 59 | rt_event_t *); 60 | 61 | void rt_trace_debugger_ctrl(unsigned int addr, unsigned int value); 62 | void rt_trace_debugger_control(rt_trace_dbg_t *); 63 | void rt_trace_debugger_close(rt_trace_dbg_t *, rt_event_t *); 64 | void __rt_trace_debugger_eot(void *arg); 65 | void __rt_spim_eot(void *arg); 66 | void rt_trace_debugger_userdata(unsigned int value); 67 | void rt_trace_debugger_userdata_time(unsigned int value); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /driver/test_interrupt/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | UseTab: Always 5 | BreakBeforeBraces: Linux 6 | AlwaysBreakBeforeMultilineStrings: true 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortLoopsOnASingleLine: false 9 | AllowShortFunctionsOnASingleLine: false 10 | IndentCaseLabels: false 11 | AlignEscapedNewlinesLeft: false 12 | AlignTrailingComments: true 13 | AllowAllParametersOfDeclarationOnNextLine: false 14 | AlignAfterOpenBracket: true 15 | SpaceAfterCStyleCast: false 16 | MaxEmptyLinesToKeep: 2 17 | BreakBeforeBinaryOperators: NonAssignment 18 | BreakStringLiterals: false 19 | SortIncludes: false 20 | ContinuationIndentWidth: 4 21 | ColumnLimit: 80 -------------------------------------------------------------------------------- /driver/test_interrupt/Makefile: -------------------------------------------------------------------------------- 1 | PULP_APP = interrupt 2 | PULP_APP_FC_SRCS = interrupt.c 3 | PULP_APP_HOST_SRCS = interrupt.c 4 | PULP_CFLAGS = -O3 -g -mnohwloop 5 | 6 | include $(PULP_SDK_HOME)/install/rules/pulp_rt.mk 7 | -------------------------------------------------------------------------------- /driver/test_interrupt/interrupt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Robert Balas 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Author: Robert Balas (balasr@student.ethz.ch) 17 | * Description: Test for a straightforward udma interrupt situation 18 | */ 19 | 20 | #include "pulp.h" 21 | #include 22 | 23 | 24 | int main() 25 | { 26 | plp_udma_cg_set(plp_udma_cg_get() | (1 << ARCHI_UDMA_TRACER_ID(0))); 27 | soc_eu_fcEventMask_setEvent(ARCHI_SOC_EVENT_TRACER_RX(0)); 28 | plp_udma_enqueue(UDMA_TRACER_RX_ADDR(0), (unsigned int)rt_l2_base(), 12, 29 | UDMA_CHANNEL_CFG_SIZE_32); 30 | wait_soc_event(ARCHI_SOC_EVENT_TRACER_RX(0)); 31 | clear_soc_event(ARCHI_SOC_EVENT_TRACER_RX(0)); 32 | printf("Got interrupt\n"); 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /include/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/trace_debugger/0df525be5a3856a8af2b99a4396aece3bfd141a9/include/.gitkeep -------------------------------------------------------------------------------- /include/trdb_tb_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Testbench settings 13 | package trdb_tb_pkg; 14 | 15 | import trdb_pkg::*; 16 | 17 | // stimuli file 18 | // const string default_stimuli_path = "trdb/data/trdb_stimuli"; 19 | // const string stimuli_path = "trdb/data/enqueue_delayed/build/pulpissimo-riscy/trdb_stimuli"; 20 | // const string stimuli_path = "trdb/data/timer_oneshot/build/pulpissimo-riscy/trdb_stimuli"; 21 | // const string stimuli_path = "trdb/data/uart_loopback/build/pulpissimo-riscy/trdb_stimuli"; 22 | 23 | // test that is being run by default 24 | string default_stimuli_path = "trdb/data/coremark/build/pulpissimo-riscy/trdb_stimuli"; 25 | // name of current test 26 | string testname; 27 | // clock and acquisition related settings 28 | const time CLK_PHASE_HI = 5ns; 29 | const time CLK_PHASE_LO = 5ns; 30 | const time CLK_PERIOD = CLK_PHASE_HI + CLK_PHASE_LO; 31 | const time STIM_APPLICATION_DEL = CLK_PERIOD * 0.1; 32 | const time RESP_ACQUISITION_DEL = CLK_PERIOD * 0.9; 33 | const time RESET_DEL = STIM_APPLICATION_DEL; 34 | 35 | const int RESET_WAIT_CYCLES = 4; 36 | 37 | typedef struct { 38 | logic ivalid; 39 | logic iexception; 40 | logic interrupt; 41 | logic [CAUSELEN-1:0] cause; 42 | logic [XLEN-1:0] tval; 43 | logic [PRIVLEN-1:0] priv; 44 | logic [XLEN-1:0] iaddr; 45 | logic [ILEN-1:0] instr; 46 | logic compressed; 47 | } trdb_instr; 48 | 49 | typedef union packed { 50 | // TODO: we would like to have this parametrizable 51 | logic [127:0] bits; 52 | logic [4][31:0] slices; 53 | } trdb_packet; 54 | 55 | import "DPI-C" function void trdb_sv_alloc(); 56 | import "DPI-C" function void trdb_sv_free(); 57 | import "DPI-C" function void trdb_sv_set_full_address(input int full_address); 58 | import "DPI-C" function void trdb_sv_set_implicit_ret(input int implicit_ret); 59 | import "DPI-C" function void trdb_sv_feed_trace 60 | (input logic ivalid, iexception, interrupt, 61 | input logic [CAUSELEN-1:0] cause, input logic [XLEN-1:0] tval, 62 | input logic [PRIVLEN-1:0] priv, input logic [XLEN-1:0] iaddr, 63 | input logic [ILEN-1:0] instr, input logic compressed, 64 | input int packet_max_len, 65 | output logic [PACKET_TOTAL-1:0] packet_bits, output logic packet_valid); 66 | 67 | `include "../tb/stimuli.svh" 68 | `include "../tb/response.svh" 69 | `include "../tb/driver.svh" 70 | `include "../tb/reader.svh" 71 | `include "../tb/scoreboard.svh" 72 | 73 | endpackage // trdb_tb_pkg 74 | -------------------------------------------------------------------------------- /rtl/trace_debugger.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Compress instruction traces and filter them 13 | 14 | module trace_debugger import trdb_pkg::*; 15 | #(parameter APB_ADDR_WIDTH = 32) 16 | (input logic clk_i, 17 | input logic rst_ni, 18 | input logic test_mode_i, 19 | 20 | // data from the cpu 21 | input logic ivalid_i, //TODO: pipelined valid 22 | input logic iexception_i, 23 | input logic interrupt_i, 24 | input logic [CAUSELEN-1:0] cause_i, 25 | input logic [XLEN-1:0] tval_i, 26 | input logic [PRIVLEN-1:0] priv_i, 27 | input logic [XLEN-1:0] iaddr_i, 28 | input logic [ILEN-1:0] instr_i, 29 | input logic compressed_i, 30 | 31 | APB_BUS.Slave apb_slave, 32 | 33 | // generated packets, which go the the udma (or somewhere else) 34 | output logic [XLEN-1:0] packet_word_o, 35 | output logic packet_word_valid_o, 36 | input logic grant_i); 37 | 38 | 39 | // general control of this module 40 | // clock enabled 41 | logic trace_enable; 42 | logic clk_gated; 43 | // tracing enabled 44 | logic trace_activated; 45 | // proper privileges for debugging 46 | logic debug_mode; 47 | // whether input is good 48 | logic trace_valid; 49 | // control the streamer unit 50 | logic flush_stream; 51 | logic flush_confirm; 52 | // control the packet fifo 53 | logic clear_fifo; 54 | logic fifo_overflow; 55 | // special case to jump over vector table entries (which can't be inferred 56 | // by inspecting the programs' executable 57 | logic packet_after_exception; 58 | 59 | logic trace_full_addr; 60 | 61 | // register all inputs, we don't want to extend riscy's paths 62 | logic ivalid_q, ivalid_d; 63 | logic iexception_q, iexception_d; 64 | logic interrupt_q, interrupt_d; 65 | logic [CAUSELEN-1:0] cause_q, cause_d; 66 | // logic [XLEN-1:0] tval_d, tval_q; 67 | logic [PRIVLEN-1:0] priv_q, priv_d; 68 | logic [XLEN-1:0] iaddr_q, iaddr_d; 69 | logic [ILEN-1:0] instr_q, instr_d; 70 | logic compressed_q, compressed_d; 71 | 72 | 73 | // unused variables for a more extensive implementation 74 | // riscy doesn't have those features 75 | logic [XLEN-1:0] lc_tval; 76 | logic [CONTEXTLEN-1:0] tc_context; 77 | 78 | 79 | // we have three phases, called next cycle (nc), this cycle (tc) and next 80 | // cycle (nc), based on which we make decision whether we need to emit a 81 | // packet or not. 82 | logic [PRIVLEN-1:0] nc_priv, tc_priv; 83 | logic nc_privchange, tc_privchange; 84 | logic nc_exception, lc_exception; 85 | logic lc_u_discontinuity; 86 | logic tc_first_qualified; 87 | logic tc_is_branch; 88 | logic tc_branch_taken; 89 | logic tc_qualified, lc_qualified, nc_qualified, 90 | nc_unqualified; 91 | logic tc_compressed; 92 | logic [XLEN-1:0] tc_iaddr, nc_iaddr; 93 | logic lc_exception_sync; 94 | logic lc_interrupt; 95 | 96 | // pass delayed data 97 | logic [CAUSELEN-1:0] lc_cause; 98 | 99 | // registers to hold onto the input data for a few phases, mostly one 100 | logic interrupt0_q, interrupt0_d; 101 | logic interrupt1_q, interrupt1_d; 102 | logic [CAUSELEN-1:0] cause0_q, cause0_d; 103 | logic [CAUSELEN-1:0] cause1_q, cause1_d; 104 | logic [PRIVLEN-1:0] priv0_q, priv0_d; 105 | logic privchange0_q, privchange0_d; 106 | logic exception0_q, exception0_d, 107 | exception1_q, exception1_d, 108 | exception2_q, exception2_d; 109 | logic u_discontinuity0_q, u_discontinuity0_d, 110 | u_discontinuity1_q, u_discontinuity1_d; 111 | logic is_branch0_q, is_branch0_d; 112 | logic compressed0_q, compressed0_d; 113 | logic [XLEN-1:0] iaddr0_q, iaddr0_d; 114 | logic qualified0_q, qualified0_d, qualified1_q, 115 | qualified1_d; 116 | 117 | // variables for discontinuity decision making 118 | logic trace_implicit_ret; 119 | logic not_ret; 120 | logic really_c_jalr; 121 | logic really_c_jr; 122 | logic is_ret; 123 | logic is_c_ret; 124 | logic is_jump; 125 | logic is_priv_ret; 126 | 127 | // variables for the branch map 128 | logic branch_map_flush; 129 | logic branch_map_full; 130 | logic branch_map_empty; 131 | logic [30:0] branch_map; 132 | logic [4:0] branch_map_cnt; 133 | 134 | // variables for the packet generation 135 | logic packet_valid; 136 | trdb_format_e packet_format; 137 | trdb_subformat_e packet_subformat; 138 | 139 | // variables for address compression 140 | logic [$clog2(XLEN)-1+1:0] keep_addr_bits; 141 | logic [XLEN-1:0] diff_addr; 142 | 143 | // generated packet 144 | logic [PACKET_LEN-1:0] packet_gen_bits; 145 | logic [6:0] packet_gen_len; 146 | logic packet_gen_valid; 147 | 148 | // packet from fifo 149 | logic [PACKET_LEN-1:0] packet_fifo_bits; 150 | logic [6:0] packet_fifo_len; 151 | logic packet_fifo_valid; 152 | logic packet_fifo_not_full; 153 | 154 | // packet to word 155 | logic packet_is_read; 156 | logic [XLEN-1:0] packet_word; 157 | logic packet_word_valid; 158 | 159 | // Holds data from/to advanced peripheral bus 160 | logic [31:0] per_rdata; 161 | logic per_ready; 162 | logic [31:0] per_wdata; 163 | logic [APB_ADDR_WIDTH-1:0] per_addr; 164 | logic per_we; 165 | logic per_valid; 166 | 167 | // software dumping: certain writes to the trace debugger are included in 168 | // the packet stream 169 | logic [31:0] sw_word; 170 | logic sw_valid; 171 | logic sw_grant; 172 | 173 | // timer unit 174 | logic timer_rst; 175 | logic [TIMER_WIDTH-1:0] tu_time; 176 | logic tu_fulltime; 177 | logic tu_grant; 178 | logic tu_valid; 179 | logic tu_req; 180 | 181 | // filter unit 182 | logic apply_filters; 183 | logic trace_selected_priv; 184 | logic [1:0] trace_which_priv; 185 | logic trace_range_event; 186 | logic trace_stop_event; 187 | logic [XLEN-1:0] trace_lower_addr; 188 | logic [XLEN-1:0] trace_higher_addr; 189 | logic filter_qualified_decision; 190 | logic trace_req_deactivate; 191 | logic trace_range_match; 192 | logic trace_priv_match; 193 | 194 | // TODO: send this to reg 195 | assign timer_rst = '0; 196 | 197 | // to register all inputs 198 | assign ivalid_d = ivalid_i; 199 | assign iexception_d = iexception_i; 200 | assign interrupt_d = interrupt_i; 201 | assign cause_d = cause_i; 202 | assign priv_d = priv_i; 203 | assign iaddr_d = iaddr_i; 204 | assign instr_d = instr_i; 205 | assign compressed_d = compressed_i; 206 | 207 | // whether we do tracing at all 208 | assign trace_valid = ivalid_q && debug_mode && trace_enable; 209 | assign debug_mode = priv_q[PRIVLEN-1]; 210 | 211 | // TODO: make this configurationr register mapped 212 | assign packet_after_exception = '1; 213 | 214 | // unimplemented, just tie to zero 215 | assign lc_tval = '0; 216 | assign tc_context = '0; 217 | 218 | `ifndef SYNTHESIS 219 | trace_valid_and_debug: assert property 220 | (@(posedge clk_gated) disable iff (~rst_ni) (trace_enable |=> debug_mode)) 221 | else $info("[TRDB] @%t: Tracing works only in debug mode", 222 | $time); 223 | `endif 224 | 225 | // Buffer variables. Certain variables we need to hold up to three cycles 226 | assign interrupt0_d = interrupt_q; 227 | assign interrupt1_d = interrupt0_q; 228 | assign cause0_d = cause_q; 229 | assign cause1_d = cause0_q; 230 | assign priv0_d = priv_q; 231 | assign exception0_d = iexception_q && ivalid_q; 232 | assign exception1_d = exception0_q; 233 | assign exception2_d = exception1_q; 234 | assign compressed0_d = compressed_q; 235 | assign iaddr0_d = iaddr_q; 236 | 237 | // assign privchange0_d (below) 238 | // assign u_discontinuity0_d (below) 239 | // assign is_branch0_d (below) 240 | 241 | assign u_discontinuity1_d = u_discontinuity0_q; 242 | // TODO: add feature to have selective tracing, add enable with regmap 243 | assign qualified0_d = trace_enable && filter_qualified_decision; //& ivalid_q 244 | assign qualified1_d = qualified0_q; 245 | 246 | // Hook phase related variables up to proper register 247 | assign nc_priv = priv0_d; 248 | assign tc_priv = priv0_q; 249 | assign lc_interrupt = interrupt1_q; 250 | assign lc_cause = cause1_q; 251 | assign nc_privchange = privchange0_d; 252 | assign tc_privchange = privchange0_q; 253 | assign nc_exception = exception0_d; 254 | assign lc_exception = exception1_q; 255 | // with that variable we force another packet after an exception packet, so 256 | // that we don't need to know the vector table entries 257 | assign lc_exception_sync = exception2_q; 258 | assign lc_u_discontinuity = u_discontinuity1_q; 259 | assign tc_is_branch = is_branch0_q; 260 | assign nc_qualified = qualified0_d; 261 | assign tc_qualified = qualified0_q; 262 | assign lc_qualified = qualified1_q; 263 | assign tc_compressed = compressed0_q; 264 | assign nc_iaddr = iaddr0_d; 265 | assign tc_iaddr = iaddr0_q; 266 | // assign tc_first_qualified (below) 267 | // assign tc_branch_taken (below) 268 | 269 | // determine if we are allowed to emit packets for nc (next cycle) 270 | trdb_filter i_trdb_filter 271 | (.trace_activated_i(trace_activated), 272 | .trace_req_deactivate_o(trace_req_deactivate), 273 | .apply_filters_i(apply_filters), 274 | .trace_selected_priv_i(trace_selected_priv), 275 | .which_priv_i(trace_which_priv), 276 | .priv_i(priv_d[1:0]), 277 | .trace_range_event_i(trace_range_event), 278 | .trace_stop_event_i(trace_stop_event), 279 | .trace_lower_addr_i(trace_lower_addr), 280 | .trace_higher_addr_i(trace_higher_addr), 281 | .iaddr_i(iaddr_d), 282 | .trace_range_match_o(trace_range_match), 283 | .trace_priv_match_o(trace_priv_match), 284 | .trace_qualified_o(filter_qualified_decision)); 285 | 286 | 287 | // decide whether a privilege change occured 288 | always_comb begin 289 | privchange0_d = (tc_priv != nc_priv) && ivalid_q; 290 | end 291 | 292 | // decide whether we have a branch instruction 293 | // beq, bne, blt, bge, bltu, bgeu, p_bneimm, p_beqimm 294 | always_comb begin: is_branch 295 | is_branch0_d 296 | = ((instr_q & MASK_BEQ) == MATCH_BEQ) || 297 | ((instr_q & MASK_BNE) == MATCH_BNE) || 298 | ((instr_q & MASK_BLT) == MATCH_BLT) || 299 | ((instr_q & MASK_BGE) == MATCH_BGE) || 300 | ((instr_q & MASK_BLTU) == MATCH_BLTU) || 301 | ((instr_q & MASK_BGEU) == MATCH_BGEU) || 302 | ((instr_q & MASK_P_BNEIMM) == MATCH_P_BNEIMM) || 303 | ((instr_q & MASK_P_BEQIMM) == MATCH_P_BEQIMM) || 304 | ((instr_q & MASK_C_BEQZ) == MATCH_C_BEQZ) || 305 | ((instr_q & MASK_C_BNEZ) == MATCH_C_BNEZ); 306 | end 307 | 308 | // decide whether we have a unpredictable discontinuity 309 | // jalr, mret, sret, uret 310 | always_comb begin: is_discontinuity 311 | 312 | really_c_jalr = ((instr_q & MASK_C_JALR) == MATCH_C_JALR) 313 | && ((instr_q & MASK_RD) != 0); 314 | 315 | really_c_jr = ((instr_q & MASK_C_JR) == MATCH_C_JR) 316 | && ((instr_q & MASK_RD) != 0); 317 | 318 | is_jump = ((instr_q & MASK_JALR) == MATCH_JALR) || 319 | really_c_jalr || really_c_jr; 320 | 321 | is_priv_ret = ((instr_q & MASK_MRET) == MATCH_MRET) || 322 | ((instr_q & MASK_SRET) == MATCH_SRET) || 323 | ((instr_q & MASK_URET) == MATCH_URET); 324 | 325 | // allows us to mark ret's as not being discontinuities, if we want 326 | not_ret = '1; 327 | is_ret = ((instr_q & (MASK_JALR | MASK_RD | MASK_RS1 | MASK_IMM)) == 328 | (MATCH_JALR | (X_RA << OP_SH_RS1))); 329 | is_c_ret = (instr_q & (MASK_C_JR | MASK_RD)) == 330 | (MATCH_C_JR | (X_RA << OP_SH_RD)); 331 | 332 | if(trace_implicit_ret) 333 | not_ret = !(is_ret || is_c_ret); 334 | 335 | u_discontinuity0_d = (is_jump || is_priv_ret) && not_ret; 336 | end 337 | 338 | // figure out whether we are dealing with the first qualified instruction 339 | always_comb begin: is_qualified 340 | tc_first_qualified = !lc_qualified && tc_qualified; 341 | end 342 | 343 | always_comb begin: becomes_unqualified 344 | nc_unqualified = !nc_qualified; 345 | end 346 | 347 | // is this branch taken? 348 | // TODO: change to tc_compressed? 2 :4 349 | always_comb begin: is_branch_taken 350 | tc_branch_taken = tc_compressed ? 351 | !(tc_iaddr + 2 == nc_iaddr): 352 | !(tc_iaddr + 4 == nc_iaddr); 353 | end 354 | 355 | // update branch map, careful there is a direct combinatorial path 356 | trdb_branch_map i_trdb_branch_map 357 | (.clk_i(clk_gated), 358 | .rst_ni(rst_ni), 359 | .valid_i(tc_is_branch && trace_valid && tc_qualified), 360 | .branch_taken_i(tc_branch_taken), 361 | .flush_i(branch_map_flush), 362 | .map_o(branch_map), 363 | .branches_o(branch_map_cnt), 364 | .is_full_o(branch_map_full), 365 | .is_empty_o(branch_map_empty)); 366 | 367 | // decides, by looking at the history of instructions, whether a packet is 368 | // necessary or not 369 | trdb_priority i_trdb_priority 370 | (// there might be some data stuck in the 371 | // pipeline if valid never goes high again (e.g. 372 | // after wfi), but this shouldnt matter 373 | .valid_i(trace_valid && tc_qualified), 374 | .full_addr_i(tc_iaddr), 375 | .diff_addr_i(diff_addr), 376 | .lc_exception_i(lc_exception), 377 | .lc_exception_sync_i(lc_exception_sync && packet_after_exception), 378 | 379 | .tc_first_qualified_i(tc_first_qualified), 380 | .nc_unqualified_i(nc_unqualified), 381 | 382 | //input logic tc_unhalted, 383 | .tc_privchange_i(tc_privchange), 384 | //input logic resync & branch_map_cnt 385 | 386 | .lc_u_discontinuity_i(lc_u_discontinuity), 387 | 388 | // input logic resync 389 | // input logic branch_map_nonempty, 390 | 391 | //input logic nc_halt, 392 | .nc_exception_i(nc_exception), 393 | .nc_privchange_i(nc_privchange), 394 | //input logic nc_qualified, 395 | 396 | .branch_map_full_i(branch_map_full), 397 | 398 | //input logic tc_context_change, 399 | .branch_map_empty_i(branch_map_empty), 400 | .use_full_addr_i(trace_full_addr), 401 | .keep_bits_o(keep_addr_bits), 402 | .valid_o(packet_valid), 403 | .packet_format_o(packet_format), 404 | .packet_subformat_o(packet_subformat)); 405 | 406 | 407 | // keep track of time for time packets 408 | trdb_timer 409 | #(.TIMER_WIDTH(TIMER_WIDTH)) 410 | i_trdb_timer 411 | (.clk_i(clk_gated), 412 | .rst_ni(rst_ni), 413 | .manual_rst_i(timer_rst), 414 | .tu_req_i(tu_req), 415 | .tu_valid_o(tu_valid), 416 | .tu_grant_i(tu_grant), 417 | .trdb_time_o(tu_time)); 418 | 419 | 420 | // whole packet generation logic 421 | trdb_packet_emitter i_trdb_packet_emitter 422 | (.clk_i(clk_gated), 423 | .rst_ni(rst_ni), 424 | .packet_format_i(packet_format), 425 | .packet_subformat_i(packet_subformat), 426 | .keep_bits_i(keep_addr_bits), 427 | .valid_i(packet_valid), 428 | .use_full_addr_i(trace_full_addr), 429 | .interrupt_i(lc_interrupt), // get the value of the trapped instr 430 | .cause_i(lc_cause), 431 | .tval_i(lc_tval), 432 | .priv_i(tc_priv), 433 | .iaddr_i(tc_iaddr), 434 | .context_i(tc_context), 435 | .lc_u_discontinuity_i(lc_u_discontinuity), 436 | .branch_map_i(branch_map), 437 | .branch_map_cnt_i(branch_map_cnt), 438 | .branch_map_empty_i(branch_map_empty), 439 | .branch_map_full_i(branch_map_full), 440 | .is_branch_i(tc_is_branch), 441 | .branch_map_flush_o(branch_map_flush), 442 | .diff_addr_o(diff_addr), 443 | .sw_valid_i(sw_valid), 444 | .sw_word_i(sw_word), 445 | .sw_grant_o(sw_grant), 446 | .tu_valid_i(tu_valid), 447 | .tu_time_i(tu_time), 448 | .tu_fulltime_i(tu_fulltime), 449 | .tu_grant_o(tu_grant), 450 | .packet_bits_o(packet_gen_bits), 451 | .packet_len_o(packet_gen_len), 452 | .packet_valid_o(packet_gen_valid)); 453 | 454 | //TODO: implement fifo clear logic 455 | //TODO: request resync logic on nuked fifo 456 | assign clear_fifo = 1'b0; 457 | assign fifo_overflow = ~packet_fifo_not_full; 458 | 459 | // this buffers our generated packet, since packets can be generated every 460 | // cycle, but we only read atmost 32 bit per cycle 461 | generic_fifo_adv 462 | #(.DATA_WIDTH(PACKET_LEN + $clog2(PACKET_LEN)), 463 | .DATA_DEPTH(PACKET_BUFFER_STAGES)) 464 | i_packet_fifo 465 | (.clk(clk_i), 466 | .rst_n(rst_ni), 467 | .clear_i(clear_fifo), //clear fifo if overflowing 468 | .data_i({packet_gen_bits, packet_gen_len}), 469 | .valid_i(packet_gen_valid), 470 | .grant_o(packet_fifo_not_full), 471 | .data_o({packet_fifo_bits, packet_fifo_len}), 472 | .valid_o(packet_fifo_valid), 473 | .grant_i(packet_is_read), 474 | .test_mode_i('0)); // TODO: what to do with this 475 | 476 | `ifndef SYNTHESIS 477 | packet_fifo_overflow: assert property 478 | (@(posedge clk_i) disable iff (~rst_ni) (packet_fifo_not_full == 1'b1)) 479 | else $error("[TRDB] @%t: Packet FIFO is overflowing.", $time); 480 | `endif 481 | 482 | trdb_align8 i_trdb_align8 483 | (.clk_i(clk_gated), 484 | .rst_ni(rst_ni), 485 | .payload_bits_i(packet_fifo_bits), 486 | .payload_len_i(packet_fifo_len), 487 | .valid_i(packet_fifo_valid), 488 | .grant_o(packet_is_read), 489 | .flush_stream_i(flush_stream), 490 | .flush_confirm_o(flush_confirm), 491 | .data_o(packet_word), 492 | .grant_i(grant_i), 493 | .valid_o(packet_word_valid)); 494 | 495 | assign packet_word_o = packet_word; 496 | assign packet_word_valid_o = packet_word_valid; 497 | 498 | // TODO: assert that we are not dealing with an unsupported instruction 499 | always_ff @(posedge clk_gated, negedge rst_ni) begin 500 | if(~rst_ni) begin 501 | ivalid_q <= '0; 502 | iexception_q <= '0; 503 | interrupt_q <= '0; 504 | cause_q <= '0; 505 | priv_q <= '0; 506 | iaddr_q <= '0; 507 | instr_q <= '0; 508 | compressed_q <= '0; 509 | 510 | interrupt0_q <= '0; 511 | interrupt1_q <= '0; 512 | cause0_q <= '0; 513 | cause1_q <= '0; 514 | priv0_q <= 3'h7; //we always start in M-mode 515 | privchange0_q <= '0; 516 | exception0_q <= '0; 517 | exception1_q <= '0; 518 | exception2_q <= '0; 519 | u_discontinuity0_q <= '0; 520 | u_discontinuity1_q <= '0; 521 | is_branch0_q <= '0; 522 | compressed0_q <= '0; 523 | iaddr0_q <= '0; 524 | qualified0_q <= '0; 525 | qualified1_q <= '0; 526 | end else begin 527 | ivalid_q <= ivalid_d; 528 | iexception_q <= iexception_d; 529 | interrupt_q <= interrupt_d; 530 | cause_q <= cause_d; 531 | priv_q <= priv_d; 532 | iaddr_q <= iaddr_d; 533 | instr_q <= instr_d; 534 | compressed_q <= compressed_d; 535 | 536 | if(ivalid_q) begin 537 | interrupt0_q <= interrupt0_d; 538 | interrupt1_q <= interrupt1_d; 539 | cause0_q <= cause0_d; 540 | cause1_q <= cause1_d; 541 | priv0_q <= priv0_d; 542 | privchange0_q <= privchange0_d; 543 | exception0_q <= exception0_d; 544 | exception1_q <= exception1_d; 545 | exception2_q <= exception2_d; 546 | u_discontinuity0_q <= u_discontinuity0_d; 547 | u_discontinuity1_q <= u_discontinuity1_d; 548 | is_branch0_q <= is_branch0_d; 549 | compressed0_q <= compressed0_d; 550 | iaddr0_q <= iaddr0_d; 551 | qualified0_q <= qualified0_d; 552 | qualified1_q <= qualified1_d; 553 | end 554 | end 555 | end 556 | 557 | // Connection to the APB. Used to configure the trace debugger. This is just 558 | // a translation layer. 559 | trdb_apb_if 560 | #(.APB_ADDR_WIDTH(APB_ADDR_WIDTH)) 561 | i_trdb_apb_if 562 | (.paddr(apb_slave.paddr), 563 | .pwdata(apb_slave.pwdata), 564 | .pwrite(apb_slave.pwrite), 565 | .psel(apb_slave.psel), 566 | .penable(apb_slave.penable), 567 | .prdata(apb_slave.prdata), 568 | .pready(apb_slave.pready), 569 | .pslverr(apb_slave.pslverr), 570 | 571 | .per_rdata_i(per_rdata), 572 | .per_ready_i(per_ready), 573 | .per_wdata_o(per_wdata), 574 | .per_addr_o(per_addr), 575 | .per_we_o(per_we), 576 | .per_valid_o(per_valid)); 577 | 578 | // Holds configuration data written from the APB and asserts relevant 579 | // control signals depending on that 580 | trdb_reg 581 | #(.APB_ADDR_WIDTH(APB_ADDR_WIDTH)) 582 | i_trdb_reg 583 | (.clk_i(clk_i), 584 | .rst_ni(rst_ni), 585 | .test_mode_i(test_mode_i), 586 | .clk_gated_o(clk_gated), 587 | .per_rdata_o(per_rdata), 588 | .per_ready_o(per_ready), 589 | .per_wdata_i(per_wdata), 590 | .per_addr_i(per_addr), 591 | .per_we_i(per_we), 592 | .per_valid_i(per_valid), 593 | .flush_stream_o(flush_stream), 594 | .flush_confirm_i(flush_confirm), 595 | .clear_fifo_o(), // TODO: connect 596 | .trace_enable_o(trace_enable), 597 | .trace_activated_o(trace_activated), 598 | .trace_full_addr_o(trace_full_addr), 599 | .trace_req_deactivate_i(trace_req_deactivate), 600 | .trace_implicit_ret_o(trace_implicit_ret), 601 | .apply_filters_o(apply_filters), 602 | .trace_selected_priv_o(trace_selected_priv), 603 | .trace_which_priv_o(trace_which_priv), 604 | .trace_range_event_o(trace_range_event), 605 | .trace_stop_event_o(trace_stop_event), 606 | .trace_lower_addr_o(trace_lower_addr), 607 | .trace_higher_addr_o(trace_higher_addr), 608 | .trace_qualified_i(qualified0_d), 609 | .trace_priv_match_i(trace_priv_match), 610 | .trace_range_match_i(trace_range_match), 611 | .trace_fifo_overflow_i(fifo_overflow), 612 | .external_fifo_overflow_i(~grant_i), //external stall is a fifo overflow 613 | .sw_word_o(sw_word), 614 | .sw_valid_o(sw_valid), 615 | .sw_grant_i(sw_grant), 616 | .tu_req_o(tu_req)); 617 | 618 | 619 | endmodule // trace_debugger 620 | -------------------------------------------------------------------------------- /rtl/trace_debugger_stimuli_gen.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Captures incoming instruction samples and writes to file 13 | 14 | module trace_debugger_stimuli_gen 15 | (input logic clk_i, 16 | input logic rst_ni, 17 | 18 | input logic ivalid_i, 19 | input logic iexception_i, 20 | input logic interrupt_i, 21 | input logic [ 4:0] cause_i, 22 | input logic [31:0] tval_i, 23 | input logic [ 2:0] priv_i, 24 | input logic [31:0] iaddr_i, 25 | input logic [31:0] instr_i, 26 | input logic compressed_i); 27 | 28 | logic ivalid_q, ivalid_d; 29 | logic iexception_q, iexception_d; 30 | logic interrupt_q, interrupt_d; 31 | logic [ 4:0] cause_q, cause_d; 32 | logic [31:0] tval_q, tval_d; 33 | logic [ 2:0] priv_q, priv_d; 34 | logic [31:0] iaddr_q, iaddr_d; 35 | logic [31:0] instr_q, instr_d; 36 | 37 | `ifndef SYNTHESIS 38 | initial begin 39 | 40 | automatic string name = "trdb_stimuli"; 41 | int fd; 42 | 43 | fd = $fopen(name, "w"); 44 | 45 | if(fd) 46 | $display("[TRDB] Opening file %s", name); 47 | else 48 | $fatal("[TRDB] Failed to open file"); 49 | 50 | forever @(negedge clk_i) begin 51 | if(~rst_ni) begin 52 | continue; 53 | end 54 | // if(!ivalid_i) begin 55 | // continue; 56 | // end 57 | $fdisplay(fd,"valid=%h exception=%h interrupt=%h cause=%h", 58 | ivalid_i, iexception_i, interrupt_i, cause_i, 59 | " tval=%h priv=%h compressed=%h addr=%h instr=%h", 60 | 32'b0, priv_i, compressed_i, iaddr_i, instr_i); 61 | end 62 | //tval_i is just 'x for now so ignore it 63 | 64 | //$fclose(fd); 65 | end 66 | `endif 67 | 68 | endmodule // trace_debugger_stimuli_gen 69 | -------------------------------------------------------------------------------- /rtl/tracer_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Peripheral module that pushes tracer data to the udma 13 | 14 | module tracer_if 15 | #(parameter L2_AWIDTH_NOAL = 12, // L2 address bus 16 | parameter TRANS_SIZE = 16) // buffer size in L2 / transfer length 17 | (input logic clk_i, 18 | input logic rst_ni, 19 | 20 | // Configuration r/w from APB 21 | input logic [31:0] cfg_data_i, 22 | input logic [4:0] cfg_addr_i, 23 | input logic cfg_valid_i, 24 | input logic cfg_rw_ni, 25 | output logic [31:0] cfg_data_o, 26 | output logic cfg_ready_o, 27 | 28 | // Configuration state for the udma 29 | output logic [L2_AWIDTH_NOAL-1:0] cfg_rx_startaddr_o, 30 | output logic [TRANS_SIZE-1:0] cfg_rx_size_o, 31 | output logic cfg_rx_continuous_o, 32 | output logic cfg_rx_en_o, 33 | output logic cfg_rx_filter_o, 34 | output logic cfg_rx_clr_o, 35 | input logic cfg_rx_en_i, 36 | input logic cfg_rx_pending_i, 37 | input logic [L2_AWIDTH_NOAL-1:0] cfg_rx_curr_addr_i, 38 | input logic [TRANS_SIZE-1:0] cfg_rx_bytes_left_i, 39 | 40 | // Data from the tracer that goes to the udma 41 | output logic [1:0] data_rx_datasize_o, 42 | output logic [31:0] data_rx_data_o, 43 | output logic data_rx_valid_o, 44 | input logic data_rx_ready_i, 45 | 46 | // Data from the trace debugger unit to this interface 47 | input logic [31:0] trdb_packet_i, 48 | input logic trdb_word_valid_i, 49 | output logic trdb_stall_o); 50 | 51 | // buffer data from trace debugger 52 | logic [31:0] data_rx_data_q; 53 | logic data_rx_valid_q; 54 | 55 | // statemachine for stall signal 56 | enum logic [1:0] {IDLE, TRANSFER, STALL} cs, ns; 57 | 58 | // signal that the udma fifo is overflowing 59 | logic stall; 60 | 61 | // We are in the same clockdomain as the SoC, so no DC stuff needed. This 62 | // block just buffers all the udma configuration data, it is the same 63 | // boilerplate stuff as in the other interfaces. 64 | tracer_reg_if 65 | #(.L2_AWIDTH_NOAL(L2_AWIDTH_NOAL), 66 | .TRANS_SIZE(TRANS_SIZE)) 67 | i_tracer_reg_if 68 | (.clk_i (clk_i), 69 | .rst_ni (rst_ni), 70 | 71 | .cfg_data_i (cfg_data_i), 72 | .cfg_addr_i (cfg_addr_i), 73 | .cfg_valid_i (cfg_valid_i), 74 | .cfg_rw_ni (cfg_rw_ni), 75 | .cfg_ready_o (cfg_ready_o), 76 | .cfg_data_o (cfg_data_o), 77 | 78 | .cfg_rx_startaddr_o (cfg_rx_startaddr_o), 79 | .cfg_rx_size_o (cfg_rx_size_o), 80 | .cfg_rx_datasize_o (data_rx_datasize_o), 81 | .cfg_rx_continuous_o(cfg_rx_continuous_o), 82 | .cfg_rx_en_o (cfg_rx_en_o), 83 | .cfg_rx_filter_o (cfg_rx_filter_o), 84 | .cfg_rx_clr_o (cfg_rx_clr_o), 85 | .cfg_rx_en_i (cfg_rx_en_i), 86 | .cfg_rx_pending_i (cfg_rx_pending_i), 87 | .cfg_rx_curr_addr_i (cfg_rx_curr_addr_i), 88 | .cfg_rx_bytes_left_i(cfg_rx_bytes_left_i)); 89 | 90 | // Signal the trace debugger if we have to stall because of FIFO overflow in 91 | // UDMA 92 | always_comb begin 93 | ns = cs; 94 | stall = '0; 95 | 96 | case(cs) 97 | 98 | IDLE: begin 99 | stall = '0; 100 | if(data_rx_valid_q && data_rx_ready_i) begin 101 | ns = TRANSFER; 102 | end else if(data_rx_valid_q && !data_rx_ready_i) begin 103 | ns = STALL; 104 | end else begin 105 | ns = IDLE; 106 | end 107 | end 108 | 109 | TRANSFER: begin 110 | stall = '0; 111 | if(data_rx_valid_q && data_rx_ready_i) begin 112 | ns = TRANSFER; 113 | end else if(data_rx_valid_q && !data_rx_ready_i) begin 114 | ns = STALL; 115 | end else if(!data_rx_valid_q) begin 116 | ns = IDLE; 117 | end 118 | end 119 | 120 | STALL: begin 121 | stall = '1; 122 | if(!data_rx_ready_i) begin 123 | ns = STALL; 124 | end else begin 125 | ns = TRANSFER; 126 | end 127 | end 128 | 129 | endcase // case (cs) 130 | end 131 | 132 | assign trdb_stall_o = stall; 133 | assign data_rx_data_o = data_rx_data_q; 134 | assign data_rx_valid_o = data_rx_valid_q; 135 | 136 | always_ff @(posedge clk_i, negedge rst_ni) begin 137 | if(~rst_ni) begin 138 | cs <= IDLE; 139 | data_rx_data_q <= 'h0; 140 | data_rx_valid_q <= 'h0; 141 | end else begin 142 | cs <= ns; 143 | data_rx_data_q <= trdb_packet_i; 144 | data_rx_valid_q <= trdb_word_valid_i; 145 | end 146 | end 147 | endmodule // tracer_if 148 | -------------------------------------------------------------------------------- /rtl/tracer_reg_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Manages peripheral state, i.e. the memory mapped registers 13 | 14 | `define REG_RX_SADDR 5'h0 //BASEADDR+0x00 15 | `define REG_RX_SIZE 5'h1 //BASEADDR+0x04 16 | `define REG_RX_CFG 5'h2 //BASEADDR+0x08 17 | `define REG_RX_INTCFG 5'h3 //BASEADDR+0x0C 18 | 19 | module tracer_reg_if 20 | #(parameter L2_AWIDTH_NOAL = 12, 21 | parameter TRANS_SIZE = 16) 22 | (input logic clk_i, 23 | input logic rst_ni, 24 | 25 | // Configuration r/w from APB 26 | input logic [31:0] cfg_data_i, 27 | input logic [4:0] cfg_addr_i, 28 | input logic cfg_valid_i, 29 | input logic cfg_rw_ni, 30 | output logic [31:0] cfg_data_o, 31 | output logic cfg_ready_o, 32 | 33 | // Configuration state for the udma 34 | output logic [L2_AWIDTH_NOAL-1:0] cfg_rx_startaddr_o, 35 | output logic [TRANS_SIZE-1:0] cfg_rx_size_o, 36 | output logic [1:0] cfg_rx_datasize_o, 37 | output logic cfg_rx_continuous_o, 38 | output logic cfg_rx_en_o, 39 | output logic cfg_rx_filter_o, 40 | output logic cfg_rx_clr_o, 41 | input logic cfg_rx_en_i, 42 | input logic cfg_rx_pending_i, 43 | input logic [L2_AWIDTH_NOAL-1:0] cfg_rx_curr_addr_i, 44 | input logic [TRANS_SIZE-1:0] cfg_rx_bytes_left_i); 45 | 46 | // This peripheral only outputs data, keep necessary state 47 | logic [L2_AWIDTH_NOAL-1:0] rx_startaddr_q; 48 | logic [TRANS_SIZE-1 : 0] rx_size_q; 49 | // logic [1 : 0] rx_datasize_q; 50 | logic rx_continuous_q; 51 | logic rx_en_q; 52 | logic rx_filter_q; 53 | logic rx_clr_q; 54 | 55 | // Internal read and write addresses for the registers 56 | logic [4:0] wr_addr; 57 | logic [4:0] rd_addr; 58 | 59 | assign cfg_rx_startaddr_o = rx_startaddr_q; 60 | assign cfg_rx_size_o = rx_size_q; 61 | assign cfg_rx_datasize_o = 2'h2; //rx_datasize_q; 62 | assign cfg_rx_continuous_o = rx_continuous_q; 63 | assign cfg_rx_en_o = rx_en_q; 64 | assign cfg_rx_filter_o = rx_filter_q; 65 | assign cfg_rx_clr_o = rx_clr_q; 66 | 67 | assign wr_addr = (cfg_valid_i & ~cfg_rw_ni) ? cfg_addr_i : 5'h0; 68 | assign rd_addr = (cfg_valid_i & cfg_rw_ni) ? cfg_addr_i : 5'h0; 69 | 70 | assign cfg_ready_o = 1'b1; 71 | 72 | 73 | always_comb begin 74 | cfg_data_o = 32'h0; 75 | case (rd_addr) 76 | `REG_RX_SADDR: 77 | cfg_data_o = cfg_rx_curr_addr_i; 78 | `REG_RX_SIZE: 79 | cfg_data_o[TRANS_SIZE-1:0] = cfg_rx_bytes_left_i; 80 | `REG_RX_CFG: 81 | cfg_data_o = {26'h0, cfg_rx_pending_i, cfg_rx_en_i, 82 | rx_filter_q, 2'h2, rx_continuous_q}; 83 | default: 84 | cfg_data_o = 'h0; 85 | endcase 86 | end 87 | 88 | 89 | always_ff @(posedge clk_i, negedge rst_ni) begin 90 | if(~rst_ni) begin 91 | rx_startaddr_q <= 'h0; 92 | rx_size_q <= 'h0; 93 | rx_continuous_q <= 'h0; 94 | rx_filter_q <= 'h0; 95 | rx_en_q = 'h0; // TODO: figure this out 96 | rx_clr_q = 'h0; 97 | // rx_datasize_q <= 'h2; //b -> h 98 | end else begin 99 | rx_en_q = 'h0; 100 | rx_clr_q = 'h0; 101 | 102 | if (cfg_valid_i & ~cfg_rw_ni) begin 103 | case (wr_addr) 104 | `REG_RX_SADDR: 105 | rx_startaddr_q <= cfg_data_i[L2_AWIDTH_NOAL-1:0]; 106 | `REG_RX_SIZE: 107 | rx_size_q <= cfg_data_i[TRANS_SIZE-1:0]; 108 | `REG_RX_CFG: 109 | begin 110 | rx_clr_q = cfg_data_i[5]; 111 | rx_en_q = cfg_data_i[4]; 112 | rx_filter_q <= cfg_data_i[3]; 113 | // rx_datasize_q <= cfg_data_i[2:1]; 114 | rx_continuous_q <= cfg_data_i[0]; 115 | end 116 | //TODO: default case 117 | endcase 118 | end 119 | end 120 | end 121 | endmodule // tracer_reg_if 122 | -------------------------------------------------------------------------------- /rtl/trdb_align.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Take packets and funnel them through a 32 bit interface 13 | 14 | import trdb_pkg::*; 15 | 16 | // TODO: doesn't do alignment yet, just zero fill empty words 17 | // TODO: inserting double WORD header not done yet 18 | module trdb_align 19 | #(parameter ID = 1) 20 | (input logic clk_i, 21 | input logic rst_ni, 22 | 23 | input logic [PACKET_LEN-1:0] packet_bits_i, 24 | input logic [$clog2(PACKET_LEN)-1:0] packet_len_i, 25 | input logic valid_i, 26 | output logic grant_o, 27 | 28 | output logic [31:0] data_o, 29 | output logic valid_o); 30 | 31 | 32 | enum logic [1:0] {WORD0, WORD1} cs, ns; 33 | 34 | logic [32+PACKET_TOTAL-1:0] padded_packet_bits; 35 | logic [$clog2(32+PACKET_TOTAL):0] low_ptr_d, low_ptr_q, high_ptr; 36 | 37 | logic [31:0] data_q, data_d, residual_q, residual_d; 38 | logic [4:0] residual_fill_q, residual_fill_d; 39 | logic valid_d, valid_q; 40 | 41 | // TODO: this is not used for now, meant for multi core tracing 42 | logic [4:0] instance_id; 43 | 44 | assign instance_id = ID; 45 | 46 | assign valid_o = valid_q; 47 | assign data_o = data_q; 48 | assign padded_packet_bits = {32'b0, packet_bits_i, packet_len_i}; 49 | 50 | // TODO: halfword, byte, nibble, bit alignment 51 | // TODO: flush capabilities 52 | // TODO: source tag 53 | // TODO: word tag 54 | 55 | always_comb begin 56 | ns = cs; 57 | low_ptr_d = low_ptr_q; 58 | valid_d = '0; 59 | data_d = '0; 60 | grant_o = '0; 61 | 62 | if(valid_i) begin 63 | case(cs) 64 | 65 | WORD0: begin 66 | ns = WORD1; 67 | high_ptr = low_ptr_q + 32-7; 68 | data_d = {padded_packet_bits[low_ptr_q +: 32-7], 2'b1, 69 | instance_id}; 70 | valid_d = '1; 71 | 72 | low_ptr_d = high_ptr; 73 | if(high_ptr >= packet_len_i) begin 74 | //we are done with the current packet 75 | low_ptr_d = '0; 76 | // request the next packet 77 | grant_o = '1; 78 | end 79 | end 80 | 81 | WORD1: begin 82 | ns = WORD0; 83 | high_ptr = low_ptr_q + 32; 84 | // check if we can still output 32 bit words for the current 85 | // packet 86 | data_d = padded_packet_bits[low_ptr_q +: 32]; 87 | valid_d = '1; 88 | 89 | low_ptr_d = high_ptr; 90 | // TODO: make this state machine maybe 91 | if(high_ptr >= packet_len_i) begin 92 | //we are done with the current packet 93 | low_ptr_d = '0; 94 | // request the next packet 95 | grant_o = '1; //TODO: doesn't cause comb loop with fifo? 96 | end 97 | end 98 | 99 | endcase 100 | end 101 | end 102 | 103 | 104 | always_ff @(posedge clk_i, negedge rst_ni) begin 105 | if(~rst_ni) begin 106 | cs <= WORD0; 107 | low_ptr_q <= '0; 108 | residual_q <= '0; 109 | residual_fill_q <= '0; 110 | valid_q <= '0; 111 | data_q <= '0; 112 | end else begin 113 | cs <= ns; 114 | low_ptr_q <= low_ptr_d; 115 | residual_q <= residual_d; 116 | residual_fill_q <= residual_fill_d; 117 | valid_q <= valid_d; 118 | data_q <= data_d; 119 | end 120 | end 121 | 122 | endmodule // trdb_align 123 | -------------------------------------------------------------------------------- /rtl/trdb_align8.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright 2019 ETH Zurich and University of Bologna.9 Robert Balas 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | // 12 | // Author: Robert Balas (balasr@iis.ee.ethz.ch) 13 | // Description: Take packets and funnel them through a DATA_WIDTH bit interface 14 | 15 | 16 | 17 | // TODO: doesn't do alignment yet, just zero fill empty words 18 | // TODO: inserting double WORD header not done yet 19 | module trdb_align8 import trdb_pkg::*; #( 20 | parameter ID = 1 21 | ) ( 22 | input logic clk_i, 23 | input logic rst_ni, 24 | 25 | input logic [PACKET_LEN-1:0] payload_bits_i, 26 | input logic [$clog2(PACKET_LEN)-1:0] payload_len_i, 27 | input logic valid_i, 28 | output logic grant_o, 29 | 30 | input logic flush_stream_i, 31 | output logic flush_confirm_o, 32 | 33 | 34 | output logic [BUS_DATA_WIDTH-1:0] data_o, 35 | input logic grant_i, 36 | output logic valid_o 37 | ); 38 | 39 | localparam PACKET_MAX_BYTES = PACKET_TOTAL/8 + (PACKET_TOTAL % 8 != 0); 40 | localparam DATA_WIDTH = BUS_DATA_WIDTH; 41 | localparam DATA_OFFSET_LEN = BUS_DATA_WIDTH/8 + 1; 42 | localparam DATA_BYTES = BUS_DATA_WIDTH/8; 43 | 44 | logic [DATA_WIDTH+PACKET_TOTAL-1:0] padded_packet_bits; 45 | logic [$clog2(DATA_WIDTH+PACKET_TOTAL):0] low_ptr_d, low_ptr_q, high_ptr; 46 | 47 | // TODO: change hardcoding, use $clog 48 | // TODO: remove PACKER_HEADER_LEN, move upwards to packet emitter 49 | // TODO: this is a mess, clean up 50 | logic [PACKET_BYTE_HEADER_LEN-1:0] payload_bytes; 51 | logic [$clog2(PACKET_LEN)-1:0] packet_len_no_header; 52 | logic [$clog2(PACKET_TOTAL)-1:0] effective_packet_len; 53 | logic [$clog2(PACKET_MAX_BYTES)-1:0] packet_bytes; 54 | 55 | // for keeping track of the offset (carry over bytes) of residual 56 | logic [$clog2(DATA_OFFSET_LEN)-1:0] offset_q, offset_d, offset_inv; 57 | // same as above, but in terms of bit position 58 | logic [$clog2(DATA_OFFSET_LEN)-1+3:0] offset_shifted, offset_inv_shifted; 59 | // TODO: change residual size 60 | logic [DATA_WIDTH-1:0] data_q, data_d, residual_q, residual_d; 61 | logic valid_d, valid_q; 62 | 63 | logic update; 64 | 65 | enum logic [2:0] {Idle, Waitgrant, Stream, Full, Overfull} state_q, state_d; 66 | 67 | // TODO: this is not used for now, meant for multi core tracing 68 | logic [4:0] instance_id; 69 | 70 | assign instance_id = ID; 71 | 72 | // assign valid_o = valid_q; 73 | assign data_o = data_q; 74 | 75 | //outgoing handshake 76 | assign update = valid_o && grant_i; 77 | 78 | 79 | // strip off 4 custom bits 80 | assign packet_len_no_header = payload_len_i - 4; 81 | assign payload_bytes = (packet_len_no_header >> 3) 82 | + (packet_len_no_header[2:0] != 2'h0); 83 | 84 | assign padded_packet_bits = {{DATA_WIDTH{1'b0}}, 85 | payload_bits_i, 86 | payload_bytes}; 87 | 88 | // TODO: halfword, byte, nibble, bit alignment 89 | assign offset_shifted = offset_q << 3; 90 | assign offset_inv = DATA_BYTES - offset_q; 91 | assign offset_inv_shifted = offset_inv << 3; 92 | 93 | // packet length with header TODO: should rename other to payload 94 | assign effective_packet_len = payload_len_i + PACKET_BYTE_HEADER_LEN; 95 | // ceiling division 96 | assign packet_bytes = (effective_packet_len >> 3) 97 | + (effective_packet_len[2:0] != 2'h0); 98 | 99 | 100 | always_comb begin : align_bytes 101 | logic [15:0] offset; 102 | 103 | low_ptr_d = low_ptr_q; 104 | valid_d = '0; 105 | valid_o = '0; 106 | data_d = '0; 107 | grant_o = '0; 108 | 109 | residual_d = residual_q; 110 | offset_d = offset_q; 111 | 112 | high_ptr = '0; 113 | 114 | flush_confirm_o = '0; 115 | 116 | state_d = state_q; 117 | 118 | if(valid_i) begin 119 | low_ptr_d = low_ptr_q; 120 | high_ptr = low_ptr_q + DATA_BYTES; 121 | 122 | // check if we can still output DATA_WIDTH bit words for the current 123 | // packet combine "carry" and current data, and save residual 124 | // for next word 125 | data_d = (padded_packet_bits[low_ptr_q*8 +: DATA_WIDTH] << offset_shifted) | residual_q; 126 | if (update) 127 | residual_d = (padded_packet_bits[low_ptr_q*8 +: DATA_WIDTH] >> offset_inv_shifted); 128 | 129 | unique case (state_q) 130 | Idle: begin 131 | if (high_ptr < packet_bytes) begin 132 | state_d = Stream; 133 | end else if (high_ptr == packet_bytes) begin 134 | state_d = Full; 135 | end else if (high_ptr > packet_bytes) begin 136 | state_d = Overfull; 137 | end 138 | end 139 | Stream: begin 140 | valid_o = '1; 141 | if (update) begin 142 | state_d = Idle; 143 | low_ptr_d = high_ptr; 144 | end 145 | end 146 | Full: begin 147 | valid_o = '1; 148 | if (update) begin 149 | state_d = Idle; 150 | low_ptr_d = '0; 151 | grant_o = '1; 152 | end 153 | end 154 | Overfull: begin 155 | offset = ((packet_bytes % DATA_BYTES) + offset_q); 156 | 157 | if (offset == DATA_BYTES) begin 158 | valid_o = '1; 159 | if (update) 160 | residual_d = '0; 161 | 162 | end else if (offset > DATA_BYTES) begin 163 | valid_o = '1; 164 | if (update) begin 165 | unique case (offset % DATA_BYTES) 166 | 0: residual_d = residual_d; 167 | 1: residual_d = residual_d & {1{8'hff}}; 168 | 2: residual_d = residual_d & {2{8'hff}}; 169 | 3: residual_d = residual_d & {3{8'hff}}; 170 | `ifdef TRDB_ARCH64 171 | 4: residual_d = residual_d & {4{8'hff}}; 172 | 5: residual_d = residual_d & {5{8'hff}}; 173 | 6: residual_d = residual_d & {6{8'hff}}; 174 | 7: residual_d = residual_d & {7{8'hff}}; 175 | `endif 176 | endcase 177 | end 178 | 179 | end else if (offset < DATA_BYTES) begin 180 | valid_o = '0; 181 | unique case (offset) 182 | 0: residual_d = data_q; //TODO: need to mask this 183 | 1: residual_d = data_q & {1{8'hff}}; 184 | 2: residual_d = data_q & {2{8'hff}}; 185 | 3: residual_d = data_q & {3{8'hff}}; 186 | `ifdef TRDB_ARCH64 187 | 4: residual_d = data_q & {4{8'hff}}; 188 | 5: residual_d = data_q & {5{8'hff}}; 189 | 6: residual_d = data_q & {6{8'hff}}; 190 | 7: residual_d = data_q & {7{8'hff}}; 191 | `endif 192 | endcase 193 | state_d = Idle; 194 | offset_d = offset % DATA_BYTES; 195 | //we are done with the current packet 196 | low_ptr_d = '0; 197 | // request the next packet 198 | grant_o = '1; 199 | end 200 | 201 | if (update) begin 202 | state_d = Idle; 203 | offset_d = offset % DATA_BYTES; 204 | //we are done with the current packet 205 | low_ptr_d = '0; 206 | // request the next packet 207 | grant_o = '1; 208 | end 209 | 210 | end 211 | endcase // unique case (state_q) 212 | 213 | end else if(flush_stream_i) begin 214 | // check if we actually have something to flush from residual_d 215 | flush_confirm_o = '1; 216 | if(offset_d != 0) begin 217 | data_d = residual_d; 218 | valid_d = '1; 219 | end 220 | // TODO: after flush user has to clear 221 | end 222 | end 223 | 224 | always_ff @(posedge clk_i, negedge rst_ni) begin 225 | if(~rst_ni) begin 226 | offset_q <= '0; 227 | low_ptr_q <= '0; 228 | residual_q <= '0; 229 | valid_q <= '0; 230 | data_q <= '0; 231 | state_q <= Idle; 232 | end else begin 233 | offset_q <= offset_d; 234 | low_ptr_q <= low_ptr_d; 235 | residual_q <= residual_d; 236 | valid_q <= valid_d; 237 | data_q <= data_d; 238 | state_q <= state_d; 239 | end 240 | end 241 | 242 | endmodule // trdb_align8 243 | -------------------------------------------------------------------------------- /rtl/trdb_apb_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | 3 | // Copyright and related rights are licensed under the Solderpad Hardware 4 | // License, Version 0.51 (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 7 | // or agreed to in writing, software, hardware and materials distributed under 8 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | // specific language governing permissions and limitations under the License. 11 | // 12 | // Author: Robert Balas (balasr@student.ethz.ch) 13 | // Description: Translate APB to tracer configuration interface 14 | 15 | 16 | module trdb_apb_if 17 | #(parameter APB_ADDR_WIDTH = 12) 18 | (input logic [APB_ADDR_WIDTH-1:0] paddr, 19 | input logic [31:0] pwdata, 20 | input logic pwrite, 21 | input logic psel, 22 | input logic penable, 23 | output logic [31:0] prdata, 24 | output logic pready, 25 | output logic pslverr, 26 | 27 | input logic [31:0] per_rdata_i, 28 | input logic per_ready_i, 29 | output logic [31:0] per_wdata_o, 30 | output logic [APB_ADDR_WIDTH-1:0] per_addr_o, 31 | output logic per_we_o, 32 | output logic per_valid_o); 33 | 34 | 35 | // we always get the whole 32 bit address, but if we get an access, 36 | // indicated through psel we don't really need to check the upper bits. 37 | assign per_addr_o = paddr[11:0]; 38 | assign per_we_o = pwrite; 39 | assign per_wdata_o = pwdata; 40 | // psel indicates if your device is selected 41 | // penable indicates the access phase 42 | assign per_valid_o = psel & penable; 43 | 44 | assign prdata = per_rdata_i; 45 | assign pready = per_ready_i; 46 | 47 | // we never cause an error 48 | assign pslverr = 1'b0; 49 | 50 | 51 | endmodule // trdb_apb_if 52 | -------------------------------------------------------------------------------- /rtl/trdb_branch_map.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Records the sequence of taken and not taken branches 13 | 14 | module trdb_branch_map 15 | (input logic clk_i, 16 | input logic rst_ni, 17 | 18 | input logic valid_i, 19 | input logic branch_taken_i, 20 | input logic flush_i, 21 | 22 | output logic [30:0] map_o, 23 | output logic [4:0] branches_o, 24 | output logic is_full_o, 25 | output logic is_empty_o); 26 | 27 | logic [30:0] map_d, map_q; 28 | logic [4:0] branchcnt_d, branchcnt_q; 29 | 30 | // when valid_i then store the new branch value branch_taken_i into map_d. 31 | // branchcnt_q contains the current number of stored branches. 32 | always_comb begin 33 | map_d = map_q; 34 | branchcnt_d = branchcnt_q; 35 | 36 | // TODO: do a case here? 37 | if(flush_i) begin 38 | map_d = '0; 39 | branchcnt_d = '0; 40 | end 41 | 42 | if(valid_i) begin 43 | if(flush_i) begin 44 | map_d[0] = ~branch_taken_i; 45 | branchcnt_d = 5'b1; 46 | end else begin 47 | map_d[branchcnt_q] = ~branch_taken_i; 48 | branchcnt_d = branchcnt_q + 1; 49 | end 50 | end 51 | end 52 | 53 | // we have a direct input output path because we need the result this cycle 54 | // maybe should be changed later if this path is too long 55 | assign map_o = map_d; 56 | assign branches_o = branchcnt_d; 57 | assign is_full_o = (branchcnt_d == 31); 58 | assign is_empty_o = (branchcnt_d == 0); 59 | 60 | always_ff @(posedge clk_i, negedge rst_ni) begin 61 | if(~rst_ni) begin 62 | map_q <= '0; 63 | branchcnt_q <= '0; 64 | end else begin 65 | map_q <= map_d; 66 | branchcnt_q <= branchcnt_d; 67 | end 68 | end 69 | endmodule // trdb_branch_map 70 | -------------------------------------------------------------------------------- /rtl/trdb_filter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Filtering logic to reduce number of packets generated. There are 13 | // several settings which influence when packets are generated. They all boil 14 | // down to whether qualified is high (generated packets) or not. 15 | 16 | 17 | import trdb_pkg::*; 18 | 19 | 20 | module trdb_filter 21 | ( 22 | // this is manually controllable by the user 23 | input logic trace_activated_i, 24 | output logic trace_req_deactivate_o, 25 | 26 | // whether to consider filters at all 27 | input logic apply_filters_i, 28 | 29 | // trace a specific privilege mode (disabled on RISCY) 30 | input logic trace_selected_priv_i, 31 | input logic [1:0] which_priv_i, 32 | input logic [1:0] priv_i, 33 | 34 | // trace specific address ranges 35 | input logic trace_range_event_i, 36 | input logic trace_stop_event_i, 37 | input logic [XLEN-1:0] trace_lower_addr_i, 38 | input logic [XLEN-1:0] trace_higher_addr_i, 39 | input logic [XLEN-1:0] iaddr_i, 40 | 41 | output logic trace_range_match_o, 42 | output logic trace_priv_match_o, 43 | output logic trace_qualified_o); 44 | 45 | logic ip_in_range; 46 | logic priv_matching; 47 | 48 | // ip in specified range 49 | always_comb begin: ip_range_check 50 | if(trace_lower_addr_i <= iaddr_i && iaddr_i < trace_higher_addr_i) 51 | ip_in_range = '1; 52 | else 53 | ip_in_range = '0; 54 | end 55 | 56 | // deactivate when ip lands in specified range 57 | always_comb begin: stop_check 58 | trace_req_deactivate_o = apply_filters_i && ip_in_range && 59 | trace_stop_event_i; 60 | end 61 | 62 | // privilege matching 63 | always_comb begin: priv_check 64 | // priv_matching = '0; 65 | // if(trace_priv_i == which_priv_i) 66 | // priv_matching = '1; 67 | // else 68 | // priv_matching = '0; 69 | // // consider the case when we want to trace all privilege modes 70 | // priv_matching = priv_matching | ~trace_selected_priv_i; 71 | priv_matching = '1; 72 | end 73 | 74 | assign trace_range_match_o = ip_in_range; 75 | assign trace_priv_match_o = priv_matching; 76 | 77 | always_comb begin 78 | trace_qualified_o = '0; 79 | // if we are not interested in filters then the users controls the 80 | // tracing 81 | if(!apply_filters_i) 82 | trace_qualified_o = trace_activated_i; 83 | else 84 | trace_qualified_o = trace_activated_i && 85 | (trace_range_event_i && ip_in_range) && 86 | priv_matching; 87 | end 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /rtl/trdb_lzc.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: msfschaffner(?) from https://github.com/pulp-platform/common_cells 12 | // Description: Parametrizable leading zero counter 13 | 14 | 15 | // A trailing zero counter / leading zero counter. 16 | // Set LZC to 0 for trailing zero counter => cnt_o is the number of trailing zeroes (from the LSB) 17 | // Set LZC to 1 for leading zero counter => cnt_o is the number of leading zeroes (from the MSB) 18 | module trdb_lzc #( 19 | // The width of the input vector. 20 | parameter int WIDTH = -1, 21 | parameter int MODE = 0 22 | )( 23 | input logic [WIDTH-1:0] in_i, 24 | output logic [$clog2(WIDTH)-1:0] cnt_o, 25 | output logic empty_o // asserted if all bits in in_i are zero 26 | ); 27 | 28 | localparam int NUM_LEVELS = $clog2(WIDTH); 29 | 30 | // pragma translate_off 31 | initial begin 32 | assert(WIDTH > 0) else $fatal("input must be at least one bit wide"); 33 | end 34 | // pragma translate_on 35 | 36 | logic [WIDTH-1:0][NUM_LEVELS-1:0] index_lut; 37 | logic [2**NUM_LEVELS-1:0] sel_nodes; 38 | logic [2**NUM_LEVELS-1:0][NUM_LEVELS-1:0] index_nodes; 39 | 40 | logic [WIDTH-1:0] in_tmp; 41 | 42 | for (genvar i = 0; i < WIDTH; i++) begin 43 | assign in_tmp[i] = MODE ? in_i[WIDTH-1-i] : in_i[i]; 44 | end 45 | 46 | for (genvar j = 0; j < WIDTH; j++) begin 47 | assign index_lut[j] = j; 48 | end 49 | 50 | for (genvar level = 0; level < NUM_LEVELS; level++) begin 51 | 52 | if (level < NUM_LEVELS-1) begin 53 | for (genvar l = 0; l < 2**level; l++) begin 54 | assign sel_nodes[2**level-1+l] = sel_nodes[2**(level+1)-1+l*2] | sel_nodes[2**(level+1)-1+l*2+1]; 55 | assign index_nodes[2**level-1+l] = (sel_nodes[2**(level+1)-1+l*2] == 1'b1) ? 56 | index_nodes[2**(level+1)-1+l*2] : index_nodes[2**(level+1)-1+l*2+1]; 57 | end 58 | end 59 | 60 | if (level == NUM_LEVELS-1) begin 61 | for (genvar k = 0; k < 2**level; k++) begin 62 | // if two successive indices are still in the vector... 63 | if (k * 2 < WIDTH-1) begin 64 | assign sel_nodes[2**level-1+k] = in_tmp[k*2] | in_tmp[k*2+1]; 65 | assign index_nodes[2**level-1+k] = (in_tmp[k*2] == 1'b1) ? index_lut[k*2] : index_lut[k*2+1]; 66 | end 67 | // if only the first index is still in the vector... 68 | if (k * 2 == WIDTH-1) begin 69 | assign sel_nodes[2**level-1+k] = in_tmp[k*2]; 70 | assign index_nodes[2**level-1+k] = index_lut[k*2]; 71 | end 72 | // if index is out of range 73 | if (k * 2 > WIDTH-1) begin 74 | assign sel_nodes[2**level-1+k] = 1'b0; 75 | assign index_nodes[2**level-1+k] = '0; 76 | end 77 | end 78 | end 79 | end 80 | 81 | assign cnt_o = NUM_LEVELS > 0 ? index_nodes[0] : '0; 82 | assign empty_o = NUM_LEVELS > 0 ? ~sel_nodes[0] : ~(|in_i); 83 | 84 | endmodule : trdb_lzc 85 | -------------------------------------------------------------------------------- /rtl/trdb_packet_emitter.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Generate packet on output and buffer 13 | 14 | 15 | import trdb_pkg::*; 16 | 17 | 18 | module trdb_packet_emitter 19 | (input logic clk_i, 20 | input logic rst_ni, 21 | 22 | // trace packet generation request with associated conditions 23 | input trdb_format_e packet_format_i, 24 | input trdb_subformat_e packet_subformat_i, 25 | 26 | input logic [$clog2(XLEN):0] keep_bits_i, 27 | input logic valid_i, 28 | 29 | input logic use_full_addr_i, 30 | 31 | input logic interrupt_i, 32 | input logic [CAUSELEN-1:0] cause_i, 33 | input logic [XLEN-1:0] tval_i, 34 | input logic [PRIVLEN-1:0] priv_i, 35 | input logic [XLEN-1:0] iaddr_i, 36 | input logic [CONTEXTLEN-1:0] context_i, 37 | 38 | input logic lc_u_discontinuity_i, 39 | 40 | input logic [30:0] branch_map_i, 41 | input logic [4:0] branch_map_cnt_i, 42 | input logic branch_map_empty_i, 43 | input logic branch_map_full_i, 44 | input logic is_branch_i, 45 | 46 | // command the branch map to flush when we generated a packet 47 | output logic branch_map_flush_o, 48 | 49 | // information for trdb_priority to decide what packet type we need 50 | output logic [XLEN-1:0] diff_addr_o, 51 | 52 | // software packet generation request (dumping a write to stream) 53 | input logic sw_valid_i, 54 | input logic [XLEN-1:0] sw_word_i, 55 | output logic sw_grant_o, 56 | 57 | // timer packet generation request 58 | input logic tu_valid_i, 59 | input logic [TIMER_WIDTH-1:0] tu_time_i, 60 | input logic tu_fulltime_i, 61 | output logic tu_grant_o, 62 | 63 | // packet bits which were generated from request 64 | output logic [PACKET_LEN-1:0] packet_bits_o, //TODO: adjust sizes 65 | output logic [6:0] packet_len_o, 66 | output logic packet_valid_o); 67 | 68 | logic [PACKET_LEN-1:0] packet_bits; 69 | logic [$clog2(PACKET_LEN)-1:0] packet_len; 70 | logic packet_gen_valid; 71 | 72 | // request to flush the branch map so that it is empty for the next packet 73 | logic branch_map_flush_q, branch_map_flush_d; 74 | 75 | // needed for the calculation of the length of the branch map len field 76 | logic [4:0] branch_packet_off ; 77 | 78 | // to handle the edge case where we need to store an address in a full 79 | // branch map 80 | logic branch_map_edge_case; 81 | 82 | // compute and handle differential addresses 83 | logic [XLEN-1:0] caddr; 84 | logic [XLEN-1:0] diff_addr; 85 | logic [XLEN-1:0] last_addr_q, last_addr_d; 86 | 87 | assign branch_map_flush_o = branch_map_flush_q; 88 | 89 | // quantize the length of the branch map to the fixed values below 90 | always_comb begin: branch_map_offset 91 | if(branch_map_cnt_i == 0) begin 92 | branch_packet_off = 31; 93 | end else if(branch_map_cnt_i <= 1) begin 94 | branch_packet_off = 1; 95 | end else if(branch_map_cnt_i <= 9) begin 96 | branch_packet_off = 9; 97 | end else if(branch_map_cnt_i <= 17) begin 98 | branch_packet_off = 17; 99 | end else if(branch_map_cnt_i <= 25) begin 100 | branch_packet_off = 25; 101 | end else begin 102 | branch_packet_off = 31; 103 | end 104 | end 105 | 106 | `ifndef SYNTHESIS 107 | branch_map_size_check: assert property 108 | (@(posedge clk_i) disable iff (~rst_ni) (branch_map_cnt_i < 32)) 109 | else $error("[TRDB] @%t: branch_map_cnt_i=%d is too large", 110 | $time, branch_map_cnt_i); 111 | `endif 112 | 113 | assign diff_addr = last_addr_q - iaddr_i; 114 | 115 | assign diff_addr_o = diff_addr; 116 | 117 | always_comb begin: compress_address 118 | caddr = (use_full_addr_i || packet_format_i == F_BRANCH_FULL) ? 119 | iaddr_i : diff_addr; 120 | end 121 | 122 | 123 | always_comb begin: set_packet_bits 124 | packet_bits = '0; 125 | packet_len = '0; 126 | branch_map_flush_d = '0; 127 | 128 | branch_map_edge_case = lc_u_discontinuity_i; 129 | packet_gen_valid = '0; 130 | 131 | sw_grant_o = '0; 132 | tu_grant_o = '0; 133 | last_addr_d = last_addr_q; 134 | 135 | if(valid_i) begin 136 | // remember full address in this packet for next packet 137 | last_addr_d = iaddr_i; 138 | 139 | packet_gen_valid = '1; 140 | packet_bits[1:0] = W_TRACE; 141 | 142 | // packet format 143 | packet_bits[3:2] = packet_format_i; 144 | 145 | // always flush branchmap 146 | branch_map_flush_d = '1; 147 | 148 | case(packet_format_i) 149 | 150 | F_BRANCH_FULL, F_BRANCH_DIFF: begin 151 | // We shouldn't have an empty branch map if we want to generate 152 | // this packet TODO: there is an issue since branch_map_flush_d 153 | // immediately changes branch_map_cnt_i 154 | // assert(branch_map_cnt_i != 0); 155 | 156 | packet_bits[8:4] = branch_map_cnt_i; 157 | branch_map_flush_d = '1; 158 | 159 | if(branch_packet_off == 1) begin 160 | packet_bits[9+:1+XLEN] = {caddr, branch_map_i[0]}; 161 | packet_len = 2 + FORMATLEN + BRANCHLEN + 1 + keep_bits_i; 162 | 163 | end else if(branch_packet_off == 9) begin 164 | packet_bits[9+:9+XLEN] = {caddr, branch_map_i[8:0]}; 165 | packet_len = 2 + FORMATLEN + BRANCHLEN + 9 + keep_bits_i; 166 | 167 | end else if(branch_packet_off == 17) begin 168 | packet_bits[9+:17+XLEN] = {caddr, branch_map_i[16:0]}; 169 | packet_len = 2 + FORMATLEN + BRANCHLEN + 17 + keep_bits_i; 170 | 171 | end else if(branch_packet_off == 25) begin 172 | packet_bits[9+:25+XLEN] = {caddr, branch_map_i[24:0]}; 173 | packet_len = 2 + FORMATLEN + BRANCHLEN + 25 + keep_bits_i; 174 | 175 | end else if (branch_packet_off == 31 && !branch_map_full_i) begin 176 | packet_bits[9+:31+XLEN] = {caddr, branch_map_i[30:0]}; 177 | packet_len = 2 + FORMATLEN + BRANCHLEN + 31 + keep_bits_i; 178 | 179 | end else begin 180 | packet_bits[9+:31+XLEN] = {branch_map_edge_case ? caddr : 181 | 32'b0, branch_map_i[30:0]}; 182 | packet_len = 2 + FORMATLEN + BRANCHLEN + 31 + 183 | (branch_map_edge_case ? keep_bits_i : 0); 184 | // if we dont have to put an address we indicate that by 185 | // settings branchmap to 0 186 | packet_bits[8:4] = branch_map_edge_case ? 187 | packet_bits[8:4] : 5'b0; 188 | // don't remember any address since there is none 189 | 190 | // TODO: the spec says something about extending branch-map 191 | // to fill the address field when branches = 0. Does this 192 | // come into play here? 193 | last_addr_d = branch_map_edge_case ? iaddr_i : last_addr_q; 194 | end 195 | end 196 | 197 | F_ADDR_ONLY: begin 198 | packet_bits[4+:XLEN] = caddr; 199 | packet_len = 2 + FORMATLEN + keep_bits_i; 200 | end 201 | 202 | F_SYNC: begin 203 | // 2: subformat 204 | // PRIVLEN: privilege level 205 | // 1: is this instruction a branch 206 | // XLEN: address 207 | // CAUSELEN: exception cause 208 | // 1: is interrupt? 209 | `ifndef SYNTHESIS 210 | assert(packet_subformat_i != SF_CONTEXT); 211 | assert(packet_subformat_i != SF_UNDEF); 212 | `endif 213 | 214 | case(packet_subformat_i) 215 | 216 | SF_START: begin 217 | packet_bits[4+:2+PRIVLEN+1+XLEN] 218 | = {iaddr_i, is_branch_i, priv_i, packet_subformat_i}; 219 | packet_len = 2 + FORMATLEN + FORMATLEN + PRIVLEN + 1 + XLEN; 220 | end 221 | 222 | SF_EXCEPTION: begin 223 | packet_bits[4+:2+PRIVLEN+1+XLEN+CAUSELEN+1] 224 | = {interrupt_i, cause_i, iaddr_i, is_branch_i, priv_i, 225 | packet_subformat_i}; 226 | packet_len = 2 + FORMATLEN + FORMATLEN + PRIVLEN + 1 + XLEN 227 | + CAUSELEN + 1; 228 | end 229 | 230 | SF_CONTEXT: begin 231 | end 232 | 233 | endcase 234 | 235 | end 236 | endcase 237 | 238 | end else if(sw_valid_i) begin 239 | packet_gen_valid = '1; 240 | sw_grant_o = '1; 241 | packet_bits[1:0] = W_SOFTWARE; 242 | packet_bits[2+:32] = sw_word_i; 243 | packet_len = 2 + 32; 244 | 245 | end else if(tu_valid_i) begin 246 | packet_gen_valid = '1; 247 | tu_grant_o = '1; 248 | packet_bits[1:0] = W_TIME; 249 | // TODO: handle fulltime flag 250 | packet_bits[2+:TIMER_WIDTH] = tu_time_i; 251 | packet_len = 2+TIMER_WIDTH; 252 | 253 | end 254 | 255 | end 256 | 257 | assign packet_bits_o = packet_bits; 258 | assign packet_len_o = packet_len; 259 | assign packet_valid_o = packet_gen_valid; 260 | 261 | 262 | always_ff @(posedge clk_i, negedge rst_ni) begin 263 | if(~rst_ni) begin 264 | branch_map_flush_q <= '0; 265 | last_addr_q <= '0; 266 | end else begin 267 | branch_map_flush_q <= branch_map_flush_d; 268 | last_addr_q <= last_addr_d; 269 | end 270 | end 271 | 272 | endmodule // trdb_packet_emitter 273 | -------------------------------------------------------------------------------- /rtl/trdb_priority.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Order packet generation request by priority 13 | 14 | 15 | import trdb_pkg::*; 16 | 17 | // TODO: add commented out signals 18 | module trdb_priority 19 | (input logic valid_i, 20 | 21 | input logic [XLEN-1:0] full_addr_i, 22 | input logic [XLEN-1:0] diff_addr_i, 23 | 24 | input logic lc_exception_i, 25 | input logic lc_exception_sync_i, 26 | 27 | input logic tc_first_qualified_i, 28 | input logic nc_unqualified_i, 29 | //input logic tc_unhalted, 30 | input logic tc_privchange_i, 31 | //input logic resync & branch_map_cnt 32 | 33 | input logic lc_u_discontinuity_i, 34 | 35 | // input logic resync 36 | // input logic branch_map_nonempty, 37 | 38 | //input logic nc_halt, 39 | input logic nc_exception_i, 40 | input logic nc_privchange_i, 41 | //input logic nc_qualified, 42 | 43 | input logic branch_map_full_i, 44 | 45 | //input logic tc_context_change, 46 | 47 | input logic branch_map_empty_i, 48 | 49 | input logic use_full_addr_i, 50 | 51 | // how many bits of the address are useful 52 | output logic [$clog2(XLEN):0] keep_bits_o, 53 | output logic valid_o, 54 | output trdb_format_e packet_format_o, 55 | output trdb_subformat_e packet_subformat_o); 56 | 57 | // to compress addresses we can, instead of always giving out the full 58 | // address, only give out the difference to the last emitted packet address 59 | logic prefer_differential; 60 | 61 | logic [$clog2(XLEN)-1:0] diff_addr_zeros, diff_addr_ones; 62 | logic [$clog2(XLEN)-1:0] full_addr_zeros, full_addr_ones; 63 | 64 | logic [$clog2(XLEN)-1:0] abs_sign_extendable, diff_sign_extendable, 65 | sign_extendable; 66 | 67 | 68 | // TODO: temporarily put here to make it compile 69 | logic tc_unhalted_i; 70 | logic nc_halt_i; 71 | logic tc_context_change; 72 | 73 | assign tc_unhalted_i = '0; 74 | assign nc_halt_i = '0; 75 | assign tc_context_change = '0; 76 | 77 | 78 | // TODO: same as in C-code, differential address generation when 79 | // TODO: assert for X's 80 | always_comb begin: select_packet 81 | // TODO: default value for packet_*format_o 82 | valid_o = '0; 83 | packet_format_o = F_ADDR_ONLY; 84 | packet_subformat_o = SF_UNDEF; 85 | 86 | if (valid_i) begin 87 | if (lc_exception_i) begin 88 | packet_format_o = F_SYNC; 89 | packet_subformat_o = SF_EXCEPTION; 90 | valid_o = '1; 91 | // TODO: lc_emitted_exception_sync 92 | // TODO: missing some conditions 93 | end else if (lc_exception_sync_i) begin 94 | packet_format_o = F_SYNC; 95 | packet_subformat_o = SF_START; 96 | valid_o = '1; 97 | 98 | end else if (tc_first_qualified_i || tc_unhalted_i || 99 | tc_privchange_i) begin 100 | packet_format_o = F_SYNC; 101 | packet_subformat_o = SF_START; 102 | valid_o = '1; 103 | 104 | end else if (lc_u_discontinuity_i) begin 105 | if (branch_map_empty_i) 106 | packet_format_o = F_ADDR_ONLY; 107 | else begin 108 | if (use_full_addr_i) begin 109 | packet_format_o = F_BRANCH_FULL; 110 | end else begin 111 | packet_format_o = prefer_differential ? 112 | F_BRANCH_DIFF : F_BRANCH_FULL; 113 | end 114 | end 115 | valid_o = '1; 116 | 117 | //TODO: resync and branch_map_nonempty clause 118 | end else if (nc_halt_i || nc_exception_i || nc_privchange_i || 119 | nc_unqualified_i) begin 120 | if(branch_map_empty_i) 121 | packet_format_o = F_ADDR_ONLY; 122 | else begin 123 | if (use_full_addr_i) begin 124 | packet_format_o = F_BRANCH_FULL; 125 | end else begin 126 | packet_format_o = prefer_differential ? 127 | F_BRANCH_DIFF : F_BRANCH_FULL; 128 | end 129 | end 130 | valid_o = '1; 131 | 132 | end else if (branch_map_full_i) begin 133 | // prefer_differential doesn't matter since we don't have an 134 | // address anyway 135 | packet_format_o = F_BRANCH_FULL; 136 | valid_o = '1; 137 | 138 | end else if (tc_context_change) begin 139 | packet_format_o = F_SYNC; 140 | packet_subformat_o = SF_CONTEXT; 141 | valid_o = '1; 142 | end 143 | end 144 | end 145 | 146 | // we want to take the address which needs the least bits to represent by 147 | // omitting the bits which can be inferred through sign-extension 148 | // TODO: we don't need to know the exact number of leading zeros/ones 149 | always_comb begin: absolute_or_differential 150 | abs_sign_extendable = full_addr_zeros > full_addr_ones ? 151 | full_addr_zeros : full_addr_ones; 152 | diff_sign_extendable = diff_addr_zeros > diff_addr_ones ? 153 | diff_addr_zeros : diff_addr_ones; 154 | prefer_differential = diff_sign_extendable > abs_sign_extendable; 155 | sign_extendable = prefer_differential ? 156 | diff_sign_extendable : abs_sign_extendable; 157 | 158 | // if we always want the full address then we have to signal that we 159 | // want to keep all bits 160 | keep_bits_o = use_full_addr_i ? XLEN : XLEN - sign_extendable + 1; 161 | end 162 | 163 | trdb_lzc 164 | #(.WIDTH(XLEN), 165 | .MODE(1)) 166 | i_trdb_lzc_full 167 | (.in_i(full_addr_i), 168 | .cnt_o(full_addr_zeros), 169 | .empty_o()); 170 | 171 | trdb_lzc 172 | #(.WIDTH(XLEN), 173 | .MODE(1)) 174 | i_trdb_loc_full 175 | (.in_i(~full_addr_i), 176 | .cnt_o(full_addr_ones), 177 | .empty_o()); 178 | 179 | trdb_lzc 180 | #(.WIDTH(XLEN), 181 | .MODE(1)) 182 | i_trdb_lzc_diff 183 | (.in_i(diff_addr_i), 184 | .cnt_o(diff_addr_zeros), 185 | .empty_o()); 186 | 187 | trdb_lzc 188 | #(.WIDTH(XLEN), 189 | .MODE(1)) 190 | i_trdb_loc_diff 191 | (.in_i(~diff_addr_i), 192 | .cnt_o(diff_addr_ones), 193 | .empty_o()); 194 | 195 | 196 | endmodule // trdb_priority 197 | -------------------------------------------------------------------------------- /rtl/trdb_reg.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Memory mapped control registers for the trace debugger 13 | 14 | import trdb_pkg::*; 15 | 16 | module trdb_reg 17 | #(parameter APB_ADDR_WIDTH = 12) 18 | (input logic clk_i, 19 | input logic rst_ni, 20 | input logic test_mode_i, 21 | output logic clk_gated_o, 22 | 23 | // write and reads from the APB 24 | output logic [31:0] per_rdata_o, 25 | output logic per_ready_o, 26 | input logic [31:0] per_wdata_i, 27 | input logic [APB_ADDR_WIDTH-1:0] per_addr_i, 28 | input logic per_we_i, 29 | input logic per_valid_i, 30 | 31 | // packet streamer control 32 | output flush_stream_o, 33 | input flush_confirm_i, 34 | output logic clear_fifo_o, 35 | 36 | // trace debugger settings and control 37 | output logic trace_enable_o, 38 | output logic trace_activated_o, 39 | output logic trace_full_addr_o, 40 | input logic trace_req_deactivate_i, 41 | output logic trace_implicit_ret_o, 42 | 43 | // signals that control the filtering settings 44 | output logic apply_filters_o, 45 | output logic trace_selected_priv_o, 46 | output logic [1:0] trace_which_priv_o, 47 | output logic trace_range_event_o, 48 | output logic trace_stop_event_o, 49 | output logic [XLEN-1:0] trace_lower_addr_o, 50 | output logic [XLEN-1:0] trace_higher_addr_o, 51 | 52 | // trace debugger status signals 53 | input logic trace_qualified_i, 54 | input logic trace_priv_match_i, 55 | input logic trace_range_match_i, 56 | input logic trace_fifo_overflow_i, 57 | input logic external_fifo_overflow_i, 58 | 59 | // user data writes which get merged into packet stream 60 | output logic [31:0] sw_word_o, 61 | output logic sw_valid_o, 62 | input logic sw_grant_i, 63 | 64 | // timer packet request through user 65 | output logic tu_req_o); 66 | 67 | import trdb_pkg::*; 68 | 69 | // clock gating for everything but the ctrl register 70 | logic clk_gated; 71 | 72 | // hold control status 73 | trdb_ctrl_t ctrl_q, ctrl_d; 74 | 75 | // hold trace debugger status 76 | trdb_status_t status_q, status_d; 77 | 78 | // hold trace debugger filter settings 79 | trdb_filterconf_t filter_q, filter_d; 80 | 81 | // allow the user to write to this register to dump data through the trace 82 | // debugger 83 | logic [31:0] dump_q, dump_d; 84 | logic dump_valid_q, dump_valid_d; 85 | logic sw_fifo_not_full; 86 | logic clear_sw_fifo; 87 | 88 | // remember address ranges 89 | logic [XLEN-1:0] higher_addr_q, higher_addr_d; 90 | logic [XLEN-1:0] lower_addr_q, lower_addr_d; 91 | 92 | 93 | // control reg outgoing signals 94 | assign trace_enable_o = ctrl_q.enable; 95 | assign trace_activated_o = ctrl_q.activated; 96 | assign clear_fifo_o = ctrl_q.clear_fifo; 97 | assign flush_stream_o = ctrl_q.flush_stream; 98 | assign trace_full_addr_o = ctrl_q.full_addr; 99 | assign trace_implicit_ret_o = ctrl_q.implicit_ret; 100 | 101 | // status reg outgoing signals 102 | assign apply_filters_o = filter_q.apply_filters; 103 | assign trace_selected_priv_o = filter_q.trace_priv; 104 | assign trace_which_priv_o = filter_q.which_priv; 105 | assign trace_range_event_o = filter_q.range_event[0]; 106 | assign trace_stop_event_o = filter_q.stop_event[0]; 107 | 108 | // for range tracing 109 | assign trace_lower_addr_o = lower_addr_q; 110 | assign trace_higher_addr_o = higher_addr_q; 111 | 112 | 113 | always_comb begin: read_reg 114 | per_rdata_o = 32'h0; 115 | if(per_valid_i & ~per_we_i) begin 116 | case(per_addr_i[7:0]) 117 | REG_TRDB_CTRL: 118 | per_rdata_o = ctrl_q; 119 | REG_TRDB_STATUS: 120 | per_rdata_o = status_q; 121 | REG_TRDB_FILTER: 122 | per_rdata_o = filter_q; 123 | REG_TRDB_DUMP: 124 | per_rdata_o = 32'h0; 125 | REG_TRDB_DUMP_WITH_TIME: 126 | per_rdata_o = 32'h0; 127 | default: 128 | per_rdata_o = 32'h0; 129 | endcase 130 | end 131 | end 132 | 133 | 134 | // this buffers our software writes, since we are contesting with packets 135 | // which have a priority over software writes. 136 | generic_fifo_adv 137 | #(.DATA_WIDTH(32), 138 | .DATA_DEPTH(SOFTWARE_BUFFER_STAGES)) 139 | i_sw_fifo 140 | (.clk(clk_i), 141 | .rst_n(rst_ni), 142 | .clear_i(clear_sw_fifo), 143 | .data_i(dump_q), 144 | .valid_i(dump_valid_q), 145 | .grant_o(sw_fifo_not_full), // TODO: make this visible in register 146 | .data_o(sw_word_o), 147 | .valid_o(sw_valid_o), 148 | .grant_i(sw_grant_i), 149 | .test_mode_i('0)); // TODO: what to do with this 150 | 151 | `ifndef SYNTHESIS 152 | sw_fifo_overflow: assert property 153 | (@(posedge clk_i) disable iff (~rst_ni) (sw_fifo_not_full == 1'b1)) 154 | else $error("[TRDB] @%t: Software FIFO is overflowing.", $time); 155 | `endif 156 | 157 | 158 | // we can tie this high since according the apb protocol if we react in the 159 | // next cycle this is allowed 160 | assign per_ready_o = 1'b1; 161 | 162 | 163 | // status from trace debugger 164 | assign status_d.qualified = trace_qualified_i; 165 | assign status_d.priv_match = trace_priv_match_i; 166 | assign status_d.range_match = trace_range_match_i; 167 | assign status_d.fifo_overflow = trace_fifo_overflow_i; 168 | assign status_d.ext_fifo_overflow = external_fifo_overflow_i; 169 | 170 | // register write logic 171 | always_comb begin: write_reg 172 | trdb_ctrl_t ctrl_w; 173 | 174 | ctrl_w = '0; 175 | ctrl_d = ctrl_q; 176 | filter_d = filter_q; 177 | dump_d = dump_q; 178 | dump_valid_d = '0; 179 | tu_req_o = '0; 180 | lower_addr_d = lower_addr_q; 181 | higher_addr_d = higher_addr_q; 182 | 183 | if(per_valid_i & per_we_i) begin 184 | case (per_addr_i[7:0]) 185 | REG_TRDB_CTRL: begin 186 | ctrl_w = trdb_ctrl_t'(per_wdata_i); 187 | ctrl_d.activated = ctrl_w.activated; 188 | ctrl_d.flush_stream = ctrl_w.flush_stream; 189 | ctrl_d.enable = ctrl_w.enable; 190 | ctrl_d.clear_fifo = ctrl_w.clear_fifo; 191 | ctrl_d.full_addr = ctrl_w.full_addr; 192 | ctrl_d.implicit_ret = ctrl_w.implicit_ret; 193 | end 194 | REG_TRDB_STATUS: begin 195 | end 196 | REG_TRDB_FILTER: 197 | filter_d = {per_wdata_i[6], 1'b0, per_wdata_i[4:0]}; 198 | REG_TRDB_DUMP: begin 199 | dump_d = per_wdata_i; 200 | dump_valid_d = '1; 201 | end 202 | REG_TRDB_DUMP_WITH_TIME: begin 203 | dump_d = per_wdata_i; 204 | dump_valid_d = '1; 205 | tu_req_o = '1; 206 | end 207 | REG_TRDB_LOWER_ADDR: 208 | lower_addr_d = per_wdata_i; 209 | REG_TRDB_HIGHER_ADDR: 210 | higher_addr_d = per_wdata_i; 211 | endcase 212 | end 213 | 214 | if(flush_confirm_i) 215 | ctrl_d.flush_stream = 1'b0; 216 | 217 | // Force disable tracer when we the filter requests it. User needs to 218 | // change filter to allow tracing in filtered region. 219 | if(trace_req_deactivate_i) 220 | ctrl_d.activated = 1'b0; 221 | 222 | end 223 | 224 | // clock gating logic 225 | pulp_clock_gating i_trdb_clock_gating 226 | (.clk_i(clk_i), 227 | .test_en_i(test_mode_i), 228 | .en_i(ctrl_q.enable), 229 | .clk_o(clk_gated)); 230 | 231 | assign clk_gated_o = clk_gated; 232 | 233 | always_ff @(posedge clk_i, negedge rst_ni) begin 234 | if(~rst_ni) begin 235 | ctrl_q <= 'h0; 236 | end else begin 237 | ctrl_q <= ctrl_d; 238 | end 239 | end 240 | 241 | always_ff @(posedge clk_gated, negedge rst_ni) begin 242 | if(~rst_ni) begin 243 | status_q <= 'h0; 244 | filter_q <= 'h0; 245 | dump_q <= 'h0; 246 | dump_valid_q <= 'h0; 247 | higher_addr_q <= 'h0; 248 | lower_addr_q <= 'h0; 249 | 250 | end else begin 251 | status_q <= status_d; 252 | filter_q <= filter_d; 253 | dump_q <= dump_d; 254 | dump_valid_q <= dump_valid_d; 255 | higher_addr_q <= higher_addr_d; 256 | lower_addr_q <= lower_addr_d; 257 | 258 | end 259 | end 260 | endmodule // trdb_reg 261 | -------------------------------------------------------------------------------- /rtl/trdb_timer.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Keep track of cpu clock cycles for time packets 13 | 14 | import trdb_pkg::*; 15 | 16 | module trdb_timer 17 | #(parameter TIMER_WIDTH = 40) 18 | (input logic clk_i, 19 | input logic rst_ni, 20 | input logic manual_rst_i, // TODO: make this handshake 21 | 22 | input logic tu_req_i, 23 | output logic tu_valid_o, 24 | input logic tu_grant_i, 25 | 26 | output logic [TIMER_WIDTH-1:0] trdb_time_o); 27 | 28 | logic [TIMER_WIDTH-1:0] trdb_time_q, trdb_time_d; 29 | 30 | enum logic [1:0] {IDLE, REQ} cs, ns; 31 | 32 | assign trdb_time_o = trdb_time_q; 33 | 34 | // the request logic has a one cycle delay, but when we generated a timer 35 | // packet by a write to REG_TRDB_DUMP_WITH_TIME, we have to wait for the sw 36 | // packet anyway 37 | always_comb begin: timer_req_packet 38 | ns = cs; 39 | tu_valid_o = '0; 40 | 41 | case(cs) 42 | IDLE: begin 43 | tu_valid_o = '0; 44 | if(tu_req_i) 45 | ns = REQ; 46 | end 47 | 48 | REQ: begin 49 | tu_valid_o = '1; 50 | if(tu_grant_i) 51 | ns = IDLE; 52 | end 53 | endcase // case (cs) 54 | end 55 | 56 | always_comb begin: inc_timer 57 | if(!manual_rst_i) 58 | trdb_time_d <= trdb_time_q + 1; 59 | else 60 | trdb_time_d <= '0; 61 | end 62 | 63 | always_ff @(posedge clk_i, negedge rst_ni) begin 64 | if(~rst_ni) begin 65 | trdb_time_q <= '0; 66 | cs <= IDLE; 67 | end else begin 68 | trdb_time_q <= trdb_time_d; 69 | cs <= ns; 70 | end 71 | end 72 | 73 | endmodule 74 | -------------------------------------------------------------------------------- /src_files.yml: -------------------------------------------------------------------------------- 1 | trace_debugger: 2 | incdirs: [ 3 | include, 4 | ] 5 | files: [ 6 | include/trdb_pkg.sv, 7 | rtl/trace_debugger_stimuli_gen.sv, 8 | rtl/trace_debugger.sv, 9 | rtl/tracer_if.sv, 10 | rtl/tracer_reg_if.sv, 11 | rtl/trdb_apb_if.sv, 12 | rtl/trdb_branch_map.sv, 13 | rtl/trdb_packet_emitter.sv, 14 | rtl/trdb_priority.sv, 15 | rtl/trdb_reg.sv, 16 | rtl/trdb_align.sv, 17 | rtl/trdb_align8.sv, 18 | rtl/trdb_timer.sv, 19 | rtl/trdb_filter.sv, 20 | rtl/trdb_lzc.sv, 21 | ] 22 | -------------------------------------------------------------------------------- /tb/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/trace_debugger/0df525be5a3856a8af2b99a4396aece3bfd141a9/tb/.gitkeep -------------------------------------------------------------------------------- /tb/Makefile: -------------------------------------------------------------------------------- 1 | %: 2 | $(MAKE) -C .. $@ 3 | -------------------------------------------------------------------------------- /tb/driver.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Push stimuli to duv 13 | 14 | import trdb_pkg::*; 15 | import trdb_tb_pkg::*; 16 | 17 | class Driver; 18 | 19 | virtual trace_debugger_if duv_if; 20 | mailbox #(Stimuli) mail; 21 | event tb_eos; 22 | 23 | function new(virtual trace_debugger_if duv_if, mailbox #(Stimuli) mail, 24 | event tb_eos); 25 | this.duv_if = duv_if; 26 | this.mail = mail; 27 | this.tb_eos = tb_eos; 28 | endfunction 29 | 30 | 31 | // parse stimuli file 32 | function int parse_stimuli(string path, Stimuli stimuli); 33 | string line; 34 | int fp, c; 35 | string err_str; 36 | int linecnt = 0; 37 | 38 | logic ivalid; 39 | logic iexception; 40 | logic interrupt; 41 | logic [CAUSELEN-1:0] cause; 42 | logic [XLEN-1:0] tval; 43 | logic [PRIVLEN-1:0] priv; 44 | logic [XLEN-1:0] iaddr; 45 | logic [ILEN-1:0] instr; 46 | logic compressed; 47 | 48 | if($test$plusargs("debug")) 49 | $display("[STIMULI]@%t: Opening file %s.", $time, path); 50 | fp = $fopen(path, "r"); 51 | 52 | if($ferror(fp, err_str)) begin 53 | $error(err_str); 54 | return -1; 55 | end 56 | 57 | 58 | while ($fgets(line, fp) != 0) begin 59 | c = $sscanf(line,"valid=%h exception=%h interrupt=%h cause=%h \ 60 | tval=%h priv=%h compressed=%h addr=%h instr=%h", 61 | ivalid, iexception, interrupt, cause, 62 | tval, priv, compressed, iaddr, instr); 63 | if (c <= 0) begin 64 | $error("$sscanf error"); 65 | return -1; 66 | end 67 | linecnt++; 68 | stimuli.ivalid.push_front(ivalid); 69 | stimuli.iexception.push_front(iexception); 70 | stimuli.interrupt.push_front(interrupt); 71 | stimuli.cause.push_front(cause); 72 | stimuli.tval.push_front(tval); 73 | stimuli.priv.push_front(priv); 74 | stimuli.iaddr.push_front(iaddr); 75 | stimuli.instr.push_front(instr); 76 | stimuli.compressed.push_front(compressed); 77 | end 78 | 79 | if($test$plusargs("debug")) begin 80 | $display("[STIMULI]@%t: Read %d lines.", $time, linecnt); 81 | end 82 | 83 | if ($ferror(fp, err_str)) begin 84 | $error("[ERROR]: %s", err_str); 85 | return -1; 86 | end else if ($feof(fp)) begin 87 | if($test$plusargs("debug")) 88 | $display("[STIMULI]@%t: Finished parsing %s.", $time, path); 89 | end 90 | 91 | if(!fp) 92 | $fclose(fp); 93 | return 0; 94 | endfunction 95 | 96 | // parse stimuli file in cvs format 97 | function int parse_cvs_stimuli(string path, Stimuli stimuli); 98 | string line; 99 | int fp, c; 100 | string err_str; 101 | int linecnt = 0; 102 | 103 | logic ivalid; 104 | logic iexception; 105 | logic interrupt; 106 | logic [CAUSELEN-1:0] cause; 107 | logic [XLEN-1:0] tval; 108 | logic [PRIVLEN-1:0] priv; 109 | logic [XLEN-1:0] iaddr; 110 | logic [ILEN-1:0] instr; 111 | logic compressed; 112 | 113 | if($test$plusargs("debug")) 114 | $display("[STIMULI]@%t: Opening file %s.", $time, path); 115 | fp = $fopen(path, "r"); 116 | 117 | if($ferror(fp, err_str)) begin 118 | $error(err_str); 119 | return -1; 120 | end 121 | 122 | c = $fgets(line, fp); 123 | if (c <= 0) begin 124 | $error("$sscanf error"); 125 | return -1; 126 | end 127 | 128 | 129 | while ($fgets(line, fp) != 0) begin 130 | c = $sscanf(line,"%h,%h,%h,%h,%h,%h,%h,%h", 131 | ivalid, iaddr, instr, priv, iexception, 132 | cause, tval, interrupt); 133 | if (c <= 0) begin 134 | $error("$sscanf error"); 135 | return -1; 136 | end 137 | compressed = ((instr[1:0] & 2'h3) != 2'h3); 138 | linecnt++; 139 | stimuli.ivalid.push_front(ivalid); 140 | stimuli.iexception.push_front(iexception); 141 | stimuli.interrupt.push_front(interrupt); 142 | stimuli.cause.push_front(cause); 143 | stimuli.tval.push_front(tval); 144 | stimuli.priv.push_front(priv); 145 | stimuli.iaddr.push_front(iaddr); 146 | stimuli.instr.push_front(instr); 147 | stimuli.compressed.push_front(compressed); 148 | end 149 | 150 | if($test$plusargs("debug")) begin 151 | $display("[STIMULI]@%t: Read %d lines.", $time, linecnt); 152 | end 153 | 154 | if ($ferror(fp, err_str)) begin 155 | $error("[ERROR]: %s", err_str); 156 | return -1; 157 | end else if ($feof(fp)) begin 158 | if($test$plusargs("debug")) 159 | $display("[STIMULI]@%t: Finished parsing %s.", $time, path); 160 | end 161 | 162 | if(!fp) 163 | $fclose(fp); 164 | return 0; 165 | endfunction 166 | 167 | 168 | function void apply_zero(); 169 | if($test$plusargs("debug")) 170 | $display("[DRIVER] @%t: Applying zero stimuli.", $time); 171 | this.duv_if.cb.ivalid <= 1'b0; 172 | this.duv_if.cb.iexception <= 1'b0; 173 | this.duv_if.cb.interrupt <= 1'b0; 174 | this.duv_if.cb.cause <= 5'b0; 175 | this.duv_if.cb.tval <= '0; 176 | this.duv_if.cb.priv <= 3'h7; // PRIVLEN'h7; 177 | this.duv_if.cb.iaddr <= '0; 178 | this.duv_if.cb.instr <= '0; 179 | this.duv_if.cb.compressed <= 1'b0; 180 | endfunction 181 | 182 | 183 | task write_apb(input logic [3:0] waddr, input logic [31:0] wdata); 184 | // write request 185 | @(this.duv_if.cb); 186 | this.duv_if.cb.paddr <= waddr; 187 | this.duv_if.cb.pwrite <= 1'b1; 188 | this.duv_if.cb.psel <= 1'b1; 189 | this.duv_if.cb.pwdata <= wdata; 190 | 191 | @(this.duv_if.cb); 192 | // we are now the access state of the apb 193 | this.duv_if.cb.penable <= 1'b1; 194 | 195 | // wait until request consumed 196 | @(this.duv_if.cb); 197 | wait(this.duv_if.cb.pready == 1); 198 | this.duv_if.cb.penable <= 1'b0; 199 | this.duv_if.cb.psel <= 1'b0; 200 | endtask 201 | 202 | 203 | task test_sw_dump(); 204 | write_apb(REG_TRDB_DUMP, 32'ha0a0a0a0); 205 | write_apb(REG_TRDB_DUMP, 32'hb0b0b0b0); 206 | write_apb(REG_TRDB_DUMP, 32'hc0c0c0c0); 207 | write_apb(REG_TRDB_DUMP, 32'hd0d0d0d0); 208 | write_apb(REG_TRDB_DUMP, 32'hf0f0f0f0); 209 | endtask 210 | 211 | 212 | task run(); 213 | Stimuli stimuli; 214 | int full_address, implicit_ret; 215 | 216 | full_address = ($test$plusargs("fulladdr") != 0); 217 | implicit_ret = ($test$plusargs("implicitret") != 0); 218 | 219 | if($test$plusargs("debug")) 220 | $display("[DRIVER] @%t: Entering run() task.", $time); 221 | 222 | wait(this.duv_if.rst_ni == 1); 223 | if($test$plusargs("debug")) 224 | $display("[DRIVER] @%t: Reset low.", $time); 225 | 226 | 227 | // parse stimuli file 228 | stimuli = new(); 229 | 230 | // assign default test 231 | if(!$value$plusargs("testname=%s", testname)) 232 | testname = default_stimuli_path; 233 | 234 | if($test$plusargs("cvs")) begin 235 | if(parse_cvs_stimuli(testname, stimuli)) 236 | $fatal("parse_cvs_stimuli() failed"); 237 | end else begin 238 | if(parse_stimuli(testname, stimuli)) 239 | $fatal("parse_stimuli() failed"); 240 | end 241 | 242 | // send to scoreboard 243 | mail.put(stimuli); 244 | 245 | //TODO: fix this hack 246 | apply_zero(); 247 | 248 | @(this.duv_if.cb); 249 | apply_zero(); 250 | 251 | // enable trace debugger 252 | write_apb(REG_TRDB_CTRL, (1 << TRDB_ENABLE) 253 | | (1 << TRDB_TRACE_ACTIVATED) 254 | | (full_address << TRDB_FULL_ADDR) 255 | | (implicit_ret << TRDB_IMPLICIT_RET)); 256 | 257 | // apply stimuli according to Top-Down Digital VLSI Design (Kaeslin) 258 | for(int i = stimuli.ivalid.size() - 1; i >= 0; i--) begin 259 | 260 | @(this.duv_if.cb); 261 | 262 | // #STIM_APPLICATION_DEL; 263 | 264 | this.duv_if.cb.ivalid <= stimuli.ivalid[i]; 265 | this.duv_if.cb.iexception <= stimuli.iexception[i]; 266 | this.duv_if.cb.interrupt <= stimuli.interrupt[i]; 267 | this.duv_if.cb.cause <= stimuli.cause[i]; 268 | this.duv_if.cb.tval <= stimuli.tval[i]; 269 | this.duv_if.cb.priv <= stimuli.priv[i]; 270 | this.duv_if.cb.priv[2] <= 1'b1; // we force debug mode, stimuli from 271 | // spike traces don't know that bit 272 | this.duv_if.cb.iaddr <= stimuli.iaddr[i]; 273 | this.duv_if.cb.instr <= stimuli.instr[i]; 274 | this.duv_if.cb.compressed <= stimuli.compressed[i]; 275 | 276 | // #(RESP_ACQUISITION_DEL - STIM_APPLICATION_DEL); 277 | // take response in monitor.svh 278 | end 279 | 280 | // wait for the tracer fifo to empty (TODO: poll fifo or something) 281 | repeat (30) @(this.duv_if.cb); 282 | 283 | $display("[DRIVER] @%t: Testing software writes", $time); 284 | test_sw_dump(); 285 | 286 | // wait for the tracer fifo to empty (TODO: poll fifo or something) 287 | repeat (30) @(this.duv_if.cb); 288 | 289 | $display("[DRIVER] @%t: Flushing buffers.", $time); 290 | // write flush command to register 291 | write_apb(REG_TRDB_CTRL, (1 << TRDB_FLUSH_STREAM | 3)); 292 | 293 | 294 | $display("[DRIVER] @%t: Driver finished.", $time); 295 | 296 | repeat (100) begin 297 | @(this.duv_if.cb); 298 | apply_zero(); 299 | end 300 | 301 | -> tb_eos; 302 | 303 | endtask; 304 | 305 | 306 | endclass // Driver 307 | -------------------------------------------------------------------------------- /tb/dummy/apb_bus_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2018 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | interface APB_BUS 12 | #( 13 | parameter APB_ADDR_WIDTH = 32, 14 | parameter APB_DATA_WIDTH = 32 15 | ); 16 | 17 | logic [APB_ADDR_WIDTH-1:0] paddr; 18 | logic [APB_DATA_WIDTH-1:0] pwdata; 19 | logic pwrite; 20 | logic psel; 21 | logic penable; 22 | logic [APB_DATA_WIDTH-1:0] prdata; 23 | logic pready; 24 | logic pslverr; 25 | 26 | 27 | // Master Side 28 | //*************************************** 29 | modport Master 30 | ( 31 | output paddr, pwdata, pwrite, psel, penable, 32 | input prdata, pready, pslverr 33 | ); 34 | 35 | // Slave Side 36 | //*************************************** 37 | modport Slave 38 | ( 39 | input paddr, pwdata, pwrite, psel, penable, 40 | output prdata, pready, pslverr 41 | ); 42 | 43 | endinterface 44 | 45 | 46 | 47 | 48 | /////////////////////////////////////////////////////// 49 | // // 50 | // █████╗ ██╗ ██╗██╗ ██████╗ ██╗ ██╗███████╗ // 51 | // ██╔══██╗╚██╗██╔╝██║ ██╔══██╗██║ ██║██╔════╝ // 52 | // ███████║ ╚███╔╝ ██║ ██████╔╝██║ ██║███████╗ // 53 | // ██╔══██║ ██╔██╗ ██║ ██╔══██╗██║ ██║╚════██║ // 54 | // ██║ ██║██╔╝ ██╗██║ ██████╔╝╚██████╔╝███████║ // 55 | // ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ // 56 | // // 57 | /////////////////////////////////////////////////////// 58 | interface AXI_BUS 59 | #( 60 | parameter AXI_ADDR_WIDTH = 32, 61 | parameter AXI_DATA_WIDTH = 64, 62 | parameter AXI_ID_WIDTH = 20, 63 | parameter AXI_USER_WIDTH = 6 64 | ); 65 | 66 | localparam AXI_STRB_WIDTH = AXI_DATA_WIDTH/8; 67 | 68 | logic [AXI_ADDR_WIDTH-1:0] aw_addr; 69 | logic [2:0] aw_prot; 70 | logic [3:0] aw_region; 71 | logic [7:0] aw_len; 72 | logic [2:0] aw_size; 73 | logic [1:0] aw_burst; 74 | logic aw_lock; 75 | logic [3:0] aw_cache; 76 | logic [3:0] aw_qos; 77 | logic [AXI_ID_WIDTH-1:0] aw_id; 78 | logic [AXI_USER_WIDTH-1:0] aw_user; 79 | logic aw_ready; 80 | logic aw_valid; 81 | 82 | logic [AXI_ADDR_WIDTH-1:0] ar_addr; 83 | logic [2:0] ar_prot; 84 | logic [3:0] ar_region; 85 | logic [7:0] ar_len; 86 | logic [2:0] ar_size; 87 | logic [1:0] ar_burst; 88 | logic ar_lock; 89 | logic [3:0] ar_cache; 90 | logic [3:0] ar_qos; 91 | logic [AXI_ID_WIDTH-1:0] ar_id; 92 | logic [AXI_USER_WIDTH-1:0] ar_user; 93 | logic ar_ready; 94 | logic ar_valid; 95 | 96 | logic w_valid; 97 | logic [AXI_DATA_WIDTH-1:0] w_data; 98 | logic [AXI_STRB_WIDTH-1:0] w_strb; 99 | logic [AXI_USER_WIDTH-1:0] w_user; 100 | logic w_last; 101 | logic w_ready; 102 | 103 | logic [AXI_DATA_WIDTH-1:0] r_data; 104 | logic [1:0] r_resp; 105 | logic r_last; 106 | logic [AXI_ID_WIDTH-1:0] r_id; 107 | logic [AXI_USER_WIDTH-1:0] r_user; 108 | logic r_ready; 109 | logic r_valid; 110 | 111 | logic [1:0] b_resp; 112 | logic [AXI_ID_WIDTH-1:0] b_id; 113 | logic [AXI_USER_WIDTH-1:0] b_user; 114 | logic b_ready; 115 | logic b_valid; 116 | 117 | // Master Side 118 | //*************************************** 119 | modport Master 120 | ( 121 | 122 | output aw_valid, output aw_addr, output aw_prot, output aw_region, 123 | output aw_len, output aw_size, output aw_burst, output aw_lock, 124 | output aw_cache, output aw_qos, output aw_id, output aw_user, 125 | input aw_ready, 126 | 127 | output ar_valid, output ar_addr, output ar_prot, output ar_region, 128 | output ar_len, output ar_size, output ar_burst, output ar_lock, 129 | output ar_cache, output ar_qos, output ar_id, output ar_user, 130 | input ar_ready, 131 | 132 | output w_valid, output w_data, output w_strb, output w_user, output w_last, 133 | input w_ready, 134 | 135 | input r_valid, input r_data, input r_resp, input r_last, input r_id, input r_user, 136 | output r_ready, 137 | 138 | input b_valid, input b_resp, input b_id, input b_user, 139 | output b_ready 140 | ); 141 | 142 | // Master Side 143 | //*************************************** 144 | modport Slave 145 | ( 146 | 147 | input aw_valid, input aw_addr, input aw_prot, input aw_region, 148 | input aw_len, input aw_size, input aw_burst, input aw_lock, 149 | input aw_cache, input aw_qos, input aw_id, input aw_user, 150 | output aw_ready, 151 | 152 | input ar_valid, input ar_addr, input ar_prot, input ar_region, 153 | input ar_len, input ar_size, input ar_burst, input ar_lock, 154 | input ar_cache, input ar_qos, input ar_id, input ar_user, 155 | output ar_ready, 156 | 157 | input w_valid, input w_data, input w_strb, input w_user, input w_last, 158 | output w_ready, 159 | 160 | output r_valid, output r_data, output r_resp, output r_last, output r_id, output r_user, 161 | input r_ready, 162 | 163 | output b_valid, output b_resp, output b_id, output b_user, 164 | input b_ready 165 | 166 | ); 167 | 168 | endinterface 169 | -------------------------------------------------------------------------------- /tb/reader.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Acquisition of output 13 | 14 | 15 | class Reader; 16 | 17 | virtual trace_debugger_if duv_if; 18 | mailbox #(Response) outbox_duv; 19 | 20 | function new(virtual trace_debugger_if duv_if, 21 | mailbox #(Response) outbox_duv); 22 | this.duv_if = duv_if; 23 | this.outbox_duv = outbox_duv; 24 | endfunction 25 | 26 | // old function that assumes that packets are packed in two words frames and 27 | // are always zero extended to fit into whole words 28 | task acquire_word2(); 29 | // helper variables to parse packet 30 | automatic int pbits; 31 | automatic int totalbits; 32 | automatic int max_reads; 33 | automatic int off; 34 | automatic int wordmod; 35 | automatic int packet_ptr; 36 | automatic trdb_packet packet; 37 | Response response; 38 | 39 | forever begin: acquire 40 | @(this.duv_if.cb); 41 | 42 | if(this.duv_if.cb.packet_word_valid && this.duv_if.cb.grant) begin 43 | if(off == 0) begin 44 | //we are dealing with a new packet 45 | packet.bits = '0; 46 | pbits = (wordmod == 0 ? 47 | this.duv_if.cb.packet_word[$clog2(PACKET_LEN)-1+7:7]: 48 | this.duv_if.cb.packet_word[$clog2(PACKET_LEN)-1:0]); 49 | 50 | // every other words (wordmod == 0) has an additional 7 bits 51 | totalbits = pbits + (pbits/(32+32-7)) * 7 52 | + ((pbits % (32+32-7)) != 0) * 7 53 | - (wordmod == 0 ? 0 : 7); 54 | 55 | max_reads = (totalbits + 32 - 1) / 32; 56 | 57 | if(wordmod == 0) begin 58 | packet.bits[packet_ptr+:32-7] = this.duv_if.cb.packet_word[31:7]; 59 | packet_ptr += 32-7; 60 | end else begin 61 | packet.bits[packet_ptr+:32] = this.duv_if.cb.packet_word; 62 | packet_ptr += 32; 63 | end 64 | off++; 65 | 66 | end else begin 67 | if(wordmod == 0) begin 68 | packet.bits[packet_ptr+:32-7] = this.duv_if.cb.packet_word[31:7]; 69 | packet_ptr += 32-7; 70 | end else begin 71 | packet.bits[packet_ptr+:32] = this.duv_if.cb.packet_word; 72 | packet_ptr += 32; 73 | end 74 | off++; 75 | end 76 | 77 | // next packet 78 | if(off == max_reads) begin 79 | packet_ptr = 0; 80 | off = 0; 81 | response = new(packet); 82 | outbox_duv.put(response); 83 | end 84 | 85 | // emulate word state of streamer 86 | wordmod ++; 87 | wordmod %= 2; 88 | end 89 | end 90 | 91 | endtask 92 | 93 | task acquire_bytewise(); 94 | logic [BUS_DATA_WIDTH-1:0] packet_word; 95 | logic [7:0] packet_byte; 96 | int packet_byte_len; 97 | int effective_bits; 98 | int packet_byte_off; 99 | int packet_ptr; 100 | automatic trdb_packet packet; 101 | Response response; 102 | 103 | int tmp = 1; 104 | 105 | forever begin: acquire 106 | @(this.duv_if.cb); 107 | 108 | if(this.duv_if.cb.packet_word_valid && this.duv_if.cb.grant) begin 109 | packet_word = this.duv_if.cb.packet_word; 110 | if($test$plusargs("debug")) 111 | $display("[READER]@%t: slurping %h", $time, packet_word); 112 | 113 | for(int i = 0; i < BUS_DATA_WIDTH/8; i++) begin 114 | packet_byte = packet_word[i*8+:8]; 115 | 116 | // begin of a new packet 117 | if(packet_byte_off == 0) begin 118 | // clean slate 119 | packet.bits = '0; 120 | // read payload length, assuming its less than 8 bits 121 | effective_bits = packet_byte[PACKET_BYTE_HEADER_LEN-1:0] 122 | * 8 123 | + 8; //for the header 124 | 125 | // a zero length packet can't be good 126 | if(!(effective_bits > PACKET_BYTE_HEADER_LEN)) 127 | continue; 128 | 129 | packet_byte_len 130 | = effective_bits / 8 131 | + ((effective_bits % 8) != 0 ? 1 : 0); 132 | 133 | packet.bits[packet_byte_off*8+:8] = packet_byte; 134 | packet_byte_off++; 135 | end else begin 136 | packet.bits[packet_byte_off*8+:8] = packet_byte; 137 | packet_byte_off++; 138 | end 139 | 140 | if(packet_byte_off == packet_byte_len) begin 141 | packet_byte_off = 0; 142 | response = new(packet); 143 | outbox_duv.put(response); 144 | end 145 | end 146 | end 147 | end 148 | endtask 149 | 150 | task run(); 151 | // acquire_word2(); 152 | acquire_bytewise(); 153 | 154 | repeat(10) 155 | @(this.duv_if.cb); 156 | 157 | endtask 158 | 159 | endclass // Reader 160 | -------------------------------------------------------------------------------- /tb/response.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: SV representation of a response (i.e. packets) 13 | 14 | import trdb_pkg::*; 15 | 16 | class Response; 17 | 18 | trdb_packet packet; 19 | 20 | function new(trdb_packet packet); 21 | this.packet = packet; 22 | endfunction 23 | 24 | function void print; 25 | // automatic logic [1:0] format = packet[8:7]; 26 | // case(format) begin 27 | // F_BRANCH_DIFF: 28 | // $display("F_BRANCH_DIFF not implemented."); 29 | // F_BRANCH_FULL: 30 | // $write("PACKET "); 31 | // format == F_BRANCH_FULL ? $write("0: F_BRANCH_FULL\n") 32 | // : $write("1: F_BRANCH_DIFF\n"); 33 | // $write(stream, " branches : %" "\n", packet->branches); 34 | // $write(stream, " branch_map: 0x%" PRIx32 "\n", packet->branch_map); 35 | // $write(stream, " address : 0x%" PRIx32 "\n", packet->address); 36 | // /* TODO: that special full branch map behaviour */ 37 | // end 38 | 39 | // case F_ADDR_ONLY: 40 | // fprintf(stream, "PACKET 2: F_ADDR_ONLY\n"); 41 | // fprintf(stream, " address : 0x%" PRIx32 "\n", packet->address); 42 | // break; 43 | // case F_SYNC: 44 | // fprintf(stream, "PACKET 3: F_SYNC\n"); 45 | // const char *subf[4]; 46 | // subf[0] = "SF_START"; 47 | // subf[1] = "SF_EXCEPTION"; 48 | // subf[2] = "SF_CONTEXT"; 49 | // subf[3] = "RESERVED"; 50 | // fprintf(stream, " subformat : %s\n", subf[packet->subformat]); 51 | 52 | // /* TODO fix this */ 53 | // fprintf(stream, " context :\n"); 54 | // fprintf(stream, " privilege : 0x%" PRIx32 "\n", packet->privilege); 55 | // if (packet->subformat == SF_CONTEXT) 56 | // return; 57 | 58 | // fprintf(stream, " branch : %s\n", 59 | // packet->branch ? "true" : "false"); 60 | // fprintf(stream, " address : 0x%" PRIx32 "\n", packet->address); 61 | // if (packet->subformat == SF_START) 62 | // return; 63 | 64 | // fprintf(stream, " ecause : 0x%" PRIx32 "\n", packet->ecause); 65 | // fprintf(stream, " interrupt : %s\n", 66 | // packet->interrupt ? "true" : "false"); 67 | // fprintf(stream, " tval : 0x%" PRIx32 "\n", packet->tval); 68 | // /* SF_EXCEPTION */ 69 | // end 70 | 71 | endfunction 72 | 73 | endclass // Response 74 | -------------------------------------------------------------------------------- /tb/scoreboard.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Scoreboard 13 | 14 | import trdb_pkg::*; 15 | 16 | class Scoreboard; 17 | mailbox #(Response) duv_box; 18 | mailbox #(Response) gm_box; 19 | mailbox #(Stimuli) inbox; 20 | 21 | event tb_eos; 22 | 23 | class Statistics; 24 | longint total_packets; 25 | longint packet_bad; 26 | 27 | function void print(); 28 | $display("------------------------------------------------------"); 29 | $display("------------------------------------------------------"); 30 | $display("Simulation Results"); 31 | $display("Test name: %s", testname); 32 | $display("FULL_ADDRESS: %0d IMPLICIT_RET: %0d", 33 | ($test$plusargs("fulladdr") != 0), 34 | ($test$plusargs("implicitret") != 0)); 35 | $display("Good packets %0d/%0d", total_packets - packet_bad, 36 | total_packets); 37 | if (packet_bad != 0) 38 | $display("TEST FAIL"); 39 | else 40 | $display("TEST PASSED"); 41 | $display("------------------------------------------------------"); 42 | $display("------------------------------------------------------"); 43 | endfunction; 44 | 45 | endclass // Statistics 46 | Statistics stats; 47 | 48 | 49 | function new(mailbox #(Stimuli) inbox, mailbox #(Response) duv_box, 50 | event tb_eos); 51 | this.duv_box = duv_box; 52 | this.inbox = inbox; 53 | this.tb_eos = tb_eos; 54 | endfunction 55 | 56 | 57 | function void print; 58 | endfunction 59 | 60 | 61 | task run_gm(); 62 | automatic logic ivalid; 63 | automatic logic iexception; 64 | automatic logic interrupt; 65 | automatic logic [CAUSELEN-1:0] cause; 66 | automatic logic [XLEN-1:0] tval; 67 | automatic logic [PRIVLEN-1:0] priv; 68 | automatic logic [XLEN-1:0] iaddr; 69 | automatic logic [ILEN-1:0] instr; 70 | automatic logic compressed; 71 | 72 | automatic int packet_max_len; 73 | automatic logic [PACKET_TOTAL-1:0] packet_bits; 74 | automatic logic packet_valid; 75 | 76 | automatic trdb_packet packet; 77 | Response response; 78 | Stimuli stimuli; 79 | 80 | // reserve memory for golden model 81 | trdb_sv_alloc(); 82 | 83 | // configure golden model 84 | trdb_sv_set_full_address($test$plusargs("fulladdr") != 0); 85 | trdb_sv_set_implicit_ret($test$plusargs("implicitret") != 0); 86 | 87 | // acquire stimuli 88 | inbox.get(stimuli); 89 | 90 | 91 | for(int i = stimuli.ivalid.size() - 1; i >= 0; i--) begin 92 | ivalid = stimuli.ivalid[i]; 93 | iexception = stimuli.iexception[i]; 94 | interrupt = stimuli.interrupt[i]; 95 | cause = stimuli.cause[i]; 96 | tval = stimuli.tval[i]; 97 | priv = stimuli.priv[i]; 98 | priv[2] = 1'b1; // we force debug mode, stimuli from spike 99 | // traces don't know that bit 100 | iaddr = stimuli.iaddr[i]; 101 | instr = stimuli.instr[i]; 102 | compressed = stimuli.compressed[i]; 103 | 104 | packet_max_len = PACKET_TOTAL; 105 | trdb_sv_feed_trace(ivalid, iexception, interrupt, cause, tval, priv, 106 | iaddr, instr, compressed, packet_max_len, 107 | packet_bits, packet_valid); 108 | 109 | if(packet_valid) begin 110 | packet.bits = packet_bits; 111 | response = new(packet); 112 | gm_box.put(response); 113 | end 114 | end 115 | $display("[SCORE] @%t: Finished golden model computation, queued %d \ 116 | packets.", $time, gm_box.num()); 117 | 118 | //cleanup 119 | trdb_sv_free(); 120 | 121 | endtask 122 | 123 | task add_packet(logic [127:0] bits); 124 | trdb_packet packet; 125 | Response response; 126 | packet.bits = bits; 127 | response = new(packet); 128 | gm_box.put(response); 129 | endtask 130 | 131 | // generated the response for the sw dump writes TODO: a bit hacky 132 | task generate_sw_dump(); 133 | logic [3:0] len; 134 | logic [1:0] msgtype; 135 | len = 4; // payload bytes after first byte 136 | msgtype = W_SOFTWARE; 137 | 138 | add_packet({32'ha0a0a0a0, msgtype,len}); 139 | add_packet({32'hb0b0b0b0, msgtype,len}); 140 | add_packet({32'hc0c0c0c0, msgtype,len}); 141 | add_packet({32'hd0d0d0d0, msgtype,len}); 142 | add_packet({32'hf0f0f0f0, msgtype,len}); 143 | 144 | endtask; 145 | 146 | task run(); 147 | automatic int packetcnt; 148 | automatic int packet_bytes; 149 | Response gm_response; 150 | Response duv_response; 151 | trdb_packet gm_packet; 152 | trdb_packet duv_packet; 153 | trdb_marker_e msgtype; 154 | int tmp = 1; 155 | 156 | 157 | gm_box = new(); 158 | // generate responses 159 | run_gm(); 160 | generate_sw_dump(); 161 | 162 | stats = new(); 163 | packetcnt = 0; 164 | 165 | forever begin 166 | duv_box.get(duv_response); 167 | gm_box.get(gm_response); 168 | gm_packet = gm_response.packet; 169 | duv_packet = duv_response.packet; 170 | stats.total_packets = packetcnt++; 171 | 172 | assert(gm_packet.bits[127:0] === duv_packet.bits[127:0]) begin 173 | msgtype = trdb_marker_e'{duv_packet.bits[5:4]}; 174 | packet_bytes = duv_packet.bits[3:0] + 1; 175 | $display("[SCORE]: Packet with msgtype %s, length %0d,", 176 | msgtype.name, packet_bytes, 177 | "payload %h and number %0d ok", 178 | duv_packet.bits, packetcnt); 179 | end else begin 180 | $error("[SCORE]: ERROR - Packet mismatch for number %0d\n", 181 | packetcnt, 182 | "Expected: %h\n", gm_packet.bits, 183 | "Received: %h", duv_packet.bits); 184 | stats.packet_bad++; 185 | end 186 | end 187 | 188 | endtask 189 | 190 | task print_stats(); 191 | Response gm_response; 192 | Response duv_response; 193 | trdb_packet gm_packet; 194 | trdb_packet duv_packet; 195 | trdb_marker_e msgtype; 196 | 197 | if (gm_box.num() > 0) 198 | $warning("[SCORE] @%t: GM has %0d pending packets.", $time, 199 | gm_box.num()); 200 | if (duv_box.num() > 0) begin 201 | $warning("[SCORE] @%t: DUV has %0d pending packets.", 202 | $time, duv_box.num()); 203 | while(duv_box.num() > 0) begin 204 | duv_box.try_get(duv_response); 205 | duv_packet = duv_response.packet; 206 | msgtype = trdb_marker_e'{duv_packet.bits[5:4]}; 207 | $display("[SCORE] @%t: Remaning: %h", $time, duv_packet.bits); 208 | $display("[SCORE] @%t: length: %0d msgtype: %s", 209 | $time, duv_packet.bits[6:0], msgtype.name); 210 | end 211 | end 212 | 213 | stats.print(); 214 | 215 | endtask 216 | 217 | endclass // Scoreboard 218 | -------------------------------------------------------------------------------- /tb/scripts/vsim.tcl: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Robert Balas 2 | # Copyright and related rights are licensed under the Solderpad Hardware 3 | # License, Version 0.51 (the "License"); you may not use this file except in 4 | # compliance with the License. You may obtain a copy of the License at 5 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | # or agreed to in writing, software, hardware and materials distributed under 7 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | # specific language governing permissions and limitations under the License. 10 | 11 | # Author: Robert Balas (balasr@student.ethz.ch) 12 | # Description: TCL scripts to facilitate simulations 13 | 14 | set NoQuitOnFinish 1 15 | source waves/trace_debugger.tcl 16 | run -all 17 | 18 | # TODO: catch return code 19 | -------------------------------------------------------------------------------- /tb/stimuli.svh: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: SV representation of a stimuli file 13 | 14 | import trdb_pkg::*; 15 | 16 | class Stimuli; 17 | // TODO: make struct instead 18 | logic ivalid[$]; 19 | logic iexception[$]; 20 | logic interrupt[$]; 21 | logic [CAUSELEN-1:0] cause[$]; 22 | logic [XLEN-1:0] tval[$]; 23 | logic [PRIVLEN-1:0] priv[$]; 24 | logic [XLEN-1:0] iaddr[$]; 25 | logic [ILEN-1:0] instr[$]; 26 | logic compressed[$]; 27 | 28 | function new(); 29 | endfunction 30 | 31 | function void print; 32 | 33 | endfunction 34 | 35 | endclass // Stimuli 36 | -------------------------------------------------------------------------------- /tb/stimuli/test: -------------------------------------------------------------------------------- 1 | hello 2 | world 3 | stimuli 4 | output 5 | now -------------------------------------------------------------------------------- /tb/trace_debugger_if.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Interface of the trace debugger module 13 | 14 | `timescale 1ns/1ns 15 | 16 | interface trace_debugger_if ( 17 | input logic clk_i, 18 | input logic rst_ni, 19 | input logic test_mode_i 20 | ); 21 | import trdb_pkg::*; 22 | import trdb_tb_pkg::*; 23 | 24 | // inputs 25 | logic ivalid; 26 | logic iexception; 27 | logic interrupt; 28 | logic [CAUSELEN-1:0] cause; 29 | logic [XLEN-1:0] tval; 30 | logic [PRIVLEN-1:0] priv; 31 | logic [XLEN-1:0] iaddr; 32 | logic [ILEN-1:0] instr; 33 | logic compressed; 34 | 35 | logic grant; 36 | 37 | // outputs 38 | logic [XLEN-1:0] packet_word; 39 | logic packet_word_valid; 40 | 41 | APB_BUS #(.APB_ADDR_WIDTH(32)) apb_bus(); 42 | 43 | clocking cb @(posedge clk_i); 44 | default input #(CLK_PERIOD - RESP_ACQUISITION_DEL) output #STIM_APPLICATION_DEL; 45 | 46 | // trace debugger 47 | output ivalid; 48 | output iexception; 49 | output interrupt; 50 | output cause; 51 | output tval; 52 | output priv; 53 | output iaddr; 54 | output instr; 55 | output compressed; 56 | inout grant; 57 | 58 | input packet_word; 59 | input packet_word_valid; 60 | 61 | // apb 62 | output paddr = apb_bus.paddr; 63 | output pwdata = apb_bus.pwdata; 64 | output pwrite = apb_bus.pwrite; 65 | output psel = apb_bus.psel; 66 | output penable = apb_bus.penable; 67 | input prdata = apb_bus.prdata; 68 | input pready = apb_bus.pready; 69 | input pslverr = apb_bus.pslverr; 70 | 71 | endclocking 72 | 73 | endinterface 74 | -------------------------------------------------------------------------------- /tb/trace_debugger_wrapper.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Connect interface to DUV 13 | 14 | module trace_debugger_wrapper 15 | (trace_debugger_if duv_if); 16 | 17 | trace_debugger i_trace_debugger 18 | (.clk_i(duv_if.clk_i), 19 | .rst_ni(duv_if.rst_ni), 20 | .test_mode_i(duv_if.test_mode_i), 21 | .ivalid_i(duv_if.ivalid), 22 | .iexception_i(duv_if.iexception), 23 | .interrupt_i(duv_if.interrupt), 24 | .cause_i(duv_if.cause), 25 | .tval_i(duv_if.tval), 26 | .priv_i(duv_if.priv), 27 | .iaddr_i(duv_if.iaddr), 28 | .instr_i(duv_if.instr), 29 | .compressed_i(duv_if.compressed), 30 | .apb_slave(duv_if.apb_bus), 31 | .packet_word_o(duv_if.packet_word), 32 | .packet_word_valid_o(duv_if.packet_word_valid), 33 | .grant_i(duv_if.grant)); 34 | 35 | endmodule // trace_debugger_wrapper 36 | -------------------------------------------------------------------------------- /tb/trdb_tb.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Testbench 13 | 14 | import trdb_tb_pkg::*; 15 | 16 | module trdb_tb 17 | (trace_debugger_if tb_if); 18 | 19 | // run test like instantiate a module 20 | tb_run i_tb_run(); 21 | 22 | program automatic tb_run; 23 | Driver driver; 24 | Reader reader; 25 | Scoreboard scoreboard; 26 | 27 | event tb_eos; 28 | 29 | mailbox #(Stimuli) stimuli; 30 | mailbox #(Response) gm_scoreboard; 31 | mailbox #(Response) duv_scoreboard; 32 | 33 | initial begin 34 | stimuli = new(); 35 | gm_scoreboard = new(); 36 | duv_scoreboard = new(); 37 | 38 | driver = new(tb_if, stimuli, tb_eos); 39 | reader = new(tb_if, duv_scoreboard); 40 | scoreboard = new(stimuli, duv_scoreboard, tb_eos); 41 | 42 | fork 43 | driver.run(); 44 | reader.run(); 45 | scoreboard.run(); 46 | join_any 47 | 48 | wait (tb_eos.triggered) begin 49 | $display("[TB] @%t: Signaled end of stimulation.", $time); 50 | scoreboard.print_stats(); 51 | end 52 | end 53 | 54 | endprogram 55 | 56 | endmodule // trdb_tb 57 | -------------------------------------------------------------------------------- /tb/trdb_tb_top.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Robert Balas 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the "License"); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | // 11 | // Author: Robert Balas (balasr@student.ethz.ch) 12 | // Description: Top level testbench 13 | 14 | // TODO: inspect this value 15 | `timescale 1ns/1ns 16 | 17 | module trdb_tb_top #( 18 | parameter NumRegs = 3 19 | ); 20 | 21 | import trdb_tb_pkg::*; 22 | 23 | // testbench signals to dut 24 | logic clk = 'b1; 25 | logic rst_n = 'b0; 26 | logic eos_s = 'b0; //end of simulation 27 | logic test_mode; 28 | 29 | 30 | assign test_mode = '0; 31 | 32 | trace_debugger_if duv_if(clk, rst_n, test_mode); 33 | 34 | //instantiate duv 35 | trace_debugger_wrapper i_trace_debugger_wrapper(.duv_if(duv_if)); 36 | 37 | // randomized handshake 38 | always_ff @(duv_if.cb) begin 39 | //duv_if.grant = repeat (NumRegs) @(posedge clk) duv_if.packet_word_valid; 40 | duv_if.cb.grant <= $urandom_range(0, 1); 41 | end 42 | 43 | //instantiate testbench 44 | trdb_tb i_trdb_tb(.tb_if(duv_if)); 45 | 46 | // clock generation 47 | initial begin: clock_gen 48 | while (!eos_s) begin 49 | #CLK_PHASE_HI clk = 1'b0; 50 | #CLK_PHASE_LO clk = 1'b1; 51 | end 52 | end: clock_gen 53 | 54 | // reset generation 55 | initial begin: reset_gen 56 | rst_n = 1'b0; 57 | // wait a few cycles 58 | repeat (RESET_WAIT_CYCLES) begin 59 | @(posedge clk); //TODO: was posedge, see below 60 | end 61 | //TODO: think about when the reset sould happen 62 | #RESET_DEL rst_n = 1'b1; 63 | if($test$plusargs("debug")) 64 | $display("[RESET] @%t: Reset deasserted.", $time); 65 | 66 | end: reset_gen 67 | 68 | // set timing format 69 | initial begin: timing_format 70 | $timeformat(-9, 0, "ns", 9); 71 | end: timing_format 72 | 73 | 74 | endmodule // trdb_tb 75 | -------------------------------------------------------------------------------- /test-64/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/trace_debugger/0df525be5a3856a8af2b99a4396aece3bfd141a9/test-64/.gitkeep -------------------------------------------------------------------------------- /test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulp-platform/trace_debugger/0df525be5a3856a8af2b99a4396aece3bfd141a9/test/.gitkeep -------------------------------------------------------------------------------- /waves/trace_debugger.tcl: -------------------------------------------------------------------------------- 1 | set tracer_if [find instances -recursive -bydu tracer_if -nodu] 2 | set trace_debugger [find instances -recursive -bydu trace_debugger -nodu] 3 | set trdb_all [find instances -recursive -bydu trdb_* -nodu] 4 | 5 | if {$tracer_if ne ""} { 6 | add wave -group "tracer_if" $tracer_if/* 7 | } 8 | 9 | if {$trace_debugger ne ""} { 10 | add wave -group [file tail $trace_debugger] $trace_debugger/* 11 | } 12 | 13 | catch { 14 | if {$trdb_all ne ""} { 15 | foreach inst $trdb_all { 16 | add wave -group [file tail $inst] $inst/* 17 | } 18 | } 19 | } err 20 | 21 | if {$err ne ""} { 22 | puts "\[TCL\]: Suppressed error: $err" 23 | } 24 | 25 | configure wave -namecolwidth 250 26 | configure wave -valuecolwidth 100 27 | configure wave -justifyvalue left 28 | configure wave -signalnamewidth 1 29 | configure wave -timelineunits ns 30 | --------------------------------------------------------------------------------