FPGAの部屋

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

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。ご利用ください。 http://marsee101.web.fc2.com/index.html

2021年02月

調歩同期式シリアル通信の送信 IP (uart_tx)を Vitis HLS で作成する1”の続き。

調歩同期式シリアル通信の受信 IP とその後の 3 軸加速度センサー・データの処理 IP を作成した。今回は、調歩同期式シリアル通信の送信 IP (uart_tx)を Vitis HLS で作成しようとうことで、前回は、uart_tx のソースコードとテストベンチ・コードを貼って、Vitis HLS 2020.2 の uart_tx プロジェクトを作成した。今回は、C シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTL を行っていこう。

まずは、C シミュレーションからやってみるが、txst にシリアルデータを出力するだけなので、このテストベンチでは、芸がない。。。
8a0cca87.png


C コードの合成をやってみた。結果を示す。
9be95a89.png

6621ebae.png


Latency は 1923 クロックだった。
12 分周 x 16 サンプル x ( 1 スタートビット + 8 キャラクタ + 1 ストップビット) = 1920 クロック
良いところだと思う。

C/RTL 協調シミュレーションを行った。
0bd0f9f8.png


C/RTL 協調シミュレーションの全体波形を示す。
51ce5236.png


ピンクの楕円の部分を拡大した。
586328f8.png


txst_V_din が X の部分があるので、これは良くない。。。

txst_V_din を出力する uart_tx.v のコードを見てみると、 else の場合が X に指定されていた。
f6525168.png


C 言語ベースで修正できないようなので、Verilog HDL コードを書き換えてしまった。(禁断の術だ。。。)
3dee22e4.png


これで、C/RTL 協調シミュレーションをして、波形を表示した。
22ce6264.png


先ほどと同じ部分を拡大すると、txst_V_din は 1 のままなので、これで OK だ。
b6aef357.png


しかし、txst_V_din が組み合わせ回路出力なのはいただけないので、もう一度、 FF 出力に変更した。
fdbc3643.png


always @ (posedge ap_clk) begin
    if (ap_rst_n_inv == 1'b1) begin
        txst_V_din = 1'd1;
    end else if ((txst_V_full_n == 1'b1)) begin
        if ((1'b1 == ap_CS_fsm_state6)) begin
            txst_V_din = 1'd1;
        end else if ((1'b1 == ap_CS_fsm_state4)) begin
            txst_V_din = trunc_ln213_fu_307_p1;
        end else if ((1'b1 == ap_CS_fsm_state2)) begin
            txst_V_din = 1'd0;
        end else begin
            txst_V_din = 1'd1;
        end
    end else begin
        txst_V_din = 1'd1;
    end
end


これで、C/RTL 協調シミュレーションを行った。
9faaa2ba.png


C/RTL 協調シミュレーションの波形を表示した。
c7781fa4.png


2 クロック分ロスしているだけのようだ。問題無さそう。

uart_tx.v は修正したファイルになっている。
a84599a8.png


Export RTL を行った。結果を示す。
uart_tx_16_210227.png

uart_tx IP も確認したが、修正済みの Verilog HDL ファイルになっている。

内部で使用されていない出力ポートのレベルを変更することや、レジスタ化はやっても良いと思っている。ただ、ソースコードを修正した時は、Verilog HDL の再修正を忘れないようにする必要がある。

調歩同期式シリアル通信の受信 IP とその後の 3 軸加速度センサー・データの処理 IP を作成した。残りっている調歩同期式シリアル通信の送信 IP (uart_tx)を Vitis HLS で作成しよう。
今回は、 uart_tx のソースコードとテストベンチ・コードを貼っておく。

ソースコードの uart_tx.h を貼っておく。

// uart_tx.h
// 2021/02/18 by marsee
//

#ifndef __UART_TX_H__
#define __UART_TX_H__

#include
#include

#define DIV_8M 12
#define DIV_500k 16

#endif


uart_tx.cpp を貼っておく。

// uart_tx.cpp
// 2021/02/18 by marsee
//

#include "uart_tx.h"

bool send_zero_bit(hls::stream<ap_uint<1> >& txst){
    const ap_uint<1> tx=0;

    LOOP_DZB1: for(int i=0; i<DIV_8M; i++){
        LOOP_DZB2: for(int j=0; j<DIV_500k; j++){
#pragma HLS PIPELINE II=1 rewind
            txst << tx;
        }
    }
    return(true);
}

bool send_data_byte(ap_uint<8> tx_data, hls::stream<ap_uint<1> >& txst){
    ap_uint<1> tx;

    LOOP_DDB1: for(int k=0; k<8; k++){
        LOOP_DDB2: for(int i=0; i<DIV_8M; i++){
            LOOP_DDB3: for(int j=0; j<DIV_500k; j++){
#pragma HLS PIPELINE II=1 rewind
                tx = tx_data & 1;
                txst << tx;
                if(i==(DIV_8M-1) && j==(DIV_500k-1)){
                    tx_data >>= 1;
                }
            }
        }
    }
    return(true);

}

bool send_stop_bit(hls::stream<ap_uint<1> >& txst){
    const ap_uint<1> tx = 1;

    LOOP_CSB1: for(int i=0; i<DIV_8M; i++){
        LOOP_CSB2: for(int j=0; j<DIV_500k; j++){
#pragma HLS PIPELINE II=1 rewind
            txst << tx;
        }
    }
    return(true);
}

int uart_tx(ap_uint<8> tx_data, hls::stream<ap_uint<1> >& txst){
#pragma HLS INTERFACE s_axilite port=tx_data
#pragma HLS INTERFACE ap_ctrl_hs port=return
    send_zero_bit(txst);
    send_data_byte(tx_data, txst);
    send_stop_bit(txst);

    return(0);
}


テストベンチの uart_tx_tb.cpp を貼っておく。

// uart_tx_tb.cpp
// 2021/02/18 by marsee
//

#include "uart_tx.h"

int uart_tx(ap_uint<8> tx_data, hls::stream<ap_uint<1> >& txst);

int main(){
    ap_uint<8> tx_data;
    hls::stream<ap_uint<1> > txst;

    tx_data = 0x55;
    uart_tx(tx_data, txst);

    tx_data = 0xaa;
    uart_tx(tx_data, txst);

    return(0);
}


Vitis HLS 2020.2 で ZYBO Z7-20 用の uart_tx プロジェクトを作成した。
78315757.png

uart_rx と uart_rx_axi4ls を連結してシミュレーションする1”の続き。

3 軸加速度センサーの RS-422 インターフェースのデータを受けるために uart_rx とその後段の uart_rx_axi4ls を Vitis HLS で作ってきたが、それらを連結してシミュレーションしてみようということで、前回は、Vivado 2020.2 の uart_rx_axi4ls_top プロジェクトを作成し、 uart_rx IP と uart_rx_axi4ls IP を IP Catalog に追加した。そてひ、 uart_rx_axi4ls_top_tb.sv のソースコードを貼った。今回は、Viado でブロックデザインを作成し、ラッパー Verilog HDL ファイルを生成して、論理シミュレーションを行う。

uart_rx_axi4ls_top ブロックデザインを作成し、 uart_rx IP と uart_rx_axi4ls IP を Add IP して追加し、配線を行った。
6100df88.png


uart_rx_axi4ls_top ブロックデザインを拡大する。
90e88f6c.png


Address Editor を示す。アドレスマップは実行されていない。
bdf1e758.png


Source ウインドウで uart_rx_axi4ls_top_i を右クリックし右クリックメニューから Create HDL Wrapper... を選択して、Verilog HDL のラッパーファイルを生成した。
3159c334.png


Add Sources で”uart_rx と uart_rx_axi4ls を連結してシミュレーションする1”の uart_rx_axi4ls_top_tb.sv ファイルを追加した。
そして、SIMULATION から Run Simulation -> Run Behavioral Simulation を選択して、論理シミュレーションを行った。
639e5421.png


シミュレーションの画面が表示された。
Run All ボタンをクリックして、シミュレーションを終了させる。
88ab6250.png


$STOP 行までシミュレーションを行って、停止している。
9dd5fe39.png


シミュレーション波形を見てみる。
a8820fb8.png


x 軸データ、 y 軸データ、 z 軸データが受かっているか確認するために波形の終わりの部分を拡大した。
4e07d343.png


キーコード + x 軸データは 0x5a112233 、 y 軸データは 0x00445566 、 z 軸データは 0x00778899 が受かっていることが分かる。これで正解で、成功だ。

3 軸加速度センサーの RS-422 インターフェースのデータを受けるために uart_rx とその後段の uart_rx_axi4ls を Vitis HLS で作ってきたが、それらを連結してシミュレーションしてみよう。
今回は、Vivado 2020.2 の uart_rx_axi4ls_top プロジェクトを作成し、 uart_rx IP と uart_rx_axi4ls IP を IP Catalog に追加した。そてひ、 uart_rx_axi4ls_top_tb.sv のソースコードを貼った。

まずは、Viavdo 2020.2 で uart_rx_axi4ls_top プロジェクトを作成した。
c8caee46.png


uart_rx_axi4ls_top プロジェクトのディレクトリに uart_rx と uart_rx_axi4ls ディレクトリを新規作成した。

uart_rx ディレクトリには、uart_rx/solution1/impl/export.zip を展開して、コピーした。
80208026.png


uart_rx_axi4ls ディレクトリには、uart_rx_axi4ls/solution1/impl/export.zip を展開して、コピーした。
2dad3d4b.png


uart_rx IP と uart_rx_axi4ls IP を IP catalog に追加した。
c8caee46.png


最後に、次回使用する SystemVerilog のテストベンチの uart_rx_axi4ls_top_tb.sv を貼っておく。
uart_rx にシリアル・データを入力して、

task automatic axi_master_rd_reg(input logic [5:0] araddr)

で AXI4 Lite インターフェースでキーコード + x 軸、 y 軸、 z軸のデータを読み出す。

`timescale 100ps / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 02/17/2021
// Design Name: 
// Module Name: uart_rx_axi4ls_top_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_rx_axi4ls_top_tb;
    parameter DELAY = 10; // delay = 1 ns
    
    logic ap_clk;
    logic ap_rst;
    logic ap_start;
    logic ap_done;
    logic ap_idle;
    logic ap_ready;
    logic ap_start_0;
    logic ap_done_0;
    logic ap_idle_0;
    logic ap_ready_0;
    logic rxst_V_dout;
    logic [5:0] s_axi_control_araddr;
    logic s_axi_control_arready;
    logic s_axi_control_arvalid;
    logic [5:0] s_axi_control_awaddr;
    logic s_axi_control_awready;
    logic s_axi_control_awvalid;
    logic s_axi_control_bready;
    logic [1:0] s_axi_control_bresp;
    logic s_axi_control_bvalid;
    logic [31:0] s_axi_control_rdata;
    logic s_axi_control_rready;
    logic [1:0] s_axi_control_rresp;
    logic s_axi_control_rvalid;
    logic [31:0] s_axi_control_wdata;
    logic s_axi_control_wready;
    logic [3:0] s_axi_control_wstrb;
    logic s_axi_control_wvalid;
   
    uart_rx_axi4ls_top_wrapper uart_rx_axi4ls_top_i(.*);
    
    task gen_ap_clk;
        forever begin
            #52 ap_clk <= ~ap_clk; // 10.4 ns = 96.15 MHz
        end
    endtask
    
    task start_bit_gen;
        begin
            @(posedge ap_clk);
            #DELAY
            rxst_V_dout <= 1'b0;
            repeat(12*16)@(posedge ap_clk);
        end
    endtask
    
    task rx_data_gen(input logic [7:0] rxd);
        begin
            for(int i=0; i<8; i++) begin
                #DELAY
                rxst_V_dout <= rxd[i];
                repeat(12*16)@(posedge ap_clk);
             end
         end
     endtask
     
    task stop_bit_gen;
        begin
            #DELAY
            rxst_V_dout <= 1'b1;
            repeat(12*16)@(posedge ap_clk);
        end
    endtask
    
    task automatic axi_master_rd_reg(input logic [5:0] araddr);
        @(posedge ap_clk);
        #DELAY
        s_axi_control_araddr <= araddr;
        s_axi_control_arvalid <= 1'b1;
        do begin
            @(posedge ap_clk);
        end while (s_axi_control_arready == 1'b0);

        #DELAY
        s_axi_control_arvalid <= 1'b0;
        s_axi_control_rvalid <= 1'b1;
        do begin
            @(posedge ap_clk);
        end while (s_axi_control_rready == 1'b0);
        #DELAY
        s_axi_control_rvalid <= 1'b0;
    endtask //automatic

    initial begin
        ap_clk <= 1'b0;
        ap_rst <= 1'b1;
        ap_start <= 1'b0;
        ap_start_0 <= 1'b0;
        rxst_V_dout <= 1'b1;
        s_axi_control_araddr <= 0;
        s_axi_control_arvalid <= 1'b0;
        s_axi_control_awaddr <= 0;
        s_axi_control_awvalid <= 1'b0;
        s_axi_control_bready <= 1'b1;
        s_axi_control_rready <= 1'b1;
        s_axi_control_wdata <= 0;
        s_axi_control_wstrb <= 0;
        s_axi_control_wvalid <= 1'b0;
        
        #300 fork
            gen_ap_clk;
        join_none
        
        #300 ap_rst <= 1'b0;
        #300 ap_start <= 1'b1;
        ap_start_0 <= 1'b1;
        repeat(12*16)@(posedge ap_clk);
        
        #300 // X key
        start_bit_gen;
        rx_data_gen(0'h5A);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);
        
        #300 // x_data_0
        start_bit_gen;
        rx_data_gen(0'h11);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // x_data_1
        start_bit_gen;
        rx_data_gen(0'h22);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // x_data_2
        start_bit_gen;
        rx_data_gen(0'h33);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // y_data_0
        start_bit_gen;
        rx_data_gen(0'h44);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // y_data_1
        start_bit_gen;
        rx_data_gen(0'h55);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // y_data_2
        start_bit_gen;
        rx_data_gen(0'h66);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // z_data_0
        start_bit_gen;
        rx_data_gen(0'h77);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // z_data_1
        start_bit_gen;
        rx_data_gen(0'h88);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300 // y_data_2
        start_bit_gen;
        rx_data_gen(0'h99);
        stop_bit_gen;
        repeat(12*16)@(posedge ap_clk);

        #300
        axi_master_rd_reg(6'b01_0000); // 0x10 x_data
        #300
        axi_master_rd_reg(6'b10_0000); // 0x20 y_data
        #300
        axi_master_rd_reg(6'b11_0000); // 0x30 z_data
        repeat(12*16)@(posedge ap_clk);

        $stop;
    end
endmodule


uart_rx_axi4ls IP の AXI4 Lite のアドレスマップを貼っておく。

//------------------------Address Info-------------------
// 0x00 : reserved
// 0x04 : reserved
// 0x08 : reserved
// 0x0c : reserved
// 0x10 : Data signal of x_data
//        bit 31~0 - x_data[31:0] (Read)
// 0x14 : Control signal of x_data
//        bit 0  - x_data_ap_vld (Read/COR)
//        others - reserved
// 0x20 : Data signal of y_data
//        bit 31~0 - y_data[31:0] (Read)
// 0x24 : Control signal of y_data
//        bit 0  - y_data_ap_vld (Read/COR)
//        others - reserved
// 0x30 : Data signal of z_data
//        bit 31~0 - z_data[31:0] (Read)
// 0x34 : Control signal of z_data
//        bit 0  - z_data_ap_vld (Read/COR)
//        others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


uart_rx を使用して 3 軸加速度センサー用のデータを作成する uart_rx_axi4ls IP の作成1”の続き。

uart_rx の後段で 3 軸加速度センサー用のデータを作成する IP である uart_rx_axi4ls IP を作成していこうということで、前回は、ソースコードとテストベンチのコードを貼って、 Vitis HLS 2020.2 の uart_rx_axi4ls プロジェクトを作成した。今回は、C シミュレーション、C コードの合成、 C/RTL 協調シミュレーション、Export RTL を行う。

C シミュレーションを行った。結果を示す。
80f4cef1.png

x_data = 55112233, y_data = 445566, z_data = 778899

と表示されている。これで正しい。

次に、C コードの合成を行った。結果を示す。
fb5a1a45.png

9109ae47.png


Latency は 13 クロックだった。
合成された Verilog HDL ファイルを示す。
uart_rx_axi4ls.v、 uart_rx_axi4ls_control_s_axi.v、 uart_rx_axi4ls_regslice_both.v の 3 個だった。
c0f498c0.png


uart_rx_axi4ls_control_s_axi.v のレジスタ・マップ部分を示す。

//------------------------Address Info-------------------
// 0x00 : reserved
// 0x04 : reserved
// 0x08 : reserved
// 0x0c : reserved
// 0x10 : Data signal of x_data
//        bit 31~0 - x_data[31:0] (Read)
// 0x14 : Control signal of x_data
//        bit 0  - x_data_ap_vld (Read/COR)
//        others - reserved
// 0x20 : Data signal of y_data
//        bit 31~0 - y_data[31:0] (Read)
// 0x24 : Control signal of y_data
//        bit 0  - y_data_ap_vld (Read/COR)
//        others - reserved
// 0x30 : Data signal of z_data
//        bit 31~0 - z_data[31:0] (Read)
// 0x34 : Control signal of z_data
//        bit 0  - z_data_ap_vld (Read/COR)
//        others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)



C/RTL 協調シミュレーションを行った。結果を示す。
ee6b8480.png


Latency は 14 クロックで、 Initiation Interval は 47 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
6691b406.png


x_data, y_data, z_data を AXI4 Lite インターフェース経由で取得できている。

Export RTL の結果を示す。
uart_rx_28_210223.png

問題ない。

次は、 uart_rx と uart_rx_axi4ls をつないで Vivado でシミュレーションを行う。

↑このページのトップヘ