This section outlines some of the Simics features that are available when running SystemC models in Simics.
In Simics the SystemC scheduler runs under the control of the Simics framework, meaning that simulation can be started and stopped using the Simics GUI or normal Simics commands such as continue
or stop
.
All SystemC objects, derived from sc_object
class, are visible in Simics as configuration objects. This means that it is possible to interact with the objects from the Simics CLI.
If some SystemC object is not visible in Simics, check that all the following conditions apply:
The name complies to the recommendation of IEEE 1666-2011 5.17 which is also a requirement for naming Simics objects. Non-compliant names are transformed and the Simics object created under Adapter.renamed using the corresponding hierarchy. Invalid characters are escaped with _0x and replaced with the ASCII value in hex. E.g: a.b.test[A] becomes renamed.a.b.test_0x5B_A_0x5D_
The object is not dynamic, as stated in section 5.3.2.1;
Use help SystemC
to get a list of all supported SystemC CLI commands. And use help
on selected command to get detail information.
Typical operations available on SystemC objects are enabling tracing or breakpoints on sockets and signals. In addition, 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.3 for more information about trace and break on SystemC objects.
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
simics>
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.
SystemC Library implements 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:133
[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:133
[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>
simics>
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.
If a custom log API is being used, it is often possible to enable it to support multiple front ends. One simple approach is to specialize it to work in Simics using the standard set of SIM_log*
functions, as described in the API Reference Manual. If the log API works with streams Simics provides a convenience class called LogStream
that can be used. The convenience class has the following signature:
template<log_type_t Type = Sim_Log_Info,
unsigned Level = 1,
int Groups = 0>
class LogStream : public std::ostream {
public:
explicit LogStream(ConfObjectRef log_obj)
...
It is possible to use multiple LogStream
objects to map different types of output to different Simics log-types, log-levels, and log-groups. The streams can be used wherever the logging API outputs to a std::ostream
object and the log will automatically be turned into a Simics log message with the appropriate type, level, and group.
The LogStream
can also be used to redirect standard streams, for example std::cout
. This is done by replacing the stream's streambuf
with the streambuf
of the Simics LogStream
as is shown in the example below.
#include <simics/systemc/awareness/log.h>
class CoutRedirect : public simics::ConfObject {
public:
explicit CoutRedirect(simics::ConfObjectRef o)
: simics::ConfObject(o),
simLog_(o) {
std::cout.rdbuf(simLog_.rdbuf());
}
static void init_class(simics::ConfClass *cls);
private:
void print_a_log() const {
std::cout << "Print a simple message to std::cout" << std::flush;
}
simics::LogStream<Sim_Log_Info, 2> simLog_;
};
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 1
will 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());
}
};
class Adapter : public scl::Adapter
[...]
BigInt1024Access big_int_1024_access_;
[...]
The function attrToValueT
implements the transformation from a Simics attr_value_t
to the signal's value-type. If the transformation can not 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 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.3.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.3.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.
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.3.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.3.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 can not 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 key tlm_dmi
descriptor is dmi For 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
simics>
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 set attr_value_t
'list' attr_value_t
'list', and should not be explicitly set Injecting 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
simics>
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_express | PciExpressExtension |
pci_upstream_operation | PciUpstreamOperationExtension |
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.