Home > Community > Blogs > System Design and Verification > esl design systemc tlm2 ip authoring a practical experiment
Login with a Cadence account.
Not a member yet?
Create a permanent login account to make interactions with Cadence more conveniennt.

Register | Membership benefits
Get email delivery of the System Design and Verification blog (individual posts).


* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

ESL Design - SystemC TLM2 IP Authoring: A Practical Experiment

Comments(0)Filed under: System Design and Verification, Incisive, SystemC, osci registers, spirit, systemrdl, virtual prototype, ip-xactIntroduction

ESL Virtual Platforms (systems or sub-systems) require heterogeneous libraries of TLM IP models that can interconnect. Indeed, the OSCI TLM2 interfaces appear to be the only viable solution to solve this interoperability issue. Moreover the IP you need is not always available (because it is a new IP or a custom IP or because it is not yet available from your 3rd party provider). For whatever reason, you have to hand-write it and this is sometimes really painful and error prone, mainly when your IP includes hundreds of registers.

The experiment

This experiment shows how you can save time and coding effort by automating the generation of your TLM2 IP SystemC code, mainly for accessing the registers, and for automating the generation of a C API for eSW programmers or Verification engineers. The following is based on a simple SystemC TLM2 un-timed description of the ARM UART pcell PL011.

Creating the TLM2 IP

The first step of this experiment is to create the TLM2 SystemC model for your IP.  I propose to automate this step by using an existing feature of Incisive Enterprise Simulator -XL (IES -XL) (see SystemC reference doc, chapter 11) called nccodegen.  This allows you – among other things – to automatically generate a template SystemC TLM code for your HW model. Today this tool generates a TLM1 model, but with little changes you can easily make it a “TLM2-ready” IP.

To generate the HW IP, follow these steps:

1)     Describe the PL011 registers (as defined in the section 3.2 summary of registers of the TRM version r1p5) in a simple Register Description Language (RDL) format. This is a very simple grammar but it’s enough to describe the UART registers. A sample of the RDL file for the PL011 is given here after: 
// describe registers

REGISTER rsr_ecr {
    ACCESS = rw;
    DESC = receive status register / error clear register;
    SIZE = 4;
    RESET_VAL = 0x0;
    PREAMBLE = rw;
    POSTAMBLE = rw;
    ACCESS = ro;
    DESC = flag register;
    SIZE = 9;
    RESET_VAL = 0x090;
    PREAMBLE = ro;
    POSTAMBLE = ro;

// describe memory map
REGISTER_BANK reg_bank {
    SIZE = 0xFFF;

     rsr_ecr     0x004
     RESERVED     0x008 - 0x014
     fr         0x018

2)     Run the command:   % nccodegen -name uartPL011 -rmf uart_registers.rdl -samplebus -hwonlyIt generates a SystemC TLM template for the HW model of the UART. It derives from an automatically generated base class with all the registers defined and the access methods to these registers.
3)     Update the generated HW template code to match the uart behavior (i.e. add processes, ports ...) and cleanup the code to make it TLM2-ready. The main change is to replace the target sc_export by a simple target socket, and to modify the register base class to remove dependency to the bus_slave_adaptor.h and bus_info.h. You obtain a Uart model with a simple TLM target socket (Ts) and two serial ports (Rx and Tx). The Tx and Rx ports are modeled as simple signals. Note: the advantage of using nccodegen is not only that you save writing time and coding errors, but also that all the registers can be visualized in SimVision when running the simulation because all the registers are declared as ncsc_register.
A sample of the automatically generated base class is given here after: 

template <typename ADDR_TYPE, typename DATA_TYPE>
class uartPL011_base : public sc_module
    ncsc_register<char, NCSC_REG_RW_ACCESS> rsr_ecr_reg;
    ncsc_register<short, NCSC_REG_RO_ACCESS> fr_reg;


    char read_rsr_ecr() {return rsr_ecr_reg.read() & 0xF;}
    short read_fr()     {return fr_reg.read() & 0x1FF;}

    void write_rsr_ecr(DATA_TYPE data) {rsr_ecr_reg = data;}
    // the rsr_ecr register is read-only, therefore it has
    // no write method defined

    // these methods are called by the method registered
    // on the target socket
    bool read_register(ADDR_TYPE offset, DATA_TYPE *data);
    bool write_register(ADDR_TYPE offset, DATA_TYPE *data);

Converting a TLM1 IP into a TLM2 IP  An alternative to (re)creating a TLM2 IP from scratch is to wrap it. This is to be used when you just want to reuse an existing – legacy – TLM1 IP that you can not edit. For example, it could be a 3rd party IP for which you don’t have the source implementation. This process consists in wrapping all the TLM1 blocking interfaces/ports of your IP with TLM2 interfaces/sockets. This is done by creating a hierarchical module with sockets, instantiating the TLM1 module and a module converting from each TLM1 blocking interface port/export into socket. This is illustrated in the following picture. 




Note that as consequence to the hierarchical binding is the use of a TLM2 multi passthrough socket (instead of a simple socket) in both the bridge and the TLM2 wrapping module. Note also that to keep the TLM bridge code independent of the user-defined payload; I have defined the bridge as a template of the payload. Moreover, the payload used is a derived class of a pure virtual class defining two methods to copy from and to a tlm generic payload. An example of the TLM1 to TLM2 Initiator Bridge is given here after: 

template <typename PAYLOAD>
class bridge_initiator_tlm1tlm2 : public sc_module,
  public tlm_transport_if<PAYLOAD,PAYLOAD> {
  // port and socket declarations
  sc_export<tlm_transport_if<PAYLOAD,PAYLOAD> > target;
    32,tlm::tlm_base_protocol_types,2>          initor;
// Constructor
// binds the target sc_export to this
bridge_initiator_tlm1tlm2(sc_module_name module_name);
// implements the TLM1 target transport
// converts the TLM1 PAYLOAD into a TLM2 generic payload
// and calls b_transport on the initor port
  virtual PAYLOAD transport( const PAYLOAD &tlm_req );

A trivial example of user-defined payload is defined here after.  

// a simple payload
class simple_payload {
// data
int addr;
int data;
std::string msg;
// a pure virtual class for payloads conversion
// Every tlm1 payload should derive from this
// to be used in a tlm1-tlm2 bridge
class payload_adapter {
  // these methods allow writing payload adapters generic code
  virtual void copy_from_gp (const tlm_generic_payload& tgp) = 0;
  virtual void update_gp (tlm_generic_payload& tgp) const  = 0;
// the convertible payload
class simple_convertible_payload :
  public simple_payload,
  public virtual payload_adapter {
  // get data from the generic payload
  void copy_from_gp (const tlm_generic_payload& tgp);
// set data to the generic payload
void update_gp (tlm_generic_payload& tgp) const;


Generating the C API for embedded SW  SW developers (mainly the device driver SW) need a C API to access and write to registers. This API can be automatically generated from the same source input (the RDL file) used for generating the HW IP. Moreover the API can be re-generated when the input changes. 

To generate the C API, follow these steps:
1)     Run the command:% nccodegen -name uartPL011 -rmf uart_registers.rdl -samplebus -swonlyIt generates a .c and a .h file files for reading and writing the form/to the HW registers. 2)     Modify the generated header file by defining the type of the ADDR_TYPE and DATA_TYPE macros and removing the inclusion of the bus_info.h file. A sample of the generated API is given here after:
 #define ADDR_TYPE unsigned
#define DATA_TYPE unsigned

/* Read API for the Registers */

BUS_DATA_TYPE get_uartPL011_rsr_ecr(ADDR_TYPE baseAddr);
BUS_DATA_TYPE get_uartPL011_fr(ADDR_TYPE baseAddr);

/* Write API for the Registers */

void set_uartPL011_rsr_ecr(ADDR_TYPE baseAddr, DATA_TYPE value);
Generating HTML documentation   The nccodegen utility includes a documentation generator which generates a basic HTML document. Documentation is crucial in design IP packaging (every IP comes with source or compiled code plus documentation) and a key area for automation. But each company has its own documentation format and conventions. A customized HTML documentation could be obtained by (1) converting the generated HTML doc into XML format and (2) apply an XSLT to transform it into a new HTML format. The conversion from HTML to XML can be automated using free tools such as HTML Tidi (see http://www.ibm.com/developerworks/library/x-tiptidy.html). A sample of transformed HTML doc is given here after: 




Conclusion & future posts

You have now the basic bricks to ease the modeling of your TLM2 IP (mainly for those with large number of registers) using the IES -XL nccodegen utility, and for generating code and documentation for embedded SW developers. Soon you’ll see these features directly implemented in upcoming Cadence Incisive releases; we’re working on it J

So what’s next?

More experiments – stay tuned! – will include additional guidelines for TLM2 IP modeling and use of OVM testbench for verifying the TLM2 IP. Note also that alternative solutions for describing registers could be used as input to nccodegen. Currently nccodegen takes as input a Cadence proprietary format for describing registers. However other standard formats exist or are emerging that could be used as input to nccodegen to generate SW and documentation. For example, IP-XACT 1.5alpha and SystemRDL 1.0alpha (hosted by The SPIRIT Consortium http://www.spiritconsortium.org), both include detailed registers description.

This Team ESL posting is provided by Jean-Michel Fernandez, Core Comp Archtect for system level design and verification


Leave a Comment

E-mail (will not be published)
 I have read and agree to the Terms of use and Community Guidelines.
Community Guidelines
The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.