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

Constraint writer for Xilinx Vivado (reopened: CDC rework) #1369

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

KireinaHoro
Copy link
Contributor

@KireinaHoro KireinaHoro commented Mar 20, 2024

Redoing #1306. I think I accidentally closed this due to some branch dancing errors, now the PR head branch should be safe.

I also dropped from the last state of the PR stuff related to Flow: m2sPipe and FlowCCByToggle (cf. #1360), since these are not inherently safe CDC primitives.

@andreasWallner sorry to bother you again but can you review it (or just a brief look, since most of the stuff has been fixed already)? Thanks a lot!

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.

Looks quite good to me

@@ -810,6 +810,8 @@ object noLatchCheck extends SpinalTag
object noBackendCombMerge extends SpinalTag
object crossClockDomain extends SpinalTag{ override def moveToSyncNode = true }
object crossClockBuffer extends SpinalTag{ override def moveToSyncNode = true }
case class crossClockFalsePath(source: Option[BaseType] = None, destIsReset: Boolean = false) extends SpinalTag { override def allowMultipleInstance: Boolean = false }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's about (keep in mind i'm not skilled into this things):

case class FalsePath(source: Option[BaseType] = None, onData: Boolean = false, onReset: Boolean = false, onEnable: Boolean = false)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or should we have a sealed trait for the destination type instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh yes, that is right, like a enum, yes yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we build this with an enum and keep the current prohibition for multiple tags then we can' have a path were both data and clock get a false path constraint - I have to admit that I can't think of a use-case for that one ATM, but reset & clock does make some sense...
Not sure having separate booleans isn't the preferable solution here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked with

case class Test() extends Component {
  val io = new Bundle {
    val i = in port Bool()
    val o = out port Bool()
  }
  io.o := BufferCC(io.i, inputAttributes = List(crossClockFalsePath(destType=TimingEndpointType.RESET), crossClockFalsePath(destType=TimingEndpointType.CLOCK_EN)))
}

which gives the error

[error]  Conflicting tags added to the same item! crossClockFalsePath(None,RESET) ; crossClockFalsePath(None,CLOCK_EN)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh but what you're doing doesn't make sense: you're not actually using it to drive the clock enable/reset signal. If you look at this on the netlist level, clock enable (CE) and reset (PRE, etc.) are always separate pins and thus create separate paths; you can always add the attribute on the non-shared parts of the paths and not having to worry about tag conflict.
UPDATE: Ah I see the reasoning now. I think a better example is like this:

case class TestCC() extends Component {
  val io = new Bundle  {
    val i = in(Bool())
    val o = out(UInt(16 bits))
  }

  val cdWithEnRst = ClockDomain.internal(
    "cdWithEnRst",
    withClockEnable = true,
    config = ClockDomainConfig(
      resetKind = SYNC,
      resetActiveLevel = LOW,
    )
  )

  val inSync = BufferCC(io.i, allBufAttributes = Seq(
    crossClockFalsePath(destType = TimingEndpointType.CLOCK_EN),
    crossClockFalsePath(destType = TimingEndpointType.RESET),
  ))

  cdWithEnRst.clock := clockDomain.clock
  cdWithEnRst.clockEnable := inSync
  cdWithEnRst.reset := inSync

  new ClockingArea(cdWithEnRst) {
    io.o := CounterFreeRun(16 bits)
  }
}

But this is very much an artificial example. While we can surely lift the single tag instance requirement, I really cannot think of a case where this is important enough to warrant dropping the check.

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 the example is actually not that esoteric - Altera recommends a synchronizer using the CE input of a FF, depending on where the reset for that is coming from you need the constraint on both of them.

Looks like this: https://www.intel.com/content/www/us/en/programmable/quartushelp/current/index.htm#da_rules/cdc_50102.htm
Personally I think these should then be delay constraints instead of false path constraints, but I've seen the latter used for that.

Instead of allowing multiple instances I'd go for multiple arguments, much shorter, just as extendible and if used with explicit parameter names just as readable.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KireinaHoro
How should we continue here? Modify it or leave as it is and drop the uniqueness requirement once we really need it?

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 with leaving it as is. We can always come back when such a use case comes up

@andreasWallner
Copy link
Collaborator

@KireinaHoro @Dolu1990 what should we do with the two open threads? Would be great if we could merge this^^

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.

None yet

3 participants