?? i2c_slave.vhd
字號:
------------------------------------------------------------------------------
--
-- Name: i2c_slave.vhd
--
-- Description: i2c slave emulation model for simulation
--
-- $Revision: 1.0 $
--
-- Copyright 2004 Lattice Semiconductor Corporation. All rights reserved.
--
------------------------------------------------------------------------------
-- Permission:
--
-- Lattice Semiconductor grants permission to use this code for use
-- in synthesis for any Lattice programmable logic product. Other
-- use of this code, including the selling or duplication of any
-- portion is strictly prohibited.
--
-- Disclaimer:
--
-- This VHDL or Verilog source code is intended as a design reference
-- which illustrates how these types of functions can be implemented.
-- It is the user's responsibility to verify their design for
-- consistency and functionality through the use of formal
-- verification methods. Lattice Semiconductor provides no warranty
-- regarding the use or functionality of this code.
------------------------------------------------------------------------------
--
-- Lattice Semiconductor Corporation
-- 5555 NE Moore Court
-- Hillsboro, OR 97124
-- U.S.A
--
-- TEL: 1-800-Lattice (USA and Canada)
-- 408-826-6000 (other locations)
--
-- web: http://www.latticesemi.com/
-- email: techsupport@latticesemi.com
--
------------------------------------------------------------------------------
--This is a generic standard mode slave model for I2C.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned."-";
use ieee.std_logic_unsigned."+";
use ieee.std_logic_textio.all;
use std.textio.all;
use ieee.numeric_std.all;
entity i2c_slave is port ( scl : in std_logic;
sda : inout std_logic);
end i2c_slave;
architecture behave of i2c_slave is
signal clk : std_logic := '0';
signal rst_l : std_logic;
type mem_256 is array (255 downto 0) of std_logic_vector(7 downto 0);
signal mem:mem_256;
signal word_address : std_logic_vector(7 downto 0) := "00000000"; -- counts the active byte
signal start_detect : std_logic;
signal stop_detect : std_logic;
signal sda_reg : std_logic;
signal sda_reg_delayed : std_logic;
signal scl_reg : std_logic;
signal scl_reg_delayed : std_logic;
signal start_pulse : std_logic;
signal stop_pulse : std_logic;
signal scl_pulse : std_logic;
signal scl_neg_pulse : std_logic;
signal address_reg_7 : std_logic_vector(6 downto 0);-- All 7 Bits of 7 bit addressing
signal temp10 : std_logic_vector(9 downto 0);
signal address_reg_10_upper : std_logic_vector(6 downto 0);-- Upper 2 bits of address
signal address_reg_10_lower : std_logic_vector(7 downto 0); -- lower 8 bits of address
signal current_state : std_logic_vector(3 downto 0);
signal next_state : std_logic_vector(3 downto 0);
signal in_reg : std_logic_vector(7 downto 0) := "00000000";
signal out_reg : std_logic_vector(7 downto 0):= "00000000"; -- registers used to hold the input
-- and output data to-from the sda line
signal bit_counter : std_logic_vector(3 downto 0) := "0000"; -- Used to counter what bit is being selected
-- for the in_reg and out_reg
signal r_w_bit : std_logic := '0'; -- used to hold the read write bit;
signal hit_7 : std_logic := '0';
signal hit_10_upper : std_logic := '0';
signal hit_10_lower : std_logic := '0'; -- flags for address hits
signal sda_out : std_logic := '0';
signal sda_out2 : std_logic := '0';
signal ack_ctrl : std_logic := '0';
signal in_reg_enable : std_logic := '0'; -- the clock enable for the in_reg registers.
signal out_en : std_logic := '0'; -- the output enable
signal word_add_flag : std_logic := '0';
signal ack_flag : std_logic := '0';
signal temp_add_upper : std_logic_vector(7 downto 1) := "0000000";
signal temp_add_lower : std_logic_vector(7 downto 0) := "00000000"; -- temp_add_upper & temp_add_lower are
-- used to hold the first &
-- second address bytes of 10 bit
-- addressing so that during a 10 bit addressing
-- read the value of the current 10 bit address
-- can be compared with the last read.
signal read_10_flag : std_logic := '0'; -- This flag is set when the temp_add matches the current
-- address_reg_10_upper and the r/w is a 1. This tells
-- the ack to goto a data read state instead of getting
-- the second byte of address.
-----------------------------------------------------------------------
-- defines
-- used for address_mode parameter
constant seven_bit : integer := 0;
-- used for address_mode parameter
constant ten_bit : integer := 1;
-- used in upper 5 bits of address_reg_10_upper
-- DON'T CHANGE
--`define ten_bit_add "11110"
constant ten_bit_add : std_logic_vector(4 downto 0) := "11110";
-- a 1 turns this on and a 0 off
--`define debug 0
constant debug : integer := 0;
-----------------------------------------------------------------------
-- constants
constant period : time := 30 ns;-- using 33 MHz
constant reset_time : time := 20 ns;-- hold reset low this long
-- DESIGNER SET the following parameter to use 7 or 10 bit addressing
constant address_mode : integer := 0; --`seven_bit; Use `seven_bit or `ten_bit
-- depending on the value in address_mode either seven_bit_address or
-- ten_bit_address will be used.
-- DESIGNER SET the next parameter with the 7 bit address the slave
-- should respond to. MSB->LSB
-- example: "1010_000";
constant seven_bit_address : std_logic_vector(6 downto 0) := "1010000";
-- DESIGNER SET the next parameter with the 10 bit address the slave
-- should respond to. MSB->LSB
-- example: "1011001010";
constant ten_bit_address : std_logic_vector(9 downto 0) := "1011001010";
-- state bits
constant idle : std_logic_vector(3 downto 0) := "0000";
constant start : std_logic_vector(3 downto 0) := "0001";
constant address : std_logic_vector(3 downto 0) := "0010";
constant ack : std_logic_vector(3 downto 0) := "0011";
constant data : std_logic_vector(3 downto 0) := "0100";
constant data_ack : std_logic_vector(3 downto 0) := "0101";
signal test_std_vec : std_logic_vector(7 downto 0);
signal test_int :integer;
-- signals to convert sda and scl from 0 or H values to bit values
signal sda1 : bit;
signal scl1 : bit;
begin
test_std_vec <= "00000010";
-----------------------------------------------------------------------
-- internal clock for the model
clk <= not clk after(period / 2);
-----------------------------------------------------------------------
-----------------------------------------------------------------------------
-- sda_out is an internal reg that is assigned a 0 when the output should be
-- 0 and it assigns a Z otherwise.
sda <= '0' when (sda_out = '0' and out_en = '1' and sda_out2 = '0') else 'Z';
sda1 <= To_bit(sda);
scl1 <= To_bit(scl);
----------------------------------------------------------------------
-- print some status
status1:process(scl1)
variable L :line;
begin
if(rising_edge(clk)) then
if (debug = 1 and scl1 = '1') then
write(L,now, justified => right, field=>10,unit=>ns);
write(L,string'(" Received Clock Data "));
write(L, sda1);
writeline(output,L);
end if;
end if;
end process;
-----------------------------------------------------------------------
-- initialize the address registers, mem array, clk and control the reset
initial : process
variable L : line;
variable cnt:std_logic_vector(7 downto 0);
begin
rst_l <= '0'; -- turn on reset signal
wait for reset_time;
rst_l <= '1'; -- turn off reset signal
temp10 <= "0000000000";
address_reg_10_upper <= "0000000";
address_reg_10_lower <= "00000000";
-- initialize the address registers
if (address_mode = seven_bit) then
write(L,now, justified => right, field=>10,unit=>ns);
write(L,string'(" Using 7 bit Addressing "));
writeline(output,L);
address_reg_7 <= seven_bit_address;
elsif (address_mode = ten_bit) then
write(L,now, justified => right, field=>10,unit=>ns);
write(L,string'(" Using 10 Bit Addressing "));
writeline(output,L);
temp10 <= ten_bit_address;
address_reg_10_upper <= ten_bit_add & temp10(9 downto 9); --{`ten_bit_add, temp10[9:8]}; 2 MSB
address_reg_10_lower <= temp10(7 downto 0);
else
write(L,now, justified => right, field=>10,unit=>ns);
write(L,string'(" ERROR address_mode parameter is INVALID "));
writeline(output,L);
end if;
wait; -- execute this process only once
end process;
------------------------------------------------------------------------
-- start and stop detect logic
ss : process (clk,rst_l,sda1)
begin
if (rst_l = '0') then
sda_reg <= '1'; -- bus is active low
sda_reg_delayed <= '1';
elsif(rising_edge(clk)) then
if(sda1 = '1') then
sda_reg <= '1';
else
sda_reg <= '0';
end if;
sda_reg_delayed <= sda_reg;
end if;
end process;
-- detect a high to low while scl is high
-- start_pulse
srtpulse : process(clk,rst_l)
begin
if (rst_l = '0') then
start_pulse <= '0';
elsif(rising_edge(clk)) then
if(sda_reg = '0' and sda_reg_delayed = '1' and scl1 = '1') then
start_pulse <= '1';
else
start_pulse <= '0';
end if;
end if;
end process;
-- start flag
srtflg : process(clk,rst_l)
begin
if (rst_l = '0') then
start_detect <= '0';
elsif(rising_edge(clk)) then
if(start_pulse = '1') then
start_detect <= '1';
elsif (scl1 = '0') then
start_detect <= '0'; -- clear start bit
else
start_detect <= start_detect;
end if;
end if;
end process;
-- detect a low to high while scl is high
-- stop_pulse
stppulse : process(clk,rst_l)
begin
if (rst_l = '0') then
stop_pulse <= '0';
elsif(rising_edge(clk)) then
if (sda_reg = '1' and sda_reg_delayed = '0' and scl1 = '1') then
stop_pulse <= '1';
else
stop_pulse <= '0';
end if;
end if;
end process;
--stop flag
stpflg : process(clk,rst_l)
begin
if (rst_l = '0') then
stop_detect <= '0';
elsif(rising_edge(clk)) then
if (stop_pulse = '1') then
stop_detect <= '1';
elsif (current_state = idle) then
stop_detect <= '0'; -- clear start bit
end if;
end if;
end process;
------------------------------------------
------------------------------------------
-- SCL posedge & nededge detector regs
scldet : process(clk,rst_l,scl)
begin
if (rst_l = '0') then
scl_reg <= '1';
scl_reg_delayed <= '1';
elsif(rising_edge(clk)) then
if(scl1 = '1') then
scl_reg <= '1';
else
scl_reg <= '0';
end if;
scl_reg_delayed <= scl_reg;
end if;
end process;
-- SCL posedge detector
sclpos : process(clk,rst_l)
begin
if (rst_l = '0') then
scl_pulse <= '0';
elsif(rising_edge(clk)) then
if (scl_reg = '1' and scl_reg_delayed = '0') then
scl_pulse <= '1';
else
scl_pulse <= '0';
end if;
end if;
end process;
-- SCL negedge detector
sclneg : process(clk,rst_l)
begin
if (rst_l = '0') then
scl_neg_pulse <= '0';
elsif(rising_edge(clk)) then
if (scl_reg = '0' and scl_reg_delayed = '1') then
scl_neg_pulse <= '1';
else
scl_neg_pulse <= '0';
end if;
end if;
end process;
--------------------------------------------
--------------------------------------------
-- Output Mux
outmux:process(out_reg, bit_counter,ack_ctrl,sda_out2)
begin
if(ack_ctrl = '0') then
case bit_counter is
when "0000" =>
sda_out <= out_reg(7);
when "0001" =>
sda_out <= out_reg(6);
when "0010" =>
sda_out <= out_reg(5);
when "0011" =>
sda_out <= out_reg(4);
when "0100" =>
sda_out <= out_reg(3);
when "0101" =>
sda_out <= out_reg(2);
when "0110" =>
sda_out <= out_reg(1);
when "0111" =>
sda_out <= out_reg(0);
when others =>
sda_out <= out_reg(0);
end case;
else
sda_out <= sda_out2;
end if;
end process;
--------------------------------------------
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -