diff --git a/modules/common/gc_glitch_filt.vhd b/modules/common/gc_glitch_filt.vhd index b291d8af1dd6ea7eaefdda1e7f66bfd808a2a9ea..bbd8fbb7f09c2229e99c993069465e0ac10c8e91 100644 --- a/modules/common/gc_glitch_filt.vhd +++ b/modules/common/gc_glitch_filt.vhd @@ -66,29 +66,10 @@ end entity gc_glitch_filt; architecture behav of gc_glitch_filt is - --============================================================================ - -- Component declarations - --============================================================================ - component gc_sync_ffs is - generic( - g_sync_edge : string := "positive" - ); - port( - clk_i : in std_logic; -- clock from the destination clock domain - rst_n_i : in std_logic; -- reset - data_i : in std_logic; -- async input - synced_o : out std_logic; -- synchronized output - npulse_o : out std_logic; -- negative edge detect output (single-clock - -- pulse) - ppulse_o : out std_logic -- positive edge detect output (single-clock - -- pulse) - ); - end component gc_sync_ffs; - --============================================================================ -- Signal declarations --============================================================================ - signal gc_glitch_filt : std_logic_vector(g_len downto 0); + signal glitch_filt : std_logic_vector(g_len downto 0); signal dat_synced : std_logic; --============================================================================== @@ -112,7 +93,7 @@ begin ); -- Then, assign the current sample of the glitch filter - gc_glitch_filt(0) <= dat_synced; + glitch_filt(0) <= dat_synced; -- Generate glitch filter FFs when the filter length is > 0 gen_glitch_filt: if (g_len > 0) generate @@ -120,9 +101,9 @@ begin begin if rising_edge(clk_i) then if (rst_n_i = '0') then - gc_glitch_filt(g_len downto 1) <= (others => '0'); + glitch_filt(g_len downto 1) <= (others => '0'); else - gc_glitch_filt(g_len downto 1) <= gc_glitch_filt(g_len-1 downto 0); + glitch_filt(g_len downto 1) <= glitch_filt(g_len-1 downto 0); end if; end if; end process p_glitch_filt; @@ -134,9 +115,9 @@ begin if rising_edge(clk_i) then if (rst_n_i = '0') then dat_o <= '0'; - elsif (gc_glitch_filt = (gc_glitch_filt'range => '1')) then + elsif (glitch_filt = (glitch_filt'range => '1')) then dat_o <= '1'; - elsif (gc_glitch_filt = (gc_glitch_filt'range => '0')) then + elsif (glitch_filt = (glitch_filt'range => '0')) then dat_o <= '0'; end if; end if; diff --git a/modules/common/gc_i2c_slave.vhd b/modules/common/gc_i2c_slave.vhd index b549e21b7ed7958176b7e34dd62ea0ef7badfeef..d7c0111c2d030d5c166992c8ad2a2ab41d0dbde5 100644 --- a/modules/common/gc_i2c_slave.vhd +++ b/modules/common/gc_i2c_slave.vhd @@ -49,6 +49,8 @@ --============================================================================== -- last changes: -- 2013-03-13 Theodor Stana t.stana@cern.ch File created +-- 2013-11-22 Theodor Stana Changed to sampling SDA +-- on SCL rising edge --============================================================================== -- TODO: -- - Stop condition @@ -61,53 +63,57 @@ use ieee.numeric_std.all; use work.gencores_pkg.all; entity gc_i2c_slave is + generic + ( + -- Length of glitch filter + -- 0 - SCL and SDA lines are passed only through synchronizer + -- 1 - one clk_i glitches filtered + -- 2 - two clk_i glitches filtered + g_gf_len : natural := 0 + ); port ( -- Clock, reset ports - clk_i : in std_logic; - rst_n_i : in std_logic; + clk_i : in std_logic; + rst_n_i : in std_logic; -- I2C lines - scl_i : in std_logic; - scl_o : out std_logic; - scl_en_o : out std_logic; - sda_i : in std_logic; - sda_o : out std_logic; - sda_en_o : out std_logic; + scl_i : in std_logic; + scl_o : out std_logic; + scl_en_o : out std_logic; + sda_i : in std_logic; + sda_o : out std_logic; + sda_en_o : out std_logic; -- Slave address - i2c_addr_i : in std_logic_vector(6 downto 0); + addr_i : in std_logic_vector(6 downto 0); -- ACK input, should be set after done_p_o = '1' -- (note that the bit is reversed wrt I2C ACK bit) -- '1' - ACK -- '0' - NACK - i2c_ack_i : in std_logic; - - -- I2C bus operation, set after address detection - -- '0' - write - -- '1' - read - op_o : out std_logic; + ack_i : in std_logic; -- Byte to send, should be loaded while done_p_o = '1' - tx_byte_i : in std_logic_vector(7 downto 0); + tx_byte_i : in std_logic_vector(7 downto 0); -- Received byte, valid after done_p_o = '1' - rx_byte_o : out std_logic_vector(7 downto 0); - - -- Done pulse signal, valid when - -- * received address matches i2c_addr_i, signaling valid op_o; - -- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be - -- sent to master; - -- * sent a byte, should set tx_byte_i. - done_p_o : out std_logic; - - -- I2C transfer state - -- "00" - Idle - -- "01" - Got address, matches i2c_addr_i - -- "10" - Read done, waiting ACK/NACK - -- "11" - Write done, waiting next byte - stat_o : out std_logic_vector(1 downto 0) + rx_byte_o : out std_logic_vector(7 downto 0); + + -- Pulse outputs signaling various I2C actions + -- Start and stop conditions + sta_p_o : out std_logic; + sto_p_o : out std_logic; + -- Received address corresponds addr_i + addr_good_p_o : out std_logic; + -- Read and write done + r_done_p_o : out std_logic; + w_done_p_o : out std_logic; + + -- I2C bus operation, set after address detection + -- '0' - write + -- '1' - read + op_o : out std_logic ); end entity gc_i2c_slave; @@ -120,8 +126,8 @@ architecture behav of gc_i2c_slave is type t_state is ( IDLE, -- idle - STA, -- start condition received ADDR, -- shift in I2C address bits + ADDR_CHECK, -- check received I2C address ADDR_ACK, -- ACK/NACK to I2C address RD, -- shift in byte to read RD_ACK, -- ACK/NACK to received byte @@ -134,8 +140,8 @@ architecture behav of gc_i2c_slave is -- Signal declarations --============================================================================ -- Deglitched signals and delays for SCL and SDA lines - signal scl_deglitched : std_logic; - signal scl_deglitched_d0 : std_logic; + signal scl_deglitched : std_logic; + signal scl_deglitched_d0 : std_logic; signal sda_deglitched : std_logic; signal sda_deglitched_d0 : std_logic; signal scl_r_edge_p : std_logic; @@ -143,30 +149,32 @@ architecture behav of gc_i2c_slave is signal sda_f_edge_p : std_logic; signal sda_r_edge_p : std_logic; - -- FSM - signal state : t_state; - - -- FSM tick - signal tick_p : std_logic; - signal tick_cnt : std_logic_vector(5 downto 0); + -- FSM signals + signal state : t_state; + signal inhibit : std_logic; -- RX and TX shift registers - signal txsr : std_logic_vector(7 downto 0); - signal rxsr : std_logic_vector(7 downto 0); + signal txsr : std_logic_vector(7 downto 0); + signal rxsr : std_logic_vector(7 downto 0); -- Bit counter on RX & TX - signal bit_cnt : unsigned(2 downto 0); + signal bit_cnt : unsigned(2 downto 0); + + -- Start and stop condition pulse signals + signal sta_p, sto_p : std_logic; - -- Watchdog counter signals - signal watchdog_cnt : unsigned(26 downto 0); - signal watchdog_rst : std_logic; - signal rst_fr_watchdog : std_logic; + -- Master ACKed after it has read a byte from the slave + signal mst_acked : std_logic; + + + signal sda_en : std_logic; --============================================================================== -- architecture begin --============================================================================== begin + sda_en_o <= sda_en; --============================================================================ -- I/O logic --============================================================================ @@ -187,7 +195,7 @@ begin cmp_scl_deglitch : gc_glitch_filt generic map ( - g_len => 7 + g_len => g_gf_len ) port map ( @@ -203,9 +211,9 @@ begin begin if rising_edge(clk_i) then if (rst_n_i = '0') then - scl_deglitched_d0 <= '0'; - scl_f_edge_p <= '0'; - scl_r_edge_p <= '0'; + scl_deglitched_d0 <= '0'; + scl_f_edge_p <= '0'; + scl_r_edge_p <= '0'; else scl_deglitched_d0 <= scl_deglitched; scl_f_edge_p <= (not scl_deglitched) and scl_deglitched_d0; @@ -218,7 +226,7 @@ begin cmp_sda_deglitch : gc_glitch_filt generic map ( - g_len => 7 + g_len => g_gf_len ) port map ( @@ -234,9 +242,9 @@ begin begin if rising_edge(clk_i) then if (rst_n_i = '0') then - sda_deglitched_d0 <= '0'; - sda_f_edge_p <= '0'; - sda_r_edge_p <= '0'; + sda_deglitched_d0 <= '0'; + sda_f_edge_p <= '0'; + sda_r_edge_p <= '0'; else sda_deglitched_d0 <= sda_deglitched; sda_f_edge_p <= (not sda_deglitched) and sda_deglitched_d0; @@ -246,30 +254,23 @@ begin end process p_sda_deglitched_d0; --============================================================================ - -- Tick generation + -- Start and stop condition outputs --============================================================================ --- p_tick : process (clk_i) is --- begin --- if rising_edge(clk_i) then --- if (rst_n_i = '0') then --- tick_cnt <= '0'; --- tick_p <= '0'; --- elsif (scl_f_edge_p = '1') then --- tick_en <= '1'; --- else --- if (tick_en = '1') then --- tick_cnt <= tick_cnt + 1; --- tick_p <= '0'; --- if (tick_cnt = (tick_cnt'range => '1')) then --- tick_p <= '1'; --- tick_en <= '0'; --- end if; --- else --- tick_p <= '0'; --- end if; --- end if; --- end if; --- end process p_tick; + p_sta_sto : process (clk_i) is + begin + if rising_edge(clk_i) then + if (rst_n_i = '0') then + sta_p <= '0'; + sto_p <= '0'; + else + sta_p <= sda_f_edge_p and scl_deglitched; + sto_p <= sda_r_edge_p and scl_deglitched; + end if; + end if; + end process p_sta_sto; + + sta_p_o <= sta_p; + sto_p_o <= sto_p; --============================================================================ -- FSM logic @@ -277,28 +278,24 @@ begin p_fsm: process (clk_i) is begin if rising_edge(clk_i) then - if (rst_n_i = '0') or (rst_fr_watchdog = '1') then - state <= IDLE; - watchdog_rst <= '1'; - bit_cnt <= (others => '0'); - rxsr <= (others => '0'); - txsr <= (others => '0'); - sda_en_o <= '0'; - done_p_o <= '0'; - op_o <= '0'; - stat_o <= c_i2cs_idle; - - -- I2C start condition - elsif (sda_f_edge_p = '1') and (scl_deglitched = '1') then - state <= ADDR; - bit_cnt <= (others => '0'); - watchdog_rst <= '0'; - - -- I2C stop condition - elsif (sda_r_edge_p = '1') and (scl_deglitched = '1') then - state <= IDLE; - done_p_o <= '1'; - stat_o <= c_i2cs_idle; + if (rst_n_i = '0') then + state <= IDLE; + inhibit <= '0'; + bit_cnt <= (others => '0'); + rxsr <= (others => '0'); + txsr <= (others => '0'); + mst_acked <= '0'; + sda_en <= '0'; + r_done_p_o <= '0'; + w_done_p_o <= '0'; + addr_good_p_o <= '0'; + op_o <= '0'; + + -- start and stop conditions take the FSM back to IDLE and reset the + -- FSM inhibit signal to read the address + elsif (sta_p = '1') or (sto_p = '1') then + state <= IDLE; + inhibit <= '0'; -- state machine logic else @@ -307,27 +304,20 @@ begin -- IDLE --------------------------------------------------------------------- -- When idle, outputs and bit counters are cleared, while waiting - -- for a start condition. + -- for a falling edge on SCL. The falling edge has to be validated + -- by the inhibit signal, which states whether it is this or another + -- slave being addressed. --------------------------------------------------------------------- when IDLE => - bit_cnt <= (others => '0'); - sda_en_o <= '0'; - done_p_o <= '0'; - watchdog_rst <= '1'; - stat_o <= c_i2cs_idle; - --- --------------------------------------------------------------------- --- -- STA --- --------------------------------------------------------------------- --- -- When a start condition is received, the bit counter gets cleared --- -- to prepare for receiving the address byte. On the falling edge of --- -- SCL, we go into the address state. --- --------------------------------------------------------------------- --- when STA => --- bit_cnt <= (others => '0'); --- if (scl_f_edge_p = '1') then --- state <= ADDR; --- end if; + bit_cnt <= (others => '0'); + sda_en <= '0'; + mst_acked <= '0'; + r_done_p_o <= '0'; + w_done_p_o <= '0'; + addr_good_p_o <= '0'; + if (scl_f_edge_p = '1') and (inhibit = '0') then + state <= ADDR; + end if; --------------------------------------------------------------------- -- ADDR @@ -342,67 +332,65 @@ begin if (scl_r_edge_p = '1') then rxsr <= rxsr(6 downto 0) & sda_deglitched; bit_cnt <= bit_cnt + 1; + end if; + if (scl_f_edge_p = '1') then -- Shifted in 8 bits, go to ADDR_ACK. Check to see if received -- address is ours and set op_o if so. - if (bit_cnt = 7) then - state <= ADDR_ACK; - if (rxsr(6 downto 0) = i2c_addr_i) then - op_o <= sda_deglitched; - done_p_o <= '1'; - stat_o <= c_i2cs_addr_good; - end if; + if (bit_cnt = 0) then + state <= ADDR_CHECK; end if; end if; --------------------------------------------------------------------- - -- ADDR_ACK + -- ADDR_CHECK --------------------------------------------------------------------- - -- Here, we check to see if the address is ours and ACK/NACK - -- accordingly. The next action is dependent upon the state of the - -- R/W bit received via I2C. + when ADDR_CHECK => + -- if the address is ours, set the OP output and go to ACK state + if (rxsr(7 downto 1) = addr_i) then + op_o <= rxsr(0); + addr_good_p_o <= '1'; + state <= ADDR_ACK; + + -- if the address is not ours, the FSM should be inhibited so a + -- byte sent to another slave doesn't get interpreted as this + -- slave's address + else + inhibit <= '1'; + state <= IDLE; + end if; + + --------------------------------------------------------------------- + -- ADDR_ACK --------------------------------------------------------------------- when ADDR_ACK => - -- Clear done pulse - done_p_o <= '0'; - - -- we write the ACK bit, so enable output - sda_en_o <= i2c_ack_i; - - -- If the received address is ours, send the ACK set by external - -- module and, on the falling edge of SCL, go to appropriate state - -- based on R/W bit. - if (rxsr(7 downto 1) = i2c_addr_i) then - if (scl_f_edge_p = '1') then - sda_en_o <= '0'; - if (rxsr(0) = '0') then - state <= RD; - else - state <= WR_LOAD_TXSR; - end if; + addr_good_p_o <= '0'; + sda_en <= ack_i; + if (scl_f_edge_p = '1') then + if (rxsr(0) = '0') then + state <= RD; + else + state <= WR_LOAD_TXSR; end if; - -- If received address is not ours, NACK and go back to IDLE - else - sda_en_o <= '0'; - state <= IDLE; end if; --------------------------------------------------------------------- -- RD --------------------------------------------------------------------- - -- Shift in bits sent by the master. + -- Shift in bits sent by the master --------------------------------------------------------------------- when RD => - -- Shifting occurs on falling edge of SCL - if (scl_f_edge_p = '1') then + sda_en <= '0'; + if (scl_r_edge_p = '1') then rxsr <= rxsr(6 downto 0) & sda_deglitched; bit_cnt <= bit_cnt + 1; + end if; + if (scl_f_edge_p = '1') then -- Received 8 bits, go to RD_ACK and signal external module - if (bit_cnt = 7) then - state <= RD_ACK; - done_p_o <= '1'; - stat_o <= c_i2cs_rd_done; + if (bit_cnt = 0) then + state <= RD_ACK; + r_done_p_o <= '1'; end if; end if; @@ -413,16 +401,15 @@ begin --------------------------------------------------------------------- when RD_ACK => -- Clear done pulse - done_p_o <= '0'; + r_done_p_o <= '0'; -- we write the ACK bit, so enable output and send the ACK bit - sda_en_o <= i2c_ack_i; + sda_en <= ack_i; -- based on the ACK received by external command, we read the next -- bit (ACK) or go back to idle state (NACK) if (scl_f_edge_p = '1') then - sda_en_o <= '0'; - if (i2c_ack_i = '1') then + if (ack_i = '1') then state <= RD; else state <= IDLE; @@ -432,7 +419,7 @@ begin --------------------------------------------------------------------- -- WR_LOAD_TXSR --------------------------------------------------------------------- - -- Load TXSR with the input value. + -- Load TXSR with the input value --------------------------------------------------------------------- when WR_LOAD_TXSR => txsr <= tx_byte_i; @@ -441,39 +428,48 @@ begin --------------------------------------------------------------------- -- WR --------------------------------------------------------------------- - -- Shift out the eight bits of TXSR. + -- Shift out the eight bits of TXSR --------------------------------------------------------------------- when WR => - -- slave writes, so enable output - sda_en_o <= txsr(7); + -- slave writes, SDA output enable is the negated value of the bit + -- to send (since on I2C, '1' is a release of the bus) + sda_en <= not txsr(7); - -- Shift TXSR on falling edge of SCL - if (scl_f_edge_p = '1') then - txsr <= txsr(6 downto 0) & '0'; + -- increment bit counter on rising edge + if (scl_r_edge_p = '1') then bit_cnt <= bit_cnt + 1; + end if; + + -- Shift TXSR after falling edge of SCL + if (scl_f_edge_p = '1') then + txsr <= txsr(6 downto 0) & '0'; - -- Eight bits sent, disable SDA end go to WR_ACK - if (bit_cnt = 7) then - sda_en_o <= '0'; - state <= WR_ACK; - done_p_o <= '1'; - stat_o <= c_i2cs_wr_done; + -- Eight bits sent, disable SDA and go to WR_ACK + if (bit_cnt = 0) then + state <= WR_ACK; + w_done_p_o <= '1'; end if; end if; --------------------------------------------------------------------- -- WR_ACK --------------------------------------------------------------------- - -- The master drives the ACK bit here, so on the falling edge of - -- SCL, we check the ack bit. A '0' (ACK) means more bits should be sent, - -- so we load the next value of the TXSR. A '1' (NACK) means the - -- master is done reading and a STO follows, so we go back to IDLE - -- state. + -- Check the ACK bit received from the master and go back to writing + -- another byte if ACKed, or to IDLE if NACKed --------------------------------------------------------------------- when WR_ACK => - done_p_o <= '0'; - if (scl_f_edge_p = '1') then + sda_en <= '0'; + w_done_p_o <= '0'; + if (scl_r_edge_p = '1') then if (sda_deglitched = '0') then + mst_acked <= '1'; + else + mst_acked <= '0'; + end if; + end if; + + if (scl_f_edge_p = '1') then + if (mst_acked = '1') then state <= WR_LOAD_TXSR; else state <= IDLE; @@ -481,7 +477,7 @@ begin end if; --------------------------------------------------------------------- - -- Any other state: go back to idle. + -- Any other state: go back to IDLE --------------------------------------------------------------------- when others => state <= IDLE; @@ -491,30 +487,6 @@ begin end if; end process p_fsm; - --============================================================================ - -- Watchdog counter process - -- Resets the FSM after one second. The watchdog_rst signal is controlled by - -- the FSM and resets the watchdog if the I2C master still controls the - -- slave, signaled by the SCL line going low. If for one second the master - -- does not toggle the SCL line, the FSM gets reset. - --============================================================================ - p_watchdog: process(clk_i) - begin - if rising_edge(clk_i) then - if (rst_n_i = '0') or (watchdog_rst = '1') then - watchdog_cnt <= (others => '0'); - rst_fr_watchdog <= '0'; - else - watchdog_cnt <= watchdog_cnt + 1; - rst_fr_watchdog <= '0'; - if (watchdog_cnt = 124999999) then - watchdog_cnt <= (others => '0'); - rst_fr_watchdog <= '1'; - end if; - end if; - end if; - end process p_watchdog; - end architecture behav; --============================================================================== -- architecture end diff --git a/modules/common/gencores_pkg.vhd b/modules/common/gencores_pkg.vhd index ad09c551d603abe54bd01de0cdfc839d7c6bd5ff..d0ec6d4ba8cb29e2bb9b8724395d89f9ee7750eb 100644 --- a/modules/common/gencores_pkg.vhd +++ b/modules/common/gencores_pkg.vhd @@ -4,9 +4,10 @@ ------------------------------------------------------------------------------- -- File : gencores_pkg.vhd -- Author : Tomasz Wlostowski +-- Theodor-Adrian Stana -- Company : CERN -- Created : 2009-09-01 --- Last update: 2013-07-02 +-- Last update: 2013-11-20 -- Platform : FPGA-generic -- Standard : VHDL '93 ------------------------------------------------------------------------------- @@ -38,6 +39,7 @@ -- Date Version Author Description -- 2009-09-01 0.9 twlostow Created -- 2011-04-18 1.0 twlostow Added comments & header +-- 2013-11-20 1.1 tstana Added glitch filter and I2C slave ------------------------------------------------------------------------------- library ieee; @@ -48,7 +50,9 @@ use work.genram_pkg.all; package gencores_pkg is - + --============================================================================ + -- Component instantiations + --============================================================================ component gc_extend_pulse generic ( g_width : natural); @@ -201,7 +205,7 @@ package gencores_pkg is q_valid_o : out std_logic; q_input_id_o : out std_logic_vector(f_log2_size(g_num_inputs)-1 downto 0)); end component; - + -- Power-On reset generation component gc_reset is generic( @@ -240,7 +244,7 @@ package gencores_pkg is q_o : out std_logic_vector(g_output_width-1 downto 0); q_valid_o : out std_logic; q_req_i : in std_logic); - end component; + end component; component gc_big_adder is generic( @@ -256,8 +260,7 @@ package gencores_pkg is x2_o : out std_logic_vector(g_data_bits-1 downto 0); c2_o : out std_logic); end component; - - ------------------------------------------------------------------------------ + ------------------------------------------------------------------------------ -- I2C slave ------------------------------------------------------------------------------ constant c_i2cs_idle : std_logic_vector(1 downto 0) := "00"; @@ -266,53 +269,57 @@ package gencores_pkg is constant c_i2cs_wr_done : std_logic_vector(1 downto 0) := "11"; component gc_i2c_slave is + generic + ( + -- Length of glitch filter + -- 0 - SCL and SDA lines are passed only through synchronizer + -- 1 - one clk_i glitches filtered + -- 2 - two clk_i glitches filtered + g_gf_len : natural := 0 + ); port ( -- Clock, reset ports - clk_i : in std_logic; - rst_n_i : in std_logic; + clk_i : in std_logic; + rst_n_i : in std_logic; -- I2C lines - scl_i : in std_logic; - scl_o : out std_logic; - scl_en_o : out std_logic; - sda_i : in std_logic; - sda_o : out std_logic; - sda_en_o : out std_logic; + scl_i : in std_logic; + scl_o : out std_logic; + scl_en_o : out std_logic; + sda_i : in std_logic; + sda_o : out std_logic; + sda_en_o : out std_logic; -- Slave address - i2c_addr_i : in std_logic_vector(6 downto 0); + addr_i : in std_logic_vector(6 downto 0); -- ACK input, should be set after done_p_o = '1' -- (note that the bit is reversed wrt I2C ACK bit) -- '1' - ACK -- '0' - NACK - i2c_ack_i : in std_logic; - - -- I2C bus operation, set after address detection - -- '0' - write - -- '1' - read - op_o : out std_logic; + ack_i : in std_logic; -- Byte to send, should be loaded while done_p_o = '1' - tx_byte_i : in std_logic_vector(7 downto 0); + tx_byte_i : in std_logic_vector(7 downto 0); -- Received byte, valid after done_p_o = '1' - rx_byte_o : out std_logic_vector(7 downto 0); - - -- Done pulse signal, valid when - -- * received address matches i2c_addr_i, signaling valid op_o; - -- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be - -- sent to master; - -- * sent a byte, should set tx_byte_i. - done_p_o : out std_logic; - - -- I2C transfer state - -- "00" - Idle - -- "01" - Got address, matches i2c_addr_i - -- "10" - Read done, waiting ACK/NACK - -- "11" - Write done, waiting next byte - stat_o : out std_logic_vector(1 downto 0) + rx_byte_o : out std_logic_vector(7 downto 0); + + -- Pulse outputs signaling various I2C actions + -- Start and stop conditions + sta_p_o : out std_logic; + sto_p_o : out std_logic; + -- Received address corresponds addr_i + addr_good_p_o : out std_logic; + -- Read and write done + r_done_p_o : out std_logic; + w_done_p_o : out std_logic; + + -- I2C bus operation, set after address detection + -- '0' - write + -- '1' - read + op_o : out std_logic ); end component gc_i2c_slave; @@ -342,10 +349,32 @@ package gencores_pkg is ); end component gc_glitch_filt; + ------------------------------------------------------------------------------ + -- FSM Watchdog Timer + ------------------------------------------------------------------------------ + component gc_fsm_watchdog is + generic + ( + -- Maximum value of watchdog timer in clk_i cycles + g_wdt_max : positive := 65535 + ); + port + ( + -- Clock and active-low reset line + clk_i : in std_logic; + rst_n_i : in std_logic; + + -- Active-high watchdog timer reset line, synchronous to clk_i + wdt_rst_i : in std_logic; + + -- Active-high reset output, synchronous to clk_i + fsm_rst_o : out std_logic + ); + end component gc_fsm_watchdog; --============================================================================ - -- Procedures - --============================================================================ procedure f_rr_arbitrate ( + -- Procedures and functions + --============================================================================ procedure f_rr_arbitrate ( signal req : in std_logic_vector; signal pre_grant : in std_logic_vector; @@ -359,7 +388,7 @@ package body gencores_pkg is -- req = requests (1 = pending request), -- pre_grant = previous grant vector (1 cycle delay) -- grant = new grant vector - + procedure f_rr_arbitrate ( signal req : in std_logic_vector; signal pre_grant : in std_logic_vector; @@ -370,7 +399,7 @@ package body gencores_pkg is variable gnt : std_logic_vector(req'length - 1 downto 0); variable gntM : std_logic_vector(req'length - 1 downto 0); variable zeros : std_logic_vector(req'length - 1 downto 0); - + begin zeros := (others => '0'); @@ -390,7 +419,7 @@ package body gencores_pkg is else grant <= pre_grant; end if; - + end f_rr_arbitrate; function f_big_ripple(a, b : std_logic_vector; c : std_logic) return std_logic_vector is diff --git a/modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd b/modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd index f168dfb24baba007ba4b1e043f1b2157e680f9bf..f0d61b26292abc692d8cec344de1a68769676fc4 100644 --- a/modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd +++ b/modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd @@ -66,24 +66,30 @@ entity wb_i2c_bridge is rst_n_i : in std_logic; -- I2C lines - sda_en_o : out std_logic; - sda_i : in std_logic; - sda_o : out std_logic; - scl_en_o : out std_logic; scl_i : in std_logic; scl_o : out std_logic; + scl_en_o : out std_logic; + sda_i : in std_logic; + sda_o : out std_logic; + sda_en_o : out std_logic; -- I2C address i2c_addr_i : in std_logic_vector(6 downto 0); - -- Transfer In Progress (TIP) and Error outputs - -- TIP : '1' when the I2C slave detects a matching I2C address, thus a - -- transfer is in progress - -- '0' when idle - -- ERR : '1' when the SysMon attempts to access an invalid WB slave + -- Status outputs + -- TIP : Transfer In Progress + -- '1' when the I2C slave detects a matching I2C address, thus a + -- transfer is in progress + -- '0' when idle + -- ERR : Error + -- '1' when the SysMon attempts to access an invalid WB slave -- '0' when idle - tip_o : out std_logic; - err_o : out std_logic; + -- WDTO : Watchdog timeout (single clock cycle pulse) + -- '1' -- timeout of watchdog occured + -- '0' -- when idle + tip_o : out std_logic; + err_p_o : out std_logic; + wdto_p_o : out std_logic; -- Wishbone master signals wbm_stb_o : out std_logic; @@ -120,77 +126,75 @@ architecture behav of wb_i2c_bridge is -- Signal declarations --============================================================================ -- Slave component signals - signal i2c_ack : std_logic; - signal op : std_logic; - signal start_op : std_logic; - signal tx_byte : std_logic_vector(7 downto 0); - signal rx_byte : std_logic_vector(7 downto 0); - signal done : std_logic; - signal done_d0 : std_logic; - signal stat : std_logic_vector(1 downto 0); + signal slv_ack : std_logic; + signal op : std_logic; + signal tx_byte : std_logic_vector(7 downto 0); + signal rx_byte : std_logic_vector(7 downto 0); + signal slv_sta_p : std_logic; + signal slv_sto_p : std_logic; + signal slv_addr_good_p : std_logic; + signal slv_r_done_p : std_logic; + signal slv_w_done_p : std_logic; -- Wishbone temporary signals - signal wb_dat_out : std_logic_vector(31 downto 0); - signal wb_dat_in : std_logic_vector(31 downto 0); - signal wb_adr : std_logic_vector(15 downto 0); - signal wb_cyc : std_logic; - signal wb_stb : std_logic; - signal wb_we : std_logic; - signal wb_ack : std_logic; - signal wb_err : std_logic; - signal wb_rty : std_logic; + signal wb_dat_out : std_logic_vector(31 downto 0); + signal wb_dat_in : std_logic_vector(31 downto 0); + signal wb_adr : std_logic_vector(15 downto 0); + signal wb_cyc : std_logic; + signal wb_stb : std_logic; + signal wb_we : std_logic; + signal wb_ack : std_logic; + signal wb_err : std_logic; + signal wb_rty : std_logic; -- FSM control signals - signal state : t_state; - signal dat_byte_cnt : unsigned(1 downto 0); - signal adr_byte_cnt : unsigned(0 downto 0); + signal state : t_state; + signal dat_byte_cnt : unsigned(1 downto 0); + signal adr_byte_cnt : unsigned(0 downto 0); + -- FSM watchdog signals + signal wdt_rst : std_logic; + signal rst_fr_wdt : std_logic; + signal rst_fr_wdt_d0 : std_logic; + +--============================================================================== +-- architecture begin +--============================================================================== begin --============================================================================ -- Slave component instantiation and connection --============================================================================ cmp_i2c_slave: gc_i2c_slave + generic map + ( + g_gf_len => 8 + ) port map ( - clk_i => clk_i, - rst_n_i => rst_n_i, - - -- I2C lines - scl_i => scl_i, - scl_o => scl_o, - scl_en_o => scl_en_o, - sda_i => sda_i, - sda_o => sda_o, - sda_en_o => sda_en_o, - - -- Slave address - i2c_addr_i => i2c_addr_i, - - -- ACK input, should be set after done_p_o = '1' - -- '0' - ACK - -- '1' - NACK - i2c_ack_i => i2c_ack, - - -- I2C bus operation, set after address detection - -- '0' - write - -- '1' - read - op_o => op, - - -- Byte to send, should be loaded while done_p_o = '1' - tx_byte_i => tx_byte, - - -- Received byte, valid after done_p_o = '1' - rx_byte_o => rx_byte, - - -- Done signal, valid when - -- * received address matches i2c_addr_i, signaling valid op_o; - -- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be - -- sent to master; - -- * sent a byte, should set tx_byte_i. - done_p_o => done, - - stat_o => stat + clk_i => clk_i, + rst_n_i => rst_n_i, + + scl_i => scl_i, + scl_o => scl_o, + scl_en_o => scl_en_o, + sda_i => sda_i, + sda_o => sda_o, + sda_en_o => sda_en_o, + + addr_i => i2c_addr_i, + + ack_i => slv_ack, + + tx_byte_i => tx_byte, + rx_byte_o => rx_byte, + + sta_p_o => open, + sto_p_o => slv_sto_p, + addr_good_p_o => slv_addr_good_p, + r_done_p_o => slv_r_done_p, + w_done_p_o => slv_w_done_p, + op_o => op ); --============================================================================ @@ -218,7 +222,7 @@ begin p_fsm: process (clk_i) is begin if rising_edge(clk_i) then - if (rst_n_i = '0') then + if (rst_n_i = '0') or (rst_fr_wdt = '1') then state <= IDLE; wb_adr <= (others => '0'); wb_dat_out <= (others => '0'); @@ -226,13 +230,16 @@ begin wb_cyc <= '0'; wb_stb <= '0'; wb_we <= '0'; - start_op <= '0'; - i2c_ack <= '0'; + slv_ack <= '0'; tip_o <= '0'; - err_o <= '0'; + err_p_o <= '0'; + wdt_rst <= '1'; adr_byte_cnt <= (others => '0'); dat_byte_cnt <= (others => '0'); + elsif (slv_sto_p = '1') then + state <= IDLE; + else case state is --------------------------------------------------------------------- @@ -245,15 +252,17 @@ begin -- address, start_op will be '0' (write). --------------------------------------------------------------------- when IDLE => - err_o <= '0'; - tip_o <= '0'; - i2c_ack <= '0'; + err_p_o <= '0'; + tip_o <= '0'; + slv_ack <= '0'; + adr_byte_cnt <= (others => '0'); dat_byte_cnt <= (others => '0'); - if (done = '1') and (stat = c_i2cs_addr_good) then + wdt_rst <= '1'; + if (slv_addr_good_p = '1') then tip_o <= '1'; - i2c_ack <= '1'; + slv_ack <= '1'; + wdt_rst <= '0'; state <= SYSMON_WB_ADR; - start_op <= op; end if; --------------------------------------------------------------------- @@ -263,17 +272,12 @@ begin -- them. The second byte's ACK is also controlled by the next state. --------------------------------------------------------------------- when SYSMON_WB_ADR => - if (done = '1') then - if (stat = c_i2cs_rd_done) then - wb_adr <= wb_adr(7 downto 0) & rx_byte; - i2c_ack <= '1'; - adr_byte_cnt <= adr_byte_cnt + 1; - if (adr_byte_cnt = 1) then - state <= SIM_WB_TRANSF; - end if; - else - i2c_ack <= '0'; - state <= IDLE; + if (slv_r_done_p = '1') then + wb_adr <= wb_adr(7 downto 0) & rx_byte; + slv_ack <= '1'; + adr_byte_cnt <= adr_byte_cnt + 1; + if (adr_byte_cnt = 1) then + state <= SIM_WB_TRANSF; end if; end if; @@ -288,13 +292,13 @@ begin wb_cyc <= '1'; wb_stb <= '1'; if (wb_ack = '1') then - i2c_ack <= '1'; + slv_ack <= '1'; wb_cyc <= '0'; wb_stb <= '0'; state <= OPER; elsif (wb_err = '1') then - err_o <= '1'; - i2c_ack <= '0'; + err_p_o <= '1'; + slv_ack <= '0'; wb_cyc <= '0'; wb_stb <= '0'; state <= IDLE; @@ -317,19 +321,14 @@ begin -- output are cleared to avoid conflicts with future transfers. --------------------------------------------------------------------- when OPER => - if (done = '1') then - if (stat = c_i2cs_rd_done) then - wb_dat_out <= rx_byte & wb_dat_out(31 downto 8); - dat_byte_cnt <= dat_byte_cnt + 1; - i2c_ack <= '1'; - state <= SYSMON_WR; - elsif (stat = c_i2cs_addr_good) and (op /= start_op) then - i2c_ack <= '1'; - state <= SYSMON_RD_WB; - else - i2c_ack <= '0'; - state <= IDLE; - end if; + if (slv_r_done_p = '1') then + wb_dat_out <= rx_byte & wb_dat_out(31 downto 8); + dat_byte_cnt <= dat_byte_cnt + 1; + slv_ack <= '1'; + state <= SYSMON_WR; + elsif (slv_addr_good_p = '1') and (op = '1') then + slv_ack <= '1'; + state <= SYSMON_RD_WB; end if; --------------------------------------------------------------------- @@ -340,18 +339,15 @@ begin -- write transfer is initiated in the next state. --------------------------------------------------------------------- when SYSMON_WR => - if (done = '1') then - if (stat = c_i2cs_rd_done) then - wb_dat_out <= rx_byte & wb_dat_out(31 downto 8); - dat_byte_cnt <= dat_byte_cnt + 1; - i2c_ack <= '1'; - if (dat_byte_cnt = 3) then - state <= SYSMON_WR_WB; - end if; - else - i2c_ack <= '0'; - state <= IDLE; + if (slv_r_done_p = '1') then + wb_dat_out <= rx_byte & wb_dat_out(31 downto 8); + dat_byte_cnt <= dat_byte_cnt + 1; + slv_ack <= '1'; + if (dat_byte_cnt = 3) then + state <= SYSMON_WR_WB; end if; +-- elsif (slv_sto_p = '1') then +-- state <= IDLE; end if; --------------------------------------------------------------------- @@ -370,7 +366,7 @@ begin wb_we <= '0'; state <= SYSMON_WR; --IDLE; elsif (wb_err = '1') then - err_o <= '1'; + err_p_o <= '1'; state <= IDLE; end if; @@ -391,10 +387,10 @@ begin wb_stb <= '0'; state <= SYSMON_RD; elsif (wb_err = '1') then - err_o <= '1'; - wb_cyc <= '0'; - wb_stb <= '0'; - state <= IDLE; + err_p_o <= '1'; + wb_cyc <= '0'; + wb_stb <= '0'; + state <= IDLE; end if; --------------------------------------------------------------------- @@ -403,18 +399,15 @@ begin -- Shift out the bytes over I2C and go back to IDLE state. --------------------------------------------------------------------- when SYSMON_RD => - if (done = '1') then - if (stat = c_i2cs_wr_done) then - wb_dat_in <= x"00" & wb_dat_in(31 downto 8); - dat_byte_cnt <= dat_byte_cnt + 1; - i2c_ack <= '1'; - if (dat_byte_cnt = 3) then - state <= IDLE; - end if; - else - i2c_ack <= '0'; - state <= IDLE; + if (slv_w_done_p = '1') then + wb_dat_in <= x"00" & wb_dat_in(31 downto 8); + dat_byte_cnt <= dat_byte_cnt + 1; + slv_ack <= '1'; + if (dat_byte_cnt = 3) then + state <= IDLE; end if; +-- elsif (slv_sto_p = '1') then +-- state <= IDLE; end if; --------------------------------------------------------------------- @@ -428,4 +421,48 @@ begin end if; end process p_fsm; + --============================================================================ + -- FSM watchdog timer + --============================================================================ + -- * in the case of writemregs command, a maximum of 35 bytes can be written + -- - 1 I2C address byte + -- - 2 register (Wishbone) address bytes + -- - 8*4 Wishbone register values + -- * we will therefore set the watchdog max. value to allow for 36 bytes to + -- be sent, considering a maximum clk_i frequency of 20 MHz (period = 50 ns) + -- and an SCL frequency of 100 kHz + -- * 100 us / 50 ns = 2000 clock cycles to send one byte + -- * 2000 * 36 bytes = 72000 clock cycles to send 36 bytes + -- * g_wdt_max = 72000 + cmp_watchdog : gc_fsm_watchdog + generic map + ( + g_wdt_max => 72000 + ) + port map + ( + clk_i => clk_i, + rst_n_i => rst_n_i, + wdt_rst_i => wdt_rst, + fsm_rst_o => rst_fr_wdt + ); + + -- Process to set the timeout status pulse + p_wdto_outp : process (clk_i) + begin + if rising_edge(clk_i) then + if (rst_n_i = '0') then + rst_fr_wdt_d0 <= '0'; + wdto_p_o <= '0'; + else + rst_fr_wdt_d0 <= rst_fr_wdt; + wdto_p_o <= rst_fr_wdt and (not rst_fr_wdt_d0); + end if; + end if; + end process p_wdto_outp; + end behav; +--============================================================================== +-- architecture end +--============================================================================== + diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index 42228b582e2d2a5320eb2530142bed9fc2577024..e919fce1075c66262cbb3dfd756ac8ad86b2e319 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -910,24 +910,30 @@ package wishbone_pkg is rst_n_i : in std_logic; -- I2C lines - sda_en_o : out std_logic; - sda_i : in std_logic; - sda_o : out std_logic; - scl_en_o : out std_logic; scl_i : in std_logic; scl_o : out std_logic; + scl_en_o : out std_logic; + sda_i : in std_logic; + sda_o : out std_logic; + sda_en_o : out std_logic; -- I2C address i2c_addr_i : in std_logic_vector(6 downto 0); - -- Transfer In Progress (TIP) and Error outputs - -- TIP : '1' when the I2C slave detects a matching I2C address, thus a - -- transfer is in progress - -- '0' when idle - -- ERR : '1' when the SysMon attempts to access an invalid WB slave + -- Status outputs + -- TIP : Transfer In Progress + -- '1' when the I2C slave detects a matching I2C address, thus a + -- transfer is in progress + -- '0' when idle + -- ERR : Error + -- '1' when the SysMon attempts to access an invalid WB slave -- '0' when idle - tip_o : out std_logic; - err_o : out std_logic; + -- WDTO : Watchdog timeout (single clock cycle pulse) + -- '1' -- timeout of watchdog occured + -- '0' -- when idle + tip_o : out std_logic; + err_p_o : out std_logic; + wdto_p_o : out std_logic; -- Wishbone master signals wbm_stb_o : out std_logic; diff --git a/sim/wb_i2c_bridge/i2c_bus_model.vhd b/sim/wb_i2c_bridge/i2c_bus_model.vhd new file mode 100644 index 0000000000000000000000000000000000000000..0acc69aa3223bc6a86e257c0c3182dfce6fc717a --- /dev/null +++ b/sim/wb_i2c_bridge/i2c_bus_model.vhd @@ -0,0 +1,89 @@ +--============================================================================== +-- CERN (BE-CO-HT) +-- I2C bus model +--============================================================================== +-- +-- author: Theodor Stana (t.stana@cern.ch) +-- +-- date of creation: 2013-11-27 +-- +-- version: 1.0 +-- +-- description: +-- A very simple I2C bus model for use in simulation, implementing the +-- wired-AND on the I2C protocol. +-- +-- Masters and slaves should implement the buffers internally and connect the +-- SCL and SDA lines to the input ports of this model, as below: +-- - masters should connect to mscl_i and msda_i +-- - slaves should connect to sscl_i and ssda_i +-- +-- dependencies: +-- +-- references: +-- +--============================================================================== +-- GNU LESSER GENERAL PUBLIC LICENSE +--============================================================================== +-- This source file is free software; you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as published by the +-- Free Software Foundation; either version 2.1 of the License, or (at your +-- option) any later version. This source is distributed in the hope that it +-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-- See the GNU Lesser General Public License for more details. You should have +-- received a copy of the GNU Lesser General Public License along with this +-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html +--============================================================================== +-- last changes: +-- 2013-11-27 Theodor Stana File created +--============================================================================== +-- TODO: - +--============================================================================== + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + + +entity i2c_bus_model is + generic + ( + g_nr_masters : positive := 1; + g_nr_slaves : positive := 1 + ); + port + ( + -- Input ports from master lines + mscl_i : in std_logic_vector(g_nr_masters-1 downto 0); + msda_i : in std_logic_vector(g_nr_masters-1 downto 0); + + -- Input ports from slave lines + sscl_i : in std_logic_vector(g_nr_slaves-1 downto 0); + ssda_i : in std_logic_vector(g_nr_slaves-1 downto 0); + + -- SCL and SDA line outputs + scl_o : out std_logic; + sda_o : out std_logic + ); +end entity i2c_bus_model; + + +architecture behav of i2c_bus_model is + +--============================================================================== +-- architecture begin +--============================================================================== +begin + + scl_o <= '1' when (mscl_i = (mscl_i'range => '1')) and + (sscl_i = (sscl_i'range => '1')) else + '0'; + sda_o <= '1' when (msda_i = (msda_i'range => '1')) and + (ssda_i = (ssda_i'range => '1')) else + '0'; + +end architecture behav; +--============================================================================== +-- architecture end +--============================================================================== diff --git a/sim/wb_i2c_bridge/i2c_master_bit_ctrl.vhd b/sim/wb_i2c_bridge/i2c_master_bit_ctrl.vhd new file mode 100644 index 0000000000000000000000000000000000000000..a095fde0e882d3b0d6322145e9396759b223b9c2 --- /dev/null +++ b/sim/wb_i2c_bridge/i2c_master_bit_ctrl.vhd @@ -0,0 +1,576 @@ +--------------------------------------------------------------------- +---- ---- +---- WISHBONE revB2 I2C Master Core; bit-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_bit_ctrl.vhd,v 1.17 2009-02-04 20:17:34 rherveille Exp $ +-- +-- $Date: 2009-02-04 20:17:34 $ +-- $Revision: 1.17 $ +-- $Author: rherveille $ +-- $Locker: $ +-- $State: Exp $ +-- +-- Change History: +-- $Log: not supported by cvs2svn $ +-- Revision 1.16 2009/01/20 20:40:36 rherveille +-- Fixed type iscl_oen instead of scl_oen +-- +-- Revision 1.15 2009/01/20 10:34:51 rherveille +-- Added SCL clock synchronization logic +-- Fixed slave_wait signal generation +-- +-- Revision 1.14 2006/10/11 12:10:13 rherveille +-- Added missing semicolons ';' on endif +-- +-- Revision 1.13 2006/10/06 10:48:24 rherveille +-- fixed short scl high pulse after clock stretch +-- +-- Revision 1.12 2004/05/07 11:53:31 rherveille +-- Fixed previous fix :) Made a variable vs signal mistake. +-- +-- Revision 1.11 2004/05/07 11:04:00 rherveille +-- Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit. +-- +-- Revision 1.10 2004/02/27 07:49:43 rherveille +-- Fixed a bug in the arbitration-lost signal generation. VHDL version only. +-- +-- Revision 1.9 2003/08/12 14:48:37 rherveille +-- Forgot an 'end if' :-/ +-- +-- Revision 1.8 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.7 2003/02/05 00:06:02 rherveille +-- Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles. +-- +-- Revision 1.6 2003/02/01 02:03:06 rherveille +-- Fixed a few 'arbitration lost' bugs. VHDL version only. +-- +-- Revision 1.5 2002/12/26 16:05:47 rherveille +-- Core is now a Multimaster I2C controller. +-- +-- Revision 1.4 2002/11/30 22:24:37 rherveille +-- Cleaned up code +-- +-- Revision 1.3 2002/10/30 18:09:53 rherveille +-- Fixed some reported minor start/stop generation timing issuess. +-- +-- Revision 1.2 2002/06/15 07:37:04 rherveille +-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment. +-- +-- 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. +-- + + +-- +------------------------------------- +-- Bit controller section +------------------------------------ +-- +-- Translate simple commands into SCL/SDA transitions +-- Each command has 5 states, A/B/C/D/idle +-- +-- start: SCL ~~~~~~~~~~~~~~\____ +-- SDA XX/~~~~~~~\______ +-- x | A | B | C | D | i +-- +-- repstart SCL ______/~~~~~~~\___ +-- SDA __/~~~~~~~\______ +-- x | A | B | C | D | i +-- +-- stop SCL _______/~~~~~~~~~~~ +-- SDA ==\___________/~~~~~ +-- x | A | B | C | D | i +-- +--- write SCL ______/~~~~~~~\____ +-- SDA XXX===============XX +-- x | A | B | C | D | i +-- +--- read SCL ______/~~~~~~~\____ +-- SDA XXXXXXX=XXXXXXXXXXX +-- x | A | B | C | D | i +-- + +-- Timing: Normal mode Fast mode +----------------------------------------------------------------- +-- Fscl 100KHz 400KHz +-- Th_scl 4.0us 0.6us High period of SCL +-- Tl_scl 4.7us 1.3us Low period of SCL +-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition +-- Tsu:sto 4.0us 0.6us setup time for a stop conditon +-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity 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 completed + 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 entity i2c_master_bit_ctrl; + +architecture structural of i2c_master_bit_ctrl is + 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"; + + type states is (idle, start_a, start_b, start_c, start_d, start_e, + stop_a, stop_b, stop_c, stop_d, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d); + signal c_state : states; + + signal iscl_oen, isda_oen : std_logic; -- internal I2C lines + signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) + signal dscl_oen : std_logic; -- delayed scl_oen signals + signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs + signal dSCL, dSDA : std_logic; -- delayed versions ofsSCL and sSDA + signal clk_en : std_logic; -- statemachine clock enable + signal scl_sync, slave_wait : std_logic; -- clock generation signals + signal ial : std_logic; -- internal arbitration lost signal + signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis) + +begin + -- whenever the slave is not ready it can delay the cycle by pulling SCL low + -- delay scl_oen + process (clk, nReset) + begin + if (nReset = '0') then + dscl_oen <= '0'; + elsif (clk'event and clk = '1') then + dscl_oen <= iscl_oen; + end if; + end process; + + -- slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low + -- slave_wait remains asserted until the slave releases SCL + process (clk, nReset) + begin + if (nReset = '0') then + slave_wait <= '0'; + elsif (clk'event and clk = '1') then + slave_wait <= (iscl_oen and not dscl_oen and not sSCL) or (slave_wait and not sSCL); + end if; + end process; + + -- master drives SCL high, but another master pulls it low + -- master start counting down its low cycle now (clock synchronization) + scl_sync <= dSCL and not sSCL and iscl_oen; + + -- generate clk enable signal + gen_clken: process(clk, nReset) + begin + if (nReset = '0') then + cnt <= (others => '0'); + clk_en <= '1'; + elsif (clk'event and clk = '1') then + if ((rst = '1') or (cnt = 0) or (ena = '0') or (scl_sync = '1')) then + cnt <= clk_cnt; + clk_en <= '1'; + elsif (slave_wait = '1') then + cnt <= cnt; + clk_en <= '0'; + else + cnt <= cnt -1; + clk_en <= '0'; + end if; + end if; + end process gen_clken; + + + -- generate bus status controller + bus_status_ctrl: block + signal cSCL, cSDA : std_logic_vector( 1 downto 0); -- capture SDA and SCL + signal fSCL, fSDA : std_logic_vector( 2 downto 0); -- filter inputs for SCL and SDA + signal filter_cnt : unsigned(13 downto 0); -- clock divider for filter + signal sta_condition : std_logic; -- start detected + signal sto_condition : std_logic; -- stop detected + signal cmd_stop : std_logic; -- STOP command + signal ibusy : std_logic; -- internal busy signal + begin + -- capture SCL and SDA + capture_scl_sda: process(clk, nReset) + begin + if (nReset = '0') then + cSCL <= "00"; + cSDA <= "00"; + elsif (clk'event and clk = '1') then + if (rst = '1') then + cSCL <= "00"; + cSDA <= "00"; + else + cSCL <= (cSCL(0) & scl_i); + cSDA <= (cSDA(0) & sda_i); + end if; + end if; + end process capture_scl_sda; + + -- filter SCL and SDA; (attempt to) remove glitches + filter_divider: process(clk, nReset) + begin + if (nReset = '0') then + filter_cnt <= (others => '0'); + elsif (clk'event and clk = '1') then + if ( (rst = '1') or (ena = '0') ) then + filter_cnt <= (others => '0'); + elsif (filter_cnt = 0) then + filter_cnt <= clk_cnt(15 downto 2); + else + filter_cnt <= filter_cnt -1; + end if; + end if; + end process filter_divider; + + filter_scl_sda: process(clk, nReset) + begin + if (nReset = '0') then + fSCL <= (others => '1'); + fSDA <= (others => '1'); + elsif (clk'event and clk = '1') then + if (rst = '1') then + fSCL <= (others => '1'); + fSDA <= (others => '1'); + elsif (filter_cnt = 0) then + fSCL <= (fSCL(1 downto 0) & cSCL(1)); + fSDA <= (fSDA(1 downto 0) & cSDA(1)); + end if; + end if; + end process filter_scl_sda; + + -- generate filtered SCL and SDA signals + scl_sda: process(clk, nReset) + begin + if (nReset = '0') then + sSCL <= '1'; + sSDA <= '1'; + + dSCL <= '1'; + dSDA <= '1'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + sSCL <= '1'; + sSDA <= '1'; + + dSCL <= '1'; + dSDA <= '1'; + else + sSCL <= (fSCL(2) and fSCL(1)) or + (fSCL(2) and fSCL(0)) or + (fSCL(1) and fSCL(0)); + sSDA <= (fSDA(2) and fSDA(1)) or + (fSDA(2) and fSDA(0)) or + (fSDA(1) and fSDA(0)); + + dSCL <= sSCL; + dSDA <= sSDA; + end if; + end if; + end process scl_sda; + + + -- detect start condition => detect falling edge on SDA while SCL is high + -- detect stop condition => detect rising edge on SDA while SCL is high + detect_sta_sto: process(clk, nReset) + begin + if (nReset = '0') then + sta_condition <= '0'; + sto_condition <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + sta_condition <= '0'; + sto_condition <= '0'; + else + sta_condition <= (not sSDA and dSDA) and sSCL; + sto_condition <= (sSDA and not dSDA) and sSCL; + end if; + end if; + end process detect_sta_sto; + + + -- generate i2c-bus busy signal + gen_busy: process(clk, nReset) + begin + if (nReset = '0') then + ibusy <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + ibusy <= '0'; + else + ibusy <= (sta_condition or ibusy) and not sto_condition; + end if; + end if; + end process gen_busy; + busy <= ibusy; + + + -- generate arbitration lost signal + -- aribitration lost when: + -- 1) master drives SDA high, but the i2c bus is low + -- 2) stop detected while not requested (detect during 'idle' state) + gen_al: process(clk, nReset) + begin + if (nReset = '0') then + cmd_stop <= '0'; + ial <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + cmd_stop <= '0'; + ial <= '0'; + else + if (clk_en = '1') then + if (cmd = I2C_CMD_STOP) then + cmd_stop <= '1'; + else + cmd_stop <= '0'; + end if; + end if; + + if (c_state = idle) then + ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); + else + ial <= (sda_chk and not sSDA and isda_oen); + end if; + end if; + end if; + end process gen_al; + al <= ial; + + + -- generate dout signal, store dout on rising edge of SCL + gen_dout: process(clk, nReset) + begin + if (nReset = '0') then + dout <= '0'; + elsif (clk'event and clk = '1') then + if (sSCL = '1' and dSCL = '0') then + dout <= sSDA; + end if; + end if; + end process gen_dout; + end block bus_status_ctrl; + + + -- generate statemachine + nxt_state_decoder : process (clk, nReset) + begin + if (nReset = '0') then + c_state <= idle; + cmd_ack <= '0'; + iscl_oen <= '1'; + isda_oen <= '1'; + sda_chk <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1' or ial = '1') then + c_state <= idle; + cmd_ack <= '0'; + iscl_oen <= '1'; + isda_oen <= '1'; + sda_chk <= '0'; + else + cmd_ack <= '0'; -- default no acknowledge + + if (clk_en = '1') then + case (c_state) is + -- idle + when idle => + case cmd is + when I2C_CMD_START => c_state <= start_a; + when I2C_CMD_STOP => c_state <= stop_a; + when I2C_CMD_WRITE => c_state <= wr_a; + when I2C_CMD_READ => c_state <= rd_a; + when others => c_state <= idle; -- NOP command + end case; + + iscl_oen <= iscl_oen; -- keep SCL in same state + isda_oen <= isda_oen; -- keep SDA in same state + sda_chk <= '0'; -- don't check SDA + + -- start + when start_a => + c_state <= start_b; + iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start) + isda_oen <= '1'; -- set SDA high + sda_chk <= '0'; -- don't check SDA + + when start_b => + c_state <= start_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '1'; -- keep SDA high + sda_chk <= '0'; -- don't check SDA + + when start_c => + c_state <= start_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- set SDA low + sda_chk <= '0'; -- don't check SDA + + when start_d => + c_state <= start_e; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when start_e => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + -- stop + when stop_a => + c_state <= stop_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= '0'; -- set SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_b => + c_state <= stop_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_c => + c_state <= stop_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '1'; -- set SDA high + sda_chk <= '0'; -- don't check SDA + + -- read + when rd_a => + c_state <= rd_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_b => + c_state <= rd_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_c => + c_state <= rd_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + -- write + when wr_a => + c_state <= wr_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= din; -- set SDA + sda_chk <= '0'; -- don't check SDA (SCL low) + + when wr_b => + c_state <= wr_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= din; -- keep SDA + sda_chk <= '0'; -- don't check SDA yet + -- Allow some more time for SDA and SCL to settle + + when wr_c => + c_state <= wr_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= din; -- keep SDA + sda_chk <= '1'; -- check SDA + + when wr_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= din; -- keep SDA + sda_chk <= '0'; -- don't check SDA (SCL low) + + when others => + + end case; + end if; + end if; + end if; + end process nxt_state_decoder; + + + -- assign outputs + scl_o <= '0'; + scl_oen <= iscl_oen; + sda_o <= '0'; + sda_oen <= isda_oen; +end architecture structural; + diff --git a/sim/wb_i2c_bridge/i2c_master_byte_ctrl.vhd b/sim/wb_i2c_bridge/i2c_master_byte_ctrl.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e1691032544c15215f32e95480512ee91bc04d59 --- /dev/null +++ b/sim/wb_i2c_bridge/i2c_master_byte_ctrl.vhd @@ -0,0 +1,368 @@ +--------------------------------------------------------------------- +---- ---- +---- 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.5 2004-02-18 11:41:48 rherveille Exp $ +-- +-- $Date: 2004-02-18 11:41:48 $ +-- $Revision: 1.5 $ +-- $Author: rherveille $ +-- $Locker: $ +-- $State: Exp $ +-- +-- Change History: +-- $Log: not supported by cvs2svn $ +-- 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; +use ieee.numeric_std.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; + type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop); + signal c_state : states; + +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 + 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; + diff --git a/sim/wb_i2c_bridge/run.do b/sim/wb_i2c_bridge/run.do new file mode 100644 index 0000000000000000000000000000000000000000..e93d07883d5ff1085c6892976e6006159e6f70a9 --- /dev/null +++ b/sim/wb_i2c_bridge/run.do @@ -0,0 +1,30 @@ +vlib work + +vcom -explicit -93 "../../modules/genrams/genram_pkg.vhd" +vcom -explicit -93 "../../modules/common/gencores_pkg.vhd" +vcom -explicit -93 "../../modules/wishbone/wishbone_pkg.vhd" +vcom -explicit -93 "../../modules/common/gc_sync_ffs.vhd" +vcom -explicit -93 "../../modules/common/gc_glitch_filt.vhd" +vcom -explicit -93 "../../modules/common/gc_fsm_watchdog.vhd" +vcom -explicit -93 "../../modules/common/gc_i2c_slave.vhd" + +vcom -explicit -93 "../../modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd" + +vcom -explicit -93 "i2c_master_bit_ctrl.vhd" +vcom -explicit -93 "i2c_master_byte_ctrl.vhd" + +vcom -explicit -93 "i2c_bus_model.vhd" + +vcom -explicit -93 "tb_wb_i2c_bridge.vhd" +#vcom -explicit -93 "tb_gc_i2c_slave.vhd" + +vsim -t 1ps -voptargs="+acc" -lib work work.tb_wb_i2c_bridge + +radix -hexadecimal +#add wave * +do wave.do +#do busmdl.do +#do wave-i2cs.do + +run 20 ms +wave zoomfull diff --git a/sim/wb_i2c_bridge/tb_gc_i2c_slave.vhd b/sim/wb_i2c_bridge/tb_gc_i2c_slave.vhd new file mode 100644 index 0000000000000000000000000000000000000000..fd6846797eb01c331a5c313ab3e415d52af67100 --- /dev/null +++ b/sim/wb_i2c_bridge/tb_gc_i2c_slave.vhd @@ -0,0 +1,505 @@ +--============================================================================== +-- CERN (BE-CO-HT) +-- Testbench for old repeater design +--============================================================================== +-- +-- author: Theodor Stana (t.stana@cern.ch) +-- +-- date of creation: 2013-02-28 +-- +-- version: 1.0 +-- +-- description: +-- +-- dependencies: +-- +-- references: +-- +--============================================================================== +-- GNU LESSER GENERAL PUBLIC LICENSE +--============================================================================== +-- This source file is free software; you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as published by the +-- Free Software Foundation; either version 2.1 of the License, or (at your +-- option) any later version. This source is distributed in the hope that it +-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-- See the GNU Lesser General Public License for more details. You should have +-- received a copy of the GNU Lesser General Public License along with this +-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html +--============================================================================== +-- last changes: +-- 2013-02-28 Theodor Stana t.stana@cern.ch File created +--============================================================================== +-- TODO: - +--============================================================================== + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.gencores_pkg.all; + +entity tb_gc_i2c_slave is +end entity tb_gc_i2c_slave; + + +architecture behav of tb_gc_i2c_slave is + + --============================================================================ + -- Type declarations + --============================================================================ + type t_state_mst is + ( + MST_IDLE, + MST_W1, MST_W1_ACK, + MST_W2, MST_W2_ACK, + MST_W3, MST_W3_ACK, + MST_R1, MST_R1_ACK, + MST_R2, + MST_R3, + MST_SUCCESS, + MST_ERR + ); + + + type t_state_slv is + ( + SLV_IDLE, + SLV_DETOP, + SLV_R1, SLV_R1_ACK, + SLV_R2, SLV_R2_ACK, + SLV_W1, SLV_W1_ACK, + SLV_W2, SLV_W2_ACK + ); + + --============================================================================ + -- Constant declarations + --============================================================================ + constant c_clk_per : time := 50 ns; + constant c_reset_width : time := 31 ns; + + --============================================================================ + -- Component declarations + --============================================================================ + -- I2C master + component 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 component i2c_master_byte_ctrl; + + --============================================================================ + -- Signal declarations + --============================================================================ + signal clk, rst_n : std_logic := '0'; + signal rst : std_logic; + + signal scl_to_slv : std_logic; + signal scl_fr_slv : std_logic; + signal scl_en_slv : std_logic; + signal sda_to_slv : std_logic; + signal sda_fr_slv : std_logic; + signal sda_en_slv : std_logic; + + signal slv_ack : std_logic; + signal slv_op : std_logic; + + signal scl_to_mst : std_logic; + signal scl_fr_mst : std_logic; + signal scl_en_mst : std_logic; + signal sda_to_mst : std_logic; + signal sda_fr_mst : std_logic; + signal sda_en_mst : std_logic; + + signal addr : std_logic_vector(6 downto 0); + + signal txb, rxb : std_logic_vector(7 downto 0); + signal rcvd : std_logic_vector(7 downto 0); + + signal slv_r_done_p : std_logic; + signal slv_w_done_p : std_logic; + signal slv_addr_good_p : std_logic; + signal slv_sta_p : std_logic; + signal slv_sto_p : std_logic; + + signal mst_sta : std_logic; + signal mst_sto : std_logic; + signal mst_rd : std_logic; + signal mst_wr : std_logic; + signal mst_ack : std_logic; + + signal mst_dat_in : std_logic_vector(7 downto 0); + signal mst_dat_out : std_logic_vector(7 downto 0); + + signal mst_cmd_ack : std_logic; + signal ack_fr_slv : std_logic; + + signal state_mst : t_state_mst; + signal state_slv : t_state_slv; + + signal cnt : unsigned(2 downto 0); + signal once : boolean; + signal tmp : std_logic_vector(7 downto 0); + +--============================================================================== +-- architecture begin +--============================================================================== +begin + + -- CLOCK GENERATION + p_clk: process + begin + clk <= not clk; + wait for c_clk_per/2; + end process p_clk; + + -- RESET GENERATION + rst <= not rst_n; + p_rst_n: process + begin + rst_n <= '0'; + wait for c_reset_width; + rst_n <= '1'; + wait; + end process p_rst_n; + + -- DUT INSTANTIATION + DUT: gc_i2c_slave + port map + ( + clk_i => clk, + rst_n_i => rst_n, + + scl_i => scl_to_slv, + scl_o => scl_fr_slv, + scl_en_o => scl_en_slv, + sda_i => sda_to_slv, + sda_o => sda_fr_slv, + sda_en_o => sda_en_slv, + + addr_i => addr, + + ack_i => slv_ack, + + tx_byte_i => txb, + rx_byte_o => rxb, + + sta_p_o => slv_sta_p, + sto_p_o => slv_sto_p, + addr_good_p_o => slv_addr_good_p, + r_done_p_o => slv_r_done_p, + w_done_p_o => slv_w_done_p, + op_o => slv_op + ); + + scl_to_slv <= scl_fr_mst when scl_en_mst = '0' else + scl_fr_slv when scl_en_slv = '1' else + '1'; + sda_to_slv <= sda_fr_slv when sda_en_slv = '1' else + sda_fr_mst when sda_en_mst = '0' else + '1'; + + -- MASTER INSTANTIATION + cmp_master: i2c_master_byte_ctrl + port map + ( + clk => clk, + rst => rst, + nReset => rst_n, + ena => '1', + + clk_cnt => x"00FA", + + -- input signals + start => mst_sta, + stop => mst_sto, + read => mst_rd, + write => mst_wr, + ack_in => mst_ack, + din => mst_dat_in, + + -- output signals + cmd_ack => mst_cmd_ack, + ack_out => ack_fr_slv, + i2c_busy => open, + i2c_al => open, + dout => mst_dat_out, + + -- i2c lines + scl_i => scl_to_mst, + scl_o => scl_fr_mst, + scl_oen => scl_en_mst, + sda_i => sda_to_mst, + sda_o => sda_fr_mst, + sda_oen => sda_en_mst + ); + + -- BUS MODEL + scl_to_mst <= scl_fr_mst when scl_en_mst = '0' else + scl_fr_slv when scl_en_slv = '1' else + '1'; + + sda_to_mst <= sda_fr_slv when sda_en_slv = '1' else + sda_fr_mst when sda_en_mst = '0' else + '1'; + + -- STIMULI + addr <= "1011110"; + + -- I2C SLAVE FSM + p_slv_fsm: process (clk) is + begin + if rising_edge(clk) then + if (rst_n = '0') then + state_slv <= SLV_IDLE; + slv_ack <= '0'; + txb <= (others => '0'); + else + case state_slv is + + -- IDLE, wait for slave to do something + when SLV_IDLE => + if (slv_addr_good_p = '1') then + slv_ack <= '1'; + state_slv <= SLV_DETOP; + end if; + + -- master sent something to our slave, see what + -- we have to do... + when SLV_DETOP => + if (slv_op = '0') then + state_slv <= SLV_R1; + else + state_slv <= SLV_W1; + end if; + + -- SLV_R1 + -- when done = '1', the slave goes into + -- WAIT_ACK state, so we must provide ACK. + when SLV_R1 => + if (slv_r_done_p = '1') then + state_slv <= SLV_R1_ACK; + rcvd <= rxb; + end if; + + -- tell the slave to ACK, go back to IDLE + when SLV_R1_ACK => + slv_ack <= '1'; + state_slv <= SLV_R2; + + -- reading second byte from master, wait until + -- done = '1', and go to R2_ACK state + when SLV_R2 => + if (slv_r_done_p = '1') then + state_slv <= SLV_R2_ACK; + rcvd <= rxb; + end if; + + -- R2_ACK + when SLV_R2_ACK => + slv_ack <= '1'; + state_slv <= SLV_IDLE; + + -- loopback received byte + when SLV_W1 => + txb <= rcvd; + if (slv_w_done_p = '1') then + state_slv <= SLV_W2; + end if; + + -- loopback received byte + when SLV_W2 => + txb <= rcvd; + if (slv_w_done_p = '1') then + state_slv <= SLV_IDLE; + end if; + + when others => + state_slv <= SLV_IDLE; + + end case; + + end if; + end if; + end process p_slv_fsm; + + -- I2C MASTER FSM + tmp <= mst_dat_out; + + p_mst_fsm: process (clk) is + begin + if rising_edge(clk) then + if (rst_n = '0') then + state_mst <= MST_IDLE; + mst_sta <= '0'; + mst_wr <= '0'; + mst_sto <= '0'; + mst_rd <= '0'; + mst_dat_in <= (others => '0'); + mst_ack <= '1'; + cnt <= (others => '0'); + once <= true; + else + case state_mst is + + when MST_IDLE => + state_mst <= MST_W1; + + when MST_W1 => + mst_sta <= '1'; + mst_wr <= '1'; + mst_dat_in <= addr & '0'; + if (mst_cmd_ack = '1') then + mst_sta <= '0'; + mst_wr <= '0'; + state_mst <= MST_W1_ACK; + end if; + + when MST_W1_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state_mst <= MST_W2; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_W2 => + mst_wr <= '1'; + mst_dat_in <= x"33"; + if (mst_cmd_ack = '1') then + mst_wr <= '0'; + state_mst <= MST_W2_ACK; + end if; + + when MST_W2_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state_mst <= MST_W3; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_W3 => + mst_wr <= '1'; + mst_dat_in <= x"12"; + if (mst_cmd_ack = '1') then + mst_wr <= '0'; + mst_sto <= '0'; + state_mst <= MST_W3_ACK; + end if; + + when MST_W3_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state_mst <= MST_R1; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_R1 => + mst_sta <= '1'; + mst_wr <= '1'; + mst_dat_in <= addr & '1'; + if (mst_cmd_ack = '1') then + mst_sta <= '0'; + mst_wr <= '0'; + state_mst <= MST_R1_ACK; + end if; + + when MST_R1_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state_mst <= MST_R2; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_R2 => + mst_rd <= '1'; + --mst_sto <= '1'; + mst_ack <= '0'; + if (mst_cmd_ack = '1') then + mst_rd <= '0'; + mst_sto <= '0'; + if (tmp = x"12") then + state_mst <= MST_R3; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_R3 => + mst_rd <= '1'; + mst_sto <= '1'; + mst_ack <= '0'; + if (mst_cmd_ack = '1') then + mst_rd <= '0'; + mst_sto <= '0'; + if (tmp = x"12") then + state_mst <= MST_SUCCESS; + else + state_mst <= MST_ERR; + end if; + end if; + + when MST_SUCCESS => + if (once) then + report("Success!"); + once <= false; + end if; + + when MST_ERR => + if (once) then + report("Error!"); + once <= false; + end if; + + when others => + state_mst <= MST_ERR; + + end case; + end if; + end if; + end process p_mst_fsm; +end architecture behav; +--============================================================================== +-- architecture end +--============================================================================== diff --git a/sim/wb_i2c_bridge/tb_wb_i2c_bridge.vhd b/sim/wb_i2c_bridge/tb_wb_i2c_bridge.vhd new file mode 100644 index 0000000000000000000000000000000000000000..10ba53e0098e54191a02c23ae95dff0f6f590a3e --- /dev/null +++ b/sim/wb_i2c_bridge/tb_wb_i2c_bridge.vhd @@ -0,0 +1,698 @@ +--============================================================================== +-- CERN (BE-CO-HT) +-- Testbench for old repeater design +--============================================================================== +-- +-- author: Theodor Stana (t.stana@cern.ch) +-- +-- date of creation: 2013-02-28 +-- +-- version: 1.0 +-- +-- description: +-- +-- dependencies: +-- +-- references: +-- +--============================================================================== +-- GNU LESSER GENERAL PUBLIC LICENSE +--============================================================================== +-- This source file is free software; you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as published by the +-- Free Software Foundation; either version 2.1 of the License, or (at your +-- option) any later version. This source is distributed in the hope that it +-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-- See the GNU Lesser General Public License for more details. You should have +-- received a copy of the GNU Lesser General Public License along with this +-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html +--============================================================================== +-- last changes: +-- 2013-02-28 Theodor Stana t.stana@cern.ch File created +--============================================================================== +-- TODO: - +--============================================================================== + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.wishbone_pkg.all; + +entity tb_wb_i2c_bridge is +end entity tb_wb_i2c_bridge; + + +architecture behav of tb_wb_i2c_bridge is + + --============================================================================ + -- Type declarations + --============================================================================ + type t_state is + ( + IDLE, + I2C_ADDR, I2C_ADDR_ACK, + + WB_ADDR_B0, WB_ADDR_B0_ACK, + WB_ADDR_B1, WB_ADDR_B1_ACK, + + ST_OP, + + RD_RESTART, RD_RESTART_ACK, + RD, RD_ACK, + + WR, WR_ACK, + + STO, + + SUCCESS, + ERR + ); + + type t_reg is array(0 to 3) of std_logic_vector(31 downto 0); + + --============================================================================ + -- Constant declarations + --============================================================================ + constant c_clk_per : time := 50 ns; + constant c_reset_width : time := 112 ns; + + constant c_nr_masters : positive := 1; + constant c_nr_slaves : positive := 2; + + constant c_sval : unsigned := x"424c4f24"; + constant c_eval : unsigned := c_sval + x"A"; + + --============================================================================ + -- Component declarations + --============================================================================ + -- I2C master + component 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 component i2c_master_byte_ctrl; + + -- I2C bus model + component i2c_bus_model is + generic + ( + g_nr_masters : positive := 1; + g_nr_slaves : positive := 1 + ); + port + ( + -- Input ports from master lines + mscl_i : in std_logic_vector(g_nr_masters-1 downto 0); + msda_i : in std_logic_vector(g_nr_masters-1 downto 0); + + -- Input ports from slave lines + sscl_i : in std_logic_vector(g_nr_slaves-1 downto 0); + ssda_i : in std_logic_vector(g_nr_slaves-1 downto 0); + + -- SCL and SDA line outputs + scl_o : out std_logic; + sda_o : out std_logic + ); + end component i2c_bus_model; + + --============================================================================ + -- Signal declarations + --============================================================================ + -- Clock, reset signals + signal clk, rst_n : std_logic := '0'; + signal rst : std_logic; + + -- Slave-side I2C signals + signal scl_to_slv : std_logic; + signal scl_fr_slv : std_logic; + signal scl_en_slv : std_logic; + signal sda_to_slv : std_logic; + signal sda_fr_slv : std_logic; + signal sda_en_slv : std_logic; + + signal scl_to_slv_1 : std_logic; + signal scl_fr_slv_1 : std_logic; + signal scl_en_slv_1 : std_logic; + signal sda_to_slv_1 : std_logic; + signal sda_fr_slv_1 : std_logic; + signal sda_en_slv_1 : std_logic; + + -- SCL and SDA signals from slaves + signal sscl, ssda : std_logic_vector(c_nr_slaves-1 downto 0); + + -- Master-side I2C signals + signal scl_to_mst : std_logic; + signal scl_fr_mst : std_logic; + signal scl_en_mst : std_logic; + signal sda_to_mst : std_logic; + signal sda_fr_mst : std_logic; + signal sda_en_mst : std_logic; + + -- SCL and SDA signals from master + signal mscl, msda : std_logic_vector(c_nr_masters-1 downto 0); + + -- I2C bus signals + signal scl, sda : std_logic; + + -- I2C address, done + signal slv_addr : std_logic_vector(6 downto 0); + signal i2c_tip : std_logic; + signal i2c_err : std_logic; + signal i2c_tip_1 : std_logic; + signal i2c_err_1 : std_logic; + + -- I2C master signals + signal mst_sta : std_logic; + signal mst_sto : std_logic; + signal mst_rd : std_logic; + signal mst_wr : std_logic; + signal mst_ack : std_logic; + signal mst_dat_in : std_logic_vector(7 downto 0); + signal mst_dat_out : std_logic_vector(7 downto 0); + signal mst_cmd_ack : std_logic; + signal ack_fr_slv : std_logic; + + -- Master FSM signals + signal state : t_state; + signal mst_fsm_op : std_logic; + signal mst_fsm_start : std_logic; + signal stim_cnt : unsigned(31 downto 0); + + -- misc signals + signal cnt : unsigned(2 downto 0); + signal once : boolean; + + signal byte_cnt : unsigned(1 downto 0); + signal rcvd : std_logic_vector(31 downto 0); + signal read4 : std_logic; + signal send : std_logic_vector(31 downto 0); + signal wrote : std_logic; + signal adr : std_logic_vector(31 downto 0); + + -- Wishbone signals + signal wb_stb : std_logic; + signal wb_cyc : std_logic; + signal wb_sel : std_logic_vector(3 downto 0); + signal wb_we : std_logic; + signal wb_dat_m2s : std_logic_vector(31 downto 0); + signal wb_dat_s2m : std_logic_vector(31 downto 0); + signal wb_adr : std_logic_vector(31 downto 0); + signal wb_ack : std_logic; + + signal reg : t_reg; + + signal wb_stb_1 : std_logic; + signal wb_cyc_1 : std_logic; + signal wb_sel_1 : std_logic_vector(3 downto 0); + signal wb_we_1 : std_logic; + signal wb_dat_m2s_1 : std_logic_vector(31 downto 0); + signal wb_dat_s2m_1 : std_logic_vector(31 downto 0); + signal wb_adr_1 : std_logic_vector(31 downto 0); + signal wb_ack_1 : std_logic; + + signal reg_1 : t_reg; + +--============================================================================== +-- architecture begin +--============================================================================== +begin + + --============================================================================ + -- Reset and clock generation + --============================================================================ + -- clock + p_clk: process + begin + clk <= not clk; + wait for c_clk_per/2; + end process p_clk; + + -- reset + rst <= not rst_n; + p_rst_n: process + begin + rst_n <= '0'; + wait for c_reset_width; + rst_n <= '1'; + wait; + end process p_rst_n; + + --============================================================================ + -- DUT instantiation + --============================================================================ + ------------------------------------------------------------------------------ + -- SLAVE 1 + ------------------------------------------------------------------------------ + -- First, the instantiation itself + DUT : wb_i2c_bridge + port map + ( + -- Clock, reset + clk_i => clk, + rst_n_i => rst_n, + + -- I2C lines + scl_i => scl, + scl_o => scl_fr_slv, + scl_en_o => scl_en_slv, + sda_i => sda, + sda_o => sda_fr_slv, + sda_en_o => sda_en_slv, + + -- I2C address and status + i2c_addr_i => "1011110", + tip_o => i2c_tip, + err_p_o => i2c_err, + + -- Wishbone master signals + wbm_stb_o => wb_stb, + wbm_cyc_o => wb_cyc, + wbm_sel_o => wb_sel, + wbm_we_o => wb_we, + wbm_dat_i => wb_dat_s2m, + wbm_dat_o => wb_dat_m2s, + wbm_adr_o => wb_adr, + wbm_ack_i => wb_ack, + wbm_rty_i => '0', + wbm_err_i => '0' + ); + + -- Then, the tri-state buffer for the I2C lines + sscl(0) <= scl_fr_slv when (scl_en_slv = '1') else + '1'; + ssda(0) <= sda_fr_slv when (sda_en_slv = '1') else + '1'; + + ------------------------------------------------------------------------------ + -- SLAVE 2 + ------------------------------------------------------------------------------ + -- First, the instantiation itself + DUT_1 : wb_i2c_bridge + port map + ( + -- Clock, reset + clk_i => clk, + rst_n_i => rst_n, + + -- I2C lines + scl_i => scl, + scl_o => scl_fr_slv_1, + scl_en_o => scl_en_slv_1, + sda_i => sda, + sda_o => sda_fr_slv_1, + sda_en_o => sda_en_slv_1, + + -- I2C address and status + i2c_addr_i => "1011101", + tip_o => i2c_tip_1, + err_p_o => i2c_err_1, + + -- Wishbone master signals + wbm_stb_o => wb_stb_1, + wbm_cyc_o => wb_cyc_1, + wbm_sel_o => wb_sel_1, + wbm_we_o => wb_we_1, + wbm_dat_i => wb_dat_s2m_1, + wbm_dat_o => wb_dat_m2s_1, + wbm_adr_o => wb_adr_1, + wbm_ack_i => wb_ack_1, + wbm_rty_i => '0', + wbm_err_i => '0' + ); + + -- Then, the tri-state buffer for the I2C lines + sscl(1) <= scl_fr_slv_1 when (scl_en_slv_1 = '1') else + '1'; + ssda(1) <= sda_fr_slv_1 when (sda_en_slv_1 = '1') else + '1'; + + --============================================================================ + -- Master instantiation + --============================================================================ + -- First, the component instantiation + cmp_master: i2c_master_byte_ctrl + port map + ( + clk => clk, + rst => rst, + nReset => rst_n, + ena => '1', + + clk_cnt => x"0027", + + -- input signals + start => mst_sta, + stop => mst_sto, + read => mst_rd, + write => mst_wr, + ack_in => mst_ack, + din => mst_dat_in, + + -- output signals + cmd_ack => mst_cmd_ack, + ack_out => ack_fr_slv, + i2c_busy => open, + i2c_al => open, + dout => mst_dat_out, + + -- i2c lines + scl_i => scl, + scl_o => scl_fr_mst, + scl_oen => scl_en_mst, + sda_i => sda, + sda_o => sda_fr_mst, + sda_oen => sda_en_mst + ); + + -- Then, the tri-state buffers on the line + mscl(0) <= scl_fr_mst when (scl_en_mst = '0') else + '1'; + msda(0) <= sda_fr_mst when (sda_en_mst = '0') else + '1'; + + --============================================================================ + -- Bus model instantiation and connection to master and slaves + --============================================================================ + cmp_i2c_bus : i2c_bus_model + generic map + ( + g_nr_masters => c_nr_masters, + g_nr_slaves => c_nr_slaves + ) + port map + ( + mscl_i => mscl, + msda_i => msda, + sscl_i => sscl, + ssda_i => ssda, + scl_o => scl, + sda_o => sda + ); + + --============================================================================ + -- I2C Master FSM + --============================================================================ + -- This FSM controls the signals to the master component to implement the I2C + -- protocol defined together with ELMA. The FSM is controlled by the + -- stimuli process below + p_mst_fsm : process (clk) is + begin + if rising_edge(clk) then + if (rst_n = '0') then + state <= IDLE; + mst_sta <= '0'; + mst_wr <= '0'; + mst_sto <= '0'; + mst_rd <= '0'; + mst_dat_in <= (others => '0'); + mst_ack <= '0'; + cnt <= (others => '0'); + once <= true; + byte_cnt <= (others => '0'); + rcvd <= (others => '0'); + wrote <= '0'; + send <= (others => '0'); + else + case state is + + when IDLE => + if (mst_fsm_start = '1') then + state <= I2C_ADDR; + send <= std_logic_vector(stim_cnt); + end if; + + when I2C_ADDR => + mst_sta <= '1'; + mst_wr <= '1'; + mst_dat_in <= slv_addr & '0'; + if (mst_cmd_ack = '1') then + mst_sta <= '0'; + mst_wr <= '0'; + state <= I2C_ADDR_ACK; + end if; + + when I2C_ADDR_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state <= WB_ADDR_B0; + else + state <= ERR; + end if; + end if; + + when WB_ADDR_B0 => + mst_wr <= '1'; + mst_dat_in <= adr(15 downto 8); + if (mst_cmd_ack = '1') then + mst_wr <= '0'; + state <= WB_ADDR_B0_ACK; + end if; + + when WB_ADDR_B0_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state <= WB_ADDR_B1; + else + state <= ERR; + end if; + end if; + + when WB_ADDR_B1 => + mst_wr <= '1'; + mst_dat_in <= adr(7 downto 0); + if (mst_cmd_ack = '1') then + mst_wr <= '0'; + state <= WB_ADDR_B1_ACK; + end if; + + when WB_ADDR_B1_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state <= ST_OP; + else + state <= ERR; + end if; + end if; + + when ST_OP => + if (mst_fsm_op = '1') then + state <= RD_RESTART; + else + state <= WR; + end if; + + when RD_RESTART => + mst_wr <= '1'; + mst_dat_in <= slv_addr & '1'; + mst_sta <= '1'; + if (mst_cmd_ack = '1') then + mst_sta <= '0'; + mst_wr <= '0'; + state <= RD_RESTART_ACK; + end if; + + when RD_RESTART_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + state <= RD; + else + state <= ERR; + end if; + end if; + + when RD => + mst_rd <= '1'; + mst_ack <= '0'; + if (byte_cnt = 3) then + mst_ack <= '1'; + end if; + if (mst_cmd_ack = '1') then + mst_rd <= '0'; + byte_cnt <= byte_cnt + 1; + rcvd <= mst_dat_out & rcvd(31 downto 8); + mst_ack <= '0'; + state <= RD; + if (byte_cnt = 3) then + state <= STO; + end if; + end if; + + when RD_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + byte_cnt <= byte_cnt + 1; + rcvd <= mst_dat_out & rcvd(31 downto 8); + mst_ack <= '0'; + state <= RD; + if (byte_cnt = 3) then + state <= STO; + end if; + end if; + + when WR => + mst_wr <= '1'; + mst_dat_in <= send(7 downto 0); + if (mst_cmd_ack = '1') then + mst_wr <= '0'; + state <= WR_ACK; + end if; + + when WR_ACK => + cnt <= cnt + 1; + if (cnt = 7) then + if (ack_fr_slv = '0') then + byte_cnt <= byte_cnt + 1; + send <= x"00" & send(31 downto 8); + state <= WR; + if (byte_cnt = 3) then + state <= STO; + end if; + else + state <= ERR; + end if; + end if; + + when STO => + mst_sto <= '1'; + if (mst_cmd_ack = '1') then + mst_sto <= '0'; + state <= IDLE; + end if; + + when ERR => + if (once) then + report("Error!"); + once <= false; + end if; + + when others => + state <= ERR; + + end case; + end if; + end if; + end process p_mst_fsm; + + --============================================================================ + -- Wishbone slaves + --============================================================================ + -- First slave + p_wb_slv: process (clk) is + begin + if rising_edge(clk) then + if (rst_n = '0') then + reg <= ( + x"00000000", + x"00000000", + x"00000000", + x"00000000" + ); + wb_ack <= '0'; + wb_dat_s2m <= (others => '0'); + else + wb_ack <= '0'; + if (wb_cyc = '1') and (wb_stb = '1') then + wb_ack <= '1'; + wb_dat_s2m <= reg(to_integer(unsigned(wb_adr))); + if (wb_we = '1') then + reg(to_integer(unsigned(wb_adr))) <= wb_dat_m2s; + end if; + end if; + end if; + end if; + end process p_wb_slv; + + -- Second slave + p_wb_slv_1: process (clk) is + begin + if rising_edge(clk) then + if (rst_n = '0') then + reg_1 <= ( + x"00000000", + x"00000000", + x"00000000", + x"00000000" + ); + wb_ack_1 <= '0'; + wb_dat_s2m_1 <= (others => '0'); + else + wb_ack_1 <= '0'; + if (wb_cyc_1 = '1') and (wb_stb_1 = '1') then + wb_ack_1 <= '1'; + wb_dat_s2m_1 <= reg_1(to_integer(unsigned(wb_adr_1))); + if (wb_we_1 = '1') then + reg_1(to_integer(unsigned(wb_adr_1))) <= wb_dat_m2s_1; + end if; + end if; + end if; + end if; + end process p_wb_slv_1; + + --============================================================================ + -- A stimuli process to control the I2C FSM + --============================================================================ + p_stim : process (rst_n, state) + begin + if (rst_n = '0') then + stim_cnt <= c_sval; --(others => '0'); + mst_fsm_start <= '0'; + mst_fsm_op <= '0'; + slv_addr <= "1011110"; + adr <= (others => '0'); + elsif (state = IDLE) then + stim_cnt <= stim_cnt + 1; + mst_fsm_start <= '1'; + adr(1 downto 0) <= std_logic_vector(stim_cnt(1 downto 0)); + if (stim_cnt(0) = '1') then + slv_addr <= "1011110"; + else + slv_addr <= "1011101"; + end if; + case to_integer(stim_cnt) is + when to_integer(c_sval) to to_integer(c_eval) => + mst_fsm_op <= '0'; + when others => + mst_fsm_op <= '1'; + end case; + end if; + end process p_stim; + +end architecture behav; +--============================================================================== +-- architecture end +--============================================================================== diff --git a/sim/wb_i2c_bridge/wave-i2cs.do b/sim/wb_i2c_bridge/wave-i2cs.do new file mode 100644 index 0000000000000000000000000000000000000000..dd39ab49985b32911d187aab55dac6fb72fab6a2 --- /dev/null +++ b/sim/wb_i2c_bridge/wave-i2cs.do @@ -0,0 +1,64 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate /tb_gc_i2c_slave/clk +add wave -noupdate /tb_gc_i2c_slave/state_mst +add wave -noupdate /tb_gc_i2c_slave/state_slv +add wave -noupdate /tb_gc_i2c_slave/scl_to_slv +add wave -noupdate /tb_gc_i2c_slave/sda_to_slv +add wave -noupdate /tb_gc_i2c_slave/sda_fr_slv +add wave -noupdate /tb_gc_i2c_slave/scl_fr_mst +add wave -noupdate /tb_gc_i2c_slave/sda_to_mst +add wave -noupdate /tb_gc_i2c_slave/sda_fr_mst +add wave -noupdate -divider BUS +add wave -noupdate /tb_gc_i2c_slave/scl_to_slv +add wave -noupdate /tb_gc_i2c_slave/scl_fr_slv +add wave -noupdate /tb_gc_i2c_slave/sda_to_slv +add wave -noupdate /tb_gc_i2c_slave/sda_fr_slv +add wave -noupdate /tb_gc_i2c_slave/scl_to_mst +add wave -noupdate /tb_gc_i2c_slave/scl_fr_mst +add wave -noupdate /tb_gc_i2c_slave/sda_to_mst +add wave -noupdate /tb_gc_i2c_slave/sda_fr_mst +add wave -noupdate -divider loopback +add wave -noupdate /tb_gc_i2c_slave/txb +add wave -noupdate /tb_gc_i2c_slave/rxb +add wave -noupdate /tb_gc_i2c_slave/rcvd +add wave -noupdate /tb_gc_i2c_slave/tmp +add wave -noupdate -divider slave +add wave -noupdate /tb_gc_i2c_slave/DUT/scl_i +add wave -noupdate /tb_gc_i2c_slave/DUT/sda_i +add wave -noupdate /tb_gc_i2c_slave/DUT/tick_p +add wave -noupdate /tb_gc_i2c_slave/DUT/tick_en +add wave -noupdate /tb_gc_i2c_slave/DUT/tick_cnt +add wave -noupdate /tb_gc_i2c_slave/DUT/ack_i +add wave -noupdate /tb_gc_i2c_slave/DUT/sda_en_o +add wave -noupdate /tb_gc_i2c_slave/DUT/tx_byte_i +add wave -noupdate /tb_gc_i2c_slave/DUT/rx_byte_o +add wave -noupdate /tb_gc_i2c_slave/DUT/state +add wave -noupdate /tb_gc_i2c_slave/DUT/txsr +add wave -noupdate /tb_gc_i2c_slave/DUT/rxsr +add wave -noupdate /tb_gc_i2c_slave/DUT/bit_cnt +add wave -noupdate /tb_gc_i2c_slave/cnt +add wave -noupdate /tb_gc_i2c_slave/DUT/op_o +add wave -noupdate /tb_gc_i2c_slave/DUT/sta_p_o +add wave -noupdate /tb_gc_i2c_slave/DUT/sto_p_o +add wave -noupdate /tb_gc_i2c_slave/DUT/addr_good_p_o +add wave -noupdate /tb_gc_i2c_slave/DUT/r_done_p_o +add wave -noupdate /tb_gc_i2c_slave/DUT/w_done_p_o +add wave -noupdate /tb_gc_i2c_slave/DUT/op_o +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {2555133080 ps} 0} +configure wave -namecolwidth 400 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +configure wave -timelineunits ns +update +WaveRestoreZoom {0 ps} {4200 us} diff --git a/sim/wb_i2c_bridge/wave.do b/sim/wb_i2c_bridge/wave.do new file mode 100644 index 0000000000000000000000000000000000000000..026cf98384b1144307c2b37f5318d93553773639 --- /dev/null +++ b/sim/wb_i2c_bridge/wave.do @@ -0,0 +1,32 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate /tb_wb_i2c_bridge/clk +add wave -noupdate /tb_wb_i2c_bridge/scl +add wave -noupdate /tb_wb_i2c_bridge/sscl +add wave -noupdate /tb_wb_i2c_bridge/sda +add wave -noupdate -expand /tb_wb_i2c_bridge/ssda +add wave -noupdate /tb_wb_i2c_bridge/state +add wave -noupdate /tb_wb_i2c_bridge/stim_cnt +add wave -noupdate /tb_wb_i2c_bridge/send +add wave -noupdate -expand /tb_wb_i2c_bridge/reg +add wave -noupdate -expand /tb_wb_i2c_bridge/reg_1 +add wave -noupdate /tb_wb_i2c_bridge/rcvd +add wave -noupdate /tb_wb_i2c_bridge/DUT/cmp_i2c_slave/state +add wave -noupdate /tb_wb_i2c_bridge/DUT_1/cmp_i2c_slave/state +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 2} {728700000 ps} 0} +configure wave -namecolwidth 400 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +configure wave -timelineunits ns +update +WaveRestoreZoom {0 ps} {1640625 ns}