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

ClockDomain for input/output ports? #1299

Open
KireinaHoro opened this issue Jan 30, 2024 · 10 comments
Open

ClockDomain for input/output ports? #1299

KireinaHoro opened this issue Jan 30, 2024 · 10 comments

Comments

@KireinaHoro
Copy link
Contributor

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
Copy link
Contributor Author

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

@Readon
Copy link
Collaborator

Readon commented Jan 30, 2024

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

@Dolu1990
Copy link
Member

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

@KireinaHoro
Copy link
Contributor Author

KireinaHoro commented Jan 30, 2024

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

@Dolu1990
Copy link
Member

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

@KireinaHoro
Copy link
Contributor Author

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

@Dolu1990
Copy link
Member

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.

@andreasWallner
Copy link
Collaborator

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

@KireinaHoro
Copy link
Contributor Author

@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?

Dolu1990 added a commit that referenced this issue Feb 26, 2024
Dolu1990 added a commit that referenced this issue Feb 26, 2024
@Dolu1990
Copy link
Member

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
}

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

No branches or pull requests

4 participants