⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_master_tb.vhd

📁 SPI的VHDL程序
💻 VHD
📖 第 1 页 / 共 3 页
字号:
                go <= '0';
                wait until uc_done = '1';
                            
                -- continue reading status register until bus busy negates
                while data_in(BUS_BUSY_BIT) = '1' loop
                    write <= '0';
                    uc_addr <= BASE_ADDR & SPISR_ADDR;
                    go <= '1';
                    wait until clk'event and clk='1';
                    wait until clk'event and clk='1';
                    go <= '0';
                    wait until uc_done = '1';
                end loop;
                
            end loop;   -- end loop for CPHA, CPOL
        end loop;       -- end loop for CLKDIV

wait;

end process;

-- *********************************** uC Process *********************************
--  Synthesize uProc bus protocol
UCBUS: process
begin

    -- Set up defaults
    uc_done <= '1';
    ad_oe <= '0';
    ale_n <= '1';
    psen_n <= '1';
    addr <= (others => '0');
    ad_out <= (others => '0');
    data_in_ce <= '0';
    wr_n <= '1';
    rd_n <= '1';
    
    -- Wait for go to assert
    wait until go'event and go = '1';
    
    -- start bus cycle
    uc_done <= '0';
    
    -- wait part of ALE_N negation cycle (ALE_N pulse width - address setup time)
    wait for TLHLL - TAVLL;
    
    -- setup address on busses
    addr <= uc_addr(15 downto 8);
    ad_out <= uc_addr(7 downto 0);
    ad_oe <= '1';
    
    -- wait address setup time then assert ALE_N
    wait for TAVLL;
    ale_n <= '0';
    
    
    
    -- determine if this is a program store cycle, write cycle, or read cycle
    if assert_psen = '1' then
        -- program store cycle
    
        -- wait before asserting PSEN_N
        wait for TLLPL;
        psen_n <= '0';
        
        -- wait address hold time then tri-state
        wait for TPLAZ;
        ad_oe <= '0';       -- tri-state ad bus
        
        -- wait for instruction access time then capture data
        -- by asserting clock enable for input data register
        wait for TPLIV;
        data_in_ce <= '1';
        
        -- wait remainder of PSEN_N pulse width then negate PSEN_N and ALE_N
        -- and negate clock enable for input data register
        wait for TPLPH - TPLIV;
        psen_n <= '1';
        ale_n <= '1';
        data_in_ce <= '0';
    
    elsif write = '1' then
        -- write cycle
        -- wait address hold time
        wait for TLLAX;
        
        -- write cycle, put data on ad
        ad_oe <= '1';
        ad_out <= uc_data;
        
        -- wait data setup time then assert WR_N
        wait for TQVWX;
        wr_n <= '0';
        
        -- wait write pulse width then negate WR_N
        wait for TWLWH;
        wr_n <= '1';
        
        -- wait data hold time after WR_N then remove data
        wait for TWHQX;
        ad_oe <= '0';
        
        -- wait remaining ALE_N hold time after WR_N then negate ALE_N
        wait for TWHLH - TWHQX;
        ale_n <= '1';
    
    else
        -- read cycle
        -- wait address hold time
        wait for TLLAX;
        ad_oe <= '0';
        
        -- read cycle, wait address Z time before asserting RD_N
        wait for TRLAZ;
        rd_n <= '0';
        
        -- wait for data to be valid, then capture it
        -- by asserting clock enable for input data register
        wait for TRLDV;
        data_in_ce <= '1';
        
        -- wait remainding time in read pulse then negate RD_N
        -- by negating clock enable for input data register 
        wait for TRLRH - TRLDV;
        rd_n <= '1';
        data_in_ce <= '0';
        
        -- wait ALE_N hold time then negate ALE_N;
        wait for TWHLH;
        ale_n <= '1';
    end if;
    
    -- signify end of bus cycle by asserting UC_DONE
    uc_done <= '1';
    
    -- process will now return to beginning to wait for GO
end process;

-- *********************************** Input Register Process *********************************
-- This process captures data from the ADDR_DATA bus during read and program store bus cycles
-- Data is clocked into the register when the clock enable is asserted from the uC bus cycle
-- process
INPUT_REGS: process(reset, clk)
begin
    if reset = RESET_ACTIVE then
        data_in <= (others => '0');
    elsif clk'event and clk = '1' then
        if data_in_ce = '1' then
            data_in <= addr_data;
        else
            data_in <= data_in;
        end if;
    end if;
end process;

-- *********************************** SS_IN_N Process *********************************
-- This process will asynchronously assert SS_IN_N as determined by the constant SS_IN_ASSERT_TIME.
-- If this time is set to 0, then SS_IN_N will never be asserted. This allows the testbench to be
-- run without interference of this signal
SS_IN_PROC: process

begin
    ss_in_n <= '1';
    if SS_IN_ASSERT_TIME = 0 uS then
        wait;
    else
        wait for SS_IN_ASSERT_TIME;
        ss_in_n <= '0';
        wait for SS_IN_ASSERT_TIME;
        ss_in_n <= '1';
        wait;
    end if;
end process;    

-- *********************************** SPI Slave Processes *********************************
-- This process will "mock-up" an SPI slave. A shift register will be pre-loaded with a constant.
-- MOSI will be shifted in and MISO will be shifted out. An additional register will be loaded
-- with the SPI shifted in data just for verification purposes. 
-- For now, this process will use the edge of SCK specified by SLAVE_CPHA and SLAVE_CPOL
--
--  SLAVE_CPHA  SLAVE_CPOL  slave_clkedge (to input data, opposite edge used to output)
--  ----------  ----------  -------------
--  0       0       1
--  0       1       0
--  1       0       0
--  1       1       1
-- 
slave_clkedge <= '1' when SLAVE_CPHA = SLAVE_CPOL
          else '0';
          
-- Define a 3-bit counter to count SCK edges and data into register so that parallel
-- register is loaded. Use same clock edge that is used to input data
SLAVE_IN_CNTR: process(sck, reset)
begin  
          -- Clear output register
          if (reset = RESET_ACTIVE) then
           slave_cnt_int <= (others => '0');
           
      -- On SLAVE_CLKEDGE edge of clock count
      elsif sck'event and sck = slave_clkedge then
        if ss_n /= ALL_ONES then
                slave_cnt_int <= slave_cnt_int + 1;
        end if;
      end if;

end process;

slave_cnt <= STD_LOGIC_VECTOR(slave_cnt_int);

-- Count bits going out to help control mux for MISO data
-- This count is on the same edge as data being output
SLAVE_OUT_CNTR: process(sck, reset)
begin  
          -- Clear output register
          if (reset = RESET_ACTIVE) or ss_n = ALL_ONES then
           slave_outcnt_int <= (others => '0');
           
      -- On SLAVE_CLKEDGE edge of clock count
      elsif sck'event and sck = not(slave_clkedge) then
                slave_outcnt_int <= slave_outcnt_int + 1;
      end if;

end process;

slave_outcnt <= STD_LOGIC_VECTOR(slave_outcnt_int);


-- Define an 8-bit shift register for shifting in MOSI and shifting out MISO
-- Preset register to CE
SLAVE_SHFTREG: process(sck, reset)
begin
          if (reset = RESET_ACTIVE) then
           slave_data <= CE;
           
      -- On SLAVE_CLKEDGE edge of spi clock, shift in data
      elsif sck'event and sck = slave_clkedge then
            -- Shift the data if SS_N is asserted
            if ss_n /= ALL_ONES then
                slave_data <= slave_data(6 downto 0) & mosi;
            end if;

      end if;

end process;
-- MISO will be shifted out using opposite edge of clock
-- If CPHA=1 then first sck edge clocks out first data
MISO_REG_PROC: process(sck, reset)
begin
    if reset = RESET_ACTIVE then
        miso_reg <= '0';
    elsif sck'event and sck = not(slave_clkedge) then
        miso_reg <= slave_data(7);
    end if;
end process;

-- If CPHA=0, falling edge of SS_N clocks out first data
-- NOTE: A gated clock is described here ONLY for test purposes
            
ssn_ck <= '1' when ss_n /= ALL_ONES
            else '0';
            
MISO_REG_SSN_PROC: process(ssn_ck, reset)
begin
    if reset = RESET_ACTIVE then
        miso_reg_ssn <= '0';
    elsif ssn_ck'event and ssn_ck = '1' then
                miso_reg_ssn <= slave_data(7);
    end if;
end process;

miso <= miso_reg_ssn when SLAVE_CPHA = '0' and slave_outcnt = "000"
      else miso_reg;

-- Define an 8-bit parallel load register that holds data received from the SPI bus
SLAVE_RCVREG: process(clk, reset)
begin
    if (reset = RESET_ACTIVE) then
        slave_rcvdata <= (others => '0');
    elsif clk'event and clk = '1' then
        if slave_cnt = "000" then
            slave_rcvdata <= slave_data;
        else
            slave_rcvdata <= slave_rcvdata;
        end if;
    end if;
end process;

    

END;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -