Search code examples
c++segmentation-faultsystemctest-bench

Managing signals within a testbench module in SystemC


I'm trying to simulate in SystemC a module with a CABA (Cycle Accurate / Bit Accurate) model which adds two numbers. It has the following signals:

Module addition_CABA

  • a: Input number for the addition.
  • b: Input number for the addition.
  • clk: Clock input.
  • valid: Input signal which changes to 1 when the inputs a and b are available.
  • result: Output signal containing the result of a + b.
  • ready: Output signal which changes to 1 when result is ready.

In order to test if the result from this module is right I have created a testbench module which has the following signals:

Module testbench

  • result_tb: Input signal which receives the result signal from addition_CABA module.
  • ready_tb: Input signal which receives the ready signal from addition_CABA module.
  • clk_tb: Clock input signal. It's the same for both modules.
  • rst_tb: Reset input signal. It's the same for both modules.
  • a_tb: Output signal which sends the number a to addition_CABA module.
  • b_tb: Output signal which sends the number b to addition_CABA module.
  • valid_tb: Output signal which sends the valid signal to addition_CABA module.

The test I'm doing is as follows:

  • Within the module testbench a pair of random numbers is generated to give values to a and b.
  • The module calcules the result after some clock cycles.
  • The testbench directly does the addition operation and compares it with the one resulting from the module.
  • These actions are within a loop which repeats five times.

The problem I'm having is that when I run the simulation testbench gives the right result, and addition_CABA shows the result but some clock cycles later, so the comparison is between two different numbers. In addition, when the program ends I have a Segmentation fault (core dumped) message. What I'm trying to figure it out is how to indicate testbench to wait until the result is ready (with signal ready_tb) so it can do the comparison with the right number. I have tried with a while(!ready_tb.read()) wait(); condition just before starting the test, but when doing this the program ends and the simulation never starts.

In the main.cpp file I'm just doing the connections between modules, generating the clock and setting the rst signal to 0. Below is my code:

addition_CABA.h

#include <systemc.h>
//Module which adds two numbers
SC_MODULE(addition_CABA){
    sc_in< sc_uint<8> > a;
    sc_in< sc_uint<8> > b;
    sc_in<bool> clk;
    sc_in<bool> valid;
    sc_in<bool> rst;
    sc_out<bool> ready;
    sc_out< sc_uint<8> > result;

    int addcaba(int a, int b){
        int c;
        c = a+b;
        wait(3);
        return c;
    }

    void loop();

    SC_CTOR(addition_CABA){
        SC_CTHREAD(loop, clk.pos());
        async_reset_signal_is(rst, true);
    }

};

addition_CABA.cpp

void addition_CABA::loop(){

    ready.write(0);
    result.write(0);

    if(rst){
        ready.write(0);
        result.write(0);
    }   

    else{

        while(1){
            while (!valid.read()) wait();

            result.write(addcaba(a.read(),b.read()));
            ready.write(1);

            wait();
            ready.write(0);
        }

    }
}

testbench.h

#include <systemc.h>

SC_MODULE(testbench){

    sc_in< sc_uint<8> > result_tb;
    sc_in<bool> ready_tb;
    sc_in<bool> clk_tb;
    sc_in<bool> rst_tb;

    sc_out< sc_uint<8> > a_tb;
    sc_out< sc_uint<8> > b_tb;
    sc_out<bool> valid_tb;

    void test();

    SC_CTOR(testbench){
        SC_CTHREAD(test, clk_tb.pos());
        async_reset_signal_is(rst_tb, true);
    }   

};

testbench.cpp

void testbench::test(){

    uint8_t c = 0;
    int k = 0;

    if (rst_tb){
        c = 0;
        k = 0;
        cout << "\nReset on!\n" << endl;
    }

    else{
        //while(!ready_tb.read()) wait(); //when using this condition the simulation never starts
            while(k < 5){
                a_tb.write( (1 + rand() % (128-1)) );
                b_tb.write( (1 + rand() % (128-1)) );

                valid_tb.write(1);
                sc_start(10, SC_NS);

                valid_tb.write(0);
                sc_start(10, SC_NS);

                cout << "\nTest number " << k+1 << endl;
                cout << "\ta = " << a_tb.read() << " and b = " << b_tb.read() << endl;
                cout << "\tAddition of " << a_tb.read() << " and " << b_tb.read();
                cout << " = " << result_tb.read() << endl;

                c = a_tb.read() + b_tb.read();

                if ( result_tb.read() != c ){
                    cout << "Real result = " << a_tb.read() + b_tb.read();
                    cout << " and result with module = " << result_tb.read() << endl;  
                    cout << "Wrong result\n" << endl;
                    //  exit(1);
                }

                else cout << "Result OK\n" << endl;
                k++;
        }   
    }
}

Solution

  • The root causes of the problem were the following ones:

    1. The simulation time in main.cpp function was too short (10 ns, I modified to 500 ns).
    2. As the test function in the testbench module is an SC_CTHREAD, it must be within an infinite loop. The previous implementation was completely wrong and I think this was also the root cause of the Segmentation fault (core dumped) message.

    In addition, the loop which repeats the test five times is not necessary as the number of iterations is related to the simulation time (set in the main.cpp function). Below is the code for testbench.cpp corrected:

    void testbench::test(){
    
        uint8_t c = 0;
        int k = 0;
    
        if (rst_tb){
            c = 0;
            k = 0;
            cout << "\nReset on!\n" << endl;
        }
    
        else{
            while(1){   
                    a_tb.write( (1 + rand() % (128-1)) );
                    b_tb.write( (1 + rand() % (128-1)) );
    
                    valid_tb.write(1);
                    wait();
                    valid_tb.write(0);
                    wait();
    
                    while(!ready_tb.read()) wait();//This condition waits until ready_tb = true to continue the simulation
    
                    cout << "\nTest number " << k+1 << endl;
                    cout << "\ta = " << a_tb.read() << " and b = " << b_tb.read() << endl;
                    cout << "\tAddition of " << a_tb.read() << " and " << b_tb.read();
                    cout << " = " << result_tb.read() << endl;
    
                    c = a_tb.read() + b_tb.read();
    
                    if ( result_tb.read() != c ){
                        cout << "Real result = " << a_tb.read() + b_tb.read();
                        cout << " and result with module = " << result_tb.read() << endl;  
                        cout << "Wrong result\n" << endl;
                        exit(1);
                    }
    
                    else cout << "Result OK\n" << endl;
    
                    k++;
            }   
        }
    }