SystemC Tutorial Note

SystemC Tutorial Note

Hardware simultion

Introduction

  • systemC?
    • library of C++ classes
    • hardware aware
      • concurrency
      • bit accuracy
      • simulation time advancement
      #include <systemc.h>
      SC_MODULE( and2 ){
          sc_in<DT> a;
          sc_in<DT> b;
          sc_out<DT> f;
          sc_in<bool> clk;
          //DT -> sc_uint<1>
    
          void func(){
              f.write( a.read() & b.read() );
          }
    
          SC_CTOR( and2 ){ //systemC constructor  
              //case1
              SC_METHOD(func);
              sensitivity << a << b;
    
              //case2
              SC_METHOD(func);
              sensitive << clk.pos(); // or clk.neg()
          }
      }
    
  • Threads
    • a function made to act like a hardware process
      • run concurrently
      • sensitive to signals, clock edges or fixed amount of simulation time
      • Not called by the user, always active
    • three types
      • SC_METHOD()
        • Executes once every sensitivity event
        • runs continuously
        • verilog’s @always block
        • synthesizable
          • useful for combinational expressions or simple sequential logic
      • SC_THREAD()
        • runs once at start of simulation, then suspends itself when done
        • can contain an infinite loop to execute code at a fixed rate of time
        • similar to @initial block
        • NOT synthesizable
          • uesful for testbenches to describe clocks or initial startup signal sequences
      • SC_CTHREAD()
        • “clocked thread”
        • runs continuously
        • references a clock edge
        • synthesizable
        • can take one or more clock cycles to execute a single iteration
        • used in 99% of all high-level behavioral designs
  • Integer datatypes:
    • bit-accurate
      • fixed width
      • always 32bits
    • Unsigned and signed
      • sc_uint where N is the bitwidth
      • sc_int

Using SC_CTHREADs

  • SC_METHODs
    • Limited to one cycle
    • fine for counters or simple sequential designs
    • not much different than hand coded RTL
    • can’t handle multi-cycle algorithms
  • SC_CTHREADs
    • not limted to one cycle
    • can contain continous loops
    • can contain large blocks of code with operations or control
    • great for behavior synthesis
  • FIR Filter
    • fir.h: module and thread declaration
      ``` cpp #include SC_MODULE( fir ){ sc_in< bool > clk; sc_in< bool > rst; sc_in< sc_int<16> > inp; sc_out< sc_int<16> > outp;

      void fir_main(); //just declaration here

      SC_CTOR( fir ){ //systemC constructor
      SC_CTHREAD( fir_main, clk.pos() ); reset_signal_is(rst, true ); } }

    // Coefficients for each FIR const sc_unint<8> coef[5] = {18,77,107,77,18};

      * `fir.cc`: thread definition  
    
      ```cpp
      // FIR Main thread
      #include "fir.h"
    
      void fir::fir_main(void)
      {
          // Reset code
          // Reset internal variables
          // Reset outputs
          sc_int<16> taps[5]; // set coefficients
          outp.write( 0 ); // initialize
          wait();
    
          while( true ){
              // Read inputs
              // Algorithm code
              // Write outputs
    
              for(int i = 4; i > 0; i--){
                  taps[i] = taps[i-1];
              }
              taps[0]=inp.read();
    
              sc_int<16> val;
              for(int i=0; i < 5; i++){
                  val += coef[i]*taps[i];
              }
              outp.write(val);
              wait(); // Associated with 'clk' class
          }
      }
    

Testbenches

  • Verification
    • Hierarchical test environment
      • top level test structure
        • instance of FIR module (DUT)
        • instance of testbench module
        • connectivity
      • tentbench module

image

  • Test environment
    • In a host module System
      • Module fir0
        • clk, rst, inp, outp
      • Testbench tb0
        • clk, rst, inp, outp
      • clk is generated from systemC
  • Basic SYSTEM structure
      SC_MODULE( SYSTEM ){
          // Module declarations
    
          // Local signal declarations
    
          SC_CTOR( SYSTEM ){ // Constructor
              // Module instance signal connections
          }
    
          ~SYSTEM()
          // Destructor
      }
    
    
  • main.cc
      #include <systemc.h>
      #include "fir.h"
      #include "tb.h"
    
      SC_MODULE( SYSTEM ){
          tb *tb0; // declare a pointer(*) to its reference name(tb0)
          fir *fir0;
    
          sc_signal<bool>         rst_sig;
          sc_signal<sc_int<16>>   inp_sig;
          sc_signal<sc_int<16>>   outp_sig;
    
          sc_clock clk_sig;
    
          SC_CTOR( SYSTEM )
              : clk_sig ("clk_sig",10, SC_NS)
          {
              tb0 =  new tb("tb0");
              tb0->clk( clk_sig ); // remind that tb0 is a pointer
              tb0->rst( rst_sig );
              tb0->inp( inp_sig );
              tb0->outp( outp_sig);
    
              fir0 = new fir("fir0");
              fir0->clk(clk_sig);
              fir0->rst( rst_sig );
              fir0->inp( inp_sig );
              fir0->outp( outp_sig);
          }
    
          ~SYSTEM(){
              delete tb0;
              delete fir0;
          }
      }
    
      // SYSTEM instantiation
      SYSTEM *top = NULL;
    
      int sc_main(int argc, char* argv[]){ 
          // acgc = arg count, argv = arg vector
          top = new SYSTEM("top");
          sc_start();
          return 0;
      }
    
    
  • tb.h
      #include <systemc.h>
      SC_MODULE( tb ){
          sc_in< bool > clk;
          sc_out< bool > rst;       //opposit to fir module
          sc_out< sc_int<16> > inp; //opposit to fir module
          sc_in< sc_int<16> > outp; //opposit to fir module
    
          void source();
          void sink();
    
          SC_CTOR(tb){
              SC_CTHREAD( source, clk.pos() );
              SC_CTHREAD( sink, clk.pos() );
          }
    
    
  • tb.cc
      #include "tb.h"
    
      void tb::source(){
          //reset
          inp.write( 0 );
          rst.write( 1 );
          wait();
          rst.write( 0 );
          wait();
    
    
          sc_int<16> tmp;
          //send stimulus to FIR
          for( int i=0; i<64; i++){
              if(i>23 && i<29)
                  tmp = 256;
              else
                  tmp = 0;
              inp.write( tmp );
              wait();
          }
      }
    
      void tb::sink(){
          sc_int<16> indata;
          //Read output coming from DUT
          for(int i = 0; i<64; i++){
              indata = outp.read();
              wait();
              cout << i << " :\t" << indata.to_int() << endl;
          }
    
          // End simulation
          sc_stop(); // calls destructors
      }
    
    

Handshaking

  • In the folder …
    • Makefile file and type make
    • golden folder

image2

  • If simulation fails… communication between tb0 and fir0 failed
    • Handshake: Add single bit (bool) valid(vld) and ready(rdy) signals for both input/ouput like ..
    • image2
          // Add below to SC_MODULE( SYSTEM )
    
          sc_signal<bool>         inp_sig_vld;
          sc_signal<bool>         inp_sig_rdy;
            
          sc_signal<bool>         outp_sig_vld;
          sc_signal<bool>         outp_sig_rdy;
    
          // Add to signal connection in constructor
          // Add valid/ready pins to 'tb.h' and 'fir.h' 
    
  • Modeling asynchronous communication at different levels of abstraction using systemC LINK

This is a preview of Clap Button, a new feedback and analytics tools for Hydejack, built by yours truly. You can try it out on localhost for free, but it will be removed (together with this message) when building with JEKYLL_ENV=production. To use Clap Button on your site, get a subscription
and set clap_button: true in your config file.