//------------------------------------------------------------------
// Catalina Rx interface:
//
// Use XILINX SERDES to de-serialize interleaved sample data off
// half-wordwidth LVDS differnetial data bus from catalina.
//
// Use FRAME signal to initially synchronise to incomming data after reset
// de-asserts.
//
// In all modes (SISO or MIMO) we output a clock of 1/4 the frequency
// of the Catalina source-synchronous bus clock to be used as the radio_clk.
//
// In SISO mode, every cycle of the radio_clk supplies a new RX sample which
// is routed to both radios, even if only one is actively receving.
//
// In MIMO mode, every other cycle of the radio clock supplies a pair of
// time alligned MIMO samples which are routed to different radios.
//
//------------------------------------------------------------------


module cat_input_lvds
  #(
    parameter INVERT_FRAME_RX = 0,
    parameter INVERT_DATA_RX = 6'b00_0000,
    parameter CLOCK_DELAY = 0,
    parameter DATA_DELAY = 0,
    parameter WIDTH = 6,
    parameter GROUP = "DEFAULT"
    )
    (
     input 			clk200,
     input 			rst,
     input 			mimo,
     // Region local Clocks for I/O cells.
     output                     ddr_clk,
     output                     sdr_clk,
     
     // Source Synchronous external input clock
     input 			ddr_clk_p,
     input 			ddr_clk_n,
     // Source Synchronous data lines
     input [WIDTH-1:0] 		ddr_data_p,
     input [WIDTH-1:0] 		ddr_data_n,
     input 			ddr_frame_p,
     input 			ddr_frame_n,
     // delay control interface
     input 			ctrl_clk,
     input [4:0]		ctrl_data_delay,
     input [4:0]		ctrl_clk_delay,
     input 			ctrl_ld_data_delay,
     input                      ctrl_ld_clk_delay,
     // global output clocks, ddr_clk/4 & ddr_clk/2
     output 			radio_clk,
     output                     radio_clk_2x,
     // SDR Data buses
     output reg [(WIDTH*2)-1:0] i0,
     output reg [(WIDTH*2)-1:0] q0,
     output reg [(WIDTH*2)-1:0] i1,
     output reg [(WIDTH*2)-1:0] q1, 
     output reg 		rx_aligned
     );
   
   //------------------------------------------------------------------
   // UG471 says take reset high asynchronously, and de-assert
   // synchronized to CLKDIV (sdr_clk) for SERDES.
   //------------------------------------------------------------------
   reg 			    rst_sdr_sync;
   
   always @(posedge sdr_clk or posedge rst)
     if (rst)
       rst_sdr_sync <= 1'b1;
     else
       rst_sdr_sync <= 1'b0;
   
   //------------------------------------------------------------------
   // IDELAY is calibrated using (mandatory) IDELAYCTRL cell..
   // Must be feed stable free running clock specified by: FIDELAYCTRL_REF.(200MHz)
   // Mandatory async reset required, min pulse of: TIDELAYCTRL_RPW (~60nS)
   //------------------------------------------------------------------
   IDELAYCTRL IDELAYCTRL_i0
     (
      .REFCLK(clk200),
      .RST(rst_sdr_sync),
      .RDY()
      );
   
   
   //------------------------------------------------------------------
   // Clock input
   //------------------------------------------------------------------
   wire 		    ddr_clk_dly, ddr_clk_unbuf;
     
   IBUFDS  #(.DIFF_TERM("TRUE")) clk_ibufds (.O(ddr_clk_unbuf), .I(ddr_clk_p), .IB(ddr_clk_n));

   (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
     IDELAYE2 #(
		.CINVCTRL_SEL("FALSE"),          // Enable dynamic clock inversion (FALSE, TRUE)
		.DELAY_SRC("IDATAIN"),           // Delay input (IDATAIN, DATAIN)
		.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
		.IDELAY_TYPE("VAR_LOAD"), 
		.IDELAY_VALUE(CLOCK_DELAY), 
		.PIPE_SEL("FALSE"), 
		.REFCLK_FREQUENCY(200.0), 
		.SIGNAL_PATTERN("CLOCK")
		)
       ddr_clk_idelaye2 (
			 .CNTVALUEOUT(), // 5-bit output: Counter value output
			 .DATAOUT(ddr_clk_dly), // 1-bit output: Delayed data output
			 .C(ctrl_clk), // 1-bit input: Clock input
			 .CE(1'b0), // 1-bit input: Active high enable increment/decrement input
			 .CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
			 .CNTVALUEIN(ctrl_clk_delay), // 5-bit input: Counter value input
			 .DATAIN(1'b0), // 1-bit input: Internal delay data input
			 .IDATAIN(ddr_clk_unbuf), // 1-bit input: Data input from the I/O
			 .INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
			 .LD(ctrl_ld_clk_delay), // 1-bit input: Load IDELAY_VALUE input
			 .LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
			 .REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
			 );

   // IO CLock is DDR freq. This drives SERDES and other I/O elements with minimal clock skew.
   BUFIO ddr_clk_bufio (.O(ddr_clk),.I(ddr_clk_dly));
   // SDR clock is one quarter DDR freq and local to regio using BUFR
   // BUFR is a constraint of the SERDES since we need frequency agnostic clock division.
   // UG471 states can use BUFIO and BUFR divided to directly drive a SERDES legally.
   // (Other option is pair of BUFG's plus an MMCM - But MMCM has fixed frequency)
   wire 		    sdr_clk_2x;
   BUFR #(.BUFR_DIVIDE("2"),.SIM_DEVICE("7SERIES")) sdr_clk_2x_bufr(.O(sdr_clk_2x),.CE(1'b1),.CLR(1'b0),.I(ddr_clk_dly));
   BUFR #(.BUFR_DIVIDE("4"),.SIM_DEVICE("7SERIES")) sdr_clk_bufr(.O(sdr_clk), .CE(1'b1),.CLR(1'b0),.I(ddr_clk_dly));
   // radio_clock is sdr_clk re-buffered with BUFG, and radio_clk_2x is sdr_clk_2x rebuffered, so both can be used globally. 
   // This introduces skew between 
   // sdr_clk -> radio_clock so we must hand data between them carefully even though they have a fixed 
   // phase relationship.
   BUFG radio_clk_1x_bufg (.O(radio_clk), .I(sdr_clk));
   BUFG radio_clk_2x_bufg (.O(radio_clk_2x), .I(sdr_clk_2x));
   
   //------------------------------------------------------------------
   // Frame Signal
   //------------------------------------------------------------------
   wire 		    ddr_frame, ddr_frame_dly;
   wire [7:0] 		    des_frame; // deserialized frame signal
   reg 			    bitslip;
   reg 			    aligned;
   
   
   //
   // Use FRAME signal to get bitstream word alligned.
   // 
   // In MIMO mode FRAME is asserted during the entirity of channel 0, and deassert during the entirity of
   // channel 1.
   //
   localparam IDLE = 0;
   localparam SEARCH = 1;
   localparam SLIP1 = 3;
   localparam SLIP2 = 2;
   localparam SLIP3 = 4;
   localparam SLIP4 = 5;
   localparam SYNC = 6;
   
	     
   reg [2:0] 		    frame_state;

   //
   // Delay start of framesync operation for 64 clocks after reset de-asserts to SERDES to be
   // sure they are in a steady state.
   // Each time we assert bitslip we then have to wait 2 cycles before we can examine the results.
   //
   wire frame_is_aligned = (des_frame[7:0] ==  (INVERT_FRAME_RX ? 8'h0F : 8'hF0));

   reg [5:0] sync_delay;
   reg 	     run_sync;
   

   always @(posedge sdr_clk)
     if (rst_sdr_sync) begin
	sync_delay <= 6'h0;
	run_sync <= 1'b0;
     end else if (sync_delay == 64'h3F)
       run_sync <= 1'b1;
     else
       sync_delay <= sync_delay + 1'b1;
 
   always @(posedge sdr_clk)
     if (!run_sync)
       begin
	  frame_state <= IDLE;
	  bitslip <= 1'b0;
	  aligned <= 1'b0;	  
       end
     else case (frame_state)
	    IDLE: begin
	       bitslip <= 1'b0;
	       aligned <= 1'b0;
	       frame_state <= SEARCH;
	    end

	    SEARCH: begin
	       if (frame_is_aligned) begin
		  frame_state <= SYNC;
		  bitslip <= 1'b0;
		  aligned <= 1'b1;
	       end else begin
		  //  bitslip until captured frame is aligned
		  bitslip <= 1'b1;
		  frame_state <= SLIP1;
		  aligned <= 1'b0;
	       end
	    end
	    
	    SLIP1: begin
	       frame_state <= SLIP2;
	       bitslip <= 1'b0;
	       aligned <= 1'b0;
	    end

	    SLIP2: begin
	       frame_state <= SLIP3;
	       bitslip <= 1'b0;
	       aligned <= 1'b0;
	    end

	    SLIP3: begin
	       frame_state <= SLIP4;
	       bitslip <= 1'b0;
	       aligned <= 1'b0;
	    end

	    SLIP4: begin
	       frame_state <= SEARCH;
	       bitslip <= 1'b0;
	       aligned <= 1'b0;
	    end
	    

	    SYNC: begin
	       if (frame_is_aligned) begin
		  frame_state <= SYNC;
		  aligned <= 1'b1; 
	       end else begin
		  frame_state <= SEARCH;
		  aligned <= 1'b0; 
	       end 
	    end

	  endcase // case(frame_state)
   
	    
   IBUFDS  #(.DIFF_TERM("TRUE")) ddr_frame_ibufds (.O(ddr_frame), .I(ddr_frame_p), .IB(ddr_frame_n));

   (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
     IDELAYE2 #(
		.CINVCTRL_SEL("FALSE"),          // Enable dynamic clock inversion (FALSE, TRUE)
		.DELAY_SRC("IDATAIN"),           // Delay input (IDATAIN, DATAIN)
		.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
		.IDELAY_TYPE("VAR_LOAD"), 
		.IDELAY_VALUE(DATA_DELAY), 
		.PIPE_SEL("FALSE"), 
		.REFCLK_FREQUENCY(200.0), 
		.SIGNAL_PATTERN("DATA")
		)
       ddr_frame_idelaye2 (
			   .CNTVALUEOUT(), // 5-bit output: Counter value output
			   .DATAOUT(ddr_frame_dly), // 1-bit output: Delayed data output
			   .C(ctrl_clk), // 1-bit input: Clock input
			   .CE(1'b0), // 1-bit input: Active high enable increment/decrement input
			   .CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
			   .CNTVALUEIN(ctrl_data_delay), // 5-bit input: Counter value input
			   .DATAIN(1'b0), // 1-bit input: Internal delay data input
			   .IDATAIN(ddr_frame), // 1-bit input: Data input from the I/O
			   .INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
			   .LD(ctrl_ld_data_delay), // 1-bit input: Load IDELAY_VALUE input
			   .LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
			   .REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
			   );

   ISERDESE2 #(
               .DATA_RATE("DDR"),           // DDR, SDR
               .DATA_WIDTH(8),              // Parallel data width (2-8,10,14)
               .DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
               .DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE)
               // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
               .INIT_Q1(1'b0),
               .INIT_Q2(1'b0),
               .INIT_Q3(1'b0),
               .INIT_Q4(1'b0),
               .INTERFACE_TYPE("NETWORKING"),
               .IOBDELAY("BOTH"),
               .NUM_CE(1),
               .OFB_USED("FALSE"),
               .SERDES_MODE("MASTER"),
	       // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
	       .SRVAL_Q1(1'b0),
	       .SRVAL_Q2(1'b0),
	       .SRVAL_Q3(1'b0),
	       .SRVAL_Q4(1'b0)
	       )
     ddr_frame_serdese2 (
			 .O(), // 1-bit output: Combinatorial output
			 // Q1 - Q8: 1-bit (each) output: Registered data outputs
			 .Q1(des_frame[0]),
			 .Q2(des_frame[1]),
			 .Q3(des_frame[2]),
			 .Q4(des_frame[3]),
			 .Q5(des_frame[4]),
			 .Q6(des_frame[5]),
			 .Q7(des_frame[6]),
			 .Q8(des_frame[7]),
			 // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports 
			 .SHIFTOUT1(),
			 .SHIFTOUT2(),     
			 // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
			 // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
			 // to Q8 output ports will shift, as in a barrel-shifter operation, one 
			 // position every time Bitslip is invoked (DDR operation is different from SDR)
			 .BITSLIP(bitslip),
			 // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
			 .CE1(1'b1),
			 .CE2(1'b1),
			 .CLKDIVP(1'b0),         // 1-bit input: TBD
			 // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
			 .CLK(ddr_clk),          // 1-bit input: High-speed clock
			 .CLKB(!ddr_clk),        // 1-bit input: High-speed secondary clock
			 .CLKDIV(sdr_clk),	 // 1-bit input: Divided clock
			 .OCLK(1'b0),	         // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
			 // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
			 .DYNCLKDIVSEL(1'b0),    // 1-bit input: Dynamic CLKDIV inversion
			 .DYNCLKSEL(1'b0),       // 1-bit input: Dynamic CLK/CLKB inversion
			 // Input Data: 1-bit (each) input: ISERDESE2 data input ports
			 .D(1'b0),	         // 1-bit input: Data input
			 .DDLY(ddr_frame_dly),   // 1-bit input: Serial data from IDELAYE2
			 .OFB(1'b0),             // 1-bit input: Data feedback from OSERDESE2
			 .OCLKB(1'b0),           // 1-bit input: High speed negative edge output clock
			 .RST(rst_sdr_sync),	 // 1-bit input: Active high asynchronous reset
			 // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
			 .SHIFTIN1(1'b0),
			 .SHIFTIN2(1'b0)
			 );

   
   //------------------------------------------------------------------
   // Data Bus
   //------------------------------------------------------------------
   wire [WIDTH-1:0] ddr_data;
   wire [WIDTH-1:0] ddr_data_dly;
   wire [(WIDTH*2)-1:0]	data_i0, data_i1;
   wire [(WIDTH*2)-1:0] data_q0, data_q1;
   
   
   
   genvar 		    i; 
   generate
      for (i=0 ; i<WIDTH ; i=i+1) begin : generate_data_bus
	 
	 IBUFDS  #(.DIFF_TERM("TRUE")) ddr_data_ibufds (.O(ddr_data[i]), .I(ddr_data_p[i]), .IB(ddr_data_n[i]));

	 (* IODELAY_GROUP = GROUP *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
	   IDELAYE2 #(
		      .CINVCTRL_SEL("FALSE"),          // Enable dynamic clock inversion (FALSE, TRUE)
		      .DELAY_SRC("IDATAIN"),           // Delay input (IDATAIN, DATAIN)
		      .HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
		      .IDELAY_TYPE("VAR_LOAD"), 
		      .IDELAY_VALUE(DATA_DELAY), 
		      .PIPE_SEL("FALSE"), 
		      .REFCLK_FREQUENCY(200.0), 
		      .SIGNAL_PATTERN("DATA")
		      )
	     ddr_data_idelaye2 (
				.CNTVALUEOUT(), // 5-bit output: Counter value output
				.DATAOUT(ddr_data_dly[i]), // 1-bit output: Delayed data output
				.C(ctrl_clk), // 1-bit input: Clock input
				.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
				.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
				.CNTVALUEIN(ctrl_data_delay), // 5-bit input: Counter value input
				.DATAIN(1'b0), // 1-bit input: Internal delay data input
				.IDATAIN(ddr_data[i]), // 1-bit input: Data input from the I/O
				.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
				.LD(ctrl_ld_data_delay), // 1-bit input: Load IDELAY_VALUE input
				.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
				.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
				);

	 ISERDESE2 #(
		     .DATA_RATE("DDR"),           // DDR, SDR
		     .DATA_WIDTH(8),              // Parallel data width (2-8,10,14)
		     .DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
		     .DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE)
		     // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
		     .INIT_Q1(1'b0),
		     .INIT_Q2(1'b0),
		     .INIT_Q3(1'b0),
		     .INIT_Q4(1'b0),
		     .INTERFACE_TYPE("NETWORKING"),
		     .IOBDELAY("BOTH"),
		     .NUM_CE(1),
		     .OFB_USED("FALSE"),
		     .SERDES_MODE("MASTER"),
		     // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
		     .SRVAL_Q1(1'b0),
		     .SRVAL_Q2(1'b0),
		     .SRVAL_Q3(1'b0),
		     .SRVAL_Q4(1'b0)
		     )
	   ddr_data_serdese2 (
			      .O(), // 1-bit output: Combinatorial output
			      // Q1 - Q8: 1-bit (each) output: Registered data outputs
			      .Q1(data_q1[i]),
			      .Q2(data_i1[i]),
			      .Q3(data_q1[WIDTH+i]),
			      .Q4(data_i1[WIDTH+i]),
			      .Q5(data_q0[i]),
			      .Q6(data_i0[i]),
			      .Q7(data_q0[WIDTH+i]),
			      .Q8(data_i0[WIDTH+i]), 
			      // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports 
			      .SHIFTOUT1(),
			      .SHIFTOUT2(),     
			      // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
			      // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
			      // to Q8 output ports will shift, as in a barrel-shifter operation, one 
			      // position every time Bitslip is invoked (DDR operation is different from SDR)
			      .BITSLIP(bitslip),
			      // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
			      .CE1(1'b1),
			      .CE2(1'b1),
			      .CLKDIVP(1'b0),         // 1-bit input: TBD
			      // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
			      .CLK(ddr_clk),      // 1-bit input: High-speed clock
			      .CLKB(!ddr_clk),    // 1-bit input: High-speed secondary clock
			      .CLKDIV(sdr_clk),	     // 1-bit input: Divided clock
			      .OCLK(1'b0),	             // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
			      // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
			      .DYNCLKDIVSEL(1'b0),    // 1-bit input: Dynamic CLKDIV inversion
			      .DYNCLKSEL(1'b0),       // 1-bit input: Dynamic CLK/CLKB inversion
			      // Input Data: 1-bit (each) input: ISERDESE2 data input ports
			      .D(1'b0),	             // 1-bit input: Data input
			      .DDLY(ddr_data_dly[i]),   // 1-bit input: Serial data from IDELAYE2
			      .OFB(1'b0),              // 1-bit input: Data feedback from OSERDESE2
			      .OCLKB(1'b0),          // 1-bit input: High speed negative edge output clock
			      .RST(rst_sdr_sync),	             // 1-bit input: Active high asynchronous reset
			      // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
			      .SHIFTIN1(1'b0),
			      .SHIFTIN2(1'b0)
			      );	 
      end // block: generate_data_bus
   endgenerate

   //
   // Cross these cycles to radio_clk using negative edge.
   // this give 1/2 a radio clock period + BUFG insertion delay for signals to propogate. Thats > 6nS.
   //
   reg [(WIDTH*2)-1:0] radio_data_i0, radio_data_i1, radio_data_q0, radio_data_q1;
   reg 		       radio_aligned;
   
   always @(negedge radio_clk)
     begin
	radio_data_i0[(WIDTH*2)-1:0] <= data_i0[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
	radio_data_q0[(WIDTH*2)-1:0] <= data_q0[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
	radio_data_i1[(WIDTH*2)-1:0] <= data_i1[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
	radio_data_q1[(WIDTH*2)-1:0] <= data_q1[(WIDTH*2)-1:0] ^ {INVERT_DATA_RX,INVERT_DATA_RX};
	radio_aligned <= aligned;	
     end

   always @(posedge radio_clk)
     begin
	i0 <= radio_data_i0;
	q0 <= radio_data_q0;
	if (mimo) { i1, q1 } <= { radio_data_i1, radio_data_q1 };
	else { i1, q1 } <= { radio_data_i0, radio_data_q0 }; // dup single valid channel to both radios
	rx_aligned <= radio_aligned;
     end

   /*******************************************************************
    * Debug only logic below here.
    ******************************************************************/
/* -----\/----- EXCLUDED -----\/-----
   (* keep = "true", max_fanout = 10 *) reg [7:0] des_frame_reg;
   (* keep = "true", max_fanout = 10 *) reg rst_sdr_sync_reg;
   (* keep = "true", max_fanout = 10 *) reg run_sync_reg;
   (* keep = "true", max_fanout = 10 *) reg bitslip_reg;
   (* keep = "true", max_fanout = 10 *) reg aligned_reg;
   (* keep = "true", max_fanout = 10 *) reg [2:0] frame_state_reg;

   always @(posedge sdr_clk)
     begin
	des_frame_reg <= des_frame;
	rst_sdr_sync_reg <= rst_sdr_sync;
	run_sync_reg <= run_sync;
	bitslip_reg <= bitslip;
	aligned_reg <= aligned;
	frame_state_reg <= frame_state;
     end

    ila64 ila64_i (
		   .clk(sdr_clk),        // input clk
		   .probe0(
			   {
			    des_frame_reg,
			    rst_sdr_sync_reg,
			    run_sync_reg,
			    bitslip_reg,
			    aligned_reg,
			    frame_state_reg
			    }
			   )
		   );
 -----/\----- EXCLUDED -----/\----- */
   
			   
endmodule 

