-
-
Notifications
You must be signed in to change notification settings - Fork 303
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
base: dev
Are you sure you want to change the base?
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.
Looks quite good to me
lib/src/main/scala/spinal/lib/eda/xilinx/VivadoConstraintWriter.scala
Outdated
Show resolved
Hide resolved
5b93412
to
7e91b72
Compare
@@ -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 } |
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.
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)
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.
Or should we have a sealed trait for the destination type instead?
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.
Ahhhh yes, that is right, like a enum, yes yes
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.
fixed
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.
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?
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 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)
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.
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.
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 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.
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.
@KireinaHoro
How should we continue here? Modify it or leave as it is and drop the uniqueness requirement once we really need it?
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 with leaving it as is. We can always come back when such a use case comes up
@KireinaHoro @Dolu1990 what should we do with the two open threads? Would be great if we could merge this^^ |
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
andFlowCCByToggle
(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!