我尝试使用我在SystemC(this one)网站上找到的一个示例来测试我的环境。以下是示例的代码:
#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;
}
没什么。交易者和DUV是模块的扩展类,交易者生成地址并将其发送到DUV,DUV用该地址从内存中读取数据。一切看起来都很好但是当我尝试运行它时我得到错误:
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
当只有DUV发送该信号并且交易者只读取信号时,我无法看到多个驱动器在哪里。即使我删除了对此信号执行任何操作的所有行,它仍然显示相同的错误。
答案 0 :(得分:8)
之前的回复是正确的:错误是duv.bus_data
和tr.bus_data
sc_inout
端口的结果。 SystemC将其标记为错误,因为两个端口都可以写入信号。
有三种解决方案:
SC_SIGNAL_WRITE_CHECK
设置为DISABLE
。这种方法已经过时了。SC_DEFAULT_WRITER_POLICY
预处理器变量设置为SC_MANY_WRITERS
。sc_signal<sc_uint<8>, SC_MANY_WRITERS> bus_data
。这是您最好的选择。有关详细信息,请参阅Accellera SystemC发行版根目录中的INSTALL
文件。
使用此代码来证明上述解决方案:
#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;
}
答案 1 :(得分:1)
由于duv.bus_data和tr.bus_data都是sc_inout类型,我相信它们都可以写入信号,SystemC可能不允许。如果您注释掉绑定到该信号的其中一行,例如行
duv.bus_addr(bus_addr);
错误可能会消失,这会暗示这是问题所在。此讨论似乎与您的问题有关:
http://forums.accellera.org/topic/2311-inout-port-binding-issue/