diff --git a/syn/SpiMasterE.vhd b/syn/SpiMasterE.vhd index 39ddc94..80c29d1 100644 --- a/syn/SpiMasterE.vhd +++ b/syn/SpiMasterE.vhd @@ -1,11 +1,13 @@ library ieee; use ieee.std_logic_1164.all; + use ieee.numeric_std.all; entity SpiMasterE is generic ( G_DATA_WIDTH : positive := 8; --* data bus width + G_DATA_DIR : natural range 0 to 1 := 0; --* start from lsb/msb 0/1 G_SPI_CPOL : natural range 0 to 1 := 0; --* SPI clock polarity G_SPI_CPHA : natural range 0 to 1 := 0; --* SPI clock phase G_SCLK_DIVIDER : positive range 6 to positive'high := 10 --* SCLK divider related to system clock @@ -57,6 +59,9 @@ architecture rtl of SpiMasterE is alias a_miso : std_logic is s_miso_d(s_miso_d'left); + constant C_BIT_COUNTER_START : natural := (G_DATA_WIDTH-1) * G_DATA_DIR; + constant C_BIT_COUNTER_END : natural := (G_DATA_WIDTH-1) * to_integer(not(to_unsigned(G_DATA_DIR, 1))); + begin @@ -96,7 +101,7 @@ begin begin if (Reset_n_i = '0') then s_recv_register <= (others => '0'); - v_bit_counter := G_DATA_WIDTH-1; + v_bit_counter := C_BIT_COUNTER_START; v_sclk_counter := G_SCLK_DIVIDER-1; s_transfer_valid <= false; s_ste <= '1'; @@ -111,7 +116,7 @@ begin s_sclk <= std_logic'val(G_SPI_CPOL+2); s_mosi <= '0'; s_recv_register <= (others => '0'); - v_bit_counter := G_DATA_WIDTH-1; + v_bit_counter := C_BIT_COUNTER_START; v_sclk_counter := G_SCLK_DIVIDER/2-1; s_transfer_valid <= false; if(DataValid_i = '1' and s_data_accept = '1') then @@ -120,7 +125,7 @@ begin end if; when WRITE => - if (G_SPI_CPHA = 0 and v_bit_counter = G_DATA_WIDTH-1) then + if (G_SPI_CPHA = 0 and v_bit_counter = C_BIT_COUNTER_START) then s_mosi <= s_send_register(v_bit_counter); s_spi_state <= READ; else @@ -139,14 +144,18 @@ begin s_sclk <= not(s_sclk); s_recv_register(v_bit_counter) <= a_miso; v_sclk_counter := G_SCLK_DIVIDER/2-1; - if (v_bit_counter = 0) then + if (v_bit_counter = C_BIT_COUNTER_END) then if (G_SPI_CPHA = 0) then s_spi_state <= CYCLE; else s_spi_state <= STORE; end if; else - v_bit_counter := v_bit_counter - 1; + if (G_DATA_DIR = 0) then + v_bit_counter := v_bit_counter + 1; + else + v_bit_counter := v_bit_counter - 1; + end if; s_spi_state <= WRITE; end if; else diff --git a/syn/SpiSlaveE.vhd b/syn/SpiSlaveE.vhd index e7e7249..849ad09 100644 --- a/syn/SpiSlaveE.vhd +++ b/syn/SpiSlaveE.vhd @@ -1,11 +1,13 @@ library ieee; use ieee.std_logic_1164.all; + use ieee.numeric_std.all; entity SpiSlaveE is generic ( G_DATA_WIDTH : positive := 8; --* data bus width + G_DATA_DIR : natural range 0 to 1 := 0; --* start from lsb/msb 0/1 G_SPI_CPOL : natural range 0 to 1 := 0; --* SPI clock polarity G_SPI_CPHA : natural range 0 to 1 := 0 --* SPI clock phase ); @@ -56,6 +58,9 @@ architecture rtl of SpiSlaveE is alias a_ste : std_logic is s_ste_d(s_ste_d'left); alias a_mosi : std_logic is s_mosi_d(s_mosi_d'left); + constant C_BIT_COUNTER_START : natural := (G_DATA_WIDTH-1) * G_DATA_DIR; + constant C_BIT_COUNTER_END : natural := (G_DATA_WIDTH-1) * to_integer(not(to_unsigned(G_DATA_DIR, 1))); + begin @@ -114,7 +119,7 @@ begin if (Reset_n_i = '0') then s_miso <= '0'; s_recv_register <= (others => '0'); - v_bit_counter := G_DATA_WIDTH-1; + v_bit_counter := C_BIT_COUNTER_START; s_transfer_valid <= false; s_spi_state <= IDLE; elsif rising_edge(Clk_i) then @@ -123,7 +128,7 @@ begin when IDLE => s_miso <= '0'; s_recv_register <= (others => '0'); - v_bit_counter := G_DATA_WIDTH-1; + v_bit_counter := C_BIT_COUNTER_START; s_transfer_valid <= false; if (a_ste = '0') then if (G_SPI_CPHA = 0) then @@ -135,10 +140,14 @@ begin when TRANSFER => if s_read_edge then s_recv_register(v_bit_counter) <= a_mosi; - if (v_bit_counter = 0) then + if (v_bit_counter = C_BIT_COUNTER_END) then s_spi_state <= STORE; else - v_bit_counter := v_bit_counter - 1; + if (G_DATA_DIR = 0) then + v_bit_counter := v_bit_counter + 1; + else + v_bit_counter := v_bit_counter - 1; + end if; end if; elsif s_write_edge then s_miso <= s_send_register(v_bit_counter); diff --git a/test/SpiT.vhd b/test/SpiT.vhd index 7dd691b..29b2213 100644 --- a/test/SpiT.vhd +++ b/test/SpiT.vhd @@ -31,6 +31,7 @@ architecture sim of SpiT is component SpiMasterE is generic ( G_DATA_WIDTH : positive := 8; + G_DATA_DIR : natural range 0 to 1 := 0; G_SPI_CPOL : natural range 0 to 1 := 0; G_SPI_CPHA : natural range 0 to 1 := 0; G_SCLK_DIVIDER : positive range 6 to positive'high := 10 @@ -58,6 +59,7 @@ architecture sim of SpiT is component SpiSlaveE is generic ( G_DATA_WIDTH : positive := 8; + G_DATA_DIR : natural range 0 to 1 := 0; G_SPI_CPOL : natural range 0 to 1 := 0; G_SPI_CPHA : natural range 0 to 1 := 0 ); @@ -130,6 +132,15 @@ begin begin + --* Stimuli generator and BFM for the valid-accept interface + --* on the local data input of the DUT + --* + --* Generates random stimuli and serves it to the + --* valid-accept interface at the input of the DUT + --* + --* The stimuli data is also pushed into the mosi queue + --* which serves as simple abstract reference model + --* of the SPI transmit (master -> slave) channel SpiMasterStimP : process is variable v_random : RandomPType; begin @@ -149,9 +160,11 @@ begin end process SpiMasterStimP; + --* DUT: SpiMasterE component i_SpiMasterE : SpiMasterE generic map ( G_DATA_WIDTH => C_DATA_WIDTH, + G_DATA_DIR => 1, G_SPI_CPOL => mode / 2, G_SPI_CPHA => mode mod 2, G_SCLK_DIVIDER => 10 @@ -175,6 +188,13 @@ begin ); + --* Checker and BFM for the valid-accept interface + --* on the local data output of the DUT + --* + --* Reads the output of the DUT and compares it to + --* data popped from the miso queue which serves as + --* simple abstract reference model of the SPI receive + --* (slave -> master) channel SpiMasterCheckP : process is variable v_queue_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); begin @@ -194,8 +214,20 @@ begin end process SpiMasterCheckP; - -- Unit test of spi slave procedure, checks all combinations - -- of cpol & cpha against spi master procedure + --* Stimuli generator and BFM for the SPI slave + --* interface on the SPI miso input of the DUT + --* + --* Generates random stimuli and serves it to the + --* SPI interface at the input of the DUT + --* + --* The stimuli data is also pushed into the miso queue + --* which serves as simple abstract reference model + --* of the SPI receive (slave -> master) channel + --* + --* Furthermore the data received by the SPI slave BFM + --* is checked against data popped from the mosi queue + --* which serves as simple abstract reference model of + --* the SPI receive (master -> slave) channel SpiSlaveP : process is variable v_send_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); variable v_receive_data : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); @@ -307,6 +339,7 @@ begin i_SpiSlaveE : SpiSlaveE generic map ( G_DATA_WIDTH => C_DATA_WIDTH, + G_DATA_DIR => 1, G_SPI_CPOL => mode / 2, G_SPI_CPHA => mode mod 2 )