----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    14:40:52 07/09/2012 
-- Design Name: 
-- Module Name:    onewire - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if itantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

library WORK;
use WORK.common.ALL;

entity onewire is
	Generic (
		ctrl_reg		: integer;
		read_reg		: integer;
		write_reg	: integer;
	   crc_reg		: integer
	);
   Port (
		i 		: in t_onewire_i;
		o 		: out t_onewire_o;
		wire	: inout std_logic;
		clk40 : in std_logic
	 );
end onewire;

architecture Behavioral of onewire is


	type t_owstatus is (idle, init, wr, rd);
	
	constant ow_init_total 				: integer := 40 * 700;
	constant ow_init_asserted 			: integer := 40 * 600;
	constant ow_init_sampledelay 		: integer := 40 * 30;
	
	constant ow_write_total 			: integer := 40 * 70;
	constant ow_write_asserted0 		: integer := 40 * 60;
	constant ow_write_asserted1 		: integer := 40 * 5;
	
	constant ow_read_total 				: integer := 40 * 70;
	constant ow_read_asserted 			: integer := 40 * 5;
	constant ow_read_sampledelay 		: integer := 40 * 30; 
	
	constant ow_maxcount					: integer := ow_init_total;

begin



process (clk40)
	variable state 			: t_owstatus := idle;
	variable substate 		: integer range 8 downto 0 := 0;
	variable counter 			: integer range ow_maxcount downto 0 := 0;
	variable deassert_point	: integer range ow_maxcount downto 0 := 0;
	variable sample_point 	: integer range ow_maxcount downto 0 := 0;
begin
	if rising_edge(clk40) then
		o.reg_int <= (others => (others => 'Z'));
		o.reg_ch_int <= (others => 'Z');
	
		if counter > 0 then counter := counter -1;
		end if;

		case state is
			----------------------------------------------------------------------
			when idle =>
				if i.ext_wr(ctrl_reg) = '1' then 
					if i.reg(ctrl_reg)(0) = '1' then 
						state := init;
						substate := 1;
					elsif i.reg(ctrl_reg)(1) = '1' then 
						state := wr;
						substate := 1;
					elsif i.reg(ctrl_reg)(2) = '1' then 
						state := rd;
						substate := 1;
					elsif i.reg(ctrl_reg)(3) = '1' then 
						state := wr;
						substate := 8;
					elsif i.reg(ctrl_reg)(4) = '1' then 
						state := rd;
						substate := 8;
					end if;
				end if;
			----------------------------------------------------------------------
			when init =>
				if counter = 0 and substate = 1 then
					substate := 0;
					wire <= '0';
					counter := ow_init_total;
					deassert_point := ow_init_total - ow_init_asserted;
					sample_point := deassert_point - ow_init_sampledelay;
				elsif counter = deassert_point then wire <= 'Z';
				elsif counter = sample_point then 
					o.reg_int(read_reg) <= "0000000" & wire;
					o.reg_ch_int(read_reg) <= not i.reg_ch_int(read_reg);
					o.reg_int(crc_reg) <= (others => '0');
					o.reg_ch_int(crc_reg) <= not i.reg_ch_int(crc_reg);				
				elsif counter = 0 then state := idle;
				end if;
			----------------------------------------------------------------------
			when wr =>
				if counter = 0 and substate > 0 then
					substate := substate - 1;
					wire <= '0';
					counter := ow_write_total;
					if i.reg(write_reg)(7-substate) = '0' then	deassert_point := ow_write_total - ow_write_asserted0;
					else deassert_point := ow_write_total - ow_write_asserted1;
					end if;
				elsif counter = deassert_point then wire <= 'Z';
				elsif counter = 0 then state := idle;
				end if;
			----------------------------------------------------------------------
			when rd =>
				if counter = 0 and substate > 0 then
					substate := substate - 1;
					wire <= '0';
					counter := ow_read_total;
					deassert_point := ow_read_total - ow_read_asserted;
					sample_point := deassert_point - ow_read_sampledelay;
				elsif counter = deassert_point then wire <= 'Z';
				elsif counter = sample_point then
					o.reg_int(read_reg) <= wire & "0000000" ;
					o.reg_ch_int(read_reg) <= not i.reg_ch_int(read_reg);
					o.reg_int(crc_reg) <= (i.reg(crc_reg)(0) xor wire) & 
					                        (i.reg(crc_reg)(7) )& 
					                        (i.reg(crc_reg)(6) )& 
					                        (i.reg(crc_reg)(5) )& 
					                        (i.reg(crc_reg)(4) xor (i.reg(crc_reg)(0) xor wire) )& 
					                        (i.reg(crc_reg)(3) xor (i.reg(crc_reg)(0) xor wire) )& 
					                        (i.reg(crc_reg)(2) )& 
					                        (i.reg(crc_reg)(1) );
					o.reg_ch_int(crc_reg) <= not i.reg_ch_int(crc_reg);				
				elsif counter = 0 then state := idle;
				end if;
		end case;
	end if;
end process;



end Behavioral;

