I'm studying VHDL right now, and I have a pretty simple homework assignment - I need to build a synchronous BCD counter that will count from 0 to 9 and when it reaches 9, will go back to 0. I wanted to experiment a little so I decided not to do the code in a (at least the way I see it) traditional way (with if, elseif) but with the when-else statement (mostly due to the fact that counter is from 0 to 9 and has to go back to 0 once it hits 9).
library IEEE;
use IEEE.std_logic_1164.all;
Entity sync_counter is
port (rst, clk: in std_logic);
end Entity;
Architecture implement of sync_counter is
signal counter: integer range 0 to 10;
Begin
counter <= 0 when (rst = '1') else
counter + 1 when (clk='1' and clk'event) else
0 when (counter = 10);
end Architecture;
So everything compiles, but in the simulation, initially counter jumps from 0 to 2, but after a cycle (0-9 - 0) it is acting normal, meaning counter goes from 0 to 1 as it should be. Same if you force rst = '1'.
Simulation image:
Why does it jump from 0 to 2 in the start?
Thank you.
It may not explain why it goes from 0 to 2. Please post your testbench code on that front. However, your code is bad. This code translate to this, with comments:
process(rst, clk, counter)
begin
if rst = '1' then -- Asynchronous reset, so far so good
counter <= 0;
elsif clk'event and clk = '1' then -- Rising edge, we got an asynchronous flip-flop?
counter <= counter + 1;
elsif counter = 10 then -- What is this!?! not an asynchronous reset, not a synchronous reset, not a clock. How does this translate to hardware?
counter <= 0;
end if;
end process;
I'm not sure if this would work in hardware, but I can't quickly figure out how it would be implemented, what you want is this:
process(rst, clk)
begin
if rst = '1' then -- Asynchronous reset
counter <= 0;
elsif clk'event and clk = '1' then
if counter = 9 then -- Synchronous reset
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
I leave the "when-else" statements for purely combinational code, or at most to the single line reg <= value when rising_edge(clk).
Related
I had a problem with synthesizing my code with using ISE. Please check the code and give me a suggestion how to modify it with need of a specific condition. My problem is only with the STAYCOUNT entity of a counter. Note that clk is feeding by another circuit and staycount is also feeding by another circuits.
at the initialization step, STAYCOUNT = 0, and if Reset = 0 , and the clk = 1 then count=count+1, and give an output DOUT = COUNT.
if reset = 1 then count = count - count.
then the next circuit process the output of DOUT, and it will either stop feeding the counter or feeding it (staycount = 1) in a specific condition.
whenever staycount = 1.
if clk = 1 then
while staycount = 1 loop
count = count + 1
DOUT <= count
end loop
end if
there are 2 problems: 1. at the initialization step only if staycount = 0 and clk= 1 it should only process count=count+ 1 for only 1 time and give an output DOUT.
After DOUT send a signal to another circuit, this circuit has 2 output either staycount which is going to be equal to 1 or proceed to for another output.
2. suppose that the other circuit give an output staycount = 1, it should feed the counter, and the counter again will check if the clk= 1 and the staycount= 1 to make count=count + 1 and give another output DOUT = COUNT.
please check my code for the counter. However, it missed the statement of problem#1, and succeeded in problem# 2, but with error Xilinx ISE "Non-static loop limit exceeded".
entity counter is
generic(n: natural :=4);
port( CLK: in std_logic;
Reset : in std_logic;
staycount: in std_logic;
DOUT : out std_logic_vector(n-1 downto 0) );
end counter;
architecture behavior of counter is
begin
process(CLK,CLK,Reset,staycount,COUNT) -- behavior describe the counter
variable COUNT:std_logic_vector(n-1 downto 0);
begin
if Reset = '1' then
COUNT := COUNT - COUNT;
elsif (CLK='1' and CLK'event) then
while (staycount = '1') loop
COUNT := COUNT + 1;
DOUT <= COUNT after 50 ns;
end loop;
else DOUT <= COUNT;
end if;
end process;
end behavior;
Make count a register
It looks like you are using count to keep the state of your design. It is neater, and often easier to debug, to make it a signal - which becomes a register if you assign it on clock edges.
Declare count as a signal in the architecture instead of as a variable, and assign it its next value at every clock edge. I also recommend resetting, in the process, to zeros instead of subtracting by itself - otherwise you may end up with propagating uninitialized values in your implementation.
if reset = '1' then
count <= (others => '0');
elsif (CLK='1' and CLK'event) then
count <= count_n;
end if;
Assign the count_n signal concurrently, being mindful of that you always want to increment it at least once:
count_n <= (n-1 downto 1 => '0') & '1' when count = 0 else
count when staycount = '0' else
count + 1;
Now also assign your output concurrently based on the count signal, and note that you can limit your sensitivity list to only clk and reset.
The following code is for a very simple program in VHDL.
entity ent is
port(
clk: in std_logic;
out_value: out std_logic;
);
end entity ent;
architecture ent_arch of ent is
signal counter: std_logic_vector(3 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
counter <= counter + 1;
if counter = 10 then
counter <= (others => '0') ;
end if;
end if;
end process;
end ent_arch;
Imagine counter = 9 and we enter in the if statement (if rising_edge(clk)). The first statement counter <= counter + 1 will assign 10 to counter. My question is "Is the if statetement (if counter = 10) evaluted as true in this entrance or in the next entrance of the process?". In other words "For this comparison in this entrance of the process, is counter = 10 due to the previous statement?"
Thanks a lot for any answer!
Signal assignments are always delayed. You didn't specified a delay explicitly using the after keyword, thus the assignment is delayed for one delta cycle (same as after 0 fs). That means, that the value of the expression on the right side of this statement:
counter <= counter + 1;
will be assigned to counter at the beginning of the next simulation cycle.
But, all remaining statements in your process, are executed in the current simulation cycle. Thus, this read of the counter value,
if counter = 10 then
will still use the old value, so that, the counter will be reseted when it is already 10 at the rising clock edge. The counter counts from 0 to 10 inclusive.
The delay of at least one delta cycle, easily allows to swap the content of registers:
-- within declarative part of architecture
signal reg_a, reg_b : std_logic;
-- within architecture body
process(clock)
begin
if rising_edge(clock) then
reg_a <= reg_b;
reg_b <= reg_a; -- assign old value of reg_a !
end if;
end process;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
entity counter is
port(CLK, CLR : in std_logic;
output : inout std_logic_vector(3 downto 0));
end counter;
architecture archi of counter is
signal tmp: std_logic_vector(3 downto 0);
begin
process (CLK, CLR)
variable i: integer:=0;
begin
if (CLR='1') then
tmp <= "0000";
elsif (clk = '1') then
for i in 0 to 6 loop
tmp <= tmp + 1;
end loop;
end if;
to count upto 7 i have done for i in 0 to 10. it is not showing any error but it counts from 0000 to 1111
end process;
output <= tmp;
end architecture;
could you please suggest how to do it....sorry for wrong grammar in english
Needs to operate off one clock edge
Because your counter port has clk in it, we can assume you want the counter to count synchronous to the clock.
You're operating off of both clock edges
elsif (clk = '1') then
should be something like
elsif clk'event and clk = '1' then
or
elsif rising_edge(clk) then
These examples use the rising edge of clk. You can't synthesize something that uses both clock edges under the IEEE-1076.6 IEEE Standard for VHDL Register
Transfer Level (RTL) Synthesis. It's not a recognized clocking method.
Making a modulo 10 counter
Under the assumption you want the counter to go from 0 to 9 and rollover this
for i in 0 to 6 loop
tmp <= tmp + 1;
end loop;
Should be something like
if tmp = "1001" then # binary 9
tmp <= (others => '0'); # equivalent to "0000"
else
tmp <= tmp + 1;
end if;
And this emulates a synchronous load that takes priority over increment driven by an external 'state' recognizer. With an asynchronous clear it would emulate an 74163 4 bit counter with an external 4 input gate recognizing "1001" and producing a synchronous parallel load signal loading "0000".
What's wrong with the loop statement
The loop process as shown would result in a single increment and resulting counter rollover at "1111" like you describe. You could remove the for ... loop and end loop; statements and it would behave identically. There's only one schedule future update for a signal for each driver, and a process only has one driver for each signal it assigns. All the loop iterations occur at the same clk event. tmp won't get updated until the next simulation cycle (after the loop is completed) and it's assignment is identical in all loop iterations, the expression tmp + 1. The last loop iterated assignment would be the one that actually occurs and the value it assigns would be identical.
Using a loop statement isn't necessary when counter is state driven (state ≃ tmp). The additional state represented by i isn't needed.
entity mod10 is
Port ( d : out std_logic_vector(3 downto 0);
clr: in std_logic;
clk : in std_logic);
end mod10;
architecture Behavioral of mod10 is
begin
process(clk)
variable temp:std_logic_vector(3 downto 0);
begin
if(clr='1') then temp:="0000";
elsif(rising_edge(clk)) then
temp:=temp+1;
if(temp="1010") then temp:="0000";
end if;
end if;
d<=temp;
end process;
end Behavioral;
I am trying to design a synchronous state machine with one input X and one output Z
z is 1 only if x has no. of 1's mod 3=0
and even no. of 0's
anyways i prepared my state diagram
i tried to test bench the code on xillinix and print the signals to trace it
but its not jumping from state to state correctly as written in the code
any help appreciated
here is the output in the link thanks
http://pastebin.com/14e5ZkX4
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity machine is
Port ( X : in STD_LOGIC;
clk : in STD_LOGIC;
Z : out STD_LOGIC);
end machine;
architecture Behavioral of machine is
signal state,nextstate : integer range 0 to 5 := 0;
signal flag : integer range 0 to 5 := 0;
begin
--state 0 (even and mod3=0)
--state 1 (odd and mod3=0)
--state 2 (even and mod3=1)
--state 3 (odd and mod3=1)
--state 4 (even and mod3=2)
--state 5 (odd and mod3=2)
sequence:process(CLK)
begin
if rising_edge(CLK) then
report "prevstate"& integer'image(state);
report "x" & STD_LOGIC'image(X);
if X='0' then
case state is
when 0=>
nextstate<= 1;
when 1=>
nextstate<= 0;
when 2=>
nextstate<= 3;
when 3=>
nextstate<= 2;
when 4=>
nextstate<= 5;
when 5=>
nextstate<= 4;
end case;
--if x=1
else
case state is
when 0=>
flag<= 1;
nextstate<= 2;
when 1=>
nextstate<= 3;
when 2=>
nextstate<= 4;
when 3=>
nextstate<= 5;
when 4=>
nextstate<= 0;
when 5=>
nextstate<= 1;
end case;
end if;
-- report "flag"& integer'image(flag);
report "next state"& integer'image(nextstate);
state<=nextstate;
if state=1 then
z<='1';
else
z<='0';
end if;
end if;
end process;
end Behavioral;
Seems like a weird way to achieve what you want... very complicated and combines two separate tasks into one, making it very difficult to check (by eye) that everything is as it should be. I'm in favour of describing the solution as you described the problem.
Keep track of the two bits of information separately. Some sample code below, which is not complete, you'll have to combine it into a clocked process and ensure the reset is done.
Have an 'even' flag, and each time X is '0', toggle it. Make sure to reset it to zero.
if x = '1' then
even := not even;
end if;
Also have a counter and each time X is a '1', increment it. If it gets to 3, reset it to zero. And make sure it starts from zero after reset!
if x = '1' then
counter := counter + 1;
if counter = 3 then
counter := 0;
end if;
end if;
Then take the two and combine them to produce the output:
z <= '0';
if counter = 0 and even = '1' then
z <= '1';
end if;
Well, I'm new to VHDL, but I think there is one big problem.
You try to use standard sequential-'Programming'-patterns to describe hardware!
When describing hardware, you have to keep in mind, that hardware is concurrent.
Your FSM won't have the expected behavior, because you did't keep that in mind.
For example the nextstate calculation is done in a clocked process, which is okay,
but then there should be a concurrent signal assignment (outside of the process) for the state-signal.
The new values for nextstate-signals won't be available in the same process-cycle.
They will be assigned after the process is done. (Warning: It is true for signals only,
variables have some different behavior!)
I think a good VHDL book will teach you the basics...
I have this signal that should be zero until another signal Start = 0. How can I accomplish this? Here is the relevant code:
din<=0;
wait until falling_edge(start);
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
end if;
if (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
wait;
I thought I could just make din = 0 until the falling edge of start but it stops at the rising edge of start. I want to start reading the din values when start =0. Before that din = 0.
Here is a pic:
EDIT: Actually I got it to start at the correct signal values but the dout value always has an intermediate value that isn't necessary. In this case its 78450. I know this has to do with the testbench code but I can't get it to just calculate the correct value at the correct time. What changes can be made to the code below to get rid of the intermediate value?
din<=0;
for i in 0 to 63 loop
wait until clk = '1' and clk'event;
if i = 0 then
Start <= '1','0' after clk_period;
elsif (i < 24) then
din <= 255;
elsif (i > 40) then
din <= 255;
else
din <= 0;
end if;
end loop;
First of all I assume (and hope) you are writing a testbench. If not, you should avoid using wait statements, as these have very limited support in synthesis tools.
Even in a testbench, it is best to use time-based wait or after statements only to generate the clock, and make all other signals dependent on an event (e.g. rising_edge(clk)). This avoids the problem of having multiple signals changing during delta cycle 0 along with the clock.
Consider the following code for a typical register:
process(clk) begin
if(rising_edge(clk)) then
a <= b;
end if;
end process;
and assume that clk and b are generated in a testbench as follows:
clk <= not clock after 1 ns;
process begin
b <= '1', '0' after 10 ns;
wait;
end process;
At time 0 delta 0, clk changes to '1' and b would change to '1'.
At time 0 delta 1, the register process would run since clk changed, and a would change to '1'.
No further sensitivity exists, so time would update to the next event at 1 ns.
At time 1 delta 0, clk changes to '0'.
At time 1 delta 1, the register process is run since clk changed, but nothing happens because rising_edge(clk) is false.
The above repeats for time 2-9 ns.
At time 10 delta 0, clk changes to '1' and b changes to '0'. Note that clk and b change in the same delta cycle.
At time 10 delta 1, the register process runs and a changes to '0'! As far as the result is concerned, this means that b changed before the rising clock edge!
Even if this behavior is understandable in this simple system, it can lead to some incredibly difficult to find simulation bugs. It is therefore better to base all signals off of the appropriate clock.
process begin
-- Initialize b to 1.
b <= '1';
-- Wait for 5 cycles.
for i in 1 to 5 loop
wait for rising_edge(clk);
end loop;
-- Set b to 0.
b <= '0';
-- Done.
wait;
end process;
This avoids unexpected behavior, since all signals will change at least one delta cycle after the associated clock, meaning causality is maintained throughout all of your processes.
I have this signal that should be zero until another signal Start = 0. How can I accomplish this?
Maybe you can use a handshake signal and put it in the sensitive list of the process. It will behave like a reset signal.
process (handshake_s, ...)
begin
if (handshake_s = '1') then -- failing edge of start
din <= 0;
else
-- do something
end if;
end process;
Use another process to update handshake_s.
process (start, ...)
begin
if failing_edge(start) then
handshake_s <= '1', '0' after 10 ns; -- produce a pulse
end if;
-- do something
end process;
Would you mind post all your code here so that we could understand the waveform better?
Testbench or RTL code?
For a testbench, your coding style is mostly ok, however, your signal Start has a problem and will never be '1' during a rising edge of clock. It goes to '1' just after the rising edge of clock and will return to '0' either simultaneously with clock or 1 delta cycle before clock (depending on your clock setup). Either way, anything running on rising_edge clock, such as your design, will not see it as a '1'.
A simple way to avoid this is to use nominal delays (25% of tperiod_Clk) on all of your testbench outputs that go to the DUT (Device Under Test). The pattern for a pulse is as follows.
wait until clk = '1' ; -- I recommend using rising_edge(Clk) for readability
Start <= '1' after tpd, '0' after tpd + tperiod_clk ;
Alternately, you can avoid this issue by not using waveform assignments. Such as the following. In this case, you don't need the tpd, however, if it really is a testbench, I recommend using it.
wait until clk = '1' ;
if i = 0 then
Start <= '1' after tpd ;
else
Start <= '0' after tpd ;
end if ;
For RTL code, you need to explore a different approach. Very briefly one way to approach it is as follows. Note do not use any delays, waveform assignments, or loops.
-- Counter to count from 0 to 63. Use "+ 1". Use "mod 64" if using type integer.
-- Start logic = decoder (can be coded separately)
-- Din Logic = decoder (can be coded separately)