$display
and registers
#661
Replies: 6 comments 6 replies
-
looking at the RTL* it looks like for some reason register reads in
presumably there's a rationale (maybe not generating junk during reset? idk) but it looks like it's deliberate. *after changing the first rule predicate to |
Beta Was this translation helpful? Give feedback.
-
I think there are a couple things at play here: what BSC does when a rule
has no clock/reset; and how reset is implemented, in the code generation
for rules.
A rule has an associated clock domain and resets, which are determined by
the state that the rule touches. BSC collects the clocks and resets of all
the called methods and, for example, reports an error if clocks from
different domains are found. A rule that only contains $display has no
method calls, so it is a degenerate case without any clocks or resets. BSC
could have rejected the rule (and required the user to explicitly specify
the clock and resets), but the current behavior is to pick the default
clock of the module.
A principle of BSC's clock support was that the common case should be easy,
and that users who aren't writing multi-clock designs don't even
necessarily need to know that it exists (or how it works). This is why you
don't have to mention a clock or reset when writing a module, even though
it does have both by default. That may be why BSC silently picks the
default clock as the associated clock for a rule with only $display. I
tried to see if I could find an old document from when the current clock
support was added (in 2004 to 2006-ish, internally referred to as MCD),
describing the design choices, but I can't find much -- and it doesn't
discuss reset, probably because only enough was added to get started and it
was considered a later project to come back to and get right.
Rules must be associated with a clock, but they are not required to be
associated with a reset. A rule can have zero, one, or multiple resets --
and if there are multiple, BSC will warn that the user needs to be sure
that they know what they're doing (as we'll see). So in this case with
only $display, BSC has left the rule as associated with no reset, rather
than also assigning it the default reset (along with the default clock).
So this is maybe a case where the single-clock/reset user is being exposed
to the larger MCD/Reset capabilities, and maybe it would be better to pick
the default reset for them, but I'm not sure that's the right thing to do
either. At best, maybe there should be a warning about degenerate rules
(that can be silenced with a flag, or we can introduce syntax for
explicitly giving a clock/reset to a rule that doesn't touch state). [You
can also get a rule without a reset if it only uses state without a reset,
like "mkRegU"; it may even be worth warning users in that case (similar to
multi-reset), particularly if the rule calls system tasks or foreign
functions.]
I believe the idea with reset is that a rule should not execute if the
state it touches is in reset. One way this could be implemented is to have
the reset signal be part of the RDY of the methods. I believe it was
decided that this would introduce too much logic in the Verilog; instead,
it was decied that the rule logic would still construct the EN and input
signals as usual, but the submodule would just ignore the method call when
in reset. If you look at the Verilog "RegN" module, for example, the
register is always assigned the init value when reset, and only consults
the EN/D_IN when not in reset. [This is why BSC warns when a rule has
multiple resets: if some state is in reset and other state is not, part of
the action will execute without the rest, which is not correct for "atomic"
actions. This would not be a problem if the reset was part of the RDY, I
think.]
This choice to implement the reset by ignoring the EN input (rather than
including in the RDY output) means that we have to do something about the
system tasks (and foreign functions) that a rule calls. A rule that writes
a register will appear to not fire during reset of the register, because
the register won't update; but if the rule also has $display, the
implementation needs to disable that display. BSC does this by adding the
reset of the rule to the condition on the $display: the $display is already
conditional on WILL_FIRE of the rule that it appears in, but now its
WILL_FIRE && !RST. (Essentially implementing the reset-in-the-RDY
implementation, but only for tasks.) (If there are multiple resets, they
are all included in the condition. If a module has an internal reset that
is not exported, that's tricky, but you at least get a warning or error
that the module has a method on a reset that is not exported.)
In your example, "rule2" has a reset, because it touches state ("r") that
has a reset, and so the $display is guaraded (that is, the rule doesn't
appear to execute when its state is in reset). In contrast, "rule1" has no
reset, so it is free to execute on every clock cycle -- just because a
reset is being asserted on some other part of the system, doesn't mean this
rule needs to react to it. (And, of course, the rules execute on the edges
of CLK -- not because rules in a module are just always on the module's
clock, but because "rule2" uses state on that clock and is therefore
associated with it, and because "rule1" has no associated clock and was
therefore silently given the default clock of the module.)
As I said, just enough reset support was added to make MCD work when it was
added, with the intention of some day doing a proper think about reset
methodology and how to support it in BSC. I doubt that ever happened, so I
think we're still living with the initial good-enough support. So it's
possible that BSC could be doing a lot more to check that users are making
proper use of reset. If someone wanted to think on this and propose
something, that'd be welcome. (While BSC could do more checking, on the
other hand, that might require more explicit declarations from the user,
which would be contrary to wanting to keep the common case simple. So I
don't know if there are easy answers.)
One thing that this discussion makes me wonder about is designs that use
"mkReg" and "mkRegU": in a sense, that's mixing two different resets (RST
and no reset), and BSC doesn't warn (even though, when a rule writes to
both, some state will update while other state is in reset -- but at least,
this is a property of the register that a user knew when they declared
it). System tasks and foreign functions are like method calls with no
associated reset, so maybe there's some way to unify their handling.
FYI, here's some of the documents I could find on MCD, but mostly they
leave out any discussion of reset:
- Paper at MEMOCODE'08 on the design choice, "Reliable Design with
Multiple Clock Domains":
https://web.ece.ucsb.edu/its/bluespec/training/BSV/papers/Memocode06.pdf
- BSV training lecture on MCD:
https://github.com/BSVLang/Main/blob/master/Tutorials/BSV_Training/Reference/Lec12_Multiple_Clock_Domains.pdf
|
Beta Was this translation helpful? Give feedback.
-
Yeah, except I think in this case it's not the rule suddenly having a reset, it's the You can check this on a slight variant of your example:
This generates the RTL below:
You can see that the So I guess rules are not guaranteed to be atomic under reset if they have a |
Beta Was this translation helpful? Give feedback.
-
No, it's the rule. I'm having trouble relating what you say in the text to the code that you quoted. For example, you said this:
But the display that's in the same rule as the assignment to
If you want to make a code example to test the hypothesis about whether the guard on a display is only for uses by the display or if the guard includes resets from elsewhere in the rule, then you'd need to add, to the rule with "Hello World", an action that actually carries a reset -- you added a use of
That doesn't follow. But, as I mentioned in my comment, using |
Beta Was this translation helpful? Give feedback.
-
Sorry I mistyped the example. It should be:
Then if But what you get is the
and the update to
So it's seems that it's not the full rule that is guarded by reset? |
Beta Was this translation helpful? Give feedback.
-
I understand why there is no reset on the assignment to But I think the behaviour is inconsistent with the semantics as explained. You wrote that
so let's try that out. There are two ways to interpret "touches":
In any case, I think the practical issue is that the overall behaviour is unexpected: some I wonder if it wouldn't be be more reasonable™ to define behaviour based on
As I said I personally think it's worth thinking about the semantics of things like |
Beta Was this translation helpful? Give feedback.
-
Consider this simple BH program:
This has two rules, both of which should run on every clock cycle. Let's compile this and simulate it for two clock cycles:
This produces some counter-intuitive results:
rule1
produces two lines of output, butrule2
only produces one line of output. The only difference between the two rules is thatrule2
references a register value, butrule1
does not.If I look at the compiled Verilog output, I see this code:
Which suggests that this distinction is deliberate. Is there a reason why this happens?
Beta Was this translation helpful? Give feedback.
All reactions