FC2カウンター FPGAの部屋 AXI4-Stream Switcher IP の製作1(CPP ソースコードの公開)

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

FPGAの部屋

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

AXI4-Stream Switcher IP の製作1(CPP ソースコードの公開)

AXI4-Stream Switcher IP の製作を行う。
AXI4-Stream Switcher IP は、”AXI4-Stream版ラプラシアンフィルタIPのカメラ表示システム1(構想編)”のブロック図に示してあるが、ラプラシアンフィルタを通した画像データのAXI4-Steram とカメラの画像データのAXI4-Steram を切り替える。

AXI4-Stream Switcher IP は、Vivado HLS 2014.4 で作製する。

まずは、ZYBO用 (xc7z010clg400-1)のVivado HLS 2014.4 の axis_switcher_2014_4 プロジェクトを作製した。

Source に、axis_switcher.cpp と axis_switcher.h を Add Source した。

Test Bench に axis_switcher_tb.cpp を Add Source した。

下に Vivado HLS 2014.4 のプロジェクトを示す。下の図はIP化まで終わった状態だ。
今回は、テストベンチを作るのに手間取ってしまった。
AXI4_Stream_Switcher_1_150515.png

下に、axis_switcher.cpp を示す。

//
// axis_switcher.cpp
// 2015/05/14
// by marsee
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "axis_switcher.h"

int axis_switcher(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1, 
    hls::stream<ap_axis<32,1,1,1> >& outs, int select) {
#pragma HLS INTERFACE axis port=ins0
#pragma HLS INTERFACE axis port=ins1
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=select bundle=BUS_AXI4LS
#pragma HLS INTERFACE s_axilite port=return bundle=BUS_AXI4LS
#pragma HLS INTERFACE ap_none port=select

    ap_axis<32,1,1,1> pix;

    do {    // user が 1になった時にフレームがスタートする
        if (select == 0){
            ins0 >> pix;
        } else{
            ins1 >> pix;
        }
    } while(pix.user == 0);

    for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
            if (!(x==0 && y==0)){    // 最初の入力はすでに入力されている
                if (select == 0){
                    ins0 >> pix;
                } else{
                    ins1 >> pix;
                }
            }

            outs << pix;    // AXI4-Stream へ出力
        }
    }

    return 1;
}


次に、axis_switcher.h を示す。現在はHDL Simulation 用の小さい値にしている。

//
// axis_switcher.h
// 2015/05/14
// by marsee
//

// #define HORIZONTAL_PIXEL_WIDTH 800
// #define VERTICAL_PIXEL_WIDTH 600

#define HORIZONTAL_PIXEL_WIDTH 20
#define VERTICAL_PIXEL_WIDTH 5

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)


最後に、テストベンチの axis_switcher_tb.cpp を下に示す。

//
// axis_switcher_tb.cpp
// 2015/05/14
// by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>

#include "axis_switcher.h"

int axis_switcher(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1, 
    hls::stream<ap_axis<32,1,1,1> >& outs, int select);

#define CLOCK_PERIOD 10

int main() {
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins0;
    hls::stream<ap_axis<32,1,1,1> > ins1;
    hls::stream<ap_axis<32,1,1,1> > outs;

    ap_axis<32,1,1,1> pix0, pix1;
    ap_axis<32,1,1,1> vals;
 
    int m_seq = 1// M系列の値
    int i;
    int xor_shift;
    int rect_wave;
    int select;

    for(int i=0; i<5; i++){ // dummy data
        pix0.user = 0;
        pix0.data = i;
        pix1.user = 0;
        pix1.data = i;
        ins0 << pix0;
        ins1 << pix1;
    }

    // ins0 には M系列、ins1 には、矩形波を入力する
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            xor_shift = (m_seq>>30 & 1) ^ ((m_seq>>2)& 1) ^ ((m_seq>>1) & 1) ^ (m_seq & 1); // (31, 3, 2, 1) 31ビットのM系列
            m_seq = ((m_seq<<1) | xor_shift) & 0x7FFFFFFF;
            if (((i+j)%CLOCK_PERIOD) < (CLOCK_PERIOD/2))
                rect_wave = 0;
            else
                rect_wave = 1000;

            pix0.data = (ap_int<32>)m_seq;
            pix1.data = (ap_int<32>)rect_wave;

            select = 0// M 系列            

            if (j==0 && i==0) { // 最初のデータの時に TUSER を 1 にする
                pix0.user = 1;
                pix1.user = 1;
            } else {
                pix0.user = 0;
                pix1.user = 0;
            }

            if (i == HORIZONTAL_PIXEL_WIDTH-1) { // 行の最後でTLASTをアサートする
                pix0.last = 1;
                pix1.last = 1;
            } else {
                pix0.last = 0;
                pix1.last = 0;
            }

            ins0 << pix0;
            ins1 << pix1;
        }
    }

    axis_switcher(ins0, ins1, outs, select);

    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            outs >> vals;
            ap_int<32> val = vals.data;
            cout << hex << val << endl;
            if (vals.last)
                cout << "AXI-Stream is end" << endl;
        }
    }

    // ins0 には M系列、ins1 には、矩形波を入力する
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            xor_shift = (m_seq>>30 & 1) ^ ((m_seq>>2)& 1) ^ ((m_seq>>1) & 1) ^ (m_seq & 1); // (31, 3, 2, 1) 31ビットのM系列
            m_seq = ((m_seq<<1) | xor_shift) & 0x7FFFFFFF;
            if (((i+j)%CLOCK_PERIOD) < (CLOCK_PERIOD/2))
                rect_wave = 0;
            else
                rect_wave = 1000;

            pix0.data = (ap_int<32>)m_seq;
            pix1.data = (ap_int<32>)rect_wave;

            select = 1// 矩形波            

            if (j==0 && i==0) { // 最初のデータの時に TUSER を 1 にする
                pix0.user = 1;
                pix1.user = 1;
            } else {
                pix0.user = 0;
                pix1.user = 0;
            }

            if (i == HORIZONTAL_PIXEL_WIDTH-1) { // 行の最後でTLASTをアサートする
                pix0.last = 1;
                pix1.last = 1;
            } else {
                pix0.last = 0;
                pix1.last = 0;
            }

            ins0 << pix0;
            ins1 << pix1;
        }
    }

    axis_switcher(ins0, ins1, outs, select);

    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            outs >> vals;
            ap_int<32> val = vals.data;
            cout << hex << val << endl;
            if (vals.last)
                cout << "AXI-Stream is end" << endl;
        }
    }

    return 0;   
}

  1. 2015年05月15日 04:36 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3151-7e5308a4
この記事にトラックバックする(FC2ブログユーザー)