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

Subversion Repositories irig_regenerator

[/] [irig_regenerator/] [trunk/] [rtl/] [irig_time_pack.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------
-- Package of IRIG time pattern generator components
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
package irig_time_pack is
 
-- This component includes the capability to output both DC Level and modulated timecode streams.
-- It has been coded with 32 bit wide registers
  component irig_time_generator
    generic (
      SYS_CLK_RATE : real; -- Needed for carrier generation
      DEF_R_0 : unsigned(31 downto 0); -- Years, Days
      DEF_R_1 : unsigned(31 downto 0); -- Hours, Minutes, Seconds
      DEF_R_2 : unsigned(31 downto 0); -- Control(31:0)
      DEF_R_3 : unsigned(31 downto 0); -- Control(44:32)
      DEF_R_4 : unsigned(31 downto 0); -- Rate Setting
      DEF_R_5 : unsigned(31 downto 0); -- Fields Used [ctrl,sbs,year]
      DEF_R_6 : unsigned(31 downto 0); -- Carrier Frequency
      DEF_R_Z : unsigned(31 downto 0)  -- Value returned for nonexistent registers
    );
    port ( 
 
      sys_rst_n   : in std_logic;
      sys_clk     : in std_logic;
      sys_clk_en  : in std_logic;
 
      -- Bus interface
      adr_i       : in  unsigned(3 downto 0);
      sel_i       : in  std_logic;
      we_i        : in  std_logic;
      dat_i       : in  unsigned(31 downto 0);
      dat_o       : out unsigned(31 downto 0);
      ack_o       : out std_logic;
 
      -- Pulse per second time reference
      pps_i       : in  std_logic;
      pps_ext_i   : in  std_logic;
 
      -- IRIG select inputs
      -- Active only when register 0x4 set to zero.
      rate_i      : in  unsigned(2 downto 0); -- Rates    : 0,1=>B, 2=>A, 3=>G, 4=>NASA 36-bit
      carrier_i   : in  unsigned(2 downto 0); -- Carriers : 0=DCLS, 1=100Hz, 2=1kHz, 3=10kHz, 4=100kHz
      codes_i     : in  unsigned(2 downto 0); -- Codes    : (2)=> control, (1)=> SBS, (0)=> year
 
      -- Serial IRIG time stream, LVTTL level output
      time_dcl_o  : out std_logic;
      cap_gnd_o   : out unsigned(2 downto 0);
      ref_o       : out std_logic;
      carrier_o   : out unsigned(1 downto 0)
    );
  end component;
 
-- This component includes the capability to receive DC Level timecode streams.
-- External circuitry should low-pass filter the timecode signal to remove the
-- carrier frequency, and pass the envelope signal directly
-- to this module, where it is treated as a digital input.
-- Although it is a receiver, it also acts as a "synchronized transmitter."
  component irig_time_regenerator
    generic (
      SYS_CLK_RATE   : real;
      LOCK_THRESHOLD : integer; -- Packets received before entering locked state
      DEF_R_0 : unsigned(31 downto 0); -- Years, Days
      DEF_R_1 : unsigned(31 downto 0); -- Hours, Minutes, Seconds
      DEF_R_2 : unsigned(31 downto 0); -- Control(31:0)
      DEF_R_3 : unsigned(31 downto 0); -- Control(44:32)
      DEF_R_4 : unsigned(31 downto 0); -- Rate Setting
      DEF_R_5 : unsigned(31 downto 0); -- Fields Used [ctrl,sbs,year]
      DEF_R_6 : unsigned(31 downto 0); -- Carrier Frequency
      DEF_R_A : unsigned(31 downto 0); -- Initial value of carrier detect bias
      DEF_R_Z : unsigned(31 downto 0)  -- Value returned for nonexistent registers
    );
    port ( 
      sys_rst_n     : in std_logic;
      sys_clk       : in std_logic;
      sys_clk_en    : in std_logic;
 
      -- Bus interface
      adr_i         : in  unsigned(3 downto 0);
      sel_i         : in  std_logic;
      we_i          : in  std_logic;
      dat_i         : in  unsigned(31 downto 0);
      dat_o         : out unsigned(31 downto 0);
      ack_o         : out std_logic;
 
      -- IRIG select inputs
      -- Active only when register 0x4 set to zero.
      rate_i        : in  unsigned(2 downto 0); -- Rates    : 0,1=>B, 2=>A, 3=>G, 4=>NASA 36-bit
      carrier_i     : in  unsigned(2 downto 0); -- Carriers : 0=DCLS, 1=100Hz, 2=1kHz, 3=10kHz, 4=100kHz
      codes_i       : in  unsigned(2 downto 0); -- Codes    : (2)=> control, (1)=> SBS, (0)=> year
 
      -- IRIG time output, parallel form
      time_o        : out unsigned(67 downto 0);
 
      -- Carrier Detect Select output, PPS input,
      -- IRIG time input, tracking and lock indicators
      cdet_sel_o    : out std_logic;
      pps_i         : in  std_logic;
      time_cdet_i   : in  std_logic;
      cdet_val_o    : out unsigned(1 downto 0);
      active_o      : out std_logic;
      tracking_o    : out std_logic;
      lock_o        : out std_logic;
      neverlocked_o : out std_logic;
 
      -- Serial IRIG time stream output, LVTTL level
      time_dcl_o    : out std_logic;
      cap_gnd_o     : out std_logic;
      ref_o         : out std_logic;
      carrier_o     : out unsigned(1 downto 0)
    );
  end component;
 
end irig_time_pack;
 
package body irig_time_pack is
end irig_time_pack;
 
 
-------------------------------------------------------------------------------
-- IRIG time pattern generator core
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date  : Oct. 14, 2010 Copied code from irig_time, changed registers to
--                       a 32-bit format.
--         Nov. 24, 2010 Added DEF_R_Z generic parameter
--         Mar. 28, 2012 Moved clk_en_1mhz logic inside this module, updated
--                       description.  Added "pps_ext_i" input.  Changed name
--                       to "irig_time_generator"
--         Apr.  4, 2012 Swapped R0 and R1, so that years & days are first.
--                       This arrangement will be more congruent with the
--                       IRIG time receiver.
--         Apr.  5, 2012 Added support for NASA 36-bit (WWV) format, by
--                       extending the rate setting to include a new value,
--                       of 4.
--         Apr. 30, 2013 Changed SYS_CLK_RATE from integer to real type.
--         Dec.  2, 2013 Decreased SQF_BITS from 6 to 4, in order to increase
--                       the frequency of the square_fast signal by a factor
--                       of 4.
--         Mar. 11, 2015 Added leap_year bit to register zero.  Prevented
--                       day values higher than 366 from persisting.
--
-- Description
-------------------------------------------------------------------------------
-- This time pattern generator outputs DC Level data, plus a pair of digital outputs
-- which contain a modulated carrier signal.  The modulated carrier frequency is
-- the low-frequency heterodyne signal generated by digital mixing of a 500 kHz 
-- squarewave with a 501 kHz (IRIG "B"), 510 kHz (IRIG "A") or 600 kHz (IRIG "G") 
-- squarewave, as generated by a DDS.  As such, the digital output needs to be
-- low-pass filtered in order to cut down the amplitude of the high-frequency
-- heterodyne signal, plus the 3rd and higher order harmonics of the squarewaves
-- used.  In order to modulate the amplitude of the resulting low-pass filtered
-- carrier over a 3:1 ratio (An AM modulation index of 0.5, meaning 50% modulation
-- depth) a 2-bit R-2R resistor ladder network DAC is recommended for use outside
-- the FPGA.  Also, in order to keep the modulated signal balanced, a reference
-- voltage other than ground is used.  The reference voltage is nominally 1/2 of
-- the FPGA VCCo supply voltage (3.3V * 0.5 = 1.65V).  The FPGA generates this
-- reference voltage through the use of an output which provides a 50% duty cycle
-- squarewave.  The schematic is as follows:
--
--                    R  1.65V  R     R
--         ref_o o---/\/\--.--/\/\--/\/\--.
--                         |              |
--                    Cref - +            |
--                    15uF -              |
--                         |              |
--                        GND             |
--                              R     R   |
--  carrier_o(0) o------------/\/\--/\/\--.
--    (LSB)                               |
--                                      R <
--                                        <     Cout
--                              R     R   |     4.7uF
--  carrier_o(1) o------------/\/\--/\/\--.-----|(-------o AC coupled, Modulated Output
--    (MSB)                               |
--                          Cfilt         |
--                          0.01uF        |
--  cap_gnd_o(0) o------------|(----------.
--                                        |
--                          Cfilt         |
--                          0.01uF        |
--  cap_gnd_o(1) o------------|(----------.
--                                        |
--                          Cfilt         |
--                          1300pF        |
--  cap_gnd_o(2) o------------|(----------.
--
--  In practice, R=270 ohms has been successfully used.
--  The Cfilt values are not exact, but the values shown worked well enough.
--
-- The two carrier signals are identical, except that the LSB is constantly driving
-- the heterodyne signal out, while the MSB is only driving the heterodyne signal
-- during times when the irig DC level pulse is high.  The cap_gnd_o outputs serves
-- to adjust the corner frequency of the RC low pass filter.  They are not pulsed
-- with any high frequency signals.  They simply apply ground or else high impedance,
-- thereby effectively bringing the Cfilt capacitors in and out of the circuit.
--
-- It is recommended to use the Cout capacitor in series with the output to provide
-- AC coupling of the signal, and some DC isolation for the FPGA.
--
-- This core uses a 1MHz clock enable pulse, to count the passage of time
-- and output a pulse stream which conforms to IRIG standard 200-04, for the
-- following IRIG formats:
--
--   First  letter: B (100 pps), A (1000 pps) or G (10000 pps)
--   First  digit : 0 = DC Level shift output (no modulation)
--   Second digit : 0 = No carrier
--   Third  digit : [0..7] (BCD plus combinations of Year, CF and SBS fields)
--
-- The core can generate its own 1 MHz clock enable by dividing the sys_clk
-- by an integer divisor.  If no integer divisor can be found, then then
-- perhaps an NCO should be used to come arbitrarily close to the desired
-- 1 MHz rate.  No NCO is currently provided, so if you run into this situation
-- you may have to buckle up, and start coding.
--
-- Keeping the time accurate over the longer term is accomplished by using
-- the pps_i input, a single pulse per second, one sys_clk in duration.
-- The pps_i input may be supplied by an external GPS module for accurate time,
-- although in the absence of GPS reference, the local system clock can be
-- used to create a somewhat less accurate reference.  An internal pps
-- generator creates a pps signal by counting one million of the 1 MHz clock
-- enable pulses, which is useful as a surrogate when there is no external pps
-- reference.  To use the external pps_i input, simply make "pps_ext_i" high.
--
-- All settings for the core are contained in read/write registers, which
-- have default values determined by generics.  In the case of a "code"
-- selection which includes straight binary seconds ("SBS"), the control
-- bits for the P8 and P9 portions of the output are not used, and the
-- internally calculated SBS field is used instead.
--
-- The year field also displaces control bits when it is selected.  The two
-- digit year is fully supported, and will increment properly at the end of
-- 23:59:59 on day 364. (No leap year).
--
-- For rates A and G, there is a tenths of a second BCD digit present in the
-- latter end of the P4 period.
--
-- For rate G, there is a hundredths of a second BCD digit present in the
-- former end of the P5 period.
--
-- If the year is desired, it can be placed in the proper position within
-- the control bits, as shown here...
--    Format B or A :
--      Year_1 (the most significant BCD digit) =>
--          control_1(0) & control_0(7 downto 5)
--          control_0(4) remains '0'
--      Year_0 (the least significant BCD digit) =>
--          control_0(3 downto 0)
--
--    Format G :
--      Year_1 (the most significant BCD digit) =>
--          control_2(1 downto 0) & control_1(7 downto 6)
--          control_1(5) remains '0'
--      Year_0 (the least significant BCD digit) =>
--          control_1(4 downto 1)
--
-- Bus interface writes to the registers cannot be given higher priority
-- than internal updates for timekeeping based on pps_i, since bus writes
-- only affect one value, while timekeeping can occasionally alter all of
-- them.  Thus corrupt and undesired behavior could result if bus writes
-- were to override the timekeeping update values.  Therefore, the ack_o
-- signal is used to ensure that the timekeeping is finished before bus
-- writes take place.
--
-- The registers are summarized as follows:
--
-- Address   Structure      Function
-- -------   ----------   ----------------------------------------
--   0x0     [**YY*DDD]    BCD Year, Day of Year (Day is 1..365 or 366)
--   0x1     [**HHMMSS]    BCD Hours, Minutes, Seconds. (*=unused nibble)
--   0x2     [CCCCCCCC]    Control Bits (31:0)
--   0x3     [**CCCCCC]    Control Bits (44:32)
--   0x4     (2:0)         Rate Setting (See Notes below)
--   0x5     (2:0)         Codes Used [ctrl,SBS,year]
--   0x6     (2:0)         Carrier Modulation Frequency
--
-- Notes:
--
--   Register 0x0 (Leap Year, Year, Day of Year)
--
--    Bit 28 controls the leap year setting:
--    This register currently has only a single bit for setting leap year
--    behavior.  When the leap year bit is set, the day field advances to 366
--    before rolling over back to 1.  When the bit is clear, the day field
--    to 1 after the 365 day value.  Note that the DDD field can be written
--    with values higher than 366, but it will immediately roll over.
--
--   Register 0x4 (Rate)
--    000 => (Use external input for Rate/Form/Carrier/Codes)*
--    001 => IRIG-B (1 second updates)
--    010 => IRIG-A (0.1 second updates)
--    011 => IRIG-G (0.01 second updates)
--    100 => NASA 36-bit (WWV) time code
--
--    The "rate_i" input is used along with the register setting, in such
--    a way that the register Rate value being zero, causes the "rate_i" and
--    "codes_i" inputs to be used.  If, however, the register Rate is set to
--    a non-zero value, then the external input is ignored.
--
--    When external rate input is used, a setting of "000" results
--    in IRIG-B (1 second updates.)  All other settings remain
--    as outlined above.
--
--   Register 0x5 (Codes)
--    Each bit position, when set, activates the use of a specific field
--    within the output, according to the form:
--
--       [ctrl,SBS,year]
--
--    Where ctrl = Control field
--           SBS = Straight Binary Seconds
--          year = Year field
--
--     If year and control are both selected, then the year is used in its 
--     appropriate spot, preventing the control bits there from being used.
--
--     For Rate "G", the hundredths of a second field occludes the first four
--     control bits, so that they are not used.  The hundredths of a second field
--     is encoded in the register area for "year" since year is not used in
--     Rate "G"
--
--   Register 0x6 (Carrier)
--   000 => No carrier (DC Level Shift)
--   001 => 100 Hz / 10 ms. resolution
--   010 => 1 kHz / 1 millisecond resolution
--   011 => 10 kHz / 100 microsecond resolution
--   100 => 100 kHz / 10 microsecond resolution
--
-- Internal logic takes the day, hour, minute and second values and derives
-- a value for the SBS field (Straight Binary Second).
--
-- The generics used as defaults for the registers are the full width of the
-- data bus.  However, only those bits which are actually present in the actual
-- registers are used.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
 
entity irig_time_generator is
    generic (
      SYS_CLK_RATE : real := 40000000.0; -- Needed for carrier generation
      DEF_R_0 : unsigned(31 downto 0) := str2u("00100123",32);
      DEF_R_1 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_2 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_3 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_4 : unsigned(31 downto 0) := str2u("00000001",32);
      DEF_R_5 : unsigned(31 downto 0) := str2u("00000007",32);
      DEF_R_6 : unsigned(31 downto 0) := str2u("00000002",32);
      DEF_R_Z : unsigned(31 downto 0) := str2u("00000000",32)  -- Value returned for nonexistent registers
    );
    port ( 
 
      sys_rst_n   : in std_logic;
      sys_clk     : in std_logic;
      sys_clk_en  : in std_logic;
 
      -- Bus interface
      adr_i       : in  unsigned(3 downto 0);
      sel_i       : in  std_logic;
      we_i        : in  std_logic;
      dat_i       : in  unsigned(31 downto 0);
      dat_o       : out unsigned(31 downto 0);
      ack_o       : out std_logic;
 
      -- Pulse per second time reference
      pps_i       : in  std_logic;
      pps_ext_i   : in  std_logic;
 
      -- IRIG select inputs
      -- Active only when register 0xC set to zero.
      rate_i      : in  unsigned(2 downto 0); -- Rates    : 0,1=>B, 2=>A, 3=>G, 4=> NASA 36-bit
      carrier_i   : in  unsigned(2 downto 0); -- Carriers : 0=DCLS, 1=100Hz, 2=1kHz, 3=10kHz, 4=100kHz
      codes_i     : in  unsigned(2 downto 0); -- Codes    : (2)=> control, (1)=> SBS, (0)=> year
 
      -- serial IRIG time stream, LVTTL level output
      time_dcl_o  : out std_logic;
      cap_gnd_o   : out unsigned(2 downto 0);
      ref_o       : out std_logic;
      carrier_o   : out unsigned(1 downto 0)
    );
end irig_time_generator;
 
 
architecture beh of irig_time_generator is
 
-- Constants
constant DDS_WIDTH          : integer := 32;
constant INCREMENT_600KHZ   : unsigned(DDS_WIDTH-1 downto 0) := to_unsigned(integer(2.0**DDS_WIDTH/SYS_CLK_RATE*600000.0),DDS_WIDTH);
constant INCREMENT_510KHZ   : unsigned(DDS_WIDTH-1 downto 0) := to_unsigned(integer(2.0**DDS_WIDTH/SYS_CLK_RATE*510000.0),DDS_WIDTH);
constant INCREMENT_501KHZ   : unsigned(DDS_WIDTH-1 downto 0) := to_unsigned(integer(2.0**DDS_WIDTH/SYS_CLK_RATE*501000.0),DDS_WIDTH);
constant INCREMENT_500100HZ : unsigned(DDS_WIDTH-1 downto 0) := to_unsigned(integer(2.0**DDS_WIDTH/SYS_CLK_RATE*500100.0),DDS_WIDTH);
 
constant DIVISOR_PPS     : real :=  1000000.0;
constant DIVISOR_1MHZ    : real :=  SYS_CLK_RATE/DIVISOR_PPS;
constant DIV_COUNT_WIDTH : natural :=  bit_width(DIVISOR_1MHZ);
constant PPS_COUNT_WIDTH : natural :=  bit_width(DIVISOR_PPS);
constant SQF_BITS        : natural :=  4; -- square_fast frequency is Fsys_clk/2^(SQF_BITS+1)
 
-- Internal signal declarations
  -- State Machine
type FSM_STATE_TYPE is (RESET, IDLE, P0_REF, PR_REF, P0_DOUT, P1_PLUS_REF, P1_PLUS_DOUT);
signal fsm_state        : FSM_STATE_TYPE;
signal fsm_ack          : std_logic;
 
-- Related to SBS calculation
  -- SBS Calculation State
type SBS_STATE_TYPE is (RESET, IDLE, TIMEKEEPING_DELAY, SBS_10H, SBS_1H, SBS_10M, SBS_1M, SBS_10S);
signal sbs_state        : SBS_STATE_TYPE;
 
-- Related to Registers
 
signal leap_year        : std_logic;
 
signal secs_0           : unsigned(3 downto 0);
signal secs_1           : unsigned(2 downto 0);
signal mins_0           : unsigned(3 downto 0);
signal mins_1           : unsigned(2 downto 0);
signal hours_0          : unsigned(3 downto 0);
signal hours_1          : unsigned(1 downto 0);
signal days_0           : unsigned(3 downto 0);
signal days_1           : unsigned(3 downto 0);
signal days_2           : unsigned(1 downto 0);
signal years_0          : unsigned(3 downto 0);
signal years_1          : unsigned(3 downto 0);
signal tenths           : unsigned(3 downto 0);
signal hundredths       : unsigned(3 downto 0);
signal micros           : unsigned(13 downto 0); -- Microsecond count
 
signal sbs              : unsigned(16 downto 0);
signal sbs_next         : unsigned(16 downto 0);
signal sbs_add_count    : unsigned(3 downto 0);
 
signal control          : unsigned(44 downto 0);
signal reg_rate         : unsigned(2 downto 0);
signal reg_carrier      : unsigned(2 downto 0);
signal reg_codes        : unsigned(2 downto 0);
signal irig_rate        : unsigned(2 downto 0);
signal irig_carrier     : unsigned(2 downto 0);
signal irig_codes       : unsigned(2 downto 0);
 
-- Related to pulse per second and 1MHz clock enable
signal clk_en_1mhz      : std_logic;
signal clk_div_count    : unsigned(DIV_COUNT_WIDTH-1 downto 0);
signal pps              : std_logic;
signal pps_local        : std_logic;
signal pps_count        : unsigned(PPS_COUNT_WIDTH-1 downto 0);
 
-- Related to generation of the output pulse stream
signal pulse_clk_count  : unsigned(9 downto 0); -- Divides by factor of 10, 100 or 1000
signal pulse_clk_en     : std_logic;
signal pulse_sub_count  : unsigned(3 downto 0); -- Advances when pulse_clk_en=1
signal sub_count_nine   : std_logic;
signal p_count          : unsigned(3 downto 0); -- Advances when sub_count=9 and pulse_sr_count=9
signal cycle_count      : unsigned(6 downto 0); -- Counts output cycles during the current second.
signal pulse_sr         : unsigned(8 downto 0);
signal pulse_sr_count   : unsigned(3 downto 0); -- Advances when sub_count=9
signal sr_load_bus      : unsigned(8 downto 0);
signal p0               : unsigned(8 downto 0); -- sr load value
signal p1               : unsigned(8 downto 0); -- sr load value
signal p2               : unsigned(8 downto 0); -- sr load value
signal p3               : unsigned(8 downto 0); -- sr load value
signal p4               : unsigned(8 downto 0); -- sr load value
signal p5               : unsigned(8 downto 0); -- sr load value
signal p6               : unsigned(8 downto 0); -- sr load value
signal p7               : unsigned(8 downto 0); -- sr load value
signal p8               : unsigned(8 downto 0); -- sr load value
signal p9               : unsigned(8 downto 0); -- sr load value
signal pulse_extent     : unsigned(3 downto 0);
signal time_pulses      : std_logic;
 
-- Related to generation of the sinewave carrier
signal dds_sync          : std_logic;
signal sqf_count         : unsigned(SQF_BITS-1 downto 0);
signal square_fast       : std_logic;
signal square_500khz     : std_logic;
signal heterodyne        : std_logic;
signal modulated_carrier : std_logic;
signal phase_dds         : unsigned(DDS_WIDTH-1 downto 0);
signal increment_dds     : unsigned(DDS_WIDTH-1 downto 0);
 
-----------------------------------------------------------------------------
begin
 
  --------------------------
  -- Clock enable generation
  -- This creates output pulses at 1MHz rate, for use by the IRIG time generator
  -- It also creates a 1 Hz "pps" signal in lieu of such a signal from a GPS reference.
  clk_en_1mhz_proc: Process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n = '0') then
      clk_div_count <= (others=>'0');
--      pps_count     <= (others=>'0');
      pps_count     <= to_unsigned(integer(DIVISOR_PPS-200.0),pps_count'length); -- For better simulation
      clk_en_1mhz   <= '0';
      pps_local     <= '0';
    elsif (sys_clk'event AND sys_clk='1') then
      if (sys_clk_en='1') then
        clk_en_1mhz <= '0';  -- Default
        pps_local   <= '0';  -- Default
        if (clk_div_count=integer(DIVISOR_1MHZ-1.0)) then
          clk_div_count <= (others=>'0');
          clk_en_1mhz   <= '1';
          if (pps_count=integer(DIVISOR_PPS-1.0)) then
            pps_count   <= (others=>'0');
            pps_local   <= '1';
          else
            pps_count   <= pps_count+1;
          end if;
        else
          clk_div_count <= clk_div_count+1;
        end if;
      end if; -- sys_clk_en
    end if; -- sys_clk
  end process;
 
-- Select which PPS signal to use
pps <= pps_local when pps_ext_i='0' else pps_i;
 
-- Select which settings to use
irig_rate    <= reg_rate    when (reg_rate/=0) else rate_i;
irig_carrier <= reg_carrier when (reg_rate/=0) else carrier_i;
irig_codes   <= reg_codes   when (reg_rate/=0) else codes_i;
 
-- Register read mux
with (adr_i) select
  dat_o <=
    "000" & leap_year & "0000" & years_1 & years_0 & "000000" & days_2 & days_1 & days_0 when "0000",  --  "0";
    "0000000000" & hours_1 & hours_0 & "0" & mins_1 & mins_0 & "0" & secs_1 & secs_0     when "0001",  --  "1";
    control(31 downto 0)                                                                 when "0010",  --  "2";
    "0000000000000000000" & control(44 downto 32)                                        when "0011",  --  "3";
    u_resize(reg_rate,32)                                                                when "0100",  --  "4";
    u_resize(reg_carrier,32)                                                             when "0101",  --  "5";
    u_resize(reg_codes,32)                                                               when "0110",  --  "6";
    DEF_R_Z                                                                              when others;   -- Default
 
-- Create acknowledge signal
ack_o <= '1' when (sel_i='1' and we_i='0') else fsm_ack;
 
 
  --------------------------
  -- Heterodyning Signals
  -- The idea here is to multiply or "mix" two "squarewave" sequences
  -- by using an XOR gate, to produce a sum and difference frequency.
  -- The sum frequency should be easily filtered out by an RC filter
  -- external to the FPGA.
  proc_square: Process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n = '0') then
      square_fast <= '0';
      sqf_count   <= (others=>'0');
    elsif (sys_clk'event AND sys_clk='1') then
      if (sys_clk_en='1') then
        sqf_count <= sqf_count+1;
        if (sqf_count=0) then
          square_fast <= not square_fast;
        end if;
      end if;
    end if;
  end process;
  proc_square_500khz: Process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n = '0') then
      square_500khz <= '0';
    elsif (sys_clk'event AND sys_clk='1') then
      if (sys_clk_en='1') then
        if (clk_en_1mhz='1') then
          square_500khz <= not square_500khz;
        end if;
      end if;
    end if;
  end process;
  proc_dds: Process(sys_rst_n,sys_clk)
  begin
    if (sys_rst_n = '0') then
      phase_dds <= (phase_dds'length-2=>'1',others=>'0'); -- Set to 1/4 phase point (sinewave "zero" output)
    elsif (sys_clk'event AND sys_clk='1') then
      if (sys_clk_en='1') then
        if (dds_sync='1') then
          phase_dds <= (phase_dds'length-2=>'1',others=>'0'); -- Set to 1/4 phase point (sinewave "zero" output)
        else
          phase_dds <= phase_dds + increment_dds;
        end if;
      end if; -- sys_clk_en
    end if; -- sys_clk
  end process;
  increment_dds <= INCREMENT_600KHZ when irig_carrier=4 else
                   INCREMENT_510KHZ when irig_carrier=3 else
                   INCREMENT_501KHZ when irig_carrier=2 else
                   INCREMENT_500100HZ;
  heterodyne <= square_500khz xor phase_dds(31); -- A sort of digital signal multiplication
  modulated_carrier <= heterodyne when time_pulses='1' else square_fast; -- Output midpoint when pulse is low
  carrier_o(0) <= '0' when irig_carrier=0 else heterodyne;
  carrier_o(1) <= time_pulses when irig_carrier=0 else
                  modulated_carrier;
  ref_o        <= '0' when irig_carrier=0 else square_fast; -- Used as a "midpoint" voltage reference
 
  --------------------------
  -- Setting for output filter capacitor.
  -- The idea here is to ground the particular capacitor needed to
  -- low pass filter the output.  Three different outputs are provided.
  cap_gnd_o     <= "ZZZ" when irig_carrier=0 or irig_carrier=1 else
                   "Z00" when irig_carrier=2 else  -- Two capacitors in parallel
                   "Z0Z" when irig_carrier=3 else
                   "0ZZ";
 
-- This process is where the different BCD values are compiled into
-- a "straight binary seconds" (SBS) field.
-- The calculations are done in a multiply accumulate fashion (MAC)
-- wherein the multiply is implemented as a series of additions.
-- An SBS accumulator stores the intermediate calculation total,
-- while a state variable tracks the current stage of calculation,
-- beginning at "tens of hours" and finishing at "seconds."
-- All the adds performed here are unsigned...
sbs_proc : process(sys_clk,sys_rst_n)
begin
  if (sys_rst_n='0') then
    sbs_state <= RESET;
    sbs <= (others=>'0');
    sbs_next <= (others=>'0');
    sbs_add_count <= (others=>'0');
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
      case (sbs_state) is
        when RESET =>
          sbs_state <= IDLE;
        when IDLE  =>
          if (pps='1') then
            sbs_state <= TIMEKEEPING_DELAY;
          end if;
        -- This state waits for changes to the BCD time values to propagate,
        -- so they will be stable before this process begins calculation of
        -- the SBS field.
        when TIMEKEEPING_DELAY =>
          sbs <= (others=>'0'); -- Clear accumulator
          sbs_next <= u_resize(hours_1,sbs'length);
          sbs_add_count <= "1010"; -- Multiply by 10
          sbs_state <= SBS_10H;
        -- The following series of states performs multiply and accumulate
        -- calculations to generate the SBS value.
        when SBS_10H =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(hours_0,sbs'length);
            sbs_add_count <= "0110"; -- Multiply by 6
            sbs_state <= SBS_1H;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_1H  =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(mins_1,sbs'length);
            sbs_add_count <= "1010"; -- Multiply by 10
            sbs_state <= SBS_10M;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_10M =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(mins_0,sbs'length);
            sbs_add_count <= "0110"; -- Multiply by 6
            sbs_state <= SBS_1M;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_1M  =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(secs_1,sbs'length);
            sbs_add_count <= "1010"; -- Multiply by 10
            sbs_state <= SBS_10S;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_10S =>
          if (sbs_add_count=0) then
            sbs <= sbs + u_resize(secs_0,sbs'length); -- Add seconds (no more multiplication.)
            sbs_state <= IDLE;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when others =>
          null;
      end case;
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
 
-- sr load values
  p0 <= "00000" & secs_0 when (irig_rate=4) else
        "0" & secs_1 & "0" & secs_0;
  p1 <= "000000" & secs_1 when (irig_rate=4) else
        "0" & mins_1 & "0" & mins_0;
  p2 <= "00000" & mins_0 when (irig_rate=4) else
        "00" & hours_1 & "0" & hours_0;
  p3 <= "000000" & mins_1 when (irig_rate=4) else
        days_1 & "0" & days_0;
  p4 <= "00000" & hours_0 when (irig_rate=4) else
        "0000000" & days_2 when (irig_rate=0 or irig_rate=1) else
        tenths & "000" & days_2;
  p5 <= "0000000" & hours_1 when (irig_rate=4) else
        control(8 downto 4) & hundredths when (irig_rate=3) else
        years_1 & '0' & years_0 when (irig_codes(2)='1') else
        control(8 downto 0) when (irig_codes(0)='1') else
        "000000000";
  p6 <= "00000" & days_0 when (irig_rate=4) else
        years_1 & '0' & years_0 when (irig_rate=3 and irig_codes(2)='1') else
        control(17 downto 9) when (irig_codes(0)='1') else
        "000000000";
  p7 <= "00000" & days_1 when (irig_rate=4) else
        control(26 downto 18) when (irig_codes(0)='1') else
        "000000000";
  p8 <= "0000000" & days_2 when (irig_rate=4) else
        sbs(8 downto 0) when (irig_codes(1)='1') else
        control(35 downto 27) when (irig_codes(0)='1') else
        "000000000";
  p9 <= "111110000" when (irig_rate=4) else
        '0' & sbs(16 downto 9) when (irig_codes(1)='1') else
        control(44 downto 36) when (irig_codes(0)='1') else
        "000000000";
 
-- sr_load_bus mux
with (p_count) select
  sr_load_bus <=
    p0 when "0000",  --  "0";
    p1 when "0001",  --  "1";
    p2 when "0010",  --  "2";
    p3 when "0011",  --  "3";
    p4 when "0100",  --  "4";
    p5 when "0101",  --  "5";
    p6 when "0110",  --  "6";
    p7 when "0111",  --  "7";
    p8 when "1000",  --  "8";
    p9 when "1001",  --  "9";
    "000000000" when others;   -- Not needed for synthesis...
 
-- Generate a clock enable for advancing the output carrier state
-- The rate of this pulse is determined by the selected IRIG rate.
-- The rate has been selected to allow 10 digital samples per cycle
-- of carrier output.
-- 
-- Selected Carrier    carrier_clk rate   Carrier Frequency
-- ----------------    ----------------   -----------------
--       000              DC Level             -None-
--       001                 1 kHz            100  Hz
--       010                10 kHz              1 kHz
--       011               100 kHz             10 kHz
--       100                 1 MHz            100 kHz
--
-- Generate a clock enable for advancing the output pulse state
-- The rate of this pulse is determined by the selected IRIG rate.
-- The rate has been selected to allow output pulse duty cycle
-- to be set in increments of 1/10th the total pulse time.
-- 
-- Selected Rate    pulse_clk rate   Pulse Frequency
-- -------------    --------------   -----------------
--     000                1 kHz           100 Hz
--     001 (B)            1 kHz           100 Hz
--     010 (A)           10 kHz             1 kHz
--     011 (G)          100 kHz            10 kHz
--     100 (NASA 36)      1 kHz           100 Hz
 
pulse_clk_proc : process(sys_clk,sys_rst_n)
begin
  if (sys_rst_n='0') then
    pulse_clk_count <= (others=>'0');
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
      if (pulse_clk_en='1') then
        pulse_clk_count <= (others=>'0');
      elsif (clk_en_1mhz='1') then
        pulse_clk_count <= pulse_clk_count + 1;
      end if;
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
pulse_clk_en <= '1' when (clk_en_1mhz='1' and (irig_rate=0 or irig_rate=1 or irig_rate=4) and pulse_clk_count=999) else
                '1' when (clk_en_1mhz='1' and irig_rate=2 and pulse_clk_count=99) else
                '1' when (clk_en_1mhz='1' and irig_rate=3 and pulse_clk_count=9) else
                '0';
 
-- This is the state machine.
-- It handles updates to the timekeeping registers, based on the "pps" signal,
-- and creates the output pulse stream.
fsm_proc: process(sys_clk, sys_rst_n)
begin
  if (sys_rst_n='0') then
    fsm_state        <= RESET;   -- asynchronous reset
    leap_year        <= '0';
    micros           <= (others=>'0');
    hundredths       <= (others=>'0');
    tenths           <= (others=>'0');
    years_1          <= DEF_R_0(23 downto 20);
    years_0          <= DEF_R_0(19 downto 16);
    days_2           <= DEF_R_0(9 downto 8);
    days_1           <= DEF_R_0(7 downto 4);
    days_0           <= DEF_R_0(3 downto 0);
    hours_1          <= DEF_R_1(21 downto 20);
    hours_0          <= DEF_R_1(19 downto 16);
    mins_1           <= DEF_R_1(14 downto 12);
    mins_0           <= DEF_R_1(11 downto 8);
    secs_1           <= DEF_R_1(6 downto 4);
    secs_0           <= DEF_R_1(3 downto 0);
    control          <= DEF_R_3(12 downto 0) & DEF_R_2;
    reg_rate         <= DEF_R_4(2 downto 0);
    reg_carrier      <= DEF_R_5(2 downto 0);
    reg_codes        <= DEF_R_6(2 downto 0);
 
    p_count          <= (others=>'0');
    pulse_sr         <= (others=>'0');
    pulse_sr_count   <= to_unsigned(1,pulse_sr_count'length); -- To avoid sending out an initial stream of reference pulses while waiting for pps_local
    pulse_sub_count  <= (others=>'0');
    cycle_count      <= (others=>'0');
 
    fsm_ack          <= '0';
    dds_sync         <= '0';
 
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
 
      -- Default values
      fsm_ack <= '0';
      dds_sync <= '0';
 
      -- Handle timekeeping for fractions of seconds, based on 1MHz clock enable.
      -- These updates are overridden by pps, which resets all the time count values.
      if (clk_en_1mhz='1') then
        if (micros=9999) then
          micros <= (others=>'0');
          if (hundredths=9) then
            tenths <= tenths+1;
            hundredths <= (others=>'0');
            if (tenths=9) then
              -- No need to increment seconds here.  pps does that.
              tenths <= (others=>'0');
            else
              tenths <= tenths+1;
            end if;
          else
            hundredths <= hundredths+1;
          end if;
        else
          micros <= micros+1;
        end if;
      end if;
 
      -- Handle the timekeeping items, based on pps
      if (pps='1') then
        secs_0 <= secs_0+1;
        tenths <= (others=>'0');
        hundredths <= (others=>'0');
        micros <= (others=>'0');
        if (secs_0=9) then
          secs_1 <= secs_1+1;
          secs_0 <= (others=>'0');
          if (secs_1=5) then
            mins_0 <= mins_0+1;
            secs_1 <= (others=>'0');
            if (mins_0=9) then
              mins_1 <= mins_1+1;
              mins_0 <= (others=>'0');
              if (mins_1=5) then
                hours_0 <= hours_0+1;
                mins_1  <= (others=>'0');
                if (hours_1=2 and hours_0=3) then
                  days_0  <= days_0+1;
                  hours_1 <= (others=>'0');
                  hours_0 <= (others=>'0');
                  if (days_2>=3 and days_1>=6 and ((days_0>=5 and leap_year='0') or (days_0>=6 and leap_year='1'))) then
                    years_0 <= years_0+1;
                    days_0  <= "0001";
                    days_1  <= (others=>'0');
                    days_2  <= (others=>'0');
                    if (years_0=9) then
                      years_1 <= years_1+1;
                      years_0 <= (others=>'0');
                      if (years_1=9) then
                        years_1 <= (others=>'0');
                      end if;
                    end if;
                  elsif (days_0=9) then
                    days_1 <= days_1+1;
                    days_0 <= (others=>'0');
                    if (days_1=9) then
                      days_2 <= days_2+1;
                      days_1 <= (others=>'0');
                    end if;
                  end if;
                elsif (hours_0=9) then
                  hours_1 <= hours_1+1;
                  hours_0 <= (others=>'0');
                end if;
              end if;
            end if;
          end if;
        end if;
      elsif (sel_i='1' and we_i='1') then -- Handle bus writes to registers
      -- Cannot do this during pps, since this only writes one value, while
      -- pps timekeeping can potentially affect all the values.  Therefore,
      -- generate an acknowledge signal for the register writes... so that
      -- incoming bus cycles are extended when they collide with pps...
        fsm_ack <= '1';
        case (adr_i) is
          when "0000" =>
            leap_year <= dat_i(28);
            years_1 <= dat_i(23 downto 20);
            years_0 <= dat_i(19 downto 16);
            days_2  <= dat_i(9  downto 8);
            days_1  <= dat_i(7  downto 4);
            days_0  <= dat_i(3  downto 0);
          when "0001" =>
            hours_1 <= dat_i(21 downto 20);
            hours_0 <= dat_i(19 downto 16);
            mins_1  <= dat_i(14 downto 12);
            mins_0  <= dat_i(11 downto 8);
            secs_1  <= dat_i(6  downto 4);
            secs_0  <= dat_i(3  downto 0);
          when "0010" =>
            control(31 downto 0) <= dat_i;
          when "0011" =>
            control(44 downto 32) <= dat_i(12 downto 0);
          when "0100" =>
            reg_rate <= dat_i(2 downto 0);
          when "0101" =>
            reg_carrier <= dat_i(2 downto 0);
          when "0110" =>
            reg_codes <= dat_i(2 downto 0);
          when others => null;
        end case;
      end if;
 
      -- Handle pulse_sub_count
      if (pulse_clk_en='1') then
        if (sub_count_nine='1') then
          pulse_sub_count <= (others=>'0');
          dds_sync <= '1'; -- Set the carrier wave phase.
        else
          pulse_sub_count <= pulse_sub_count + 1;
        end if;
      end if;
 
      -- Handle state transitions
      case (fsm_state) is
 
        when RESET =>
          fsm_state <= IDLE;
 
        when IDLE =>
          if (pps='1') then
            fsm_state <= P0_REF;
            p_count   <= (others=>'0');
            cycle_count <= (others=>'0');
            pulse_sr_count <= (others=>'0');
          end if;
 
        when P0_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            pulse_sr  <= sr_load_bus;
            if (irig_rate=4) then
              fsm_state <= P0_DOUT; -- No special reference pulse for IRIG 36-bit 
            else
              fsm_state <= PR_REF;
            end if;
          end if;
 
        when PR_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            fsm_state <= P0_DOUT;
          end if;
 
        when P0_DOUT =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            if (pulse_sr_count=9) then
              pulse_sr_count <= (others=>'0');
              p_count   <= p_count+1;
              fsm_state <= P1_PLUS_REF;
            else
              pulse_sr  <= '0' & pulse_sr(8 downto 1);
              pulse_sr_count <= pulse_sr_count+1;
            end if;
          end if;
 
        when P1_PLUS_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            pulse_sr  <= sr_load_bus;
            fsm_state <= P1_PLUS_DOUT;
          end if;
 
        when P1_PLUS_DOUT =>
          if (p_count=9 and pps='1') then -- pps should not occur before p_count=9 anyway...
            fsm_state <= P0_REF;
            p_count   <= (others=>'0');
            cycle_count <= (others=>'0');
            pulse_sr_count <= (others=>'0');
          elsif (pulse_clk_en = '1' and sub_count_nine='1') then
            if (pulse_sr_count=9) then
              if (p_count=9) then
                if (cycle_count=99 and irig_rate=3) then
                  fsm_state <= IDLE;
                elsif (cycle_count=9 and irig_rate=2) then
                  fsm_state <= IDLE;
                elsif (irig_rate=0 or irig_rate=1 or irig_rate=4) then
                  fsm_state <= IDLE;
                else
                  cycle_count <= cycle_count+1;
                  p_count     <= (others=>'0');
                  pulse_sr_count <= (others=>'0');
                  fsm_state <= P0_REF;
                end if;
              else
                pulse_sr_count <= (others=>'0');
                p_count   <= p_count+1;
                pulse_sr  <= sr_load_bus;
                fsm_state <= P1_PLUS_REF;
              end if;
            else
              pulse_sr  <= '0' & pulse_sr(8 downto 1);
              pulse_sr_count <= pulse_sr_count+1;
            end if;
          end if;
 
        --when others => 
        --  fsm_state <= IDLE;
      end case;
 
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
 
sub_count_nine <= '1' when (pulse_sub_count=9) else '0';
 
-- Form output pulses
pulse_extent <= "0010" when (irig_rate=4 and pulse_sr_count=0 and p_count=0) else
                "0101" when (irig_rate=4 and pulse_sr_count=0) else
                "1000" when (pulse_sr_count=0 or fsm_state=PR_REF) else
                "0101" when (pulse_sr(0)='1') else
                "0010";
 
time_pulses <= '1' when (pulse_sub_count<pulse_extent) else '0';
time_dcl_o  <= time_pulses;
 
end beh;
 
-------------------------------------------------------------------------------
-- IRIG time pattern receiver-generator core
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date  : Apr.  4, 2012 Copied code from irig_time_generator.  Updated
--                       description.
--         Oct. 12, 2012 Added read only status registers, that allow
--                       reporting of the lock condition, as well as the
--                       "slow_err" and "fast_err" signals.  These were
--                       not being used, and were being optimized away
--                       ("pruned") at synthesis time.
--         Apr. 30, 2013 Changed SYS_CLK_RATE from integer to real type.
--         June 12, 2013 Changed low pass filter circuit topology, reducing
--                       the number of "cap_gnd_o" lines.  Increased the
--                       heterodyne input frequency from 500kHz to 2MHz.
--         Oct. 10, 2013 Added the cdet_sel_o line to activate carrier
--                       detect circuitry by register control.  Added leaky
--                       integrator based lowpass filter from
--                       "signal_conditioning_pack.vhd"
--         Oct. 14, 2013 Cleaned up the design, changing the heterodyne
--                       from 2MHz to 1MHz, eliminating "square_fast" and
--                       using the 1MHz squarewave instead.  Eliminated
--                       rx_phase and rx_dds_r1 by using "dds_squarewave"
--                       module.  Changed rx_phase_incr -> rx_freq,
--                       rx_dds_rising -> rx_1mhz_pulse.  Eliminated
--                       "phase_dds" and "increment_dds" by using
--                       dds_squarewave_phase_load module.
--         Nov.  6, 2013 Divided receive and generate logic into separate
--                       processes.  removed rx_lock_state state machine.
--                       Eliminated rx_frame_count. Added rx_c_count,
--                       gave priority to external PPS tracking over
--                       carrier count PPS (IRIG) tracking.  Added
--                       hdyne_base_square so that modulation frequency
--                       is not "warped" or affected by the tracking
--                       mechanism.  Added "set_time" signal.  Removed
--                       rx_fast_err and rx_slow_err.  Removed rx_speed_sense.
--         Dec.  6, 2013 Moved timecode gated pulse stretcher to a higher level,
--                       and introduced time_cdet_i.  Now, "time_dcl_i" really
--                       will be a DC-level timecode input, and "time_cdet_i"
--                       is a squarewave at the carrier rate, during times
--                       when cdet_sel_o is high.  Removed the 
--                       "rx_pulse_stretcher" register bit.
--         Dec.  9, 2013 Removed the time_dcl_i input, in favor of using the
--                       time_cdet_i input always.  Added reg_time_lp lowpass
--                       filter enable bit.
--         Dec. 10, 2013 Revised the data detection logic to use "rx_lo_count"
--                       and tested in hardware.  All seems to be working!
--                       O, happy day!
--         Dec. 11, 2013 Added rx_active_count to separate rx activity detect
--                       from the data receive counter "rx_lo_count."  This
--                       allows activity detect to be on edges, while the
--                       data receive is on levels, thus allowing reception of
--                       true dc-level timecode input data.
--         Nov. 14, 2014 Reduced cdet_val from 4 bits down to 2 bits, and
--                       provided it as an output signal for inclusion in
--                       a status stream.
--         Mar. 11, 2015 Added leap_year bit to register zero.  Prevented
--                       day values higher than 366 from persisting.
--
-- Description
-------------------------------------------------------------------------------
-- This time pattern receiver is also a time pattern generator.
-- More correctly, it is a time pattern generator which synchronizes itself to
-- an incoming IRIG time signal.  Also, it provides parallel output of the
-- current time so that timestamps may be taken when telemetered data is being
-- sent to an archive.
--
-- Note that during playback, "one time" syncronization is used.  The IRIG
-- time is set once, at the start of the playback, to match the first minor
-- frame timestamp.  Thereafter, the freewheeling quartz crystal based
-- IRIG time is sent out along with the playback data.  This is necessary
-- because there is no feasible way to simultaneously adjust the IRIG time
-- and the data playback rate so as to keep them both matched to some outside
-- time reference, without introducing discontinuities in the IRIG time
-- signal.
--
-- The incoming IRIG time signal is applied to a pulse period meter, which is
-- built using a binary counter.  As the period is measured, decisions are 
-- made about what type of bit is being encountered.  A period close to 20 
-- counts is considered a zero, close to 50 counts, a one, and close to 80 
-- counts, a "reference" pulse.  The counter is clocked by a pre-scaler so
-- that it can measure the period in units of 100, 10 or 1 microsecond, for
-- IRIG types B, A and G, respectively.  For rapid acquisition of all types,
-- the default is to use units of 1 microsecond (type G.)  If the count 
-- exceeds 85, then the prescaler is adjusted to provide units of 10 
-- microseconds (type A).  If, once again, the count exceeds 85, then the 
-- prescaler is adjusted to use units of 100 microseconds (type B.)  Since
-- type B is the slowest supported type, if the count once again exceeds 85
-- counts, then a "slow" error condition is flagged.
--
-- Similar converse adjustments are made for period measurements less than
-- 10 counts.  If pulses of under 10 microseconds are found, then a "fast"
-- error condition is flagged.
--
-- This unit is set up to receive DC Level data, and no attempt is made to
-- use the modulating carrier for timing reference information.
--
-- The unit outputs DC Level data, plus a pair of digital outputs which
-- contain a modulated carrier signal.  The modulated carrier frequency is the
-- low-frequency heterodyne signal generated by digital mixing of a 1 MHz
-- squarewave with a 1001 kHz (IRIG "B"), 1010 kHz (IRIG "A") or 1600 kHz
-- (IRIG "G") squarewave, as generated by a DDS.  As such, the digital output
-- needs to be low-pass filtered in order to cut down the amplitude of the
-- high-frequency components.
--
-- In order to modulate the amplitude of the resulting low-pass filtered
-- carrier over a 3:1 ratio (An AM modulation index of 0.5, meaning 50% modulation
-- depth) a 2-bit R-2R resistor ladder network DAC is recommended for use outside
-- the FPGA.  Also, in order to keep the modulated signal balanced, a reference
-- voltage other than ground is used.  The reference voltage is nominally 1/2 of
-- the FPGA VCCo supply voltage (3.3V * 0.5 = 1.65V).  The FPGA generates this
-- reference voltage through the use of an output which provides a 50% duty cycle
-- squarewave.  The schematic is as follows:
--
--                    R  1.65V  R     R
--         ref_o o---/\/\--.--/\/\--/\/\--.
--                         |              |
--                    Cref - +            |
--                    15uF -              |
--                         |              |
--                        GND             |
--                              R     R   |
--  carrier_o(0) o------------/\/\--/\/\--.
--    (LSB)                               |
--                                      R <
--                                        <     Cout
--                              R     R   |     4.7uF
--  carrier_o(1) o------------/\/\--/\/\--.-----|(-------o AC coupled, Modulated Output
--    (MSB)                               |
--                          Cfilt         |
--                          0.1uF         |
--     cap_gnd_o o------.-----|(----------.
--                      |                   
--                      .-------------. 
--                                    |
--                          Cfilt     |
--                          0.01uF    |
--           GND o------------|(------.
--
--  In practice, R=270 ohms has been successfully used.
--  The Cfilt values are not exact, but the values shown worked well enough.
--
-- The two carrier signals are identical, except that the LSB is constantly driving
-- the heterodyne signal out, while the MSB is only driving the heterodyne signal
-- during times when the irig DC level pulse is high, otherwise is outputs a 50%
-- duty cycle signal, similar to ref_o.  The cap_gnd_o outputs serves to adjust
-- the corner frequency of the RC low pass filter.  They are not pulsed with any
-- high frequency signals.  They simply apply ground or else high impedance,
-- thereby effectively bringing the Cfilt capacitors in and out of the circuit.
--
-- It is recommended to use the Cout capacitor in series with the output to provide
-- AC coupling of the signal, and some DC isolation for the FPGA.
--
-- This core uses a 1MHz clock enable pulse, to count the passage of time
-- and output a pulse stream which conforms to IRIG standard 200-04, for the
-- following IRIG formats:
--
--   First  letter: B (100 pps), A (1000 pps) or G (10000 pps)
--   First  digit : 0 = DC Level shift output (no modulation)
--   Second digit : 0 = No carrier
--   Third  digit : [0..7] (BCD plus combinations of Year, CF and SBS fields)
--
-- The core generates its own 1 MHz clock enable by using an NCO, with a phase
-- accumulator register whose size is set by generics.  When locked to an 
-- incoming timecode signal, the "integrated residual" (a.k.a. residusum)
-- is checked and adjusted each second in order to "warp" the timebase rate
-- to match the incoming timecode signal.  In this way, the timecode
-- regenerator tracks variations in the timing of the incoming IRIG signal.
--
-- When not locked to an incoming timecode signal, there is an alternate method
-- for keeping the time accurate over the longer term, namely the use of
-- the pps_i input, a single pulse per second, detected on its rising edge.
-- The pps_i input may be supplied by an external GPS module for accurate time.
-- In the absence of incoming IRIG time signal or outside GPS reference, the 
-- local quartz crystal based system clock is left to "freewheel" on its own,
-- which inevitably results in the buildup of inaccuracies in timekeeping,
-- depending on temperature, aging and physical handling of the quartz crystal
-- itself.
--
-- All settings for the core are contained in read/write registers, which
-- have default values determined by generics.  In the case of a "code"
-- selection which includes straight binary seconds ("SBS"), the control
-- bits for the P8 and P9 portions of the output are not used, and the
-- internally calculated SBS field is used instead.
--
-- The year field also displaces control bits when it is selected.  The two
-- digit year is fully supported, and will increment properly at the end of
-- 23:59:59 on day 364. (No leap year).
--
-- For rates A and G, there is a tenths of a second BCD digit present in the
-- latter end of the P4 period.
--
-- For rate G, there is a hundredths of a second BCD digit present in the
-- former end of the P5 period.
--
-- If the year is desired, it can be placed in the proper position within
-- the control bits, as shown here...
--    Format B or A :
--      Year_1 (the most significant BCD digit) =>
--          control_1(0) & control_0(7 downto 5)
--          control_0(4) remains '0'
--      Year_0 (the least significant BCD digit) =>
--          control_0(3 downto 0)
--
--    Format G :
--      Year_1 (the most significant BCD digit) =>
--          control_2(1 downto 0) & control_1(7 downto 6)
--          control_1(5) remains '0'
--      Year_0 (the least significant BCD digit) =>
--          control_1(4 downto 1)
--
-- Bus interface writes to the registers cannot be given higher priority
-- than internal updates for timekeeping based on pps_i, since bus writes
-- only affect one value, while timekeeping can occasionally alter all of
-- them.  Thus corrupt and undesired behavior could result if bus writes
-- were to override the timekeeping update values.  Therefore, the ack_o
-- signal is used to ensure that the timekeeping is finished before bus
-- writes take place.
--
-- The registers are summarized as follows:
--
-- Address   Structure      Function
-- -------   ----------   ----------------------------------------
--   0x0     [**YY*DDD]    BCD Year, Day of Year (Day is 1..365)
--   0x1     [**HHMMSS]    BCD Hours, Minutes, Seconds. (*=unused nibble)
--   0x2     [CCCCCCCC]    Control Bits (31:0)
--   0x3     [**CCCCCC]    Control Bits (44:32)
--   0x4     (2:0)         Rate Setting (See Notes below)
--   0x5     (2:0)         Carrier Modulation Frequency
--   0x6     (2:0)         Codes Used [ctrl,SBS,year]
--   0x7     (6:0)         Time receiver control and status
--   0x8     (31:0)        Statistical report (read only)
--   0x9     (31:0)        PPS residusum, a 25 bit signed value, (sign extended)
--   0xA     (8:0)         Lowpass filter enable, CDET bias setting
--
-- Notes:
--
--   Register 0x0 (Leap Year, Year, Day of Year)
--
--    Bit 28 controls the leap year setting:
--    This register currently has only a single bit for setting leap year
--    behavior.  When the leap year bit is set, the day field advances to 366
--    before rolling over back to 1.  When the bit is clear, the day field
--    to 1 after the 365 day value.  Note that the DDD field can be written
--    with values higher than 366, but it will immediately roll over.
--
--   Register 0x4 (Rate)
--    000 => (Use external input for Rate/Form/Carrier/Codes)*
--    001 => IRIG-B (1 second updates)
--    010 => IRIG-A (0.1 second updates)
--    011 => IRIG-G (0.01 second updates)
--    100 => NASA 36-bit (WWV) time code
--
--    The "rate_i" input is used along with the register setting, in such
--    a way that the register Rate value being zero, causes the "rate_i" and
--    "codes_i" inputs to be used.  If, however, the register Rate is set to
--    a non-zero value, then the external input is ignored.
--
--    When external rate input is used, a setting of "000" results
--    in IRIG-B (1 second updates.)  All other settings remain
--    as outlined above.
--
--   Register 0x5 (Carrier)
--
--   000 => No carrier (DC Level Shift)
--   001 => 100 Hz / 10 ms. resolution
--   010 => 1 kHz / 1 millisecond resolution
--   011 => 10 kHz / 100 microsecond resolution
--   100 => 100 kHz / 10 microsecond resolution
--
-- Internal logic takes the day, hour, minute and second values and derives
-- a value for the SBS field (Straight Binary Second).
--
--   Register 0x6 (Codes)
--    Each bit position, when set, activates the use of a specific field
--    within the output, according to the form:
--
--       [ctrl,SBS,year]
--
--    Where ctrl = Control field
--           SBS = Straight Binary Seconds
--          year = Year field
--
--     If year and control are both selected, then the year is used in its 
--     appropriate spot, preventing the control bits there from being used.
--
--     For Rate "G", the hundredths of a second field occludes the first four
--     control bits, so that they are not used.  The hundredths of a second field
--     is encoded in the register area for "year" since year is not used in
--     Rate "G"
--
-- Register 0x07
--   Time Receiver Status register
--     bits (1:0) = cdet_val.  These bits are the carrier detect value,
--                  which relates to the detected IRIG timecode speed.
--                     cdet_val   Meaning
--                     --------   -----------------------------
--                         3      IRIG G speed (100kHz carrier)
--                         2      IRIG A speed (10 kHz carrier)
--                         1      IRIG B speed (1  kHz carrier)
--                         0      no carrier detected.
--
--     bits (3:2) = reserved (value is set to "00").
--
--     bit (4) = active status bit.  '1' means activity was detected on the
--               irig_dcl_i input.
--     bit (5) = lock status bit.  '1' indicates the receiver is in the 
--               TRACK_IRIG state
--     bit (6) = IRIG tracking status bit.  Read only bit that indicates the
--               received IRIG timecode is valid for time tracking
--     bit (7) = PPS tracking status bit.  Read only bit that indicates the
--               received PPS signal is valid for time tracking
--     bit (8) = neverlocked status bit.  '1' indicates the unit has not locked
--               since reset.  This bit can only be set after Power On Reset.
--               Read only.
--     bit (9) = rx_nasa36 bit.  This bit is set whenever NASA 36 timecode is
--               detected and used.  Read only.
--     bit (10)= cdet_sel_l bit.  This bit is read only, and indicates when
--               the receiver state machine is asserting carrier detect mode.
--               When this bit is set, external circuitry is configured to 
--               strip out the time information, and only provide a 
--               "zero crossing" detected carrier on the time_cdet_i input.
--               The "zero crossing" detected carrier is a squarewave at the
--               frequency of the carrier.  When this bit is clear, pulses arrive
--               corresponding to the times when the carrier is at high-amplitude.
--     bits (31:24) = rx_pulse_width.  This is the most recently measured pulse
--               low value as a percentage.  Nominal IRIG timecode pulses
--               should be high: 20% for zero, 50% for one, and 80% for ref.
--               The rx_pulse_width is a count of the low time after the
--               trailing edge of the received pulse.  Thus, values >96
--               represent pulses which are too short, >72 are zeros,
--               >48 are ones and >16 are ref pulses.  These thresholds are
--               defined as constants within the code.
--                 
-- Register 0x08
--   Receiver additional information
--     bits (3:0) = receiver current state
--       value   name           meaning
--       -----   -----------    --------------------------------------------------------------
--         0     SETTLE_DOWN    Awaiting capacitor discharge following cdet_sel_o being cleared
--         1     CDET_1         Awaiting carrier speed detect synchronization
--         2     CDET_2         Awaiting carrier speed detect
--         3     SETTLE_UP      Awaiting capacitor charge following cdet_sel_o being set
--         4     SEEK_REF_1     Seeking a longer "reference" type pulse
--         5     SEEK_REF_2     Seeking a second CONSECUTIVE "reference" type pulse
--         6     RECEIVE_PULSES Receiving and decoding IRIG time pulses
--         7     SETTLE_IN      Awaiting capacitor discharge heading into TRACK_IRIG
--         8     TRACK_IRIG     Tracking incoming IRIG time carrier based PPS
--
--     bits (7:4) = reserved
--
--     bits (15:8)  = number of times rx_active has been asserted. Write to clear.
--     bits (23:16) = number of times RECEIVE_PULSES has been entered. Write to clear.
--     bits (31:24) = number of times TRACK_IRIG has been entered. Write to clear.
--
-- Register 0x09
--   Receiver PPS tracking "residusum"
--     This is a signed quantity which represents the speed adjustment to the internally
--     generated IRIG time output.  It is based on measurements against a incoming pulse
--     per second time reference.  There are two PPS references: pps_i and an internal
--     irig_pps which is based on dividing down the received carrier frequency whenever
--     the receiver is in the TRACK_IRIG state.
--     This is a signed quantity, which has been sign extended to 32 bits.  It is limited
--     by the constant RESIDUSUM_BITS to be at most +/- 1/128 the magnitude of the frequency
--     setting (An allowed frequency variation window of +/- 0.7825 percent.)
--
-- Register 0x0A
--   Carrier Detect Bias, and time lowpass filter enable
--     bits (5:0) = Carrier detect bias value.  Ranging from 0x00 to 0x20, this value
--                  drives a PWM output to an RC filter network, creating a voltage used
--                  as a threshold to detect either the timecode carrier, or the carrier
--                  "high amplitude peaks" depending on cdet_sel_o.
--     bit (8)    = time_cdet_i lowpass filter enable.  When set, this bit enables use of
--                  a leaky-integrator based lowpass filter.
--
-- The generics used as defaults for the registers are the full width of the
-- data bus.  However, only those bits which are actually present in the actual
-- registers are used.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.dds_pack.all;
use work.pwm_pack.all;
use work.convert_pack.all;
use work.signal_conditioning_pack.all;
 
entity irig_time_regenerator is
    generic (
      SYS_CLK_RATE   : real := 40000000.0; -- Needed for carrier generation
      LOCK_THRESHOLD : integer :=        8; -- Frames received before entering locked state
      DEF_R_0 : unsigned(31 downto 0) := str2u("00100123",32);
      DEF_R_1 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_2 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_3 : unsigned(31 downto 0) := str2u("00000000",32);
      DEF_R_4 : unsigned(31 downto 0) := str2u("00000001",32);
      DEF_R_5 : unsigned(31 downto 0) := str2u("00000002",32);
      DEF_R_6 : unsigned(31 downto 0) := str2u("00000007",32);
      DEF_R_A : unsigned(31 downto 0) := str2u("00000014",32); -- Initial value of carrier detect bias
      DEF_R_Z : unsigned(31 downto 0) := str2u("00000000",32)  -- Value returned for nonexistent registers
    );
    port ( 
 
      sys_rst_n     : in std_logic;
      sys_clk       : in std_logic;
      sys_clk_en    : in std_logic;
 
      -- Bus interface
      adr_i         : in  unsigned(3 downto 0);
      sel_i         : in  std_logic;
      we_i          : in  std_logic;
      dat_i         : in  unsigned(31 downto 0);
      dat_o         : out unsigned(31 downto 0);
      ack_o         : out std_logic;
 
      -- Pulse per second time reference
 
      -- IRIG select inputs
      -- Active only when register 0x4 set to zero.
      rate_i        : in  unsigned(2 downto 0); -- Rates    : 0,1=>B, 2=>A, 3=>G, 4=>NASA 36-bit
      carrier_i     : in  unsigned(2 downto 0); -- Carriers : 0=DCLS, 1=100Hz, 2=1kHz, 3=10kHz, 4=100kHz
      codes_i       : in  unsigned(2 downto 0); -- Codes    : (2)=> control, (1)=> SBS, (0)=> year
 
      -- IRIG time output, parallel form
      time_o        : out unsigned(67 downto 0);
 
      -- Carrier Detect Select output, PPS input,
      -- IRIG time input, tracking and lock indicators
      cdet_sel_o    : out std_logic;
      pps_i         : in  std_logic;
      time_cdet_i   : in  std_logic;
      cdet_val_o    : out unsigned(1 downto 0);
      active_o      : out std_logic;
      tracking_o    : out std_logic;
      lock_o        : out std_logic;
      neverlocked_o : out std_logic;
 
      -- Serial IRIG time stream output, LVTTL level
      time_dcl_o    : out std_logic;
      cap_gnd_o     : out std_logic;
      ref_o         : out std_logic;
      carrier_o     : out unsigned(1 downto 0)
    );
end irig_time_regenerator;
 
architecture beh of irig_time_regenerator is
 
-- Constants
 
  -- IRIG Generator Constants
    -- DDS size
constant RX_1MHZ_DDS_BITS : natural := 32;
constant HDYNE_DDS_BITS      : integer := 32;
    -- Digital Heterodyne constants
constant INCREMENT_1000KHZ   : unsigned(HDYNE_DDS_BITS-1 downto 0) := to_unsigned(integer(2.0**HDYNE_DDS_BITS/SYS_CLK_RATE*1000000.0),HDYNE_DDS_BITS);
constant INCREMENT_1100KHZ   : unsigned(HDYNE_DDS_BITS-1 downto 0) := to_unsigned(integer(2.0**HDYNE_DDS_BITS/SYS_CLK_RATE*1100000.0),HDYNE_DDS_BITS);
constant INCREMENT_1010KHZ   : unsigned(HDYNE_DDS_BITS-1 downto 0) := to_unsigned(integer(2.0**HDYNE_DDS_BITS/SYS_CLK_RATE*1010000.0),HDYNE_DDS_BITS);
constant INCREMENT_1001KHZ   : unsigned(HDYNE_DDS_BITS-1 downto 0) := to_unsigned(integer(2.0**HDYNE_DDS_BITS/SYS_CLK_RATE*1001000.0),HDYNE_DDS_BITS);
constant INCREMENT_1000100HZ : unsigned(HDYNE_DDS_BITS-1 downto 0) := to_unsigned(integer(2.0**HDYNE_DDS_BITS/SYS_CLK_RATE*1000100.0),HDYNE_DDS_BITS);
 
  -- IRIG receiver constants
constant FRAME_COUNT_BITS : natural := bit_width(LOCK_THRESHOLD);
constant PHASE_INCR_1MHZ  : natural := natural(1000000.0/SYS_CLK_RATE*(2**real(RX_1MHZ_DDS_BITS)));
constant RESIDUSUM_BITS   : natural := RX_1MHZ_DDS_BITS-7; -- Restrict variation to approx. 1% (1/128) of frequency setting
constant RX_EDGE_VAL      : natural := 16;
constant RX_ONE_VAL       : natural := 48;
constant RX_ZERO_VAL      : natural := 72;
constant RX_TOO_SHORT     : natural := 96;
constant RX_C_SEED_B      : integer := 1000;   -- Counts carrier pulses
constant RX_C_SEED_A      : integer := 10000;  -- Counts carrier pulses
constant RX_C_SEED_G      : integer := 100000; -- Counts carrier pulses
constant PPS_R_COUNT_SEED : integer := 999999; -- Counts 1 million microseconds...
constant PPS_TRACK_LIMIT  : integer := 1000;
constant CDET_SETTLE_TIME : integer := 24; -- Milliseconds of settling when cdet_sel_o changes.
--constant CDET_SETTLE_TIME : integer := 0; -- For fast simulation
-- NOTE: It was discovered during testing that, with the enhancements to the
-- IRIG timecode receiver, settling time is not needed in order to obtain a
-- lock on the incoming signal.  Therefore, apart from a slight initial
-- inaccuracy in frequency tracking for <24ms in the TRACK_IRIG state, there
-- is no effect from skipping the settling time.  It will be left at zero ms
-- unless a compelling reason is found to increase it.
 
-- Internal signal declarations
  -- State Machine
type FSM_STATE_TYPE is (RESET, IDLE, P0_REF, PR_REF, P0_DOUT, P1_PLUS_REF, P1_PLUS_DOUT);
signal fsm_state        : FSM_STATE_TYPE;
signal fsm_ack          : std_logic;
signal ack_l            : std_logic;
 
-- Related to SBS calculation
  -- SBS Calculation State
type SBS_STATE_TYPE is (RESET, IDLE, TIMEKEEPING_DELAY, SBS_10H, SBS_1H, SBS_10M, SBS_1M, SBS_10S);
signal sbs_state        : SBS_STATE_TYPE;
 
-- Related to Registers
signal leap_year        : std_logic;
signal secs_0           : unsigned(3 downto 0);
signal secs_1           : unsigned(2 downto 0);
signal mins_0           : unsigned(3 downto 0);
signal mins_1           : unsigned(2 downto 0);
signal hours_0          : unsigned(3 downto 0);
signal hours_1          : unsigned(1 downto 0);
signal days_0           : unsigned(3 downto 0);
signal days_1           : unsigned(3 downto 0);
signal days_2           : unsigned(1 downto 0);
signal years_0          : unsigned(3 downto 0);
signal years_1          : unsigned(3 downto 0);
signal tenths           : unsigned(3 downto 0);
signal hundredths       : unsigned(3 downto 0);
 
signal sbs              : unsigned(16 downto 0);
signal sbs_next         : unsigned(16 downto 0);
signal sbs_add_count    : unsigned(3 downto 0);
 
signal control          : unsigned(44 downto 0);
signal reg_rate         : unsigned(2 downto 0);
signal reg_carrier      : unsigned(2 downto 0);
signal reg_codes        : unsigned(2 downto 0);
signal irig_rate        : unsigned(2 downto 0);
signal irig_carrier     : unsigned(2 downto 0);
signal irig_codes       : unsigned(2 downto 0);
 
-- Related to generation of the output pulse stream
signal tx_1mhz_pulse    : std_logic; -- 1MHz pulse stream which can warp when tracking.
signal set_time         : std_logic;
signal pulse_clk_count  : unsigned(9 downto 0); -- Divides by factor of 10, 100 or 1000
signal pulse_clk_en     : std_logic;
signal pulse_sub_count  : unsigned(3 downto 0); -- Advances when pulse_clk_en=1
signal sub_count_nine   : std_logic;
signal p_count          : unsigned(3 downto 0); -- Advances when sub_count=9 and pulse_sr_count=9
signal cycle_count      : unsigned(6 downto 0); -- Counts output cycles during the current second.
signal pulse_sr         : unsigned(8 downto 0);
signal pulse_sr_count   : unsigned(3 downto 0); -- Advances when sub_count=9
signal sr_load_bus      : unsigned(8 downto 0);
signal p0               : unsigned(8 downto 0); -- sr load value
signal p1               : unsigned(8 downto 0); -- sr load value
signal p2               : unsigned(8 downto 0); -- sr load value
signal p3               : unsigned(8 downto 0); -- sr load value
signal p4               : unsigned(8 downto 0); -- sr load value
signal p5               : unsigned(8 downto 0); -- sr load value
signal p6               : unsigned(8 downto 0); -- sr load value
signal p7               : unsigned(8 downto 0); -- sr load value
signal p8               : unsigned(8 downto 0); -- sr load value
signal p9               : unsigned(8 downto 0); -- sr load value
signal pulse_extent     : unsigned(3 downto 0);
signal time_pulses      : std_logic;
signal pps              : std_logic;
 
-- Related to generation of the sinewave carrier
signal hdyne_dds_sync    : std_logic;
signal hdyne_base_square : std_logic;
signal hdyne_in_square   : std_logic;
signal hdyne_out         : std_logic;
signal hdyne_in_freq     : unsigned(HDYNE_DDS_BITS-1 downto 0);
signal modulated_carrier : std_logic;
 
-- Related to Timecode Receiver
type RX_STATE_TYPE is (WAIT_ACTIVE, SEEK_REF_1, SEEK_REF_2, RECEIVE_PULSES, SETTLE_IN, TRACK_IRIG);
signal rx_state         : RX_STATE_TYPE;
signal rx_nasa36        : std_logic; -- High means NASA 36-bit code detected
signal rx_sr            : unsigned(9 downto 0);
signal rx_scale_factor  : unsigned(7 downto 0);
signal rx_scale_count   : unsigned(7 downto 0);
signal rx_lo_count      : unsigned(7 downto 0);
signal rx_pulse_width   : unsigned(7 downto 0);
signal rx_pulse_count   : unsigned(3 downto 0);
signal rx_group_count   : unsigned(3 downto 0);
signal rx_freq          : unsigned(RX_1MHZ_DDS_BITS-1 downto 0); -- Sets frequency
signal rx_1mhz_pulse    : std_logic;
signal rx_posedge       : std_logic;
signal rx_pstart        : std_logic;
signal rx_hi_count      : unsigned(7 downto 0);
signal rx_raise_count   : unsigned(3 downto 0);
signal rx_active_wdog   : unsigned(7 downto 0);
signal rx_active_count  : unsigned(3 downto 0);
signal rx_active        : std_logic;
signal rx_pps_tracking  : std_logic;
signal rx_irig_tracking : std_logic;
signal rx_lock          : std_logic;
signal micro_bcd_0      : unsigned(3 downto 0);
signal micro_bcd_1      : unsigned(3 downto 0);
signal micro_bcd_2      : unsigned(3 downto 0);
signal micro_bcd_3      : unsigned(3 downto 0);
signal micro_bcd_4      : unsigned(3 downto 0);
signal micro_bcd_5      : unsigned(3 downto 0);
signal rx_c_count       : unsigned(16 downto 0);
signal pps_r_count      : signed(20 downto 0); -- Counts down 1 sec. worth of microseconds.
signal pps_residusum    : signed(RESIDUSUM_BITS-1 downto 0);
signal rx_secs_0        : unsigned(3 downto 0);
signal rx_secs_1        : unsigned(2 downto 0);
signal rx_mins_0        : unsigned(3 downto 0);
signal rx_mins_1        : unsigned(2 downto 0);
signal rx_hours_0       : unsigned(3 downto 0);
signal rx_hours_1       : unsigned(1 downto 0);
signal rx_days_0        : unsigned(3 downto 0);
signal rx_days_1        : unsigned(3 downto 0);
signal rx_days_2        : unsigned(1 downto 0);
signal rx_years_0       : unsigned(3 downto 0);
signal rx_years_1       : unsigned(3 downto 0);
signal rx_neverlocked   : std_logic;
signal cdet_fixed       : std_logic;
signal cdet_val_l       : unsigned(1 downto 0);
signal cdet_sel_l       : std_logic;
signal pulse_1ms        : std_logic;
signal cdet_ms_timer    : unsigned(4 downto 0);
signal cdet_bias        : unsigned(5 downto 0);
signal cdet_dac_clk_en  : std_logic;
signal time_cleaner_input : signed(15 downto 0);
signal time_cleaned     : std_logic;
signal time_rx          : std_logic;
signal time_rx_r1       : std_logic;
signal time_rx_r2       : std_logic;
signal reg_time_lp      : std_logic;
signal pps_r1           : std_logic;
signal pps_r2           : std_logic;
signal rx_state_report  : unsigned(3 downto 0);
signal rx_stat_1        : unsigned(7 downto 0);
signal rx_stat_2        : unsigned(7 downto 0);
signal rx_stat_3        : unsigned(7 downto 0);
 
-----------------------------------------------------------------------------
begin
 
-- Select which settings to use
irig_rate    <= reg_rate    when (reg_rate/=0) else rate_i;
irig_carrier <= reg_carrier when (reg_rate/=0) else carrier_i;
irig_codes   <= reg_codes   when (reg_rate/=0) else codes_i;
 
-- Register read mux
with (adr_i) select
  dat_o <=
    "000" & leap_year & "0000" & years_1 & years_0 & "000000" & days_2 & days_1 & days_0 when "0000",  --  "0";
    "0000000000" & hours_1 & hours_0 & "0" & mins_1 & mins_0 & "0" & secs_1 & secs_0     when "0001",  --  "1";
    control(31 downto 0)                                                                 when "0010",  --  "2";
    "0000000000000000000" & control(44 downto 32)                                        when "0011",  --  "3";
    u_resize(reg_rate,32)                                                                when "0100",  --  "4";
    u_resize(reg_carrier,32)                                                             when "0101",  --  "5";
    "00000000000000000000000000000" & reg_codes                                          when "0110",  --  "6";
    rx_pulse_width & "0000000000000" & cdet_fixed & rx_nasa36 & rx_neverlocked &
               rx_pps_tracking & rx_irig_tracking & rx_lock & rx_active & "00" & cdet_val_l when "0111",  --  "7";
    rx_stat_3 & rx_stat_2 & rx_stat_1 & "0000" & rx_state_report                       when "1000",  --  "8";
    unsigned(s_resize_se(pps_residusum,32))                                            when "1001",  --  "9";
    "00000000000000000000000" & reg_time_lp & u_resize(cdet_bias,8)                    when "1010",  --  "A";
    DEF_R_Z                                                                            when others;   -- Default
 
-- Create acknowledge signal
ack_l <= fsm_ack when (sel_i='1' and we_i='1' and adr_i<7) else -- special ack for tx fsm registers
         '1' when (sel_i='1') else
         '0';
ack_o <= ack_l;
 
-- Produce parallel output
time_o <= years_1 & years_0 & "00" & days_2 & days_1 & days_0 & "00" & hours_1 & hours_0 &
          '0' & mins_1 & mins_0 & '0' & secs_1 & secs_0 & micro_bcd_5 & micro_bcd_4 &
          micro_bcd_3 & micro_bcd_2 & micro_bcd_1 & micro_bcd_0;
 
  --------------------------
  -- Heterodyning Signals
  -- The idea here is to multiply or "mix" two "squarewave" sequences
  -- by using an XOR gate, to produce a sum and difference frequency.
  -- The sum frequency should be easily filtered out by an RC filter
  -- external to the FPGA.
 
  hdyne_base_squarewave : dds_squarewave
    generic map(
      ACC_BITS     => HDYNE_DDS_BITS
    )
    port map(
 
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => sys_clk_en,
 
      -- Frequency setting
      freq_i       => INCREMENT_1000KHZ,
 
      -- Output
      pulse_o      => open,
      squarewave_o => hdyne_base_square
    );
 
  hdyne_in_squarewave : dds_squarewave_phase_load
    generic map(
      ACC_BITS     => HDYNE_DDS_BITS
    )
    port map(
 
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => sys_clk_en,
 
      -- Frequency setting
      freq_i       => hdyne_in_freq,
 
      -- Synchronous load
      phase_i      => ((HDYNE_DDS_BITS-2)=>'1', others=>'0'), -- Set to 1/4 phase point (sinewave "zero" output)
      phase_ld_i   => hdyne_dds_sync,
 
      -- Output
      pulse_o      => open,
      squarewave_o => hdyne_in_square
    );
 
  hdyne_in_freq <= INCREMENT_1100KHZ when irig_carrier=4 else
                   INCREMENT_1010KHZ when irig_carrier=3 else
                   INCREMENT_1001KHZ when irig_carrier=2 else
                   INCREMENT_1000100HZ;
  hdyne_out <= hdyne_base_square xor hdyne_in_square; -- A sort of digital signal multiplication
  modulated_carrier <= hdyne_out when time_pulses='1' else hdyne_base_square; -- Output midpoint when pulse is low
  carrier_o(0) <= '0' when irig_carrier=0 else hdyne_out;
  carrier_o(1) <= time_pulses when irig_carrier=0 else
                  modulated_carrier;
  ref_o        <= '0' when irig_carrier=0 else hdyne_base_square; -- Used as a "midpoint" voltage reference
 
  --------------------------
  -- Setting for output filter capacitor.
  -- The idea here is to ground the larger capacitor for low frequency
  -- carriers, and for the highest frequency, not ground it.  It will
  -- be connected in series with a smaller capacitor then.
  cap_gnd_o     <= '0' when irig_carrier=4 else
                   '1';
 
-- This process is where the different BCD values are compiled into
-- a "straight binary seconds" (SBS) field.
-- The calculations are done in a multiply accumulate fashion (MAC)
-- wherein the multiply is implemented as a series of additions.
-- An SBS accumulator stores the intermediate calculation total,
-- while a state variable tracks the current stage of calculation,
-- beginning at "tens of hours" and finishing at "seconds."
-- All the adds performed here are unsigned...
sbs_proc : process(sys_clk,sys_rst_n)
begin
  if (sys_rst_n='0') then
    sbs_state <= RESET;
    sbs <= (others=>'0');
    sbs_next <= (others=>'0');
    sbs_add_count <= (others=>'0');
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
      case (sbs_state) is
        when RESET =>
          sbs_state <= IDLE;
        when IDLE  =>
          if (pps='1') then
            sbs_state <= TIMEKEEPING_DELAY;
          end if;
        -- This state waits for changes to the BCD time values to propagate,
        -- so they will be stable before this process begins calculation of
        -- the SBS field.
        when TIMEKEEPING_DELAY =>
          sbs <= (others=>'0'); -- Clear accumulator
          sbs_next <= u_resize(hours_1,sbs'length);
          sbs_add_count <= "1010"; -- Multiply by 10
          sbs_state <= SBS_10H;
        -- The following series of states performs multiply and accumulate
        -- calculations to generate the SBS value.
        when SBS_10H =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(hours_0,sbs'length);
            sbs_add_count <= "0110"; -- Multiply by 6
            sbs_state <= SBS_1H;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_1H  =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(mins_1,sbs'length);
            sbs_add_count <= "1010"; -- Multiply by 10
            sbs_state <= SBS_10M;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_10M =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(mins_0,sbs'length);
            sbs_add_count <= "0110"; -- Multiply by 6
            sbs_state <= SBS_1M;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_1M  =>
          if (sbs_add_count=0) then
            sbs <= (others=>'0');
            sbs_next <= sbs + u_resize(secs_1,sbs'length);
            sbs_add_count <= "1010"; -- Multiply by 10
            sbs_state <= SBS_10S;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when SBS_10S =>
          if (sbs_add_count=0) then
            sbs <= sbs + u_resize(secs_0,sbs'length); -- Add seconds (no more multiplication.)
            sbs_state <= IDLE;
          else
            sbs <= sbs + sbs_next;
            sbs_add_count <= sbs_add_count-1;
          end if;
        when others =>
          null;
      end case;
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
 
-- sr load values
  p0 <= "00000" & secs_0 when (irig_rate=4) else
        "0" & secs_1 & "0" & secs_0;
  p1 <= "000000" & secs_1 when (irig_rate=4) else
        "0" & mins_1 & "0" & mins_0;
  p2 <= "00000" & mins_0 when (irig_rate=4) else
        "00" & hours_1 & "0" & hours_0;
  p3 <= "000000" & mins_1 when (irig_rate=4) else
        days_1 & "0" & days_0;
  p4 <= "00000" & hours_0 when (irig_rate=4) else
        "0000000" & days_2 when (irig_rate=0 or irig_rate=1) else
        tenths & "000" & days_2;
  p5 <= "0000000" & hours_1 when (irig_rate=4) else
        control(8 downto 4) & hundredths when (irig_rate=3) else
        years_1 & '0' & years_0 when (irig_codes(2)='1') else
        control(8 downto 0) when (irig_codes(0)='1') else
        "000000000";
  p6 <= "00000" & days_0 when (irig_rate=4) else
        years_1 & '0' & years_0 when (irig_rate=3 and irig_codes(2)='1') else
        control(17 downto 9) when (irig_codes(0)='1') else
        "000000000";
  p7 <= "00000" & days_1 when (irig_rate=4) else
        control(26 downto 18) when (irig_codes(0)='1') else
        "000000000";
  p8 <= "0000000" & days_2 when (irig_rate=4) else
        sbs(8 downto 0) when (irig_codes(1)='1') else
        control(35 downto 27) when (irig_codes(0)='1') else
        "000000000";
  p9 <= "111110000" when (irig_rate=4) else
        '0' & sbs(16 downto 9) when (irig_codes(1)='1') else
        control(44 downto 36) when (irig_codes(0)='1') else
        "000000000";
 
-- sr_load_bus mux
with (p_count) select
  sr_load_bus <=
    p0 when "0000",  --  "0";
    p1 when "0001",  --  "1";
    p2 when "0010",  --  "2";
    p3 when "0011",  --  "3";
    p4 when "0100",  --  "4";
    p5 when "0101",  --  "5";
    p6 when "0110",  --  "6";
    p7 when "0111",  --  "7";
    p8 when "1000",  --  "8";
    p9 when "1001",  --  "9";
    "000000000" when others;   -- Not needed for synthesis...
 
-- Generate a clock enable for advancing the output pulse state
-- The rate of this pulse is determined by the selected IRIG rate.
-- The rate has been selected to allow output pulse duty cycle
-- to be set in increments of 1/10th the total pulse time.
-- 
-- Selected Rate    pulse_clk rate   Pulse Frequency
-- -------------    --------------   -----------------
--     000                1 kHz           100 Hz
--     001 (B)            1 kHz           100 Hz
--     010 (A)           10 kHz             1 kHz
--     011 (G)          100 kHz            10 kHz
--     100 (NASA 36)      1 kHz           100 Hz
--
-- Generate a clock enable for advancing the output carrier state
-- The rate of this pulse is determined by the selected IRIG rate.
-- The rate has been selected to allow 10 digital samples per cycle
-- of carrier output.
-- 
-- Selected Carrier    carrier_clk rate   Carrier Frequency
-- ----------------    ----------------   -----------------
--       000              DC Level             -None-
--       001                 1 kHz            100  Hz
--       010                10 kHz              1 kHz
--       011               100 kHz             10 kHz
--       100                 1 MHz            100 kHz
--
 
pulse_clk_proc : process(sys_clk,sys_rst_n)
begin
  if (sys_rst_n='0') then
    pulse_clk_count <= (others=>'0');
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
      if (pulse_clk_en='1') then
        pulse_clk_count <= (others=>'0');
      elsif (tx_1mhz_pulse='1') then
        pulse_clk_count <= pulse_clk_count + 1;
      end if;
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
pulse_clk_en <= '1' when (tx_1mhz_pulse='1' and (irig_rate=0 or irig_rate=1 or irig_rate=4) and pulse_clk_count=999) else
                '1' when (tx_1mhz_pulse='1' and irig_rate=2 and pulse_clk_count=99) else
                '1' when (tx_1mhz_pulse='1' and irig_rate=3 and pulse_clk_count=9) else
                '0';
 
-- This is the IRIG timecode generating state machine.
-- It handles updates to the timekeeping registers, based on the "pps" signal,
-- and creates the output pulse stream.
fsm_proc: process(sys_clk, sys_rst_n)
begin
  if (sys_rst_n='0') then
    fsm_state        <= RESET;   -- asynchronous reset
    leap_year        <= '0';
    micro_bcd_0      <= to_unsigned(0,4);
    micro_bcd_1      <= to_unsigned(9,4);
    micro_bcd_2      <= to_unsigned(9,4);
    micro_bcd_3      <= to_unsigned(9,4);
    micro_bcd_4      <= to_unsigned(9,4);
    micro_bcd_5      <= to_unsigned(9,4);
    hundredths       <= (others=>'0');
    tenths           <= (others=>'0');
    days_0           <= DEF_R_0(3 downto 0);
    days_1           <= DEF_R_0(7 downto 4);
    days_2           <= DEF_R_0(9 downto 8);
    years_0          <= DEF_R_0(19 downto 16);
    years_1          <= DEF_R_0(23 downto 20);
    secs_0           <= DEF_R_1(3 downto 0);
    secs_1           <= DEF_R_1(6 downto 4);
    mins_0           <= DEF_R_1(11 downto 8);
    mins_1           <= DEF_R_1(14 downto 12);
    hours_0          <= DEF_R_1(19 downto 16);
    hours_1          <= DEF_R_1(21 downto 20);
    control          <= DEF_R_3(12 downto 0) & DEF_R_2;
    reg_rate         <= DEF_R_4(2 downto 0);
    reg_carrier      <= DEF_R_5(2 downto 0);
    reg_codes        <= DEF_R_6(2 downto 0);
 
    p_count          <= (others=>'0');
    pulse_sr         <= (others=>'0');
    pulse_sr_count   <= (others=>'0');
    pulse_sub_count  <= (others=>'0');
    cycle_count      <= (others=>'0');
 
    fsm_ack          <= '0';
    hdyne_dds_sync   <= '0';
 
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
 
      -- Default values
      fsm_ack <= '0';
      hdyne_dds_sync <= '0';
 
      -- Use DDS to advance the six digit microsecond BCD counter.
      -- This can be overridden by other statements further below.
      if (tx_1mhz_pulse='1') then
        if (micro_bcd_0=9) then
          micro_bcd_0 <= (others=>'0');
          if (micro_bcd_1=9) then
            micro_bcd_1 <= (others=>'0');
            if (micro_bcd_2=9) then
              micro_bcd_2 <= (others=>'0');
              if (micro_bcd_3=9) then
                micro_bcd_3 <= (others=>'0');
                if (micro_bcd_4=9) then
                  micro_bcd_4 <= (others=>'0');
                  if (micro_bcd_5=9) then
                    micro_bcd_5 <= (others=>'0');
                  else
                    micro_bcd_5 <= micro_bcd_5+1;
                  end if;
                else
                  micro_bcd_4 <= micro_bcd_4+1;
                end if;
              else
                micro_bcd_3 <= micro_bcd_3+1;
              end if;
            else
              micro_bcd_2 <= micro_bcd_2+1;
            end if;
          else
            micro_bcd_1 <= micro_bcd_1+1;
          end if;
        else
          micro_bcd_0 <= micro_bcd_0+1;
        end if;
      end if;
      -- Handle timekeeping for fractions of seconds, based on 1MHz clock enable.
      -- These updates are overridden by pps, which resets all the time count values.
      if (tx_1mhz_pulse='1') then
        if (                  -- Check for .01 second transition
            micro_bcd_0=9 and
            micro_bcd_1=9 and
            micro_bcd_2=9 and
            micro_bcd_3=9
            ) then
          if (hundredths=9) then
            tenths <= tenths+1;
            hundredths <= (others=>'0');
            if (tenths=9) then
              -- No need to increment seconds here.  pps does that.
              tenths <= (others=>'0');
            else
              tenths <= tenths+1;
            end if;
          else
            hundredths <= hundredths+1;
          end if;
        end if;
      end if;
 
      -- Handle the timekeeping items, based on pps
      -- The highest priority is "set_time" which immediately resets all time
      -- quantities.  Next highest priority is normal timekeeping, and finally,
      -- the lowest priority is register writes to time quantities.
      if (set_time='1') then
        micro_bcd_0 <= (others=>'0');
        micro_bcd_1 <= (others=>'0');
        micro_bcd_2 <= (others=>'0');
        micro_bcd_3 <= (others=>'0');
        micro_bcd_4 <= (others=>'0');
        micro_bcd_5 <= (others=>'0');
        secs_0  <= rx_secs_0;
        secs_1  <= rx_secs_1;
        mins_0  <= rx_mins_0;
        mins_1  <= rx_mins_1;
        hours_0 <= rx_hours_0;
        hours_1 <= rx_hours_1;
        days_0  <= rx_days_0;
        days_1  <= rx_days_1;
        days_2  <= rx_days_2;
        years_0 <= rx_years_0;
        years_1 <= rx_years_1;
      elsif (pps='1') then
        secs_0 <= secs_0+1;
        tenths <= (others=>'0');
        hundredths <= (others=>'0');
        if (secs_0=9) then
          secs_1 <= secs_1+1;
          secs_0 <= (others=>'0');
          if (secs_1=5) then
            mins_0 <= mins_0+1;
            secs_1 <= (others=>'0');
            if (mins_0=9) then
              mins_1 <= mins_1+1;
              mins_0 <= (others=>'0');
              if (mins_1=5) then
                hours_0 <= hours_0+1;
                mins_1  <= (others=>'0');
                if (hours_1=2 and hours_0=3) then
                  days_0  <= days_0+1;
                  hours_1 <= (others=>'0');
                  hours_0 <= (others=>'0');
                  if (days_2>=3 and days_1>=6 and ((days_0>=5 and leap_year='0') or (days_0>=6 and leap_year='1'))) then
                    years_0 <= years_0+1;
                    days_0  <= "0001";
                    days_1  <= (others=>'0');
                    days_2  <= (others=>'0');
                    if (years_0=9) then
                      years_1 <= years_1+1;
                      years_0 <= (others=>'0');
                      if (years_1=9) then
                        years_1 <= (others=>'0');
                      end if;
                    end if;
                  elsif (days_0=9) then
                    days_1 <= days_1+1;
                    days_0 <= (others=>'0');
                    if (days_1=9) then
                      days_2 <= days_2+1;
                      days_1 <= (others=>'0');
                    end if;
                  end if;
                elsif (hours_0=9) then
                  hours_1 <= hours_1+1;
                  hours_0 <= (others=>'0');
                end if;
              end if;
            end if;
          end if;
        end if;
      elsif (sel_i='1' and we_i='1') then -- Handle bus writes to registers
      -- Cannot do this during pps, since this only writes one value, while
      -- pps timekeeping can potentially affect all the values.  Therefore,
      -- generate an acknowledge signal for the register writes... so that
      -- incoming bus cycles are extended when they collide with pps...
        fsm_ack <= '1';
        case (adr_i) is
          when "0000" =>
            leap_year <= dat_i(28);
            days_0  <= dat_i(3  downto 0);
            days_1  <= dat_i(7  downto 4);
            days_2  <= dat_i(9  downto 8);
            years_0 <= dat_i(19 downto 16);
            years_1 <= dat_i(23 downto 20);
          when "0001" =>
            secs_0  <= dat_i(3  downto 0);
            secs_1  <= dat_i(6  downto 4);
            mins_0  <= dat_i(11 downto 8);
            mins_1  <= dat_i(14 downto 12);
            hours_0 <= dat_i(19 downto 16);
            hours_1 <= dat_i(21 downto 20);
          when "0010" =>
            control(31 downto 0) <= dat_i;
          when "0011" =>
            control(44 downto 32) <= dat_i(12 downto 0);
          when "0100" =>
            reg_rate <= dat_i(2 downto 0);
          when "0101" =>
            reg_carrier <= dat_i(2 downto 0);
          when "0110" =>
            reg_codes <= dat_i(2 downto 0);
          when others => null;
        end case;
      end if;
 
      -- Handle pulse_sub_count
      if (pulse_clk_en='1') then
        if (sub_count_nine='1') then
          pulse_sub_count <= (others=>'0');
          hdyne_dds_sync <= '1'; -- Set the carrier wave phase.
        else
          pulse_sub_count <= pulse_sub_count + 1;
        end if;
      end if;
 
      -- Handle state transitions
      case (fsm_state) is
 
        when RESET =>
          fsm_state <= IDLE;
 
        when IDLE =>
          if (pps='1') then
            fsm_state <= P0_REF;
            p_count   <= (others=>'0');
            cycle_count <= (others=>'0');
            pulse_sr_count <= (others=>'0');
          end if;
 
        when P0_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            pulse_sr  <= sr_load_bus;
            if (irig_rate=4) then
              fsm_state <= P0_DOUT; -- No special reference pulse for IRIG 36-bit 
            else
              fsm_state <= PR_REF;
            end if;
          end if;
 
        when PR_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            fsm_state <= P0_DOUT;
          end if;
 
        when P0_DOUT =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            if (pulse_sr_count=9) then
              pulse_sr_count <= (others=>'0');
              p_count   <= p_count+1;
              fsm_state <= P1_PLUS_REF;
            else
              pulse_sr  <= '0' & pulse_sr(8 downto 1);
              pulse_sr_count <= pulse_sr_count+1;
            end if;
          end if;
 
        when P1_PLUS_REF =>
          if (pulse_clk_en = '1' and sub_count_nine='1') then
            pulse_sr_count <= pulse_sr_count+1;
            pulse_sr  <= sr_load_bus;
            fsm_state <= P1_PLUS_DOUT;
          end if;
 
        when P1_PLUS_DOUT =>
          if (p_count=9 and pps='1') then -- pps should not occur before p_count=9 anyway...
            fsm_state <= P0_REF;
            p_count   <= (others=>'0');
            cycle_count <= (others=>'0');
            pulse_sr_count <= (others=>'0');
          elsif (pulse_clk_en = '1' and sub_count_nine='1') then
            if (pulse_sr_count=9) then
              if (p_count=9) then
                if (cycle_count=99 and irig_rate=3) then
                  fsm_state <= IDLE;
                elsif (cycle_count=9 and irig_rate=2) then
                  fsm_state <= IDLE;
                elsif (irig_rate=0 or irig_rate=1 or irig_rate=4) then
                  fsm_state <= IDLE;
                else
                  cycle_count <= cycle_count+1;
                  p_count     <= (others=>'0');
                  pulse_sr_count <= (others=>'0');
                  fsm_state <= P0_REF;
                end if;
              else
                pulse_sr_count <= (others=>'0');
                p_count   <= p_count+1;
                pulse_sr  <= sr_load_bus;
                fsm_state <= P1_PLUS_REF;
              end if;
            else
              pulse_sr  <= '0' & pulse_sr(8 downto 1);
              pulse_sr_count <= pulse_sr_count+1;
            end if;
          end if;
 
        --when others => 
        --  fsm_state <= IDLE;
      end case;
 
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
 
  -- This pulse per second signal is for IRIG timecode generation
  pps <= '1' when (tx_1mhz_pulse='1' and
                    (
                     micro_bcd_0=9 and
                     micro_bcd_1=9 and
                     micro_bcd_2=9 and
                     micro_bcd_3=9 and
                     micro_bcd_4=9 and
                     micro_bcd_5=9
                     )
                   ) else '0';
 
  -- Create signal which indicates last portion of time generator pulse.
  sub_count_nine <= '1' when (pulse_sub_count=9) else '0';
 
  -- Form output pulses
  pulse_extent <= "0010" when (irig_rate=4 and pulse_sr_count=0 and p_count=0) else
                  "0101" when (irig_rate=4 and pulse_sr_count=0) else
                  "1000" when (pulse_sr_count=0 or fsm_state=PR_REF) else
                  "0101" when (pulse_sr(0)='1') else
                  "0010";
 
  time_pulses <= '1' when (pulse_sub_count<pulse_extent) else '0';
  time_dcl_o  <= time_pulses;
 
-- Related to time receiver
----------------------------
 
  --------------------------
  -- generate pulses at 1 MHz nominal rate.
  -- The term nominal is used here, because the actual rate can be "warped" up/down
  -- to track an external PPS reference.
  rx_mega_pulser : dds_squarewave
    generic map(
      ACC_BITS     => RX_1MHZ_DDS_BITS
    )
    port map(
 
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => sys_clk_en,
 
      -- Frequency setting
      freq_i       => rx_freq,
 
      -- Output
      pulse_o      => rx_1mhz_pulse,
      squarewave_o => open
    );
  tx_1mhz_pulse <= rx_1mhz_pulse;
 
  -- Create the frequency setting
  -- It is composed of two terms: the constant term for 1 MHz, and
  -- the fine adjustment term, for varying slightly above or below
  -- the constant value.  The varying term is "pps_residusum".
  rx_freq <= to_unsigned(PHASE_INCR_1MHZ,rx_freq'length) + unsigned(s_resize_se(pps_residusum,rx_freq'length));
 
 
  -- An input signal conditioner for low pass filtering the
  -- carrier squarewave clock signal
  signal_cleanup : multi_stage_leaky_integrator
    generic map(
      STAGES           =>  2,
      LEAK_FACTOR_BITS =>  5, -- Inversely related to LP corner frequency. (Min=1)
      HYSTERESIS_BITS  =>  8,
      INTEGRATOR_BITS  => time_cleaner_input'length
    )
    port map(
      -- System Clock and Clock Enable
      sys_rst_n   => sys_rst_n,
      sys_clk     => sys_clk,
      sys_clk_en  => sys_clk_en,
 
      -- Settings
      input       => time_cleaner_input,
      hysteresis  => str2u("10",8),
 
      -- Integration Result
      integrator  => open,
 
      -- Conditioned Digital Output Signal
      output      => time_cleaned
    );
  time_cleaner_input <= to_signed(64,time_cleaner_input'length) when time_cdet_i='1' else
                        to_signed(-64,time_cleaner_input'length);
 
  -- Select the appropriate time_rx signal
  time_rx <= time_cdet_i when reg_time_lp='0' else time_cleaned;
 
  -- Create IRIG time receiver state report signal
  with (rx_state) select
    rx_state_report <=
      "0011" when WAIT_ACTIVE,
      "0100" when SEEK_REF_1,
      "0101" when SEEK_REF_2,
      "0110" when RECEIVE_PULSES,
      "0111" when SETTLE_IN,
      "1000" when TRACK_IRIG,
      "1111" when others;
 
  -- Assert outputs when in the correct state
  rx_lock       <= '1' when rx_state=TRACK_IRIG else '0';
  lock_o        <= rx_lock;
  active_o      <= rx_active;
--  tracking_o    <= rx_irig_tracking when rx_state=TRACK_IRIG else rx_pps_tracking;
  tracking_o    <= rx_irig_tracking;
  neverlocked_o <= rx_neverlocked;
  cdet_sel_o    <= '1' when rx_state=SETTLE_IN or rx_state=TRACK_IRIG else cdet_sel_l;
 
  dac_clk1 : dds_clk_en_gen
    generic map(
      ACC_BITS  => 24
    )
    port map(
      -- Reset, System Clock and Clock Enable
      sys_rst_n    => sys_rst_n,
      sys_clk      => sys_clk,
      sys_clk_en   => sys_clk_en,
 
      -- Frequency setting
      freq_i       => str2u("001A37",24),
 
      -- Output
      clk_en_o     => cdet_dac_clk_en
    );
 
  dac1 : pwm_unsigned
  generic map(
    PERIOD     => 32,
    COUNT_BITS => 6
  )
  port map(
    -- Reset, System Clock and Clock Enable
    sys_rst_n    => sys_rst_n,
    sys_clk      => sys_clk,
    sys_clk_en   => cdet_dac_clk_en,
 
    -- Input Data
    dat_i        => cdet_bias,
 
    -- Output Signal
    dat_o        => cdet_sel_l
  );
 
  -- Create pulse that indicates the rising edge of receive data
  rx_posedge <= '1' when time_rx_r2='0' and time_rx_r1='1' else '0';
  -- Create pulse that indicates the start of a new timecode pulse
  -- (whether carrier modulated or DC level)
  rx_pstart <= '1' when rx_posedge='1' and rx_lo_count>RX_EDGE_VAL else '0';
 
  -- Select the rx_scale_factor based on carrier detect value
  with (to_integer(cdet_val_l)) select
    rx_scale_factor <=
      to_unsigned(1,rx_scale_factor'length)   when 3,
      to_unsigned(10,rx_scale_factor'length)  when 2,
      to_unsigned(100,rx_scale_factor'length) when 1,
      to_unsigned(100,rx_scale_factor'length) when others;
  -- Provide cdet_val_l as an output signal
  cdet_val_o <= cdet_val_l;
 
-- This is the IRIG timecode receive process
-- It handles updates to the receive time values
rx_proc: process(sys_clk, sys_rst_n)
begin
  if (sys_rst_n='0') then
    rx_state         <= WAIT_ACTIVE;
    rx_nasa36        <= '0';
    rx_pulse_count   <= (others=>'0');
    rx_group_count   <= (others=>'0');
    time_rx_r1       <= '0';
    time_rx_r2       <= '0';
    rx_raise_count   <= (others=>'0');
    rx_active_count  <= (others=>'0');
    rx_active_wdog   <= (others=>'0');
    rx_hi_count      <= (others=>'0');
    rx_lo_count      <= (others=>'0');
    rx_pulse_width   <= (others=>'0');
    pps_r1           <= '0';
    pps_r2           <= '0';
    rx_sr            <= (others=>'0');
    rx_c_count       <= (others=>'0');
    pps_r_count      <= to_signed(PPS_R_COUNT_SEED,pps_r_count'length);
    pps_residusum    <= (others=>'0');
    rx_secs_0        <= (others=>'0');
    rx_secs_1        <= (others=>'0');
    rx_mins_0        <= (others=>'0');
    rx_mins_1        <= (others=>'0');
    rx_hours_0       <= (others=>'0');
    rx_hours_1       <= (others=>'0');
    rx_days_0        <= (others=>'0');
    rx_days_1        <= (others=>'0');
    rx_days_2        <= (others=>'0');
    rx_years_0       <= (others=>'0');
    rx_years_1       <= (others=>'0');
    rx_active        <= '0';
    rx_pps_tracking  <= '0';
    rx_irig_tracking <= '0';
    rx_neverlocked   <= '1';
    cdet_fixed       <= '0';
    cdet_ms_timer    <= (others=>'0');
    cdet_val_l       <= (others=>'0');
    rx_scale_count   <= to_unsigned(1,rx_scale_count'length);
    cdet_bias        <= DEF_R_A(cdet_bias'length-1 downto 0);
    reg_time_lp      <= DEF_R_A(8);
    set_time         <= '0';
    rx_stat_1        <= (others=>'0');
    rx_stat_2        <= (others=>'0');
    rx_stat_3        <= (others=>'0');
 
  elsif (sys_clk'event and sys_clk='1') then
    if (sys_clk_en='1') then
 
      -- Default values
      set_time <= '0'; -- pulses high to set the IRIG generator time
 
      -- Handle carrier detect millisecond timer
      -- Used to time the settling period when cdet_sel_o is changed
      if (pulse_1ms='1') then
        cdet_ms_timer <= cdet_ms_timer+1;
      end if;
 
      -- Service residual counter
      if (rx_1mhz_pulse='1') then
        pps_r_count <= pps_r_count-1;
      end if;
 
      -- Capture incoming carrier pulses
      if (rx_1mhz_pulse='1') then
        time_rx_r1 <= time_rx;
      end if;
      time_rx_r2 <= time_rx_r1;
 
      -- Apply selected scale factor to produce 1 MHz, 100 kHz or 10 kHz rx_sample pulses
      -- rx_posedge is used to synchronize the sample pulse to each new rising edge of
      -- the rx line.
      if (rx_1mhz_pulse='1' and rx_scale_count=1) or rx_posedge='1' then
        rx_scale_count <= rx_scale_factor;
      elsif (rx_1mhz_pulse='1') then
        rx_scale_count <= rx_scale_count-1;
      end if;
 
      -- An up-counter that advances each sample time, but resets when
      -- the rx line is high... rx_lo_count is to be thresholded for data detection.
      -- Keeping rx_lo_count reset when the receive line is high enables
      -- reception of "dc level" irig time data as well as the
      -- "gated carrier pulse" data from the demodulator circuit.      
      if (time_rx_r2='1') then
        rx_lo_count <= (others=>'0');
      elsif (rx_1mhz_pulse='1' and rx_scale_count=1) then
        if (rx_lo_count<255) then -- Do not let counter roll over.
          rx_lo_count <= rx_lo_count+1;
        end if;
      end if;
      -- Capture the pulse width for reporting purposes only.
      if (rx_pstart='1') then
        rx_pulse_width <= rx_lo_count;
      end if;
 
      -- Handle receive shift register
      if (rx_pstart='1') then
        if (rx_lo_count > RX_ZERO_VAL) then
          rx_sr(rx_sr'length-2 downto 0) <= rx_sr(rx_sr'length-1 downto 1);
          rx_sr(rx_sr'length-1) <= '0';
        else
          rx_sr(rx_sr'length-2 downto 0) <= rx_sr(rx_sr'length-1 downto 1);
          rx_sr(rx_sr'length-1) <= '1';
        end if;
      end if;
 
      -- Detect timecode activity here, by examining the rx_lo_count, and
      -- adjusting the sample rate to seek a sensible input signal.
      -- 1) If, at rx_posedge, rx_lo_count>RX_TOO_SHORT even once select a 
      --   lower sample rate.
      -- 2) If, at rx_posedge, rx_lo_count<RX_EDGE_COUNT 10 times in a row,
      --   select a higher sample rate.
      -- 3) Require a duty cycle between 10% and 80%
      -- 4) Once locked, require rx_posedge activity during an N sample
      --      interval.
      -- If, at rx_pstart, all the above conditions are met ten
      --   times in a row, then the input signal and sample rate are
      --   considered correct, and an input "active" condition is declared.
      -- The "active" condition is rescinded if any of the conditions
      --   are not met, at any time.
      if (rx_1mhz_pulse='1' and rx_scale_count=1 and time_rx_r2='1') then
        if (rx_hi_count<((2**rx_hi_count'length)-1)) then -- Do not let counter roll over.
          rx_hi_count <= rx_hi_count+1;
        end if;
      end if;
      -- Count number of times all conditions are met
      if (rx_pstart='1') then
        rx_hi_count <= (others=>'0');
        if (rx_active='0' and rx_hi_count>9 and rx_hi_count<81) then
          rx_active_count <= rx_active_count+1;
          rx_raise_count <= (others=>'0');
          if (rx_active_count=9) then
            rx_active <= '1';
            if (cdet_fixed='0' and cdet_val_l=0) then
              cdet_val_l <= cdet_val_l+1;
            end if;
          end if;
        end if;
      end if;
      -- Handle sample rate adjustments automatically, until a successful
      -- reception of all pulse groups is achieved. Thereafter, only lose
      -- lock due to watchdog.
      if (rx_posedge='1' and not (rx_state=SETTLE_IN or rx_state=TRACK_IRIG)) then
        if (rx_lo_count>RX_TOO_SHORT) then
          rx_active_count <= (others=>'0');
          rx_active <= '0';
          rx_stat_1 <= rx_stat_1+1;
          rx_pulse_width <= to_unsigned(16#AB#,rx_pulse_width'length);
          if (cdet_fixed='0' and cdet_val_l>0) then
            cdet_val_l <= cdet_val_l-1; -- Lower the sample rate
          end if;
        elsif (rx_lo_count<3) then
          rx_raise_count <= rx_raise_count+1;
          rx_active_count <= (others=>'0');
          rx_active <= '0';
          rx_stat_2 <= rx_stat_2+1;
          rx_pulse_width <= to_unsigned(16#AA#,rx_pulse_width'length);
          if (rx_raise_count=9) then
            rx_raise_count <= (others=>'0');
            if (cdet_fixed='0' and cdet_val_l<3) then
              cdet_val_l <= cdet_val_l+1; -- Raise the sample rate
            end if;
          end if;
        end if;
      end if;
      -- Handle activity watchdog
      if (rx_posedge='1') then
        rx_active_wdog <= (others=>'0'); -- reset activity watchdog
      end if;
      if (rx_1mhz_pulse='1' and rx_scale_count=1) then
        rx_active_wdog <= rx_active_wdog+1;
        if (rx_active='1' and rx_active_wdog=200) then
          cdet_val_l <= (others=>'0');
          rx_nasa36  <= '0';
          rx_active_count <= (others=>'0');
          rx_active <= '0';
          rx_stat_3 <= rx_stat_3+1;
        end if;
      end if;
 
      -- Handle state transitions
      case (rx_state) is
 
        when WAIT_ACTIVE =>
          if (rx_active='1') then
            rx_state <= SEEK_REF_1;
          end if;
 
        when SEEK_REF_1 =>
          if (rx_pstart='1') then
            if (rx_sr="0111110000") then
              rx_pulse_count <= to_unsigned(0,rx_pulse_count'length);
              rx_group_count <= to_unsigned(0,rx_group_count'length);
              rx_state  <= RECEIVE_PULSES;
              rx_nasa36 <= '1';
            elsif (rx_lo_count<=RX_ONE_VAL) then
              rx_state  <= SEEK_REF_2;
            end if;
          end if;
 
        when SEEK_REF_2 =>
          if (rx_pstart='1') then
            if (rx_lo_count<=RX_ONE_VAL) then
              rx_pulse_count <= to_unsigned(0,rx_pulse_count'length);
              rx_group_count <= to_unsigned(0,rx_group_count'length);
              rx_state <= RECEIVE_PULSES;
            else
              rx_state <= SEEK_REF_1;
            end if;
          end if;
 
        when RECEIVE_PULSES =>
          if (rx_pstart='1') then
            -- Service the pulse, group and frame counters
            -- Must obtain "group lock" before using received data
            rx_pulse_count <= rx_pulse_count+1;  -- default action
            if (rx_pulse_count=9) then
              rx_pulse_count <= (others=>'0');
              rx_group_count <= rx_group_count+1; -- Default is to advance the count.
              if (rx_group_count=9) then
                rx_group_count <= (others=>'0');
                cdet_ms_timer  <= (others=>'0');
                rx_state <= SETTLE_IN; -- At the end of the full reading, move on
                rx_neverlocked <= '0';
                set_time <= '1';
              end if;
              -- Initialize the time fields as they are received...
              case (to_integer(rx_group_count)) is
                when 0 =>
                  if (rx_sr(4 downto 1)<9) then
                    rx_secs_0 <= rx_sr(4 downto 1)+1;
                  else
                    rx_state <= SEEK_REF_1; -- Adding one during rollover case is too hard.  Just try again later.
                  end if;
                  if (rx_nasa36='0') then
                    rx_secs_1 <= rx_sr(8 downto 6);
                  end if;
                when 1 =>
                  if (rx_nasa36='0') then
                    rx_mins_0 <= rx_sr(3 downto 0);
                    rx_mins_1 <= rx_sr(7 downto 5);
                  else
                    rx_secs_1 <= rx_sr(2 downto 0);
                  end if;
                when 2 =>
                  if (rx_nasa36='0') then
                    rx_hours_0 <= rx_sr(3 downto 0);
                    rx_hours_1 <= rx_sr(6 downto 5);
                  else
                    rx_mins_0 <= rx_sr(3 downto 0);
                  end if;
                when 3 =>
                  if (rx_nasa36='0') then
                    rx_days_0 <= rx_sr(3 downto 0);
                    rx_days_1 <= rx_sr(8 downto 5);
                  else
                    rx_mins_1 <= rx_sr(2 downto 0);
                  end if;
                when 4 =>
                  if (rx_nasa36='0') then
                    rx_days_2 <= rx_sr(1 downto 0);
                  else
                    rx_hours_0 <= rx_sr(3 downto 0);
                  end if;
                when 5 =>
                  if (cdet_val_l/=3) then
                    rx_years_0 <= rx_sr(3 downto 0);
                    rx_years_1 <= rx_sr(8 downto 5);
                  end if;
                  if (rx_nasa36='1') then
                    rx_hours_1 <= rx_sr(1 downto 0);
                  end if;
                when 6 =>
                  if (cdet_val_l=3) then
                    rx_years_0 <= rx_sr(3 downto 0);
                    rx_years_1 <= rx_sr(8 downto 5);
                  end if;
                  if (rx_nasa36='1') then
                    rx_days_0 <= rx_sr(3 downto 0);
                  end if;
                when 7 =>
                  if (rx_nasa36='1') then
                    rx_days_1 <= rx_sr(3 downto 0);
                  end if;
                when 8 =>
                  if (rx_nasa36='1') then
                    rx_days_2 <= rx_sr(1 downto 0);
                  end if;
                when 9 =>
                  null;
                when others =>
                  null;
              end case;
            end if;
          end if; -- if rx_pstart
 
        -- Spend some time waiting for the demodulator circuit to settle.
        -- There are capacitors in it which need to discharge before it works
        -- following a switching event.
        when SETTLE_IN =>
          if (cdet_ms_timer=CDET_SETTLE_TIME) then
            rx_state <= TRACK_IRIG;
            case (to_integer(cdet_val_l)) is
              when 3 =>
                rx_c_count <= to_unsigned(RX_C_SEED_G,rx_c_count'length);
              when 2 =>
                rx_c_count <= to_unsigned(RX_C_SEED_A,rx_c_count'length);
              when 1 =>
                rx_c_count <= to_unsigned(RX_C_SEED_B,rx_c_count'length);
              when others =>
                rx_c_count <= to_unsigned(RX_C_SEED_B,rx_c_count'length);
            end case;
          end if;
 
        when TRACK_IRIG => -- Tracking on received IRIG time signal based PPS
          -- Service carrier pulse countdown.
          -- Counter is reloaded by statements below.
          if (rx_posedge='1') then
            if (rx_c_count=1) then
              case (to_integer(cdet_val_l)) is
                when 3 =>
                  rx_c_count <= to_unsigned(RX_C_SEED_G,rx_c_count'length);
                when 2 =>
                  rx_c_count <= to_unsigned(RX_C_SEED_A,rx_c_count'length);
                when 1 =>
                  rx_c_count <= to_unsigned(RX_C_SEED_B,rx_c_count'length);
                when others =>
                  rx_c_count <= to_unsigned(RX_C_SEED_B,rx_c_count'length);
              end case;
              -- Service time tracking counters
              pps_r_count  <= to_signed(PPS_R_COUNT_SEED,pps_r_count'length);
              if (abs(pps_r_count) > PPS_TRACK_LIMIT) then
                rx_irig_tracking <= '0';
              else
                pps_residusum <= pps_residusum + s_resize_se(s_resize_l(pps_r_count,pps_r_count'length-1),pps_residusum'length); -- divide by two
                rx_irig_tracking <= '1';
              end if;
            else
              rx_c_count <= rx_c_count-1;
            end if;
          end if;
 
        --when others => 
        --  fsm_state <= IDLE;
      end case;
 
      -- Restart acquisition if there is no incoming activity
      -- It is not helpful to increment the stats counter for this...
      if (rx_state/=WAIT_ACTIVE and rx_active='0') then
        pps_r_count  <= to_signed(PPS_R_COUNT_SEED,pps_r_count'length);
        rx_irig_tracking <= '0';
        cdet_ms_timer    <= (others=>'0');
        cdet_val_l <= (others=>'0');
        rx_state <= WAIT_ACTIVE;
      end if;
 
      -- Metastability mitigation chain.
      -- Also used to detect rising edge of pps_i
      pps_r1 <= pps_i;
      pps_r2 <= pps_r1;
 
      -- When not tracking IRIG input, track PPS input if present
      if (rx_state/=TRACK_IRIG and pps_r2='0' and pps_r1='1') then
        if (abs(pps_r_count) > PPS_TRACK_LIMIT) then
          rx_pps_tracking <= '0';
        else
          pps_r_count  <= to_signed(PPS_R_COUNT_SEED,pps_r_count'length);
          pps_residusum <= pps_residusum + s_resize_se(s_resize_l(pps_r_count,pps_r_count'length-1),pps_residusum'length); -- divide by two
          rx_pps_tracking <= '1';
        end if;
      end if;
 
      -- Reset stats registers
      if (sel_i='1' and we_i='1' and ack_l='1') then -- Handle bus writes to registers
        if (adr_i=7) then
          cdet_fixed <= dat_i(10);
          if (cdet_fixed='1') then
            rx_nasa36  <= dat_i(9);
            cdet_val_l <= dat_i(cdet_val_l'length-1 downto 0);
          end if;
        end if;
        if (adr_i=8) then
          rx_stat_1 <= (others=>'0');
          rx_stat_2 <= (others=>'0');
          rx_stat_3 <= (others=>'0');
        end if;
        if (adr_i=10) then
          cdet_bias <= dat_i(cdet_bias'length-1 downto 0);
          reg_time_lp <= dat_i(8);
        end if;
      end if;
 
    end if; -- sys_clk_en
  end if; -- sys_clk
end process;
 
-- A pulse that occurs once every millisecond, based on transmit signals.
pulse_1ms <= '1' when (micro_bcd_0=9 and micro_bcd_1=9 and micro_bcd_2=9 and micro_bcd_3=9 and tx_1mhz_pulse='1') else '0';
 
end beh;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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