SpinalHDL icon indicating copy to clipboard operation
SpinalHDL copied to clipboard

ClockDomain for input/output ports?

Open KireinaHoro opened this issue 2 years ago • 10 comments

Per my current understanding, we sample input ports in a given clock domain (when it's not the default one) as follows:

case class DUT(monClock: ClockDomain = ClockDomain.external("monClock")) extends Component {
  val io = new Bundle {
    val monFire = in Bool()
  }
  val monArea = new ClockingArea(monClock) {
    val fire = RegNext(io.monFire) init False
  }
  val cdcMonFire = BufferCC(monArea.fire, False)
  // ...
}

I didn't manage to find a way to specify that monFire is clocked by and should only be sampled in monClock. Since it's mentioned in the document that SpinalHDL checks CDCs:

SpinalHDL checks at compile time that there are no unwanted/unspecified cross clock domain signal reads.

Is it possible to mark the input port with a specific clock domain to enforce this to the module ports as well?

KireinaHoro avatar Jan 30 '24 10:01 KireinaHoro

To elaborate a bit, the purpose is to have the following trigger CLOCK CROSSING VIOLATION:

val monArea = new ClockingArea(monClock) {
  val fire = in Bool()
}
val incorrectCdcFromPort = monArea.fire

KireinaHoro avatar Jan 30 '24 10:01 KireinaHoro

To elaborate a bit, the purpose is to have the following trigger CLOCK CROSSING VIOLATION:

val monArea = new ClockingArea(monClock) {
  val fire = in Bool()
}
val incorrectCdcFromPort = monArea.fire

you can not assign clockdomain for a wire individually, but can be on a register

Readon avatar Jan 30 '24 11:01 Readon

Is it what you are looking for ?

    val cdA = ClockDomain.external("cdA")
    val cdB = ClockDomain.external("cdB")

    val a = in Bool()
    val b = out Bool()

    val tmp = Bool()
    tmp := a
    b := tmp

    a.addTag(ClockDomainTag(cdA))
    b.addTag(ClockDomainTag(cdB))

=>

CLOCK CROSSING VIOLATION :
- Source            : (toplevel/a : in Bool) spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:318)
- Source clock      : (cdA_clk :  Bool)
- Destination       : (toplevel/b : out Bool) spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:319)
- Destination clock : (cdB_clk :  Bool)
- Source declaration :
    spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:318)
    spinal.tester.code.Debug2$.gen(Debug.scala:310)
    spinal.tester.code.Debug2$.$anonfun$new$10(Debug.scala:618)
    spinal.sim.JvmThread.run(SimManager.scala:51)


- Destination declaration :
    spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:319)
    spinal.tester.code.Debug2$.gen(Debug.scala:310)
    spinal.tester.code.Debug2$.$anonfun$new$10(Debug.scala:618)
    spinal.sim.JvmThread.run(SimManager.scala:51)


- Connection path :
      >>> (toplevel/a : in Bool) at spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:318) >>>
      >>> (toplevel/tmp :  Bool) at spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:321) >>>
      >>> (toplevel/b : out Bool) at spinal.tester.code.Debug2$$anon$21.<init>(Debug.scala:319) >>>

Dolu1990 avatar Jan 30 '24 14:01 Dolu1990

Nice! But looks like it doesn't work for BlackBoxes?

val cdA = ClockDomain.external("cdA")
val i = in Bool() addTag ClockDomainTag(cdA)
val bb = new BlackBox {
  val i = in Bool()
  val clk = in Bool()
  val rst = in Bool()

  mapCurrentClockDomain(clk, rst)
}
bb.i := i

KireinaHoro avatar Jan 30 '24 15:01 KireinaHoro

hmm, did you tried i.addTag(ClockDomainTag(ClockDomain.current)) ?

Dolu1990 avatar Jan 30 '24 15:01 Dolu1990

Ok that works. But it seems like this tag is not implicitly added for all signals in a clock domain (either ClockArea or the default clock domain)? It's a bit tedious to add this to everything...

KireinaHoro avatar Jan 30 '24 16:01 KireinaHoro

But it seems like this tag is not implicitly added for all signals in a clock domain

that's right

It's a bit tedious to add this to everything...

There is ways to automate that : getAllIo.foreach(_.addTag(ClockDomainTag(ClockDomain.current)))

Assuming they all use the blackbox current clockdomain

hmm overall i understand the point. There could be a baked in API to handle this.

Dolu1990 avatar Jan 30 '24 16:01 Dolu1990

@KireinaHoro Did this answer your question? If yes we should close it.

andreasWallner avatar Feb 14 '24 01:02 andreasWallner

@andreasWallner it forms as a workaround, but since @Dolu1990 mentioned that there could be a baked API for this, I'm thinking of either keeping this open or having a tracking issue for that feature (request). What do you think?

KireinaHoro avatar Feb 19 '24 08:02 KireinaHoro

Currently, the smootest api is :

class DemoBlackbox extends BlackBox {
  val io = new Bundle{
    val a = in Bool()
    val b = out Bool()
  }

  ClockDomainTag(this.clockDomain)(
    io.a,
    io.b
  )  
}

You can also do :

class DemoBlackbox extends BlackBox {
  val io = new Bundle{
    val a = in Bool()
    val b = out Bool()
  }

  ClockDomainTag(this.clockDomain)(io)  
}

I also just pushed feature :

class DemoBlackbox extends BlackBox {
  val io = new Bundle{
    val a = in Bool()
    val b = out Bool()
  }

  setIoCd() //This will add the tag to all the previsouly defined io
}

Dolu1990 avatar Feb 26 '24 13:02 Dolu1990