Skip to content
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

Closed
wants to merge 0 commits into from

Conversation

KireinaHoro
Copy link
Contributor

@KireinaHoro KireinaHoro commented Feb 8, 2024

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:

  • added crossClockFalsePathSource tag to handle cases where BufferCC is used for generating synchronous reset, e.g.:
    val samplerCD = clockDomain.copy(
    reset = input,
    config = clockDomain.config.copy(
    resetKind = ASYNC,
    resetActiveLevel = inputPolarity
    )
    )
    val solvedOutputPolarity = if(outputPolarity == null) clockDomain.config.resetActiveLevel else outputPolarity
    samplerCD(BufferCC(
    input = (if(solvedOutputPolarity == HIGH) False else True) ^ inputSync,
    init = (if(solvedOutputPolarity == HIGH) True else False),
    bufferDepth = bufferDepth)
    )
  • write OOC clock definitions for IP packager
  • refined get_* queries to reliably find signal in netlist
  • make ConstraintWriter private and added writeConstraints to SpinalReport, such that we have all signal names

More work needed:

  • better clock domain determination for set_max_delay: I had to add ClockDomainTag manually in some places to find the correct source and destination clocks
  • check if the constraints result in a working design
  • cover all existing CC gadgets (*ByToggle, StreamFifoCC, and more)
  • implement the goal from @andreasWallner to make CC requirements more explicit, maybe like the style of XPM_CDC_*
  • support for other EDA tool vendors (other than Xilinx; I have no experience on this one)
  • documentation on what to use for what situation

@andreasWallner @Dolu1990 please take a look ^^

Closes #1109

Copy link
Collaborator

@andreasWallner andreasWallner left a 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)

/*
Copy link
Collaborator

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)

Copy link
Contributor Author

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")
Copy link
Collaborator

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 (?))

Copy link
Contributor Author

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))
Copy link
Collaborator

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

lib/src/main/scala/spinal/lib/Flow.scala Outdated Show resolved Hide resolved
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
Copy link
Collaborator

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?

Copy link
Contributor Author

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

Copy link
Collaborator

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.

Copy link
Collaborator

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

Copy link
Collaborator

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

Copy link
Contributor Author

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.

Copy link
Collaborator

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.

lib/src/main/scala/spinal/lib/eda/ConstraintWriter.scala Outdated Show resolved Hide resolved
lib/src/main/scala/spinal/lib/eda/ConstraintWriter.scala Outdated Show resolved Hide resolved
lib/src/main/scala/spinal/lib/eda/ConstraintWriter.scala Outdated Show resolved Hide resolved
bufferDepth = bufferDepth)
init = if(solvedOutputPolarity == HIGH) True else False,
bufferDepth = bufferDepth,
allBufAttributes = falsePathAttrs)
Copy link
Collaborator

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

lib/src/main/scala/spinal/lib/CrossClock.scala Outdated Show resolved Hide resolved
@KireinaHoro
Copy link
Contributor Author

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.

Agreed--should we also deprecate any direct invocations of BufferCC? Since that's rarely what the user actually wants...

W.r.t. #1299: there is a solution to that posted in that Issue?

IMO @Dolu1990 mentioned a possible native API to mark clock domains automatically, so that no manual ClockDomainTags would be needed (if I understood his intentions correctly).

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 ;-)

Yeah, I'll do a bit of refactoring to decouple the Xilinx-specific bits; other contributors can fill in the rest ^^

@KireinaHoro
Copy link
Contributor Author

@andreasWallner I made a bunch of small fixes to address most of the issues. Please take another look ^^

@andreasWallner
Copy link
Collaborator

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:
I think we should not deprecate BufferCC. It'll still be the component to use when synchronizing an async signal coming from the outside. (And if we did we'd get warnings on the code that rightfully uses BufferCC). But we can mark it accordingly on the documentation.

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

@KireinaHoro
Copy link
Contributor Author

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)

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 -hier *compName/... all over the place. This does require the user to package the spinal top as an IP, if they're including it in another module; I'm not sure if we should also support the case without the IP packager. Even better, it would be nice if we can automatically generate the IP-XACT XML file, so that the user does not have to package the IP by hand.

One other thing: if we skip the implementation of trustSpinalTimings for now(which is totally fine) we should just revive it for now

What's trustSpinalTimings?

@andreasWallner
Copy link
Collaborator

andreasWallner commented Mar 4, 2024

he IP-XACT flow automatically scopes the constraints

great - didn't want to put any -hier stuff in anyways, have used loading a constraint file with a hierarchy a few times manually, but I didn't know that Vivado does it automatically when packaging the IP (though it makes sense, but I haven't done that in a long while...)

What's trustSpinalTimings?

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.
Had a typo there, revive should have been remove...

Sorry for the delay with the other stuff, had a bit of chaos around me lately - getting back to it.

@KireinaHoro
Copy link
Contributor Author

KireinaHoro commented Mar 7, 2024

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 *CCByToggle. Maybe also the renaming/wrapping BufferCC into the proper CDCC categories? Such as the following (modeled after the Xilinx XPM list)

  • ArraySingle
  • SyncReset
  • AsyncReset
  • Pulse
  • Handshake
  • Gray
  • Fifo

And then we can deprecate and gut out the existing StreamCCByToggle, StreamCCFifo, etc.

@andreasWallner
Copy link
Collaborator

Some additional info: FlowCCByToggle is not intended as a general synchronization primitive and is expected to work only if the source is (either in clock or datarate) is slower then the destination. We'll reflect that in the name.
Constraint-wise it should then work with max-delay/skew constraints + sync flags on the valid

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

@KireinaHoro
Copy link
Contributor Author

Wait, I think github closed this automatically since I force-pushed dev in my branch to be in sync with upstream. I'll do a new one in a PR branch and clean up a bit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CDC rework and constraint generation
2 participants