2010年6月28日 星期一

Color Transform Engine @ Verilog

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 切乾淨 把 YUV2RGBRGB2YUV 分成兩個 PE(process element), 再用 Ctl status 來控制每個 status. 3. 處理 Input/Output 的 Sequence YUV / RGB 的 vector 擺放位置跟順序關係 底下就針對這3個 topic 來完成Design YUV2RGB.v 為 YUV2RGB PE RGB2YUV.v 為 RGB2YUV 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

4 則留言:

  1. Verilog Quick Reference

    http://www.asic-world.com/verilog/vqref1.html

    回覆刪除
  2. 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才為所求。

    版主您參考一下
    感謝你這篇文章跟浮點數運算那篇, 讓我獲益良多。

    回覆刪除
  3. 你好,想請教您一個問題:我想要增加循環小數的準確度(ex. 0.2909,09循環)是不是只要增加運算時候的bit數? 因為我試過這個方式增加到56bit,但是error還是在E level,如果方便回復的話請用email與我聯絡謝謝你!^^ (fengwei1012111@gmail.com)

    回覆刪除