FC2カウンター FPGAの部屋 2023年03月27日
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vitis アクセラレーション・プラットホームを使用してハードウェアを作り、それを自作アプリケーション・ソフトウェアで動作させる7

Vitis アクセラレーション・プラットホームを使用してハードウェアを作り、それを自作アプリケーション・ソフトウェアで動作させる6”の続き。

Vitis アクセラレーション・プラットホームを使用してハードウェアを完成させ、それを自作アプリケーション・ソフトウェアで動作させてみたいということで、前回は、pl.dtsi の krnl_vadd セクションを最小限にして、コンパイルし、Petalinux に転送して、ロードしたところ、krnl_vadd が uio8 として実装できた。今回は、uio ドライバを使用して、multi_axi4ls IP と DMA_pow2 IP、krnl_vadd IP を使用するアプリケーション・ソフトウェアを作成し、動作を確認した。

KR260 の Petalinux 2022.1 の ~/kr260_ip_vadd2 ディレクトリに アプリケーション・ソフトウェアの kr260_ip_vadd2.c を作成した。
KR260_419_230326.png

KR260_420_230326.png

kr260_ip_vadd2.c のコードを示す。

// kr260_ip_vadd2.c
// 2023/03/26 by marsee

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>

int32_t multi_calc(int32_t *multi_axi4ls, int32_t a, int32_t b){
    while((multi_axi4ls[0] &4) == 0) ; // wait ap_idle
    multi_axi4ls[6] = a; // reg a, 0x18
    multi_axi4ls[8] = b; // reg b, 0x20
    multi_axi4ls[0] = 1; // ap_start = 1
    while((multi_axi4ls[11] & 1) == 0) ; // wait c_ap_vld
    return(multi_axi4ls[10]);
}

void main(){
    int uio9_fd;
    int32_t *multi_axi4ls;
    int32_t a, b, c;
    int uio4_fd;
    volatile int32_t *dma_pow2;
    volatile int32_t *data;
    int fd_udmabuf0;
    u_int32_t fd_paddr;
    unsigned long  phys_addr;
    int uio8_fd;
    int32_t *krnl_vadd;
    unsigned char  attr[1024];

    // uio9, multi_axi4ls IP
    if((uio9_fd = open("/dev/uio9", O_RDWR)) == -1) {
        printf("Can not open /dev/uio9\n");
        exit(1);
    }
    multi_axi4ls = (uint32_t*)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, uio9_fd, 0);
    
    printf("multi_axi4ls\n");
    for(a = 0, b = 1; a < 10; a++, b++){
        c = multi_calc(multi_axi4ls, a, b);
        printf("a = %d, b = %d, c = %d\n", a, b, c);
    }

    // uio4, DMP_pow2 IP
    if((uio4_fd = open("/dev/uio4", O_RDWR)) == -1) {
        printf("Can not open /dev/uio4\n");
        exit(1);
    }
    dma_pow2 = (volatile int32_t*)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, uio4_fd, 0);
    
    // udmabuf0
    fd_udmabuf0 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled. 
    if (fd_udmabuf0 == -1){
        fprintf(stderr, "/dev/udmabuf0 open errorn");
        exit(-1);
    }

    // phys_addr of udmabuf0
    fd_paddr = open("/sys/class/u-dma-buf/udmabuf0/phys_addr", O_RDONLY);
    if (fd_paddr == -1){
        fprintf(stderr, "/sys/class/u-dma-buf/udmabuf0/phys_addr open errorn");
        exit(-1);
    }
    read(fd_paddr, (void *)attr, 1024);
    sscanf((const char *)attr, "%lx", &phys_addr);  
    close(fd_paddr);
    printf("phys_addr = %x\n", (unsigned int)phys_addr);
  
    data = (volatile int32_t *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd_udmabuf0, 0);
    if (data == MAP_FAILED){
        fprintf(stderr, "data mmap error\n");
        exit(-1);
    }

    // data Initialization
    for(int i=0; i<10; i++){
        data[i] = i;
    }
    
    // DMA_pow2 start
    while((dma_pow2[0] & 4) == 0) ; // wait ap_idle
    dma_pow2[6] = phys_addr; // in_r
    dma_pow2[8] = phys_addr + 10 * sizeof(int32_t);
    dma_pow2[0] = 1; // ap_start
    while((dma_pow2[0] & 2) == 0) ; // wait ap_done
    
    printf("\n DMA_pow2\n");
    for(int i=0; i<10; i++){
        printf("in = %d, out = %d\n", data[i], data[i+10]);
    }

    // uio8, krnl_vadd IP
    if((uio8_fd = open("/dev/uio8", O_RDWR)) == -1) {
        printf("Can not open /dev/uio8\n");
        exit(1);
    }
    krnl_vadd = (uint32_t*)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, uio8_fd, 0);

    for(int i=0; i<10; i++){
        data[i+20] = i;
        data[i+30] = i+1;
    }

    // krnl_vadd start
    while((krnl_vadd[0] & 4) == 0) ; // wait ap_idle
    krnl_vadd[4] = (uint32_t)((phys_addr + 20 * sizeof(int32_t))&0xffffffff); // in1
    krnl_vadd[5] = (uint32_t)(((phys_addr + 20 * sizeof(int32_t))&0xffffffff00000000)>>32); // in1
    krnl_vadd[7] = (uint32_t)((phys_addr + 30 * sizeof(int32_t))&0xffffffff); // in2
    krnl_vadd[8] = (uint32_t)(((phys_addr + 30 * sizeof(int32_t))&0xffffffff00000000)>>32); // in2
    krnl_vadd[10] = (uint32_t)((phys_addr + 40 * sizeof(int32_t))&0xffffffff); // out_r
    krnl_vadd[11] = (uint32_t)(((phys_addr + 30 * sizeof(int32_t))&0xffffffff00000000)>>32); // out_r
    krnl_vadd[13] = 10; // size
    krnl_vadd[0] = 1; // ap_start
    while((krnl_vadd[0] & 2) == 0) ; // wait ap_done
   
    printf("\nkrnl_vadd\n");
    for(int i=0; i<10; i++){
       printf("in1 = %d, in2 = %d, out_r = %d\n", data[i+20], data[i+30], data[i+40]);
    }
}


kr260_ip_vadd2.c をコンパイルした。
kr260_ip_vadd 実行ファイルが生成された。
gcc -o kr260_ip_vadd2 kr260_ip_vadd2.c
ログを示す。

xilinx-kr260-starterkit-20221:~/kr260_ip_vadd2$ gcc -o kr260_ip_vadd2 kr260_ip_vadd2.c
kr260_ip_vadd2.c: In function 'main':
kr260_ip_vadd2.c:66:5: warning: implicit declaration of function 'read'; did you mean 'fread'? [-Wimplicit-function-declaration]
   66 |     read(fd_paddr, (void *)attr, 1024);
      |     ^~~~
      |     fread
kr260_ip_vadd2.c:68:5: warning: implicit declaration of function 'close'; did you mean 'pclose'? [-Wimplicit-function-declaration]
   68 |     close(fd_paddr);
      |     ^~~~~
      |     pclose


u-dma-buf.ko をロードし、kr260_ip_vadd2 ディレクトリに移動する。
現在、ロードされているアクセラレーション・アプリケーションをアンロードして、kr260_ip_vadd をロードする。
/dev/uio* と /dev/udmabuf0 をユーザー書き込み可能モードにした。
kr260_ip_vadd を動作させたところ成功した。
cd
sudo insmod u-dma-buf.ko udmabuf0=0x10000
cd kr260_ip_vadd2
sudo xmutil unloadapp
sudo xmutil loadapp kr260_ip_vadd2
sudo chmod 666 /dev/uio*
sudo chmod 666 /dev/udmabuf0
./kr260_ip_vadd2

KR260_417_230326.png

KR260_418_230326.png

これで、Vitis アクセラレーション・プラットホームを使用してハードウェアを完成させ、それを自作アプリケーション・ソフトウェアで動作させることができた。
空のホスト・アプリケーション・ソフトウェアとアクセラレーション・カーネルの krnl_vadd を使って、ハードウェアを完成させて、ハードウェア・プラットホーム上の multi_axi4ls IP と DMA_pow2 IP を動作させながら krnl_vadd も自作アプリケーション・ソフトウェアで動作させることができた。
  1. 2023年03月27日 04:11 |
  2. KR260
  3. | トラックバック:0
  4. | コメント:0