Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Basic VHDL Question about Edges

Status
Not open for further replies.

dohzer

Member level 1
Joined
Oct 25, 2008
Messages
39
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,636
vhdl increment

I'm writing a simple program (as my first VHDL program) to take a clock signal and divide it by powers of two (1,2,4,8,....). Basically I have a signal that counts up, and depending on the divider input, one of the signal's bits is used as the output.

Here's my current code:

Code:
--Clock Divider

library ieee;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;


entity clock_divider is
	port(	RESET:		in std_logic;
			CLK_IN:		in std_logic;
			DIV_SEL:	in std_logic_vector(4 downto 0);
			CLK_OUT:	out std_logic
	);
end clock_divider;

architecture clock_divider of clock_divider is
	signal count: unsigned(31 downto 0);
	
	begin

	mux:	process(count,DIV_SEL)
			begin
				--Select output bit
				case DIV_SEL is
					when "00000" =>	CLK_OUT <= std_logic(count(0));
					when "00001" =>	CLK_OUT <= std_logic(count(1));
					when "00010" =>	CLK_OUT <= std_logic(count(2));
					when "00011" =>	CLK_OUT <= std_logic(count(3));
					when "00100" =>	CLK_OUT <= std_logic(count(4));
					when "00101" =>	CLK_OUT <= std_logic(count(5));
					when "00110" =>	CLK_OUT <= std_logic(count(6));
					when "00111" =>	CLK_OUT <= std_logic(count(7));
					when "01000" =>	CLK_OUT <= std_logic(count(8));
					when "01001" =>	CLK_OUT <= std_logic(count(9));
					when "01010" =>	CLK_OUT <= std_logic(count(10));
					when "01011" =>	CLK_OUT <= std_logic(count(11));
					when "01100" =>	CLK_OUT <= std_logic(count(12));
					when "01101" =>	CLK_OUT <= std_logic(count(13));
					when "01110" =>	CLK_OUT <= std_logic(count(14));
					when "01111" =>	CLK_OUT <= std_logic(count(15));
					when "10000" =>	CLK_OUT <= std_logic(count(16));
					when "10001" =>	CLK_OUT <= std_logic(count(17));
					when "10010" =>	CLK_OUT <= std_logic(count(18));
					when "10011" =>	CLK_OUT <= std_logic(count(19));
					when "10100" =>	CLK_OUT <= std_logic(count(20));
					when "10101" =>	CLK_OUT <= std_logic(count(21));
					when "10110" =>	CLK_OUT <= std_logic(count(22));
					when "10111" =>	CLK_OUT <= std_logic(count(23));
					when "11000" =>	CLK_OUT <= std_logic(count(24));
					when "11001" =>	CLK_OUT <= std_logic(count(25));
					when "11010" =>	CLK_OUT <= std_logic(count(26));
					when "11011" =>	CLK_OUT <= std_logic(count(27));
					when "11100" =>	CLK_OUT <= std_logic(count(28));
					when "11101" =>	CLK_OUT <= std_logic(count(29));
					when "11110" =>	CLK_OUT <= std_logic(count(30));
					when "11111" =>	CLK_OUT <= std_logic(count(31));
					when others =>	CLK_OUT <= 'Z';
					
				end case;
			end process mux;
	
	increment:	process(RESET,CLK_IN) is
		begin
			--Reset the counter if reset is high
			if (RESET = '1') then
				count <= (others => '0');
			--Increment the counter on each clock edge
			elsif (rising_edge(CLK_IN)) then
				count <= count + 1;
			elsif (falling_edge(CLK_IN)) then
				count <= count + 1;
				
			end if;
		end process increment;
end architecture;

There are two processes; one to increment the count signal, and the other to select which bit to use as the output based on the divider select input.
I wanted the clock input to "pass straight through" when the divider select input is '00000', and at first I thought I would do it by having the count signal increment on both the rising and falling edges, but the program didn't compile when I tried to do that. I got the following error:

Error (10819): Netlist error at clock_divider.vhd(66): can't infer register for count[0] because it changes value on both rising and falling edges of the clock

I know I could just use the clock signal without manipulating it if I want a "divide by 1" signal, but I was just wondering why using both edges give me trouble.
Can someone explain if there is a way to use both edges, or if not, explain why not.
Also, if there is any other mistake I have made in my code, let me know.
 

vhdl sample both clock edges

/.../I wanted the clock input to "pass straight through"
when the divider select input is '00000'/.../
you should rather write it this way:
when "00000" => CLK_OUT <= CLK_IN;
when "00001" => CLK_OUT <= std_logic(count(0));
incrementing the counter on both clock slopes will not help;
if you need to have a kind of consistency between
'DIV_SEL' value and the counter index declare:
signal count: unsigned(31 downto 1);
then you can write:
when "00001" => CLK_OUT <= std_logic(count(1));
when "00010" => CLK_OUT <= std_logic(count(2));

the other story is both edges sensitive flip-flops;
currently there are no such FF in fpga, the fpga flip-flops
can react on one slope only, you can write a code where
you have neg-edge triggered FF but it simply means the
synthesis tool inserts an inverter in clock path;
if you really need a counter counting both edges you have
to create 2 counters one triggered by positive clock edge
and one triggered by neg. edge and sum their outputs;

although such clock divider is good as an vhdl/synthesis exercise
you should be aware that the multiplexing process [which 'pass'
required clock as an output] requires time what means the divided
clock has unknown phase shift with respect to input clock - and
probably - with the data it is eventually processing;
---
 

increment vhdl

As the DIV_SEL is a numeric value, you should change it from std_logic_vector to unsigned.
After that, the process can be hugely simplified.

Code:
CLK_OUT <= count(to_integer(DIV_SEL));

By the way, please remove the obsolete std_logic_unsigned library. The numeric_std contains the official "unsigned" type.
 

vhdl basics

Thanks for the replies.

j_andr said:
the other story is both edges sensitive flip-flops;
currently there are no such FF in fpga, the fpga flip-flops
can react on one slope only, you can write a code where
you have neg-edge triggered FF but it simply means the
synthesis tool inserts an inverter in clock path;
if you really need a counter counting both edges you have
to create 2 counters one triggered by positive clock edge
and one triggered by neg. edge and sum their outputs;
Yeah, I thought it must have been an issues with synthesis, thanks for the explanation. I haven't done much reading yet on "synthesisability"; that is what I'm going to read next.

vomit said:
As the DIV_SEL is a numeric value, you should change it from std_logic_vector to unsigned.
After that, the process can be hugely simplified.

Code:
CLK_OUT <= count(to_integer(DIV_SEL));
Wow, much simpler. Thanks for the idea. I wouldn't have thought of doing it that way.
vomit said:
By the way, please remove the obsolete std_logic_unsigned library. The numeric_std contains the official "unsigned" type.
Yeah, I'm not too sure about which libraries to use. Are there any good guides on the internet on which libraries do what?
 

vhdl increment counters

Well, you can design ckts that use both the edges of the clock.. One such example is the DDR memory and DDR controllers. They latch in data at both the rising and falling edges of the clock.

The problem here in your code is that..at both the edges you're updating the same count variable. This cannot be done. The tool needs to infer registers to build the counter. So the count value cannot change at both edges.

To work around this problem, you have to use two count variables, one for the +ve edge and one for the -ve edge. Then the outputs have to be registered on both the edges.

count1 -> +ve edge count
count2 -> -ve edge count

output process updates the output count signal with these count values on both edges of the clock.

Code:
Process(clock)
if(risiing_edge(clock)) then
  count <= count1;
elsif(falling_edge(clock)) then
  count <= count2;
end if;
end process
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top