SystemC_TLM_2.0_Example
SystemC TLM 2.0 integration into VisualSim is accomplished through the use of the TLM_Cosim. This block can be found in the VisualSim Library structure:
Hardware Languages/SystemC/TLM_Cosim
This single block can be configured into the following three TLM block types:
By the appropriate choice of SC_Module_Name, SC_File_Path parameters.
In the tlm_sample.xml example model one can see examples of each TLM block type.
The tlm_sample model works as follows:
Source <-> Interconnect <-> Target
To this, we add the VisualSim interface blocks to make it:
Source <-> Initiator <-> Interconnect <-> SC_Intf <-> Target
The Initiator block generates the Begin_Req and End_Resp phases. The SC_Intf generates the End_Req and Begin_Resp phases. In addition, the Initiator creates and destroys the Generic Payload while the SC_Intf prepares the data structure for a VisualSim target block.
Text_Display blocks are used as probes between each of the modules to make sure the correct output/phase is being received. VisualSim block can also use the annotated time to wait.
There are two data structures in this model - VisualSim Processor_DS and Generic Payload. The individual data structure class is used in the respective domains. Fields can be mapped at the interfaces using provided methods. When the VisualSim data structure arrives at the SystemC socket or sc_in or sc_port, it first checks for the Transaction_ID. If this exists, then a generic payload is associated with the flow and is used on the SystemC side. If there is no id, then the user can define a struct or basic data type to transfer at the interface. When SystemC sends a value out on either the fw or bw sockets, the matching VisualSim data structure is sent out. The VisualSim data structure contains the transaction_id for the Generic Payload in the Hashmap, transaction_phase and transaction_time. These values can be used in the next SystemC or VisualSim modules.
Here are typical naming conventions for the three block types:
Type
|
SC_Module_Name |
SC_File_Path
|
Initiator |
“Initiator” |
“SystemC/tlm_sample/initiator.h” |
Interconnect Component |
“SimpleBus<2,2>” |
“SystemC/tlm_sample/simple_bus.h” |
Target |
“Target” |
“SystemC/tlm_sample/target.h” |
Table 1. Naming for block types
The “<2,2>” for the Interconnect Component identifies how many input and output combinations it supports. Currently, users need to add ports manually to match the input and output combinations.
The Initiator can be preceded on the left-hand-side by any VisualSim traffic generator such as the Transaction_Source or Transaction_Trigger blocks. This block can generate the VisualSim datas structure class that flows through the model. The most common data structure class used is Processor_DS. Processing blocks can modify the data structure fields and placed anywhere in the flow without incurring any latency during execution.
The Target can be VisualSim architectural library blocks, such as Cache, or DRAM memory blocks. To use VisualSim architectural library blocks as a SystemC target, add a SC_Memory_Intf Virtual_Machine block between the interconnect component and the VisualSim Memory block. This is used to generate the phase types, as is not generated by the VisualSim initiator and targets. In addition, one needs to add an Architecture_Setup Block to integrate the architectural library memory blocks. The use of these blocks are described in more detail below.
VisualSim and SystemC designs can maintain their own data structures with independent set of fields. The SystemC Generic Payload has full access to the VisualSim data structure that triggered it and can read/write to fields. A pre-built block called the Initiator_TLM is provided in the SystemC folder. This block is used to construct and destroy the Generic Payload. This is typically placed on the interface between a VisualSim source and the SystemC interconnect. This block can be extended to add logic associated with specific return, status, and phase combination.
Right-mouse-click on the block to “Documentation/Get Documentation” for more details on the TLM_Cosim block. This includes section headings for Description, Block Operation, Configure, SC_Module_Name Vs. Instance Name, Block Setup, Run-Time Parameters, Port(s), SC_Sim, Mapping to VisualSim Data Structure, List of Methods Provided, Notes, Make and Compile Parameters, and SystemC TLM Routing.
The tlm_sample.xml initiator block contains code that can be modified for most situations. It consists of some key member functions:
void Initiator :: makeRequestToTlmDomain() {...}
This member function, or method, accepts VisualSim data structures from the transaction_data port and prepares the data structure for transmission as a SystemC TLM data structure, adding generic payload information, and fields for:
transaction_id
transaction_phase
transaction_time
This member function is in the forward path, sending a transaction out of the initiator_fw port. It appears on the output as a VisualSim data structure that can be modified with a processing block, Virtual_Machine block, as required.
Initiator::sync_enum_type Initiator::bwTransport(
transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {...}
This member function supports the backward path from the Interconnect Component or Target. It also supports a mechanism to request a new transaction from a VisualSim Transaction_Trigger. Currently, this is a packet with fields A_Address_Min and A_Bytes set to the same phase value as an integer value to denote:
END_REQ phase as the value 2
BEGIN_RESP phase as the value 3
The status_port can be used to trigger a new data structure or calculate the latency. Or, one could modify the values set in data structure exiting the left-hand-side to any value for additional control within a specific model.
The SystemC TLM Interconnect Component block typically represents a Bus in an integrated SC/VS model. It can have delays for Read or Write processing, pass back phase information that might be used by the Initiator block in controlling requests, for example. Some key member functions:
void RequestThread() {...}
This member function is triggered by data structures arriving on thetarget_fw[n] LHS ports and processing the transaction that then maps to an output port with the initiator_fw[n] RHS ports. This is accomplished by code:
initiator_socket_type* decodeSocket = &initiator_socket[portId];
trans->set_address(trans->get_address() & getAddressMask(portId));
// Fill in the destination port
PendingTransactionsIterator it = mPendingTransactions.find(trans);
assert(it != mPendingTransactions.end());
it->second.to = decodeSocket;
void ResponseThread() {...}
This member function is triggered by data structures arriving on the initiator_bw[n] RHS ports and processing the transaction that then maps to the corresponding output port with the target_bw[n] LHS ports. This is accomplished by using the reverse port mapping from the forward path.
sync_enum_type fwTransport(int initiator_id,
transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t) {...}
This member function is called for the request phases.
sync_enum_type bwTransport(int portId,
transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t) {...}
This member function is called for the response phases or also with TLM status.
This Virtual_Machine block performs processing of forward and backward transport, key script portion:
SWITCH (port_name)
{
CASE: input // Left to right, to Memory
TIMEQ("Controller_Delay", port_token, 0, Cycle_Time)
port_token.A_Task_Flag = true
port_token.A_Bytes_Remaining = 0
port_token.A_Bytes_Sent = port_token.A_Bytes
port_token.A_Hop = Device_Name_
port_token.A_Destination = Device_Name_
port_token.transaction_phase = 2 // END_REQ setting
SEND (output, port_token) // send request back to initiator
SEND (output2, port_token) // send to memory
GTO (END)
CASE: input2 // Right to left, from Memory
if (port_token.A_Destination == "Architecture_1")
{
GTO (END) // Drop Hello Message
}
port_token.transaction_phase = 3 // BEGIN_RESP setting
SEND (output, port_token) // send data to initiator
GTO (END)
}
A number of fields must be set to properly operate with the VisualSim Architectural library memories. A_Task_Flag is set to true and returns For both Read’s and Write’s. A_Bytes, A_Bytes_Remaining, A_Bytes_Sent are set so the fields match the following expression:
A_Bytes = A_Bytes_Remaining + A_Bytes_Sent
This allows each memory to accept the transaction for a Read, the first word. Writes can use the same format for a single transfer, or send multiple bursts progressively decrementing the A_Bytes_Remaining by the burst size, until the last transfer. The last transfer should set A_Bytes_Sent to last set of Bytes, A_Bytes_Remaining to 0. The fields A_Hop, A_Destination need to be set to the parameter of the block Device_Name, such that the Memory Name matches and allows the transaction to be accepted.
The input sends END_REQ phase to the incoming data structure and returns to the Interconnect Component. Next, it sends to output2 which connects to the memory block.
input2 is the return port from the memory and it looks for “Hello” messages, and data returning from memory. “Hello” messages are dropped. Data returned from memory is passed through to the Interconnect Component, setting the phase to BEGIN_RESP (3).
The Target block can be used in place of the VisualSim architectural libraries. Some key member functions:
Target::sync_enum_type Target::fwTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) {...}
This member function processes incoming transactions with the same arguments as described above:
transaction_id (trans)
transaction_phase (phase)
transaction_time (t)
void Target :: sendResponse(transaction_type& trans)
This member function processes returning transactions with just the transaction “trans” argument.