module csc 
(
  Clock,
  ClockEnable,
  Reset,
  R,
  G,
  B,
  Y,
  Cb,
  Cr
);

parameter OUT_SIZE  =  8; // uncomment to get  8-bit input & output...
//  parameter OUT_SIZE  = 10; // uncomment to get 10-bit input & output...


  input  Clock; 
  input  ClockEnable; 
  input  Reset; 
  input  [(OUT_SIZE - 1):0] R; 
  input  [(OUT_SIZE - 1):0] G; 
  input  [(OUT_SIZE - 1):0] B; 
  output [(OUT_SIZE - 1):0] Y; 
  output [(OUT_SIZE - 1):0] Cb; 
  output [(OUT_SIZE - 1):0] Cr; 

  reg [(OUT_SIZE - 1):0] Y;
  reg [(OUT_SIZE - 1):0] Cb;
  reg [(OUT_SIZE - 1):0] Cr;

  // Constants and precision for each coefficients...
  //
  //-- 8-bit for Y601, Cb and Cr...
  //parameter CST_Y601_red   =   66;
  //parameter CST_Y601_green =  129;
  //parameter CST_Y601_blue  =   25;
  //parameter CST_Y601_Prec  =    8; --  8-bit (256)
  //--
  //parameter CST_Cb_red     =   38;
  //parameter CST_Cb_green   =   74;
  //parameter CST_Cb_blue    =  112;
  //parameter CST_Cb_Prec    =    8; --  8-bit (256)
  //--
  //parameter CST_Cr_red     =  112;
  //parameter CST_Cr_green   =   94;
  //parameter CST_Cr_blue    =   18;
  //parameter CST_Cr_Prec    =    8; --  8-bit (256)
  //
  //-- 9-bit for Y601, Cb and Cr...
  //parameter CST_Y601_red   =  132;
  //parameter CST_Y601_green =  258;
  //parameter CST_Y601_blue  =   50;
  //parameter CST_Y601_Prec  =    9; --  9-bit (512)
  //--
  //parameter CST_Cb_red     =   76;
  //parameter CST_Cb_green   =  149;
  //parameter CST_Cb_blue    =  225;
  //parameter CST_Cb_Prec    =    9; --  9-bit (512)
  //--
  //parameter CST_Cr_red     =  225;
  //parameter CST_Cr_green   =  188;
  //parameter CST_Cr_blue    =   36;
  //parameter CST_Cr_Prec    =    9; --  9-bit (512)
  //
  //-- 10-bit for Y601, Cb and Cr...
  //parameter CST_Y601_red   =  263;
  //parameter CST_Y601_green =  516;
  //parameter CST_Y601_blue  =  100;
  //parameter CST_Y601_Prec  =   10; --  10-bit (1024)
  //--
  //parameter CST_Cb_red     =  152;
  //parameter CST_Cb_green   =  298;
  //parameter CST_Cb_blue    =  450;
  //parameter CST_Cb_Prec    =   10; --  10-bit (1024)
  //--
  parameter CST_Cr_red     = 450; 
  parameter CST_Cr_green   = 377; 
  parameter CST_Cr_blue    =  73; 
  parameter CST_Cr_Prec    =  10; //  10-bit (1024)
  //
  //-- 11-bit for Y601, Cb and Cr...
  //parameter CST_Y601_red   =  526;
  //parameter CST_Y601_green = 1032;
  //parameter CST_Y601_blue  =  201;
  //parameter CST_Y601_Prec  =   11; --  11-bit (2048)
  //--
  parameter CST_Cb_red     = 303; 
  parameter CST_Cb_green   = 596; 
  parameter CST_Cb_blue    = 899; 
  parameter CST_Cb_Prec    =  11; //  11-bit (2048)
  //--
  //parameter CST_Cr_red     =  899;
  //parameter CST_Cr_green   =  754;
  //parameter CST_Cr_blue    =  145;
  //parameter CST_Cr_Prec    =   11; --  11-bit (2048)
  //
  //--12-bit for Y601, Cb and Cr...
  //parameter CST_Y601_red   = 1053;
  //parameter CST_Y601_green = 2064;
  //parameter CST_Y601_blue  =  401;
  //parameter CST_Y601_Prec  =   12; --  12-bit (4096)
  //--
  //parameter CST_Cb_red     =  606;
  //parameter CST_Cb_green   = 1192;
  //parameter CST_Cb_blue    = 1798;
  //parameter CST_Cb_Prec    =   12; --  12-bit (4096)
  //--
  //parameter CST_Cr_red     = 1798;
  //parameter CST_Cr_green   = 1507;
  //parameter CST_Cr_blue    =  291;
  //parameter CST_Cr_Prec    =   12; --  12-bit (4096)
  //
  //-- 13-bit for Y601, Cb and Cr...
  parameter CST_Y601_red   = 2105; 
  parameter CST_Y601_green = 4129; 
  parameter CST_Y601_blue  =  803; 
  parameter CST_Y601_Prec  =   13; //  13-bit (8192)
  //--
  //parameter CST_Cb_red     = 1212;
  //parameter CST_Cb_green   = 2384;
  //parameter CST_Cb_blue    = 3596;
  //parameter CST_Cb_Prec    =   13; --  13-bit (8192)
  //--
  //parameter CST_Cr_red     = 3596;
  //parameter CST_Cr_green   = 3015;
  //parameter CST_Cr_blue    =  582;
  //parameter CST_Cr_Prec    =   13; --  13-bit (8192)
  //
  //
  //
  // Combined constants...
  parameter CST_Y601_OutSize = CST_Y601_Prec + OUT_SIZE; 
  parameter CST_Cb_OutSize   = CST_Cb_Prec   + OUT_SIZE; 
  parameter CST_Cr_OutSize   = CST_Cr_Prec   + OUT_SIZE; 
  // Takes care of offset for 8- and 10-bit input/output entity
  parameter CST_Offset_Y601  = ( ( 33 << (OUT_SIZE - 8) ) << (CST_Y601_Prec - 1) );  // (  16 + 0.5 ) * 2 * 2^(CST_Y601_Prec-1)
  parameter CST_Offset_Cb    = ( (257 << (OUT_SIZE - 8) ) << (  CST_Cb_Prec - 1) );  // ( 128 + 0.5 ) * 2 * 2^(CST_Cb_Prec-1)
  parameter CST_Offset_Cr    = ( (257 << (OUT_SIZE - 8) ) << (  CST_Cr_Prec - 1) );  // ( 128 + 0.5 ) * 2 * 2^(CST_Cr_Prec-1)
  //
  //
  // Component Declarations
  // Constant multipliers Y601, Cb and Cr components...
  // Define internal signals
  wire [(CST_Y601_OutSize - 1):0] Y_R_KCM; 
  wire [(CST_Y601_OutSize - 1):0] Y_G_KCM; 
  wire [(CST_Y601_OutSize - 1):0] Y_B_KCM; 
  wire [  (CST_Cb_OutSize - 1):0] Cb_R_KCM; 
  wire [  (CST_Cb_OutSize - 1):0] Cb_G_KCM; 
  wire [  (CST_Cb_OutSize - 1):0] Cb_B_KCM; 
  wire [  (CST_Cr_OutSize - 1):0] Cr_R_KCM; 
  wire [  (CST_Cr_OutSize - 1):0] Cr_G_KCM; 
  wire [  (CST_Cr_OutSize - 1):0] Cr_B_KCM; 
  //
  reg [ (CST_Y601_OutSize - 1):0] Y_cst_G; 
  reg [   (CST_Cb_OutSize - 1):0] Cb_cst_B; 
  reg [   (CST_Cr_OutSize - 1):0] Cr_cst_R; 
  //
  reg [(CST_Y601_OutSize - 1):0] Y_Red_Blue; 
  reg [(CST_Y601_OutSize - 1):0] Y601_full; 
  reg [  (CST_Cb_OutSize - 1):0] Cb_Red_Green; 
  reg [  (CST_Cb_OutSize - 1):0] Cb_full; 
  reg [  (CST_Cr_OutSize - 1):0] Cr_Green_Blue; 
  reg [  (CST_Cr_OutSize - 1):0] Cr_full; 


  // ---------------------------------
  // Compute the Y601 component...
  // ---------------------------------
  const_mult #(OUT_SIZE, CST_Y601_OutSize, CST_Y601_red)   Y601_KCM_red(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(R), .Color_Out(Y_R_KCM)); 

  const_mult #(OUT_SIZE, CST_Y601_OutSize, CST_Y601_green) Y601_KCM_green(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(G), .Color_Out(Y_G_KCM)); 

  const_mult #(OUT_SIZE, CST_Y601_OutSize, CST_Y601_blue)  Y601_KCM_blue(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(B), .Color_Out(Y_B_KCM)); 

  // Adder for (G + constant), where constant "16" is scaled up by Y601 coefficient precision
  // Constant is also modified to perform rounding (+0.5)
  always @(posedge Clock or posedge Reset)
  begin : CST_Green_Adder
    if (Reset)
      Y_cst_G <= 0; 
    else if (ClockEnable)
      Y_cst_G <= Y_G_KCM + CST_Offset_Y601; // add 16.5 (scaled up by coefficient precision)
  end 

  // Adder for (R + B)
  always @(posedge Clock or posedge Reset)
  begin : Y_Red_Blue_Adder
    if (Reset)
      Y_Red_Blue <= 0; 
    else if (ClockEnable)
      Y_Red_Blue <= Y_R_KCM + Y_B_KCM; 
  end 

  // Adder for Y601 => (R + B) + (G + constant), where constant "16.5" is scaled up by coefficient precision
  always @(posedge Clock or posedge Reset)
  begin : Y601_Adder
    if (Reset)
      Y601_full <= 0;
    else if (ClockEnable)
      Y601_full <= Y_Red_Blue + Y_cst_G; 
  end 


  // ---------------------------------
  // Compute the Cb component...
  // ---------------------------------
  const_mult #(OUT_SIZE, CST_Cb_OutSize, CST_Cb_red)   Cb_KCM_red(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(R), .Color_Out(Cb_R_KCM)); 

  const_mult #(OUT_SIZE, CST_Cb_OutSize, CST_Cb_green) Cb_KCM_green(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(G), .Color_Out(Cb_G_KCM)); 

  const_mult #(OUT_SIZE, CST_Cb_OutSize, CST_Cb_blue)  Cb_KCM_blue(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(B), .Color_Out(Cb_B_KCM)); 

  // Adder for (B + constant), where constant "128" is scaled up by Cb coefficient precision
  // Constant is also modified to perform rounding (+0.5)
  always @(posedge Clock or posedge Reset)
  begin : CST_Blue_Adder
    if (Reset)
      Cb_cst_B <= 0; 
    else if (ClockEnable)
      Cb_cst_B <= Cb_B_KCM + CST_Offset_Cb; // add 128.5 (scaled up by coefficient precision)
  end 

  // Adder for R + G
  always @(posedge Clock or posedge Reset)
  begin : Cb_Red_Green_Adder
    if (Reset)
      Cb_Red_Green <= 0;
    else if (ClockEnable)
      Cb_Red_Green <= Cb_R_KCM + Cb_G_KCM;
  end 

  // Subtractor for Cb => (B + constant) - (R + G), where constant "128.5" is scaled up by coefficient precision
  always @(posedge Clock or posedge Reset)
  begin : Cb_Subt
     if (Reset)
       Cb_full <= 0;
     else if (ClockEnable)
       Cb_full <= Cb_cst_B - Cb_Red_Green;
  end 


  // ---------------------------------
  // Compute the Cr component...
  // ---------------------------------
  const_mult #(OUT_SIZE, CST_Cr_OutSize, CST_Cr_red)   Cr_KCM_red(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(R), .Color_Out(Cr_R_KCM)); 

  const_mult #(OUT_SIZE, CST_Cr_OutSize, CST_Cr_green) Cr_KCM_green(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(G), .Color_Out(Cr_G_KCM)); 

  const_mult #(OUT_SIZE, CST_Cr_OutSize, CST_Cr_blue)  Cr_KCM_blue(.Clock(Clock), .ClockEnable(ClockEnable), .Reset(Reset), .Color(B), .Color_Out(Cr_B_KCM)); 

  // Adder for (R + constant), where constant "128" is scaled up by Cr coefficient precision
  // Constant is also modified to perform rounding (+0.5)
  always @(posedge Clock or posedge Reset)
  begin : CST_Red_Adder
    if (Reset)
      Cr_cst_R <= 0;
    else if (ClockEnable)
      Cr_cst_R <= Cr_R_KCM + CST_Offset_Cr; // add 128.5 (scaled up by coefficient precision)
  end 

  // Adder for G + B
  always @(posedge Clock or posedge Reset)
  begin : Cr_Green_Blue_Adder
    if (Reset)
      Cr_Green_Blue <= 0;
    else if (ClockEnable)
      Cr_Green_Blue <= Cr_G_KCM + Cr_B_KCM;
  end 

  // Subtractor for Cr => (R + constant) - (G + B), where constant "128.5" is scaled up by coefficient precision
  always @(posedge Clock or posedge Reset)
  begin : Cr_Subt
    if (Reset)
      Cr_full <= 0; 
    else if (ClockEnable)
      Cr_full <= Cr_cst_R - Cr_Green_Blue;
  end 


  // Limit and rounding: discard unwanted precision bits
  // Rounding already computed in result...
  always @(Y601_full or Cb_full or Cr_full)
  begin
     Y = Y601_full [(CST_Y601_OutSize - 1):(CST_Y601_OutSize - OUT_SIZE)] ; // divide by 2^(CST_Y601_OutSize-8)...
    Cb =   Cb_full [  (CST_Cb_OutSize - 1):  (CST_Cb_OutSize - OUT_SIZE)] ; // divide by 2^(CST_Cb_OutSize-8)...
    Cr =   Cr_full [  (CST_Cr_OutSize - 1):  (CST_Cr_OutSize - OUT_SIZE)] ; // divide by 2^(CST_Cr_OutSize-8)...
  end

endmodule