FC2カウンター FPGAの部屋 Ultra96 ボードでデバイスツリー・オーバーレイをテストする5
fc2ブログ

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

FPGAの部屋

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

Ultra96 ボードでデバイスツリー・オーバーレイをテストする5

Ultra96 ボードでデバイスツリー・オーバーレイをテストする4”の続き。

前回は「アプリケーション・ソフトを作成して、起動したところSegmentation fault になってしまって困っている。uio にデータを書き込むところでSegmentation fault になっているようだ。」ということだった。今回はSegmentation fault を克服するべく頑張った。ハードウェアではなく、ソフトウェアそれもVivado HLSのドライバに問題があったようだ。

いろいろと ikwzm さんに教えていただいてやってみた。ありがとうございました。
まずは、Vivado 2018.2 の DMA_pow2_test のブロック・デザインで、レジスタ設定用のAXIポートを変更したりした。それでも、うまく行かないので、ikwzm さんの”ZynqMP-FPGA-Linux Example (2) for Ultra96”をやってみることにした。

negative.bin を/lib/firmware にコピーして、FPGA のビットストリームをロードし、fclkをデバイスツリー・オーバーレイで変更して、uio と udmabuf をデバイスツリー・オーバーレイで生成した。

sudo python3 negative.py
を実行すると成功した。
Ultra96_ikwzm_95_181029.png

次に、Vivado HLS のドライバを使用して、C でアプリケーション・ソフトを書いた。
Ultra96_ikwzm_96_181029.png

その、negative_test.c を示す。

// negative_test.c
// 2018/10/28 by marsee

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#include "xnegative.h"

int main(){
    XNegative xnegative_ap;
    volatile unsigned int *udmabuf4_buf;
    int udmabuf4_fd, fd_phys_addr;
    char  attr[1024];
    unsigned long  phys_addr;
    int Xneg_status;
    int i;
    
    // udmabuf4
    udmabuf4_fd = open("/dev/udmabuf4", O_RDWR); // frame_buffer, The chache is enabled. 
    if (udmabuf4_fd == -1){
        fprintf(stderr, "/dev/udmabuf4 open error\n");
        exit(-1);
    }
    udmabuf4_buf = (volatile unsigned int *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, udmabuf4_fd, 0);
    if (!udmabuf4_buf){
        fprintf(stderr, "udmabuf4_buf mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf4
    fd_phys_addr = open("/sys/class/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd_phys_addr == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf4/phys_addr open error\n");
        exit(-1);
    }
    read(fd_phys_addr, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd_phys_addr);
    printf("phys_addr = %x\n", (int)phys_addr);

    printf("1"); fflush(stdout);
    // data set
    for(i=0; i<10; i++){
        udmabuf4_buf[i] = i;
    }
    printf("1"); fflush(stdout);
        
    Xneg_status = XNegative_Initialize(&xnegative_ap, "negative-uio");
    if (Xneg_status != XST_SUCCESS){
        fprintf(stderr, "Could not Initialize XNegative\n");
        return(-1);
    }
    printf("1"); fflush(stdout);
    
    XNegative_Set_in_r(&xnegative_ap, phys_addr);
    printf("1"); fflush(stdout);
    XNegative_Set_out_r(&xnegative_ap, (phys_addr+10*sizeof(int)));
    printf("1"); fflush(stdout);
    XNegative_Set_size(&xnegative_ap, (u32)10);

    printf("1"); fflush(stdout);
    XNegative_Start(&xnegative_ap);
    printf("1"); fflush(stdout);
    
    while(!XNegative_IsDone(&xnegative_ap));

    for(i=0; i<10; i++){
        printf("data[%d] = %d, result[%d] = %d\n", i, udmabuf4_buf[i], i, udmabuf4_buf[10+i]);
    }

    return(0);
}


コンパイルして、起動したところ Segmentation fault になってしまった。ikwzm さんのPython コードは問題なく動作しているので、これは、ハードウェアの問題ではなくソフトウェアの問題だということがわかった。
Ultra96_ikwzm_98_181029.png

次に、Vivado HLS のドライバを使用しない C のソースコードを書いてみた。negative_test2.c だ。
Ultra96_ikwzm_97_181029.png

negative_test2.c を示す。

// negative_test2.c
// 2018/10/28 by marsee
//

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

int main(){
    volatile unsigned int *udmabuf4_buf;
    int udmabuf4_fd, fd_phys_addr;
    char  attr[1024];
    unsigned long  phys_addr;
    int fd1;
    volatile unsigned int *negative;
    int i;
    
    // udmabuf4
    udmabuf4_fd = open("/dev/udmabuf4", O_RDWR|O_SYNC); // frame_buffer, The chache is enabled. 
    if (udmabuf4_fd == -1){
        fprintf(stderr, "/dev/udmabuf4 open error\n");
        exit(-1);
    }
    udmabuf4_buf = (volatile unsigned int *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, udmabuf4_fd, 0);
    if (!udmabuf4_buf){
        fprintf(stderr, "udmabuf4_buf mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf4
    fd_phys_addr = open("/sys/class/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd_phys_addr == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf4/phys_addr open error\n");
        exit(-1);
    }
    read(fd_phys_addr, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd_phys_addr);
    printf("phys_addr = %x\n", (int)phys_addr);

    // data set
    for(i=0; i<10; i++){
        udmabuf4_buf[i] = i;
    }

    // uio initialize (uio1)
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // negative IP
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (negative) open error\n");
        exit(1);
    }
    negative = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!negative){
        fprintf(stderr, "negative mmap error\n");
        exit(1);
    }
    
    negative[6] = phys_addr; // Data signal of in_r
    negative[8] = phys_addr+10*sizeof(int); // Data signal of out_r
    negative[10] = 10; // Data signal of size
    
    negative[0] = 1; // ap_start
    
    while (!(negative[0] & 0x2)) ; // ap_done ?
    
    for(i=0; i<10; i++){
        printf("data[%d] = %d, result[%d] = %d\n", i, udmabuf4_buf[i], i, udmabuf4_buf[10+i]);
    }
    
    munmap((void *)negative, 0x10000);
    close(fd1);
    munmap((void *)udmabuf4_buf, 0x1000);
    close(udmabuf4_fd);
    
    return(0);
}


negative_test2.c をコンパイルして実行したところ、成功した。なお、ikwzm さんの”ZynqMP-FPGA-Linux Example (2) for Ultra96”のZynq UltraScale+ MPSoC のAXI4 Master 用のポートは S_AXI_HP0_FPD を使用していてキャッシュに書けるポートを使用してない。よって、udmabuf をキャッシュOFF モードにするため、udmabuf4 をオープンするときのオプションに O_SYNC を加えている。
Ultra96_ikwzm_99_181029.png

これで成功したということは、Vivado HLS のドライバの関数を使用するとSegmentation fault になるということだ。Vivado HLS のドライバが原因だったようだ。

さて、自分の 2 乗IP に戻ろう。
Vivado 2018.2 のブロック・デザインを示す。最初のブロック・デザイン同様に、Zynq UltraScale+ MPSoC のレジスタ設定用のポートは M_AXI_HPM0_FPD を使用した。なお、Ultra96 のボードファイルはUltra96v1 1.2 を使用している。
Ultra96_ikwzm_100_181029.png

なお、DMP_pow2 IP のPROT value は "010" に、CACHE value は "1111" に設定してある。
Ultra96_ikwzm_44_181020.png

Vivado HLS のドライバを使用しない DMA_pow2_test2.c を作成した。
Ultra96_ikwzm_103_181029.png

DMA_pow2_test2.c を示す。

// DMA_pow2_test2.c
// 2018/10/28 by marsee
//

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

int main(){
    volatile unsigned int *udmabuf4_buf;
    int udmabuf4_fd, fd_phys_addr;
    char  attr[1024];
    unsigned long  phys_addr;
    int fd1;
    volatile unsigned int *dma_pow2;
    int i;
    
    // udmabuf4
    udmabuf4_fd = open("/dev/udmabuf4", O_RDWR); // frame_buffer, The chache is enabled. 
    if (udmabuf4_fd == -1){
        fprintf(stderr, "/dev/udmabuf4 open error\n");
        exit(-1);
    }
    udmabuf4_buf = (volatile unsigned int *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, udmabuf4_fd, 0);
    if (!udmabuf4_buf){
        fprintf(stderr, "udmabuf4_buf mmap error\n");
        exit(-1);
    }

    // phys_addr of udmabuf4
    fd_phys_addr = open("/sys/class/udmabuf/udmabuf4/phys_addr", O_RDONLY);
    if (fd_phys_addr == -1){
        fprintf(stderr, "/sys/class/udmabuf/udmabuf4/phys_addr open error\n");
        exit(-1);
    }
    read(fd_phys_addr, attr, 1024);
    sscanf(attr, "%lx", &phys_addr);  
    close(fd_phys_addr);
    printf("phys_addr = %x\n", (int)phys_addr);

    // data set
    for(i=0; i<20; i++){
        udmabuf4_buf[i] = i;
    }

    // uio initialize (uio1)
    fd1 = open("/dev/uio1", O_RDWR|O_SYNC); // dma_pow2 IP
    if (fd1 < 1){
        fprintf(stderr, "/dev/uio1 (dma_pow2) open error\n");
        exit(1);
    }
    dma_pow2 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    if (!dma_pow2){
        fprintf(stderr, "dma_pow2 mmap error\n");
        exit(1);
    }
    printf("Address of int size is %d\n", sizeof(int *));
    
    dma_pow2[6] = phys_addr; // Data signal of in_r
    dma_pow2[8] = phys_addr+10*sizeof(int); // Data signal of out_r
    
    dma_pow2[0] = 1; // ap_start
    
    while (!(dma_pow2[0] & 0x2)) ; // ap_done ?
    
    for(i=0; i<10; i++){
        printf("data[%d] = %d, result[%d] = %d\n", i, udmabuf4_buf[i], i, udmabuf4_buf[10+i]);
    }
    
    munmap((void *)dma_pow2, 0x10000);
    close(fd1);
    munmap((void *)udmabuf4_buf, 0x1000);
    close(udmabuf4_fd);
    
    return(0);
}


デバイスツリー・オーバーレイを行って、コンパイルした DMA_pow2_test2 を実行したところ実行できたのだが、値が合わない。
これは、ikwzm さんの”ZynqMP-FPGA-Linux Example (2) for Ultra96”では、boot.bin に regs.init が入っていないので、M_AXI_HPM0_FPD でキャッシュに書けなかったためだった。(ikwzm さんの”UltraZed 向け Debian GNU/Linux で AXI HPC port を使う (基礎編)”の”boot.bin による設定”を参照)

自分で作った boot.bin に regs.init を入れたので、これをSDカードの第1パーティションのULTRA96_BOO に書いた。
Ultra96_ikwzm_102_181029.png

そして、Debian をブートしてから、もう一度、DMA_pow2_test2 を実行したところ、(当然、前準備は実行している)成功した。
Ultra96_ikwzm_101_181029.png

やっとうまく行って、本当に良かった。
つまり、Vivado HLS のドライバは、Zynq UltraScale+ MPSoC では使い物にならないんじゃないかな?
やたらと u32 使っているし、DMA_pow2_test2 の実行結果でも分かるように int * のサイズは 8 バイトだったので、アドレスは 64 ビットになっているはずだ。。。
  1. 2018年10月29日 05:01 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/4340-834bc340
この記事にトラックバックする(FC2ブログユーザー)