Commit d55d7c9a authored by Dave Newbold's avatar Dave Newbold

Removing local copies of i2c and spi cores

parent 8812fd0f
<node id="i2c" description="I2C master controller" fwinfo="endpoint;width=3">
<node id="ps_lo" address="0x0" description="Prescale low byte"/>
<node id="ps_hi" address="0x1" description="Prescale low byte"/>
<node id="ctrl" address="0x2" description="Control"/>
<node id="data" address="0x3" description="Data"/>
<node id="cmd_stat" address="0x4" description="Command / status"/>
</node>
src ipbus_i2c_master.vhd i2c_master_top.vhd i2c_master_registers.vhd i2c_master_byte_ctrl.vhd i2c_master_bit_ctrl.vhd
addrtab opencores_i2c.xml
src -c ipbus-firmware:components/ipbus_core ipbus_package.vhd
----------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<
----------------------------------------------------------------------
--///////////////////////////////////////////////////////////////////
--// ////
--// WISHBONE rev.B2 compliant I2C Master bit-controller ////
--// ////
--// ////
--// Author: Richard Herveille ////
--// richard@asics.ws ////
--// www.asics.ws ////
--// ////
--// Downloaded from: http://www.opencores.org/projects/i2c/ ////
--// ////
--///////////////////////////////////////////////////////////////////
--// ////
--// Copyright (C) 2001 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. ////
--// ////
--///////////////////////////////////////////////////////////////////
-- --------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
-- --------------------------------------------------------------------
-- Copyright (c) 2008 - 2010 by Lattice Semiconductor Corporation
-- --------------------------------------------------------------------
--
-- Disclaimer:
--
-- This VHDL or Verilog source code is intended as a design reference
-- which illustrates how these types of functions can be implemented.
-- It is the user's responsibility to verify their design for
-- consistency and functionality through the use of formal
-- verification methods. Lattice Semiconductor provides no warranty
-- regarding the use or functionality of this code.
--
-- --------------------------------------------------------------------
--
-- Lattice Semiconductor Corporation
-- 5555 NE Moore Court
-- Hillsboro, OR 97214
-- U.S.A
--
-- TEL: 1-800-Lattice (USA and Canada)
-- 503-268-8001 (other locations)
--
-- web: http://www.latticesemi.com/
-- email: techsupport@latticesemi.com
--
-- --------------------------------------------------------------------
-- Code Revision History :
-- --------------------------------------------------------------------
-- Ver: | Author |Mod. Date |Changes Made:
-- V1.0 |K.P. | 7/09 | Initial ver for VHDL
-- | converted from LSC ref design RD1046
-- --------------------------------------------------------------------
--/////////////////////////////////////
--// Bit controller section
--/////////////////////////////////////
--//
--// Translate simple commands into SCL/SDA transitions
--// Each command has 5 states, A/B/C/D/idle
--//
--// start: SCL ~~~~~~~~~~\____
--// SDA ~~~~~~~~\______
--// 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 ==X=========X=
--// x | A | B | C | D | i
--//
--//- read SCL ____/~~~~\____
--// SDA XXXX=====XXXX
--// 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.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity i2c_master_bit_ctrl is
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
clk_cnt : in std_logic_vector(15 downto 0); -- clock prescale value
ena : in std_logic; -- core enable signal
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic; -- command complete acknowledge
busy : out std_logic; -- i2c bus busy
al : out std_logic; -- i2c bus arbitration lost
din : in std_logic;
dout : out std_logic;
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;
architecture arch of i2c_master_bit_ctrl is
--attribute UGROUP:string;
--attribute UGROUP of arch : label is "bit_group";
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs
signal dscl_oen : std_logic; -- delayed scl_oen
signal sda_chk : std_logic; -- check SDA output (Multi-master arbitration)
signal clk_en : std_logic; -- clock generation signals
signal slave_wait : std_logic;
-- bus status controller signals
signal dSCL,dSDA : std_logic;
signal sta_condition : std_logic;
signal sto_condition : std_logic;
signal cmd_stop : std_logic;
signal cnt : std_logic_vector(15 downto 0); -- clock divider counter
signal scl_oen_int : std_logic;
signal sda_oen_int : std_logic;
signal busy_int : std_logic;
signal al_int : std_logic;
-- state machine variable
signal c_state : std_logic_vector(16 downto 0);
constant idle : std_logic_vector(16 downto 0) := "00000000000000000";
constant start_a : std_logic_vector(16 downto 0) := "00000000000000001";
constant start_b : std_logic_vector(16 downto 0) := "00000000000000010";
constant start_c : std_logic_vector(16 downto 0) := "00000000000000100";
constant start_d : std_logic_vector(16 downto 0) := "00000000000001000";
constant start_e : std_logic_vector(16 downto 0) := "00000000000010000";
constant stop_a : std_logic_vector(16 downto 0) := "00000000000100000";
constant stop_b : std_logic_vector(16 downto 0) := "00000000001000000";
constant stop_c : std_logic_vector(16 downto 0) := "00000000010000000";
constant stop_d : std_logic_vector(16 downto 0) := "00000000100000000";
constant rd_a : std_logic_vector(16 downto 0) := "00000001000000000";
constant rd_b : std_logic_vector(16 downto 0) := "00000010000000000";
constant rd_c : std_logic_vector(16 downto 0) := "00000100000000000";
constant rd_d : std_logic_vector(16 downto 0) := "00001000000000000";
constant wr_a : std_logic_vector(16 downto 0) := "00010000000000000";
constant wr_b : std_logic_vector(16 downto 0) := "00100000000000000";
constant wr_c : std_logic_vector(16 downto 0) := "01000000000000000";
constant wr_d : std_logic_vector(16 downto 0) := "10000000000000000";
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_WRITE : std_logic_vector(3 downto 0) := "0100";
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "1000";
begin
scl_oen <= scl_oen_int;
sda_oen <= sda_oen_int;
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
-- delay scl_oen
process(clk)
begin
if rising_edge(clk) then
dscl_oen <= scl_oen_int;
end if;
end process;
slave_wait <= '1' when ((dscl_oen = '1') AND (sSCL = '0')) else '0';
-- generate clk enable signal
process(clk,nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1';
elsif rising_edge(clk) then
if (rst = '1') then
cnt <= (others => '0');
clk_en <= '1';
elsif ((cnt = "0000000000000000") OR (ena = '0')) 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;
-- synchronize SCL and SDA inputs
-- reduce metastability risc
process(clk,nReset)
begin
if (nReset = '0') then
sSCL <= '1';
sSDA <= '1';
dSCL <= '1';
dSDA <= '1';
elsif rising_edge(clk) then
if (rst = '1') then
sSCL <= '1';
sSDA <= '1';
dSCL <= '1';
dSDA <= '1';
else
dSCL <= sSCL;
dSDA <= sSDA;
-- Don't need to treat 'H' if separate I and O
-- if ((scl_i = '1') OR (scl_i = 'H')) then
if (scl_i = '1') then
sSCL <= '1';
else
sSCL <= '0';
end if;
-- if ((sda_i = '1') OR (sda_i = 'H')) then
if (sda_i = '1') then
sSDA <= '1';
else
sSDA <= '0';
end if;
end if;
end if;
end process;
-- detect start condition => detect falling edge on SDA while SCL is high
-- detect stop condition => detect rising edge on SDA while SCL is high
process(clk,nReset)
begin
if (nReset = '0') then
sta_condition <= '0';
sto_condition <= '0';
elsif rising_edge(clk) 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;
-- generate i2c bus busy signal
process(clk,nReset)
begin
if (nReset = '0') then
busy_int <= '0';
elsif rising_edge(clk) then
if (rst = '1') then
busy_int <= '0';
else
busy_int <= (sta_condition OR busy_int) AND NOT(sto_condition);
end if;
end if;
end process;
busy <= busy_int;
-- generate arbitration lost signal
-- aribitration lost when:
-- 1) master drives SDA high, but the i2c bus is low
-- 2) stop detected while not requested
process(clk,nReset)
begin
if (nReset = '0') then
cmd_stop <= '0';
elsif rising_edge(clk) then
if (rst = '1') then
cmd_stop <= '0';
elsif (clk_en = '1') then
if (cmd = I2C_CMD_STOP) then
cmd_stop <= '1';
else
cmd_stop <= '0';
end if;
end if;
end if;
end process;
process(clk,nReset)
begin
if (nReset = '0') then
al_int <= '0';
elsif rising_edge(clk) then
if (rst = '1') then
al_int <= '0';
else
if (((sda_chk = '1') AND (sSDA = '0') AND (sda_oen_int = '1')) OR ((c_state /= idle) AND (sto_condition = '1') AND (cmd_stop = '0'))) then
al_int <= '1';
else
al_int <= '0';
end if;
end if;
end if;
end process;
al <= al_int;
-- generate dout signal (store SDA on rising edge of SCL)
process(clk)
begin
if rising_edge(clk) then
if ((sSCL = '1') AND (dSCL = '0')) then
dout <= sSDA;
end if;
end if;
end process;
--generate state machine
process(clk,nReset)
begin
if (nReset = '0') then
c_state <= idle;
cmd_ack <= '0';
scl_oen_int <= '1';
sda_oen_int <= '1';
sda_chk <= '0';
elsif rising_edge(clk) then
if ((rst = '1') OR (al_int = '1')) then
c_state <= idle;
cmd_ack <= '0';
scl_oen_int <= '1';
sda_oen_int <= '1';
sda_chk <= '0';
else
cmd_ack <= '0'; --default no command acknowledge + assert cmd_ack only 1clk cycle
if (clk_en = '1') then
case (c_state) is
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;
end case;
scl_oen_int <= scl_oen_int; -- keep SCL in same state
sda_oen_int <= sda_oen_int; -- keep SDA in same state
sda_chk <= '0'; -- don't check SDA output
when start_a => -- start
c_state <= start_b;
scl_oen_int <= scl_oen_int; -- keep SCL in same state
sda_oen_int <= '1'; -- set SDA high
sda_chk <= '0'; -- don't check SDA output
when start_b =>
c_state <= start_c;
scl_oen_int <= '1'; -- set SCL high
sda_oen_int <= '1'; -- keep SDA high
sda_chk <= '0'; -- don't check SDA output
when start_c =>
c_state <= start_d;
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= '0'; -- set SDA low
sda_chk <= '0'; -- don't check SDA output
when start_d =>
c_state <= start_e;
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA output
when start_e =>
c_state <= idle;
cmd_ack <= '1';
scl_oen_int <= '0'; -- set SCL low
sda_oen_int <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA output
when stop_a => -- stop
c_state <= stop_b;
scl_oen_int <= '0'; -- keep SCL low
sda_oen_int <= '0'; -- set SDA low
sda_chk <= '0'; -- don't check SDA output
when stop_b =>
c_state <= stop_c;
scl_oen_int <= '1'; -- set SCL high
sda_oen_int <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA output
when stop_c =>
c_state <= stop_d;
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA output
when stop_d =>
c_state <= idle;
cmd_ack <= '1';
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= '1'; -- set SDA high
sda_chk <= '0'; -- don't check SDA output
when rd_a => -- read
c_state <= rd_b;
scl_oen_int <= '0'; -- keep SCL low
sda_oen_int <= '1'; -- tri-state SDA
sda_chk <= '0'; -- don't check SDA output
when rd_b =>
c_state <= rd_c;
scl_oen_int <= '1'; -- set SCL high
sda_oen_int <= '1'; -- keep SDA tri-stated
sda_chk <= '0'; -- don't check SDA output
when rd_c =>
c_state <= rd_d;
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= '1'; -- keep SDA tri-stated
sda_chk <= '0'; -- don't check SDA output
when rd_d =>
c_state <= idle;
cmd_ack <= '1';
scl_oen_int <= '0'; -- set SCL low
sda_oen_int <= '1'; -- keep SDA tri-stated
sda_chk <= '0'; -- don't check SDA output
when wr_a => -- write
c_state <= wr_b;
scl_oen_int <= '0'; -- keep SCL low
sda_oen_int <= din; -- set SDA
sda_chk <= '0'; -- don't check SDA output (SCL low)
when wr_b =>
c_state <= wr_c;
scl_oen_int <= '1'; -- set SCL high
sda_oen_int <= din; -- keep SDA
sda_chk <= '1'; -- check SDA output
when wr_c =>
c_state <= wr_d;
scl_oen_int <= '1'; -- keep SCL high
sda_oen_int <= din;
sda_chk <= '1'; -- check SDA output
when wr_d =>
c_state <= idle;
cmd_ack <= '1';
scl_oen_int <= '0'; -- set SCL low
sda_oen_int <= din;
sda_chk <= '0'; -- don't check SDA output (SCL low)
when others => NULL;
end case;
end if;
end if;
end if;
end process;
-- assign scl and sda output (always gnd)
scl_o <= '0';
sda_o <= '0';
end arch;
----------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<
----------------------------------------------------------------------
--///////////////////////////////////////////////////////////////////
--// ////
--// WISHBONE rev.B2 compliant I2C Master byte-controller ////
--// ////
--// ////
--// Author: Richard Herveille ////
--// richard@asics.ws ////
--// www.asics.ws ////
--// ////
--// Downloaded from: http://www.opencores.org/projects/i2c/ ////
--// ////
--///////////////////////////////////////////////////////////////////
--// ////
--// Copyright (C) 2001 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. ////
--// ////
--///////////////////////////////////////////////////////////////////
-----------------------------------------------------------------------
-- Copyright (c) 2008 - 2010 by Lattice Semiconductor Corporation
-- --------------------------------------------------------------------
--
-- Disclaimer:
--
-- This VHDL or Verilog source code is intended as a design reference
-- which illustrates how these types of functions can be implemented.
-- It is the user's responsibility to verify their design for
-- consistency and functionality through the use of formal
-- verification methods. Lattice Semiconductor provides no warranty
-- regarding the use or functionality of this code.
--
-- --------------------------------------------------------------------
--
-- Lattice Semiconductor Corporation
-- 5555 NE Moore Court
-- Hillsboro, OR 97214
-- U.S.A
--
-- TEL: 1-800-Lattice (USA and Canada)
-- 503-268-8001 (other locations)
--
-- web: http://www.latticesemi.com/
-- email: techsupport@latticesemi.com
--
-- --------------------------------------------------------------------
-- Code Revision History :
-- --------------------------------------------------------------------
-- Ver: | Author |Mod. Date |Changes Made:
-- V1.0 |K.P. | 7/09 | Initial ver for VHDL
-- | converted from LSC ref design RD1046
-- --------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity i2c_master_byte_ctrl is
port (
clk : in std_logic; -- master clock
rst : in std_logic; -- synchronous active high reset
nReset : in std_logic; -- asynchronous active low reset
clk_cnt : in std_logic_vector(15 downto 0); -- 4x SCL
-- control inputs
start : in std_logic;
stop : in std_logic;
read : in std_logic;
write : in std_logic;
ack_in : in std_logic;
din : in std_logic_vector(7 downto 0);
-- status outputs
cmd_ack : out std_logic;
ack_out : out std_logic; -- i2c clock line input
dout : out std_logic_vector(7 downto 0);
i2c_al : in std_logic;
-- signals for bit_controller
core_cmd : out std_logic_vector(3 downto 0);
core_txd : out std_logic;
core_rxd : in std_logic;
core_ack : in std_logic
);
end;
architecture arch of i2c_master_byte_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_WRITE : std_logic_vector(3 downto 0) := "0100";
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "1000";
constant ST_IDLE : std_logic_vector(4 downto 0) := "00000";
constant ST_START : std_logic_vector(4 downto 0) := "00001";
constant ST_READ : std_logic_vector(4 downto 0) := "00010";
constant ST_WRITE : std_logic_vector(4 downto 0) := "00100";
constant ST_ACK : std_logic_vector(4 downto 0) := "01000";
constant ST_STOP : std_logic_vector(4 downto 0) := "10000";
signal c_state : std_logic_vector(4 downto 0);
signal go : std_logic;
signal dcnt : std_logic_vector(2 downto 0);
signal cnt_done : std_logic;
signal sr : std_logic_vector(7 downto 0); --8bit shift register
signal shift, ld : std_logic;
signal cmd_ack_int : std_logic;
begin
go <= '1' when (((read = '1') OR (write = '1') OR (stop = '1')) AND (cmd_ack_int = '0')) else '0';
dout <= sr;
-- generate shift register
process(clk,nReset)
begin
if (nReset = '0') then
sr <= (others => '0');
elsif rising_edge(clk) 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;
-- generate counter
process(clk,nReset)
begin
if (nReset = '0') then
dcnt <= (others => '0');
elsif rising_edge(clk) then
if (rst = '1') then
dcnt <= (others => '0');
elsif (ld = '1') then
dcnt <= "111";
elsif (shift = '1') then
dcnt <= dcnt - '1';
end if;
end if;
end process;
cnt_done <= '1' when (dcnt = "000") else '0';
-- state machine
process(clk,nReset)
begin
if (nReset = '0') then
core_cmd <= I2C_CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
cmd_ack_int <= '0';
c_state <= ST_IDLE;
ack_out <= '0';
elsif rising_edge(clk) then
if ((rst = '1') OR (i2c_al = '1')) then
core_cmd <= I2C_CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
cmd_ack_int <= '0';
c_state <= ST_IDLE;
ack_out <= '0';
else
-- initially reset all signals
core_txd <= sr(7);
shift <= '0';
ld <= '0';
cmd_ack_int <= '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
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
shift <= '1';
end if;
shift <= '1';
core_txd <= ack_in;
end if;
when ST_ACK =>
if (core_ack = '1') then
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
cmd_ack_int <= '1';
end if;
-- assign ack_out output to bit_controller_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
cmd_ack_int <= '1';
end if;
when others => NULL;
end case;
end if;
end if;
end process;
cmd_ack <= cmd_ack_int;
end arch;
----------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<
----------------------------------------------------------------------
--///////////////////////////////////////////////////////////////////
--// ////
--// WISHBONE rev.B2 compliant I2C Master registers ////
--// ////
--// ////
--// Author: Richard Herveille ////
--// richard@asics.ws ////
--// www.asics.ws ////
--// ////
--// Downloaded from: http://www.opencores.org/projects/i2c/ ////
--// ////
--///////////////////////////////////////////////////////////////////
--// ////
--// Copyright (C) 2001 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. ////
--// ////
--///////////////////////////////////////////////////////////////////
-- --------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
-- --------------------------------------------------------------------
-- Copyright (c) 2008 - 2010 by Lattice Semiconductor Corporation
-- --------------------------------------------------------------------
--
-- Disclaimer:
--
-- This VHDL or Verilog source code is intended as a design reference
-- which illustrates how these types of functions can be implemented.
-- It is the user's responsibility to verify their design for
-- consistency and functionality through the use of formal
-- verification methods. Lattice Semiconductor provides no warranty
-- regarding the use or functionality of this code.
--
-- --------------------------------------------------------------------
--
-- Lattice Semiconductor Corporation
-- 5555 NE Moore Court
-- Hillsboro, OR 97214
-- U.S.A
--
-- TEL: 1-800-Lattice (USA and Canada)
-- 503-268-8001 (other locations)
--
-- web: http://www.latticesemi.com/
-- email: techsupport@latticesemi.com
--
-- --------------------------------------------------------------------
-- Code Revision History :
-- --------------------------------------------------------------------
-- Ver: | Author |Mod. Date |Changes Made:
-- V1.0 |K.P. | 7/09 | Initial ver for VHDL
-- | converted from LSC ref design RD1046
-- --------------------------------------------------------------------
-- --------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity i2c_master_registers is
port (
wb_clk_i : in std_logic;
rst_i : in std_logic;
wb_rst_i : in std_logic;
wb_dat_i : in std_logic_vector(7 downto 0);
wb_adr_i : in std_logic_vector(2 downto 0);
wb_wacc : in std_logic;
i2c_al : in std_logic;
i2c_busy : in std_logic;
done : in std_logic;
irxack : in std_logic;
prer : out std_logic_vector(15 downto 0); -- clock prescale register
ctr : out std_logic_vector(7 downto 0); -- control register
txr : out std_logic_vector(7 downto 0); -- transmit register
cr : out std_logic_vector(7 downto 0); -- command register
sr : out std_logic_vector(7 downto 0) -- status register
);
end;
architecture arch of i2c_master_registers is
signal ctr_int : std_logic_vector(7 downto 0);
signal cr_int : std_logic_vector(7 downto 0);
signal al : std_logic; -- status register arbitration lost bit
signal rxack : std_logic; -- received aknowledge from slave
signal tip : std_logic; -- transfer in progress
signal irq_flag : std_logic; -- interrupt pending flag
begin
-- generate prescale regisres, control registers, and transmit register
process(wb_clk_i,rst_i)
begin
if (rst_i = '0') then
prer <= (others => '1');
ctr_int <= (others => '0');
txr <= (others => '0');
elsif rising_edge(wb_clk_i) then
if (wb_rst_i = '1') then
prer <= (others => '1');
ctr_int <= (others => '0');
txr <= (others => '0');
elsif (wb_wacc = '1') then
case (wb_adr_i) is
when "000" => prer(7 downto 0) <= wb_dat_i;
when "001" => prer(15 downto 8) <= wb_dat_i;
when "010" => ctr_int <= wb_dat_i;
when "011" => txr <= wb_dat_i;
when others => NULL;
end case;
end if;
end if;
end process;
ctr <= ctr_int;
-- generate command register (special case)
process(wb_clk_i,rst_i)
begin
if (rst_i = '0') then
cr_int <= (others => '0');
elsif rising_edge(wb_clk_i) then
if (wb_rst_i = '1') then
cr_int <= (others => '0');
elsif (wb_wacc = '1') then
if ((ctr_int(7) = '1') AND (wb_adr_i = "100")) then
cr_int <= wb_dat_i;
end if;
else
if ((done = '1') OR (i2c_al = '1')) then
cr_int(7 downto 4) <= "0000"; -- clear command b
end if; -- or when aribitr
cr_int(2 downto 1) <= "00"; -- reserved bits
cr_int(0) <= '0'; -- clear IRQ_ACK b
end if;
end if;
end process;
cr <= cr_int;
-- generate status register block + interrupt request signal
-- each output will be assigned to corresponding sr register locations on top level
process(wb_clk_i,rst_i)
begin
if (rst_i = '0') then
al <= '0';
rxack <= '0';
tip <= '0';
irq_flag <= '0';
elsif rising_edge(wb_clk_i) then
if (wb_rst_i = '1') then
al <= '0';
rxack <= '0';
tip <= '0';
irq_flag <= '0';
else
al <= i2c_al OR (al AND NOT(cr_int(7)));
rxack <= irxack;
tip <= (cr_int(5) OR cr_int(4));
irq_flag <= (done OR i2c_al OR irq_flag) AND NOT(cr_int(0)); -- interrupt request flag is always generated
end if;
end if;
end process;
sr(7) <= rxack;
sr(6) <= i2c_busy;
sr(5) <= al;
sr(4 downto 2) <= "000"; -- reserved
sr(1) <= tip;
sr(0) <= irq_flag;
end arch;
----------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<
----------------------------------------------------------------------
--///////////////////////////////////////////////////////////////////
--// ////
--// WISHBONE rev.B2 compliant I2C Master bit-controller ////
--// ////
--// ////
--// Author: Richard Herveille ////
--// richard@asics.ws ////
--// www.asics.ws ////
--// ////
--// Downloaded from: http://www.opencores.org/projects/i2c/ ////
--// ////
--///////////////////////////////////////////////////////////////////
--// ////
--// Copyright (C) 2001 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. ////
--// ////
--///////////////////////////////////////////////////////////////////
-- --------------------------------------------------------------------
-- >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
-- --------------------------------------------------------------------
-- Copyright (c) 2008 - 2010 by Lattice Semiconductor Corporation
-- --------------------------------------------------------------------
--
-- Disclaimer:
--
-- This VHDL or Verilog source code is intended as a design reference
-- which illustrates how these types of functions can be implemented.
-- It is the user's responsibility to verify their design for
-- consistency and functionality through the use of formal
-- verification methods. Lattice Semiconductor provides no warranty
-- regarding the use or functionality of this code.
--
-- --------------------------------------------------------------------
--
-- Lattice Semiconductor Corporation
-- 5555 NE Moore Court
-- Hillsboro, OR 97214
-- U.S.A
--
-- TEL: 1-800-Lattice (USA and Canada)
-- 503-268-8001 (other locations)
--
-- web: http://www.latticesemi.com/
-- email: techsupport@latticesemi.com
--
-- --------------------------------------------------------------------
-- Code Revision History :
-- --------------------------------------------------------------------
-- Ver: | Author |Mod. Date |Changes Made:
-- V1.0 |K.P. | 7/09 | Initial ver for VHDL
-- | converted from LSC ref design RD1046
-------------------------------------------------------------------------------
-- Changes at University of bristol:
-- V1.0A|D.G.C | 5/11 | Changed name and ports to fit OC original
-- --------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity i2c_master_top is
generic (
ARST_LVL : integer := 0
);
port (
wb_clk_i : in std_logic;
wb_rst_i : in std_logic;
arst_i : in std_logic;
wb_adr_i : in std_logic_vector(2 downto 0);
wb_dat_i : in std_logic_vector(7 downto 0);
wb_dat_o : out std_logic_vector(7 downto 0);
wb_we_i : in std_logic;
wb_stb_i : in std_logic;
wb_cyc_i : in std_logic;
wb_ack_o : out std_logic;
wb_inta_o: out std_logic;
scl_pad_i: in std_logic;
scl_pad_o: out std_logic;
scl_padoen_o: out std_logic;
sda_pad_i: in std_logic;
sda_pad_o: out std_logic;
sda_padoen_o: out std_logic
-- scl : inout std_logic;
-- sda : inout std_logic
);
end;
architecture arch of i2c_master_top is
component i2c_master_bit_ctrl
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
clk_cnt : in std_logic_vector(15 downto 0); -- clock prescale value
ena : in std_logic; -- core enable signal
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic; -- command complete acknowledge
busy : out std_logic; -- i2c bus busy
al : out std_logic; -- i2c bus arbitration lost
din : in std_logic;
dout : out std_logic;
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;
component i2c_master_byte_ctrl
port (
clk : in std_logic; -- master clock
rst : in std_logic; -- synchronous active high reset
nReset : in std_logic; -- asynchronous active low reset
clk_cnt : in std_logic_vector(15 downto 0); -- 4x SCL
-- control inputs
start : in std_logic;
stop : in std_logic;
read : in std_logic;
write : in std_logic;
ack_in : in std_logic;
din : in std_logic_vector(7 downto 0);
-- status outputs
cmd_ack : out std_logic;
ack_out : out std_logic; -- i2c clock line input
dout : out std_logic_vector(7 downto 0);
i2c_al : in std_logic;
-- signals for bit_controller
core_cmd : out std_logic_vector(3 downto 0);
core_txd : out std_logic;
core_rxd : in std_logic;
core_ack : in std_logic
);
end component;
component i2c_master_registers
port (
wb_clk_i : in std_logic;
rst_i : in std_logic;
wb_rst_i : in std_logic;
wb_dat_i : in std_logic_vector(7 downto 0);
wb_adr_i : in std_logic_vector(2 downto 0);
wb_wacc : in std_logic;
i2c_al : in std_logic;
i2c_busy : in std_logic;
done : in std_logic;
irxack : in std_logic;
prer : out std_logic_vector(15 downto 0); -- clock prescale register
ctr : out std_logic_vector(7 downto 0); -- control register
txr : out std_logic_vector(7 downto 0); -- transmit register
cr : out std_logic_vector(7 downto 0); -- command register
sr : out std_logic_vector(7 downto 0) -- status register
);
end component;
signal prer : std_logic_vector(15 downto 0);
signal ctr : std_logic_vector(7 downto 0);
signal txr : std_logic_vector(7 downto 0);
signal rxr : std_logic_vector(7 downto 0);
signal cr : std_logic_vector(7 downto 0);
signal sr : std_logic_vector(7 downto 0);
signal done : std_logic;
signal core_en : std_logic;
signal ien : std_logic;
signal irxack : std_logic;
signal irq_flag : std_logic;
signal i2c_busy : std_logic;
signal i2c_al : std_logic;
signal core_cmd : std_logic_vector(3 downto 0);
signal core_txd : std_logic;
signal core_ack, core_rxd : std_logic;
-- Don't need these signals, since passing them through
-- component interface
--signal scl_pad_i : std_logic;
--signal scl_pad_o : std_logic;
--signal scl_padoen_o : std_logic;
--
--signal sda_pad_i : std_logic;
--signal sda_pad_o : std_logic;
--signal sda_padoen_o : std_logic;
signal rst_i : std_logic;
signal sta : std_logic;
signal sto : std_logic;
signal rd : std_logic;
signal wr : std_logic;
signal ack : std_logic;
signal iack : std_logic;
signal wb_ack_o_int : std_logic;
signal wb_wacc : std_logic;
signal acki : std_logic;
begin
-- Don't need to copy these signal - passing through
-- component interface
--scl_pad_i <= scl;
--sda_pad_i <= sda;
rst_i <= arst_i when (ARST_LVL = 0) else NOT(arst_i);
wb_wacc <= wb_cyc_i AND wb_stb_i AND wb_we_i;
sta <= cr(7);
sto <= cr(6);
rd <= cr(5);
wr <= cr(4);
ack <= cr(3);
acki <= cr(0);
core_en <= ctr(7);
ien <= ctr(6);
process(wb_clk_i)
begin
if rising_edge(wb_clk_i) then
wb_ack_o_int <= wb_cyc_i AND wb_stb_i AND NOT(wb_ack_o_int);
end if;
end process;
wb_ack_o <= wb_ack_o_int;
process(wb_clk_i)
begin
if rising_edge(wb_clk_i) then
case (wb_adr_i) is
when "000" => wb_dat_o <= prer(7 downto 0);
when "001" => wb_dat_o <= prer(15 downto 8);
when "010" => wb_dat_o <= ctr;
when "011" => wb_dat_o <= rxr;
when "100" => wb_dat_o <= sr;
when "101" => wb_dat_o <= txr;
when "110" => wb_dat_o <= cr;
when "111" => wb_dat_o <= "00000000";
when others => NULL;
end case;
end if;
end process;
process(wb_clk_i,rst_i)
begin
if (rst_i = '0') then
wb_inta_o <= '0';
elsif rising_edge(wb_clk_i) then
wb_inta_o <= sr(0) AND ien;
end if;
end process;
byte_controller: i2c_master_byte_ctrl port map(
clk => wb_clk_i,
rst => wb_rst_i,
nReset => rst_i,
clk_cnt => prer,
start => sta,
stop => sto,
read => rd,
write => wr,
ack_in => ack,
din => txr,
cmd_ack => done,
ack_out => irxack,
dout => rxr,
i2c_al => i2c_al,
core_cmd => core_cmd,
core_ack => core_ack,
core_txd => core_txd,
core_rxd => core_rxd);
bit_controller: i2c_master_bit_ctrl port map(
clk => wb_clk_i,
rst => wb_rst_i,
nReset => rst_i,
ena => core_en,
clk_cnt => prer,
cmd => core_cmd,
cmd_ack => core_ack,
busy => i2c_busy,
al => i2c_al,
din => core_txd,
dout => core_rxd,
scl_i => scl_pad_i,
scl_o => scl_pad_o,
scl_oen => scl_padoen_o,
sda_i => sda_pad_i,
sda_o => sda_pad_o,
sda_oen => sda_padoen_o);
registers: i2c_master_registers port map(
wb_clk_i => wb_clk_i,
rst_i => rst_i,
wb_rst_i => wb_rst_i,
wb_dat_i => wb_dat_i,
wb_wacc => wb_wacc,
wb_adr_i => wb_adr_i,
i2c_al => i2c_al,
i2c_busy => i2c_busy,
done => done,
irxack => irxack,
prer => prer,
ctr => ctr,
txr => txr,
cr => cr,
sr => sr);
-- edited from Lattice original to pass uni-directional signals
--scl <= scl_pad_o when (scl_padoen_o = '0') else 'Z';
--sda <= sda_pad_o when (sda_padoen_o = '0') else 'Z';
end arch;
-- ipbus_i2c_master
--
-- Wrapper for opencores i2c wishbone slave
--
-- Dave Newbold, Jan 2012
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.ipbus.all;
entity ipbus_i2c_master is
generic(addr_width: natural := 0);
port(
clk: in std_logic;
rst: in std_logic;
ipb_in: in ipb_wbus;
ipb_out: out ipb_rbus;
scl: out std_logic;
sda_o: out std_logic;
sda_i: in std_logic
);
end ipbus_i2c_master;
architecture rtl of ipbus_i2c_master is
signal stb, ack, scl_i, sda_enb: std_logic;
begin
stb <= ipb_in.ipb_strobe and not ack;
i2c: entity work.i2c_master_top port map(
wb_clk_i => clk,
wb_rst_i => rst,
arst_i => '1',
wb_adr_i => ipb_in.ipb_addr(2 downto 0),
wb_dat_i => ipb_in.ipb_wdata(7 downto 0),
wb_dat_o => ipb_out.ipb_rdata(7 downto 0),
wb_we_i => ipb_in.ipb_write,
wb_stb_i => stb,
wb_cyc_i => '1',
wb_ack_o => ack,
scl_pad_i => scl_i,
scl_padoen_o => scl_i,
sda_pad_i => sda_i,
sda_padoen_o => sda_o
);
ipb_out.ipb_rdata(31 downto 8) <= (others => '0');
ipb_out.ipb_ack <= ack;
ipb_out.ipb_err <= '0';
scl <= scl_i;
end rtl;
<node id="spi" description="SPI master controller" fwinfo="endpoint;width=3">
<node id="d0" address="0x0" description="Data reg 0"/>
<node id="d1" address="0x1" description="Data reg 1"/>
<node id="d2" address="0x2" description="Data reg 2"/>
<node id="d3" address="0x3" description="Data reg 3"/>
<node id="ctrl" address="0x4" description="Control reg"/>
<node id="divider" address="0x5" description="Clock divider reg"/>
<node id="ss" address="0x6" description="Slave select reg"/>
</node>
src ipbus_spi.vhd spi_top.v spi_clgen.v spi_shift.v spi_defines.v timescale.v
addrtab opencores_spi.xml
src -c ipbus-firmware:components/ipbus_core ipbus_package.vhd
-- ipbus_spi
--
-- Wrapper for opencores spi wishbone slave
--
-- http://opencores.org/project/spi
--
-- Dave Newbold, Jul 2015
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.ipbus.all;
entity ipbus_spi is
generic(
N_SS: positive := 8
);
port(
clk: in std_logic;
rst: in std_logic;
ipb_in: in ipb_wbus;
ipb_out: out ipb_rbus;
ss: out std_logic_vector(N_SS - 1 downto 0);
mosi: out std_logic;
miso: in std_logic;
sclk: out std_logic
);
end ipbus_spi;
architecture rtl of ipbus_spi is
signal stb, ack, err, onebit, miso_sig: std_logic;
signal ss_i: std_logic_vector(7 downto 0);
component spi_top
port(
wb_clk_i: IN std_logic;
wb_rst_i: IN std_logic;
wb_adr_i : IN std_logic_vector(4 downto 0);
wb_dat_i : IN std_logic_vector(31 downto 0);
wb_dat_o : OUT std_logic_vector(31 downto 0);
wb_sel_i : IN std_logic_vector(3 downto 0);
wb_we_i : IN std_logic;
wb_stb_i : IN std_logic;
wb_cyc_i : IN std_logic;
wb_ack_o : OUT std_logic;
wb_err_o : OUT std_logic;
wb_int_o : OUT std_logic;
ss_pad_o : OUT std_logic_vector(7 downto 0);
sclk_pad_o: OUT std_logic;
mosi_pad_o: OUT std_logic;
miso_pad_i: IN std_logic
);
end component;
begin
miso_sig <= miso;
stb <= ipb_in.ipb_strobe and not (ack or err);
spi: spi_top
port map(
wb_clk_i => clk,
wb_rst_i => rst,
wb_adr_i(4 downto 2) => ipb_in.ipb_addr(2 downto 0),
wb_adr_i(1 downto 0) => std_logic_vector'("00"),
wb_dat_i => ipb_in.ipb_wdata,
wb_dat_o => ipb_out.ipb_rdata,
wb_sel_i => std_logic_vector'("1111"),
wb_we_i => ipb_in.ipb_write,
wb_stb_i => stb,
wb_cyc_i => std_logic'('1'),
wb_ack_o => ack,
wb_err_o => err,
wb_int_o => open,
ss_pad_o => ss_i,
sclk_pad_o => sclk,
mosi_pad_o => mosi,
miso_pad_i => miso_sig
);
ss <= ss_i(N_SS - 1 downto 0);
ipb_out.ipb_ack <= ack;
ipb_out.ipb_err <= err;
end rtl;
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_clgen.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// 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 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.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
`include "timescale.v"
module spi_clgen (clk_in, rst, go, enable, last_clk, divider, clk_out, pos_edge, neg_edge);
parameter Tp = 1;
input clk_in; // input clock (system clock)
input rst; // reset
input enable; // clock enable
input go; // start transfer
input last_clk; // last clock
input [`SPI_DIVIDER_LEN-1:0] divider; // clock divider (output clock is divided by this value)
output clk_out; // output clock
output pos_edge; // pulse marking positive edge of clk_out
output neg_edge; // pulse marking negative edge of clk_out
reg clk_out;
reg pos_edge;
reg neg_edge;
reg [`SPI_DIVIDER_LEN-1:0] cnt; // clock counter
wire cnt_zero; // conter is equal to zero
wire cnt_one; // conter is equal to one
assign cnt_zero = cnt == {`SPI_DIVIDER_LEN{1'b0}};
assign cnt_one = cnt == {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
// Counter counts half period
always @(posedge clk_in or posedge rst)
begin
if(rst)
cnt <= #Tp {`SPI_DIVIDER_LEN{1'b1}};
else
begin
if(!enable || cnt_zero)
cnt <= #Tp divider;
else
cnt <= #Tp cnt - {{`SPI_DIVIDER_LEN-1{1'b0}}, 1'b1};
end
end
// clk_out is asserted every other half period
always @(posedge clk_in or posedge rst)
begin
if(rst)
clk_out <= #Tp 1'b0;
else
clk_out <= #Tp (enable && cnt_zero && (!last_clk || clk_out)) ? ~clk_out : clk_out;
end
// Pos and neg edge signals
always @(posedge clk_in or posedge rst)
begin
if(rst)
begin
pos_edge <= #Tp 1'b0;
neg_edge <= #Tp 1'b0;
end
else
begin
pos_edge <= #Tp (enable && !clk_out && cnt_one) || (!(|divider) && clk_out) || (!(|divider) && go && !enable);
neg_edge <= #Tp (enable && clk_out && cnt_one) || (!(|divider) && !clk_out && enable);
end
end
endmodule
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_define.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// 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 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.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// Number of bits used for devider register. If used in system with
// low frequency of system clock this can be reduced.
// Use SPI_DIVIDER_LEN for fine tuning theexact number.
//
//`define SPI_DIVIDER_LEN_8
`define SPI_DIVIDER_LEN_16
//`define SPI_DIVIDER_LEN_24
//`define SPI_DIVIDER_LEN_32
`ifdef SPI_DIVIDER_LEN_8
`define SPI_DIVIDER_LEN 8 // Can be set from 1 to 8
`endif
`ifdef SPI_DIVIDER_LEN_16
`define SPI_DIVIDER_LEN 16 // Can be set from 9 to 16
`endif
`ifdef SPI_DIVIDER_LEN_24
`define SPI_DIVIDER_LEN 24 // Can be set from 17 to 24
`endif
`ifdef SPI_DIVIDER_LEN_32
`define SPI_DIVIDER_LEN 32 // Can be set from 25 to 32
`endif
//
// Maximum nuber of bits that can be send/received at once.
// Use SPI_MAX_CHAR for fine tuning the exact number, when using
// SPI_MAX_CHAR_32, SPI_MAX_CHAR_24, SPI_MAX_CHAR_16, SPI_MAX_CHAR_8.
//
`define SPI_MAX_CHAR_128
//`define SPI_MAX_CHAR_64
//`define SPI_MAX_CHAR_32
//`define SPI_MAX_CHAR_24
//`define SPI_MAX_CHAR_16
//`define SPI_MAX_CHAR_8
`ifdef SPI_MAX_CHAR_128
`define SPI_MAX_CHAR 128 // Can only be set to 128
`define SPI_CHAR_LEN_BITS 7
`endif
`ifdef SPI_MAX_CHAR_64
`define SPI_MAX_CHAR 64 // Can only be set to 64
`define SPI_CHAR_LEN_BITS 6
`endif
`ifdef SPI_MAX_CHAR_32
`define SPI_MAX_CHAR 32 // Can be set from 25 to 32
`define SPI_CHAR_LEN_BITS 5
`endif
`ifdef SPI_MAX_CHAR_24
`define SPI_MAX_CHAR 24 // Can be set from 17 to 24
`define SPI_CHAR_LEN_BITS 5
`endif
`ifdef SPI_MAX_CHAR_16
`define SPI_MAX_CHAR 16 // Can be set from 9 to 16
`define SPI_CHAR_LEN_BITS 4
`endif
`ifdef SPI_MAX_CHAR_8
`define SPI_MAX_CHAR 8 // Can be set from 1 to 8
`define SPI_CHAR_LEN_BITS 3
`endif
//
// Number of device select signals. Use SPI_SS_NB for fine tuning the
// exact number.
//
`define SPI_SS_NB_8
//`define SPI_SS_NB_16
//`define SPI_SS_NB_24
//`define SPI_SS_NB_32
`ifdef SPI_SS_NB_8
`define SPI_SS_NB 8 // Can be set from 1 to 8
`endif
`ifdef SPI_SS_NB_16
`define SPI_SS_NB 16 // Can be set from 9 to 16
`endif
`ifdef SPI_SS_NB_24
`define SPI_SS_NB 24 // Can be set from 17 to 24
`endif
`ifdef SPI_SS_NB_32
`define SPI_SS_NB 32 // Can be set from 25 to 32
`endif
//
// Bits of WISHBONE address used for partial decoding of SPI registers.
//
`define SPI_OFS_BITS 4:2
//
// Register offset
//
`define SPI_RX_0 0
`define SPI_RX_1 1
`define SPI_RX_2 2
`define SPI_RX_3 3
`define SPI_TX_0 0
`define SPI_TX_1 1
`define SPI_TX_2 2
`define SPI_TX_3 3
`define SPI_CTRL 4
`define SPI_DEVIDE 5
`define SPI_SS 6
//
// Number of bits in ctrl register
//
`define SPI_CTRL_BIT_NB 14
//
// Control register bit position
//
`define SPI_CTRL_ASS 13
`define SPI_CTRL_IE 12
`define SPI_CTRL_LSB 11
`define SPI_CTRL_TX_NEGEDGE 10
`define SPI_CTRL_RX_NEGEDGE 9
`define SPI_CTRL_GO 8
`define SPI_CTRL_RES_1 7
`define SPI_CTRL_CHAR_LEN 6:0
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_shift.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// 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 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.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
`include "timescale.v"
module spi_shift (clk, rst, latch, byte_sel, len, lsb, go,
pos_edge, neg_edge, rx_negedge, tx_negedge,
tip, last,
p_in, p_out, s_clk, s_in, s_out);
parameter Tp = 1;
input clk; // system clock
input rst; // reset
input [3:0] latch; // latch signal for storing the data in shift register
input [3:0] byte_sel; // byte select signals for storing the data in shift register
input [`SPI_CHAR_LEN_BITS-1:0] len; // data len in bits (minus one)
input lsb; // lbs first on the line
input go; // start stansfer
input pos_edge; // recognize posedge of sclk
input neg_edge; // recognize negedge of sclk
input rx_negedge; // s_in is sampled on negative edge
input tx_negedge; // s_out is driven on negative edge
output tip; // transfer in progress
output last; // last bit
input [31:0] p_in; // parallel in
output [`SPI_MAX_CHAR-1:0] p_out; // parallel out
input s_clk; // serial clock
input s_in; // serial in
output s_out; // serial out
reg s_out;
reg tip;
reg [`SPI_CHAR_LEN_BITS:0] cnt; // data bit count
reg [`SPI_MAX_CHAR-1:0] data; // shift register
wire [`SPI_CHAR_LEN_BITS:0] tx_bit_pos; // next bit position
wire [`SPI_CHAR_LEN_BITS:0] rx_bit_pos; // next bit position
wire rx_clk; // rx clock enable
wire tx_clk; // tx clock enable
assign p_out = data;
assign tx_bit_pos = lsb ? {!(|len), len} - cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1};
assign rx_bit_pos = lsb ? {!(|len), len} - (rx_negedge ? cnt + {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1} : cnt) :
(rx_negedge ? cnt : cnt - {{`SPI_CHAR_LEN_BITS{1'b0}},1'b1});
assign last = !(|cnt);
assign rx_clk = (rx_negedge ? neg_edge : pos_edge) && (!last || s_clk);
assign tx_clk = (tx_negedge ? neg_edge : pos_edge) && !last;
// Character bit counter
always @(posedge clk or posedge rst)
begin
if(rst)
cnt <= #Tp {`SPI_CHAR_LEN_BITS+1{1'b0}};
else
begin
if(tip)
cnt <= #Tp pos_edge ? (cnt - {{`SPI_CHAR_LEN_BITS{1'b0}}, 1'b1}) : cnt;
else
cnt <= #Tp !(|len) ? {1'b1, {`SPI_CHAR_LEN_BITS{1'b0}}} : {1'b0, len};
end
end
// Transfer in progress
always @(posedge clk or posedge rst)
begin
if(rst)
tip <= #Tp 1'b0;
else if(go && ~tip)
tip <= #Tp 1'b1;
else if(tip && last && pos_edge)
tip <= #Tp 1'b0;
end
// Sending bits to the line
always @(posedge clk or posedge rst)
begin
if (rst)
s_out <= #Tp 1'b0;
else
s_out <= #Tp (tx_clk || !tip) ? data[tx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] : s_out;
end
// Receiving bits from the line
always @(posedge clk or posedge rst)
begin
if (rst)
data <= #Tp {`SPI_MAX_CHAR{1'b0}};
`ifdef SPI_MAX_CHAR_128
else if (latch[0] && !tip)
begin
if (byte_sel[3])
data[31:24] <= #Tp p_in[31:24];
if (byte_sel[2])
data[23:16] <= #Tp p_in[23:16];
if (byte_sel[1])
data[15:8] <= #Tp p_in[15:8];
if (byte_sel[0])
data[7:0] <= #Tp p_in[7:0];
end
else if (latch[1] && !tip)
begin
if (byte_sel[3])
data[63:56] <= #Tp p_in[31:24];
if (byte_sel[2])
data[55:48] <= #Tp p_in[23:16];
if (byte_sel[1])
data[47:40] <= #Tp p_in[15:8];
if (byte_sel[0])
data[39:32] <= #Tp p_in[7:0];
end
else if (latch[2] && !tip)
begin
if (byte_sel[3])
data[95:88] <= #Tp p_in[31:24];
if (byte_sel[2])
data[87:80] <= #Tp p_in[23:16];
if (byte_sel[1])
data[79:72] <= #Tp p_in[15:8];
if (byte_sel[0])
data[71:64] <= #Tp p_in[7:0];
end
else if (latch[3] && !tip)
begin
if (byte_sel[3])
data[127:120] <= #Tp p_in[31:24];
if (byte_sel[2])
data[119:112] <= #Tp p_in[23:16];
if (byte_sel[1])
data[111:104] <= #Tp p_in[15:8];
if (byte_sel[0])
data[103:96] <= #Tp p_in[7:0];
end
`else
`ifdef SPI_MAX_CHAR_64
else if (latch[0] && !tip)
begin
if (byte_sel[3])
data[31:24] <= #Tp p_in[31:24];
if (byte_sel[2])
data[23:16] <= #Tp p_in[23:16];
if (byte_sel[1])
data[15:8] <= #Tp p_in[15:8];
if (byte_sel[0])
data[7:0] <= #Tp p_in[7:0];
end
else if (latch[1] && !tip)
begin
if (byte_sel[3])
data[63:56] <= #Tp p_in[31:24];
if (byte_sel[2])
data[55:48] <= #Tp p_in[23:16];
if (byte_sel[1])
data[47:40] <= #Tp p_in[15:8];
if (byte_sel[0])
data[39:32] <= #Tp p_in[7:0];
end
`else
else if (latch[0] && !tip)
begin
`ifdef SPI_MAX_CHAR_8
if (byte_sel[0])
data[`SPI_MAX_CHAR-1:0] <= #Tp p_in[`SPI_MAX_CHAR-1:0];
`endif
`ifdef SPI_MAX_CHAR_16
if (byte_sel[0])
data[7:0] <= #Tp p_in[7:0];
if (byte_sel[1])
data[`SPI_MAX_CHAR-1:8] <= #Tp p_in[`SPI_MAX_CHAR-1:8];
`endif
`ifdef SPI_MAX_CHAR_24
if (byte_sel[0])
data[7:0] <= #Tp p_in[7:0];
if (byte_sel[1])
data[15:8] <= #Tp p_in[15:8];
if (byte_sel[2])
data[`SPI_MAX_CHAR-1:16] <= #Tp p_in[`SPI_MAX_CHAR-1:16];
`endif
`ifdef SPI_MAX_CHAR_32
if (byte_sel[0])
data[7:0] <= #Tp p_in[7:0];
if (byte_sel[1])
data[15:8] <= #Tp p_in[15:8];
if (byte_sel[2])
data[23:16] <= #Tp p_in[23:16];
if (byte_sel[3])
data[`SPI_MAX_CHAR-1:24] <= #Tp p_in[`SPI_MAX_CHAR-1:24];
`endif
end
`endif
`endif
else
data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]] <= #Tp rx_clk ? s_in : data[rx_bit_pos[`SPI_CHAR_LEN_BITS-1:0]];
end
endmodule
//////////////////////////////////////////////////////////////////////
//// ////
//// spi_top.v ////
//// ////
//// This file is part of the SPI IP core project ////
//// http://www.opencores.org/projects/spi/ ////
//// ////
//// Author(s): ////
//// - Simon Srot (simons@opencores.org) ////
//// ////
//// All additional information is avaliable in the Readme.txt ////
//// file. ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2002 Authors ////
//// ////
//// 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 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.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "spi_defines.v"
`include "timescale.v"
module spi_top
(
// Wishbone signals
wb_clk_i, wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_sel_i,
wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_err_o, wb_int_o,
// SPI signals
ss_pad_o, sclk_pad_o, mosi_pad_o, miso_pad_i
);
parameter Tp = 1;
// Wishbone signals
input wb_clk_i; // master clock input
input wb_rst_i; // synchronous active high reset
input [4:0] wb_adr_i; // lower address bits
input [32-1:0] wb_dat_i; // databus input
output [32-1:0] wb_dat_o; // databus output
input [3:0] wb_sel_i; // byte select inputs
input wb_we_i; // write enable input
input wb_stb_i; // stobe/core select signal
input wb_cyc_i; // valid bus cycle input
output wb_ack_o; // bus cycle acknowledge output
output wb_err_o; // termination w/ error
output wb_int_o; // interrupt request signal output
// SPI signals
output [`SPI_SS_NB-1:0] ss_pad_o; // slave select
output sclk_pad_o; // serial clock
output mosi_pad_o; // master out slave in
input miso_pad_i; // master in slave out
reg [32-1:0] wb_dat_o;
reg wb_ack_o;
reg wb_int_o;
// Internal signals
reg [`SPI_DIVIDER_LEN-1:0] divider; // Divider register
reg [`SPI_CTRL_BIT_NB-1:0] ctrl; // Control and status register
reg [`SPI_SS_NB-1:0] ss; // Slave select register
reg [32-1:0] wb_dat; // wb data out
wire [`SPI_MAX_CHAR-1:0] rx; // Rx register
wire rx_negedge; // miso is sampled on negative edge
wire tx_negedge; // mosi is driven on negative edge
wire [`SPI_CHAR_LEN_BITS-1:0] char_len; // char len
wire go; // go
wire lsb; // lsb first on line
wire ie; // interrupt enable
wire ass; // automatic slave select
wire spi_divider_sel; // divider register select
wire spi_ctrl_sel; // ctrl register select
wire [3:0] spi_tx_sel; // tx_l register select
wire spi_ss_sel; // ss register select
wire tip; // transfer in progress
wire pos_edge; // recognize posedge of sclk
wire neg_edge; // recognize negedge of sclk
wire last_bit; // marks last character bit
// Address decoder
assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_DEVIDE);
assign spi_ctrl_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL);
assign spi_tx_sel[0] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_0);
assign spi_tx_sel[1] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_1);
assign spi_tx_sel[2] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_2);
assign spi_tx_sel[3] = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_3);
assign spi_ss_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_SS);
// Read from registers
always @(wb_adr_i or rx or ctrl or divider or ss)
begin
case (wb_adr_i[`SPI_OFS_BITS])
`ifdef SPI_MAX_CHAR_128
`SPI_RX_0: wb_dat = rx[31:0];
`SPI_RX_1: wb_dat = rx[63:32];
`SPI_RX_2: wb_dat = rx[95:64];
`SPI_RX_3: wb_dat = {{128-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:96]};
`else
`ifdef SPI_MAX_CHAR_64
`SPI_RX_0: wb_dat = rx[31:0];
`SPI_RX_1: wb_dat = {{64-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:32]};
`SPI_RX_2: wb_dat = 32'b0;
`SPI_RX_3: wb_dat = 32'b0;
`else
`SPI_RX_0: wb_dat = {{32-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:0]};
`SPI_RX_1: wb_dat = 32'b0;
`SPI_RX_2: wb_dat = 32'b0;
`SPI_RX_3: wb_dat = 32'b0;
`endif
`endif
`SPI_CTRL: wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
`SPI_DEVIDE: wb_dat = {{32-`SPI_DIVIDER_LEN{1'b0}}, divider};
`SPI_SS: wb_dat = {{32-`SPI_SS_NB{1'b0}}, ss};
default: wb_dat = 32'bx;
endcase
end
// Wb data out
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
wb_dat_o <= #Tp 32'b0;
else
wb_dat_o <= #Tp wb_dat;
end
// Wb acknowledge
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
wb_ack_o <= #Tp 1'b0;
else
wb_ack_o <= #Tp wb_cyc_i & wb_stb_i & ~wb_ack_o;
end
// Wb error
assign wb_err_o = 1'b0;
// Interrupt
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
wb_int_o <= #Tp 1'b0;
else if (ie && tip && last_bit && pos_edge)
wb_int_o <= #Tp 1'b1;
else if (wb_ack_o)
wb_int_o <= #Tp 1'b0;
end
// Divider register
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
divider <= #Tp {`SPI_DIVIDER_LEN{1'b0}};
else if (spi_divider_sel && wb_we_i && !tip)
begin
`ifdef SPI_DIVIDER_LEN_8
if (wb_sel_i[0])
divider <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:0];
`endif
`ifdef SPI_DIVIDER_LEN_16
if (wb_sel_i[0])
divider[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
divider[`SPI_DIVIDER_LEN-1:8] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:8];
`endif
`ifdef SPI_DIVIDER_LEN_24
if (wb_sel_i[0])
divider[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
divider[15:8] <= #Tp wb_dat_i[15:8];
if (wb_sel_i[2])
divider[`SPI_DIVIDER_LEN-1:16] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:16];
`endif
`ifdef SPI_DIVIDER_LEN_32
if (wb_sel_i[0])
divider[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
divider[15:8] <= #Tp wb_dat_i[15:8];
if (wb_sel_i[2])
divider[23:16] <= #Tp wb_dat_i[23:16];
if (wb_sel_i[3])
divider[`SPI_DIVIDER_LEN-1:24] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:24];
`endif
end
end
// Ctrl register
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
ctrl <= #Tp {`SPI_CTRL_BIT_NB{1'b0}};
else if(spi_ctrl_sel && wb_we_i && !tip)
begin
if (wb_sel_i[0])
ctrl[7:0] <= #Tp wb_dat_i[7:0] | {7'b0, ctrl[0]};
if (wb_sel_i[1])
ctrl[`SPI_CTRL_BIT_NB-1:8] <= #Tp wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
end
else if(tip && last_bit && pos_edge)
ctrl[`SPI_CTRL_GO] <= #Tp 1'b0;
end
assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
assign go = ctrl[`SPI_CTRL_GO];
assign char_len = ctrl[`SPI_CTRL_CHAR_LEN];
assign lsb = ctrl[`SPI_CTRL_LSB];
assign ie = ctrl[`SPI_CTRL_IE];
assign ass = ctrl[`SPI_CTRL_ASS];
// Slave select register
always @(posedge wb_clk_i or posedge wb_rst_i)
begin
if (wb_rst_i)
ss <= #Tp {`SPI_SS_NB{1'b0}};
else if(spi_ss_sel && wb_we_i && !tip)
begin
`ifdef SPI_SS_NB_8
if (wb_sel_i[0])
ss <= #Tp wb_dat_i[`SPI_SS_NB-1:0];
`endif
`ifdef SPI_SS_NB_16
if (wb_sel_i[0])
ss[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
ss[`SPI_SS_NB-1:8] <= #Tp wb_dat_i[`SPI_SS_NB-1:8];
`endif
`ifdef SPI_SS_NB_24
if (wb_sel_i[0])
ss[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
ss[15:8] <= #Tp wb_dat_i[15:8];
if (wb_sel_i[2])
ss[`SPI_SS_NB-1:16] <= #Tp wb_dat_i[`SPI_SS_NB-1:16];
`endif
`ifdef SPI_SS_NB_32
if (wb_sel_i[0])
ss[7:0] <= #Tp wb_dat_i[7:0];
if (wb_sel_i[1])
ss[15:8] <= #Tp wb_dat_i[15:8];
if (wb_sel_i[2])
ss[23:16] <= #Tp wb_dat_i[23:16];
if (wb_sel_i[3])
ss[`SPI_SS_NB-1:24] <= #Tp wb_dat_i[`SPI_SS_NB-1:24];
`endif
end
end
assign ss_pad_o = ~((ss & {`SPI_SS_NB{tip & ass}}) | (ss & {`SPI_SS_NB{!ass}}));
spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
.divider(divider), .clk_out(sclk_pad_o), .pos_edge(pos_edge),
.neg_edge(neg_edge));
spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
.latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(wb_sel_i), .lsb(lsb),
.go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
.rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
.tip(tip), .last(last_bit),
.p_in(wb_dat_i), .p_out(rx),
.s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment