├── .clang-format ├── .github └── workflows │ └── style.yml ├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── docs └── DEVELOPMENT.md ├── examples ├── CMakeLists.txt ├── smoke.cc └── smoke_report.cc ├── report ├── CMakeLists.txt ├── README.md ├── include │ └── scp │ │ ├── helpers.h │ │ └── report.h └── src │ └── report.cpp ├── tlm_extensions ├── initiator_id │ ├── CMakeLists.txt │ ├── README.md │ ├── include │ │ └── scp │ │ │ └── tlm_extensions │ │ │ └── initiator_id.h │ └── tests │ │ ├── CMakeLists.txt │ │ └── smoke.cc └── path_trace │ ├── CMakeLists.txt │ ├── README.md │ ├── include │ └── scp │ │ └── tlm_extensions │ │ └── path_trace.h │ └── tests │ ├── CMakeLists.txt │ └── smoke.cc └── utils └── check_format.sh /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | 5 | ColumnLimit: 79 6 | UseTab: Never 7 | IndentWidth: 4 8 | IndentCaseLabels: false 9 | 10 | PointerAlignment: Left 11 | DerivePointerAlignment: false 12 | 13 | AccessModifierOffset: -4 14 | 15 | AlignAfterOpenBracket: Align 16 | AlignConsecutiveMacros: true 17 | AlignConsecutiveAssignments: false 18 | 19 | AllowAllArgumentsOnNextLine: false 20 | AllowShortFunctionsOnASingleLine: InlineOnly 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | 24 | BreakConstructorInitializers: AfterColon 25 | BreakBeforeBinaryOperators: None 26 | BreakStringLiterals: true 27 | BreakBeforeBraces: Custom 28 | BraceWrapping: 29 | AfterClass: true 30 | 31 | SpaceBeforeCtorInitializerColon: false 32 | SpacesBeforeTrailingComments: 1 33 | 34 | SortIncludes: false 35 | SortUsingDeclarations: false 36 | 37 | Cpp11BracedListStyle: false 38 | PenaltyBreakAssignment: 2000 39 | 40 | ForEachMacros: ['SC_MODULE', 'SC_CTOR'] 41 | -------------------------------------------------------------------------------- /.github/workflows/style.yml: -------------------------------------------------------------------------------- 1 | name: style 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | style: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | 14 | - name: Check code style 15 | run: ./utils/check_format.sh -n 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /_build/ 3 | /.cproject 4 | /.project 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | project(scp VERSION 1.0 LANGUAGES CXX C) 3 | 4 | set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.") 5 | 6 | set(GITHUB "https://github.com/" CACHE STRING "github base url") 7 | 8 | include(FetchContent) 9 | include(CTest) 10 | 11 | FetchContent_Declare( 12 | cpm-cmake 13 | GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git 14 | GIT_SHALLOW True 15 | GIT_TAG v0.31.1 16 | ) 17 | 18 | FetchContent_MakeAvailable(cpm-cmake) 19 | include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) 20 | 21 | cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") 22 | 23 | cpmaddpackage( 24 | NAME SystemCLanguage 25 | GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git 26 | GIT_SHALLOW True 27 | GIT_TAG main 28 | ) 29 | 30 | cpmaddpackage( 31 | NAME initiator_id 32 | SOURCE_DIR ${PROJECT_SOURCE_DIR}/tlm_extensions/initiator_id 33 | ) 34 | cpmaddpackage( 35 | NAME path_trace 36 | SOURCE_DIR ${PROJECT_SOURCE_DIR}/tlm_extensions/path_trace 37 | ) 38 | cpmaddpackage( 39 | NAME report 40 | SOURCE_DIR ${PROJECT_SOURCE_DIR}/report 41 | ) 42 | 43 | if("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}") 44 | add_subdirectory(examples) 45 | if(BUILD_TESTING) 46 | enable_testing() 47 | endif() 48 | endif() 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to Contribute 2 | ================= 3 | 4 | This repository is owned by the [Accellera Systems Initiative][1] and 5 | is maintained by the SystemC Common Practices Working Group 6 | according to the [Accellera Policies and Procedures][2]. 7 | 8 | **Contributions to this reference implementation can only be 9 | accepted from Accellera members.** 10 | 11 | ### Join the Accellera SystemC Common Practices Working Group 12 | 13 | If you would like to contribute to the development of one of the SystemC 14 | reference implementations, have your company, organization, or university 15 | join Accellera and its working groups. 16 | Find out more information at http://www.accellera.org/about/join. 17 | If your company, organization or university is already an Accellera member, 18 | you can request to [join the SystemC Language Working Group here][3]. 19 | 20 | ### Join the SystemC community 21 | 22 | If you are not an Accellera member, please join the **[SystemC Forum][4]** 23 | to provide feedback, report bugs and join the general 24 | discussion around the evolution of SystemC and its ecosystem. 25 | 26 | --------------------------------------------------------------------- 27 | Issue reporting 28 | --------------------------------------------------------------------- 29 | 30 | You can post issues, bugs and suggestions of general interest to the 31 | [SystemC Forum][4] or [Issue tracker][5]. When reporting bugs, please specify 32 | the following information (if applicable): 33 | 34 | 1. SystemC library version 35 | 2. platform, compiler, flags 36 | 3. description of the problem 37 | 4. steps to reproduce the problem 38 | 5. compile/runtime warnings and errors 39 | 6. code sample, not more than 100 lines to demonstrate the problem 40 | 41 | > **Note** 42 | > All bugs will only be tested against the latest publicly available 43 | > version of the product. 44 | 45 | > **Note** 46 | > All C++ compilers that SystemC supports have bugs of different 47 | > degree of severity. We cannot fix those bugs. 48 | > Please report them to the compiler vendor. 49 | 50 | --------------------------------------------------------------------- 51 | Patch submission 52 | --------------------------------------------------------------------- 53 | 54 | The following **sign-off procedure** is established to ensure that 55 | patches submitted for inclusion into this Accellera reference 56 | implementation are properly licensed under the 57 | [Apache License Version 2.0](LICENSE). 58 | 59 | The sign-off is a simple line at the end of the explanation for the 60 | patch (or commit message), which certifies that you wrote it yourself 61 | or otherwise have the right to pass it on as an open-source patch: 62 | 63 | ### Accellera Developer's Certificate of Origin 64 | 65 | By making a signed-off contribution to this Accellera project, 66 | I certify that: 67 | 68 | 1. The contribution was created in whole or in part by me and I have 69 | the right to submit it under the Apache License Version 2.0 70 | (see LICENSE). 71 | 72 | 2. The contribution was provided directly to me by some other person 73 | who certified (1) above, and I am forwarding it without 74 | modification. 75 | 76 | 3. I understand and agree that this Accellera project and the 77 | contribution are public and that a record of the contribution 78 | (including all personal information I submit with it, including 79 | my sign-off) is maintained indefinitely and may be redistributed 80 | in accordance with this project or the Apache License Version 2.0. 81 | 82 | If you can certify the above *Accellera Developer's Certificate of Origin*, 83 | please use `git commit --signoff` to add a line of the form: 84 | ``` 85 | Signed-off-by: Ima Contributor 86 | ``` 87 | using your real name (no pseudonyms or anonymous contributions). 88 | 89 | > **Note** 90 | > For Accellera members, contributions are already bound by the 91 | > [Accellera policies and procedures][2] and the sign-off is optional, 92 | > but recommended. For **non-Accellera** members, the sign-off is 93 | > **mandatory** for consideration by the Accellera WGs. 94 | 95 | When submitting a pull-request against the public repository, the 96 | contribution may be considered by the Accellera WGs for inclusion. It 97 | stays under the sole governance 98 | of the corresponding WGs to decide whether a contribution will be included 99 | in the reference implementation (or future Accellera standards). 100 | 101 | --------------------------------------------------------------------- 102 | Repository organization 103 | --------------------------------------------------------------------- 104 | 105 | More information on the repository organization can be found in the 106 | [Development process description](./docs/DEVELOPMENT.md). 107 | 108 | 109 | [1]: https://www.accellera.org 110 | [2]: https://accellera.org/about/policies-and-procedures 111 | [3]: https://workspace.accellera.org/apps/org/workgroup/lwg/ 112 | [4]: https://forums.accellera.org/forum/9-systemc/ 113 | [5]: https://github.com/accellera-official/systemc-common-practices/issues -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4 d of the Apache License, == 3 | == Version 2.0, in this case for SystemC Common Practices == 4 | == sample code == 5 | ========================================================================= 6 | 7 | 8 | This product includes software developed by GreenSocs SAS, 24380 Chalagnac, France, 9 | Copyright(c) 2022 GreenSocs SAS. 10 | All rights reserved. 11 | 12 | Qualcomm Innovation Center, Inc. 13 | Copyright(c) 2022 14 | All Rights Reserved. 15 | 16 | MINRES Technologies GmbH 17 | Copyright(c) 2022 18 | All Rights Reserved. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Common Practices Working group additions 3 | 4 | 5 | ## Collection of TLM Extensions 6 | 7 | The collection of interfaces here are independent of each other. They provide 'common' functionality in an architecturally independent way. 8 | 9 | ## CCI Parameters 10 | 11 | This is a list of parameter names and their meanings 12 | 13 | 14 | | Applies to | parameter name | type | Description | 15 | |:----------:| -------------- | ---- | ----------- | 16 | Initiator socket | "initiator_id" | uint64_t | The ID that should be applied to a transaction leaving this initiator (typically stamped on a initiator_id extension) | 17 | Target socket | "address" | int64_t/uint64_t | Base address of a target socket. A "signed" value should be interpreted correctly (this is convenient to be able to specify remaining, large, address ranges) 18 | Target socket | "size" | uint64_t | Size of address range of a target socket. The address and size pair specify the part of the address space which should be 'routed' to the target socket. 19 | Target socket | "relative_addresses" | bool | Specifies that relative addresses should be used (which should be the default). In other words, the address space, as seen by the target socket, will start at 0. 20 | 21 | ## Reporting infrastructure 22 | 23 | The reporting infrastructure consist of 2 part: the frontend on to of sc_report and the backend, replacing SystemC standard handler. Both can be used independently. 24 | 25 | ### Reporting frontend 26 | 27 | The frontend consist of a set of macros which provide a std::ostream to log a message. The execution of the logging code is dependend on the loglevel thus not impacting performance if the message is not logged. 28 | 29 | The macros take an optional argument which becomes the message type. If not is provided, the default 'SystemC' is being used. The following table outlines how the scp::log level map to the SystemC logging parameter. 30 | 31 | | SCP log level | SystemC severity | SystemC verbosity | 32 | |---------------|------------------|-------------------| 33 | | SCCFATAL | SC_FATAL | -- | 34 | | SCCERR | SC_ERROR | -- | 35 | | SCCWARN | SC_WARNING | -- | 36 | | SCCINFO | SC_INFO | SC_MEDIUM | 37 | | SCCDEBUG | SC_INFO | SC_HIGH | 38 | | SCCTRACE | SC_INFO | SC_FULL | 39 | | SCCTRACEALL | SC_INFO | SC_DEBUG | 40 | 41 | ### Reporting backend 42 | 43 | The backend is initialized using the short form: 44 | 45 | ``` 46 | scp::init_logging(scp::log::INFO); 47 | ``` 48 | 49 | or the long form 50 | 51 | ``` 52 | scp::init_logging(scp::LogConfig() 53 | .logLevel(scp::log::DEBUG) // set log level to debug 54 | .msgTypeFieldWidth(10)); // make the msg type column a bit tighter 55 | ``` 56 | 57 | which allows more configurability. For detail please check the header file report.h 58 | In both case an alternate report handler is installed which which uses a tabular format and spdlog for writing. By default spdlog logs asyncronously to keep the performance impact low. 59 | -------------------------------------------------------------------------------- /docs/DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | Development process of the Accellera SystemC Common Practices library 2 | ===================================================================== 3 | 4 | This document focuses on the technical aspects related to the development 5 | of the SystemC Common Practices library. 6 | Legal and formal procedures are documented at 7 | 8 | https://accellera.org/about/policies-and-procedures. 9 | 10 | --------------------------------------------------------------------- 11 | Repository setup 12 | --------------------------------------------------------------------- 13 | 14 | The central source code repository of the Accellera Common Practices library 15 | is hosted at [GitHub](https://github.com/accellera-official/). 16 | The read-only repository can be found at 17 | 18 | * https://github.com/accellera-official/systemc-common-practices 19 | 20 | ### Creating a personal fork 21 | 22 | In order to contribute changes to the repository, it is recommended to create 23 | personal (or company-based) [forks][2] of the repository on GitHub and push 24 | the proposed changes (bugfixes, features, ...) there. Details of the intended 25 | work-flow are described in the next [section](#basic-branch-setup). It is 26 | convenient to add this GitHub fork as a remote to your local clone of the 27 | repository: 28 | 29 | cd / 30 | git remote add origin git@github.com:/.git 31 | git branch --set-upstream master origin/master 32 | 33 | Contributions to the Accellera SystemC Common Practices library should comply with the 34 | [contributing guidelines][1]. 35 | 36 | Any changes can then be pushed to GitHub using: 37 | 38 | git push [options] [] [...] 39 | 40 | * If you omit the ``, the default destination is 41 | the remote of the current branch (or `origin`). 42 | * The `` basically follows the format 43 | `:`, or just ``, if 44 | both are the same. 45 | * Omitting the `` pushes all branches with 'matching' 46 | remote branches to the repository. 47 | 48 | A basic cheat sheet containing the an overview of the general 49 | Git commands and workflow can be found [online][3]. 50 | 51 | --------------------------------------------------------------------- 52 | Development flow 53 | --------------------------------------------------------------------- 54 | 55 | ### Adding a feature (set) or bug fix 56 | 57 | The development of a new contribution in form of a feature or a 58 | complex bug fix is best done in a new feature branch, which is 59 | forked and checked out from the `main` branch: 60 | 61 | git checkout -b - main 62 | 63 | Then code up the new contribution. Please try to facilitate code 64 | review by other Accellera members by logically grouping your changes into 65 | one commit per addressed issue. For the commit messages, please 66 | consider to follow these suggestions: 67 | 68 | > *Note:* **Commit messages** 69 | > 70 | > Though not required, it's a good idea to begin the commit message with 71 | > a single short (less than 50 character) line summarizing the change, 72 | > followed by a blank line and then a more thorough description. Tools 73 | > that turn commits into email, for example, use the first line on the 74 | > `Subject:` line and the rest of the commit in the body. 75 | 76 | > *Note:* **Sign-off procedure for commits** 77 | > 78 | > In order to document that contributions are submitted under the 79 | > Apache-2.0 license (see `LICENSE`), a sign-off procedure is 80 | > defined in the [contributing guidelines][1]. 81 | 82 | During the development of the contribution, the `main` branch may 83 | receive other commits. In that case, consider rebasing the commits in 84 | your feature branch onto the `HEAD` of the `main` branch to keep the 85 | history clean. Once the contribution is ready for review by the 86 | working group, push the feature branch in your fork of the respective 87 | repository on GitHub: 88 | 89 | git push - 90 | 91 | Then, send a [pull request][4] either manually or via [GitHub][4] to 92 | initiate the code review by the Accellera working group members. 93 | The summary can be manually generated by 94 | 95 | git request-pull main git@github.com//.git \ 96 | 97 | 98 | To review the proposed contributions, one can either browse the 99 | repository at GitHub, or add the remote location to a local 100 | clone of the repository 101 | 102 | # add the fork to your set of "remotes" 103 | git remote add git@github.com//.git 104 | git fetch 105 | 106 | # examine differences 107 | git diff main../ 108 | git log / 109 | 110 | After the contribution is accepted, it will be merged into the 111 | `main` branch by the responsible source code maintainer. This should 112 | be done with an explicit *merge commit*, to keep the individual 113 | contributions separated: 114 | 115 | git merge --no-ff --log \ 116 | / 117 | 118 | Instead of fully merging the contribution, the maintainer may choose 119 | to cherry-pick individual commits or to rebase the feature branch on 120 | an intermittently updated `main`. He may also request additional 121 | changes to be done by the submitter. In that case, the submitter may 122 | need to merge recent changes to the `main` branch into his feature 123 | branch before carrying out the requested changes. 124 | 125 | After the contribution has been fully merged into the `main` branch, the 126 | feature branch in the local and Github fork may be deleted. 127 | 128 | git branch -d # delete local branch 129 | git push origin : # delete remote branch 130 | 131 | --------------------------------------------------------------------- 132 | Issue tracking 133 | --------------------------------------------------------------------- 134 | 135 | Open issues (bugs, cleanups, features) related to the reference 136 | implementation of SystemC Common Practices library are tracked via GitHub: 137 | 138 | * 139 | 140 | The discussion on issues usually starts on the Accellera Working Group 141 | email reflector or during the working group meetings. After an initial 142 | consensus on the "validity" of the issue, the issue is added to the 143 | issue tracking system, a classification is done (including a target 144 | milestone), and preferably a responsible person is assigned. 145 | 146 | 147 | [1]: ../CONTRIBUTING.md "How to Contribute" 148 | [2]: https://docs.github.com/en/get-started/quickstart/fork-a-repo 149 | [3]: http://zrusin.blogspot.de/2007/09/git-cheat-sheet.html "Git Cheat Sheet" 150 | [4]: https://help.github.com/articles/using-pull-requests "Using Pull Requests - github:help" -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(scp-tests VERSION 1.0 LANGUAGES CXX C) 3 | 4 | macro(run_test test) 5 | add_executable(${test} ${test}.cc) 6 | target_link_libraries(${test} scp::tlm_extensions::initiator_id scp::tlm_extensions::path_trace scp::reporting SystemC::systemc SystemC::cci) 7 | add_test(NAME ${test} COMMAND ${test}) 8 | set_tests_properties(${test} PROPERTIES TIMEOUT 10) 9 | endmacro() 10 | 11 | run_test(smoke) 12 | run_test(smoke_report) 13 | -------------------------------------------------------------------------------- /examples/smoke.cc: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | SC_MODULE (test) { 24 | SC_CTOR (test) { 25 | scp::tlm_extensions::path_trace ext; 26 | ext.stamp(this); 27 | SCP_INFO(SCMOD) << ext.to_string(); 28 | ext.reset(); 29 | 30 | ext.stamp(this); 31 | ext.stamp(this); 32 | ext.stamp(this); 33 | 34 | SCP_INFO(SCMOD) << ext.to_string(); 35 | ext.reset(); 36 | 37 | scp::tlm_extensions::initiator_id mid(0x1234); 38 | mid = 0x2345; 39 | mid &= 0xff; 40 | mid <<= 4; 41 | uint64_t myint = mid + mid; 42 | myint += mid; 43 | if (mid == 0x450) { 44 | SC_REPORT_INFO("ext test", "Success"); 45 | } else { 46 | SC_REPORT_INFO("ext test", "Failour"); 47 | } 48 | } 49 | }; 50 | 51 | int sc_main(int argc, char** argv) { 52 | SCP_INFO() << "Constructing design"; 53 | test test1("test"); 54 | SCP_INFO() << "Starting simulation"; 55 | sc_core::sc_start(); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/smoke_report.cc: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | SC_MODULE (test4) { 31 | SC_CTOR (test4) { 32 | SCP_INFO(()) << " . T4 Logger() 1"; 33 | SCP_WARN(()) << " . T4 Logger() 1"; 34 | SCP_INFO(()) << " . T4 Logger() 2"; 35 | SCP_WARN(()) << " . T4 Logger() 2"; 36 | } 37 | SCP_LOGGER(); 38 | }; 39 | 40 | SC_MODULE (test3) { 41 | SC_CTOR (test3) { 42 | SCP_INFO((D)) << " . T3 D Logger \"other\" \"feature.one\""; 43 | SCP_WARN((D)) << " . T3 D Logger \"other\" \"feature.one\""; 44 | SCP_INFO(()) << " . T3 Logger ()"; 45 | SCP_WARN(()) << " . T3 Logger ()"; 46 | } 47 | SCP_LOGGER((D), "other", "feature.one"); 48 | SCP_LOGGER(()); 49 | }; 50 | 51 | SC_MODULE (test2) { 52 | SC_CTOR (test2) : t31("t3_1"), t32("t3_2"), t4("t4") { 53 | SCP_INFO(()) << " T2 Logger()"; 54 | SCP_WARN(()) << " T2 Logger()"; 55 | } 56 | SCP_LOGGER(); 57 | test3 t31, t32; 58 | test4 t4; 59 | }; 60 | 61 | SC_MODULE (test1) { 62 | SC_CTOR (test1) : t2("t2") { 63 | SCP_WARN((), "My.Name") << " T1 My.Name typed log"; 64 | SCP_INFO(()) << " T1 Logger()"; 65 | SCP_WARN(()) << " T1 Logger()"; 66 | 67 | SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing1"); 68 | SCP_LOGGER_VECTOR_PUSH_BACK(vec, "some", "thing2"); 69 | 70 | SCP_INFO((vec[0])) << "Thing1?"; 71 | SCP_WARN((vec[0])) << "Thing1?"; 72 | SCP_INFO((vec[1])) << "Thing2?"; 73 | SCP_WARN((vec[1])) << "Thing2?"; 74 | } 75 | SCP_LOGGER("something", "else"); 76 | SCP_LOGGER_VECTOR(vec); 77 | test2 t2; 78 | }; 79 | 80 | class outside_class 81 | { 82 | SCP_LOGGER("out.class", "thing1"); 83 | 84 | public: 85 | outside_class() { 86 | SCP_INFO(())("constructor"); 87 | SCP_WARN(())("constructor"); 88 | } 89 | }; 90 | 91 | SC_MODULE (test) { 92 | outside_class oc; 93 | SC_CTOR (test) { 94 | SCP_DEBUG(SCMOD) << "First part"; 95 | scp::tlm_extensions::path_trace ext; 96 | ext.stamp(this); 97 | SCP_INFO(SCMOD) << ext.to_string(); 98 | ext.reset(); 99 | 100 | ext.stamp(this); 101 | ext.stamp(this); 102 | ext.stamp(this); 103 | 104 | SCP_INFO(SCMOD) << ext.to_string(); 105 | ext.reset(); 106 | 107 | SCP_DEBUG(SCMOD) << "Second part"; 108 | scp::tlm_extensions::initiator_id mid(0x1234); 109 | mid = 0x2345; 110 | mid &= 0xff; 111 | mid <<= 4; 112 | uint64_t myint = mid + mid; 113 | myint += mid; 114 | if (mid == 0x450) { 115 | SC_REPORT_INFO("ext test", "Success"); 116 | } else { 117 | SC_REPORT_INFO("ext test", "Failour"); 118 | } 119 | 120 | SCP_INFO() << "Uncached version empty"; 121 | SCP_INFO(())("FMT String : Cached version default"); 122 | SCP_INFO(SCMOD) << "UnCached version feature using SCMOD macro"; 123 | SCP_INFO((m_my_logger)) << "Cached version using (m_my_logger)"; 124 | SCP_INFO((D)) << "Cached version with D"; 125 | } 126 | 127 | SCP_LOGGER((m_my_logger)); 128 | SCP_LOGGER(()); 129 | SCP_LOGGER((1), "other"); 130 | SCP_LOGGER((D), "other", "feature.one"); 131 | }; 132 | 133 | int sc_main(int argc, char** argv) { 134 | cci_utils::consuming_broker broker("global_broker"); 135 | cci_register_broker(broker); 136 | cci::cci_originator orig("config"); 137 | broker.set_preset_cci_value("log_level", cci::cci_value(1), orig); 138 | broker.set_preset_cci_value("top.log_level", cci::cci_value(5), orig); 139 | broker.set_preset_cci_value("*.t3_1.log_level", cci::cci_value(5), orig); 140 | broker.set_preset_cci_value("feature.log_level", cci::cci_value(5), orig); 141 | 142 | broker.set_preset_cci_value("test4.log_level", cci::cci_value(4), orig); 143 | broker.set_preset_cci_value("thing1.log_level", cci::cci_value(5), orig); 144 | 145 | std::string logfile = "/tmp/scp_smoke_report_test." + 146 | std::to_string(getpid()); 147 | scp::init_logging( 148 | scp::LogConfig() 149 | .logLevel(scp::log::DEBUG) // set log level to debug 150 | .msgTypeFieldWidth(20) 151 | .fileInfoFrom(5) 152 | .logAsync(false) 153 | .printSimTime(false) 154 | .logFileName(logfile)); // make the msg type column a bit tighter 155 | SCP_INFO() << "Constructing design"; 156 | test toptest("top"); 157 | test1 t1("t1"); 158 | 159 | SCP_INFO() << "Starting simulation"; 160 | sc_core::sc_start(); 161 | SCP_WARN() << "Ending simulation"; 162 | 163 | #ifdef FMT_SHARED 164 | std::string fmtstr = "FMT String : Cached version default"; 165 | #else 166 | std::string fmtstr = "Please add FMT library for FMT support."; 167 | #endif 168 | 169 | std::string expected = 170 | R"([ info] [ 0 s ]SystemC : Constructing design 171 | [ info] [ 0 s ]out.class : constructor 172 | [ warning] [ 0 s ]out.class : constructor 173 | [ debug] [ 0 s ]top : First part 174 | [ info] [ 0 s ]top : top 175 | [ info] [ 0 s ]top : top->top->top 176 | [ debug] [ 0 s ]top : Second part 177 | [ info] [ 0 s ]ext test : Success 178 | [ info] [ 0 s ]SystemC : Uncached version empty 179 | [ info] [ 0 s ]top : )" + 180 | fmtstr + R"( 181 | [ info] [ 0 s ]top : UnCached version feature using SCMOD macro 182 | [ info] [ 0 s ]top : Cached version using (m_my_logger) 183 | [ info] [ 0 s ]top : Cached version with D 184 | [ info] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" 185 | [ warning] [ 0 s ]t1.t2.t3_1 : . T3 D Logger "other" "feature.one" 186 | [ info] [ 0 s ]t1.t2.t3_1 : . T3 Logger () 187 | [ warning] [ 0 s ]t1.t2.t3_1 : . T3 Logger () 188 | [ info] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" 189 | [ warning] [ 0 s ]t1.t2.t3_2 : . T3 D Logger "other" "feature.one" 190 | [ warning] [ 0 s ]t1.t2.t3_2 : . T3 Logger () 191 | [ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 192 | [ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 1 193 | [ info] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 194 | [ warning] [ 0 s ]t1.t2.t4 : . T4 Logger() 2 195 | [ warning] [ 0 s ]t1.t2 : T2 Logger() 196 | [ warning] [ 0 s ]My.Name : T1 My.Name typed log 197 | [ warning] [ 0 s ]t1 : T1 Logger() 198 | [ info] [ 0 s ]t1 : Thing1? 199 | [ warning] [ 0 s ]t1 : Thing1? 200 | [ warning] [ 0 s ]t1 : Thing2? 201 | [ info] [ 0 s ]SystemC : Starting simulation 202 | [ warning] [ 0 s ]SystemC : Ending simulation 203 | )"; 204 | 205 | std::ifstream lf(logfile); 206 | std::string out((std::istreambuf_iterator(lf)), 207 | std::istreambuf_iterator()); 208 | 209 | std::cout << "out file\n" << out << "\n"; 210 | std::cout << "expected\n" << expected << "\n"; 211 | std::cout << "Number of difference: " << out.compare(expected) << "\n"; 212 | 213 | std::remove(logfile.c_str()); 214 | return out.compare(expected); 215 | } 216 | -------------------------------------------------------------------------------- /report/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | project(reporting VERSION 1.0 LANGUAGES CXX C) 3 | 4 | set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.") 5 | 6 | set(GITHUB "https://github.com/" CACHE STRING "github base url") 7 | 8 | include(FetchContent) 9 | include(CTest) 10 | 11 | FetchContent_Declare( 12 | cpm-cmake 13 | GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git 14 | GIT_SHALLOW True 15 | GIT_TAG v0.31.1 16 | ) 17 | 18 | FetchContent_MakeAvailable(cpm-cmake) 19 | include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) 20 | 21 | cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") 22 | 23 | cpmaddpackage( 24 | NAME SystemCLanguage 25 | GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git 26 | GIT_SHALLOW True 27 | GIT_TAG main 28 | ) 29 | 30 | cpmaddpackage( 31 | NAME SystemCCCI 32 | GIT_REPOSITORY ${GITHUB}accellera-official/cci.git 33 | GIT_SHALLOW True 34 | GIT_TAG main 35 | ) 36 | 37 | set(WITH_FMT "true" CACHE STRING "Include FMT library") 38 | if (WITH_FMT) 39 | cpmaddpackage( 40 | NAME fmt 41 | GIT_REPOSITORY ${GITHUB}fmtlib/fmt.git 42 | GIT_SHALLOW True 43 | GIT_TAG 9.1.0 44 | OPTIONS FMT_INSTALL "" ON 45 | ) 46 | endif() 47 | 48 | FetchContent_Declare( 49 | spdlog_git 50 | GIT_REPOSITORY "https://github.com/gabime/spdlog.git" 51 | GIT_TAG "v1.9.2" 52 | GIT_SHALLOW ON 53 | ) 54 | FetchContent_Populate(spdlog_git) 55 | FetchContent_GetProperties( 56 | spdlog_git 57 | SOURCE_DIR spdlog_git_SRC_DIR 58 | POPULATED spdlog_git_FOUND 59 | ) 60 | 61 | add_library(${PROJECT_NAME} src/report.cpp) 62 | 63 | target_include_directories( 64 | ${PROJECT_NAME} PUBLIC 65 | $ 66 | $ 67 | ) 68 | 69 | if(TARGET fmt) 70 | target_link_libraries(${PROJECT_NAME} PUBLIC fmt::fmt) 71 | endif() 72 | 73 | target_include_directories(${PROJECT_NAME} PRIVATE ${spdlog_git_SRC_DIR}/include) 74 | if(TARGET SystemC::cci) 75 | target_compile_definitions(${PROJECT_NAME} PRIVATE HAS_CCI) 76 | target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::cci) 77 | endif() 78 | target_link_libraries(${PROJECT_NAME} PUBLIC SystemC::systemc) 79 | set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) 80 | 81 | #No tests yet. WIP. 82 | #if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) 83 | # enable_testing() 84 | # add_subdirectory(tests) 85 | #endif() 86 | 87 | add_library("scp::report::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) 88 | packageproject( 89 | NAME "${PROJECT_NAME}" 90 | VERSION ${PROJECT_VERSION} 91 | NAMESPACE scp 92 | BINARY_DIR ${PROJECT_BINARY_DIR} 93 | INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include 94 | INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 95 | VERSION_HEADER "${VERSION_HEADER_LOCATION}" 96 | COMPATIBILITY SameMajorVersion 97 | ) 98 | install( 99 | TARGETS ${PROJECT_NAME} 100 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 101 | COMPONENT "${PROJECT_NAME}_Runtime" 102 | NAMELINK_COMPONENT "${PROJECT_NAME}_Development" 103 | ) 104 | 105 | -------------------------------------------------------------------------------- /report/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Reporting macros 4 | 5 | The library offers the following macros. These macros ensure that, in general, a single 'if' is used to guard against output, so they can be used liberally throughout model code. 6 | 7 | The library uses the Cmake Package Manager to fetch SystemC, CCI, RapidJSON, FMT Library, Spdlog. 8 | For SystemC and CCI by default we use the "Master" Branch. Use a package lock to set a specific version if you need to. 9 | 10 | see: https://github.com/cpm-cmake/CPM.cmake 11 | 12 | ---- 13 | 14 | The Log levels used by the scp library are as follows : 15 | 16 | | SCP log
level value | SCP_ report macro | Log levels name | Print Level | Equivelent sc_core | 17 | | --- | --- | --- | --- | --- | 18 | | 0 | NONE | | sc_core::SC_NONE | 19 | | 1 | SCP_FATAL() | FATAL | sc_core::SC_LOW | `sc_core::SC_FATAL` (Always printed) 20 | | 1 | SCP_ERROR() | ERROR | sc_core::SC_LOW | `sc_core::SC_ERROR` (Always printed) 21 | | 1 | SCP_WARNING() | WARNING | sc_core::SC_LOW | `sc_core::SC_WARNING` 22 | | 4 | SCP_INFO() | INFO | sc_core::SC_MEDIUM| `sc_core::SC_MEDIUM` 23 | | 5 | SCP_DEBUG() | DEBUG | sc_core::SC_HIGH | `sc_core::SC_HIGH` 24 | | 6 | SCP_TRACE() | TRACE | sc_core::SC_FULL | `sc_core::SC_FULL` 25 | | 7 | SCP_TRACEALL() | TRACEAL | sc_core::SC_DEBUG | `sc_core::SC_DEBUG` 26 | 27 | Hence WARNINGS will be printed if the log level is set above 1. Hence setting a log_level of 3 will print Fatal, Error and Warning messages only. 28 | 29 | ## SCP_ report macros 30 | 31 | The following SCP_ report macros can process an [{FMT}](https://github.com/fmtlib/fmt) formatter, or operate as a normal stream (accepting normal operators for output). 32 | ```C 33 | SCP_TRACE() << "My trace message"; 34 | SCP_TRACE()("The answer is {}.", 42); 35 | ``` 36 | 37 | The macros can take the following options: 38 | 39 | ```C 40 | SCP_TRACE() 41 | ``` 42 | Uses the global default report level set up during initialization to determine whether the message is printed. (Defaults to 'SC_WARNING' in the absence of any initialization). No 'feature' information will be printed with the message. 43 | 44 | 45 | ```C 46 | SCP_TRACE("string") 47 | ``` 48 | The string represents a `feature` that is being reported upon. The message will be tagged with the feature name, and the feature name will be printed along with the message. The name will also be used to look up a `CCI` parameter with the extension `log_level`. 49 | Hence: 50 | ```C 51 | SCP_TRACE("top.mymodel") 52 | ``` 53 | will check for, in order of priority: 54 | `top.mymodel.log_level` 55 | `top.log_level` 56 | `log_level` 57 | The first matching parameter will be used. Hence it is possible to set a top level `top.log_level` and overwrite that for specific models in the hierarchy (`top.mymodel.log_level`). 58 | If no parameters with matching names are found, the global default report level set up during initialization will be used (Defaults to 'SC_WARNING' in the absence of any initialization). 59 | 60 | Any string can be used, and it maybe a `std::string` or a `const char*`. Hence, users may create hierarchies of reporting features outside of the SystemC hierarchy itself. None the less, a convenience macro `SCMOD` is provided to use the current `SC_MODULE` name. Hence a typical example would be 61 | ```C 62 | SCP_TRACE(SCMOD) << "My trace message"; 63 | ``` 64 | Having established whether the feature should be printed or not, the result is cached in a lookup table. This lookup table will be used on all subsequent calls to any macro using the same feature string. (see thread safety below) 65 | 66 | This form of `SCP_TRACE` uses a global lookup table. This means there is a look-up 'cost' each time an SCP_ report function is used. Also see below for thread safety concerns. (Only one string is permitted in this form, because it will be 'hashed' and used to look up in the table) 67 | 68 | ```C 69 | SCP_TRACE((logger)) 70 | ``` 71 | In this form, the `logger` is expected to be within scope of the macro, it should be instantiated using the `SCP_LOGGER` macro. It will be used to store the debug level at which printing should occur and feature information which will be shared by all users of the `logger`. An alternate form makes use of the default logger (see below) : `SCP_TRACE(())`. 72 | 73 | ```C 74 | SCP_TRACE((logger),"string") 75 | ``` 76 | Both forms can be used together, in which case the logging type used in the output will be the feature string, while the logger will be used to determine if the 77 | 78 | ```C 79 | SCP_LOGGER() 80 | ``` 81 | The `SCP_LOGGER` macro is used to instantiate a logger for use in an SCP_ report macro. It is expected to be used in a class definition and the logger is expected to be used within that class. It should be constructed with the 'features' of logging for which it will be used. There are several forms of the SCP_LOGGER macro. With no arguments, the macro will construct a logger with the default name in the current scope. It is an error to use the macro more than once with no arguments. 82 | 83 | By default, the logger will be initiated with some default features on the first use of any SCP_ report macro. This MUST happen within the SystemC context (on the SystemC thread) - it is safest to use an `SC_TRACE` macro (for instance) in the sc_module constructor. 84 | 85 | The default features are the SystemC hierarchial name (`this->name()`) and the C++ type name. The C++ type name is demangled, and will be pre-pended with the SystemC hierarchical name. 86 | 87 | Hence an sc_module `"my_mod"` instanced with the hierarchical name `top.a.b.mod` will automatically include the feature `top.a.b.mod.my_mod` and may be enabled using the parameter `top.a.b.mod.m_mod.log_level`. (See below for wildcard options). 88 | 89 | 90 | ```C 91 | SCP_LOGGER("string"...) 92 | ``` 93 | In this variant, the variable umber of feature strings passes will be *prepended* to the list of default features such that the features listed take precedence over the default features. The strings may be either `std::string`'s or `const char*`'s. 94 | 95 | The feature names will be pre-pended with the SystemC hierarchical name (at the point the first SCP_ report macro is used). 96 | 97 | Hence a string `"spacial"` used in model `top.a.b` will be inserted interpreted as feature `top.a.b.special` and may be enabled using the parameter `top.a.b.special.log_level`. (See below for wildcard options). 98 | 99 | 100 | ```C 101 | SCP_LOGGER((my_logger)) 102 | ``` 103 | In this form, `my_logger` will be used as the logger name, which should also be used as the logger name for the SCP_ report macros. The actual name of the instantiated variable will be 'mangled' such that there is no danger of name collision, hence short logger names are perfectly permissable, they may even be single digits (e.g. `SCP_LOGGER((1))` which would allow the use of report functions such as `SCP_TRACE((1))`. Omitting the logger name will be equivalent of the previous macros (hence `SCP_LOGGER(())` is the same as `SCP_LOGGER()`). These variants may be combined e.g. `SCP_LOGGER((1),"feature", "feature.sub_feature")` 104 | 105 | ## feature matching rules 106 | 107 | A logger can be initialized with a variable number of feature strings, each of which may be used to identify features that can then be enabled using CCI parameters. The hierarchical SystemC decomposition is used to find the best match for a feature. The feature (and corresponding log level) that best matches (i.e is the closest in the hierarchy to the feature) will be used. In addition, CCI parameters who's name starts with `*.` can be used to match several levels of hierarchy. 108 | 109 | Hence a module of type `mymod`, instanced with hierarchical name `top.foo` with feature `a.b` will search in order for: 110 | 111 | | Priority | | 112 | | --- | --- | 113 | | 4 |`top.foo.a.b.log_level` | 114 | | 3 |`top.foo.a.log_level` | 115 | | 2 |`top.foo.log_level` | 116 | | 4 |`*.foo.a.b.log_level` | 117 | | 3 |`*.foo.a.log_level` | 118 | | 2 |`*.foo.log_level` | 119 | | 3 |`top.a.b.log_level` | 120 | | 2 |`top.a.log_level` | 121 | | 1 |`top.log_level` | 122 | | 2 |`a.b.log_level` | 123 | | 2 |`*.b.log_level` | 124 | | 1 |`mymod.log_level` | 125 | | 1 |`*.log_level` | 126 | | 0 |`log_level` | 127 | 128 | 129 | 130 | 131 | ## Initialization 132 | ```C 133 | scp::init_logging(config) 134 | ``` 135 | This is an optional function which enables the more complex logging mechanisms. Without it, only basic logging is possible. This takes a configuration structure as a parameter. 136 | 137 | The configuration structure can be constructed simply: 138 | ```C 139 | scp::LogConfig() 140 | ``` 141 | Convenience functions are provided on a configuration structure that return a modified structure, hence for example: 142 | ```C 143 | scp::init_logging( 144 | scp::LogConfig() 145 | .logLevel(scp::log::DEBUG) 146 | .msgTypeFieldWidth(20) 147 | .fileInfoFrom(5) 148 | .logAsync(false) 149 | .printSimTime(false) 150 | .logFileName(logfile)); 151 | ``` 152 | 153 | | Use | method | Default 154 | | ---- | ---- | --- | 155 | | set the logging level | `logLevel(int)` | WARNING (3) | 156 | | define the width of the message field, 0 to disable,
`std::numeric_limits::max()` for arbitrary width | ` msgTypeFieldWidth(unsigned)` | | 157 | | enable/disable printing of system time | `printSysTime(bool)` | true | 158 | | enable/disable printing of simulation time | `printSimTime(bool)` | true | 159 | | enable/disable printing delta cycles | `printDelta(bool)` | true | 160 | | enable/disable printing of severity level | `printSeverity(bool)` | true | 161 | | enable/disable colored output | `coloredOutput(bool)` | true | 162 | | set the file name for the log output file | `logFileName([const] std::string&)` | | 163 | | set the regular expression to filter the output | `logFilterRegex([const] std::string&)` | | 164 | | enable/disable asynchronous output (write to file in separate thread | `logAsync(bool)` | true | 165 | | print the file name from this log level | `fileInfoFrom(int)` | sc_core::SC_INFO (4) | 166 | | disable/enable the suppression of all error messages after the first | `reportOnlyFirstError(bool)` | true | 167 | 168 | ## Thread safety 169 | 170 | None of the macro's are thread safe. SCP_LOGGER *must* be used within a SystemC module context. The SCP_ report macros MAY be used outside of a SystemC module context, and may be used on separate threads. However they *must* first be used on the SystemC thread within a module context. 171 | 172 | Hence it is recommended that every sc_module constructor includes something like: 173 | ```C 174 | SCP_TRACE(()) << "Constructor"; 175 | ``` 176 | (This will print the module hierarchy name as well as other information so the short message string is still useful.) 177 | 178 | This is equally true whether using a local 'logger' or the global lookup table. When using the global lookup table, in separate threads, care has to be taken that NO logger is added once reporting starts on the non SystemC thread as this could potentially corrupt the lookup table (which is only thread safe for multiple reads). In general, it is highly recommended to use the `(logger)` form for such cases. 179 | 180 | ## Recommendations 181 | 182 | The recommended way to use this library is: 183 | 184 | For Systems that are not using CCI parameters, use the SCP_ report macros with no parameters, either with or without a top level initialization. e.g. `SCP_TRACE() << "your message";` 185 | 186 | For modules that need very occasional reporting can use the "string" form of the SCP_ report macros, ideally using SCMOD. e.g. `SCP_TRACE(SCMOD) << "your message";` 187 | 188 | For modules that either use a lot of reporting, or require multiple threads, use the `(logger)` form, e.g. `SCP_TRACE(()) << "your message";`. This will require instantiating the logger which can be done with `SCP_LOGGER(())` in the class. 189 | 190 | For Systems and modules that have specific features which do not align with the module hierarchy, the `(logger)` form should be used, with additional feature strings. 191 | 192 | For the user, reporting can be enabled using CCI parameters. This can be achieved in most cases on the command line. To enable or disable specific modules in the hierarchy the full hierarchy name can be used e.g. `-p top.a.b.my_module.log_level=5`. To enable all instances of a specific model the wildcard can be used e.g. `-p *.model.log_level=5`. A global 'default' can be provided at the top level. 193 | 194 | 195 | ## Advanced Arrays 196 | 197 | Sometimes it's important to use both a 'cached' approach, and to allow the cache to be (locally) dynamic. For instance as now client devices are added to a tlm multi-port, it may be important to log messages per client. To achieve this 2 macros are provided: 198 | 199 | ```C 200 | SCP_LOGGER_VECTOR(NAME) 201 | ``` 202 | This instantiates a vector of loggers (with the base name `NAME`). 203 | 204 | ```C 205 | SCP_LOGGER_VECTOR_PUSH_BACK(NAME, "features"... ) 206 | ``` 207 | This will push_back a new logger to the logger vector, initialized with the features listed. 208 | From this point on any of the SCP_ reporting macro's can be used with the form `SCP_INFO((NAME[i]))` 209 | 210 | ## Utilities 211 | 212 | A utility function is provided to list all the logging parameters available in the system. This can be used for help messages for instance. 213 | ```C 214 | std::vector get_logging_parameters(); 215 | ``` 216 | -------------------------------------------------------------------------------- /report/include/scp/helpers.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | 3 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 | more contributor license agreements. See the NOTICE file distributed 5 | with this work for additional information regarding copyright ownership. 6 | Accellera licenses this file to you under the Apache License, Version 2.0 7 | (the "License"); you may not use this file except in compliance with the 8 | License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | implied. See the License for the specific language governing 16 | permissions and limitations under the License. 17 | 18 | *****************************************************************************/ 19 | 20 | #include 21 | #include 22 | #ifndef _SCP_HELPERS_H_ 23 | #define _SCP_HELPERS_H_ 24 | namespace scp { 25 | static std::string scp_txn_tostring(tlm::tlm_generic_payload& trans) { 26 | std::stringstream info; 27 | const char* cmd = "UNKOWN"; 28 | switch (trans.get_command()) { 29 | case tlm::TLM_IGNORE_COMMAND: 30 | cmd = "IGNORE"; 31 | break; 32 | case tlm::TLM_WRITE_COMMAND: 33 | cmd = "WRITE"; 34 | break; 35 | case tlm::TLM_READ_COMMAND: 36 | cmd = "READ"; 37 | break; 38 | } 39 | info << cmd << " to address: " 40 | << "0x" << std::hex << trans.get_address(); 41 | info << " len: " << trans.get_data_length(); 42 | unsigned char* ptr = trans.get_data_ptr(); 43 | info << " data: 0x"; 44 | for (int i = trans.get_data_length(); i; i--) { 45 | info << std::setw(2) << std::setfill('0') << std::hex 46 | << (unsigned int)(ptr[i - 1]); 47 | } 48 | info << " status: " << trans.get_response_string() << " "; 49 | for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) { 50 | if (trans.get_extension(i)) { 51 | info << " extn:" << i; 52 | } 53 | } 54 | return info.str(); 55 | } 56 | 57 | } // namespace scp 58 | #endif /* _SCP_HELPERS_H_ */ -------------------------------------------------------------------------------- /report/include/scp/report.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2016-2022 MINRES Technologies GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | 17 | #ifndef _SCP_REPORT_H_ 18 | #define _SCP_REPORT_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __GNUG__ 31 | #include 32 | #include 33 | #include 34 | #endif 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef FMT_SHARED 41 | #include 42 | #endif 43 | 44 | #if defined(_MSC_VER) && defined(ERROR) 45 | #undef ERROR 46 | #endif 47 | 48 | namespace sc_core { 49 | const sc_core::sc_verbosity SC_UNSET = (sc_core::sc_verbosity)INT_MAX; 50 | } 51 | 52 | //! the name of the CCI property to attach to modules to control logging of 53 | //! this module 54 | #define SCP_LOG_LEVEL_PARAM_NAME "log_level" 55 | 56 | // must be global for macro to work. 57 | static const char* _SCP_FMT_EMPTY_STR = ""; 58 | 59 | /** \ingroup scp-report 60 | * @{ 61 | */ 62 | /**@{*/ 63 | //! @brief reporting utilities 64 | namespace scp { 65 | //! \brief array holding string representations of log levels 66 | static std::array buffer = { 67 | { "NONE", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", 68 | "TRACEALL" } 69 | }; 70 | //! \brief enum defining the log levels 71 | enum class log { 72 | NONE, 73 | FATAL, 74 | ERROR, 75 | WARNING, 76 | INFO, 77 | DEBUG, 78 | TRACE, 79 | TRACEALL, 80 | DBGTRACE = TRACEALL 81 | }; 82 | 83 | /** 84 | * @fn log as_log(int) 85 | * @brief safely convert an integer into a log level 86 | * 87 | * @param logLevel the logging level 88 | * @return the log level 89 | */ 90 | inline log as_log(int logLevel) { 91 | assert(logLevel >= static_cast(log::NONE) && 92 | logLevel <= static_cast(log::TRACEALL)); 93 | std::array m = { { log::NONE, log::FATAL, log::ERROR, 94 | log::WARNING, log::INFO, log::DEBUG, 95 | log::TRACE, log::TRACEALL } }; 96 | return m[logLevel]; 97 | } 98 | /** 99 | * @fn std::istream& operator >>(std::istream&, log&) 100 | * @brief read a log level from input stream e.g. used by boost::lexical_cast 101 | * 102 | * @param is input stream holding the string representation 103 | * @param val the value holding the resulting value 104 | * @return the input stream 105 | */ 106 | inline std::istream& operator>>(std::istream& is, log& val) { 107 | std::string buf; 108 | is >> buf; 109 | for (auto i = 0U; i <= static_cast(log::TRACEALL); ++i) { 110 | if (std::strcmp(buf.c_str(), buffer[i]) == 0) { 111 | val = as_log(i); 112 | return is; 113 | } 114 | } 115 | return is; 116 | } 117 | /** 118 | * @fn std::ostream& operator <<(std::ostream&, const log&) 119 | * @brief output the textual representation of the log level 120 | * 121 | * @param os output stream 122 | * @param val logging level 123 | * @return reference to the stream for chaining 124 | */ 125 | inline std::ostream& operator<<(std::ostream& os, log const& val) { 126 | os << buffer[static_cast(val)]; 127 | return os; 128 | } 129 | /** 130 | * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) 131 | * @brief initializes the SystemC logging system with a particular logging 132 | * level 133 | * 134 | * @param level the log level 135 | * @param type_field_width the with of the type field in the output 136 | * @param print_time whether to print the system time stamp 137 | */ 138 | void init_logging(log level = log::WARNING, unsigned type_field_width = 24, 139 | bool print_time = false); 140 | /** 141 | * @fn void init_logging(log=log::WARNING, unsigned=24, bool=false) 142 | * @brief initializes the SystemC logging system with a particular logging 143 | * level 144 | * 145 | * @param level the log level 146 | * @param type_field_width the with of the type field in the output 147 | * @param print_time whether to print the system time stamp 148 | */ 149 | void reinit_logging(log level = log::WARNING); 150 | /** 151 | * @struct LogConfig 152 | * @brief the configuration class for the logging setup 153 | * 154 | * using this class allows to configure the logging output in many aspects. The 155 | * class follows the builder pattern. 156 | */ 157 | struct LogConfig { 158 | log level{ log::WARNING }; 159 | unsigned msg_type_field_width{ 24 }; 160 | bool print_sys_time{ false }; 161 | bool print_sim_time{ true }; 162 | bool print_delta{ false }; 163 | bool print_severity{ true }; 164 | bool colored_output{ true }; 165 | std::string log_file_name{ "" }; 166 | std::string log_filter_regex{ "" }; 167 | bool log_async{ true }; 168 | bool report_only_first_error{ false }; 169 | int file_info_from{ sc_core::SC_INFO }; 170 | 171 | //! set the logging level 172 | LogConfig& logLevel(log); 173 | //! define the width of the message field, 0 to disable, 174 | //! std::numeric_limits::max() for arbitrary width 175 | LogConfig& msgTypeFieldWidth(unsigned); 176 | //! enable/disable printing of system time 177 | LogConfig& printSysTime(bool = true); 178 | //! enable/disable printing of simulation time 179 | LogConfig& printSimTime(bool = true); 180 | //! enable/disable printing delta cycles 181 | LogConfig& printDelta(bool = true); 182 | //! enable/disable printing of severity level 183 | LogConfig& printSeverity(bool = true); 184 | //! enable/disable colored output 185 | LogConfig& coloredOutput(bool = true); 186 | //! set the file name for the log output file 187 | LogConfig& logFileName(std::string&&); 188 | //! set the file name for the log output file 189 | LogConfig& logFileName(const std::string&); 190 | //! set the regular expression to filter the output 191 | LogConfig& logFilterRegex(std::string&&); 192 | //! set the regular expression to filter the output 193 | LogConfig& logFilterRegex(const std::string&); 194 | //! enable/disable asynchronous output (write to file in separate thread 195 | LogConfig& logAsync(bool = true); 196 | //! disable the printing of the file name from this level upwards. 197 | LogConfig& fileInfoFrom(int); 198 | //! disable/enable the supression of all error messages after the first 199 | LogConfig& reportOnlyFirstError(bool = true); 200 | }; 201 | 202 | /** 203 | * @brief cached logging information used in the (logger) form. 204 | * 205 | */ 206 | struct scp_logger_cache { 207 | sc_core::sc_verbosity level = sc_core::SC_UNSET; 208 | std::string type; 209 | std::vector features; 210 | 211 | /** 212 | * @brief Initialize the verbosity cache and/or return the cached value. 213 | * 214 | * @return sc_core::sc_verbosity 215 | */ 216 | sc_core::sc_verbosity get_log_verbosity_cached(const char*, const char*); 217 | }; 218 | 219 | /** 220 | * @fn void init_logging(const LogConfig&) 221 | * @brief initializes the SystemC logging system with a particular 222 | * configuration 223 | * 224 | * @param log_config the logging configuration 225 | */ 226 | void init_logging(const LogConfig& log_config); 227 | /** 228 | * @fn void set_logging_level(log) 229 | * @brief sets the SystemC logging level 230 | * 231 | * @param level the logging level 232 | */ 233 | void set_logging_level(log level); 234 | /** 235 | * @fn log get_logging_level() 236 | * @brief get the SystemC logging level 237 | * 238 | * @return the logging level 239 | */ 240 | log get_logging_level(); 241 | /** 242 | * @fn void set_cycle_base(sc_core::sc_time) 243 | * @brief sets the cycle base for cycle based logging 244 | * 245 | * if this is set to a non-SC_ZERO_TIME value all logging timestamps are 246 | * printed as cyles (multiple of this value) 247 | * 248 | * @param period the cycle period 249 | */ 250 | void set_cycle_base(sc_core::sc_time period); 251 | /** 252 | * @fn sc_core::sc_verbosity get_log_verbosity() 253 | * @brief get the global verbosity level 254 | * 255 | * @return the global verbosity level 256 | */ 257 | inline sc_core::sc_verbosity get_log_verbosity() { 258 | return static_cast( 259 | ::sc_core::sc_report_handler::get_verbosity_level()); 260 | } 261 | /** 262 | * @fn sc_core::sc_verbosity get_log_verbosity(const char*) 263 | * @brief get the scope-based verbosity level 264 | * 265 | * The function returns a scope specific verbosity level if defined (e.g. by 266 | * using a CCI param named "log_level"). Otherwise the global verbosity level 267 | * is being returned 268 | * 269 | * @param t the SystemC hierarchy scope name 270 | * @return the verbosity level 271 | */ 272 | sc_core::sc_verbosity get_log_verbosity(char const* t); 273 | /** 274 | * @fn sc_core::sc_verbosity get_log_verbosity(const char*) 275 | * @brief get the scope-based verbosity level 276 | * 277 | * The function returns a scope specific verbosity level if defined (e.g. by 278 | * using a CCI param named "log_level"). Otherwise the global verbosity level 279 | * is being returned 280 | * 281 | * @param t the SystemC hierarchy scope name 282 | * @return the verbosity level 283 | */ 284 | inline sc_core::sc_verbosity get_log_verbosity(std::string const& t) { 285 | return get_log_verbosity(t.c_str()); 286 | } 287 | 288 | /** 289 | * @brief Return list of logging parameters that have been used 290 | * 291 | */ 292 | std::vector get_logging_parameters(); 293 | 294 | /** 295 | * @struct ScLogger 296 | * @brief the logger class 297 | * 298 | * The ScLogger creates a RTTI based output stream to be used similar to 299 | * std::cout 300 | * 301 | * @tparam SEVERITY 302 | */ 303 | template 304 | struct ScLogger { 305 | /** 306 | * @fn ScLogger(const char*, int, int=sc_core::SC_MEDIUM) 307 | * @brief 308 | * 309 | * @param file where the log entry originates 310 | * @param line number where the log entry originates 311 | * @param verbosity the log level 312 | */ 313 | ScLogger(const char* file, int line, int verbosity = sc_core::SC_MEDIUM): 314 | t(nullptr), file(file), line(line), level(verbosity){}; 315 | 316 | ScLogger() = delete; 317 | 318 | ScLogger(const ScLogger&) = delete; 319 | 320 | ScLogger(ScLogger&&) = delete; 321 | 322 | ScLogger& operator=(const ScLogger&) = delete; 323 | 324 | ScLogger& operator=(ScLogger&&) = delete; 325 | /** 326 | * @fn ~ScLogger() 327 | * @brief the destructor generating the SystemC report 328 | * 329 | */ 330 | virtual ~ScLogger() { 331 | ::sc_core::sc_report_handler::report( 332 | SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line); 333 | } 334 | /** 335 | * @fn ScLogger& type() 336 | * @brief reset the category of the log entry 337 | * 338 | * @return reference to self for chaining 339 | */ 340 | inline ScLogger& type() { 341 | this->t = nullptr; 342 | return *this; 343 | } 344 | /** 345 | * @fn ScLogger& type(const char*) 346 | * @brief set the category of the log entry 347 | * 348 | * @param t type of th elog entry 349 | * @return reference to self for chaining 350 | */ 351 | inline ScLogger& type(char const* t) { 352 | this->t = const_cast(t); 353 | return *this; 354 | } 355 | /** 356 | * @fn ScLogger& type(std::string const&) 357 | * @brief set the category of the log entry 358 | * 359 | * @param t type of th elog entry 360 | * @return reference to self for chaining 361 | */ 362 | inline ScLogger& type(std::string const& t) { 363 | this->t = const_cast(t.c_str()); 364 | return *this; 365 | } 366 | /** 367 | * @fn std::ostream& get() 368 | * @brief get the underlying ostringstream 369 | * 370 | * @return the output stream collecting the log message 371 | */ 372 | inline std::ostream& get() { return os; }; 373 | 374 | protected: 375 | std::ostringstream os{}; 376 | char* t{ nullptr }; 377 | const char* file; 378 | const int line; 379 | const int level; 380 | }; 381 | 382 | /** 383 | * logging macros 384 | */ 385 | 386 | /** 387 | * Boilerplate convenience macros 388 | */ 389 | #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) 390 | #define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ 391 | 392 | #define IIF(c) PRIMITIVE_CAT(IIF_, c) 393 | #define IIF_0(t, ...) __VA_ARGS__ 394 | #define IIF_1(t, ...) t 395 | 396 | #define CHECK_N(x, n, ...) n 397 | #define CHECK(...) CHECK_N(__VA_ARGS__, 0, ) 398 | #define PROBE(x) x, 1, 399 | 400 | #define EXPAND(...) __VA_ARGS__ 401 | 402 | #define FIRST_ARG(f, ...) f 403 | #define POP_ARG(f, ...) __VA_ARGS__ 404 | 405 | #define STR_HELPER(x) #x 406 | #define STR(x) STR_HELPER(x) 407 | 408 | #define IS_PAREN(x) CHECK(IS_PAREN_PROBE x) 409 | #define IS_PAREN_PROBE(...) PROBE(~) 410 | /********/ 411 | 412 | /* default logger cache name */ 413 | #define SCP_LOGGER_NAME(x) CAT(_m_scp_log_level_cache_, x) 414 | 415 | /* User interface macros */ 416 | #define SCMOD this->sc_core::sc_module::name() 417 | #define SCP_LOGGER(...) \ 418 | scp::scp_logger_cache IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ 419 | SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))), \ 420 | SCP_LOGGER_NAME()) = { sc_core::SC_UNSET, \ 421 | "", \ 422 | { IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__)))( \ 423 | POP_ARG(__VA_ARGS__), ##__VA_ARGS__) } } 424 | 425 | #define SCP_LOGGER_VECTOR(NAME) \ 426 | std::vector SCP_LOGGER_NAME(NAME) 427 | #define SCP_LOGGER_VECTOR_PUSH_BACK(NAME, ...) \ 428 | SCP_LOGGER_NAME(NAME).push_back( \ 429 | { sc_core::SC_UNSET, "", { __VA_ARGS__ } }); 430 | 431 | class call_sc_name_fn 432 | { 433 | template 434 | static auto test(T* p) 435 | -> decltype(p->sc_core::sc_module::name(), std::true_type()); 436 | template 437 | static auto test(...) -> decltype(std::false_type()); 438 | 439 | template 440 | static constexpr bool has_method = decltype(test(nullptr))::value; 441 | 442 | public: 443 | // define a function IF the method exists 444 | template 445 | auto operator()(TYPE* p) const 446 | -> std::enable_if_t, const char*> { 447 | return p->sc_core::sc_module::name(); 448 | } 449 | 450 | // define a function IF NOT the method exists 451 | template 452 | auto operator()(TYPE* p) const 453 | -> std::enable_if_t, const char*> { 454 | return nullptr; 455 | } 456 | }; 457 | 458 | // critical thing is that the initial if 'fails' as soon as possible - if it is 459 | // going to pass, we have all the time we want, as we will be logging anyway 460 | // This HAS to be done as a macro, because the first argument may be a string 461 | // or a cache'd level 462 | 463 | /*** Helper macros for SCP_ report macros ****/ 464 | #define SCP_VBSTY_CHECK_CACHED(lvl, features, cached, ...) \ 465 | (cached.level >= lvl) && \ 466 | (cached.get_log_verbosity_cached(scp::call_sc_name_fn()(this), \ 467 | typeid(*this).name()) >= lvl) 468 | 469 | #define SCP_VBSTY_CHECK_UNCACHED(lvl, ...) \ 470 | (::scp::get_log_verbosity(__VA_ARGS__) >= lvl) 471 | 472 | #define SCP_VBSTY_CHECK(lvl, ...) \ 473 | IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ 474 | (SCP_VBSTY_CHECK_CACHED( \ 475 | lvl, FIRST_ARG(__VA_ARGS__), \ 476 | SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__)))), \ 477 | SCP_VBSTY_CHECK_UNCACHED(lvl, ##__VA_ARGS__)) 478 | 479 | #define SCP_GET_FEATURES(...) \ 480 | IIF(IS_PAREN(FIRST_ARG(__VA_ARGS__))) \ 481 | (FIRST_ARG EXPAND((POP_ARG( \ 482 | __VA_ARGS__, \ 483 | SCP_LOGGER_NAME(EXPAND(FIRST_ARG FIRST_ARG(__VA_ARGS__))).type))), \ 484 | __VA_ARGS__) 485 | 486 | #ifdef FMT_SHARED 487 | #define _SCP_FMT_EMPTY_STR(...) fmt::format(__VA_ARGS__) 488 | #else 489 | #define _SCP_FMT_EMPTY_STR(...) "Please add FMT library for FMT support." 490 | #endif 491 | 492 | #define SCP_LOG(lvl, ...) \ 493 | ::scp::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, lvl / 10) \ 494 | .type(SCP_GET_FEATURES(__VA_ARGS__)) \ 495 | .get() \ 496 | << _SCP_FMT_EMPTY_STR 497 | /*** End HELPER Macros *******/ 498 | 499 | //! macro for debug trace level output 500 | #define SCP_TRACEALL(...) \ 501 | if (SCP_VBSTY_CHECK(sc_core::SC_DEBUG, ##__VA_ARGS__)) \ 502 | SCP_LOG(sc_core::SC_DEBUG, __VA_ARGS__) 503 | //! macro for trace level output 504 | #define SCP_TRACE(...) \ 505 | if (SCP_VBSTY_CHECK(sc_core::SC_FULL, ##__VA_ARGS__)) \ 506 | SCP_LOG(sc_core::SC_FULL, __VA_ARGS__) 507 | //! macro for debug level output 508 | #define SCP_DEBUG(...) \ 509 | if (SCP_VBSTY_CHECK(sc_core::SC_HIGH, ##__VA_ARGS__)) \ 510 | SCP_LOG(sc_core::SC_HIGH, __VA_ARGS__) 511 | //! macro for info level output 512 | #define SCP_INFO(...) \ 513 | if (SCP_VBSTY_CHECK(sc_core::SC_MEDIUM, ##__VA_ARGS__)) \ 514 | SCP_LOG(sc_core::SC_MEDIUM, __VA_ARGS__) 515 | //! macro for warning level output 516 | #define SCP_WARN(...) \ 517 | if (SCP_VBSTY_CHECK(sc_core::SC_LOW, ##__VA_ARGS__)) \ 518 | ::scp::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, \ 519 | sc_core::SC_MEDIUM) \ 520 | .type(SCP_GET_FEATURES(__VA_ARGS__)) \ 521 | .get() \ 522 | << _SCP_FMT_EMPTY_STR 523 | //! macro for error level output 524 | #define SCP_ERR(...) \ 525 | ::scp::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, \ 526 | sc_core::SC_MEDIUM) \ 527 | .type(SCP_GET_FEATURES(__VA_ARGS__)) \ 528 | .get() \ 529 | << _SCP_FMT_EMPTY_STR 530 | //! macro for fatal message output 531 | #define SCP_FATAL(...) \ 532 | ::scp::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, \ 533 | sc_core::SC_MEDIUM) \ 534 | .type(SCP_GET_FEATURES(__VA_ARGS__)) \ 535 | .get() \ 536 | << _SCP_FMT_EMPTY_STR 537 | 538 | #ifdef NDEBUG 539 | #define SCP_ASSERT(expr) ((void)0) 540 | #else 541 | #define SCP_ASSERT(expr) \ 542 | ((void)((expr) ? 0 \ 543 | : (SC_REPORT_FATAL(::sc_core::SC_ID_ASSERTION_FAILED_, \ 544 | #expr), \ 545 | 0))) 546 | #endif 547 | 548 | } // namespace scp 549 | /** @} */ // end of scp-report 550 | #endif /* _SCP_REPORT_H_ */ 551 | -------------------------------------------------------------------------------- /report/src/report.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2017-2022 MINRES Technologies GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | /* 17 | * report.cpp 18 | * 19 | * Created on: 19.09.2017 20 | * Author: eyck@minres.com 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #ifdef HAS_CCI 29 | #include 30 | #endif 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #if defined(__GNUC__) || defined(__clang__) 40 | #define likely(x) __builtin_expect(x, 1) 41 | #define unlikely(x) __builtin_expect(x, 0) 42 | #else 43 | #define likely(x) x 44 | #define unlikely(x) x 45 | #endif 46 | 47 | #include 48 | #ifdef ERROR 49 | #undef ERROR 50 | #endif 51 | 52 | namespace { 53 | // Making this thread_local could cause thread copies of the same cache 54 | // entries, but more likely naming will be thread local too, and this avoids 55 | // races in the unordered_map 56 | 57 | #ifdef DISABLE_REPORT_THREAD_LOCAL 58 | std::unordered_map lut; 59 | #else 60 | thread_local std::unordered_map lut; 61 | #endif 62 | 63 | #ifdef HAS_CCI 64 | cci::cci_originator scp_global_originator("scp_reporting_global"); 65 | #endif 66 | 67 | std::set logging_parameters; 68 | 69 | struct ExtLogConfig : public scp::LogConfig { 70 | std::shared_ptr file_logger; 71 | std::shared_ptr console_logger; 72 | std::regex reg_ex; 73 | sc_core::sc_time cycle_base{ 0, sc_core::SC_NS }; 74 | auto operator=(const scp::LogConfig& o) -> ExtLogConfig& { 75 | scp::LogConfig::operator=(o); 76 | return *this; 77 | } 78 | auto match(const char* type) -> bool { return regex_search(type, reg_ex); } 79 | }; 80 | 81 | /* normally put the config in thread local. If two threads try to use logging 82 | * they would both need to init the config from both threads. The alternative 83 | * is to switch on this define, but then care has to be taken not to 84 | * (re)initialize from different threads which would then be unsafe.*/ 85 | #ifdef DISABLE_REPORT_THREAD_LOCAL 86 | ExtLogConfig log_cfg; 87 | #else 88 | thread_local ExtLogConfig log_cfg; 89 | #endif 90 | 91 | inline std::string padded(std::string str, size_t width, 92 | bool show_ellipsis = true) { 93 | if (width < 7) 94 | return str; 95 | if (str.length() > width) { 96 | if (show_ellipsis) { 97 | auto pos = str.size() - (width - 6); 98 | return str.substr(0, 3) + "..." + 99 | str.substr(pos, str.size() - pos); 100 | } else 101 | return str.substr(0, width); 102 | } else { 103 | return str + std::string(width - str.size(), ' '); 104 | } 105 | } 106 | 107 | auto get_tuple(const sc_core::sc_time& t) 108 | -> std::tuple { 109 | auto val = t.value(); 110 | auto tr = (uint64_t)(sc_core::sc_time::from_value(1).to_seconds() * 1E15); 111 | auto scale = 0U; 112 | while ((tr % 10) == 0) { 113 | tr /= 10; 114 | scale++; 115 | } 116 | sc_assert(tr == 1); 117 | 118 | auto tu = scale / 3; 119 | while (tu < sc_core::SC_SEC && (val % 10) == 0) { 120 | val /= 10; 121 | scale++; 122 | tu += (0 == (scale % 3)); 123 | } 124 | for (scale %= 3; scale != 0; scale--) 125 | val *= 10; 126 | return std::make_tuple(val, static_cast(tu)); 127 | } 128 | 129 | auto time2string(const sc_core::sc_time& t) -> std::string { 130 | const std::array time_units{ "fs", "ps", "ns", 131 | "us", "ms", "s " }; 132 | const std::array multiplier{ 1ULL, 133 | 1000ULL, 134 | 1000ULL * 1000, 135 | 1000ULL * 1000 * 1000, 136 | 1000ULL * 1000 * 1000 * 1000, 137 | 1000ULL * 1000 * 1000 * 1000 * 138 | 1000 }; 139 | std::ostringstream oss; 140 | if (!t.value()) { 141 | oss << "0 s "; 142 | } else { 143 | const auto tt = get_tuple(t); 144 | const auto val = std::get<0>(tt); 145 | const auto scale = std::get<1>(tt); 146 | const auto fs_val = val * multiplier[scale]; 147 | for (int j = multiplier.size() - 1; j >= scale; --j) { 148 | if (fs_val >= multiplier[j]) { 149 | const auto i = val / multiplier[j - scale]; 150 | const auto f = val % multiplier[j - scale]; 151 | oss << i << '.' << std::setw(3 * (j - scale)) 152 | << std::setfill('0') << std::right << f << ' ' 153 | << time_units[j]; 154 | break; 155 | } 156 | } 157 | } 158 | return oss.str(); 159 | } 160 | auto compose_message(const sc_core::sc_report& rep, const scp::LogConfig& cfg) 161 | -> const std::string { 162 | if (rep.get_severity() > sc_core::SC_INFO || 163 | cfg.log_filter_regex.length() == 0 || 164 | rep.get_verbosity() == sc_core::SC_MEDIUM || 165 | log_cfg.match(rep.get_msg_type())) { 166 | std::stringstream os; 167 | if (likely(cfg.print_sim_time)) { 168 | if (unlikely(log_cfg.cycle_base.value())) { 169 | if (unlikely(cfg.print_delta)) 170 | os << "[" << std::setw(7) << std::setfill(' ') 171 | << sc_core::sc_time_stamp().value() / 172 | log_cfg.cycle_base.value() 173 | << "(" << std::setw(5) << sc_core::sc_delta_count() 174 | << ")]"; 175 | else 176 | os << "[" << std::setw(7) << std::setfill(' ') 177 | << sc_core::sc_time_stamp().value() / 178 | log_cfg.cycle_base.value() 179 | << "]"; 180 | } else { 181 | auto t = time2string(sc_core::sc_time_stamp()); 182 | if (unlikely(cfg.print_delta)) 183 | os << "[" << std::setw(20) << std::setfill(' ') << t << "(" 184 | << std::setw(5) << sc_core::sc_delta_count() << ")]"; 185 | else 186 | os << "[" << std::setw(20) << std::setfill(' ') << t 187 | << "]"; 188 | } 189 | } 190 | if (unlikely(rep.get_id() >= 0)) 191 | os << "(" 192 | << "IWEF"[rep.get_severity()] << rep.get_id() << ") " 193 | << rep.get_msg_type() << ": "; 194 | else if (cfg.msg_type_field_width) { 195 | if (cfg.msg_type_field_width == 196 | std::numeric_limits::max()) 197 | os << rep.get_msg_type() << ": "; 198 | else 199 | os << padded(rep.get_msg_type(), cfg.msg_type_field_width) 200 | << ": "; 201 | } 202 | if (*rep.get_msg()) 203 | os << rep.get_msg(); 204 | if (rep.get_severity() >= cfg.file_info_from) { 205 | if (rep.get_line_number()) 206 | os << "\n [FILE:" << rep.get_file_name() << ":" 207 | << rep.get_line_number() << "]"; 208 | sc_core::sc_simcontext* simc = sc_core::sc_get_curr_simcontext(); 209 | if (simc && sc_core::sc_is_running()) { 210 | const char* proc_name = rep.get_process_name(); 211 | if (proc_name) 212 | os << "\n [PROCESS:" << proc_name << "]"; 213 | } 214 | } 215 | return os.str(); 216 | } else 217 | return ""; 218 | } 219 | 220 | inline auto get_verbosity(const sc_core::sc_report& rep) -> int { 221 | return rep.get_verbosity() > sc_core::SC_NONE && 222 | rep.get_verbosity() < sc_core::SC_LOW 223 | ? rep.get_verbosity() * 10 224 | : rep.get_verbosity(); 225 | } 226 | 227 | inline void log2logger(spdlog::logger& logger, const sc_core::sc_report& rep, 228 | const scp::LogConfig& cfg) { 229 | auto msg = compose_message(rep, cfg); 230 | if (!msg.size()) 231 | return; 232 | switch (rep.get_severity()) { 233 | case sc_core::SC_INFO: 234 | switch (get_verbosity(rep)) { 235 | case sc_core::SC_DEBUG: 236 | case sc_core::SC_FULL: 237 | logger.trace(msg); 238 | break; 239 | case sc_core::SC_HIGH: 240 | logger.debug(msg); 241 | break; 242 | default: 243 | logger.info(msg); 244 | break; 245 | } 246 | break; 247 | case sc_core::SC_WARNING: 248 | logger.warn(msg); 249 | break; 250 | case sc_core::SC_ERROR: 251 | logger.error(msg); 252 | break; 253 | case sc_core::SC_FATAL: 254 | logger.critical(msg); 255 | break; 256 | default: 257 | break; 258 | } 259 | } 260 | 261 | inline void log2logger(spdlog::logger& logger, scp::log lvl, 262 | const std::string& msg) { 263 | switch (lvl) { 264 | case scp::log::DBGTRACE: 265 | case scp::log::TRACE: 266 | logger.trace(msg); 267 | return; 268 | case scp::log::DEBUG: 269 | logger.debug(msg); 270 | return; 271 | case scp::log::INFO: 272 | logger.info(msg); 273 | return; 274 | case scp::log::WARNING: 275 | logger.warn(msg); 276 | return; 277 | case scp::log::ERROR: 278 | logger.error(msg); 279 | return; 280 | case scp::log::FATAL: 281 | logger.critical(msg); 282 | return; 283 | default: 284 | break; 285 | } 286 | } 287 | 288 | void report_handler(const sc_core::sc_report& rep, 289 | const sc_core::sc_actions& actions) { 290 | thread_local bool sc_stop_called = false; 291 | if (actions & sc_core::SC_DO_NOTHING) 292 | return; 293 | if (rep.get_severity() == sc_core::SC_INFO || 294 | !log_cfg.report_only_first_error || 295 | sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) < 2) { 296 | if ((actions & sc_core::SC_DISPLAY) && 297 | (!log_cfg.file_logger || get_verbosity(rep) < sc_core::SC_HIGH)) 298 | log2logger(*log_cfg.console_logger, rep, log_cfg); 299 | if ((actions & sc_core::SC_LOG) && log_cfg.file_logger) { 300 | scp::LogConfig lcfg(log_cfg); 301 | lcfg.print_sim_time = true; 302 | if (!lcfg.msg_type_field_width) 303 | lcfg.msg_type_field_width = 24; 304 | log2logger(*log_cfg.file_logger, rep, lcfg); 305 | } 306 | } 307 | if (actions & sc_core::SC_STOP) { 308 | std::this_thread::sleep_for(std::chrono::milliseconds( 309 | static_cast(log_cfg.level) * 10)); 310 | if (sc_core::sc_is_running() && !sc_stop_called) { 311 | sc_core::sc_stop(); 312 | sc_stop_called = true; 313 | } 314 | } 315 | if (actions & sc_core::SC_ABORT) { 316 | std::this_thread::sleep_for(std::chrono::milliseconds( 317 | static_cast(log_cfg.level) * 20)); 318 | abort(); 319 | } 320 | if (actions & sc_core::SC_THROW) { 321 | std::this_thread::sleep_for(std::chrono::milliseconds( 322 | static_cast(log_cfg.level) * 20)); 323 | throw rep; 324 | } 325 | if (sc_core::sc_time_stamp().value() && !sc_core::sc_is_running()) { 326 | log_cfg.console_logger->flush(); 327 | if (log_cfg.file_logger) 328 | log_cfg.file_logger->flush(); 329 | } 330 | } 331 | 332 | // BKDR hash algorithm 333 | auto char_hash(char const* str) -> uint64_t { 334 | constexpr unsigned int seed = 131; // 31 131 1313 13131131313 etc// 335 | uint64_t hash = 0; 336 | while (*str) { 337 | hash = (hash * seed) + (*str); 338 | str++; 339 | } 340 | return hash; 341 | } 342 | } // namespace 343 | 344 | static const std::array severity = { 345 | sc_core::SC_FATAL, // scp::log::NONE 346 | sc_core::SC_FATAL, // scp::log::FATAL 347 | sc_core::SC_ERROR, // scp::log::ERROR 348 | sc_core::SC_WARNING, // scp::log::WARNING 349 | sc_core::SC_INFO, // scp::log::INFO 350 | sc_core::SC_INFO, // scp::log::DEBUG 351 | sc_core::SC_INFO, // scp::log::TRACE 352 | sc_core::SC_INFO // scp::log::TRACEALL 353 | }; 354 | static const std::array verbosity = { 355 | sc_core::SC_NONE, // scp::log::NONE 356 | sc_core::SC_LOW, // scp::log::FATAL 357 | sc_core::SC_LOW, // scp::log::ERROR 358 | sc_core::SC_LOW, // scp::log::WARNING 359 | sc_core::SC_MEDIUM, // scp::log::INFO 360 | sc_core::SC_HIGH, // scp::log::DEBUG 361 | sc_core::SC_FULL, // scp::log::TRACE 362 | sc_core::SC_DEBUG // scp::log::TRACEALL 363 | }; 364 | static std::mutex cfg_guard; 365 | static void configure_logging() { 366 | std::lock_guard lock(cfg_guard); 367 | static bool spdlog_initialized = false; 368 | 369 | sc_core::sc_report_handler::set_actions( 370 | sc_core::SC_ERROR, 371 | sc_core::SC_DEFAULT_ERROR_ACTIONS | sc_core::SC_DISPLAY); 372 | sc_core::sc_report_handler::set_actions(sc_core::SC_FATAL, 373 | sc_core::SC_DEFAULT_FATAL_ACTIONS); 374 | sc_core::sc_report_handler::set_verbosity_level( 375 | verbosity[static_cast(log_cfg.level)]); 376 | sc_core::sc_report_handler::set_handler(report_handler); 377 | if (!spdlog_initialized) { 378 | spdlog::init_thread_pool( 379 | 1024U, 380 | log_cfg.log_file_name.size() 381 | ? 2U 382 | : 1U); // queue with 8k items and 1 backing thread. 383 | log_cfg.console_logger = log_cfg.log_async 384 | ? spdlog::stdout_color_mt< 385 | spdlog::async_factory>( 386 | "console_logger") 387 | : spdlog::stdout_color_mt( 388 | "console_logger"); 389 | auto logger_fmt = log_cfg.print_severity ? "[%L] %v" : "%v"; 390 | if (log_cfg.colored_output) { 391 | std::ostringstream os; 392 | os << "%^" << logger_fmt << "%$"; 393 | log_cfg.console_logger->set_pattern(os.str()); 394 | } else 395 | log_cfg.console_logger->set_pattern("[%L] %v"); 396 | log_cfg.console_logger->flush_on(spdlog::level::warn); 397 | log_cfg.console_logger->set_level(spdlog::level::level_enum::trace); 398 | if (log_cfg.log_file_name.size()) { 399 | { 400 | std::ofstream ofs; 401 | ofs.open(log_cfg.log_file_name, 402 | std::ios::out | std::ios::trunc); 403 | } 404 | log_cfg.file_logger = log_cfg.log_async 405 | ? spdlog::basic_logger_mt< 406 | spdlog::async_factory>( 407 | "file_logger", 408 | log_cfg.log_file_name) 409 | : spdlog::basic_logger_mt( 410 | "file_logger", 411 | log_cfg.log_file_name); 412 | if (log_cfg.print_severity) 413 | log_cfg.file_logger->set_pattern("[%8l] %v"); 414 | else 415 | log_cfg.file_logger->set_pattern("%v"); 416 | log_cfg.file_logger->flush_on(spdlog::level::warn); 417 | log_cfg.file_logger->set_level(spdlog::level::level_enum::trace); 418 | } 419 | spdlog_initialized = true; 420 | } else { 421 | log_cfg.console_logger = spdlog::get("console_logger"); 422 | if (log_cfg.log_file_name.size()) 423 | log_cfg.file_logger = spdlog::get("file_logger"); 424 | } 425 | if (log_cfg.log_filter_regex.size()) { 426 | log_cfg.reg_ex = std::regex(log_cfg.log_filter_regex, 427 | std::regex::extended | std::regex::icase); 428 | } 429 | } 430 | 431 | void scp::reinit_logging(scp::log level) { 432 | sc_core::sc_report_handler::set_handler(report_handler); 433 | log_cfg.level = level; 434 | lut.clear(); 435 | } 436 | 437 | void scp::init_logging(scp::log level, unsigned type_field_width, 438 | bool print_time) { 439 | log_cfg.msg_type_field_width = type_field_width; 440 | log_cfg.print_sys_time = print_time; 441 | log_cfg.level = level; 442 | configure_logging(); 443 | } 444 | 445 | void scp::init_logging(const scp::LogConfig& log_config) { 446 | log_cfg = log_config; 447 | configure_logging(); 448 | } 449 | 450 | void scp::set_logging_level(scp::log level) { 451 | log_cfg.level = level; 452 | sc_core::sc_report_handler::set_verbosity_level( 453 | verbosity[static_cast(level)]); 454 | log_cfg.console_logger->set_level(static_cast( 455 | SPDLOG_LEVEL_OFF - 456 | std::min(SPDLOG_LEVEL_OFF, static_cast(log_cfg.level)))); 457 | } 458 | 459 | auto scp::get_logging_level() -> scp::log { 460 | return log_cfg.level; 461 | } 462 | 463 | void scp::set_cycle_base(sc_core::sc_time period) { 464 | log_cfg.cycle_base = period; 465 | } 466 | 467 | auto scp::LogConfig::logLevel(scp::log level) -> scp::LogConfig& { 468 | this->level = level; 469 | return *this; 470 | } 471 | 472 | auto scp::LogConfig::msgTypeFieldWidth(unsigned width) -> scp::LogConfig& { 473 | this->msg_type_field_width = width; 474 | return *this; 475 | } 476 | 477 | auto scp::LogConfig::printSysTime(bool enable) -> scp::LogConfig& { 478 | this->print_sys_time = enable; 479 | return *this; 480 | } 481 | 482 | auto scp::LogConfig::printSimTime(bool enable) -> scp::LogConfig& { 483 | this->print_sim_time = enable; 484 | return *this; 485 | } 486 | 487 | auto scp::LogConfig::printDelta(bool enable) -> scp::LogConfig& { 488 | this->print_delta = enable; 489 | return *this; 490 | } 491 | 492 | auto scp::LogConfig::printSeverity(bool enable) -> scp::LogConfig& { 493 | this->print_severity = enable; 494 | return *this; 495 | } 496 | 497 | auto scp::LogConfig::logFileName(std::string&& name) -> scp::LogConfig& { 498 | this->log_file_name = name; 499 | return *this; 500 | } 501 | 502 | auto scp::LogConfig::logFileName(const std::string& name) -> scp::LogConfig& { 503 | this->log_file_name = name; 504 | return *this; 505 | } 506 | 507 | auto scp::LogConfig::coloredOutput(bool enable) -> scp::LogConfig& { 508 | this->colored_output = enable; 509 | return *this; 510 | } 511 | 512 | auto scp::LogConfig::logFilterRegex(std::string&& expr) -> scp::LogConfig& { 513 | this->log_filter_regex = expr; 514 | return *this; 515 | } 516 | 517 | auto scp::LogConfig::logFilterRegex(const std::string& expr) 518 | -> scp::LogConfig& { 519 | this->log_filter_regex = expr; 520 | return *this; 521 | } 522 | 523 | auto scp::LogConfig::logAsync(bool v) -> scp::LogConfig& { 524 | this->log_async = v; 525 | return *this; 526 | } 527 | 528 | auto scp::LogConfig::reportOnlyFirstError(bool v) -> scp::LogConfig& { 529 | this->report_only_first_error = v; 530 | return *this; 531 | } 532 | 533 | auto scp::LogConfig::fileInfoFrom(int v) -> scp::LogConfig& { 534 | this->file_info_from = v; 535 | return *this; 536 | } 537 | 538 | std::vector split(const std::string& s) { 539 | std::vector result; 540 | std::istringstream iss(s); 541 | std::string item; 542 | while (std::getline(iss, item, '.')) { 543 | result.push_back(item); 544 | } 545 | return result; 546 | } 547 | 548 | std::string join(std::vector vec) { 549 | if (vec.empty()) 550 | return ""; 551 | return std::accumulate( 552 | vec.begin(), vec.end(), std::string(), 553 | [](const std::string& a, const std::string& b) -> std::string { 554 | return a + (a.length() > 0 ? "." : "") + b; 555 | }); 556 | } 557 | 558 | std::vector scp::get_logging_parameters() { 559 | return std::vector(logging_parameters.begin(), 560 | logging_parameters.end()); 561 | } 562 | 563 | sc_core::sc_verbosity cci_lookup(cci::cci_broker_handle broker, 564 | std::string name) { 565 | auto param_name = (name.empty()) ? SCP_LOG_LEVEL_PARAM_NAME 566 | : name + "." SCP_LOG_LEVEL_PARAM_NAME; 567 | auto h = broker.get_param_handle(param_name); 568 | if (h.is_valid()) { 569 | return verbosity.at(std::min(h.get_cci_value().get_int(), 570 | verbosity.size() - 1)); 571 | } else { 572 | auto val = broker.get_preset_cci_value(param_name); 573 | 574 | if (val.is_int()) { 575 | broker.lock_preset_value(param_name); 576 | return verbosity.at( 577 | std::min(val.get_int(), verbosity.size() - 1)); 578 | } 579 | } 580 | return sc_core::SC_UNSET; 581 | } 582 | 583 | #ifdef __GNUG__ 584 | std::string demangle(const char* name) { 585 | int status = -4; // some arbitrary value to eliminate the compiler 586 | // warning 587 | 588 | // enable c++11 by passing the flag -std=c++11 to g++ 589 | std::unique_ptr res{ 590 | abi::__cxa_demangle(name, NULL, NULL, &status), std::free 591 | }; 592 | 593 | return (status == 0) ? res.get() : name; 594 | } 595 | #else 596 | // does nothing if not GNUG 597 | std::string demangle(const char* name) { 598 | return name; 599 | } 600 | #endif 601 | 602 | void insert(std::multimap>& map, 603 | std::string s, bool interesting) { 604 | int n = std::count(s.begin(), s.end(), '.'); 605 | map.insert(make_pair(n, s)); 606 | 607 | if (interesting) { 608 | logging_parameters.insert(s + "." SCP_LOG_LEVEL_PARAM_NAME); 609 | } 610 | } 611 | 612 | sc_core::sc_verbosity scp::scp_logger_cache::get_log_verbosity_cached( 613 | const char* scname, const char* tname = "") { 614 | if (level != sc_core::SC_UNSET) { 615 | return level; 616 | } 617 | 618 | if (!scname && features.size()) 619 | scname = features[0].c_str(); 620 | if (!scname) 621 | scname = ""; 622 | 623 | type = std::string(scname); 624 | 625 | #ifdef HAS_CCI 626 | try { 627 | // we rely on there being a broker, allow this to throw if not 628 | auto broker = sc_core::sc_get_current_object() 629 | ? cci::cci_get_broker() 630 | : cci::cci_get_global_broker(scp_global_originator); 631 | 632 | std::multimap> allfeatures; 633 | 634 | /* initialize */ 635 | for (auto scn = split(scname); scn.size(); scn.pop_back()) { 636 | for (int first = 0; first < scn.size(); first++) { 637 | auto f = scn.begin() + first; 638 | std::vector p(f, scn.end()); 639 | auto scn_str = ((first > 0) ? "*." : "") + join(p); 640 | 641 | for (auto ft : features) { 642 | for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { 643 | insert(allfeatures, scn_str + "." + join(ftn), 644 | first == 0); 645 | } 646 | } 647 | insert(allfeatures, scn_str + "." + demangle(tname), 648 | first == 0); 649 | insert(allfeatures, scn_str, first == 0); 650 | } 651 | } 652 | for (auto ft : features) { 653 | for (auto ftn = split(ft); ftn.size(); ftn.pop_back()) { 654 | insert(allfeatures, join(ftn), true); 655 | insert(allfeatures, "*." + join(ftn), false); 656 | } 657 | } 658 | insert(allfeatures, demangle(tname), true); 659 | insert(allfeatures, "*", false); 660 | insert(allfeatures, "", false); 661 | 662 | for (std::pair f : allfeatures) { 663 | sc_core::sc_verbosity v = cci_lookup(broker, f.second); 664 | if (v != sc_core::SC_UNSET) { 665 | level = v; 666 | return v; 667 | } 668 | } 669 | } catch (const std::exception&) { 670 | // If there is no global broker, revert to initialized verbosity level 671 | } 672 | 673 | #endif 674 | 675 | return level = static_cast( 676 | ::sc_core::sc_report_handler::get_verbosity_level()); 677 | } 678 | 679 | auto scp::get_log_verbosity(char const* str) -> sc_core::sc_verbosity { 680 | auto k = char_hash(str); 681 | auto it = lut.find(k); 682 | if (it != lut.end()) 683 | return it->second; 684 | 685 | scp::scp_logger_cache tmp; 686 | lut[k] = tmp.get_log_verbosity_cached(str); 687 | return lut[k]; 688 | } 689 | -------------------------------------------------------------------------------- /tlm_extensions/initiator_id/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | project(initiator_id VERSION 1.0 LANGUAGES CXX C) 3 | 4 | set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.") 5 | 6 | set(GITHUB "https://github.com/" CACHE STRING "github base url") 7 | 8 | include(FetchContent) 9 | include(CTest) 10 | 11 | FetchContent_Declare( 12 | cpm-cmake 13 | GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git 14 | GIT_SHALLOW True 15 | GIT_TAG v0.31.1 16 | ) 17 | 18 | FetchContent_MakeAvailable(cpm-cmake) 19 | include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) 20 | 21 | cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") 22 | 23 | cpmaddpackage( 24 | NAME SystemCLanguage 25 | GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git 26 | GIT_SHALLOW True 27 | GIT_TAG main 28 | ) 29 | 30 | add_library(${PROJECT_NAME} INTERFACE) 31 | 32 | target_include_directories( 33 | ${PROJECT_NAME} INTERFACE 34 | $ 35 | $ 36 | ) 37 | 38 | if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) 39 | enable_testing() 40 | add_subdirectory(tests) 41 | endif() 42 | 43 | add_library("scp::tlm_extensions::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) 44 | packageproject( 45 | NAME "${PROJECT_NAME}" 46 | VERSION ${PROJECT_VERSION} 47 | NAMESPACE scp::tlm_extensions 48 | BINARY_DIR ${PROJECT_BINARY_DIR} 49 | INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include 50 | INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 51 | VERSION_HEADER "${VERSION_HEADER_LOCATION}" 52 | COMPATIBILITY SameMajorVersion 53 | ) 54 | install( 55 | TARGETS ${PROJECT_NAME} 56 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 57 | COMPONENT "${PROJECT_NAME}_Runtime" 58 | NAMELINK_COMPONENT "${PROJECT_NAME}_Development" 59 | ) 60 | 61 | -------------------------------------------------------------------------------- /tlm_extensions/initiator_id/README.md: -------------------------------------------------------------------------------- 1 | # initiatorID Extension 2 | 3 | This extension provides a simple uint64_t type. The expectation is that the users of this extension will know the ID that they need to 'stamp' on the initiator ID. It would be advisable to use a configurable parameter to set this initiator ID. 4 | 5 | 6 | -------------------------------------------------------------------------------- /tlm_extensions/initiator_id/include/scp/tlm_extensions/initiator_id.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #ifndef _SCP_INITIATOR_ID_EXTENSION_H 17 | #define _SCP_INITIATOR_ID_EXTENSION_H 18 | 19 | #include 20 | #include 21 | 22 | namespace scp { 23 | namespace tlm_extensions { 24 | /** 25 | * @class initiator ID recording TLM extension 26 | * 27 | * @brief initiator ID recording TLM extension 28 | * 29 | * @details Ignorable Extension type that can be used to add a initiator ID 30 | * (uint64_t). This is typically used for e.g. evaluating exclusive accesses. 31 | */ 32 | 33 | class initiator_id : public tlm::tlm_extension 34 | { 35 | uint64_t m_id; 36 | 37 | public: 38 | initiator_id(uint64_t id) { m_id = id; } 39 | initiator_id(const initiator_id&) = default; 40 | 41 | virtual tlm_extension_base* clone() const override { 42 | return new initiator_id(*this); 43 | } 44 | 45 | virtual void copy_from(const tlm_extension_base& ext) override { 46 | const initiator_id& other = static_cast(ext); 47 | *this = other; 48 | } 49 | 50 | operator uint64_t() { return m_id; }; 51 | 52 | #define overload(_OP) \ 53 | initiator_id& operator _OP(const uint64_t id) { \ 54 | this->m_id _OP id; \ 55 | return *this; \ 56 | } 57 | overload(+=); 58 | overload(-=); 59 | overload(*=); 60 | overload(/=); 61 | overload(%=); 62 | overload(&=); 63 | overload(|=); 64 | overload(^=); 65 | overload(<<=); 66 | overload(>>=); 67 | 68 | initiator_id& operator=(const uint64_t id) { 69 | m_id = id; 70 | return *this; 71 | } 72 | }; 73 | } // namespace tlm_extensions 74 | } // namespace scp 75 | #endif 76 | -------------------------------------------------------------------------------- /tlm_extensions/initiator_id/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(run_test test) 2 | add_executable(${test} ${test}.cc) 3 | target_link_libraries(${test} scp::tlm_extensions::initiator_id SystemC::systemc) 4 | add_test(NAME ${test} COMMAND ${test}) 5 | endmacro() 6 | 7 | run_test(smoke) 8 | -------------------------------------------------------------------------------- /tlm_extensions/initiator_id/tests/smoke.cc: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | SC_MODULE (test) { 22 | SC_CTOR (test) { 23 | scp::tlm_extensions::initiator_id mid(0x1234); 24 | mid = 0x2345; 25 | mid &= 0xff; 26 | mid <<= 4; 27 | uint64_t myint = mid + mid; 28 | myint += mid; 29 | if (mid == 0x450) { 30 | SC_REPORT_INFO("ext test", "Success\n"); 31 | } else { 32 | SC_REPORT_INFO("ext test", "Failour\n"); 33 | } 34 | } 35 | }; 36 | 37 | int sc_main(int argc, char** argv) { 38 | test test1("test"); 39 | 40 | sc_core::sc_start(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /tlm_extensions/path_trace/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | project(path_trace VERSION 1.0 LANGUAGES CXX C) 3 | 4 | set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.") 5 | 6 | set(GITHUB "https://github.com/" CACHE STRING "github base url") 7 | 8 | include(FetchContent) 9 | include(CTest) 10 | 11 | FetchContent_Declare( 12 | cpm-cmake 13 | GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git 14 | GIT_SHALLOW True 15 | GIT_TAG v0.31.1 16 | ) 17 | 18 | FetchContent_MakeAvailable(cpm-cmake) 19 | include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake) 20 | 21 | cpmaddpackage("${GITHUB}TheLartians/PackageProject.cmake.git@1.4.1") 22 | 23 | cpmaddpackage( 24 | NAME SystemCLanguage 25 | GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git 26 | GIT_SHALLOW True 27 | GIT_TAG main 28 | ) 29 | 30 | add_library(${PROJECT_NAME} INTERFACE) 31 | 32 | target_include_directories( 33 | ${PROJECT_NAME} INTERFACE 34 | $ 35 | $ 36 | ) 37 | 38 | if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")) 39 | enable_testing() 40 | add_subdirectory(tests) 41 | endif() 42 | 43 | add_library("scp::tlm_extensions::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) 44 | packageproject( 45 | NAME "${PROJECT_NAME}" 46 | VERSION ${PROJECT_VERSION} 47 | NAMESPACE scp::tlm_extensions 48 | BINARY_DIR ${PROJECT_BINARY_DIR} 49 | INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include 50 | INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 51 | VERSION_HEADER "${VERSION_HEADER_LOCATION}" 52 | COMPATIBILITY SameMajorVersion 53 | ) 54 | install( 55 | TARGETS ${PROJECT_NAME} 56 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 57 | COMPONENT "${PROJECT_NAME}_Runtime" 58 | NAMELINK_COMPONENT "${PROJECT_NAME}_Development" 59 | ) 60 | 61 | -------------------------------------------------------------------------------- /tlm_extensions/path_trace/README.md: -------------------------------------------------------------------------------- 1 | # Path Trace Extension 2 | 3 | This extension provides a vector of SystemC objects. The expectation is that each SystemC model will 'stamp' the transaction as it passes through a network. 4 | The extension provides the following API: 5 | 6 | `void stamp(sc_core::sc_object* obj)` 7 | : Stamp object obj into the Path Trace 8 | 9 | `void reset()` 10 | : Clear the Path trace, (eg. before returning it to a memeory allocation pool) 11 | 12 | `std::string to_string(std::string separator = "->")` 13 | :Convert the Path trace to a string, using the separator (default "->") 14 | 15 | 16 | -------------------------------------------------------------------------------- /tlm_extensions/path_trace/include/scp/tlm_extensions/path_trace.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #ifndef _SCP_PATHTRACE_EXTENSION_H 17 | #define _SCP_PATHTRACE_EXTENSION_H 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace scp { 24 | namespace tlm_extensions { 25 | 26 | /** 27 | * @class Path recording TLM extension 28 | * 29 | * @brief Path recording TLM extension 30 | * 31 | * @details Ignorable Extension type that can be used to trace 32 | * transactions as they pass through a network. 33 | */ 34 | 35 | class path_trace : public tlm::tlm_extension 36 | { 37 | std::vector m_path; 38 | 39 | public: 40 | path_trace() = default; 41 | path_trace(const path_trace&) = default; 42 | 43 | virtual tlm_extension_base* clone() const override { 44 | return new path_trace(*this); 45 | } 46 | 47 | virtual void copy_from(const tlm_extension_base& ext) override { 48 | const path_trace& other = static_cast(ext); 49 | *this = other; 50 | } 51 | 52 | /** 53 | * @brief Stamp object into the PathTrace 54 | * @param obj Object to add to the PathTrace 55 | */ 56 | void stamp(sc_core::sc_object* obj) { m_path.push_back(obj); } 57 | 58 | /** 59 | * @brief Convenience function to clear vector (eg. before returning to a 60 | * pool) 61 | */ 62 | void reset() { m_path.clear(); } 63 | /** 64 | * @brief convert extension to a string 65 | * @param separator (default "->") 66 | * @return a string consisting of the names of each object stamped into the 67 | * path separated with the separator provided. 68 | */ 69 | std::string to_string(std::string separator = "->") { 70 | std::stringstream info; 71 | std::string s; 72 | for (auto o : m_path) { 73 | info << s << o->name(); 74 | s = separator; 75 | } 76 | return info.str(); 77 | } 78 | }; 79 | } // namespace tlm_extensions 80 | } // namespace scp 81 | #endif 82 | -------------------------------------------------------------------------------- /tlm_extensions/path_trace/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(run_test test) 2 | add_executable(${test} ${test}.cc) 3 | target_link_libraries(${test} scp::tlm_extensions::path_trace SystemC::systemc) 4 | add_test(NAME ${test} COMMAND ${test}) 5 | endmacro() 6 | 7 | run_test(smoke) 8 | -------------------------------------------------------------------------------- /tlm_extensions/path_trace/tests/smoke.cc: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 3 | more contributor license agreements. See the NOTICE file distributed 4 | with this work for additional information regarding copyright ownership. 5 | Accellera licenses this file to you under the Apache License, Version 2.0 6 | (the "License"); you may not use this file except in compliance with the 7 | License. You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | implied. See the License for the specific language governing 13 | permissions and limitations under the License. 14 | ****************************************************************************/ 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | SC_MODULE (test) { 22 | SC_CTOR (test) { 23 | scp::tlm_extensions::path_trace ext; 24 | ext.stamp(this); 25 | SC_REPORT_INFO("ext test", ext.to_string().c_str()); 26 | ext.reset(); 27 | 28 | ext.stamp(this); 29 | ext.stamp(this); 30 | ext.stamp(this); 31 | SC_REPORT_INFO("ext test", ext.to_string().c_str()); 32 | 33 | if (ext.to_string() == "test->test->test") { 34 | SC_REPORT_INFO("ext test", "Success\n"); 35 | } else { 36 | SC_REPORT_INFO("ext test", "Failour\n"); 37 | } 38 | ext.reset(); 39 | } 40 | }; 41 | 42 | int sc_main(int argc, char** argv) { 43 | test test1("test"); 44 | 45 | sc_core::sc_start(); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /utils/check_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ############################################################################## 4 | # # 5 | # Copyright 2022 Lukas Jünger # 6 | # # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); # 8 | # you may not use this file except in compliance with the License. # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | # # 19 | ############################################################################## 20 | 21 | source=$(find -name "*.h" -or -name "*.hpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cpp") 22 | exec clang-format --Werror $source $@ 23 | --------------------------------------------------------------------------------