module zq_calib_ctrl #(parameter TCQ = 100, MAINT_PRESCALER_PERIOD = 200000) (
	input clk,
	input rst,
	
	input zq_ack,
	output reg zq_request,
	
	input dfi_init_complete,
	input maint_prescaler_tick
);

	function integer clogb2 (input integer size); // ceiling logb2
    begin
      size = size - 1;
      for (clogb2=1; size>1; clogb2=clogb2+1)
            size = size >> 1;
    end
	endfunction // clogb2

	// ZQ timebase.  Nominally 128 mS
	localparam MAINT_PRESCALER_PERIOD_NS = MAINT_PRESCALER_PERIOD / 1000;
	localparam tZQI = 128_000_000;
	localparam ZQ_TIMER_DIV = tZQI/MAINT_PRESCALER_PERIOD_NS;
	localparam ZQ_TIMER_WIDTH = clogb2(ZQ_TIMER_DIV + 1);
	localparam ONE = 1;
	
	generate
		begin : zq_cntrl
			reg zq_tick = 1'b0;
			
			if (ZQ_TIMER_DIV !=0) begin : zq_timer
				reg [ZQ_TIMER_WIDTH-1:0] zq_timer_r;
				reg [ZQ_TIMER_WIDTH-1:0] zq_timer_ns;
				
				always @(/*AS*/dfi_init_complete or maint_prescaler_tick
				or zq_tick or zq_timer_r) begin
					zq_timer_ns = zq_timer_r;
					if (~dfi_init_complete || zq_tick)
						zq_timer_ns = ZQ_TIMER_DIV[ZQ_TIMER_WIDTH-1:0];
					else if (|zq_timer_r && maint_prescaler_tick)
						zq_timer_ns = zq_timer_r - ONE[ZQ_TIMER_WIDTH-1:0];
				end
				
				always @(posedge clk) zq_timer_r <= #TCQ zq_timer_ns;
				
				always @(/*AS*/maint_prescaler_tick or zq_timer_r)
					zq_tick = (zq_timer_r == ONE[ZQ_TIMER_WIDTH-1:0] && maint_prescaler_tick);
			end // zq_timer

			// ZQ request. Set request with timer tick, and when exiting PHY init.  Never
			// request if ZQ_TIMER_DIV == 0.
			begin : zq_request_logic
				wire zq_clears_zq_request = zq_ack;
				reg zq_request_r;
				wire zq_request_ns = ~rst && ((~dfi_init_complete && (ZQ_TIMER_DIV != 0)) || 
					(zq_request_r && ~zq_clears_zq_request) || zq_tick);
				
				always @(posedge clk) zq_request_r <= #TCQ zq_request_ns;
				
				always @(/*AS*/dfi_init_complete or zq_request_r)
					zq_request = dfi_init_complete && zq_request_r;
			end // zq_request_logic
		end
	endgenerate

endmodule