OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [gpsclock.v] - Diff between revs 34 and 50

Only display areas with differences | Details | Blame | View Log

Rev 34 Rev 50
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    gpsclock.v
// Filename:    gpsclock.v
//              
//              
// Project:     A GPS Schooled Clock Core
// Project:     A GPS Schooled Clock Core
//
//
// Purpose:     The purpose of this module is to school a counter, run off of
// Purpose:     The purpose of this module is to school a counter, run off of
//              the FPGA's local oscillator, to match a GPS 1PPS signal.  Should
//              the FPGA's local oscillator, to match a GPS 1PPS signal.  Should
//              the GPS 1PPS vanish, the result will flywheel with its last
//              the GPS 1PPS vanish, the result will flywheel with its last
//              solution (both frequency and phase) until GPS is available
//              solution (both frequency and phase) until GPS is available
//              again.
//              again.
//
//
//              This approach can be used to measure the speed of the
//              This approach can be used to measure the speed of the
//              local oscillator, although there may be other more appropriate
//              local oscillator, although there may be other more appropriate
//              means to do this.
//              means to do this.
//
//
//              Note that this core does not produce anything more than
//              Note that this core does not produce anything more than
//              subsecond timing resolution.
//              subsecond timing resolution.
//
//
// Parameters:  This core needs two parameters set below, the DEFAULT_STEP
// Parameters:  This core needs two parameters set below, the DEFAULT_STEP
//              and the DEFAULT_WORD_STEP.  The first must be set to
//              and the DEFAULT_WORD_STEP.  The first must be set to
//              2^RW / (nominal local clock rate), whereas the second must be
//              2^RW / (nominal local clock rate), whereas the second must be
//              set to 2^(RW/2) / (nominal clock rate), where RW is the register
//              set to 2^(RW/2) / (nominal clock rate), where RW is the register
//              width used for our computations.  (64 is sufficient for up to
//              width used for our computations.  (64 is sufficient for up to
//              4 GHz clock speeds, 56 is minimum for 100 MHz.)  Although
//              4 GHz clock speeds, 56 is minimum for 100 MHz.)  Although
//              RW is listed as a variable parameter, I have no plans to 
//              RW is listed as a variable parameter, I have no plans to 
//              test values other than 64.  So your mileage might vary there.
//              test values other than 64.  So your mileage might vary there.
//
//
//              Other parameters, alpha, beta, and gamma are specific to the
//              Other parameters, alpha, beta, and gamma are specific to the
//              loop bandwidth you would like to choose.  Please see the
//              loop bandwidth you would like to choose.  Please see the
//              accompanying specification for a selection of what values
//              accompanying specification for a selection of what values
//              may be useful.
//              may be useful.
//
//
// Inputs:
// Inputs:
//      i_clk   A synchronous clock signal for all logic.  Must be slow enough
//      i_clk   A synchronous clock signal for all logic.  Must be slow enough
//              that the FPGA can accomplish 64 bit math.
//              that the FPGA can accomplish 64 bit math.
//
//
//      i_rst   Resets the clock speed / counter step to be the nominal
//      i_rst   Resets the clock speed / counter step to be the nominal
//              value given by our parameter.  This is useful in case the
//              value given by our parameter.  This is useful in case the
//              control loop has gone off into never never land and doesn't
//              control loop has gone off into never never land and doesn't
//              seem to be returning.
//              seem to be returning.
//
//
//      i_pps   The 1PPS signal from the GPS chip.
//      i_pps   The 1PPS signal from the GPS chip.
//
//
//      Wishbone bus
//      Wishbone bus
//
//
// Outputs:     
// Outputs:     
//      o_led   No circuit would be complete without a properly blinking LED.
//      o_led   No circuit would be complete without a properly blinking LED.
//              This one blinks an LED at the top of the GPS 1PPS and the
//              This one blinks an LED at the top of the GPS 1PPS and the
//              internal 1PPS.  When the two match, the LED will be on for
//              internal 1PPS.  When the two match, the LED will be on for
//              1/16th of a second.  When no GPS 1PPS is present, the LED
//              1/16th of a second.  When no GPS 1PPS is present, the LED
//              will blink with a 50% duty cycle.
//              will blink with a 50% duty cycle.
//
//
//      o_tracking      A boolean value indicating whether the control loop
//      o_tracking      A boolean value indicating whether the control loop
//              is open (0) or closed (1).  Does not indicate performance.
//              is open (0) or closed (1).  Does not indicate performance.
//
//
//      o_count         A counter, from zero to 2^RW-1, indicating the position
//      o_count         A counter, from zero to 2^RW-1, indicating the position
//              of the current clock within a second.  (This'll be off by 
//              of the current clock within a second.  (This'll be off by 
//              two clocks due to internal latencies.)
//              two clocks due to internal latencies.)
//
//
//      o_step          The amount the counter, o_count, is stepped each clock.
//      o_step          The amount the counter, o_count, is stepped each clock.
//              This is related to the actual speed of the oscillator (when
//              This is related to the actual speed of the oscillator (when
//              locked) by f_XO = 2^(RW) / o_step.
//              locked) by f_XO = 2^(RW) / o_step.
//
//
//      o_err   For those interested in how well this device is performing,
//      o_err   For those interested in how well this device is performing,
//              this is the error signal coming out of the device.
//              this is the error signal coming out of the device.
//
//
//      o_locked        Indicates a locked condition.  While it should work,
//      o_locked        Indicates a locked condition.  While it should work,
//              it isn't the best and most versatile lock indicator.  A better
//              it isn't the best and most versatile lock indicator.  A better
//              indicator should be based upon how good the user wants the
//              indicator should be based upon how good the user wants the
//              lock indicator to be.  This isn't that.
//              lock indicator to be.  This isn't that.
//
//
//
//
// Creator:     Dan Gisselquist, Ph.D.
// Creator:     Dan Gisselquist, Ph.D.
//              Gisselquist Technology, LLC
//              Gisselquist Technology, LLC
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) 2015, Gisselquist Technology, LLC
// Copyright (C) 2015, Gisselquist Technology, LLC
//
//
// This program is free software (firmware): you can redistribute it and/or
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
// your option) any later version.
//
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// for more details.
//
//
// You should have received a copy of the GNU General Public License along
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
// <http://www.gnu.org/licenses/> for a copy.
//
//
// License:     GPL, v3, as defined and found on www.gnu.org,
// License:     GPL, v3, as defined and found on www.gnu.org,
//              http://www.gnu.org/licenses/gpl.html
//              http://www.gnu.org/licenses/gpl.html
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
// `define      DEBUG
// `define      DEBUG
//
//
module  gpsclock(i_clk, i_rst, i_pps, o_pps, o_led,
module  gpsclock(i_clk, i_rst, i_pps, o_pps, o_led,
                i_wb_cyc_stb, i_wb_we, i_wb_addr, i_wb_data,
                i_wb_cyc_stb, i_wb_we, i_wb_addr, i_wb_data,
                        o_wb_ack, o_wb_stall, o_wb_data,
                        o_wb_ack, o_wb_stall, o_wb_data,
                o_tracking, o_count, o_step, o_err, o_locked, o_dbg);
                o_tracking, o_count, o_step, o_err, o_locked, o_dbg);
        parameter       DEFAULT_STEP = 32'h834d_c736;//2^64/81.25 MHz
        parameter [31:0] DEFAULT_STEP = 32'h834d_c736;//2^64/81.25 MHz
        parameter       RW=64, // Needs to be 2ceil(Log_2(i_clk frequency))
        parameter       RW=64, // Needs to be 2ceil(Log_2(i_clk frequency))
                        DW=32, // The width of our data bus
                        DW=32, // The width of our data bus
                        ONE_SECOND = 0,
                        ONE_SECOND = 0,
                        NPW=RW-DW, // Width of non-parameter data
                        NPW=RW-DW, // Width of non-parameter data
                        HRW=RW/2; // Half of RW
                        HRW=RW/2; // Half of RW
        input           i_clk, i_rst;
        input           i_clk, i_rst;
        input           i_pps;  // From the GPS device
        input           i_pps;  // From the GPS device
        output  reg     o_pps;  // To our local circuitry
        output  reg     o_pps;  // To our local circuitry
        output  reg     o_led;  // A blinky light showing how well we're doing
        output  reg     o_led;  // A blinky light showing how well we're doing
        // Wishbone Configuration interface
        // Wishbone Configuration interface
        input                           i_wb_cyc_stb, i_wb_we;
        input                           i_wb_cyc_stb, i_wb_we;
        input           [1:0]            i_wb_addr;
        input           [1:0]            i_wb_addr;
        input           [(DW-1):0]       i_wb_data;
        input           [(DW-1):0]       i_wb_data;
        output  reg                     o_wb_ack;
        output  reg                     o_wb_ack;
        output  wire                    o_wb_stall;
        output  wire                    o_wb_stall;
        output  reg     [(DW-1):0]       o_wb_data;
        output  reg     [(DW-1):0]       o_wb_data;
        // Status and timing outputs
        // Status and timing outputs
        output  reg                     o_tracking; // 1=closed loop, 0=open
        output  reg                     o_tracking; // 1=closed loop, 0=open
        output  reg     [(RW-1):0]       o_count, // Fraction of a second
        output  reg     [(RW-1):0]       o_count, // Fraction of a second
                                        o_step, // 2^RW / clock speed (in Hz)
                                        o_step, // 2^RW / clock speed (in Hz)
                                        o_err; // Fraction of a second err
                                        o_err; // Fraction of a second err
        output  reg                     o_locked; // 1 if Locked, 0 o.w.
        output  reg                     o_locked; // 1 if Locked, 0 o.w.
        output  wire    [1:0]            o_dbg;
        output  wire    [1:0]            o_dbg;
 
 
 
 
        // Clock resynchronization variables
        // Clock resynchronization variables
        reg     pps_d, ck_pps, lst_pps;
        reg     pps_d, ck_pps, lst_pps;
        wire    tick;           // And a variable indicating the top of GPS 1PPS
        wire    tick;           // And a variable indicating the top of GPS 1PPS
 
 
        //
        //
        // Configuration variables.  These control the loop bandwidth, the speed
        // Configuration variables.  These control the loop bandwidth, the speed
        // of convergence, the speed of adaptation to changes, and more.  If
        // of convergence, the speed of adaptation to changes, and more.  If
        // you adjust these outside of what the specification recommends, 
        // you adjust these outside of what the specification recommends, 
        // be careful that the control loop still synchronizes!
        // be careful that the control loop still synchronizes!
        reg                     new_config;
        reg                     new_config;
        reg     [5:0]            r_alpha;
        reg     [5:0]            r_alpha;
        reg     [(DW-1):0]       r_beta, r_gamma, r_def_step;
        reg     [(DW-1):0]       r_beta, r_gamma, r_def_step;
        reg     [(RW-1):0]       pre_step;
        reg     [(RW-1):0]       pre_step;
 
 
        //
        //
        // This core really operates rather slowly, in FPGA time.  Of the
        // This core really operates rather slowly, in FPGA time.  Of the
        // millions of ticks per second, we only do things on about less than
        // millions of ticks per second, we only do things on about less than
        // a handful.  These timing signals below help us to determine when
        // a handful.  These timing signals below help us to determine when
        // our data is valid during those handful.
        // our data is valid during those handful.
        //
        //
        // Timing
        // Timing
        reg     err_tick, shift_tick, config_tick, mpy_aux, mpy_sync_two,
        reg     err_tick, shift_tick, config_tick, mpy_aux, mpy_sync_two,
                delay_step_clk, step_carry_tick;
                delay_step_clk, step_carry_tick;
        wire    sub_tick, fltr_tick;
        wire    sub_tick, fltr_tick;
 
 
        //
        //
        // When tracking, each second we'll produce a lowpass filtered_err
        // When tracking, each second we'll produce a lowpass filtered_err
        // (via a recursive average), a count_correction and a step_correction.
        // (via a recursive average), a count_correction and a step_correction.
        // The two _correction terms then get applied at the top of the second.
        // The two _correction terms then get applied at the top of the second.
        // Here's the declaration of those parameters.  The
        // Here's the declaration of those parameters.  The
        // 'pre_count_correction' parameter allows us to avoid adding three
        // 'pre_count_correction' parameter allows us to avoid adding three
        // 64-bit numbers in a single clock, splitting part of that amount into
        // 64-bit numbers in a single clock, splitting part of that amount into
        // an earlier clock.
        // an earlier clock.
        //
        //
        // Tracking
        // Tracking
        reg                     config_filter_errors;
        reg                     config_filter_errors;
        reg     [(RW-1):0]       pre_count_correction, r_count_correction,
        reg     [(RW-1):0]       pre_count_correction, r_count_correction,
                                r_filtered_err;
                                r_filtered_err;
        wire    [(RW-1):0]       count_correction;
        wire    [(RW-1):0]       count_correction;
        reg     [(HRW-1):0]      step_correction;
        reg     [(HRW-1):0]      step_correction;
        reg     [(HRW-1):0]      delayed_step_correction, delayed_step;
        reg     [(HRW-1):0]      delayed_step_correction, delayed_step;
        reg     signed [(HRW-1):0]       mpy_input;
        reg     signed [(HRW-1):0]       mpy_input;
        wire            [(RW-1):0]       w_mpy_out;
        wire            [(RW-1):0]       w_mpy_out;
        wire    signed [(RW-1):0]        filter_sub_count, filtered_err;
        wire    signed [(RW-1):0]        filter_sub_count, filtered_err;
 
 
 
 
 
 
        //
        //
        //
        //
        //
        //
        // Wishbone access ... adjust our tracking parameters
        // Wishbone access ... adjust our tracking parameters
        //
        //
        //
        //
        //
        //
        // DEFAULT_STEP = 64'h0000_0034_dc73_67da, // 2^64 / 81.25 MHz
        // DEFAULT_STEP = 64'h0000_0034_dc73_67da, // 2^64 / 81.25 MHz
        //    = 28'hd371cd9 << (20-10), and hence we have 32'had37_1cd9
        //    = 28'hd371cd9 << (20-10), and hence we have 32'had37_1cd9
        // Other useful values:
        // Other useful values:
        //      32'had6bf94d    //  80MHz
        //      32'had6bf94d    //  80MHz
        //      32'haabcc771    // 100MHz
        //      32'haabcc771    // 100MHz
        //      32'hbd669d0e    // 160.5MHz
        //      32'hbd669d0e    // 160.5MHz
        initial r_def_step = DEFAULT_STEP;
        initial r_def_step = DEFAULT_STEP;
        always @(posedge i_clk)
        always @(posedge i_clk)
                pre_step <= { 16'h00,
                pre_step <= { 16'h00,
                        (({ r_def_step[27:0], 20'h00 })>>r_def_step[31:28])};
                        (({ r_def_step[27:0], 20'h00 })>>r_def_step[31:28])};
 
 
        // Delay writes by one clock
        // Delay writes by one clock
        wire    [1:0]    wb_addr;
        wire    [1:0]    wb_addr;
        wire    [31:0]   wb_data;
        wire    [31:0]   wb_data;
        reg             wb_write;
        reg             wb_write;
        reg     [1:0]    r_wb_addr;
        reg     [1:0]    r_wb_addr;
        reg     [31:0]   r_wb_data;
        reg     [31:0]   r_wb_data;
        reg     [7:0]    lost_ticks;
        reg     [7:0]    lost_ticks;
        initial lost_ticks = 0;
        initial lost_ticks = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                wb_write <= (i_wb_cyc_stb)&&(i_wb_we);
                wb_write <= (i_wb_cyc_stb)&&(i_wb_we);
        always @(posedge i_clk)
        always @(posedge i_clk)
                r_wb_data <= i_wb_data;
                r_wb_data <= i_wb_data;
        always @(posedge i_clk)
        always @(posedge i_clk)
                r_wb_addr <= i_wb_addr;
                r_wb_addr <= i_wb_addr;
        assign  wb_data = r_wb_data;
        assign  wb_data = r_wb_data;
        assign  wb_addr = r_wb_addr;
        assign  wb_addr = r_wb_addr;
 
 
        initial config_filter_errors = 1'b1;
        initial config_filter_errors = 1'b1;
        initial r_alpha = 6'h2;
        initial r_alpha = 6'h2;
        initial r_beta  = 32'h14bda12f;
        initial r_beta  = 32'h14bda12f;
        initial r_gamma = 32'h1f533ae8;
        initial r_gamma = 32'h1f533ae8;
        initial new_config = 1'b0;
        initial new_config = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (wb_write)
                if (wb_write)
                begin
                begin
                        new_config <= 1'b1;
                        new_config <= 1'b1;
                        case(wb_addr)
                        case(wb_addr)
                        2'b00: begin
                        2'b00: begin
                                r_alpha    <= wb_data[5:0];
                                r_alpha    <= wb_data[5:0];
                                config_filter_errors <= (wb_data[5:0] != 6'h0);
                                config_filter_errors <= (wb_data[5:0] != 6'h0);
                                end
                                end
                        2'b01: r_beta     <= wb_data;
                        2'b01: r_beta     <= wb_data;
                        2'b10: r_gamma    <= wb_data;
                        2'b10: r_gamma    <= wb_data;
                        2'b11: r_def_step <= wb_data;
                        2'b11: r_def_step <= wb_data;
                        // default: begin end
                        // default: begin end
                        // r_defstep <= i_wb_data;
                        // r_defstep <= i_wb_data;
                        endcase
                        endcase
                end else
                end else
                        new_config <= 1'b0;
                        new_config <= 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                case (i_wb_addr)
                case (i_wb_addr)
                        2'b00: o_wb_data <= { lost_ticks, 18'h00, r_alpha };
                        2'b00: o_wb_data <= { lost_ticks, 18'h00, r_alpha };
                        2'b01: o_wb_data <= r_beta;
                        2'b01: o_wb_data <= r_beta;
                        2'b10: o_wb_data <= r_gamma;
                        2'b10: o_wb_data <= r_gamma;
                        2'b11: o_wb_data <= r_def_step;
                        2'b11: o_wb_data <= r_def_step;
                        // default: o_wb_data <= 0;
                        // default: o_wb_data <= 0;
                endcase
                endcase
 
 
        reg     dly_config;
        reg     dly_config;
        initial dly_config = 1'b0;
        initial dly_config = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                dly_config <= new_config;
                dly_config <= new_config;
        always @(posedge i_clk)
        always @(posedge i_clk)
                o_wb_ack <= i_wb_cyc_stb;
                o_wb_ack <= i_wb_cyc_stb;
        assign  o_wb_stall = 1'b0;
        assign  o_wb_stall = 1'b0;
 
 
 
 
        //
        //
        //
        //
        // Deal with the realities of an unsynchronized 1PPS signal: 
        // Deal with the realities of an unsynchronized 1PPS signal: 
        // register it with two flip flops to avoid metastability issues.
        // register it with two flip flops to avoid metastability issues.
        // Create a 'tick' variable to note the top of a second.
        // Create a 'tick' variable to note the top of a second.
        //
        //
        //
        //
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin // This will delay our resulting time by a known 2 clock ticks
        begin // This will delay our resulting time by a known 2 clock ticks
                pps_d <= i_pps;
                pps_d <= i_pps;
                ck_pps <= pps_d;
                ck_pps <= pps_d;
                lst_pps <= ck_pps;
                lst_pps <= ck_pps;
        end
        end
 
 
        // Provide a touch of debounce protection ... equal to about
        // Provide a touch of debounce protection ... equal to about
        // one quarter of a second.  This is a coarse predictor, however,
        // one quarter of a second.  This is a coarse predictor, however,
        // since it uses only the top 32-bits of the step.
        // since it uses only the top 32-bits of the step.
        //
        //
        // Here's the idea: on any tick, we start a 32-bit counter, stepping
        // Here's the idea: on any tick, we start a 32-bit counter, stepping
        // unevenly by o_step[61:30] at each tick.  Once the counter crosses
        // unevenly by o_step[61:30] at each tick.  Once the counter crosses
        // zero, we stop counting and we enable the clock tick.  Since the
        // zero, we stop counting and we enable the clock tick.  Since the
        // counter should overflow 4x per second (assuming our clock rate is
        // counter should overflow 4x per second (assuming our clock rate is
        // less than 16GHz), we should be good to go.  Oh, and we also round
        // less than 16GHz), we should be good to go.  Oh, and we also round
        // our step up by one ... to guarantee that we always end earlier than
        // our step up by one ... to guarantee that we always end earlier than
        // designed, rather than ever later.
        // designed, rather than ever later.
        //
        //
        wire            w_tick_enable;
        wire            w_tick_enable;
        reg     [31:0]   tick_enable_counter;
        reg     [31:0]   tick_enable_counter;
        reg             tick_enable_carry;
        reg             tick_enable_carry;
        initial tick_enable_carry   = 0;
        initial tick_enable_carry   = 0;
        initial tick_enable_counter = 0;
        initial tick_enable_counter = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin
        begin
                if ((ck_pps)&&(~lst_pps))
                if ((ck_pps)&&(~lst_pps))
                        { tick_enable_carry, tick_enable_counter } <= 0;
                        { tick_enable_carry, tick_enable_counter } <= 0;
                else if (tick_enable_carry)
                else if (tick_enable_carry)
                        tick_enable_counter <= 32'hffff_ffff;
                        tick_enable_counter <= 32'hffff_ffff;
                else
                else
                        {tick_enable_carry, tick_enable_counter}
                        {tick_enable_carry, tick_enable_counter}
                                <= o_step[(RW-3):(RW-34)]
                                <= o_step[(RW-3):(RW-34)]
                                        + tick_enable_counter + 1'b1;
                                        + tick_enable_counter + 1'b1;
        end
        end
        assign  w_tick_enable = tick_enable_carry;
        assign  w_tick_enable = tick_enable_carry;
 
 
        assign  tick= (ck_pps)&&(~lst_pps)&&(w_tick_enable);
        assign  tick= (ck_pps)&&(~lst_pps)&&(w_tick_enable);
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (wb_write)
                if (wb_write)
                        lost_ticks <= 8'h00;
                        lost_ticks <= 8'h00;
                else if ((ck_pps)&&(~lst_pps)&&(!w_tick_enable))
                else if ((ck_pps)&&(~lst_pps)&&(!w_tick_enable))
                        lost_ticks <= lost_ticks+1'b1;
                        lost_ticks <= lost_ticks+1'b1;
        assign  o_dbg[0] = tick;
        assign  o_dbg[0] = tick;
        assign  o_dbg[1] = w_tick_enable;
        assign  o_dbg[1] = w_tick_enable;
 
 
        //
        //
        //
        //
        // Here's our counter proper: Add o_step to o_count each clock tick
        // Here's our counter proper: Add o_step to o_count each clock tick
        // to have a current time value.  Corrections are applied at the top
        // to have a current time value.  Corrections are applied at the top
        // of the second if we are in tracking mode.  The 'o_pps' signal is
        // of the second if we are in tracking mode.  The 'o_pps' signal is
        // generated from the carry/overflow of the o_count addition.
        // generated from the carry/overflow of the o_count addition.
        //
        //
        // The output of this loop, both o_pps and o_count, is the current
        // The output of this loop, both o_pps and o_count, is the current
        // subsecond time as determined by this clock.
        // subsecond time as determined by this clock.
        //
        //
        //
        //
        reg     cnt_carry;
        reg     cnt_carry;
        reg     [31:0]   p_count;
        reg     [31:0]   p_count;
        initial o_count = 0;
        initial o_count = 0;
        initial o_pps = 1'b0;
        initial o_pps = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
`ifndef USE_THE_OLD_CODE
`ifndef USE_THE_OLD_CODE
                begin
                begin
                // Very simple: we add the count correction, which is given by
                // Very simple: we add the count correction, which is given by
                // a pre-determined sum of the step and any error, to our
                // a pre-determined sum of the step and any error, to our
                // "count" at every clock tick.  If this ever overflows, the
                // "count" at every clock tick.  If this ever overflows, the
                // overflow or carry is our PPS signal.  Unlike the last time
                // overflow or carry is our PPS signal.  Unlike the last time
                // we built this logic, here we acknowledge that the count
                // we built this logic, here we acknowledge that the count
                // correction can never be negative.  As a result, we have no
                // correction can never be negative.  As a result, we have no
                // o_pps suppression.
                // o_pps suppression.
                { cnt_carry, p_count } <= p_count[31:0] + r_count_correction[31:0];
                { cnt_carry, p_count } <= p_count[31:0] + r_count_correction[31:0];
                { o_pps, o_count[63:32] } <= o_count[63:32]
                { o_pps, o_count[63:32] } <= o_count[63:32]
                                + r_count_correction[63:32]
                                + r_count_correction[63:32]
                                + { 31'h00, cnt_carry };
                                + { 31'h00, cnt_carry };
                if (r_count_correction[(RW-1)])
                if (r_count_correction[(RW-1)])
                        o_pps <= 1'b0;
                        o_pps <= 1'b0;
                // Delay the bottom bits of o_count by one clock, so that they
                // Delay the bottom bits of o_count by one clock, so that they
                // now match up with the top bits.
                // now match up with the top bits.
                o_count[31:0] <= p_count;
                o_count[31:0] <= p_count;
                end
                end
`else
`else
                if ((o_tracking)&&(tick))
                if ((o_tracking)&&(tick))
                begin
                begin
                        // Save the carry to be applied at the next clock, so
                        // Save the carry to be applied at the next clock, so
                        // that we never have to do more than a 32-bit add.
                        // that we never have to do more than a 32-bit add.
                        // (well, okay, a 33-bit add ...)
                        // (well, okay, a 33-bit add ...)
                        //
                        //
                        // The count_correction value here is really our step,
                        // The count_correction value here is really our step,
                        // plus a value determined from our filter loop.
                        // plus a value determined from our filter loop.
                        { cnt_carry, p_count }
                        { cnt_carry, p_count }
                           <= p_count[31:0] + count_correction[31:0];
                           <= p_count[31:0] + count_correction[31:0];
                        //
                        //
                        // On the second clock, we add the high order bits
                        // On the second clock, we add the high order bits
                        // together, and possibly get a carry.  We use this
                        // together, and possibly get a carry.  We use this
                        // carry as our o_pps output.
                        // carry as our o_pps output.
                        if (~count_correction[(RW-1)])
                        if (~count_correction[(RW-1)])
                        begin
                        begin
                                // Here, we need to correct by jumping forward.
                                // Here, we need to correct by jumping forward.
                                //
                                //
                                // Note that we don't create an o_pps just
                                // Note that we don't create an o_pps just
                                // because the gps_pps states that there should
                                // because the gps_pps states that there should
                                // be one.  Instead, we hold to the normal
                                // be one.  Instead, we hold to the normal
                                // means of business.  At the tick, however,
                                // means of business.  At the tick, however,
                                // we add both the step and the correction to
                                // we add both the step and the correction to
                                // the current count.
                                // the current count.
                                { o_pps, o_count[63:32] } <= o_count[63:32]
                                { o_pps, o_count[63:32] } <= o_count[63:32]
                                        + count_correction[63:32]
                                        + count_correction[63:32]
                                        + { 31'h00, cnt_carry };
                                        + { 31'h00, cnt_carry };
                        end else begin
                        end else begin
                                // If the count correction is negative, it means
                                // If the count correction is negative, it means
                                // we need to go backwards.  In this case,
                                // we need to go backwards.  In this case,
                                // there shouldn't be any o_pps, least we get
                                // there shouldn't be any o_pps, least we get
                                // two of them.  So ... we skip an output PPS,
                                // two of them.  So ... we skip an output PPS,
                                // knowing the correct PPS is coming next.
                                // knowing the correct PPS is coming next.
                                o_pps <= 1'b0;
                                o_pps <= 1'b0;
                                o_count[63:32] <= o_count[63:32]
                                o_count[63:32] <= o_count[63:32]
                                                + count_correction[63:32]
                                                + count_correction[63:32]
                                        + { 31'h00, cnt_carry };
                                        + { 31'h00, cnt_carry };
                        end
                        end
                end else begin
                end else begin
                        // The difference between count_correction and
                        // The difference between count_correction and
                        // o_step is the phase correction from the last tick.
                        // o_step is the phase correction from the last tick.
                        // If we aren't tracking, we don't want to use the
                        // If we aren't tracking, we don't want to use the
                        // correction.  Likewise, even if we are, we only
                        // correction.  Likewise, even if we are, we only
                        // want to use it on the ticks.
                        // want to use it on the ticks.
                        { cnt_carry, p_count } <= p_count + o_step[31:0];
                        { cnt_carry, p_count } <= p_count + o_step[31:0];
                        { o_pps, o_count[63:32] } <= o_count[63:32]
                        { o_pps, o_count[63:32] } <= o_count[63:32]
                                                + o_step[63:32]
                                                + o_step[63:32]
                                                + { 31'h00, cnt_carry};
                                                + { 31'h00, cnt_carry};
                end
                end
 
 
        // Here we delay the bottom bits of o_count by one clock, so that they
        // Here we delay the bottom bits of o_count by one clock, so that they
        // now match up with the top bits.
        // now match up with the top bits.
        always @(posedge i_clk)
        always @(posedge i_clk)
                o_count[31:0] <= p_count;
                o_count[31:0] <= p_count;
`endif
`endif
 
 
 
 
 
 
        //
        //
        // The step
        // The step
        //
        //
        // The counter above is only as good as the step size given to it.
        // The counter above is only as good as the step size given to it.
        // Here, we work with that step size, and apply a correction based
        // Here, we work with that step size, and apply a correction based
        // upon the last tick.  The idea in the step correction is that we
        // upon the last tick.  The idea in the step correction is that we
        // wish to add this step correction to our step amount.  We have one
        // wish to add this step correction to our step amount.  We have one
        // clock tick (i.e. one second) from when we make our error measurement
        // clock tick (i.e. one second) from when we make our error measurement
        // until we must apply the correction.
        // until we must apply the correction.
        //
        //
        // The correction, calculated far below, will be placed into the value
        // The correction, calculated far below, will be placed into the value
        //
        //
        //      step_correction
        //      step_correction
        //
        //
        // We just need to figure out what the new step will be here, given
        // We just need to figure out what the new step will be here, given
        // that correction.
        // that correction.
        //
        //
        reg     [(HRW):0]        step_correction_plus_carry;
        reg     [(HRW):0]        step_correction_plus_carry;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (step_carry_tick)
                if (step_carry_tick)
                        step_correction_plus_carry
                        step_correction_plus_carry
                                <= { step_correction[(HRW-1)],step_correction }
                                <= { step_correction[(HRW-1)],step_correction }
                                        + { 32'h00, delayed_carry };
                                        + { 32'h00, delayed_carry };
 
 
 
 
        wire    w_step_correct_unused;
        wire    w_step_correct_unused;
        wire    [(RW-1):0]       new_step;
        wire    [(RW-1):0]       new_step;
        bigadd  getnewstep(i_clk, 1'b0, o_step,
        bigadd  getnewstep(i_clk, 1'b0, o_step,
                        { { (HRW-1){step_correction_plus_carry[HRW]} },
                        { { (HRW-1){step_correction_plus_carry[HRW]} },
                                step_correction_plus_carry},
                                step_correction_plus_carry},
                        new_step, w_step_correct_unused);
                        new_step, w_step_correct_unused);
 
 
        reg     delayed_carry;
        reg     delayed_carry;
        initial delayed_carry = 0;
        initial delayed_carry = 0;
 
 
        wire    [31:0]   initial_default_step = DEFAULT_STEP;
        wire    [31:0]   initial_default_step = DEFAULT_STEP;
        // initial      o_step = 64'h002af31dc461; // 100MHz
        // initial      o_step = 64'h002af31dc461; // 100MHz
        initial o_step = { 16'h00, (({ initial_default_step[27:0], 20'h00 })
        initial o_step = { 16'h00, (({ DEFAULT_STEP[27:0], 20'h00 })
                                >> initial_default_step[31:28])};
                                >> DEFAULT_STEP[31:28])};
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((i_rst)||(dly_config))
                if ((i_rst)||(dly_config))
                        o_step <= pre_step;
                        o_step <= pre_step;
`ifndef DEBUG
`ifndef DEBUG
                else if ((o_tracking) && (tick))
                else if ((o_tracking) && (tick))
                         o_step <= new_step;
                         o_step <= new_step;
`endif
`endif
 
 
        initial delayed_step = 0;
        initial delayed_step = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((i_rst)||(dly_config))
                if ((i_rst)||(dly_config))
                        { delayed_carry, delayed_step } <= 0;
                        { delayed_carry, delayed_step } <= 0;
                else if (delay_step_clk)
                else if (delay_step_clk)
                        { delayed_carry, delayed_step } <= delayed_step
                        { delayed_carry, delayed_step } <= delayed_step
                                        + delayed_step_correction;
                                        + delayed_step_correction;
 
 
 
 
 
 
        //
        //
        //
        //
        // Now to start our tracking loop.  The steps are:
        // Now to start our tracking loop.  The steps are:
        //      1. Measure our error
        //      1. Measure our error
        //      2. Filter our error (lowpass, recursive averager)
        //      2. Filter our error (lowpass, recursive averager)
        //      3. Multiply the filtered error by two user-supplied constants
        //      3. Multiply the filtered error by two user-supplied constants
        //              (beta and gamma)
        //              (beta and gamma)
        //      4. The results of this multiply then become the new
        //      4. The results of this multiply then become the new
        //              count and step corrections.
        //              count and step corrections.
        //
        //
        //
        //
        // A negative error means we were too fast ... the count rolled over
        // A negative error means we were too fast ... the count rolled over
        // and is near zero, the o_err is then the negation of this when the
        // and is near zero, the o_err is then the negation of this when the
        // tick does show up.
        // tick does show up.
        //
        //
 
 
        // Note that our measured error, o_err, will be valid one tick *after*
        // Note that our measured error, o_err, will be valid one tick *after*
        // the top of the second tick (tick).
        // the top of the second tick (tick).
        //
        //
        // ONE_SECOND in this equation is set to 2^64, or zero during
        // ONE_SECOND in this equation is set to 2^64, or zero during
        // implementation.  This makes the 64-bit subtract ... doable.
        // implementation.  This makes the 64-bit subtract ... doable.
        initial o_err = 0;
        initial o_err = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (tick)
                if (tick)
                        o_err <= ONE_SECOND - o_count;
                        o_err <= ONE_SECOND - o_count;
 
 
        // Because o_err is delayed one clock from the tick, we create a strobe
        // Because o_err is delayed one clock from the tick, we create a strobe
        // capturing when the error is valid.
        // capturing when the error is valid.
        initial err_tick = 1'b0;
        initial err_tick = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                err_tick <= tick;
                err_tick <= tick;
 
 
        //
        //
        // We are now going to filter this error, via:
        // We are now going to filter this error, via:
        //
        //
        //      filtered_err <= o_err>>r_alpha + (1-1>>r_alpha)*filtered_err
        //      filtered_err <= o_err>>r_alpha + (1-1>>r_alpha)*filtered_err
        //
        //
        // This implements a very simple recursive averager.
        // This implements a very simple recursive averager.
        //
        //
        // You may not recognize it below, though, since we have simplified the
        // You may not recognize it below, though, since we have simplified the
        // equation into:
        // equation into:
        //
        //
        //      filtered_err <= filtered_err + (o_err - filtered_err)>>r_alpha
        //      filtered_err <= filtered_err + (o_err - filtered_err)>>r_alpha
        //
        //
 
 
        // On some architectures, adding and subtracting 64'bit number cannot
        // On some architectures, adding and subtracting 64'bit number cannot
        // be done in a single clock tick.  On these architectures, we may
        // be done in a single clock tick.  On these architectures, we may
        // take a couple clocks.  Here, the "bigsub" module captures what it 
        // take a couple clocks.  Here, the "bigsub" module captures what it 
        // takes to subtract 64-bit numbers.
        // takes to subtract 64-bit numbers.
        //
        //
        // Either way, here we subtract our error from our filtered_err.  This
        // Either way, here we subtract our error from our filtered_err.  This
        // is the first step of the recursive average--figuring out what value
        // is the first step of the recursive average--figuring out what value
        // we are going to apply to the recursive average.
        // we are going to apply to the recursive average.
        bigsub  suberri(i_clk, err_tick, o_err,
        bigsub  suberri(i_clk, err_tick, o_err,
                        filtered_err, filter_sub_count, sub_tick);
                        filtered_err, filter_sub_count, sub_tick);
 
 
        //
        //
        // This shouldn't be required: We only want to shift our 
        // This shouldn't be required: We only want to shift our 
        // filter_sub_count by r_alpha bits, why the extra struggles?
        // filter_sub_count by r_alpha bits, why the extra struggles?
        // Why is because Verilator decides that these values are unsigned,
        // Why is because Verilator decides that these values are unsigned,
        // and so despite being told that they are signed values, verilator
        // and so despite being told that they are signed values, verilator
        // doesn't sign extend them upon shifting.  Put together,
        // doesn't sign extend them upon shifting.  Put together,
        // { shift_hi[low-bits], shift_lo[low-bits] } make up a full RW (i.e.64)
        // { shift_hi[low-bits], shift_lo[low-bits] } make up a full RW (i.e.64)
        // bit correction factor.
        // bit correction factor.
        reg     signed [(RW-1):0] shift_hi, shift_lo;
        reg     signed [(RW-1):0] shift_hi, shift_lo;
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin
        begin
                shift_tick<= sub_tick;
                shift_tick<= sub_tick;
 
 
                // Because we do our add (below) on *every* clock tick, we must
                // Because we do our add (below) on *every* clock tick, we must
                // make certain that the value we add to it is only non-zero
                // make certain that the value we add to it is only non-zero
                // on one clock tick.  Hence, we wait for sub_tick to be true,
                // on one clock tick.  Hence, we wait for sub_tick to be true,
                // set the value, and otherwise keep it clear.
                // set the value, and otherwise keep it clear.
                if (sub_tick)
                if (sub_tick)
                begin
                begin
                        shift_hi <= { {(HRW){filter_sub_count[(RW-1)]}},
                        shift_hi <= { {(HRW){filter_sub_count[(RW-1)]}},
                                filter_sub_count[(RW-1):HRW] }>>r_alpha;
                                filter_sub_count[(RW-1):HRW] }>>r_alpha;
                        shift_lo <= filter_sub_count[(RW-1):0]>>r_alpha;
                        shift_lo <= filter_sub_count[(RW-1):0]>>r_alpha;
                end else begin
                end else begin
                        shift_hi <= 0;
                        shift_hi <= 0;
                        shift_lo <= 0;
                        shift_lo <= 0;
                end
                end
        end
        end
 
 
        // You may notice, it's now been several clocks since the top of the
        // You may notice, it's now been several clocks since the top of the
        // second.  Still, filtered_err hasn't changed.  It only changes once
        // second.  Still, filtered_err hasn't changed.  It only changes once
        // a second based upon the results of these computations.  Here we take
        // a second based upon the results of these computations.  Here we take
        // another clock (or two) to figure out the next step in our algorithm.
        // another clock (or two) to figure out the next step in our algorithm.
        bigadd adderr(i_clk, shift_tick, r_filtered_err,
        bigadd adderr(i_clk, shift_tick, r_filtered_err,
                        { shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] },
                        { shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] },
                        filtered_err, fltr_tick);
                        filtered_err, fltr_tick);
 
 
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (fltr_tick)
                if (fltr_tick)
                        r_filtered_err <= filtered_err;
                        r_filtered_err <= filtered_err;
                else if ((dly_config)||(!o_tracking))
                else if ((dly_config)||(!o_tracking))
                        r_filtered_err <= 0;
                        r_filtered_err <= 0;
 
 
        reg     [(RW-1):0]       r_mpy_err;
        reg     [(RW-1):0]       r_mpy_err;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (err_tick)
                if (err_tick)
                r_mpy_err <= (config_filter_errors) ? r_filtered_err : o_err;
                r_mpy_err <= (config_filter_errors) ? r_filtered_err : o_err;
        always @(posedge i_clk)
        always @(posedge i_clk)
                config_tick <= err_tick;
                config_tick <= err_tick;
 
 
        // Okay, so we've gone from our original tick to the err_tick, the
        // Okay, so we've gone from our original tick to the err_tick, the
        // sub_tick, the shift_tick, and now the fltr_tick. 
        // sub_tick, the shift_tick, and now the fltr_tick. 
        //
        //
        // We want to multiply our filtered error by one of two constants.
        // We want to multiply our filtered error by one of two constants.
        // Here, we set up those constants.  We use the fltr_tick as a strobe,
        // Here, we set up those constants.  We use the fltr_tick as a strobe,
        // but also to select one particular constant.  When the multiply comes
        // but also to select one particular constant.  When the multiply comes
        // back, and the strobe is true, we'll know that the constant going
        // back, and the strobe is true, we'll know that the constant going
        // in with the strobe on (r_beta) corresponds to the product coming out,
        // in with the strobe on (r_beta) corresponds to the product coming out,
        // and that the second product we need will be on the next clock.
        // and that the second product we need will be on the next clock.
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (err_tick)
                if (err_tick)
                        mpy_input <= r_beta;
                        mpy_input <= r_beta;
                else
                else
                        mpy_input <= r_gamma;
                        mpy_input <= r_gamma;
        always @(posedge i_clk)
        always @(posedge i_clk)
                mpy_aux <= err_tick;
                mpy_aux <= err_tick;
 
 
        //
        //
        // The multiply
        // The multiply
        //
        //
        // Remember, we take our filtered error and multiply it by a constant
        // Remember, we take our filtered error and multiply it by a constant
        // to determine our step correction and another constant to determine
        // to determine our step correction and another constant to determine
        // our count correction?  We'll ... here's that multiply.
        // our count correction?  We'll ... here's that multiply.
        //
        //
        wire                    mpy_sync;
        wire                    mpy_sync;
        initial mpy_sync_two = 1'b0;
        initial mpy_sync_two = 1'b0;
        // Sign extend all inputs to RW bits
        // Sign extend all inputs to RW bits
        wire    signed  [(RW-1):0]       w_mpy_input, w_mpy_err;
        wire    signed  [(RW-1):0]       w_mpy_input, w_mpy_err;
        assign  w_mpy_input = { {(RW-DW){mpy_input[(DW-1)]}},
        assign  w_mpy_input = { {(RW-DW){mpy_input[(DW-1)]}},
                                                mpy_input[(DW-1):0]};
                                                mpy_input[(DW-1):0]};
        assign  w_mpy_err   = { {(RW-NPW){r_mpy_err[(RW-1)]}},
        assign  w_mpy_err   = { {(RW-NPW){r_mpy_err[(RW-1)]}},
                                                r_mpy_err[(RW-1):(RW-NPW)]};
                                                r_mpy_err[(RW-1):(RW-NPW)]};
        //
        //
        // Here's our big multiply.
        // Here's our big multiply.
        //
        //
        bigsmpy #(.NCLOCKS(1))
        bigsmpy #(.NCLOCKS(1))
                mpyi(i_clk, mpy_aux, 1'b1, w_mpy_input[31:0], w_mpy_err[31:0],
                mpyi(i_clk, mpy_aux, 1'b1, w_mpy_input[31:0], w_mpy_err[31:0],
                        w_mpy_out, mpy_sync);
                        w_mpy_out, mpy_sync);
 
 
        // We use this to grab the second product from the multiply.  This
        // We use this to grab the second product from the multiply.  This
        // second product is true the clock after mpy_sync is high, so we
        // second product is true the clock after mpy_sync is high, so we
        // just do a simple delay to get this strobe logic.
        // just do a simple delay to get this strobe logic.
        always @(posedge i_clk)
        always @(posedge i_clk)
                mpy_sync_two <= mpy_sync;
                mpy_sync_two <= mpy_sync;
 
 
 
 
        // The post-multiply
        // The post-multiply
        //
        //
        // Remember, the mpy_sync line coming out of the multiply will be true
        // Remember, the mpy_sync line coming out of the multiply will be true
        // when the product of the error and i_beta comes out.
        // when the product of the error and i_beta comes out.
        //
        //
        initial pre_count_correction    = 0;
        initial pre_count_correction    = 0;
        initial step_correction         = 0;
        initial step_correction         = 0;
        initial delayed_step_correction = 0;
        initial delayed_step_correction = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (mpy_sync)   // i_beta product
                if (mpy_sync)   // i_beta product
                        pre_count_correction <= w_mpy_out;
                        pre_count_correction <= w_mpy_out;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (mpy_sync_two) begin // i_gamma product
                if (mpy_sync_two) begin // i_gamma product
                        step_correction <= w_mpy_out[(RW-1):HRW];
                        step_correction <= w_mpy_out[(RW-1):HRW];
                        delayed_step_correction <= w_mpy_out[(HRW-1):0];
                        delayed_step_correction <= w_mpy_out[(HRW-1):0];
                end
                end
 
 
`ifdef  DEBUG
`ifdef  DEBUG
        assign  count_correction = o_step;
        assign  count_correction = o_step;
`else
`else
        // The correction for the number of counts in our counter is given
        // The correction for the number of counts in our counter is given
        // by pre_count_correction.  When we add this to the counter, we'll
        // by pre_count_correction.  When we add this to the counter, we'll
        // need to add the step to it as well.  To help timing out with 64-bit
        // need to add the step to it as well.  To help timing out with 64-bit
        // math, let's do that step+correction math here, so that we can later
        // math, let's do that step+correction math here, so that we can later
        // do 
        // do 
        //      counts = counts + count_correction
        //      counts = counts + count_correction
        // instead of
        // instead of
        //      counts = counts + step + pre_count_correction
        //      counts = counts + step + pre_count_correction
        // saves us one addition--especially since we have the clock to do this.
        // saves us one addition--especially since we have the clock to do this.
        wire    count_correction_strobe;
        wire    count_correction_strobe;
        bigadd  ccounts(i_clk, mpy_sync_two, o_step, pre_count_correction,
        bigadd  ccounts(i_clk, mpy_sync_two, o_step, pre_count_correction,
                        count_correction, count_correction_strobe);
                        count_correction, count_correction_strobe);
 
 
        // Our original plan was to apply this correction at the top of the
        // Our original plan was to apply this correction at the top of the
        // second.  The problem is that our loop filter math depends upon this
        // second.  The problem is that our loop filter math depends upon this
        // correction being applied before the top of the second error gets
        // correction being applied before the top of the second error gets
        // measured.  Hence, we'll apply it at some time mid-second, not
        // measured.  Hence, we'll apply it at some time mid-second, not
        // long after the error is measured (w/in 16 clocks or so), and never
        // long after the error is measured (w/in 16 clocks or so), and never
        // notice the difference until the top of the next second where it 
        // notice the difference until the top of the next second where it 
        // now appears to have properly taken place.
        // now appears to have properly taken place.
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (count_correction_strobe)
                if (count_correction_strobe)
                        r_count_correction <= count_correction;
                        r_count_correction <= count_correction;
                else
                else
                        r_count_correction <= o_step;
                        r_count_correction <= o_step;
`endif
`endif
 
 
        initial delay_step_clk = 1'b0;
        initial delay_step_clk = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                delay_step_clk <= mpy_sync_two;
                delay_step_clk <= mpy_sync_two;
        initial step_carry_tick = 1'b0;
        initial step_carry_tick = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                step_carry_tick <= delay_step_clk;
                step_carry_tick <= delay_step_clk;
 
 
        //
        //
        //
        //
        // LED Logic -- Note that this is where we tell if we've had a GPS
        // LED Logic -- Note that this is where we tell if we've had a GPS
        // 1PPS pulse or not.  To have had such a pulse, it needs to have
        // 1PPS pulse or not.  To have had such a pulse, it needs to have
        // been within the last two seconds.
        // been within the last two seconds.
        //
        //
        //
        //
        reg     no_pulse;
        reg     no_pulse;
        reg     [32:0]   time_since_pps;
        reg     [32:0]   time_since_pps;
        initial no_pulse = 1'b1;
        initial no_pulse = 1'b1;
        initial time_since_pps = 33'hffffffff;
        initial time_since_pps = 33'hffffffff;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (tick)
                if (tick)
                begin
                begin
                        time_since_pps <= 0;
                        time_since_pps <= 0;
                        no_pulse <= 0;
                        no_pulse <= 0;
                end else if (time_since_pps[32:29] == 4'hf)
                end else if (time_since_pps[32:29] == 4'hf)
                begin
                begin
                        time_since_pps <= 33'hffffffff;
                        time_since_pps <= 33'hffffffff;
                        no_pulse <= 1'b1;
                        no_pulse <= 1'b1;
                end else
                end else
                        time_since_pps <= time_since_pps + pre_step[(RW-1):HRW];
                        time_since_pps <= time_since_pps + pre_step[(RW-1):HRW];
 
 
        //
        //
        // 1. Pulse with a 50% duty cycle every second if no GPS is available.
        // 1. Pulse with a 50% duty cycle every second if no GPS is available.
        // 2. Pulse with a 6% duty cycle any time a pulse is present, and any
        // 2. Pulse with a 6% duty cycle any time a pulse is present, and any
        //      time we think (when a pulse is present) that we have time.
        //      time we think (when a pulse is present) that we have time.
        //
        //
        // This should produce a set of conflicting pulses when out of lock,
        // This should produce a set of conflicting pulses when out of lock,
        // and a nice short once per second pulse when locked.  Further, you
        // and a nice short once per second pulse when locked.  Further, you
        // should be able to tell when the core is flywheeling by the duration
        // should be able to tell when the core is flywheeling by the duration
        // of the pulses (50% vs 6%).
        // of the pulses (50% vs 6%).
        //
        //
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (no_pulse)
                if (no_pulse)
                        o_led <= o_count[(RW-1)];
                        o_led <= o_count[(RW-1)];
                else
                else
                        o_led <= ((time_since_pps[31:28] == 4'h0)
                        o_led <= ((time_since_pps[31:28] == 4'h0)
                                ||(o_count[(RW-1):(RW-4)]== 4'h0));
                                ||(o_count[(RW-1):(RW-4)]== 4'h0));
 
 
        //
        //
        //
        //
        // Now, are we tracking or not?
        // Now, are we tracking or not?
        // We'll attempt to close the loop after seeing 7 valid GPS 1PPS
        // We'll attempt to close the loop after seeing 7 valid GPS 1PPS
        // rising edges.
        // rising edges.
        //
        //
        //
        //
        reg     [2:0]    count_valid_ticks;
        reg     [2:0]    count_valid_ticks;
        initial count_valid_ticks = 3'h0;
        initial count_valid_ticks = 3'h0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((tick)&&(count_valid_ticks < 3'h7))
                if ((tick)&&(count_valid_ticks < 3'h7))
                        count_valid_ticks <= count_valid_ticks+1;
                        count_valid_ticks <= count_valid_ticks+1;
                else if (no_pulse)
                else if (no_pulse)
                        count_valid_ticks <= 3'h0;
                        count_valid_ticks <= 3'h0;
        initial o_tracking = 1'b0;
        initial o_tracking = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (dly_config) // Break the tracking loop on a config change
                if (dly_config) // Break the tracking loop on a config change
                        o_tracking <= 1'b0;
                        o_tracking <= 1'b0;
                else if ((tick)&&(&count_valid_ticks))
                else if ((tick)&&(&count_valid_ticks))
                        o_tracking <= 1'b1;
                        o_tracking <= 1'b1;
                else if ((tick)||(count_valid_ticks == 0))
                else if ((tick)||(count_valid_ticks == 0))
                        o_tracking <= 1'b0;
                        o_tracking <= 1'b0;
 
 
        //
        //
        //
        //
        // Are we locked or not?
        // Are we locked or not?
        // We'll use the top eight bits of our error to tell.  If the top eight
        // We'll use the top eight bits of our error to tell.  If the top eight
        // bits are all ones or all zeros, then we'll call ourselves locked.
        // bits are all ones or all zeros, then we'll call ourselves locked.
        // This is equivalent to calling ourselves locked if, at the top of
        // This is equivalent to calling ourselves locked if, at the top of
        // the second, we are within 1/128th of a second of the GPS 1PPS.
        // the second, we are within 1/128th of a second of the GPS 1PPS.
        //
        //
        initial o_locked = 1'b0;
        initial o_locked = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((o_tracking)&&(tick)&&(
                if ((o_tracking)&&(tick)&&(
                        ((   o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'hff))
                        ((   o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'hff))
                        ||((~o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'h00))))
                        ||((~o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'h00))))
                        o_locked <= 1'b1;
                        o_locked <= 1'b1;
                else if (tick)
                else if (tick)
                        o_locked <= 1'b0;
                        o_locked <= 1'b0;
 
 
endmodule
endmodule
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.