FPGA, SoC, And CPLD Boards And Kits
FPGA Evaluation and Development Kits
5924 Discussions

Need help creating a simple 32bit counter

Altera_Forum
Honored Contributor II
2,472 Views

I'm trying to learn VHDL so I thought I'd try converting the "my_first_fpga" example from verilog to VHDL (how complicated can adding one to a number be?), three hours later, lots of googling and searching through books has yielded no result. Sorry if this is the wrong place to ask (if so where is a better place?) 

 

So I run this code through the simulator, apply a 50Mhz clock to CLK and get nothing from the counter bus. to make sure the process is running I output CLK to OUT, if I hard code a value ie X"FFFF0000" to counter it outputs that value but counter := counter +1 gets me no where. 

 

Also is it possible to step through code as with C? 

 

Here is my code: 

-- import std_logic from the IEEE library library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; -- this is the entity entity counter_example is port ( CLK : in std_logic; OUT1: out std_logic; Q : out std_logic_vector(31 downto 0)); end counter_example; architecture counter_code of counter_example is begin process (CLK) variable counter : std_logic_vector(31 downto 0); begin counter := counter + 1; OUT1 <= CLK; -- Sanity Check that I am actually outputting something Q <= counter; end process; end counter_code;Thanks.
0 Kudos
13 Replies
Altera_Forum
Honored Contributor II
1,188 Views

Thats the reason why i stay with verilog HDL as VHDL has so much typo for such simple stuff. 

 

module counter_example { CLK, OUT1 Q }; 

 

input CLK; 

output OUT1; 

output [31:0] Q; 

 

always @ ( posedge CLK ) 

Q <= Q + 1; // or write 32'd1 to avoid warnings due to truncation 

 

always @ ( posedge CLK ) 

OUT1 <= CLK; 

 

endmodule // thats it 

 

stepping trough like c code, haven't seen that even on our SUN used for ASIC designs with much much more expensiv tools ($$$ per year)
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

The edge sensitive condition is missing. See the VHDL templates in Quartus editor for the basic syntax of clock synchronous logic. 

 

Although VHDL is a hardware description language rather than being executed line by line like a C program, you can single step it in a simulator as ModelSim, that is interpreting the VHDL text in this place.
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

Thanks, a friend suggested verilog over VHDL, maybe I should listen to him. 

 

Question: The following works 

Q : buffer std_logic_vector(31 downto 0)); if CLK'EVENT AND CLK = '1' then Q <= Q + 1 ; end if;But if the counter is stored in a variable and copied to Q on a positive edge it doesn't work. 

 

ie: 

if CLK'EVENT AND CLK = '1' then counter := counter + 1; Q <= counter ; end if; 

 

Why doesn't that work?
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

First off, welcome to VHDL. 

 

2nd. There is a reason it is not updating with the variable and its all down to how the language works. You should find that if you swap around the counter + 1 statement and the q <= counter statement (so the Q output is set first) it will work. 

 

This is because variables are updated immediately, whereas signals are not. The code you currently have will work in a simulator, but when you synthesise it, as the variable is used to assing a value to Q, there is no need to store the value in counter between clock cycles (because you have stored the value in Q. Now if you swapped the 2 statements around to this: 

 

if CLK'EVENT AND CLK = '1' then Q <= counter ; counter := counter + 1; end if;  

 

The synethsiser notes that counter is not assigned to a register at the end of the process, but you do give the value to Q before you increment it, so it will create one for you to store the value of counter between clocks. Like I said before, either way round will work in simulation, but not in synthesis. 

 

 

3rdly. As you are new to VHDL please can I ask you to stop using std_logic_unsigned/arith now, and use the IEEE standard instead, which is numeric_std, so you dont get into bad (or old fashioned) habits. You can also use rising_edge(clk) instead of clk'event and clk = '1', as it is slightly safer to use in simulation. The rising_edge function will only trigger when the clk signal changes from '0' or 'L' to '1' or 'H', whereas the latter will trigger whenever the clk signal changes from anything to '1' (so 'X', 'U', '-', '0', 'Z', 'H', 'L'). 

 

the numeric_std library offers the signed and unsigned types which you can use in the same file (with the std_logic_unsigned/signed you cannot use both types at the same time). You could also do this counter simply by doing this: 

 

signal counter : unsigned(31 downto 0); ..... process(clk) begin if rising_edge(clk) then counter <= counter + 1; end if; end process; Q <= std_logic_vector(counter);  

 

 

Another thing to keep in mind is that port lists only HAVE to be std_logic/vector at the top level, theres nothing to stop you using integers, unsigneds, booleans, fixed point types in the port definition of an entity.
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

You should show complete library and signal/variable definition. 

 

Generally, this code is supposed to work. But possibly, you found a way to thwart it. 

if CLK'EVENT AND CLK = '1' then counter := counter + 1; Q <= counter ; end if;
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

 

--- Quote Start ---  

You should show complete library and signal/variable definition. 

 

Generally, this code is supposed to work. But possibly, you found a way to thwart it. 

if CLK'EVENT AND CLK = '1' then counter := counter + 1; Q <= counter ; end if; 

--- Quote End ---  

 

 

Like I said, it thwarts the synthesisor because there it sees no point in registering counter, because it registers Q instead. Because counter never read's back from Q, counter is always assumed to be 0. 

 

The best way to fix it and make it synethsise is swap the 2 statement, or do this instead: 

 

if CLK'EVENT AND CLK = '1' then counter := Q; counter := counter + 1; Q <= counter ; end if;
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

Thanks Tricky, that got me up and running :) 

 

Does verilog operate the same way in relation to instruction flow and signal vs variable? Also is there a good source for these idiosyncrasies in the language? 

 

In an unrelated question every time I recompile I need to goto 

Tools -> Simulator Tool -> Generate Functional Simulation Netlist  

to run a simulation, is there a way to automatically generate the netlist or am I doing something wrong?
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

 

--- Quote Start ---  

Thanks Tricky, that got me up and running :) 

 

Does verilog operate the same way in relation to instruction flow and signal vs variable? Also is there a good source for these idiosyncrasies in the language? 

 

In an unrelated question every time I recompile I need to goto 

Tools -> Simulator Tool -> Generate Functional Simulation Netlist  

to run a simulation, is there a way to automatically generate the netlist or am I doing something wrong? 

--- Quote End ---  

 

 

I do not know anything about verilog, though the words blocking and non-blocking assignments has been used before to equate signals and variables in VHDL from time to time. 

 

for the 2nd point you're simulating a post-P&R netlist, which will be slow (but will function as it would on real hardware). In modelsim you can simulate your VHDL text files directly with no synthesis required. You will need to create a testbench to stimulate all of the inputs (like generating a clock) but thats quite straight forward. 

 

To generate a clock in a VHDL testbench you can just use the line: 

 

signal clock : std_logic := '0'; clk <= not clk after 10 ns; --will give 50MHz clock and then just connect the clock to the clk port on your counter.
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

in verilog you can use blocking and non blocking assignments, you can mix them but you need to decide which one you use inside an always block for this particular block 

 

non blocking 

 

q <= counter; 

counter <= counter + 1; 

 

is the same as if you swap the lines 

 

counter <= counter + 1; 

q <= counter; 

 

both work the same way. 

 

but if you use blocking assignments then it does matter in which order you write your code. 

i personaly use non blocking assingments as ther are enough bugs around to catch ...
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

I found the "Start Compilation and Simulation" option in Quartus which saves a few steps, however I thought I'd try setting up a test bench. I installed ModelSim, when I run the simulation and look in wave I can see the clock but counter_out has no value. Did I set this up correctly? 

 

-- import std_logic from the IEEE library library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; -- this is the entity entity counter_example is port ( counter_out : buffer unsigned(31 downto 0)); end counter_example; architecture counter_code of counter_example is signal clock : std_logic := '0'; begin process (clock) begin clock <= not clock after 10 ns; --will give 50MHz clock if rising_edge(clock) then counter_out <= counter_out + 1; end if; end process; end counter_code; 

 

Thanks
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

Your process that generates the clock is also triggered by the clock, which won't work. It's a bit like the chicken-and-egg problem ;) 

You should have two processes, one to generate the clock, and another one that triggers on it: 

Clockgen: process begin clock <= not clock after 10 ns; --will give 50MHz clock end process; Sim: process (clock) begin if rising_edge(clock) then counter_out <= counter_out + 1; end if; end process;It is also a good idea to add a reset signal to give your counter (and clock) an initial value. If you don't do that counter_out will start with UUUUU (uninitialised) in the simulator and will become XXXXX (unknown) at the first clock cycle.
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

 

--- Quote Start ---  

Your process that generates the clock is also triggered by the clock, which won't work. It's a bit like the chicken-and-egg problem ;) 

You should have two processes, one to generate the clock, and another one that triggers on it: 

Clockgen: process begin clock <= not clock after 10 ns; --will give 50MHz clock end process;  

--- Quote End ---  

 

 

This does not have to be inside a process, as it is a simple 1 line statement.  

 

Also, remember do not put this kind of code in your synthesisable code. Keep them separate as a testbench and a counter. If you put this code in and tried to synthesise it you'll some odd things getting generated.
0 Kudos
Altera_Forum
Honored Contributor II
1,188 Views

Yes, I mixed up with the way I usually do a clock, which is either 

Clockgen: process begin wait for 10ns; clock <= not clock; end process;orClockgen: process begin clock <= '0'; wait for 10ns; clock <= '1'; wait for 10ns; end process;The latter is longer but doesn't require to initialize the clock value
0 Kudos
Reply