From 15942a4d627c9baa360ef1bf5ded9fd6390341f7 Mon Sep 17 00:00:00 2001 From: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Date: Mon, 28 Dec 2020 21:34:50 -0600 Subject: [PATCH 1/3] Add pulp_riscv_dbg module source code Import a copy of ./hw/vendor/pulp_riscv_dbg from opentitan project, and place it in ./vendor/. --- vendor/pulp_riscv_dbg/.travis.yml | 85 + vendor/pulp_riscv_dbg/Bender.yml | 16 + vendor/pulp_riscv_dbg/CHANGELOG.md | 67 + vendor/pulp_riscv_dbg/LICENSE | 176 ++ vendor/pulp_riscv_dbg/LICENSE.SiFive | 202 +++ vendor/pulp_riscv_dbg/README.md | 39 + vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh | 12 + vendor/pulp_riscv_dbg/ci/get-openocd.sh | 40 + vendor/pulp_riscv_dbg/ci/install-verilator.sh | 28 + vendor/pulp_riscv_dbg/ci/make-tmp.sh | 5 + vendor/pulp_riscv_dbg/ci/openocd-to-junit.py | 62 + .../ci/run-openocd-compliance.sh | 47 + .../ci/veri-run-openocd-compliance.sh | 33 + vendor/pulp_riscv_dbg/debug_rom/.gitignore | 3 + vendor/pulp_riscv_dbg/debug_rom/Makefile | 28 + vendor/pulp_riscv_dbg/debug_rom/debug_rom.S | 121 ++ vendor/pulp_riscv_dbg/debug_rom/debug_rom.h | 44 + vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv | 65 + .../debug_rom/debug_rom_one_scratch.h | 32 + .../debug_rom/debug_rom_one_scratch.sv | 59 + vendor/pulp_riscv_dbg/debug_rom/encoding.h | 1475 +++++++++++++++++ vendor/pulp_riscv_dbg/debug_rom/gen_rom.py | 134 ++ vendor/pulp_riscv_dbg/debug_rom/link.ld | 16 + vendor/pulp_riscv_dbg/doc/debug-system.md | 453 +++++ .../pulp_riscv_dbg/doc/debugsys_schematic.svg | 679 ++++++++ vendor/pulp_riscv_dbg/doc/dmi_protocol.json | 13 + vendor/pulp_riscv_dbg/doc/dmi_protocol.svg | 4 + vendor/pulp_riscv_dbg/src/dm_csrs.sv | 642 +++++++ vendor/pulp_riscv_dbg/src/dm_mem.sv | 523 ++++++ vendor/pulp_riscv_dbg/src/dm_obi_top.sv | 187 +++ vendor/pulp_riscv_dbg/src/dm_pkg.sv | 414 +++++ vendor/pulp_riscv_dbg/src/dm_sba.sv | 172 ++ vendor/pulp_riscv_dbg/src/dmi_cdc.sv | 85 + vendor/pulp_riscv_dbg/src/dmi_jtag.sv | 264 +++ vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv | 345 ++++ vendor/pulp_riscv_dbg/tb/.gitignore | 26 + vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley | 24 + vendor/pulp_riscv_dbg/tb/LICENSE.SiFive | 202 +++ vendor/pulp_riscv_dbg/tb/Makefile | 323 ++++ vendor/pulp_riscv_dbg/tb/README.md | 51 + vendor/pulp_riscv_dbg/tb/SimJTAG.sv | 85 + vendor/pulp_riscv_dbg/tb/boot_rom.sv | 39 + .../pulp_riscv_dbg/tb/dm_compliance_test.cfg | 31 + vendor/pulp_riscv_dbg/tb/dm_debug.cfg | 32 + vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv | 58 + vendor/pulp_riscv_dbg/tb/dp_ram.sv | 84 + vendor/pulp_riscv_dbg/tb/mm_ram.sv | 571 +++++++ vendor/pulp_riscv_dbg/tb/prog/crt0.S | 66 + vendor/pulp_riscv_dbg/tb/prog/link.ld | 385 +++++ vendor/pulp_riscv_dbg/tb/prog/syscalls.c | 270 +++ vendor/pulp_riscv_dbg/tb/prog/test.c | 6 + vendor/pulp_riscv_dbg/tb/prog/vectors.S | 152 ++ .../tb/remote_bitbang/.gitignore | 3 + .../pulp_riscv_dbg/tb/remote_bitbang/Makefile | 124 ++ .../tb/remote_bitbang/rbs_test.c | 34 + .../tb/remote_bitbang/remote_bitbang.c | 275 +++ .../tb/remote_bitbang/remote_bitbang.h | 52 + .../tb/remote_bitbang/sim_jtag.c | 29 + vendor/pulp_riscv_dbg/tb/tb_test_env.sv | 338 ++++ vendor/pulp_riscv_dbg/tb/tb_top.sv | 138 ++ vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp | 105 ++ vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv | 330 ++++ vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv | 81 + vendor/pulp_riscv_dbg/tb/vsim_batch.tcl | 15 + vendor/pulp_riscv_dbg/tb/vsim_gui.tcl | 16 + vendor/pulp_riscv_dbg/tb/waves.tcl | 117 ++ 66 files changed, 10632 insertions(+) create mode 100644 vendor/pulp_riscv_dbg/.travis.yml create mode 100644 vendor/pulp_riscv_dbg/Bender.yml create mode 100644 vendor/pulp_riscv_dbg/CHANGELOG.md create mode 100644 vendor/pulp_riscv_dbg/LICENSE create mode 100644 vendor/pulp_riscv_dbg/LICENSE.SiFive create mode 100644 vendor/pulp_riscv_dbg/README.md create mode 100755 vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh create mode 100755 vendor/pulp_riscv_dbg/ci/get-openocd.sh create mode 100755 vendor/pulp_riscv_dbg/ci/install-verilator.sh create mode 100755 vendor/pulp_riscv_dbg/ci/make-tmp.sh create mode 100755 vendor/pulp_riscv_dbg/ci/openocd-to-junit.py create mode 100755 vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh create mode 100755 vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh create mode 100644 vendor/pulp_riscv_dbg/debug_rom/.gitignore create mode 100644 vendor/pulp_riscv_dbg/debug_rom/Makefile create mode 100644 vendor/pulp_riscv_dbg/debug_rom/debug_rom.S create mode 100644 vendor/pulp_riscv_dbg/debug_rom/debug_rom.h create mode 100644 vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv create mode 100644 vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h create mode 100644 vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv create mode 100644 vendor/pulp_riscv_dbg/debug_rom/encoding.h create mode 100755 vendor/pulp_riscv_dbg/debug_rom/gen_rom.py create mode 100644 vendor/pulp_riscv_dbg/debug_rom/link.ld create mode 100644 vendor/pulp_riscv_dbg/doc/debug-system.md create mode 100644 vendor/pulp_riscv_dbg/doc/debugsys_schematic.svg create mode 100644 vendor/pulp_riscv_dbg/doc/dmi_protocol.json create mode 100644 vendor/pulp_riscv_dbg/doc/dmi_protocol.svg create mode 100644 vendor/pulp_riscv_dbg/src/dm_csrs.sv create mode 100755 vendor/pulp_riscv_dbg/src/dm_mem.sv create mode 100644 vendor/pulp_riscv_dbg/src/dm_obi_top.sv create mode 100644 vendor/pulp_riscv_dbg/src/dm_pkg.sv create mode 100644 vendor/pulp_riscv_dbg/src/dm_sba.sv create mode 100644 vendor/pulp_riscv_dbg/src/dmi_cdc.sv create mode 100644 vendor/pulp_riscv_dbg/src/dmi_jtag.sv create mode 100644 vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv create mode 100644 vendor/pulp_riscv_dbg/tb/.gitignore create mode 100644 vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley create mode 100644 vendor/pulp_riscv_dbg/tb/LICENSE.SiFive create mode 100644 vendor/pulp_riscv_dbg/tb/Makefile create mode 100644 vendor/pulp_riscv_dbg/tb/README.md create mode 100644 vendor/pulp_riscv_dbg/tb/SimJTAG.sv create mode 100644 vendor/pulp_riscv_dbg/tb/boot_rom.sv create mode 100644 vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg create mode 100644 vendor/pulp_riscv_dbg/tb/dm_debug.cfg create mode 100644 vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv create mode 100644 vendor/pulp_riscv_dbg/tb/dp_ram.sv create mode 100644 vendor/pulp_riscv_dbg/tb/mm_ram.sv create mode 100644 vendor/pulp_riscv_dbg/tb/prog/crt0.S create mode 100644 vendor/pulp_riscv_dbg/tb/prog/link.ld create mode 100644 vendor/pulp_riscv_dbg/tb/prog/syscalls.c create mode 100644 vendor/pulp_riscv_dbg/tb/prog/test.c create mode 100644 vendor/pulp_riscv_dbg/tb/prog/vectors.S create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h create mode 100644 vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c create mode 100644 vendor/pulp_riscv_dbg/tb/tb_test_env.sv create mode 100644 vendor/pulp_riscv_dbg/tb/tb_top.sv create mode 100644 vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp create mode 100644 vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv create mode 100644 vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv create mode 100644 vendor/pulp_riscv_dbg/tb/vsim_batch.tcl create mode 100644 vendor/pulp_riscv_dbg/tb/vsim_gui.tcl create mode 100644 vendor/pulp_riscv_dbg/tb/waves.tcl diff --git a/vendor/pulp_riscv_dbg/.travis.yml b/vendor/pulp_riscv_dbg/.travis.yml new file mode 100644 index 0000000000..7d8bce5917 --- /dev/null +++ b/vendor/pulp_riscv_dbg/.travis.yml @@ -0,0 +1,85 @@ +language: cpp +# run on new infrastructure +dist: xenial +sudo: false +cache: + apt: true + directories: + $RISCV + $VERILATOR_ROOT + timeout: 1000 + +# required packages to install +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-7 + - g++-7 + - gperf + - autoconf + - automake + - autotools-dev + - libmpc-dev + - libmpfr-dev + - libgmp-dev + - gawk + - build-essential + - bison + - flex + - texinfo + - python-pexpect + - libusb-1.0-0-dev + - default-jdk + - zlib1g-dev + - valgrind +env: + global: + - RISCV="/home/travis/riscv_install" + - VERILATOR_ROOT="/home/travis/verilator-4.018" + + +before_install: + - export CXX=g++-7 CC=gcc-7 + # setup dependent paths + - export PATH=$RISCV/bin:$VERILATOR_ROOT/bin:$PATH + - export LIBRARY_PATH=$RISCV/lib + - export LD_LIBRARY_PATH=$RISCV/lib + - export C_INCLUDE_PATH=$RISCV/include:$VERILATOR_ROOT/share/verilator/include + - export CPLUS_INCLUDE_PATH=$RISCV/include:$VERILATOR_ROOT/share/verilator/include + - export PKG_CONFIG_PATH=$VERILATOR_ROOT/share/pkgconfig + # number of parallel jobs to use for make commands and simulation + - export NUM_JOBS=4 + - ci/make-tmp.sh + - git submodule update --init --recursive + +stages: + - download + - compile1 + - compile2 + - test + +jobs: + include: + - stage: download + name: download pulp gcc + script: + - ci/download-pulp-gcc.sh + + - stage: compile2 + name: build verilator + script: + - ci/install-verilator.sh + - stage: compile2 + name: build openocd + script: + - ci/get-openocd.sh + + - stage: test + name: run openocd debug module tests + script: + - ci/veri-run-openocd-compliance.sh + +# extra time during long builds +install: travis_wait diff --git a/vendor/pulp_riscv_dbg/Bender.yml b/vendor/pulp_riscv_dbg/Bender.yml new file mode 100644 index 0000000000..150a79dba8 --- /dev/null +++ b/vendor/pulp_riscv_dbg/Bender.yml @@ -0,0 +1,16 @@ +package: + name: riscv-dbg + +sources: + files: + - src/dm_pkg.sv + - debug_rom/debug_rom.sv + - debug_rom/debug_rom_snd_scratch.sv + - src/dm_csrs.sv + - src/dm_mem.sv + - src/dm_top.sv + - src/dm_obi_top.sv + - src/dmi_cdc.sv + - src/dmi_jtag.sv + - src/dmi_jtag_tap.sv + - src/dm_sba.sv diff --git a/vendor/pulp_riscv_dbg/CHANGELOG.md b/vendor/pulp_riscv_dbg/CHANGELOG.md new file mode 100644 index 0000000000..f95fde842b --- /dev/null +++ b/vendor/pulp_riscv_dbg/CHANGELOG.md @@ -0,0 +1,67 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- Optional wrapper `dm_obi_top.sv` that wraps `dm_top` providing an OBI compliant interface +- `tb` that runs dm in conjunction with ri5cy and OpenOCD +- `.travis-ci.yml` running `tb` with verilator + +### Changed +- Made second scratch register optional (default is two) from [@zarubaf](https://github.com/zarubaf + +### Fixed +- Off-by-one error in data and progbuf end address from [@pbing](https://github.com/pbing) +- Haltsum1-3 calculation + +## [0.3.0] - 2020-01-23 + +### Added +- Documentation in `doc/` from [@imphil](https://github.com/imphil) + +### Changed +- Various linting issues and cleanups from [@msfschaffner](https://github.com/msfschaffner) + +### Fixed +- Corruption on debug exception entry [@tomroberts-lowrisc](https://github.com/tomroberts-lowrisc) +- truncation of `selected_hart` + +## [0.2.0] - 2019-08-16 + +## Added +- Add Bender.yml + +### Fixed +- Fix haltsum1, haltsum2 and haltsum3 +- Fix minor linter issues + +## [0.1.0] - 2019-05-18 + +### Added +- Parametrize buswidth to support 32-bit and 64-bit cores +- Support arbitrary base addresses in debug ROM +- Add misc helper functions to facilitate code generation +- Add README +- Fork from Ariane + +### Changed +- Allow generic number of data registers +- Make JTAG IDCODE parametrizable + +### Removed +- Remove ariane specific packages + +### Fixed +- Fix resumeack and resumereq behaviour to be cleared and set according to debug + specification +- Add missing JTAG test logic reset handling +- Fix resume logic in multihart situations +- Fix missing else(s) in system bus access +- Fix bad transitions into program buffer +- Fix error handling when using unsupported abstract commands +- Prevent harts from being in multiple states +- Fix various style issues diff --git a/vendor/pulp_riscv_dbg/LICENSE b/vendor/pulp_riscv_dbg/LICENSE new file mode 100644 index 0000000000..5ca76ba6b9 --- /dev/null +++ b/vendor/pulp_riscv_dbg/LICENSE @@ -0,0 +1,176 @@ +SOLDERPAD HARDWARE LICENSE version 0.51 + +This license is based closely on the Apache License Version 2.0, but is not +approved or endorsed by the Apache Foundation. A copy of the non-modified +Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any +Work licensed under this License, at the option of the Licensee, to be treated +as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular +clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the Rights owner or entity authorized by the Rights owner +that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Rights” means copyright and any similar right including design right (whether +registered or unregistered), semiconductor topography (mask) rights and +database rights (but excluding Patents and Trademarks). + +“Source” form shall mean the preferred form for making modifications, including +but not limited to source code, net lists, board layouts, CAD files, +documentation source, and configuration files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, the instantiation of a hardware design and +conversions to other media types, including intermediate forms such as +bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask +works). + +“Work” shall mean the work of authorship, whether in Source form or other +Object form, made available under the License, as indicated by a Rights notice +that is included in or attached to the work (an example is provided in the +Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) or physically connect to or interoperate with the interfaces of, the Work +and Derivative Works thereof. + +“Contribution” shall mean any design or work of authorship, including the +original version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the Rights owner or by an individual or Legal Entity +authorized to submit on behalf of the Rights owner. For the purposes of this +definition, “submitted” means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not +limited to communication on electronic mailing lists, source code control +systems, and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated in writing +by the Rights owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable license under the Rights to reproduce, +prepare Derivative Works of, publicly display, publicly perform, sublicense, +and distribute the Work and such Derivative Works in Source or Object form and +do anything in relation to the Work as if the Rights did not exist. + +3. Grant of Patent License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this +section) patent license to make, have made, use, offer to sell, sell, import, +and otherwise transfer the Work, where such license applies only to those +patent claims licensable by such Contributor that are necessarily infringed by +their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent +litigation against any entity (including a cross-claim or counterclaim in a +lawsuit) alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent +licenses granted to You under this License for that Work shall terminate as of +the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and in +Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy + of this License; and + + You must cause any modified files to carry prominent notices stating that + You changed the files; and + + You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from + the Source form of the Work, excluding those notices that do not pertain to + any part of the Derivative Works; and + + If the Work includes a “NOTICE” text file as part of its distribution, then + any Derivative Works that You distribute must include a readable copy of + the attribution notices contained within such NOTICE file, excluding those + notices that do not pertain to any part of the Derivative Works, in at + least one of the following places: within a NOTICE text file distributed as + part of the Derivative Works; within the Source form or documentation, if + provided along with the Derivative Works; or, within a display generated by + the Derivative Works, if and wherever such third-party notices normally + appear. The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum to + the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works as a + whole, provided Your use, reproduction, and distribution of the Work + otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any +additional terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may have +executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in +writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in +tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to in +writing, shall any Contributor be liable to You for damages, including any +direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability to +use the Work (including but not limited to damages for loss of goodwill, work +stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the +possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such +obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree +to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/vendor/pulp_riscv_dbg/LICENSE.SiFive b/vendor/pulp_riscv_dbg/LICENSE.SiFive new file mode 100644 index 0000000000..7e70933754 --- /dev/null +++ b/vendor/pulp_riscv_dbg/LICENSE.SiFive @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2017 SiFive, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/pulp_riscv_dbg/README.md b/vendor/pulp_riscv_dbg/README.md new file mode 100644 index 0000000000..fe28e6d8de --- /dev/null +++ b/vendor/pulp_riscv_dbg/README.md @@ -0,0 +1,39 @@ +[![Build Status](https://travis-ci.com/pulp-platform/riscv-dbg.svg?branch=master)](https://travis-ci.com/pulp-platform/riscv-dbg) + +# RISC-V Debug Support for PULP Cores + +This module is an implementation of a debug unit compliant with the [RISC-V +debug specification](https://github.com/riscv/riscv-debug-spec) v0.13.1. It is +used in the [Ariane](https://github.com/pulp-platform/ariane) and +[RI5CY](https://github.com/pulp-platform/riscv) cores. + +## Implementation +We use an execution-based technique, also described in the specification, where +the core is running in a "park loop". Depending on the request made to the debug +unit via JTAG over the Debug Transport Module (DTM), the code that is being +executed is changed dynamically. This approach simplifies the implementation +side of the core, but means that the core is in fact always busy looping while +debugging. + +## Features +The following features are currently supported + +* Parametrizable buswidth for `XLEN=32` `XLEN=64` cores +* Accessing registers over abstract command +* Program buffer +* System bus access (only `XLEN`) +* DTM with JTAG interface + +These are not implemented (yet) + +* Trigger module +* Quick access using abstract commands +* Accessing memory using abstract commands +* Authentication + +## Tests + +We use OpenOCD's [RISC-V compliance +tests](https://github.com/riscv/riscv-openocd/blob/riscv/src/target/riscv/riscv-013.c), +our custom testbench in `tb/` and +[riscv-tests/debug](https://github.com/riscv/riscv-tests/tree/master/debug). diff --git a/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh b/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh new file mode 100755 index 0000000000..eaab8ada43 --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -o pipefail +set -e + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +VERSION="v1.0.16" + +# mkdir -p $RISCV + +wget https://github.com/pulp-platform/pulp-riscv-gnu-toolchain/releases/download/$VERSION/$VERSION-pulp-riscv-gcc-ubuntu-16.tar.bz2 +echo "unpacking pulp gcc and installing to $RISCV" +tar -xvf $VERSION-pulp-riscv-gcc-ubuntu-16.tar.bz2 -C "$RISCV" --strip 1 diff --git a/vendor/pulp_riscv_dbg/ci/get-openocd.sh b/vendor/pulp_riscv_dbg/ci/get-openocd.sh new file mode 100755 index 0000000000..5d379367af --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/get-openocd.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -e + +VERSION="af3a034b57279d2a400d87e7508c9a92254ec165" + +mkdir -p $RISCV/ +cd $RISCV + +check_version() { + $1 --version | awk "NR==1 {if (\$NF>$2) {exit 0} exit 1}" || ( + echo $3 requires at least version $2 of $1. Aborting. + exit 1 + ) +} + + +if [ -z ${NUM_JOBS} ]; then + NUM_JOBS=1 +fi + +if ! [ -e $RISCV/bin/openocd ]; then + if ! [ -e $RISCV/riscv-openocd ]; then + git clone https://github.com/riscv/riscv-openocd.git + fi + check_version automake 1.14 "OpenOCD build" + check_version autoconf 2.64 "OpenOCD build" + + cd riscv-openocd + git checkout $VERSION + git submodule update --init --recursive + + echo "Compiling OpenOCD" + ./bootstrap + ./configure --prefix=$RISCV --disable-werror --disable-wextra --enable-remote-bitbang + make -j${NUM_JOBS} + make install + echo "Compilation Finished" +fi + diff --git a/vendor/pulp_riscv_dbg/ci/install-verilator.sh b/vendor/pulp_riscv_dbg/ci/install-verilator.sh new file mode 100755 index 0000000000..2dae38513e --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/install-verilator.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +cd $ROOT/tmp + +if [ -z ${NUM_JOBS} ]; then + NUM_JOBS=1 +fi + +if [ ! -e "$VERILATOR_ROOT/bin/verilator" ]; then + echo "Installing Verilator" + rm -f verilator*.tgz + wget https://www.veripool.org/ftp/verilator-4.018.tgz + tar xzf verilator*.tgz + rm -f verilator*.tgz + cd verilator-4.018 + mkdir -p $VERILATOR_ROOT + # copy scripts + autoconf && ./configure --prefix="$VERILATOR_ROOT" && make -j${NUM_JOBS} + make install + # not obvious to me why these symlinks are missing + ln -s $VERILATOR_ROOT/share/verilator/include $VERILATOR_ROOT/include + ln -s $VERILATOR_ROOT/share/verilator/bin/verilator_includer \ + $VERILATOR_ROOT/bin/verilator_includer + make test +else + echo "Using Verilator from cached directory." +fi diff --git a/vendor/pulp_riscv_dbg/ci/make-tmp.sh b/vendor/pulp_riscv_dbg/ci/make-tmp.sh new file mode 100755 index 0000000000..a3c34c1e88 --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/make-tmp.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +cd "$(dirname "${BASH_SOURCE[0]}")/.." +[ -d tmp ] || rm -rf tmp +mkdir -p tmp diff --git a/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py b/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py new file mode 100755 index 0000000000..392fb74c48 --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +import sys, getopt +from junit_xml import * + + +def main(argv): + inputfile = '' + outputfile = '' + + try: + opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="]) + except getopt.GetoptError: + print ('openocd-to-junit.py -i -o ') + sys.exit(2) + for opt, arg in opts: + if opt == '-h': + print ('openocd-to-junit.py -i -o ') + sys.exit() + elif opt in ("-i", "--ifile"): + inputfile = arg + elif opt in ("-o", "--ofile"): + outputfile = arg + + test_strings = defaultdict(list) + test_timestamps = {} + current_testname = '' + + test_cases = [] + current_test_case = None + + ocd_stdout = '' + + with open(inputfile, 'r') as infile: + for line in infile: + if 'Info' in line and 'riscv013_test_compliance()' in line: + print(line.split(' ')) + current_testname = ' '.join(line.split(' ')[7:]) + test_strings[current_testname].append(line) + test_timestamps[current_testname] = line.split(' ')[3] + + ocd_stdout += line + + for k,v in test_strings.items(): + current_test_case = TestCase(k, stdout=''.join(v), + timestamp=test_timestamps[k]) + error_msg = "" + for line in v: + if 'FAILED' in line: + error_msg += line; + + if error_msg: + current_test_case.add_error_info(error_msg) + + test_cases.append(current_test_case) + + ts = TestSuite("openocd-compliance", test_cases, stdout=ocd_stdout) + # pretty printing is on by default but can be disabled using prettyprint=False + with open(outputfile, 'w') as outfile: + TestSuite.to_file(outfile, [ts]) + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh b/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh new file mode 100755 index 0000000000..ad37aaab8d --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -e + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) + +if [ -z "${RISCV}" ] +then + echo "RISCV is empty" + exit 1 +fi + +function cleanup { + echo "cleaning up processes and tmp files" + sleep 2 + echo "vsim pid is:${vsim_pid} pgid:${vsim_pgid}" + if ps -p "${vsim_pid}" > /dev/null + then + echo "vsim pid exists, killing it" + kill -- -"${vsim_pgid}" + fi + rm "${vsim_out}" +} + +trap cleanup EXIT + +vsim_out=$(mktemp) +openocd_out=openocd.log + +make -C "${ROOT}"/tb/dm vsim-run &> "${vsim_out}"& +# record vsim pid/pgid to kill it if it survives this script +vsim_pid=$! +vsim_pgid=$(ps -o pgid= ${vsim_pid} | grep -o [0-9]*) + +# block until we get "Listening on port" so that we are safe to connect openocd +coproc grep -m 1 "Listening on port" +tail -f -n0 "${vsim_out}" --pid "$COPROC_PID" >&"${COPROC[1]}" + +echo "Starting openocd" +"${RISCV}"/bin/openocd -f "${ROOT}"/tb/dm/dm_compliance_test.cfg |& tee "${openocd_out}" + + +if grep -q "ALL TESTS PASSED" "${openocd_out}"; then + exit 0 +fi +exit 1 + diff --git a/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh b/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh new file mode 100755 index 0000000000..09b589259d --- /dev/null +++ b/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -e + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) + +if [ -z "${RISCV}" ] +then + echo "RISCV is empty" + exit 1 +fi + + +veri_out=$(mktemp) +openocd_out=openocd.log + +make -C "${ROOT}"/tb veri-run |& tee "${veri_out}"& +# record veri pid/pgid to kill it if it survives this script +veri_pid=$! +veri_pgid=$(ps -o pgid= ${veri_pid} | grep -o [0-9]*) + +# block until we get "Listening on port" so that we are safe to connect openocd +coproc grep -m 1 "Listening on port" +tail -f -n0 "${veri_out}" --pid "$COPROC_PID" >&"${COPROC[1]}" + +echo "Starting openocd" +"${RISCV}"/bin/openocd -f "${ROOT}"/tb/dm_compliance_test.cfg |& tee "${openocd_out}" + +if grep -q "ALL TESTS PASSED" "${openocd_out}"; then + exit 0 +fi +exit 1 + diff --git a/vendor/pulp_riscv_dbg/debug_rom/.gitignore b/vendor/pulp_riscv_dbg/debug_rom/.gitignore new file mode 100644 index 0000000000..e04ab73239 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/.gitignore @@ -0,0 +1,3 @@ +*.bin +*.elf +debug_rom.img diff --git a/vendor/pulp_riscv_dbg/debug_rom/Makefile b/vendor/pulp_riscv_dbg/debug_rom/Makefile new file mode 100644 index 0000000000..b23370aac0 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/Makefile @@ -0,0 +1,28 @@ +# See LICENSE.SiFive for license details + +debug_rom = debug_rom.sv debug_rom_one_scratch.sv + +GCC?=riscv64-unknown-elf-gcc +OBJCOPY?=riscv64-unknown-elf-objcopy +OBJDUMP?=riscv64-unknown-elf-objdump +PYTHON?=python + +all: $(debug_rom) + +%.sv: %.img + $(PYTHON) gen_rom.py $< + +%.img: %.bin + dd if=$< of=$@ bs=256 count=1 + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +%.elf: $(findstring debug_rom, $(debug_rom)).S link.ld + $(GCC) $(if $(findstring one_scratch,$@),,-DSND_SCRATCH=1) -I$(RISCV)/include -Tlink.ld $< -nostdlib -fPIC -static -Wl,--no-gc-sections -o $@ + +%.dump: %.elf + $(OBJDUMP) -d $< --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data > $@ + +clean: + rm -f *.img *.dump *.bin *.sv diff --git a/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S new file mode 100644 index 0000000000..2989c7e855 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S @@ -0,0 +1,121 @@ +// See LICENSE.SiFive for license details. + +#include "encoding.h" + +// The debugger can assume as second scratch register. +// # define SND_SCRATCH 1 +// These are implementation-specific addresses in the Debug Module +#define HALTED 0x100 +#define GOING 0x104 +#define RESUMING 0x108 +#define EXCEPTION 0x10C + +// Region of memory where each hart has 1 +// byte to read. +#define FLAGS 0x400 +#define FLAG_GO 0 +#define FLAG_RESUME 1 + + .option norvc + .global entry + .global exception + + // Entry location on ebreak, Halt, or Breakpoint + // It is the same for all harts. They branch when + // their GO or RESUME bit is set. + +entry: + jal zero, _entry +resume: + jal zero, _resume +exception: + jal zero, _exception + + + +_entry: + // This fence is required because the execution may have written something + // into the Abstract Data or Program Buffer registers. + fence + csrw CSR_DSCRATCH0, s0 // Save s0 to allow signaling MHARTID +#ifdef SND_SCRATCH + csrw CSR_DSCRATCH1, a0 // Save a0 to allow loading arbitrary DM base + auipc a0, 0 // Get PC + srli a0, a0, 12 // And throw away lower 12 bits to get the DM base + slli a0, a0, 12 +#endif + // We continue to let the hart know that we are halted in order that + // a DM which was reset is still made aware that a hart is halted. + // We keep checking both whether there is something the debugger wants + // us to do, or whether we should resume. +entry_loop: + csrr s0, CSR_MHARTID +#ifdef SND_SCRATCH + sw s0, HALTED(a0) + add s0, s0, a0 +#else + sw s0, HALTED(zero) +#endif + lbu s0, FLAGS(s0) // 1 byte flag per hart. Only one hart advances here. + andi s0, s0, (1 << FLAG_GO) + bnez s0, going + csrr s0, CSR_MHARTID +#ifdef SND_SCRATCH + add s0, s0, a0 +#endif + lbu s0, FLAGS(s0) // multiple harts can resume here + andi s0, s0, (1 << FLAG_RESUME) + bnez s0, resume + jal zero, entry_loop + +_exception: + // We can only get here due to an exception while in debug mode. Hence, + // we do not need to save a0 to a scratch register as it has already + // been saved on debug entry. +#ifdef SND_SCRATCH + auipc a0, 0 // Get POC + srli a0, a0, 12 // And throw away lower 12 bits to get the DM base + slli a0, a0, 12 + sw zero, EXCEPTION(a0) // Let debug module know you got an exception. + // It is safe to always restore the scratch registers here as they must + // have been saved on debug entry. Restoring them here avoids issues + // with registers being overwritten by exceptions occuring during + // program buffer execution. + csrr a0, CSR_DSCRATCH1 // Restore a0 here +#else + sw zero, EXCEPTION(zero) // Let debug module know you got an exception. +#endif + csrr s0, CSR_DSCRATCH0 // Restore s0 here + ebreak + +going: +#ifdef SND_SCRATCH + sw zero, GOING(a0) // When debug module sees this write, the GO flag is reset. + csrr a0, CSR_DSCRATCH1 // Restore a0 here +#else + sw zero, GOING(zero) // When debug module sees this write, the GO flag is reset. +#endif + csrr s0, CSR_DSCRATCH0 // Restore s0 here + jal zero, whereto +_resume: + csrr s0, CSR_MHARTID +#ifdef SND_SCRATCH + sw s0, RESUMING(a0) // When Debug Module sees this write, the RESUME flag is reset. + csrr a0, CSR_DSCRATCH1 // Restore a0 here +#else + sw s0, RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset. +#endif + csrr s0, CSR_DSCRATCH0 // Restore s0 here + dret + + // END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT. + +.section .whereto +whereto: + nop + // Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer, + // or jal x0 resume, as desired. + // Debug Module state machine tracks what is 'desired'. + // We don't need/want to use jalr here because all of the + // Variable ROM contents are set by + // Debug Module before setting the OK_GO byte. diff --git a/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h new file mode 100644 index 0000000000..b4f2d35a88 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h @@ -0,0 +1,44 @@ +// Auto-generated code + +const int reset_vec_size = 38; + +uint32_t reset_vec[reset_vec_size] = { + 0x00c0006f, + 0x07c0006f, + 0x04c0006f, + 0x0ff0000f, + 0x7b241073, + 0x7b351073, + 0x00000517, + 0x00c55513, + 0x00c51513, + 0xf1402473, + 0x10852023, + 0x00a40433, + 0x40044403, + 0x00147413, + 0x02041c63, + 0xf1402473, + 0x00a40433, + 0x40044403, + 0x00247413, + 0xfa041ce3, + 0xfd5ff06f, + 0x00000517, + 0x00c55513, + 0x00c51513, + 0x10052623, + 0x7b302573, + 0x7b202473, + 0x00100073, + 0x10052223, + 0x7b302573, + 0x7b202473, + 0xa85ff06f, + 0xf1402473, + 0x10852423, + 0x7b302573, + 0x7b202473, + 0x7b200073, + 0x00000000 +}; diff --git a/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv new file mode 100644 index 0000000000..a0e02084bb --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv @@ -0,0 +1,65 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: $filename.v + * + * Description: Auto-generated bootrom + */ + +// Auto-generated code +module debug_rom ( + input logic clk_i, + input logic req_i, + input logic [63:0] addr_i, + output logic [63:0] rdata_o +); + + localparam int unsigned RomSize = 19; + + const logic [RomSize-1:0][63:0] mem = { + 64'h00000000_7b200073, + 64'h7b202473_7b302573, + 64'h10852423_f1402473, + 64'ha85ff06f_7b202473, + 64'h7b302573_10052223, + 64'h00100073_7b202473, + 64'h7b302573_10052623, + 64'h00c51513_00c55513, + 64'h00000517_fd5ff06f, + 64'hfa041ce3_00247413, + 64'h40044403_00a40433, + 64'hf1402473_02041c63, + 64'h00147413_40044403, + 64'h00a40433_10852023, + 64'hf1402473_00c51513, + 64'h00c55513_00000517, + 64'h7b351073_7b241073, + 64'h0ff0000f_04c0006f, + 64'h07c0006f_00c0006f + }; + + logic [$clog2(RomSize)-1:0] addr_q; + + always_ff @(posedge clk_i) begin + if (req_i) begin + addr_q <= addr_i[$clog2(RomSize)-1+3:3]; + end + end + + // this prevents spurious Xes from propagating into + // the speculative fetch stage of the core + always_comb begin : p_outmux + rdata_o = '0; + if (addr_q < $clog2(RomSize)'(RomSize)) begin + rdata_o = mem[addr_q]; + end + end + +endmodule diff --git a/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h b/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h new file mode 100644 index 0000000000..625d66a057 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h @@ -0,0 +1,32 @@ +// Auto-generated code + +const int reset_vec_size = 26; + +uint32_t reset_vec[reset_vec_size] = { + 0x00c0006f, + 0x0500006f, + 0x0340006f, + 0x0ff0000f, + 0x7b241073, + 0xf1402473, + 0x10802023, + 0x40044403, + 0x00147413, + 0x02041263, + 0xf1402473, + 0x40044403, + 0x00247413, + 0xfc0418e3, + 0xfddff06f, + 0x10002623, + 0x7b202473, + 0x00100073, + 0x10002223, + 0x7b202473, + 0xab1ff06f, + 0xf1402473, + 0x10802423, + 0x7b202473, + 0x7b200073, + 0x00000000 +}; diff --git a/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv b/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv new file mode 100644 index 0000000000..78d47be604 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv @@ -0,0 +1,59 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: $filename.v + * + * Description: Auto-generated bootrom + */ + +// Auto-generated code +module debug_rom_one_scratch ( + input logic clk_i, + input logic req_i, + input logic [63:0] addr_i, + output logic [63:0] rdata_o +); + + localparam int unsigned RomSize = 13; + + const logic [RomSize-1:0][63:0] mem = { + 64'h00000000_7b200073, + 64'h7b202473_10802423, + 64'hf1402473_ab1ff06f, + 64'h7b202473_10002223, + 64'h00100073_7b202473, + 64'h10002623_fddff06f, + 64'hfc0418e3_00247413, + 64'h40044403_f1402473, + 64'h02041263_00147413, + 64'h40044403_10802023, + 64'hf1402473_7b241073, + 64'h0ff0000f_0340006f, + 64'h0500006f_00c0006f + }; + + logic [$clog2(RomSize)-1:0] addr_q; + + always_ff @(posedge clk_i) begin + if (req_i) begin + addr_q <= addr_i[$clog2(RomSize)-1+3:3]; + end + end + + // this prevents spurious Xes from propagating into + // the speculative fetch stage of the core + always_comb begin : p_outmux + rdata_o = '0; + if (addr_q < $clog2(RomSize)'(RomSize)) begin + rdata_o = mem[addr_q]; + end + end + +endmodule diff --git a/vendor/pulp_riscv_dbg/debug_rom/encoding.h b/vendor/pulp_riscv_dbg/debug_rom/encoding.h new file mode 100644 index 0000000000..f5a40afdad --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/encoding.h @@ -0,0 +1,1475 @@ +// See LICENSE for license details. + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define SATP32_MODE 0x80000000 +#define SATP32_ASID 0x7FC00000 +#define SATP32_PPN 0x003FFFFF +#define SATP64_MODE 0xF000000000000000 +#define SATP64_ASID 0x0FFFF00000000000 +#define SATP64_PPN 0x00000FFFFFFFFFFF + +#define SATP_MODE_OFF 0 +#define SATP_MODE_SV32 1 +#define SATP_MODE_SV39 8 +#define SATP_MODE_SV48 9 +#define SATP_MODE_SV57 10 +#define SATP_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +# define SATP_MODE SATP64_MODE +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define SATP_MODE SATP32_MODE +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif + +#endif + +#endif + +#endif +/* Automatically generated by parse-opcodes. */ +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_URET 0x200073 +#define MASK_URET 0xffffffff +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FMV_X_Q 0xe6000053 +#define MASK_FMV_X_Q 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FMV_Q_X 0xf6000053 +#define MASK_FMV_Q_X 0xfff0707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xffff +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_LI 0x4001 +#define MASK_C_LI 0xe003 +#define MATCH_C_LUI 0x6001 +#define MASK_C_LUI 0xe003 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_LWSP 0x4002 +#define MASK_C_LWSP 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_CUSTOM0 0xb +#define MASK_CUSTOM0 0x707f +#define MATCH_CUSTOM0_RS1 0x200b +#define MASK_CUSTOM0_RS1 0x707f +#define MATCH_CUSTOM0_RS1_RS2 0x300b +#define MASK_CUSTOM0_RS1_RS2 0x707f +#define MATCH_CUSTOM0_RD 0x400b +#define MASK_CUSTOM0_RD 0x707f +#define MATCH_CUSTOM0_RD_RS1 0x600b +#define MASK_CUSTOM0_RD_RS1 0x707f +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b +#define MASK_CUSTOM0_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM1 0x2b +#define MASK_CUSTOM1 0x707f +#define MATCH_CUSTOM1_RS1 0x202b +#define MASK_CUSTOM1_RS1 0x707f +#define MATCH_CUSTOM1_RS1_RS2 0x302b +#define MASK_CUSTOM1_RS1_RS2 0x707f +#define MATCH_CUSTOM1_RD 0x402b +#define MASK_CUSTOM1_RD 0x707f +#define MATCH_CUSTOM1_RD_RS1 0x602b +#define MASK_CUSTOM1_RD_RS1 0x707f +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b +#define MASK_CUSTOM1_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM2 0x5b +#define MASK_CUSTOM2 0x707f +#define MATCH_CUSTOM2_RS1 0x205b +#define MASK_CUSTOM2_RS1 0x707f +#define MATCH_CUSTOM2_RS1_RS2 0x305b +#define MASK_CUSTOM2_RS1_RS2 0x707f +#define MATCH_CUSTOM2_RD 0x405b +#define MASK_CUSTOM2_RD 0x707f +#define MATCH_CUSTOM2_RD_RS1 0x605b +#define MASK_CUSTOM2_RD_RS1 0x707f +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b +#define MASK_CUSTOM2_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM3 0x7b +#define MASK_CUSTOM3 0x707f +#define MATCH_CUSTOM3_RS1 0x207b +#define MASK_CUSTOM3_RS1 0x707f +#define MATCH_CUSTOM3_RS1_RS2 0x307b +#define MASK_CUSTOM3_RS1_RS2 0x707f +#define MATCH_CUSTOM3_RD 0x407b +#define MASK_CUSTOM3_RD 0x707f +#define MATCH_CUSTOM3_RD_RS1 0x607b +#define MASK_CUSTOM3_RD_RS1 0x707f +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b +#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_SATP 0x180 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 +#define CSR_DSCRATCH0 CSR_DSCRATCH +#define CSR_DSCRATCH1 0x7b3 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(stval, CSR_STVAL) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(satp, CSR_SATP) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mtval, CSR_MTVAL) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) +DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) +DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) +DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) +DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) +DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) +DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) +DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) +DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) +DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) +DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) +DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) +DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) +DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) +DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) +DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) +DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) +DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) +DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(dscratch0, CSR_DSCRATCH0) +DECLARE_CSR(dscratch1, CSR_DSCRATCH1) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) +DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) +DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +#endif diff --git a/vendor/pulp_riscv_dbg/debug_rom/gen_rom.py b/vendor/pulp_riscv_dbg/debug_rom/gen_rom.py new file mode 100755 index 0000000000..b3ce019436 --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/gen_rom.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +from string import Template +import argparse +import os.path +import sys +import binascii + + +parser = argparse.ArgumentParser(description='Convert binary file to verilog rom') +parser.add_argument('filename', metavar='filename', nargs=1, + help='filename of input binary') + +args = parser.parse_args() +file = args.filename[0]; + +# check that file exists +if not os.path.isfile(file): + print("File {} does not exist.".format(filename)) + sys.exit(1) + +filename = os.path.splitext(file)[0] + +license = """\ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: $filename.v + * + * Description: Auto-generated bootrom + */ + +// Auto-generated code +""" + +module = """\ +module $filename ( + input logic clk_i, + input logic req_i, + input logic [63:0] addr_i, + output logic [63:0] rdata_o +); + + localparam int unsigned RomSize = $size; + + const logic [RomSize-1:0][63:0] mem = { +$content + }; + + logic [$$clog2(RomSize)-1:0] addr_q; + + always_ff @(posedge clk_i) begin + if (req_i) begin + addr_q <= addr_i[$$clog2(RomSize)-1+3:3]; + end + end + + // this prevents spurious Xes from propagating into + // the speculative fetch stage of the core + always_comb begin : p_outmux + rdata_o = '0; + if (addr_q < $$clog2(RomSize)'(RomSize)) begin + rdata_o = mem[addr_q]; + end + end + +endmodule +""" + +c_var = """\ +// Auto-generated code + +const int reset_vec_size = $size; + +uint32_t reset_vec[reset_vec_size] = { +$content +}; +""" + +def read_bin(): + + with open(filename + ".img", 'rb') as f: + rom = binascii.hexlify(f.read()) + rom = map(''.join, zip(rom[::2], rom[1::2])) + + + # align to 64 bit + align = (int((len(rom) + 7) / 8 )) * 8; + + for i in range(len(rom), align): + rom.append("00") + + return rom + +rom = read_bin() + +""" Generate C header file for simulator +""" +with open(filename + ".h", "w") as f: + rom_str = "" + # process in junks of 32 bit (4 byte) + for i in range(0, int(len(rom)/4)): + rom_str += " 0x" + "".join(rom[i*4:i*4+4][::-1]) + ",\n" + + # remove the trailing comma + rom_str = rom_str[:-2] + + s = Template(c_var) + f.write(s.substitute(filename=filename, size=int(len(rom)/4), content=rom_str)) + + f.close() + +""" Generate SystemVerilog bootcode for FPGA and ASIC +""" +with open(filename + ".sv", "w") as f: + rom_str = "" + # process in junks of 64 bit (8 byte) + for i in reversed(range(int(len(rom)/8))): + rom_str += " 64'h" + "".join(rom[i*8+4:i*8+8][::-1]) + "_" + "".join(rom[i*8:i*8+4][::-1]) + ",\n" + + # remove the trailing comma + rom_str = rom_str[:-2] + + f.write(license) + s = Template(module) + f.write(s.substitute(filename=filename, size=int(len(rom)/8), content=rom_str)) + diff --git a/vendor/pulp_riscv_dbg/debug_rom/link.ld b/vendor/pulp_riscv_dbg/debug_rom/link.ld new file mode 100644 index 0000000000..053bb43c1f --- /dev/null +++ b/vendor/pulp_riscv_dbg/debug_rom/link.ld @@ -0,0 +1,16 @@ +/* See LICENSE.SiFive for license details. */ +OUTPUT_ARCH( "riscv" ) +ENTRY( entry ) +SECTIONS +{ + .whereto 0x300 : + { + *(.whereto) + } + . = 0x800; + .text : + { + *(.text) + } + _end = .; +} diff --git a/vendor/pulp_riscv_dbg/doc/debug-system.md b/vendor/pulp_riscv_dbg/doc/debug-system.md new file mode 100644 index 0000000000..708aa92b29 --- /dev/null +++ b/vendor/pulp_riscv_dbg/doc/debug-system.md @@ -0,0 +1,453 @@ +# Overview + +This document specifies the processor debug system. The debug system implements run-control debug and bus access functionality according to the [RISC-V Debug Specification 0.13.2](https://github.com/riscv/riscv-debug-spec/raw/4e0bb0fc2d843473db2356623792c6b7603b94d4/riscv-debug-release.pdf). It can be accessed over JTAG (IEEE Std 1149.1-2013). + +## Features + +- Run-control debug functionality according to the [RISC-V Debug Specification version 0.13.2](https://github.com/riscv/riscv-debug-spec/raw/4e0bb0fc2d843473db2356623792c6b7603b94d4/riscv-debug-release.pdf), which includes all standard debug features: breakpoints, stepping, access to the CPU's GPRs and arbitrary memory locations. +- Implementation following the Execution Based method as outlined in Section A.2 of the RISC-V Debug Specification. This allows the execution of arbitrary instructions on the core and requires minimal changes to the core. +- JTAG Debug Transport Module (DTM) according to the RISC-V Debug Specification. +- System Bus Access with generic 32 or 64 bit bus interface. +- Support for up to 2^20 harts through one Debug Module +- Support for arbitrary memory location of DM +- Support for one debug scratch register if the DM is located at the zero page. + +## Description + +The debug system described in this document consists of two modules, which are implemented according to the RISC-V Debug Specification: The Debug Module (DM) implemented with a Program Buffer, and a JTAG Debug Transport Module (DTM). + +## Compatibility + +The debug system is compatible with the RISC-V Debug Specification 0.13.2. +The specification marks some features as optional. +The status of these features is visible from the table below. + +**Feature** | **Support** +-------------------------------------- | -------------------------------------------------------------------------------------- +External triggers (Section 3.6) | Not supported at this time. +Halt groups (Section 3.6) | Not supported at this time. +Hardware triggers | Not supported at this time. Triggers read 0 according to the specification. +System Bus Access (SBA) (Section 3.10) | Supported with generic 32 or 64 bit wide interface. +Authentication | Not supported at this time. +Non-intrusive access to core registers | Not supported at this time. All registers must be accessed through the program buffer. + +# Theory of Operations + +The functionality of the debug system is implemented according to the RISC-V Debug Specification. +Refer to this document for more information. + +## Block Diagram + +![Block diagram of the debug system](debugsys_schematic.svg) + +## Debug Module Registers + +An external debugger performs all interaction with the Debug Module through a register interface, accessed over a dedicated bus, the Debug Module Interface (DMI). +The registers are called "Debug Module Registers" and defined in the RISC-V Debug Specification, Section 3.14. +Our implementation only provides a single Debug Module on the DMI bus mapped to base address 0, hence all addresses below can be considered absolute. + +**Address** | **Name** | **Implementation Notes** +----------- | -------------------------------------------- | ------------------------ +0x04 | Abstract Data 0 (data0) +0x0f | Abstract Data 11 (data11) +0x10 | Debug Module Control (dmcontrol) | see table below +0x11 | Debug Module Status (dmstatus) | see table below +0x12 | Hart Info (hartinfo) +0x13 | Halt Summary 1 (haltsum1) +0x14 | Hart Array Window Select (hawindowsel) +0x15 | Hart Array Window (hawindow) +0x16 | Abstract Control and Status (abstractcs) +0x17 | Abstract Command (command) +0x18 | Abstract Command Autoexec (abstractauto) +0x19 | Configuration String Pointer 0 (confstrptr0) +0x1a | Configuration String Pointer 1 (confstrptr1) +0x1b | Configuration String Pointer 2 (confstrptr2) +0x1c | Configuration String Pointer 3 (confstrptr3) +0x1d | Next Debug Module (nextdm) +0x1f | Custom Features (custom) +0x20 | Program Buffer 0 (progbuf0) +0x2f | Program Buffer 15 (progbuf15) +0x30 | Authentication Data (authdata) +0x32 | Debug Module Control and Status 2 (dmcs2) +0x34 | Halt Summary 2 (haltsum2) +0x35 | Halt Summary 3 (haltsum3) +0x37 | System Bus Address 127:96 (sbaddress3) +0x38 | System Bus Access Control and Status (sbcs) +0x39 | System Bus Address 31:0 (sbaddress0) +0x3a | System Bus Address 63:32 (sbaddress1) +0x3b | System Bus Address 95:64 (sbaddress2) +0x3c | System Bus Data 31:0 (sbdata0) +0x3d | System Bus Data 63:32 (sbdata1) +0x3e | System Bus Data 95:64 (sbdata2) +0x3f | System Bus Data 127:96 (sbdata3) +0x40 | Halt Summary 0 (haltsum0) + +### dmcontrol (0x10) + +**Field** | **Access** | **(Reset) Value** | **Comment** +--------------- | ---------- | ----------------- | ------------------------------------------------------------------------------------------------------------- +haltreq | WARZ +resumereq | W1 +hartreset | WARL | 0 | Not implemented, reads constant 0 +ackhavereset | W1 +hasel | WARL | 0 | Hart array masks are not supported +hartsello | R/W +hartselhi | R/W +setresethaltreq | W1 | - | Writing this register is a no-op. Halt-on-reset is not implemented, as indicated by dmstatus.hasresethaltreq. +clrresethaltreq | W1 | - | Writing this register is a no-op. Halt-on-reset is not implemented, as indicated by dmstatus.hasresethaltreq. +ndmreset | R/W +dmactive | R/W + +### dmstatus (0x11) + +**Field** | **Access** | **(Reset) Value** | **Comment** +--------------- | ---------- | ----------------- | --------------------------------------------------------------- +impebreak | R | 0 | No implicit ebreak is inserted after the Program Buffer. +allhavereset | R | | Hart array masks are not supported; identical to anyhavereset. +anyhavereset | R | | Hart array masks are not supported; identical to allhavereset. +allresumeack | R | | Hart array masks are not supported; identical to anyresumeack. +anyresumeack | R | | Hart array masks are not supported; identical to allresumeack. +allnonexistent | R | | Hart array masks are not supported; identical to anynonexistent +anynonexistent | R | | Hart array masks are not supported; identical to allnonexistent +allunavail | R | | Hart array masks are not supported; identical to anyunavail. +anyunavail | R | | Hart array masks are not supported; identical to allunavail. +allrunning | R | | Hart array masks are not supported; identical to anyrunning. +anyrunning | R | | Hart array masks are not supported; identical to allrunning. +allhalted | R | | Hart array masks are not supported; identical to anyhalted. +anyhalted | R | | Hart array masks are not supported; identical to allhalted. +authenticated | R | 1 | Authentication is not implemented, reads always 1. +authbusy | R | 0 | Authentication is not implemented, reads always 0. +hasresethaltreq | R | 0 | Halt-on-reset is not implemented, reads always 0. +confstrptrvalid | R | 0 | Configuration strings are not supported. +version | R | 2 | Specification version 0.13 + +## Customization + +The debug system can be configured at synthesis time through parameters. + +**Parameter Name** | **Valid values** | **Default** | **Description** +------------------ | ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------- +NrHarts | 1..2^20 | 1 | Number of connected harts +BusWidth | 32, 64 | 32 | Bus width (for debug memory and SBA busses) +SelectableHarts | | 1 | Bitmask to select physically available harts for systems that don't use hart numbers in a contiguous fashion. + +In addition to these parameters, additional configuration is provided through top-level signals, which are expected to be set to a fixed value at synthesis time. + +Signal Name | Data Type | Width | Description +----------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +hartinfo | hartinfo_t | NrHarts | Value of the hartinfo DM register, see the RISC-V Debug Specification v0.13, Section 3.14.2 for details. **nscratch**: Number of debug scratch registers. Must be set to 2. **dataaccess**: Must be set to 1. (The data register are shadowed in the hart's memory.) **datasize**: Must be set to `dm::DataCount`. **dataaddr**: Must be set to `dm::DataAddr` (0x380). + +**SystemVerilog definition of the hartinfo_t structure** + +```verilog +typedef struct packed { + logic [31:24] zero1; + logic [23:20] nscratch; + logic [19:17] zero0; + logic dataaccess; + logic [15:12] datasize; + logic [11:0] dataaddr; +} hartinfo_t; +``` + +## Hardware Interfaces + +The debug system interacts with multiple components, which are described in this section. +The Debug Module interacts the debugged hart(s) through the core interface, with the system bus through its bus host and device, and with system management and reset functionality, and with the Debug Transport Module through the Debug Module Interface (DMI). + +The JTAG Debug Transport Module interacts with the host PC through JTAG, and with the Debug Module through the Debug Module Interface (DMI). + +### System Interface + +**Signal** | **Direction** | **Description** +---------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +clk_i | input | clock. All components of the debug module and the DMI are synchronous to this clock, except for the JTAG components, which are clocked with the external TCLK. +rst_ni | input | asynchronous, active low reset. +testmode_i | input | not used currently +ndmreset_o | output | Non-Debug Mode reset (ndmreset). ndmreset is triggered externally through JTAG, e.g. by a debugger, and should reset the whole system except for the debug system. See the RISC-V Debug Specification v0.13, Section 3.2 (Reset Control) for more details. +dmactive_o | output | debug module is active + +**SystemVerilog interface definition** + +```verilog +input logic clk_i, +input logic rst_ni, +input logic testmode_i, +output logic ndmreset_o, +output logic dmactive_o +``` + +### Core Interface + +The debug system is compatible with any RISC-V compliant CPU core, given that it support execution based debugging according to the RISC-V Debug Specification, Section A.2. + +#### Debug Request Interrupt + +The debug request interrupt is a level-sensitive interrupt. It is issued by the Debug Module to the hart(s). + +**Signal** | **Direction** | **Description** +------------------------ | ------------- | --------------------------------------- +debug_req_o[NrHarts-1:0] | output | Level-sensitive debug request interrupt + +The Debug Module issues the debug request to request the core to enter its debug mode. +In consequence, the core is expected to + +- jump to the halt address in the Debug ROM, +- save pc in dpc, +- update dcsr. + +#### Auxiliary Signalling + +**Signal** | **Direction** | **Description** +------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +unavailable_i[NrHarts-1] | input | Set to 0 to mark the hart has unavailable (e.g.: power down). This information is made available to the debugger through the dmstatus.allunavail and dmstatus.anyavail fields. + +#### Debug Control and Status Register (CSRs) + +Four debug-specific CSRs must be supported by the core, as described in the Debug Specification Section 4.8. + +**Address** | **Name** | **Access** | **Description** +----------- | --------- | ----------------------------- | ---------------------------------------------------------------------------- +0x7b0 | dcsr | _field-dependent; check spec_ | Debug Control and Status +0x7b1 | dpc | RW from Debug Mode only | Debug PC +0x7b2 | dscratch0 | RW from Debug Mode only | Debug Scratch Register 0 +0x7b3 | dscratch1 | RW from Debug Mode only | Debug Scratch Register 1 (only required if DM is not located at address 0x0) + +#### DRET Instruction + +To return from debug mode the DRET instruction must be supported by the core according to the Debug Specification Section 4.7. + +### JTAG + +The JTAG Debug Transport Module (JTAG DTM) provides a standard IEEE 1149.1 JTAG connection. + +**Signal** | **Direction** | **Description** +---------- | ------------- | ----------------------------------------------------------------------------------------------------- +tck_i | input | Test Clock +tms_i | input | Test Mode Select +td_i | input | Test Data In (host to debug system) +td_o | output | Test Data Out (debug system to host) +tdo_oe_o | output | TDO output enable +trst_ni | input | Test Reset (active low). Usage of TRST is optional, but recommended for reliable reset functionality. + +### Bus Interface +The Debug Module connects to the system bus as device, exposing the debug memory (the Program Buffer and the Debug ROM), and as host for the System Bus Access (SBA) functionality. +The same generic bus interface is used in both cases. +The bus width is configurable to be 32 or 64 bit using the `BusWidth` parameter. + +#### Host (Master) Interface + +The bus host interface is compatible to the [instruction and data interfaces of Ibex](https://ibex-core.readthedocs.io/en/latest/load_store_unit.html). + +**Signal** | **Width (bit)** | **Direction** | **Description** +---------- | --------------- | ------------- | --------------------------------------------------------------------------------------------------------- +req | 1 | output | Request valid, must stay high until gnt is high for one cycle +add | BusWidth | output | Address, word aligned +we | BusWidth | output | Write Enable, high for writes, low for reads. Sent together with req +be | 1 | output | Byte Enable. Is set for the bytes to write/read, sent together with req +wdata | BusWidth | output | Data to be written to device, sent together with req +gnt | 1 | input | The device accepted the request. Host outputs may change in the next cycle. +r_valid | 1 | input | r_rdata hold valid data when r_valid is high. This signal will be high for exactly one cycle per request. +r_rdata | BusWidth | input | Data read from the device + +No error response is currently implemented. + +**SystemVerilog interface definition (host side)** + +```verilog +output logic req_o, +output logic [BusWidth-1:0] add_o, +output logic we_o, +output logic [BusWidth-1:0] wdata_o, +output logic [BusWidth/8-1:0] be_o, +input logic gnt_i, +input logic r_valid_i, +input logic [BusWidth-1:0] r_rdata_i +``` + +**SystemVerilog interface definition (device side)** + +```verilog +input logic slave_req_i, +input logic slave_we_i, +input logic [BusWidth-1:0] slave_addr_i, +input logic [BusWidth/8-1:0] slave_be_i, +input logic [BusWidth-1:0] slave_wdata_i, +output logic [BusWidth-1:0] slave_rdata_o +``` +### OBI Bus Interface (optional) + +A wrapper (called dm_obi_top) is provided which wraps the Debug Module (dm_top) and makes it OBI compliant. This wrapper +can be ignored (and dm_top can be used directly instead) in case of non OBI compatible systems. + +The OBI (Open Bus Interface) specification is at https://github.com/openhwgroup/core-v-docs/blob/master/cores/cv32e40p/. + +The Debug Module connects to the system bus as device, exposing the debug memory (the Program Buffer and the Debug ROM), +and as host for the System Bus Access (SBA) functionality. The bus interface is according to the OBI specification in both cases. +The bus width is configurable to be 32 or 64 bit using the `BusWidth` parameter. The transfer identifier width is configurable +using the `IdWidth` parameter. + +#### Host (Master) OBI Interface + +Compared to dm_top the slave interface of dm_obi_top has the following additional signals: slave_gnt_o, slave_rvalid_o, slave_aid_i, +slave_rid_o. Compared to dm_top the master interface of dm_obi_top has some renamed signals (master_addr_o, master_rvalid_i, master_rdata_i +instead of master_add_o, master_r_valid_i, master_r_rdata_i). + +Both interfaces are OBI compliant. + +**Signal** | **Width (bit)** | **Direction** | **Description** +---------- | --------------- | ------------- | --------------------------------------------------------------------------------------------------------- +req | 1 | output | Request valid, must stay high until gnt is high for one cycle +addr | BusWidth | output | Address, word aligned +we | BusWidth | output | Write Enable, high for writes, low for reads. Sent together with req +be | 1 | output | Byte Enable. Is set for the bytes to write/read, sent together with req +wdata | BusWidth | output | Data to be written to device, sent together with req +gnt | 1 | input | The device accepted the request. Host outputs may change in the next cycle. +rvalid | 1 | input | r_rdata hold valid data when r_valid is high. This signal will be high for exactly one cycle per request. +rdata | BusWidth | input | Data read from the device + +No error response is currently implemented. + +**SystemVerilog interface definition (host side)** + +```verilog +output logic master_req_o, +output logic [BusWidth-1:0] master_addr_o, +output logic master_we_o, +output logic [BusWidth-1:0] master_wdata_o, +output logic [BusWidth/8-1:0] master_be_o, +input logic master_gnt_i, +input logic master_rvalid_i, +input logic [BusWidth-1:0] master_rdata_i +``` + +**SystemVerilog interface definition (device side)** + +```verilog +input logic slave_req_i, +output logic slave_gnt_o, +input logic slave_we_i, +input logic [BusWidth-1:0] slave_addr_i, +input logic [BusWidth/8-1:0] slave_be_i, +input logic [BusWidth-1:0] slave_wdata_i, +input logic [IdWidth-1:0] slave_aid_i, +output logic slave_rvalid_o, +output logic [BusWidth-1:0] slave_rdata_o, +output logic [IdWidth-1:0] slave_rid_o +``` + +### The Debug Module Interface (DMI) + +The Debug Module Interface is a bus connecting the JTAG Debug Transport Module (DTM) with the Debug Module (DM). +The Debug Specification does not require a specific implementation or hardware interface of the DMI bus. +Our implementation is inspired by the implementation used by the Rocket Chip Generator. + +Transfers on the DMI are performed on two channels, a request and a response channel. +A valid and a ready signal on each channel is used for handshaking. + +#### DMI Request Channel + +A DMI request is issued from a DMI host to a DMI device. + +**Signal** | **Width (bit)** | **Direction** | **Description** +---------- | --------------- | -------------- | ---------------------------------------------------------------------------------------- +addr | 7 | host -> device | Address of a debug module register (c.f. Section 3.14 of the RISC-V Debug Specification) +op | 2 | host -> device | Performed operation: DTM_NOP = 2'h0, DTM_READ = 2'h1, DTM_WRITE = 2'h2 +data | 32 | host -> device | write data +valid | 1 | host -> device | handshaking: request is valid +ready | 1 | device -> host | handshaking: transaction processed + +**SystemVerilog interface definition (host side)** + +```verilog +typedef enum logic [1:0] { + DTM_NOP = 2'h0, + DTM_READ = 2'h1, + DTM_WRITE = 2'h2 +} dtm_op_e; + +typedef struct packed { + logic [6:0] addr; + dtm_op_e op; + logic [31:0] data; +} dmi_req_t; + +output logic dmi_req_valid_o, +input logic dmi_req_ready_i, +output dmi_req_t dmi_req_o +``` + +#### DMI Response Channel + +**Signal** | **Width (bit)** | **Direction** | **Description** +---------- | --------------- | -------------- | ------------------------------------------- +resp | 2 | device -> host | Result of the operation. DTM_SUCCESS = 2'h0 +data | 32 | device -> host | requested read data +valid | 1 | device -> host | handshaking: response is valid +ready | 1 | host -> device | handshaking: transaction processed + +**SystemVerilog interface definition (host side)** + +```verilog +typedef struct packed { + logic [31:0] data; + logic [1:0] resp; +} dmi_resp_t; + +input dmi_resp_t dmi_resp_i, +output logic dmi_resp_ready_o, +input logic dmi_resp_valid_i +``` + +#### Protocol + +A DMI transaction consists of a request and a response. + A DMI host issues a request on the request channel. + The request is transmitted as soon as both ready and valid are high. + After some time, the device sends the answers the request on the response channel. + The response is considered sent as soon as ready and valid of the response channel are both high. + A transaction is completed as soon as the response is received by the host. + Only one transaction may be active at any given time. + +The following timing diagram shows two DMI transactions. + +A READ transaction, reading address 0x12 successfully, the value 0x1234 is returned. +A WRITE transaction, writing the value 0xabcd to address 0x34 successfully. + +![DMI protocol](dmi_protocol.svg) + +## System Bus Access + +The system bus and all attached peripherals, including the memories, can be accessed from the host system through the System Bus Access (SBA) component. +A typical use case is writing the program memory through this interface, or verifying its contents. +The implementation conforms to the [RISC-V Debug Specification v0.13](https://github.com/riscv/riscv-debug-spec/raw/4e0bb0fc2d843473db2356623792c6b7603b94d4/riscv-debug-release.pdf), refer to this document for further information. + +## Debug Memory + +The Debug Module exposes a 16 kB memory over its device bus interface. +This memory is called the Debug Memory. +It consists of a ROM portion, containing the Debug ROM, multiple memory-mapped control and status registers, and a RAM portion, the Program Buffer. +The Debug Memory should only be accessible from the CPU if it is in debug mode. + +### Debug Memory Map + +The memory map is an implementation detail of the Debug Module and should not be relied on when using the Debug Module. + +Address | Description +--------------- | ------------------------------------------------------------------------------------------------------------------------------------------ +0x0 to 0x0ff | _unused_ +0x100 | Halted. Write to this address to acknowledge that the core is halted. +0x104 | Going. Write to this address to acknowledge that the core is executing. +0x108 | Resuming. Write to this address to acknowledge that the core is resuming non-debug operation. +0x10c | Exception. An exception was triggered while the core was in debug mode. +0x300 | WhereTo +0x338 to 0x35f | AbstractCmd +0x360 to 0x37f | Program Buffer (8 words) +0x380 to 0x388 | DataAddr +0x400 to 0x7ff | Flags +0x800 to 0x1000 | Debug ROM +0x800 | HaltAddress. Entry point into the Debug Module. The core must jump to this address when it was requested to halt. +0x804 | ResumeAddress. Entry point into the Debug Module. Jumping to this address instructs the debug module to bring the core out of debug mode and back into normal operation mode. +0x808 | ExceptionAddress. Entry point into the Debug Module. The core must jump to this address when it receives an exception while being in debug mode. + +(Note: The debug memory addressing scheme is adopted from the Rocket Chip Generator.) diff --git a/vendor/pulp_riscv_dbg/doc/debugsys_schematic.svg b/vendor/pulp_riscv_dbg/doc/debugsys_schematic.svg new file mode 100644 index 0000000000..28bab27e58 --- /dev/null +++ b/vendor/pulp_riscv_dbg/doc/debugsys_schematic.svg @@ -0,0 +1,679 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + JTAG Test Access Port (TAP) + + Debug Module (DM) + + Debug ModuleRegisters + + System Bus Access (SBA) + + Debug Memory + + JTAG + + Debug Module Interface (DMI) + + + JTAG DTM Registers + debug request (IRQ) + + RISC-V hart + + system bus + + bus host (SBA) + + bus device (mem) + + + + memory andperipherals + + + + accessto + JTAG Debug Transport Module (DTM) + + diff --git a/vendor/pulp_riscv_dbg/doc/dmi_protocol.json b/vendor/pulp_riscv_dbg/doc/dmi_protocol.json new file mode 100644 index 0000000000..8275e951c0 --- /dev/null +++ b/vendor/pulp_riscv_dbg/doc/dmi_protocol.json @@ -0,0 +1,13 @@ +{signal: [ + {name: 'clk', wave: 'p...|....|....|....'}, + {name: 'dmi_req.op', wave: 'x=.x|....|x=.x|....', data: ['READ', 'WRITE']}, + {name: 'dmi_req.addr', wave: 'x=.x|....|x=.x|....', data: ['0x12', '0x34']}, + {name: 'dmi_req.data', wave: 'x...|....|x=.x|....', data: ['0xabcd']}, + {name: 'dmi_req_valid', wave: '01.0|....|.1.0|....'}, + {name: 'dmi_req_ready', wave: '0.1.|..0.|..1.|....'}, + {}, + {name: 'dmi_resp.resp',wave: 'x...|x=.x|....|x=.x', data: ['SUCCESS', 'SUCCESS']}, + {name: 'dmi_resp.data',wave: 'x...|x=.x|....|....', data: ['0x1234']}, + {name: 'dmi_resp_valid', wave: '0...|.1.0|....|..10'}, + {name: 'dmi_resp_ready', wave: '1...|0.1.|....|....'}, +]} diff --git a/vendor/pulp_riscv_dbg/doc/dmi_protocol.svg b/vendor/pulp_riscv_dbg/doc/dmi_protocol.svg new file mode 100644 index 0000000000..3927140fe3 --- /dev/null +++ b/vendor/pulp_riscv_dbg/doc/dmi_protocol.svg @@ -0,0 +1,4 @@ + + + +clkdmi_req.opREADWRITEdmi_req.addr0x120x34dmi_req.data0xabcddmi_req_validdmi_req_readydmi_resp.respSUCCESSSUCCESSdmi_resp.data0x1234dmi_resp_validdmi_resp_readyg \ No newline at end of file diff --git a/vendor/pulp_riscv_dbg/src/dm_csrs.sv b/vendor/pulp_riscv_dbg/src/dm_csrs.sv new file mode 100644 index 0000000000..0d88e792d4 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dm_csrs.sv @@ -0,0 +1,642 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the “License”); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: dm_csrs.sv + * Author: Florian Zaruba + * Date: 30.6.2018 + * + * Description: Debug CSRs. Communication over Debug Transport Module (DTM) + */ + +module dm_csrs #( + parameter int unsigned NrHarts = 1, + parameter int unsigned BusWidth = 32, + parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}} +) ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic testmode_i, + input logic dmi_rst_ni, // Debug Module Intf reset active-low + input logic dmi_req_valid_i, + output logic dmi_req_ready_o, + input dm::dmi_req_t dmi_req_i, + // every request needs a response one cycle later + output logic dmi_resp_valid_o, + input logic dmi_resp_ready_i, + output dm::dmi_resp_t dmi_resp_o, + // global ctrl + output logic ndmreset_o, // non-debug module reset active-high + output logic dmactive_o, // 1 -> debug-module is active, + // 0 -> synchronous re-set + // hart status + input dm::hartinfo_t [NrHarts-1:0] hartinfo_i, // static hartinfo + input logic [NrHarts-1:0] halted_i, // hart is halted + input logic [NrHarts-1:0] unavailable_i, // e.g.: powered down + input logic [NrHarts-1:0] resumeack_i, // hart acknowledged resume request + // hart control + output logic [19:0] hartsel_o, // hartselect to ctrl module + output logic [NrHarts-1:0] haltreq_o, // request to halt a hart + output logic [NrHarts-1:0] resumereq_o, // request hart to resume + output logic clear_resumeack_o, + + output logic cmd_valid_o, // debugger writing to cmd field + output dm::command_t cmd_o, // abstract command + input logic cmderror_valid_i, // an error occurred + input dm::cmderr_e cmderror_i, // this error occurred + input logic cmdbusy_i, // cmd is currently busy executing + + output logic [dm::ProgBufSize-1:0][31:0] progbuf_o, // to system bus + output logic [dm::DataCount-1:0][31:0] data_o, + + input logic [dm::DataCount-1:0][31:0] data_i, + input logic data_valid_i, + // system bus access module (SBA) + output logic [BusWidth-1:0] sbaddress_o, + input logic [BusWidth-1:0] sbaddress_i, + output logic sbaddress_write_valid_o, + // control signals in + output logic sbreadonaddr_o, + output logic sbautoincrement_o, + output logic [2:0] sbaccess_o, + // data out + output logic sbreadondata_o, + output logic [BusWidth-1:0] sbdata_o, + output logic sbdata_read_valid_o, + output logic sbdata_write_valid_o, + // read data in + input logic [BusWidth-1:0] sbdata_i, + input logic sbdata_valid_i, + // control signals + input logic sbbusy_i, + input logic sberror_valid_i, // bus error occurred + input logic [2:0] sberror_i // bus error occurred +); + + // the amount of bits we need to represent all harts + localparam int unsigned HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts); + localparam int unsigned NrHartsAligned = 2**HartSelLen; + + dm::dtm_op_e dtm_op; + assign dtm_op = dm::dtm_op_e'(dmi_req_i.op); + + logic [31:0] resp_queue_data; + + localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'b0, dm::DataCount} - 8'h1); + localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'b0, dm::ProgBufSize} - 8'h1); + + logic [31:0] haltsum0, haltsum1, haltsum2, haltsum3; + logic [((NrHarts-1)/2**5 + 1) * 32 - 1 : 0] halted; + logic [(NrHarts-1)/2**5:0][31:0] halted_reshaped0; + logic [(NrHarts-1)/2**10:0][31:0] halted_reshaped1; + logic [(NrHarts-1)/2**15:0][31:0] halted_reshaped2; + logic [((NrHarts-1)/2**10+1)*32-1:0] halted_flat1; + logic [((NrHarts-1)/2**15+1)*32-1:0] halted_flat2; + logic [31:0] halted_flat3; + + // haltsum0 + logic [14:0] hartsel_idx0; + always_comb begin : p_haltsum0 + halted = '0; + haltsum0 = '0; + hartsel_idx0 = hartsel_o[19:5]; + halted[NrHarts-1:0] = halted_i; + halted_reshaped0 = halted; + if (hartsel_idx0 < 15'((NrHarts-1)/2**5+1)) begin + haltsum0 = halted_reshaped0[hartsel_idx0]; + end + end + + // haltsum1 + logic [9:0] hartsel_idx1; + always_comb begin : p_reduction1 + halted_flat1 = '0; + haltsum1 = '0; + hartsel_idx1 = hartsel_o[19:10]; + + for (int unsigned k = 0; k < (NrHarts-1)/2**5+1; k++) begin + halted_flat1[k] = |halted_reshaped0[k]; + end + halted_reshaped1 = halted_flat1; + + if (hartsel_idx1 < 10'(((NrHarts-1)/2**10+1))) begin + haltsum1 = halted_reshaped1[hartsel_idx1]; + end + end + + // haltsum2 + logic [4:0] hartsel_idx2; + always_comb begin : p_reduction2 + halted_flat2 = '0; + haltsum2 = '0; + hartsel_idx2 = hartsel_o[19:15]; + + for (int unsigned k = 0; k < (NrHarts-1)/2**10+1; k++) begin + halted_flat2[k] = |halted_reshaped1[k]; + end + halted_reshaped2 = halted_flat2; + + if (hartsel_idx2 < 5'(((NrHarts-1)/2**15+1))) begin + haltsum2 = halted_reshaped2[hartsel_idx2]; + end + end + + // haltsum3 + always_comb begin : p_reduction3 + halted_flat3 = '0; + for (int unsigned k = 0; k < NrHarts/2**15+1; k++) begin + halted_flat3[k] = |halted_reshaped2[k]; + end + haltsum3 = halted_flat3; + end + + + dm::dmstatus_t dmstatus; + dm::dmcontrol_t dmcontrol_d, dmcontrol_q; + dm::abstractcs_t abstractcs; + dm::cmderr_e cmderr_d, cmderr_q; + dm::command_t command_d, command_q; + logic cmd_valid_d, cmd_valid_q; + dm::abstractauto_t abstractauto_d, abstractauto_q; + dm::sbcs_t sbcs_d, sbcs_q; + logic [63:0] sbaddr_d, sbaddr_q; + logic [63:0] sbdata_d, sbdata_q; + + logic [NrHarts-1:0] havereset_d, havereset_q; + // program buffer + logic [dm::ProgBufSize-1:0][31:0] progbuf_d, progbuf_q; + logic [dm::DataCount-1:0][31:0] data_d, data_q; + + logic [HartSelLen-1:0] selected_hart; + + // a successful response returns zero + assign dmi_resp_o.resp = dm::DTM_SUCCESS; + // SBA + assign sbautoincrement_o = sbcs_q.sbautoincrement; + assign sbreadonaddr_o = sbcs_q.sbreadonaddr; + assign sbreadondata_o = sbcs_q.sbreadondata; + assign sbaccess_o = sbcs_q.sbaccess; + assign sbdata_o = sbdata_q[BusWidth-1:0]; + assign sbaddress_o = sbaddr_q[BusWidth-1:0]; + + assign hartsel_o = {dmcontrol_q.hartselhi, dmcontrol_q.hartsello}; + + // needed to avoid lint warnings + logic [NrHartsAligned-1:0] havereset_d_aligned, havereset_q_aligned, + resumeack_aligned, unavailable_aligned, + halted_aligned; + assign resumeack_aligned = NrHartsAligned'(resumeack_i); + assign unavailable_aligned = NrHartsAligned'(unavailable_i); + assign halted_aligned = NrHartsAligned'(halted_i); + + assign havereset_d = NrHarts'(havereset_d_aligned); + assign havereset_q_aligned = NrHartsAligned'(havereset_q); + + dm::hartinfo_t [NrHartsAligned-1:0] hartinfo_aligned; + always_comb begin : p_hartinfo_align + hartinfo_aligned = '0; + hartinfo_aligned[NrHarts-1:0] = hartinfo_i; + end + + // helper variables + dm::sbcs_t sbcs; + dm::dmcontrol_t dmcontrol; + dm::abstractcs_t a_abstractcs; + logic [4:0] autoexecdata_idx; + always_comb begin : csr_read_write + // -------------------- + // Static Values (R/O) + // -------------------- + // dmstatus + dmstatus = '0; + dmstatus.version = dm::DbgVersion013; + // no authentication implemented + dmstatus.authenticated = 1'b1; + // we do not support halt-on-reset sequence + dmstatus.hasresethaltreq = 1'b0; + // TODO(zarubaf) things need to change here if we implement the array mask + dmstatus.allhavereset = havereset_q_aligned[selected_hart]; + dmstatus.anyhavereset = havereset_q_aligned[selected_hart]; + + dmstatus.allresumeack = resumeack_aligned[selected_hart]; + dmstatus.anyresumeack = resumeack_aligned[selected_hart]; + + dmstatus.allunavail = unavailable_aligned[selected_hart]; + dmstatus.anyunavail = unavailable_aligned[selected_hart]; + + // as soon as we are out of the legal Hart region tell the debugger + // that there are only non-existent harts + dmstatus.allnonexistent = logic'(32'(hartsel_o) > (NrHarts - 1)); + dmstatus.anynonexistent = logic'(32'(hartsel_o) > (NrHarts - 1)); + + // We are not allowed to be in multiple states at once. This is a to + // make the running/halted and unavailable states exclusive. + dmstatus.allhalted = halted_aligned[selected_hart] & ~unavailable_aligned[selected_hart]; + dmstatus.anyhalted = halted_aligned[selected_hart] & ~unavailable_aligned[selected_hart]; + + dmstatus.allrunning = ~halted_aligned[selected_hart] & ~unavailable_aligned[selected_hart]; + dmstatus.anyrunning = ~halted_aligned[selected_hart] & ~unavailable_aligned[selected_hart]; + + // abstractcs + abstractcs = '0; + abstractcs.datacount = dm::DataCount; + abstractcs.progbufsize = dm::ProgBufSize; + abstractcs.busy = cmdbusy_i; + abstractcs.cmderr = cmderr_q; + + // abstractautoexec + abstractauto_d = abstractauto_q; + abstractauto_d.zero0 = '0; + + // default assignments + havereset_d_aligned = NrHartsAligned'(havereset_q); + dmcontrol_d = dmcontrol_q; + cmderr_d = cmderr_q; + command_d = command_q; + progbuf_d = progbuf_q; + data_d = data_q; + sbcs_d = sbcs_q; + sbaddr_d = 64'(sbaddress_i); + sbdata_d = sbdata_q; + + resp_queue_data = 32'b0; + cmd_valid_d = 1'b0; + sbaddress_write_valid_o = 1'b0; + sbdata_read_valid_o = 1'b0; + sbdata_write_valid_o = 1'b0; + clear_resumeack_o = 1'b0; + + // helper variables + sbcs = '0; + dmcontrol = '0; + a_abstractcs = '0; + + autoexecdata_idx = dmi_req_i.addr[4:0] - 5'(dm::Data0); + + // localparam int unsigned DataCountAlign = $clog2(dm::DataCount); + // reads + if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) begin + unique case ({1'b0, dmi_req_i.addr}) inside + [(dm::Data0):DataEnd]: begin + // logic [$clog2(dm::DataCount)-1:0] resp_queue_idx; + // resp_queue_idx = dmi_req_i.addr[4:0] - int'(dm::Data0); + resp_queue_data = data_q[$clog2(dm::DataCount)'(autoexecdata_idx)]; + if (!cmdbusy_i) begin + // check whether we need to re-execute the command (just give a cmd_valid) + if (autoexecdata_idx < $bits(abstractauto_q.autoexecdata)) begin + cmd_valid_d = abstractauto_q.autoexecdata[autoexecdata_idx]; + end + end + end + dm::DMControl: resp_queue_data = dmcontrol_q; + dm::DMStatus: resp_queue_data = dmstatus; + dm::Hartinfo: resp_queue_data = hartinfo_aligned[selected_hart]; + dm::AbstractCS: resp_queue_data = abstractcs; + dm::AbstractAuto: resp_queue_data = abstractauto_q; + // command is read-only + dm::Command: resp_queue_data = '0; + [(dm::ProgBuf0):ProgBufEnd]: begin + resp_queue_data = progbuf_q[dmi_req_i.addr[$clog2(dm::ProgBufSize)-1:0]]; + if (!cmdbusy_i) begin + // check whether we need to re-execute the command (just give a cmd_valid) + // range of autoexecprogbuf is 31:16 + cmd_valid_d = abstractauto_q.autoexecprogbuf[{1'b1, dmi_req_i.addr[3:0]}]; + end + end + dm::HaltSum0: resp_queue_data = haltsum0; + dm::HaltSum1: resp_queue_data = haltsum1; + dm::HaltSum2: resp_queue_data = haltsum2; + dm::HaltSum3: resp_queue_data = haltsum3; + dm::SBCS: begin + resp_queue_data = sbcs_q; + end + dm::SBAddress0: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + resp_queue_data = sbaddr_q[31:0]; + end + end + dm::SBAddress1: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + resp_queue_data = sbaddr_q[63:32]; + end + end + dm::SBData0: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbdata_read_valid_o = (sbcs_q.sberror == '0); + resp_queue_data = sbdata_q[31:0]; + end + end + dm::SBData1: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + resp_queue_data = sbdata_q[63:32]; + end + end + default:; + endcase + end + + // write + if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_WRITE) begin + unique case (dm::dm_csr_e'({1'b0, dmi_req_i.addr})) inside + [(dm::Data0):DataEnd]: begin + // attempts to write them while busy is set does not change their value + if (!cmdbusy_i && dm::DataCount > 0) begin + data_d[dmi_req_i.addr[$clog2(dm::DataCount)-1:0]] = dmi_req_i.data; + // check whether we need to re-execute the command (just give a cmd_valid) + if (autoexecdata_idx < $bits(abstractauto_q.autoexecdata)) begin + cmd_valid_d = abstractauto_q.autoexecdata[autoexecdata_idx]; + end + end + end + dm::DMControl: begin + dmcontrol = dm::dmcontrol_t'(dmi_req_i.data); + // clear the havreset of the selected hart + if (dmcontrol.ackhavereset) begin + havereset_d_aligned[selected_hart] = 1'b0; + end + dmcontrol_d = dmi_req_i.data; + end + dm::DMStatus:; // write are ignored to R/O register + dm::Hartinfo:; // hartinfo is R/O + // only command error is write-able + dm::AbstractCS: begin // W1C + // Gets set if an abstract command fails. The bits in this + // field remain set until they are cleared by writing 1 to + // them. No abstract command is started until the value is + // reset to 0. + a_abstractcs = dm::abstractcs_t'(dmi_req_i.data); + // reads during abstract command execution are not allowed + if (!cmdbusy_i) begin + cmderr_d = dm::cmderr_e'(~a_abstractcs.cmderr & cmderr_q); + end else if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end + end + dm::Command: begin + // writes are ignored if a command is already busy + if (!cmdbusy_i) begin + cmd_valid_d = 1'b1; + command_d = dm::command_t'(dmi_req_i.data); + // if there was an attempted to write during a busy execution + // and the cmderror field is zero set the busy error + end else if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end + end + dm::AbstractAuto: begin + // this field can only be written legally when there is no command executing + if (!cmdbusy_i) begin + abstractauto_d = 32'b0; + abstractauto_d.autoexecdata = 12'(dmi_req_i.data[dm::DataCount-1:0]); + abstractauto_d.autoexecprogbuf = 16'(dmi_req_i.data[dm::ProgBufSize-1+16:16]); + end else if (cmderr_q == dm::CmdErrNone) begin + cmderr_d = dm::CmdErrBusy; + end + end + [(dm::ProgBuf0):ProgBufEnd]: begin + // attempts to write them while busy is set does not change their value + if (!cmdbusy_i) begin + progbuf_d[dmi_req_i.addr[$clog2(dm::ProgBufSize)-1:0]] = dmi_req_i.data; + // check whether we need to re-execute the command (just give a cmd_valid) + // this should probably throw an error if executed during another command + // was busy + // range of autoexecprogbuf is 31:16 + cmd_valid_d = abstractauto_q.autoexecprogbuf[{1'b1, dmi_req_i.addr[3:0]}]; + end + end + dm::SBCS: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbcs = dm::sbcs_t'(dmi_req_i.data); + sbcs_d = sbcs; + // R/W1C + sbcs_d.sbbusyerror = sbcs_q.sbbusyerror & (~sbcs.sbbusyerror); + sbcs_d.sberror = sbcs_q.sberror & (~sbcs.sberror); + end + end + dm::SBAddress0: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbaddr_d[31:0] = dmi_req_i.data; + sbaddress_write_valid_o = (sbcs_q.sberror == '0); + end + end + dm::SBAddress1: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbaddr_d[63:32] = dmi_req_i.data; + end + end + dm::SBData0: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbdata_d[31:0] = dmi_req_i.data; + sbdata_write_valid_o = (sbcs_q.sberror == '0); + end + end + dm::SBData1: begin + // access while the SBA was busy + if (sbbusy_i) begin + sbcs_d.sbbusyerror = 1'b1; + end else begin + sbdata_d[63:32] = dmi_req_i.data; + end + end + default:; + endcase + end + // hart threw a command error and has precedence over bus writes + if (cmderror_valid_i) begin + cmderr_d = cmderror_i; + end + + // update data registers + if (data_valid_i) begin + data_d = data_i; + end + + // set the havereset flag when we did a ndmreset + if (ndmreset_o) begin + havereset_d_aligned[NrHarts-1:0] = '1; + end + // ------------- + // System Bus + // ------------- + // set bus error + if (sberror_valid_i) begin + sbcs_d.sberror = sberror_i; + end + // update read data + if (sbdata_valid_i) begin + sbdata_d = 64'(sbdata_i); + end + + // dmcontrol + // TODO(zarubaf) we currently do not implement the hartarry mask + dmcontrol_d.hasel = 1'b0; + // we do not support resetting an individual hart + dmcontrol_d.hartreset = 1'b0; + dmcontrol_d.setresethaltreq = 1'b0; + dmcontrol_d.clrresethaltreq = 1'b0; + dmcontrol_d.zero1 = '0; + dmcontrol_d.zero0 = '0; + // Non-writeable, clear only + dmcontrol_d.ackhavereset = 1'b0; + if (!dmcontrol_q.resumereq && dmcontrol_d.resumereq) begin + clear_resumeack_o = 1'b1; + end + if (dmcontrol_q.resumereq && resumeack_i) begin + dmcontrol_d.resumereq = 1'b0; + end + // static values for dcsr + sbcs_d.sbversion = 3'd1; + sbcs_d.sbbusy = sbbusy_i; + sbcs_d.sbasize = $bits(sbcs_d.sbasize)'(BusWidth); + sbcs_d.sbaccess128 = 1'b0; + sbcs_d.sbaccess64 = logic'(BusWidth == 32'd64); + sbcs_d.sbaccess32 = logic'(BusWidth == 32'd32); + sbcs_d.sbaccess16 = 1'b0; + sbcs_d.sbaccess8 = 1'b0; + sbcs_d.sbaccess = (BusWidth == 32'd64) ? 3'd3 : 3'd2; + end + + // output multiplexer + always_comb begin : p_outmux + selected_hart = hartsel_o[HartSelLen-1:0]; + // default assignment + haltreq_o = '0; + resumereq_o = '0; + if (selected_hart < (HartSelLen+1)'(NrHarts)) begin + haltreq_o[selected_hart] = dmcontrol_q.haltreq; + resumereq_o[selected_hart] = dmcontrol_q.resumereq; + end + end + + assign dmactive_o = dmcontrol_q.dmactive; + assign cmd_o = command_q; + assign cmd_valid_o = cmd_valid_q; + assign progbuf_o = progbuf_q; + assign data_o = data_q; + + assign ndmreset_o = dmcontrol_q.ndmreset; + + logic unused_testmode; + assign unused_testmode = testmode_i; + + // response FIFO + prim_fifo_sync #( + .Width (32), + .Pass (1'b0), + .Depth (2) + ) i_fifo ( + .clk_i ( clk_i ), + .rst_ni ( dmi_rst_ni ), // reset only when system is re-set + .clr_i ( 1'b0 ), + .wdata_i ( resp_queue_data ), + .wvalid_i( dmi_req_valid_i ), + .wready_o( dmi_req_ready_o ), + .rdata_o ( dmi_resp_o.data ), + .rvalid_o( dmi_resp_valid_o ), + .rready_i( dmi_resp_ready_i ), + .depth_o ( ) // Doesn't use + ); + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + // PoR + if (!rst_ni) begin + dmcontrol_q <= '0; + // this is the only write-able bit during reset + cmderr_q <= dm::CmdErrNone; + command_q <= '0; + cmd_valid_q <= '0; + abstractauto_q <= '0; + progbuf_q <= '0; + data_q <= '0; + sbcs_q <= '0; + sbaddr_q <= '0; + sbdata_q <= '0; + havereset_q <= '1; + end else begin + havereset_q <= SelectableHarts & havereset_d; + // synchronous re-set of debug module, active-low, except for dmactive + if (!dmcontrol_q.dmactive) begin + dmcontrol_q.haltreq <= '0; + dmcontrol_q.resumereq <= '0; + dmcontrol_q.hartreset <= '0; + dmcontrol_q.ackhavereset <= '0; + dmcontrol_q.zero1 <= '0; + dmcontrol_q.hasel <= '0; + dmcontrol_q.hartsello <= '0; + dmcontrol_q.hartselhi <= '0; + dmcontrol_q.zero0 <= '0; + dmcontrol_q.setresethaltreq <= '0; + dmcontrol_q.clrresethaltreq <= '0; + dmcontrol_q.ndmreset <= '0; + // this is the only write-able bit during reset + dmcontrol_q.dmactive <= dmcontrol_d.dmactive; + cmderr_q <= dm::CmdErrNone; + command_q <= '0; + cmd_valid_q <= '0; + abstractauto_q <= '0; + progbuf_q <= '0; + data_q <= '0; + sbcs_q <= '0; + sbaddr_q <= '0; + sbdata_q <= '0; + end else begin + dmcontrol_q <= dmcontrol_d; + cmderr_q <= cmderr_d; + command_q <= command_d; + cmd_valid_q <= cmd_valid_d; + abstractauto_q <= abstractauto_d; + progbuf_q <= progbuf_d; + data_q <= data_d; + sbcs_q <= sbcs_d; + sbaddr_q <= sbaddr_d; + sbdata_q <= sbdata_d; + end + end + end + + /////////////////////////////////////////////////////// + // assertions + /////////////////////////////////////////////////////// + + //pragma translate_off + `ifndef VERILATOR + haltsum: assert property ( + @(posedge clk_i) disable iff (!rst_ni) + (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) |-> + !({1'b0, dmi_req_i.addr} inside + {dm::HaltSum0, dm::HaltSum1, dm::HaltSum2, dm::HaltSum3})) + else $warning("Haltsums have not been properly tested yet."); + `endif + //pragma translate_on + +endmodule : dm_csrs diff --git a/vendor/pulp_riscv_dbg/src/dm_mem.sv b/vendor/pulp_riscv_dbg/src/dm_mem.sv new file mode 100755 index 0000000000..550b7cc361 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dm_mem.sv @@ -0,0 +1,523 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. +* Copyright and related rights are licensed under the Solderpad Hardware +* License, Version 0.51 (the “License”); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +* or agreed to in writing, software, hardware and materials distributed under +* this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR +* CONDITIONS OF ANY KIND, either express or implied. See the License for the +* specific language governing permissions and limitations under the License. +* +* File: dm_mem.sv +* Author: Florian Zaruba +* Date: 11.7.2018 +* +* Description: Memory module for execution-based debug clients +* +*/ + +module dm_mem #( + parameter int unsigned NrHarts = 1, + parameter int unsigned BusWidth = 32, + parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}}, + parameter int unsigned DmBaseAddress = '0 +) ( + input logic clk_i, // Clock + input logic rst_ni, // debug module reset + + output logic [NrHarts-1:0] debug_req_o, + input logic [19:0] hartsel_i, + // from Ctrl and Status register + input logic [NrHarts-1:0] haltreq_i, + input logic [NrHarts-1:0] resumereq_i, + input logic clear_resumeack_i, + + // state bits + output logic [NrHarts-1:0] halted_o, // hart acknowledge halt + output logic [NrHarts-1:0] resuming_o, // hart is resuming + + input logic [dm::ProgBufSize-1:0][31:0] progbuf_i, // program buffer to expose + + input logic [dm::DataCount-1:0][31:0] data_i, // data in + output logic [dm::DataCount-1:0][31:0] data_o, // data out + output logic data_valid_o, // data out is valid + // abstract command interface + input logic cmd_valid_i, + input dm::command_t cmd_i, + output logic cmderror_valid_o, + output dm::cmderr_e cmderror_o, + output logic cmdbusy_o, + // data interface + + // SRAM interface + input logic req_i, + input logic we_i, + input logic [BusWidth-1:0] addr_i, + input logic [BusWidth-1:0] wdata_i, + input logic [BusWidth/8-1:0] be_i, + output logic [BusWidth-1:0] rdata_o +); + localparam int unsigned DbgAddressBits = 12; + localparam int unsigned HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts); + localparam int unsigned NrHartsAligned = 2**HartSelLen; + localparam int unsigned MaxAar = (BusWidth == 64) ? 4 : 3; + localparam bit HasSndScratch = (DmBaseAddress != 0); + // Depending on whether we are at the zero page or not we either use `x0` or `x10/a0` + localparam logic [4:0] LoadBaseAddr = (DmBaseAddress == 0) ? 5'd0 : 5'd10; + + localparam logic [DbgAddressBits-1:0] DataBaseAddr = (dm::DataAddr); + localparam logic [DbgAddressBits-1:0] DataEndAddr = (dm::DataAddr + 4*dm::DataCount - 1); + localparam logic [DbgAddressBits-1:0] ProgBufBaseAddr = (dm::DataAddr - 4*dm::ProgBufSize); + localparam logic [DbgAddressBits-1:0] ProgBufEndAddr = (dm::DataAddr - 1); + localparam logic [DbgAddressBits-1:0] AbstractCmdBaseAddr = (ProgBufBaseAddr - 4*10); + localparam logic [DbgAddressBits-1:0] AbstractCmdEndAddr = (ProgBufBaseAddr - 1); + + localparam logic [DbgAddressBits-1:0] WhereToAddr = 'h300; + localparam logic [DbgAddressBits-1:0] FlagsBaseAddr = 'h400; + localparam logic [DbgAddressBits-1:0] FlagsEndAddr = 'h7FF; + + localparam logic [DbgAddressBits-1:0] HaltedAddr = 'h100; + localparam logic [DbgAddressBits-1:0] GoingAddr = 'h104; + localparam logic [DbgAddressBits-1:0] ResumingAddr = 'h108; + localparam logic [DbgAddressBits-1:0] ExceptionAddr = 'h10C; + + logic [dm::ProgBufSize/2-1:0][63:0] progbuf; + logic [7:0][63:0] abstract_cmd; + logic [NrHarts-1:0] halted_d, halted_q; + logic [NrHarts-1:0] resuming_d, resuming_q; + logic resume, go, going; + + logic exception; + logic unsupported_command; + + logic [63:0] rom_rdata; + logic [63:0] rdata_d, rdata_q; + logic word_enable32_q; + + // this is needed to avoid lint warnings related to array indexing + // resize hartsel to valid range + logic [HartSelLen-1:0] hartsel, wdata_hartsel; + + assign hartsel = hartsel_i[HartSelLen-1:0]; + assign wdata_hartsel = wdata_i[HartSelLen-1:0]; + + logic [NrHartsAligned-1:0] resumereq_aligned, haltreq_aligned, + halted_d_aligned, halted_q_aligned, + halted_aligned, resumereq_wdata_aligned, + resuming_d_aligned, resuming_q_aligned; + + assign resumereq_aligned = NrHartsAligned'(resumereq_i); + assign haltreq_aligned = NrHartsAligned'(haltreq_i); + assign resumereq_wdata_aligned = NrHartsAligned'(resumereq_i); + + assign halted_q_aligned = NrHartsAligned'(halted_q); + assign halted_d = NrHarts'(halted_d_aligned); + assign resuming_q_aligned = NrHartsAligned'(resuming_q); + assign resuming_d = NrHarts'(resuming_d_aligned); + + // distinguish whether we need to forward data from the ROM or the FSM + // latch the address for this + logic fwd_rom_d, fwd_rom_q; + dm::ac_ar_cmd_t ac_ar; + + // Abstract Command Access Register + assign ac_ar = dm::ac_ar_cmd_t'(cmd_i.control); + assign debug_req_o = haltreq_i; + assign halted_o = halted_q; + assign resuming_o = resuming_q; + + // reshape progbuf + assign progbuf = progbuf_i; + + typedef enum logic [1:0] { Idle, Go, Resume, CmdExecuting } state_e; + state_e state_d, state_q; + + // hart ctrl queue + always_comb begin : p_hart_ctrl_queue + cmderror_valid_o = 1'b0; + cmderror_o = dm::CmdErrNone; + state_d = state_q; + go = 1'b0; + resume = 1'b0; + cmdbusy_o = 1'b1; + + unique case (state_q) + Idle: begin + cmdbusy_o = 1'b0; + if (cmd_valid_i && halted_q_aligned[hartsel] && !unsupported_command) begin + // give the go signal + state_d = Go; + end else if (cmd_valid_i) begin + // hart must be halted for all requests + cmderror_valid_o = 1'b1; + cmderror_o = dm::CmdErrorHaltResume; + end + // CSRs want to resume, the request is ignored when the hart is + // requested to halt or it didn't clear the resuming_q bit before + if (resumereq_aligned[hartsel] && !resuming_q_aligned[hartsel] && + !haltreq_aligned[hartsel] && halted_q_aligned[hartsel]) begin + state_d = Resume; + end + end + + Go: begin + // we are already busy here since we scheduled the execution of a program + cmdbusy_o = 1'b1; + go = 1'b1; + // the thread is now executing the command, track its state + if (going) begin + state_d = CmdExecuting; + end + end + + Resume: begin + cmdbusy_o = 1'b1; + resume = 1'b1; + if (resuming_q_aligned[hartsel]) begin + state_d = Idle; + end + end + + CmdExecuting: begin + cmdbusy_o = 1'b1; + go = 1'b0; + // wait until the hart has halted again + if (halted_aligned[hartsel]) begin + state_d = Idle; + end + end + + default: ; + endcase + + // only signal once that cmd is unsupported so that we can clear cmderr + // in subsequent writes to abstractcs + if (unsupported_command && cmd_valid_i) begin + cmderror_valid_o = 1'b1; + cmderror_o = dm::CmdErrNotSupported; + end + + if (exception) begin + cmderror_valid_o = 1'b1; + cmderror_o = dm::CmdErrorException; + end + end + + // word mux for 32bit and 64bit buses + logic [63:0] word_mux; + assign word_mux = (fwd_rom_q) ? rom_rdata : rdata_q; + + if (BusWidth == 64) begin : gen_word_mux64 + assign rdata_o = word_mux; + end else begin : gen_word_mux32 + assign rdata_o = (word_enable32_q) ? word_mux[32 +: 32] : word_mux[0 +: 32]; + end + + // read/write logic + logic [63:0] data_bits; + logic [7:0][7:0] rdata; + always_comb begin : p_rw_logic + + halted_d_aligned = NrHartsAligned'(halted_q); + resuming_d_aligned = NrHartsAligned'(resuming_q); + rdata_d = rdata_q; + // convert the data in bits representation + data_bits = data_i; + rdata = '0; + + // write data in csr register + data_valid_o = 1'b0; + exception = 1'b0; + halted_aligned = '0; + going = 1'b0; + + // The resume ack signal is lowered when the resume request is deasserted + if (clear_resumeack_i) begin + resuming_d_aligned[hartsel] = 1'b0; + end + // we've got a new request + if (req_i) begin + // this is a write + if (we_i) begin + unique case (addr_i[DbgAddressBits-1:0]) inside + HaltedAddr: begin + halted_aligned[wdata_hartsel] = 1'b1; + halted_d_aligned[wdata_hartsel] = 1'b1; + end + GoingAddr: begin + going = 1'b1; + end + ResumingAddr: begin + // clear the halted flag as the hart resumed execution + halted_d_aligned[wdata_hartsel] = 1'b0; + // set the resuming flag which needs to be cleared by the debugger + resuming_d_aligned[wdata_hartsel] = 1'b1; + end + // an exception occurred during execution + ExceptionAddr: exception = 1'b1; + // core can write data registers + [DataBaseAddr:DataEndAddr]: begin + data_valid_o = 1'b1; + for (int i = 0; i < $bits(be_i); i++) begin + if (be_i[i]) begin + data_bits[i*8+:8] = wdata_i[i*8+:8]; + end + end + end + default ; + endcase + + // this is a read + end else begin + unique case (addr_i[DbgAddressBits-1:0]) inside + // variable ROM content + WhereToAddr: begin + // variable jump to abstract cmd, program_buffer or resume + if (resumereq_wdata_aligned[wdata_hartsel]) begin + rdata_d = {32'b0, dm::jal('0, 21'(dm::ResumeAddress[11:0])-21'(WhereToAddr))}; + end + + // there is a command active so jump there + if (cmdbusy_o) begin + // transfer not set is shortcut to the program buffer if postexec is set + // keep this statement narrow to not catch invalid commands + if (cmd_i.cmdtype == dm::AccessRegister && + !ac_ar.transfer && ac_ar.postexec) begin + rdata_d = {32'b0, dm::jal('0, 21'(ProgBufBaseAddr)-21'(WhereToAddr))}; + // this is a legit abstract cmd -> execute it + end else begin + rdata_d = {32'b0, dm::jal('0, 21'(AbstractCmdBaseAddr)-21'(WhereToAddr))}; + end + end + end + + [DataBaseAddr:DataEndAddr]: begin + rdata_d = { + data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] - + DataBaseAddr[DbgAddressBits-1:3] + 1'b1)], + data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] - + DataBaseAddr[DbgAddressBits-1:3])] + }; + end + + [ProgBufBaseAddr:ProgBufEndAddr]: begin + rdata_d = progbuf[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] - + ProgBufBaseAddr[DbgAddressBits-1:3])]; + end + + // two slots for abstract command + [AbstractCmdBaseAddr:AbstractCmdEndAddr]: begin + // return the correct address index + rdata_d = abstract_cmd[3'(addr_i[DbgAddressBits-1:3] - + AbstractCmdBaseAddr[DbgAddressBits-1:3])]; + end + // harts are polling for flags here + [FlagsBaseAddr:FlagsEndAddr]: begin + // release the corresponding hart + if (({addr_i[DbgAddressBits-1:3], 3'b0} - FlagsBaseAddr[DbgAddressBits-1:0]) == + (DbgAddressBits'(hartsel) & {{(DbgAddressBits-3){1'b1}}, 3'b0})) begin + rdata[DbgAddressBits'(hartsel) & DbgAddressBits'(3'b111)] = {6'b0, resume, go}; + end + rdata_d = rdata; + end + default: ; + endcase + end + end + + data_o = data_bits; + end + + always_comb begin : p_abstract_cmd_rom + // this abstract command is currently unsupported + unsupported_command = 1'b0; + // default memory + // if ac_ar.transfer is not set then we can take a shortcut to the program buffer + abstract_cmd[0][31:0] = dm::illegal(); + // load debug module base address into a0, this is shared among all commands + abstract_cmd[0][63:32] = HasSndScratch ? dm::auipc(5'd10, '0) : dm::nop(); + // clr lowest 12b -> DM base offset + abstract_cmd[1][31:0] = HasSndScratch ? dm::srli(5'd10, 5'd10, 6'd12) : dm::nop(); + abstract_cmd[1][63:32] = HasSndScratch ? dm::slli(5'd10, 5'd10, 6'd12) : dm::nop(); + abstract_cmd[2][31:0] = dm::nop(); + abstract_cmd[2][63:32] = dm::nop(); + abstract_cmd[3][31:0] = dm::nop(); + abstract_cmd[3][63:32] = dm::nop(); + abstract_cmd[4][31:0] = HasSndScratch ? dm::csrr(dm::CSR_DSCRATCH1, 5'd10) : dm::nop(); + abstract_cmd[4][63:32] = dm::ebreak(); + abstract_cmd[7:5] = '0; + + // this depends on the command being executed + unique case (cmd_i.cmdtype) + // -------------------- + // Access Register + // -------------------- + dm::AccessRegister: begin + if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && ac_ar.write) begin + // store a0 in dscratch1 + abstract_cmd[0][31:0] = HasSndScratch ? dm::csrr(dm::CSR_DSCRATCH1, 5'd10) : dm::nop(); + // this range is reserved + if (ac_ar.regno[15:14] != '0) begin + abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap + unsupported_command = 1'b1; + // A0 access needs to be handled separately, as we use A0 to load + // the DM address offset need to access DSCRATCH1 in this case + end else if (HasSndScratch && ac_ar.regno[12] && (!ac_ar.regno[5]) && + (ac_ar.regno[4:0] == 5'd10)) begin + // store s0 in dscratch + abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8); + // load from data register + abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr); + // and store it in the corresponding CSR + abstract_cmd[3][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd8); + // restore s0 again from dscratch + abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8); + // GPR/FPR access + end else if (ac_ar.regno[12]) begin + // determine whether we want to access the floating point register or not + if (ac_ar.regno[5]) begin + abstract_cmd[2][31:0] = + dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr); + end else begin + abstract_cmd[2][31:0] = + dm::load(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr); + end + // CSR access + end else begin + // data register to CSR + // store s0 in dscratch + abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8); + // load from data register + abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr); + // and store it in the corresponding CSR + abstract_cmd[3][31:0] = dm::csrw(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8); + // restore s0 again from dscratch + abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8); + end + end else if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && !ac_ar.write) begin + // store a0 in dscratch1 + abstract_cmd[0][31:0] = HasSndScratch ? + dm::csrr(dm::CSR_DSCRATCH1, LoadBaseAddr) : + dm::nop(); + // this range is reserved + if (ac_ar.regno[15:14] != '0) begin + abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap + unsupported_command = 1'b1; + // A0 access needs to be handled separately, as we use A0 to load + // the DM address offset need to access DSCRATCH1 in this case + end else if (HasSndScratch && ac_ar.regno[12] && (!ac_ar.regno[5]) && + (ac_ar.regno[4:0] == 5'd10)) begin + // store s0 in dscratch + abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8); + // read value from CSR into s0 + abstract_cmd[2][63:32] = dm::csrr(dm::CSR_DSCRATCH1, 5'd8); + // and store s0 into data section + abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr); + // restore s0 again from dscratch + abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8); + // GPR/FPR access + end else if (ac_ar.regno[12]) begin + // determine whether we want to access the floating point register or not + if (ac_ar.regno[5]) begin + abstract_cmd[2][31:0] = + dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr); + end else begin + abstract_cmd[2][31:0] = + dm::store(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr); + end + // CSR access + end else begin + // CSR register to data + // store s0 in dscratch + abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8); + // read value from CSR into s0 + abstract_cmd[2][63:32] = dm::csrr(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8); + // and store s0 into data section + abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr); + // restore s0 again from dscratch + abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8); + end + end else if (32'(ac_ar.aarsize) >= MaxAar || ac_ar.aarpostincrement == 1'b1) begin + // this should happend when e.g. ac_ar.aarsize >= MaxAar + // Openocd will try to do an access with aarsize=64 bits + // first before falling back to 32 bits. + abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap + unsupported_command = 1'b1; + end + + // Check whether we need to execute the program buffer. When we + // get an unsupported command we really should abort instead of + // still trying to execute the program buffer, makes it easier + // for the debugger to recover + if (ac_ar.postexec && !unsupported_command) begin + // issue a nop, we will automatically run into the program buffer + abstract_cmd[4][63:32] = dm::nop(); + end + end + // not supported at the moment + // dm::QuickAccess:; + // dm::AccessMemory:; + default: begin + abstract_cmd[0][31:0] = dm::ebreak(); + unsupported_command = 1'b1; + end + endcase + end + + logic [63:0] rom_addr; + assign rom_addr = 64'(addr_i); + + // Depending on whether the debug module is located + // at the zero page we can instantiate a simplified version + // which only requires one scratch register per hart. + // For all other cases we need to set aside + // two registers per hart, hence we also need + // two scratch registers. + if (HasSndScratch) begin : gen_rom_snd_scratch + debug_rom i_debug_rom ( + .clk_i, + .req_i, + .addr_i ( rom_addr ), + .rdata_o ( rom_rdata ) + ); + end else begin : gen_rom_one_scratch + // It uses the zero register (`x0`) as the base + // for its loads. The zero register does not need to + // be saved. + debug_rom_one_scratch i_debug_rom ( + .clk_i, + .req_i, + .addr_i ( rom_addr ), + .rdata_o ( rom_rdata ) + ); + end + + // ROM starts at the HaltAddress of the core e.g.: it immediately jumps to + // the ROM base address + assign fwd_rom_d = logic'(addr_i[DbgAddressBits-1:0] >= dm::HaltAddress[DbgAddressBits-1:0]); + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + if (!rst_ni) begin + fwd_rom_q <= 1'b0; + rdata_q <= '0; + state_q <= Idle; + word_enable32_q <= 1'b0; + end else begin + fwd_rom_q <= fwd_rom_d; + rdata_q <= rdata_d; + state_q <= state_d; + word_enable32_q <= addr_i[2]; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + halted_q <= 1'b0; + resuming_q <= 1'b0; + end else begin + halted_q <= SelectableHarts & halted_d; + resuming_q <= SelectableHarts & resuming_d; + end + end + +endmodule : dm_mem diff --git a/vendor/pulp_riscv_dbg/src/dm_obi_top.sv b/vendor/pulp_riscv_dbg/src/dm_obi_top.sv new file mode 100644 index 0000000000..190830c5f7 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dm_obi_top.sv @@ -0,0 +1,187 @@ +// Copyright 2020 Silicon Labs, Inc. +// +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"). +// +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// +// You may obtain a copy of the License at: +// +// https://solderpad.org/licenses/SHL-2.0/ +// +// Unless required by applicable law or agreed to in writing, software +// and hardware implementations thereof distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// Engineer: Arjan Bink - arjan.bink@silabs.com // +// // +// Design Name: OBI Wrapper for Debug Module (dm_top) // +// Project Name: CV32E40P // +// Language: SystemVerilog // +// // +// Description: Wrapper for the Debug Module (dm_top) which gives it an // +// OBI (Open Bus Interface) compatible interfaces so that it // +// can be integrated without further glue logic (other than // +// tie offs in an OBI compliant system. // +// // +// This wrapper is only intended for OBI compliant systems; // +// in other systems the existing dm_top can be used as before // +// and this wrapper can be ignored. // +// // +// The OBI spec is available at: // +// // +// - https://github.com/openhwgroup/core-v-docs/blob/master/ // +// cores/cv32e40p/ // +// // +// Compared to 'logint' interfaces of dm_top the following // +// signals are added: // +// // +// - slave_* OBI interface: // +// // +// - slave_gnt_o // +// - slave_rvalid_o // +// - slave_aid_i // +// - slave_rid_o // +// // +// Compared to 'logint' interfaces of dm_top the following // +// signals have been renamed: // +// // +// - master_* OBI interface: // +// // +// - Renamed master_add_o to master_addr_o // +// - Renamed master_r_valid_i to master_rvalid_i // +// - Renamed master_r_rdata_i to master_rdata_i // +// // +//////////////////////////////////////////////////////////////////////////////// + +module dm_obi_top #( + parameter int unsigned IdWidth = 1, // Width of aid/rid + parameter int unsigned NrHarts = 1, + parameter int unsigned BusWidth = 32, + parameter int unsigned DmBaseAddress = 'h1000, // default to non-zero page + // Bitmask to select physically available harts for systems + // that don't use hart numbers in a contiguous fashion. + parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}} +) ( + input logic clk_i, // clock + // asynchronous reset active low, connect PoR here, not the system reset + input logic rst_ni, + input logic testmode_i, + output logic ndmreset_o, // non-debug module reset + output logic dmactive_o, // debug module is active + output logic [NrHarts-1:0] debug_req_o, // async debug request + // communicate whether the hart is unavailable (e.g.: power down) + input logic [NrHarts-1:0] unavailable_i, + dm::hartinfo_t [NrHarts-1:0] hartinfo_i, + + input logic slave_req_i, + // OBI grant for slave_req_i (not present on dm_top) + output logic slave_gnt_o, + input logic slave_we_i, + input logic [BusWidth-1:0] slave_addr_i, + input logic [BusWidth/8-1:0] slave_be_i, + input logic [BusWidth-1:0] slave_wdata_i, + // Address phase transaction identifier (not present on dm_top) + input logic [IdWidth-1:0] slave_aid_i, + // OBI rvalid signal (end of response phase for reads/writes) (not present on dm_top) + output logic slave_rvalid_o, + output logic [BusWidth-1:0] slave_rdata_o, + // Response phase transaction identifier (not present on dm_top) + output logic [IdWidth-1:0] slave_rid_o, + + output logic master_req_o, + output logic [BusWidth-1:0] master_addr_o, // Renamed according to OBI spec + output logic master_we_o, + output logic [BusWidth-1:0] master_wdata_o, + output logic [BusWidth/8-1:0] master_be_o, + input logic master_gnt_i, + input logic master_rvalid_i, // Renamed according to OBI spec + input logic [BusWidth-1:0] master_rdata_i, // Renamed according to OBI spec + + // Connection to DTM - compatible to RocketChip Debug Module + input logic dmi_rst_ni, + input logic dmi_req_valid_i, + output logic dmi_req_ready_o, + input dm::dmi_req_t dmi_req_i, + + output logic dmi_resp_valid_o, + input logic dmi_resp_ready_i, + output dm::dmi_resp_t dmi_resp_o +); + + // Slave response phase (rvalid and identifier) + logic slave_rvalid_q; + logic [IdWidth-1:0] slave_rid_q; + + // dm_top instance + dm_top #( + .NrHarts ( NrHarts ), + .BusWidth ( BusWidth ), + .DmBaseAddress ( DmBaseAddress ), + .SelectableHarts ( SelectableHarts ) + ) i_dm_top ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .ndmreset_o ( ndmreset_o ), + .dmactive_o ( dmactive_o ), + .debug_req_o ( debug_req_o ), + .unavailable_i ( unavailable_i ), + .hartinfo_i ( hartinfo_i ), + + .slave_req_i ( slave_req_i ), + .slave_we_i ( slave_we_i ), + .slave_addr_i ( slave_addr_i ), + .slave_be_i ( slave_be_i ), + .slave_wdata_i ( slave_wdata_i ), + .slave_rdata_o ( slave_rdata_o ), + + .master_req_o ( master_req_o ), + .master_add_o ( master_addr_o ), // Renamed according to OBI spec + .master_we_o ( master_we_o ), + .master_wdata_o ( master_wdata_o ), + .master_be_o ( master_be_o ), + .master_gnt_i ( master_gnt_i ), + .master_r_valid_i ( master_rvalid_i ), // Renamed according to OBI spec + .master_r_rdata_i ( master_rdata_i ), // Renamed according to OBI spec + + .dmi_rst_ni ( dmi_rst_ni ), + .dmi_req_valid_i ( dmi_req_valid_i ), + .dmi_req_ready_o ( dmi_req_ready_o ), + .dmi_req_i ( dmi_req_i ), + + .dmi_resp_valid_o ( dmi_resp_valid_o ), + .dmi_resp_ready_i ( dmi_resp_ready_i ), + .dmi_resp_o ( dmi_resp_o ) + ); + + // Extension to wrap dm_top as an OBI-compliant module + // + // dm_top has an implied rvalid pulse the cycle after its granted request. + + // Registers + always_ff @(posedge clk_i or negedge rst_ni) begin : obi_regs + if (!rst_ni) begin + slave_rvalid_q <= 1'b0; + slave_rid_q <= 'b0; + end else begin + if (slave_req_i && slave_gnt_o) begin // 1 cycle pulse on rvalid for every granted request + slave_rvalid_q <= 1'b1; + slave_rid_q <= slave_aid_i; // Mirror aid to rid + end else begin + slave_rvalid_q <= 1'b0; // rid is don't care if rvalid = 0 + end + end + end + + assign slave_gnt_o = 1'b1; // Always receptive to request (slave_req_i) + assign slave_rvalid_o = slave_rvalid_q; + assign slave_rid_o = slave_rid_q; + +endmodule : dm_obi_top diff --git a/vendor/pulp_riscv_dbg/src/dm_pkg.sv b/vendor/pulp_riscv_dbg/src/dm_pkg.sv new file mode 100644 index 0000000000..1b7d0f54a7 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dm_pkg.sv @@ -0,0 +1,414 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the “License”); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: dm_pkg.sv + * Author: Florian Zaruba + * Date: 30.6.2018 + * + * Description: Debug-module package, contains common system definitions. + * + */ + +package dm; + localparam logic [3:0] DbgVersion013 = 4'h2; + // size of program buffer in junks of 32-bit words + localparam logic [4:0] ProgBufSize = 5'h8; + + // amount of data count registers implemented + localparam logic [3:0] DataCount = 4'h2; + + // address to which a hart should jump when it was requested to halt + localparam logic [63:0] HaltAddress = 64'h800; + localparam logic [63:0] ResumeAddress = HaltAddress + 4; + localparam logic [63:0] ExceptionAddress = HaltAddress + 8; + + // address where data0-15 is shadowed or if shadowed in a CSR + // address of the first CSR used for shadowing the data + localparam logic [11:0] DataAddr = 12'h380; // we are aligned with Rocket here + + // debug registers + typedef enum logic [7:0] { + Data0 = 8'h04, + Data1 = 8'h05, + Data2 = 8'h06, + Data3 = 8'h07, + Data4 = 8'h08, + Data5 = 8'h09, + Data6 = 8'h0A, + Data7 = 8'h0B, + Data8 = 8'h0C, + Data9 = 8'h0D, + Data10 = 8'h0E, + Data11 = 8'h0F, + DMControl = 8'h10, + DMStatus = 8'h11, // r/o + Hartinfo = 8'h12, + HaltSum1 = 8'h13, + HAWindowSel = 8'h14, + HAWindow = 8'h15, + AbstractCS = 8'h16, + Command = 8'h17, + AbstractAuto = 8'h18, + DevTreeAddr0 = 8'h19, + DevTreeAddr1 = 8'h1A, + DevTreeAddr2 = 8'h1B, + DevTreeAddr3 = 8'h1C, + NextDM = 8'h1D, + ProgBuf0 = 8'h20, + ProgBuf15 = 8'h2F, + AuthData = 8'h30, + HaltSum2 = 8'h34, + HaltSum3 = 8'h35, + SBAddress3 = 8'h37, + SBCS = 8'h38, + SBAddress0 = 8'h39, + SBAddress1 = 8'h3A, + SBAddress2 = 8'h3B, + SBData0 = 8'h3C, + SBData1 = 8'h3D, + SBData2 = 8'h3E, + SBData3 = 8'h3F, + HaltSum0 = 8'h40 + } dm_csr_e; + + // debug causes + localparam logic [2:0] CauseBreakpoint = 3'h1; + localparam logic [2:0] CauseTrigger = 3'h2; + localparam logic [2:0] CauseRequest = 3'h3; + localparam logic [2:0] CauseSingleStep = 3'h4; + + typedef struct packed { + logic [31:23] zero1; + logic impebreak; + logic [21:20] zero0; + logic allhavereset; + logic anyhavereset; + logic allresumeack; + logic anyresumeack; + logic allnonexistent; + logic anynonexistent; + logic allunavail; + logic anyunavail; + logic allrunning; + logic anyrunning; + logic allhalted; + logic anyhalted; + logic authenticated; + logic authbusy; + logic hasresethaltreq; + logic devtreevalid; + logic [3:0] version; + } dmstatus_t; + + typedef struct packed { + logic haltreq; + logic resumereq; + logic hartreset; + logic ackhavereset; + logic zero1; + logic hasel; + logic [25:16] hartsello; + logic [15:6] hartselhi; + logic [5:4] zero0; + logic setresethaltreq; + logic clrresethaltreq; + logic ndmreset; + logic dmactive; + } dmcontrol_t; + + typedef struct packed { + logic [31:24] zero1; + logic [23:20] nscratch; + logic [19:17] zero0; + logic dataaccess; + logic [15:12] datasize; + logic [11:0] dataaddr; + } hartinfo_t; + + typedef enum logic [2:0] { + CmdErrNone, CmdErrBusy, CmdErrNotSupported, + CmdErrorException, CmdErrorHaltResume, + CmdErrorBus, CmdErrorOther = 7 + } cmderr_e; + + typedef struct packed { + logic [31:29] zero3; + logic [28:24] progbufsize; + logic [23:13] zero2; + logic busy; + logic zero1; + cmderr_e cmderr; + logic [7:4] zero0; + logic [3:0] datacount; + } abstractcs_t; + + typedef enum logic [7:0] { + AccessRegister = 8'h0, + QuickAccess = 8'h1, + AccessMemory = 8'h2 + } cmd_e; + + typedef struct packed { + cmd_e cmdtype; + logic [23:0] control; + } command_t; + + typedef struct packed { + logic [31:16] autoexecprogbuf; + logic [15:12] zero0; + logic [11:0] autoexecdata; + } abstractauto_t; + + typedef struct packed { + logic zero1; + logic [22:20] aarsize; + logic aarpostincrement; + logic postexec; + logic transfer; + logic write; + logic [15:0] regno; + } ac_ar_cmd_t; + + // DTM + typedef enum logic [1:0] { + DTM_NOP = 2'h0, + DTM_READ = 2'h1, + DTM_WRITE = 2'h2 + } dtm_op_e; + + typedef struct packed { + logic [31:29] sbversion; + logic [28:23] zero0; + logic sbbusyerror; + logic sbbusy; + logic sbreadonaddr; + logic [19:17] sbaccess; + logic sbautoincrement; + logic sbreadondata; + logic [14:12] sberror; + logic [11:5] sbasize; + logic sbaccess128; + logic sbaccess64; + logic sbaccess32; + logic sbaccess16; + logic sbaccess8; + } sbcs_t; + + localparam logic [1:0] DTM_SUCCESS = 2'h0; + + typedef struct packed { + logic [6:0] addr; + dtm_op_e op; + logic [31:0] data; + } dmi_req_t; + + typedef struct packed { + logic [31:0] data; + logic [1:0] resp; + } dmi_resp_t; + + // privilege levels + typedef enum logic[1:0] { + PRIV_LVL_M = 2'b11, + PRIV_LVL_S = 2'b01, + PRIV_LVL_U = 2'b00 + } priv_lvl_t; + + // debugregs in core + typedef struct packed { + logic [31:28] xdebugver; + logic [27:16] zero2; + logic ebreakm; + logic zero1; + logic ebreaks; + logic ebreaku; + logic stepie; + logic stopcount; + logic stoptime; + logic [8:6] cause; + logic zero0; + logic mprven; + logic nmip; + logic step; + priv_lvl_t prv; + } dcsr_t; + + // CSRs + typedef enum logic [11:0] { + // Floating-Point CSRs + CSR_FFLAGS = 12'h001, + CSR_FRM = 12'h002, + CSR_FCSR = 12'h003, + CSR_FTRAN = 12'h800, + // Supervisor Mode CSRs + CSR_SSTATUS = 12'h100, + CSR_SIE = 12'h104, + CSR_STVEC = 12'h105, + CSR_SCOUNTEREN = 12'h106, + CSR_SSCRATCH = 12'h140, + CSR_SEPC = 12'h141, + CSR_SCAUSE = 12'h142, + CSR_STVAL = 12'h143, + CSR_SIP = 12'h144, + CSR_SATP = 12'h180, + // Machine Mode CSRs + CSR_MSTATUS = 12'h300, + CSR_MISA = 12'h301, + CSR_MEDELEG = 12'h302, + CSR_MIDELEG = 12'h303, + CSR_MIE = 12'h304, + CSR_MTVEC = 12'h305, + CSR_MCOUNTEREN = 12'h306, + CSR_MSCRATCH = 12'h340, + CSR_MEPC = 12'h341, + CSR_MCAUSE = 12'h342, + CSR_MTVAL = 12'h343, + CSR_MIP = 12'h344, + CSR_PMPCFG0 = 12'h3A0, + CSR_PMPADDR0 = 12'h3B0, + CSR_MVENDORID = 12'hF11, + CSR_MARCHID = 12'hF12, + CSR_MIMPID = 12'hF13, + CSR_MHARTID = 12'hF14, + CSR_MCYCLE = 12'hB00, + CSR_MINSTRET = 12'hB02, + CSR_DCACHE = 12'h701, + CSR_ICACHE = 12'h700, + + CSR_TSELECT = 12'h7A0, + CSR_TDATA1 = 12'h7A1, + CSR_TDATA2 = 12'h7A2, + CSR_TDATA3 = 12'h7A3, + CSR_TINFO = 12'h7A4, + + // Debug CSR + CSR_DCSR = 12'h7b0, + CSR_DPC = 12'h7b1, + CSR_DSCRATCH0 = 12'h7b2, // optional + CSR_DSCRATCH1 = 12'h7b3, // optional + + // Counters and Timers + CSR_CYCLE = 12'hC00, + CSR_TIME = 12'hC01, + CSR_INSTRET = 12'hC02 + } csr_reg_t; + + + // Instruction Generation Helpers + function automatic logic [31:0] jal (logic [4:0] rd, + logic [20:0] imm); + // OpCode Jal + return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f}; + endfunction + + function automatic logic [31:0] jalr (logic [4:0] rd, + logic [4:0] rs1, + logic [11:0] offset); + // OpCode Jal + return {offset[11:0], rs1, 3'b0, rd, 7'h67}; + endfunction + + function automatic logic [31:0] andi (logic [4:0] rd, + logic [4:0] rs1, + logic [11:0] imm); + // OpCode andi + return {imm[11:0], rs1, 3'h7, rd, 7'h13}; + endfunction + + function automatic logic [31:0] slli (logic [4:0] rd, + logic [4:0] rs1, + logic [5:0] shamt); + // OpCode slli + return {6'b0, shamt[5:0], rs1, 3'h1, rd, 7'h13}; + endfunction + + function automatic logic [31:0] srli (logic [4:0] rd, + logic [4:0] rs1, + logic [5:0] shamt); + // OpCode srli + return {6'b0, shamt[5:0], rs1, 3'h5, rd, 7'h13}; + endfunction + + function automatic logic [31:0] load (logic [2:0] size, + logic [4:0] dest, + logic [4:0] base, + logic [11:0] offset); + // OpCode Load + return {offset[11:0], base, size, dest, 7'h03}; + endfunction + + function automatic logic [31:0] auipc (logic [4:0] rd, + logic [20:0] imm); + // OpCode Auipc + return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h17}; + endfunction + + function automatic logic [31:0] store (logic [2:0] size, + logic [4:0] src, + logic [4:0] base, + logic [11:0] offset); + // OpCode Store + return {offset[11:5], src, base, size, offset[4:0], 7'h23}; + endfunction + + function automatic logic [31:0] float_load (logic [2:0] size, + logic [4:0] dest, + logic [4:0] base, + logic [11:0] offset); + // OpCode Load + return {offset[11:0], base, size, dest, 7'b00_001_11}; + endfunction + + function automatic logic [31:0] float_store (logic [2:0] size, + logic [4:0] src, + logic [4:0] base, + logic [11:0] offset); + // OpCode Store + return {offset[11:5], src, base, size, offset[4:0], 7'b01_001_11}; + endfunction + + function automatic logic [31:0] csrw (csr_reg_t csr, + logic [4:0] rs1); + // CSRRW, rd, OpCode System + return {csr, rs1, 3'h1, 5'h0, 7'h73}; + endfunction + + function automatic logic [31:0] csrr (csr_reg_t csr, + logic [4:0] dest); + // rs1, CSRRS, rd, OpCode System + return {csr, 5'h0, 3'h2, dest, 7'h73}; + endfunction + + function automatic logic [31:0] branch(logic [4:0] src2, + logic [4:0] src1, + logic [2:0] funct3, + logic [11:0] offset); + // OpCode Branch + return {offset[11], offset[9:4], src2, src1, funct3, + offset[3:0], offset[10], 7'b11_000_11}; + endfunction + + function automatic logic [31:0] ebreak (); + return 32'h00100073; + endfunction + + function automatic logic [31:0] wfi (); + return 32'h10500073; + endfunction + + function automatic logic [31:0] nop (); + return 32'h00000013; + endfunction + + function automatic logic [31:0] illegal (); + return 32'h00000000; + endfunction + +endpackage : dm diff --git a/vendor/pulp_riscv_dbg/src/dm_sba.sv b/vendor/pulp_riscv_dbg/src/dm_sba.sv new file mode 100644 index 0000000000..c97f9565ae --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dm_sba.sv @@ -0,0 +1,172 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. +* Copyright and related rights are licensed under the Solderpad Hardware +* License, Version 0.51 (the “License”); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +* or agreed to in writing, software, hardware and materials distributed under +* this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR +* CONDITIONS OF ANY KIND, either express or implied. See the License for the +* specific language governing permissions and limitations under the License. +* +* File: dm_sba.sv +* Author: Florian Zaruba +* Date: 1.8.2018 +* +* Description: System Bus Access Module +* +*/ +module dm_sba #( + parameter int unsigned BusWidth = 32 +) ( + input logic clk_i, // Clock + input logic rst_ni, + input logic dmactive_i, // synchronous reset active low + + output logic master_req_o, + output logic [BusWidth-1:0] master_add_o, + output logic master_we_o, + output logic [BusWidth-1:0] master_wdata_o, + output logic [BusWidth/8-1:0] master_be_o, + input logic master_gnt_i, + input logic master_r_valid_i, + input logic [BusWidth-1:0] master_r_rdata_i, + + input logic [BusWidth-1:0] sbaddress_i, + input logic sbaddress_write_valid_i, + // control signals in + input logic sbreadonaddr_i, + output logic [BusWidth-1:0] sbaddress_o, + input logic sbautoincrement_i, + input logic [2:0] sbaccess_i, + // data in + input logic sbreadondata_i, + input logic [BusWidth-1:0] sbdata_i, + input logic sbdata_read_valid_i, + input logic sbdata_write_valid_i, + // read data out + output logic [BusWidth-1:0] sbdata_o, + output logic sbdata_valid_o, + // control signals + output logic sbbusy_o, + output logic sberror_valid_o, // bus error occurred + output logic [2:0] sberror_o // bus error occurred +); + + typedef enum logic [2:0] { Idle, Read, Write, WaitRead, WaitWrite } state_e; + state_e state_d, state_q; + + logic [BusWidth-1:0] address; + logic req; + logic gnt; + logic we; + logic [BusWidth/8-1:0] be; + logic [$clog2(BusWidth/8)-1:0] be_idx; + + assign sbbusy_o = logic'(state_q != Idle); + + always_comb begin : p_fsm + req = 1'b0; + address = sbaddress_i; + we = 1'b0; + be = '0; + be_idx = sbaddress_i[$clog2(BusWidth/8)-1:0]; + + sberror_o = '0; + sberror_valid_o = 1'b0; + sbaddress_o = sbaddress_i; + + state_d = state_q; + + unique case (state_q) + Idle: begin + // debugger requested a read + if (sbaddress_write_valid_i && sbreadonaddr_i) state_d = Read; + // debugger requested a write + if (sbdata_write_valid_i) state_d = Write; + // perform another read + if (sbdata_read_valid_i && sbreadondata_i) state_d = Read; + end + + Read: begin + req = 1'b1; + if (gnt) state_d = WaitRead; + end + + Write: begin + req = 1'b1; + we = 1'b1; + // generate byte enable mask + unique case (sbaccess_i) + 3'b000: begin + be[be_idx] = '1; + end + 3'b001: begin + be[int'({be_idx[$high(be_idx):1], 1'b0}) +: 2] = '1; + end + 3'b010: begin + if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'h0}) +: 4] = '1; + else be = '1; + end + 3'b011: be = '1; + default: ; + endcase + if (gnt) state_d = WaitWrite; + end + + WaitRead: begin + if (sbdata_valid_o) begin + state_d = Idle; + // auto-increment address + if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i); + end + end + + WaitWrite: begin + if (sbdata_valid_o) begin + state_d = Idle; + // auto-increment address + if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i); + end + end + + default: state_d = Idle; // catch parasitic state + endcase + + // handle error case + if (sbaccess_i > 3 && state_q != Idle) begin + req = 1'b0; + state_d = Idle; + sberror_valid_o = 1'b1; + sberror_o = 3'd3; + end + // further error handling should go here ... + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs + if (!rst_ni) begin + state_q <= Idle; + end else begin + state_q <= state_d; + end + end + + assign master_req_o = req; + assign master_add_o = address[BusWidth-1:0]; + assign master_we_o = we; + assign master_wdata_o = sbdata_i[BusWidth-1:0]; + assign master_be_o = be[BusWidth/8-1:0]; + assign gnt = master_gnt_i; + assign sbdata_valid_o = master_r_valid_i; + assign sbdata_o = master_r_rdata_i[BusWidth-1:0]; + + + //pragma translate_off + `ifndef VERILATOR + // maybe bump severity to $error if not handled at runtime + dm_sba_access_size: assert property(@(posedge clk_i) disable iff (dmactive_i !== 1'b0) + (state_d != Idle) |-> (sbaccess_i < 4)) + else $warning ("accesses > 8 byte not supported at the moment"); + `endif + //pragma translate_on + +endmodule : dm_sba diff --git a/vendor/pulp_riscv_dbg/src/dmi_cdc.sv b/vendor/pulp_riscv_dbg/src/dmi_cdc.sv new file mode 100644 index 0000000000..1299b096c1 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dmi_cdc.sv @@ -0,0 +1,85 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. +* Copyright and related rights are licensed under the Solderpad Hardware +* License, Version 0.51 (the “License”); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +* or agreed to in writing, software, hardware and materials distributed under +* this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR +* CONDITIONS OF ANY KIND, either express or implied. See the License for the +* specific language governing permissions and limitations under the License. +* +* File: axi_riscv_debug_module.sv +* Author: Andreas Traber +* Author: Florian Zaruba +* +* Description: Clock domain crossings for JTAG to DMI very heavily based +* on previous work by Andreas Traber for the PULP project. +* This is mainly a wrapper around the existing CDCs. +*/ +module dmi_cdc ( + // JTAG side (master side) + input logic tck_i, + input logic trst_ni, + + input dm::dmi_req_t jtag_dmi_req_i, + output logic jtag_dmi_ready_o, + input logic jtag_dmi_valid_i, + + output dm::dmi_resp_t jtag_dmi_resp_o, + output logic jtag_dmi_valid_o, + input logic jtag_dmi_ready_i, + + // core side (slave side) + input logic clk_i, + input logic rst_ni, + + output dm::dmi_req_t core_dmi_req_o, + output logic core_dmi_valid_o, + input logic core_dmi_ready_i, + + input dm::dmi_resp_t core_dmi_resp_i, + output logic core_dmi_ready_o, + input logic core_dmi_valid_i +); + + // TODO: Make it clean for synthesis. + + prim_fifo_async #( + .Width ( $bits(dm::dmi_req_t) ), + .Depth ( 4 ) + ) i_cdc_req ( + .clk_wr_i ( tck_i ), + .rst_wr_ni ( trst_ni ), + .wvalid_i ( jtag_dmi_valid_i ), + .wready_o ( jtag_dmi_ready_o ), // wrclk + .wdata_i ( jtag_dmi_req_i ), + .wdepth_o ( ), + + .clk_rd_i ( clk_i ), + .rst_rd_ni ( rst_ni ), + .rvalid_o ( core_dmi_valid_o ), + .rready_i ( core_dmi_ready_i ), + .rdata_o ( core_dmi_req_o ), + .rdepth_o ( ) + ); + + prim_fifo_async #( + .Width ( $bits(dm::dmi_resp_t) ), + .Depth ( 4 ) + ) i_cdc_resp ( + .clk_wr_i ( clk_i ), + .rst_wr_ni ( rst_ni ), + .wvalid_i ( core_dmi_valid_i ), + .wready_o ( core_dmi_ready_o ), // wrclk + .wdata_i ( core_dmi_resp_i ), + .wdepth_o ( ), + + .clk_rd_i ( tck_i ), + .rst_rd_ni ( trst_ni ), + .rvalid_o ( jtag_dmi_valid_o ), + .rready_i ( jtag_dmi_ready_i ), + .rdata_o ( jtag_dmi_resp_o ), + .rdepth_o ( ) + ); + +endmodule : dmi_cdc diff --git a/vendor/pulp_riscv_dbg/src/dmi_jtag.sv b/vendor/pulp_riscv_dbg/src/dmi_jtag.sv new file mode 100644 index 0000000000..2039e25986 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dmi_jtag.sv @@ -0,0 +1,264 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. +* Copyright and related rights are licensed under the Solderpad Hardware +* License, Version 0.51 (the “License”); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +* or agreed to in writing, software, hardware and materials distributed under +* this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR +* CONDITIONS OF ANY KIND, either express or implied. See the License for the +* specific language governing permissions and limitations under the License. +* +* File: axi_riscv_debug_module.sv +* Author: Florian Zaruba +* Date: 19.7.2018 +* +* Description: JTAG DMI (debug module interface) +* +*/ + +module dmi_jtag #( + parameter logic [31:0] IdcodeValue = 32'h00000001 +) ( + input logic clk_i, // DMI Clock + input logic rst_ni, // Asynchronous reset active low + input logic testmode_i, + + output logic dmi_rst_no, // hard reset + output dm::dmi_req_t dmi_req_o, + output logic dmi_req_valid_o, + input logic dmi_req_ready_i, + + input dm::dmi_resp_t dmi_resp_i, + output logic dmi_resp_ready_o, + input logic dmi_resp_valid_i, + + input logic tck_i, // JTAG test clock pad + input logic tms_i, // JTAG test mode select pad + input logic trst_ni, // JTAG test reset pad + input logic td_i, // JTAG test data input pad + output logic td_o, // JTAG test data output pad + output logic tdo_oe_o // Data out output enable +); + assign dmi_rst_no = rst_ni; + + logic test_logic_reset; + logic shift_dr; + logic update_dr; + logic capture_dr; + logic dmi_access; + logic dtmcs_select; + logic dmi_reset; + logic dmi_tdi; + logic dmi_tdo; + + dm::dmi_req_t dmi_req; + logic dmi_req_ready; + logic dmi_req_valid; + + dm::dmi_resp_t dmi_resp; + logic dmi_resp_valid; + logic dmi_resp_ready; + + typedef struct packed { + logic [6:0] address; + logic [31:0] data; + logic [1:0] op; + } dmi_t; + + typedef enum logic [1:0] { + DMINoError = 2'h0, DMIReservedError = 2'h1, + DMIOPFailed = 2'h2, DMIBusy = 2'h3 + } dmi_error_e; + + typedef enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_e; + state_e state_d, state_q; + + logic [$bits(dmi_t)-1:0] dr_d, dr_q; + logic [6:0] address_d, address_q; + logic [31:0] data_d, data_q; + + dmi_t dmi; + assign dmi = dmi_t'(dr_q); + assign dmi_req.addr = address_q; + assign dmi_req.data = data_q; + assign dmi_req.op = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ; + // we'will always be ready to accept the data we requested + assign dmi_resp_ready = 1'b1; + + logic error_dmi_busy; + dmi_error_e error_d, error_q; + + always_comb begin : p_fsm + error_dmi_busy = 1'b0; + // default assignments + state_d = state_q; + address_d = address_q; + data_d = data_q; + error_d = error_q; + + dmi_req_valid = 1'b0; + + unique case (state_q) + Idle: begin + // make sure that no error is sticky + if (dmi_access && update_dr && (error_q == DMINoError)) begin + // save address and value + address_d = dmi.address; + data_d = dmi.data; + if (dm::dtm_op_e'(dmi.op) == dm::DTM_READ) begin + state_d = Read; + end else if (dm::dtm_op_e'(dmi.op) == dm::DTM_WRITE) begin + state_d = Write; + end + // else this is a nop and we can stay here + end + end + + Read: begin + dmi_req_valid = 1'b1; + if (dmi_req_ready) begin + state_d = WaitReadValid; + end + end + + WaitReadValid: begin + // load data into register and shift out + if (dmi_resp_valid) begin + data_d = dmi_resp.data; + state_d = Idle; + end + end + + Write: begin + dmi_req_valid = 1'b1; + // got a valid answer go back to idle + if (dmi_req_ready) begin + state_d = Idle; + end + end + + default: begin + // just wait for idle here + if (dmi_resp_valid) begin + state_d = Idle; + end + end + endcase + + // update_dr means we got another request but we didn't finish + // the one in progress, this state is sticky + if (update_dr && state_q != Idle) begin + error_dmi_busy = 1'b1; + end + + // if capture_dr goes high while we are in the read state + // or in the corresponding wait state we are not giving back a valid word + // -> throw an error + if (capture_dr && state_q inside {Read, WaitReadValid}) begin + error_dmi_busy = 1'b1; + end + + if (error_dmi_busy) begin + error_d = DMIBusy; + end + // clear sticky error flag + if (dmi_reset && dtmcs_select) begin + error_d = DMINoError; + end + end + + // shift register + assign dmi_tdo = dr_q[0]; + + always_comb begin : p_shift + dr_d = dr_q; + + if (capture_dr) begin + if (dmi_access) begin + if (error_q == DMINoError && !error_dmi_busy) begin + dr_d = {address_q, data_q, DMINoError}; + // DMI was busy, report an error + end else if (error_q == DMIBusy || error_dmi_busy) begin + dr_d = {address_q, data_q, DMIBusy}; + end + end + end + + if (shift_dr) begin + if (dmi_access) begin + dr_d = {dmi_tdi, dr_q[$bits(dr_q)-1:1]}; + end + end + + if (test_logic_reset) begin + dr_d = '0; + end + end + + always_ff @(posedge tck_i or negedge trst_ni) begin : p_regs + if (!trst_ni) begin + dr_q <= '0; + state_q <= Idle; + address_q <= '0; + data_q <= '0; + error_q <= DMINoError; + end else begin + dr_q <= dr_d; + state_q <= state_d; + address_q <= address_d; + data_q <= data_d; + error_q <= error_d; + end + end + + // --------- + // TAP + // --------- + dmi_jtag_tap #( + .IrLength (5), + .IdcodeValue(IdcodeValue) + ) i_dmi_jtag_tap ( + .tck_i, + .tms_i, + .trst_ni, + .td_i, + .td_o, + .tdo_oe_o, + .testmode_i, + .test_logic_reset_o ( test_logic_reset ), + .shift_dr_o ( shift_dr ), + .update_dr_o ( update_dr ), + .capture_dr_o ( capture_dr ), + .dmi_access_o ( dmi_access ), + .dtmcs_select_o ( dtmcs_select ), + .dmi_reset_o ( dmi_reset ), + .dmi_error_i ( error_q ), + .dmi_tdi_o ( dmi_tdi ), + .dmi_tdo_i ( dmi_tdo ) + ); + + // --------- + // CDC + // --------- + dmi_cdc i_dmi_cdc ( + // JTAG side (master side) + .tck_i, + .trst_ni, + .jtag_dmi_req_i ( dmi_req ), + .jtag_dmi_ready_o ( dmi_req_ready ), + .jtag_dmi_valid_i ( dmi_req_valid ), + .jtag_dmi_resp_o ( dmi_resp ), + .jtag_dmi_valid_o ( dmi_resp_valid ), + .jtag_dmi_ready_i ( dmi_resp_ready ), + // core side + .clk_i, + .rst_ni, + .core_dmi_req_o ( dmi_req_o ), + .core_dmi_valid_o ( dmi_req_valid_o ), + .core_dmi_ready_i ( dmi_req_ready_i ), + .core_dmi_resp_i ( dmi_resp_i ), + .core_dmi_ready_o ( dmi_resp_ready_o ), + .core_dmi_valid_i ( dmi_resp_valid_i ) + ); + +endmodule : dmi_jtag diff --git a/vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv b/vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv new file mode 100644 index 0000000000..94b51d6b91 --- /dev/null +++ b/vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv @@ -0,0 +1,345 @@ +/* Copyright 2018 ETH Zurich and University of Bologna. + * Copyright and related rights are licensed under the Solderpad Hardware + * License, Version 0.51 (the “License”); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law + * or agreed to in writing, software, hardware and materials distributed under + * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * File: dmi_jtag_tap.sv + * Author: Florian Zaruba + * Date: 19.7.2018 + * + * Description: JTAG TAP for DMI (according to debug spec 0.13) + * + */ + +module dmi_jtag_tap #( + parameter int unsigned IrLength = 5, + // JTAG IDCODE Value + parameter logic [31:0] IdcodeValue = 32'h00000001 + // xxxx version + // xxxxxxxxxxxxxxxx part number + // xxxxxxxxxxx manufacturer id + // 1 required by standard +) ( + input logic tck_i, // JTAG test clock pad + input logic tms_i, // JTAG test mode select pad + input logic trst_ni, // JTAG test reset pad + input logic td_i, // JTAG test data input pad + output logic td_o, // JTAG test data output pad + output logic tdo_oe_o, // Data out output enable + input logic testmode_i, + output logic test_logic_reset_o, + output logic shift_dr_o, + output logic update_dr_o, + output logic capture_dr_o, + + // we want to access DMI register + output logic dmi_access_o, + // JTAG is interested in writing the DTM CSR register + output logic dtmcs_select_o, + // clear error state + output logic dmi_reset_o, + input logic [1:0] dmi_error_i, + // test data to submodule + output logic dmi_tdi_o, + // test data in from submodule + input logic dmi_tdo_i +); + + // to submodule + assign dmi_tdi_o = td_i; + + typedef enum logic [3:0] { + TestLogicReset, RunTestIdle, SelectDrScan, + CaptureDr, ShiftDr, Exit1Dr, PauseDr, Exit2Dr, + UpdateDr, SelectIrScan, CaptureIr, ShiftIr, + Exit1Ir, PauseIr, Exit2Ir, UpdateIr + } tap_state_e; + + tap_state_e tap_state_q, tap_state_d; + + typedef enum logic [IrLength-1:0] { + BYPASS0 = 'h0, + IDCODE = 'h1, + DTMCSR = 'h10, + DMIACCESS = 'h11, + BYPASS1 = 'h1f + } ir_reg_e; + + typedef struct packed { + logic [31:18] zero1; + logic dmihardreset; + logic dmireset; + logic zero0; + logic [14:12] idle; + logic [11:10] dmistat; + logic [9:4] abits; + logic [3:0] version; + } dtmcs_t; + + // ---------------- + // IR logic + // ---------------- + + // shift register + logic [IrLength-1:0] jtag_ir_shift_d, jtag_ir_shift_q; + // IR register -> this gets captured from shift register upon update_ir + ir_reg_e jtag_ir_d, jtag_ir_q; + logic capture_ir, shift_ir, update_ir; // pause_ir + + always_comb begin : p_jtag + jtag_ir_shift_d = jtag_ir_shift_q; + jtag_ir_d = jtag_ir_q; + + // IR shift register + if (shift_ir) begin + jtag_ir_shift_d = {td_i, jtag_ir_shift_q[IrLength-1:1]}; + end + + // capture IR register + if (capture_ir) begin + jtag_ir_shift_d = IrLength'(4'b0101); + end + + // update IR register + if (update_ir) begin + jtag_ir_d = ir_reg_e'(jtag_ir_shift_q); + end + + // synchronous test-logic reset + if (test_logic_reset_o) begin + jtag_ir_shift_d = '0; + jtag_ir_d = IDCODE; + end + end + + always_ff @(posedge tck_i, negedge trst_ni) begin : p_jtag_ir_reg + if (!trst_ni) begin + jtag_ir_shift_q <= '0; + jtag_ir_q <= IDCODE; + end else begin + jtag_ir_shift_q <= jtag_ir_shift_d; + jtag_ir_q <= jtag_ir_d; + end + end + + // ---------------- + // TAP DR Regs + // ---------------- + // - Bypass + // - IDCODE + // - DTM CS + logic [31:0] idcode_d, idcode_q; + logic idcode_select; + logic bypass_select; + dtmcs_t dtmcs_d, dtmcs_q; + logic bypass_d, bypass_q; // this is a 1-bit register + + assign dmi_reset_o = dtmcs_q.dmireset; + + always_comb begin + idcode_d = idcode_q; + bypass_d = bypass_q; + dtmcs_d = dtmcs_q; + + if (capture_dr_o) begin + if (idcode_select) idcode_d = IdcodeValue; + if (bypass_select) bypass_d = 1'b0; + if (dtmcs_select_o) begin + dtmcs_d = '{ + zero1 : '0, + dmihardreset : 1'b0, + dmireset : 1'b0, + zero0 : '0, + idle : 3'd1, // 1: Enter Run-Test/Idle and leave it immediately + dmistat : dmi_error_i, // 0: No error, 1: Op failed, 2: too fast + abits : 6'd7, // The size of address in dmi + version : 4'd1 // Version described in spec version 0.13 (and later?) + }; + end + end + + if (shift_dr_o) begin + if (idcode_select) idcode_d = {td_i, 31'(idcode_q >> 1)}; + if (bypass_select) bypass_d = td_i; + if (dtmcs_select_o) dtmcs_d = {td_i, 31'(dtmcs_q >> 1)}; + end + + if (test_logic_reset_o) begin + idcode_d = IdcodeValue; + bypass_d = 1'b0; + end + end + + // ---------------- + // Data reg select + // ---------------- + always_comb begin : p_data_reg_sel + dmi_access_o = 1'b0; + dtmcs_select_o = 1'b0; + idcode_select = 1'b0; + bypass_select = 1'b0; + unique case (jtag_ir_q) + BYPASS0: bypass_select = 1'b1; + IDCODE: idcode_select = 1'b1; + DTMCSR: dtmcs_select_o = 1'b1; + DMIACCESS: dmi_access_o = 1'b1; + BYPASS1: bypass_select = 1'b1; + default: bypass_select = 1'b1; + endcase + end + + // ---------------- + // Output select + // ---------------- + logic tdo_mux; + + always_comb begin : p_out_sel + // we are shifting out the IR register + if (shift_ir) begin + tdo_mux = jtag_ir_shift_q[0]; + // here we are shifting the DR register + end else begin + unique case (jtag_ir_q) + IDCODE: tdo_mux = idcode_q[0]; // Reading ID code + DTMCSR: tdo_mux = dtmcs_q.version[0]; + DMIACCESS: tdo_mux = dmi_tdo_i; // Read from DMI TDO + default: tdo_mux = bypass_q; // BYPASS instruction + endcase + end + end + + // ---------------- + // DFT + // ---------------- + logic tck_n; + + prim_clock_inv #( + .HasScanMode(1'b1) + ) i_tck_inv ( + .clk_i ( tck_i ), + .clk_no ( tck_n ), + .scanmode_i ( testmode_i ) + ); + + // TDO changes state at negative edge of TCK + always_ff @(posedge tck_n, negedge trst_ni) begin : p_tdo_regs + if (!trst_ni) begin + td_o <= 1'b0; + tdo_oe_o <= 1'b0; + end else begin + td_o <= tdo_mux; + tdo_oe_o <= (shift_ir | shift_dr_o); + end + end + // ---------------- + // TAP FSM + // ---------------- + // Determination of next state; purely combinatorial + always_comb begin : p_tap_fsm + + test_logic_reset_o = 1'b0; + + capture_dr_o = 1'b0; + shift_dr_o = 1'b0; + update_dr_o = 1'b0; + + capture_ir = 1'b0; + shift_ir = 1'b0; + // pause_ir = 1'b0; unused + update_ir = 1'b0; + + unique case (tap_state_q) + TestLogicReset: begin + tap_state_d = (tms_i) ? TestLogicReset : RunTestIdle; + test_logic_reset_o = 1'b1; + end + RunTestIdle: begin + tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle; + end + // DR Path + SelectDrScan: begin + tap_state_d = (tms_i) ? SelectIrScan : CaptureDr; + end + CaptureDr: begin + capture_dr_o = 1'b1; + tap_state_d = (tms_i) ? Exit1Dr : ShiftDr; + end + ShiftDr: begin + shift_dr_o = 1'b1; + tap_state_d = (tms_i) ? Exit1Dr : ShiftDr; + end + Exit1Dr: begin + tap_state_d = (tms_i) ? UpdateDr : PauseDr; + end + PauseDr: begin + tap_state_d = (tms_i) ? Exit2Dr : PauseDr; + end + Exit2Dr: begin + tap_state_d = (tms_i) ? UpdateDr : ShiftDr; + end + UpdateDr: begin + update_dr_o = 1'b1; + tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle; + end + // IR Path + SelectIrScan: begin + tap_state_d = (tms_i) ? TestLogicReset : CaptureIr; + end + // In this controller state, the shift register bank in the + // Instruction Register parallel loads a pattern of fixed values on + // the rising edge of TCK. The last two significant bits must always + // be "01". + CaptureIr: begin + capture_ir = 1'b1; + tap_state_d = (tms_i) ? Exit1Ir : ShiftIr; + end + // In this controller state, the instruction register gets connected + // between TDI and TDO, and the captured pattern gets shifted on + // each rising edge of TCK. The instruction available on the TDI + // pin is also shifted in to the instruction register. + ShiftIr: begin + shift_ir = 1'b1; + tap_state_d = (tms_i) ? Exit1Ir : ShiftIr; + end + Exit1Ir: begin + tap_state_d = (tms_i) ? UpdateIr : PauseIr; + end + PauseIr: begin + // pause_ir = 1'b1; // unused + tap_state_d = (tms_i) ? Exit2Ir : PauseIr; + end + Exit2Ir: begin + tap_state_d = (tms_i) ? UpdateIr : ShiftIr; + end + // In this controller state, the instruction in the instruction + // shift register is latched to the latch bank of the Instruction + // Register on every falling edge of TCK. This instruction becomes + // the current instruction once it is latched. + UpdateIr: begin + update_ir = 1'b1; + tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle; + end + default: ; // can't actually happen since case is full + endcase + end + + always_ff @(posedge tck_i or negedge trst_ni) begin : p_regs + if (!trst_ni) begin + tap_state_q <= RunTestIdle; + idcode_q <= IdcodeValue; + bypass_q <= 1'b0; + dtmcs_q <= '0; + end else begin + tap_state_q <= tap_state_d; + idcode_q <= idcode_d; + bypass_q <= bypass_d; + dtmcs_q <= dtmcs_d; + end + end + +endmodule : dmi_jtag_tap diff --git a/vendor/pulp_riscv_dbg/tb/.gitignore b/vendor/pulp_riscv_dbg/tb/.gitignore new file mode 100644 index 0000000000..667cf44f23 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/.gitignore @@ -0,0 +1,26 @@ +TAGS +memory_dump.bin +modelsim.ini +*.o +work/* +*.vstf +*.wlf +*.log +objdump +.build-rtl +.lib-rtl +.opt-rtl +*.elf +*.hex +riscv +common_cells +tech_cells_generic +fpnew +transcript +.nfs* +simv* +ucli.key +DVEfiles +cobj_dir +obj_dir +testbench_verilator diff --git a/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley b/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley new file mode 100644 index 0000000000..5e890e5c35 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley @@ -0,0 +1,24 @@ +Copyright (c) 2011-2016, The Regents of the University of California +(Regents). All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Regents nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive b/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive new file mode 100644 index 0000000000..7e70933754 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2017 SiFive, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/pulp_riscv_dbg/tb/Makefile b/vendor/pulp_riscv_dbg/tb/Makefile new file mode 100644 index 0000000000..9395fe08d8 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/Makefile @@ -0,0 +1,323 @@ +# Copyright 2019 Clifford Wolf +# Copyright 2019 Robert Balas +# Copyright 2020 ETH Zurich and University of Bologna. +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# Author: Robert Balas (balasr@iis.ee.ethz.ch) +# Description: All in one. Uses parts of picorv32's makefile. + +MAKE = make +CTAGS = ctags + +# vsim configuration +VVERSION = "10.7b" + +VLIB = vlib-$(VVERSION) +VWORK = work + +VLOG = vlog-$(VVERSION) +VLOG_FLAGS = -pedanticerrors -suppress 2577 -suppress 2583 +VLOG_LOG = vloggy + +VOPT = vopt-$(VVERSION) +VOPT_FLAGS = -debugdb -fsmdebug -pedanticerrors #=mnprft + +VSIM = vsim-$(VVERSION) +VSIM_HOME = /usr/pack/modelsim-$(VVERSION)-kgf/questasim +VSIM_FLAGS = # user defined +ALL_VSIM_FLAGS = $(VSIM_FLAGS) -sv_lib remote_bitbang/librbs_vsim +VSIM_DEBUG_FLAGS = -debugdb +VSIM_GUI_FLAGS = -gui -debugdb +VSIM_SCRIPT_BATCH = vsim_batch.tcl +VSIM_SCRIPT_GUI = vsim_gui.tcl + +VCS = vcs-2017.03-kgf vcs +VCS_HOME = /usr/pack/vcs-2017.03-kgf +VCS_FLAGS = +SIMV_FLAGS = + +# verilator configuration +VERILATOR = verilator +VERI_FLAGS = +VERI_COMPILE_FLAGS = +VERI_TRACE = +VERI_DIR = cobj_dir +VERI_CFLAGS = -O2 + +# RTL source files +RTLSRC_TB_PKG := +RTLSRC_TB_TOP := tb_top.sv +RTLSRC_TB := boot_rom.sv \ + dp_ram.sv \ + mm_ram.sv \ + SimJTAG.sv \ + tb_test_env.sv \ + tb_top.sv + +RTLSRC_VERI_TB := boot_rom.sv \ + dp_ram.sv \ + mm_ram.sv \ + SimJTAG.sv \ + tb_test_env.sv \ + tb_top_verilator.sv + +RTLSRC_INCDIR := riscv/rtl/include + +RTLSRC_FPNEW_PKG := fpnew/src/fpnew_pkg.sv +RTLSRC_RISCV_PKG += $(addprefix riscv/rtl/include/,\ + apu_core_package.sv riscv_defines.sv \ + riscv_tracer_defines.sv) +RTLSRC_DM_PKG += ../src/dm_pkg.sv + +RTLSRC_PKG = $(RTLSRC_FPNEW_PKG) dm_tb_pkg.sv $(RTLSRC_RISCV_PKG) $(RTLSRC_DM_PKG) +RTLSRC_RISCV := $(addprefix riscv/rtl/,\ + cv32e40p_sim_clock_gating.sv \ + register_file_test_wrap.sv \ + riscv_tracer.sv \ + riscv_register_file.sv \ + riscv_alu.sv \ + riscv_alu_basic.sv \ + riscv_alu_div.sv \ + riscv_compressed_decoder.sv \ + riscv_controller.sv \ + riscv_cs_registers.sv \ + riscv_decoder.sv \ + riscv_int_controller.sv \ + riscv_ex_stage.sv \ + riscv_hwloop_controller.sv \ + riscv_hwloop_regs.sv \ + riscv_id_stage.sv \ + riscv_if_stage.sv \ + riscv_load_store_unit.sv \ + riscv_mult.sv \ + riscv_prefetch_buffer.sv \ + riscv_prefetch_L0_buffer.sv \ + riscv_core.sv \ + riscv_apu_disp.sv \ + riscv_fetch_fifo.sv \ + riscv_L0_buffer.sv \ + riscv_pmp.sv) +RTLSRC_COMMON := $(addprefix common_cells/src/,\ + cdc_2phase.sv fifo_v2.sv fifo_v3.sv\ + rstgen.sv rstgen_bypass.sv) +RTLSRC_TECH := $(addprefix tech_cells_generic/src/,\ + cluster_clock_inverter.sv pulp_clock_mux2.sv\ + cluster_clock_gating.sv) +RTLSRC_DEBUG := ../debug_rom/debug_rom.sv +RTLSRC_DEBUG += $(addprefix ../src/,\ + dm_csrs.sv dmi_cdc.sv dmi_jtag.sv \ + dmi_jtag_tap.sv dm_mem.sv \ + dm_sba.sv dm_top.sv dm_obi_top.sv) + +RTLSRC += $(RTLSRC_RISCV) $(RTLSRC_COMMON) $(RTLSRC_TECH) $(RTLSRC_DEBUG) + +# versions for this tb +RI5CY_SHA = d049690e7867291830631db7dbeb47c92718ed9e +FPU_SHA = v0.6.1 +COMMON_SHA = 337f54a7cdfdad78b124cbdd2a627db3e0939141 +TECH_SHA = b35652608124b7ea813818b14a00ca76edd7599d + +RAM_START_ADDR = 0x1c000000 + +# TODO: clean this up +RTLSRC_VLOG_TB_TOP := $(basename $(notdir $(RTLSRC_TB_TOP))) +RTLSRC_VOPT_TB_TOP := $(addsuffix _vopt, $(RTLSRC_VLOG_TB_TOP)) + +# riscv bare metal cross compiling +RISCV ?= $(HOME)/.riscv +RV_CC = $(RISCV)/bin/riscv32-unknown-elf-gcc +RV_CFLAGS = -march=rv32imc -Os -g +RV_LDFLAGS = -nostdlib -static -T prog/link.ld +RV_LDLIBS = -lc -lm -lgcc +RV_OBJCOPY = $(RISCV)/bin/riscv32-unknown-elf-objcopy + +# assume verilator if no target chosen +.DEFAULT_GOAL := veri-run + +all: veri-run + +# vsim testbench compilation and optimization +vlib: .lib-rtl + +.lib-rtl: + $(VLIB) $(VWORK) + touch .lib-rtl + +# rebuild if we change some sourcefile +.build-rtl: .lib-rtl $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) + $(VLOG) -work $(VWORK) +incdir+$(RTLSRC_INCDIR) $(VLOG_FLAGS) \ + $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) + touch .build-rtl + +vsim-all: .opt-rtl + +.opt-rtl: .build-rtl + $(VOPT) -work $(VWORK) $(VOPT_FLAGS) $(RTLSRC_VLOG_TB_TOP) -o \ + $(RTLSRC_VOPT_TB_TOP) + touch .opt-rtl + +# vcs testbench compilation + +vcsify: $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) remote_bitbang/librbs_vcs.so + $(VCS) +vc -sverilog -race=all -ignore unique_checks -full64 \ + -timescale=1ns/1ps \ + -CC "-I$(VCS_HOME)/include -O3 -march=native" $(VCS_FLAGS) \ + $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) \ + +incdir+$(RTLSRC_INCDIR) + +vcs-clean: + rm -rf simv* *.daidir *.vpd *.db csrc ucli.key vc_hdrs.h + +# verilator testbench compilation + +# We first test if the user wants to to vcd dumping. This hacky part is required +# because we need to conditionally compile the testbench (-DVCD_TRACE) and pass +# the --trace flags to the verilator call +ifeq ($(findstring +vcd,$(VERI_FLAGS)),+vcd) +VERI_TRACE="--trace" +VERI_CFLAGS+="-DVCD_TRACE" +endif +VPATH += ../ +verilate: testbench_verilator + +# We set the RUNPATH (not RPATH, allows LD_LIBRARY_PATH to overwrite) to +# remote_bitbang and manually link against librbs_veri since putting in +# librbs_veri.so as parameter doesn't work because it searches in the build +# directory +testbench_verilator: $(RTLSRC_VERI_TB) $(RTLSRC_PKG) $(RTLSRC) \ + remote_bitbang/librbs_veri.so + $(VERILATOR) --cc --sv --exe $(VERI_TRACE) \ + --Wno-lint --Wno-UNOPTFLAT --Wno-BLKANDNBLK \ + --Wno-MODDUP +incdir+$(RTLSRC_INCDIR) --top-module \ + tb_top_verilator --Mdir $(VERI_DIR) \ + -CFLAGS "-std=gnu++11 $(VERI_CFLAGS)" $(VERI_COMPILE_FLAGS) \ + $(RTLSRC_PKG) $(RTLSRC_VERI_TB) $(RTLSRC) \ + -LDFLAGS "-L../remote_bitbang \ + -Wl,--enable-new-dtags -Wl,-rpath,remote_bitbang -lrbs_veri" \ + tb_top_verilator.cpp + cd $(VERI_DIR) && $(MAKE) -f Vtb_top_verilator.mk + cp $(VERI_DIR)/Vtb_top_verilator testbench_verilator + +verilate-clean: + if [ -d $(VERI_DIR) ]; then rm -r $(VERI_DIR); fi + rm -rf testbench_verilator + +# git dependencies +download_deps: fpnew/src/fpnew_pkg.sv $(RTLSRC_COMMON) $(RTLSRC_TECH) $(RTLSRC_RISCV) + +fpnew/src/fpnew_pkg.sv: + git clone https://github.com/pulp-platform/fpnew.git --recurse -b v0.6.1 + +$(RTLSRC_COMMON): + git clone https://github.com/pulp-platform/common_cells.git + cd common_cells/ && git checkout $(COMMON_SHA) + +$(RTLSRC_TECH): + git clone https://github.com/pulp-platform/tech_cells_generic.git + cd tech_cells_generic/ && git checkout $(TECH_SHA) + +$(RTLSRC_RISCV_PKG) $(RTLSRC_RISCV): + git clone https://github.com/openhwgroup/cv32e40p.git riscv + cd riscv/ && git checkout $(RI5CY_SHA) + +# openocd server +remote_bitbang/librbs_veri.so: INCLUDE_DIRS =./ $(VSIM_HOME)/include +remote_bitbang/librbs_veri.so: + $(MAKE) -C remote_bitbang all + mv remote_bitbang/librbs.so $@ + +remote_bitbang/librbs_vsim.so: INCLUDE_DIRS =./ $(VSIM_HOME)/include +remote_bitbang/librbs_vsim.so: + $(MAKE) -C remote_bitbang all + mv remote_bitbang/librbs.so $@ + +remote_bitbang/librbs_vcs.so: INCLUDE_DIRS =./ $(VCS_HOME)/include +remote_bitbang/librbs_vcs.so: + $(MAKE) -C remote_bitbang all + mv remote_bitbang/librbs.so $@ + +rbs-clean: + $(MAKE) -C remote_bitbang clean + rm -rf remote_bitbang/librbs_vsim.so remote_bitbang/librbs_vcs.so + +# run tb and exit +.PHONY: vsim-tb-run +vsim-tb-run: ALL_VSIM_FLAGS += -c +vsim-tb-run: vsim-all remote_bitbang/librbs_vsim.so + $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \ + $(RTLSRC_VOPT_TB_TOP) -do 'source $(VSIM_SCRIPT_BATCH); exit -f' + +# run tb and drop into interactive shell +.PHONY: vsim-tb-run-sh +vsim-tb-run: ALL_VSIM_FLAGS += -c +vsim-tb-run-sh: vsim-all remote_bitbang/librbs_vsim.so + $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \ + $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT_BATCH) + +# run tb with simulator gui +.PHONY: vsim-tb-run-gui +vsim-tb-run-gui: ALL_VSIM_FLAGS += $(VSIM_GUI_FLAGS) +vsim-tb-run-gui: vsim-all remote_bitbang/librbs_vsim.so + $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \ + $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT_GUI) + + +.PHONY: vsim-clean +vsim-clean: + if [ -d $(VWORK) ]; then rm -r $(VWORK); fi + rm -f transcript vsim.wlf vsim.dbg trace_core*.log \ + .build-rtl .opt-rtl .lib-rtl *.vcd objdump + +# compile and dump program +prog/test.elf: prog/test.c prog/crt0.S prog/syscalls.c prog/vectors.S + $(RV_CC) $(RV_CFLAGS) $(RV_CPPFLAGS) $(RV_LDFLAGS) $^ $(RV_LDLIBS) -o $@ + +prog/test.hex: prog/test.elf + $(RV_OBJCOPY) -O verilog --change-addresses -$(RAM_START_ADDR) $< $@ + +.PHONY: prog-clean +prog-clean: + rm -vrf $(addprefix prog/,test.elf test.hex) + +# run program +.PHONY: veri-run +veri-run: verilate prog/test.hex + ./testbench_verilator $(VERI_FLAGS) \ + "+firmware=prog/test.hex" + +.PHONY: vsim-run +vsim-run: vsim-all prog/test.hex +vsim-run: ALL_VSIM_FLAGS += "+firmware=prog/test.hex" +vsim-run: vsim-tb-run + +.PHONY: vsim-run-gui +vsim-run-gui: vsim-all prog/test.hex +vsim-run-gui: ALL_VSIM_FLAGS += "+firmware=prog/test.hex" +vsim-run-gui: vsim-tb-run-gui + +.PHONY: vcs-run +vcs-run: vcsify prog/test.hex + ./simv -sv_lib remote_bitbang/librbs_vcs $(SIMV_FLAGS) "+firmware=prog/test.hex" + +.PHONY: vcs-run-gui +vcs-run-gui: VCS_FLAGS+=-debug_all +vcs-run-gui: vcsify prog/test.hex + ./simv -sv_lib remote_bitbang/librbs_vcs $(SIMV_FLAGS) -gui "+firmware=prog/test.hex" + +# general targets +.PHONY: clean +clean: vsim-clean verilate-clean vcs-clean rbs-clean prog-clean + +.PHONY: distclean +distclean: clean + rm -rf common_cells/ tech_cells_generic/ fpnew/ riscv/ diff --git a/vendor/pulp_riscv_dbg/tb/README.md b/vendor/pulp_riscv_dbg/tb/README.md new file mode 100644 index 0000000000..59960eb833 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/README.md @@ -0,0 +1,51 @@ +Debug Unit plus RI5CY Testbench +===================== + +This testbench tests RI5CY together with a v0.13.1 compliant [debug +unit](https://www.github.com/pulp-platform/riscv-dbg). There are several tests +that can be run, but for now it is just `riscv test_compliance` of +[riscv-openocd](https://www.github.com/riscv/riscv-openocd) (see in +`pulpissimo.cfg`) and a not yet scripted run of gdb connecting to openocd, +loading and running a hello world program (see `prog/test.c`). + +You need `riscv-openocd`. + +Running the testbench with vsim +---------------------- +Point you environment variable `RISCV` to your RISC-V toolchain. Call `make +vsim-run` to build the testbench and the program, and run it with vsim. Use +`VSIM_FLAGS` to configure the simulator e.g. `make vsim-run VSIM_FLAGS="-gui +-debugdb"`. + +Running the testbench with vcs +---------------------- +Point you environment variable `RISCV` to your RISC-V toolchain. Call `make +vcs-run`. Use `VCS_FLAGS` and `SIMV_FLAGS` to configure vcs e.g. `make vcs-run +VCS_FLAGS="-debug_all"`. + + +Running the testbench with [verilator](https://www.veripool.org/wiki/verilator) +---------------------- +Point you environment variable `RISCV` to your RISC-V toolchain. Call `make +veri-run`. Use `VERI_FLAGS` to configure verilator e.g. `make firmware-veri-run +VERI_FLAGS="+firmware=path_to_firmware +vcd"` to use a custom firmware and dump +to a vcd file. + + +Options +---------------------- +A few plusarg options are supported. +* `+verbose` to show all memory read and writes and other miscellaneous information. + +* `+vcd` to produce a vcd file called `riscy_tb.vcd`. Verilator always produces + a vcd file called `verilator_tb.vcd`. + +* `+firmware=path_to_firmware` to load a specific firmware. It is a bit tricky to +build and link your own program. Look into the `prog` folder for an example. + +Example Run +----------------------- +1. `make veri-run` +3. (in new terminal) `export JTAG_VPI_PORT=port_name_from 1.` +2. (in new terminal) `openocd -f dm_compliance_test.cfg` +4. Now you can connect with gdb and interact with the testbench diff --git a/vendor/pulp_riscv_dbg/tb/SimJTAG.sv b/vendor/pulp_riscv_dbg/tb/SimJTAG.sv new file mode 100644 index 0000000000..7c6c11011b --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/SimJTAG.sv @@ -0,0 +1,85 @@ +// See LICENSE.SiFive for license details. +//VCS coverage exclude_file +import "DPI-C" function int jtag_tick +( + input int port, + output bit jtag_TCK, + output bit jtag_TMS, + output bit jtag_TDI, + output bit jtag_TRSTn, + + input bit jtag_TDO +); + +module SimJTAG #( + parameter TICK_DELAY = 50, + parameter PORT = 0 + )( + + input clock, + input reset, + + input enable, + input init_done, + + output jtag_TCK, + output jtag_TMS, + output jtag_TDI, + output jtag_TRSTn, + + input jtag_TDO_data, + input jtag_TDO_driven, + + output [31:0] exit + ); + + reg [31:0] tickCounterReg; + wire [31:0] tickCounterNxt; + + assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1); + + bit r_reset; + + wire [31:0] random_bits = $random; + + wire #0.1 __jtag_TDO = jtag_TDO_driven ? + jtag_TDO_data : random_bits[0]; + + bit __jtag_TCK; + bit __jtag_TMS; + bit __jtag_TDI; + bit __jtag_TRSTn; + int __exit; + + reg init_done_sticky; + + assign #0.1 jtag_TCK = __jtag_TCK; + assign #0.1 jtag_TMS = __jtag_TMS; + assign #0.1 jtag_TDI = __jtag_TDI; + assign #0.1 jtag_TRSTn = __jtag_TRSTn; + + assign #0.1 exit = __exit; + + always @(posedge clock) begin + r_reset <= reset; + if (reset || r_reset) begin + __exit = 0; + tickCounterReg <= TICK_DELAY; + init_done_sticky <= 1'b0; + end else begin + init_done_sticky <= init_done | init_done_sticky; + if (enable && init_done_sticky) begin + tickCounterReg <= tickCounterNxt; + if (tickCounterReg == 0) begin + __exit = jtag_tick(PORT, + __jtag_TCK, + __jtag_TMS, + __jtag_TDI, + __jtag_TRSTn, + __jtag_TDO); + end + end // if (enable && init_done_sticky) + end // else: !if(reset || r_reset) + end // always @ (posedge clock) + +endmodule diff --git a/vendor/pulp_riscv_dbg/tb/boot_rom.sv b/vendor/pulp_riscv_dbg/tb/boot_rom.sv new file mode 100644 index 0000000000..3610af4414 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/boot_rom.sv @@ -0,0 +1,39 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Author: Robert Balas +// Description: Bootrom for firmware booting + +module boot_rom ( + input logic clk_i, + input logic req_i, + input logic [31:0] addr_i, + output logic [31:0] rdata_o +); + localparam int RomSize = 2; + localparam logic [31:0] entry_addr = 32'h1c00_0080; + + const logic [RomSize-1:0][31:0] mem = { + dm_tb_pkg::jalr(5'h0, 5'h1, entry_addr[11:0]), + dm_tb_pkg::lui(5'h1, entry_addr[31:12]) + }; + + logic [$clog2(RomSize)-1:0] addr_q; + + + assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0; + + always_ff @(posedge clk_i) begin + if (req_i) begin + addr_q <= addr_i[$clog2(RomSize)-1+3:2]; + end + end + +endmodule diff --git a/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg b/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg new file mode 100644 index 0000000000..96c7ca6de5 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg @@ -0,0 +1,31 @@ +debug_level 4 +adapter_khz 10000 + +interface remote_bitbang +remote_bitbang_host localhost + +remote_bitbang_port 9999 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x249511C3 + +foreach t [jtag names] { + puts [format "TAP: %s\n" $t] +} + +set _TARGETNAME $_CHIPNAME.cpu +#target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x3e0 +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv + +riscv set_reset_timeout_sec 2000 +riscv set_command_timeout_sec 2000 + +# prefer to use sba for system bus access +riscv set_prefer_sba on + +# dump jtag chain +scan_chain + +init +riscv test_compliance +shutdown diff --git a/vendor/pulp_riscv_dbg/tb/dm_debug.cfg b/vendor/pulp_riscv_dbg/tb/dm_debug.cfg new file mode 100644 index 0000000000..1ac2555aa3 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/dm_debug.cfg @@ -0,0 +1,32 @@ +debug_level 4 +adapter_khz 10000 + +interface remote_bitbang +remote_bitbang_host localhost + +remote_bitbang_port $::env(JTAG_VPI_PORT) + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x249511C3 + +foreach t [jtag names] { + puts [format "TAP: %s\n" $t] +} + +set _TARGETNAME $_CHIPNAME.cpu +#target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x3e0 +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv + +riscv set_reset_timeout_sec 2000 +riscv set_command_timeout_sec 2000 + +# prefer to use sba for system bus access +riscv set_prefer_sba on + +# dump jtag chain +scan_chain + +init + +halt +echo "Ready for Remote Connections" diff --git a/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv b/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv new file mode 100644 index 0000000000..e0c56749be --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv @@ -0,0 +1,58 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Contributor: Robert Balas + + +package dm_tb_pkg; + + // PULPissimo-like memory map + typedef enum logic [31:0] { + ROM_BASE = 32'h1A00_0000, + FLL_BASE = 32'h1A10_0000, + GPIO_BASE = 32'h1A10_1000, + UDMA_BASE = 32'h1A10_2000, + CNTRL_BASE = 32'h1A10_4000, + ADVTIMER_BASE = 32'h1A10_5000, + EVENT_BASE = 32'h1A10_6000, + TIMER_BASE = 32'h1A10_B000, + HWPE_BASE = 32'h1A10_C000, + STDOUT_BASE = 32'h1A10_F000, + DEBUG_BASE = 32'h1A11_0000, + SRAM_BASE = 32'h1C00_0000 + } mmap_base_t; + + localparam logic [31:0] ROM_LEN = 32'h0010_0000; + localparam logic [31:0] FLL_LEN = 32'h0000_1000; + localparam logic [31:0] GPIO_LEN = 32'h0000_1000; + localparam logic [31:0] UDMA_LEN = 32'h0000_2000; + localparam logic [31:0] CNTRL_LEN = 32'h0000_1000; + localparam logic [31:0] ADVTIMER_LEN = 32'h0000_1000; + localparam logic [31:0] EVENT_LEN = 32'h0000_5000; + localparam logic [31:0] TIMER_LEN = 32'h0000_1000; + localparam logic [31:0] HWPE_LEN = 32'h0000_3000; + localparam logic [31:0] STDOUT_LEN = 32'h0000_1000; + localparam logic [31:0] DEBUG_LEN = 32'h0000_1000; + localparam logic [31:0] SRAM_LEN = 32'h000f_C000; + + // helper functions + function automatic logic [31:0] jal (logic[4:0] rd, logic [20:0] imm); + return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f}; + endfunction + + function automatic logic [31:0] jalr (logic[4:0] rd, logic[4:0] rs1, logic [11:0] offset); + return {offset[11:0], rs1, 3'b0, rd, 7'h67}; + endfunction + + function automatic logic [31:0] lui (logic[4:0] rd, logic [19:0] uimm); + return {uimm, rd, 7'b0110111}; + endfunction + +endpackage // riscv_tb_pkg diff --git a/vendor/pulp_riscv_dbg/tb/dp_ram.sv b/vendor/pulp_riscv_dbg/tb/dp_ram.sv new file mode 100644 index 0000000000..f7f224b9c8 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/dp_ram.sv @@ -0,0 +1,84 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright 2017 Embecosm Limited +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +module dp_ram #( + parameter int unsigned ADDR_WIDTH = 8, + parameter int unsigned INSTR_RDATA_WIDTH = 128 +) ( + input logic clk_i, + + input logic en_a_i, + input logic [ADDR_WIDTH-1:0] addr_a_i, + input logic [31:0] wdata_a_i, + output logic [INSTR_RDATA_WIDTH-1:0] rdata_a_o, + input logic we_a_i, + input logic [3:0] be_a_i, + + input logic en_b_i, + input logic [ADDR_WIDTH-1:0] addr_b_i, + input logic [31:0] wdata_b_i, + output logic [31:0] rdata_b_o, + input logic we_b_i, + input logic [3:0] be_b_i +); + + localparam bytes = 2**ADDR_WIDTH; + + logic [7:0] mem[bytes]; + logic [ADDR_WIDTH-1:0] addr_a_int; + logic [ADDR_WIDTH-1:0] addr_b_int; + + always_comb addr_a_int = {addr_a_i[ADDR_WIDTH-1:2], 2'b0}; + always_comb addr_b_int = {addr_b_i[ADDR_WIDTH-1:2], 2'b0}; + + always @(posedge clk_i) begin + for (int i = 0; i < INSTR_RDATA_WIDTH/8; i++) begin + rdata_a_o[(i*8)+: 8] <= mem[addr_a_int + i]; + end + + /* addr_b_i is the actual memory address referenced */ + if (en_b_i) begin + /* handle writes */ + if (we_b_i) begin + if (be_b_i[0]) mem[addr_b_int ] <= wdata_b_i[ 0+:8]; + if (be_b_i[1]) mem[addr_b_int + 1] <= wdata_b_i[ 8+:8]; + if (be_b_i[2]) mem[addr_b_int + 2] <= wdata_b_i[16+:8]; + if (be_b_i[3]) mem[addr_b_int + 3] <= wdata_b_i[24+:8]; + end + /* handle reads */ + else begin + if ($test$plusargs("verbose")) + $display("read addr=0x%08x: data=0x%08x", addr_b_int, + {mem[addr_b_int + 3], mem[addr_b_int + 2], + mem[addr_b_int + 1], mem[addr_b_int + 0]}); + + rdata_b_o[ 7: 0] <= mem[addr_b_int ]; + rdata_b_o[15: 8] <= mem[addr_b_int + 1]; + rdata_b_o[23:16] <= mem[addr_b_int + 2]; + rdata_b_o[31:24] <= mem[addr_b_int + 3]; + end + end + end + + export "DPI-C" function read_byte; + export "DPI-C" task write_byte; + + function int read_byte(input logic [ADDR_WIDTH-1:0] byte_addr); + read_byte = mem[byte_addr]; + endfunction + + task write_byte(input integer byte_addr, logic [7:0] val, output logic [7:0] other); + mem[byte_addr] = val; + other = mem[byte_addr]; + + endtask + +endmodule // dp_ram diff --git a/vendor/pulp_riscv_dbg/tb/mm_ram.sv b/vendor/pulp_riscv_dbg/tb/mm_ram.sv new file mode 100644 index 0000000000..887baa63f5 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/mm_ram.sv @@ -0,0 +1,571 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// RAM and MM wrapper for RI5CY +// Contributor: Robert Balas +// +// This maps the dp_ram module to the instruction and data ports of the RI5CY +// processor core and some pseudo peripherals + +module mm_ram #( + parameter int unsigned RAM_ADDR_WIDTH = 16, + parameter int unsigned INSTR_RDATA_WIDTH = 32, + parameter bit JTAG_BOOT = 1 +) ( + input logic clk_i, + input logic rst_ni, + + input logic instr_req_i, + input logic [31:0] instr_addr_i, + output logic [INSTR_RDATA_WIDTH-1:0] instr_rdata_o, + output logic instr_rvalid_o, + output logic instr_gnt_o, + + input logic data_req_i, + input logic [31:0] data_addr_i, + input logic data_we_i, + input logic [3:0] data_be_i, + input logic [31:0] data_wdata_i, + output logic [31:0] data_rdata_o, + output logic data_rvalid_o, + output logic data_gnt_o, + + input logic sb_req_i, + input logic [31:0] sb_addr_i, + input logic sb_we_i, + input logic [3:0] sb_be_i, + input logic [31:0] sb_wdata_i, + output logic [31:0] sb_rdata_o, + output logic sb_rvalid_o, + output logic sb_gnt_o, + + output logic dm_req_o, + output logic [31:0] dm_addr_o, + output logic dm_we_o, + output logic [3:0] dm_be_o, + output logic [31:0] dm_wdata_o, + input logic [31:0] dm_rdata_i, + input logic dm_rvalid_i, + input logic dm_gnt_i, + + + input logic [4:0] irq_id_i, + input logic irq_ack_i, + output logic [4:0] irq_id_o, + output logic irq_o, + + output logic tests_passed_o, + output logic tests_failed_o +); + + import dm_tb_pkg::*; + + localparam int TIMER_IRQ_ID = 3; + + // mux for read and writes + enum logic [2:0]{RAM, DEBUG, ROM, UNMAP, IDLE_READ} select_rdata_d, select_rdata_q; + + enum logic [1:0]{SB, CORE, IDLE_WRITE} select_wdata_d, select_wdata_q; + + logic data_rvalid_d, data_rvalid_q; + logic sb_rvalid_d, sb_rvalid_q; + logic instr_rvalid_d, instr_rvalid_q; + + // TODO: oof + logic [31:0] data_addr_aligned; + + // signals to ram + logic ram_data_req; + logic [RAM_ADDR_WIDTH-1:0] ram_data_addr; + logic [31:0] ram_data_wdata; + logic [31:0] ram_data_rdata; + logic ram_data_we; + logic [3:0] ram_data_be; + + // signals to rom + logic rom_req; + logic [31:0] rom_addr; + logic [31:0] rom_rdata; + + // signals to read access debug unit + logic dm_req; + logic [31:0] dm_addr; + logic dm_we; + logic [3:0] dm_be; + logic [31:0] dm_wdata; + logic [31:0] dm_rdata; + logic dm_rvalid; + logic dm_gnt; + + logic ram_instr_req; + logic [31:0] ram_instr_addr; + logic [INSTR_RDATA_WIDTH-1:0] ram_instr_rdata; + + + + + // signals to print peripheral + logic [31:0] print_wdata; + logic print_valid; + + // signals to timer + logic [31:0] timer_irq_mask_q; + logic [31:0] timer_cnt_q; + logic irq_q; + logic timer_reg_valid; + logic timer_val_valid; + logic [31:0] timer_wdata; + + + // uhh, align? + always_comb data_addr_aligned = {data_addr_i[31:2], 2'b0}; + + // Handle system bus, core data accesses and instr access to rom, ram and + // debug unit. Someone make a for gen loop here. + always_comb begin + sb_gnt_o = '0; + data_gnt_o = '0; + instr_gnt_o = '0; + + ram_data_req = '0; + ram_data_addr = '0; + ram_data_wdata = '0; + ram_data_we = '0; + ram_data_be = '0; + + ram_instr_req = '0; + ram_instr_addr = '0; + + dm_req = '0; + dm_addr = '0; + dm_we = '0; + dm_be = '0; + dm_wdata = '0; + + rom_req = '0; + rom_addr = '0; + + print_wdata = '0; + print_valid = '0; + + select_rdata_d = IDLE_READ; + select_wdata_d = IDLE_WRITE; + + data_rvalid_d = '0; + sb_rvalid_d = '0; + instr_rvalid_d = '0; + + tests_passed_o = '0; + tests_failed_o = '0; + + + // memory map: + // the ram is mapped from 0 to SRAM_LEN and SRAM_BASE to SRAM_BASE + SRAM_LEN + // this mirroring is the same as in pulpissimo + + // instruction data reads to ram can always go + if (instr_req_i && ((instr_addr_i >= SRAM_BASE && instr_addr_i < SRAM_BASE + SRAM_LEN) || + (instr_addr_i >= 0 && instr_addr_i < SRAM_LEN))) begin + instr_gnt_o = '1; + instr_rvalid_d = '1; + ram_instr_req = '1; + ram_instr_addr = instr_addr_i; + + end + + + // priority to sb access over data access + if (sb_req_i) begin + sb_gnt_o = '1; + sb_rvalid_d = '1; + + if (sb_we_i) begin // handle writes + if (sb_addr_i >= ROM_BASE && sb_addr_i < ROM_BASE + ROM_LEN) begin + end else if (sb_addr_i >= FLL_BASE && sb_addr_i < FLL_BASE + FLL_LEN) begin + end else if (sb_addr_i >= GPIO_BASE && sb_addr_i < GPIO_BASE + GPIO_LEN) begin + end else if (sb_addr_i >= UDMA_BASE && sb_addr_i < UDMA_BASE + UDMA_LEN) begin + end else if (sb_addr_i >= CNTRL_BASE && sb_addr_i < CNTRL_BASE + CNTRL_LEN) begin + end else if (sb_addr_i >= ADVTIMER_BASE && sb_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin + end else if (sb_addr_i >= EVENT_BASE && sb_addr_i < EVENT_BASE + EVENT_LEN) begin + end else if (sb_addr_i >= TIMER_BASE && sb_addr_i < TIMER_BASE + TIMER_LEN) begin + end else if (sb_addr_i >= HWPE_BASE && sb_addr_i < HWPE_BASE + HWPE_LEN) begin + end else if (sb_addr_i >= STDOUT_BASE && sb_addr_i < STDOUT_BASE + STDOUT_LEN) begin + select_wdata_d = SB; + print_wdata = sb_wdata_i; + print_valid = '1; + + end else if (sb_addr_i >= DEBUG_BASE && sb_addr_i < DEBUG_BASE + DEBUG_LEN) begin + end else if ((sb_addr_i >= SRAM_BASE && sb_addr_i < SRAM_BASE + SRAM_LEN) || + (sb_addr_i >= 0 && sb_addr_i < SRAM_LEN)) begin + select_wdata_d = SB; + ram_data_req = sb_req_i; + ram_data_addr = sb_addr_i[RAM_ADDR_WIDTH-1:0]; // just clip higher bits + ram_data_wdata = sb_wdata_i; + ram_data_we = sb_we_i; + ram_data_be = sb_be_i; + + end else begin + $error("Writing to unmapped memory at %x", sb_addr_i); + end + + end else begin // handle reads + if (sb_addr_i >= ROM_BASE && sb_addr_i < ROM_BASE + ROM_LEN) begin + select_rdata_d = ROM; + + end else if (sb_addr_i >= FLL_BASE && sb_addr_i < FLL_BASE + FLL_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= GPIO_BASE && sb_addr_i < GPIO_BASE + GPIO_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= UDMA_BASE && sb_addr_i < UDMA_BASE + UDMA_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= CNTRL_BASE && sb_addr_i < CNTRL_BASE + CNTRL_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= ADVTIMER_BASE && sb_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= EVENT_BASE && sb_addr_i < EVENT_BASE + EVENT_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= TIMER_BASE && sb_addr_i < TIMER_BASE + TIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= HWPE_BASE && sb_addr_i < HWPE_BASE + HWPE_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= STDOUT_BASE && sb_addr_i < STDOUT_BASE + STDOUT_LEN) begin + select_rdata_d = UNMAP; + end else if (sb_addr_i >= DEBUG_BASE && sb_addr_i < DEBUG_BASE + DEBUG_LEN) begin + select_rdata_d = UNMAP; + end else if ((sb_addr_i >= SRAM_BASE && sb_addr_i < SRAM_BASE + SRAM_LEN) || + (sb_addr_i >= 0 && sb_addr_i < SRAM_LEN)) begin + select_rdata_d = RAM; + ram_data_req = sb_req_i; + ram_data_addr = sb_addr_i[RAM_ADDR_WIDTH-1:0]; + ram_data_wdata = sb_wdata_i; + ram_data_we = sb_we_i; + ram_data_be = sb_be_i; + + end else begin + select_rdata_d = UNMAP; + end + + end + end else if (data_req_i) begin + data_gnt_o = '1; + data_rvalid_d = '1; + + if (data_we_i) begin // handle writes + if (data_addr_i >= ROM_BASE && data_addr_i < ROM_BASE + ROM_LEN) begin + end else if (data_addr_i >= FLL_BASE && data_addr_i < FLL_BASE + FLL_LEN) begin + end else if (data_addr_i >= GPIO_BASE && data_addr_i < GPIO_BASE + GPIO_LEN) begin + end else if (data_addr_i >= UDMA_BASE && data_addr_i < UDMA_BASE + UDMA_LEN) begin + end else if (data_addr_i >= CNTRL_BASE && data_addr_i < CNTRL_BASE + CNTRL_LEN) begin + if(data_wdata_i === 32'hF00D) + tests_passed_o = 1'b1; + else + tests_failed_o = 1'b1; + + end else if (data_addr_i >= ADVTIMER_BASE && data_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin + end else if (data_addr_i >= EVENT_BASE && data_addr_i < EVENT_BASE + EVENT_LEN) begin + end else if (data_addr_i >= TIMER_BASE && data_addr_i < TIMER_BASE + TIMER_LEN) begin + end else if (data_addr_i >= HWPE_BASE && data_addr_i < HWPE_BASE + HWPE_LEN) begin + end else if (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN) begin + select_wdata_d = CORE; + print_wdata = data_wdata_i; + print_valid = '1; + + end else if (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN) begin + select_wdata_d = CORE; + dm_req = data_req_i; + dm_addr = data_addr_i; + dm_we = data_we_i; + dm_be = data_be_i; + dm_wdata = data_wdata_i; + + end else if ((data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN) || + (data_addr_i >= 0 && data_addr_i < SRAM_LEN)) begin + select_wdata_d = CORE; + ram_data_req = data_req_i; + ram_data_addr = data_addr_i[RAM_ADDR_WIDTH-1:0]; // just clip higher bits + ram_data_wdata = data_wdata_i; + ram_data_we = data_we_i; + ram_data_be = data_be_i; + + end else begin + end + + end else begin // handle reads + if (data_addr_i >= ROM_BASE && data_addr_i < ROM_BASE + ROM_LEN) begin + select_rdata_d = ROM; + rom_req = data_req_i; + rom_addr = data_addr_i - ROM_BASE; + // TODO data_be_i + + end else if (data_addr_i >= FLL_BASE && data_addr_i < FLL_BASE + FLL_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= GPIO_BASE && data_addr_i < GPIO_BASE + GPIO_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= UDMA_BASE && data_addr_i < UDMA_BASE + UDMA_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= CNTRL_BASE && data_addr_i < CNTRL_BASE + CNTRL_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= ADVTIMER_BASE && data_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= EVENT_BASE && data_addr_i < EVENT_BASE + EVENT_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= TIMER_BASE && data_addr_i < TIMER_BASE + TIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= HWPE_BASE && data_addr_i < HWPE_BASE + HWPE_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN) begin + select_rdata_d = UNMAP; + end else if (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN) begin + select_rdata_d = DEBUG; + dm_req = data_req_i; + dm_addr = data_addr_i; + dm_we = data_we_i; + dm_be = data_be_i; + + end else if ((data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN) || + (data_addr_i >= 0 && data_addr_i < SRAM_LEN)) begin + select_rdata_d = RAM; + ram_data_req = data_req_i; + ram_data_addr = data_addr_i[RAM_ADDR_WIDTH-1:0]; + ram_data_we = data_we_i; + ram_data_be = data_be_i; + + end else begin + select_rdata_d = UNMAP; + end + + end + end else if (instr_req_i) begin + instr_gnt_o = '1; + instr_rvalid_d = '1; + // handle reads + if (instr_addr_i >= ROM_BASE && instr_addr_i < ROM_BASE + ROM_LEN) begin + select_rdata_d = ROM; + rom_req = instr_req_i; + rom_addr = instr_addr_i - ROM_BASE - 32'h80; + + end else if (instr_addr_i >= FLL_BASE && instr_addr_i < FLL_BASE + FLL_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= GPIO_BASE && instr_addr_i < GPIO_BASE + GPIO_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= UDMA_BASE && instr_addr_i < UDMA_BASE + UDMA_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= CNTRL_BASE && instr_addr_i < CNTRL_BASE + CNTRL_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= ADVTIMER_BASE && instr_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= EVENT_BASE && instr_addr_i < EVENT_BASE + EVENT_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= TIMER_BASE && instr_addr_i < TIMER_BASE + TIMER_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= HWPE_BASE && instr_addr_i < HWPE_BASE + HWPE_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= STDOUT_BASE && instr_addr_i < STDOUT_BASE + STDOUT_LEN) begin + select_rdata_d = UNMAP; + end else if (instr_addr_i >= DEBUG_BASE && instr_addr_i < DEBUG_BASE + DEBUG_LEN) begin + select_rdata_d = DEBUG; + dm_req = '1; + dm_addr = instr_addr_i; + dm_we = '0; + dm_be = 4'b1111; + + end else if ((instr_addr_i >= SRAM_BASE && instr_addr_i < SRAM_BASE + SRAM_LEN) || + (instr_addr_i >=0 && instr_addr_i < SRAM_LEN)) begin + // handled separately + select_rdata_d = RAM; + end else begin + select_rdata_d = UNMAP; + end + end + end + + +`ifndef VERILATOR + // make sure we don't access any unmapped memory + + out_of_bounds_write: assert property + (@(posedge clk_i) disable iff (!rst_ni) + (data_req_i && data_gnt_o && data_we_i |-> + (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN) + || (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN) + || (data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN) + || (data_addr_i >= 0 && data_addr_i < SRAM_LEN))) + else $error("out of bounds write to %08x with %08x", + data_addr_i, data_wdata_i); + + out_of_bounds_read: assert property + (@(posedge clk_i) disable iff (!rst_ni) + (select_rdata_q != UNMAP)) + else $error("out of bounds read"); +`endif + + // make sure we select the proper read data + always_comb begin: read_mux_sb_data_instr + data_rdata_o = '0; + sb_rdata_o = '0; + instr_rdata_o = ram_instr_rdata; + + if(select_rdata_q == RAM) begin + data_rdata_o = ram_data_rdata; + sb_rdata_o = ram_data_rdata; + + end else if (select_rdata_q == DEBUG) begin + data_rdata_o = dm_rdata; + sb_rdata_o = dm_rdata; //TODO: not possible + instr_rdata_o = dm_rdata; + + end else if (select_rdata_q == ROM) begin + // either we got into a loop for jtag booting or we jumpt to the l2 + // boot address (1c00_0080 === 0000_0080) to run a firmware directly + if (JTAG_BOOT) begin + data_rdata_o = 32'b00000000000000000000000001101111; //while(true) + sb_rdata_o = 32'b00000000000000000000000001101111; + instr_rdata_o = 32'b00000000000000000000000001101111; + end else begin + data_rdata_o = rom_rdata; //jal(5'b0, 21'h80); // jump to 0x0 + 0x80 + sb_rdata_o = rom_rdata; //jal(5'b0, 21'h80); + instr_rdata_o = rom_rdata; //jal(5'b0, 21'h80); + end + + end else if (select_rdata_q == IDLE_READ) begin + end + end + + // print to stdout pseudo peripheral + always_ff @(posedge clk_i, negedge rst_ni) begin: print_peripheral + if(print_valid) begin + if ($test$plusargs("verbose")) begin + if (32 <= print_wdata && print_wdata < 128) + $display("OUT: '%c'", print_wdata[7:0]); + else + $display("OUT: %3d", print_wdata); + + end else begin + $write("%c", print_wdata[7:0]); +`ifndef VERILATOR + $fflush(); +`endif + end + end + end + + assign irq_id_o = TIMER_IRQ_ID; + assign irq_o = irq_q; + + // Control timer. We need one to have some kind of timeout for tests that + // get stuck in some loop. The riscv-tests also mandate that. Enable timer + // interrupt by writing 1 to timer_irq_mask_q. Write initial value to + // timer_cnt_q which gets counted down each cycle. When it transitions from + // 1 to 0, and interrupt request (irq_q) is made (masked by timer_irq_mask_q). + always_ff @(posedge clk_i, negedge rst_ni) begin: tb_timer + if(~rst_ni) begin + timer_irq_mask_q <= '0; + timer_cnt_q <= '0; + irq_q <= '0; + + end else begin + // set timer irq mask + if(timer_reg_valid) begin + timer_irq_mask_q <= timer_wdata; + + // write timer value + end else if(timer_val_valid) begin + timer_cnt_q <= timer_wdata; + + end else begin + if(timer_cnt_q > 0) + timer_cnt_q <= timer_cnt_q - 1; + + if(timer_cnt_q == 1) + irq_q <= 1'b1 && timer_irq_mask_q[TIMER_IRQ_ID]; + + if(irq_ack_i == 1'b1 && irq_id_i == TIMER_IRQ_ID) + irq_q <= '0; + + end + end + end + + // show writes if requested + always_ff @(posedge clk_i, negedge rst_ni) begin: verbose_writes + if ($test$plusargs("verbose") && data_req_i && data_we_i) + $display("write addr=0x%08x: data=0x%08x", + data_addr_i, data_wdata_i); + end + + // debug rom for booting directly to the firmware + boot_rom boot_rom_i ( + .clk_i ( clk_i ), + .req_i ( rom_req ), + .addr_i ( rom_addr ), + .rdata_o( rom_rdata ) + ); + + + // instantiate the ram + dp_ram #( + .ADDR_WIDTH (RAM_ADDR_WIDTH), + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH) + ) dp_ram_i ( + .clk_i ( clk_i ), + + .en_a_i ( ram_instr_req ), + .addr_a_i ( ram_instr_addr[RAM_ADDR_WIDTH-1:0] ), + .wdata_a_i ( '0 ), // Not writing so ignored + .rdata_a_o ( ram_instr_rdata ), + .we_a_i ( '0 ), + .be_a_i ( 4'b1111 ), // Always want 32-bits + + .en_b_i ( ram_data_req ), + .addr_b_i ( ram_data_addr ), + .wdata_b_i ( ram_data_wdata ), + .rdata_b_o ( ram_data_rdata ), + .we_b_i ( ram_data_we ), + .be_b_i ( ram_data_be ) + ); + + // do the handshacking stuff by assuming we always react in one cycle + assign dm_req_o = dm_req; + assign dm_addr_o = dm_addr; + assign dm_we_o = dm_we; + assign dm_be_o = dm_be; + assign dm_wdata_o = dm_wdata; + assign dm_rdata = dm_rdata_i; + assign dm_rvalid = dm_rvalid_i; // TODO: we dont' care about this + assign dm_gnt = dm_gnt_i; // TODO: we don't care about this + + + // sb and core rvalid + assign data_rvalid_o = data_rvalid_q; + assign sb_rvalid_o = sb_rvalid_q; + assign instr_rvalid_o = instr_rvalid_q; + + + always_ff @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + select_rdata_q <= IDLE_READ; + select_wdata_q <= IDLE_WRITE; + + data_rvalid_q <= '0; + sb_rvalid_q <= '0; + instr_rvalid_q <= '0; + + end else begin + select_rdata_q <= select_rdata_d; + select_wdata_q <= select_wdata_d; + + data_rvalid_q <= data_rvalid_d; + sb_rvalid_q <= sb_rvalid_d; + instr_rvalid_q <= instr_rvalid_d; + + end + end + +endmodule // ram diff --git a/vendor/pulp_riscv_dbg/tb/prog/crt0.S b/vendor/pulp_riscv_dbg/tb/prog/crt0.S new file mode 100644 index 0000000000..5f8d2b2d6d --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/prog/crt0.S @@ -0,0 +1,66 @@ +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + * Copyright (c) 2019 ETH Zürich and University of Bologna + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the FreeBSD License. This program is distributed in the hope that + * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + * including the implied warranties of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. A copy of this license is available at + * http://www.opensource.org/licenses. + */ + +/* Entry point for bare metal programs */ +.section .text.start +.global _start +.type _start, @function + +_start: +/* initialize global pointer */ +.option push +.option norelax +1: auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) +.option pop + +/* initialize stack pointer */ + la sp, _sp + +/* set vector table address */ + la a0, __vector_start + csrw mtvec, a0 +/* set vector table address for CLINTx */ + la a0, __vector_x_start + csrw 0x307, a0 + +/* clear the bss segment */ + la a0, __bss_start + la a2, __bss_end + sub a2, a2, a0 + li a1, 0 + call memset + +/* new-style constructors and destructors */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +/* call main */ + lw a0, 0(sp) /* a0 = argc */ + addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ + li a2, 0 /* a2 = envp = NULL */ + call main + tail exit + +.size _start, .-_start + +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: +_fini: + /* These don't have to do anything since we use init_array/fini_array. Prevent + missing symbol error */ + ret +.size _init, .-_init +.size _fini, .-_fini diff --git a/vendor/pulp_riscv_dbg/tb/prog/link.ld b/vendor/pulp_riscv_dbg/tb/prog/link.ld new file mode 100644 index 0000000000..e8fb802592 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/prog/link.ld @@ -0,0 +1,385 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +/* Copyright (C) 2014-2018 Free Software Foundation, Inc. + Copyright (C) 2019 ETH Zürich and University of Bologna + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ + +/* This linker script is derived from the default linker script of the RISC-V + gcc compiler. We have made a few changes to make it suitable for linking bare + metal programs. These are mostly removing dynamic linking related sections and + putting sections into our memory regions. */ + +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", + "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) + +MEMORY +{ + /* the memory in the testbench is 1024k in size; + * set LENGTH=1008k and leave at least 16k for stack */ + ram (rwxai) : ORIGIN = 0x1c000000, LENGTH = 0x000fc000 +} + +SECTIONS +{ + /* we want a fixed entry point */ + PROVIDE(__boot_address = ORIGIN(ram) + 0x180); + + /* stack and heap related settings */ + __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; + PROVIDE(__stack_size = __stack_size); + __heap_size = DEFINED(__heap_size) ? __heap_size : 0x400; + + + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS; + + + /* We don't do any dynamic linking so we remove everything related to it */ +/* + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rela.plt : + { + *(.rela.plt) + } +*/ + + /* interrupt vectors */ + .vectors (ORIGIN(ram)): + { + PROVIDE(__vector_start = .); + KEEP(*(.vectors)); + } >ram + + /* interrupt vectors x*/ + .vectors_x (ORIGIN(ram) + 0x100): + { + PROVIDE(__vector_x_start = .); + KEEP(*(.vectors_x)); + } >ram + + /* crt0 init code */ + .init (__boot_address): + { + KEEP (*(SORT_NONE(.init))) + KEEP (*(.text.start)) + } >ram + + + /* More dynamic linking sections */ +/* + .plt : { *(.plt) } + .iplt : { *(.iplt) } +*/ + + + /* the bulk of the program: main, libc, functions etc. */ + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } >ram + + + /* not used by RISC-V*/ + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + + /* read-only sections */ + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } >ram + .rodata1 : + { + *(.rodata1) + } >ram + + + /* second level sbss and sdata, I don't think we need this */ + /* .sdata2 : {*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)} */ + /* .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } */ + + + /* gcc language agnostic exception related sections (try-catch-finally) */ + .eh_frame_hdr : + { + *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) + } >ram + .eh_frame : ONLY_IF_RO + { + KEEP (*(.eh_frame)) *(.eh_frame.*) + } >ram + .gcc_except_table : ONLY_IF_RO + { + *(.gcc_except_table .gcc_except_table.*) + } >ram + .gnu_extab : ONLY_IF_RO + { + *(.gnu_extab*) + } >ram + /* These sections are generated by the Sun/Oracle C++ compiler. */ + /* + .exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } + */ + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + + + /* Exception handling */ + .eh_frame : ONLY_IF_RW + { + KEEP (*(.eh_frame)) *(.eh_frame.*) + } >ram + .gnu_extab : ONLY_IF_RW + { + *(.gnu_extab) + } >ram + .gcc_except_table : ONLY_IF_RW + { + *(.gcc_except_table .gcc_except_table.*) + } >ram + .exception_ranges : ONLY_IF_RW + { + *(.exception_ranges .exception_ranges*) + } >ram + + + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } >ram + .tbss : + { + *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) + } >ram + + + /* initialization and termination routines */ + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram + + /* .jcr : { KEEP (*(.jcr)) } */ + /* .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } */ + /* .dynamic : { *(.dynamic) } */ + . = DATA_SEGMENT_RELRO_END (0, .); + + + /* data sections for initalized data */ + .data : + { + __DATA_BEGIN__ = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } >ram + .data1 : + { + *(.data1) + } > ram + + /* no dynamic linking, no object tables required */ + /* .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } */ + + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + } >ram + _edata = .; PROVIDE (edata = .); + . = .; + + + /* zero initialized sections */ + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } >ram + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } >ram + . = ALIGN(32 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(32 / 8); + __BSS_END__ = .; + __bss_end = .; + + /* The compiler uses this to access data in the .sdata, .data, .sbss and .bss + sections with fewer instructions (relaxation). This reduces code size. */ + __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, + MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + + + /* heap: we should consider putting this to the bottom of the address space */ + .heap : + { + PROVIDE(__heap_start = .); + . = __heap_size; + PROVIDE(__heap_end = .); + } >ram + + + /* stack: we should consider putting this further to the top of the address + space */ + .stack : ALIGN(16) /* this is a requirement of the ABI(?) */ + { + PROVIDE(__stack_start = .); + . = __stack_size; + PROVIDE(_sp = .); + PROVIDE(__stack_end = .); + } >ram + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/vendor/pulp_riscv_dbg/tb/prog/syscalls.c b/vendor/pulp_riscv_dbg/tb/prog/syscalls.c new file mode 100644 index 0000000000..31f0159e22 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/prog/syscalls.c @@ -0,0 +1,270 @@ +/* An extremely minimalist syscalls.c for newlib + * Based on riscv newlib libgloss/riscv/sys_*.c + * + * Copyright 2019 Clifford Wolf + * Copyright 2019 ETH Zürich and University of Bologna + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#undef errno +extern int errno; + +/* write to this reg for outputting strings */ +#define STDOUT_REG 0x10000000 +/* write test result of program to this reg */ +#define RESULT_REG 0x20000000 +/* write exit value of program to this reg */ +#define EXIT_REG 0x20000004 + +#define STDOUT_FILENO 1 + +/* It turns out that older newlib versions use different symbol names which goes + * against newlib recommendations. Anyway this is fixed in later version. + */ +#if __NEWLIB__ <= 2 && __NEWLIB_MINOR__ <= 5 +# define _sbrk sbrk +# define _write write +# define _close close +# define _lseek lseek +# define _read read +# define _fstat fstat +# define _isatty isatty +#endif + +void unimplemented_syscall() +{ + const char *p = "Unimplemented system call called!\n"; + while (*p) + *(volatile int *)STDOUT_REG = *(p++); +} + +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + errno = ENOSYS; + return -1; +} + +int _access(const char *file, int mode) +{ + errno = ENOSYS; + return -1; +} + +int _chdir(const char *path) +{ + errno = ENOSYS; + return -1; +} + +int _chmod(const char *path, mode_t mode) +{ + errno = ENOSYS; + return -1; +} + +int _chown(const char *path, uid_t owner, gid_t group) +{ + errno = ENOSYS; + return -1; +} + +int _close(int file) +{ + return -1; +} + +int _execve(const char *name, char *const argv[], char *const env[]) +{ + errno = ENOMEM; + return -1; +} + +void _exit(int exit_status) +{ + *(volatile int *)EXIT_REG = exit_status; + asm volatile("wfi"); +} + +int _faccessat(int dirfd, const char *file, int mode, int flags) +{ + errno = ENOSYS; + return -1; +} + +int _fork(void) +{ + errno = EAGAIN; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; + // errno = -ENOSYS; + // return -1; +} + +int _fstatat(int dirfd, const char *file, struct stat *st, int flags) +{ + errno = ENOSYS; + return -1; +} + +int _ftime(struct timeb *tp) +{ + errno = ENOSYS; + return -1; +} + +char *_getcwd(char *buf, size_t size) +{ + errno = -ENOSYS; + return NULL; +} + +int _getpid() +{ + return 1; +} + +int _gettimeofday(struct timeval *tp, void *tzp) +{ + errno = -ENOSYS; + return -1; +} + +int _isatty(int file) +{ + return (file == STDOUT_FILENO); +} + +int _kill(int pid, int sig) +{ + errno = EINVAL; + return -1; +} + +int _link(const char *old_name, const char *new_name) +{ + errno = EMLINK; + return -1; +} + +off_t _lseek(int file, off_t ptr, int dir) +{ + return 0; +} + +int _lstat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} + +int _open(const char *name, int flags, int mode) +{ + return -1; +} + +int _openat(int dirfd, const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} + +ssize_t _read(int file, void *ptr, size_t len) +{ + return 0; +} + +int _stat(const char *file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; + // errno = ENOSYS; + // return -1; +} + +long _sysconf(int name) +{ + + return -1; +} + +clock_t _times(struct tms *buf) +{ + return -1; +} + +int _unlink(const char *name) +{ + errno = ENOENT; + return -1; +} + +int _utime(const char *path, const struct utimbuf *times) +{ + errno = ENOSYS; + return -1; +} + +int _wait(int *status) +{ + errno = ECHILD; + return -1; +} + +ssize_t _write(int file, const void *ptr, size_t len) +{ + if (file != STDOUT_FILENO) { + errno = ENOSYS; + return -1; + } + + const void *eptr = ptr + len; + while (ptr != eptr) + *(volatile int *)STDOUT_REG = *(char *)(ptr++); + return len; +} + +extern char __heap_start[]; +extern char __heap_end[]; +static char *brk = __heap_start; + +int _brk(void *addr) +{ + brk = addr; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *old_brk = brk; + + if (__heap_start == __heap_end) { + return NULL; + } + + if ((brk += incr) < __heap_end) { + brk += incr; + } else { + brk = __heap_end; + } + return old_brk; +} diff --git a/vendor/pulp_riscv_dbg/tb/prog/test.c b/vendor/pulp_riscv_dbg/tb/prog/test.c new file mode 100644 index 0000000000..81a3579ead --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/prog/test.c @@ -0,0 +1,6 @@ +#include + +int main(){ + printf("hello world!\n"); + return 0; +} diff --git a/vendor/pulp_riscv_dbg/tb/prog/vectors.S b/vendor/pulp_riscv_dbg/tb/prog/vectors.S new file mode 100644 index 0000000000..f23c057f70 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/prog/vectors.S @@ -0,0 +1,152 @@ +/* +* Copyright 2019 ETH Zürich and University of Bologna +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +.section .vectors, "ax" +.option norvc +vector_table: + j sw_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j verification_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + +/* this is fixed to 0x8000, used for PULP_SECURE=0. We redirect this entry to the +new vector table (which is at mtvec) */ +/* .section .legacy_irq, "ax" */ +/* j vector_table */ +/* j __no_irq_handler */ +/* j __no_irq_handler */ +/* j __no_irq_handler */ + +.section .text.vecs +/* exception handling */ +__no_irq_handler: + la a0, no_exception_handler_msg + jal ra, puts + j __no_irq_handler + + +sw_irq_handler: + csrr t0, mcause + slli t0, t0, 1 /* shift off the high bit */ + srli t0, t0, 1 + li t1, 2 + beq t0, t1, handle_illegal_insn + li t1, 11 + beq t0, t1, handle_ecall + li t1, 3 + beq t0, t1, handle_ebreak + j handle_unknown + +handle_ecall: + la a0, ecall_msg + jal ra, puts + j end_handler + +handle_ebreak: + la a0, ebreak_msg + jal ra, puts + j end_handler + +handle_illegal_insn: + la a0, illegal_insn_msg + jal ra, puts + j end_handler + +handle_unknown: + la a0, unknown_msg + jal ra, puts + j end_handler + +end_handler: + csrr a0, mepc + addi a0, a0, 4 + csrw mepc, a0 + mret +/* this interrupt can be generated for verification purposes, random or when the PC is equal to a given value*/ +verification_irq_handler: + mret + +.section .rodata +illegal_insn_msg: + .string "illegal instruction exception handler entered\n" +ecall_msg: + .string "ecall exception handler entered\n" +ebreak_msg: + .string "ebreak exception handler entered\n" +unknown_msg: + .string "unknown exception handler entered\n" +no_exception_handler_msg: + .string "no exception handler installed\n" diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore b/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore new file mode 100644 index 0000000000..0015e3f5a6 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore @@ -0,0 +1,3 @@ +*.o +*.d +*.so \ No newline at end of file diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile b/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile new file mode 100644 index 0000000000..8deb36ae53 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile @@ -0,0 +1,124 @@ +# Copyright (C) 2020 ETH Zurich and University of Bologna +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Author: Robert Balas (balasr@iis.ee.ethz.ch) + +CFLAGS = -Wall -Wextra -Wno-missing-field-initializers \ + -Wno-unused-function -Wno-missing-braces \ + -O2 -g -march=native \ + -DENABLE_LOGGING -DNDEBUG +CFLAGS_DBG = +# we need gnu11 and no-strict-aliasing +ALL_CFLAGS = -std=gnu11 -fno-strict-aliasing $(CFLAGS) +ALL_CFLAGS_DBG = -std=gnu11 -Wall -Wextra -Wno-missing-field-initializers \ + -Wno-unused-function -Wno-missing-braces \ + -O0 -g -fno-strict-aliasing \ + -fsanitize=address -fno-omit-frame-pointer \ + -DENABLE_LOGGING -DENABLE_DEBUG $(CFLAGS_DBG)\ +# -fsanitize=undefined \ +# -fsanitize=leak \ + + +# TODO: better path? +LIB_DIRS = +LIBS = +INCLUDE_DIRS = ./ + + +LDFLAGS = $(addprefix -L, $(LIB_DIRS)) +LDLIBS = $(addprefix -l, $(LIBS)) + +SRCS = remote_bitbang.c sim_jtag.c +OBJS = $(SRCS:.c=.o) +INCLUDES = $(addprefix -I, $(INCLUDE_DIRS)) + +HEADERS = $(wildcard *.h) + +# libs +SV_LIB = librbs.so + +# header file dependency generation +DEPDIR := .d +DEPDIRS := $(addsuffix /$(DEPDIR),.) +# goal: make gcc put a dependency file called obj.Td (derived from subdir/obj.o) +# in subdir/.d/ +DEPFLAGS = -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F)) +# move gcc generated header dependencies to DEPDIR +# this rename step is here to make the header dependency generation "atomic" +POSTCOMPILE = @mv -f $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F)) \ + $(@D)/$(DEPDIR)/$(patsubst %.o,%.d,$(@F)) && touch $@ + +# GNU recommendations for install targets +prefix = /usr/local +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +includedir = $(prefix)/include + +INSTALL = install +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = ${INSTALL} -m 644 + +CTAGS = ctags + +# compilation targets +all: sv-lib + +debug: ALL_CFLAGS = $(ALL_CFLAGS_DBG) +debug: all + +sv-lib: ALL_CFLAGS += -fPIC +sv-lib: $(SV_LIB) + +#compilation boilerplate +$(SV_LIB): $(OBJS) + $(LD) -shared -E --exclude-libs ALL -o $(SV_LIB) $(LDFLAGS) \ + $(OBJS) $(LDLIBS) + +# $@ = name of target +# $< = first dependency +%.o: %.c +%.o: %.c $(DEPDIR)/%.d $(DEPDIRS) + $(CC) $(DEPFLAGS) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) \ + -c $(CPPFLAGS) $< -o $@ $(LDLIBS) + $(POSTCOMPILE) + +# check if we need to create the dependencies folders (gcc doesn't) +$(DEPDIRS): + $(shell mkdir -p $(DEPDIRS) > /dev/null) +# make won't fail if the dependency file doesn't exist +$(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi): ; + +# prevent automatic deletion as intermediate file +.PRECIOUS: $(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi) + +# emacs tag generation +.PHONY: TAGS +TAGS: + $(CTAGS) -R -e -h=".c.h" --tag-relative=always \ + . $(LIB_DIRS) $(INCLUDE_DIRS) $(BINUTILS_PATH)/bfd + +# TODO: missing install targets +# cleanup +.PHONY: clean +clean: + rm -rf $(SV_LIB) $(OBJS) $(DEPDIRS) + +.PHONY: distclean +distclean: clean + rm -f TAGS + +# include auto generated header dependency information +include $(wildcard $(addsuffix /*.d,$(DEPDIRS))) diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c b/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c new file mode 100644 index 0000000000..328574ec26 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2020 ETH Zurich and University of Bologna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Author: Robert Balas (balasr@iis.ee.ethz.ch) + */ + +#include +#include "remote_bitbang.h" + +int main() +{ + unsigned char jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn; + unsigned char jtag_TDO = 0; + + printf("calling rbs_init\n"); + int v = rbs_init(0); + + printf("tick 1\n"); + rbs_tick(&jtag_TCK, &jtag_TMS, &jtag_TDI, &jtag_TRSTn, jtag_TDO); + printf("jtag exit is %d\n", rbs_done()); + return 0; +} diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c b/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c new file mode 100644 index 0000000000..e77c00dd41 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c @@ -0,0 +1,275 @@ +// See LICENSE.Berkeley for license details. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "remote_bitbang.h" + +int rbs_init(uint16_t port) +{ + socket_fd = 0; + client_fd = 0; + recv_start = 0; + recv_end = 0; + rbs_err = 0; + + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + fcntl(socket_fd, F_SETFL, O_NONBLOCK); + int reuseaddr = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, + sizeof(int)) == -1) { + fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + if (listen(socket_fd, 1) == -1) { + fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + socklen_t addrlen = sizeof(addr); + if (getsockname(socket_fd, (struct sockaddr *)&addr, &addrlen) == -1) { + fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n", + strerror(errno), errno); + abort(); + } + + tck = 1; + tms = 1; + tdi = 1; + trstn = 1; + quit = 0; + + fprintf(stderr, "JTAG remote bitbang server is ready\n"); + fprintf(stderr, "Listening on port %d\n", ntohs(addr.sin_port)); + return 1; +} + +void rbs_accept() +{ + fprintf(stderr, "Attempting to accept client socket\n"); + int again = 1; + while (again != 0) { + client_fd = accept(socket_fd, NULL, NULL); + if (client_fd == -1) { + if (errno == EAGAIN) { + // No client waiting to connect right now. + } else { + fprintf(stderr, "failed to accept on socket: %s (%d)\n", + strerror(errno), errno); + again = 0; + abort(); + } + } else { + fcntl(client_fd, F_SETFL, O_NONBLOCK); + fprintf(stderr, "Accepted successfully."); + again = 0; + } + } +} + +void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms, + unsigned char *jtag_tdi, unsigned char *jtag_trstn, + unsigned char jtag_tdo) +{ + if (client_fd > 0) { + tdo = jtag_tdo; + rbs_execute_command(); + } else { + rbs_accept(); + } + + *jtag_tck = tck; + *jtag_tms = tms; + *jtag_tdi = tdi; + *jtag_trstn = trstn; +} + +void rbs_reset() +{ + // trstn = 0; +} + +void rbs_set_pins(char _tck, char _tms, char _tdi) +{ + tck = _tck; + tms = _tms; + tdi = _tdi; +} + +void rbs_execute_command() +{ + char command; + int again = 1; + while (again) { + ssize_t num_read = read(client_fd, &command, sizeof(command)); + if (num_read == -1) { + if (errno == EAGAIN) { + // We'll try again the next call. + if (VERBOSE) + fprintf( + stderr, + "Received no command. Will try again on the next call\n"); + } else { + fprintf(stderr, + "remote_bitbang failed to read on socket: %s (%d)\n", + strerror(errno), errno); + again = 0; + abort(); + } + } else if (num_read == 0) { + fprintf(stderr, "No command received. Stopping further reads.\n"); + // again = 1; + return; + } else { + again = 0; + } + } + + int dosend = 0; + + char tosend = '?'; + + switch (command) { + case 'B': + if (VERBOSE) + fprintf(stderr, "*BLINK*\n"); + break; + case 'b': + if (VERBOSE) + fprintf(stderr, "blink off\n"); + break; + case 'r': + if (VERBOSE) + fprintf(stderr, "r-reset\n"); + rbs_reset(); + break; // This is wrong. 'r' has other bits that indicated TRST and + // SRST. + case 's': + if (VERBOSE) + fprintf(stderr, "s-reset\n"); + rbs_reset(); + break; // This is wrong. + case 't': + if (VERBOSE) + fprintf(stderr, "t-reset\n"); + rbs_reset(); + break; // This is wrong. + case 'u': + if (VERBOSE) + fprintf(stderr, "u-reset\n"); + rbs_reset(); + break; // This is wrong. + case '0': + if (VERBOSE) + fprintf(stderr, "Write 0 0 0\n"); + rbs_set_pins(0, 0, 0); + break; + case '1': + if (VERBOSE) + fprintf(stderr, "Write 0 0 1\n"); + rbs_set_pins(0, 0, 1); + break; + case '2': + if (VERBOSE) + fprintf(stderr, "Write 0 1 0\n"); + rbs_set_pins(0, 1, 0); + break; + case '3': + if (VERBOSE) + fprintf(stderr, "Write 0 1 1\n"); + rbs_set_pins(0, 1, 1); + break; + case '4': + if (VERBOSE) + fprintf(stderr, "Write 1 0 0\n"); + rbs_set_pins(1, 0, 0); + break; + case '5': + if (VERBOSE) + fprintf(stderr, "Write 1 0 1\n"); + rbs_set_pins(1, 0, 1); + break; + case '6': + if (VERBOSE) + fprintf(stderr, "Write 1 1 0\n"); + rbs_set_pins(1, 1, 0); + break; + case '7': + if (VERBOSE) + fprintf(stderr, "Write 1 1 1\n"); + rbs_set_pins(1, 1, 1); + break; + case 'R': + if (VERBOSE) + fprintf(stderr, "Read req\n"); + dosend = 1; + tosend = tdo ? '1' : '0'; + break; + case 'Q': + if (VERBOSE) + fprintf(stderr, "Quit req\n"); + quit = 1; + break; + default: + fprintf(stderr, "remote_bitbang got unsupported command '%c'\n", + command); + } + if (dosend) { + while (1) { + ssize_t bytes = write(client_fd, &tosend, sizeof(tosend)); + if (bytes == -1) { + fprintf(stderr, "failed to write to socket: %s (%d)\n", + strerror(errno), errno); + abort(); + } + if (bytes > 0) { + break; + } + } + } + + if (quit) { + fprintf(stderr, "Remote end disconnected\n"); + close(client_fd); + client_fd = 0; + } +} + +unsigned char rbs_done() +{ + return quit; +} + +int rbs_exit_code() +{ + return rbs_err; +} diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h b/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h new file mode 100644 index 0000000000..460819e20c --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h @@ -0,0 +1,52 @@ +// See LICENSE.Berkeley for license details. + +#ifndef REMOTE_BITBANG_H +#define REMOTE_BITBANG_H + +#include +#include + +#define VERBOSE 0 + +int rbs_err; + +unsigned char tck; +unsigned char tms; +unsigned char tdi; +unsigned char trstn; +unsigned char tdo; +unsigned char quit; + +int socket_fd; +int client_fd; + +static const ssize_t buf_size = 64 * 1024; +char recv_buf[64 * 1024]; +ssize_t recv_start, recv_end; + +// Create a new server, listening for connections from localhost on the given +// port. +int rbs_init(uint16_t port); + +// Do a bit of work. +void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms, + unsigned char *jtag_tdi, unsigned char *jtag_trstn, + unsigned char jtag_tdo); + +unsigned char rbs_done(); + +int rbs_exit_code(); + +// Check for a client connecting, and accept if there is one. +void rbs_accept(); +// Execute any commands the client has for us. +// But we only execute 1 because we need time for the +// simulation to run. +void rbs_execute_command(); + +// Reset. Currently does nothing. +void rbs_reset(); + +void rbs_set_pins(char _tck, char _tms, char _tdi); + +#endif diff --git a/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c b/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c new file mode 100644 index 0000000000..769ba8894e --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c @@ -0,0 +1,29 @@ +// See LICENSE.SiFive for license details. + +#include +#include +#include +#include "remote_bitbang.h" + +int init = 0; + +int jtag_tick(int port, unsigned char *jtag_TCK, unsigned char *jtag_TMS, + unsigned char *jtag_TDI, unsigned char *jtag_TRSTn, + unsigned char jtag_TDO) + +{ + if (!init) { + if (port < 0 || port > UINT16_MAX) + fprintf(stderr, "Port number of out range: %d\n", port); + init = rbs_init(port); + } + + rbs_tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, jtag_TDO); + if (VERBOSE) + fprintf( + stderr, + "Tick with: TCK=%hhd TMS=%hhd TDI=%hhd TRSTn=%hhd --> TDO=%hhd\n", + *jtag_TCK, *jtag_TMS, *jtag_TDI, *jtag_TRSTn, jtag_TDO); + + return rbs_done() ? (rbs_exit_code() << 1 | 1) : 0; +} diff --git a/vendor/pulp_riscv_dbg/tb/tb_test_env.sv b/vendor/pulp_riscv_dbg/tb/tb_test_env.sv new file mode 100644 index 0000000000..f9e72a8adc --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/tb_test_env.sv @@ -0,0 +1,338 @@ +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Wrapper for a RI5CY testbench, containing RI5CY, Memory and stdout peripheral +// Contributor: Robert Balas + +module tb_test_env #( + parameter int unsigned INSTR_RDATA_WIDTH = 32, + parameter int unsigned RAM_ADDR_WIDTH = 20, + parameter logic [31:0] BOOT_ADDR = 'h80, + parameter bit PULP_SECURE = 1, + parameter bit JTAG_BOOT = 1, + parameter int unsigned OPENOCD_PORT = 0, + parameter bit A_EXTENSION = 0 +) ( + input logic clk_i, + input logic rst_ni, + + // currently we are not making use of those signals + input logic fetch_enable_i, + output logic tests_passed_o, + output logic tests_failed_o); + + // defs from pulpissimo + // localparam CLUSTER_ID = 6'd31; + // localparam CORE_ID = 4'd0; + // test defs + localparam CLUSTER_ID = 6'd0; + localparam CORE_ID = 4'd0; + + localparam CORE_MHARTID = {CLUSTER_ID, 1'b0, CORE_ID}; + localparam NrHarts = 1; + localparam logic [NrHarts-1:0] SELECTABLE_HARTS = 1 << CORE_MHARTID; + + // signals connecting core to memory + logic instr_req; + logic instr_gnt; + logic instr_rvalid; + logic [31:0] instr_addr; + logic [INSTR_RDATA_WIDTH-1:0] instr_rdata; + + logic data_req; + logic data_gnt; + logic data_rvalid; + logic [31:0] data_addr; + logic data_we; + logic [3:0] data_be; + logic [31:0] data_rdata; + logic [31:0] data_wdata; + + // jtag openocd bridge signals + logic sim_jtag_tck; + logic sim_jtag_tms; + logic sim_jtag_tdi; + logic sim_jtag_trstn; + logic sim_jtag_tdo; + logic [31:0] sim_jtag_exit; + logic sim_jtag_enable; + + // signals for debug unit + logic debug_req_ready; + dm::dmi_resp_t debug_resp; + logic jtag_req_valid; + dm::dmi_req_t jtag_dmi_req; + logic jtag_resp_ready; + logic jtag_resp_valid; + logic [NrHarts-1:0] dm_debug_req; + logic ndmreset, ndmreset_n; + + // debug unit slave interface + logic dm_grant; + logic dm_rvalid; + logic dm_req; + logic dm_we; + logic [31:0] dm_addr; + logic [31:0] dm_wdata; + logic [31:0] dm_rdata; + logic [3:0] dm_be; + + // debug unit master interface (system bus access) + logic sb_req; + logic [31:0] sb_addr; + logic sb_we; + logic [31:0] sb_wdata; + logic [3:0] sb_be; + logic sb_gnt; + logic sb_rvalid; + logic [31:0] sb_rdata; + + // irq signals (not used) + logic irq; + logic [0:4] irq_id_in; + logic irq_ack; + logic [0:4] irq_id_out; + logic irq_sec; + + // make jtag bridge work + assign sim_jtag_enable = JTAG_BOOT; + + // interrupts (only timer for now) + assign irq_sec = '0; + + // instantiate the core + riscv_core #( + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH), + .PULP_SECURE(PULP_SECURE), + .A_EXTENSION(A_EXTENSION), + .FPU(0) + ) riscv_core_i ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + + .clock_en_i ( '1 ), + .test_en_i ( '0 ), + + .boot_addr_i ( BOOT_ADDR ), + .core_id_i ( CORE_ID ), + .cluster_id_i ( CLUSTER_ID ), + + .instr_addr_o ( instr_addr ), + .instr_req_o ( instr_req ), + .instr_rdata_i ( instr_rdata ), + .instr_gnt_i ( instr_gnt ), + .instr_rvalid_i ( instr_rvalid ), + + .data_addr_o ( data_addr ), + .data_wdata_o ( data_wdata ), + .data_we_o ( data_we ), + .data_req_o ( data_req ), + .data_be_o ( data_be ), + .data_rdata_i ( data_rdata ), + .data_gnt_i ( data_gnt ), + .data_rvalid_i ( data_rvalid ), + .data_atop_o ( ), + + .apu_master_req_o ( ), + .apu_master_ready_o ( ), + .apu_master_gnt_i ( ), + .apu_master_operands_o ( ), + .apu_master_op_o ( ), + .apu_master_type_o ( ), + .apu_master_flags_o ( ), + .apu_master_valid_i ( ), + .apu_master_result_i ( ), + .apu_master_flags_i ( ), + + + .irq_software_i ( 1'b0 ), + .irq_timer_i ( 1'b0 ), + .irq_external_i ( 1'b0 ), + .irq_fast_i ( 15'b0 ), + .irq_nmi_i ( 1'b0 ), + .irq_fastx_i ( 32'b0 ), + + .irq_ack_o ( irq_ack ), + .irq_id_o ( irq_id_out ), + .irq_sec_i ( irq_sec ), + + .sec_lvl_o ( sec_lvl_o ), + + .debug_req_i ( dm_debug_req[CORE_MHARTID] ), + + .fetch_enable_i ( fetch_enable_i ), + .core_busy_o ( core_busy_o ), + + .ext_perf_counters_i ( ), + .fregfile_disable_i ( 1'b0 ) + ); + + // this handles read to RAM and memory mapped pseudo peripherals + mm_ram #( + .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH), + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH), + .JTAG_BOOT(JTAG_BOOT) + ) mm_ram_i ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + + // core instruction access + .instr_req_i ( instr_req ), + .instr_addr_i ( instr_addr ), + .instr_rdata_o ( instr_rdata ), + .instr_rvalid_o ( instr_rvalid ), + .instr_gnt_o ( instr_gnt ), + + // core data access + .data_req_i ( data_req ), + .data_addr_i ( data_addr ), + .data_we_i ( data_we ), + .data_be_i ( data_be ), + .data_wdata_i ( data_wdata ), + .data_rdata_o ( data_rdata ), + .data_rvalid_o ( data_rvalid ), + .data_gnt_o ( data_gnt ), + + // system bus access from debug unit + .sb_req_i ( sb_req ), + .sb_addr_i ( sb_addr ), + .sb_we_i ( sb_we ), + .sb_be_i ( sb_be ), + .sb_wdata_i ( sb_wdata ), + .sb_rdata_o ( sb_rdata ), + .sb_rvalid_o ( sb_rvalid ), + .sb_gnt_o ( sb_gnt ), + + // access to debug unit + .dm_req_o ( dm_req ), + .dm_addr_o ( dm_addr ), + .dm_we_o ( dm_we ), + .dm_be_o ( dm_be ), + .dm_wdata_o ( dm_wdata ), + .dm_rdata_i ( dm_rdata ), + .dm_rvalid_i ( dm_rvalid ), + .dm_gnt_i ( dm_gnt ), + + + .irq_id_i ( irq_id_out ), + .irq_ack_i ( irq_ack ), + .irq_id_o ( irq_id_in ), + .irq_o ( irq ), + + .tests_passed_o ( tests_passed_o ), + .tests_failed_o ( tests_failed_o ) + ); + + // debug subsystem + dmi_jtag #( + .IdcodeValue ( 32'h249511C3 ) + ) i_dmi_jtag ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( 1'b0 ), + .dmi_req_o ( jtag_dmi_req ), + .dmi_req_valid_o ( jtag_req_valid ), + .dmi_req_ready_i ( debug_req_ready ), + .dmi_resp_i ( debug_resp ), + .dmi_resp_ready_o ( jtag_resp_ready ), + .dmi_resp_valid_i ( jtag_resp_valid ), + .dmi_rst_no ( ), // not connected + .tck_i ( sim_jtag_tck ), + .tms_i ( sim_jtag_tms ), + .trst_ni ( sim_jtag_trstn ), + .td_i ( sim_jtag_tdi ), + .td_o ( sim_jtag_tdo ), + .tdo_oe_o ( ) + ); + + dm_top #( + .NrHarts ( NrHarts ), + .BusWidth ( 32 ), + .SelectableHarts ( SELECTABLE_HARTS ) + ) i_dm_top ( + + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( 1'b0 ), + .ndmreset_o ( ndmreset ), + .dmactive_o ( ), // active debug session TODO + .debug_req_o ( dm_debug_req ), + .unavailable_i ( ~SELECTABLE_HARTS ), + .hartinfo_i ( '0 ), + + .slave_req_i ( dm_req ), + .slave_we_i ( dm_we ), + .slave_addr_i ( dm_addr ), + .slave_be_i ( dm_be ), + .slave_wdata_i ( dm_wdata ), + .slave_rdata_o ( dm_rdata ), + + .master_req_o ( sb_req ), + .master_add_o ( sb_addr ), + .master_we_o ( sb_we ), + .master_wdata_o ( sb_wdata ), + .master_be_o ( sb_be ), + .master_gnt_i ( sb_gnt ), + .master_r_valid_i ( sb_rvalid ), + .master_r_rdata_i ( sb_rdata ), + + .dmi_rst_ni ( rst_ni ), + .dmi_req_valid_i ( jtag_req_valid ), + .dmi_req_ready_o ( debug_req_ready ), + .dmi_req_i ( jtag_dmi_req ), + .dmi_resp_valid_o ( jtag_resp_valid ), + .dmi_resp_ready_i ( jtag_resp_ready ), + .dmi_resp_o ( debug_resp ) + ); + + // grant in the same cycle + assign dm_gnt = dm_req; + // valid read/write in the next cycle + always_ff @(posedge clk_i or negedge rst_ni) begin : dm_valid_handler + if(~rst_ni) begin + dm_rvalid <= '0; + end else begin + dm_rvalid <= dm_gnt; + end + end + + // reset handling with ndmreset + rstgen i_rstgen_main ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni & (~ndmreset) ), + .test_mode_i ( '0 ), + .rst_no ( ndmreset_n ), + .init_no ( ) // keep open + ); + + // jtag calls from dpi + SimJTAG #( + .TICK_DELAY (1), + .PORT(OPENOCD_PORT) + ) i_sim_jtag ( + .clock ( clk_i ), + .reset ( ~rst_ni ), + .enable ( sim_jtag_enable ), + .init_done ( rst_ni ), + .jtag_TCK ( sim_jtag_tck ), + .jtag_TMS ( sim_jtag_tms ), + .jtag_TDI ( sim_jtag_tdi ), + .jtag_TRSTn ( sim_jtag_trstn ), + .jtag_TDO_data ( sim_jtag_tdo ), + .jtag_TDO_driven ( 1'b1 ), + .exit ( sim_jtag_exit ) + ); + + always_comb begin : jtag_exit_handler + if (sim_jtag_exit) + $finish(2); // print stats too + end + +endmodule // tb_test_env diff --git a/vendor/pulp_riscv_dbg/tb/tb_top.sv b/vendor/pulp_riscv_dbg/tb/tb_top.sv new file mode 100644 index 0000000000..9e7525f7d5 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/tb_top.sv @@ -0,0 +1,138 @@ +// Copyright 2017 Embecosm Limited +// Copyright 2018 Robert Balas +// Copyright 2020 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Top level wrapper for a RI5CY testbench +// Contributor: Robert Balas +// Jeremy Bennett + +module tb_top #( + parameter int unsigned INSTR_RDATA_WIDTH = 32, + parameter int unsigned RAM_ADDR_WIDTH = 22, + parameter logic [31:0] BOOT_ADDR = 'h1A00_0180, + parameter bit JTAG_BOOT = 1, + parameter int unsigned OPENOCD_PORT = 9999 +); + + // comment to record execution trace + //`define TRACE_EXECUTION + + const time CLK_PHASE_HI = 5ns; + const time CLK_PHASE_LO = 5ns; + const time CLK_PERIOD = CLK_PHASE_HI + CLK_PHASE_LO; + const time STIM_APPLICATION_DEL = CLK_PERIOD * 0.1; + const time RESP_ACQUISITION_DEL = CLK_PERIOD * 0.9; + const time RESET_DEL = STIM_APPLICATION_DEL; + const int RESET_WAIT_CYCLES = 4; + + // clock and reset for tb + logic clk = 'b1; + logic rst_n = 'b0; + + // testbench result + logic tests_passed; + logic tests_failed; + + // signals for ri5cy + logic fetch_enable; + + + // make the core start fetching instruction immediately + assign fetch_enable = '1; + + // allow vcd dump + initial begin: dump_vars + if ($test$plusargs("vcd")) begin + $dumpfile("riscy_tb.vcd"); + $dumpvars(0, tb_top); + end +`ifdef QUESTA + if ($test$plusargs("wlfdump")) begin + $wlfdumpvars(0, tb_top); + end +`endif + end + + // we either load the provided firmware or execute a small test program that + // doesn't do more than an infinite loop with some I/O + initial begin: load_prog + automatic logic [1023:0] firmware; + automatic int prog_size = 6; + + if($value$plusargs("firmware=%s", firmware)) begin + if($test$plusargs("verbose")) + $display("[TESTBENCH] %t: loading firmware %0s ...", + $time, firmware); + $readmemh(firmware, tb_test_env_i.mm_ram_i.dp_ram_i.mem); + + end else begin + $display("No firmware specified"); + end + end + + // clock generation + initial begin: clock_gen + forever begin + #CLK_PHASE_HI clk = 1'b0; + #CLK_PHASE_LO clk = 1'b1; + end + end: clock_gen + + // reset generation + initial begin: reset_gen + rst_n = 1'b0; + + // wait a few cycles + repeat (RESET_WAIT_CYCLES) begin + @(posedge clk); //TODO: was posedge, see below + end + + // start running + #RESET_DEL rst_n = 1'b1; + if($test$plusargs("verbose")) + $display("reset deasserted", $time); + + end: reset_gen + + // set timing format + initial begin: timing_format + $timeformat(-9, 0, "ns", 9); + end: timing_format + + // check if we succeded + always_ff @(posedge clk, negedge rst_n) begin + if (tests_passed) begin + $display("Exit Success"); + $finish; + end + if (tests_failed) begin + $display("Exit FAILURE"); + $finish; + end + end + + // wrapper for riscv, the memory system and stdout peripheral + tb_test_env #( + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH), + .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH), + .BOOT_ADDR (BOOT_ADDR), + .PULP_SECURE (1), + .JTAG_BOOT (JTAG_BOOT), + .OPENOCD_PORT (OPENOCD_PORT) + ) tb_test_env_i( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .fetch_enable_i ( fetch_enable ), + .tests_passed_o ( tests_passed ), + .tests_failed_o ( tests_failed ) + ); + +endmodule // tb_top diff --git a/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp b/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp new file mode 100644 index 0000000000..1009b13a0c --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp @@ -0,0 +1,105 @@ +// Copyright 2018 Robert Balas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// Top level wrapper for a verilator RI5CY testbench +// Contributor: Robert Balas + +#include "svdpi.h" +#include "Vtb_top_verilator__Dpi.h" +#include "Vtb_top_verilator.h" +#include "verilated_vcd_c.h" +#include "verilated.h" + +#include +#include +#include +#include +#include +#include +#include + +void dump_memory(); +double sc_time_stamp(); + +static vluint64_t t = 0; +Vtb_top_verilator *top; + +int main(int argc, char **argv, char **env) +{ + Verilated::commandArgs(argc, argv); + Verilated::traceEverOn(true); + top = new Vtb_top_verilator(); + + svSetScope(svGetScopeFromName( + "TOP.tb_top_verilator.mm_ram_i.dp_ram_i")); + Verilated::scopesDump(); + +#ifdef VCD_TRACE + VerilatedVcdC *tfp = new VerilatedVcdC; + top->trace(tfp, 99); + tfp->open("verilator_tb.vcd"); +#endif + top->fetch_enable_i = 1; + top->clk_i = 0; + top->rst_ni = 0; + + top->eval(); + dump_memory(); + + while (!Verilated::gotFinish()) { + if (t > 40) + top->rst_ni = 1; + top->clk_i = !top->clk_i; + top->eval(); +#ifdef VCD_TRACE + tfp->dump(t); +#endif + t += 5; + } +#ifdef VCD_TRACE + tfp->close(); +#endif + delete top; + exit(0); +} + +double sc_time_stamp() +{ + return t; +} + +void dump_memory() +{ + errno = 0; + std::ofstream mem_file; + svLogicVecVal addr = {0}; + + mem_file.exceptions(std::ofstream::failbit | std::ofstream::badbit); + try { + mem_file.open("memory_dump.bin"); + for (size_t i = 0; i < 1048576; i++) { + addr.aval = i; + uint32_t val = read_byte(&addr); + mem_file << std::setfill('0') << std::setw(2) << std::hex << val + << std::endl; + } + mem_file.close(); + + std::cout << "finished dumping memory" << std::endl; + + } catch (std::ofstream::failure e) { + std::cerr << "exception opening/reading/closing file memory_dump.bin\n"; + } +} diff --git a/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv b/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv new file mode 100644 index 0000000000..2c7ef95901 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv @@ -0,0 +1,330 @@ +// Copyright 2018 Robert Balas +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// Top level wrapper for a verilator RI5CY testbench +// Contributor: Robert Balas + +module tb_top_verilator #( + parameter int unsigned INSTR_RDATA_WIDTH = 32, + parameter int unsigned RAM_ADDR_WIDTH = 22, + parameter logic [31:0] BOOT_ADDR = 'h1A00_0180, + parameter bit JTAG_BOOT = 1, + parameter int unsigned OPENOCD_PORT = 9999 +) ( + input logic clk_i, + input logic rst_ni, + input logic fetch_enable_i, + output logic tests_passed_o, + output logic tests_failed_o +); + // defs from pulpissimo + // localparam CLUSTER_ID = 6'd31; + // localparam CORE_ID = 4'd0; + // test defs + localparam CLUSTER_ID = 6'd0; + localparam CORE_ID = 4'd0; + + localparam CORE_MHARTID = {CLUSTER_ID, 1'b0, CORE_ID}; + localparam NrHarts = 1; + localparam logic [NrHarts-1:0] SELECTABLE_HARTS = 1 << CORE_MHARTID; + + // signals connecting core to memory + logic instr_req; + logic instr_gnt; + logic instr_rvalid; + logic [31:0] instr_addr; + logic [INSTR_RDATA_WIDTH-1:0] instr_rdata; + + logic data_req; + logic data_gnt; + logic data_rvalid; + logic [31:0] data_addr; + logic data_we; + logic [3:0] data_be; + logic [31:0] data_rdata; + logic [31:0] data_wdata; + + // jtag openocd bridge signals + logic sim_jtag_tck; + logic sim_jtag_tms; + logic sim_jtag_tdi; + logic sim_jtag_trstn; + logic sim_jtag_tdo; + logic [31:0] sim_jtag_exit; + logic sim_jtag_enable; + + // signals for debug unit + logic debug_req_ready; + dm::dmi_resp_t debug_resp; + logic jtag_req_valid; + dm::dmi_req_t jtag_dmi_req; + logic jtag_resp_ready; + logic jtag_resp_valid; + logic [NrHarts-1:0] dm_debug_req; + logic ndmreset, ndmreset_n; + + // debug unit slave interface + logic dm_grant; + logic dm_rvalid; + logic dm_req; + logic dm_we; + logic [31:0] dm_addr; + logic [31:0] dm_wdata; + logic [31:0] dm_rdata; + logic [3:0] dm_be; + + // debug unit master interface (system bus access) + logic sb_req; + logic [31:0] sb_addr; + logic sb_we; + logic [31:0] sb_wdata; + logic [3:0] sb_be; + logic sb_gnt; + logic sb_rvalid; + logic [31:0] sb_rdata; + + // irq signals (not used) + logic irq; + logic [0:4] irq_id_in; + logic irq_ack; + logic [0:4] irq_id_out; + logic irq_sec; + + // make jtag bridge work + assign sim_jtag_enable = JTAG_BOOT; + + // interrupts (only timer for now) + assign irq_sec = '0; + + // instantiate the core + riscv_core #( + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH), + .PULP_SECURE(1), + .FPU(0) + ) riscv_core_i ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + + .clock_en_i ( '1 ), + .test_en_i ( '0 ), + + .boot_addr_i ( BOOT_ADDR ), + .core_id_i ( CORE_ID ), + .cluster_id_i ( CLUSTER_ID ), + + .instr_addr_o ( instr_addr ), + .instr_req_o ( instr_req ), + .instr_rdata_i ( instr_rdata ), + .instr_gnt_i ( instr_gnt ), + .instr_rvalid_i ( instr_rvalid ), + + .data_addr_o ( data_addr ), + .data_wdata_o ( data_wdata ), + .data_we_o ( data_we ), + .data_req_o ( data_req ), + .data_be_o ( data_be ), + .data_rdata_i ( data_rdata ), + .data_gnt_i ( data_gnt ), + .data_rvalid_i ( data_rvalid ), + + .apu_master_req_o ( ), + .apu_master_ready_o ( ), + .apu_master_gnt_i ( ), + .apu_master_operands_o ( ), + .apu_master_op_o ( ), + .apu_master_type_o ( ), + .apu_master_flags_o ( ), + .apu_master_valid_i ( ), + .apu_master_result_i ( ), + .apu_master_flags_i ( ), + + + .irq_software_i ( 1'b0 ), + .irq_timer_i ( 1'b0 ), + .irq_external_i ( 1'b0 ), + .irq_fast_i ( 15'b0 ), + .irq_nmi_i ( 1'b0 ), + .irq_fastx_i ( 32'b0 ), + .irq_ack_o ( irq_ack ), + .irq_id_o ( irq_id_out ), + .irq_sec_i ( irq_sec ), + + .sec_lvl_o ( sec_lvl_o ), + + .debug_req_i ( dm_debug_req[CORE_MHARTID] ), + + .fetch_enable_i ( fetch_enable_i ), + .core_busy_o ( core_busy_o ), + + .ext_perf_counters_i ( ), + .fregfile_disable_i ( 1'b0 )); + + // this handles read to RAM and memory mapped pseudo peripherals + mm_ram #( + .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH), + .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH), + .JTAG_BOOT(JTAG_BOOT) + ) mm_ram_i ( + .clk_i ( clk_i ), + .rst_ni ( ndmreset_n ), + + // core instruction access + .instr_req_i ( instr_req ), + .instr_addr_i ( instr_addr ), + .instr_rdata_o ( instr_rdata ), + .instr_rvalid_o ( instr_rvalid ), + .instr_gnt_o ( instr_gnt ), + + // core data access + .data_req_i ( data_req ), + .data_addr_i ( data_addr ), + .data_we_i ( data_we ), + .data_be_i ( data_be ), + .data_wdata_i ( data_wdata ), + .data_rdata_o ( data_rdata ), + .data_rvalid_o ( data_rvalid ), + .data_gnt_o ( data_gnt ), + + // system bus access from debug unit + .sb_req_i ( sb_req ), + .sb_addr_i ( sb_addr ), + .sb_we_i ( sb_we ), + .sb_be_i ( sb_be ), + .sb_wdata_i ( sb_wdata ), + .sb_rdata_o ( sb_rdata ), + .sb_rvalid_o ( sb_rvalid ), + .sb_gnt_o ( sb_gnt ), + + // access to debug unit + .dm_req_o ( dm_req ), + .dm_addr_o ( dm_addr ), + .dm_we_o ( dm_we ), + .dm_be_o ( dm_be ), + .dm_wdata_o ( dm_wdata ), + .dm_rdata_i ( dm_rdata ), + .dm_rvalid_i ( dm_rvalid ), + .dm_gnt_i ( dm_gnt ), + + + .irq_id_i ( irq_id_out ), + .irq_ack_i ( irq_ack ), + .irq_id_o ( irq_id_in ), + .irq_o ( irq ), + + .tests_passed_o ( tests_passed_o ), + .tests_failed_o ( tests_failed_o )); + + // debug subsystem + dmi_jtag #( + .IdcodeValue ( 32'h249511C3 ) + ) i_dmi_jtag ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( 1'b0 ), + .dmi_req_o ( jtag_dmi_req ), + .dmi_req_valid_o ( jtag_req_valid ), + .dmi_req_ready_i ( debug_req_ready ), + .dmi_resp_i ( debug_resp ), + .dmi_resp_ready_o ( jtag_resp_ready ), + .dmi_resp_valid_i ( jtag_resp_valid ), + .dmi_rst_no ( ), // not connected + .tck_i ( sim_jtag_tck ), + .tms_i ( sim_jtag_tms ), + .trst_ni ( sim_jtag_trstn ), + .td_i ( sim_jtag_tdi ), + .td_o ( sim_jtag_tdo ), + .tdo_oe_o ( ) + ); + + dm_top #( + .NrHarts ( NrHarts ), + .BusWidth ( 32 ), + .SelectableHarts ( SELECTABLE_HARTS ) + ) i_dm_top ( + + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( 1'b0 ), + .ndmreset_o ( ndmreset ), + .dmactive_o ( ), // active debug session TODO + .debug_req_o ( dm_debug_req ), + .unavailable_i ( ~SELECTABLE_HARTS ), + .hartinfo_i ( '0 ), + + .slave_req_i ( dm_req ), + .slave_we_i ( dm_we ), + .slave_addr_i ( dm_addr ), + .slave_be_i ( dm_be ), + .slave_wdata_i ( dm_wdata ), + .slave_rdata_o ( dm_rdata ), + + .master_req_o ( sb_req ), + .master_add_o ( sb_addr ), + .master_we_o ( sb_we ), + .master_wdata_o ( sb_wdata ), + .master_be_o ( sb_be ), + .master_gnt_i ( sb_gnt ), + .master_r_valid_i ( sb_rvalid ), + .master_r_rdata_i ( sb_rdata ), + + .dmi_rst_ni ( rst_ni ), + .dmi_req_valid_i ( jtag_req_valid ), + .dmi_req_ready_o ( debug_req_ready ), + .dmi_req_i ( jtag_dmi_req ), + .dmi_resp_valid_o ( jtag_resp_valid ), + .dmi_resp_ready_i ( jtag_resp_ready ), + .dmi_resp_o ( debug_resp ) + ); + + // grant in the same cycle + assign dm_gnt = dm_req; + // valid read/write in the next cycle + always_ff @(posedge clk_i or negedge rst_ni) begin : dm_valid_handler + if(~rst_ni) begin + dm_rvalid <= '0; + end else begin + dm_rvalid <= dm_gnt; + end + end + + // reset handling with ndmreset + rstgen i_rstgen_main ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni & (~ndmreset) ), + .test_mode_i ( '0 ), + .rst_no ( ndmreset_n ), + .init_no ( ) // keep open + ); + + // jtag calls from dpi + SimJTAG #( + .TICK_DELAY (1), + .PORT(OPENOCD_PORT) + ) i_sim_jtag ( + .clock ( clk_i ), + .reset ( ~rst_ni ), + .enable ( sim_jtag_enable ), + .init_done ( rst_ni ), + .jtag_TCK ( sim_jtag_tck ), + .jtag_TMS ( sim_jtag_tms ), + .jtag_TDI ( sim_jtag_tdi ), + .jtag_TRSTn ( sim_jtag_trstn ), + .jtag_TDO_data ( sim_jtag_tdo ), + .jtag_TDO_driven ( 1'b1 ), + .exit ( sim_jtag_exit ) + ); + + always_comb begin : jtag_exit_handler + if (sim_jtag_exit) + $finish(2); // print stats too + end + +endmodule // tb_top_verilator + diff --git a/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv b/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv new file mode 100644 index 0000000000..293e7841bf --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv @@ -0,0 +1,81 @@ +// See LICENSE.SiFive for license details. +//VCS coverage exclude_file + +import "DPI-C" function int debug_tick +( + output bit debug_req_valid, + input bit debug_req_ready, + output int debug_req_bits_addr, + output int debug_req_bits_op, + output int debug_req_bits_data, + + input bit debug_resp_valid, + output bit debug_resp_ready, + input int debug_resp_bits_resp, + input int debug_resp_bits_data +); + +module SimDTM( + input clk, + input reset, + + output debug_req_valid, + input debug_req_ready, + output [ 6:0] debug_req_bits_addr, + output [ 1:0] debug_req_bits_op, + output [31:0] debug_req_bits_data, + + input debug_resp_valid, + output debug_resp_ready, + input [ 1:0] debug_resp_bits_resp, + input [31:0] debug_resp_bits_data, + + output [31:0] exit +); + + bit r_reset; + + wire #0.1 __debug_req_ready = debug_req_ready; + wire #0.1 __debug_resp_valid = debug_resp_valid; + wire [31:0] #0.1 __debug_resp_bits_resp = {30'b0, debug_resp_bits_resp}; + wire [31:0] #0.1 __debug_resp_bits_data = debug_resp_bits_data; + + bit __debug_req_valid; + int __debug_req_bits_addr; + int __debug_req_bits_op; + int __debug_req_bits_data; + bit __debug_resp_ready; + int __exit; + + assign #0.1 debug_req_valid = __debug_req_valid; + assign #0.1 debug_req_bits_addr = __debug_req_bits_addr[6:0]; + assign #0.1 debug_req_bits_op = __debug_req_bits_op[1:0]; + assign #0.1 debug_req_bits_data = __debug_req_bits_data[31:0]; + assign #0.1 debug_resp_ready = __debug_resp_ready; + assign #0.1 exit = __exit; + + always @(posedge clk) + begin + r_reset <= reset; + if (reset || r_reset) + begin + __debug_req_valid = 0; + __debug_resp_ready = 0; + __exit = 0; + end + else + begin + __exit = debug_tick( + __debug_req_valid, + __debug_req_ready, + __debug_req_bits_addr, + __debug_req_bits_op, + __debug_req_bits_data, + __debug_resp_valid, + __debug_resp_ready, + __debug_resp_bits_resp, + __debug_resp_bits_data + ); + end + end +endmodule diff --git a/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl b/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl new file mode 100644 index 0000000000..01c0d3e09b --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl @@ -0,0 +1,15 @@ +# Copyright 2020 ETH Zurich and University of Bologna. +# Copyright and related rights are licensed under the Solderpad Hardware +# License, Version 0.51 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +# or agreed to in writing, software, hardware and materials distributed under +# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Author: Robert Balas (balasr@student.ethz.ch) +# Description: TCL scripts to facilitate simulations + +set NoQuitOnFinish 1 +run -all diff --git a/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl b/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl new file mode 100644 index 0000000000..571b66e0a6 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl @@ -0,0 +1,16 @@ +# Copyright 2019 ETH Zurich and University of Bologna. +# Copyright and related rights are licensed under the Solderpad Hardware +# License, Version 0.51 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +# or agreed to in writing, software, hardware and materials distributed under +# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Author: Robert Balas (balasr@student.ethz.ch) +# Description: TCL scripts to facilitate simulations + +set NoQuitOnFinish 1 +source waves.tcl +run -all diff --git a/vendor/pulp_riscv_dbg/tb/waves.tcl b/vendor/pulp_riscv_dbg/tb/waves.tcl new file mode 100644 index 0000000000..f535d80da2 --- /dev/null +++ b/vendor/pulp_riscv_dbg/tb/waves.tcl @@ -0,0 +1,117 @@ +# Copyright 2020 ETH Zurich and University of Bologna. +# Copyright and related rights are licensed under the Solderpad Hardware +# License, Version 0.51 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +# or agreed to in writing, software, hardware and materials distributed under +# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Author: Robert Balas (balasr@iis.ee.ethz.ch) +# Description: TCL scripts to facilitate simulations +# catch { +# if {$trdb_all ne ""} { +# foreach inst $trdb_all { +# add wave -group [file tail $inst] $inst/* +# } +# } +# } err + +# if {$err ne ""} { +# puts "\[TCL\]: Suppressed error: $err" +# } + +# add fc +set rvcores [find instances -recursive -bydu riscv_core -nodu] +set fpuprivate [find instances -recursive -bydu fpu_private] +set tb_top [find instances -recursive -bydu tb_top -nod] +set mm_ram [find instances -recursive -bydu mm_ram -nod] +set dp_ram [find instances -recursive -bydu dp_ram -nod] + +if {$tb_top ne ""} { + foreach inst $tb_top { + add wave -group [file tail $inst] $inst/* + } +} + +if {$mm_ram ne ""} { + foreach inst $mm_ram { + add wave -group [file tail $inst] $inst/* + } +} + +if {$dp_ram ne ""} { + foreach inst $dp_ram { + add wave -group [file tail $inst] $inst/* + } +} + +if {$rvcores ne ""} { + set rvprefetch [find instances -recursive -bydu riscv_prefetch_L0_buffer -nodu] + + add wave -group "Core" $rvcores/* + add wave -group "IF Stage" -group "Hwlp Ctrl" $rvcores/if_stage_i/hwloop_controller_i/* + if {$rvprefetch ne ""} { + add wave -group "IF Stage" -group "Prefetch" -group "L0" $rvcores/if_stage_i/prefetch_128/prefetch_buffer_i/L0_buffer_i/* + add wave -group "IF Stage" -group "Prefetch" $rvcores/if_stage_i/prefetch_128/prefetch_buffer_i/* + } { + add wave -group "IF Stage" -group "Prefetch" -group "FIFO" $rvcores/if_stage_i/prefetch_32/prefetch_buffer_i/fifo_i/* + add wave -group "IF Stage" -group "Prefetch" $rvcores/if_stage_i/prefetch_32/prefetch_buffer_i/* + } + add wave -group "IF Stage" $rvcores/if_stage_i/* + add wave -group "ID Stage" $rvcores/id_stage_i/* + add wave -group "RF" $rvcores/id_stage_i/registers_i/riscv_register_file_i/mem + add wave -group "RF_FP" $rvcores/id_stage_i/registers_i/riscv_register_file_i/mem_fp + add wave -group "Decoder" $rvcores/id_stage_i/decoder_i/* + add wave -group "Controller" $rvcores/id_stage_i/controller_i/* + add wave -group "Int Ctrl" $rvcores/id_stage_i/int_controller_i/* + add wave -group "Hwloop Regs" $rvcores/id_stage_i/hwloop_regs_i/* + add wave -group "EX Stage" -group "ALU" $rvcores/ex_stage_i/alu_i/* + add wave -group "EX Stage" -group "ALU_DIV" $rvcores/ex_stage_i/alu_i/int_div/div_i/* + add wave -group "EX Stage" -group "MUL" $rvcores/ex_stage_i/mult_i/* + if {$fpuprivate ne ""} { + add wave -group "EX Stage" -group "APU_DISP" $rvcores/ex_stage_i/genblk1/apu_disp_i/* + add wave -group "EX Stage" -group "FPU" $rvcores/ex_stage_i/genblk1/genblk1/fpu_i/* + } + add wave -group "EX Stage" $rvcores/ex_stage_i/* + add wave -group "LSU" $rvcores/load_store_unit_i/* + add wave -group "CSR" $rvcores/cs_registers_i/* +} + +# add dm +set dm [find instances -recursive -bydu dm_top -nodu] +set dm_mem [find instances -recursive -bydu dm_mem -nodu] +set dm_csrs [find instances -recursive -bydu dm_csrs -nodu] +set dm_sba [find instances -recursive -bydu dm_sba -nodu] + +if {$dm ne ""} { + add wave -group "DM" $dm/* +} +if {$dm_mem ne ""} { + add wave -group "DM" -group "dm_mem" $dm_mem/* +} +if {$dm_csrs ne ""} { + add wave -group "DM" -group "dm_csrs" $dm_csrs/* +} +if {$dm_sba ne ""} { + add wave -group "DM" -group "dm_sba" $dm_sba/* +} + +# add dmi_jtag +set dmi [find instances -recursive -bydu dmi_jtag -nodu] +set dmi_tap [find instances -recursive -bydu dmi_jtag_tap -nodu] + +if {$dmi ne ""} { + add wave -group "DMI" $dmi/* +} +if {$dmi_tap ne ""} { + add wave -group "DMI" -group "dmi_tap" $dmi_tap/* +} + + +configure wave -namecolwidth 250 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -timelineunits ns From 371c4bcbe5763261cd08dd1500a0fde320a93cfa Mon Sep 17 00:00:00 2001 From: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Date: Mon, 28 Dec 2020 21:38:29 -0600 Subject: [PATCH 2/3] Integrate riscv_dbg into artya7 FPGA example Overhaul top_artya7.sv to both instantiate a debug module and provide bus arbitration between all three bus hosts (Ibex instr, Ibex data, and the debug module). A defacto standard from SiFive on JTAG pinouts exists for Arty boards; adapt the existing pin constraints to use this standard. --- examples/fpga/artya7/README.md | 16 ++ examples/fpga/artya7/data/pins_artya7.xdc | 18 +- examples/fpga/artya7/rtl/dm_top.sv | 260 ++++++++++++++++++++++ examples/fpga/artya7/rtl/jtag_pkg.sv | 24 ++ examples/fpga/artya7/rtl/top_artya7.sv | 238 +++++++++++++++----- examples/fpga/artya7/top_artya7.core | 3 + pulp_riscv_dbg.core | 28 +++ 7 files changed, 527 insertions(+), 60 deletions(-) create mode 100644 examples/fpga/artya7/rtl/dm_top.sv create mode 100644 examples/fpga/artya7/rtl/jtag_pkg.sv create mode 100644 pulp_riscv_dbg.core diff --git a/examples/fpga/artya7/README.md b/examples/fpga/artya7/README.md index fedf379f4a..dfbb50a876 100644 --- a/examples/fpga/artya7/README.md +++ b/examples/fpga/artya7/README.md @@ -70,3 +70,19 @@ fusesoc --cores-root=. run --target=synth --run lowrisc:ibex:top_artya7 ``` LED1/LED3 and LED0/LED2 should alternately be on after the FPGA programming is finished. + +## Debug + +By default, a debug unit compliant with the [RISC-V debug specification](https://github.com/riscv/riscv-debug-spec) v0.13.1 is integrated and is available via JTAG pins on PMOD header JD; the pinouts are: + +| PMOD header JD | | +| ------------ | ------------ | +| 1 : TDO | 7 : TDI | +| 2 : TRST_N | 8 : TMS | +| 3 : TCK | 9 : RESET_N | +| 4 | 10 : | +| 5 : GND | 11 : GND | +| 6 : VREF | 12 : VREF | + +The Arty board JTAG pinout is a defacto standard by SiFive promulgated in their documents [SiFive Freedom E310 Arty FPGA Dev Kit Getting Started Guide](https://www.sifive.com/documentation/freedom-soc/freedom-e300-arty-fpga-dev-kit-getting-started-guide/) (see Section 2.2), [SiFive Core IP FPGA Eval Kit User Guide Version v2019p05](https://sifive.cdn.prismic.io/sifive%2Fa76dc011-5d11-4d73-9e7a-900640d76f3d_fpga-getting-started_v2019p05.pdf) (see Section 3.2), and [SiFive Core IP FPGA Eval Kit User Guide Version v19.08p0](https://sifive.cdn.prismic.io/sifive%2Ff290f543-87e9-4e0b-8a4a-6287217f79bc_coreip-fpga-eval-userguide-v19_08.pdf) (see Section 3.2). + diff --git a/examples/fpga/artya7/data/pins_artya7.xdc b/examples/fpga/artya7/data/pins_artya7.xdc index a43b31bc9e..47c2bb78a0 100644 --- a/examples/fpga/artya7/data/pins_artya7.xdc +++ b/examples/fpga/artya7/data/pins_artya7.xdc @@ -71,15 +71,21 @@ set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { LED[3] #set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] ## Pmod Header JD -#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] -#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] -#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] +set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { JTAG_TDO }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] +set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { JTAG_TRST_N }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] +set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { JTAG_TCK }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] #set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] -#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] -#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] -#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9] +set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { JTAG_TDI }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] +set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { JTAG_TMS }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] +set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { JTAG_RESET_N }]; #IO_L15P_T2_DQS_35 Sch=jd[9] #set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10] +set_property PULLUP true [get_ports { JTAG_TRST_N }]; +set_property PULLUP true [get_ports { JTAG_TCK }]; +set_property PULLUP true [get_ports { JTAG_TDI }]; +set_property PULLUP true [get_ports { JTAG_TMS }]; +set_property PULLUP true [get_ports { JTAG_RESET_N }]; + ## USB-UART Interface #set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16 Sch=uart_rxd_out #set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16 Sch=uart_txd_in diff --git a/examples/fpga/artya7/rtl/dm_top.sv b/examples/fpga/artya7/rtl/dm_top.sv new file mode 100644 index 0000000000..00311bd455 --- /dev/null +++ b/examples/fpga/artya7/rtl/dm_top.sv @@ -0,0 +1,260 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Top-level debug module (DM) +// +// This module implements the RISC-V debug specification version 0.13, +// +// This toplevel wraps the PULP debug module available from +// https://github.com/pulp-platform/riscv-dbg to match the needs of +// the TL-UL-based lowRISC chip design. + +`include "prim_assert.sv" + +module dm_top #( + parameter int NrHarts = 1, + parameter logic [31:0] IdcodeValue = 32'h 0000_0001 +) ( + input logic clk_i, // clock + input logic rst_ni, // asynchronous reset active low, connect PoR + // here, not the system reset + input logic testmode_i, + output logic ndmreset_o, // non-debug module reset + output logic dmactive_o, // debug module is active + output logic [NrHarts-1:0] debug_req_o, // async debug request + input logic [NrHarts-1:0] unavailable_i, // communicate whether the hart is unavailable + // (e.g.: power down) + + // bus device with debug memory, for an execution based technique + input logic slave_req_i, + input logic slave_we_i, + input logic [BusWidth-1:0] slave_addr_i, + input logic [BusWidth/8-1:0] slave_be_i, + input logic [BusWidth-1:0] slave_wdata_i, + output logic [BusWidth-1:0] slave_rdata_o, + + // bus host, for system bus accesses + output logic master_req_o, + output logic [BusWidth-1:0] master_add_o, + output logic master_we_o, + output logic [BusWidth-1:0] master_wdata_o, + output logic [BusWidth/8-1:0] master_be_o, + input logic master_gnt_i, + input logic master_r_valid_i, + input logic [BusWidth-1:0] master_r_rdata_i, + + input jtag_pkg::jtag_req_t jtag_req_i, + output jtag_pkg::jtag_rsp_t jtag_rsp_o +); + + `ASSERT_INIT(paramCheckNrHarts, NrHarts > 0) + + localparam int BusWidth = 32; + // all harts have contiguous IDs + localparam logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}}; + + // Debug CSRs + dm::hartinfo_t [NrHarts-1:0] hartinfo; + logic [NrHarts-1:0] halted; + // logic [NrHarts-1:0] running; + logic [NrHarts-1:0] resumeack; + logic [NrHarts-1:0] haltreq; + logic [NrHarts-1:0] resumereq; + logic clear_resumeack; + logic cmd_valid; + dm::command_t cmd; + + logic cmderror_valid; + dm::cmderr_e cmderror; + logic cmdbusy; + logic [dm::ProgBufSize-1:0][31:0] progbuf; + logic [dm::DataCount-1:0][31:0] data_csrs_mem; + logic [dm::DataCount-1:0][31:0] data_mem_csrs; + logic data_valid; + logic [19:0] hartsel; + // System Bus Access Module + logic [BusWidth-1:0] sbaddress_csrs_sba; + logic [BusWidth-1:0] sbaddress_sba_csrs; + logic sbaddress_write_valid; + logic sbreadonaddr; + logic sbautoincrement; + logic [2:0] sbaccess; + logic sbreadondata; + logic [BusWidth-1:0] sbdata_write; + logic sbdata_read_valid; + logic sbdata_write_valid; + logic [BusWidth-1:0] sbdata_read; + logic sbdata_valid; + logic sbbusy; + logic sberror_valid; + logic [2:0] sberror; + + dm::dmi_req_t dmi_req; + dm::dmi_resp_t dmi_rsp; + logic dmi_req_valid, dmi_req_ready; + logic dmi_rsp_valid, dmi_rsp_ready; + logic dmi_rst_n; + + // static debug hartinfo + localparam dm::hartinfo_t DebugHartInfo = '{ + zero1: '0, + nscratch: 2, // Debug module needs at least two scratch regs + zero0: 0, + dataaccess: 1'b1, // data registers are memory mapped in the debugger + datasize: dm::DataCount, + dataaddr: dm::DataAddr + }; + for (genvar i = 0; i < NrHarts; i++) begin : gen_dm_hart_ctrl + assign hartinfo[i] = DebugHartInfo; + end + + dm_csrs #( + .NrHarts(NrHarts), + .BusWidth(BusWidth), + .SelectableHarts(SelectableHarts) + ) i_dm_csrs ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .testmode_i ( testmode_i ), + .dmi_rst_ni ( dmi_rst_n ), + .dmi_req_valid_i ( dmi_req_valid ), + .dmi_req_ready_o ( dmi_req_ready ), + .dmi_req_i ( dmi_req ), + .dmi_resp_valid_o ( dmi_rsp_valid ), + .dmi_resp_ready_i ( dmi_rsp_ready ), + .dmi_resp_o ( dmi_rsp ), + .ndmreset_o ( ndmreset_o ), + .dmactive_o ( dmactive_o ), + .hartsel_o ( hartsel ), + .hartinfo_i ( hartinfo ), + .halted_i ( halted ), + .unavailable_i, + .resumeack_i ( resumeack ), + .haltreq_o ( haltreq ), + .resumereq_o ( resumereq ), + .clear_resumeack_o ( clear_resumeack ), + .cmd_valid_o ( cmd_valid ), + .cmd_o ( cmd ), + .cmderror_valid_i ( cmderror_valid ), + .cmderror_i ( cmderror ), + .cmdbusy_i ( cmdbusy ), + .progbuf_o ( progbuf ), + .data_i ( data_mem_csrs ), + .data_valid_i ( data_valid ), + .data_o ( data_csrs_mem ), + .sbaddress_o ( sbaddress_csrs_sba ), + .sbaddress_i ( sbaddress_sba_csrs ), + .sbaddress_write_valid_o ( sbaddress_write_valid ), + .sbreadonaddr_o ( sbreadonaddr ), + .sbautoincrement_o ( sbautoincrement ), + .sbaccess_o ( sbaccess ), + .sbreadondata_o ( sbreadondata ), + .sbdata_o ( sbdata_write ), + .sbdata_read_valid_o ( sbdata_read_valid ), + .sbdata_write_valid_o ( sbdata_write_valid ), + .sbdata_i ( sbdata_read ), + .sbdata_valid_i ( sbdata_valid ), + .sbbusy_i ( sbbusy ), + .sberror_valid_i ( sberror_valid ), + .sberror_i ( sberror ) + ); + + dm_sba #( + .BusWidth(BusWidth) + ) i_dm_sba ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .master_req_o ( master_req_o ), + .master_add_o ( master_add_o ), + .master_we_o ( master_we_o ), + .master_wdata_o ( master_wdata_o ), + .master_be_o ( master_be_o ), + .master_gnt_i ( master_gnt_i ), + .master_r_valid_i ( master_r_valid_i ), + .master_r_rdata_i ( master_r_rdata_i ), + .dmactive_i ( dmactive_o ), + .sbaddress_i ( sbaddress_csrs_sba ), + .sbaddress_o ( sbaddress_sba_csrs ), + .sbaddress_write_valid_i ( sbaddress_write_valid ), + .sbreadonaddr_i ( sbreadonaddr ), + .sbautoincrement_i ( sbautoincrement ), + .sbaccess_i ( sbaccess ), + .sbreadondata_i ( sbreadondata ), + .sbdata_i ( sbdata_write ), + .sbdata_read_valid_i ( sbdata_read_valid ), + .sbdata_write_valid_i ( sbdata_write_valid ), + .sbdata_o ( sbdata_read ), + .sbdata_valid_o ( sbdata_valid ), + .sbbusy_o ( sbbusy ), + .sberror_valid_o ( sberror_valid ), + .sberror_o ( sberror ) + ); + + dm_mem #( + .NrHarts(NrHarts), + .BusWidth(BusWidth), + .SelectableHarts(SelectableHarts), + // The debug module provides a simplified ROM for systems that map the debug ROM to offset 0x0 + // on the system bus. In that case, only one scratch register has to be implemented in the core. + // However, we require that the DM can be placed at arbitrary offsets in the system, which + // requires the generalized debug ROM implementation and two scratch registers. We hence set + // this parameter to a non-zero value (inside dm_mem, this just feeds into a comparison with 0). + .DmBaseAddress(1) + ) i_dm_mem ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .debug_req_o ( debug_req_o ), + .hartsel_i ( hartsel ), + .haltreq_i ( haltreq ), + .resumereq_i ( resumereq ), + .clear_resumeack_i ( clear_resumeack ), + .halted_o ( halted ), + .resuming_o ( resumeack ), + .cmd_valid_i ( cmd_valid ), + .cmd_i ( cmd ), + .cmderror_valid_o ( cmderror_valid ), + .cmderror_o ( cmderror ), + .cmdbusy_o ( cmdbusy ), + .progbuf_i ( progbuf ), + .data_i ( data_csrs_mem ), + .data_o ( data_mem_csrs ), + .data_valid_o ( data_valid ), + .req_i ( slave_req_i ), + .we_i ( slave_we_i ), + .addr_i ( slave_addr_i ), + .wdata_i ( slave_wdata_i ), + .be_i ( slave_be_i ), + .rdata_o ( slave_rdata_o ) + ); + + // Bound-in DPI module replaces the TAP +`ifndef DMIDirectTAP + // JTAG TAP + dmi_jtag #( + .IdcodeValue (IdcodeValue) + ) dap ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .testmode_i (testmode_i), + + .dmi_rst_no (dmi_rst_n), + .dmi_req_o (dmi_req), + .dmi_req_valid_o (dmi_req_valid), + .dmi_req_ready_i (dmi_req_ready), + + .dmi_resp_i (dmi_rsp ), + .dmi_resp_ready_o (dmi_rsp_ready), + .dmi_resp_valid_i (dmi_rsp_valid), + + //JTAG + .tck_i (jtag_req_i.tck), + .tms_i (jtag_req_i.tms), + .trst_ni (jtag_req_i.trst_n), + .td_i (jtag_req_i.tdi), + .td_o (jtag_rsp_o.tdo), + .tdo_oe_o (jtag_rsp_o.tdo_oe) + ); +`endif + +endmodule diff --git a/examples/fpga/artya7/rtl/jtag_pkg.sv b/examples/fpga/artya7/rtl/jtag_pkg.sv new file mode 100644 index 0000000000..2a67ee07e2 --- /dev/null +++ b/examples/fpga/artya7/rtl/jtag_pkg.sv @@ -0,0 +1,24 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// + +package jtag_pkg; + + typedef struct packed { + logic tck; + logic tms; + logic trst_n; + logic tdi; + } jtag_req_t; + + parameter jtag_req_t JTAG_REQ_DEFAULT = '0; + + typedef struct packed { + logic tdo; + logic tdo_oe; + } jtag_rsp_t; + + parameter jtag_rsp_t JTAG_RSP_DEFAULT = '0; + +endpackage : jtag_pkg diff --git a/examples/fpga/artya7/rtl/top_artya7.sv b/examples/fpga/artya7/rtl/top_artya7.sv index c26ca459d3..8351c7cabf 100644 --- a/examples/fpga/artya7/rtl/top_artya7.sv +++ b/examples/fpga/artya7/rtl/top_artya7.sv @@ -5,7 +5,14 @@ module top_artya7 ( input IO_CLK, input IO_RST_N, - output [3:0] LED + output [3:0] LED, + + input JTAG_TCK, + input JTAG_TMS, + input JTAG_TRST_N, + input JTAG_TDI, + output JTAG_TDO, + input JTAG_RESET_N ); parameter int MEM_SIZE = 64 * 1024; // 64 kB @@ -13,16 +20,22 @@ module top_artya7 ( parameter logic [31:0] MEM_MASK = MEM_SIZE-1; parameter SRAMInitFile = ""; - logic clk_sys, rst_sys_n; + parameter logic [31:0] DEBUG_START = 32'h 1a110000; + parameter int DEBUG_SIZE = 64 * 1024; // 64 kB + parameter logic [31:0] DEBUG_MASK = DEBUG_SIZE-1; + + // debug functionality is optional + localparam DBG = 1; - // Instruction connection to SRAM + logic clk_sys, rst_sys_n, rst_core_n; + + // Ibex instruction host bus logic instr_req; logic instr_gnt; logic instr_rvalid; logic [31:0] instr_addr; - logic [31:0] instr_rdata; - // Data connection to SRAM + // Ibex data host bus logic data_req; logic data_gnt; logic data_rvalid; @@ -30,25 +43,40 @@ module top_artya7 ( logic [3:0] data_be; logic [31:0] data_addr; logic [31:0] data_wdata; - logic [31:0] data_rdata; - // SRAM arbiter - logic [31:0] mem_addr; - logic mem_req; - logic mem_write; - logic [3:0] mem_be; - logic [31:0] mem_wdata; - logic mem_rvalid; - logic [31:0] mem_rdata; + // debug unit host interface + logic dumi_req; + logic dumi_gnt; + logic dumi_rvalid; + logic [31:0] dumi_addr; + logic dumi_we; + logic [31:0] dumi_wdata; + logic [3:0] dumi_be; + + // shared system bus (arbitrated between Ibex instr, Ibex data, and debug) + logic ssb_req; + logic [31:0] ssb_addr; + logic ssb_we; + logic [31:0] ssb_wdata; + logic [3:0] ssb_be; + logic [31:0] ssb_rdata; + // addressed devices on shared system bus + logic [31:0] ssb_rdata_debug; + logic [31:0] ssb_rdata_sram; + logic ssb_req_sram, ssb_req_debug; + logic ssb_device_sram, ssb_device_debug; + + logic ndmreset_req; + logic dm_debug_req; ibex_core #( .RegFile(ibex_pkg::RegFileFPGA), - .DmHaltAddr(32'h00000000), - .DmExceptionAddr(32'h00000000) + .DmHaltAddr(DEBUG_START + dm::HaltAddress), + .DmExceptionAddr(DEBUG_START + dm::ExceptionAddress) ) u_core ( .clk_i (clk_sys), - .rst_ni (rst_sys_n), + .rst_ni (rst_core_n), .test_en_i ('b0), @@ -60,7 +88,7 @@ module top_artya7 ( .instr_gnt_i (instr_gnt), .instr_rvalid_i (instr_rvalid), .instr_addr_o (instr_addr), - .instr_rdata_i (instr_rdata), + .instr_rdata_i (ssb_rdata), .instr_err_i ('b0), .data_req_o (data_req), @@ -70,7 +98,7 @@ module top_artya7 ( .data_be_o (data_be), .data_addr_o (data_addr), .data_wdata_o (data_wdata), - .data_rdata_i (data_rdata), + .data_rdata_i (ssb_rdata), .data_err_i ('b0), .irq_software_i (1'b0), @@ -79,7 +107,7 @@ module top_artya7 ( .irq_fast_i (15'b0), .irq_nm_i (1'b0), - .debug_req_i ('b0), + .debug_req_i (dm_debug_req), .fetch_enable_i ('b1), .alert_minor_o (), @@ -87,25 +115,35 @@ module top_artya7 ( .core_sleep_o () ); - // Connect Ibex to SRAM + // arbitrate between the three would-be bus hosts always_comb begin - mem_req = 1'b0; - mem_addr = 32'b0; - mem_write = 1'b0; - mem_be = 4'b0; - mem_wdata = 32'b0; - if (instr_req) begin - mem_req = (instr_addr & ~MEM_MASK) == MEM_START; - mem_addr = instr_addr; + ssb_addr = 32'b0; + ssb_we = 1'b0; + ssb_be = 4'b0; + ssb_wdata = 32'b0; + dumi_gnt = 1'b0; + instr_gnt = 1'b0; + data_gnt = 1'b0; + if (dumi_req) begin + ssb_we = dumi_we; + ssb_be = dumi_be; + ssb_addr = dumi_addr; + ssb_wdata = dumi_wdata; + dumi_gnt = 1'b1; + end else if (instr_req) begin + ssb_addr = instr_addr; + instr_gnt = 1'b1; end else if (data_req) begin - mem_req = (data_addr & ~MEM_MASK) == MEM_START; - mem_write = data_we; - mem_be = data_be; - mem_addr = data_addr; - mem_wdata = data_wdata; + ssb_we = data_we; + ssb_be = data_be; + ssb_addr = data_addr; + ssb_wdata = data_wdata; + data_gnt = 1'b1; end end + assign ssb_req = dumi_req | instr_req | data_req; + // SRAM block for instruction and data storage ram_1p #( .Depth(MEM_SIZE / 4), @@ -113,28 +151,46 @@ module top_artya7 ( ) u_ram ( .clk_i ( clk_sys ), .rst_ni ( rst_sys_n ), - .req_i ( mem_req ), - .we_i ( mem_write ), - .be_i ( mem_be ), - .addr_i ( mem_addr ), - .wdata_i ( mem_wdata ), - .rvalid_o ( mem_rvalid ), - .rdata_o ( mem_rdata ) + .req_i ( ssb_req_sram ), + .we_i ( ssb_we ), + .be_i ( ssb_be ), + .addr_i ( ssb_addr ), + .wdata_i ( ssb_wdata ), + .rvalid_o (), + .rdata_o ( ssb_rdata_sram ) ); - // SRAM to Ibex - assign instr_rdata = mem_rdata; - assign data_rdata = mem_rdata; - assign instr_rvalid = mem_rvalid; - always_ff @(posedge clk_sys or negedge rst_sys_n) begin - if (!rst_sys_n) begin - instr_gnt <= 'b0; - data_gnt <= 'b0; - data_rvalid <= 'b0; + // decode which device is being addressed + + always @(posedge clk_sys, negedge rst_sys_n) + begin + if (~rst_sys_n) + begin + ssb_device_debug <= 1'b0; + ssb_device_sram <= 1'b0; + end else begin + ssb_device_debug <= ssb_req_debug; + ssb_device_sram <= ssb_req_sram; + end + end + + assign ssb_req_sram = ((ssb_addr & ~MEM_MASK) == MEM_START) && ssb_req; + assign ssb_req_debug = ((ssb_addr & ~DEBUG_MASK) == DEBUG_START) && ssb_req; + + assign ssb_rdata = ( {32{ssb_device_debug}} & ssb_rdata_debug ) | + ( {32{ssb_device_sram}} & ssb_rdata_sram ); + + always @(posedge clk_sys, negedge rst_sys_n) + begin + if (~rst_sys_n) + begin + instr_rvalid <= 1'b0; + data_rvalid <= 1'b0; + dumi_rvalid <= 1'b0; end else begin - instr_gnt <= instr_req && mem_req; - data_gnt <= ~instr_req && data_req && mem_req; - data_rvalid <= ~instr_req && data_req && mem_req; + instr_rvalid <= instr_gnt; + data_rvalid <= data_gnt; + dumi_rvalid <= dumi_gnt; end end @@ -145,7 +201,7 @@ module top_artya7 ( if (!rst_sys_n) begin leds <= 4'b0; end else begin - if (mem_req && data_req && data_we) begin + if (ssb_req_sram && data_req && data_we) begin for (int i = 0; i < 4; i = i + 1) begin if (data_be[i] == 1'b1) begin leds <= data_wdata[i*8 +: 4]; @@ -165,4 +221,78 @@ module top_artya7 ( .rst_sys_n ); + assign rst_core_n = rst_sys_n & JTAG_RESET_N & ~ndmreset_req; + + // Manufacturers must replace this code with one of their own IDs. + // Field structure as defined in the IEEE 1149.1 (JTAG) specification, + // section 12.1.1. + localparam logic [31:0] JTAG_IDCODE = { + 4'h0, // Version + 16'h4942, // Part Number: "IB" + 11'h426, // Manufacturer Identity: Google + 1'b1 // (fixed) + }; + + // instantiate debug unit + + jtag_pkg::jtag_req_t jtag_req; + jtag_pkg::jtag_rsp_t jtag_rsp; + logic unused_jtag_tdo_oe_o; + + assign jtag_req.tck = JTAG_TCK; + assign jtag_req.tms = JTAG_TMS; + assign jtag_req.trst_n = JTAG_TRST_N; + assign jtag_req.tdi = JTAG_TDI; + assign JTAG_TDO = jtag_rsp.tdo; + assign unused_jtag_tdo_oe_o = jtag_rsp.tdo_oe; + + generate + if (DBG == 1) begin + dm_top #( + .NrHarts (1), + .IdcodeValue (JTAG_IDCODE) + ) u_dm_top ( + .clk_i (clk_sys), + .rst_ni (rst_sys_n), + .testmode_i (1'b0), + .ndmreset_o (ndmreset_req), + .dmactive_o (), + .debug_req_o (dm_debug_req), + .unavailable_i (1'b0), + + // bus device with debug memory (for execution-based debug) + .slave_req_i ( ssb_req_debug ), + .slave_we_i ( ssb_we ), + .slave_addr_i ( ssb_addr ), + .slave_be_i ( ssb_be ), + .slave_wdata_i ( ssb_wdata ), + .slave_rdata_o ( ssb_rdata_debug ), + + // bus host (for system bus accesses, SBA) + .master_req_o ( dumi_req ), + .master_add_o ( dumi_addr ), + .master_we_o ( dumi_we ), + .master_wdata_o ( dumi_wdata ), + .master_be_o ( dumi_be ), + .master_gnt_i ( dumi_gnt ), + .master_r_valid_i ( dumi_rvalid ), + .master_r_rdata_i ( ssb_rdata ), + + //JTAG + .jtag_req_i (jtag_req), + .jtag_rsp_o (jtag_rsp) + ); + end + if (DBG == 0) begin + assign dm_debug_req = 1'b0; + assign ndmreset_req = 1'b0; + assign dumi_req = 1'b0; + assign dumi_addr = 32'h0; + assign dumi_we = 1'b0; + assign dumi_wdata = 32'h0; + assign dumi_be = 4'b0; + assign ssb_rdata_debug = 32'h0; + end + endgenerate + endmodule diff --git a/examples/fpga/artya7/top_artya7.core b/examples/fpga/artya7/top_artya7.core index 811fb93cad..6521b8f661 100644 --- a/examples/fpga/artya7/top_artya7.core +++ b/examples/fpga/artya7/top_artya7.core @@ -9,8 +9,11 @@ filesets: depend: - lowrisc:ibex:ibex_core - lowrisc:ibex:fpga_xilinx_shared + - pulp-platform:riscv-dbg:0.1 files: + - rtl/jtag_pkg.sv - rtl/top_artya7.sv + - rtl/dm_top.sv file_type: systemVerilogSource files_constraints: diff --git a/pulp_riscv_dbg.core b/pulp_riscv_dbg.core new file mode 100644 index 0000000000..5e3f4e8583 --- /dev/null +++ b/pulp_riscv_dbg.core @@ -0,0 +1,28 @@ +CAPI=2: +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "pulp-platform:riscv-dbg:0.1" +description: "RISC-V Debug Module" + +filesets: + files_src: + depend: + - lowrisc:prim:all + - lowrisc:prim:clock_inv + files: + - vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv + - vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv + - vendor/pulp_riscv_dbg/src/dm_pkg.sv + - vendor/pulp_riscv_dbg/src/dm_sba.sv + - vendor/pulp_riscv_dbg/src/dm_csrs.sv + - vendor/pulp_riscv_dbg/src/dm_mem.sv + - vendor/pulp_riscv_dbg/src/dmi_cdc.sv + - vendor/pulp_riscv_dbg/src/dmi_jtag.sv + - vendor/pulp_riscv_dbg/src/dmi_jtag_tap.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_src From d1c9e5db4ba6608e153990a63849b42e4717ab01 Mon Sep 17 00:00:00 2001 From: Peter Lawrence <12226419+majbthrd@users.noreply.github.com> Date: Sun, 10 Jan 2021 15:03:18 -0600 Subject: [PATCH 3/3] Enable two debug triggers (breakpoints) in artya7 FPGA example Set the ibex_core parameters 'DbgTriggerEn' and 'DbgHwBreakNum' for two hardware breakpoints when DBG is enabled. Enabling this in the Ibex core is strongly desirable to present a good debug experience. Moreover, some RISC-V debug tools assume that breakpoints exist on the target, so failure to have this in the example only causes a frustrated user. --- examples/fpga/artya7/rtl/top_artya7.sv | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/fpga/artya7/rtl/top_artya7.sv b/examples/fpga/artya7/rtl/top_artya7.sv index 8351c7cabf..f022ff7d90 100644 --- a/examples/fpga/artya7/rtl/top_artya7.sv +++ b/examples/fpga/artya7/rtl/top_artya7.sv @@ -26,6 +26,8 @@ module top_artya7 ( // debug functionality is optional localparam DBG = 1; + localparam int unsigned DbgHwBreakNum = (DBG == 1) ? 2 : 0; + localparam bit DbgTriggerEn = (DBG == 1) ? 1'b1 : 1'b0; logic clk_sys, rst_sys_n, rst_core_n; @@ -72,6 +74,8 @@ module top_artya7 ( ibex_core #( .RegFile(ibex_pkg::RegFileFPGA), + .DbgTriggerEn(DbgTriggerEn), + .DbgHwBreakNum(DbgHwBreakNum), .DmHaltAddr(DEBUG_START + dm::HaltAddress), .DmExceptionAddr(DEBUG_START + dm::ExceptionAddress) ) u_core (