Jump to content

Problem with multiple process|Threads and runtime error E115 of multiple writers


Luis.Cargnini

Recommended Posts

Hello,

 

I'm trying to model a packet switcher, for such I broke the packet assignment of different ports in different methods, because I need to evaluate each port in parallel, however the system complains of multiple access at the same signal. To try to avoid this, before execution, I had a sc_mutex placed, but it didn't seem to have worked, my code follows the following ruleset (I'll copy only two methods to avoid long threads):

enum sqstate_t {SQINIT,SQIDLE,LRS0,LRS1, LRS2,LRS2N,LRS2S,LRS2W,LRS2E};

sc_signal < sqstate_t > sqControlQ0;
sc_signal < sqstate_t > sqControlQ1;

 sc_mutex _qmux;
void SwitchFabric::sendDataQueues0(){
    Packet _temp;
    if(rstn.read() == false){
    if(_qmux.trylock() > 0){
            _bufferIn_read[0].write(false);
            _bufferOut_write[0].write(false);
            _qmux.unlock();
        }
    
        sqControlQ0 = SQINIT;

    }
    else{


        //TODO: Working to transform it into a FSM
        /**
         * Cycle across multiple queues
         */
        switch(sqControlQ0){
        case SQINIT:

            _bufferIn_read[0].write(false);
            _bufferOut_write[0].write(false);
            sqControlQ = SQIDLE;
            break;
        case SQIDLE:
            //for(int i = 0; i < _NPORTS; i++){
                if(_bufferIn_busyOut[0].read() != false){
                    _temp = _inpktOut[0].read();
                    _bufferIn_read[0].write(true);
                    sqControlQ0 = LRS0;
                }
                else{
                    _bufferIn_read[0].write(false);
                    sqControlQ0 = SQIDLE;
                }
            //}
            break;
        case LRS0:
            _bufferIn_read[0].write(false);
            sqControlQ0 = LRS1;
            break;
        case LRS1:
            if(addressing_logic){
                    if(_bufferOut_busyIn[1].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[1].write(_temp);
                            _bufferOut_write[1].write(true);
                            //_qmux.unlock();
                            sqControlQ0 = LRS2S;
                        }
                        else{
                            sqControlQ0 = LRS1;
                        }

                    }
                    else{
                        sqControlQ0 = LRS1;
                    }
                }
                else
                {
                    if(_bufferOut_busyIn[3].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[3].write(_temp);
                            _bufferOut_write[3].write(true);
                            //_qmux.unlock();
                            sqControlQ0 = LRS2E;
                        }
                        else{
                            sqControlQ0 = LRS1;
                        }

                    }
                    else{
                        sqControlQ0 = LRS1;
                    }
                }
            }
            else{
                if(addressing_logic){
                    if(_bufferOut_busyIn[2].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[2].write(_temp);
                            _bufferOut_write[2].write(true);
                            //_qmux.unlock();
                            sqControlQ0 = LRS2W;
                        }
                        else{
                            sqControlQ0 = LRS1;
                        }

                    }
                    else{
                        sqControlQ0 = LRS1;
                    }
                }
                else
                {
                    if(_bufferOut_busyIn[0].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[0].write(_temp);
                            _bufferOut_write[0].write(true);
                            //_qmux.unlock();
                            sqControlQ0 = LRS2N;
                        }
                        else{
                            sqControlQ0 = LRS1;
                        }

                    }
                    else{
                        sqControlQ0 = LRS1;
                    }
                }
            }
            break;

        case LRS2N:
            _bufferOut_write[0].write(false);
            _qmux.unlock();
            sqControlQ0 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2S:
            _bufferOut_write[1].write(false);
            _qmux.unlock();
            sqControlQ0 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2W:
            _bufferOut_write[2].write(true);
            _qmux.unlock();
            sqControlQ0 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2E:
            _bufferOut_write[3].write(true);
            _qmux.unlock();
            sqControlQ0 = SQIDLE; //TODO: or maybe some other state
            break;
        default:
            break;
        }



    }

}
void SwitchFabric::sendDataQueues1(){
    Packet _temp;

    if(rstn.read() == false){


        if(_qmux.trylock() > 0){
            _bufferIn_read[1].write(false);
            _bufferOut_write[1].write(false);
            _qmux.unlock();
        }

        sqControlQ1 = SQINIT;

    }
    else{


        //TODO: Working to transform it into a FSM
        /**
         * Cycle across multiple queues
         */
        switch(sqControlQ1){
        case SQINIT:
            //for(int i = 0; i < _NPORTS; i++){
            _bufferIn_read[1].write(false);
            _bufferOut_write[1].write(false);
            //}

            sqControlQ = SQIDLE;
            break;
        case SQIDLE:
            //for(int i = 0; i < _NPORTS; i++){
                if(_bufferIn_busyOut[1].read() != false){
                    _temp = _inpktOut[1].read();
                    _bufferIn_read[1].write(true);
                    sqControlQ1 = LRS0;
                }
                else{
                    _bufferIn_read[1].write(false);
                    sqControlQ1 = SQIDLE;
                }
            //}
            break;
        case LRS0:
            _bufferIn_read[1].write(false);
            sqControlQ1 = LRS1;
            break;
        case LRS1:
            if(Adressing_logic){
                    if(_bufferOut_busyIn[1].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[1].write(_temp);
                            _bufferOut_write[1].write(true);
                            //_qmux.unlock();
                            sqControlQ1 = LRS2S;
                        }
                        else{
                            sqControlQ1 = LRS1;
                        }

                    }
                    else{
                        sqControlQ1 = LRS1;
                    }
                }
                else
                {
                    if(_bufferOut_busyIn[3].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[3].write(_temp);
                            _bufferOut_write[3].write(true);
                            //_qmux.unlock();
                            sqControlQ1 = LRS2E;
                        }
                        else{
                            sqControlQ1 = LRS1;
                        }

                    }
                    else{
                        sqControlQ1 = LRS1;
                    }
                }
            }
            else{
                if(Adressing_logic2)
                ){
                    //this->_bufferOut[1].dataIn = _temp;
                    if(_bufferOut_busyIn[2].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[2].write(_temp);
                            _bufferOut_write[2].write(true);
                            //_qmux.unlock();
                            sqControlQ1 = LRS2W;
                        }
                        else{
                            sqControlQ1 = LRS1;
                        }

                    }
                    else{
                        sqControlQ1 = LRS1;
                    }
                }
                else
                {
                    if(_bufferOut_busyIn[0].read() == false){
                        if(_qmux.trylock() > 0){
                            _outpktIn[0].write(_temp);
                            _bufferOut_write[0].write(true);
                            //_qmux.unlock();
                            sqControlQ1 = LRS2N;
                        }
                        else{
                            sqControlQ1 = LRS1;
                        }

                    }
                    else{
                        sqControlQ1 = LRS1;
                    }
                }
            }
            break;

        case LRS2N:
            _bufferOut_write[0].write(false);
            _qmux.unlock();
            sqControlQ1 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2S:
            _bufferOut_write[1].write(false);
            _qmux.unlock();
            sqControlQ1 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2W:
            _bufferOut_write[2].write(true);
            _qmux.unlock();
            sqControlQ1 = SQIDLE; //TODO: or maybe some other state
            break;
        case LRS2E:
            _bufferOut_write[3].write(true);
            _qmux.unlock();
            sqControlQ1 = SQIDLE; //TODO: or maybe some other state
            break;
        default:
            break;
        }



    }

}

Please, if anyone could advise me on how to proceed to have this as parallel process in any way, even if I have to t everything in the same process, but working as Threads I would appreciate it.

 

P.S.: I saw in the internet people saying to use export SC_SIGNAL_WRITE_CHECK=DISABLE, and the problem disappear, it may disappear, but I'm not sure if this is the right fix in this case.

Link to post
Share on other sites

If you really want to do this, sc_signal has a template argument WRITER_POLICY which can be set to SC_MANY_WRITERS to allow you to have multiple writers to the same signal  (as long as the writes occur in different deltas). See section 6.4.4 in the LRM.

 

This may be what you want - but of course writing to a single object from parallel threads is always going to be "interesting" :-)

 

regards

Alan

Link to post
Share on other sites

Thanks Alan,

 

In HDL I would place this in separated process (different signals) and use a last process to unify, everything, or place this multiple process as one process and, since pretty much everyone is in a different channel.

 

I was trying with for() interactions, but the problem is I have to test them independently not sequentially.

 

Do you know if there is a way to have threads inside of a process ? this would make more sense than splitting into different process (in HDL would occur concurrence) in SystemC I'm not sure if things will happen sequentially, locking the entire processes flow in any given moment, especially in the following test:

if(_bufferOut_busyIn[*].read() == false){
......
}

This line is the reason why I broke into multiple processes to avoid starvation in any interface with data while some may not have, and to control the flow of the ack signals.

 

Also, could I wrote some code like :

SwitchFabric:::SwitchFabric(){
SC_METHOD(sendDatasAcrossQueues)
sensitive << rstn;
sensitive clk.pos();
}

...

void SwitchFabric::sendDatasAcrossQueues(){
SC_THREAD(sendDataQueues0);
sensitive << rstn;
sensitive clk.pos();
SC_THREAD(sendDataQueues1);
sensitive << rstn;
sensitive clk.pos();
SC_THREAD(sendDataQueues1);
sensitive << rstn;
sensitive clk.pos();
SC_THREAD(sendDataQueues1);
sensitive << rstn;
sensitive clk.pos();

}

Regards

Vitorio.

Link to post
Share on other sites

You can launch processes from within a method using sc_spawn(). The SC_THREAD and SC_METHOD macros are only valid inside module constructors. By default sc_spawn() specifies SC_THREAD style behavior. If you need to specify static sensitivity, you will need to use sc_spawn_options. You could also use dynamic sensitivity and process control as an alternative.

Link to post
Share on other sites

Thanks David,,

I f using sc_spawn, ca I ahve multiple threads drivng a vector signal ?

Because this is my main problem, currently. I have a process 0 that writes in vector[0] and process1 in vector[1], during simulation if raises a flag tha ttwo separated methods are trying to drive teh same signal, it is thea sam signal but not in the same position.

 

I tried to fix that using 'consolidation approach' as explained in "a systemC Primer" page 135, but now I had the same problem. So now I'm trying the sc_spawn, but I'm not finding the way to use sc_spawn_options to set the sensitive list of the spawned process in the main process.

 

Any links for examples ?

Link to post
Share on other sites

Hi Vitorio,

   the way the sc_signal code works is that it keeps track of the process handle of the first writer, and then if a write from a different process handle occurs, it is considered an error.

 

Using dynamic processes and sc_spawn will still be considered as multiple writers, and you'll get the same error.

 

There's an example of of sc_spawn/sc_spawn_options on page 66 of the Language Reference Manual.

 

regards

Alan

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...