본문 바로가기

SystemC Tutorial

Ch2. SystemC의 구성 요소 - 인터페이스,포트,채널

반응형

 

 

자 이제 SystemC를 이용하여 하드웨어 모듈을 정의할 수 있었다. 그러면 모듈과 모듈간의 통신은 어떻게 할까? Verilog에서 모듈과 모듈을 연결할 때는 input/output port를 wire로 연결 해 주면 된다. SystemC에서는 약간 복잡한 메카니즘을 갖고 있다. 하지만 사용자 입장에서 세부적인 사항까지 다 이해할 필요는 없다.

SystemC의 모듈간 통신을 위해서는 3가지 class가 필요하다. 그 하나는 인터페이스(interface) class이고 또 하나는 포트(port) class 그리고 마지막으로 채널(channel) class이다.

SystemC의 모듈은 class이다. 모듈간 통신은 class간 통신과 같다. 그런데 class라는 것은 sw component이기 때문에 verilog와 같은 HDL에서 처럼 hardware간의 통신을 위한 class들이 따로 필요한 것이다. module과 module은 channel을 통해서 연결된다. 그리고 이 channel의 변수를 read/write함으로써 data를 주고 받는다.

이를 위해 SystemC에서는 interface-method-call (IMC)라는 방식을 사용한다. 즉 port에 연결된 interface의 method function을 call함으로써 channel의 값을 read/write하는 방식이다. interface class에는 channel class의 데이터를 조작할 수 있는 가상 함수를 선언한다.

실제 이 함수의 구현은 channel class내부에서 이루어진다. 모든 interface class는 sc_interface로부터 파생되어야 한다. sc_interface class에는 register_port라고 하는 가상 함수를 제공하고 channel class에서는 이 가상함수를 통해 port와의 mapping에 대한 적합성을 검증한다.

sc_module에서 다른 모듈과의 통신을 위해서 input/output port class를 정의해 주어야 한다. port class는 통신의 매개체로 이용되는 채널 class의 멤버 함수를 호출하기 위하여 interface를 binding시켜 주는 역할을 한다.

channel class는 앞서 말한 대로 interface의 가상 함수를 실제로 구현하여 channel class내부의 데이터를 조작할 수 있도록 한다.

하나 예를 들어 보자.

class sender :: public sc_module {

    sc_out<int> Y; // 포트 선언

....

}


class receiver::public sc_module {

    sc_in<int> A; // 포트 선언

....

}


sender u_sender("sender"); // 모듈 사례화

receiver u_receiver("recevier"); // 모듈 사례화


sc_signal<int> data; // 채널 선언


u_sender.Y(data); // 포트 매핑

u_receiver.A(data); // 포트 매핑

sender module의 output port Y와 receiver module의 input port A는 sc_signal이라고 channel class 'data'로 연결된다. 

sc_signal class의 내부를 들여다 보면 sc_signal_inout_if class의 가상 함수 read()/write()가 구현되어 있다. sender module에서는 Y.write(10); 과 같은 방법으로 Y port에 데이터를 쓸 수 있다. 또 receiver module에서는 A.read();와 같은 방법으로 A port의 데이터를 읽을 수 있다. Y.write(10);이라는 구문이 실행 절차를 분석해 보면 Y class의 write() 멤버 함수가 실행되고 이 멤버 함수는 포트 매핑을 통해 연결된 sc_signal channel class의 interface class의 포인터를 통해 sc_signal channel class 내부에 구현된 write()함수를 호출한다.

여러가지 다양한 interface,port,channel을 사용자가 구현 할 수 있다. sc_signal과 같은 channel은 SystemC의 primive channel이라고 부른다.

앞 장에서 예를 든 Adder module을 확장하여 Multiplier module을 만들고 서로 연결하는 code는 아래와 같다.

위에 설명한 것처럼 sc_signal 을 통해 서로 연결하여 데이터를 전달할 수 있음을 알 수 있다.

#include <stdio.h>
#include <systemc.h>
 
class Adder : public sc_module
{
	public :
 
    sc_in<int>    a;
    sc_in<int>    b;
    sc_out<int>   y;
 
    SC_HAS_PROCESS(Adder);
 
    Adder(sc_module_name name) : sc_module(name) {
        SC_THREAD (main);
        sensitive << a << b;
    }
 
	void main();
};
 
void Adder::main()
{
    while(1)
    {
        y = a + b;
        wait();
    }
}

class Mult : public sc_module
{
	public :
 
    sc_in<int>    a;
    sc_in<int>    b;
    sc_out<int>   y;
 
    SC_HAS_PROCESS(Mult);
 
    Mult(sc_module_name name) : sc_module(name) {
        SC_THREAD (main);
        sensitive << a << b;
    }
 
	void main();
};
 
void Mult::main()
{
    while(1)
    {
        y = a * b;
        wait();
    }
}
 
int sc_main(int argc, char *argv[])
{
	sc_signal<int> a0;
	sc_signal<int> b0;
	sc_signal<int> y0;

	sc_signal<int> a1;
	sc_signal<int> b1;
	sc_signal<int> y1;

	sc_signal<int> mult;
 
	Adder u_Adder0 ("adder0");
	Adder u_Adder1 ("adder1");
	Mult u_Mult ("mult");
 
	u_Adder0.a(a0);
	u_Adder0.b(b0);
	u_Adder0.y(y0);

	u_Adder1.a(a1);
	u_Adder1.b(b1);
	u_Adder1.y(y1);

	u_Mult.a(y0);
	u_Mult.b(y1);
	u_Mult.y(mult);
 
	a0 = 10;
	b0 = 20;
	a1 = 2;
	b1 = 5;
	sc_start(100, SC_NS);
 
	printf("Adder 0 : %d + %d = %d\n", a0.read(), b0.read(), y0.read());
	printf("Adder 1 : %d + %d = %d\n", a1.read(), b1.read(), y1.read());
	printf("Mult Out = %d\n", mult.read());
 
	return 0;
 
}
반응형