ASIC SoC2010.12.02 15:37

The Example Design



 

Memory Map

 
사용자 삽입 이미지

 메모리 맵은 위와 같습니니다.
 Instruction Memory (ROM)은 0x0400_0000에 위치합니다.
 부팅시에 부팅 코드를 SRAM으로 카피하고 움직이게 됩니다.

 Interrupt Assignments

 
 OpenRISC 1000은 프로그래머블한 인터럽트 코아를 가지고 있고, 외부에서 20개의 인터럽트를 연결할 수 있습니다. 그중에서 사용하는 인터럽트는 아래와 같이 배치되어 있습니다.

사용자 삽입 이미지

Test Bench Modeling of Peripherals


Peripherals들은 모델링이 되어 있지 않습니다
외부 포트들은 모두 적당한 값으로 매핑되어 둡니다.

ORPSoC의 트래킹은 OpenRISC 100의 l.nop 명령어를 활용하여서 내부 정보를 얻어냅니다.
l.nop 명령은 immediate 값을 가질 수 있는데 이 값에 적당한 값을 할당 함으로서 원하는 동작을 수행합니다.

여기서 사용하는 방식은 아래 테이블에 정리되어 있다.

사용자 삽입 이미지
 다른 l.nop의 인자는 모두 무시합니다.
 testbench 구현은 이 새로운 l.nop 명령을 활용하여 구현하게 됩니다.
 

Test Software Application


Test Application은 Dhrystone 2.1 벤치마크 프로그램을 활용합니다.
앞서 설명한 n.lop 명령을 활용하여 라이브러리 중 일부룰 수정하여서 필요한 정보를 프린트하거나 얻게 됩니다.

OpenRISC 1000의 l.nop 명령어 사용하기

앞서 설명했듯이 l.nop명령은 16비트의 immediate 값을 가지고 움직입니다.
이 값은 CPU에서는 무시되지만, 테스트 벤치에 의해서 모니터링 되고 사용됩니다.
이 ORPSoC에서는 이것을 이용해서 I/O를 제공하고, C Code가 운용될 때 내부 정보를 얻을 수 있는 컨트롤 함수의 기능을 구현하는 활용합니다.

l.nop 1  : 32'h1500_0001
    GPR3에 있는 값을 리턴코드로 하여 프로그램을 끝냅니다.
    C Lib 함수는 다음과 같이 구현됩니다.

void exit (int i)
{
  asm("l.add r3,r0,%0": : "r" (i));
  asm("l.nop %0": :"K" (NOP_EXIT));
  while (1);
}



l.nop 2  : 32'h1500_0002
    GPR 3의 값을  Hex로 덤프하여 줍니다.

l.nop 3  : 32'h1500_0003
    printf을 지원해 주지만 아직까지는 제대로 구현이 안되어 있다.

l.nop 4  : 32'h1500_0004
    LSB를 Character로 프린트 해줍니다.
    PUTC를 구현하는 것은 아래와 같습니다.

void putc(int value)
{
  asm("l.addi\tr3,%0,0": :"r" (value));
  asm("l.nop %0": :"K" (NOP_PUTC));
}
	  
   이것을 이용해서 나중에 printf등을 구현할 수 있을 겁니다.




Posted by GUNDAM_IM
ASIC SoC2009.11.01 22:26
SystemC와  Verilog의 가장 큰 차이점 중에 한가지는 배포본 만들기에 있습니다.

C/C++은 각각의 Class에 필요한 함수와 변수등을 Header파일에 선언하고 함수 등을 선언 한 뒤에
cpp파일에서 구현하게 됩니다.

비록 배포 버전에서는 cpp파일을 object로 바꾸어서 전달할 수 있지만 header파일을 찬찬히 보면,
세부 사양은 알 수 없더라도, 어떤 방식으로 구성되어 있는지 등은 알 수 있습니다.  
SystemC도 엄밀하게는 C++위에서 구성되어 있어서 마찬가지로 이런 문제점이 발생합니다.

IP의 생명인 보안성 부분에서는 상당히 취약하다고 할 수 있습니다.  

그래서 귀찮지만 Pointer로 받아서 구현하는 방식을 취합니다.
이 방식은 ME C++에서 설명한 방식입니다만, SystemC에서 응용할 줄은 몰랐습니다.

PIMPL Idiom 구현 방식입니다. 말 그대로 Pointer로 받아서 구현하는 것이므로,  Pointer IMPlementation 구현 방식입니다.

일종의 Pointer Wrapper 방식이라 할 수 있습니다.

사용자 삽입 이미지
위와 같이 DesignModule을 설계하였으면 이것을 그냥 배포하는 것은 곤란하므로
DesignModule_wrapper를 쒸워서 내부 설계 정보를 최대한 Hidden 시켜서 배포하게 됩니다.

Wrapper가 가지는 조건은 다음과 같이 됩니다.

당연하게 포트가 같아야 합니다.
   - 나중에 실제 모듈로 대치하게 된다면 포트 이름도 같이 해두는게 당연히 좋습니다.


그럼 아래와 같이 예를 들어 보겠습니다.

설계한 모듈은

DesignModule이라고 한다면 header파일과 cpp파일을 가지고 있습니다.

DesignModule.h

SC_MODULE(DesigModule)
{
// Port Declaration
PortA ;
PortB ;
PortC ;
// 이하는 뭔가 중요할 것만 같은 .. 중요해야 되는 디자인 정보.. T__T;;
......
......
}

DesignModule.cpp
.....


이것을 쒸울 Wrapper는

DesignModule_Wrapper.h

class DesignModule; // 미리 클래스라고 알려주어서 컴파일 시에 오류가 생기지 않도록 한다.

SC_MODULE(DesignModule_Wrapper)
{
// Port Declaration
        SC_CTOR(DesignModule_Wrapper){
DesignModule_Wrapper_port();
        };
//
private :
DesignModule * pDesignModule;       // 이렇게 하위 클래스의 포인터를 선언해서 받아온다.
virtual ~ DesignModule_Wrapper();  // 포인터로 선언해서 나중에 new 연산으로 할당
                                                                     //  할 것이므로 Destructor에서 반드시 Delete해 주어야 한다.
                void DesignModule_Wrapper_port();

}

DesignModule_Wrapper.cpp

#include "DesignModulle.h"

DesignModule_Wrapper::DesignModule_Wrapper_port()
{
   pDesignModule = new DesignModule;

   pDesignModule->PortA(PortA);
   pDesignModule->PortB(PortB);
   pDesignModule->PortC(PortC);

}

......
DesignModule_Wrapper ::~ DesignModule_Wrapper()
{
delete pDesignModule;
}

 





DesignModule.h파일을 DesignModule_Wrapper.cpp파일에서 불러들인다는 점이 중요합니다.
즉, 실제 디자인에 관련된 정보는 DesignModule.h파일에 있으며 이 것을 Wrapper용 Header File에서 Include하지 않음으로서 Compile 시에 Dependency를 제거해 주는 것이 목적이 됩니다.

따라서 최종 사용자는

DesignModule_Wrapper.h


DesignModule_Wrapper.o
DesignModule.o

3개 파일을 받게 되는 것입니다.
물론 Obj들은 Lib으로 묶어 버리면 2개 정도 파일만 가면 되는 것이어서 큰 문제가 없이 잘 됩니다.

최종 유저에게 오픈되어 있는 정보는 DesignModule_Wrapper.h 파일 뿐이므로 실제 디자인 내부 정보는 오픈되지 않습니다.

이 방식은 Wrapper를 거치는 방식이므로, 실제 동작시에는 느려진다고 합니다.
어느정도까지 느려질 지는 테스트 해보지 않아서 잘 모르겠습니다.

Posted by GUNDAM_IM
Books2009.10.30 13:59
사용자 삽입 이미지
시중에 나온 대부분의 SystemC책들은 아직 SystemC 자체를 가리키는 데 목적을 두어서 응용편에서는 한없이 취약합니다. 원서들도 마땅히 그런 책을 찾아보기 힘듭니다.
이번에 발견한 책은 Amazon Japan에서 발견한 책입니다.

물론 이 책은 1/2 정도는 SystemC를 설명하고 있고 그 나머지 부분에서 JPEG을 설계하는 것을 알려주고 있습니다.  Untimed Functional Model에서  Cycle Accurate 모델까지 차례로 발전시켜 나가면서 설계를 하고 있습니다. 이러한 설명법은 모델간 차이점을 실제 구현에서 확인해 볼 수 있는 좋은 접근법입니다.

소스코드는 이책의 출판사 사이트에서 다운 받을 수 있을거라고 설명되어 있지만, 아직 사이트에 올라오지는 않은것 같구요..  2005년도 버전이라서 약간 예전 SystemC 코드를 사용한다는 점이 아쉽지만, 실제 구현예를 볼 수 있는 유일한 서적에 가까우니 권할 만 합니다. 이 책으로 완전한 JPEG을 구현하겠다는 분이 보신다면 좀 아쉬울 것입니다. 그냥 SystemC 코드의 실제 응용 예를 보는데 만족한다면 충분히 좋은 책입니다.

책은 JPEG 전체를 설명하지 않고 DCT 부분만 설계를 하고 있고 나머지 부분은  mcore라고 하는 프로세서를 연결시켜서 하게 되어 있습니다. 예전에 다른 문서를 보면 이 mcore는 도시바에서 (기억이 가물가물합니다. ) 사용한것으로 설명된 자료를 본적이 있습니다.

혹자가 말하길 이제 일본어는 제 2 외국어 축에 못낀다고 하죠.. 이 책의 일본어는 마크로스 대사를 외우시는 분들이 본다면,  쉽게 따라가면서 읽어 볼 수 있는 수준의 책입니다.  물론 책장에 한권 영어 말고 일본어 서적이 꽂혀 있으면 원서만 꽂아놓은 다른 분들 책장 보다 더~~~~욱 반짝이는 가오 효과를 볼 수 있다는 점도 장점입니다.


Posted by GUNDAM_IM
ASIC SoC2009.10.21 12:55

SystemC에서 Module을 생성할 때에 파라미터를 전달하는 방법이 가끔 필요합니다.

같은 모듈을 인스턴스로 생성시키지만, 특정 파라미터를 바꾸어서 동작을 틀리게 할 경우에 유용하게 사용할 수 있습니다.


이런 경우에 아래와 같이 구성하면 됩니다.


#if 0

SC_CTOR(AXI_TestMaster)  {

// main function

SC_CTHREAD(AXI_TM_entry,CLK.pos());

}//end of SC_CTOR

#else

SC_HAS_PROCESS(AXI_TestMaster);

AXI_TestMaster(sc_module_name nm, char * filename = "Default.tsq") : sc_module(nm) {

// main function

FileName = filename;

SC_CTHREAD(AXI_TM_entry,CLK.pos());

}

#endif


........
사용 예
      AXI_TestMaster AXI_TM0("TestMaster0.cfg");
      AXI_TestMaster AXI_TM1("TestMaster1.cfg");
      AXI_TestMaster AXI_TM2("TestMaster2.cfg");

각각의 모듈이 기본적인 동작은 같지만 운용 방법을 조금 씩 틀리게 할 경우 위와 같이 준비하여 두면 편리합니다.

이 방식에 대한 참고 사이트는 아래와 같습니다.

http://www.doulos.com/knowhow/systemc/faq/
 

Posted by GUNDAM_IM
ASIC SoC2009.09.25 09:26
SystemC언어로 설계하면 여러가지 편한점과 불편한 점이 있는데요
가장 불편한점은 누구 하나 속시원하게 해본적이 없다는 점입니다.

상위 수준 상위수준 하지만, 얼마 만큼의 상위수준까지가 합성이 되는지에 대해서 아직은 아는 사람이 없다는  부분이 또 걸리는 문제입니다. 결국 ERROR & TRY를 계속하면서 가는 수 밖에 없는 것 같습니다.


아직은 불편한 점도 많지만,
편한점은 몇가지 루틴만 이해하면 바로 설계에 들어갈 수 있다는 점이 장점입니다.

그런 점에서 보았을때 Typedef를 적절하게 이용하면 편리한 설계를 할 수 있습니다.
typedef + struct로 정의하는 것입니다. 이런 방식은 VHDL의 Record 타입과 비슷한 개념입니다.

몇가지 사항을 typedef로 정해서 진행하다 보면 쓸데 없는 오류에 봉착하는데요.. 아래에 그런 것에 대해서
한가지를 정리해 두었습니다.
진행하다가 더 나오면 그때 그때 정리하도록 하겠습니다.


SystemC에서 BUS는

sc_uint< bussize > busname;

으로 정의가 됩니다.

그런데 귀찮아서 이를 typedef로 정의하고 사용하면 에러가 발생합니다.

typedef sc_uint<32> tBUS_TYPE;

이라고 정의하고,

아래와 같이 함수에서 사용하면 에러가 발생합니다.

void classname::foo()
{
switch(BUS_TYPE)
{
....
.......
}
}


그래서

void classname::foo()
{

sc_uint<32> BUS_TYPE_int ;
BUS_TYPE_int = BUS_TYPE;

switch(BUS_TYPE_int)
{
case AHB :
....
case AXI  :
....
case WISHBONE :
....
}

}

위와 같이 로컬 변수로 받고 정의하면 에러가 없이 실행이 됩니다.
이것은 Signal로 선언되면 Signal Class로 다시 한번 상속되기 때문에,
container로 확장된 값과는 틀린 의미여서 switch로 사용할 수 없기 때문입니다.

좀더 직접적인 방법은 read() 메쏘드를 사용하는 것입니다.

switch(BUS_TYPE.read())
{
case AHB :
....
case AXI  :
....

이렇게 하면 후처리 작업이 필요 없이 정리할 수 있습니다.

Posted by GUNDAM_IM
ASIC SoC2009.08.26 05:57
SystemC에서는 3개의 Thread 모델링 방식을 제공하는데
어떤 것이 하드웨어적으로 맞는지에 대해서는 그 상황에 따라서 선택하는 것이 좋습니다.
하지만 합성을 목적으로 한다면, SystemC 합성 툴이 제시하는 문법에 따라서 정리하는 것이 나중에 번거롭게
두번 작업하지 않고 정리할 수 있습니다.

Forte에서 제공하는 자료에는 아래와 같은 형태를 권장하고 있습니다.
이해를 쉽게 하기 위한 그림이 아래와 같습니다.


사용자 삽입 이미지




위의 그림은 Verilog와 비교하여서 준비된 것입니다.
verilog와의 차이점은 verilog는 묵시적으로 내부에서 wait 구문이 존재하여서 always 블럭의 끝에 도달하면 wait 상태에 들어가는 것이 당연합니다. 하지만, CTHREAD에서는 wait()를 CTHREAD의 끝에서 명시해 두어야 합니다.
물론 그 중간에 넣어도 됩니다. 이런 경우 Multi Stage가 될 수 있습니다.

Posted by GUNDAM_IM
ASIC SoC2009.08.21 12:22
SystemC는 하드웨어 기술 언어입니다.

여러가지 장점과 단점이 있지만, 그런 부분에 대한 내용은 다른 자료를 참고하시면 됩니다.
공부하면서 정리하는 자료들입니다.

하드웨어와 일반 컴퓨터 언어의 가장 큰 차이점은 병렬성입니다.
일반 컴퓨터 언어는 순차적으로 프로그램이 진행되지만, 하드웨어 기술 언어는 일정 블럭 단위 혹은 라인단위로 병렬성을 가지고 실행합니다.

엄밀하게는 순차적으로 움직이지만, 잘 계산하여서 마치 병렬로 움직이는 것처럼 보이게 됩니다.

SystemC는 하드웨어의 병렬성을 모델링 하기 위해서 process  모델로 운용을 합니다.
시뮬레이션 커널은 이 프로세스 모델을 크게 나누어 아래와 같이 3가지 형태로 구분됩니다.

1. SC_THREAD


SC_THREAD(process_name);

SystemC 커널에 process_name 이라는 프로세스 함수를 SC_THREAD 형식으로 등록을 시킵니다.
이것은 시뮬레이션 커널에게 ,  THREAD 형태로 등록되도록 하여 주면, 이후 시뮬레이션이 시작되면 적당한 방법으로 실행하게 됩니다.

다만 다른 프로세스 모델과 틀린점은  아래와 같습니다.
 - 시뮬레이터에서 단 한번만 호출됩니다.
   따라서 지속적으로 운용하고 싶다면, 무한 루프를 만들어서 운용해야 합니다.
 - 함수로서 주고 받는 파라미터가 없습니다.
    즉 전달하는 파라미터나 리턴되는 값이 없이 함수 자체로만 존재합니다.
    이는 시뮬레이션 커널이 해당 쓰레드를 위한 함수를 등록하고 호출하기 위한 매커니즘을 단순하게 하기 위해서 준비된 규칙입니다.

SC_MODULE(onemethod) {
   sc_in<bool> in;
   sc_out<bool> out;

   void toggler(); /* Process a method of the class */

   SC_CTOR(onemethod) {
        SC_THREAD(toggler) ; /* Create an instance of the process */
        sensitive << in ;        /* Sensitive 리스트 */
   }
};

void onemethod::toggler() {
bool last = false;
for(;;) {
last = in ; out = last ; wait();
last = in ; out = last ; wait();
}
}


 2.SC_CTHREAD


 
SC_CTHREAD(process_name,clockname);
 
 SC_THREAD를 조금 확장한 버전입니다. C가 의미하는 것은 Clock을 의미합니다.
 즉 THREAD 버전은 한번만 호출된다는 것을 특징으로 하지만
 SC_CTHREAD로 등록되는 프로세스는 Clock의 이벤트 마다 호출된다는 점을 특징으로 합니다.

SC_MODULE(onemethod) {
   sc_in_clk clock;
   sc_in<bool> trigger,  in;
   sc_out<bool> out;

   void toggler(); /* Process a method of the class */

   SC_CTOR(onemethod) {
        SC_CTHREAD(toggler,clock.pos()) ; /* 사용할 클럭 에지와 함께 선언됩니다.*/
   }
};

void onemethod::toggler() {
bool last = false;
for ( ;; ) {
wait_until (trigger.delayed == true ) ;
last = in ; out = last ;
wait();
last = in ; out = last ;
wait();
}
}

 3. SC_METHOD


  SC_METHOD(process_name);

 Sensitive list에 등록된 인자들이 변할때 마다 호출됩니다. 하지만, 매 호출될때 마다 내부 값들이 보존되지 않고 새로 할당됩니다.

앞서의 2개의 프로세서와의 가장 큰 차이점은 내부에서 wait()를 쓸 수 없다는 점입니다.

SC_MODULE(onemethod) {
sc_in <bool> in;
sc_out <bool> out ;
void inverter ();

SC_CTOR(onemethod) {
SC_METHOD(inverter);
sensitive << in ;
}
};

void onemethod:: inverter()
{
bool internal;
internal = in;
out       = internal;
}

'ASIC SoC' 카테고리의 다른 글

SystemC : Thread 2nd  (0) 2009.08.26
GTKWave 를 OSX에서 구동하기  (0) 2009.08.24
SystemC : Thread  (0) 2009.08.21
Sound Engine Processor  (0) 2009.08.18
맥에서 SystemC 하기  (0) 2009.08.10
[5] 가장 작은 32비트 프로세서 ZPU 입니다  (0) 2009.07.28
Posted by GUNDAM_IM
ASIC SoC2009.08.10 21:39
맥에서 SystemC를 하는 것을 검토해 봅니다.

SystemC를 최근에 사용을 검토해보고 있습니다.

회로가 자꾸 커지고 있고, 설계해야 할 IP들중에서  간단한 것들은 이미 다 설계했기 때문에,
남은것은 무지 복잡하고  귀찮은  IP들만 남아 있습니다. 이런것들을  설계하고 검증하기 위해서는
기존 방식과는 다른 방법으로 접근해야 할 필요성이 있다고 생각되어서
검토를 합니다. 언제나 그렇듯이 중간에 때려칠수도 있습니다. 흐흐흐..

SystemC의 장단점은 뭐 이렇쿵 저렇쿵 할 필요 없이
다른곳에 있는  자료에서 많이 발견할 수 있어서 여기서는 생략합니다. (역쉬 퀴차니즘..)

라이브러리 컴파일 하기 (실패)


일단, 먼저 , 시작하기 전에  맥에서 사용하는 것은 조금 난망한 일이 될뻔 했습니다.
systemc.org에서 필요한 라이브러리를 다운받아서 컴파일을 시도했습니다.
그런데  그동안 웬만한 라이브러리는 다 컴파일이 되었는데 이넘은 컴파일 하면서 계속 오류가 발생합니다.
이리저리 컴파일해서 진행하는데 손볼데가 의외로 많이 발생해서, 하다가 에잉.. 하고 포기하기로 하였습니다. 웬지 바보같고, 검토만 하면 될일이이서, 여기서는 컴파일하는 것을 포기하고 다른 분들이 컴파일한것을 찾아서 사용하기로 했습니다.

그런데 재미있는것이 발견되었습니다.

http://www.logicpoet.com/

이 회사는 (정확하게는 회사인지 불명확하지만...) 맥용 SystemC Lib과 XCode에서 컴파일 하는 컴파일 슈트를 배포하고 있습니다. 다운 받아서 설치하면 그걸로 끝입니다.

그리고 Scansion 이라고 하는 맥용 Wave form viewer를 제공하고 있습니다.
오픈된 버전은 크기의 제한을 가지지만 $100 정도만 내면 크기에 제한이 없는 버전을 사용할 수 있습니다.리눅스로 들어가지 않아도 되는 솔루션을 파는것입니다.

$100이면 요새 많이 질러서 아주 많이 궁한 저로서는 조금 구매하기가 벅찬 금액이어서..
일단 시험버전을 가지고 어느정도 까지 사용해보고 좋으면 구매하는 것으로 생각하였습니다.
(오늘 확인해 보니 $49로 내려갔네요.. 아직 버그가 있어서 그런듯합니다.
 가격을 내렸다는 이야긴 업데이트를 않한다는 이야기로 들립니다.
 업데이트 되는 것을 봐서 구매하도록 해야 하겠습니다.)

아래 그림은 해당 프로그램 그림입니다.
나름 편리하니 사용하면 좋을듯 합니다.

사용자 삽입 이미지
일단 이것으로 사용하면 됩니다.

그리고 같은 페이지에서 제공하는
SystemC Suite를 설치하면 XCode에서 SystemC 코드를 컴파일하는 것이 가능합니다.



사용자 삽입 이미지

위의 그림은 XCOde에서 SystemC프로젝트를 선택하는 것입니다.

사용자 삽입 이미지

프로젝트 이름을 지정하는 과정입니다.

사용자 삽입 이미지
생성된 프로젝트입니다.
라이브러리와 메인 코드 파일을 포함하고 있습니다.

그대로 빌드하여서 실행하면 다음과 같은 창을 얻을 수 있습니다.

사용자 삽입 이미지

제대로 된 컴파일은 다음 기회에 하기로 하고 여기서는 이정도로 마무리하겠습니다.

그리고 Scansion은


WAVE Viewer인 Scansion은 VCD파일만 읽어들일 수 있습니다.
그리고  아직 완성된 버전이 아니라 조금씩 버그가 눈에 띄고 있습니다.
시간이 많이.. 되어야 버그가 좀 고쳐질 것 같습니다.
그래도 맥에서 Wave를 볼 수 있는 거의 유일한 프로그램이라서 좋습니다.
 

Posted by GUNDAM_IM