问题
Here is my code and it's pretty simple. I'm to cycle through the first 8 letters of the alphabet on a Altera Cyclone II board.
entity lettercycle is
port(
SW : in std_logic; -- toggle switch
HEX0 : out std_logic_vector(6 downto 0) -- 7-segment display
);
end lettercycle;
architecture behavioural of lettercycle is
signal counter : integer range 0 to 7 := 0;
begin
process
type SEGMENT_ARRAY is array (0 to 7) of std_logic_vector(6 downto 0);
variable SEVENSEG : SEGMENT_ARRAY := ("0001000","0000011","1000110","0100001","0000110","0001110","0010000","0001001");
begin
HEX0 <= SEVENSEG(counter);
wait until SW = '0';
counter <= counter + 1;
end process;
end behavioural;
This works great, it cycles but initially it doesn't display "A" on my seven segment display. It displays "8" (so nothing essentially). Once I push SW which is a logic 0 switch it changes to 'A' and cycles to 'B', 'C', etc properly. It also loops correctly. What it isn't doing is initially setting to 'A'. If I force
HEX0 <= SEVENSEG(0);
Then it will display 'A' initially so I'm out ideas. Could this be related to bouncing?
回答1:
The synthesis tool implements the process with falling edge flip-flops, as a
result of the wait until SW = '0';
, so both the counter
and HEX0
inside
the process are updated at falling edge of SW
(thus HEX0
is not a latch).
The synthesis tool does however not propagate the initial 0 value of counter
to initial value on HEX0
based on mapping through SEVENSEG
, so you won't
see an initial 'A' on the output.
The synthesis output is shown on the figure below, whereby the flip-flops on the output can also be seen.
The intended operation is possible with update of process and HEX0
assign to:
process (SW) is
begin
if falling_edge(SW) then
counter <= counter + 1;
end if;
end process;
HEX0 <= SEVENSEG(counter);
This will also remove the unnecessary flip-flops on the output for HEX0
.
Note the SEVENSEG
is moved to architectural level declaration as constant.
回答2:
Morten is right about the falling edge treatment of HEX0.
The alternative is to declare SEVENSEG as a constant in the architecture declarative region and move the assignment from counter (which is a signal) to HEX0 outside of the process:
library ieee;
use ieee.std_logic_1164.all;
entity lettercycle is
port(
SW : in std_logic; -- toggle switch
HEX0 : out std_logic_vector(6 downto 0) -- 7-segment display
);
end lettercycle;
architecture behavioural of lettercycle is
signal counter : integer range 0 to 7 := 0;
type SEGMENT_ARRAY is array (0 to 7) of std_logic_vector(6 downto 0);
constant SEVENSEG : SEGMENT_ARRAY :=
("0001000","0000011","1000110","0100001",
"0000110","0001110","0010000","0001001");
begin
process
-- type SEGMENT_ARRAY is array (0 to 7) of std_logic_vector(6 downto 0);
-- variable SEVENSEG : SEGMENT_ARRAY :=
-- ("0001000","0000011","1000110","0100001",
-- "0000110","0001110","0010000","0001001");
begin
-- HEX0 <= SEVENSEG(counter);
wait until SW = '0';
if counter = 7 then
counter <= 0;
else
counter <= counter + 1;
end if;
end process;
HEX0 <= SEVENSEG(counter);
end behavioural;
library ieee;
use ieee.std_logic_1164.all;
entity lettercycle_tb is
end entity;
architecture foo of lettercycle_tb is
signal SW: std_logic := '1';
signal HEX0: std_logic_vector(6 downto 0);
begin
DUT:
entity work.lettercycle
port map (
SW => SW,
HEX0 => HEX0
);
STIMULUS:
process
begin
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
SW <= '0';
wait for 60 ms;
SW <= '1';
wait for 60 ms;
wait;
end process;
end architecture;
And the bit about if counter = 7 then...
is because integer "+" has it's mathematical meaning, the output of the add can be out of range and give you a nasty run time message:
ghdl -r lettercycle_tb --wave=lettercycle_tb.ghw
./lettercycle_tb:error: bound check failure at lettercycle.vhdl:29
./lettercycle_tb:error: simulation failed ghdl: compilation error
This says simulation can fail and should encourage the use of std_ulogic based array values for counters and other values undergoing arithmetic operations, which would have counter rollover. A range of 0 to 7 happens to fit exactly within 3 bits and in the synthesized product you'd expect counter to roll over.
There's a description of the verification methodology in the now withdrawn IEEE Std 1076.6 (Register Transfer Level Synthesis):
The process of verifying synthesis results using simulation consists of applying equivalent inputs to both the original model and synthesized model and then comparing their outputs to ensure that they are equivalent. Equivalent in this context means that a synthesis tool shall produce a circuit that is equivalent at the input, output, and bidirectional ports of the model. As synthesis in general does not recognize the same delays as simulators, the outputs cannot be compared at every simulation time. Rather, they can only be compared at specific simulation times when all transient delays have settled and all active timeout clauses have been exceeded. If the outputs do not match at all comparable times, the synthesis tool shall not be compliant. There shall be no matching requirement placed on any internal nodes.
Essentially, the synthesized result is supposed to match what VHDL simulation does other than ignoring meta-value transactions. So you're synthesized result did as much as possible.
回答3:
This isn't a switch bounce issue (although your design is susceptible). In your design HEX0
is a latch. You never set it to an initial value which is why it starts up in a tool assigned initial state of "0000000". Note that this is not an inherent property of VHDL which would start up with "UUUUUUU" (all uninitialized) in simulation but synthesis tools take some liberties when implementing 9-value logic in real hardware.
There is no need for SEVENSEG
to be a variable so you can turn it into an architecture level constant and turn the assignment to HEX0
into a continuous assignment outside the process as a simple way to make it start up as desired.
来源:https://stackoverflow.com/questions/23797127/a-simple-vhdl-circuit-wont-display-initial-value