LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;


-- This is the VHDL code that describes the logic for the
-- DDS & vacuum fluorescent display module controller that
-- is detailed in the QEX magazine article "Modern Digital
-- Design for the Radio Amateur".

-- Written by John Wiseman - KE3QG.
-- Last updated - June 1997.

-- This VHDL code was synthesized with the Synopsys FPGA
-- Analyzer, then compiled with the Altera Maxplus2 software.
-- The resulting circuit was implemented on an Altera 81500
-- FPGA chip and is presently being used successfully in a
-- homebrew transceiver design.


ENTITY qex IS

  -- Generics for the design are defined here.  The value
  -- of Max_Integer_Count gives a delay of (8 x 32768) x
  -- 1 microsecond = 0.26 second.  Shift_Register_End is
  -- determined by taking the number of potential shift
  -- register states and subtracting 1.  This means that
  -- 22 potential set-up and character bytes (note - not
  -- all of the set-up bytes are actually needed) times
  -- 8 bits/byte = 176.  Max_Timer_Count should be equal
  -- to Max_Integer_Count - 2.  
  
  GENERIC (Max_Integer_Count:   INTEGER := 32767;
           Max_Timer_Count:     INTEGER := 32765;
           Shift_Register_End:  INTEGER := 175
          );
          
  -- Input and output ports for the design are defined here.
  -- Type BIT is used for inputs to remain compatible with the
  -- READ function within the VHDL testbench.
  
  -- Clock is connected to a 1.0 MHz. crystal oscillator.
  -- Reset is pulled high with a 1K ohm resister.
  -- Fine_Tuning defines the tuning resolution from the front panel.
  -- Up increments the DDS & display from a front panel pushbutton.
  -- Down decrements the DDS & display from a front panel pushbutton.
  
  -- DDS_Strobe mimmick the 4 control lines on a parallel port.
  -- DDS_Data_Output sends 8-bit data over the parallel port.
  
  -- Serial_Data_Output sends serial data to the display module.
  -- Serial_Clock_Output sends the serial clock to the display module.
  -- CS_Output sends the chip select to the display module.
  
  -- Timer_Output is for simulation/testing only, and may be deleted.
  
  PORT (Clock:                  IN  BIT;
        Reset:                  IN  BIT;
        Fine_Tuning:            IN  BIT;
        Up:                     IN  BIT;
        Down:                   IN  BIT;
        DDS_Strobe:             OUT BIT_VECTOR (0 TO 3);
        Timer_Output:           OUT BIT;
        DDS_Data_Out:           OUT UNSIGNED (7 DOWNTO 0);
        Serial_Data_Output:     OUT STD_LOGIC;
        Serial_Clock_Output:    OUT BIT;
        CS_Output:              OUT BIT
        );
        
END qex;



ARCHITECTURE test1 OF qex IS

  -- Constants are defined here.
  
  -- Note - It is nice to use UNSIGNED values for characters, as
  -- concatenation is easy later on when it is necessary to load
  -- the 175 bit shift register.
  
  -- Note - Some values are given for an 80 meter implementation
  -- as well as for the presently used 40 meter version. Of course
  -- any other values may be implemented as well... 
  
  CONSTANT Display_Length_Byte:     UNSIGNED := "00000111";
  CONSTANT Scan_Time_Byte:          UNSIGNED := "11110110";
  CONSTANT Luminance_Level_Byte:    UNSIGNED := "00001111";
  CONSTANT Character_Position_Byte: UNSIGNED := "11100000";
  CONSTANT Auto_Incr_Mode_Byte:     UNSIGNED := "11110101";
  CONSTANT Display_Mode_Byte:       UNSIGNED := "11110001";
  CONSTANT Character_Zero:          UNSIGNED := "00110000";
  CONSTANT Character_Four:          UNSIGNED := "00110100";
  CONSTANT Character_Five:          UNSIGNED := "00110101";
  CONSTANT Character_Seven:         UNSIGNED := "00110111";
  CONSTANT Character_Eight:         UNSIGNED := "00111000";
  CONSTANT Character_H:             UNSIGNED := "01001000";
  CONSTANT Character_M:             UNSIGNED := "01001101";
  CONSTANT Character_z:             UNSIGNED := "01111010";
  CONSTANT Character_Blank:         UNSIGNED := "00100000";
  CONSTANT Character_Comma:         UNSIGNED := "00101100";
  CONSTANT Character_Enable:        UNSIGNED := "0011";
  CONSTANT Fine_Tuning_Offset:      UNSIGNED := 
"000000000000000000001010";
  CONSTANT Coarse_Tuning_Offset:    UNSIGNED := 
"000000000000001111101000";
--80M parameters:
--CONSTANT Tx_Reset_Freq:           UNSIGNED := 
"001110000111010100100000";
--CONSTANT Rx_Reset_Freq:           UNSIGNED := 
"100000110111011010110000";
--40M parameters:
  CONSTANT Tx_Reset_Freq:           UNSIGNED := 
"011010111001001100010000";
  CONSTANT Rx_Reset_Freq:           UNSIGNED := 
"001000001001000110000000";

  -- Types are defined here.
  
  TYPE States_Enum_Type IS (State0, State1, State2, State3, State4, 
State5,
                            State6, State7, State8, State9, State10, 
State11,
                            State12, State13, State14, State15, State16,
                            State17
                           );
                           
  -- Internal signals are defined here.    
                       
  SIGNAL Current_State:           States_Enum_Type;
  SIGNAL Next_State:              States_Enum_Type;                      
     
  SIGNAL DDS_Data_Counter_Rx:     UNSIGNED (23 DOWNTO 0);
  SIGNAL DDS_Data_Counter_Tx:     UNSIGNED (23 DOWNTO 0);
  SIGNAL Cycle_Enable:            BIT;
  SIGNAL Timer_Count:             INTEGER RANGE 0 TO Max_Integer_Count;
  SIGNAL Timer_Count_Int:         INTEGER RANGE 0 TO Max_Integer_Count;
  SIGNAL Timer_Preind:            BIT;
  SIGNAL Timer_Ind_Int:           BIT;
  SIGNAL Up_Int:                  BIT;
  SIGNAL Up_Int_Secon:            BIT;
  SIGNAL Up_Int_Single:           BIT;
  SIGNAL Up_Del:                  BIT;
  SIGNAL Down_Int:                BIT;
  SIGNAL Down_Int_Secon:          BIT;
  SIGNAL Down_Int_Single:         BIT;
  SIGNAL Down_Del:                BIT;
  SIGNAL Data_Mux_En:             BIT_VECTOR (0 TO 2);
  SIGNAL Fine_Tuning_Int:         BIT;
  SIGNAL Ones:                    UNSIGNED (3 DOWNTO 0);
  SIGNAL Tens:                    UNSIGNED (3 DOWNTO 0);
  SIGNAL Hundreds:                UNSIGNED (3 DOWNTO 0);
  SIGNAL Thousands:               UNSIGNED (3 DOWNTO 0);
  SIGNAL Ten_Thousands:           UNSIGNED (3 DOWNTO 0);
  SIGNAL Hundred_Thousands:       UNSIGNED (3 DOWNTO 0);
  SIGNAL Millions:                UNSIGNED (3 DOWNTO 0);
  SIGNAL Serial_Register:         UNSIGNED (175 DOWNTO 0);
  SIGNAL Reset_Del:               BIT;
  SIGNAL Reset_Del_1:             BIT;
  SIGNAL Init_Signal:             BIT;
  SIGNAL Serial_Clock_Preout:     BIT;
  SIGNAL Serial_Data_Preout:      STD_LOGIC;
  SIGNAL Serial_Data_Del:         STD_LOGIC;
  SIGNAL Serial_Data_Del_2:       STD_LOGIC;
  SIGNAL Cycle_Over:              BIT;
  SIGNAL Serial_Clock_Enable:     BIT;
  SIGNAL Serial_Clock_Enable_Del: BIT;
  SIGNAL Output_Strobe:           BIT_VECTOR (0 TO 3);
  SIGNAL Timer_Count_Clock:       BIT;
  SIGNAL Reset_Int:               BIT;
  SIGNAL Chip_Select_Mod:         BIT;
  SIGNAL Clock_Div:               BIT;
  SIGNAL Clock_Div_Int:           BIT;
  
  
  

BEGIN

  Main_Clock_Divider_1:
  PROCESS(Clock)
  BEGIN
  
  -- This process divides the clock oscillator by 2 for the chip.
  
    IF Clock = '1' AND Clock'EVENT THEN
      Clock_Div_Int <= NOT Clock_Div_Int;
    END IF;
    
  END PROCESS Main_Clock_Divider_1;
  
  
  
  Main_Clock_Divider_2:
  PROCESS(Clock_Div_Int)
  BEGIN
  
  -- This process divides the clock oscillator by 4 for the chip.
  -- It was necessary to add this process to compensate for an
  -- error in the Futaba display data sheet (MINIMUM time between
  -- data words must be 20 microseconds, not MAXIMUM time as stated).
  
    IF Clock_Div_Int = '1' AND Clock_Div_Int'EVENT THEN
      Clock_Div <= NOT Clock_Div;
    END IF;
    
  END PROCESS Main_Clock_Divider_2;
      
    

  Serial_Clock_Divider:
  PROCESS(Clock_Div)
  BEGIN
  
  -- This process produces a divide-by-2 clock for the serial section.
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Serial_Clock_Enable = '0' OR Reset_Int = '0' THEN
        Serial_Clock_Preout <= '1';
      ELSE
        Serial_Clock_Preout <= NOT Serial_Clock_Preout;
      END IF;
    END IF;
    
  END PROCESS Serial_Clock_Divider;
  
  
  
  Timer_Count_Clock_Divider:
  PROCESS(Clock_Div)
  
  -- This process divides Clock_Div by 2 to produce Timer_Count_Clock.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int /= '0' THEN
        Timer_Count_Clock <= NOT Timer_Count_Clock;
      END IF;
    END IF;
    
  END PROCESS Timer_Count_Clock_Divider;
  
  
  
  Control_Signal_Delay:
  PROCESS(Clock_Div)
  
  -- This process latches the incoming Reset, Fine_Tuning, Up, 
  -- and Down signals.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      Reset_Int <= Reset;
      Fine_Tuning_Int <= Fine_Tuning;
      Up_Del <= NOT Up;
      Down_Del <= NOT Down;
    END IF;
    
  END PROCESS Control_Signal_Delay;
      
          
  
  Serial_Clock_Data_Alignment:
  PROCESS(Clock_Div)
  
  -- This process syncs the 3 serial output control lines 
  -- Serial_Clock_Output, Serial_Data_Output, and CS_Output 
  -- with Clock_Div to eliminate glitches.
  
    BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      Serial_Clock_Output <= Serial_Clock_Preout;
      Serial_Data_Del <= Serial_Data_Preout;
      Serial_Data_Del_2 <= Serial_Data_Del;
      Serial_Data_Output <= Serial_Data_Del_2;
      Serial_Clock_Enable_Del <= NOT Chip_Select_Mod;
      CS_Output <= Serial_Clock_Enable_Del;
    END IF;
    
  END PROCESS Serial_Clock_Data_Alignment;
  
  

  Initialization:
  PROCESS(Clock_Div, Reset_Int, Reset_Del_1)
  
  -- This process produces a single pulse, Init_Signal, which is 
  -- used to trigger the initial system outputs following a reset.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      Reset_Del <= Reset_Int;
      Reset_Del_1 <= Reset_Del;
    END IF;
    Init_Signal <= Reset_Int XOR Reset_Del_1;
    
  END PROCESS Initialization;
  
  

  Parallel_To_Serial_Conversion:
  PROCESS(Clock_Div)
  
  -- This process defines the parallel-to-serial shift register
  -- used to serially communicate with the display.  The reset
  -- value is 7,050,000 Hz 40M.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Serial_Register <= (Luminance_Level_Byte & 
                            Display_Length_Byte &
                            Scan_Time_Byte &
                            Display_Mode_Byte &
                            Character_Position_Byte &
                            Auto_Incr_Mode_Byte & 
                            Character_Seven &  -- Change to _Three for 
80M
                            Character_Comma & 
                            Character_Zero &   -- Change to _Seven for 
80M
                            Character_Five &   -- Change to _Zero for 
80M
                            Character_Zero & 
                            Character_Comma &
                            Character_Zero & 
                            Character_Zero & 
                            Character_Zero & 
                            Character_Blank & 
                            Character_H &
                            Character_z & 
                            Character_Blank & 
                            Character_Four &
                            Character_Zero & 
                            Character_M
                            );
        Serial_Clock_Enable <= '0';
      ELSIF (Reset_Int = '1' AND Timer_Count_Int = 2) AND 
             Timer_Count_Clock = '1' THEN
        Serial_Register <= (Luminance_Level_Byte & 
                            Display_Length_Byte &
                            Scan_Time_Byte &
                            Display_Mode_Byte &
                            Character_Position_Byte &
                            Auto_Incr_Mode_Byte &  
                            Character_Enable & Millions & 
                            Character_Comma &
                            Character_Enable & Hundred_Thousands & 
                            Character_Enable & Ten_Thousands & 
                            Character_Enable & Thousands & 
                            Character_Comma &
                            Character_Enable & Hundreds & 
                            Character_Enable & Tens & 
                            Character_Enable & Ones &
                            Character_Blank & 
                            Character_H & 
                            Character_z & 
                            Character_Blank &
                            Character_Four & 
                            Character_Zero & 
                            Character_M
                           );
        Serial_Clock_Enable <= '0';
      ELSIF (((((((((((((((((((((((((((((((((((((((((((
                Timer_Count_Int > 2 AND Timer_Count_Int < 221) AND
              Timer_Count_Int /= 11) AND Timer_Count_Int /= 21) AND
              Timer_Count_Int /= 31) AND Timer_Count_Int /= 41) AND
              Timer_Count_Int /= 51) AND Timer_Count_Int /= 61) AND
              Timer_Count_Int /= 71) AND Timer_Count_Int /= 81) AND
              Timer_Count_Int /= 91) AND Timer_Count_Int /= 101) AND
              Timer_Count_Int /= 111) AND Timer_Count_Int /= 121) 
AND              
              Timer_Count_Int /= 131) AND Timer_Count_Int /= 141) 
AND
              Timer_Count_Int /= 151) AND Timer_Count_Int /= 161) 
AND
              Timer_Count_Int /= 171) AND Timer_Count_Int /= 181) 
AND
              Timer_Count_Int /= 191) AND Timer_Count_Int /= 201) 
AND
              Timer_Count_Int /= 211) AND              
              Timer_Count_Int /= 12) AND Timer_Count_Int /= 22) AND
              Timer_Count_Int /= 32) AND Timer_Count_Int /= 42) AND
              Timer_Count_Int /= 52) AND Timer_Count_Int /= 62) AND
              Timer_Count_Int /= 72) AND Timer_Count_Int /= 82) AND
              Timer_Count_Int /= 92) AND Timer_Count_Int /= 102) AND
              Timer_Count_Int /= 112) AND Timer_Count_Int /= 122) 
AND              
              Timer_Count_Int /= 132) AND Timer_Count_Int /= 142) 
AND
              Timer_Count_Int /= 152) AND Timer_Count_Int /= 162) 
AND
              Timer_Count_Int /= 172) AND Timer_Count_Int /= 182) 
AND
              Timer_Count_Int /= 192) AND Timer_Count_Int /= 202) 
AND
              Timer_Count_Int /= 212) THEN
        Serial_Clock_Enable <= '1';
        IF Timer_Count_Clock = '1' THEN
          Serial_Register <= SHL(Serial_Register, "1");
        END IF;
      ELSE
        Serial_Clock_Enable <= '0';
      END IF;
      Serial_Data_Preout <= Serial_Register(175);     
    END IF;
    
  END PROCESS Parallel_To_Serial_Conversion;
  
  
  
  Chip_Select_Modification:
  PROCESS(Clock_Div)
  
  -- This process modifies the Chip Select output so that it does not
  -- toggle between transmitted bytes.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Chip_Select_Mod <= '0'; 
	  ELSIF 
	    (Timer_Count_Int > 2 AND Timer_Count_Int < 11) OR
        (Timer_Count_Int > 32 AND Timer_Count_Int < 41) OR
        (Timer_Count_Int > 62 AND Timer_Count_Int < 221) THEN
	      Chip_Select_Mod <= '1';
	  ELSE
	    Chip_Select_Mod <= '0';
	  END IF;
	END IF;
	
  END PROCESS Chip_Select_Modification;
	  
	  
  
  Display_Calculator_Clock_Generator:
  PROCESS(Clock_Div)
  
  -- This process defines the counting procedure, up and down, for the 
  -- display values.  If the Fine_Tuning input is high, then the count 
  -- is plus or minus 10, if Fine_Tuning is low, then the count is plus 
  -- or minus 1000.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Ones <= "0000";
        Tens <= "0000";
        Hundreds <= "0000";
        Thousands <= "0000";
        Ten_Thousands <= "0101";
        Hundred_Thousands <= "0000";
        Millions <= "0111";
      ELSIF Reset_Int = '1' THEN
        IF (Up_Int_Single = '1' AND Timer_Preind = '0') AND 
            Fine_Tuning_Int = '1' THEN
          IF Tens < 9 THEN
            Tens <= Tens + 1;
          ELSE
            Tens <= "0000";
            IF Hundreds < 9 THEN
              Hundreds <= Hundreds + 1;
            ELSE
              Hundreds <= "0000";
              IF Thousands < 9 THEN
                Thousands <= Thousands + 1;
              ELSE
                Thousands <= "0000";
                IF Ten_Thousands < 9 THEN
                  Ten_Thousands <= Ten_Thousands + 1;
                ELSE
                  Ten_Thousands <= "0000";
                  IF Hundred_Thousands < 9 THEN
                    Hundred_Thousands <= Hundred_Thousands + 1;
                  ELSE
                    Hundred_Thousands <= "0000";
                    IF Millions < 9 THEN
                      Millions <= Millions + 1;
                    END IF;
                  END IF;
                END IF;
              END IF;
            END IF;
          END IF;
        ELSIF (Down_Int_Single = '1' AND Timer_Preind = '0') AND 
               Fine_Tuning_Int = '1' THEN
          IF Tens > 0 THEN
            Tens <= Tens - 1;
          ELSE
            Tens <= "1001";
            IF Hundreds > 0 THEN
             Hundreds <= Hundreds - 1;
             ELSE
               Hundreds <= "1001";
               IF Thousands > 0 THEN
                 Thousands <= Thousands - 1;
               ELSE
                 Thousands <= "1001";
                 IF Ten_Thousands > 0 THEN
                   Ten_Thousands <= Ten_Thousands - 1;
                 ELSE
                   Ten_Thousands <= "1001";
                   IF Hundred_Thousands > 0 THEN
                     Hundred_Thousands <= Hundred_Thousands - 1;
                   ELSE
                     Hundred_Thousands <= "1001";
                     IF Millions > 0 THEN
                       Millions <= Millions - 1;
                     END IF;
                   END IF;
                 END IF;
               END IF;       
             END IF;
          END IF;
        ELSIF (Up_Int_Single = '1' AND Timer_Preind = '0') AND 
               Fine_Tuning_Int = '0' THEN
          Ones <= Ones;
          Tens <= Tens;
          Hundreds <= Hundreds;
          IF Thousands < 9 THEN
            Thousands <= Thousands + 1;
          ELSE
            Thousands <= "0000";
            IF Ten_Thousands < 9 THEN
              Ten_Thousands <= Ten_Thousands + 1;
            ELSE
              Ten_Thousands <= "0000";
              IF Hundred_Thousands < 9 THEN
                Hundred_Thousands <= Hundred_Thousands + 1;
              ELSE
                Hundred_Thousands <= "0000";
                IF Millions < 9 THEN
                  Millions <= Millions + 1;
                END IF;
              END IF;
            END IF;
          END IF;
        ELSIF (Down_Int_Single = '1' AND Timer_Preind = '0') AND 
               Fine_Tuning_Int = '0' THEN
          Ones <= Ones;
          Tens <= Tens;
          Hundreds <= Hundreds;
          IF Thousands > 0 THEN
            Thousands <= Thousands - 1;
          ELSE
            Thousands <= "1001";
            IF Ten_Thousands > 0 THEN
              Ten_Thousands <= Ten_Thousands - 1;
            ELSE
              Ten_Thousands <= "1001";
              IF Hundred_Thousands > 0 THEN
                Hundred_Thousands <= Hundred_Thousands - 1;
              ELSE
                Hundred_Thousands <= "1001";
                IF Millions > 0 THEN
                  Millions <= Millions - 1;
                END IF;
              END IF;
            END IF;
          END IF;
        END IF;        
      END IF;        
    END IF;
    
  END PROCESS Display_Calculator_Clock_Generator;
  
  
  
  Timer:
  PROCESS(Clock_Div)
  
  -- This process produces a wait between Up or Down events depending 
  -- on the length of time generated by the Timer_Count signal.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Timer_Count <= 0;
        Timer_Preind <= '0';
      ELSIF ((((Up_Int = '1' OR Down_Int = '1') OR Init_Signal = 
'1') 
               AND Timer_Count = 0) AND Timer_Count_Clock = '1') 
THEN
        Timer_Count <= Timer_Count + 1;
        Timer_Preind <= '1';
      ELSIF ((Timer_Count /= 0 AND Timer_Count < Max_Timer_Count) AND 
              Timer_Count_Clock = '1') THEN
        Timer_Count <= Timer_Count + 1;
        Timer_Preind <= '1';
      ELSIF (Timer_Count = Max_Timer_Count AND Timer_Count_Clock = 
'1') THEN
        Timer_Count <= 0;
        Timer_Preind <= '0';
      END IF;
    Timer_Output <= Timer_Preind;
    Timer_Count_Int <= Timer_Count;
    Timer_Ind_Int <= Timer_Preind;
    END IF;
    
  END PROCESS Timer;
    
    

  Up_Down_Conditioner:
  PROCESS(Clock_Div)
  
  -- This process generates a start pulse for a count up or a count down
  -- procedure depending on which input, Up or Down was set.  No start
  -- pulse will be generated if both Up and Down are set at the same 
time.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Up_Int <= '0';
        Down_Int <= '0';
      ELSIF ((Up_Del = '1' AND Down_Del = '0') AND Timer_Ind_Int = 
'0') THEN
        Up_Int <= '1';
      ELSIF ((Down_Del = '1' AND Up_Del = '0') AND Timer_Ind_Int = 
'0') THEN
        Down_Int <= '1';
      ELSE
        Up_Int <= '0';
        Down_Int <= '0';
      END IF;
    END IF;
    
  END PROCESS Up_Down_Conditioner;
  
  
  
  Up_Down_Conditioner_Secondary:
  PROCESS(Clock_Div, Up_Int, Up_Int_Secon, Down_Int, Down_Int_Secon)
  
  -- This process is necessary to provide a single clock width pulse to
  -- the frequency counters to prevent them from double counting.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Up_Int_Secon <= '0';
        Down_Int_Secon <= '0';
      ELSIF Up_Int = '1' THEN
        Up_Int_Secon <= '1';
      ELSIF Down_Int = '1' THEN
        Down_Int_Secon <= '1';
      ELSE
        Up_Int_Secon <= '0';
        Down_Int_Secon <= '0';
      END IF;
    END IF;
    
    Up_Int_Single <= Up_Int AND Up_Int_Secon;
    Down_Int_Single <= Down_Int AND Down_Int_Secon;
    
  END PROCESS Up_Down_Conditioner_Secondary;
  
  
  
  DDS_Counter:
  PROCESS(Clock_Div)
  
  -- This process defines the count, up or down, procedure for the DDS 
  -- interface portion of the output.  The reset transmit frequency is 
  -- set at 3,700,000 Hz and the receive frequency is set 4,915,600 Hz 
  -- higher at 8,615,600 Hz for 80M operation.  The reset transmit
  -- frequency is set at 7,050,000 Hz and the receive frequency is set
  -- 4,915,600 Hz lower at 2,134,400 Hz for 40M operation.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        DDS_Data_Counter_Rx <= Rx_Reset_Freq;
        DDS_Data_Counter_Tx <= Tx_Reset_Freq;
      ELSIF (Up_Int_Single = '1' AND Timer_Preind = '0') AND 
             Fine_Tuning_Int = '1' THEN
        DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx + 
Fine_Tuning_Offset;
        DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx + 
Fine_Tuning_Offset;
      ELSIF (Down_Int_Single = '1' AND Timer_Preind = '0') AND 
             Fine_Tuning_Int = '1' THEN
        DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx - 
Fine_Tuning_Offset;
        DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx - 
Fine_Tuning_Offset;
      ELSIF (Up_Int_Single = '1' AND Timer_Preind = '0') AND 
             Fine_Tuning_Int = '0' THEN
        DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx + 
Coarse_Tuning_Offset;
        DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx + 
Coarse_Tuning_Offset;
      ELSIF (Down_Int_Single = '1' AND Timer_Preind = '0') AND 
             Fine_Tuning_Int = '0' THEN
        DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx - 
Coarse_Tuning_Offset;
        DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx - 
Coarse_Tuning_Offset;
      ELSE
        DDS_Data_Counter_Rx <= DDS_Data_Counter_Rx;
        DDS_Data_Counter_Tx <= DDS_Data_Counter_Tx;
      END IF;
    END IF;
  
  END PROCESS DDS_Counter;
    
    
    
  DDS_Data_Mux:
  PROCESS(Clock_Div)
  
  -- This process multiplexes the DDS receive and transmit 24-bit words 
to
  -- 3 8-bit values to remain compatible with the PC parallel port 
interface.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN  
      IF Data_Mux_En = "000" THEN
        DDS_Data_Out <= DDS_Data_Counter_Rx(23 DOWNTO 16);
      ELSIF Data_Mux_En = "001" THEN
        DDS_Data_Out <= DDS_Data_Counter_Rx(15 DOWNTO 8);
      ELSIF Data_Mux_En = "010" THEN
        DDS_Data_OUT <= DDS_Data_Counter_Rx(7 DOWNTO 0);
      ELSIF Data_Mux_En = "011" THEN
        DDS_Data_Out <= DDS_Data_Counter_Tx(23 DOWNTO 16);
      ELSIF Data_Mux_En = "100" THEN
        DDS_Data_Out <= DDS_Data_Counter_Tx(15 DOWNTO 8);
      ELSIF Data_Mux_En = "101" THEN
        DDS_Data_Out <= DDS_Data_Counter_Tx(7 DOWNTO 0);
      END IF;    
    END IF;
    
  END PROCESS DDS_Data_Mux;     
    
    
    
  Cycle_Control:
  PROCESS(Clock_Div)
  
  -- This process generates a signal that defines the end of the 
  -- output cycle.  If the Up or Down signal is constantly active,
  -- the next cycle may now proceed.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Cycle_Enable <= '0';        
      ELSIF Init_Signal = '1' AND Cycle_Over = '0' THEN
        Cycle_Enable <= '1';     
      ELSIF Up_Int = '1' AND Cycle_Over = '0' THEN
        Cycle_Enable <= '1';
      ELSIF Down_Int = '1' AND Cycle_Over = '0' THEN
        Cycle_Enable <= '1';
      ELSIF Cycle_Over = '1' THEN
        Cycle_Enable <= '0'; 
      END IF;      
    END IF;
    
  END PROCESS Cycle_Control;
  
  
  
  Output_State_Sequential:
  PROCESS(Clock_Div)
  
  -- This process synchronizes the output state from the process
  -- defined by Output_State_Combinational.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      IF Reset_Int = '0' THEN
        Current_State <= State17;
      ELSIF Reset_Int = '1' AND Cycle_Enable = '1' THEN
        Current_State <= Next_State;
      ELSE
        Current_State <= State17;
      END IF;
    END IF;
  
  END PROCESS Output_State_Sequential;
    
    
    
  Register_Output_Strobe:
  PROCESS(Clock_Div)
  
  -- This process deglitches and aligns the DDS_Strobe signal, used
  -- as the parallel port data clocks.
  
  BEGIN
  
    IF Clock_Div = '1' AND Clock_Div'EVENT THEN
      DDS_Strobe <= Output_Strobe;
    END IF;
    
  END PROCESS Register_Output_Strobe;
  
  
  
  Output_State_Combinational:
  PROCESS(Current_State)
  
  -- This process defines the state machine that controls the generation
  -- of Output_Strobe, Data_Mux_En, and Cycle_Over.  Next_State is 
latched
  -- to Current_State in process Output_State_Sequential.
  
  BEGIN
  
    CASE Current_State IS
    
      WHEN State0 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "000";
           Next_State <= State1;
      
      WHEN State1 =>
           Output_Strobe <= "0001";
           Cycle_Over <= '0';
           Data_Mux_En <= "000";
           Next_State <= State2;
      
      WHEN State2 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "000";
           Next_State <= State3;
      
      WHEN State3 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "001";
           Next_State <= State4;
      
      WHEN State4 =>
      	   Output_Strobe <= "0010";
      	   Cycle_Over <= '0';
      	   Data_Mux_En <= "001";
      	   Next_State <= State5;
      
      WHEN State5 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "001";
           Next_State <= State6;
      
      WHEN State6 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "010";
           Next_State <= State7;
      
      WHEN State7 =>
           Output_Strobe <= "0100";
           Cycle_Over <= '0';
           Data_Mux_En <= "010";
           Next_State <= State8;
      
      WHEN State8 =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "010";
           Next_State <= State9;
      
      WHEN State9 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "011";
           Next_State <= State10;
      
      WHEN State10 =>
           Output_Strobe <= "1001";
           Cycle_Over <= '0';
           Data_Mux_En <= "011";
           Next_State <= State11;
      
      WHEN State11 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "011";
           Next_State <= State12;
      
      WHEN State12 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "100";
           Next_State <= State13;
      
      WHEN State13 =>
           Output_Strobe <= "1010";
           Cycle_Over <= '0';
           Data_Mux_En <= "100";
           Next_State <= State14;
      
      WHEN State14 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "100";
           Next_State <= State15;
           
     WHEN State15 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "101";
           Next_State <= State16;
      
      WHEN State16 =>
           Output_Strobe <= "1100";
           Cycle_Over <= '1';
           Data_Mux_En <= "101";
           Next_State <= State17;
      
      WHEN State17 =>
           Output_Strobe <= "1000";
           Cycle_Over <= '0';
           Data_Mux_En <= "101";
           Next_State <= State0;
           
      WHEN OTHERS =>
           Output_Strobe <= "0000";
           Cycle_Over <= '0';
           Data_Mux_En <= "000";
           Next_State <= State0;
                 
    END CASE;
    
  END PROCESS Output_State_Combinational;
  
  
  
  
END test1;

