I'm a complete beginner with VHDL and an almost beginner with digital logic and I'm having a problem working through a book I'm reading. In particular, an exercise asks to build a counter with an enable and a reset switch. I implemented it one way and the compiler (Xilinx ISE) complained about it enough that I took the path of least resistance and changed it to something that I thought was sub-optimal. But now I'd like to know what's wrong with my original code.
Here's the 'working' example:
-- 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;
So basically you set switch0 and the counter begins counting up. Clear switch0 and it stops counting up. Set switch1 while switch0 is clear and the counter will reset to 0. Set switch1 while switch0 is set and the counter doesn't reset.
What I really wanted was for the reset switch1 to be able to clear the counter even if switch0 was set. I wanted the reset switch1's rising edge to reset the counter back to 0 while the counter keeps climbing if the enable switch0 is still set.
I thought I could get a bit closer by changing the process to this:
-- 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;
But strangely, on the Spartan 6 chip I'm using, the enable switch0 still overrides the reset switch1? Then I tried this:
-- 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;
This should be exactly what I want, but Xilinx ISE is even less happy with this - I get these warnings from the 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 is never used? Neither is clk? Where did they go? And when I ran it on my spartan 6, it did the same thing as the 'working' example. I tried this too:
-- 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;
This won't even build - in implementation I get these warnings/errors:
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).
Can anyone clue me in as to what is it about these re-worked processes that isn't kosher? I understand that there are a lot of things that can be coded in VHDL but that can't be translated to a hardware design, and the second of my revisions seems to fall into that category, but can anyone explain to me what's going on here? What's wrong with a latch with async resets and sets? What's wrong with nested if-then-end blocks? What am I doing wrong here?
UPDATE: As in the answer, examples 3 and 4 could never have worked because a process can't be clocked multiple times - it can only have one signal with a rising_edge() or 'event on it. Example 2, it turns out, does actually work and do what I want it to do. I ran it through the simulator and it seemed ok, and then when I synthesized it again for hardware, it worked just fine on my spartan 6. I must have done something strange the first time I tried it?