Propose :
最近還找不到一個完整的 Project, 想說拿 "
CIC" 的題目當練習,也可以自己磨練一下.
XD
題目 :Color Transform Engine
Motivation:
利用影像壓縮 "
RGB 2
YUV"的方式,可減少存放在Memory的Frame大小.也可增加傳輸效率.
再硬體實現上,必須要有 Encoder ("
RGB 2
YUV")跟 Decoder ("
YUV 2
RGB")端, 才能正確的收發 Data.
可參考 97學年決賽競賽題目 (
研究所組) 有詳細的說明
設計概念:
主要會面對 3 個問題
1. 如何做 float point 的運算, 因為
Verilog 不支援 float point..
Ref:
float point @ verilog
2 . 如何把 Data Path 跟 Control Path 切乾淨
把
YUV2
RGB 跟
RGB2
YUV 分成兩個 PE(process element), 再用
Ctl status 來控制每個 status.
3. 處理 Input/Output 的 Sequence
YUV /
RGB 的 vector 擺放位置跟順序關係
底下就針對這3個 topic 來完成Design
YUV2
RGB.v 為
YUV2
RGB PE
RGB2
YUV.v 為
RGB2
YUV PE
CTE.v 為 TOP
CTL
PS: Function code 要合成 驗證後才能確定 timing OK, 不會造成 Setup or Hold time fail
CTE.v
`timescale 1ns/10ps
`include "YUV2RGB.v"
`include "RGB2YUV.v"
module CTE ( clk,
reset,
op_mode,
in_en,
yuv_in,
rgb_in,
busy,
out_valid,
rgb_out,
yuv_out
);
input clk ;
input reset ;
input op_mode;
input in_en;
output busy;
output out_valid;
input [7:0] yuv_in;
output [23:0] rgb_out;
input [23:0] rgb_in;
output [7:0] yuv_out;
reg [3:0] cur_st;
reg [3:0] nxt_st;
reg [7:0] reg_YUV2Y;
reg [7:0] reg_YUV2U;
reg [7:0] reg_YUV2V;
reg [3:0] reg_yuv_cot;
reg [3:0] reg_yuv_re_cot;
reg [3:0] reg_rgb_cot;
reg [3:0] reg_rgb_re_cot;
reg [3:0] reg_rgb_re2_cot;
reg [7:0] reg_RGB2R;
reg [7:0] reg_RGB2G;
reg [7:0] reg_RGB2B;
wire [7:0] w_reg_YUV2Y;
wire [7:0] w_reg_YUV2U;
wire [7:0] w_reg_YUV2V;
wire [7:0] w_reg_YUV2R;
wire [7:0] w_reg_YUV2G;
wire [7:0] w_reg_YUV2B;
wire [7:0] w_reg_RGB2R;
wire [7:0] w_reg_RGB2G;
wire [7:0] w_reg_RGB2B;
wire [7:0] w_reg_RGB2Y;
wire [7:0] w_reg_RGB2U;
wire [7:0] w_reg_RGB2V;
wire busy;
parameter st_IDLE = 3'b000;
parameter st_YUV2RGB = 3'b001;
parameter st_YUV_BUSY = 3'b010;
parameter st_YUV2RGB_ot = 3'b011;
parameter st_RGB2YUV = 3'b101;
parameter st_RGB_BUSY = 3'b110;
parameter st_RGB2YUV_ot = 3'b111;
assign busy = ( reg_yuv_cot ==3 || reg_rgb_cot ==1 )? 1'b1 : 1'b0;
assign out_valid= ( cur_st == st_YUV2RGB_ot || cur_st == st_RGB2YUV_ot )? 1'b1 : 1'b0;
assign rgb_done = ( reg_rgb_re_cot == 3 || reg_rgb_re2_cot ==1 )? 1'b1 : 1'b0;
assign rgb_out[23:16] = w_reg_YUV2R;
assign rgb_out[15: 8] = w_reg_YUV2G;
assign rgb_out[7 : 0] = w_reg_YUV2B;
assign w_reg_YUV2Y = reg_YUV2Y;
assign w_reg_YUV2U = reg_YUV2U;
assign w_reg_YUV2V = reg_YUV2V;
assign w_reg_RGB2R = reg_RGB2R;
assign w_reg_RGB2G = reg_RGB2G;
assign w_reg_RGB2B = reg_RGB2B;
assign yuv_out = ( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==1 && reg_rgb_re2_cot ==0 )? w_reg_RGB2U :
( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==2 && reg_rgb_re2_cot ==0 )? w_reg_RGB2Y :
( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==3 && reg_rgb_re2_cot ==0 )? w_reg_RGB2V :
( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==1 && reg_rgb_re2_cot ==1 )? w_reg_RGB2Y : 8'h00;
//State_Transitions
// cur_st <= nxt_st
always @ (posedge clk or posedge reset) begin // State_Transitions
if( reset )
cur_st <= st_IDLE;
else
cur_st <= nxt_st;
end
// Nxt_ST
always @ ( cur_st or op_mode or in_en or busy or rgb_done )begin // Nxt_ST
case(cur_st)
st_IDLE : nxt_st = ( op_mode ==1'b0 )? st_YUV2RGB : st_RGB2YUV;
st_YUV2RGB : nxt_st = ( op_mode ==1'b0 && busy==1'b1 )? st_YUV_BUSY :
( op_mode ==1'b1 )? st_IDLE : st_YUV2RGB;
st_YUV_BUSY : nxt_st = ( op_mode ==1'b0 )? st_YUV2RGB_ot : st_IDLE;
st_YUV2RGB_ot: nxt_st = ( op_mode ==1'b0 )? st_YUV2RGB : st_IDLE;
st_RGB2YUV : nxt_st = ( op_mode ==1'b1 && busy==1'b1 )? st_RGB_BUSY : st_IDLE;
st_RGB_BUSY : nxt_st = ( op_mode ==1'b1 )? st_RGB2YUV_ot : st_IDLE;
st_RGB2YUV_ot: nxt_st = ( op_mode ==1'b1 && rgb_done ==1'b1 )? st_IDLE : st_RGB2YUV_ot;
endcase
end
always @ (posedge clk or posedge reset) begin // YUV2RGB translator
if( reset ) begin
reg_yuv_cot <= 0;
reg_yuv_re_cot <= 0;
end
else
begin
if( in_en ==1'b1 && op_mode ==1'b0 && reg_yuv_cot != 3 )begin
if ( reg_yuv_cot == 0 && reg_yuv_re_cot == 0 )begin reg_YUV2U <= yuv_in; end
else if ( reg_yuv_cot == 1 && reg_yuv_re_cot == 0 )begin reg_YUV2Y <= yuv_in; end
else if ( reg_yuv_cot == 2 && reg_yuv_re_cot == 0 )begin reg_YUV2V <= yuv_in; end
else if ( reg_yuv_cot == 2 && reg_yuv_re_cot == 1 )begin reg_YUV2Y <= yuv_in; end
reg_yuv_cot <= reg_yuv_cot+1;
end
else if ( cur_st == st_YUV_BUSY )begin
if( reg_yuv_re_cot ==1 && reg_yuv_cot ==3 )begin
reg_yuv_cot <=0;
reg_yuv_re_cot <=0;
end
else if(reg_yuv_re_cot ==0 && reg_yuv_cot ==3) begin
reg_yuv_re_cot <= reg_yuv_re_cot+1;
reg_yuv_cot <= reg_yuv_cot-1;
end
end
end
end
always @ (posedge clk or posedge reset )begin // RGB2YUV translator
if ( reset ) begin
reg_rgb_cot <= 0;
reg_rgb_re_cot <= 0;
reg_rgb_re2_cot<= 0;
end
else
begin
if( in_en ==1'b1 && op_mode ==1'b1 && reg_rgb_cot !=1 )begin
reg_RGB2R <= rgb_in[23:16];
reg_RGB2G <= rgb_in[15: 8];
reg_RGB2B <= rgb_in[7 : 0];
reg_rgb_cot <= reg_rgb_cot +1;
end
else if( cur_st == st_RGB_BUSY || cur_st == st_RGB2YUV_ot ) begin
if( reg_rgb_re_cot == 3 && reg_rgb_re2_cot ==0 )begin
reg_rgb_re_cot <= 0;
reg_rgb_cot <= 0;
reg_rgb_re2_cot<= reg_rgb_re2_cot+1;
end
else if(reg_rgb_re_cot == 1 && reg_rgb_re2_cot ==1)begin
reg_rgb_re_cot <= 0;
reg_rgb_cot <= 0;
reg_rgb_re2_cot<= 0;
end
else
reg_rgb_re_cot <= reg_rgb_re_cot+1;
end
end
end
YUV2RGB Pe_YUV2RGB( .ot_R(w_reg_YUV2R),
.ot_G(w_reg_YUV2G),
.ot_B(w_reg_YUV2B),
.in_Y(w_reg_YUV2Y),
.in_U(w_reg_YUV2U),
.in_V(w_reg_YUV2V)
);
RGB2YUV Pe_RGB2YUV( .ot_Y(w_reg_RGB2Y),
.ot_U(w_reg_RGB2U),
.ot_V(w_reg_RGB2V),
.in_R(w_reg_RGB2R),
.in_G(w_reg_RGB2G),
.in_B(w_reg_RGB2B)
);
endmodule
YUV2RGB.v
module YUV2RGB ( ot_R,
ot_G,
ot_B,
in_Y,
in_U,
in_V
);
output [7 : 0 ] ot_R;
output [7 : 0 ] ot_G;
output [7 : 0 ] ot_B;
input [7 : 0 ] in_Y;
input [7 : 0 ] in_U;
input [7 : 0 ] in_V;
wire [0 : 0 ] p_n_Y;
wire [0 : 0 ] p_n_U;
wire [0 : 0 ] p_n_V;
wire [7: 0 ] w_in_Y;
wire [7: 0 ] w_in_U;
wire [7: 0 ] w_in_V;
wire [0 : 0 ] p_n_Y2R;
wire [0 : 0 ] p_n_U2R;
wire [0 : 0 ] p_n_V2R;
wire [7 : 0 ] ex_V2R; //1.625
wire [0 : 0 ] p_n_Y2G;
wire [0 : 0 ] p_n_U2G;
wire [0 : 0 ] p_n_V2G;
wire [7 : 0 ] ex_U2G; //-0.25
wire [7 : 0 ] ex_V2G; //-0.78
wire [0 : 0 ] p_n_Y2B;
wire [0 : 0 ] p_n_U2B;
wire [0 : 0 ] p_n_V2B;
wire [7 : 0 ] ex_U2B; //2
wire [19: 0 ] rst_Y2R;
wire [19: 0 ] rst_U2R;
wire [19: 0 ] rst_V2R;
wire [19: 0 ] w_rst_V2R;
wire [19: 0 ] rst_R;
wire [19: 0 ] rst_Y2G;
wire [19: 0 ] rst_U2G;
wire [19: 0 ] w_rst_U2G;
wire [19: 0 ] rst_V2G;
wire [19: 0 ] w_rst_V2G;
wire [19: 0 ] rst_G;
wire [19: 0 ] rst_Y2B;
wire [19: 0 ] rst_U2B;
wire [19: 0 ] w_rst_U2B;
wire [19: 0 ] rst_V2B;
wire [19: 0 ] rst_B;
//&& Chek Positive or Negative, if Negative, reverse it 2 Postive and mark the sign bit
// Y sign extension
assign p_n_Y [0 : 0 ] = 1'b0;
assign w_in_Y[7 : 0 ] = in_Y[7 : 0 ];
// U sign extension
assign p_n_U [0 : 0 ] = in_U[7 : 7 ];
assign w_in_U[7 : 0 ] = ( p_n_U ==1'b0 ) ? in_U[7 : 0 ] : 8'hff - in_U + 8'h01 ;
// V sign extension
assign p_n_V [0 : 0 ] = in_V[7 : 7 ];
assign w_in_V[7 : 0 ] = ( p_n_V ==1'b0 ) ? in_V[7 : 0 ] : 8'hff - in_V + 8'h01 ;
// V2R = 0 => 8'h 1.a
assign p_n_V2R[0 : 0 ] = 1'b0;
assign ex_V2R [7 : 4 ] = 4'h1;
assign ex_V2R [3 : 0 ] = 4'ha;
// U2G = -0.25 => 8'h 0.4
assign p_n_U2G[0 : 0 ] = 1'b1;
assign ex_U2G [7 : 4 ] = 4'h0;
assign ex_U2G [3 : 0 ] = 4'h4;
// V2G = -0.75 => 8'h 0.c
assign p_n_V2G[0 : 0 ] = 1'b1;
assign ex_V2G [7 : 4 ] = 4'h0;
assign ex_V2G [3 : 0 ] = 4'hc;
// U2B = 2 => 8'h 2.0
assign p_n_U2B[0 : 0 ] = 1'b0;
assign ex_U2B [7 : 4 ] = 4'h2;
assign ex_U2B [3 : 0 ] = 4'h0;
// Y2R RST
assign rst_Y2R[19 : 12] = 8'h00;
assign rst_Y2R[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2R[3 : 0 ] = 4'h0;
// U2R RST
assign rst_U2R[19 : 0 ] = 20'h00000;
// V2R RST
assign w_rst_V2R = ( ex_V2R*w_in_V );
assign rst_V2R = ( (p_n_V^p_n_V2R) == 1'b0 )? w_rst_V2R : (20'hfffff - w_rst_V2R + 20'h00001);
assign rst_R = ( rst_Y2R + rst_U2R + rst_V2R );
assign ot_R = ( rst_R[19] == 1'b0 && rst_R[19: 4 ] >= 16'h00ff ) ? 8'hff :
( rst_R[19] == 1'b0 && rst_R[3 : 3 ] == 1'b1 ) ? rst_R[11 : 4 ] + 8'h01 :
( rst_R[19] == 1'b1 ) ? 8'h00 : rst_R[11 : 4 ];
// Y2G RST
assign rst_Y2G[19 : 12] = 8'h00;
assign rst_Y2G[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2G[3 : 0 ] = 4'h0;
// U2G RST
assign w_rst_U2G = ( ex_U2G*w_in_U );
assign rst_U2G = ( (p_n_U^p_n_U2G) == 1'b0 )? w_rst_U2G : (20'hfffff - w_rst_U2G + 20'h00001);
// V2G RST
assign w_rst_V2G = ( ex_V2G*w_in_V );
assign rst_V2G = ( (p_n_V^p_n_V2G) == 1'b0 )? w_rst_V2G : (20'hfffff - w_rst_V2G + 20'h00001);
assign rst_G = ( rst_Y2G + rst_U2G + rst_V2G );
assign ot_G = ( rst_G[19] == 1'b0 && rst_G[19 : 4 ] >= 16'h00ff ) ? 8'hff :
( rst_G[19] == 1'b0 && rst_G[3 : 3 ] == 1'b1 ) ? rst_G[11 : 4 ] + 8'h01 :
( rst_G[19] == 1'b1 ) ? 8'h00 : rst_G[11 : 4 ];
// Y2B RST
assign rst_Y2B[19 : 12] = 8'h00;
assign rst_Y2B[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2B[3 : 0 ] = 4'h0;
// U2B RST
assign w_rst_U2B = ( ex_U2B*w_in_U );
assign rst_U2B = ( (p_n_U^p_n_U2B) == 1'b0 )? w_rst_U2B : (20'hfffff - w_rst_U2B + 20'h00001);
// V2B RST
assign rst_V2B[19 : 0 ] = 20'h00000;
assign rst_B = ( rst_Y2B + rst_U2B + rst_V2B );
assign ot_B = ( rst_B[19] == 1'b0 && rst_B[19 :4 ] >= 20'h00ff ) ? 8'hff :
( rst_B[19] == 1'b0 && rst_B[3 :3 ] == 1'b1 ) ? rst_B[11 : 4 ] + 8'h01 :
( rst_B[19] == 1'b1 ) ? 8'h00 : rst_B[11 : 4 ];
endmodule
RGB2YUV.v
module RGB2YUV ( ot_Y,
ot_U,
ot_V,
in_R,
in_G,
in_B
);
output[7 : 0 ] ot_Y;
output[7 : 0 ] ot_U;
output[7 : 0 ] ot_V;
input [7 : 0 ] in_R;
input [7 : 0 ] in_G;
input [7 : 0 ] in_B;
wire [43 : 0 ] ex_R2Y; //0.2909
wire [43 : 0 ] ex_G2Y; //0.6303
wire [43 : 0 ] ex_B2Y; //0.078
wire [43 : 0 ] rst_Y;
wire [43 : 0 ] ex_R2U; //0.1454
wire [43 : 0 ] ex_G2U; //0.3151
wire [43 : 0 ] ex_B2U; //0.4606
wire [43 : 0 ] rst_U;
wire [43 : 0 ] ex_R2V; //0.1454
wire [43 : 0 ] ex_G2V; //0.3151
wire [43 : 0 ] ex_B2V; //0.4606
wire [43 : 0 ] rst_V;
// 0.2909
assign ex_R2Y [43 : 0 ] = 44'h004A786C227;
//0.6303
assign ex_G2Y [43 : 0 ] = 44'h00A15B573EB;
//0.0787
assign ex_B2Y [43 : 0 ] = 44'h001425AEE63;
assign rst_Y = (ex_R2Y*in_R) + (ex_G2Y*in_G) + (ex_B2Y*in_B);
assign ot_Y = ( rst_Y[43] == 1'b0 && rst_Y[35] == 1'b1 )? rst_Y[43:36] + 8'h01 : rst_Y[43:36];
// 0.1454
assign ex_R2U [43 : 0 ] = 44'h002538EF34D;
//0.3151
assign ex_G2U [43 : 0 ] = 44'h0050AA64C30;
//0.4606
assign ex_B2U [43 : 0 ] = 44'h0075E9E1B09;
assign rst_U = -(ex_R2U*in_R) -(ex_G2U*in_G) + (ex_B2U*in_B);
assign ot_U = ( rst_U[43] == 1'b0 && rst_U[35] == 1'b1 )? rst_U[43:36] + 8'h01 :
( rst_U[43] == 1'b1 && rst_U[35:0] <= 36'h666665 )? rst_U[43:36] - 8'h01 : rst_U[43:36];
// 0.4363
assign ex_R2V [43 : 0 ] = 44'h006FB15B574;
// 0.3878
assign ex_G2V [43 : 0 ] = 44'h006346DC5D6;
// 0.0484
assign ex_B2V [43 : 0 ] = 44'h000C63F1412;
assign rst_V = (ex_R2V*in_R) -(ex_G2V*in_G) - (ex_B2V*in_B);
assign ot_V = ( rst_V[43] == 1'b0 && rst_V[35] == 1'b1 )? rst_V[43:36] + 8'h01 :
( rst_V[43] == 1'b1 && rst_V[35:0] <= 36'h666665 )? rst_V[43:36] - 8'h01 : rst_V[43:36];
endmodule
compile
% iverilog -o CTE CTE.v testfixture1.v
% ./CTE
Simulation Results
testfixture1.v
Congratulations! All data have been generated
successfully!
testfixture2.v
Square Distance of All
YUV = 233.000000
Square of All
YUV Signal = 21561234.000000
-----------------------------------------------------
So Your Error Ratio:
(Square Distance of
YUV)/(Square of All
YUV Signal) = 0.000011
-----------------------------------------------------
Your Score Level: E
Congratulations!
CTE's Function2
Successfully!
PS: 可以調整循環小數的精確度讓 Error Rate變小, 不過相對的 Area 跟 Time 會是 cost function
Download
http://sites.google.com/site/funningboy/verilog/ICC2009.tar?attredirects=0&d=1
Verilog Quick Reference
回覆刪除http://www.asic-world.com/verilog/vqref1.html
RGB2YUV 那個負數進位 好像這樣才對
回覆刪除rst_U[43] == 1'b1 && rst_U[35:0] <= 36'h666666666 )? rst_U[43:36] : rst_U[43:36]+ 8'h1;
0.4*2^36 轉成16進制 應該是有9個6~
101.01 為-4+1+0.25=-2.75,進位之後為-3,整數部分為-3,故小數部分小於0.4結果不變。
101.11為-4+1+0.75=-2.25,結果應捨去為-2,但整數部分為-3,故需加1才為所求。
版主您參考一下
感謝你這篇文章跟浮點數運算那篇, 讓我獲益良多。
感謝改錯
回覆刪除你好,想請教您一個問題:我想要增加循環小數的準確度(ex. 0.2909,09循環)是不是只要增加運算時候的bit數? 因為我試過這個方式增加到56bit,但是error還是在E level,如果方便回復的話請用email與我聯絡謝謝你!^^ (fengwei1012111@gmail.com)
回覆刪除