synchronous state machine VHDL - vhdl

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...

Related

Multiplier via Repeated Addition

I need to create a 4 bit multiplier as a part of a 4-bit ALU in VHDL code, however the requirement is that we have to use repeated addition, meaning if A is one of the four bit number and B is the other 4 bit number, we would have to add A + A + A..., B number of times. I understand this requires either a for loop or a while loop while also having a temp variable to store the values, but my code just doesn't seem to be working and I just don't really understand how the functionality of it would work.
PR and T are temporary buffer standard logic vectors and A and B are the two input 4 bit numbers and C and D are the output values, but the loop just doesn't seem to work. I don't understand how to loop it so it keeps adding the A bit B number of times and thus do the multiplication of A * B.
WHEN "010" =>
PR <= "00000000";
T <= "0000";
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
C <= PR(3 downto 0);
D <= PR(7 downto 4);
This will never work, because when a line with a signal assignment (<=) like this one:
PR <= PR + A;
is executed, the target of the signal assignment (PR in this case) is not updated immediately; instead an event (a future change) is scheduled. When is this event (change) actioned? When all processes have suspended (reached wait statements or end process statements).
So, your loop:
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
just schedules more and more events on PR and T, but these events never get actioned because the process is still executing. There is more information here.
So, what's the solution to your problem? Well, it depends what hardware you are trying to achieve. Are you trying to achieve a block of combinational logic? Or sequential? (where the multiply takes multiple clock cycles)
I advise you to try not to think in terms of "temporary variables", "for loops" and "while loops". These are software constructions that can be useful, but ultimately you are designing a piece of hardware. You need to try to think about what physical pieces of hardware can be connected together to achieve your design, then how you might describe them using VHDL. This is difficult at first.
You should provide more information about what exactly you want to achieve (and on what kind of hardware) to increase the probability of getting a good answer.
You don't mention whether your multiplier needs to operate on signed or unsigned inputs. Let's assume signed, because that's a bit harder.
As has been noted, this whole exercise makes little sense if implemented combinationally, so let's assume you want a clocked (sequential) implementation.
You also don't mention how often you expect new inputs to arrive. This makes a big difference in the implementation. I don't think either one is necessarily more difficult to write than the other, but if you expect frequent inputs (e.g. every clock cycle), then you need a pipelined implementation (which uses more hardware). If you expect infrequent inputs (e.g. every 16 or more clock cycles) then a cheaper serial implementation should be used.
Let's assume you want a serial implementation, then I would start somewhere along these lines:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity loopy_mult is
generic(
g_a_bits : positive := 4;
g_b_bits : positive := 4
);
port(
clk : in std_logic;
srst : in std_logic;
-- Input
in_valid : in std_logic;
in_a : in signed(g_a_bits-1 downto 0);
in_b : in signed(g_b_bits-1 downto 0);
-- Output
out_valid : out std_logic;
out_ab : out signed(g_a_bits+g_b_bits-1 downto 0)
);
end loopy_mult;
architecture rtl of loopy_mult is
signal a : signed(g_a_bits-1 downto 0);
signal b_sign : std_logic;
signal countdown : unsigned(g_b_bits-1 downto 0);
signal sum : signed(g_a_bits+g_b_bits-1 downto 0);
begin
mult_proc : process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
out_valid <= '0';
countdown <= (others => '0');
else
if in_valid = '1' then -- (Initialize)
-- Record the value of A and sign of B for later
a <= in_a;
b_sign <= in_b(g_b_bits-1);
-- Initialize countdown
if in_b(g_b_bits-1) = '0' then
-- Input B is positive
countdown <= unsigned(in_b);
else
-- Input B is negative
countdown <= unsigned(-in_b);
end if;
-- Initialize sum
sum <= (others => '0');
-- Set the output valid flag if we're already finished (B=0)
if in_b = 0 then
out_valid <= '1';
else
out_valid <= '0';
end if;
elsif countdown > 0 then -- (Loop)
-- Let's assume the target is an FPGA with efficient add/sub
if b_sign = '0' then
sum <= sum + a;
else
sum <= sum - a;
end if;
-- Set the output valid flag when we get to the last loop
if countdown = 1 then
out_valid <= '1';
else
out_valid <= '0';
end if;
-- Decrement countdown
countdown <= countdown - 1;
else
-- (Idle)
out_valid <= '0';
end if;
end if;
end if;
end process mult_proc;
-- Output
out_ab <= sum;
end rtl;
This is not immensely efficient, but is intended to be relatively easy to read and understand. There are many, many improvements you could make depending on your requirements.

Cannot create latch and counter with 2 clock signals in VHDL

I am completely new to programming CPLDs and I want to program a latch + counter in Xilinx ISE Project Navigator using VHDL language. This is how it must work and it MUST be only this way: this kind of device gets 2 clock signals. When one of them gets from HIGH to LOW state, data input bits get transferred to outputs and they get latched. When the 2nd clock gets from LOW to HIGH state, the output bits get incremented by 1. Unfortunately my code doesn't want to work....
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity counter8bit is
port(CLKDA, CLKLD : in std_logic;
D : in std_logic_vector(7 downto 0);
Q : out std_logic_vector(7 downto 0));
end counter8bit;
architecture archi of counter8bit is
signal tmp: std_logic_vector(7 downto 0);
begin
process (CLKDA, CLKLD, D)
begin
if (CLKLD'event and CLKLD='0') then
tmp <= D;
elsif (CLKDA'event and CLKDA='1') then
tmp <= tmp + 1;
end if;
end process;
Q <= tmp;
end archi;
Is there any other way around to achieve this?? Please for replies. Any kind of help/suggestions will be strongly appreciated. Many thanks in advance!!
Based on the added comments on what the counter is for, I came up with the following idea. Whether it would work in reality is hard to decide, because I would need a proper timing diagram for the EPROM interface. Importantly, there could be clock domain crossing issues depending on what restrictions there are on how the two clock signals are asserted; if there can be a falling edge of CLKLD close to a rising edge of CLKDA, the design may not work reliably.
signal new_start_address : std_logic := '0';
signal start_address : std_logic_vector(D'range) := (others => '0');
...
process (CLKLD, CLKDA)
begin
if (CLKDA = '1') then
new_start_address <= '0';
elsif (falling_edge(CLKLD)) then
start_address <= D;
new_start_address <= '1';
end if;
end process;
process (CLKDA)
begin
if (rising_edge(CLKDA)) then
if (new_start_address = '1') then
tmp <= start_address;
else
tmp <= tmp + 1;
end if;
end if;
end process;
I'm not completely clear on the interface, but it could be that the line tmp <= start_address; should become tmp <= start_address + 1;
You may also need to replace your assignment of Q with:
Q <= start_address when new_start_address = '1' else tmp;
Again, it's hard to know for sure without a timing diagram.

What's wrong with this VHDL code - BCD Counter?

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).

How to change signal value instatntly?

if(rising_edge(clk)) then
count := count + 1;
if count = 3 then
enable <= 1;
elsif count = 6 then
enable <= 0;
count := 0;
end if;
end if;
if enable = 0 then
a0i <= a_0;
boi <= b_0;
end if;
if enable = 1 then
a0i <= a_1;
boi <= b_1;
end if;
All are signals except the count. Value of a0i and boi should response as soon as enable becomes either 0 or 1. I tried using the variable. but it can not allow me to use out side the process.
I am getting the o/p as this. How ever I want to change the input as soon as enable signal change.
Put the last two if conditions in another process
Process(enable, a_0, b_0, a_1, b_1)
begin
If(enable = '0')THEN
a0i <= ...
....
ELSE
.....
END IF;
END PROCESS;
This process is sensitive to the enable signal so anytime there is a change in enable, independent of the clock, the statements will take effect immediately (asynchronously)
Solution 1: use 2 processes as blueprint mentioned.
Solution 2: use an internal variable.
process(clk)
variable count : natural range of 0 to 6 := 0;
variable enable_i : std_logic := '0';
begin
if(rising_edge(clk)) then
count := count + 1;
if count = 3 then
enable_i := '1';
elsif count = 6 then
enable_i := '0';
count := 0;
end if;
end if;
if enable = '0' then
a0i <= a_0;
boi <= b_0;
else
a0i <= a_1;
boi <= b_1;
end if;
enable <= enable_i;
end process;
Some hints:
Maybee, the type boolean is more suitable for your signal/variable enable_i
If enable_i is only used inside the process, then you can remove the conversion to enable
including the data path and multiplexers in a state machine (I assume this is a part of it) is not a good design choice.
You could also take these two equation below out from your process.
process(...)
[...]
if enable = 0 then
a0i <= a_0;
boi <= b_0;
end if;
if enable = 1 then
a0i <= a_1;
boi <= b_1;
end if;
end process
Then you cannot use the IF statement anymore, but you can use the WHEN statement :
a0i <= a_0 when enable = '0' else a_1;
boi <= b_0 when enable = '0' else b_1;
Note that in this case, the multiplexer will be after the latch. This could be important if you have timing issues on these signals.
From your simulation waveform, it looks to me like you failed to include enable, a_0, b_0, a_1, and b_1 in your sensitivity list, but I can't be sure because you didn't post the complete example. Because you test the values of the 5 mentioned signals outside of the if rising_edge(clk), they need to be included. The values are only updated on the falling edge of clk because, presuming that clk is the only thing in your sensitivity list, that is the next time the process is evaluated.
It should be otherwise functional as written, although you could use an else instead of a separate test for enable = 0 for a slight readability improvement. Synthesis usually ignores the sensitivity list (it just makes simulation more efficient) so it should already work if you were to synthesize.

Make a signal wait until falling edge

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)

Resources