Upload
-
View
205
Download
0
Embed Size (px)
DESCRIPTION
SystemC Channel : SC_MUTEX, SC_FIFO, SC_SEMPHORE
Citation preview
按一下以編輯母片副標題樣式
Communication Channels
林敬倫 , 蘇文鈺
成大資訊
2010/12
Without Channels• One can still exchange data among modules.
• Problems:
– Data access may not be well scheduled.
– It is possible that multiple processes try to access but clear order is not set up.
– Events can be used to set up the order but it is likely that events may be missed.
– No handshaking mechanism is embedded.
– It does not map to HW architecture.
– And so on….
Using channels• For all communication issues, it is recommended to solve the
above problems using channels.
• Channel is a SystemC embedded mechanism.
• Can be used to map to real HW architecture and communication protocols.
• Two basic types of channels are provided:
– Primitive
– Hierarchical
Primitive Channels
• For “primitive” type, no process, hierarchy, and so on in order to make the channels fast.
• Inherit from the base class, sc_prim_channel.
• Three simple SystemC channels:– sc_mutex
– sc_semaphore
– sc_fifo
sc_mutex• Mutex is a program object allowing multiple threads to share a common
resource without colliding.
• During elaboration, a mutex is created. Then, any process wants to use the resource must lock the mutex to prevent others from accessing the same source. After its access, the process must unlock the mutex to let others access the resource.
• When a process try to access a locked mutex, it is prevented until the mutex is unlocked.
• In SystemC, both blocking and unblocking types are supported.
• No signal is available to indicate that a mutex is available. SO, using trylock may be a method but it may slow down the simulation.
sc_mutex syntax
• sc_mutex name_of_mutex– name_of_mutex.lock();//blocking
– name_of_mutex.trylock();//non-blocking
– name_of_mutex.unlock();
• 下圖是一個簡單的 bus based的範例,其中有兩個 masters 加上一個 slave 以及一個簡單的 bus arbiter
Mutex_bus
master0 master1
slave
Arbitration:Using sc_mutex
Main.cpp#include <systemc.h>#include "master0.h"#include "master1.h"#include "slave.h"#include "bus.h"int sc_main (int argc , char *argv[]) { sc_clock clk("clk0", 1 , SC_NS , 0.5);
master0 master0("master0"); master1 master1("master1");
slave slave0("slave0"); bus bus0("bus0");
master0.clk(clk); master1.clk(clk);
master0.write_port(bus0); master1.write_port(bus0); bus0.write_port(slave0);
sc_start(50, SC_NS); cout << endl << endl; return 0;}
Master0.h#ifndef MASTER0_H#define MASTER0_H#include <systemc.h>#include "bus_if.h"
class master0 : public sc_module {public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1> write_port; void t1();SC_HAS_PROCESS(master0);
master0(sc_module_name name) { SC_THREAD(t1);
sensitive << clk.pos(); }};
void master0::t1(){
while(1){wait();
sc_time_stamp().print();printf("master0 request!\n");write_port->write(1,32);
wait(11,SC_NS);
sc_time_stamp().print();printf("master0 request!\n");write_port->write(5,53);
wait(11,SC_NS);}
}#endif // MASTER0_H
Master1.h#ifndef MASTER1_H#define MASTER1_H#include <systemc.h>#include "bus_if.h"
class master1 : public sc_module {public:
// clksc_in_clk clk;
// port declaration sc_port<bus_if,1> write_port;
void t1();
SC_HAS_PROCESS(master1);
master1(sc_module_name name) { SC_THREAD(t1); sensitive << clk.pos(); }};
void master1::t1(){
while(1){wait();
sc_time_stamp().print();printf("master1 request!\n");write_port->write(3,60);
wait(10,SC_NS);
sc_time_stamp().print();printf("master1 request!\n");write_port->write(5,44);
wait(10,SC_NS);}
}#endif // MASTER1_H
Bus.h & Bus_if.h#ifndef BUS_H#define BUS_H#include <systemc.h>#include "bus_if.h"
class bus :public bus_if, public sc_module{public:
// port declarationsc_port<bus_if,1> write_port;
// bus_if functionvoid write(unsigned addr, int
data);
// constructorbus(sc_module_name);
private:// sc_mutex declarationsc_mutex bus_mutex;
};#endif // BUS_H
#ifndef BUS_IF_H#define BUS_IF_H#include <systemc.h>
class bus_if : public sc_interface{
// pure virtual functionpublic:
virtual void write(unsigned addr, int data) = 0;};
#endif // BUS_IF_H
Bus.cpp#include "bus.h"
bus::bus(sc_module_name nm) : sc_module(nm){}
void bus::write(unsigned addr, int data){
// sc_mutex lock process, wait for unlockbus_mutex.lock();
write_port->write(addr,data);
// sc_mutex unlockbus_mutex.unlock();
}
Slave.h#ifndef SLAVE_H#define SLAVE_H#include <systemc.h>#include "bus_if.h"
class slave : public sc_module , public bus_if {public:
void write(unsigned addr, int data);
slave(sc_module_name name){
for(int a = 0 ; a<32 ; a++){
memory[a] = 0;}
}
private:int memory[32];
};
void slave::write(unsigned addr, int data){
memory[addr] = data;wait(2, SC_NS);sc_time_stamp().print();printf(" slave get data %d at addr %d !\n",data,addr);
}#endif // SLAVE_H
result
sc_semaphore• To have more than one resources to choose from, one can use
semaphore.
• Mutex here is one special case of semaphore.
• When a process finishes with a resource, it must post a notice.
• Syntax: sc_semaphore name_or_semaphore(count)
– name_of_semaphore.wait(); //blocking
– name_of_semaphore.trywait(); //non-blocking
– name_of_semaphore.get_value();// return # of free semaphores
– name_of_semaphore.post(); //when free a resource
09/12/9
Simple Bus Model
• 一樣是一個簡單的 Bus Model的範例 , 因為要求是可以有好幾個Modules同時進來 , 所以可以用 Semaphore來實現 .
09/12/9
Sem_bus
master0 master1
slave
Arbitration:Using sc_semaphore
Main.cpp#include <systemc.h>#include "master0.h"#include "master1.h"#include "slave.h"#include "bus.h"
int sc_main (int argc , char *argv[]) { sc_clock clk("clk0", 1 , SC_NS , 0.5);
master0 master0("master0"); master1 master1("master1");
slave slave0("slave0"); bus bus0("bus0");
master0.clk(clk); master1.clk(clk);
master0.write_port(bus0); master1.write_port(bus0); bus0.write_port(slave0);
sc_start(50, SC_NS); cout << endl << endl; return 0;}
Master0.h#ifndef MASTER0_H#define MASTER0_H#include <systemc.h>#include "bus_if.h"
class master0 : public sc_module { public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1> write_port; void t1();SC_HAS_PROCESS(master0);
master0(sc_module_name name) { SC_THREAD(t1);
sensitive << clk.pos(); }};
void master0::t1(){
while(1){wait();
sc_time_stamp().print();printf("master0 request!\n");write_port->write(1,32);
wait(11,SC_NS);
sc_time_stamp().print();printf("master0 request!\n");write_port->write(5,53);
wait(11,SC_NS);}
}#endif // MASTER0_H
Master1.h#ifndef MASTER1_H#define MASTER1_H#include <systemc.h>#include "bus_if.h"
class master1 : public sc_module {public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1>
write_port;
void t1();
SC_HAS_PROCESS(master1);
master1(sc_module_name name) { SC_THREAD(t1);
sensitive << clk.pos(); }};
void master1::t1(){
while(1){wait();
sc_time_stamp().print();printf("master1 request!\n");write_port->write(3,60);
wait(10,SC_NS);
sc_time_stamp().print();printf("master1 request!\n");write_port->write(5,44);
wait(10,SC_NS);}
}#endif // MASTER1_H
Bus.h & Bus_if.h#ifndef BUS_H#define BUS_H#include <systemc.h>#include "bus_if.h"
class bus :public bus_if, public sc_module{public:
// port declarationsc_port<bus_if,1> write_port;
// bus_if functionvoid write(unsigned addr, int
data);
// constructorbus(sc_module_name);
private:// sc_semaphore declarationsc_semaphore write_sem;
};#endif // BUS_H
#ifndef BUS_IF_H#define BUS_IF_H#include <systemc.h>
class bus_if : public sc_interface{
// pure virtual functionpublic:
virtual void write(unsigned addr, int data) = 0;};
#endif // BUS_IF_H
Bus.cpp#include "bus.h"
// write_sem constructor assign count = 1bus::bus(sc_module_name nm) : sc_module(nm), write_sem(1){}
void bus::write(unsigned addr, int data){
// sc_semaphore.wait, count-- (1=>0)write_sem.wait();
write_port->write(addr,data);
// sc_semaphore.post, count++ (0=>1)write_sem.post();
}
Slave.h#ifndef SLAVE_H#define SLAVE_H#include <systemc.h>#include "bus_if.h"
class slave : public sc_module , public bus_if {public:
void write(unsigned addr, int data);
slave(sc_module_name name){
for(int a = 0 ; a<32 ; a++){
memory[a] = 0;}
}
private:int memory[32];
};
void slave::write(unsigned addr, int data){
memory[addr] = data;wait(2, SC_NS);sc_time_stamp().print();printf(" slave get data %d at addr %d !\n",data,addr);
}#endif // SLAVE_H
result
SC_FIFO• Good for architecture modeling
• Suitable for data flow modeling too.
• Simple to implement.
• Default sc_fifo depth is 16, with its data type specified.
• The data type of sc_fifo can be complex structure.
• It can be used to buffer data between two processing units, data packets in communication networks, and so on.
Bus Wrapper
• 接續上面的 Bus Model, 接到 Bus 的 Module有一個 Wrapper, Wrapper 上有一個 FIFO 來當 buffer, 這樣就可以運用 sc_fifo來當練習了 .
FIFO_bus
master0 master1
slave
Arbitration:Using wrapper(sc_fifo)
wrapper
Main.cpp#include <systemc.h>#include "master0.h"#include "master1.h"#include "wrapper.h"#include "slave.h"#include "bus.h"
int sc_main (int argc , char *argv[]) { sc_clock clk0("clk0", 1 , SC_NS , 0.5);
master0 master0("master0");
master1 master1("master1");
wrapper wrapper0("wrapper0"); slave slave0("slave0"); bus bus0("bus0");
master0.clk(clk0);master1.clk(clk0);wrapper0.clk(clk0);
master0.write_port(wrapper0); master1.write_port(wrapper0);
wrapper0.write_port(bus0); bus0.write_port(slave0);
sc_start(50, SC_NS); cout << endl << endl; return 0;}
Master0.h#ifndef MASTER0_H#define MASTER0_H#include <systemc.h>#include "bus_if.h"
class master0 : public sc_module {public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1> write_port; void t1();SC_HAS_PROCESS(master0);
master0(sc_module_name name) { SC_THREAD(t1);
sensitive << clk.pos(); }};
void master0::t1(){
while(1){wait();
sc_time_stamp().print();printf("master0 request!\n");write_port->write(1,32);
wait(11,SC_NS);
sc_time_stamp().print();printf("master0 request!\n");write_port->write(5,53);
wait(11,SC_NS);}
}#endif // MASTER0_H
Master1.h#ifndef MASTER1_H#define MASTER1_H#include <systemc.h>#include "bus_if.h"
class master1 : public sc_module {public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1>
write_port;
void t1();
SC_HAS_PROCESS(master1);
master1(sc_module_name name) { SC_THREAD(t1);
sensitive << clk.pos(); }};
void master1::t1(){
while(1){wait();
sc_time_stamp().print();printf("master1 request!\n");write_port->write(3,60);
wait(10,SC_NS);
sc_time_stamp().print();printf("master1 request!\n");write_port->write(5,44);
wait(10,SC_NS);}
}#endif // MASTER1_H
Wrapper.h#ifndef WRAPPER_H#define WRAPPER_H#include <systemc.h>#include "bus_if.h"
class wrapper : public sc_module , public bus_if {public:
// clksc_in_clk clk;
// port declarationsc_port<bus_if,1> write_port;
void t1();void write(unsigned addr, int data);
SC_HAS_PROCESS(wrapper);
wrapper(sc_module_name name) { sc_fifo<unsigned> addr_fifo(10);
sc_fifo<int> data_fifo(10); SC_THREAD(t1);
sensitive << clk.pos(); }
private:
sc_fifo<unsigned> addr_fifo;sc_fifo<int> data_fifo;
unsigned addr_temp;int data_temp;
};
Wrapper.h(cont’)void wrapper::t1(){
while(1){
wait();sc_time_stamp().print();printf(" wrapper request!\n");addr_temp = addr_fifo.read();data_temp = data_fifo.read();write_port->write(addr_temp,data_temp);sc_time_stamp().print();printf(" wrapper write %d in %d \n",data_temp,addr_temp);
}}
void wrapper::write(unsigned addr, int data){
sc_time_stamp().print();printf(" fifo.write data = %d ; addr = %d \n",data,addr);addr_fifo.write(addr);data_fifo.write(data);
}#endif // WRAPPER_H
Bus.h & Bus_if.h#ifndef BUS_H#define BUS_H#include <systemc.h>#include "bus_if.h"
class bus :public bus_if, public sc_module{public:
// port declarationsc_port<bus_if,1> write_port;
// bus_if functionvoid write(unsigned addr, int
data);
// constructorbus(sc_module_name);
#endif // BUS_H
#ifndef BUS_IF_H#define BUS_IF_H#include <systemc.h>
class bus_if : public sc_interface{
// pure virtual functionpublic:
virtual void write(unsigned addr, int data) = 0;};
#endif // BUS_IF_H
Bus.cpp#include "bus.h"
bus::bus(sc_module_name nm) : sc_module(nm), write_sem(1)
{
}
void bus::write(unsigned addr, int data)
{
write_port->write(addr,data);
}
09/12/9
Slave.h#ifndef SLAVE_H
#define SLAVE_H
#include <systemc.h>
#include "bus_if.h"
class slave : public sc_module , public bus_if
{
public:
void write(unsigned addr, int data);
slave(sc_module_name name)
{
for(int a = 0 ; a<32 ; a++)
{
memory[a] = 0;
}
}
private:int memory[32];
};
void slave::write(unsigned addr, int data){
memory[addr] = data;wait(2, SC_NS);
}#endif // SLAVE_H
09/12/9
result
The use of Signals• When modeling signal on something like electronic
wire,
• When concurrent executions of modules are required and execution orders of modules are important,
• When using wait() and notify() cosumes too much time,
• When using FIFO consuming too much resources,
SystemC Simulation Kernel Work Flow
Signal Channel• Signal channels use the update phase as a point of synchronization.
• Each such channel has to store the current value and the new value.
• The incoming value is stored into the new position instead of the current position.
• When in update phase (Kernel calls update_request()), the current value is updated with the new value. Therefore, contention is resolved.
• All these are done within a delta cycle.
• If one writes to a channel and reads the channel within the same delta cycle, one will find the result is not the value just been written.
09/12/9
sc_signal• When using write(), the evaluate-update is performed, too.
That is, it calls sc_prim_channle:: request_update() and sc_signal::update().
• sc_signal behaves like VHDL’ signal and Verilog’s reg. By the way.
• Only one process can write to a sc_signal in order to avoid race condition.
sc_signal <datatype> name_of_signal;name_of_signal.write(new_value); name_of_signal.read(name_of_var);sensitive << name_of_signal.default_event();wait(name_of_signal.default_event);………
SIGNAL_BUS
Bus說明
m0 m1
s0
arbitermultiplexerCLK
data
addr
data
addr
data
addr
enable_s
enable1
enable0
enable_mselect
used
Signal Bus File
main.cpp
master0.h
master1.h
slave.h
arbiter.h
multiplexer.h
main.cpp
master0.h
master1.h
slave.h
arbiter.h
multiplexer.h