Immer wieder taucht die Frage auf, ob mehrere wait-Statements im Prozess synthetisierbar sind. Die Antwort dazu heißt: "Ja, aber es gelten signifikante Einschränkungen".
Aber zuerst mal die Grundlagen. Ein verzweifelter Mensch möchte sowas synthetisieren:
entity wait_im_process is Port ( din : in STD_LOGIC; dout : out STD_LOGIC := '0'; clk : out STD_LOGIC := '0'); end wait_im_process; architecture Behavioral of wait_im_process is begin process begin dout <= '0'; wait for 10ns; clk <= '1'; wait for 10ns; clk <= '0'; dout <= '0'; wait for 10ns; clk <= '1'; wait for 10ns; clk <= '0'; dout <= din; wait for 10ns; dout <= '1'; wait for 10ns; clk <= '0'; dout <= '1'; wait for 10ns; end process; end Behavioral;
Klar, sagt jetzt jemand, so geht das nicht, weil Zeiten nicht synthetisierbar sind. Für zeitliche Abläufe auf dem FPGA muß eine Statemachine mit einem entsprechenden Takt (10ns=100MHz) her, die einen Schritt nach dem anderen abarbeitet. Schade, das bedeutet viel Umschreibarbeit.
architecture Behavioral of wait_im_process is signal cnt : integer range 0 to 6; begin process begin wait until rising_edge(clk100MHz); case cnt is when 0 => dout <= '0'; when 1 => clk <= '1'; when 2 => clk <= '0'; dout <= '0'; when 3 => clk <= '1'; when 4 => clk <= '0'; dout <= din; when 5 => dout <= '1'; when 6 => clk <= '0'; dout <= '1'; end case; if (cnt<6) then cnt <= cnt+1; else cnt <= 0; end if; end process; end Behavioral;
Aber was wäre, wenn ich das Ausgangs-Beispiel einfach nur auf einen Takt mit 10ns Zyklusdauer beziehe und von dem z.B. auf die steigende Flanke reagiere? So etwa:
entity wait_im_process is Port ( clk10ns : in STD_LOGIC; din : in STD_LOGIC; dout : out STD_LOGIC := '0'; clk : out STD_LOGIC := '0'); end wait_im_process; architecture Behavioral of wait_im_process is begin process begin dout <= '0'; wait until rising_edge(clk10ns); clk <= '1'; wait until rising_edge(clk10ns); clk <= '0'; dout <= '0'; wait until rising_edge(clk10ns); clk <= '1'; wait until rising_edge(clk10ns); clk <= '0'; dout <= din; wait until rising_edge(clk10ns); dout <= '1'; wait until rising_edge(clk10ns); clk <= '0'; dout <= '1'; wait until rising_edge(clk10ns); end process; end Behavioral;
Geht sowas?
Ja, die Synthesetools (zumindest von Xilinx) sind so schlau und erkennen, dass das ganze eine Schrittkette darstellt und mithin eine Statemachine ist. Und die wird dann auch daraus generiert:
Die schlechte Nachricht ist, dass diese Schrittkette nur geradeaus durchläuft. Es gibt keine Möglichkeit, den Ablauf anzuhalten oder zu ändern, weil die States keinen Namen haben und somit auch keiner gezielt ausgewählt werden kann.
Das mit dem Anhalten kann mit einem bösen Trick umgangen werden, indem einfach ein Clock-Enable Signal verwendet wird:
process begin if enable ='1' then dout <= '0'; wait until rising_edge(clk10ns); clk <= '1'; : wait until rising_edge(clk10ns); end if; end process;
Allerdings muß dafür die Warnung
The following signals are missing in the process sensitivity list: enable
in Kauf genommen werden. Das heißt, dass die Simultion nicht mehr der Realität entspricht. Der Versuch, die Sensitivity-List zu vervollständigen gibt allerdings einen Fehler:
statement WAIT not allowed in a process with a sensitivity list
Also wie gesagt: ein übler Trick.
Einzelne wait-Abschnitte mit einem Clock-Enable zu versehen klappt dann überhaupt nicht mehr:
process begin dout <= '0'; wait until rising_edge(clk10ns); clk <= '1'; : if enable ='1' then wait until rising_edge(clk10ns); end if; clk <= '0'; dout <= '1'; wait until rising_edge(clk10ns); end process;
Dieser Versuch gibt den Fehler
Recurse wait not supported or bad place of Exit or Next statement