Category Archives: verification

Related on SoC & IP verification method.

PLI에서 TCP/IP를 통해서 통신하고, perl server에서 처리하기

예전에 PLI에서 윈도우 제어 하려고 별짓을 다했었는데, 그 중에 PLI에서 TK 윈도우를 바로 부른 것도 있었습니다. PLI에서 TK를 부르는(C-TK interwork을 이용한) 방법은 TK 스크립을 거의 직접 쓸 수 있다는 점에서 편리하긴 한데, NCVerilog에서 너무 버전을 심하게 탄다는 단점(TK의 버전도 맞춰 줘야 합니다. -_-;)이 있어서 환경이 바뀌면서 잘 안쓰게 되더군요.

게다가 시뮬레이션 돌리면서 이런 저런것을 실시간 출력할때 UNIX/Linux/Windows 안가리는 인터페이스를 고민하다보니, TCP/IP와 Perl 만한게 없더군요. Simulator에서 이런 저런 GUI 부분이 귀찮아서 socket 기반으로 만들었던 기억을 되살려 하나 만들어봤습니다. PLI에서 TCP/IP 패킷을 전송하는 부분을 하나 만들어봤습니다.

#include 
#include <"arpa/inet.h">
#include <"net/netinet.h">
#include <"sys/socket.h">
#include <"sys/types.h"> #include "vpi_user.h"

#define DEST_IP "127.0.0.1"
#define DEST_PORT 7890

static struct sockaddr_in dest_addr;

static int count = 0;
static int sockfd;
int counta;

PLI_INT32 cosim_hello_calltf(PLI_BYTE8 *userdata) {
        char buf[1024];
        s_vpi_time ctime;
        ctime.type = vpiScaledRealTime;
        vpi_get_time(NULL, &ctime);
        vpi_printf("[%2.2f] Hello VPI: %d, %d\n", ctime.real, count, counta);
        sprintf(buf, "\n##[%2.2f] Hello VPI: %d, %d\n", ctime.real, count, counta);
        send(sockfd, &buf, sizeof(buf), 0);

        count++;
        counta++;
        return(0);
}

PLI_INT32 cosim_hello_init() {
        int len, result;
        counta = 100;
        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(DEST_PORT);
        dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);

        len = sizeof(dest_addr);
        result = connect(sockfd, (struct sockaddr *)&dest_addr, len);

        if (result == -1) {
                fprintf(stderr, "socket open error\n");
                exit(1);
        }

        return(0);
}

void cosim_register_hello() {
        s_vpi_systf_data tf_data;
        tf_data.type = vpiSysTask; // make as task
        tf_data.sysfunctype = 0;
        tf_data.tfname = "$cosim_hello";
        tf_data.calltf = cosim_hello_calltf;
        tf_data.compiletf = cosim_hello_init;
        tf_data.sizetf = NULL;
        tf_data.user_data = NULL;
        vpi_register_systf(&tf_data);
}

void (*vlog_startup_routines[])() = {cosim_register_hello, 0}


별 내용은 없고, 그냥 verilog code에서 cosim_hello()를 호출하면 loop돌면서 값을 출력하는 예제입니다.

 

이 코드 틀은 다이나릿의 기안도 박사님 IDEC 강좌 자료에 있는 “HW/SW 동시 협조 시뮬레이션”이란 강좌의 첫번째 PLI 예제에서 따왔으며, 저는 이 함수에 TCP/IP 전송이 가능하도록 수정하였습니다.

컴파일은 다음과 같이 일반적인 NCVerilog 컴파일과 다르지 않지요. (Windows에서 Modelsim 사용하시는 분은 gcc보다는 visual c++의 cl 을 사용하시는 것이 속 편합니다. MingW 버전의 gcc가 되기는 하는데, Modelsim에서 버전을 상당히 심하게 탔던 것으로 기억됩니다. 요즘 버전은 어떨지 모르겠습니다만. )

 

$gcc -I$CDS_HOME/tools/inca/include -c cosim_hello.c
$ld -shared -o cosim.so cosim_hello.o

NCVerilog Compile & Elaboration

 

$ ncvlog -work worklib test_hello.v
$ ncelab worklib.test_hello -loadvpi ./cosim:cosim_register_hello
$ ncsim worklib.test_hello


이런 식으로 사용하면 되는데, 위의 패킷을 받아줄 서버는 간단히 perl로 짜주면 됩니다. Perl-TK로 GUI를 작성하는 것도 가능하구요.

이때 한가지 주의해야 할 점은 perl의 IO::INET 의 accept() 함수가 blocking type이기 때문에 이것을 non-blocking type으로 해 주시고 loop을 돌려야지만 DoOneEvent() 함수가 정상적으로 수행된다는 점이지요.
(설마 MainLoop()로 돌리실 분은 없을 테니 ^^;) 저도 처음엔 DoOneEvent함수가 좀처럼 동작을 안하는 것처럼 느껴져서 헤맸습니다. 결론은 accept()함수 문제더군요.

perl 함수의 주요 부분만간단히 정리하자면(예제를 위해서 perl script를 하나 더 만들기가 귀찮고, 전체 내용은 회사 작업이라 공개할 수 없고.. 라는 어려움 때문에 별로 문제 안되는 부분만 올립니다. )


use strict;
use IO::Socket;
use Tk;
use encoding 'utf-8';    # 한글 쓰시려면..
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);

my $portnum = 7890;

# make a socket

my $mw = MainWindow->new(-title=>"Terminal");

.....

my $sock = IO::Socket::INET->new(
                LocalHost => 'localhost',
                LocalPort => $portnum,
                Proto => 'tcp',
                Listen => 10, # SOMAXCONN 으로 해도 됩니다.
                Reuse => 1,
                TimeOut => 1,
                );

....
my($new_sock, $c_addr, $buf, $flag);
...

# NonBlocking으로 만듭시다.
$flag = fcntl($sock, F_GETFL, 0) or die "Can not get flag: $!\n";
$flag = fcntl($sock, F_SETFL, $flag | O_NONBLOCK) or die "Can not set flag: $!\n";

while(1) {
        while (($new_sock, $c_addr) = $sock->accept()) {
                ... 소켓에서 읽어서 일하세요....
                        DoOneEvent(0);
        }

 

요런 식이라는 것이지요. 중간 중간에 엄청 생략되어 있음은 유의하세요..

Open Verification Library 간단하게..

OVL(Open Verification Library)은 상당히 오래전부터 보아왔던 assertion library인데요. 제 기억이 맞다면 거의 최초의 ABV(assertionbased verification)쪽 라이브러리가 아닌가 기억됩니다. Foster라는 분이 박사 논문으로 작성한 것이, 발전을 거듭해서 ABV라는 것까지 발전한 것으로 기억되는데, 정확한 사실인지는 찾아보지 않고 기억에 의존한 것이라 틀릴 수도 있습니다. 여하튼 OVL의 출발은 상당히 오래된 거죠 ^^;

ABV에서 어찌보면 가장 보편적이었던 표준은 PSL/Sugar인데, 요즘엔 System Verilog Assertion(이후 SVA)이후에 PSL은 개화하지도 못하고 SVA쪽으로 편입되는 느낌이긴 합니다. OVL도 예전에 verilog HDL의 라이브러리의 형태로 출발한 것이 http://www.accellera.org/의 표준으로 채택되고, 여기에 SVA, PSL porting이 추가되면서 여러가지 형태를 가지고 가고 있습니다.

OVL의 가장 큰 장점은 특정 assertion 기반 언어를 사용한 것이 아니라 verilog HDL 기반이기 때문에 특정 assertion 언어를 지원하지 않는 일반적인 HDL시뮬레이터에서 다 사용할 수 있다는 것이겠습니다(앞에 설명드렸다시피 SVA, PSL port를 지원할 수도 있으니 일반론이라 볼 수는 없고, OVL2.0으로 오면서 SVA쪽에 무게를 두고 multiple fifo에 대한 관련 문법 때문에 더이상 무조건 Verilog HDL기반이라 이야기하는 건 힘들게 되었습니다만.. 이 글에서는 일단 제가 알고 있는 범위인 OVL 1.x버전대로 한정하지요..) 예전에 System Verilog 기반으로 이런 저런거 해 보려다가 tool의 라이센스가 대부분의 SystemVerilog의 verification feature부분을 사용하기 위해서(queue라던지, fifo model이라던지..하는 ) 추가적으로 돈을 지불해야 하는 방식이라 못쓰고 있다는 이야기를 드렸는데, OVL은 assertion에 있어서는 뭐 강력하지도 않지만, 추가적으로 돈이 들지 않는다는 건 장점이에요.

OVL을 요즘에 다시 관심을 가지게 된 이유는 ARM에서 AXI Protocol Checker라는 것을 배포하고 있는데, 이넘이 OVL 1.x 기반의 assertion 문법을 사용하고 있기 때문입니다. ARM에서 이런 기특한 일을 할때도 있군요. 나름 다양한 문법과 설정을 할 수 있도록 작성된 protocol checker이기 때문에, 예전에 추상적으로 알고 있던 몇몇 assertion 관련 문법을 좀더 정확히 알 수 있는 좋은 예제였습니다.

관심있으신 분은 한번 설치해서 AxiPC를 구동시켜 보실 것을 권장합니다. AXI 시스템이 있으시다면, 주욱 돌려 보면서 protocol을 잘못 이해해서 잘못 작성한 부분이 있는지 확인하는 데 도움을 줄 것이고, AxiPC 자체에 혹은 AXI 프로토콜에 관심이 있으시다면 , AXI dummy slave나 AXI protocol generator 같은건 간단하게 만들어서 프로토콜의 발생에 따른 에러 발생 여부를 확인하면 되니 생각보다 활용도가 좀 있습니다.

AXI protocol checker는 ARM 사의 홈페이지에서, OVL은 accellera의 OVL페이지에서 각각 다운 받을 수 있습니다. (verilog mode로 사용할때는 +define+OVL_VERILOG 를 쓰셔야 하심을 잊지 마세요)


Technorati : , , ,

Cygwin에서의 printer port 제어

별 다른 내용은 아닙니다만, 기억해두기 위해서 적습니다.

JTAG을 이용한 디버거를 만들고, PC상에서 테스트 하는데 소프트웨어 팀에서 만든 비주얼 스튜디오 기반의 프로그램은 제가 고칠수가 없어서(VS 라이센스가 한정되어 있다보니..), cygwin상에서 간단하게 제어하는 프로그램을 만들게 되었습니다.

제가 알기로는 linux의 경우 /port/prn 을 이용해서 간단하게 printer port를 제어할 수 있었던 것으로 기억합니다만(물론, permio같은 것을 써야 겠습니다만..), cygwin에서는 이 방법은 안되더군요.

그래서, 어쩔수 없이 giveio라는 범용 device driver를 하나 올리고, 이걸 통해서 cygwin에서 제어하는 방법을 사용했습니다. 항상 그렇지만, 중요한 부분(말하자면, 제가 기억하고 있어야 하는 부분 ^^)은 cygwin에서 windows 라이브러리(windows API)를 포함시켜서, 다른 것에서와 거의 동일하게 windows용 device driver를 연결하면 된다는 것이지요..  그 부분은 아래와 같습니다.