VHDL 代码在 ModelSim 中有效,但在 FPGA 中无效
VHDL code works in ModelSim but not on FPGA
我的 VHDL 代码功能正确,在 ModelSim 中一切正常。我用许多变体对其进行了测试,代码在功能上是正确的。
但是当我把它放在 Altera 板上时,它在 7 段显示器上显示“3”,但它应该显示“0”。
如果我将 RESET 设置为“1”,它会完全中断并仅在顶部显示一行。
我的输入 X、CLK、RESET 连接到开关。
LOAD 连接到一个按钮,DIGIT 连接到 7 段显示器。
当我切换 CLK 开关时,它应该有一个时钟信号。
这是我的完整代码:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(6 DOWNTO 0) := "1111110";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSIF (CLK'event and CLK='1') THEN
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s0 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s1;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "1111110";
WHEN "001" => DIGIT <= "0110000";
WHEN "010" => DIGIT <= "1101101";
WHEN "011" => DIGIT <= "1111001";
WHEN "100" => DIGIT <= "0110011";
WHEN "101" => DIGIT <= "1011011";
WHEN OTHERS => NULL;
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
我是 VHDL 的新手,我很确定它必须对时序做一些事情,因为功能部分应该没问题,正如已经说过的。
希望得到一些提示、技巧甚至解决方案。
编辑:没有加载的新代码,这是一个有效的想法吗? (尽管如此,整个代码无法在 FPGA 上运行……)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(0 TO 6) := "0000001";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (CLK'event and CLK='1') THEN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSE
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s1 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "0000001";
WHEN "001" => DIGIT <= "1001111";
WHEN "010" => DIGIT <= "0010010";
WHEN "011" => DIGIT <= "0000110";
WHEN "100" => DIGIT <= "1001100";
WHEN "101" => DIGIT <= "0100100";
WHEN OTHERS => DIGIT <= "0000001";
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
编辑:现在这是我的版本。
无论我做什么,它仍然会显示“0”。
- 我认为它与 COUNT 和计数器有关。
- 我也应该将其实现为同步吗?
- numeric 和 unsigned 真的有那么大的问题吗?我们在大学里就是这样做的。
- 当我把 LOAD 放到滑动开关上时它会工作吗???
此致
阿德里安
您的代码有几个问题。顺便提一句。 运行模拟并不代表你的设计是正确的,因为你可以模拟硬件无法实现的动作。
这里是问题列表:
- 您不能将开关按钮用作时钟信号。按钮不是时钟源!要么实现信号清理电路(至少是去抖动电路,需要另一个时钟),要么使用
clk
信号作为启用。
- 此外,如果连接到外部开关按钮或切换按钮,您的每个信号都需要去抖动电路,除非您的测试板有去抖动按钮...
- 您的状态机有一个初始状态(没关系),但您必须将状态分配给
state
而不是 next_state
。
- 您的代码使用了已过时的
std_logic_unsigned
。您应该为 counter
信号使用 numeric_std
和类型 unsigned
。
- 您的代码为
COUT
引入了一个额外的寄存器,这是有意的吗?
- 您的 PISO 进程使用异步
LOAD
信号,这在硬件中不受支持(假设 FPGA 作为目标设备)。
- 根据您的综合工具,它可能无法识别 FSM,因为您的 case 语句不符合 FSM 的模式。
- 看到固定的输出模式可能是由 FSM 故障引起的。如果您的合成器识别 FSM,您可以转到状态图并识别错误边缘或错误终端状态。
更多...
- 您的 7 段解码器是一个组合过程。无法重置。
- 此外,这个过程对
CLK
不敏感,只对counter
敏感。这会导致仿真和硬件之间的不匹配。 (综合忽略敏感列表)
如果你修复了这个问题,你的模拟应该有另一种行为,如果修复了,就可以像你的硬件一样工作:)。
FSM
STATE_CAL : process(state, so)
begin
-- Standardzuweisungen
next_state <= state; -- Bleib im Zustand falls in CASE nichts abweichendes bestimmt wird
Y <= '0';
-- Zustandswechsel
CASE state IS
WHEN s0 =>
IF (so = '1' THEN
next_state <= s1;
END IF;
WHEN s1 =>
IF (so = '1') THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF (so = '0') THEN
next_state <= s3;
END IF;
WHEN s3 =>
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s4;
END IF;
WHEN s4 =>
Y <= '1'; -- Moore-Ausgabe
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s2;
END IF;
END CASE;
END PROCESS;
Paebbels 已经描述了您的代码的许多问题。另请检查您的综合工具的警告。它们通常指示合成器实际输出的逻辑与您在 VHDL 中描述的逻辑不同。
我怀疑你又犯了两个与VHDL没有直接关系的错误:
- 您的 7 段显示控制线似乎处于低活动状态,因为当您按下
RESET
时,您只能看到一个活动段。这与您在本例中分配的向量 "1111110"
中唯一的零匹配(通过将 counter
重置为 "000"
)。
- 但即使在这种情况下,开明的部分也应该在中间而不是在顶部。因此,您的引脚分配似乎是相反的顺序。
我的 VHDL 代码功能正确,在 ModelSim 中一切正常。我用许多变体对其进行了测试,代码在功能上是正确的。
但是当我把它放在 Altera 板上时,它在 7 段显示器上显示“3”,但它应该显示“0”。 如果我将 RESET 设置为“1”,它会完全中断并仅在顶部显示一行。 我的输入 X、CLK、RESET 连接到开关。 LOAD 连接到一个按钮,DIGIT 连接到 7 段显示器。
当我切换 CLK 开关时,它应该有一个时钟信号。
这是我的完整代码:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(6 DOWNTO 0) := "1111110";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSIF (CLK'event and CLK='1') THEN
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s0 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s1;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "1111110";
WHEN "001" => DIGIT <= "0110000";
WHEN "010" => DIGIT <= "1101101";
WHEN "011" => DIGIT <= "1111001";
WHEN "100" => DIGIT <= "0110011";
WHEN "101" => DIGIT <= "1011011";
WHEN OTHERS => NULL;
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
我是 VHDL 的新手,我很确定它必须对时序做一些事情,因为功能部分应该没问题,正如已经说过的。
希望得到一些提示、技巧甚至解决方案。
编辑:没有加载的新代码,这是一个有效的想法吗? (尽管如此,整个代码无法在 FPGA 上运行……)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY seqdec IS
PORT ( X: IN std_logic_vector(15 DOWNTO 0);
CLK: IN std_logic;
RESET: IN std_logic;
LOAD: IN std_logic;
DIGIT: OUT std_logic_vector(0 TO 6) := "0000001";
Y: OUT std_logic);
END seqdec;
ARCHITECTURE SEQ OF seqdec IS
TYPE statetype IS (s0, s1, s2, s3, s4);
SIGNAL state: statetype:=s0;
SIGNAL next_state: statetype;
SIGNAL counter: std_logic_vector(2 DOWNTO 0) :="000" ;
SIGNAL temp: std_logic_vector(15 DOWNTO 0):= (OTHERS => '0');
SIGNAL so: std_logic := 'U';
-------------------Aktualisierung des Zustandes--------------------------------
BEGIN
STATE_AKT: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
state <= s0;
ELSIF CLK = '1' AND CLK'event THEN
state <= next_state ;
END IF;
END PROCESS STATE_AKT;
---------------------Counter---------------------------------------------------
COUNT: PROCESS (state, RESET)
BEGIN
IF (RESET = '1') THEN
counter <= (OTHERS => '0');
ELSIF (state = s4) THEN
counter <= counter + '1';
END IF;
END PROCESS COUNT;
-------------------PiSo für die Eingabe des zu Prüfenden Vektors---------------
PISO: PROCESS (CLK, LOAD, X)
BEGIN
IF (CLK'event and CLK='1') THEN
IF (LOAD = '1') THEN
temp(15 DOWNTO 0) <= X(15 DOWNTO 0);
ELSE
so <= temp(15);
temp(15 DOWNTO 1) <= temp(14 DOWNTO 0);
temp(0) <= '0';
END IF;
END IF;
END PROCESS PISO;
-------------------Zustandsabfrage und Berechnung------------------------------
STATE_CAL: PROCESS (so,state)
BEGIN
next_state <= state;
Y <= '0';
CASE state IS
WHEN s0 =>
IF so = '1' THEN
next_state <= s1 ;
END IF;
WHEN s1 =>
IF so = '1' THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF so = '0' THEN
next_state <= s3 ;
END IF;
WHEN s3 =>
IF so = '0' THEN
next_state <= s0 ;
ELSE
next_state <= s4 ;
END IF;
WHEN s4 =>
Y <= '1';
IF so = '0' THEN
next_state <= s0;
ELSE
next_state <= s2 ;
END IF;
WHEN OTHERS => NULL;
END CASE;
END PROCESS STATE_CAL;
-------------------7 Segment---------------------------------------------------
SEVEN_SEG: PROCESS (counter)
BEGIN
CASE counter IS
WHEN "000" => DIGIT <= "0000001";
WHEN "001" => DIGIT <= "1001111";
WHEN "010" => DIGIT <= "0010010";
WHEN "011" => DIGIT <= "0000110";
WHEN "100" => DIGIT <= "1001100";
WHEN "101" => DIGIT <= "0100100";
WHEN OTHERS => DIGIT <= "0000001";
END CASE;
END PROCESS SEVEN_SEG;
END SEQ;
编辑:现在这是我的版本。 无论我做什么,它仍然会显示“0”。
- 我认为它与 COUNT 和计数器有关。
- 我也应该将其实现为同步吗?
- numeric 和 unsigned 真的有那么大的问题吗?我们在大学里就是这样做的。
- 当我把 LOAD 放到滑动开关上时它会工作吗???
此致 阿德里安
您的代码有几个问题。顺便提一句。 运行模拟并不代表你的设计是正确的,因为你可以模拟硬件无法实现的动作。
这里是问题列表:
- 您不能将开关按钮用作时钟信号。按钮不是时钟源!要么实现信号清理电路(至少是去抖动电路,需要另一个时钟),要么使用
clk
信号作为启用。 - 此外,如果连接到外部开关按钮或切换按钮,您的每个信号都需要去抖动电路,除非您的测试板有去抖动按钮...
- 您的状态机有一个初始状态(没关系),但您必须将状态分配给
state
而不是next_state
。 - 您的代码使用了已过时的
std_logic_unsigned
。您应该为counter
信号使用numeric_std
和类型unsigned
。 - 您的代码为
COUT
引入了一个额外的寄存器,这是有意的吗? - 您的 PISO 进程使用异步
LOAD
信号,这在硬件中不受支持(假设 FPGA 作为目标设备)。 - 根据您的综合工具,它可能无法识别 FSM,因为您的 case 语句不符合 FSM 的模式。
- 看到固定的输出模式可能是由 FSM 故障引起的。如果您的合成器识别 FSM,您可以转到状态图并识别错误边缘或错误终端状态。
更多...
- 您的 7 段解码器是一个组合过程。无法重置。
- 此外,这个过程对
CLK
不敏感,只对counter
敏感。这会导致仿真和硬件之间的不匹配。 (综合忽略敏感列表)
如果你修复了这个问题,你的模拟应该有另一种行为,如果修复了,就可以像你的硬件一样工作:)。
FSM
STATE_CAL : process(state, so)
begin
-- Standardzuweisungen
next_state <= state; -- Bleib im Zustand falls in CASE nichts abweichendes bestimmt wird
Y <= '0';
-- Zustandswechsel
CASE state IS
WHEN s0 =>
IF (so = '1' THEN
next_state <= s1;
END IF;
WHEN s1 =>
IF (so = '1') THEN
next_state <= s2;
END IF;
WHEN s2 =>
IF (so = '0') THEN
next_state <= s3;
END IF;
WHEN s3 =>
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s4;
END IF;
WHEN s4 =>
Y <= '1'; -- Moore-Ausgabe
IF (so = '0') THEN
next_state <= s0;
else
next_state <= s2;
END IF;
END CASE;
END PROCESS;
Paebbels 已经描述了您的代码的许多问题。另请检查您的综合工具的警告。它们通常指示合成器实际输出的逻辑与您在 VHDL 中描述的逻辑不同。
我怀疑你又犯了两个与VHDL没有直接关系的错误:
- 您的 7 段显示控制线似乎处于低活动状态,因为当您按下
RESET
时,您只能看到一个活动段。这与您在本例中分配的向量"1111110"
中唯一的零匹配(通过将counter
重置为"000"
)。 - 但即使在这种情况下,开明的部分也应该在中间而不是在顶部。因此,您的引脚分配似乎是相反的顺序。