Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
13 years ago

Trying to make sense of this always block

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

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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).
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- 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...
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

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