head	1.5;
access;
symbols
	rel_1:1.4;
locks; strict;
comment	@# @;


1.5
date	2004.02.18.11.41.48;	author rherveille;	state Exp;
branches;
next	1.4;

1.4
date	2003.08.09.07.01.13;	author rherveille;	state Exp;
branches;
next	1.3;

1.3
date	2002.12.26.16.05.47;	author rherveille;	state Exp;
branches;
next	1.2;

1.2
date	2002.11.30.22.24.37;	author rherveille;	state Exp;
branches;
next	1.1;

1.1
date	2001.11.05.12.02.33;	author rherveille;	state Exp;
branches;
next	;


desc
@@


1.5
log
@Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command.
@
text
@---------------------------------------------------------------------
----                                                             ----
----  WISHBONE revB2 compl. I2C Master Core; byte-controller     ----
----                                                             ----
----                                                             ----
----  Author: Richard Herveille                                  ----
----          richard@@asics.ws                                   ----
----          www.asics.ws                                       ----
----                                                             ----
----  Downloaded from: http://www.opencores.org/projects/i2c/    ----
----                                                             ----
---------------------------------------------------------------------
----                                                             ----
---- Copyright (C) 2000 Richard Herveille                        ----
----                    richard@@asics.ws                         ----
----                                                             ----
---- This source file may be used and distributed without        ----
---- restriction provided that this copyright statement is not   ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer.----
----                                                             ----
----     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ----
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ----
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ----
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ----
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ----
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ----
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ----
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ----
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ----
---- LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ----
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ----
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ----
---- POSSIBILITY OF SUCH DAMAGE.                                 ----
----                                                             ----
---------------------------------------------------------------------

--  CVS Log
--
--  $Id: i2c_master_byte_ctrl.vhd,v 1.4 2003/08/09 07:01:13 rherveille Exp $
--
--  $Date: 2003/08/09 07:01:13 $
--  $Revision: 1.4 $
--  $Author: rherveille $
--  $Locker:  $
--  $State: Exp $
--
-- Change History:
--               $Log: i2c_master_byte_ctrl.vhd,v $
--               Revision 1.4  2003/08/09 07:01:13  rherveille
--               Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
--               Fixed a potential bug in the byte controller's host-acknowledge generation.
--
--               Revision 1.3  2002/12/26 16:05:47  rherveille
--               Core is now a Multimaster I2C controller.
--
--               Revision 1.2  2002/11/30 22:24:37  rherveille
--               Cleaned up code
--
--               Revision 1.1  2001/11/05 12:02:33  rherveille
--               Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
--               Code updated, is now up-to-date to doc. rev.0.4.
--               Added headers.
--




--
------------------------------------------
-- Byte controller section
------------------------------------------
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity i2c_master_byte_ctrl is
	port (
		clk    : in std_logic;
		rst    : in std_logic; -- synchronous active high reset (WISHBONE compatible)
		nReset : in std_logic;	-- asynchornous active low reset (FPGA compatible)
		ena    : in std_logic; -- core enable signal

		clk_cnt : in unsigned(15 downto 0);	-- 4x SCL

		-- input signals
		start,
		stop,
		read,
		write,
		ack_in : std_logic;
		din    : in std_logic_vector(7 downto 0);

		-- output signals
		cmd_ack  : out std_logic; -- command done
		ack_out  : out std_logic;
		i2c_busy : out std_logic; -- arbitration lost
		i2c_al   : out std_logic; -- i2c bus busy
		dout     : out std_logic_vector(7 downto 0);

		-- i2c lines
		scl_i   : in std_logic;  -- i2c clock line input
		scl_o   : out std_logic; -- i2c clock line output
		scl_oen : out std_logic; -- i2c clock line output enable, active low
		sda_i   : in std_logic;  -- i2c data line input
		sda_o   : out std_logic; -- i2c data line output
		sda_oen : out std_logic  -- i2c data line output enable, active low
	);
end entity i2c_master_byte_ctrl;

architecture structural of i2c_master_byte_ctrl is
	component i2c_master_bit_ctrl is
	port (
		clk    : in std_logic;
		rst    : in std_logic;
		nReset : in std_logic;
		ena    : in std_logic;				-- core enable signal

		clk_cnt : in unsigned(15 downto 0);		-- clock prescale value

		cmd     : in std_logic_vector(3 downto 0);
		cmd_ack : out std_logic; -- command done
		busy    : out std_logic; -- i2c bus busy
		al      : out std_logic; -- arbitration lost

		din  : in std_logic;
		dout : out std_logic;

		-- i2c lines
		scl_i   : in std_logic;  -- i2c clock line input
		scl_o   : out std_logic; -- i2c clock line output
		scl_oen : out std_logic; -- i2c clock line output enable, active low
		sda_i   : in std_logic;  -- i2c data line input
		sda_o   : out std_logic; -- i2c data line output
		sda_oen : out std_logic  -- i2c data line output enable, active low
	);
	end component i2c_master_bit_ctrl;

	-- commands for bit_controller block
	constant I2C_CMD_NOP  	: std_logic_vector(3 downto 0) := "0000";
	constant I2C_CMD_START	: std_logic_vector(3 downto 0) := "0001";
	constant I2C_CMD_STOP	 : std_logic_vector(3 downto 0) := "0010";
	constant I2C_CMD_READ	 : std_logic_vector(3 downto 0) := "0100";
	constant I2C_CMD_WRITE	: std_logic_vector(3 downto 0) := "1000";

	-- signals for bit_controller
	signal core_cmd : std_logic_vector(3 downto 0);
	signal core_ack, core_txd, core_rxd : std_logic;
	signal al : std_logic;

	-- signals for shift register
	signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
	signal shift, ld : std_logic;

	-- signals for state machine
	signal go, host_ack : std_logic;
	signal dcnt : unsigned(2 downto 0); -- data counter
	signal cnt_done : std_logic;

begin
	-- hookup bit_controller
	bit_ctrl: i2c_master_bit_ctrl port map(
		clk     => clk,
		rst     => rst,
		nReset  => nReset,
		ena     => ena,
		clk_cnt => clk_cnt,
		cmd     => core_cmd,
		cmd_ack => core_ack,
		busy    => i2c_busy,
		al      => al,
		din     => core_txd,
		dout    => core_rxd,
		scl_i   => scl_i,
		scl_o   => scl_o,
		scl_oen => scl_oen,
		sda_i   => sda_i,
		sda_o   => sda_o,
		sda_oen => sda_oen
	);
	i2c_al <= al;

	-- generate host-command-acknowledge
	cmd_ack <= host_ack;

	-- generate go-signal
	go <= (read or write or stop) and not host_ack;

	-- assign Dout output to shift-register
	dout <= sr;

	-- generate shift register
	shift_register: process(clk, nReset)
	begin
	    if (nReset = '0') then
	      sr <= (others => '0');
	    elsif (clk'event and clk = '1') then
	      if (rst = '1') then
	        sr <= (others => '0');
	      elsif (ld = '1') then
	        sr <= din;
	      elsif (shift = '1') then
	        sr <= (sr(6 downto 0) & core_rxd);
	      end if;
	    end if;
	end process shift_register;

	-- generate data-counter
	data_cnt: process(clk, nReset)
	begin
	    if (nReset = '0') then
	      dcnt <= (others => '0');
	    elsif (clk'event and clk = '1') then
	      if (rst = '1') then
	        dcnt <= (others => '0');
	      elsif (ld = '1') then
	        dcnt <= (others => '1');  -- load counter with 7
	      elsif (shift = '1') then
	        dcnt <= dcnt -1;
	      end if;
	    end if;
	end process data_cnt;

	cnt_done <= '1' when (dcnt = 0) else '0';

	--
	-- state machine
	--
	statemachine : block
	    type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
	    signal c_state : states;
	begin
	    --
	    -- command interpreter, translate complex commands into simpler I2C commands
	    --
	    nxt_state_decoder: process(clk, nReset)
	    begin
	        if (nReset = '0') then
	          core_cmd <= I2C_CMD_NOP;
	          core_txd <= '0';
	          shift    <= '0';
	          ld       <= '0';
	          host_ack <= '0';
	          c_state  <= st_idle;
	          ack_out  <= '0';
	        elsif (clk'event and clk = '1') then
	          if (rst = '1' or al = '1') then
	            core_cmd <= I2C_CMD_NOP;
	            core_txd <= '0';
	            shift    <= '0';
	            ld       <= '0';
	            host_ack <= '0';
	            c_state  <= st_idle;
	            ack_out  <= '0';
	          else
	            -- initialy reset all signal
	            core_txd <= sr(7);
	            shift    <= '0';
	            ld       <= '0';
	            host_ack <= '0';

	            case c_state is
	              when st_idle =>
	                 if (go = '1') then
	                   if (start = '1') then
	                     c_state  <= st_start;
	                     core_cmd <= I2C_CMD_START;
	                   elsif (read = '1') then
	                     c_state  <= st_read;
	                     core_cmd <= I2C_CMD_READ;
	                   elsif (write = '1') then
	                     c_state  <= st_write;
	                     core_cmd <= I2C_CMD_WRITE;
	                   else -- stop
	                     c_state  <= st_stop;
	                     core_cmd <= I2C_CMD_STOP;
	                   end if;

	                   ld <= '1';
	                 end if;

	              when st_start =>
	                 if (core_ack = '1') then
	                   if (read = '1') then
	                     c_state  <= st_read;
	                     core_cmd <= I2C_CMD_READ;
	                   else
	                     c_state  <= st_write;
	                     core_cmd <= I2C_CMD_WRITE;
	                   end if;

	                   ld <= '1';
	                 end if;

	              when st_write =>
	                 if (core_ack = '1') then
	                   if (cnt_done = '1') then
	                     c_state  <= st_ack;
	                     core_cmd <= I2C_CMD_READ;
	                   else
	                     c_state  <= st_write;       -- stay in same state
	                     core_cmd <= I2C_CMD_WRITE;  -- write next bit
	                     shift    <= '1';
	                   end if;
	                 end if;

	              when st_read =>
	                 if (core_ack = '1') then
	                   if (cnt_done = '1') then
	                     c_state  <= st_ack;
	                     core_cmd <= I2C_CMD_WRITE;
	                   else
	                     c_state  <= st_read;      -- stay in same state
	                     core_cmd <= I2C_CMD_READ; -- read next bit
	                   end if;

	                   shift    <= '1';
	                   core_txd <= ack_in;
	                 end if;

	              when st_ack =>
	                 if (core_ack = '1') then
	                   -- check for stop; Should a STOP command be generated ?
	                   if (stop = '1') then
	                     c_state  <= st_stop;
	                     core_cmd <= I2C_CMD_STOP;
	                   else
	                     c_state  <= st_idle;
	                     core_cmd <= I2C_CMD_NOP;

	                     -- generate command acknowledge signal
	                     host_ack <= '1';
	                   end if;

	                   -- assign ack_out output to core_rxd (contains last received bit)
	                   ack_out  <= core_rxd;

	                   core_txd <= '1';
	                 else
	                   core_txd <= ack_in;
	                 end if;

	              when st_stop =>
	                 if (core_ack = '1') then
	                   c_state  <= st_idle;
	                   core_cmd <= I2C_CMD_NOP;

	                   -- generate command acknowledge signal
	                   host_ack <= '1';
	                 end if;

	              when others => -- illegal states
	                 c_state  <= st_idle;
	                 core_cmd <= I2C_CMD_NOP;
	                 report ("Byte controller entered illegal state.");

	            end case;

	          end if;
	        end if;
	    end process nxt_state_decoder;

	end block statemachine;

end architecture structural;

@


1.4
log
@Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
Fixed a potential bug in the byte controller's host-acknowledge generation.
@
text
@d40 1
a40 1
--  $Id: i2c_master_byte_ctrl.vhd,v 1.3 2002/12/26 16:05:47 rherveille Exp $
d42 2
a43 2
--  $Date: 2002/12/26 16:05:47 $
--  $Revision: 1.3 $
d50 4
a277 1
	                     host_ack <= '1'; -- generate acknowledge signal
@


1.3
log
@Core is now a Multimaster I2C controller.
@
text
@d40 1
a40 1
--  $Id: i2c_master_byte_ctrl.vhd,v 1.2 2002/11/30 22:24:37 rherveille Exp $
d42 2
a43 2
--  $Date: 2002/11/30 22:24:37 $
--  $Revision: 1.2 $
d50 3
d328 3
a335 3
	                   -- generate command acknowledge signal
	                   host_ack <= '1';

d345 3
@


1.2
log
@Cleaned up code
@
text
@d40 1
a40 1
--  $Id: i2c_master_byte_ctrl.vhd,v 1.1 2001/11/05 12:02:33 rherveille Exp $
d42 2
a43 2
--  $Date: 2001/11/05 12:02:33 $
--  $Revision: 1.1 $
d50 3
d89 1
a89 1
		cmd_ack  : out std_logic;
d91 2
a92 1
		i2c_busy : out std_logic;
d116 3
a118 2
		cmd_ack : out std_logic;
		busy    : out std_logic;
d143 1
d156 1
a156 1
	u1: i2c_master_bit_ctrl port map(
d165 1
d175 1
d241 1
a241 1
	          if (rst = '1') then
@


1.1
log
@Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
Code updated, is now up-to-date to doc. rev.0.4.
Added headers.
@
text
@d40 1
a40 1
--  $Id: $
d42 3
a44 3
--  $Date: $
--  $Revision: $
--  $Author: $
d46 1
a46 1
--  $State: $
d49 6
a54 1
--               $Log: $
a68 3
	generic(
		Tcq : time := 1 ns
	);
d75 1
a75 1
		clk_cnt : in unsigned(15 downto 0);	-- 4x SCL 
d103 23
a125 26
		generic(
			Tcq : time := Tcq
		);
		port (
			clk    : in std_logic;
			rst    : in std_logic;
			nReset : in std_logic;
			ena    : in std_logic;				-- core enable signal

			clk_cnt : in unsigned(15 downto 0);		-- clock prescale value

			cmd     : in std_logic_vector(3 downto 0);
			cmd_ack : out std_logic;
			busy    : out std_logic;

			din  : in std_logic;
			dout : out std_logic;

			-- i2c lines
			scl_i   : in std_logic;  -- i2c clock line input
			scl_o   : out std_logic; -- i2c clock line output
			scl_oen : out std_logic; -- i2c clock line output enable, active low
			sda_i   : in std_logic;  -- i2c data line input
			sda_o   : out std_logic; -- i2c data line output
			sda_oen : out std_logic  -- i2c data line output enable, active low
		);
d171 1
a171 1
	
d181 11
a191 11
		if (nReset = '0') then
			sr <= (others => '0') after Tcq;
		elsif (clk'event and clk = '1') then
			if (rst = '1') then
				sr <= (others => '0') after Tcq;
			elsif (ld = '1') then
				sr <= din after Tcq;
			elsif (shift = '1') then
				sr <= (sr(6 downto 0) & core_rxd) after Tcq;
			end if;
		end if;
d197 11
a207 11
		if (nReset = '0') then
			dcnt <= (others => '0') after Tcq;
		elsif (clk'event and clk = '1') then
			if (rst = '1') then
				dcnt <= (others => '0') after Tcq;
			elsif (ld = '1') then
				dcnt <= (others => '1') after Tcq; -- load counter with 7
			elsif (shift = '1') then
				dcnt <= dcnt -1 after Tcq;
			end if;
		end if;
d216 2
a217 2
		type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
		signal c_state : states;
d219 127
a345 137
		--
		-- command interpreter, translate complex commands into simpler I2C commands
		--
		nxt_state_decoder: process(clk, nReset)
		begin
			if (nReset = '0') then
				core_cmd <= I2C_CMD_NOP after Tcq;
				core_txd <= '0' after Tcq;
				
				shift    <= '0' after Tcq;
				ld       <= '0' after Tcq;

				host_ack <= '0' after Tcq;
				c_state  <= st_idle after Tcq;

				ack_out  <= '0' after Tcq;
			elsif (clk'event and clk = '1') then
				if (rst = '1') then
					core_cmd <= I2C_CMD_NOP after Tcq;
					core_txd <= '0' after Tcq;
				
					shift    <= '0' after Tcq;
					ld       <= '0' after Tcq;

					host_ack <= '0' after Tcq;
					c_state  <= st_idle after Tcq;

					ack_out  <= '0' after Tcq;
				else
					-- initialy reset all signal
					core_txd <= sr(7) after Tcq;

					shift    <= '0' after Tcq;
					ld       <= '0' after Tcq;

					host_ack <= '0' after Tcq;

					case c_state is
						when st_idle =>
							if (go = '1') then
								if (start = '1') then
									c_state  <= st_start after Tcq;
									core_cmd <= I2C_CMD_START after Tcq;
								elsif (read = '1') then
									c_state  <= st_read after Tcq;
									core_cmd <= I2C_CMD_READ after Tcq;
								elsif (write = '1') then
									c_state  <= st_write after Tcq;
									core_cmd <= I2C_CMD_WRITE after Tcq;
								else -- stop
									c_state  <= st_stop after Tcq;
									core_cmd <= I2C_CMD_STOP after Tcq;

									host_ack <= '1' after Tcq; -- generate acknowledge signal
								end if;

								ld <= '1' after Tcq;
							end if;

						when st_start =>
							if (core_ack = '1') then
								if (read = '1') then
									c_state  <= st_read after Tcq;
									core_cmd <= I2C_CMD_READ after Tcq;
								else
									c_state  <= st_write after Tcq;
									core_cmd <= I2C_CMD_WRITE after Tcq;
								end if;

								ld <= '1' after Tcq;
							end if;

						when st_write =>
							if (core_ack = '1') then
								if (cnt_done = '1') then
									c_state  <= st_ack after Tcq;
									core_cmd <= I2C_CMD_READ after Tcq;
								else
									c_state  <= st_write after Tcq;       -- stay in same state
									core_cmd <= I2C_CMD_WRITE after Tcq;  -- write next bit

									shift    <= '1' after Tcq;
								end if;
							end if;			

						when st_read =>
							if (core_ack = '1') then
								if (cnt_done = '1') then
									c_state  <= st_ack after Tcq;
									core_cmd <= I2C_CMD_WRITE after Tcq;
								else
									c_state  <= st_read after Tcq;      -- stay in same state
									core_cmd <= I2C_CMD_READ after Tcq; -- read next bit
								end if;

								shift    <= '1' after Tcq;
								core_txd <= ack_in after Tcq;
							end if;			

						when st_ack =>
							if (core_ack = '1') then
								-- check for stop; Should a STOP command be generated ?
								if (stop = '1') then
									c_state  <= st_stop after Tcq;
									core_cmd <= I2C_CMD_STOP after Tcq;
								else
									c_state  <= st_idle after Tcq;
									core_cmd <= I2C_CMD_NOP after Tcq;
								end if;

								-- assign ack_out output to core_rxd (contains last received bit)
								ack_out  <= core_rxd after Tcq;

								-- generate command acknowledge signal
								host_ack <= '1' after Tcq;

								core_txd <= '1' after Tcq;
							else
								core_txd <= ack_in after Tcq;
							end if;

						when st_stop =>
							if (core_ack = '1') then
								c_state  <= st_idle after Tcq;
								core_cmd <= I2C_CMD_NOP after Tcq;
							end if;

						when others => -- illegal states
							c_state  <= st_idle after Tcq;
							core_cmd <= I2C_CMD_NOP after Tcq;
							report ("Byte controller entered illegal state.");

					end case;

				end if;
			end if;
		end process nxt_state_decoder;
@

