はじめに
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に対応出来るようにしています。以下に概略タイミングと簡単なブロック図を示します。
概略タイミング
ブロック図
RTLソース
`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限定とし、パラメータはソースに埋め込んでいますが、実用的にはレジスタ設定で変更できる形にする必要があると思います。
また、本回路とペアになる逆変換(ストリームデータから同期ビデオ信号)も必要と思いますので、機会を見て作成し投稿したいと考えています。