Creating a frequency divider in VHDL
MAJOR EDIT:
Problem was solved after reading Will Dean's comment. The original question is below the revised code:
-- REVISED CODE (NOW WORKS)
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity CLOCK_DIVIDER is
port(
reset : in std_logic;
clk : in std_logic;
half_clk : out std_logic
);
end CLOCK_DIVIDER;
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
tick <= '0';
elsif clk = '1' and clk'EVENT then
if tick = '0' then
tick <= '1';
elsif tick = '1' then
tick <= '0';
end if;
end if;
end process;
process(tick)
begin
half_clk <= tick;
end process
end CLOCK_DIVIDER;
The synthesized logic block of the revised code is a single asynchronous-reset DFF that takes half_clk as output and inverted half_clk as input, which means the value of half_clk changes on every rising edge of clk.
Thanks, Will Dean :)
==== ==== ==== ==== ====
Origin开发者_StackOverflow社区al question below:
==== ==== ==== ==== ====
I need a simple clock divider (just divide-by-two) and instead of usinga template, I thought I'd try to write one myself to keep in training.
Unfortunately, the synthesized logic block does not appear to work - I present the logic block and the code (which I really think ought to work), in that order.
logic block http://img808.imageshack.us/img808/3333/unledly.png
What I'm really wondering is what the devil is up with the "tick" DFF - it apparently takes its input from the mux-selector which is... Yeah.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity CLOCK_DIVIDER is
port(
reset : in std_logic;
clk : in std_logic;
half_clk : out std_logic
);
end CLOCK_DIVIDER;
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
half_clk <= '0';
tick <= '0';
elsif clk = '1' and clk'EVENT then
if tick = '0' then
half_clk <= '0';
tick <= '1';
elsif tick = '1' then
half_clk <= '1';
tick <= '0';
end if;
end if;
end process;
end CLOCK_DIVIDER;
I'm sure the error in the code is obvious but I've been staring myself blind trying to find it.
If halfclk is to be used as an enable and not a true clock, disregard this advice...
If this is for an FPGA target and "half_clk" is really being used as a clock (e.g. going to the clock pin on a DFF, and not the enable pin)... Don't do this.
Creating derived clocks using general FPGA logic/fabic will lead to problems with build tools, and can eventually lead to failed builds (won't meet timing), or builds that do not behave as expected because constraints not correctly passed through to all clock networks.
Instead use clock management blocks that are built into FPGA fabric especially for this purpose. In the world of Xilinx parts, these are called Digital Clock Managers (DCM) or Mixed Mode Clock Manager (MMCM). I am not sure what the equivalent Altera component is. Read up on the documentation to determine the best use for your application.
Based on your revised code, I offer this modification to the architecture:
-- REVISED CODE (NOW WORKS) and simplified and synthesisable
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
tick <= '0';
elsif rising_edge(clk) then -- use of rising_edge() is the correct idiom these days
tick <= not tick;
end if;
end process;
half_clk <= tick;
end CLOCK_DIVIDER;
I've removed this process and replaced with a concurrent assignment:
process(tick)
begin
half_clk <= tick;
end process
as what this is asking for is a flipflop clocked on both edges of tick
.
This will appear to achieve what you want in terms of the waveforms wiggling the way you want them to, but will not synthesise. It also adds an extra delta delay to the output which may or may not cause problems if you use it as a clock "down the road". As others have commented, this is not a good plan anyway in most architectures (but for some it is "the right way").
Are you sure you're resetting at startup? The way you've got your conditional for tick defined, nothing will happen if tick isn't zero or one (ie: it could be U, Z, X, etc).
I generally suggest covering all cases with your conditional expressions, ie:
if tick = '0' then
half_clk <= '0';
tick <= '1';
else
half_clk <= '1';
tick <= '0';
end if;
or
if tick = '0' then
half_clk <= '0';
tick <= '1';
elsif tick = '1' then
half_clk <= '1';
tick <= '0';
else
-- Throw error or something here
end if;
A simple counter does the trick (proper way is DCM of course):
signal cnt : std_logic_vector(3 downto 0);
...
clk_div_2 <= cnt(0);
clk_div_4 <= cnt(1);
clk_div_8 <= cnt(2);
clk_div_16 <= cnt(3);
...
process(clk)
if clk'event and clk = '1' then
cnt <= cnt + 1;
end if;
end process;
精彩评论