You've already got answers with the solution ("use non-blocking assignments"), but here's an attempt at why you need to do that.
Both of your always
statements have the same event, so they could run in any order. What seems to be happening is that the first one is running first. When the line...
done_buf_1 = done;
... is hit, it will block until the assignment is complete (it's a "blocking" assignment). Therefore done_buf_1 takes the new value immediately. This differs from the non-blocking version...
done_buf_1 <= done;
... which says 'give done_buf_1 the value of done (which I'll evaluate now) at the end of the time slice'.
Now we move on, and done_buf_2 is assigned.
done_buf_2 = done_buf_1;
Now, if done_buf_1
was updated with a blocking assignment it already has the current value of done
, and you'll see both signal rise at the same time. If it was a non-blocking assignment then done_buf_1
still has the previous value of done
, as it won't be updated until the end of the time-slice, the result being a 2 cycle delay for done_buf_2
.
There's also another problem though. Remember that I said that the always statements could be run in either order because the events were the same? Well if the second one was executed first the code would appear to work as intended (db2 = db1; db1 = done;
No problem). So it's worth knowing that using blocking assignments like this gives erratic results especially between tools. That can lead to some subtle bugs.