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

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

-- Version 05, 31-DEC-19: Expand ring to a maximum of thirteen buffers. Those not used will be eliminated by the
-- compiler. The incoming calib value sets the output frequyency. We support calib values 10-25, which in our 
-- A3036A provide a CK period 80 to 127 ns, with the period non-decreasing with increasing calib value.

entity ring_oscillator is 
	port (
		ENABLE : in std_logic;
		calib : in integer range 0 to 31;
		CK : out std_logic);
end;

architecture behavior of ring_oscillator is 

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

-- Attributes to guide the compiler.
	attribute syn_keep : boolean;
	attribute nomerge : string;

-- 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, R6, R7, R8, R9, R10, R11, R12, R13 : std_logic;
	attribute syn_keep of R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13 : signal is true;
	attribute nomerge of R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13 : signal is ""; 
	signal RIN : std_logic;
	signal end_count : integer;

begin
	
	ring1 : BUFBA port map (RIN,R1);
	ring2 : BUFBA port map (R1,R2);
	ring3 : BUFBA port map (R2,R3);
	ring4 : BUFBA port map (R3,R4);
	ring5 : BUFBA port map (R4,R5);
	ring6 : BUFBA port map (R5,R6);
	ring7 : BUFBA port map (R6,R7);
	ring8 : BUFBA port map (R7,R8);
	ring9 : BUFBA port map (R8,R9);
	ring10 : BUFBA port map (R9,R10);
	ring11 : BUFBA port map (R10,R11);
	ring12 : BUFBA port map (R11,R12);
	ring13 : BUFBA port map (R12,R13);	

	divider : process (R1, calib) is
		constant ck_length : integer := 1;
		variable count : integer range 0 to 7 := 0;
	begin	
	
		if (calib <= 10) then
			RIN <= to_std_logic((ENABLE = '1') and (R9 = '0'));
			end_count <= 5;
		end if;
		if (calib = 11) then
			RIN <= to_std_logic((ENABLE = '1') and (R7 = '0'));
			end_count <= 7;
		end if;
		if (calib = 12) then
			RIN <= to_std_logic((ENABLE = '1') and (R10 = '0'));
			end_count <= 5;
		end if;
		if (calib = 13) then
			RIN <= to_std_logic((ENABLE = '1') and (R11 = '0'));
			end_count <= 5;
		end if;
		if (calib = 14) then
			RIN <= to_std_logic((ENABLE = '1') and (R8 = '0'));
			end_count <= 7;
		end if;
		if (calib = 15) then
			RIN <= to_std_logic((ENABLE = '1') and (R13 = '0'));
			end_count <= 4;
		end if;
		if (calib = 16) then
			RIN <= to_std_logic((ENABLE = '1') and (R7 = '0'));
			end_count <= 8;
		end if;
		if (calib = 17) then
			RIN <= to_std_logic((ENABLE = '1') and (R9 = '0'));
			end_count <= 6;
		end if;
		if (calib = 18) then
			RIN <= to_std_logic((ENABLE = '1') and (R10 = '0'));
			end_count <= 6;
		end if;
		if (calib = 19) then
			RIN <= to_std_logic((ENABLE = '1') and (R12 = '0'));
			end_count <= 5;
		end if;
		if (calib = 20) then
			RIN <= to_std_logic((ENABLE = '1') and (R9 = '0'));
			end_count <= 7;
		end if;
		if (calib = 21) then
			RIN <= to_std_logic((ENABLE = '1') and (R8 = '0'));
			end_count <= 8;
		end if;
		if (calib = 22) then
			RIN <= to_std_logic((ENABLE = '1') and (R13 = '0'));
			end_count <= 5;
		end if;
		if (calib = 23) then
			RIN <= to_std_logic((ENABLE = '1') and (R11 = '0'));
			end_count <= 6;
		end if;
		if (calib = 24) then
			RIN <= to_std_logic((ENABLE = '1') and (R10 = '0'));
			end_count <= 7;
		end if;
		if (calib >= 25) then
			RIN <= to_std_logic((ENABLE = '1') and (R9 = '0'));
			end_count <= 8;
		end if;
		
		if rising_edge(R1) then
			if (count = end_count - 1) then 
				count := 0;
			else 
				count := count + 1;
			end if;
			if (count >= 0) and (count <= ck_length) then
				CK <= '1';
			else
				CK <= '0';
			end if;
		end if;
	end process;
	
end behavior;