VHDL模拟失败,结果意外

VHDL模拟失败,结果意外,vhdl,fpga,hdl,spartan,xilinx-ise,Vhdl,Fpga,Hdl,Spartan,Xilinx Ise,5年前我学习了VHDL,此后我就再也没有使用过,因为我在不同的领域工作。现在我在一个项目中工作,这个项目需要一些VHDL语言的工作。我必须实现SPI来编程ADF4158设备。我打开一本语法书,试着编写程序。我需要开发下面的模块,我按照我的理解编写代码,还有一个测试台,但它在模拟中无法像我需要的那样工作。下面是我想开发的模块和总体框图 过程和vhdl模块框图(可点击): 以下是SPI时序图,如下所示(可单击): 下面是我为实现上述SPI通信而编写的VHDL代码: library IEEE; u

5年前我学习了VHDL,此后我就再也没有使用过,因为我在不同的领域工作。现在我在一个项目中工作,这个项目需要一些VHDL语言的工作。我必须实现SPI来编程ADF4158设备。我打开一本语法书,试着编写程序。我需要开发下面的模块,我按照我的理解编写代码,还有一个测试台,但它在模拟中无法像我需要的那样工作。下面是我想开发的模块和总体框图

过程和vhdl模块框图(可点击):

以下是SPI时序图,如下所示(可单击):

下面是我为实现上述SPI通信而编写的VHDL代码:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.all;

entity sender is
  Generic( DATA_WIDTH  : INTEGER := 32); --32 bit registers to pogram (total 8 registers to program)
  Port ( sys_clk : in  STD_LOGIC;   --clock from microblaze (32 MHz)
         enable : in  STD_LOGIC;  --from microblaze to trigger start
         reset : in  STD_LOGIC;   --reset spi clk generation
         start_data_read : out STD_LOGIC;   --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to buffer
         start_data_write : out STD_LOGIC;  --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to mosi port
         data_in : in  STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --program data (32bit data in 8 phases depending on register_select)
         process_done : out  STD_LOGIC; --flag bit to microblaze when complete process is complete
         register_select : in  STD_LOGIC_VECTOR(2 downto 0); --select code to identify which register to grogram, theorder can be manupulated from microblaze
         sclk : buffer  STD_LOGIC; --spi clock for ADC (3.2 MHz)
         ss : out  STD_LOGIC := '1'; --select line for ADF (slave)
         mosi : out  STD_LOGIC); --program data for ADF
end sender;

architecture Behavioral of sender is

   type machine is(store, sending); --states of state-machine
   signal state : machine := store;
   signal clk_divide: STD_LOGIC_VECTOR(5 downto 0); --clock cycle ratio between system clock from microblaze and spi clock for ADF
   signal tx_buffer_0   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 0)
   signal tx_buffer_1   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 1)
   signal tx_buffer_2   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 2)
   signal tx_buffer_3   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 3)
   signal tx_buffer_4   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 4)
   signal tx_buffer_5   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 5)
   signal tx_buffer_6   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 6)
   signal tx_buffer_7   : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 7)
begin

   ClK_GEN: process(sys_clk)
   begin --spi sclk 20:1 cycles of sys_clk(system runs at 32 MHz and SPI CLK required is 1.6 MHz)
   if rising_edge(sys_clk) then
      if reset = '1' then
         clk_divide <= (others => '0');
         mosi <= 'Z'; --send high impedence
      else
         if clk_divide < "001010" then --10
            sclk <= '0';
            clk_divide <= clk_divide + 1;
         else
            if clk_divide < "010100" then --20
               sclk <= '1';
            else
               clk_divide <= (others => '0');
            end if;
        end if;
      end if;
   end if;
end process ClK_GEN;

SEND: process(sclk,enable,register_select)
begin
   if rising_edge(sclk) then
      if enable = '1' then
         case state is
            when store =>
               start_data_read <= '1'; --ask microblaze to send register_selectcodes and data
               case register_select is
                  when "000" =>
                      tx_buffer_7 <= data_in; --copy data to buffer
                  when "001" =>
                      tx_buffer_6 <= data_in;
                  when "010" =>
                      tx_buffer_5 <= data_in;
                  when "011" =>
                      tx_buffer_4 <= data_in;
                  when "100" =>
                      tx_buffer_3 <= data_in;
                  when "101" =>
                      tx_buffer_2 <= data_in;
                  when "110" =>
                      tx_buffer_1 <= data_in;
                  when "111" =>
                      tx_buffer_0 <= data_in;
                  when others =>
                      tx_buffer_1 <= (OTHERS => '0');
               end case;
               state <= sending; --change state to next
            when sending =>
               start_data_write <= '1'; --ask microblaze to send register_select codes to pgrogram a register
               case register_select is
                  when "000" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_7 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "001" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_6 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "010" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     ss <= '1';
                  when "011" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_4 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "100" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_3 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "101" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_2 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "110" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_1 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when "111" =>
                     ss <= '0';
                     mosi <= tx_buffer_7(DATA_WIDTH-1);
                     tx_buffer_0 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
                     ss <= '1';
                  when others =>
                    mosi <= '0';
               end case;
            end case;
         end if;
      end if;
   end process SEND;

end Behavioral;
IEEE库;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.STD_LOGIC_ARITH.ALL;
使用IEEE.STD_LOGIC_UNSIGNED.ALL;
使用IEEE.NUMERIC_STD.all;
实体发送方是
通用(数据宽度:整数=32)--32位寄存器到pogram(总共8个寄存器到程序)
端口(系统时钟:在标准逻辑中——来自微LAZE的时钟(32 MHz)
启用:在STD_逻辑中;--从微脉冲到触发启动
复位:在标准逻辑中;--复位spi时钟生成
start_data_read:out STD_LOGIC;--以microblaze为标志,以便microblaze开始发送寄存器选择代码(目标寄存器的PGGRAM数据)和数据到pogram-到缓冲区
start_data_write:out STD_LOGIC;--以microblaze为标志,以便microblaze开始发送寄存器选择代码(目标寄存器的pgogram数据)和pogram的数据-至mosi端口
数据输入:标准逻辑向量(数据宽度-1到0);--程序数据(8相32位数据,取决于寄存器选择)
过程完成:out STD_LOGIC;--完成过程时微博客的标志位
寄存器选择:在标准逻辑向量(2到0)中——选择代码以标识要生成的寄存器,可以从microblaze中生成该寄存器
sclk:缓冲器标准逻辑——用于ADC的spi时钟(3.2MHz)
ss:out标准逻辑:='1';--为ADF(从)选择线路
mosi:输出标准(U逻辑)--ADF的程序数据
端发送器;
发送方的行为体系结构是
机器类型为(存储、发送)--状态机状态
信号状态:机器:=存储;
信号时钟除法:标准逻辑向量(5到0)--来自microblaze的系统时钟与ADF的spi时钟之间的时钟周期比
信号发送缓冲区0:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器0)
信号发送缓冲区1:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器1)
信号发送缓冲区2:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器2)
信号发送缓冲区3:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器3)
信号发送缓冲区4:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器4)
信号发送缓冲区5:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器5)
信号发送缓冲区6:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器6)
信号发送缓冲区7:标准逻辑向量(数据宽度-1向下至0)--将程序数据保存到mosi的IO缓冲区(寄存器7)
开始
时钟发电机:过程(系统时钟)
开始--spi sclk 20:1系统时钟周期(系统以32 MHz运行,所需spi时钟为1.6 MHz)
如果上升沿(系统时钟),则
如果重置='1',则
clk_除以“0”);

mosi你的意思是在这个模拟中进行数据读取和数据写入吗?在RTL中,我们可以进行如下检查,因为我们查看了很多次(可能是在时钟边缘):

但是,您的测试台过程不会循环。因此,与我们在RTL代码中所做的“如果”操作不同,您需要做一些事情使您的测试停止,直到该条件存在为止。因此,您的测试将如下所示:

stim_proc: process
begin       
-- hold reset state for 100 ns.
    wait for 1ns;
    enable <= '1';
    if start_data_read /= '1' then
        wait until start_data_read = '1' ;
    end if ;
    -- Do a read sequence
    . . . 
    if start_data_write /= '1' then
        wait until start_data_write = '1' ;
    end if ;
    -- Do a write sequence
wait until rising_edge(Clk) ; 
wait until Clk = '1' ; -- assumes Clk is only '0' or '1' (safe for clocks)

一旦你的基础工作了,你可能会考虑把一个写或读操作封装到一个子程序中。

你可以缩进你的代码吗?谢谢PaBeles的建议。代码在4个空格编辑后不可读,对此表示抱歉。它现在被编辑了!您的代码有几个问题,包括死状态“发送”。下面是一个有问题的报告:将TX_Buffer设置为一个数组,您将清除许多case语句。您还将在两个单独的进程中驱动MOSI:将其重置操作移动到必须驱动它的进程中。这些虽然不能解决问题,但可以帮助清理代码。我试图让测试变得更好,但结果仍然不可理解。所以我想一步一步地解决这个问题:在一个单独的过程中生成SCLK类时钟计数器可以吗?或者我应该使用IP核心时钟向导来提供SPI时钟。谢谢Jim,非常感谢您的建议。我将按照你的建议重写测试台。时间真的很快,我会计算出数学上的意义。您认为,实际的VHDL代码是正确的吗?我使用左移位发送数据的方式?我没有检查您的RTL代码。也存在一些问题。请记住,VHDL仅用于捕获。你还得做详细的设计。我希望,一旦MicroBlaze写入寄存器文件,硬件就可以自动将值发送到SPI。您可能想做一个详细的框图,然后编写代码。仅使用数字标准,不使用标准逻辑。
stim_proc: process
begin       
-- hold reset state for 100 ns.
    wait for 1ns;
    enable <= '1';
    if start_data_read /= '1' then
        wait until start_data_read = '1' ;
    end if ;
    -- Do a read sequence
    . . . 
    if start_data_write /= '1' then
        wait until start_data_write = '1' ;
    end if ;
    -- Do a write sequence
wait until rising_edge(Clk) ; 
wait until Clk = '1' ; -- assumes Clk is only '0' or '1' (safe for clocks)