module caravel_clocking(
`ifdef USE_POWER_PINS
    input VPWR,
    input VGND,
`endif
    input porb,		// Master (negative sense) reset from power-on-reset
    input resetb, 	// Master (negative sense) reset
    input ext_clk_sel,	// 0=use PLL clock, 1=use external (pad) clock
    input ext_clk,	// External pad (slow) clock
    input pll_clk,	// Internal PLL (fast) clock
    input pll_clk90,	// Internal PLL (fast) clock, 90 degree phase
    input [2:0] sel,	// Select clock divider value (0=thru, 1=divide-by-2, etc.)
    input [2:0] sel2,	// Select clock divider value for 90 degree phase divided clock
    input ext_reset,	// Positive sense reset from housekeeping SPI.
    output core_clk,	// Output core clock
    output user_clk,	// Output user (secondary) clock
    output resetb_sync	// Output propagated and buffered reset
);

    wire pll_clk_sel;
    wire pll_clk_divided;
    wire pll_clk90_divided;
    wire core_ext_clk;
    reg  use_pll_first;
    reg  use_pll_second;
    reg	 ext_clk_syncd_pre;
    reg	 ext_clk_syncd;

    wire resetb_async;

    assign pll_clk_sel = ~ext_clk_sel;

    assign resetb_async = porb & resetb & (!ext_reset);
    // Note that this implementation does not guard against switching to
    // the PLL clock if the PLL clock is not present.

    always @(posedge pll_clk or negedge resetb_async) begin
	if (resetb_async == 1'b0) begin
	    use_pll_first <= 1'b0;
	    use_pll_second <= 1'b0;
	    ext_clk_syncd <= 1'b0;
	end else begin
	    use_pll_first <= pll_clk_sel;
	    use_pll_second <= use_pll_first;
	    ext_clk_syncd_pre <= ext_clk;	// Sync ext_clk to pll_clk
	    ext_clk_syncd <= ext_clk_syncd_pre;	// Do this twice (resolve metastability)
	end
    end

    // Apply PLL clock divider

    clock_div #(
	.SIZE(3)
    ) divider (
	.in(pll_clk),
	.out(pll_clk_divided),
	.N(sel),
	.resetb(resetb_async)
    ); 

    // Secondary PLL clock divider for user space access

    clock_div #(
	.SIZE(3)
    ) divider2 (
	.in(pll_clk90),
	.out(pll_clk90_divided),
	.N(sel2),
	.resetb(resetb_async)
    ); 


    // Multiplex the clock output

    assign core_ext_clk = (use_pll_first) ? ext_clk_syncd : ext_clk;
    assign core_clk = (use_pll_second) ? pll_clk_divided : core_ext_clk;
    assign user_clk = (use_pll_second) ? pll_clk90_divided : core_ext_clk;

    // Reset assignment.  "reset" comes from POR, while "ext_reset"
    // comes from standalone SPI (and is normally zero unless
    // activated from the SPI).

    // Staged-delay reset
    reg [2:0] reset_delay;

    always @(negedge core_clk or negedge resetb_async) begin
        if (resetb_async == 1'b0) begin
        reset_delay <= 3'b111;
        end else begin
        reset_delay <= {1'b0, reset_delay[2:1]};
        end
    end

    assign resetb_sync = ~reset_delay[0];

endmodule