// (C) 2001-2012 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License Subscription 
// Agreement, Altera MegaCore Function License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the applicable 
// agreement for further details.


`timescale 1ps/1ps

module altera_pll_reconfig_core
#(
    parameter 	reconf_width       	= 64,
    parameter 	device_family       	= "Stratix V",
    // MIF Streaming parameters
    parameter   RECONFIG_ADDR_WIDTH     = 6,
    parameter   RECONFIG_DATA_WIDTH     = 32,
    parameter   ROM_ADDR_WIDTH          = 9,
    parameter   ROM_DATA_WIDTH          = 32,
    parameter	ROM_NUM_WORDS           = 512
) ( 

    //input
    input   wire    mgmt_clk,
    input   wire    mgmt_reset,


    //conduits
    output  wire [reconf_width-1:0] reconfig_to_pll,
    input  wire [reconf_width-1:0] reconfig_from_pll,

    // user data (avalon-MM slave interface)
    output  wire [31:0] mgmt_readdata,
    output  wire        mgmt_waitrequest,
    input   wire [5:0]  mgmt_address,
    input   wire        mgmt_read,
    input   wire        mgmt_write,
    input   wire [31:0] mgmt_writedata,

    //other
    output  wire        mif_start_out,
    output  reg [ROM_ADDR_WIDTH-1:0]    mif_base_addr
);
    localparam mode_WR            = 1'b0;
    localparam mode_POLL          = 1'b1;
    localparam MODE_REG           = 6'b000000;
    localparam STATUS_REG         = 6'b000001;
    localparam START_REG          = 6'b000010;
    localparam N_REG              = 6'b000011;
    localparam M_REG              = 6'b000100;
    localparam C_COUNTERS_REG     = 6'b000101;
    localparam DPS_REG            = 6'b000110;
    localparam DSM_REG            = 6'b000111;
    localparam BWCTRL_REG         = 6'b001000;
    localparam CP_CURRENT_REG     = 6'b001001;
    localparam ANY_DPRIO          = 6'b100000;
    localparam CNT_BASE           = 5'b001010;
    localparam MIF_REG            = 6'b011111;
    
    //C Counters
    localparam number_of_counters = 5'd18;
    localparam  CNT_0 = 1'd0, CNT_1 = 5'd1, CNT_2 = 5'd2,
                CNT_3 = 5'd3, CNT_4 = 5'd4, CNT_5 = 5'd5,
                CNT_6 = 5'd6, CNT_7 = 5'd7, CNT_8 = 5'd8,
                CNT_9 = 5'd9, CNT_10 = 5'd10, CNT_11 = 5'd11,
                CNT_12 = 5'd12, CNT_13 = 5'd13, CNT_14 = 5'd14,
                CNT_15 = 5'd15, CNT_16 = 5'd16, CNT_17 = 5'd17;
    //C counter addresses
    localparam C_CNT_0_DIV_ADDR = 5'h00;
    localparam C_CNT_0_DIV_ADDR_DPRIO_1 = 5'h11;
    localparam C_CNT_0_3_BYPASS_EN_ADDR = 5'h15;
    localparam C_CNT_0_3_ODD_DIV_EN_ADDR = 5'h17;
    localparam C_CNT_4_17_BYPASS_EN_ADDR = 5'h14;
    localparam C_CNT_4_17_ODD_DIV_EN_ADDR = 5'h16;
    //N counter addresses
    localparam N_CNT_DIV_ADDR = 5'h13;
    localparam N_CNT_BYPASS_EN_ADDR = 5'h15;
    localparam N_CNT_ODD_DIV_EN_ADDR = 5'h17;
    //M counter addresses
    localparam M_CNT_DIV_ADDR = 5'h12;
    localparam M_CNT_BYPASS_EN_ADDR = 5'h15;
    localparam M_CNT_ODD_DIV_EN_ADDR = 5'h17;
    
    //DSM address
    localparam DSM_K_FRACTIONAL_DIVISION_ADDR_0 = 5'h18;
    localparam DSM_K_FRACTIONAL_DIVISION_ADDR_1 = 5'h19;
    localparam DSM_K_READY_ADDR = 5'h17;
    localparam DSM_K_DITHER_ADDR = 5'h17;
    localparam DSM_OUT_SEL_ADDR = 6'h30;
    
    //Other DSM params
    localparam DSM_K_READY_BIT_INDEX = 4'd11;
    //BWCTRL address
    //Bit 0-3 of addr
    localparam BWCTRL_ADDR = 6'h30;
    //CP_CURRENT address
    //Bit 0-2 of addr
    localparam CP_CURRENT_ADDR = 6'h31;

    localparam DPRIO_IDLE = 3'd0, ONE = 3'd1, TWO = 3'd2, THREE = 3'd3, FOUR = 3'd4,
               FIVE = 3'd5, SIX = 3'd6, SEVEN = 3'd7, EIGHT = 4'd8, NINE = 4'd9, TEN = 4'd10,
               ELEVEN = 4'd11, TWELVE = 4'd12, THIRTEEN = 4'd13, FOURTEEN = 4'd14, DPRIO_DONE = 4'd15;
    localparam IDLE = 2'b00, WAIT_ON_LOCK = 2'b01, LOCKED = 2'b10;
    
    wire            clk;
    wire            reset;
    wire            gnd;

    wire [5: 0]     slave_address;
    wire            slave_read;
    wire            slave_write;
    wire [31: 0]    slave_writedata;

    reg  [31: 0]     slave_readdata_d;
    reg  [31: 0]     slave_readdata_q;
    wire            slave_waitrequest;

    assign          clk             = mgmt_clk;

    assign          slave_address       = mgmt_address;
    assign          slave_read      = mgmt_read;    
    assign          slave_write     = mgmt_write;
    assign          slave_writedata     = mgmt_writedata;

    // Outputs
    assign          mgmt_readdata       = slave_readdata_q;
    assign          mgmt_waitrequest    = slave_waitrequest;

    //internal signals
    wire            locked;
    wire            pll_start;
    wire            pll_start_valid;
    reg             status_read;
    wire            read_slave_mode_asserted;

    wire            pll_start_asserted;

    reg  [1:0]      current_state;
    reg  [1:0]      next_state;

    reg             slave_mode;
    reg             status;//0=busy, 1=ready
    //user_mode_init user_mode_init_inst (clk, reset, dprio_mdio_dis, ser_shift_load);
    //declaring the init wires. These will have 0 on them for 64 clk cycles
    wire       [ 5:0]  init_dprio_address;
    wire               init_dprio_read;
    wire       [ 1:0]  init_dprio_byteen;
    wire               init_dprio_write;
    wire       [15:0]  init_dprio_writedata;

    wire               init_atpgmode;
    wire               init_mdio_dis;
    wire               init_scanen;
    wire               init_ser_shift_load;
    wire               dprio_init_done;

    //DPRIO output signals after initialization is done
    wire            dprio_clk;
    reg             avmm_dprio_write;
    reg             avmm_dprio_read;
    reg  [5:0]      avmm_dprio_address;
    reg  [15:0]     avmm_dprio_writedata;
    reg  [1:0]      avmm_dprio_byteen;
    wire            avmm_atpgmode;
    wire            avmm_mdio_dis;
    wire            avmm_scanen;

    //Final output wires that are muxed between the init and avmm wires.
    wire            dprio_init_reset;
    wire [5:0]      dprio_address /*synthesis keep*/;
    wire            dprio_read/*synthesis keep*/;
    wire [1:0]      dprio_byteen/*synthesis keep*/;
    wire            dprio_write/*synthesis keep*/;
    wire [15:0]     dprio_writedata/*synthesis keep*/;
    wire            dprio_mdio_dis/*synthesis keep*/;
    wire            dprio_ser_shift_load/*synthesis keep*/;
    wire            dprio_atpgmode/*synthesis keep*/;
    wire            dprio_scanen/*synthesis keep*/;


    //other PLL signals for dyn ph shift
    wire            phase_done/*synthesis keep*/;
    wire            phase_en/*synthesis keep*/;
    wire            up_dn/*synthesis keep*/;
    wire  [4:0]     cnt_sel;
    
    //DPRIO input signals
    wire  [15:0]     dprio_readdata;

    //internal logic signals
    //storage registers for user sent data
    reg             dprio_temp_read_1;
    reg             dprio_temp_read_2;
    reg             dprio_start;
    reg             mif_start_assert;
    reg             dps_start_assert;
    wire            usr_valid_changes;
    reg  [3:0]      dprio_cur_state;
    reg  [3:0]      dprio_next_state;
    reg  [15:0]     dprio_temp_m_n_c_readdata_1_d;
    reg  [15:0]     dprio_temp_m_n_c_readdata_2_d;
    reg  [15:0]     dprio_temp_m_n_c_readdata_1_q;
    reg  [15:0]     dprio_temp_m_n_c_readdata_2_q;
	reg 			dprio_write_done;
    //C counters signals
    reg  [7:0]      usr_c_cnt_lo;
    reg  [7:0]      usr_c_cnt_hi;
    reg             usr_c_cnt_bypass_en;
    reg             usr_c_cnt_odd_duty_div_en;
    reg  [7:0]      temp_c_cnt_lo [0:17]; 
    reg  [7:0]      temp_c_cnt_hi [0:17];
    reg             temp_c_cnt_bypass_en [0:17];
    reg      	    temp_c_cnt_odd_duty_div_en [0:17];
    reg             any_c_cnt_changed;
    reg             all_c_cnt_done_q;
    reg             all_c_cnt_done_d;
    reg  [17:0]     c_cnt_changed;
    reg  [17:0]     c_cnt_done_d;
    reg  [17:0]     c_cnt_done_q;
    //N counter signals
    reg  [7:0]      usr_n_cnt_lo; 
    reg  [7:0]      usr_n_cnt_hi;
    reg             usr_n_cnt_bypass_en;
    reg             usr_n_cnt_odd_duty_div_en;
    reg             n_cnt_changed;
    reg             n_cnt_done_d;
    reg             n_cnt_done_q;
    //M counter signals
    reg  [7:0]      usr_m_cnt_lo; 
    reg  [7:0]      usr_m_cnt_hi;
    reg             usr_m_cnt_bypass_en;
    reg             usr_m_cnt_odd_duty_div_en;
    reg             m_cnt_changed;
    reg             m_cnt_done_d;
    reg             m_cnt_done_q;
    //dyn phase regs
    reg  [15:0]     usr_num_shifts;
    reg  [4:0]      usr_cnt_sel /*synthesis preserve*/;
    reg             usr_up_dn;
    reg             dps_changed;
    wire            dps_changed_valid;
    wire            dps_done;

    //DSM Signals
    reg  [31:0]     usr_k_value;
    reg             dsm_k_changed;
    reg             dsm_k_done_d;
    reg             dsm_k_done_q;
    reg             dsm_k_ready_false_done_d;
    //BW signals 
    reg [3:0]       usr_bwctrl_value;
    reg             bwctrl_changed;
    reg             bwctrl_done_d;
    reg             bwctrl_done_q;
    //CP signals 
    reg [2:0]       usr_cp_current_value;
    reg             cp_current_changed;
    reg             cp_current_done_d;
    reg             cp_current_done_q;
    //Manual DPRIO signals
    reg             manual_dprio_done_q;
    reg             manual_dprio_done_d;
    reg             manual_dprio_changed;
    reg  [5:0]      usr_dprio_address;
    reg  [15:0]     usr_dprio_writedata_0;
    reg             usr_r_w;
	 //keeping track of which operation happened last
	 reg  [5:0]		  operation_address;
    // Address wires for all C_counter DPRIO registers
    // These are outputs of LUTS, changing depending
    // on whether PLL_0 or PLL_1 being used


    //Fitter will tell if FPLL1 is being used 
    wire            fpll_1;

    // other
    reg             mif_reg_asserted;
    // MAIN FSM                             
       
    always @(posedge clk)
    begin
        if (reset)
        begin
            dprio_cur_state <= DPRIO_IDLE;
            current_state <= IDLE;
        end
        else
        begin
            current_state <= next_state;
            dprio_cur_state <= dprio_next_state;
        end
    end

    always @(*)
     begin
        case(current_state)
          IDLE:
            begin
               if (pll_start & !slave_waitrequest & usr_valid_changes)
                 next_state = WAIT_ON_LOCK;
               else
                 next_state = IDLE;
            end
          WAIT_ON_LOCK:
            begin
               if (locked & dps_done & dprio_write_done)  // received locked high from PLL
                 begin
                    if (slave_mode==mode_WR) //if the mode is waitrequest, then
                                             // goto IDLE state directly
                      next_state = IDLE;
                    else
                      next_state = LOCKED; //otherwise go the locked state
                 end
               else
                  next_state = WAIT_ON_LOCK;
            end
              
          LOCKED:
            begin
               if (status_read) // stay in LOCKED until user reads status 
                 next_state = IDLE;
               else
                 next_state = LOCKED;
            end

          default: next_state = 2'bxx;
          
        endcase
     end


    // ask the pll to start reconfig
    assign pll_start = (pll_start_asserted & (current_state==IDLE))  ;
    assign pll_start_valid = (pll_start & (next_state==WAIT_ON_LOCK))  ;



    // WRITE OPERATIONS
    assign pll_start_asserted = slave_write & (slave_address == START_REG);
    assign mif_start_out = pll_start & mif_reg_asserted;

    //reading the mode register to determine what mode the slave will operate
    //in.
    always @(posedge clk)
    begin
        if (reset)
          slave_mode <= mode_WR;
        else if (slave_write & (slave_address == MODE_REG) & !slave_waitrequest)
          slave_mode <= slave_writedata[0];
    end

    //record which values user wants to change.

    //reading in the actual values that need to be reconfigged and sending
    //them to the PLL
    always @(posedge clk)
    begin
        if (reset)
        begin
            //reset all regs here
            //BW signals reset
            usr_bwctrl_value <= 0;
            bwctrl_changed <= 0;
            bwctrl_done_q <= 0;
            //CP signals reset
            usr_cp_current_value <= 0;
            cp_current_changed <= 0;
            cp_current_done_q <= 0;
            //DSM signals reset
            usr_k_value <= 0;
            dsm_k_changed <= 0;
            dsm_k_done_q <= 0;
            //N counter signals reset
            usr_n_cnt_lo <= 0;
            usr_n_cnt_hi <= 0;
            usr_n_cnt_bypass_en <= 0;
            usr_n_cnt_odd_duty_div_en <= 0;
            n_cnt_changed <= 0;
            n_cnt_done_q <= 0;
            //M counter signals reset
            usr_m_cnt_lo <= 0;
            usr_m_cnt_hi <= 0;
            usr_m_cnt_bypass_en <= 0;
            usr_m_cnt_odd_duty_div_en <= 0;
            m_cnt_changed <= 0;
            m_cnt_done_q <= 0;
            //C counter signals reset
            usr_c_cnt_lo <= 0;
            usr_c_cnt_hi <= 0;
            usr_c_cnt_bypass_en <= 0;
            usr_c_cnt_odd_duty_div_en <= 0;
            any_c_cnt_changed <= 0;
            all_c_cnt_done_q <= 0;
            c_cnt_done_q <= 0;
            //generic signals
            dprio_start <= 0;
            mif_start_assert <= 0;
            dps_start_assert <= 0;
            dprio_temp_m_n_c_readdata_1_q <= 0;
            dprio_temp_m_n_c_readdata_2_q <= 0;
            c_cnt_done_q <= 0;
            //DPS signals
            usr_up_dn <= 0;
            usr_cnt_sel <= 0;
            usr_num_shifts <= 0;
            dps_changed <= 0;
            //manual DPRIO signals
            manual_dprio_changed <= 0;
            usr_dprio_address <= 0;
            usr_dprio_writedata_0 <= 0;
            usr_r_w <= 0;
	    operation_address <= 0;
            mif_reg_asserted <= 0;
            mif_base_addr <= 0;
        end
        else
        begin
            if (dprio_temp_read_1)
            begin
                dprio_temp_m_n_c_readdata_1_q <= dprio_temp_m_n_c_readdata_1_d; 
            end
            if (dprio_temp_read_2)
            begin
                dprio_temp_m_n_c_readdata_2_q <= dprio_temp_m_n_c_readdata_2_d; 
            end
            if ((dps_done)) dps_changed <= 0;
            if (dsm_k_done_d) dsm_k_done_q <= dsm_k_done_d;
            if (n_cnt_done_d) n_cnt_done_q <= n_cnt_done_d;
            if (m_cnt_done_d) m_cnt_done_q <= m_cnt_done_d;
            if (all_c_cnt_done_d) all_c_cnt_done_q <= all_c_cnt_done_d;
            if (c_cnt_done_d != 0) c_cnt_done_q <= c_cnt_done_q | c_cnt_done_d;
            if (bwctrl_done_d) bwctrl_done_q <= bwctrl_done_d;
            if (cp_current_done_d) cp_current_done_q <= cp_current_done_d;
            if (manual_dprio_done_d) manual_dprio_done_q <= manual_dprio_done_d;

            if (mif_start_out == 1'b1)
                mif_start_assert <= 0; // Signaled MIF block to start, so deassert on next cycle
            
            if (dps_done != 1'b1)
                dps_start_assert <= 0; // DPS has started, so dessert its start signal on next cycle

            if (dprio_next_state == ONE)
                dprio_start <= 0;
            if (dprio_write_done)
            begin
                bwctrl_done_q <= 0;
                cp_current_done_q <= 0;
                dsm_k_done_q <= 0;
                dsm_k_done_q <= 0;
                n_cnt_done_q <= 0;
                m_cnt_done_q <= 0;
                all_c_cnt_done_q <= 0;
                c_cnt_done_q <= 0;
                dsm_k_changed <= 0;
                n_cnt_changed <= 0;
                m_cnt_changed <= 0;
                any_c_cnt_changed <= 0;
                bwctrl_changed <= 0;
                cp_current_changed <= 0;
                manual_dprio_changed <= 0;
                manual_dprio_done_q <= 0;
                if (dps_changed | dps_changed_valid | !dps_done )
                begin
                    usr_cnt_sel <= usr_cnt_sel;
                end
                else 
                begin
                    usr_cnt_sel <= 0;
                end
                mif_reg_asserted <= 0;
            end
            else 
            begin
                dsm_k_changed <= dsm_k_changed;
                n_cnt_changed <= n_cnt_changed;
                m_cnt_changed <= m_cnt_changed;
                any_c_cnt_changed <= any_c_cnt_changed;
                manual_dprio_changed <= manual_dprio_changed;
                mif_reg_asserted <= mif_reg_asserted;
                usr_cnt_sel <= usr_cnt_sel;
            end


            if(slave_write & !slave_waitrequest)
            begin
                case(slave_address)
                   //read in the values here from the user and act on them
                DSM_REG:
                begin
                    operation_address <= DSM_REG;
                    usr_k_value <= slave_writedata[31:0]; 
                    dsm_k_changed <= 1'b1;
                    dsm_k_done_q <= 0;
                    dprio_start <= 1'b1;
                end
                N_REG:
                begin
                    operation_address <= N_REG;
                    usr_n_cnt_lo <= slave_writedata[7:0]; 
                    usr_n_cnt_hi <= slave_writedata[15:8];
                    usr_n_cnt_bypass_en <= slave_writedata[16];
                    usr_n_cnt_odd_duty_div_en <= slave_writedata[17];
                    n_cnt_changed <= 1'b1;
                    n_cnt_done_q <= 0;
                    dprio_start <= 1'b1;
                end
                M_REG:
                begin
                    operation_address <= M_REG;
                    usr_m_cnt_lo <= slave_writedata[7:0]; 
                    usr_m_cnt_hi <= slave_writedata[15:8];
                    usr_m_cnt_bypass_en <= slave_writedata[16];
                    usr_m_cnt_odd_duty_div_en <= slave_writedata[17];
                    m_cnt_changed <= 1'b1;
                    m_cnt_done_q <= 0;
                    dprio_start <= 1'b1;
                end
                DPS_REG:
                begin
                    operation_address <= DPS_REG;
                    usr_num_shifts <= slave_writedata[15:0];
                    usr_cnt_sel <= slave_writedata[20:16];
                    usr_up_dn <= slave_writedata[21];
                    dps_changed <= 1;
                    dps_start_assert <= 1;
                end
                C_COUNTERS_REG:
                begin
						  operation_address <= C_COUNTERS_REG;
                    usr_c_cnt_lo <= slave_writedata[7:0]; 
                    usr_c_cnt_hi <= slave_writedata[15:8];
                    usr_c_cnt_bypass_en <= slave_writedata[16];
                    usr_c_cnt_odd_duty_div_en <= slave_writedata[17];
                    usr_cnt_sel <= slave_writedata[22:18];
                    any_c_cnt_changed <= 1'b1;
                    all_c_cnt_done_q <= 0;
                    dprio_start <= 1'b1;
                end
                BWCTRL_REG:
                begin
                    usr_bwctrl_value <= slave_writedata[3:0]; 
                    bwctrl_changed <= 1'b1;
                    bwctrl_done_q <= 0;
                    dprio_start <= 1'b1;
		    	  operation_address <= BWCTRL_REG;
                end
                CP_CURRENT_REG:
                begin
                    usr_cp_current_value <= slave_writedata[2:0]; 
                    cp_current_changed <= 1'b1;
                    cp_current_done_q <= 0;
                    dprio_start <= 1'b1;
		    operation_address <= CP_CURRENT_REG;
                end
                ANY_DPRIO:
                begin
						  operation_address <= ANY_DPRIO;
                    manual_dprio_changed <= 1'b1;
                    usr_dprio_address <= slave_writedata[5:0];
                    usr_dprio_writedata_0 <= slave_writedata[21:6];
                    usr_r_w <= slave_writedata[22];
                    manual_dprio_done_q <= 0;
                    dprio_start <= 1'b1;
                end
                MIF_REG:
                begin
                    mif_reg_asserted <= 1'b1;
                    mif_base_addr <= slave_writedata[ROM_ADDR_WIDTH-1:0];
                    mif_start_assert <= 1'b1;
                end                
                endcase
             end
        end 
    end
    //C Counter assigning values to the 2-d array of values for each C counter
   
    reg [4:0] j;
    always @(posedge clk)
    begin

        if (reset)
        begin
            c_cnt_changed[17:0] <= 0;
            for (j = 0; j < number_of_counters; j = j + 1'b1)
            begin : c_cnt_reset
                temp_c_cnt_bypass_en[j] <= 0;
                temp_c_cnt_odd_duty_div_en[j] <= 0;
                temp_c_cnt_lo[j][7:0] <= 0;
                temp_c_cnt_hi[j][7:0] <= 0;
            end
        end
        else 
        begin
            if (dprio_write_done)
            begin
                c_cnt_changed <= 0;
            end
            if (any_c_cnt_changed && (operation_address == C_COUNTERS_REG))
            begin
                case (cnt_sel)
                    CNT_0:
                    begin
                        temp_c_cnt_lo [0] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [0] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [0] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [0] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [0] <= 1'b1;
                    end
                    CNT_1:
                    begin
                        temp_c_cnt_lo [1] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [1] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [1] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [1] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [1] <= 1'b1;
                    end
                    CNT_2:
                    begin
                        temp_c_cnt_lo [2] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [2] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [2] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [2] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [2] <= 1'b1;
                    end
                    CNT_3:
                    begin
                        temp_c_cnt_lo [3] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [3] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [3] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [3] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [3] <= 1'b1;
                    end
                    CNT_4:
                    begin
                        temp_c_cnt_lo [4] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [4] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [4] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [4] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [4] <= 1'b1;
                    end
                    CNT_5:
                    begin
                        temp_c_cnt_lo [5] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [5] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [5] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [5] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [5] <= 1'b1;
                    end
                    CNT_6:
                    begin
                        temp_c_cnt_lo [6] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [6] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [6] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [6] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [6] <= 1'b1;
                    end
                    CNT_7:
                    begin
                        temp_c_cnt_lo [7] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [7] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [7] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [7] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [7] <= 1'b1;
                    end
                    CNT_8:
                    begin
                        temp_c_cnt_lo [8] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [8] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [8] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [8] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [8] <= 1'b1;
                    end
                    CNT_9:
                    begin
                        temp_c_cnt_lo [9] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [9] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [9] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [9] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [9] <= 1'b1;
                    end
                    CNT_10:
                    begin
                        temp_c_cnt_lo [10] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [10] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [10] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [10] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [10] <= 1'b1;
                    end
                    CNT_11:
                    begin
                        temp_c_cnt_lo [11] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [11] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [11] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [11] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [11] <= 1'b1;
                    end
                    CNT_12:
                    begin
                        temp_c_cnt_lo [12] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [12] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [12] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [12] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [12] <= 1'b1;
                    end
                    CNT_13:
                    begin
                        temp_c_cnt_lo [13] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [13] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [13] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [13] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [13] <= 1'b1;
                    end
                    CNT_14:
                    begin
                        temp_c_cnt_lo [14] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [14] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [14] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [14] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [14] <= 1'b1;
                    end
                    CNT_15:
                    begin
                        temp_c_cnt_lo [15] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [15] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [15] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [15] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [15] <= 1'b1;
                    end
                    CNT_16:
                    begin
                        temp_c_cnt_lo [16] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [16] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [16] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [16] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [16] <= 1'b1;
                    end
                    CNT_17:
                    begin
                        temp_c_cnt_lo [17] <= usr_c_cnt_lo;
                        temp_c_cnt_hi [17] <= usr_c_cnt_hi;
                        temp_c_cnt_bypass_en [17] <= usr_c_cnt_bypass_en;
                        temp_c_cnt_odd_duty_div_en [17] <= usr_c_cnt_odd_duty_div_en;
                        c_cnt_changed [17] <= 1'b1;
                    end
                endcase

            end
        end
    end


    //logic to handle which writes the user indicated and wants to start.
    assign usr_valid_changes =dsm_k_changed| any_c_cnt_changed |n_cnt_changed | m_cnt_changed | dps_changed_valid |manual_dprio_changed |cp_current_changed|bwctrl_changed;

     
    //start the reconfig operations by writing to the DPRIO
    reg break_loop;
    reg [4:0] i;
    always @(*)
    begin 
        dprio_temp_read_1 = 0;
        dprio_temp_read_2 = 0;
        dprio_temp_m_n_c_readdata_1_d = 0;
        dprio_temp_m_n_c_readdata_2_d = 0;
        break_loop = 0;
        dprio_next_state = DPRIO_IDLE;
        avmm_dprio_write = 0;
        avmm_dprio_read = 0;
        avmm_dprio_address = 0;
        avmm_dprio_writedata = 0;
        avmm_dprio_byteen = 0;
        dprio_write_done = 1;
        manual_dprio_done_d = 0;
        n_cnt_done_d = 0;
        dsm_k_done_d = 0;
        dsm_k_ready_false_done_d = 0;
        m_cnt_done_d = 0;
        c_cnt_done_d[17:0] = 0;
        all_c_cnt_done_d = 0;
        bwctrl_done_d = 0;
        cp_current_done_d = 0;
        i = 0;
       
        // Deassert dprio_write_done so it doesn't reset mif_reg_asserted (toggled writes) 
        if (dprio_start | mif_start_assert)
            dprio_write_done = 0;

        if (current_state == WAIT_ON_LOCK)
        begin
            case (dprio_cur_state)
                ONE:
                begin
                    if (n_cnt_changed & !n_cnt_done_q) 
                    begin
			dprio_write_done = 0;
                    	avmm_dprio_write = 1'b1;
                    	avmm_dprio_byteen = 2'b11;
                    	dprio_next_state = TWO;
                        avmm_dprio_address = N_CNT_DIV_ADDR;
                        avmm_dprio_writedata[7:0] = usr_n_cnt_lo;
                        avmm_dprio_writedata[15:8] = usr_n_cnt_hi;
                    end
                    else if (m_cnt_changed & !m_cnt_done_q) 
                    begin
		    	dprio_write_done = 0;
                    	avmm_dprio_write = 1'b1;
                    	avmm_dprio_byteen = 2'b11;
                    	dprio_next_state = TWO;
                        avmm_dprio_address = M_CNT_DIV_ADDR;
                        avmm_dprio_writedata[7:0] = usr_m_cnt_lo;
                        avmm_dprio_writedata[15:8] = usr_m_cnt_hi;
                    end
                    else if (any_c_cnt_changed & !all_c_cnt_done_q)
                    begin

                        for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1)
                        begin : c_cnt_write_hilo
                            if (c_cnt_changed[i] & !c_cnt_done_q[i])
                            begin
				dprio_write_done = 0;
	                    	avmm_dprio_write = 1'b1;
        	            	avmm_dprio_byteen = 2'b11;
                	    	dprio_next_state = TWO;
                                if (fpll_1) avmm_dprio_address = C_CNT_0_DIV_ADDR + C_CNT_0_DIV_ADDR_DPRIO_1 - i;
                                else avmm_dprio_address = C_CNT_0_DIV_ADDR + i;
                                avmm_dprio_writedata[7:0] = temp_c_cnt_lo[i];
                                avmm_dprio_writedata[15:8] = temp_c_cnt_hi[i];
                                //To break from the loop, since only one counter
                                //is addressed at a time
                                break_loop = 1'b1;
                            end
                        end
                    end
                    else if (dsm_k_changed & !dsm_k_done_q) 
                    begin
		    	dprio_write_done = 0;
                        avmm_dprio_write = 0;
                        dprio_next_state = TWO;
                    end
                    else if (bwctrl_changed & !bwctrl_done_q) 
                    begin
		    	dprio_write_done = 0;
                        avmm_dprio_write = 0;
                        dprio_next_state = TWO;
                    end
                    else if (cp_current_changed & !cp_current_done_q) 
                    begin
		    	dprio_write_done = 0;		    
                        avmm_dprio_write = 0;
                        dprio_next_state = TWO;
                    end
                    else if (manual_dprio_changed & !manual_dprio_done_q)
                    begin
		    	dprio_write_done = 0;
                    	avmm_dprio_byteen = 2'b11;
                    	dprio_next_state = TWO;		    
                        avmm_dprio_write = usr_r_w;
                        avmm_dprio_address = usr_dprio_address;
                        avmm_dprio_writedata[15:0] = usr_dprio_writedata_0;
                    end
                    else dprio_next_state = DPRIO_IDLE;
                end
            
                TWO:
                begin
                    //handle reading the two setting bits on n_cnt, then
                    //writing them back while preserving other bits.
                    //Issue two consecutive reads then wait; readLatency=3
                    dprio_write_done = 0;
                    dprio_next_state = THREE;
                    avmm_dprio_byteen = 2'b11;
                    avmm_dprio_read = 1'b1;
                    if (n_cnt_changed & !n_cnt_done_q)
                    begin
                        avmm_dprio_address = N_CNT_BYPASS_EN_ADDR;
                    end
                    else if (m_cnt_changed & !m_cnt_done_q)
                    begin
                        avmm_dprio_address = M_CNT_BYPASS_EN_ADDR;
                    end
                   
                    else if (any_c_cnt_changed & !all_c_cnt_done_q)
                    begin
                        for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1)
                        begin : c_cnt_read_bypass
                            if (fpll_1)
                            begin
                                if (i > 13)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                            else
                            begin
                                if (i < 4)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                        end
                    end
                    //reading the K ready 16 bit word. Need to write 0 to it
                    //afterwards to indicate that K has not been done writing
                    else if (dsm_k_changed & !dsm_k_done_q) 
                    begin
                        avmm_dprio_address = DSM_K_READY_ADDR;
                        dprio_next_state = FOUR;
                    end
                    else if (bwctrl_changed & !bwctrl_done_q) 
                    begin
                        avmm_dprio_address = BWCTRL_ADDR;
                        dprio_next_state = FOUR;
                    end
                    else if (cp_current_changed & !cp_current_done_q) 
                    begin
                        avmm_dprio_address = CP_CURRENT_ADDR;
                        dprio_next_state = FOUR;
                    end
                    else if (manual_dprio_changed & !manual_dprio_done_q)
                    begin
                        avmm_dprio_read = ~usr_r_w;
                        avmm_dprio_address = usr_dprio_address;
                        dprio_next_state = DPRIO_DONE;
                    end
                    else dprio_next_state = DPRIO_IDLE;
                end       
                THREE:
                begin
                    dprio_write_done = 0;
                    avmm_dprio_byteen = 2'b11;
                    avmm_dprio_read = 1'b1;
                    dprio_next_state = FOUR;
                    if (n_cnt_changed & !n_cnt_done_q)
                    begin
                        avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR;
                    end
                    else if (m_cnt_changed & !m_cnt_done_q)
                    begin
                        avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR;
                    end
                    else if (any_c_cnt_changed & !all_c_cnt_done_q)
                    begin
                        for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1)
                        begin : c_cnt_read_odd_div
                            if (fpll_1)
                            begin
                                if (i > 13)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                            else
                            begin
                                if (i < 4)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                        end
                    end   
                    else dprio_next_state = DPRIO_IDLE;
                end
                FOUR:
                begin
                    dprio_temp_read_1 = 1'b1;
                    dprio_write_done = 0;
                    if (cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed)
                    begin
                        dprio_temp_m_n_c_readdata_1_d = dprio_readdata;
                        dprio_next_state = FIVE;
                    end
                    else dprio_next_state = DPRIO_IDLE;
                end
                FIVE:
                begin
                    dprio_write_done = 0;
                    dprio_temp_read_2 = 1'b1;
                    if (cp_current_changed|bwctrl_changed|dsm_k_changed|n_cnt_changed|m_cnt_changed|any_c_cnt_changed)
                    begin
                        //this is where DSM ready value comes.
                        //Need to store in a register to be used later
                        dprio_temp_m_n_c_readdata_2_d = dprio_readdata;
                        dprio_next_state = SIX;
                    end
                    else dprio_next_state = DPRIO_IDLE;
                end
                SIX:
                begin
                    dprio_write_done = 0;
                    avmm_dprio_write = 1'b1;
                    avmm_dprio_byteen = 2'b11;
                    dprio_next_state = SEVEN;
                    avmm_dprio_writedata = dprio_temp_m_n_c_readdata_1_q;
                    if (n_cnt_changed & !n_cnt_done_q)
                    begin
                        avmm_dprio_address = N_CNT_BYPASS_EN_ADDR;
                        avmm_dprio_writedata[5] = usr_n_cnt_bypass_en;
                    end
                    else if (m_cnt_changed & !m_cnt_done_q)
                    begin
                        avmm_dprio_address = M_CNT_BYPASS_EN_ADDR;
                        avmm_dprio_writedata[4] = usr_m_cnt_bypass_en;
                    end
                    else if (any_c_cnt_changed & !all_c_cnt_done_q)
                    begin
                        for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1)
                        begin : c_cnt_write_bypass
                            if (fpll_1)
                            begin
                                if (i > 13)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR;
                                        avmm_dprio_writedata[i-14] = temp_c_cnt_bypass_en[i];
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR;
                                        avmm_dprio_writedata[i] = temp_c_cnt_bypass_en[i];
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                            else
                            begin
                                if (i < 4)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_BYPASS_EN_ADDR;
                                        avmm_dprio_writedata[3-i] = temp_c_cnt_bypass_en[i];
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_BYPASS_EN_ADDR;
                                        avmm_dprio_writedata[17-i] = temp_c_cnt_bypass_en[i];
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                        end
                    end    
                    else if (dsm_k_changed & !dsm_k_done_q)
                    begin
                        avmm_dprio_write = 0;
                    end
                    else if (bwctrl_changed & !bwctrl_done_q) 
                    begin
                        avmm_dprio_write = 0;
                    end
                    else if (cp_current_changed & !cp_current_done_q) 
                    begin
                        avmm_dprio_write = 0;
                    end
                    else dprio_next_state = DPRIO_IDLE;
                end
                SEVEN:
                begin
                    dprio_write_done = 0;
                    dprio_next_state = EIGHT;
                    avmm_dprio_write = 1'b1;
                    avmm_dprio_byteen = 2'b11;
                    avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q;
                    if (n_cnt_changed & !n_cnt_done_q)
                    begin
                        avmm_dprio_address = N_CNT_ODD_DIV_EN_ADDR;
                        avmm_dprio_writedata[5] = usr_n_cnt_odd_duty_div_en;
                        n_cnt_done_d = 1'b1;
                    end
                    else if (m_cnt_changed & !m_cnt_done_q)
                    begin
                        avmm_dprio_address = M_CNT_ODD_DIV_EN_ADDR;
                        avmm_dprio_writedata[4] = usr_m_cnt_odd_duty_div_en;
                        m_cnt_done_d = 1'b1;
                    end
                         
                    else if (any_c_cnt_changed & !all_c_cnt_done_q)
                    begin
                        for (i = 0; (i < number_of_counters) & !break_loop; i = i + 1'b1)
                        begin : c_cnt_write_odd_div
                            if (fpll_1)
                            begin
                                if (i > 13)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR;
                                        avmm_dprio_writedata[i-14] = temp_c_cnt_odd_duty_div_en[i];
                                        c_cnt_done_d[i] = 1'b1;
                                        //have to OR the signals to prevent
                                        //overwriting of previous dones
                                        c_cnt_done_d = c_cnt_done_d | c_cnt_done_q;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR;
                                        avmm_dprio_writedata[i] = temp_c_cnt_odd_duty_div_en[i];
                                        c_cnt_done_d[i] = 1'b1;
                                        c_cnt_done_d = c_cnt_done_d | c_cnt_done_q;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                            else
                            begin
                                if (i < 4)
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_0_3_ODD_DIV_EN_ADDR;
                                        avmm_dprio_writedata[3-i] = temp_c_cnt_odd_duty_div_en[i];
                                        c_cnt_done_d[i] = 1'b1;
                                        //have to OR the signals to prevent
                                        //overwriting of previous dones
                                        c_cnt_done_d = c_cnt_done_d | c_cnt_done_q;
                                        break_loop = 1'b1;
                                    end
                                end
                                else
                                begin
                                    if (c_cnt_changed[i] & !c_cnt_done_q[i])
                                    begin
                                        avmm_dprio_address = C_CNT_4_17_ODD_DIV_EN_ADDR;
                                        avmm_dprio_writedata[17-i] = temp_c_cnt_odd_duty_div_en[i];
                                        c_cnt_done_d[i] = 1'b1;
                                        c_cnt_done_d = c_cnt_done_d | c_cnt_done_q;
                                        break_loop = 1'b1;
                                    end
                                end
                            end
                        end
                    end
                    else if (dsm_k_changed & !dsm_k_done_q)
                    begin
                        avmm_dprio_address = DSM_K_READY_ADDR;
                        avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b0;
                        dsm_k_ready_false_done_d = 1'b1;
                    end
                    else if (bwctrl_changed & !bwctrl_done_q) 
                    begin
                        avmm_dprio_address = BWCTRL_ADDR;
                        avmm_dprio_writedata[3:0] = usr_bwctrl_value;
                        bwctrl_done_d = 1'b1;
                    end
                    else if (cp_current_changed & !cp_current_done_q) 
                    begin
                        avmm_dprio_address = CP_CURRENT_ADDR;
                        avmm_dprio_writedata[2:0] = usr_cp_current_value;
                        cp_current_done_d = 1'b1;
                    end

                   
                    //if all C_cnt that were changed are done, then assert all_c_cnt_done
                    if (c_cnt_done_d == c_cnt_changed)
                        all_c_cnt_done_d = 1'b1;
                    if (n_cnt_changed & n_cnt_done_d)
                        dprio_next_state = DPRIO_DONE;
                    if (any_c_cnt_changed & !all_c_cnt_done_d & !all_c_cnt_done_q)
                        dprio_next_state = ONE;
                    else if (m_cnt_changed & !m_cnt_done_d & !m_cnt_done_q)
                        dprio_next_state = ONE;
                    else if (dsm_k_changed & !dsm_k_ready_false_done_d)
                        dprio_next_state = TWO;
                    else if (dsm_k_changed & !dsm_k_done_q)
                        dprio_next_state = EIGHT;
                    else if (bwctrl_changed & !bwctrl_done_d)
                        dprio_next_state = TWO;
                    else if (cp_current_changed & !cp_current_done_d)
                        dprio_next_state = TWO;
                    else 
                    begin
                        dprio_next_state = DPRIO_DONE;
                        dprio_write_done = 1'b1;
                    end
                end
                //finish the rest of the DSM reads/writes
                //writing k value, writing k_ready to 1.
                EIGHT: 
                begin
                    dprio_write_done = 0;
                    dprio_next_state = NINE;
                    avmm_dprio_write = 1'b1;
                    avmm_dprio_byteen = 2'b11;
                    if (dsm_k_changed & !dsm_k_done_q)
                    begin
                        avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_0;
                        avmm_dprio_writedata[15:0] = usr_k_value[15:0];
                    end
                end
                NINE: 
                begin
                    dprio_write_done = 0;
                    dprio_next_state = TEN;
                    avmm_dprio_write = 1'b1;
                    avmm_dprio_byteen = 2'b11;
                    if (dsm_k_changed & !dsm_k_done_q)
                    begin
                        avmm_dprio_address = DSM_K_FRACTIONAL_DIVISION_ADDR_1;
                        avmm_dprio_writedata[15:0] = usr_k_value[31:16];
                    end
                end
                TEN:
                begin
                    dprio_write_done = 0;
                    dprio_next_state = ONE;
                    avmm_dprio_write = 1'b1;
                    avmm_dprio_byteen = 2'b11;
                    if (dsm_k_changed & !dsm_k_done_q)
                    begin
                        avmm_dprio_address = DSM_K_READY_ADDR;
                        //already have the readdata for DSM_K_READY_ADDR since we read it
                        //earlier. Just reuse here 
                        avmm_dprio_writedata = dprio_temp_m_n_c_readdata_2_q;
                        avmm_dprio_writedata[DSM_K_READY_BIT_INDEX] = 1'b1;
                        dsm_k_done_d = 1'b1;
                    end
                end
                DPRIO_DONE:
                begin
                    dprio_write_done = 1'b1;
                    if (dprio_start) dprio_next_state = DPRIO_IDLE;
                    else dprio_next_state = DPRIO_DONE;
                end
                DPRIO_IDLE:
                begin
                    if (dprio_start) dprio_next_state = ONE;
                    else dprio_next_state = DPRIO_IDLE;
                end 
                default:    dprio_next_state = 4'bxxxx;
            endcase
        end

    end


    //assert the waitreq signal according to the state of the slave
    assign slave_waitrequest = (slave_mode==mode_WR) ? ((locked === 1'b1) ? (((current_state==WAIT_ON_LOCK) & !dprio_write_done) | !dps_done |reset|!dprio_init_done) : 1'b1) : 1'b0;
        
    // Read operations
    always @(*)
    begin
    status = 0;
    if (slave_mode == mode_POLL)
        //asserting status to 1 if the slave is done.
       status = (current_state == LOCKED);
    end
    //************************************************************//
    //************************************************************//
    //******************** READ STATE MACHINE ********************//
    //************************************************************//
    //************************************************************//
    reg  [1:0]      current_read_state;
    reg  [1:0]      next_read_state;
    reg  [5:0]      slave_address_int_d;
    reg  [5:0]      slave_address_int_q;
    reg             dprio_read_1;
    reg  [5:0]      dprio_address_1;
    reg  [1:0]      dprio_byteen_1;
    reg  [4:0]      usr_cnt_sel_1;
    localparam READ = 2'b00, READ_WAIT = 2'b01, READ_IDLE = 2'b10;
    always @(posedge clk)
    begin
        if (reset)
        begin
            current_read_state <= READ_IDLE;
            slave_address_int_q <= 0;
            slave_readdata_q <= 0;
        end
        else
        begin
            current_read_state <= next_read_state;
            slave_address_int_q <= slave_address_int_d;
            slave_readdata_q <= slave_readdata_d;
        end
    end
    always @(*)
    begin
        dprio_read_1 = 0;
        dprio_address_1 = 0;
        dprio_byteen_1 = 0;
        slave_address_int_d = 0;
        slave_readdata_d = 0;
        status_read = 0;
        usr_cnt_sel_1 = 0;
        case(current_read_state)
        READ_IDLE:
        begin
            slave_address_int_d = 0;
            next_read_state = READ_IDLE;
            if ((current_state != WAIT_ON_LOCK) && slave_read)
            begin
                slave_address_int_d = slave_address;
                if ((slave_address >= CNT_BASE) && (slave_address < CNT_BASE+18))
                begin
                    next_read_state = READ_WAIT;
                    dprio_byteen_1 = 2'b11;
                    dprio_read_1 = 1'b1;
                    usr_cnt_sel_1 = (slave_address[4:0] - CNT_BASE);
                    if (fpll_1) dprio_address_1 = C_CNT_0_DIV_ADDR + C_CNT_0_DIV_ADDR_DPRIO_1 - cnt_sel;
                    else dprio_address_1 = C_CNT_0_DIV_ADDR + cnt_sel;
                end
                else
                begin
                case (slave_address)
                MODE_REG:
                begin
                    next_read_state = READ_WAIT;
                    slave_readdata_d = slave_mode;
                end
                STATUS_REG:
                begin
                    next_read_state = READ_WAIT;
                    status_read = 1'b1;
                    slave_readdata_d = status;
                end
                N_REG:
                begin
                    dprio_byteen_1 = 2'b11;
                    dprio_read_1 = 1'b1;
                    dprio_address_1 = N_CNT_DIV_ADDR;
                    next_read_state = READ_WAIT;
                end
                M_REG:
                begin
                    dprio_byteen_1 = 2'b11;
                    dprio_read_1 = 1'b1;
                    dprio_address_1 = M_CNT_DIV_ADDR;
                    next_read_state = READ_WAIT;
                end
                BWCTRL_REG:
                begin
                    dprio_byteen_1 = 2'b11;
                    dprio_read_1 = 1'b1;
                    dprio_address_1 = BWCTRL_ADDR;
                    next_read_state = READ_WAIT;
                end
                CP_CURRENT_REG:
                begin
                    dprio_byteen_1 = 2'b11;
                    dprio_read_1 = 1'b1;
                    dprio_address_1 = CP_CURRENT_ADDR;
                    next_read_state = READ_WAIT;
                end
                default : next_read_state = READ_IDLE;
                endcase
            end
            end
            else
                next_read_state = READ_IDLE;
        end
        READ_WAIT:
        begin
            next_read_state = READ;
            slave_address_int_d = slave_address_int_q;
            case (slave_address_int_q)
            MODE_REG:
            begin
                slave_readdata_d = slave_readdata_q;
            end
            STATUS_REG:
            begin
                slave_readdata_d = slave_readdata_q;
            end
    	    endcase
        end
        READ:
        begin
            next_read_state = READ_IDLE;
            slave_address_int_d = slave_address_int_q;
            slave_readdata_d = dprio_readdata;
            case (slave_address_int_q)
            MODE_REG:
            begin
                slave_readdata_d = slave_readdata_q;
            end
            STATUS_REG:
            begin
                slave_readdata_d = slave_readdata_q;
            end
            BWCTRL_REG:
            begin
                slave_readdata_d = dprio_readdata[3:0];
            end
            CP_CURRENT_REG:
            begin
                slave_readdata_d = dprio_readdata[2:0];
            end
    	    endcase
        end
        default: next_read_state = 2'bxx;
        endcase
     end


    dyn_phase_shift dyn_phase_shift_inst (
        .clk(clk), 
        .reset(reset),
        .phase_done(phase_done),
        .pll_start_valid(pll_start_valid),
        .dps_changed(dps_changed),
        .dps_changed_valid(dps_changed_valid),
        .dprio_write_done(dprio_write_done),
        .usr_num_shifts(usr_num_shifts),
        .usr_cnt_sel(usr_cnt_sel|usr_cnt_sel_1),
        .usr_up_dn(usr_up_dn),
        .locked(locked),
        .dps_done(dps_done),
        .phase_en(phase_en),
        .up_dn(up_dn),
        .cnt_sel(cnt_sel));
    defparam dyn_phase_shift_inst.device_family = device_family;

    assign dprio_clk = clk;
    self_reset self_reset_inst (mgmt_reset, clk, reset, dprio_init_reset);
    
    dprio_mux dprio_mux_inst (
    .init_dprio_address(init_dprio_address),
    .init_dprio_read(init_dprio_read),
    .init_dprio_byteen(init_dprio_byteen),
    .init_dprio_write(init_dprio_write),
    .init_dprio_writedata(init_dprio_writedata),


    .init_atpgmode(init_atpgmode),
    .init_mdio_dis(init_mdio_dis),
    .init_scanen(init_scanen),
    .init_ser_shift_load(init_ser_shift_load),
    .dprio_init_done(dprio_init_done),

    // Inputs from avmm master
    .avmm_dprio_address(avmm_dprio_address | dprio_address_1),
    .avmm_dprio_read(avmm_dprio_read | dprio_read_1),
    .avmm_dprio_byteen(avmm_dprio_byteen | dprio_byteen_1),
    .avmm_dprio_write(avmm_dprio_write),
    .avmm_dprio_writedata(avmm_dprio_writedata),

    .avmm_atpgmode(avmm_atpgmode),
    .avmm_mdio_dis(avmm_mdio_dis),
    .avmm_scanen(avmm_scanen),

    // Outputs to fpll
    .dprio_address(dprio_address),
    .dprio_read(dprio_read),
    .dprio_byteen(dprio_byteen),
    .dprio_write(dprio_write),
    .dprio_writedata(dprio_writedata),

    .atpgmode(dprio_atpgmode),
    .mdio_dis(dprio_mdio_dis),
    .scanen(dprio_scanen),
    .ser_shift_load(dprio_ser_shift_load)
    );


    fpll_dprio_init fpll_dprio_init_inst (
    .clk(clk),
    .reset_n(~reset),
    .locked(locked),

    //outputs
    .dprio_address(init_dprio_address),
    .dprio_read(init_dprio_read),
    .dprio_byteen(init_dprio_byteen),
    .dprio_write(init_dprio_write),
    .dprio_writedata(init_dprio_writedata),

    .atpgmode(init_atpgmode),
    .mdio_dis(init_mdio_dis),
    .scanen(init_scanen),
    .ser_shift_load(init_ser_shift_load),
    .dprio_init_done(dprio_init_done));

    //address luts, to be reconfigged by the Fitter
    //FPLL_1 or 0 address lut
    generic_lcell_comb lcell_fpll_0_1 (
		.dataa(1'b0),
        .combout (fpll_1));
    defparam lcell_fpll_0_1.lut_mask = 64'hAAAAAAAAAAAAAAAA;
	 defparam lcell_fpll_0_1.dont_touch = "on";
	 defparam lcell_fpll_0_1.family = device_family;


    wire dprio_read_combout;
     generic_lcell_comb lcell_dprio_read (
		.dataa(fpll_1),
        .datab(dprio_read),
        .datac(1'b0),
        .datad(1'b0),
        .datae(1'b0),
        .dataf(1'b0),
      .combout (dprio_read_combout));
    defparam lcell_dprio_read.lut_mask = 64'hCCCCCCCCCCCCCCCC;
	 defparam lcell_dprio_read.dont_touch = "on";
	 defparam lcell_dprio_read.family = device_family;

   
    


    //assign reconfig_to_pll signals
    assign reconfig_to_pll[0] = dprio_clk;
    assign reconfig_to_pll[1] = ~dprio_init_reset;
    assign reconfig_to_pll[2] = dprio_write;
    assign reconfig_to_pll[3] = dprio_read_combout;
    assign reconfig_to_pll[9:4] = dprio_address;
    assign reconfig_to_pll[25:10] = dprio_writedata;
    assign reconfig_to_pll[27:26] = dprio_byteen;
    assign reconfig_to_pll[28] = dprio_ser_shift_load;
    assign reconfig_to_pll[29] = dprio_mdio_dis;
    assign reconfig_to_pll[30] = phase_en;
    assign reconfig_to_pll[31] = up_dn;
    assign reconfig_to_pll[36:32] = cnt_sel;
    assign reconfig_to_pll[37] = dprio_scanen;
    assign reconfig_to_pll[38] = dprio_atpgmode;
    //assign reconfig_to_pll[40:37] = clken;
    assign reconfig_to_pll[63:39] = 0;

    //assign reconfig_from_pll signals
    assign dprio_readdata = reconfig_from_pll [15:0]; 
    assign locked         = reconfig_from_pll [16];
    assign phase_done     = reconfig_from_pll [17];

endmodule
module self_reset (input wire mgmt_reset, input wire clk, output wire reset, output wire init_reset);

    localparam RESET_COUNTER_VALUE = 3'd2;
    localparam INITIAL_WAIT_VALUE = 9'd340;
    reg [9:0]counter;
    reg local_reset;
    reg usr_mode_init_wait;
    initial 
    begin
        local_reset = 1'b1;
        counter = 0;
        usr_mode_init_wait = 0;
    end

    always @(posedge clk)
    begin
        if (mgmt_reset)
        begin
            counter <= 0;
        end
        else
        begin
            if (!usr_mode_init_wait)
            begin
                if (counter == INITIAL_WAIT_VALUE)
                begin
                    local_reset <= 0;
                    usr_mode_init_wait <= 1'b1;
                    counter <= 0;
                end
                else 
                begin
                counter <= counter + 1'b1;
                end
            end
            else
            begin
                if (counter == RESET_COUNTER_VALUE)
                    local_reset <= 0;
                else 
                    counter <= counter + 1'b1;
            end
        end
    end
    assign reset = mgmt_reset | local_reset;
    assign init_reset = local_reset;
endmodule

module dprio_mux (
    // Inputs from init block
    input       [ 5:0]  init_dprio_address,
    input               init_dprio_read,
    input       [ 1:0]  init_dprio_byteen,
    input               init_dprio_write,
    input       [15:0]  init_dprio_writedata,

    input               init_atpgmode,
    input               init_mdio_dis,
    input               init_scanen,
    input               init_ser_shift_load,
    input               dprio_init_done,

    // Inputs from avmm master
    input       [ 5:0]  avmm_dprio_address,
    input               avmm_dprio_read,
    input       [ 1:0]  avmm_dprio_byteen,
    input               avmm_dprio_write,
    input       [15:0]  avmm_dprio_writedata,

    input               avmm_atpgmode,
    input               avmm_mdio_dis,
    input               avmm_scanen,
    input               avmm_ser_shift_load,

    // Outputs to fpll
    output      [ 5:0]  dprio_address,
    output              dprio_read,
    output      [ 1:0]  dprio_byteen,
    output              dprio_write,
    output      [15:0]  dprio_writedata,

    output              atpgmode,
    output              mdio_dis,
    output              scanen,
    output              ser_shift_load
);

    assign  dprio_address   = dprio_init_done ? avmm_dprio_address    : init_dprio_address;
    assign  dprio_read      = dprio_init_done ? avmm_dprio_read       : init_dprio_read;
    assign  dprio_byteen    = dprio_init_done ? avmm_dprio_byteen     : init_dprio_byteen;
    assign  dprio_write     = dprio_init_done ? avmm_dprio_write      : init_dprio_write;
    assign  dprio_writedata = dprio_init_done ? avmm_dprio_writedata  : init_dprio_writedata;

    assign  atpgmode        = init_atpgmode;
    assign  scanen          = init_scanen;
    assign  mdio_dis        = init_mdio_dis;
    assign  ser_shift_load  = init_ser_shift_load ;
endmodule
module fpll_dprio_init (
    input               clk,
    input               reset_n,
    input               locked,

    output      [ 5:0]  dprio_address,
    output              dprio_read,
    output      [ 1:0]  dprio_byteen,
    output              dprio_write,
    output      [15:0]  dprio_writedata,

    output  reg         atpgmode,
    output  reg         mdio_dis,
    output  reg         scanen,
    output  reg         ser_shift_load,
    output  reg         dprio_init_done
);

    reg [1:0] rst_n = 2'b00;
    reg [6:0] count = 7'd0;
    reg init_done_forever;

    // Internal versions of control signals
    wire  int_mdio_dis;
    wire  int_ser_shift_load;
    wire  int_dprio_init_done;
    wire  int_atpgmode/*synthesis keep*/;
    wire  int_scanen/*synthesis keep*/;


    assign  dprio_address   = count[6] ? 5'b0 : count[5:0] ;
    assign  dprio_byteen    = 2'b11;      // always enabled
    assign  dprio_write     = ~count[6] & reset_n ;  // write for first 64 cycles
    assign  dprio_read      = 1'b0;
    assign  dprio_writedata = 16'd0;

    assign  int_ser_shift_load  = count[6] ? |count[2:1]  : 1'b1; 
    assign  int_mdio_dis        = count[6] ? ~count[2]    : 1'b1;
    assign  int_dprio_init_done = ~init_done_forever ? (count[6] ? &count[2:0]  : 1'b0)
                                                    : 1'b1;
    assign  int_atpgmode        = 0;
    assign  int_scanen          = 0;

    initial begin
        count             = 7'd0;
        init_done_forever = 0;
        mdio_dis          = 1'b1;
        ser_shift_load    = 1'b1;
        dprio_init_done   = 1'b0;
        scanen            = 1'b0;
        atpgmode          = 1'b0;
    end

    // reset synch.
    always @(posedge clk or negedge reset_n)
        if(!reset_n)  rst_n <= 2'b00;
        else          rst_n <= {rst_n[0],1'b1};

    // counter
    always @(posedge clk)
    begin
        if (!rst_n[1])
            init_done_forever <= 1'b0;
        else
        begin
        if (count[6] && &count[1:0])
            init_done_forever <= 1'b1;
        end
    end
    always @(posedge clk or negedge rst_n[1])
    begin
        if(!rst_n[1])
        begin
            count <= 7'd0;
        end
        else if(~int_dprio_init_done) 
        begin
            count <= count + 7'd1;
        end
        else
        begin
            count <= count;
        end
    end

    // outputs
    always @(posedge clk) begin
        mdio_dis        <= int_mdio_dis;
        ser_shift_load  <= int_ser_shift_load;
        dprio_init_done <= int_dprio_init_done;
        atpgmode        <= int_atpgmode;
        scanen          <= int_scanen;
    end

endmodule
module dyn_phase_shift
#(
    parameter device_family       = "Stratix V"
) ( 

    input   wire        clk,
    input   wire        reset,
    input   wire        phase_done,
    input   wire        pll_start_valid,
    input   wire        dps_changed,
    input   wire        dprio_write_done,
    input   wire [15:0] usr_num_shifts,
    input   wire [4:0]  usr_cnt_sel,
    input   wire        usr_up_dn,
    input   wire        locked,

    //output
    output  wire        dps_done,
    output  reg         phase_en,
    output  wire        up_dn,
    output  wire        dps_changed_valid,
    output  wire [4:0]  cnt_sel);
    
	

    reg        first_phase_shift_d;
    reg        first_phase_shift_q;
    reg [15:0] phase_en_counter;
    reg [3:0]       dps_current_state;
    reg [3:0]       dps_next_state;
    localparam DPS_START = 4'd0, DPS_WAIT_PHASE_DONE = 4'd1, DPS_DONE = 4'd2, DPS_WAIT_PHASE_EN = 4'd3, DPS_WAIT_DPRIO_WRITING = 4'd4, DPS_CHANGED = 4'd5; 
    localparam PHASE_EN_WAIT_COUNTER = 5'd1;

    reg [15:0] shifts_done_counter;
    reg        phase_done_final;
	 wire 		gnd /*synthesis keep*/;
	 
    //fsm
    //always block controlling the state regs
    always @(posedge clk)
    begin
        if (reset)
        begin
            dps_current_state <= DPS_DONE;
        end
        else
        begin
            dps_current_state <= dps_next_state;
        end
    end
    //the combinational part. assigning the next state
    //this turns on the phase_done_final signal when phase_done does this:
    //_____         ______
    //      |______|
    always @(*)
    begin
        phase_done_final = 0;
        first_phase_shift_d = 0;
        phase_en = 0;
        dps_next_state = DPS_DONE;
        case (dps_current_state)
            DPS_START:
            begin
                phase_en = 1'b1;
                dps_next_state = DPS_WAIT_PHASE_EN;
            end
            DPS_WAIT_PHASE_EN:
            begin
                phase_en = 1'b1;
                if (first_phase_shift_q)
                begin
                    first_phase_shift_d = 1'b1;
                    dps_next_state = DPS_WAIT_PHASE_EN;
                end
                else
                begin
                    if (phase_en_counter == PHASE_EN_WAIT_COUNTER)
                        dps_next_state = DPS_WAIT_PHASE_DONE;
                    else dps_next_state = DPS_WAIT_PHASE_EN;
                end
            end
            DPS_WAIT_PHASE_DONE:
            begin
                if (!phase_done | !locked)
                begin
                    dps_next_state = DPS_WAIT_PHASE_DONE;
                end
                else
                begin
                    if ((usr_num_shifts != shifts_done_counter) & (usr_num_shifts != 0))
                    begin
                        dps_next_state = DPS_START;
                        phase_done_final = 1'b1;
                    end
                    else
                    begin
                        dps_next_state = DPS_DONE;
                    end

                end
            end
            DPS_DONE:
            begin
                phase_done_final = 0;            
                if (dps_changed) 
                    dps_next_state = DPS_CHANGED;
                else dps_next_state = DPS_DONE;

            end
			DPS_CHANGED:
            begin
                if (pll_start_valid)
                    dps_next_state = DPS_WAIT_DPRIO_WRITING;
                else
                    dps_next_state = DPS_CHANGED;
            end
            DPS_WAIT_DPRIO_WRITING:
            begin
                if (dprio_write_done)
                    dps_next_state = DPS_START;
                else
                    dps_next_state = DPS_WAIT_DPRIO_WRITING;
            end

            default: dps_next_state = 4'bxxxx;
        endcase
    
    
    end

    always @(posedge clk)
    begin

        
        if (dps_current_state == DPS_WAIT_PHASE_DONE)
            phase_en_counter <= 0;
        else if (dps_current_state == DPS_WAIT_PHASE_EN)
            phase_en_counter <= phase_en_counter + 1'b1;

        if (reset)
        begin
            phase_en_counter <= 0;
            shifts_done_counter <= 1'b1;
            first_phase_shift_q <= 1;
        end
        else
        begin
            if (first_phase_shift_d)
                first_phase_shift_q <= 0;
            if (dps_done)
            begin
                shifts_done_counter <= 1'b1;
            end
            else
            begin
                if (phase_done_final & (dps_next_state!= DPS_DONE))
                    shifts_done_counter <= shifts_done_counter + 1'b1;
                else
                    shifts_done_counter <= shifts_done_counter;
            end
        end
    end

    assign dps_changed_valid = (dps_current_state == DPS_CHANGED);
    assign dps_done =(dps_current_state == DPS_DONE) | (dps_current_state == DPS_CHANGED);
    assign up_dn = usr_up_dn;
	 assign gnd = 1'b0;
	
    //cnt select luts (5)
    generic_lcell_comb lcell_cnt_sel_0 (
        .dataa(usr_cnt_sel[0]),
        .datab(usr_cnt_sel[1]),
        .datac(usr_cnt_sel[2]),
        .datad(usr_cnt_sel[3]),
        .datae(usr_cnt_sel[4]),
        .dataf(gnd),
        .combout (cnt_sel[0]));
    defparam lcell_cnt_sel_0.lut_mask = 64'hAAAAAAAAAAAAAAAA;
    defparam lcell_cnt_sel_0.dont_touch = "on";
    defparam lcell_cnt_sel_0.family = device_family;
    generic_lcell_comb lcell_cnt_sel_1 (
        .dataa(usr_cnt_sel[0]),
        .datab(usr_cnt_sel[1]),
        .datac(usr_cnt_sel[2]),
        .datad(usr_cnt_sel[3]),
        .datae(usr_cnt_sel[4]),
        .dataf(gnd),
        .combout (cnt_sel[1]));
    defparam lcell_cnt_sel_1.lut_mask = 64'hCCCCCCCCCCCCCCCC;
    defparam lcell_cnt_sel_1.dont_touch = "on";
    defparam lcell_cnt_sel_1.family = device_family;
    generic_lcell_comb lcell_cnt_sel_2 (
        .dataa(usr_cnt_sel[0]),
        .datab(usr_cnt_sel[1]),
        .datac(usr_cnt_sel[2]),
        .datad(usr_cnt_sel[3]),
        .datae(usr_cnt_sel[4]),
        .dataf(gnd),
        .combout (cnt_sel[2]));
    defparam lcell_cnt_sel_2.lut_mask = 64'hF0F0F0F0F0F0F0F0;
    defparam lcell_cnt_sel_2.dont_touch = "on";
    defparam lcell_cnt_sel_2.family = device_family;
    generic_lcell_comb lcell_cnt_sel_3 (
        .dataa(usr_cnt_sel[0]),
        .datab(usr_cnt_sel[1]),
        .datac(usr_cnt_sel[2]),
        .datad(usr_cnt_sel[3]),
        .datae(usr_cnt_sel[4]),
        .dataf(gnd),
        .combout (cnt_sel[3]));
    defparam lcell_cnt_sel_3.lut_mask = 64'hFF00FF00FF00FF00;
    defparam lcell_cnt_sel_3.dont_touch = "on";
    defparam lcell_cnt_sel_3.family = device_family;
    generic_lcell_comb lcell_cnt_sel_4 (
        .dataa(usr_cnt_sel[0]),
        .datab(usr_cnt_sel[1]),
        .datac(usr_cnt_sel[2]),
        .datad(usr_cnt_sel[3]),
        .datae(usr_cnt_sel[4]),
        .dataf(gnd),
        .combout (cnt_sel[4]));
    defparam lcell_cnt_sel_4.lut_mask = 64'hFFFF0000FFFF0000;
    defparam lcell_cnt_sel_4.dont_touch = "on";
    defparam lcell_cnt_sel_4.family = device_family;
   
    
endmodule

module generic_lcell_comb
#(
    //parameter
    parameter family             = "Stratix V",
    parameter lut_mask           = 64'hAAAAAAAAAAAAAAAA,
    parameter dont_touch         = "on"
) ( 

    input    dataa,
    input    datab,
    input    datac,
    input    datad,
    input    datae,
    input    dataf,

    output   combout
);

    generate
        if (family == "Stratix V")
        begin
            stratixv_lcell_comb lcell_inst (
                    .dataa(dataa),
                    .datab(datab),
                    .datac(datac),
                    .datad(datad),
                    .datae(datae),
                    .dataf(dataf),
                    .combout (combout));
            defparam lcell_inst.lut_mask = lut_mask;
            defparam lcell_inst.dont_touch = dont_touch;
        end
        else if (family == "Arria V")
        begin
            arriav_lcell_comb lcell_inst (
                    .dataa(dataa),
                    .datab(datab),
                    .datac(datac),
                    .datad(datad),
                    .datae(datae),
                    .dataf(dataf),
                    .combout (combout));
            defparam lcell_inst.lut_mask = lut_mask;
            defparam lcell_inst.dont_touch = dont_touch;
        end
        else if (family == "Arria V GZ")
        begin
            arriavgz_lcell_comb lcell_inst (
                    .dataa(dataa),
                    .datab(datab),
                    .datac(datac),
                    .datad(datad),
                    .datae(datae),
                    .dataf(dataf),
                    .combout (combout));
            defparam lcell_inst.lut_mask = lut_mask;
            defparam lcell_inst.dont_touch = dont_touch;
        end
        else if (family == "Cyclone V")
        begin
            cyclonev_lcell_comb lcell_inst (
                    .dataa(dataa),
                    .datab(datab),
                    .datac(datac),
                    .datad(datad),
                    .datae(datae),
                    .dataf(dataf),
                    .combout (combout));
            defparam lcell_inst.lut_mask = lut_mask;
            defparam lcell_inst.dont_touch = dont_touch;
        end
        endgenerate
endmodule
