7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

インテル® FPGA Advent Calendar 2020

Day 5

同期ビデオ信号と内部ストリーミングバス間の簡易IF実装

Last updated at Posted at 2020-11-20

はじめに

 FPGA内で同期ビデオ信号をAvalon-STやAXI4-Streamといったストリームバスに変換するための簡易的な実装例です。IntelのFPGA向けには、様々な画像処理に対応したIP群(VIP)がラインナップされており、その中に同期ビデオ信号をAvalon-STに変換するIPも用意されています。このIPは豊富な機能を持っていますが、その分ある程度パラメータやレジスタの設定が必要です。

 評価ボード上で実験的な画像入出力回路を動かそうとする場合、本格的なVIPを使うほどではないケースも多いかと思います。本記事はこうした用途に向けた、同期ビデオ信号変換回路の簡易な実装例になります。なお、あくまで評価等を目的としたものなので、動作仕様としてはかなり限定したものになっています。その点、事前にご了解いただけましたら幸いです。なお、今回実機検証は下記デバイスにて実施いたしましたが、特にデバイス特有な機能に依存しているところはありませんので、他のIntel FPGAにも実装可能です。

 あと、テストの際のストリームクロックは160MHzにしていますが、これに特別な意図はありません。とりあえず、ビデオクロックより高速な非同期の周波数にしておきたかっただけです。Cyclone Vであれば180MHz程度までは動くと思われます。

開発環境

項目        名称                        
記述言語      Verilog                     
検証ツール     ModelSim Altera Starter Edition        
合成ツール     Quartus Prime ver19.1              
ターゲットFPGA   Cyclone V シリーズ 5CSXFC5D6F31        

画像仕様

項目        仕様                        
画像サイズ     1920 x 1080                   
スキャン方式    progressive                   
ビデオクロック    148.5MHz                    
ストリームクロック  160MHz                     

信号端子

同期ビデオ信号

信号名        機能                   
vclk     ビデオクロック                
vsync_b    垂直同期(負論理)               
hsync_b    水平同期(負論理)                
data_en  画像有効フラグ(正論理)                
vdata[23:0]  画像データ(RGB888)                 

AvalonST信号

信号名        機能                   
av_start     スタートフラグ                
av_end    エンドフラグ               
av_data[31:0]    ストリームデータ                
av_valid  ハンドシェイク(要求)                
av_ready  ハンドシェイク(許可)                 

AXI4-stream信号

信号名        機能                   
ax_tuser     先頭データフラグ                
ax_tlast    ラインエンドフラグ               
ax_tdata[31:0]    ストリームデータ                
ax_tvalid  ハンドシェイク(要求)                
ax_tready  ハンドシェイク(許可)                 

System信号

信号名        機能                   
aclk     ストリームクロック                
reset_b    システムリセット               
st_sel    ストリームプロトコル選択               
conv_en  変換転送イネーブル                

動作概要

 出力するストリームバスは、AXI4-streamとAvalonSTの2つが選択できます。具体的には、st_sel="0"のときAvalonST側、"1"のときAXI4-streamが有効になります。

 システムリセットを解除し、conv_enを有効("1")にすると、同期ビデオ信号側は次のフレームからdata_enで示される有効データをそのまま非同期FIFOに書き込みます。ストリームバス側は、data_enをアサートした後、非同期FIFOのemptyフラグがデアサート状態になると、データ読み出しのステートになり、データの転送を開始します。この時、最初に読み出されたデータが自動的にフレームの先頭データとして取り扱われます。

 AXI4-stream側の動作としてはこの先頭データと同時にax_tuserを"1"にして出力します。以降、FIFO内にデータが存在すればax_tvalidを"1"にしつつ順次データを出力します。なお、1920データごとに1行の最後のフラグとしてax_tlastを"1"にして出力します。

 一方、AvalonST側はプロトコルとして、画像データの転送を開始する前にコントロールパケットを出力する必要があります。そのため、FIFOにデータが書き込まれると、まず、画像仕様に準じたフォーマットのコントロールパケットを出力し、それに引き続いて画像データパケットを出力します。また、こちらも1920データ出力するごとにav_endを"1"にして出力します。なお、AvalonSTのready信号には、Latencyとallowanceというプロパティが存在しています。通常、これらのプロパティの値は1になっていると思われますが、一応、本実装ではRTL内のパラメータ設定で規定の0から8に対応出来るようにしています。以下に概略タイミングと簡単なブロック図を示します。

概略タイミング

timing_1.png

ブロック図

fpga_block.png

RTLソース

vid_ax_av.v
`timescale 1ns / 1ps

module  vid_av_ax   (
    input           aclk        ,
    input           vclk        ,
    input           conv_en     ,
    input           aresetn     ,

    output  [31:0]  ax_tdata    ,
    output          ax_tvalid   ,
    output          ax_tuser    ,
    output          ax_tlast    ,
    input           ax_tready   ,

    output  [31:0]  av_data     ,
    output          av_valid    ,
    output          av_start    ,
    output          av_end      ,
    input           av_ready    ,

    input   [23:0]  vdata       ,
    input           data_en     ,
    input           hsync_b     ,
    input           vsync_b     ,

    input           st_sel      
);

//  parameter
    parameter   [31:0]  p_ctr_start     =   32'h0000000f,
                        p_vid_start     =   32'h00000000,
                        p_ctr_interlace =   32'h00000007;
    parameter   [11:0]  p_h_size        =   12'd1920,
                        p_v_size        =   12'd1080,
                        p_h_size1       =   p_h_size - 12'd1,
                        p_h_size2       =   p_h_size - 12'd2,
                        p_v_size1       =   p_v_size - 12'd1;
    parameter   [3:0]   p_ava_allowance =   4'h0,   //min0 max8
                        p_ava_latency   =   4'h0;   //min0 max8
    parameter   [2:0]   p_ctr_cnt_max   =   3'd4,
                        p_ctr_cnt_max1  =   p_ctr_cnt_max - 3'd1,
                        p_ctr_cnt_max2  =   p_ctr_cnt_max - 3'd2;
    parameter   [1:0]   p_vid_idle      =   2'b00,
                        p_vid_wait      =   2'b01,
                        p_vid_write     =   2'b11,
                        p_a_idle        =   2'b00,
                        p_a_wait        =   2'b01,
                        p_a_ctr         =   2'b10,
                        p_a_read        =   2'b11,
                        p_move_wait     =   2'b00,
                        p_to_ctr        =   2'b01,
                        p_to_rd         =   2'b11;
    parameter   [0:0]   p_ax_mode       =   1'b1,
                        p_av_mode       =   1'b0;

//  wire
    wire    [3:0]   w_ava_allow     ;
    wire            w_ava_alw_rdy   ;
    wire            w_aclr_b        ;
    wire            w_aclr          ;
    wire            w_read_en       ;
    wire            w_write_en      ;
    wire    [31:0]  w_data_out      ;
    wire            w_empty         ;
    wire            w_empty_b       ;
    wire            w_full          ;
    wire            w_ready         ;
    wire    [3:0]   w_ava_late      ;
    wire            w_ava_valid_o   ;
    wire            w_ava_end_o     ;
    wire            w_ava_start_o   ;
    wire    [31:0]  w_ava_data_o    ;

//  reg
    reg     [7:0]   r_ava_alw_rdy   ;
    reg             r_conven_v1     ;
    reg             r_conven_v2     ;
    reg             r_vsync_b_1     ;
    reg             r_vsync_b_2     ;
    reg             r_hsync_b       ;
    reg             r_en            ;
    reg     [31:0]  r_data_in       ;
    reg             r_conven_a1     ;
    reg             r_conven_a2     ;
    reg     [1:0]   r_vid_state     ;
    reg     [1:0]   r_a_state       ;
    reg     [2:0]   r_ava_ctr_cnt   ;
    reg     [1:0]   r_state_move    ;
    reg             r_read_en       ;
    reg     [10:0]  r_a_hcnt        ;
    reg     [10:0]  r_a_vcnt        ;
    reg             r_tval          ;
    reg             r_tlast         ;
    reg             r_tuser         ;
    reg     [31:0]  r_tdata         ;
    reg             r_ava_start     ;
    reg             r_ava_end       ;
    reg             r_ava_valid     ;
    reg     [31:0]  r_ava_data      ;
    reg     [7:0]   r_ava_late_val  ;
    reg     [7:0]   r_ava_late_start;
    reg     [7:0]   r_ava_late_end  ;
    reg     [31:0]  r_ava_data1     ;
    reg     [31:0]  r_ava_data2     ;
    reg     [31:0]  r_ava_data3     ;
    reg     [31:0]  r_ava_data4     ;
    reg     [31:0]  r_ava_data5     ;
    reg     [31:0]  r_ava_data6     ;
    reg     [31:0]  r_ava_data7     ;
    reg     [31:0]  r_ava_data8     ;

//  AvalonST allowance
    assign  w_ava_allow =   p_ava_allowance ;

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_alw_rdy   <=  8'h00   ;
        end
        else begin
            r_ava_alw_rdy   <=  {r_ava_alw_rdy[6:0],av_ready}   ;
        end
    end

    assign  w_ava_alw_rdy   =   (w_ava_allow == 4'h0)?  av_ready :
                                (w_ava_allow == 4'h1)?  av_ready | r_ava_alw_rdy[0] :
                                (w_ava_allow == 4'h2)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] :
                                (w_ava_allow == 4'h3)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2]   :
                                (w_ava_allow == 4'h4)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2] | r_ava_alw_rdy[3] :
                                (w_ava_allow == 4'h5)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2] | r_ava_alw_rdy[3] | r_ava_alw_rdy[4] :
                                (w_ava_allow == 4'h6)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2] | r_ava_alw_rdy[3] | r_ava_alw_rdy[4] | r_ava_alw_rdy[5] :
                                (w_ava_allow == 4'h7)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2] | r_ava_alw_rdy[3] | r_ava_alw_rdy[4] | r_ava_alw_rdy[5] | r_ava_alw_rdy[6]   :
                                (w_ava_allow == 4'h8)?  av_ready | r_ava_alw_rdy[0] | r_ava_alw_rdy[1] | r_ava_alw_rdy[2] | r_ava_alw_rdy[3] | r_ava_alw_rdy[4] | r_ava_alw_rdy[5] | r_ava_alw_rdy[6] | r_ava_alw_rdy[7]    :
                                1'b0    ;

//  input pipeline
    always @ (posedge vclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_conven_v1     <=  1'b0    ;
            r_conven_v2     <=  1'b0    ;
            r_vsync_b_1     <=  1'b1    ;
            r_vsync_b_2     <=  1'b1    ;
            r_hsync_b       <=  1'b1    ;
            r_en            <=  1'b0    ;
            r_data_in       <=  32'h00000000    ;
        end
        else begin
            r_conven_v1     <=  conv_en         ;
            r_conven_v2     <=  r_conven_v1     ;
            r_vsync_b_1     <=  vsync_b         ;
            r_vsync_b_2     <=  r_vsync_b_1     ;
            r_hsync_b       <=  hsync_b         ;
            r_en            <=  data_en         ;
            r_data_in       <=  {8'h00,vdata}   ;
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_conven_a1     <=  1'b0    ;
            r_conven_a2     <=  1'b0    ;
        end
        else begin
            r_conven_a1     <=  conv_en     ;
            r_conven_a2     <=  r_conven_a1 ;
        end
    end

//  state machine
    always @ (posedge vclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
        	r_vid_state     <=  p_vid_idle  ;
        end
        else begin
            case (r_vid_state) 
                p_vid_idle  :   begin
                    if(r_conven_v2  == 1'b1) begin
                    	r_vid_state <=  p_vid_wait  ;
                    end
                end
                p_vid_wait  :   begin
                    if(r_conven_v2 == 1'b0) begin
                    	r_vid_state <=  p_vid_idle  ;
                    end
                    else if((r_vsync_b_1 == 1'b0)&&(r_vsync_b_2 == 1'b1)) begin
                    	r_vid_state <=  p_vid_write ;
                    end
                end
                p_vid_write :   begin
                    if(r_conven_v2 == 1'b0) begin
                   		r_vid_state <=  p_vid_idle  ;
                    end
                end
                default     :   begin
                	r_vid_state     <=  p_vid_idle  ;
                end
            endcase
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_a_state   <=  p_a_idle    ;
        end
        else begin
            case(r_a_state)
                p_a_idle    :   begin
                    if(r_conven_a2  == 1'b1) begin
                        r_a_state   <=  p_a_wait    ;
                    end
                end
                p_a_wait    :   begin
                    if(r_conven_a2  == 1'b0) begin
                        r_a_state   <=  p_a_idle    ;
                    end
                    else begin
                        case(r_state_move)
                            p_to_ctr    :   begin
                                r_a_state   <=  p_a_ctr ;
                            end
                            p_to_rd     :   begin
                                r_a_state   <=  p_a_read    ;
                            end
                        endcase
                    end
                end
                p_a_ctr :   begin
                    if(r_conven_a2  == 1'b0) begin
                        r_a_state   <=  p_a_idle    ;
                    end
                    else if(r_ava_ctr_cnt == p_ctr_cnt_max) begin
                        r_a_state   <=  p_a_wait    ;
                    end
                end
                p_a_read    :   begin
                    if(r_conven_a2  == 1'b0) begin
                        r_a_state   <=  p_a_idle    ;
                    end

                    else if(r_a_vcnt == p_v_size)   begin
                        r_a_state   <=  p_a_wait    ;
                    end
                end
            endcase
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_state_move    <=  p_move_wait ;
        end
        else if(r_a_state == p_a_wait)  begin
            if(w_empty == 1'b0)begin
                if(st_sel == p_ax_mode) begin
                    r_state_move    <=  p_to_rd ;
                end
                else begin
                    r_state_move    <=  p_to_ctr    ;
                end
            end
            else begin
                r_state_move    <=  p_move_wait ;
            end
        end
        else if(r_a_state == p_a_ctr)   begin
            if(r_ava_ctr_cnt == p_ctr_cnt_max) begin
                r_state_move    <=  p_to_rd ;
            end
            else begin
                r_state_move    <=  p_move_wait ;
            end
        end
        else begin
            r_state_move    <=  p_move_wait ;
        end
    end

//  FIFO(data_width = 32    fifo_depth = 8192   show-ahead)
    assign w_aclr_b     =   aresetn & r_conven_v2 & r_conven_a2 ;
    assign w_aclr       =   ~w_aclr_b           ;
    assign w_empty_b    =   ~w_empty            ;
    assign w_ready      =   (st_sel == p_ax_mode)?      ax_tready   :   w_ava_alw_rdy   ;
    assign w_read_en    =   (r_a_hcnt == p_h_size)?	1'b0	:r_read_en & w_ready & w_empty_b         ;
    assign w_write_en   =   (r_vid_state == p_vid_write)?   r_en    :   1'b0            ;

    fifo_vid_av u1  (
        .aclr(w_aclr)       ,
        .data(r_data_in)    ,
        .rdclk(aclk)        ,
        .rdreq(w_read_en)   ,
        .wrclk(vclk)        ,
        .wrreq(w_write_en)  ,
        .q(w_data_out)      ,
        .rdempty(w_empty)   ,
        .wrfull(w_full)     
    );

    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_read_en   <=  1'b0    ;
        end
        else if(r_a_state == p_a_read)begin
            if(st_sel == p_ax_mode)begin
                if(r_state_move == p_to_rd)begin
                    r_read_en   <=  1'b1    ;
                end
                else if((r_a_hcnt == p_h_size)&&(r_a_vcnt == p_v_size1)&&(r_tval == 1'b1)&&(w_ready == 1'b1)) begin
                    r_read_en   <=  1'b0    ;
                end
            end
            else begin
                if((r_ava_valid == 1'b1)&&(r_ava_start == 1'b1)&&(w_ready == 1'b1))begin
                    r_read_en   <=  1'b1    ;
                end
                else if((r_ava_end == 1'b1)&&(r_ava_valid == 1'b1)&&(w_ready == 1'b1)) begin
                    r_read_en   <=  1'b0    ;
                end
            end
        end
        else begin
            r_read_en   <=  1'b0    ;
        end
    end

//	HVcounter
    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_a_hcnt <= 11'h000 ;
        end
        else if(r_read_en == 1'b1) begin
            if(r_a_hcnt == p_h_size) begin
				if(st_sel == p_ax_mode) begin
					if((r_tval == 1'b1)&&(w_ready == 1'b1))begin
	                	r_a_hcnt <= 11'd0   ;
					end
				end
				else begin
					if((r_ava_valid == 1'b1)&&(w_ready == 1'b1))begin
	                	r_a_hcnt <= 11'd0   ;
					end
				end
            end
            else if(w_read_en == 1'b1) begin
                r_a_hcnt <= r_a_hcnt + 11'd1    ;
            end
        end
        else begin
            r_a_hcnt <= 11'h000 ;
        end
    end

    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_a_vcnt <= 11'h000 ;
        end
        else if(r_read_en == 1'b1) begin
            if(st_sel == p_ax_mode)begin
                if((r_a_hcnt == p_h_size)&&(r_tval == 1'b1)&&(w_ready == 1'b1))begin
                    r_a_vcnt <= r_a_vcnt + 11'd1    ;
                end
            end
            else begin
                if((r_a_hcnt == p_h_size)&&(r_ava_valid == 1'b1)&&(w_ready == 1'b1))begin
                    r_a_vcnt <= r_a_vcnt + 11'd1    ;
                end
            end
        end
        else begin
            r_a_vcnt <= 11'h000 ;
        end
    end

//  AXI4-stream
    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_tval      <=  1'b0    ;
        end
        else if(r_a_state == p_a_read) begin
            if(w_read_en == 1'b1) begin
                r_tval      <=  1'b1    ;
            end
            else if(w_ready == 1'b1) begin
                r_tval      <=  1'b0    ;
            end
        end
        else begin
            r_tval      <=  1'b0    ;
        end
    end

    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_tuser     <=  1'b0    ;
        end
        else if(r_a_state == p_a_read) begin
            if((r_tuser == 1'b1)&&(r_tval == 1'b1)&&(w_ready == 1'b1)) begin
                r_tuser     <=  1'b0    ;
            end
            else if((r_a_hcnt == 11'd0)&&(r_a_vcnt == 11'd0)) begin
                r_tuser     <=  1'b1    ;
            end
        end
        else begin
            r_tuser     <=  1'b0    ;
        end
    end

    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_tlast     <=  1'b0    ;
        end
        else if(r_a_state == p_a_read) begin
            if((r_tlast == 1'b1)&&(r_tval == 1'b1)&&(w_ready == 1'b1)) begin
                r_tlast     <=  1'b0    ;
            end
            else if((r_a_hcnt == p_h_size1)&&(w_read_en == 1'b1)) begin
                r_tlast     <=  1'b1    ;
            end
        end
        else begin
            r_tlast     <=  1'b0    ;
        end
    end

    always @ (posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_tdata     <=  32'h00000000    ;
        end
        else if(r_a_state == p_a_read) begin
            if(w_read_en == 1'b1) begin
                r_tdata     <=  w_data_out      ;
            end
        end
        else begin
            r_tdata     <=  32'h00000000    ;
        end
    end

//  AvalonST
    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_ctr_cnt   <=  3'd0    ;
        end
        else if(r_a_state == p_a_ctr) begin
            if ((r_ava_valid == 1'b1)&&(w_ready == 1'b1)) begin
                r_ava_ctr_cnt   <=  r_ava_ctr_cnt + 3'd1    ;
            end
        end
        else begin
            r_ava_ctr_cnt   <=  3'd0    ;
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_start <=  1'b0    ;
        end
        else if((r_ava_start == 1'b1)&&(r_ava_valid == 1'b1)&&(w_ready == 1'b1)) begin
            r_ava_start <=  1'b0    ;
        end
        else if(r_a_state == p_a_ctr) begin
            if(r_ava_ctr_cnt == 3'd0) begin
                r_ava_start <=  1'b1    ;
            end
        end
        else if(r_a_state == p_a_read) begin
            if((r_a_vcnt == 11'd0)&&(r_read_en == 1'b0)) begin
                r_ava_start <=  1'b1    ;
            end
        end
        else begin
            r_ava_start <=  1'b0    ;
        end
    end

   always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_end   <=  1'b0    ;
        end
        else if((r_ava_end == 1'b1)&&(r_ava_valid == 1'b1)) begin
			if(w_ready == 1'b1) begin
            	r_ava_end <=    1'b0    ;
			end
        end
        else if(r_a_state == p_a_ctr)begin
			if((r_ava_ctr_cnt == p_ctr_cnt_max2)&&(w_ready == 1'b1)) begin
                r_ava_end   <=  1'b1    ;
            end
        end
        else if(r_a_state == p_a_read) begin
            if(	((r_a_vcnt == p_v_size1)&&(r_a_hcnt == p_h_size1)&&(w_read_en == 1'b1))||
				((r_a_hcnt == p_h_size)&&(r_ava_valid == 1'b1)&&(w_ready == 1'b1))	)	begin
                r_ava_end   <=  1'b1    ;
            end
			else begin
                r_ava_end   <=  1'b0    ;
            end
		end
        else begin
            r_ava_end   <=  1'b0    ;
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_valid <=  1'b0    ;
        end
        else if(r_a_state == p_a_ctr)begin
            if(r_ava_ctr_cnt == 3'd0) begin
                r_ava_valid <=  1'b1    ;
            end
            else if((r_ava_ctr_cnt == p_ctr_cnt_max1)&&(w_ready == 1'b1)) begin
                r_ava_valid <=  1'b0    ;
            end
        end
        else if(r_a_state == p_a_read) begin
            if(r_read_en == 1'b1) begin
                if((r_a_hcnt == p_h_size)&&(r_ava_valid == 1'b1)&&(w_ready == 1'b1)) begin
                    r_ava_valid     <=  1'b0    ;
                end
                else if(w_read_en == 1'b1) begin
                    r_ava_valid     <=  1'b1    ;
                end
                else if(w_ready == 1'b1) begin
                    r_ava_valid     <=  1'b0    ;
                end
            end
            else if((r_ava_valid == 1'b1)&&(r_ava_start == 1'b1)&&(w_ready == 1'b1))begin
                r_ava_valid     <=  1'b0    ;
            end
            else if(r_a_vcnt == p_v_size)begin
                r_ava_valid     <=  1'b0    ;
            end
            else begin
                r_ava_valid     <=  1'b1    ;
            end
        end
        else begin
            r_ava_valid     <=  1'b0    ;
        end
    end

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_data  <=  32'h00000000    ;
        end
        else if(r_a_state == p_a_wait) begin
            if(r_state_move == p_to_ctr)begin
                r_ava_data  <=  p_ctr_start ;
            end
            else if(r_state_move == p_to_rd)begin
                r_ava_data  <=  p_vid_start ;
            end
            else begin
                r_ava_data  <=  32'h00000000    ;
            end
        end
        else if(r_a_state == p_a_ctr) begin
            if((r_ava_valid == 1'b1)&&(w_ready == 1'b1))begin
                case(r_ava_ctr_cnt) 
                    3'd0    :   begin
                        r_ava_data[ 7: 0]   <=  {4'h0,p_h_size[ 3:0]}   ;
                        r_ava_data[15: 8]   <=  {4'h0,p_h_size[ 7:4]}   ;
                        r_ava_data[23:16]   <=  {4'h0,p_h_size[11:8]}   ;
                        r_ava_data[31:24]   <=  8'h0                    ;
                    end
                    3'd1    :   begin
                        r_ava_data[ 7: 0]   <=  {4'h0,p_v_size[ 3:0]}   ;
                        r_ava_data[15: 8]   <=  {4'h0,p_v_size[ 7:4]}   ;
                        r_ava_data[23:16]   <=  {4'h0,p_v_size[11:8]}   ;
                        r_ava_data[31:24]   <=  8'h0                    ;
                    end
                    p_ctr_cnt_max2  :   begin
                        r_ava_data          <=  p_ctr_interlace          ;
                    end
                    default :   begin
                        r_ava_data          <=  32'h00000000            ;
                    end
                endcase
            end
        end
        else if(r_a_state == p_a_read) begin
            if(w_read_en == 1'b1)begin
                r_ava_data  <=  w_data_out  ;
            end
        end
        else begin
            r_ava_data  <=  32'h00000000    ;
        end

    end

//  AvalonST latency
    assign  w_ava_late  =   p_ava_latency   ;

    always@(posedge aclk or negedge aresetn) begin
        if(aresetn == 1'b0) begin
            r_ava_late_val      <=  8'h00           ;
            r_ava_late_start    <=  8'h00           ;
            r_ava_late_end      <=  8'h00           ;
            r_ava_data1         <=  32'h00000000    ;
            r_ava_data2         <=  32'h00000000    ;
            r_ava_data3         <=  32'h00000000    ;
            r_ava_data4         <=  32'h00000000    ;
            r_ava_data5         <=  32'h00000000    ;
            r_ava_data6         <=  32'h00000000    ;
            r_ava_data7         <=  32'h00000000    ;
            r_ava_data8         <=  32'h00000000    ;
        end
        else begin
            r_ava_late_val      <=  {r_ava_late_val[6:0],r_ava_valid}       ;
            r_ava_late_start    <=  {r_ava_late_start[6:0],r_ava_start} ;
            r_ava_late_end      <=  {r_ava_late_end[6:0],r_ava_end}     ;
            r_ava_data1         <=  r_ava_data      ;
            r_ava_data2         <=  r_ava_data1     ;
            r_ava_data3         <=  r_ava_data2     ;
            r_ava_data4         <=  r_ava_data3     ;
            r_ava_data5         <=  r_ava_data4     ;
            r_ava_data6         <=  r_ava_data5     ;
            r_ava_data7         <=  r_ava_data6     ;
            r_ava_data8         <=  r_ava_data7     ;
        end
    end

    assign  w_ava_valid_o   =   (w_ava_late == 4'h0)?   r_ava_valid         :
                                (w_ava_late == 4'h1)?   r_ava_late_val[0]   :
                                (w_ava_late == 4'h2)?   r_ava_late_val[1]   :
                                (w_ava_late == 4'h3)?   r_ava_late_val[2]   :
                                (w_ava_late == 4'h4)?   r_ava_late_val[3]   :
                                (w_ava_late == 4'h5)?   r_ava_late_val[4]   :
                                (w_ava_late == 4'h6)?   r_ava_late_val[5]   :
                                (w_ava_late == 4'h7)?   r_ava_late_val[6]   :
                                (w_ava_late == 4'h8)?   r_ava_late_val[7]   :
                                                        1'b0                ;

    assign  w_ava_start_o   =   (w_ava_late == 4'h0)?   r_ava_start         :
                                (w_ava_late == 4'h1)?   r_ava_late_start[0] :
                                (w_ava_late == 4'h2)?   r_ava_late_start[1] :
                                (w_ava_late == 4'h3)?   r_ava_late_start[2] :
                                (w_ava_late == 4'h4)?   r_ava_late_start[3] :
                                (w_ava_late == 4'h5)?   r_ava_late_start[4] :
                                (w_ava_late == 4'h6)?   r_ava_late_start[5] :
                                (w_ava_late == 4'h7)?   r_ava_late_start[6] :
                                (w_ava_late == 4'h8)?   r_ava_late_start[7] :
                                                        1'b0                ;

    assign  w_ava_end_o     =   (w_ava_late == 4'h0)?   r_ava_end           :
                                (w_ava_late == 4'h1)?   r_ava_late_end[0]   :
                                (w_ava_late == 4'h2)?   r_ava_late_end[1]   :
                                (w_ava_late == 4'h3)?   r_ava_late_end[2]   :
                                (w_ava_late == 4'h4)?   r_ava_late_end[3]   :
                                (w_ava_late == 4'h5)?   r_ava_late_end[4]   :
                                (w_ava_late == 4'h6)?   r_ava_late_end[5]   :
                                (w_ava_late == 4'h7)?   r_ava_late_end[6]   :
                                (w_ava_late == 4'h8)?   r_ava_late_end[7]   :
                                                        1'b0                ;

    assign  w_ava_data_o    =   (w_ava_late == 4'h0)?   r_ava_data  :
                                (w_ava_late == 4'h1)?   r_ava_data1 :
                                (w_ava_late == 4'h2)?   r_ava_data2 :
                                (w_ava_late == 4'h3)?   r_ava_data3 :
                                (w_ava_late == 4'h4)?   r_ava_data4 :
                                (w_ava_late == 4'h5)?   r_ava_data5 :
                                (w_ava_late == 4'h6)?   r_ava_data6 :
                                (w_ava_late == 4'h7)?   r_ava_data7 :
                                (w_ava_late == 4'h8)?   r_ava_data8 :
                                                        32'h00000000;
//  output
    assign  ax_tdata    =   r_tdata     ;
    assign  ax_tvalid   =   r_tval      ;
    assign  ax_tuser    =   r_tuser     ;
    assign  ax_tlast    =   r_tlast     ;

    assign  av_data     =   w_ava_data_o    ;
    assign  av_valid    =   w_ava_valid_o   ;
    assign  av_start    =   w_ava_start_o   ;
    assign  av_end      =   w_ava_end_o ;
endmodule

まとめと今後の課題

 今回は簡易な実装例ということで画像サイズはFullHD限定とし、パラメータはソースに埋め込んでいますが、実用的にはレジスタ設定で変更できる形にする必要があると思います。
 また、本回路とペアになる逆変換(ストリームデータから同期ビデオ信号)も必要と思いますので、機会を見て作成し投稿したいと考えています。

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?