--
 Implantable Stimulator and Transponder (IST, A3036) Firmware, Toplevel Unit

-- Version A01, 05-NOV-19. Based upon P3030E03.vhd. Remove sample transmission. Add
-- place-holder support for different set numbers using constants. Replace sampling of
-- battery voltage with voltage-to-time measurement using the Battery Voltage process,
-- the BT output and the BTV input. Remove analog input sampling code. The device 
-- executes stimuli with the correct timing, reports battery test time correctly,
-- and transmits acknowledgements. But its quiescent current consumption, with no
-- active stimulus, is 200 uA instead of our expected 60 uA.

-- Version A02, 19-NOV-19. Add transmission on data channel of the state of the
-- lamp. We turn on this transmission with an XON command, and turn it off with XOFF.
-- When the lamp is on, the data takes one value, and when off a lower value, so that
-- the lamp flashing appears as a square wave in the SCT signal. We switch to the
-- Synplify synthesis engine and Lattice Diamond 3.11. Quiescent current consumption
-- remains 200 uA. The ring oscillator frequency is now well-behaved with respect
-- to fck_divisor, even though routing optimization is not being applied to the
-- clock divider.

-- Version A03, 26-NOV-19. Add battery_calib as an offset to the battery voltage counter
-- so as bring the battery measurement of all devices to 200 when the battery 
-- voltage is 3.70 V. Add RP to TP2.

-- Version A04, 28-NOV-19. Remove RP from TP2. Add nomerge and synkeep for TXI and TXD,
-- eliminates two timing violations. Move entire ring oscillator into its own entity
-- and place in Ring_Oscillator.vhd. Add a fifth BUFBA to the ring, so that all five
-- gates in the ring are always retained.

-- Version A05, 31-DEC-19. We find that routing TCK to a test pin causes timing 
-- violations because of the long route to the output pad. So we route FCK instead,
-- and calibrate FCK to lie in the range 97.5-107.5 ns. Complete support for higher 
-- device identifiers, extracting the auxilliary channel number, set number, channel 
-- number, and completion code from the device id. Enhance the synchronizing signal 
-- so it presents three levels. Enhance Ring Oscillator module so that it takes the
-- fck_calib value and creates a ring oscillator and divider to suit the value.

-- Version 06, 25-FEB-20. Random pulse generator seeded by device id, so each device
-- generates a different sequence from a shared starting instant.

library ieee;  
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;

entity main is 
	port (
		RCK, -- Reference Clock
		RP, -- Radio Frequency Power Detected
		BTV  -- Battery Test Voltage
		: in std_logic; 
		OND, -- On Device, keeps power turned on.
		ONL, -- On Lamp, closes the lamp's mosfet switch.
		XEN, -- Transmit Enable, for data transmission
		BT, -- Battery Test Enable
		TP1, -- Test Point One, available on the programming extension.
		TP2, -- Test Point Two, available on the programming extension.
		KEEPER
		: out std_logic;
		xdac -- Transmit DAC Output, to set data transmit frequency
		: out std_logic_vector(4 downto 0));

-- Configuration and Calibration Constants.
	constant device_id : integer := 28; -- The identifier number for this device
	constant fck_calib : integer := 17; -- Calibration of ring oscillator to give 10 MHz on FCK
	constant frequency_low : integer := 5; -- Low frequency code for data transmission.
	constant battery_calib : integer := 60; -- Offset to make battery measurement 200 at 3.70 V.
	
-- Stable Calibration Constants
	constant frequency_step : integer := 1; -- High minus low frequency code
	constant sample_rate : integer := 1024; -- How often we transmit diagnostic signal
	
-- Operation Codes for the Command Processor
	constant stop_stimulus : integer := 0;
	constant start_stimulus : integer := 1;
	constant configure_sensor : integer := 2;
	constant set_brightness : integer := 3;
	constant set_pulse_len_hi : integer := 4;
	constant set_pulse_len_lo : integer := 5;
	constant set_interval_len_hi : integer := 6;
	constant set_interval_len_lo : integer := 7;
	constant set_stimulus_len_hi : integer := 8;
	constant set_stimulus_len_lo : integer := 9;
	constant enable_randomizer : integer := 10;
	constant select_device : integer := 11;
	constant command_acknowledge : integer := 12;
	constant check_battery : integer := 13;

-- Other Constants
	constant device_id_max : integer := 255; -- Defines range of id codes.
	constant ack_code : integer := 1; -- The acknowledgement code in the acknowledge message
	constant bat_code : integer := 2; -- The battery report code in auxiliary message
end;

architecture behavior of main is
	
-- Attributes to guide the compiler.
	attribute syn_keep : boolean;
	attribute nomerge : string;

-- Power Controller
	signal USERSTDBY, CLRFLAG, STDBY : std_logic;
	attribute syn_keep of STDBY : signal is true;
	attribute nomerge of STDBY : signal is "";
	
-- Ring Oscillator and Transmit Clock
	signal TCK, FCK : std_logic;
	attribute syn_keep of TCK, FCK : signal is true;
	attribute nomerge of TCK, FCK : signal is "";  
	
-- Byte Receiver
	signal RPS, -- Radio Frequency Power Synchronized
		IC, -- Initiate Command Reception
		TC, -- Terminate Command Reception
		RC, -- Receiveing Command
		RBI, -- Receive Command Byte Initiate
		RBD, -- Receive Command Byte Done
		CRCERR, -- Cyclic Redundancy Checksum Error
		BYTERR, -- Byte Error
		BYTS, -- Command Byte Strobe
		BITS -- Command Bit Strobe
		: boolean := false; 
	signal cmd : std_logic_vector(7 downto 0); -- Command Byte
	
-- Command Memory
	constant addr_max : integer := 511;
	signal cm_addr : std_logic_vector(8 downto 0); -- Command Memory Address
	signal cm_out : std_logic_vector(7 downto 0); -- Command Memory Data Out
	signal BYTSEL, -- Command Memory Select
		CMWR  -- Command Memory Write
		: std_logic; 
	
-- Control Registers
	signal stimulus_len, -- Number of pulses in a stimulus, 0 for infinite.
		interval_len, -- Number of RCK periods in each pulse interval.
		pulse_len -- Number of RCK periods in each pulse.
		: std_logic_vector(15 downto 0) := "0000000000000000";
	signal sensor_config -- Code to configure the sensor.
		: std_logic_vector(7 downto 0) := "00000000";
		
-- Acknowledgement Registers and Signals
	signal ack_key -- The byte we send back on command acknowledge.
		: std_logic_vector(7 downto 0) := "00000000";
	signal AKRQ, -- Request Acknowledgment
		AKTX -- Transmit Acknowledgement
		: boolean := false;

-- Battery Voltage Reporting
	signal BVRQ, -- Request Battery Voltage
		BVRDY, -- Battery Voltage Measurement Ready
		BVTX -- Transmit Battery Voltage
		: boolean := false;
	signal bat_cnt -- Battery voltage counter.
		: std_logic_vector(7 downto 0) := "00000000";

-- Command Processor
	signal CPA -- Command Processor Active
		: boolean := false;

-- Stimulus Generator and Brightness Controller
	constant rck_per_ms : integer := 33;
	signal PA, -- Pulse Active
		STARTS, -- Start Stimulus
		STOPS, -- Stop Stimulus
		SRUN, -- Stimulus Running
		RAND, -- Enable Pulse Randomizer
		ISC, -- Initiate Stimulus Cycle
		ILP -- Initiate Lamp Pulse
		: boolean := false;
	signal STCK  -- Stimulus Clock
		: std_logic;

-- Diagnostic Transmission
	signal TXEN, -- Sample Transmission Enabled
		XWARM, -- VCO Warm-Up Signal
		TXI, -- Sample Transmit Initiate
		TXD, -- Sample Transmit Done
		TXB, -- Transmit Bit
		FHI -- Frequency High
		: boolean := false;
	attribute syn_keep of TXI, TXD: signal is true;
	attribute nomerge of TXI, TXD : signal is "";  
	signal sync_bits -- Diagnostic data bits for transmission.
		: std_logic_vector(15 downto 0) := "0000000000000000";

-- Functions and Procedures	
	function to_std_logic (v: boolean) return std_ulogic is
	begin if v then return('1'); else return('0'); end if; end function;

begin

-- We turn off the logic chip bandgap references and other unecessary
-- circuits with the power controller unit. Within a few milliseconds
-- of power-up, the chip is fully operational and ready to enter its
-- standby mode, which is the mode we run it in all the time. The PCU
-- entity has two outputs: STDBY and SFLAG. We don't connect SFLAG,
-- but we do connect STDBY to a keeper output pin on the chip. We 
-- find that the compiler eliminates the PCU unless one of its outputs
-- is connected to a pin or a state machine.
	Power_Controller: entity PCU port map (
		CLRFLAG => CLRFLAG,
		USERSTDBY => USERSTDBY, 
		STDBY => STDBY,
		SFLAG => open);
	PowerUp: process is
		constant PowerUpEnd : integer := 3;
		variable counter : integer range 0 to PowerUpEnd := 0;
	begin
		wait until (RCK = '1');
		if (counter = PowerUpEnd) then 
			counter := counter;
			CLRFLAG <= '0';
			USERSTDBY <= '1';
		else
			counter := counter + 1;
			USERSTDBY <= '0';
			if (counter = 1) then
				CLRFLAG <= '1';
			else 
				CLRFLAG <= '0';
			end if;
		end if;
		
		-- The OND signal keeps power applied to the logic chip after
		-- RP is unasserted, which is the case after the 5-ms initiate
		-- pulse, when command bits are incoming, and after the end of
		-- command transmistion. We assert OND when we have a stimulus
		-- running (SRUN), the command processor is active (CPA), data
		-- transmission is enabled (TXEN), an acknowledgement has been
		-- requested (AKRQ), or a battery voltage reading has been 
		-- requested (BVRQ).
		if (SRUN or CPA or TXEN or AKRQ or BVRQ) then
			OND <= '1';
		else
			OND <= '0';
		end if;
	end process;
	
-- The Receive Power signal must be synchronized with the RCK clock.
	Synchronize_RP: process is 
	begin
		wait until (RCK = '0');
		RPS <= (RP = '1');
	end process;
	
-- We detect a long enough burst of command power to initiate
-- command reception, and set the IC signal.
	Initiate_Command: process is 
		constant endcount : integer := 65;
		variable counter : integer range 0 to endcount := 0;
	begin
		wait until (RCK = '1');
		if RPS then 
			if (counter = endcount) then 
				counter := endcount;
				IC <= true;
			else 
				counter := counter + 1;
				IC <= false;
			end if;
		else
			counter := 0;
			IC <= false;
		end if;
	end process;
	
-- We detect a long enough period without command power to 
-- terminate command reception, and set the TC signal.
	Terminate_Command: process is 
		constant endcount : integer := 328;
		variable counter : integer range 0 to endcount := 0;
	begin
		wait until (RCK = '1');
		if not RPS then 
			if (counter = endcount) then 
				counter := endcount;
				TC <= true;
			else 
				counter := counter + 1;
				TC <= false;
			end if;
		else
			counter := 0;
			TC <=  false;
		end if;
	end process;
	
-- The Receive Command (RC) signal indicates that a command is being 
-- received. We set RC when Initiate Command (IC) occurs, and we clear
-- RC when Terminate Command (TC) occurs.
	Receive_Command: process is
	begin
		wait until (RCK = '1');
		if not RC then
			RC <= IC;
		else 
			RC <= not TC;
		end if;
	end process;

-- We watch for a start bit and receive serial bytes when instructed
-- to do so by the Command Processor with the RBI signal.
	Byte_Receiver: process is
		variable state, next_state : integer range 0 to 63 := 0;
		variable no_stop_bit : boolean := false;
	begin
		wait until (RCK = '1');
		
		-- Idle state, waiting for Receive Byte Initiate.
		if (state = 0) then
			if RBI and (not RPS) then 
				next_state := 1;
			else 
				next_state := 0;
			end if;
		end if;
		
		-- Wait for a start bit. If we wait long enough, we will see the 
		-- termination signal, in which case we abort and wait for not RPI.
		-- We clear no stop bit variable, which clears the global BYTERR 
		-- signal.
		if (state = 1) then
			if TC then 
				next_state := 63; 
			else 
				if RPS then 
					next_state := 2;
				else 
					next_state := 1; 
				end if;
			end if;
			no_stop_bit := false;
		end if;
		BYTERR <= no_stop_bit;
		
		-- Once we have a start bit, we proceed through the eight bits of
		-- a command byte, each bit taking four states. The first bit occurs
		-- at state 7 and the stop bit at state 39.
		if (state >= 2) and (state <= 38) then 
			next_state := state + 1; 
		end if;
		
		-- If the stop bit is present, we go to our end state. If it's missing,
		-- we go to our byte error state. The stop bit is zero, so RPS should 
		-- at this point be false.
		if (state = 39) then
			if not RPS then 
				next_state := 63;
			else 
				next_state := 62;
			end if;
		end if;
		
		-- Here we deal with unused states by directing them towards the byte
		-- error state.
		if (state > 39) and (state < 62) then 
			next_state := 62; 
		end if;
		
		-- In the byte error state, we set the "no stop bit" flag, which asserts the 
		-- global BYTERR signal. We will not reset this flag until the Byte Receiver
		-- starts a new byte reception. This flag tells the Command Processor to ignore
		-- the entire command. We wait in the byte error state until RBI is unasserted. 
		-- Because we do not assert RBD, the un-assertion of RBI will occur only when
		-- the Command Receiver encounters a Terminate Command signal.
		if (state = 62) then
			if not RBI then 
				next_state := 0;
			else 
				next_state := 62;
			end if;
			no_stop_bit := true;
		end if;
		
		-- In the end state, we assert Receive Byte Done and we wait for the command
		-- processor to un-assert Receive Byte Initiate. When we see not RBI, we return
		-- to the idle state. We stop asserting RBD, or refrain from asserting it, when
		-- we have Terminate Command.
		if (state = 63) then 
			if not RBI then 
				next_state := 0; 
			else 
				next_state := 63; 
			end if;
		end if;
		RBD <= (state = 63) and (not TC);
				
		-- The eight bits of the command are set every four states during
		-- the command reception.
		for i in 0 to 7 loop
			if (state = 35 - i * 4) then 
				if RPS then 
					cmd(i) <= '1'; 
				else 
					cmd(i) <= '0'; 
				end if;
			else 
				cmd(i) <= cmd(i); 
			end if;
		end loop;
		
		-- We assert Command Bit Strobe one RCK period before the best moment
		-- to sample each bit value.
		if (state = 34) or (state = 30) or (state = 26) or (state = 22) 
			or (state = 18) or (state = 14) or (state = 10) or (state = 6) then
			BITS <= true;
		else 
			BITS <= false;
		end if;
		
		-- The Byte Strobe signal indicates that we have a start bit and is 
		-- useful as a test point trigger. It provides a pulse of two RCK 
		-- periods.
		BYTS <= (state = 2) or (state = 3);
		
		-- Assert the new state.
		state := next_state;
	end process;

-- This process runs all the bits of a command through a sixteen-bit linear shift 
-- register, with local name "crc" for "cyclic redundancy check". We preset crc 
-- to all ones. The final sixteen bits of every command are chosen so that they 
-- reset the crc register to all zeros. If crc is not zero at the end of a command,
-- there was some error during reception. We use the Bit Strobe (BITS) signal to 
-- clock crc, because BITS is asserted only when a command data bit is receive,
-- not when we receive a start or stop bit.
	Error_Check : process is
		variable crc, next_crc : std_logic_vector(15 downto 0) := "1111111111111111";
	begin
		wait until (RCK = '1');
		
		if IC then
			-- When a new command transmission starts, we preload the cyclic redundancy
			-- check register to all ones.
			crc := "1111111111111111";
		else
			-- We use Command Bit Strobe to clock each command bit into the CRC.
			-- The transmitter calculates the checksum with zeros in the last
			-- sixteen bits, reverses the order of these checksum bits, and sends
			-- them as the last two bytes of the actual transmission, instead of the
			-- zeros it used when it calculated its own checksum. These last sixteen
			-- bits, thus obtained, will reset the receiver CRC to zero, provided there
			-- has been no corruption of the data on the way.
			if BITS then
				for i in 0 to 9 loop next_crc(i) := crc(i+1); end loop;
				next_crc(10) := crc(11) xor crc(0);
				next_crc(11) := crc(12);
				next_crc(12) := crc(13) xor crc(0);
				next_crc(13) := crc(14) xor crc(0);
				next_crc(14) := crc(15);
				next_crc(15) := to_std_logic(RPS) xor crc(0);	
				crc := next_crc;
			end if;		
		end if;
		
		-- The CRCERR flag tells us when the CRC is not zero. It will be zero when it
		-- has been reset by the two bytes of a correct checksum.
		CRCERR <= (crc /= "0000000000000000");
	end process;
	
-- Command Memory
	Command_Memory : entity RAM_512Byte port map (
		Clock => not RCK,
		ClockEn => '1',
		Reset => '0', 
		WE => CMWR,
		Address => cm_addr, 
		Data => cmd,
		Q => cm_out);
		
-- This Command Processor detects Inititiate Command (IC) and activates the Byte Receiver. 
-- It stores command bytes in the Command Memory until it detects Terminate Command (TC). If
-- the Error Check reports no error, the Command Processor reads the commands out of command
-- memory one at a time and executes them. The Command Processor runs on the reference clock,
-- which is 32.768 kHz, and proceeds to a new state every clock cycle. Each command byte takes
-- roughly two clock cycles to process. If the Command Memory is 512 bytes long, the maximum
-- time taken by command processing will be 30 ms. The Command Processor does not respond to
-- Initiate Command (IC) during the execution time, so the Command Transmitter must refrain
-- from sending consecutive long commands to the same device without inserting sufficient
-- delay for execution to complete. The CPA signal is asserted by the Command Processor as 
-- soon as a command is initiated, and CPA instructs the the Power Controller to keep power
-- applied to the logic chip. At the end of command processing, CPA is unasserted and other
-- signals, such as BVRQ are used in the Power Controller to keep the chip powered up.
	Command_Processor: process is
		
		-- General-purpose state names for the Command Processor
		constant idle_s : integer := 0;
		constant receive_cmd_s : integer := 1;
		constant store_cmd_s : integer := 2;
		constant inc_addr_s : integer := 3;
		constant check_cmd_s : integer := 4;
		constant opcode_s : integer := 5;
		constant dec_count_s : integer := 6;
		constant check_count_s : integer := 7;
		
		-- Opcode-specific state names for the Command Processor
		constant k : integer := 10;
		constant stop_stimulus_s : integer := stop_stimulus + k;
		constant start_stimulus_s : integer := start_stimulus + k;
		constant configure_sensor_s : integer := configure_sensor + k;
		constant set_brightness_s : integer := set_brightness + k;
		constant set_pulse_len_hi_s : integer := set_pulse_len_hi + k;
		constant set_pulse_len_lo_s : integer := set_pulse_len_lo + k;
		constant set_interval_len_hi_s : integer := set_interval_len_hi + k;
		constant set_interval_len_lo_s : integer := set_interval_len_lo + k;
		constant set_stimulus_len_hi_s : integer := set_stimulus_len_hi + k;
		constant set_stimulus_len_lo_s : integer := set_stimulus_len_lo + k;
		constant enable_randomizer_s : integer := enable_randomizer + k;
		constant select_device_s : integer := select_device + k;
		constant command_acknowledge_s : integer := command_acknowledge + k;
		constant check_battery_s : integer := check_battery + k;
		
		-- Variables for the Command Processor
		variable opcode : integer range 0 to 255 := 0;
		variable select_id : integer range 0 to device_id_max := 0;
		variable state, next_state : integer range 0 to 31 := 0;
		variable count, addr : integer range 0 to addr_max := 0;
		variable randomizer_enabled : boolean := false;
		
	begin
		wait until (RCK = '1');
	
		-- Idle State.
		if (state = idle_s) then
			if IC then 
				next_state := receive_cmd_s; 
			else 
				next_state := idle_s;
			end if;
			addr := 0;
			count := 0;
		end if;
		
		-- Receive a command byte. We assert RBI and wait for RBD. If we see 
		-- terminate command (TC), we look at the number of command bytes we have 
		-- received so far. If we have less than three, we have only the checksum,
		-- so we go back to the idle state. If we have three or more, we move on.
		-- Note that the Byte Receiver aborts on TC also.
		if (state = receive_cmd_s) then 
			if TC then 
				if (addr <= 2) then 
					next_state := idle_s;
				else 
					next_state := check_cmd_s;
				end if;
			else 
				if RBD then 
					next_state := store_cmd_s;
				else 
					next_state := receive_cmd_s;
				end if;
			end if;
		end if;
		RBI <= (state = receive_cmd_s);
		
		-- Store the new command byte in the command memory. We assert CMWR.
		if (state = store_cmd_s) then 
			if not RBD then 
				next_state := inc_addr_s;
			else 
				next_state := store_cmd_s;
			end if;
		end if;
		CMWR <= to_std_logic(state = store_cmd_s);
		
		-- Increment the command address. If we have run out of space in the
		-- Command Memory, we abort our attempt to process the command, and wait
		-- for the next command.
		if (state = inc_addr_s) then
			addr := addr + 1;
			count := count + 1;
			if (addr = addr_max) then
				next_state := idle_s;
			else
				next_state := receive_cmd_s;
			end if;
		end if;		
		
		-- There are two possible sources of error: a failure in the cyclic redundancy
		-- check (CRCERR) or an error in the structure of a command byte (BYTERR). If either
		-- is asserted, we go back to idle. Otherwise, we proceed to execution of the commands
		-- that are now stored in memory. We set the command memory address to zero in 
		-- anticipation of reading out the first command byte. But before we clear the 
		-- memory address, we save the number of data bytes in count so we will know 
		-- how many bytes to read out and execute. By construction, the count must be at 
		-- least 3 at this stage.
		if (state = check_cmd_s) then
			if CRCERR or BYTERR then 
				next_state := idle_s;
			else 
				next_state := opcode_s;
			end if;
			addr := 0;
		end if;
		
		-- We read a byte from the command memory and interpret it. We increment the
		-- command memory address so as to retrieve the next byte, which may be a 
		-- parameter.
		if (state = opcode_s) then
			case to_integer(unsigned(cm_out)) is
				when stop_stimulus => next_state := stop_stimulus_s;
				when start_stimulus => next_state := start_stimulus_s;
				when configure_sensor => next_state := configure_sensor_s;
				when set_brightness => next_state := set_brightness_s;
				when set_pulse_len_hi => next_state := set_pulse_len_hi_s;
				when set_pulse_len_lo => next_state := set_pulse_len_lo_s;
				when set_interval_len_hi => next_state := set_interval_len_hi_s;
				when set_interval_len_lo => next_state := set_interval_len_lo_s;
				when set_stimulus_len_hi => next_state := set_stimulus_len_hi_s;
				when set_stimulus_len_lo => next_state := set_stimulus_len_lo_s;
				when enable_randomizer => next_state := enable_randomizer_s;
				when select_device => next_state := select_device_s;
				when command_acknowledge => next_state := command_acknowledge_s;
				when check_battery => next_state := check_battery_s;
				when others => next_state := check_count_s;
			end case;
			addr := addr + 1;
			count := count - 1;
		end if;
		
		-- This state causes all settings to be cleared to zero.
		if (state = stop_stimulus_s) then
			next_state := check_count_s;
		end if;
		
		-- We start a new stimulus with the SS signal. 
		if (state = start_stimulus_s) then
			next_state := check_count_s;
		end if;
		
		-- The Start Stimulus and Stop Stimulus signals are asserted for one
		-- RCK period when we are in the start and stop stimulus states 
		-- respectively.
		STARTS <= (state = start_stimulus_s);
		STOPS <= (state = stop_stimulus_s);
		
		-- We set the select identifier, which we then compare to this device's id.
		-- If the device select number is not device_id, we abort command execution 
		-- and await the next string of commands.
		if (state = select_device_s) then
			select_id := to_integer(unsigned(cm_out));
			if (select_id = device_id) then
				next_state := dec_count_s;
			else 
				next_state := idle_s;
			end if;
		end if;
		
		-- We set the sensor configuration register.
		if (state = configure_sensor_s) then 
			next_state := dec_count_s;
		end if;
		
		-- Logic to control the sensor configuration register.
		if state = configure_sensor_s then
			for i in 0 to 7 loop
				sensor_config(i) <= cm_out(i);
			end loop;
		else
			sensor_config <= sensor_config;
		end if;

		-- We set brightness register, which controls the lamp's high-frequency
		-- duty cycle. In this firmware, the brightness register is not implemented.
		-- The lamp is either on or off. For backwared-compatibility, however, we 
		-- process the brightness command but take no other action.
		if (state = set_brightness_s) then 
			next_state := dec_count_s;
		end if;
		
		-- We turn on or off the pulse randomizer, based upon the parameter value.
		if (state = enable_randomizer_s) then
			next_state := dec_count_s;
		end if;
		if (state = stop_stimulus_s) then
			randomizer_enabled := false;
		else
			if (state = enable_randomizer_s) then
				randomizer_enabled := (cm_out(0) = '1');
			end if;
		end if;
		RAND <= randomizer_enabled;
		
		-- Set the HI byte of the pulse length.
		if (state = set_pulse_len_hi_s) then
			next_state := dec_count_s;
		end if;
			
		-- Set the LO byte of the pulse length.
		if (state = set_pulse_len_lo_s) then
			next_state := dec_count_s;
		end if;
				
		-- Logic to control the pulse length register.
		for i in 0 to 7 loop
			if (state = set_pulse_len_hi_s) then 
				pulse_len(i+8) <= cm_out(i);
			else 
				pulse_len(i+8) <= pulse_len(i+8);
			end if;
			if (state = set_pulse_len_lo_s) then 
				pulse_len(i) <= cm_out(i);
			else 
				pulse_len(i) <= pulse_len(i);
			end if;
		end loop;
		
		-- Set the HI byte of the interval length.
		if (state = set_interval_len_hi_s) then
			next_state := dec_count_s;
		end if;
			
		-- Set the LO byte of the interval length.
		if (state = set_interval_len_lo_s) then
			next_state := dec_count_s;
		end if;

		-- Logic to control the interval length register.
		for i in 0 to 7 loop
			if (state = set_interval_len_hi_s) then 
				interval_len(i+8) <= cm_out(i);
			else 
				interval_len(i+8) <= interval_len(i+8);
			end if;
			if (state = set_interval_len_lo_s) then 
				interval_len(i) <= cm_out(i);
			else 
				interval_len(i) <= interval_len(i);
			end if;
		end loop;

		-- Set the HI byte of the stimulus length.
		if (state = set_stimulus_len_hi_s) then
			next_state := dec_count_s;
		end if;
			
		-- Set the LO byte of the stimulus length.
		if (state = set_stimulus_len_lo_s) then
			next_state := dec_count_s;
		end if;

		-- Logic to control the stimulus length register.
		for i in 0 to 7 loop
			if (state = set_stimulus_len_hi_s) then 
				stimulus_len(i+8) <= cm_out(i);
			else 
				stimulus_len(i+8) <= stimulus_len(i+8);
			end if;
			if (state = set_stimulus_len_lo_s) then 
				stimulus_len(i) <= cm_out(i);
			else 
				stimulus_len(i) <= stimulus_len(i);
			end if;
		end loop;

		-- Set the echo byte.
		if state = command_acknowledge_s then
			next_state := dec_count_s;
		end if;
		
		-- Initiate transmission of acknowledgement.
		if not AKRQ then
			AKRQ <= (state = command_acknowledge_s);
		else
			AKRQ <= not AKTX;
		end if;
		
		-- Set the acknowledgement key.
		for i in 0 to 7 loop
			if (state = command_acknowledge_s) then 
				ack_key(i) <= cm_out(i);
			else 
				ack_key(i) <= ack_key(i);
			end if;
		end loop;

		-- Initiate battery check.
		if state = check_battery_s then
			next_state := check_count_s;
		end if;
		
		-- Request Battery Voltage.
		if not BVRQ then
			BVRQ <= (state = check_battery_s);
		else
			BVRQ <= not BVTX;
		end if;
		
		-- We increment the command memory address and decrement the command counter
		-- in preparation for reading the next op-code.
		if (state = dec_count_s) then
			addr := addr + 1;
			count := count - 1;
			next_state := check_count_s;
		end if;
		
		-- We check the command count to see if there are any more codes to be read
		-- from the command memory. The last two are always the checksum, so if they
		-- are all that is left, we will return to the idle state.
		if (state = check_count_s) then
			if (count <= 2) then 
				next_state := idle_s;
			else 
				next_state := opcode_s;
			end if;
		end if;
		
		-- Advance the state variable.
		state := next_state;
		
		-- Command Processor Active is true whenever the state is not idle.
		CPA <= (state /= idle_s);
		
		-- The Command Memory Address is always equal to the Command Processor's
		-- addr variable.
		cm_addr <= std_logic_vector(to_unsigned(addr,cm_addr'length));
	end process;

-- The Stimulus Clock Generator creates the clock that runs the Stimulus Generator.
-- The Stimulus Generator does not run off a clock with period equal to the interval
-- length, but instead a clock with period 1/rck_per_ms times the interval length.
-- The Stimulus Generator can select any one of rck_per_ms clock edges in each interval
-- to generate a pulse. The interval_len variable gives the interval length in milliseconds.
-- For 100-ms intervals, the Stimulus Clock (STCK) runs at 32.768 kHz / 100 = 327.68 Hz, 
-- which we assume is close enough to 33 to make no difference, although we can observe
-- the error in the interval length that results when we look at 10 pulses in a 1-s 
-- interval of the synchronizing signal. The Stimulus Clock Generator also provies 
-- Initiate Stimulus Cycle, which the Stimulus Generator uses to start itself up. This
-- signal is asserted during the first interval only.
	Stimulus_Clock_Generator : process is
		variable il : integer range 0 to 65535 := 0;
	begin
		wait until (RCK = '1');
		
		if STARTS then
			il := to_integer(unsigned(interval_len));
			ISC <= true;
			STCK <= '0';
		else 
			if (il = 0) or (il = 1) then
				il := to_integer(unsigned(interval_len));
				ISC <= false;
				STCK <= '0';
			else
				il := il - 1;
				ISC <= ISC;
				STCK <= '1';
			end if;
		end if;
	end process;

-- The Stimulus Generator counts the number of pulses and issues the Initiate
-- Lamp Pulse (ILP) signal. When the lamp pulses should be issued at random, this
-- process generates a random number on each STCK cycle during the interval. 
-- There will be rck_per_ms of these STCK cycles, and the random number has range
-- 0 to rck_per_ms - 2. If this random number equals the STCK cycle number, the
-- Stimulus Generator sets ILP. In this implementation of the generator, we use
-- the fact that rck_per_ms = 33 to permit us to work with a five-bit random 
-- number 0-31, which we create with a linear shift register. We seed the random
-- number generator with the device ID of this device, so that each device,
-- starting at the same instant, will generate a different sequence of flashes.
-- When we are not generating pulses at random, we generate one and only one pulse 
-- per interval, on the same STCK cycle.
	Stimulus_Generator : process (STOPS, STARTS, STCK) is
		variable state, next_state : integer range 0 to 3 := 0;
		variable sl : integer range 0 to 65535 := 0;
		variable il : integer range 0 to 63 := 0;
		variable random, next_random : std_logic_vector(7 downto 0) := 
			std_logic_vector(to_unsigned(device_id,8));

	begin 
		if STOPS or STARTS then 
			state := 0;
		elsif rising_edge(STCK) then
			if (state = 0) then 
				if ISC then 
					next_state := 1;
				else
					next_state := 0;
				end if;
			end if;
			
			if (state = 1) then
				sl := to_integer(unsigned(stimulus_len));
				il := rck_per_ms - 1;
				next_state := 2;
			end if;
			
			if (state = 2) then
				if (il = 2) then
					next_state := 3;
					sl := sl - 1;
				else
					next_state := 2;
					sl := sl;
				end if;
				il := il - 1;
			end if;
			
			if (state = 3) then
				if (sl = 0) and (to_integer(unsigned(stimulus_len)) /= 0) then 
					next_state := 0;
				else
					next_state := 2;
				end if;
				sl := sl;
				il := rck_per_ms - 1;
			end if;
			
			-- If RAND, we generate a new random number every STCK cycle.
			-- Otherwise, we set th random value to a fixed constant, so
			-- that the lamp pulse will be in the same place on every 
			-- interval.
			if RAND then
				next_random(7) := random(0);
				next_random(6) := random(7);
				next_random(5) := random(6) xor random(0);
				next_random(4) := random(5) xor random(0);
				next_random(3) := random(4) xor random(0);
				next_random(2) := random(3);
				next_random(1) := random(2);
				next_random(0) := random(1);
				random := next_random;
			else 
				random := std_logic_vector(to_unsigned(rck_per_ms - 2,8));
			end if;
			
			-- We assert ILP when il has the correct value.
			ILP <= (state = 2) and (il = to_integer(unsigned(random(4 downto 0))));
			
			-- Move to the next state.
			state := next_state;
		end if;

		-- We assert SRUN to keep the logic chip powered up.
		SRUN <= not (state = 0);
end process;
	
-- When a rising edge occurs on Initiate Lamp Pulse (ILP), the Lamp Pulse 
-- Generator asserts Pulse Active (PA) for pulse_len RCK periods. Thus the
-- units of the sixteen-bit pulse_len parameter are RCK periods.
	Lamp_Pulse_Generator : process (STOPS, RCK) is
		variable pl : integer range 0 to 65535 := 0;
		variable prev_ilp : boolean := false;
	begin
		-- We reset the pulse generator on STOPS. We start
		-- a new pulse on ILP, and count down from the pulse
		-- length to zero on RCK.
		if STOPS then
			pl := 0;
		elsif rising_edge(RCK) then 
			if ILP and (not prev_ilp) then
				pl := to_integer(unsigned(pulse_len));
			elsif (pl > 0) then
				pl := pl -1;
			else
				pl := 0;
			end if;
		end if;

		if rising_edge(RCK) then
			-- We assert PA when we want the lamp to turn on.
			PA <= (pl /= 0);
		
			-- We want to detect rising edges on ILP, so we save the previous state.
			prev_ilp := ILP;	
		end if;
	end process;

-- Ring Oscillator. This oscillator runs only during message transmission.
	fck_generator : entity ring_oscillator port map (
		ENABLE => to_std_logic(TXI or TXD), 
		calib => fck_calib,
		CK => FCK);
	
-- The Transmit Clock proces divides FCK in two so as to produce a clock with
-- exactly 50% duty cycle and frequency close to 5 MHz.
	Transmit_Clock : process is 
	begin
		-- The Transmit Clock, TCK, is FCK divided by two, but clocked by the
		-- falling edge of FCK, not the rising edge.
		wait until (FCK = '0');
		
		if (TCK = '1') then
			TCK <= '0';
		else 
			TCK <= '1';
		end if;
	end process;
	
-- The Sample Controller determines when to transmit a message, and what message
-- to transmit. It arbitrates between acknowledgements and samples. It implements
-- transmission scatter, whereby the instant of sample transmission is displaced
-- at random from the nominal instant using the lower four bits of the X-input 
-- sample value.
Sample_Controller : process (sensor_config,RCK) is
		constant divisor : integer := 32768 / sample_rate;
		variable counter : integer range 0 to divisor - 1 := 0;
		variable xmit_enable, xmit_moment, xmit_init, 
			ack_moment, bat_moment : boolean := false;
	begin
		-- These combinatorial variables make our code easier to read.
		xmit_enable := (sensor_config(0) = '1');
		xmit_moment := (counter = 0);
		bat_moment := (counter = divisor - 4);
		ack_moment := (counter = divisor - 2);
		
		if rising_edge(RCK) then
			-- We assert the TXEN signal when the transmit enable bit
			-- is set. Note that this signal applies only to the diagnostic
			-- transmission. Other transmissions being enabled or pending
			-- are declared by other signals.
			TXEN <= xmit_enable;

			-- We divide RCK by divisor to get the sampling frequency. We run
			-- this counter regardless of whether transmission is enabled.
			if (counter = divisor - 1) then
				counter := 0;
			else
				counter := counter + 1;
			end if;
		
			-- The xmit_init variable indicates a clock cycle in which we 
			-- should initiate a transmission. When data transmission is
			-- enabled, we transmit in an RCK clock period chosen at random
			-- from the first sixteen periods of the divisor-period data
			-- transmit cycle. For 512 SPS we have a 64-period cycle and 
			-- data transmission takes place in one of periods 0-15. If we
			-- are waiting to transmit an acknowledgement, or a battery 
			-- voltage measurement, we do these at their own points in the
			-- sample cycle.
			xmit_init := (xmit_enable and xmit_moment) 
				or (AKRQ and ack_moment)
				or (BVRQ and BVRDY and bat_moment);
				
			-- We communicate to the AKRQ and BVRQ signals that transmission
			-- has taken place using these two signals. 
			AKTX <= (AKRQ and ack_moment);
			BVTX <= (BVRQ and BVRDY and bat_moment);
				
			-- Acknowlegement and battery voltage conversion require that the
			-- VCO be warmed up for 60 us before transmission if the VCO has
			-- been idle for more than ten milliseconds. The XWARM signal makes
			-- sure the VCO has time to warm up.
			XWARM <= ((BVRQ and BVRDY) or AKRQ) and (counter >= divisor - 6);
		end if;
		
		-- We don't want our Transmit Initiate pulse to last an entire RCK period
		-- because this would waste power in the VCO and TCK. So we take the 
		-- xmit_init signal and combine it with the value of RCK to get a half-period
		-- pulse when we want transmission to take place. We will get a glitch in TXI
		-- when RCK rises, just before xmit_init has time to go low. But this glitch 
		-- would have to be several nanoseconds long in order to generate a pulse on
		-- TCK, which drives the Sample Transmitter. Once the TXI pulse disappears, the 
		-- ring oscillator is disabled again. But we cannot use TXI to generate, for 
		-- example, CONV, where this glitch will disrupt conversion.
		TXI <= xmit_init and (RCK = '1');
	end process;

-- The Battery Voltmeter starts up when it receives BVRQ, asserts BT so as to start
-- charging the battery measurement capacitor (C4 in the A3036).
	Battery_Voltmeter : process (RCK) is
		variable counter : integer range 0 to 255 := 0;
	begin		
		if rising_edge(RCK) then
			if not BVRQ then
				counter:=battery_calib;
			else if (BTV = '0') then 
					counter:=counter+1;
				else 
					counter:=counter;
				end if;
			end if;
			
			-- Battery Test (BT) turns on the battery test switch so as to charge up 
			-- the battery measurement capacitor. The battery test counter will start to 
			-- count, and when the BTV input transitions to HI, the count will be our 
			-- measurement of battery voltage.
			BT <= to_std_logic(BVRQ);
		
			-- We report Battery Voltage Ready when we have BVRQ and counter > 0 and !BTV.
			BVRDY <= BVRQ and (BTV = '1');
		end if;
		
		-- The battery counter is a copy of our local counter variable.
		bat_cnt <= std_logic_vector(to_unsigned(counter,8));
	end process;
	
-- The Sync Generator sets the value of the synchronizing signal that will be 
-- transmitted when this device is configured to transmit data. We encode the
-- state of the lamp in this data word.
	Sync_Generator : process (RCK) is
		variable value : integer range 0 to 65535 := 0;
		constant base_value : integer := device_id * 64 + 15000;
		constant stimulus_value : integer := base_value + 15000;
		constant pulse_value : integer := stimulus_value + 15000;
	begin
		if rising_edge(RCK) then
			if PA then
				value := pulse_value;		
			else 
				if SRUN then
					value := stimulus_value;
				else 
					value := base_value;
				end if;
			end if;
		end if;
		
		sync_bits <= std_logic_vector(to_unsigned(value,16));
	end process;

-- The Sample Transmitter responds to Transmit Initiate (TXI) by turning on the 
-- radio-frequency oscillator. The process transmits either an auxilliary message
-- or a data message, depending on certain flags. An auxilliary message will have
-- a fixed channel number, but will contain the transmitter ID. The auxilliary
-- message can be an acknowledgment or a battery voltage measurment. An acknowledgement
-- message carries as its eight-bit data the key passed with an acknowledgement
-- request. A battery voltage message carries the eight-bit battery counter value.
-- To determine whether to transmit the battery measurement or an acknowledgement, 
-- the process uses TXAD (Transmit Acknowledgement Delayed), which is a signal that 
-- is asserted for one RCK cycle after the TXA (Transmit Acknowledgement) flag has 
-- been cleared. The output of this process is a sequence of bit values TXB 
-- (Transmit Bit) changing on the rising edges of TCK. A data message contains the
-- synchronizing signal that shows when the stimulus is running, and when the pulses
-- are occurring.
	Sample_Transmitter : process (TCK) is
		constant channel_num : 
			integer := device_id mod 16; -- channel number for data
		constant set_num : 
			integer := device_id / 16; -- set number for data
		constant completion_code : 
			integer := 15 - channel_num + set_num; -- completion code for data
		
		constant num_sync_bits : integer := 11; -- Num synchronizing bits at start.
		constant num_id_bits : integer := 4; -- Number of ID bits.
		constant num_start_bits : integer := 1; -- Num zero start bits.
		constant num_stop_bits : integer := 2; -- For state machine termination only.
		constant num_data_bits : integer := 16; -- Number of ADC data bits.
		constant num_xmit_bits : integer := -- Number of transmission bit periods.
			num_sync_bits + num_start_bits + num_id_bits + num_data_bits + num_id_bits; 
		constant st_done : integer := -- Final state of sample transmit machine.
			num_xmit_bits + num_stop_bits; 
		constant first_sync_bit : integer := 1;
		constant first_start_bit : integer := first_sync_bit + num_sync_bits;
		constant first_id_bit : integer := first_start_bit + num_start_bits;
		constant first_data_bit : integer := first_id_bit + num_id_bits;
		constant first_cc_bit : integer := first_data_bit + num_data_bits;
		constant start_sck : integer := -- Determines when SCK is enabled.
			first_data_bit - 2;
		constant end_sck : integer := -- State for last SCK falling edge.
			start_sck + num_data_bits - 1;
			
		constant channel_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(channel_num,4)); -- channel number for data
		constant cc_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(completion_code,4)); -- completion code for data
		constant sn_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(set_num,4)); -- completion code for auxilliary
		constant ack_code_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(ack_code,4)); -- The acknowledgement code.
		constant bat_code_bits : std_logic_vector(3 downto 0) :=
			std_logic_vector(to_unsigned(bat_code,4)); -- The battery code.
			
		variable state : integer range 0 to 63 := 0; -- Stample Transmit State
		variable data_bit, aux_bit, bat_bit : boolean := false; -- Transmit Bit Values
	begin
		if rising_edge(TCK) then
			-- We reset the state when TXI is false. Otherwise, we increment the
			-- state until it reaches st_done. At st_done, the state remains fixed 
			-- until not TXI. When we first enable sample transmission, the state is 
			-- zero. When TXI is asserted, the ring oscillator turns on, which starts
			-- TCK, the 5-MHz transmit clock. On the first rising edge of TCK, the 
			-- state becomes 1, and thereafter increments to st_done. Now TXD is true,
			-- which keeps the ring oscillator running while TXI becomes false. Once 
			-- false, the state switches back to zero, TXD is unasserted, and the 
			-- ring oscillator turns off, unless it is kept running by some other
			-- process. With no rising edges on TCK, the state remains zero. If rising
			-- edges on TCK continue because the ring oscillator is still running,
			-- the state will remain zero so long as TXI remains unasserted.
			if (not TXI) then
				state := 0;
			elsif (state < st_done) then 
				state := state + 1;
			else 
				state := st_done;
			end if;
		
			-- TXD indicates to other processes that the transmission is complete.
			TXD <= (state = st_done);
			
			-- The data bit is the outgoing bit value for data transmission.
			data_bit := ((state >= 0) and (state < first_start_bit))
				or ((state = first_id_bit + 0) and (channel_bits(3) = '1'))
				or ((state = first_id_bit + 1) and (channel_bits(2) = '1'))
				or ((state = first_id_bit + 2) and (channel_bits(1) = '1'))
				or ((state = first_id_bit + 3) and (channel_bits(0) = '1'))
				or ((state = first_data_bit + 0) and (sync_bits(15) = '1'))
				or ((state = first_data_bit + 1) and (sync_bits(14) = '1'))
				or ((state = first_data_bit + 2) and (sync_bits(13) = '1'))
				or ((state = first_data_bit + 3) and (sync_bits(12) = '1'))
				or ((state = first_data_bit + 4) and (sync_bits(11) = '1'))
				or ((state = first_data_bit + 5) and (sync_bits(10) = '1'))
				or ((state = first_data_bit + 6) and (sync_bits(9) = '1'))
				or ((state = first_data_bit + 7) and (sync_bits(8) = '1'))
				or ((state = first_data_bit + 8) and (sync_bits(7) = '1'))
				or ((state = first_data_bit + 9) and (sync_bits(6) = '1'))
				or ((state = first_data_bit + 10) and (sync_bits(5) = '1'))
				or ((state = first_data_bit + 11) and (sync_bits(4) = '1'))
				or ((state = first_data_bit + 12) and (sync_bits(3) = '1'))
				or ((state = first_data_bit + 13) and (sync_bits(2) = '1'))
				or ((state = first_data_bit + 14) and (sync_bits(1) = '1'))
				or ((state = first_data_bit + 15) and (sync_bits(0) = '1'))
				or ((state = first_cc_bit + 0) and (cc_bits(3) = '1'))
				or ((state = first_cc_bit + 1) and (cc_bits(2) = '1'))
				or ((state = first_cc_bit + 2) and (cc_bits(1) = '1'))
				or ((state = first_cc_bit + 3) and (cc_bits(0) = '1'));

		-- The ack bit is the outgoing bit value for acknowledgment transmission. An
		-- acknowledgement is an auxilliary message, and so has channel number fifteen
		-- and completion code equal to the set number. The set number is the device_id
		-- devided by sixteen.
			aux_bit := ((state >= 0) and (state < first_start_bit))
				or (state = first_id_bit + 0)
				or (state = first_id_bit + 1)
				or (state = first_id_bit + 2)
				or (state = first_id_bit + 3)
				or ((state = first_data_bit + 0) and (channel_bits(3) = '1'))
				or ((state = first_data_bit + 1) and (channel_bits(2) = '1'))
				or ((state = first_data_bit + 2) and (channel_bits(1) = '1'))
				or ((state = first_data_bit + 3) and (channel_bits(0) = '1'))
				or ((state = first_data_bit + 4) and (ack_code_bits(3) = '1'))
				or ((state = first_data_bit + 5) and (ack_code_bits(2) = '1'))
				or ((state = first_data_bit + 6) and (ack_code_bits(1) = '1'))
				or ((state = first_data_bit + 7) and (ack_code_bits(0) = '1'))
				or ((state = first_data_bit + 8) and (ack_key(7) = '1'))
				or ((state = first_data_bit + 9) and (ack_key(6) = '1'))
				or ((state = first_data_bit + 10) and (ack_key(5) = '1'))
				or ((state = first_data_bit + 11) and (ack_key(4) = '1'))
				or ((state = first_data_bit + 12) and (ack_key(3) = '1'))
				or ((state = first_data_bit + 13) and (ack_key(2) = '1'))
				or ((state = first_data_bit + 14) and (ack_key(1) = '1'))
				or ((state = first_data_bit + 15) and (ack_key(0) = '1'))
				or ((state = first_cc_bit + 0) and (sn_bits(3) = '1'))
				or ((state = first_cc_bit + 1) and (sn_bits(2) = '1'))
				or ((state = first_cc_bit + 2) and (sn_bits(1) = '1'))
				or ((state = first_cc_bit + 3) and (sn_bits(0) = '1'));

			-- The bat bit is the outgoing bit value for battery report messages. The
			-- report messsages is an auxilliary channel message, like the acknowledgement.
			bat_bit := ((state >= 0) and (state < first_start_bit))
				or (state = first_id_bit + 0)
				or (state = first_id_bit + 1)
				or (state = first_id_bit + 2)
				or (state = first_id_bit + 3)
				or ((state = first_data_bit + 0) and (channel_bits(3) = '1'))
				or ((state = first_data_bit + 1) and (channel_bits(2) = '1'))
				or ((state = first_data_bit + 2) and (channel_bits(1) = '1'))
				or ((state = first_data_bit + 3) and (channel_bits(0) = '1'))
				or ((state = first_data_bit + 4) and (bat_code_bits(3) = '1'))
				or ((state = first_data_bit + 5) and (bat_code_bits(2) = '1'))
				or ((state = first_data_bit + 6) and (bat_code_bits(1) = '1'))
				or ((state = first_data_bit + 7) and (bat_code_bits(0) = '1'))
				or ((state = first_data_bit + 8) and (bat_cnt(7) = '1'))
				or ((state = first_data_bit + 9) and (bat_cnt(6) = '1'))
				or ((state = first_data_bit + 10) and (bat_cnt(5) = '1'))
				or ((state = first_data_bit + 11) and (bat_cnt(4) = '1'))
				or ((state = first_data_bit + 12) and (bat_cnt(3) = '1'))
				or ((state = first_data_bit + 13) and (bat_cnt(2) = '1'))
				or ((state = first_data_bit + 14) and (bat_cnt(1) = '1'))
				or ((state = first_data_bit + 15) and (bat_cnt(0) = '1'))
				or ((state = first_cc_bit + 0) and (sn_bits(3) = '1'))
				or ((state = first_cc_bit + 1) and (sn_bits(2) = '1'))
				or ((state = first_cc_bit + 2) and (sn_bits(1) = '1'))
				or ((state = first_cc_bit + 3) and (sn_bits(0) = '1'));

			-- We choose between the data_bit and the ack_bit depending upon whether
			-- this is a data or acknowledge tranmsission.
			TXB <= (aux_bit and AKTX) 
				or (bat_bit and BVTX and (not AKTX))
				or (data_bit and (not AKTX) and (not BVTX));
		
		end if;
	end process;

-- With XEN we enable the VCO and switch the antenna to transmit the VCO
-- signal. A data, acknowledgement, or battery transmission is controlled
-- by the combination of TXI and not TXD, which give a 15-us pulse. These
-- pulses are disabled any time we are receiving a command. In addition,
-- we warm up the VCO prior to acknowledgement and battery voltage transmission
-- using the XWARM signal. We need to warm up the VCO for 60 us if the VCO 
-- has not been used for tens of miliseconds.
	XEN <= to_std_logic(((TXI and (not TXD)) or XWARM) and (not RC));
	
-- The ONL signal closes the lamp switch to connect L- to 0V. We assert ONL when
-- a pulse is active.
	ONL <= to_std_logic(PA);
		
-- The Frequency Modulation process takes the transmit bit values provided by
-- the Sample Transmitter, turns them into a sequence of rising and falling
-- edges so as to balance the ratio of HI and LO, and modulates the transmit DAC
-- output (xdac) between the HI and LO frequency values. These values are turned
-- into analog voltages on the TUNE input of the radio frequency oscillator, and
-- so modulate the frequency of the transmission.
	Frequency_Modulation : process is
	begin
		-- Frequency modulation runs off the 10-MHz FCK clock. This clock is
		-- synchronous with TCK. It presents a rising edge over 10 ns after 
		-- both the rising and falling edges of TCK. Thus, when we see a
		-- rising edge on FCK, the value of TCK and TXB are both established.
		wait until (FCK = '1');
	
		-- When we are not transmitting RF power, we set the DAC output to
		-- zero so as to eliminate current consumption by the DAC resistors.
		if (not TXI) or TXD then 
			xdac <= "00000";
			FHI <= false;
			
		-- If TXB is asserted, we want the modulation frequency to go from low
		-- to high on the falling edge of TCK. When TXB is unasserted, we want
		-- the modulation frequency to go from high to low on the falling edge of
		-- TCK.
		elsif (TXB xor (TCK = '1')) then
			xdac <= std_logic_vector(to_unsigned(frequency_low + frequency_step,5));
			FHI <= true;
		else
			xdac <= std_logic_vector(to_unsigned(frequency_low,5));
			FHI <= false;
		end if;
	end process;
	
-- Test Point One appears on the programming extension. It presents FCK for 
-- calibration.
	TP1 <= to_std_logic((FCK = '1'));
	
-- Test Point Two appears on the programming extension. It is a multi-purpose
-- test output, allowing us to see pulses, transmit initiate, transmit done,
-- and the battery test voltage signal.
	TP2 <= to_std_logic(PA or TXI or TXD or (BTV = '1'));
	
-- The KEEPER output we use to force the compiler to retain certain signals it
-- would otherwise eliminate along with necessary logic. If STDBY is eliminated,
-- the entire power control unit is eliminated also, which stops the device
-- going into its low-power state.
	KEEPER <= STDBY;

end behavior;