`timescale 1 ns / 100 ps
//*****************************************************************************
// (c) Copyright 2010, National Semiconductor Corporation                      
//      All Rights Reserved
//*****************************************************************************
// NATIONAL SEMICONDUCTOR CONFIDENTIAL
//*****************************************************************************
// Module Name:  adc12d1000_rb
//
// Description:  Top level module for the ADC12D1000 Reference Board
//               Source derived from R. Masand's 10d1000 code and the fixes
//               for the DES Mode issue and the I/Q sampling done during the
//               first MMRx demo project.
//
//*****************************************************************************
module adc12d1000_rb (
		      //cypress stuff
    input [15:0] cy_addr,
    inout [7:0]  cy_data,
    output [15:0] cy_fd,
    input 	  fpga_reset,
    input 	  clk100_p,
    input 	  cs_n,
    input 	  we_n,
    input 	  rd_n,

    input 	  flaga,
    input 	  flagb,
    input 	  flagc,
    input 	  cy_req,
    input 	  load_state,
    input 	  ifclk,
    input [3:0]   state,
    input [5:3]   cy_ctl,
    output 	  cy_valid,
		      
    input 	  slcs_n,
    input 	  slrd,
    input 	  slwr,
    input 	  sloe,
    input 	  pktend,
    output [3:0]  cy_id,
    output [1:0]  fifoadr,

		      //adc clock, data, etc.
    input 	  dclkiP,
    input 	  dclkiN,
    input 	  dclkqP,
    input 	  dclkqN,
    input [11:0]   dqP,
    input [11:0]   dqN,
    input [11:0]   dqdP,
    input [11:0]   dqdN,
    input [11:0]   diP,
    input [11:0]   diN,
    input [11:0]   didP,
    input [11:0]   didN,
    input 	  oriP,
    input 	  oriN,
    input 	  orqP,
    input 	  orqN,

		      //adc controls
    output 	  pdi,
    output 	  pdq,
    output 	  ece,
    output 	  des,
    output 	  fsr,
    output 	  ddrphase,
    output 	  caldly,tpm,
    output 	  scs_adc,
    output 	  sclk_adc,
    output 	  ndm,
    output 	  wss,
    output 	  cal,
    output 	  poren,
    output 	  sdi_adc,
    input 	  sdo_adc,
    input 	  calfail,
    input 	  calrun,
		      
		      //expansion bus
    input 	  ext_trigP,
    input 	  ext_trigN,
    output [18:0] exp_a_p,
    output [18:0] exp_a_n,
    output [18:0] exp_b_p,
    output [18:0] exp_b_n,
    output [4:1]  testp,testn,
    input [5:1]   jp_,
    input [3:1]   tcrit,
		      
		      //misc
    input 	  pll_ld,
    output 	  ext_clk_sel,
    output 	  pll_le,pll_ce,
    output 	  pll_sdata,
    output 	  pll_sclk,
    output 	  led_needcal,
    output 	  led_overtemp,
    output 	  led_standby,
    output 	  led_acquire,
    output 	  led_trigger,
    output 	  led_overrange_i,
    output 	  led_overrange_q,
    output 	  led_health1,
    output 	  led_health2,

		      //usi spi
    input 	  sdi_usi,
    output 	  sdo_usi,
    output 	  sclk_usi,
    output 	  scs1_usi,
    output 	  scs2_usi
		      );
   
//------------------------- Parameters -------------------------//
   parameter
     SPEC_VER = 8'h15;

parameter [2:0]          //dcm reset state machine
  SM_DCMR_IDL  = 3'h0,
  SM_DCMR_ST1  = 3'h1,
  SM_DCMR_ST1A = 3'h2,
  SM_DCMR_ST1B = 3'h3,
  SM_DCMR_ST1C = 3'h4,
  SM_DCMR_ST2  = 3'h5;

parameter 
  SM_CAPT_IDL    = 3'h0,  //capture state machine
  SM_CAPT_IDL1   = 3'h1,  //capture state machine
  SM_CAPT_IDL2   = 3'h2,  //capture state machine
  SM_CAPT_ST1    = 3'h3,
  SM_CAPT_ST2    = 3'h4;

parameter 
  SM_FFR_IDL    = 3'h0,  //fifo read
  SM_FFR_ST1    = 3'h1,
  SM_FFR_ST2    = 3'h2,
  SM_FFR_ST3    = 3'h3;

parameter 		//Write Pulse state machine
  SM_WP_IDL    = 1'b0,
  SM_WP_ST1    = 1'b1;

parameter       //microwire state machine
  SM_MW_IDL    = 3'h0,
  SM_MW_ST0    = 3'h1,
  SM_MW_ST1    = 3'h2,
  SM_MW_ST2    = 3'h3,
  SM_MW_ST3    = 3'h4,
  SM_MW_ST4    = 3'h5,
  SM_MW_ST5    = 3'h6;

parameter       //lock state machine
  SM_HL_IDL    = 3'h0,
  SM_HL_ST0    = 3'h1,
  SM_HL_ST1    = 3'h2,
  SM_HL_ST2    = 3'h3,
  SM_HL_ST3    = 3'h4,
  SM_HL_ST4    = 3'h5;

//------------------------- Wires, Regs etc -------------------------//
    // clock nets
   wire  dclk_ib;
   wire  dclk_qb;
   wire  dclk_i;
   wire  dclk_q;
   wire  hdclk_i;
   wire  hdclk_q;
   wire  dcmi_lckd;
   wire  dcmq_lckd;
   wire  clk100;
   wire  clk6_25;
   wire  dcm100_lckd;

   // adc data nets from the IDDR primitives
   wire [11:0] di_r;
   wire [11:0] di_f;
   wire [11:0] did_r;
   wire [11:0] did_f;
   wire [11:0] dq_r;
   wire [11:0] dq_f;
   wire [11:0] dqd_r;
   wire [11:0] dqd_f;

   // first level of adc data registers
   reg [23:0]  di_reg;
   reg [23:0]  did_reg;
   reg [23:0]  dq_reg;
   reg [23:0]  dqd_reg;

   // second level of adc data registers (demuxing at half clock rate)
   reg [47:0]  di1_reg;
   reg [47:0]  did1_reg;
   reg [47:0]  dq1_reg;
   reg [47:0]  dqd1_reg;

   // third level of adc data registers (re-registering the data bus once more)
   reg [47:0]  di2_reg;
   reg [47:0]  did2_reg;
   reg [47:0]  dq2_reg;
   reg [47:0]  dqd2_reg;

   reg 	       demux_wen;  // toggles register enable for half clock rate data demux

   reg 	       fifo_wen;
   reg 	       fifo_wen_d1;
   reg 	       fifo_wr_en;
   
   reg 	       fifo_rst;
   reg 	       fifo_rst_d1;
   reg 	       fifo_reset;
   

   reg 	       cs_,wr_,rd_;
   reg [7:0]   cy_dt;
   reg [15:0]  cy_adr;

   reg 	       wp,sm_wp;
   reg [7:0]   cy_dato;

   reg [7:0]   dt_data_0,dt_data_1,dt_data_2,dt_data_3;
   wire [7:0]  tst_rg,dt_addr0,dt_addr1,dt_addr2;
   wire [7:2]  gl_csr;
   wire [7:0]  dt_pcnt0,dt_pcnt1,dt_cfg;
   wire [7:1]  dt_csr;
   wire [4:1]  spi_mctl;
   wire [7:0]  spi_cfg;

   wire [7:1]  adc_opt1;
   wire [2:0]  adc_opt21,adc_opt22;
   wire [4:0]  adc_opt3;


   reg 	       adcdcm_rst;
   reg [2:0]   sm_dcmr;

   wire        rr_tc;
   reg 	       srd,srd1,srd2,srd3,rr_tc1;
   reg 	       csr_strt,clr_csr_strt; //start bit in csr
   reg [16:0]  sr_cntr; //sample rate
   reg [15:0]  rr_cntr; //reference rate 

   reg [20:0]  clk_led_cntr;


   wire        cyaddr_vld = (cy_adr[15:8] == 8'hd0) && ~cy_adr[7];
   wire        rst = fpga_reset;

   reg [2:0]   sm_capt;
   reg 	       fifo_reg,fifo_ren;

   reg [1:0]   sm_ffr;
   reg [2:0]   fcyc;

   wire [47:0] di_sync;
   wire [47:0] did_sync;
   wire [47:0] dq_sync;
   wire [47:0] dqd_sync;

   wire [95:0] fifo_i_in;
   wire [95:0] fifo_q_in;
   
   wire [95:0] fifo_i;
   wire [95:0] fifo_q;

   wire        fifo_i_mt;      // empty flas sync'ed to the clk100 domain (fifo read clock)
   wire        fifo_q_mt;      // empty flas sync'ed to the clk100 domain (fifo read clock)
   wire        fifo_i_full;    // full flag sync'ed to the hdclk_i domain (fifo write clock)
   wire        fifo_q_full;    // full flag sync'ed to the hdclk_i domain (fifo write clock)
   reg 	       fifo_i_full_d1; // first level of re-sync flops
   reg 	       fifo_q_full_d1; // first level of re-sync flops
   reg 	       fifo_i_full_d2; // second level of re-sync flops
   reg 	       fifo_q_full_d2; // second level of re-sync flops
   reg 	       fifo_full;      // fifo full flag sync'ed to teh clk100 domain

   reg [95:0]  fifo_mux;

   wire        ori,orq;

   wire        hdclk_actv_mx,hdclk_actv;

   wire        iq_capt = adc_opt3[4];
   wire        hwtrg_en = adc_opt3[3];
   wire        q_ch     = adc_opt3[2];
   wire        des_mode = adc_opt3[1];

   wire        hw_trig;
   wire        hw_trgd  = ~hwtrg_en | (hw_trig & hwtrg_en);

reg [2:0] sm_hlck;
reg sm_pdq,clk_led_trn,clk_ledd,trg_hlck,clr_trg_hlck;

//------------------------- Instantiations -------------------------//

IBUFGDS i_dclki_bufgds (
	                .I(dclkiP), 
                        .IB(dclkiN), 
                        .O(dclk_ib)
	                );
defparam i_dclki_bufgds.IOSTANDARD = "LVDS_25";
defparam i_dclki_bufgds.DIFF_TERM  = "TRUE";

dcm_dclk dcm_dclki (
	            .CLKIN_IN(dclk_ib), 
                    .RST_IN(adcdcm_rst), 
		    .CLKDV_OUT(hdclk_i),
                    .CLK0_OUT(dclk_i),
                    .LOCKED_OUT(dcmi_lckd)
	            );

IBUFGDS i_dclkq_bufgds (
	                .I(dclkqP), 
                        .IB(dclkqN), 
                        .O(dclk_qb)
	                );
defparam i_dclkq_bufgds.IOSTANDARD = "LVDS_25";
defparam i_dclkq_bufgds.DIFF_TERM  = "TRUE";


   dcm_dclk dcm_dclkq (
	               .CLKIN_IN(dclk_qb), 
                       .RST_IN(adcdcm_rst), 
		       .CLKDV_OUT(hdclk_q),
                       .CLK0_OUT(dclk_q),
                       .LOCKED_OUT(dcmq_lckd)
	               );

   dcm100 i_dcm100 (.CLKIN_IN(clk100_p), 
                    .RST_IN(fpga_reset), 
                    .CLKDV_OUT(clk6_25), 
                    .CLKIN_IBUFG_OUT(), 
                    .CLK0_OUT(clk100), 
                    .LOCKED_OUT(dcm100_lckd)
		    );

   BUFGMUX i_bufgmux (
		      .I0(hdclk_i),
		      .I1(hdclk_q),
		      .S(adc_opt3[2]),
		      .O(hdclk_actv_mx)
		      );

   dcm_clkmeas i_dcm_cm (.CLKIN_IN(hdclk_actv_mx), 
			 .RST_IN(adcdcm_rst), 
			 .CLK0_OUT(hdclk_actv), 
			 .LOCKED_OUT()
			 );

   adc1k_if adc_if0 (
	             .dclk(dclk_i), 
                     .Dpin_N(diN), 
                     .Dpin_P(diP), 
                     .reset(fpga_reset), 
                     .SET_IN(1'b0),
                     .Dout_1(di_r), 
                     .Dout_2(di_f)
	             );

   adc1k_if adc_if1 (
	             .dclk(dclk_i), 
                     .Dpin_N(didN), 
                     .Dpin_P(didP), 
                     .reset(fpga_reset), 
                     .SET_IN(1'b0), 
		     .Dout_1(did_r), 
                     .Dout_2(did_f)
	             );

   adc1k_if adc_if2 (
	             .dclk(dclk_i), 
                     .Dpin_N(dqN), 
                     .Dpin_P(dqP), 
                     .reset(fpga_reset), 
                     .SET_IN(1'b0), 
                     .Dout_1(dq_r), 
                     .Dout_2(dq_f)
	             );

   adc1k_if adc_if3 (
	             .dclk(dclk_i), 
                     .Dpin_N(dqdN), 
                     .Dpin_P(dqdP), 
                     .reset(fpga_reset), 
                     .SET_IN(1'b0),
                     .Dout_1(dqd_r), 
                     .Dout_2(dqd_f)
	             );

   assign fifo_i_in = {di_sync[47:36],
		       did_sync[47:36],
		       di_sync[35:24],
		       did_sync[35:24],
		       di_sync[23:12],
		       did_sync[23:12],
		       di_sync[11:0],
		       did_sync[11:0]};

   fifo_96_4k fifoI (
	             .din(fifo_i_in),
	             .rd_clk(clk100),
	             .rd_en(fifo_ren),
	             .rst(fifo_reset),
	             .wr_clk(hdclk_i),
	             .wr_en(fifo_wr_en),
	             .dout(fifo_i),
	             .empty(fifo_i_mt),
	             .full(fifo_i_full)
		     );

   assign fifo_q_in = {dq_sync[47:36],
		       dqd_sync[47:36],
		       dq_sync[35:24],
		       dqd_sync[35:24],
		       dq_sync[23:12],
		       dqd_sync[23:12],
		       dq_sync[11:0],
		       dqd_sync[11:0]};

   fifo_96_4k fifoQ (
	             .din(fifo_q_in),
	             .rd_clk(clk100),
	             .rd_en(fifo_ren),
	             .rst(fifo_reset),
	             .wr_clk(hdclk_i),
	             .wr_en(fifo_wr_en),
	             .dout(fifo_q),
	             .empty(fifo_q_mt),
	             .full(fifo_q_full)
		     );

IBUFDS ORI_IBUFDS_INST  (.I(oriP), 
                         .IB(oriN), 
                         .O(ori)
				        );
defparam ORI_IBUFDS_INST.IOSTANDARD = "LVDS_25";
defparam ORI_IBUFDS_INST.DIFF_TERM = "TRUE";

IBUFDS ORQ_IBUFDS_INST (.I(orqP), 
                        .IB(orqN), 
                        .O(orq));
defparam ORQ_IBUFDS_INST.IOSTANDARD = "LVDS_25";
defparam ORQ_IBUFDS_INST.DIFF_TERM = "TRUE";

IBUFGDS i_extrg_bufgds (
	                    .I(ext_trigP), 
                        .IB(ext_trigN), 
                        .O(hw_trig)
	                   );
defparam i_extrg_bufgds.IOSTANDARD = "LVDS_25";
defparam i_extrg_bufgds.DIFF_TERM  = "TRUE";

//------------------------------ Reg Instantiations -----------------------------//
//
//rgstr #(.N(x)) tst_rg    (rst, clk,    wen,                           d,       q     );
rgstr   #(.N(6)) i_gl_csr  (rst, clk100, (wp & (cy_adr[6:0] == 7'h01)), cy_dt[7:2], gl_csr[7:2]);
rgstr   #(.N(1)) i_gl_srst (rst, clk100, (wp & (cy_adr[6:0] == 7'h01)), cy_dt[0], srst);
rgstr   #(.N(8)) i_tst_rg  (rst, clk100, (wp & (cy_adr[6:0] == 7'h16)), cy_dt, tst_rg);
rgstr   #(.N(4)) i_spimctl (rst, clk100, (wp & (cy_adr[6:0] == 7'h21)), cy_dt[4:1], spi_mctl);
rgstr   #(.N(8)) i_spimcfg (rst, clk100, (wp & (cy_adr[6:0] == 7'h22)), cy_dt, spi_cfg);
rgstr   #(.N(7)) i_dt_csr  (rst, clk100, (wp & (cy_adr[6:0] == 7'h30)), cy_dt[7:1], dt_csr);
rgstr   #(.N(8)) i_dt_cfg  (rst, clk100, (wp & (cy_adr[6:0] == 7'h31)), cy_dt, dt_cfg);
rgstr   #(.N(8)) i_dt_pcnt0(rst, clk100, (wp & (cy_adr[6:0] == 7'h33)), cy_dt, dt_pcnt0);
rgstr   #(.N(8)) i_dt_pcnt1(rst, clk100, (wp & (cy_adr[6:0] == 7'h34)), cy_dt, dt_pcnt1);
rgstr   #(.N(8)) i_dt_addr0(rst, clk100, (wp & (cy_adr[6:0] == 7'h35)), cy_dt, dt_addr0);
rgstr   #(.N(8)) i_dt_addr1(rst, clk100, (wp & (cy_adr[6:0] == 7'h36)), cy_dt, dt_addr1);
rgstr   #(.N(8)) i_dt_addr2(rst, clk100, (wp & (cy_adr[6:0] == 7'h37)), cy_dt, dt_addr2);
rgstr   #(.N(7)) i_adcopt1 (rst, clk100, (wp & (cy_adr[6:0] == 7'h41)), cy_dt[7:1], adc_opt1);
rgstr   #(.N(3)) i_adcopt21(rst, clk100, (wp & (cy_adr[6:0] == 7'h42)), cy_dt[2:0], adc_opt21);
rgstr   #(.N(3)) i_adcopt22(rst, clk100, (wp & (cy_adr[6:0] == 7'h42)), cy_dt[6:4], adc_opt22);
rgstr   #(.N(5)) i_adcopt3 (rst, clk100, (wp & (cy_adr[6:0] == 7'h43)), cy_dt[4:0], adc_opt3[4:0]);

wire [3:0] op_code = dt_csr[7:4];

//----------------------------------Real Work---------------------------------------//

//----------------------------------------------------Data capture
//
   // registering the first level of data out of the IDDR primitives
   always @(posedge fpga_reset or posedge dclk_i)
     if (fpga_reset)
       begin
	  di_reg    <= 24'h0;
	  did_reg   <= 24'h0;
	  
	  dq_reg    <= 24'h0;
	  dqd_reg   <= 24'h0;
       end 
     else
       begin
	  di_reg    <=  {di_f,di_r};
	  did_reg   <=  {did_f,did_r};
	  
	  dq_reg    <=  {dq_f,dq_r};
	  dqd_reg   <=  {dqd_f,dqd_r};
       end

   // time demuxing of the data bus into sample n and sample n+1
   // (di "n" and "n+1" and did "n" and "n+1" for example)
   always @(posedge fpga_reset or posedge dclk_i)
     if (fpga_reset)
       begin
	  demux_wen <= 1'b0;
	  
	  di1_reg   <= 48'h0;
	  di2_reg   <= 48'h0;

	  did1_reg  <= 48'h0;
	  did2_reg  <= 48'h0;
	  
	  dq1_reg   <= 48'h0;
	  dq2_reg   <= 48'h0;

	  dqd1_reg  <= 48'h0;
	  dqd2_reg  <= 48'h0;
       end
     else 
       begin
	  if(demux_wen)
	    begin
	       demux_wen <= 1'b0;
	       
	       di1_reg   <= {di_f,di_r,di_reg};
	       di2_reg   <= di1_reg;

	       did1_reg  <= {did_f,did_r,did_reg};	
	       did2_reg  <= did1_reg;

	       dq1_reg   <= {dq_f,dq_r,dq_reg};
	       dq2_reg   <= dq1_reg;

	       dqd1_reg  <= {dqd_f,dqd_r,dqd_reg};
	       dqd2_reg  <= dqd1_reg;
	    end
	  else
	    begin
	       demux_wen <= 1'b1;
	       
	       di1_reg   <= di1_reg;
	       di2_reg   <= di2_reg;
	       
	       did1_reg  <= did1_reg;
	       did2_reg  <= did2_reg;

	       dq1_reg   <= dq1_reg;
	       dq2_reg   <= dq2_reg;

	       dqd1_reg  <= dqd1_reg;
	       dqd2_reg  <= dqd2_reg;
	    end		  
       end

/* The time order for non-des mode (above) is:
* dqd1_reg[11:0]   dq1_reg[11:0]   dqd1_reg[23:12]  dq1_reg[23:12]
* dqd1_reg[25:24] dq1_reg[35:24] dqd1_reg[47:36] dq1_reg[47:36]
* same for di.
* dqd2_reg, dq2_reg,did2_reg,di2_reg simply fillow dxx1_reg
* FIFO input and output follow order above 
*
	*
/* The time order for des mode (above) is: (example for 8 bit adc)
* dqd1_reg[7:0]   did1_reg[7:0]   dq1_reg[7:0]   di1_reg[7:0]
* dqd1_reg[15:8]  did1_reg[15:8]  dq1_reg[15:8]  di1_reg[15:8]
* dqd1_reg[23:16] did1_reg[23:16] dq1_reg[23:16] di1_reg[23:16]
* dqd1_reg[31:24] did1_reg[31:24] dq1_reg[31:24] di1_reg[31:24]
*
*/

   fifo_48x16 di_syncfifo (
			   .rst(rst),
			   .wr_clk(dclk_i),
			   .rd_clk(hdclk_i),
			   .din(di2_reg),
			   .wr_en(1'b1),
			   .rd_en(1'b1),
			   .dout(di_sync),
			   .full(),
			   .empty());

   fifo_48x16 did_syncfifo (
			   .rst(rst),
			   .wr_clk(dclk_i),
			   .rd_clk(hdclk_i),
			   .din(did2_reg),
			   .wr_en(1'b1),
			   .rd_en(1'b1),
			   .dout(did_sync),
			   .full(),
			   .empty());
   fifo_48x16 dq_syncfifo (
			   .rst(rst),
			   .wr_clk(dclk_i),
			   .rd_clk(hdclk_i),
			   .din(dq2_reg),
			   .wr_en(1'b1),
			   .rd_en(1'b1),
			   .dout(dq_sync),
			   .full(),
			   .empty());
   fifo_48x16 dqd_syncfifo (
			   .rst(rst),
			   .wr_clk(dclk_i),
			   .rd_clk(hdclk_i),
			   .din(dqd2_reg),
			   .wr_en(1'b1),
			   .rd_en(1'b1),
			   .dout(dqd_sync),
			   .full(),
			   .empty());
   
//-------------------------------------- srd -- gl_csr register bit -- auto-clears
   always @(posedge rst or posedge clk100)

     if (rst)
       begin
	  srd         <= 1'b0;
	  csr_strt    <= 1'b0;
	  trg_hlck    <= 1'b0;
	  clk_led_trn <= 1'b0;
	  clk_ledd    <= 1'b0;
	  clr_csr_strt  <= 1'b0;
       end
     else 
       begin
	  srd      <= ( (wp & (cy_adr[6:0] == 7'h01) & cy_dt[1]) | (srd & ~rr_tc));
	  csr_strt <= ( (wp & (cy_adr[6:0] == 7'h30) & cy_dt[0]) | (csr_strt & ~clr_csr_strt));
	  trg_hlck <= ( (wp & (cy_adr[6:0] == 7'h16) & cy_dt[0]) | (trg_hlck & ~clr_trg_hlck));
	  clk_ledd    <= clk_led_cntr[20];
	  clk_led_trn <= clk_led_cntr[20] ^ clk_ledd;

	  // See if ADC->FIFO capture is finished, or FIFO->PC read has finished
	  // If either is finished, clear the capture start bit.
	  clr_csr_strt <= ( (sm_capt == SM_CAPT_ST1) & fifo_full) |
			  (sm_ffr  == SM_FFR_ST2) ;
       end
 

//-------------------------------------- capture state machine

   always @(posedge rst or posedge clk100)
     if(rst)
       begin
 	  fifo_i_full_d1 <= 1'b0;
 	  fifo_i_full_d2 <= 1'b0;
	  
 	  fifo_q_full_d1 <= 1'b0;
 	  fifo_q_full_d2 <= 1'b0;

	  fifo_full    <= 1'b0;
       end
     else
       begin
	  fifo_i_full_d1 <= fifo_i_full;
	  fifo_i_full_d2 <= fifo_i_full_d1;

	  fifo_q_full_d1 <= fifo_q_full;
	  fifo_q_full_d2 <= fifo_q_full_d1;
	  
	  fifo_full <= (fifo_i_full_d2 | fifo_q_full_d2);
       end

   always @(posedge rst or posedge clk100)

     if (rst) 
       begin
	  sm_capt       <= SM_CAPT_IDL;
	  fifo_wen      <= 1'b0;
	  fifo_rst      <= 1'b1;
       end
     else 
       begin
	  case (sm_capt)

	  SM_CAPT_IDL:
	    begin
	       if ((op_code == 4'h0) & csr_strt)
		 begin 
		    fifo_rst <= 1'b1;
		    sm_capt <= SM_CAPT_IDL1;  //transfer data from adc to fifo
		 end
	       else
		 begin
		    fifo_rst <= 1'b0;         //capture request not detected
		    sm_capt <= SM_CAPT_IDL;
		 end
	    end

	  SM_CAPT_IDL1:
	    begin
	       if (fifo_i_mt & fifo_q_mt)
		 begin
		    fifo_rst <= 1'b0;         // FIFOs empty, release reset
		    sm_capt <= SM_CAPT_IDL2;
		 end
	       else
		 begin
		    fifo_rst <= 1'b1;        // FIFOs not empty
		    sm_capt <= SM_CAPT_IDL1;
		 end
	    end
	    
	  SM_CAPT_IDL2:
	    begin   // fifo_full has latency wrt empty assertion, wait here
	       // * IMPORTANT, the fifo should be generated with the fifo full flag reset value = 0 instead of 1
	       // If this is not done, the latency of the clock crossing logic for the reset and full signals
	       // will break this state machine at por.
	       if (~fifo_full) sm_capt <= SM_CAPT_ST1;
	       else sm_capt <= SM_CAPT_IDL2;
	    end
	    
	  SM_CAPT_ST1:
            begin
	       if (fifo_full)
		 begin                       // FIFO is full, stop writing and go to idle
		    fifo_wen <= 1'b0;
		    sm_capt  <= SM_CAPT_ST2;
		 end
	       else
		 begin                      // FIFO still filling
		    fifo_wen <= 1'b1;
		    sm_capt  <= SM_CAPT_ST1;
		 end	       
	    end
	  
	  SM_CAPT_ST2: sm_capt <= SM_CAPT_IDL;  //wait for start bit to clear

	  default:
            sm_capt <= SM_CAPT_IDL;

	endcase
     end

//---------------------------------------------------

   // Syncronizing the fifo control lines from the clk100 domain to hdclk_i
   always @(posedge rst or posedge hdclk_i)
     begin
	if(rst)
	  begin
	     fifo_rst_d1  <= 1'b0;
	     fifo_reset   <= 1'b0;

	     fifo_wen_d1  <= 1'b0;
	     fifo_wr_en   <= 1'b0;
	  end
	else
	  begin
	     fifo_rst_d1 <= fifo_rst;
	     fifo_reset  <= fifo_rst_d1;

	     fifo_wen_d1 <= fifo_wen;
	     fifo_wr_en  <= fifo_wen_d1;
	  end
     end

//--------------------------------------------------- fifo read state machine
 always @(*)
   begin
      if(iq_capt)
	   case (op_code)
	     4'hd: fifo_mux = fifo_i;
	     4'hf: fifo_mux = fifo_q;
	     default: fifo_mux = fifo_i;
	   endcase
      else if(q_ch)
	     fifo_mux = fifo_q;
      else
	fifo_mux = fifo_i;
   end
	     
   
   always @(posedge rst or posedge clk100)
     if (rst)
       begin
	  dt_data_0     <= 8'h0;
	  dt_data_1     <= 8'h0;
	  dt_data_2     <= 8'h0;
	  dt_data_3     <= 8'h0;
	  fifo_ren      <= 1'b0;
	  fcyc          <= 3'h0;
	  sm_ffr        <= SM_FFR_IDL;
       end
     else
       begin
	if (sm_capt == SM_CAPT_ST2) fcyc <= 3'h0;

	  case (sm_ffr)
	    SM_FFR_IDL:
              if (((op_code == 4'hd) | ((op_code == 4'hf) & iq_capt)) & csr_strt)
		begin
		   if ( (~(|fcyc) )  | (~fcyc[1] & ~fcyc[0] & ~des_mode) ) fifo_ren <= 1'b1;
		   sm_ffr   <= SM_FFR_ST1;
		end

	    SM_FFR_ST1:
              begin
                 fifo_ren  <= 1'b0;
                 sm_ffr    <= SM_FFR_ST2;
              end

	    SM_FFR_ST2:
              begin
		 case (fcyc)
		   3'h0:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[11:0] : fifo_mux[11:0];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[11:0] : fifo_mux[23:12];
		     end

		   3'h1:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[23:12] : fifo_mux[35:24];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[23:12] : fifo_mux[47:36];
		     end

		   3'h2:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[35:24] : fifo_mux[59:48];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[35:24] : fifo_mux[71:60];
		     end

		   3'h3:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[47:36] : fifo_mux[83:72];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[47:36] : fifo_mux[95:84];
		     end
		   
		   3'h4:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[59:48] : fifo_mux[11:0];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[59:48] : fifo_mux[23:12];
		     end
		   
		   3'h5:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[71:60] : fifo_mux[35:24];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[71:60] : fifo_mux[47:36];
		     end
		   
		   3'h6:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[83:72] : fifo_mux[59:48];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[83:72] : fifo_mux[71:60];
		     end
		   
		   3'h7:
		     begin
			{dt_data_1[3:0], dt_data_0} <= des_mode ? fifo_q[95:84] : fifo_mux[83:72];
			{dt_data_3[3:0], dt_data_2} <= des_mode ? fifo_i[95:84] : fifo_mux[95:84];
		     end
		 endcase
		 
                 sm_ffr    <= SM_FFR_ST3;
              end
	    
	    SM_FFR_ST3:
              begin
		 fcyc      <= fcyc + 1'b1;
                 sm_ffr    <= SM_FFR_IDL;
              end

	    default: sm_ffr <= SM_FFR_IDL;
	    
	  endcase
       end

   
//--------------------------------------
//
//--------------------------------------reference rate counter
assign rr_tc = ~|rr_cntr;// & srd;

always @(posedge rst or posedge clk100)

  if (rst) begin
    rr_cntr    <= 16'd50000;	//or 53125
	srd1       <= 1'b0;
  end else begin
	srd1   <= srd;
    if (~srd1)  rr_cntr <= 16'd50000;
	else if (srd & srd1 & ~rr_tc) rr_cntr <= rr_cntr - 1'b1;
  end

//--------------------------------------sample rate counter
  
always @(posedge rst or posedge hdclk_actv)

  if (rst) begin
    sr_cntr    <= 17'h0;
	srd2       <= 1'b0;
	srd3       <= 1'b0;
	rr_tc1     <= 1'b0;
  end else begin
	srd2    <= srd;
	srd3    <= srd2;
	rr_tc1  <= rr_tc;
  
    if (srd2 & ~srd3)  sr_cntr <= 17'h0;
  	else if (srd2 & srd3 & ~rr_tc1) sr_cntr <= sr_cntr + 1'b1;

  end
    
//-----------------------------------------------------------------
//Cypress's read multiplexer

assign cy_data = (cyaddr_vld & ~cs_ & ~rd_) ? cy_dato : 8'hz;

always @(*)

  begin

    case (cy_adr[6:0])

      7'h00: cy_dato = SPEC_VER;
      7'h01: cy_dato = {gl_csr[7:2],srd,srst};
//    7'h14: cy_dato = 8'ha8;
//    7'h15: cy_dato = 8'h61;
      7'h12: cy_dato = 8'h0;	//fsr1
      7'h13: cy_dato = 8'h4;	//fsr2
      7'h14: cy_dato = {sr_cntr[8:3],dcmi_lckd,pll_ld};
      7'h15: cy_dato = sr_cntr[16:9];
      7'h16: cy_dato = {dcmi_lckd,pll_ld,tst_rg[5:0]};
      7'h17: cy_dato = 8'h04; //fpga version 0.4
      7'h21: cy_dato = {3'h0,spi_mctl,sdo_adc};
      7'h22: cy_dato = spi_cfg;
      7'h30: cy_dato = {dt_csr[7:1],csr_strt};
      7'h31: cy_dato = dt_cfg;
      7'h35: cy_dato = dt_addr0;
      7'h36: cy_dato = dt_addr1;
      7'h37: cy_dato = dt_addr2;
      7'h38: cy_dato = dt_data_0;
      7'h39: cy_dato = dt_data_1;
      7'h3a: cy_dato = dt_data_2;
      7'h3b: cy_dato = dt_data_3;
      7'h40: cy_dato = 8'h0d;		//dut id
      7'h41: cy_dato = {adc_opt1,calrun};
      7'h42: cy_dato = {pll_ld,adc_opt22,calfail,adc_opt21};
      7'h43: cy_dato = {3'h0,adc_opt3[4:0]};

      default: cy_dato = 8'hxx;

	endcase
  end
	     

//-----------------------------------------------------------------
always @(posedge rst or posedge clk100)  //write pulse

  if (rst) begin
    wp    <= 1'b0;
    sm_wp <= SM_WP_IDL;
    end else begin

    case (sm_wp)

      SM_WP_IDL:
        if ( (~(cs_ | wr_)) & cyaddr_vld) begin
          wp    <= 1'b1;
	      sm_wp <= SM_WP_ST1;
	    end

      SM_WP_ST1: 
	    begin
          wp    <= 1'b0;
          if ( (cs_ & wr_)) sm_wp <= SM_WP_IDL;
	    end

      default: sm_wp <= SM_WP_IDL;

    endcase
  end


//----------------------------------------------- dcm reset


always @(posedge fpga_reset or posedge clk100)

		if (fpga_reset) begin
		  adcdcm_rst <= 1'b1;
		  sm_dcmr    <= SM_DCMR_IDL;
		end
	    else begin

	      case (sm_dcmr)

		    SM_DCMR_IDL:
		      begin
			    adcdcm_rst <= 1'b0;
			    if (clk_led_cntr[20] & (~dcmi_lckd | ~dcmq_lckd)) begin
			      adcdcm_rst <= 1'b1;
			      sm_dcmr    <= SM_DCMR_ST1;
			    end
		      end

		    SM_DCMR_ST1:
	          sm_dcmr    <= SM_DCMR_ST1A;

		    SM_DCMR_ST1A:
	          sm_dcmr    <= SM_DCMR_ST1B;

		    SM_DCMR_ST1B:
	          sm_dcmr    <= SM_DCMR_ST1C;

		    SM_DCMR_ST1C:
	          sm_dcmr    <= SM_DCMR_ST2;

		    SM_DCMR_ST2:
		      begin
		        adcdcm_rst <= 1'b0;
			    if (~clk_led_cntr[20]) sm_dcmr <= SM_DCMR_IDL;
		      end

            default:
		      sm_dcmr <= SM_DCMR_IDL;

	      endcase
	    end
//------------------------------------------------------------------------------------

always @(posedge fpga_reset or posedge clk100)

		if (fpga_reset) begin
		  sm_pdq       <= 1'b0;
		  sm_hlck      <= SM_HL_IDL;
		  clr_trg_hlck <= 1'b0;
		end
	    else begin

	      case (sm_hlck)

		    SM_HL_IDL:
		      begin
			    sm_pdq <= 1'b0;
			    if (trg_hlck & clk_led_trn) begin
			      sm_hlck    <= SM_HL_ST1;
			    end
		      end

		    SM_HL_ST1:
		      begin
				sm_pdq   <= 1'b1;
	            if (clk_led_trn) sm_hlck <= SM_HL_ST2;
		      end

		    SM_HL_ST2:
		      begin
				sm_pdq   <= 1'b0;
	            if (clk_led_trn) sm_hlck <= SM_HL_ST3;
		      end

		    SM_HL_ST3:
		      begin
	            if (led_overtemp) sm_hlck <= SM_HL_ST1;
				else begin 
				  clr_trg_hlck <= 1'b1;
				  sm_hlck <= SM_HL_ST4;
				end
		      end

		    SM_HL_ST4:
			  begin
				clr_trg_hlck <= 1'b0;
		        if (~trg_hlck) sm_hlck <= SM_HL_IDL;
			  end
            
			default:
		      sm_hlck <= SM_HL_IDL;

	      endcase
	    end

//------------------------------------------------------------------------------------

  always @(posedge fpga_reset or posedge clk6_25)
	if (fpga_reset) begin 
      clk_led_cntr <= 21'h0;
	end else begin 
		clk_led_cntr <= clk_led_cntr + 1'b1;
	end

//-------------------------------------- Cypress' I/O FF
always @(posedge clk100)

 begin
  cy_adr <= cy_addr;
  cy_dt  <= cy_data;
  cs_    <= cs_n;
  rd_    <= rd_n;
  wr_    <= we_n;
 end

//--------------------------------------- ADC SPI

assign scs_adc  = spi_mctl[3] & (spi_cfg[2:0] == 0);
assign sclk_adc = spi_mctl[2] & (spi_cfg[2:0] == 0);
assign sdi_adc  = spi_mctl[1] & (spi_cfg[2:0] == 0);

//--------------------------------------- USI SPI

//assign sdo_usi  = spi_mctl[4] ? (spi_mctl[1] & spi_cfg[2]) : 1'bZ;
assign sdo_usi  = spi_mctl[1] & spi_cfg[2];
assign sclk_usi = spi_mctl[2] & spi_cfg[2];
assign scs1_usi = ~(~spi_mctl[3] & (spi_cfg[2:0] == 3'h4) );
assign scs2_usi = ~(~spi_mctl[3] & (spi_cfg[2:0] == 3'h5) );

//--------------------------------------- 2531 Microwire

assign pll_ce   = ~adc_opt22[2];
//assign pll_le   = mw_le_reg;
//assign pll_sdata = rom_dat_reg[23];
//assign pll_sclk = mw_clk_reg;
assign pll_le    = spi_mctl[3] & (spi_cfg[2:0] == 3'h1);
assign pll_sclk  = spi_mctl[2] & (spi_cfg[2:0] == 3'h1);
assign pll_sdata = spi_mctl[1] & (spi_cfg[2:0] == 3'h1);
//--------------------------------------- LEDs

   assign led_standby     = tst_rg[0];
   assign led_acquire     = hdclk_actv;
   assign led_trigger     = 1'b1;
   assign led_overrange_i = ~ori;
   assign led_overrange_q = ~orq;
   assign led_health1    = clk_led_cntr[20] & ~fpga_reset;
   assign led_health2     = ~dcmi_lckd & ~dcmq_lckd;
   assign led_needcal     = 1'b1;
   assign led_overtemp    = 1'b1;

   assign pdi =      1'bz;
   assign pdq =      sm_pdq;
   assign ece =      1'bz;
   assign des =      1'bz;
   assign fsr =      1'bz;
   assign ddrphase = 1'bz;
   assign caldly   = 1'bz;
   assign tpm      = 1'bz;
   assign ndm      = 1'bz;
   assign wss      = 1'bz;
   assign cal      = 1'bz;
   assign poren    = 1'bz;
   assign cy_fd    = 16'hz;
   assign fifoadr  = 2'hz;
   assign testp    = 4'bz;
   assign testn    = 4'bz;
   assign cy_id    = 4'hz;
   assign ext_clk_sel = adc_opt3[0];
   assign cy_valid = 1'bz;

   assign exp_a_p[18:0] = 19'hz;
   assign exp_a_n[18:0] = 19'hz;

   assign exp_b_p[18:0] = 19'hz;
   assign exp_b_n[18:0] = 19'hz;
   
endmodule


module rgstr (rst,clk,wen,d,q);
  parameter N = 1;
  input  [N-1:0] d;
  output [N-1:0] q;
  input rst,clk,wen;

  reg [N-1:0] q;

  always @(posedge clk or posedge rst)

    if (rst) q <= 0;
    else if (wen) q <= d;

  
endmodule

