Ich bin ein absoluter Anfänger mit VHDL und ein fast Anfänger mit digitaler Logik und ich habe ein Problem beim Durcharbeiten eines Buches, das ich gerade lese. Insbesondere soll in einer Übung ein Zähler mit einem Enable- und einem Reset-Schalter gebaut werden. Ich habe es auf eine Weise implementiert und der Compiler (Xilinx ISE) hat sich so sehr darüber beschwert, dass ich den Weg des geringsten Widerstands genommen und es in etwas geändert habe, das ich für suboptimal hielt. Aber jetzt würde ich gerne wissen, was mit meinem ursprünglichen Code falsch ist.
Hier ist das "funktionierende" Beispiel:
-- EXAMPLE 1
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity clocks is
Port (
switch0 : in STD_LOGIC;
switch1 : in STD_LOGIC;
LEDs : out STD_LOGIC_VECTOR (7 downto 0);
clk : in STD_LOGIC
);
end clocks;
architecture Behavioral of clocks is
signal counter : STD_LOGIC_VECTOR( 29 downto 0 ) := ( others => '0' );
begin
LEDs <= counter( 29 downto 22 );
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
elsif switch1 = '1' then
counter <= ( others => '0' );
end if;
end if;
end process;
end Behavioral;
Also im Grunde setzen Sie switch0 und der Zähler beginnt hochzuzählen. Löschen Sie switch0 und es hört auf zu zählen. Stellen Sie Schalter1 ein, während Schalter0 frei ist, und der Zähler wird auf 0 zurückgesetzt. Stellen Sie Schalter1 ein, während Schalter0 gesetzt ist und der Zähler nicht zurückgesetzt wird.
Was ich wirklich wollte, war, dass der Reset-Schalter1 den Zähler löschen kann, auch wenn Schalter0 gesetzt war. Ich wollte, dass die steigende Flanke des Reset-Schalters 1 den Zähler auf 0 zurücksetzt, während der Zähler weiter steigt, wenn der Aktivierungsschalter 0 noch gesetzt ist.
Ich dachte, ich könnte ein bisschen näher kommen, indem ich den Prozess so ändere:
-- EXAMPLE 2
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( clk ) then
if switch1 = '1' then
counter <= ( others => '0' );
elsif switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Aber seltsamerweise überschreibt der Aktivierungsschalter0 auf dem Spartan 6-Chip, den ich verwende, immer noch den Reset-Schalter1? Dann habe ich das versucht:
-- EXAMPLE 3
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( switch1 ) then
counter <= ( others => '0' );
else
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end if;
end process;
Das sollte genau das sein, was ich will, aber Xilinx ISE ist damit noch weniger zufrieden - ich bekomme diese Warnungen vom Compiler:
WARNING:Xst:647 - Input <switch0> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:647 - Input <clk> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:2404 - FFs/Latches <counter<1:30>> (without init value) have a constant value of 0 in block <clocks>.
WARNING:Par:288 - The signal clk_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:288 - The signal switch0_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:288 - The signal switch1_IBUF has no load. PAR will not attempt to route this signal.
WARNING:Par:283 - There are 3 loadless signals in this design. This design will cause Bitgen to issue DRC warnings.
switch0 wird nie verwendet? clk auch nicht? Wohin sind sie gegangen? Und als ich es auf meinem Spartan 6 ausführte, tat es dasselbe wie das „funktionierende“ Beispiel. Das habe ich auch probiert:
-- EXAMPLE 4
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( switch1 ) then
counter <= ( others => '0' );
end if;
if rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Dies wird nicht einmal erstellt - in der Implementierung erhalte ich diese Warnungen/Fehler:
WARNING:Xst:647 - Input <clk> is never used. This port will be preserved and left unconnected if it belongs to a top-level block or it belongs to a sub-block and the hierarchy of this sub-block is preserved.
WARNING:Xst:3002 - This design contains one or more registers/latches that are directly
incompatible with the Spartan6 architecture. The two primary causes of this is
either a register or latch described with both an asynchronous set and
asynchronous reset, or a register or latch described with an asynchronous
set or reset which however has an initialization value of the opposite
polarity (i.e. asynchronous reset with an initialization value of 1).
Kann mir jemand sagen, was an diesen überarbeiteten Prozessen nicht koscher ist? Ich verstehe, dass es viele Dinge gibt, die in VHDL codiert werden können, aber nicht in ein Hardwaredesign übersetzt werden können, und die zweite meiner Überarbeitungen scheint in diese Kategorie zu fallen, aber kann mir jemand erklären, was hier vor sich geht? ? Was ist falsch an einem Latch mit asynchronen Resets und Sets? Was ist falsch an verschachtelten Wenn-Dann-End-Blöcken? Was mache ich hier falsch?
UPDATE: Wie in der Antwort hätten die Beispiele 3 und 4 niemals funktionieren können, da ein Prozess nicht mehrmals getaktet werden kann - er kann nur ein Signal mit einer steigenden Flanke () oder einem Ereignis darauf haben. Es stellt sich heraus, dass Beispiel 2 tatsächlich funktioniert und das tut, was ich will. Ich habe es durch den Simulator laufen lassen und es schien in Ordnung zu sein, und als ich es dann erneut für Hardware synthetisierte, funktionierte es auf meinem Spartan 6 einwandfrei. Ich muss etwas Seltsames getan haben, als ich es das erste Mal ausprobiert habe?
der rise_edge() Parameter ist eigentlich nur für Taktsignale. Eine Möglichkeit wäre folgende:
clk_proc: process( clk, switch1, switch0 )
begin
if switch1 = '1' then
counter <= ( others => '0' );
elseif rising_edge( clk ) then
if switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Dies wird als asynchroner Reset-Prozess bezeichnet, was bedeutet, dass der Zähler immer dann zurückgesetzt wird, wenn reset (switch1) hoch ist, unabhängig vom Taktstatus. Ein synchron zurückgesetzter Prozess würde genauso aussehen wie Ihr zweites Beispiel:
clk_proc: process( clk, switch1, switch0 )
begin
if rising_edge( clk ) then
if switch1 = '1' then
counter <= ( others => '0' );
elsif switch0 = '1' then
counter <= counter + 1;
end if;
end if;
end process;
Sie haben jedoch angegeben, dass Ihr zweites Beispiel nicht wie erwartet funktioniert hat. Mein Verdacht ist, dass dies daran liegt, dass die Signale, die es ansteuern, eher Schalter als getaktete Logiksignale sind. Schalter schalten nicht wirklich sofort, sondern hüpfen ein paar Mal zwischen Ein und Aus, bevor sie sich niederlassen. Sie müssen eine Art Entprellprozess implementieren, um ein Signal zu erzeugen, das mit Ihrer Uhr synchron ist und Ihren Timer steuern kann.
Erwähnenswert ist auch, dass das FPGA-Design viel einfacher ist , wenn Sie die Dinge zuerst simulieren. Xilinx ISE enthält einen Simulator – erstellen Sie eine Testbench und verwenden Sie sie! So können Sie leicht sehen, was in Ihrer Implementierung passiert, bevor Sie sich jemals der Hardware nähern.
Ted Middleton
Ted Middleton
Stanri
Stanri