// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2010 by Lattice Semiconductor Corporation
// Permission:
//   Lattice Semiconductor grants permission to use this code for use
//   in synthesis for any Lattice programmable logic product.  Other
//   use of this code, including the selling or duplication of any
//   portion is strictly prohibited.
// Disclaimer:
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Lattice Semiconductor provides no warranty
//   regarding the use or functionality of this code.                
// --------------------------------------------------------------------                
//                     Lattice Semiconductor Corporation                
//                     5555 NE Moore Court                
//                     Hillsboro, OR 97214                
//                     U.S.A                         
//                     TEL: 1-800-Lattice (USA and Canada)                
//                          503-268-8001 (other locations)                
//                     web: http://www.latticesemi.com/                
//                     email: techsupport@latticesemi.com                
// --------------------------------------------------------------------    
module pix_clock_gen #(
parameter pmi_family     = "XO2",           //"ECP3" or "XP2"
parameter c_WORD_WIDTH   = 12,              //8/10/12/14/16
parameter c_LANE_WIDTH   = 2                //LANE NUMBER 1/2/3/4
)(
input rstn,
input clk_div2,
output pixel_clk,
output pixel_clk_x2,
output pixel_clk_x2_45deg,
output reg lock_status
);
wire  pll_lock /*synthesis syn_keep = 1 */;
reg   pll_lock_d1 /*synthesis syn_preserve = 1 */;
reg   pll_lock_sync /*synthesis syn_preserve = 1 */;
reg   [7:0] pll_lock_d /*synthesis syn_preserve = 1 */;

//frequency of pixel_clk = frequency of clk_div2 * c_LANE_WIDTH * 4 / c_WORD_WIDTH
generate                          
   if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 1) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (2/5)
pll_ww10_1lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 1) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (2/5)
pll_ww10_1lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

//   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 2) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (4/5)
//pll_ww10_2lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 2) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (3/2)
pll_ww10_2lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 2) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (4/5)
pll_ww10_2lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 3) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (6/5)
pll_ww10_3lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 3) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (6/5)
pll_ww10_3lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 4) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (8/5)
pll_ww10_4lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 10) && (c_LANE_WIDTH == 4) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (8/5)
pll_ww10_4lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

//   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 1) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (1/3)
//pll_ww12_1lane_xp2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 1) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (1/3)
pll_ww12_1lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 1) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (1/3)
pll_ww12_1lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

//   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 2) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (2/3)
//pll_ww12_2lane_xp2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 2) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (2/3)
pll_ww12_2lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk_x2), .CLKOS(pixel_clk_x2_45deg), .CLKOS2(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 2) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (2/3)
pll_ww12_2lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 3) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (1/1)
pll_ww12_3lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 3) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (1/1)
pll_ww12_3lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 4) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div4 * (2/3)
pll_ww12_4lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~rstn), .CLKOP(pixel_clk_x2), .CLKOS(pixel_clk_x2_45deg), .CLKOS2(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 12) && (c_LANE_WIDTH == 4) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (4/3)
pll_ww12_4lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 1) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (2/7)
pll_ww14_1lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 1) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (2/7)
pll_ww14_1lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

//   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 2) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (4/7)
//pll_ww14_2lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 2) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (4/7)
pll_ww14_2lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 2) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (4/7)
pll_ww14_2lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 3) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (6/7)
pll_ww14_3lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 3) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (6/7)
pll_ww14_3lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 4) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (8/7)
pll_ww14_4lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 14) && (c_LANE_WIDTH == 4) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (8/7)
pll_ww14_4lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 1) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (1/4)
pll_ww16_1lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 1) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (1/4)
pll_ww16_1lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 2) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (1/2)
pll_ww16_2lane_xo2   I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 2) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (1/2)
pll_ww16_2lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 3) && (pmi_family == "XP2")) //frequency of pixel_clk = frequency of clk_div2 * (3/4)
pll_ww16_3lane_xp2  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn && (pmi_family == "ECP3")), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 3)) //frequency of pixel_clk = frequency of clk_div2 * (3/4)
pll_ww16_3lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 4) && (pmi_family == "XO2")) //frequency of pixel_clk = frequency of clk_div2 * (1/1)
pll_ww16_4lane_xo2  I_pll_ww (.CLKI(clk_div2), .RST(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));
   else if ((c_WORD_WIDTH == 16) && (c_LANE_WIDTH == 4) && (pmi_family == "ECP3")) //frequency of pixel_clk = frequency of clk_div2 * (1/1)
pll_ww16_4lane_ecp3  I_pll_ww (.CLK(clk_div2), .RESET(~ rstn), .CLKOP(pixel_clk), .LOCK(pll_lock));

endgenerate

always @(posedge clk_div2 or negedge rstn)
   if (!rstn) begin
      pll_lock_d1   <= 0;
      pll_lock_sync <= 0;
      pll_lock_d    <= 0;
      lock_status   <= 1'b0;
   end
   else begin
      pll_lock_d1   <= pll_lock;
      pll_lock_sync <= pll_lock_d1;
      
      pll_lock_d <= {pll_lock_d[6:0], pll_lock_sync};
      if (pll_lock_d == 8'hff)
         lock_status <= 1'b1;
      else if (pll_lock_d == 8'h00)
         lock_status <= 1'b0;
   end


endmodule