-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
blocking assignment must be used for a clock divider #44
base: master
Are you sure you want to change the base?
Conversation
I tried to send the pull request of the fix on 957948e. |
VerilogCodingStyle.md
Outdated
@@ -1756,6 +1756,18 @@ an always block as occurring in a separate simulation event as the non-blocking | |||
assignment. This process makes some signals jump registers, potentially leading | |||
to total protonic reversal. That's bad. | |||
|
|||
Exception: For a clock divider blocking assingment must be used not to case race condition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggesting:
Exception: for a clock divider, blocking assignment must be used to not cause race condition.
That said, I'm not agreeing with it yet, and we'll discuss some more internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I really think this needs different terminology: a race condition causes non-deterministic behaviour, depending on the whims of the simulator's scheduling. Your example has deterministic behaviour (I think), but not the behaviour you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sjgitty and @rswarbrick ,
Thank you for your comments.
How about this?
Exception: for a clock divider, blocking assignment must be used to have the behavior you want. See #44 for details.
I'm not sure if a link to this pull request is allowed. But it is too much to include explanation above in the Style Guide.
That said, I'm not agreeing with it yet, and we'll discuss some more internally.
Thank you.
I was pointed to this conversation by a colleague. My thinking about this is along these lines: The general rules (for flop-based designs) are: With these rules in place, I believe you should create all your clocks using blocking assigns. I believe this is what you're proposing, i.e. to add a style guide statement that all clocks should be generated using blocking assigns. I think that perhaps the wording needs to be clearer and the reason made explicit. |
@rich-ho, thank you for you comment.
Yes.
In either case we need an example code of clock divider for readers. |
I'm sorry I left this PR for a long time. I've push update, but something wrong.
I did "git rebase". Is it the cause? Sorry for my mess. |
e6d6776
to
c47686d
Compare
Ok, I think I've fixed the PR by removing the merge commits. @hirooih do you want to go through and fix the merge conflicts? |
Thanks. |
c47686d
to
6cce84e
Compare
Over the past four years, I have gained experience with git. Now I could make it a clean PR.
Don't ask me why non-blocking assignment is used in |
To be clear (since this seems to be accidental misdirection), the rule is about synthesizable design modules, and it will not be changed. Delay statements only apply to simulation models, which is what you investigated and provided guidance for. |
Signed-off-by: Hiroo HAYASHI <[email protected]>
6cce84e
to
d88b6c7
Compare
Synthesizable design module often includes clock dividers. But the following code does not work. // clock with nonblocking assignment
logic clk_div_nb;
always_ff @(posedge clk, negedge rst_n)
if (~rst_n)
clk_div_nb <= '0;
else
clk_div_nb <= ~clk_div_nb; We can solve this issue by using #delay only for this case. (The Plan C in my first comment) This PR proposes to use blocking assignment only for clock generation. // clock with blocking assignment
logic clk_div_b;
always_ff @(posedge clk, negedge rst_n)
if (~rst_n)
clk_div_b = '0;
else
clk_div_b = ~clk_div_b; The following timing chart using Wavedrom would be easier to understand the problem. I've added the following comments by reading your feedback. Thank you. // only for test bench code
...
// for both synthesizable and test bench code |
The discussion confused what's happening in the actual code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits.
@@ -1900,6 +1900,28 @@ separate combinational (`always_comb`) block. Ideally, sequential blocks should | |||
contain only a register instantiation, with perhaps a load enable or an | |||
increment. | |||
|
|||
***All clock signals should be generated using blocking assignment even |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a new section. It's currently written under Sequential Logic (Registers)
, but it is not about registers. Perhaps Sequential Logic (Clock Dividers)
or some such?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you.
On my first PR it was only for clock dividers. During the discussion on this PR @rich-ho suggested me applying this rule to clock generation in general.
... to add a style guide statement that all clocks should be generated using blocking assigns. I think that perhaps the wording needs to be clearer and the reason made explicit.
I agreed with him, too. But if we do that, we also need an example for clock generation other than clock divider, so I added it.
As you wrote this rule is not for the section "Sequential Logic (Registers)" now.
I have separated it into a section called “Generating Clock”.
This time I did not squash the commits so that the changes are visible.
How about this?
// only for test bench code | ||
logic clk; | ||
initial begin | ||
clk <= 1'b0; | ||
forever #5 clk = ~clk; // blocking assignment | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This portion of the code isn't really relevant for this section. Since this guidance is about how to construct the divider, we don't need to see how clk
is generated. I'd recommend removing it.
Edit: Or am I misunderstanding and you also want to show how to generate clock source stimulus in a testbench?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: Or am I misunderstanding and you also want to show how to generate clock source stimulus in a testbench?
No, I don't.
Signed-off-by: Hiroo HAYASHI <[email protected]>
Let me propose this again. It gets longer, but I hope this let you understand.
We have the following rule;
This rule does not work with a divided clock.
The following code demonstrates the issue.
q_nb_ng and q_b_ok are D-Flip-flops clocked by divided clocks. They capture the output value of d.
The following is the simulation result of the sample code above.
q_b_ok works as we expect, but q_nb_ok does not. For example at the timing on the yellow line they have to capture value 0b0010 as q_b_ok does.
The following shows how they works on the yellow line.
This is not the behavior expected. (cf. LRM 2017 Figure 4-1—Event scheduling regions)
Plan B: Use
#delay
for all FFs (when we have a divided clock)Many engineers are choosing this solution. But we know this degrades simulation performance.
Plan C: Use
#delay
for FFs clocked by divided clock and capture signals derived from FFs clocked by the original clock.This may be better performance than plan B, but very easy to cause bugs.
I should create a branch after fetching updated upstream. Sorry.