--
 Implantable Sensor with Lamp (A3030) Firmware, Master File
library ieee;  
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- Version X10, 17-SEP-14. Command Reception and Stimulus Controller working,
-- use in the A3030A for delivery ISL4C.

-- Version B02, 29-SEP-14. Add data transmission but without transmission
-- scatter. Re-assign command code 2 as configure_sensor, was formerly
-- set_polarity.

-- Version B03, 02-OCT-14. Add transmission scatter, but ring oscillator
-- is erratic and we cannot get good reception. Slow down the ring oscillator with 
-- two extra gates. Simplifiy FCK and TCK logic. Assign high routing priority to 
-- FCK divider bits. 

-- Version B04, 24-OCT-14. Correct error by which ring oscillator turns on when
-- we assert OND without enabling transmission. This error was adding to the power
-- consumed during command reception.

-- Version B05, 12-NOV-14. We remove one gate from the ring oscillator so as to
-- give us better resolution in obtaining TCK.

-- Version C01, 25-MAR-15. We stop transmitting when we receive an initiate command
-- pulse, and start again when we see a terminate command pulse.

-- Version C02, 10-APR-15. We turn off the lamp power boost regulator between
-- so as to reduce interference with the EEG amplifier.

-- Version C03, 21-APR-15. We add the acknowledgment command, whereby a byte sent
-- from the Command Transmitter gets sent back on the SCT slow communications 
-- as an acknowledgement.

-- Version D01, 18-JUN-15. Move the acknowledgement time farther from the sample
-- transmit time. Transform the stimulus generator into one that provides random
-- pulse generation at the specified frequency.

entity main is port (
		RCK, -- Reference Clock
		RP, -- Radio Frequency Power Detected
		SDO -- Serial Data Out, from ADC
		: in std_logic; 
		OND, -- On Device, keeps power turned on.
		ENL, -- Enable Lamp, enables boost regulator.
		ONL, -- On Lamp, closes the lamp's mosfet switch.
		CONV, -- Convert, initiates ADC conversion
		SDI, -- Serial Data In, for ADC channel configuration
		SCK, -- Serial Clock, for ADC communication
		XEN, -- Transmit Enable, for data transmission
		TP1, -- Test Point One, available on the programming extension.
		TP2, -- Test Point Two, available on the programming extension.
		TP3 -- Test Point Three, a dummy output for code retention. 
		: 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 := 7; -- The identifier for this device.
	constant fck_divisor : integer := 12; -- Divisor to give 10 MHz on FCK, 5 MHz on TCK.
	constant frequency_low : integer := 12; -- Low frequency code for data transmission.
	constant sample_rate : integer := 512; -- Data sampling rate.
	
-- Stable Calibration Constants
	constant frequency_step : integer := 3; -- High minus low frequency code
	
-- 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;

-- Other Constants
	constant select_all : integer := 15; -- The all-device select id code.
	constant device_id_max : integer := 15; -- Defines range of id codes.
	constant max_brightness : integer := 5; -- For lamp full power.
	constant aux_id : integer := 15; -- The channel to use for acknowledgement
	constant ack_code : integer := 1; -- The acknowledgement code in the acknowledge message
	constant ack_time : integer := 21; -- The timestamp value for acknowledgement transmission
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;
	
-- Ring Oscillator and Transmit Clock
	component BUFBA is port (A : in std_logic; Z : out std_logic); end component;
	signal R1, R2, R3, R4, R5, ROCK, TCK, FCK : std_logic;
	attribute syn_keep of R1, R2, R3, R4, R5 : signal is true;
	attribute nomerge of R1, R2, R3, R4, R5 : signal is "";  
	
-- Byte Receiver
	signal RPS, -- Radio Frequency Power Synchronized
		IC, -- Initiate Command Reception
		TC, -- Terminate Command Reception
		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 brightness -- A code to set the lamp high-speed duty cycle.
		: std_logic_vector(2 downto 0) := std_logic_vector(
			to_unsigned(max_brightness,3));
	signal sensor_config -- A 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 TXA, -- Transmit Acknowledgment
		TXAD -- Transmit Acknowledgment Done
		: boolean := false;
		
-- 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
		SCRATCHBIT
		: boolean := false;
	signal STCK  -- Stimulus Clock
		: std_logic;

-- Sensor Sampling and Transmission
	signal TXEN, -- Sample Transmission Enabled
		TXI, -- Sample Transmit Initiate
		TXD, -- Sample Transmit Done
		TXB, -- Transmit Bit
		SCKEN, -- Enable SCK
		FHI, -- Frequency hi
		SSDO -- Synchronized SDO
		: boolean := false;
	signal scatter -- The transmission scatter value
		: std_logic_vector(3 downto 0) := "0000";
	signal sample -- The ADC sample value
		: 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

-- Power Cotroller
	Power_Controller: entity PCU port map (
		USERSTDBY => USERSTDBY, 
		CLRFLAG => CLRFLAG, 
		STDBY => STDBY);
	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;
			USERSTDBY <= '1';
			CLRFLAG <= '0';
		else
			counter := counter + 1;
			USERSTDBY <= '0';
			if (counter = PowerUpEnd-1) then 
				CLRFLAG <= '1'; 
			else 
				CLRFLAG <= '0'; 
			end if;
		end if;
		OND <= to_std_logic(SRUN or CPA or TXEN);
	end process;
	
-- Synchronize Radio Power Input.
	Synchronize_RP: process is 
	begin
		wait until (RCK = '0');
		RPS <= (RP = '1');
	end process;
	
-- Initiate Command Signal
-- We detect a long enough burst of command power to initiate
-- command reception.
	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;
	
-- Terminate Command Signal
-- We detect a long enough period without command power to 
-- terminate command reception.
	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;

-- Byte Receiver
-- 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;

-- Command Error Check
-- 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);
	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);
		
-- Command Processor
-- This process 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 dealay
-- for execution.
	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;
		
		-- 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 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 select_all and 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 = select_all) or (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.
		if (state = set_brightness_s) then 
			next_state := dec_count_s;
		end if;
		
		-- Logic to control the brightness register. We clear the brightness
		-- to all ones so the default setting is 100% duty cycle, or full power.
		if (state = stop_stimulus_s) then
			brightness <= std_logic_vector(to_unsigned(max_brightness,brightness'length));
		else
			if (state = set_brightness_s) then
				for i in 0 to 2 loop
					brightness(i) <= cm_out(i);
				end loop;
			else
				brightness <= brightness;
			end if;
		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 state = command_acknowledge_s then
			TXA <= true;
		else
			if TXAD then 
				TXA <= false;
			else
				TXA <= TXA;
			end if;
		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;

		-- 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;

-- Stimulus Clock Generator
	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;

-- Stimulus Generator
	Stimulus_Generator : process (STOPS, STCK) is
		variable state, next_state : integer range 0 to 4 := 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(rck_per_ms-2,8));
	
	begin 
		if STOPS 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 (state > 3) then
				next_state := 0;
			end if;

			state := next_state;
		end if;
		
		if rising_edge(STCK) then		
			-- 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 SRUN to keep the logic chip powered up.
			SRUN <= (state > 0);
		
			-- We assert ILP when il has the correct value.
			ILP <= (state = 2) and (il = to_integer(unsigned(random(4 downto 0))));
		end if;

		SCRATCHBIT <= (state = 3);
end process;
	
-- Lamp Pulse generator
	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, although its output
			-- may be modulated to reduce brightness.
			PA <= (pl > 0);
		
			-- We assert ENL to turn on the boost regulator only when we want the
			-- light to turn on. 
			ENL <= to_std_logic(PA);
		
			-- We want to detect rising edges on ILP, so we save the previous state.
			prev_ilp := ILP;	
		end if;
	end process;

-- Ring Oscillator. 
	R1 <= to_std_logic((SRUN or TXI or TXD) and (R4 = '0')); 	
	ring1 : BUFBA port map (R1,R2);
	ring2 : BUFBA port map (R2,R3);
	ring3 : BUFBA port map (R3,R4);
	ring4 : BUFBA port map (R4,R5);
	ROCK <= R5;

-- Fast Clock. 
	Fast_Clock : process is
		constant fck_length : integer := 2;
		variable count : integer range 0 to fck_divisor - 1 := 0;
	begin
		-- We run this state machine off the ring oscillator.
		wait until (ROCK = '1');
		
		-- The fck_divisor is set at the top of the code, and should be such that
		-- FCK is 10 MHz and TCK, which we obtain in the next process, is 5 MHz.
		-- In particular, the period of TCK must be within 195-215 ns.
		if (count = fck_divisor - 1) then 
			count := 0;
		else 
			count := count + 1;
		end if;
		
		-- The Fast Clock is a negative pulse of fck_length periods of ROCK.
		-- We will later use the falling edge of FCK to clock TCK, and the 
		-- rising edge to set outputs that depend upon the state of TCK.
		FCK <= to_std_logic((count >= 0) and (count <= fck_length));
	end process;
	
-- Transmit Clock.
	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;
	
-- Brightness Controller
	Brightness_Controller : process is
		variable count : integer range 0 to max_brightness - 1 := 0;
	begin
		-- This TCK is close to 5 MHz.
		wait until (TCK = '1');
		
		-- We want to modulate the lamp at 1 MHz, so we have a five-step 
		-- counter to govern the duty cycle.
		if (count = max_brightness - 1) then 
			count := 0;
		else
			count := count + 1;
		end if;
			
		-- We have the following relationship between the brightness code
		-- and the duty cycle of the lamp power during a pulse. Code 0 = 0%,
		-- 1 = 20%, 2 = 40%, 3 = 60%, 4 = 80%, >=5 = 100%. The default value
		-- of the brightness code is 5, so duty cycle is by default 100%.
		ONL <= to_std_logic(PA and (to_integer(unsigned(brightness)) > count));
	end process;

-- Sample Controller
	Sample_Controller : process is
		constant divisor : integer := 32768 / sample_rate;
		variable counter : integer range 0 to divisor - 1 := 0;
		variable xmit_sample : boolean := false;
		variable xmit_ack : boolean := false;
		variable xmit_sample_enable : boolean := false;
	begin
		-- Clock RCK is 32.768 kHz.
		wait until (RCK = '1');
		
		-- Sample transmission is enabled by the first configuration bit.
		xmit_sample_enable := (sensor_config(0) = '1');
		
		-- We assert the TXEN signal when xmit_sample_enable is true
		-- or when we are waiting to transmit an acknowledgement. We 
		-- use TXEN to keep the logic chip powered up.
		TXEN <= xmit_sample_enable or TXA;
		
		-- 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 := counter + 1;
		else
			counter := 0;
		end if;
		
		-- When the counter reaches the end of a sample period, we set
		-- the scatter value to the lower bits of the sample value.
		if (counter = divisor - 1) then
			for i in 0 to 3 loop
				scatter(i) <= sample(i);
			end loop;
		else
			scatter <= scatter;
		end if;
		
		-- We transmit a sample when the scatter is equal to the counter
		-- and sample transmission is enabled.
		xmit_sample := xmit_sample_enable and (counter = to_integer(unsigned(scatter)));
		
		-- We transmit an acknowledgement when the counter is equal to
		-- the acknowledgement time and we have TXA.
		xmit_ack := TXA and (counter = ack_time) and (not CPA);
		
		-- We initiate sampling and transmission with TXI when it is time
		-- to transmit a sample or an acknowledgement.
		TXI <= xmit_sample or xmit_ack;
		
		-- We issue Transmit Acknowledgement Done (TXAD) as soon was we
		-- start to transmit an acknowledgement, and for only one RCK cycle.
		-- By this means, TXA will be cleared on the next clock cycle, 
		-- avoiding double-tranmission of the acknowledgement. We also
		-- use TXAD in the Sample Transmitter to detect an acknowlegement
		-- transmission.
		TXAD <= xmit_ack;
	end process;

-- Sample Transmitter
	Sample_Transmitter : process is
		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_iid_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 data_id_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(device_id,4)); -- The device id bits.
		constant aux_id_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(aux_id,4)); -- The acknowledgement id bits.
		constant ack_code_bits : std_logic_vector(3 downto 0) := 
			std_logic_vector(to_unsigned(ack_code,4)); -- The acknowledgement code.
		variable state : integer range 0 to 63 := 0; -- Stample Transmit State
		variable data_bit, aux_bit : boolean := false; -- Transmit Data Bit
	begin
		wait until (TCK = '1');
		
		-- 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;
		else
			if (state < st_done) then 
				state := state + 1;
			else 
				state := st_done;
			end if;
		end if; 
		
		-- We synchronise the SDO input with TCK.
		SSDO <= (SDO = '1');

		-- 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 (data_id_bits(3) = '1'))
			or ((state = first_id_bit + 1) and (data_id_bits(2) = '1'))
			or ((state = first_id_bit + 2) and (data_id_bits(1) = '1'))
			or ((state = first_id_bit + 3) and (data_id_bits(0) = '1'))
			or ((state >= first_data_bit) and (state < first_iid_bit) and SSDO)
			or ((state = first_iid_bit + 0) and (data_id_bits(3) = '0'))
			or ((state = first_iid_bit + 1) and (data_id_bits(2) = '0'))
			or ((state = first_iid_bit + 2) and (data_id_bits(1) = '0'))
			or ((state = first_iid_bit + 3) and (data_id_bits(0) = '0'));
			
		-- The ack bit is the outgoing bit value for acknowledgment transmission.
		aux_bit := ((state >= 0) and (state < first_start_bit))
			or ((state = first_id_bit + 0) and (aux_id_bits(3) = '1'))
			or ((state = first_id_bit + 1) and (aux_id_bits(2) = '1'))
			or ((state = first_id_bit + 2) and (aux_id_bits(1) = '1'))
			or ((state = first_id_bit + 3) and (aux_id_bits(0) = '1'))
			or ((state = first_data_bit + 0) and (data_id_bits(3) = '1'))
			or ((state = first_data_bit + 1) and (data_id_bits(2) = '1'))
			or ((state = first_data_bit + 2) and (data_id_bits(1) = '1'))
			or ((state = first_data_bit + 3) and (data_id_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_iid_bit + 0) and (aux_id_bits(3) = '0'))
			or ((state = first_iid_bit + 1) and (aux_id_bits(2) = '0'))
			or ((state = first_iid_bit + 2) and (aux_id_bits(1) = '0'))
			or ((state = first_iid_bit + 3) and (aux_id_bits(0) = '0'));
		
		-- We choose between the data_bit and the ack_bit depending upon whether
		-- this is a data or acknowledge tranmsission.
		if TXAD then
			TXB <= aux_bit;
		else
			TXB <= data_bit;
		end if;
				
		-- SCKEN asserts TCK onto SCK.
		SCKEN <= (state >= start_sck) and (state <= end_sck);
		
		-- SDI configures the ADC.
		SDI <= to_std_logic(state = start_sck); 
		
		-- Shift the ADC bits into the sample register.
		for i in 0 to 15 loop
			if (state = end_sck - i) then
				sample(i) <= to_std_logic(SSDO);
			else
				sample(i) <= sample(i);
			end if;
		end loop;
	end process;

	CONV <= to_std_logic(not TXI);
	SCK <= to_std_logic((TCK = '0') and SCKEN);
	XEN <= to_std_logic(TXI and (not TXD) and (not CPA));
	
-- Frequency Modulation 
	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 Points. 
	TP1 <= to_std_logic(SCRATCHBIT);
	TP2 <= to_std_logic(ILP);
	
-- Keeper Outputs. If we don't send these signals to an output, the compiler
-- will eliminate them and all the logic behind them. In the case of STDBY, 
-- for example, all the standy power logic is eliminated and the chip is
-- always in full-power mode. It may be that some combination of attributes
-- will stop the elimination, but we have not found it yet.
	TP3 <= to_std_logic((STDBY = '1'));
		
end behavior;