This section highlights several Simics features available when running SystemC models within the Simics environment.
In Simics, the SystemC scheduler runs under the control of the Simics framework, allowing simulations to be started and paused using the Simics GUI or standard Simics commands like continue and stop. For more details, refer to the section 5.1.
SystemC logs are seamlessly integrated into Simics logs on the Adapter object. The mapping of different SystemC verbosity and severity levels to Simics log levels and types is detailed in the section 5.2.
All SystemC objects derived from the sc_object class are visible in Simics as
configuration objects, enabling interaction with these objects via the Simics
CLI. For more details, refer to section 5.3.
There are many Simics commands available to use on a SystemC object. Use help SystemC (after loading a SystemC module) to get a list of all supported SystemC
CLI commands. And use help on a selected command to get detailed information.
Besides the SystemC related commands, normal Simics commands work as expected.
For example, to find all SystemC ports the command list-objects can be used
with sc_port as the type argument.
simics> list-objects -show-port-objects iface=sc_port
┌─────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────┐
│ Object │ Class │
├─────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────┤
│lt.dut.m_at_and_lt_target_1.memory_socket_1_port_0 │<lt_example_sc_port> │
│lt.dut.m_bus.simple_initiator_socket_tagged_0 │<lt_example_tlm_initiator_socket_dut_m_bus_simple_initiator_socket_tagged_0> │
│lt.dut.m_bus.simple_initiator_socket_tagged_1 │<lt_example_tlm_initiator_socket_dut_m_bus_simple_initiator_socket_tagged_1> │
│lt.dut.m_bus.simple_target_socket_tagged_0_port_0 │<lt_example_sc_port> │
│lt.dut.m_bus.simple_target_socket_tagged_1_port_0 │<lt_example_sc_port> │
│lt.dut.m_initiator_1.m_initiator.initiator_socket │<lt_example_tlm_initiator_socket_dut_m_initiator_1_m_initiator_initiator_socket> │
│lt.dut.m_initiator_1.m_initiator.initiator_socket_opt│<lt_example_tlm_initiator_socket_dut_m_initiator_1_m_initiator_initiator_socket_opt>│
│lt.dut.m_initiator_1.m_initiator.port_0 │<lt_example_sc_port> │
│lt.dut.m_initiator_1.m_initiator.port_1 │<lt_example_sc_port> │
│lt.dut.m_initiator_1.m_traffic_gen.port_0 │<lt_example_sc_port> │
│lt.dut.m_initiator_1.m_traffic_gen.port_1 │<lt_example_sc_port> │
│lt.dut.m_initiator_1.top_initiator_socket │<lt_example_tlm_initiator_socket_dut_m_initiator_1_top_initiator_socket> │
│lt.dut.m_initiator_2.m_initiator.initiator_socket │<lt_example_tlm_initiator_socket_dut_m_initiator_2_m_initiator_initiator_socket> │
│lt.dut.m_initiator_2.m_initiator.initiator_socket_opt│<lt_example_tlm_initiator_socket_dut_m_initiator_2_m_initiator_initiator_socket_opt>│
│lt.dut.m_initiator_2.m_initiator.port_0 │<lt_example_sc_port> │
│lt.dut.m_initiator_2.m_initiator.port_1 │<lt_example_sc_port> │
│lt.dut.m_initiator_2.m_traffic_gen.port_0 │<lt_example_sc_port> │
│lt.dut.m_initiator_2.m_traffic_gen.port_1 │<lt_example_sc_port> │
│lt.dut.m_initiator_2.top_initiator_socket │<lt_example_tlm_initiator_socket_dut_m_initiator_2_top_initiator_socket> │
│lt.dut.m_lt_target_2.memory_socket_2_opt_port_0 │<lt_example_sc_port> │
│lt.dut.m_lt_target_2.memory_socket_2_port_0 │<lt_example_sc_port> │
└─────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────┘
SystemC signals and TLM2 sockets can be traced or have breakpoints attached to them. Please refer to section 5.5 for more information about trace and break on SystemC objects.
Standalone SystemC application does not support pausing and resuming simulations
like a traditional debugger. To simulate a pause, you can run the simulation for
a specified duration using sc_start() with a time argument, and then resume it
later by calling sc_start() again. However, this approach requires rebuilding
the test bench and restarting the simulation from the beginning each time you
need to pause at a specific point.
Running SystemC within the Simics framework provides enhanced simulation control, as the SystemC scheduler operates under Simics’ management. This setup offers several significant advantages:
Consider the example of the empty-device-sc-only from the section
3.2. Instead of running
the simulation to completion, you can pause it at any desired moment. For
instance, in the simulation example below, the simulation is paused at 500 ns.
You can check the simulation time in picoseconds by using the ptime command
with the -pico-seconds option. Additionally, you can inspect the current
SystemC event queue with peq -i. In this example, it shows that the next
SystemC event is scheduled after 500 ns. The simulation can then be continued
from this point.
simics> @SIM_create_object('empty_device_sc_only', 'dev')
<the empty_device_sc_only 'dev'>
simics> dev.log-level 2
[dev] Changing log level: 1 -> 2
simics> run-seconds seconds = 500e-9
[dev info] Looping... @ 0 s of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 500 ns of intel/empty-device-sc-only/info in sc-device.cc:14
simics> ptime -pico-seconds
┌─────────┬───────────┐
│Processor│Picoseconds│
├─────────┼───────────┤
│dev │ 500000│
└─────────┴───────────┘
simics> peq -i
┌──────────┬──────────┬──────────────┐
│ Cycle │ Object │ Description │
├──────────┼──────────┼──────────────┤
│4999500000│dev.engine│Internal: stop│
└──────────┴──────────┴──────────────┘
┌────────────┬──────┬─────────────────────────────┐
│SystemC (ps)│Object│ Description │
├────────────┼──────┼─────────────────────────────┤
│ 500000│dev │top.run_test (dynamic thread)│
└────────────┴──────┴─────────────────────────────┘
simics> continue
[dev info] Looping... @ 1 us of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 1500 ns of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 2 us of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 2500 ns of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 3 us of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 3500 ns of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 4 us of intel/empty-device-sc-only/info in sc-device.cc:14
[dev info] Looping... @ 4500 ns of intel/empty-device-sc-only/info in sc-device.cc:14
In Simics and SystemC, the terminology regarding simulation control differs significantly. In Simics, the term “stop” refers to pausing the current execution of the simulation, allowing you to resume it later from the same point. Conversely, in SystemC, “stop”, as in the context of “sc_stop()”, means terminating the simulation entirely, with no option to resume from where it left off.
SystemC Library implements a report handler which forwards SystemC reports to
Simics according to sc_report actions. Since SystemC does not have the concept
of objects attached to log messages, all messages will be printed on the
top-level Adapter object in Simics. It is possible to control SystemC logging
level using log-level command on the Adapter object. Also, all the normal
Simics logging commands, such as log-setup, log-type, work.
Simics performs a mapping from SystemC log concepts such as verbosity and
severity into Simics concepts. The sc_report actions work as defined by
IEEE-1666 standard. The most important mapping is the one from the SystemC
verbosity to the Simics log-level, as shown in the table below:
| Simics log-level | SystemC verbosity |
|---|---|
| 1 | verbosity < SC_MEDIUM |
| 2 | SC_MEDIUM ≤ verbosity < SC_HIGH |
| 3 | SC_HIGH ≤ verbosity < SC_DEBUG |
| 4 | SC_DEBUG ≤ verbosity |
Log messages map to the info category in Simics, unless the severity is greater than SC_WARNING, in which case the error category is used. It is also possible to emit unimplemented and spec-violation log categories by ending the message type with “unimplemented” or “unimpl”, or “spec-violation” or “spec-viol”, respectively. However, a severity greater than SC_WARNING will always generate an error log.
simics> lt.log-level level = 3
[lt] Changing log level: 1 -> 3
simics> bp.log.break object = lt
simics> c
[lt info] 0 s - traffic_generator_thread
Initiator: 101 Starting Traffic @ 0 s of traffic_generator.cpp in traffic_generator.cpp:114
[lt info] 0 s - traffic_generator_thread
Initiator: 102 Starting Traffic @ 0 s of traffic_generator.cpp in traffic_generator.cpp:114
[lt info] 0 s - initiator_thread
Initiator: 101 b_transport(GP, 0 s) @ 0 s of lt_initiator.cpp in lt_initiator.cpp:124
[lt info] 0 s - print
ID: 201 COMMAND: WRITE Length: 04
Addr: 0x0000000000000000 Data: 0x00000000 @ 0 s of memory.cpp in report.cpp:189
[lt info] 0 s - b_transport
Target: 201 returned delay of 0 s + 20 ns + 60 ns = 80 ns @ 0 s of at_target_1_phase.cpp in at_target_1_phase.cpp:111
[lt info] 0 s - initiator_thread
Initiator: 101 b_transport returned delay = 80 ns @ 0 s of lt_initiator.cpp in lt_initiator.cpp:145
[lt info] 0 s - initiator_thread
Initiator: 102 b_transport(GP, 0 s) @ 0 s of lt_initiator.cpp in lt_initiator.cpp:124
[lt info] 0 s - print
ID: 201 COMMAND: WRITE Length: 04
Addr: 0x0000000000000000 Data: 0x00000000 @ 0 s of memory.cpp in report.cpp:189
[lt info] 0 s - b_transport
Target: 201 returned delay of 0 s + 20 ns + 60 ns = 80 ns @ 0 s of at_target_1_phase.cpp in at_target_1_phase.cpp:111
[lt info] 0 s - initiator_thread
Initiator: 102 b_transport returned delay = 80 ns @ 0 s of lt_initiator.cpp in lt_initiator.cpp:145
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
[lt] Breakpoint 1: lt log message of type <all>
>
SystemC Library allows breaking simulation on SystemC log messages, which is
enabled by bp.log.break command. It should be noted that Simics does not break
immediately on the first log message, but rather after several log messages have
been printed. This is because a “break” in Simics corresponds to stopping
virtual time. All the log messages above were printed at the same virtual time,
and thus there is no way to stop until all messages have been printed and
virtual time is ready to move on. To understand what is going on between the
various log messages, source level debugging is required.
Logs using sc_report are automatically integrated with the Simics logging
system. However, since sc_report has some issues of its own it is common that
SystemC developers have their own logging API or resort to using plain
std::cout. While the use of standard streams for logging is highly discouraged
this sections explains how to redirect these logs to Simics. For more details,
refer to the section LogStream.
All SystemC objects derived from the sc_object class are visible in Simics as
configuration objects, enabling interaction with these objects via the Simics
CLI. For instance, the value of a SystemC signal can be read by invoking an
interface provided on the signal’s proxy object. For more details, refer to the
section SystemC Signal Read and Write.
The creation of these objects is governed by the create_proxy_objects
attribute of the adapter. If this attribute is set to false when creating the
SystemC module, no proxy objects are created, which can be beneficial in very
large systems where exposing all SystemC objects as Simics objects would consume
excessive memory.
If a SystemC object is not visible in Simics, ensure the following conditions are met:
SystemC Library has support for read and write of SystemC signals sc_signal,
sc_in, sc_out, and sc_inout. A signal’s value can be read by invoking the
Simics interface sc_signal_read on the signal object.
There is a second Simics interface, sc_signal_write, which is used to write a
value to the signal object. Based on the type of signal, either the
sc_signal_read, sc_signal_write, or both interfaces are implemented by the
object.
When writing a value to the signal object, the value will be updated during the next SystemC cycle. From the command line, simply invoke
c 1will update the signal object’s value.
SystemC signals use a template parameter that specifies the underlying value-type of the signal. This allows to use arbitrary classes as value-types. The current implementation directly supports the following value-types:
To support SystemC signals with a value-type not listed above,
simics::systemc::ScSignalAccessTemplate needs to be implemented.
To activate support for the additional type, the template class needs to be instantiated. This is required to register the support for the new value-type in the infrastructure. One possibility is to declare it as a member variable of the Adapter.
Below is an example that shows the required steps to support signals with a
value-type of sc_dt::sc_bigint<1024>.
class BigInt1024Access
: public simics::systemc::ScSignalAccessTemplate<sc_dt::sc_bigint<1024> > {
public:
bool attrToValueT(const attr_value_t *attr,
sc_dt::sc_bigint<1024> *value) const {
const char *str = NULL;
if (!attrToValue(attr, &str))
return false;
*value = str;
return true;
}
attr_value_t valueToAttrT(const sc_dt::sc_bigint<1024> &value) const {
std::string str = value.to_string();
return valueToAttr(str.c_str());
}
};
The function attrToValueT implements the transformation from a Simics
attr_value_t to the signal’s value-type. If the transformation cannot be
performed, false must be returned, otherwise true.
The template class provides attrToValue functions to transform from
attr_value_t to:
The function valueToAttrT is used to transform from the SystemC signal
value-type to a attr_value_t. The template class provides transformation for
the same types as listed above.
SystemC Library comes with a variety of tools that use the Simics instrumentation framework and interact with the SystemC objects. For generic information on how Simics instrumentation framework works please refer to the chapter in Analyzer User’s Guide
The following table shows the different kinds of SystemC objects and when they interact with the SystemC Library tools:
| SystemC object | Event |
|---|---|
sc_event | an event is notified |
SC_METHOD | a method process is triggered |
SC_THREAD | a thread process is triggered or resumed |
tlm_initiator_socket | a TLM initiator socket method is called |
tlm_target_socket | a TLM target socket method is called |
sc_signal | a signal’s value is changed |
sc_in/sc_out/sc_inout | a port’s value is changed |
There are two different ways to use the tools and their provided functionality. The user could use the Simics commands registered on the SystemC objects. These commands are tool-specific both in terms of functionality and usage. They automatically create an instrumentation tool for internal use by the commands. The user should avoid using this tool directly.
When using trace and break tools, existing DMI tables are automatically invalidated and the DMI hint is suppressed. When all tools have been removed, DMI hint is no longer suppressed - allowing the initiator to build up a new DMI table if supported.
In the following example, by invoking the command trace-sc on the SystemC
target socket, an internal instrumentation tool is created and connected to the
target socket. It traces the invocation of any socket method.
simics> simple.simple_device.target_socket.trace-sc
Created simple.internal.sc_trace_tool (connected to 1 provider)
For advanced instrumentation tasks, the user should use the Simics instrumentation framework directly. This makes it possible to use more tool features. It is, for example, possible to create a tool that only traces a certain event or method invocation. Other tools with different filtering options can of course be instantiated and operated in parallel.
The commands bound to the SystemC objects are covered in the tool specific sections below. The remainder of this section shows how the tools provided with SystemC Library can be used.
In the following example, a new trace tool is created that traces all supported SystemC objects. To avoid mixing different C++ ABIs, the standard SystemC tools are built together with the adapter as part of building the corresponding Simics module. The default name of the tool if not provided is prefixed with the module’s name. For readability it is recommended to create the tool as a sub-object of the adapter instead, as shown by the example below, whenever that makes sense.
When using trace and break tools, existing DMI tables are automatically invalidated and the DMI hint is suppressed. When all tools have been removed, DMI hint is no longer suppressed - allowing the initiator to build up a new DMI table if supported.
simics> simple.new-sc-trace-tool -connect-all name=simple.trace_tool
[simple.gasket_simple_device_target_socket.initiator_socket trace-invalidate-dmi-in] start_addr:0x0 end_addr:0xffffffffffffffff
Created simple.trace_tool (connected to 7 providers)
The newly created tool can now be disabled, enabled and, if it is of no use
anymore, removed. Additional SystemC objects can also be connected and
disconnected. All this information is available by invoking the command help
on the tool.
simics> help simple.trace_tool
To trace TLM sockets only, the user can instantiate a filter that only matches
sockets and add it to the tool. The filter can be removed later to trace all
supported objects again. There are four kinds of filters: signal, event, process
and socket. All this information is available by invoking help on the
new-systemc-filter command.
simics> new-systemc-filter socket
Created SystemC filter sc_filter0
simics> simple.trace_tool.add-filter sc_filter0
simics> simple.trace_tool.remove-filter sc_filter0
When connecting the tool to objects of socket kind the functions argument can be
used to select which TLM2 functions to act on. The functions argument correspond
to the methods in the tlm_bw_transport_if and tlm_fw_transport_if
interfaces. For each interface method there exists a pair of pre and post
functions. The pre function is used to instrument the transaction before it is
sent through the socket. The post function is used to instrument the transaction
after the invocation of the interface method has been performed.
The functions argument is optional. If omitted, all interface methods are handled by the tool. The argument is ignored and has no effect for connections to other kind of objects.
A summary of all tools and their supported functions can be shown by running:
simics> help topic = Instrumentation
SystemC allows to create and delete processes and events dynamically during simulation. Due to their dynamic nature, these objects do not have dedicated Simics configuration objects. Instead, they are grouped together and have one shared object for each type that can be used by the tools.
<adapter>.sc_event_all_dynamic can be used to connect tools to all dynamic
sc_event objects.
<adapter>.sc_process_all_dynamic can be used to connect tools to all dynamic
SC_METHOD or SC_THREAD objects.
The commands trace-sc, untrace-sc, break-sc, and unbreak-sc can be used
on these two Simics configuration objects.
The sc_trace_tool can be used for tracing any event listed in section
5.5.1.
To enable or disable tracing of these events, trace-sc or untrace-sc needs
to be invoked on the corresponding SystemC object. See help <sc_provider_controller>.trace-sc and help <sc_provider_controller>.untrace-sc for more information about the commands.
Section 5 contains an example of how to
enable tracing on a TLM2 socket.
There is also a set of commands that makes it possible to trace and untrace on
all objects of a certain kind. These commands are located in the corresponding
adapter. The following commands trace-sc-event-all, trace-sc-signal-all,
trace-sc-process-all, and trace-sc-socket-all are available for enabling
instrumentation and the following commands untrace-sc-event-all,
untrace-sc-signal-all, untrace-sc-process-all, and untrace-sc-socket-all
are available for disabling instrumentation.
The sc_break_tool is a tool that can be used to stop the simulation on any
event listed in section 5.5.1.
To enable or disable break on these events, break-sc or unbreak-sc has to be
invoked on the corresponding SystemC object. See help <sc_provider_controller>.break-sc and help <sc_provider_controller>.unbreak-sc for more information about the commands.
Section 5 contains an example of how to
enable tracing on a TLM2 socket; the break tools works just like trace.
There is also a set of commands that makes it possible to break and unbreak on
all objects of a certain kind. These commands are located in the corresponding
adapter. The following commands break-sc-event-all, break-sc-signal-all,
break-sc-process-all, and break-sc-socket-all are available for enabling
instrumentation and the following commands unbreak-sc-event-all,
unbreak-sc-signal-all, unbreak-sc-process-all, and unbreak-sc-socket-all
are available for disabling instrumentation.
For example, a transaction break-point can be set on a target socket as shown below.
simics> lt.dut.m_lt_target_2.memory_socket_2.break-sc
simics> c
[lt.dut.m_lt_target_2.memory_socket_2 break-b-in] write sz:4 addr:0x0 data:0xefffffff
[lt.dut.m_lt_target_2.memory_socket_2 break-b-out] write sz:4 addr:0x0 data:0xefffffff status:TLM_OK_RESPONSE
[lt.dut.m_lt_target_2.memory_socket_2 break-b-in] write sz:4 addr:0x0 data:0xefffffff
[lt.dut.m_lt_target_2.memory_socket_2 break-b-out] write sz:4 addr:0x0 data:0xefffffff status:TLM_OK_RESPONSE
>
In order to reduce the message length, Simics shortens common SystemC terminology. For instance, in the example above “b_in” refers to an inbound blocking transaction. The table below summarizes all the abbreviations.
| Simics | SystemC |
|---|---|
| b | blocking |
| nb | non-blocking |
| in | inbound |
| out | outbound |
| fw | forward |
| bw | backwards |
When a new socket type/protocol is used, it is necessary to register the
type/protocol with the awareness framework. If it is not registered the commands
trace-sc and break-sc will not be available for the new socket. As an
example, for a socket that uses width 64 and protocol “MyProtocol”, it is
necessary to register the socket calling the function registerSocketType<64, MyProtocol>().
Tracing and breaking has certain limitations. Please refer to chapter 7.
To simplify debugging of complex SystemC models where multiple TLM transactions are sent between multiple sockets, Simics has a capability to track the path a transaction went through as well as to save the history of the transaction changes which happened when the transaction travelled along the path. This capability is provided by the transaction tracker tool which is based on Simics instrumentation framework.
To track a transaction the tool connects to TLM sockets of the SystemC model and observes all the transactions which are sent between the sockets. The tool adds special TLM extension to each transaction passed through a socket, if the transaction does not have the extension added earlier, and uses the extension to save the transaction history. A new entry, consisting of current transaction attributes and hierarchical name of the socket, is appended to the history when the transaction is passed through the socket. Currently, the only transaction attribute which is saved in the entry is transaction address.
To create and connect the tool to all sockets of the SystemC model one should
use adapter’s track-transactions-all command. Corresponding
untrack-transactions-all command disconnects the tool from all the sockets.
One may use track-transactions command of a selected socket to connect the
socket to the tool, and untrack-transactions command to disconnect it. Also it
is possible to use instrumentation tool commands, such as add-instrumentation
or remove-instrumentation, to control connection of the tool to all or
selected sockets. Please refer to corresponding help commands or the
Instrumentation
chapter in
the Model Builder User’s Guide.
To view the transaction history user should enable GDB pretty printing for TLM transactions. The pretty printer output can be seen in GDB console.
The sc_protocol_checker_tool is a tool for validation of TLM2 transactions. It
checks the transactions sent through sockets and detect those which are not in
compliance with the “OSCI TLM-2.0 USER MANUAL”.
The checker is using the Doulos TLM-2.0 Base Protocol Checker of an older version. The checker will be upgraded to a more recent version checking against the IEEE Std 1666-2011 specification.
The sc_protocol_checker_tool supports tlm_initiator_socket and
tlm_target_socket as stated in section 5.5.1. This
tool does not have commands registered on the SystemC objects.
The protocol checker keeps track of the transaction state before the transaction is sent through a socket and after it returns. It checks all TLM socket methods for possible TLM2 transaction specification violations.
As an example, <adapter>.new-sc-protocol-checker-tool -connect-all can be used
to check all sockets in a simulation.
The sc_vcd_trace_tool generates files based on the VCD format.
As an example, the command <adapter>.new-sc-vcd-trace-tool file = myfile.vcd -connect-all would generate a file in VCD format containing changes for any
SystemC object listed in section 5.5.1 with the
exception of type SC_THREAD and SC_METHOD.
During generation, two files are created. One contains the header section with
variable definitions and the second file contains the value change section. When
Simics ends or the tool is deleted, these two files are merged together into a
single file. If this merge cannot be performed automatically, it should be
sufficient to append the file with the value change section on to the header
file. For instance: cat myfile.vcd.tail >> myfile.vcd
To aid users in developing well-performing models, Simics offers two ways of profiling SystemC processes. These features encompass a process profiler, that helps users identify performance-heavy processes, and memory profiling, that compiles memory statistics of memory-intensive processes. Details on how to enable and use these features are presented below.
The process profiler feature measures wall clock time execution of method- and
thread-processes. The feature is disabled by default, but can be enabled on
adapters by using the enable-process-profiler command. The feature can be
disabled again by using the command disable-process-profiler.
The profiling results can be obtained by using the adapter command
process-profiler-results. This command will show the number of processes of
each type and the number of calls and total time spent executing them.
If using the status command on a process, more detailed information will be
shown. This information will consist of minimum time, maximum time, total time
executing and number of calls to the process. For thread processes the number of
calls will represent the number of times we yielded to that process.
The clear-process-profiler-results command clears accumulated profiling
results. All process profiler data including the aggregated execution time is
cleared.
Memory profiling is enabled and disabled for each adapter by using the
enable-memory-profiler and disable-memory-profiler commands. Memory
profiling is disabled by default.
When memory profiling is enabled, Simics will record allocations and deallocations made in underlying processes. Please note that memory profiling has to be enabled for each adapter you wish to profile.
Users may inspect the current memory usage of a process by using the status
command on the corresponding object in the awareness object hierarchy.
Additionally, the collective memory usage of processes in a module may be
inspected by using the status command on that module.
Memory profiling has certain limitations listed in chapter 7.
SystemC Library supports unscheduled running of SystemC thread and SystemC
method process objects. Two different options are available to run the
processes. The first way is to locate the event object that the processes are
sensitive to and invoke notify on the event object. This will cause all
processes that are sensitive to the event object to be run during the next
SystemC cycle. The second option is to locate the SystemC thread or process and
invoke run on the object directly. The process will be run during the next
SystemC cycle. This implies that SIM_continue() must be invoked before the
process is run. From the command line, this corresponds to invoking c 1.
Sockets, registered with the awareness framework, provide the Simics
sc_tlm_fw_transport and sc_tlm_bw_transport interfaces. The interfaces
correspond to the SystemC TLM2 transport interfaces and support injection. The
following rules specify the mapping between the Simics interfaces and the
SystemC transport interfaces.
attr_value_t are dictionaries with string as keytlm_dmi descriptor is dmiFor example, injecting a write transaction into a socket could be done as shown below.
simics> dut.top.simple_initiator_socket_0.trace-sc
Created dut.internal.sc_trace_tool (connected to 1 provider)
simics> @socket = dut.top.simple_initiator_socket_0.iface.sc_tlm_fw_transport
simics> @socket.b_transport({'gp.command' : 1, 'gp.data_ptr' : (0, 1, 2, 3)}, 0)
None
simics> c 1
[dut.top.simple_initiator_socket_0 trace-b-out] write sz:4 addr:0x0 data:0x03020100
[dut.top.simple_initiator_socket_0 trace-b-in] write sz:4 addr:0x0 data:0x03020100 status:TLM_OK_RESPONSE
>
The transaction is injected into the socket by invoking b_transport of the
sc_tlm_fw_transport interface. To avoid blocking Simics when the interface is
called, the transaction is queued up and sent when simulation starts. This is
only required for b_transport. All other functions of sc_tlm_fw_transport
and sc_tlm_bw_transport execute their side-effects directly. The fields of the
tlm_generic_payload are set by building the key prefixed with gp.,
followed by the name of the setter function. The key gp.command addresses
the generic payload and invokes set_command on the generic payload. The
functions expects a tlm_command enum type when invoked in SystemC. For
argument passing, enums are passed as signed integer types. The value 0
reflects a read transaction and 1 corresponds to a write transaction. This is
according to the tlm_command enum definition in the SystemC kernel.
To simplify matters, gp.data_ptr invokes set_data_ptr, set_data_length
and set_streaming_width. The following guidelines should be followed when
setting the value of the key-value pair in dictionaries.
attr_value_t ‘data’attr_value_t ‘data’, and
should not be explicitly setattr_value_t ‘list’attr_value_t ‘list’, and
should not be explicitly setInjecting a read transaction into a socket could be done as shown below.
simics> @socket.b_transport({'gp.command' : 0, 'gp.data_ptr' : (0,) * 4}, 0)
None
simics> c 1
[dut.top.simple_initiator_socket_0 trace-b-out] read sz:4 addr:0x0 data:0x00000000
[dut.top.simple_initiator_socket_0 trace-b-in] read sz:4 addr:0x0 data:0x03020100 status:TLM_OK_RESPONSE
>
The length of the data to be read is specified by the Python tuple. Because the
transaction is sent into the socket at a later point in time, the Simics
instrumentation framework is used to display the actual data returned from the
b_transport call.
To add an extension to the transaction, additional key-value pairs need to be set in the dictionary associated with the transaction argument. The table below lists the mapping between each namespace and the corresponding SystemC Library extension.
| Namespace key | Extension |
|---|---|
| ethernet_common | EthernetCommonExtension |
| i2c_master_v2 | I2cMasterV2Extension |
| i2c_slave_v2 | I2cSlaveV2Extension |
| map_info | MapInfoExtension |
| pci_bus | PciBusExtension |
| pci_device | PciDeviceExtension |
| pci_upstream_operation | PciUpstreamOperationExtension |
| pcie_device | PcieDeviceExtension |
| serial_device | SerialDeviceExtension |
The key-value pairs for the extensions are specific. For details about the valid
pairs, please refer to the implementation of the extension injector located in
simics/systemc/iface/. One example that demonstrates the inject of a
transaction with an EthernetCommonExtension set is shown below.
simics> @data = tuple(bytearray(b'ABCDEF'))
simics> @fraglist = [data[:4], data[4:]]
simics> @frame = {'len' : len(data), 'fraglist' : fraglist}
simics> @socket.b_transport({'ethernet_common.frame' : {'frame' : frame, 'crc_ok' : 1}}, 0)
None
simics> c 1
[dut.top.simple_initiator_socket_0 trace-b-out] ignore sz:0 addr:0x0
[dut.top.simple_initiator_socket_0 trace-b-in] ignore sz:0 addr:0x0 status:TLM_OK_RESPONSE
To support inject of extensions not provided by SystemC Library,
simics::systemc::injection::InjectBase needs to be implemented.
To activate support for the additional injector, the template class needs to be instantiated. This is required to register the support for the new injector in the infrastructure. One possibility is to declare it as a member variable of the Adapter. Below is an example that shows the required steps to support a new extension.
class CustomExtension : public tlm::tlm_extension<CustomExtension> {
public:
CustomExtension() : member_a_(0), member_b_(0),
member_d_(NULL), member_d_len_(0),
member_x_(0), member_y_(0) {}
virtual tlm::tlm_extension_base *clone() const {
return new CustomExtension(*static_cast<const CustomExtension *>(this));
}
virtual void copy_from(tlm::tlm_extension_base const &extension) {
*this = static_cast<const CustomExtension &>(extension);
}
void set_member_b(uint8_t member) {
member_b_ = member;
}
void set_xy(uint8_t x, int8_t y) {
member_x_ = x;
member_y_ = y;
}
virtual ~CustomExtension() {}
uint8_t member_a_;
uint8_t member_b_;
std::vector<uint8_t> member_c_;
const uint8_t *member_d_;
uint64_t member_d_len_;
private:
uint8_t member_x_;
int8_t member_y_;
};
#include <simics/systemc/injection/inject_base.h> // NOLINT
template <typename TPAYLOAD>
class InjectCustomExtension
: public simics::systemc::injection::InjectBase<TPAYLOAD> {
public:
ATTR_DICT_PARSER_NAMESPACE("custom.")
virtual bool setValue(simics::systemc::injection::AttrDictParser *parser,
const std::string &key, attr_value_t *attr,
TPAYLOAD *gp) {
if (key == "member_a") {
CustomExtension *extension =
this->template get_extension<CustomExtension>(gp);
if (!parser->value(&extension->member_a_))
return false;
return true;
}
INJECT_SET_VALUE(set_member_b, uint8_t, CustomExtension);
if (key == "set_xy") {
simics::systemc::injection::AttrDictParser p = parser->init(attr);
CustomExtension *extension =
this->template get_extension<CustomExtension>(gp);
uint8_t x = 0;
if (!p.lookUp("x", &x))
return false;
int8_t y = 0;
if (!p.lookUp("y", &y))
return false;
extension->set_xy(x, y);
return true;
}
if (key == "member_c") {
CustomExtension *extension =
this->template get_extension<CustomExtension>(gp);
if (!parser->value(&extension->member_c_))
return false;
return true;
}
if (key == "member_d") {
CustomExtension *extension =
this->template get_extension<CustomExtension>(gp);
if (!SIM_attr_is_data(*attr)) {
parser->reportError("member_d must be data");
return false;
}
extension->member_d_ = SIM_attr_data(*attr);
extension->member_d_len_ = SIM_attr_data_size(*attr);
return true;
}
return false;
}
};
static InjectCustomExtension<tlm::tlm_generic_payload> injector_;
The example shows different ways to set the members in the CustomerExtension.
If the member in the extension is directly accessible, it could be set as shown
for member_a. Data access is usually provided by setters and getters,
set_member_b can be called by INJECT_SET_VALUE. If multiple arguments are
required by the extension method, the arguments should be grouped in another
dictionary or list as key set_xy shows. The key member_c demonstrates
how a Python list can be loaded into a vector. Setting a data pointer is shown
by key member_d. If a member in the extension cannot be properly setup,
false must be returned. The failing key will be reported as an error and the
inject call will be aborted.
The corresponding calls to setup the extension from Python could be as in the following example.
simics> @socket.b_transport({'custom.member_a' : 1}, 0)
simics> @socket.b_transport({'custom.set_member_b' : 2}, 0)
simics> @socket.b_transport({'custom.set_xy' : {'x' : 3, 'y' : 4}}, 0)
simics> @socket.b_transport({'custom.member_c' : [5, 6]}, 0)
simics> @socket.b_transport({'custom.member_d' : (7, 8, 9)}, 0)
According to SystemC language standard, port instances defined by sc_port
class cannot remain unbound at the end of elaboration, unless allowed by port
policy. SystemC Library optionally permits using unbound ports. Such ports are
then automatically bound to a dynamically allocated object implementing the
corresponding interface. Access to an unbound port will log an unimplemented
message in Simics, for example:
[device unimpl] Access to unbound port: device.simple_initiator_socket_0 @ 0 s
of intc/unimplemented in unconnected_base.h:28
The feature is disabled by default and can be enabled using
allow_unconnected_ports attribute of the SystemC adapter. The list of
supported unbound ports includes specialized sc_in, sc_out and sc_inout
ports as well as socket ports which use the standard TLM-2.0 forward and
backward transport interfaces.
The SystemC Checkpoint Library offers the ability to save and restore the state of SystemC devices. By utilizing the provided checkpoint API, users can add checkpoint support to their devices.
This feature is disabled by default. To enable checkpointing, set
USE_SIMICS_CHECKPOINTING=yes when building the SystemC Library and SystemC
modules.
Using CMake, the SystemC Library is split in two parts: the main part without checkpointing support and a second, optional, part with checkpointing. The modules can then opt-in per module if they need checkpointing or not. See 8 for more details.
The checkpoint API is detailed in a separate document, which can be found at
[The installation path for package 1013]/doc/systemc-checkpoint.pdf.