URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [o8_spi_16b_tx.vhd] - Rev 295
Go to most recent revision | Compare with Previous | Blame | View Log
-- Copyright (c) 2020 Jeremy Seth Henry -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- * Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution, -- where applicable (as part of a user interface, debugging port, etc.) -- -- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY 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. -- -- VHDL units : o8_spi_16b_tx -- Description: Transmits (only) a 16-bit word using a synchronous interface -- Clock_Polarity sets the clock state at idle -- Clock_Phase sets the clock edge data is shifted on -- Half_Period_Clks sets the number of CPU clocks used to generate -- a half-period tick that runs the transmit state machine. -- (Note that 2x this value is the full SPI period in CPU clocks) -- -- Register Map: -- Offset Bitfield Description Read/Write -- 0x0 AAAAAAAA Pending Word (7:0) (R/W) -- 0x1 AAAAAAAA Pending Word (11:8) (R/W) -- 0x2 A------- Busy Flag / TX on Write (R/W) -- -- Revision History -- Author Date Change ------------------ -------- --------------------------------------------------- -- Seth Henry 09/16/20 Initial version library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; library work; use work.open8_pkg.all; entity o8_spi_16b_tx is generic( Clock_Polarity : std_logic; Clock_Phase : std_logic; Half_Period_Clks : integer range 1 to integer'high; Address : ADDRESS_TYPE ); port( Open8_Bus : in OPEN8_BUS_TYPE; Write_Qual : in std_logic; Rd_Data : out DATA_TYPE; -- SPI DOUT : out std_logic; SCLK : out std_logic; SYNC : out std_logic ); end entity; architecture behave of o8_spi_16b_tx is alias Clock is Open8_Bus.Clock; alias Reset is Open8_Bus.Reset; alias uSec_Tick is Open8_Bus.uSec_Tick; constant Clk_Div_i : integer := Half_Period_Clks - 1; constant Clk_Div_Bits : integer := ceil_log2(Clk_Div_i); constant CLK_DIV_VAL : std_logic_vector(Clk_Div_Bits - 1 downto 0) := conv_std_logic_vector(Clk_Div_i,Clk_Div_Bits); signal HT_Cntr : std_logic_vector(Clk_Div_Bits - 1 downto 0); signal HT_Tick : std_logic := '0'; constant User_Addr : std_logic_vector(15 downto 2) := Address(15 downto 2); alias Comp_Addr is Open8_Bus.Address(15 downto 2); signal Addr_Match : std_logic; alias Reg_Sel_d is Open8_Bus.Address(1 downto 0); signal Reg_Sel_q : std_logic_vector(1 downto 0); signal Wr_En_d : std_logic := '0'; signal Wr_En_q : std_logic := '0'; alias Wr_Data_d is Open8_Bus.Wr_Data; signal Wr_Data_q : DATA_TYPE := x"00"; signal Rd_En_d : std_logic := '0'; signal Rd_En_q : std_logic := '0'; signal spi_xmit : std_logic := '0'; type SPI_STATES is ( IDLE, ALIGN, SYNC_START, CLK_SETUP, CLK_HOLD, CLK_END, SYNC_END ); signal spi_state : SPI_STATES; signal spi_buffer : std_logic_vector(15 downto 0) := x"0000"; alias spi_buffer_lb is spi_buffer(7 downto 0); alias spi_buffer_ub is spi_buffer(15 downto 8); signal bit_cntr : std_logic_vector(3 downto 0) := x"0"; signal spi_busy : std_logic := '0'; begin Addr_Match <= '1' when Comp_Addr = User_Addr else '0'; Wr_En_d <= Addr_Match and Open8_Bus.Wr_En; Rd_En_d <= Addr_Match and Open8_Bus.Rd_En; io_reg: process( Clock, Reset ) begin if( Reset = Reset_Level )then Reg_Sel_q <= "00"; Wr_En_q <= '0'; Wr_Data_q <= x"00"; Rd_En_q <= '0'; Rd_Data <= OPEN8_NULLBUS; spi_buffer <= (others => '0'); spi_xmit <= '0'; elsif( rising_edge( Clock ) )then Reg_Sel_q <= Reg_Sel_d; Wr_En_q <= Wr_En_d; Wr_Data_q <= Wr_Data_d; spi_xmit <= '0'; if( Wr_En_q = '1' and Write_Qual = '1' )then case( Reg_Sel_q )is when "00" => spi_buffer_lb <= Wr_Data_q; when "01" => spi_buffer_ub <= Wr_Data_q; when "10" | "11" => spi_xmit <= '1'; when others => null; end case; end if; Rd_En_q <= Rd_En_d; Rd_Data <= OPEN8_NULLBUS; if( Rd_En_q = '1' )then case( Reg_Sel_q )is when "00" => Rd_Data <= spi_buffer_lb; when "01" => Rd_Data <= spi_buffer_ub; when "10" | "11" => Rd_Data <= spi_busy & "0000000"; when others => null; end case; end if; end if; end process; ADC_IO_FSM: process( Clock, Reset ) begin if( Reset = Reset_Level )then spi_state <= IDLE; bit_cntr <= (others => '0'); spi_busy <= '0'; HT_Cntr <= (others => '0'); HT_Tick <= '0'; DOUT <= '0'; SCLK <= '0'; SYNC <= '1'; elsif( rising_edge(Clock) )then HT_Cntr <= HT_Cntr - 1; HT_Tick <= '0'; if( HT_Cntr = 0 )then HT_Cntr <= CLK_DIV_VAL; HT_Tick <= '1'; end if; case( spi_state )is when IDLE => DOUT <= '0'; SCLK <= Clock_Polarity; SYNC <= '1'; bit_cntr <= x"F"; spi_busy <= '0'; if( spi_xmit = '1' )then spi_busy <= '1'; spi_state <= ALIGN; end if; when ALIGN => if( HT_Tick = '1' )then spi_state <= CLK_SETUP; if( Clock_Phase = '1' )then spi_state <= SYNC_START; end if; end if; when SYNC_START => SYNC <= '0'; if( HT_Tick = '1' )then spi_state <= CLK_SETUP; end if; when CLK_SETUP => SCLK <= Clock_Polarity xor Clock_Phase; DOUT <= spi_buffer(conv_integer(bit_cntr)); SYNC <= '0'; if( HT_Tick = '1' )then spi_state <= CLK_HOLD; end if; when CLK_HOLD => SCLK <= (not Clock_Polarity) xor Clock_Phase; DOUT <= spi_buffer(conv_integer(bit_cntr)); if( HT_Tick = '1' )then bit_cntr <= bit_cntr - 1; spi_state <= CLK_SETUP; if( bit_cntr = 0 )then spi_state <= CLK_END; end if; end if; when CLK_END => SCLK <= Clock_Polarity; if( Clock_Phase = '1' )then SYNC <= '1'; end if; if( HT_Tick = '1' )then spi_state <= SYNC_END; if( Clock_Phase = '1' )then spi_state <= IDLE; end if; end if; when SYNC_END => SYNC <= '1'; if( HT_Tick = '1' )then spi_state <= IDLE; end if; when others => null; end case; end if; end process; end architecture;
Go to most recent revision | Compare with Previous | Blame | View Log