Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
21330 Discussions

Trying to make sense of this always block

Altera_Forum
Honored Contributor II
1,088 Views

Hi, 

 

So I wanted to take an input and decrement it in a combinational block.. here is the code I am talking about.. 

 

always @ (posedge clock or posedge reset) begin if (reset) begin t0_reg <= 0; t1_reg <= 20'd1; n <= i; end else begin t0_reg <= t0_next; t1_reg <= t1_next; n <= n_next; end end always @ (*) begin t0_next = t0_reg; t1_next = t1_reg; n_next = i; if(n == 0) t0_next = 0; else begin t1_next = t0_reg + t1_reg; t0_next = t1_reg; n_next = n - 1; end end 

 

here i is a 4 bit input.. This circuit is for a fibonacci series..  

 

When I made this I did not think this would work, because I thought at the end of the always @ * block the n_next signal would have been decremented by 1, but at the start of the same block it would again be assigned the value of i..  

 

but what really happens is i keeps decrementing till it reaches 0.. and after it reaches 0 it gets the original value of i again and keeps going forever like this.. 

 

isnt this block read from top to bottom.. why does it appear that it stays in the else block till it decrements n_next to 0? 

 

Thanks
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
389 Views

Your always @ (*) block will only update its outputs when the following signals change: t0_reg, t1_reg, i, or n. 

So what is happening is that n_next is getting decremented when the block updates, but then that block does not update again until one of the signals listed above changes. So the event will be that the "always @ (posedge clock or posedge reset)" block will be updated on the next clock. But in that block n is being assigned the value of n_next (which was decremented). So now that "n" has changed the always @ (*) block will update sequentially. So first, n_next gets assigned the value of "i" but that doesn't matter because the if statement is false so n_next gets the value of n-1. This continues with n=n_next then n_next=n-1 until n==0 is true then n_next gets to keep the value of i. 

 

Hope this helps.
0 Kudos
Altera_Forum
Honored Contributor II
389 Views

The behavior you mentioned is what I would expect... I think I never write combinational code in always statements like that. To me this would be much easier to understand .... 

 

assign t1_next = (n == 0)? 0 : (t0_reg + t1_reg); 

assign t0_next = (n == 0)? t0_reg : t1_reg; 

assign n_next = (n == 0)? n : n - 1; 

 

If you are not familar with the terinary operator this is what it means: 

 

assign signal = (conditional)? true statement : false statement; 

 

So above when n equals 0 the statement before the colon is used, otherwise the statement after the colon is used (2:1 mux). If you use something with more statements then I recommend using case statements instead to implement the mux since a casescade of terinary operators uses priority (unless that's what you want).
0 Kudos
Altera_Forum
Honored Contributor II
389 Views

Thanks for the helpful responses. 

 

 

--- Quote Start ---  

So first, n_next gets assigned the value of "i" but that doesn't matter because the if statement is false so n_next gets the value of n-1. 

--- Quote End ---  

 

 

However I did not understand this.. How does it not matter as the value is assigned before the if statement.. need some clarification here please. 

 

 

--- Quote Start ---  

The behavior you mentioned is what I would expect... I think I never write combinational code in always statements like that. To me this would be much easier to understand ... 

--- Quote End ---  

 

 

Im familiar with this but with these statements I get confused with nested if's.. 

 

Thanks
0 Kudos
Altera_Forum
Honored Contributor II
389 Views

 

--- Quote Start ---  

However I did not understand this.. How does it not matter as the value is assigned before the if statement.. need some clarification here please. 

 

--- Quote End ---  

 

 

The value i does get assigned to n_next, but immediately after that once the if statement resvolves n_next gets the value of n-1. So, effectively you never see the assignment of the value of i to n_next. By the time the clocked process triggers, n_next is equal to n-1, not i. The only time n_next will retain the value of i (instead of being re-assigned to n-1) when the process resolves is when the if statement is true (i.e. n==0). 

 

So, if the clocked process we call Process1 and the always@(*) we call Process2 

then follow through the logic of what happens... 

 

On reset Process1 n=i; --A change on 'n' triggers Process2 

Process2 n_next=i; -- n_next gets set to i at first 

Process2 n_next=n-1; --since 'n' is not equal to zero 

-- reset state ends 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; 

Process2 n_next=n-1; --since 'n' is not equal to zero 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; 

Process2 n_next=n-1; --since 'n' is not equal to zero 

--this continues until n_next==0 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; --since 'n' is now equal to zero 

then the whole thing starts over...
0 Kudos
Altera_Forum
Honored Contributor II
389 Views

 

--- Quote Start ---  

The value i does get assigned to n_next, but immediately after that once the if statement resvolves n_next gets the value of n-1. So, effectively you never see the assignment of the value of i to n_next. By the time the clocked process triggers, n_next is equal to n-1, not i. The only time n_next will retain the value of i (instead of being re-assigned to n-1) when the process resolves is when the if statement is true (i.e. n==0). 

 

So, if the clocked process we call Process1 and the always@(*) we call Process2 

then follow through the logic of what happens... 

 

On reset Process1 n=i; --A change on 'n' triggers Process2 

Process2 n_next=i; -- n_next gets set to i at first 

Process2 n_next=n-1; --since 'n' is not equal to zero 

-- reset state ends 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; 

Process2 n_next=n-1; --since 'n' is not equal to zero 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; 

Process2 n_next=n-1; --since 'n' is not equal to zero 

--this continues until n_next==0 

On clk Process1 n=n_next; --A change on 'n' triggers Process2 

Process2 n_next=i; --since 'n' is now equal to zero 

then the whole thing starts over... 

--- Quote End ---  

 

 

 

That was beautiful.. 

 

Many thanks for this detailed explanation.
0 Kudos
Reply