Report Handler Internals
How SC_REPORT macros become sc_report objects, actions, severity counts, cached reports, and simulation control.
Report Handler Internals
Reports are the diagnostic backbone of a serious SystemC model. std::cout is fine for quick hacks, but a reusable, LRM-compliant model must use SC_REPORT_INFO, SC_REPORT_WARNING, SC_REPORT_ERROR, and SC_REPORT_FATAL.
To truly master SystemC reporting, you need to understand how the sc_core::sc_report_handler translates a macro call into an actionable event, how severity limits work, and how to write custom report handlers.
The Standard LRM Report Flow
When you call SC_REPORT_WARNING("ROUTER", "Unmapped access");, the LRM dictates the following sequence:
- Macro Expansion: The macro captures the file name (
__FILE__) and line number (__LINE__). - Object Creation: It instantiates an
sc_core::sc_reportobject containing the severity, message type ("ROUTER"), message text, file, and line. - Handler Dispatch: The global
sc_core::sc_report_handler::report()function is invoked. - Action Resolution: The handler looks up the configured
sc_actionfor the specific message type or severity. - Limit Checking: The handler increments the count for that severity/type. If the count exceeds the configured limit (e.g., maximum 10 errors allowed), the handler forces an
SC_STOPorSC_ABORT. - Execution: The resolved actions (
SC_LOG,SC_DISPLAY,SC_THROW, etc.) are executed.
Verbosity Limits
SystemC also supports verbosity levels (from SC_NONE to SC_DEBUG). You can filter out low-level debug messages dynamically without recompiling:
sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_HIGH);
// This will be suppressed if verbosity is set below SC_DEBUG
SC_REPORT_INFO_VERB("CACHE", "Cache hit on line 4", sc_core::SC_DEBUG);Severity Limits and Quotas
You can instruct the kernel to automatically stop the simulation if too many warnings or errors occur:
// Stop simulation after 5 errors
sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, sc_core::SC_DISPLAY | sc_core::SC_STOP);
sc_core::sc_report_handler::stop_after(sc_core::SC_ERROR, 5);Complete Example: Custom Report Handler
The ultimate power of the sc_report_handler is the ability to bypass the default printing mechanism entirely and install a custom handler hook. This is heavily used in professional verification environments (like UVM-SystemC) to pipe SystemC reports into external logging frameworks (like JSON loggers or Python test runners).
This complete sc_main demonstrates setting up a custom report handler.
#include <systemc>
#include <iostream>
#include <string>
// 1. Define a custom handler function matching the LRM signature
void custom_json_report_handler(const sc_core::sc_report& rep, const sc_core::sc_actions& actions) {
// Only process if the action dictates display or log
if (actions & sc_core::SC_DISPLAY) {
std::cout << "{ \"severity\": \"";
switch (rep.get_severity()) {
case sc_core::SC_INFO: std::cout << "INFO"; break;
case sc_core::SC_WARNING: std::cout << "WARNING"; break;
case sc_core::SC_ERROR: std::cout << "ERROR"; break;
case sc_core::SC_FATAL: std::cout << "FATAL"; break;
}
std::cout << "\", \"type\": \"" << rep.get_msg_type() << "\""
<< ", \"time\": \"" << rep.get_time() << "\""
<< ", \"file\": \"" << rep.get_file_name() << "\""
<< ", \"line\": " << rep.get_line_number()
<< ", \"message\": \"" << rep.get_msg() << "\" }\n";
}
// Always respect the SC_STOP and SC_ABORT actions in a custom handler!
if (actions & sc_core::SC_STOP) {
sc_core::sc_stop();
}
if (actions & sc_core::SC_ABORT) {
std::abort();
}
if (actions & sc_core::SC_THROW) {
throw rep;
}
}
SC_MODULE(CustomLoggerDemo) {
SC_CTOR(CustomLoggerDemo) {
SC_THREAD(run);
}
void run() {
wait(10, sc_core::SC_NS);
SC_REPORT_INFO("SYSTEM", "Booting kernel...");
wait(15, sc_core::SC_NS);
SC_REPORT_WARNING("MEM", "Memory usage at 90%");
wait(5, sc_core::SC_NS);
SC_REPORT_ERROR("BUS", "Timeout on AHB bus transaction!");
}
};
int sc_main(int argc, char* argv[]) {
// 2. Install the custom handler hook
sc_core::sc_report_handler::set_handler(custom_json_report_handler);
// Ensure errors don't throw, but just display (which routes to our JSON handler)
sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, sc_core::SC_DISPLAY);
CustomLoggerDemo demo("demo");
sc_core::sc_start();
return 0;
}Explanation of the Execution
When run, instead of the standard SystemC text output, the custom handler generates structured JSON logs:
{ "severity": "INFO", "type": "SYSTEM", "time": "10 ns", "file": "main.cpp", "line": 42, "message": "Booting kernel..." }
{ "severity": "WARNING", "type": "MEM", "time": "25 ns", "file": "main.cpp", "line": 45, "message": "Memory usage at 90%" }
{ "severity": "ERROR", "type": "BUS", "time": "30 ns", "file": "main.cpp", "line": 48, "message": "Timeout on AHB bus transaction!" }By hooking into sc_report_handler, you have complete control over how diagnostics are formatted and routed, allowing seamless integration with CI/CD pipelines and external databases.
Comments and Corrections