Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"sc_signal<T> cannot have more than one driver" error, SystemC

I tried to test my environment with one of the examples I found on a website for SystemC (this one). Here is the code of the example:

#include "scv.h"

const unsigned ram_size = 256;

class rw_task_if : virtual public sc_interface {
public:
   typedef sc_uint<8> addr_t;
   typedef sc_uint<8> data_t;
   struct write_t {
     addr_t addr;
     data_t data;
   };

   virtual data_t read(const addr_t*) = 0;
   virtual void write(const write_t*) = 0;
};

SCV_EXTENSIONS(rw_task_if::write_t) {
public:
   scv_extensions<rw_task_if::addr_t> addr;
   scv_extensions<rw_task_if::data_t> data;
   SCV_EXTENSIONS_CTOR(rw_task_if::write_t) {
     SCV_FIELD(addr);
     SCV_FIELD(data);
   }
};

class pipelined_bus_ports : public sc_module {
public:
   sc_in< bool > clk;
   sc_inout< bool > rw;
   sc_inout< bool > addr_req;
   sc_inout< bool > addr_ack;
   sc_inout< sc_uint<8> > bus_addr;
   sc_inout< bool > data_rdy;
   sc_inout< sc_uint<8> > bus_data;

   SC_CTOR(pipelined_bus_ports)
     : clk("clk"), rw("rw"),
       addr_req("addr_req"),
       addr_ack("addr_ack"), bus_addr("bus_addr"),
       data_rdy("data_rdy"), bus_data("bus_data") {}
};

class rw_pipelined_transactor
   : public rw_task_if,
     public pipelined_bus_ports {

   sc_mutex addr_phase;
   sc_mutex data_phase;

   scv_tr_stream pipelined_stream;
   scv_tr_stream addr_stream;
   scv_tr_stream data_stream;
   scv_tr_generator<sc_uint<8>, sc_uint<8> > read_gen;
   scv_tr_generator<sc_uint<8>, sc_uint<8> > write_gen;
   scv_tr_generator<sc_uint<8> > addr_gen;
   scv_tr_generator<sc_uint<8> > data_gen;

public:
   rw_pipelined_transactor(sc_module_name nm) :  
       pipelined_bus_ports(nm),
       addr_phase("addr_phase"),
       data_phase("data_phase"),
       pipelined_stream("pipelined_stream", "transactor"),
       addr_stream("addr_stream", "transactor"),
       data_stream("data_stream", "transactor"),
       read_gen("read",pipelined_stream,"addr","data"),
       write_gen("write",pipelined_stream,"addr","data"),
       addr_gen("addr",addr_stream,"addr"),
       data_gen("data",data_stream,"data")
   {}
   virtual data_t read(const addr_t* p_addr);
   virtual void write(const write_t * req);
};

rw_task_if::data_t rw_pipelined_transactor::read(const rw_task_if::addr_t* 
addr) {
   addr_phase.lock();
   scv_tr_handle h = read_gen.begin_transaction(*addr);

   scv_tr_handle h1 = addr_gen.begin_transaction(*addr,"addr_phase",h);
   wait(clk->posedge_event());
   bus_addr = *addr;
   addr_req = 1;
   wait(addr_ack->posedge_event());
   wait(clk->negedge_event());
   addr_req = 0;
   wait(addr_ack->negedge_event());
   addr_gen.end_transaction(h1);
   addr_phase.unlock();

   data_phase.lock();
   scv_tr_handle h2 = data_gen.begin_transaction("data_phase",h);
   wait(data_rdy->posedge_event());
   data_t data = bus_data.read();
   wait(data_rdy->negedge_event());
   data_gen.end_transaction(h2);
   read_gen.end_transaction(h,data);
   data_phase.unlock();

   return data;
}

void rw_pipelined_transactor::write(const write_t * req) {
   scv_tr_handle h = write_gen.begin_transaction(req->addr);
   // ...
   write_gen.end_transaction(h,req->data);
}

class test : public sc_module {
public:
   sc_port< rw_task_if > transactor;
   SC_CTOR(test) {
     SC_THREAD(main);
   }
   void main();
};

class write_constraint : virtual public scv_constraint_base {
public:
   scv_smart_ptr<rw_task_if::write_t> write;
   SCV_CONSTRAINT_CTOR(write_constraint) {
     SCV_CONSTRAINT( write->addr() <= ram_size );
     SCV_CONSTRAINT( write->addr() != write->data() );
   }
};

inline void process(scv_smart_ptr<int> data) {}

inline void test::main() {
   // simple sequential tests
   for (int i=0; i<3; i++) {
     rw_task_if::addr_t addr = i;
     rw_task_if::data_t data = transactor->read(&addr);
     cout << "at time " << sc_time_stamp() << ": ";
     cout << "received data : " << data << endl;
   }

   scv_smart_ptr<rw_task_if::addr_t> addr;
   for (int i=0; i<3; i++) {

     addr->next();
     rw_task_if::data_t data = transactor->read( addr->get_instance() );
     cout << "data for address " << *addr << " is " << data << endl;
   }

   scv_smart_ptr<rw_task_if::write_t> write;
   for (int i=0; i<3; i++) {
     write->next();
     transactor->write( write->get_instance() );
     cout << "send data : " << write->data << endl;
   }

   scv_smart_ptr<int> data;
   scv_bag<int> distribution;
   distribution.push(1,40);
   distribution.push(2,60);
   data->set_mode(distribution);
   for (int i=0;i<3; i++) { data->next(); process(data); }
}

class design : public pipelined_bus_ports {
   list< sc_uint<8> > outstandingAddresses;
   list< bool > outstandingType;
   sc_uint<8>  memory[ram_size];

public:
   SC_HAS_PROCESS(design);
   design(sc_module_name nm) : pipelined_bus_ports(nm) {
     for (unsigned i=0; i<ram_size; ++i) { memory[i] = i; }
     SC_THREAD(addr_phase);
     SC_THREAD(data_phase);
   }
   void addr_phase();
   void data_phase();
};

inline void design::addr_phase() {
   while (1) {
     while (addr_req.read() != 1) {
       wait(addr_req->value_changed_event());
     }
     sc_uint<8> _addr = bus_addr.read();
     bool _rw = rw.read();

     int cycle = rand() % 10 + 1;
     while (cycle-- > 0) {
       wait(clk->posedge_event());
     }

     addr_ack = 1;
     wait(clk->posedge_event());
     addr_ack = 0;

     outstandingAddresses.push_back(_addr);
     outstandingType.push_back(_rw);
     cout << "at time " << sc_time_stamp() << ": ";
     cout << "received request for memory address " << _addr << endl;
   }
}

inline void design::data_phase() {
   while (1) {
     while (outstandingAddresses.empty()) {
       wait(clk->posedge_event());
     }
     int cycle = rand() % 10 + 1;
     while (cycle-- > 0) {
       wait(clk->posedge_event());
     }
     if (outstandingType.front() == 0) {
       cout << "reading memory address " << outstandingAddresses.front()
            << " with value " << memory[outstandingAddresses.front()] << endl;
       bus_data = memory[outstandingAddresses.front()];
       data_rdy = 1;
       wait(clk->posedge_event());
       data_rdy = 0;

     } else {
       cout << "not implemented yet" << endl;
     }
     outstandingAddresses.pop_front();
     outstandingType.pop_front();
   }
}

int sc_main (int argc , char *argv[])
{
   scv_startup();

   scv_tr_text_init();
   scv_tr_db db("my_db");
   scv_tr_db::set_default_db(&db);

   // create signals
   sc_clock clk("clk",20,SC_NS,0.5,0,SC_NS,true);
   sc_signal< bool > rw;
   sc_signal< bool > addr_req;
   sc_signal< bool > addr_ack;
   sc_signal< sc_uint<8> > bus_addr;
   sc_signal< bool > data_rdy;
   sc_signal< sc_uint<8> > bus_data;

   // create modules/channels
   test t("t");
   rw_pipelined_transactor tr("tr");
   design duv("duv");

   // connect them up
   t.transactor(tr);

   tr.clk(clk);
   tr.rw(rw);
   tr.addr_req(addr_req);
   tr.addr_ack(addr_ack);
   tr.bus_addr(bus_addr);
   tr.data_rdy(data_rdy);
   tr.bus_data(bus_data);

   duv.clk(clk);
   duv.rw(rw);
   duv.addr_req(addr_req);
   duv.addr_ack(addr_ack);
   duv.bus_addr(bus_addr);
   duv.data_rdy(data_rdy);
   duv.bus_data(bus_data);

   // run the simulation
   sc_start(1000000, SC_NS);

   return 0;
}

It's nothing much. The transactor and the DUV are extended classes of the module and the transactor generates the address and sends it to the DUV and the DUV reads the data from memory with that address. Everything looks fine but when I try to run it i get error:

TB Transaction Recording has started, file = my_db
Transaction Recording is closing file: my_db

Error: (E115) sc_signal<T> cannot have more than one driver: 
 signal 'signal_5' (sc_signal)
 first driver 'duv.bus_data'  (sc_inout)
 second driver 'tr.bus_data' (sc_inout)
In file: ../../../../src/sysc/communication/sc_signal.cpp:73 

I can't see where are multiple drivers when only the DUV sends that signal and the transactor only reads the signal. Even if I delete all of the lines that do anything with this signal it still shows the same error.

like image 955
tokyo Avatar asked Sep 22 '16 13:09

tokyo


2 Answers

The previous reply is correct: the error is the result of both duv.bus_data and tr.bus_data being sc_inout ports. SystemC flags that as an error because both ports could write to the signal.

There are three solutions:

  1. Set the environment variable SC_SIGNAL_WRITE_CHECK to DISABLE before running your simulation. This method is out dated.
  2. Set the SC_DEFAULT_WRITER_POLICY preprocesor variable to SC_MANY_WRITERS when compiling your code.
  3. Define the writer policy for the signal such that it allows many writers: sc_signal<sc_uint<8>, SC_MANY_WRITERS> bus_data. This is your best option.

See the INSTALL file at the root of the Accellera SystemC distribution for more information.

Use this code to proove the above solutions:

#include <systemc.h>

SC_MODULE(Module) {
    sc_inout< sc_uint<8> > bus_data;
    SC_CTOR(Module): bus_data("bus_data") {}
};

int sc_main (int argc , char *argv[]) {
    // sc_signal< sc_uint<8> > bus_data;
    sc_signal<sc_uint<8>, SC_MANY_WRITERS> bus_data;
    Module m1("m1");
    Module m2("m2");
    m1.bus_data(bus_data);
    m2.bus_data(bus_data);

    sc_start(1, SC_NS);

    return 0;
}
like image 129
DarrylLawson Avatar answered Nov 17 '22 10:11

DarrylLawson


Since both duv.bus_data and tr.bus_data are of type sc_inout, I believe they can both write to the signal, which SystemC may not allow. If you comment out one of the lines where you are binding to that signal, such as the line

duv.bus_addr(bus_addr);

the error might go away, which would give a hint that this is the problem. This discussion appears to be related to your question:

http://forums.accellera.org/topic/2311-inout-port-binding-issue/

like image 43
plafratt Avatar answered Nov 17 '22 10:11

plafratt