OpenCores
URL https://opencores.org/ocsvn/mpeg2fpga/mpeg2fpga/trunk

Subversion Repositories mpeg2fpga

[/] [mpeg2fpga/] [trunk/] [rtl/] [mpeg2/] [yuv2rgb.v] - Rev 2

Compare with Previous | Blame | View Log

/* 
 * yuv2rgb.v
 * 
 * Copyright (c) 2006 - 2007 Koen De Vleeschauwer. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */
 
/*
 * yuv2rgb - conversion from y, u, v, to r, g, b.
 */
 
`include "timescale.v"
 
`undef DEBUG
//`define DEBUG 1
 
module yuv2rgb (clk, clk_en, rst,
                matrix_coefficients, y, u, v, h_sync_in, v_sync_in, pixel_en_in,
                r, g, b, y_out, u_out, v_out, h_sync_out, v_sync_out, c_sync_out, pixel_en_out
                );
  input  clk;
  input  clk_en;
  input  rst;
 
  input [7:0] matrix_coefficients; /* extracted from mpeg2 bitstream. Determines yuv -> rgb conversion factors. ISO/IEC 13818-2, par. 6.3.6 */
 
  input [7:0]y;
  input [7:0]u;
  input [7:0]v;
 
  output reg [7:0]r;
  output reg [7:0]g;
  output reg [7:0]b;
  output reg [7:0]y_out;
  output reg [7:0]u_out;
  output reg [7:0]v_out;
 
  /*
   * pixel_en_out, h_sync_out, v_sync_out are pixel_en_in, h_sync_in and v_sync_in, delayed so as to balance the delay from yuv -> rgb.
   * Typical use is to connect r, g, b to the 24-bit data-in of the dvi transmitter,
   * pixel_en_out, h_sync_out and video_out to de (data enable), h_sync and v_sync of the dvi transmitter.
   */
 
  input pixel_en_in;
  input h_sync_in;
  input v_sync_in;
  output reg pixel_en_out;
  output reg h_sync_out;
  output reg v_sync_out;
  output reg c_sync_out;
 
  reg signed [26:0]cy_y;
  reg signed [26:0]crv_v;
  reg signed [26:0]cbu_u;
  reg signed [26:0]cgu_u;
  reg signed [26:0]cgv_v;
 
  reg signed [17:0]crv;
  reg signed [17:0]cbu;
  reg signed [17:0]cgu;
  reg signed [17:0]cgv;
 
  reg signed [8:0]y_offset;
  reg signed [8:0]u_offset;
  reg signed [8:0]v_offset;
 
  reg signed [29:0]r_0;
  reg signed [29:0]g1_0;
  reg signed [29:0]g2_0;
  reg signed [29:0]b_0;
 
  reg signed [29:0]r_1;
  reg signed [29:0]g_1;
  reg signed [29:0]b_1;
 
  reg pixel_en_0;
  reg h_sync_0;
  reg v_sync_0;
  reg [7:0]y_0;
  reg [7:0]u_0;
  reg [7:0]v_0;
 
  reg pixel_en_1;
  reg h_sync_1;
  reg v_sync_1;
  reg [7:0]y_1;
  reg [7:0]u_1;
  reg [7:0]v_1;
 
  reg pixel_en_2;
  reg h_sync_2;
  reg v_sync_2;
  reg [7:0]y_2;
  reg [7:0]u_2;
  reg [7:0]v_2;
 
  /*
   * Simplify matrix_coefficients: values 8..255 are reserved and should not occur.
   * If value of matrix_coefficients outside 0..7 range, replace with 0.
   */
 
  reg         [2:0]mat_coeff;
  always @(posedge clk)
    if (~rst) mat_coeff <= 0;
    else if (clk_en && (matrix_coefficients[7:3] == 5'b0)) mat_coeff <= matrix_coefficients[2:0];
    else mat_coeff <= 0;
 
  /*
   *
   * Table 6-9 inverted.
   *
   * y        = cr * r + cg * g + cb * b
   * cr + cg + cb = 1
   *
   * cy       = (255/219) * 32768
   * crv      = (255/224) * 32768 * (1-cr) / 0.5
   * cbu      = (255/224) * 32768 * (1-cb) / 0.5
   * cgu      = (255/224) * 32768 * (cb/cg) * (1 - cb) / 0.5
   * cgv      = (255/224) * 32768 * (cr/cg) * (1 - cr) / 0.5
   * r        = ( cy * (y - 16)                   + crv * (v - 128) + 16384) >> 15;
   * g        = ( cy * (y - 16) - cgu * (u - 128) + crv * (v - 128) + 16384) >> 15;
   * b        = ( cy * (y - 16) - cbu * (u - 128)                   + 16384) >> 15;
   */
 
  parameter signed [17:0]
    cy = 18'sd38155;
 
  always @(posedge clk)
    if (clk_en)
      case (mat_coeff)
        3'd0, /* default value, no sequence_display_extension */
        3'd1: /* ITU-R Rec. 709 (1990) */
              begin
                crv <= 18'sd58752;
                cbu <= 18'sd69227;
                cgu <= 18'sd6977;
                cgv <= 18'sd17452;
              end
        3'd2, /* unspecified */
        3'd3, /* reserved */
        3'd5, /* ITU-R Rec. 624-4 System B, G */
        3'd6: /* SMPTE 170M */
              begin
                crv <= 18'sd52299;
                cbu <= 18'sd66101;
                cgu <= 18'sd12838;
                cgv <= 18'sd26640;
              end
        3'd4: /* FCC */
              begin
                crv <= 18'sd52224;
                cbu <= 18'sd66399;
                cgu <= 18'sd12380;
                cgv <= 18'sd26555;
              end
        3'd7: /* SMPTE 240M (1987) */
              begin
                crv <= 18'sd58790;
                cbu <= 18'sd68115;
                cgu <= 18'sd8454;
                cgv <= 18'sd17780;
              end
     endcase
 
  /* conversion */
  always @(posedge clk)
    if (~rst)
      begin
        y_offset <= 0;
        u_offset <= 0;
        v_offset <= 0;
 
        cy_y  <= 0;
        crv_v <= 0;
        cgv_v <= 0;
        cgu_u <= 0;
        cbu_u <= 0;
 
        r_0   <= 0;
        g1_0  <= 0;
        g2_0  <= 0;
        b_0   <= 0;
 
        r_1   <= 0;
        g_1   <= 0;
        b_1   <= 0;
      end
    else if (clk_en)
      begin
        y_offset <= {1'b0, y} - 9'sd16;
        u_offset <= {1'b0, u} - 9'sd128;
        v_offset <= {1'b0, v} - 9'sd128;
 
        cy_y  <= cy  * y_offset;
        cgu_u <= cgu * u_offset;
        cbu_u <= cbu * u_offset;
        crv_v <= crv * v_offset;
        cgv_v <= cgv * v_offset;
 
        r_0   <=   {{3{cy_y[26]}}, cy_y}  + {{3{crv_v[26]}}, crv_v};
        g1_0  <=   {{3{cy_y[26]}}, cy_y}  - {{3{cgu_u[26]}}, cgu_u};
        g2_0  <=                          - {{3{cgv_v[26]}}, cgv_v} + 30'sd16384;
        b_0   <=   {{3{cy_y[26]}}, cy_y}  + {{3{cbu_u[26]}}, cbu_u};
 
        r_1   <= (r_0 + 30'sd16384) >>> 15;
        g_1   <= (g1_0 + g2_0) >>> 15;
        b_1   <= (b_0 + 30'sd16384) >>> 15;
      end
    else
      begin
        y_offset <= y_offset;
        u_offset <= u_offset;
        v_offset <= v_offset;
 
        cy_y  <= cy_y;
        cgu_u <= cgu_u;
        cbu_u <= cbu_u;
        crv_v <= crv_v;
        cgv_v <= cgv_v;
 
        r_0   <= r_0;
        g1_0  <= g1_0;
        g2_0  <= g2_0;
        b_0   <= b_0;
 
        r_1   <= r_1;
        g_1   <= r_1;
        b_1   <= r_1;
      end
 
  /* clipping */
  always @(posedge clk)
    if (~rst) r <= 8'd0;
    else if (clk_en && r_1[29]) r <= 8'd0; /* negative, clip to 0 */
    else if (clk_en && (r_1[29:8] != 22'b0)) r <= 8'd255; /* 256 or more, clip to 255 */
    else if (clk_en) r <= r_1[7:0]; /* between 0 and 255, copy */
    else r <= r;
 
  always @(posedge clk)
    if (~rst) g <= 8'd0;
    else if (clk_en && g_1[29]) g <= 8'd0;
    else if (clk_en && (g_1[29:8] != 22'b0)) g <= 8'd255;
    else if (clk_en) g <= g_1[7:0];
    else g <= g;
 
  always @(posedge clk)
    if (~rst) b <= 8'd0;
    else if (clk_en && b_1[29]) b <= 8'd0;
    else if (clk_en && (b_1[29:8] != 22'b0)) b <= 8'd255;
    else if (clk_en) b <= b_1[7:0];
    else b <= b;
 
 /* delay pixel_en, h_sync and v_sync so they are balanced with r, g, b */
 
  always @(posedge clk)
    if (~rst)
      begin
        pixel_en_0 <= 1'b0;
        pixel_en_1 <= 1'b0;
        pixel_en_2 <= 1'b0;
        pixel_en_out <= 1'b0;
     end
   else if (clk_en)
     begin
        pixel_en_0 <= pixel_en_in;
        pixel_en_1 <= pixel_en_0;
        pixel_en_2 <= pixel_en_1;
        pixel_en_out <= pixel_en_2;
     end
   else
     begin
        pixel_en_0 <= pixel_en_0;
        pixel_en_1 <= pixel_en_1;
        pixel_en_2 <= pixel_en_2;
        pixel_en_out <= pixel_en_out;
     end
 
  always @(posedge clk)
    if (~rst)
      begin
        h_sync_0 <= 1'b0;
        h_sync_1 <= 1'b0;
        h_sync_2 <= 1'b0;
        h_sync_out <= 1'b0;
     end
   else if (clk_en)
     begin
        h_sync_0 <= h_sync_in;
        h_sync_1 <= h_sync_0;
        h_sync_2 <= h_sync_1;
        h_sync_out <= h_sync_2;
     end
   else
     begin
        h_sync_0 <= h_sync_0;
        h_sync_1 <= h_sync_1;
        h_sync_2 <= h_sync_2;
        h_sync_out <= h_sync_out;
     end
 
  always @(posedge clk)
    if (~rst)
      begin
        v_sync_0 <= 1'b0;
        v_sync_1 <= 1'b0;
        v_sync_2 <= 1'b0;
        v_sync_out <= 1'b0;
     end
   else if (clk_en)
     begin
        v_sync_0 <= v_sync_in;
        v_sync_1 <= v_sync_0;
        v_sync_2 <= v_sync_1;
        v_sync_out <= v_sync_2;
     end
   else
     begin
        v_sync_0 <= v_sync_0;
        v_sync_1 <= v_sync_1;
        v_sync_2 <= v_sync_2;
        v_sync_out <= v_sync_out;
     end
  /*
   * composite sync
   */
 
  always @(posedge clk)
    if (~rst) c_sync_out <= 1'b0;
    else if (clk_en) c_sync_out <= ~(h_sync_2 ^ v_sync_2);
    else c_sync_out <= c_sync_out;
 
  /*
   * yuv
   */
 
  always @(posedge clk)
    if (~rst)
      begin
        y_0 <= 8'd0;
        y_1 <= 8'd0;
        y_2 <= 8'd0;
        y_out <= 8'd0;
     end
   else if (clk_en)
     begin
        y_0 <= y;
        y_1 <= y_0;
        y_2 <= y_1;
        y_out <= y_2;
     end
   else
     begin
        y_0 <= y_0;
        y_1 <= y_1;
        y_2 <= y_2;
        y_out <= y_out;
     end
 
  always @(posedge clk)
    if (~rst)
      begin
        u_0 <= 8'd0;
        u_1 <= 8'd0;
        u_2 <= 8'd0;
        u_out <= 8'd0;
     end
   else if (clk_en)
     begin
        u_0 <= u;
        u_1 <= u_0;
        u_2 <= u_1;
        u_out <= u_2;
     end
   else
     begin
        u_0 <= u_0;
        u_1 <= u_1;
        u_2 <= u_2;
        u_out <= u_out;
     end
 
  always @(posedge clk)
    if (~rst)
      begin
        v_0 <= 8'd0;
        v_1 <= 8'd0;
        v_2 <= 8'd0;
        v_out <= 8'd0;
     end
   else if (clk_en)
     begin
        v_0 <= v;
        v_1 <= v_0;
        v_2 <= v_1;
        v_out <= v_2;
     end
   else
     begin
        v_0 <= v_0;
        v_1 <= v_1;
        v_2 <= v_2;
        v_out <= v_out;
     end
 
`ifdef DEBUG
  always @(posedge clk)
    begin
      $strobe("%m\tyuv: %0d %0d %0d pixel_en_in: %0d rgb: %0d %0d %0d pixel_en_out: %0d", y, u, v, pixel_en_in, r, g, b, pixel_en_out);
      $strobe("%m\tmatrix_coefficients: %4d y: %4d u: %4d v: %d y_offset: %d u_offset: %d v_offset: %d cy_y: %d crv_v: %d cgv_v: %d cgu_u: %d cbu_u: %d r_0: %d g1_0: %d g2_0: %d b_0: %d r_1: %d g_1: %d b_1: %d r: %4d g: %4d b: %4d ", 
                   matrix_coefficients,     y,     u,     v,    y_offset,    u_offset,    v_offset,    cy_y,    crv_v,    cgv_v,    cgu_u,    cbu_u,    r_0,    g1_0,    g2_0,    b_0,    r_1,    g_1,    b_1,    r,     g,     b);
    end
`endif
endmodule
/* not truncated */
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.