-
-
Notifications
You must be signed in to change notification settings - Fork 310
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
take over cdc rework branch from andreasWallner #1306
Conversation
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.
Really cool that you are picking this up^^
I didn't go too much into detail on the code, but I think most of it looks good from a scala POV.
W.r.t. your TODO list: I think the only component really missing is a "safe" version of BufferCC (that buffers the input by default, maybe with a parameter to switch it off, preventing states from comb propagation to be latched to the other CD) - leaving BufferCC as a building block for CDC stuff and sync for external inputs.
W.r.t. #1299: there is a solution to that posted in that Issue?
PS: I don't think we need to go through e.g. implementing this for all tool vendors for this initial PR - only to keep in mind that they also exist ;-)
@@ -126,6 +126,17 @@ object ImplicitArea{ | |||
class ClockingArea(val clockDomain: ClockDomain) extends Area with PostInitCallback { | |||
val ctx = ClockDomainStack.set(clockDomain) | |||
|
|||
/* |
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 think that's not an approach that will work: a path can be placed in an area connecting FFs that are both outside of that area, where a tag applied by this code would be very misleading. (and I'd say a path doesn't have a CD, only FFs do)
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.
Agreed. I'm thinking that maybe it is possible to automatically derive the actual clockdomain (instead of relying on Component.clockDomain
, which is in a lot of cases not the correct domain) from connection relationships? Given that we can specify clock domain for input and output ports, we should be able to propagate this information along the path...
|
||
io.dataOut := buffers.last | ||
|
||
addAttribute("keep_hierarchy", "TRUE") |
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.
in the long run I think we might need something here that generates depending on the toolchain (dont_touch
is for vivado, I think yosys uses keep
, synplify syn_keep
(?), altera preserve
(?))
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 think we only need a keep_hierarchy
here, since what I'm trying to do is prevent flattening to get a predictable port name. I'm not sure if the other tools have the same semantics.
@@ -97,7 +102,7 @@ class PulseCCByToggle(clockIn: ClockDomain, clockOut: ClockDomain, withOutputBuf | |||
|
|||
val finalOutputClock = clockOut.withOptionalBufferedResetFrom(withOutputBufferedReset)(clockIn) | |||
val outArea = finalOutputClock on new Area { | |||
val target = BufferCC(inArea.target, False) | |||
val target = BufferCC(inArea.target, False, inputAttributes = List(crossClockFalsePath)) |
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 think I'd personally also use a max_delay constraint here and not remove all constraints on the path - but I know that's an often discussed topic...
val hit = RegNext(target).addTag(noInit) | ||
|
||
val flow = cloneOf(io.input) | ||
flow.valid := (target =/= hit) | ||
flow.payload := inputArea.data | ||
// FIXME: general solution such that clock domain propagates during assign? | ||
flow.payload.addTag(ClockDomainTag(inputClock)) := inputArea.data |
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.
in which case did it not work to search for the original driving circuit, we should be able to find inputArea.data
?
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.
We can find the driving circuit no problem, but we cannot determine the clock domain of the driver. As far as I know it's impossible to find the actual clock domain of a FF with the current API (using .clockDomain
does not work since that is the default clock domain of the containing component).
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'll have a look, should be able to find some more time tomorrow.
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've had a look at https://github.com/SpinalHDL/SpinalHDL/blob/dev/core/src/main/scala/spinal/core/BaseType.scala#L62 and that should work: it gets initialized with the current CD (not default CD) at creation time, but all ways to place a register in a specific CD will modify that (via the CD stack).
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.
Btw. If you want to print the AST I have somewhat unfinished but often helpful tool here: https://github.com/andreasWallner/spinalStuff/blob/master/src/main/scala/andreasWallner/Utils.scala#L100
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'm holding on fixing this--you mentioned that FlowCCByToggle
is not a proper CDCC since it does not involve handshaking.
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.
ah, ok - if this was the only case were you encountered that problem that's one less thing to worry about.
bufferDepth = bufferDepth) | ||
init = if(solvedOutputPolarity == HIGH) True else False, | ||
bufferDepth = bufferDepth, | ||
allBufAttributes = falsePathAttrs) |
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.
we normally have max_delay constraints as well on these, but I could not find any official docs on that (and I guess the async_reg attribute should take care of that anyways, at least for the xilinx case?)
only think that I could find was: https://support.xilinx.com/s/question/0D52E00006hpdDoSAI/ucf-constraints-for-reset-synchronizer?language=en_US - hardly authoritative
Agreed--should we also deprecate any direct invocations of BufferCC? Since that's rarely what the user actually wants...
IMO @Dolu1990 mentioned a possible native API to mark clock domains automatically, so that no manual
Yeah, I'll do a bit of refactoring to decouple the Xilinx-specific bits; other contributors can fill in the rest ^^ |
@andreasWallner I made a bunch of small fixes to address most of the issues. Please take another look ^^ |
For two of the points I'll have another look, otherwise this looks quite cool. Have you tried whether the resulting constraint file can be used for IP blocks (so in case the generated spinal top is not the real top) Regarding your last questions: Ad API: I read it as "we could add some API to make assigning the CD to BB I/Os easier" - but well have to wait for him to clarify (we could add a flag to mapClockDomain maybe?) One other thing: if we skip the implementation of trustSpinalTimings for now(which is totally fine) we should just revive it for now |
Yes! This is why I generated the OOC clock constraints, since I'm using them in the IP packager. The IP-XACT flow automatically scopes the constraints so there's no need to do
What's |
great - didn't want to put any
The parameter was initially intended for getting clock domain information (mainly freq) from the CD directly in spinal (a CD can know it's own frequency), instead of tracing in the design in the TCL code. Sorry for the delay with the other stuff, had a bit of chaos around me lately - getting back to it. |
Great and don't worry! I think this is getting on the right track; it should be ready for review once you get to take a look at the existing CDC stuff e.g. those
And then we can deprecate and gut out the existing |
Some additional info: W.r.t. renaming: As it stands I don't see a good enough reason to rename all synchronization primitives. Thanks for investing the time here^^ |
Wait, I think github closed this automatically since I force-pushed |
Further work on #1109. This is still currently a draft, since I'm not entirely sure if the resulting constraints work in hardware yet; but seems like Vivado is picking them up (they get listed in
report_timing_exceptions
and STA does not fail on false paths).Some notable changes from @andreasWallner's branch:
crossClockFalsePathSource
tag to handle cases whereBufferCC
is used for generating synchronous reset, e.g.:SpinalHDL/lib/src/main/scala/spinal/lib/CrossClock.scala
Lines 124 to 137 in 83efd66
get_*
queries to reliably find signal in netlistConstraintWriter
private and addedwriteConstraints
toSpinalReport
, such that we have all signal namesMore work needed:
set_max_delay
: I had to addClockDomainTag
manually in some places to find the correct source and destination clocks*ByToggle
,StreamFifoCC
, and more)XPM_CDC_*
@andreasWallner @Dolu1990 please take a look ^^
Closes #1109