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

remove clock and cond from probe force/release API #3605

Merged
merged 4 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 43 additions & 8 deletions core/src/main/scala/chisel3/probe/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ package object probe extends SourceInfoDoc {
}
}

/** Initialize a probe with a provided probe value. */
/** Initialize a probe with a provided probe value.
*
* @param sink probe to initialize
* @param probeExpr value to initialize the sink to
*/
def define[T <: Data](sink: T, probeExpr: T)(implicit sourceInfo: SourceInfo): Unit = {
if (!checkTypeEquivalence(sink, probeExpr)) {
Builder.error("Cannot define a probe on a non-equivalent type.")
Expand All @@ -41,7 +45,10 @@ package object probe extends SourceInfoDoc {
pushCommand(ProbeDefine(sourceInfo, sink.ref, probeExpr.ref))
}

/** Access the value of a probe. */
/** Access the value of a probe.
*
* @param source probe whose value is getting accessed
*/
def read[T <: Data](source: T): T = macro chisel3.internal.sourceinfo.ProbeTransform.sourceRead[T]

/** @group SourceInfoTransformMacro */
Expand Down Expand Up @@ -88,27 +95,55 @@ package object probe extends SourceInfoDoc {
}
}

/** Override existing driver of a writable probe on initialization. */
/** Override existing driver of a writable probe on initialization.
*
* @param probe writable Probe to force
* @param value to force onto the probe
*/
def forceInitial(probe: Data, value: Data)(implicit sourceInfo: SourceInfo): Unit = {
requireHasWritableProbeTypeModifier(probe, "Cannot forceInitial a non-writable Probe.")
pushCommand(ProbeForceInitial(sourceInfo, probe.ref, padDataToProbeWidth(value, probe).ref))
}

/** Release initial driver on a probe. */
/** Release initial driver on a probe.
*
* @param probe writable Probe to release
*/
def releaseInitial(probe: Data)(implicit sourceInfo: SourceInfo): Unit = {
requireHasWritableProbeTypeModifier(probe, "Cannot releaseInitial a non-writable Probe.")
pushCommand(ProbeReleaseInitial(sourceInfo, probe.ref))
}

/** Override existing driver of a writable probe. */
def force(clock: Clock, cond: Bool, probe: Data, value: Data)(implicit sourceInfo: SourceInfo): Unit = {
/** Override existing driver of a writable probe. If called within the scope
* of a [[when]] block, the force will only occur on cycles that the when
* condition is true.
*
* Fires only when reset has been asserted and then deasserted through the
* [[Disable]] API.
*
* @param probe writable Probe to force
* @param value to force onto the probe
*/
def force(probe: Data, value: Data)(implicit sourceInfo: SourceInfo): Unit = {
requireHasWritableProbeTypeModifier(probe, "Cannot force a non-writable Probe.")
val clock = Builder.forcedClock
val cond = Module.disableOption.map(!_.value).getOrElse(true.B)
pushCommand(ProbeForce(sourceInfo, clock.ref, cond.ref, probe.ref, padDataToProbeWidth(value, probe).ref))
}

/** Release driver on a probe. */
def release(clock: Clock, cond: Bool, probe: Data)(implicit sourceInfo: SourceInfo): Unit = {
/** Release driver on a probe. If called within the scope of a [[when]]
* block, the release will only occur on cycles that the when condition
* is true.
*
* Fires only when reset has been asserted and then deasserted through the
* [[Disable]] API.
*
* @param probe writable Probe to release
*/
def release(probe: Data)(implicit sourceInfo: SourceInfo): Unit = {
requireHasWritableProbeTypeModifier(probe, "Cannot release a non-writable Probe.")
val clock = Builder.forcedClock
val cond = Module.disableOption.map(!_.value).getOrElse(true.B)
pushCommand(ProbeRelease(sourceInfo, clock.ref, cond.ref, probe.ref))
}

Expand Down
29 changes: 15 additions & 14 deletions src/test/scala/chiselTests/ProbeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,20 @@ class ProbeSpec extends ChiselFlatSpec with Utils {

releaseInitial(u1.io.out)

force(clock, io.x, u2.io.out, u1.io.out)
release(clock, io.y, u2.io.out)
when(io.x) { force(u2.io.out, u1.io.out) }
when(io.y) { release(u2.io.out) }
},
Array("--full-stacktrace")
)

(processChirrtl(chirrtl) should contain).allOf(
"output io : { flip in : RWProbe<UInt<1>>, out : RWProbe<UInt<1>>}",
"define u1.io.in = rwprobe(io.x)",
"define u2.io.in = u1.io.out",
"connect io.y, read(u2.io.out)",
"force_initial(u1.io.out, UInt<1>(0h0))",
"release_initial(u1.io.out)",
"force(clock, io.x, u2.io.out, u1.io.out)",
"release(clock, io.y, u2.io.out)"
"force(clock, _T, u2.io.out, u1.io.out)",
"release(clock, _T_1, u2.io.out)"
)
}

Expand Down Expand Up @@ -468,7 +467,7 @@ class ProbeSpec extends ChiselFlatSpec with Utils {
new Module {
val in = IO(Input(Bool()))
val out = IO(Output(Probe(Bool())))
force(clock, in, out, in)
force(out, in)
},
Array("--throw-on-first-error")
)
Expand Down Expand Up @@ -504,7 +503,7 @@ class ProbeSpec extends ChiselFlatSpec with Utils {
val in = IO(Input(UInt(4.W)))
val p = IO(Output(RWProbe(UInt(16.W))))
forceInitial(p, 123.U)
force(clock, reset.asBool, p, in)
force(p, in)
},
Array("--full-stacktrace")
)
Expand Down Expand Up @@ -535,7 +534,7 @@ class ProbeSpec extends ChiselFlatSpec with Utils {
new Module {
val in = IO(Input(UInt()))
val p = IO(Output(RWProbe(UInt(16.W))))
force(clock, reset.asBool, p, in)
force(p, in)
},
Array("--throw-on-first-error")
)
Expand All @@ -549,7 +548,7 @@ class ProbeSpec extends ChiselFlatSpec with Utils {
new Module {
val in = IO(Input(UInt(16.W)))
val p = IO(Output(RWProbe(UInt())))
force(clock, reset.asBool, p, in)
force(p, in)
},
Array("--throw-on-first-error")
)
Expand Down Expand Up @@ -597,23 +596,25 @@ class ProbeSpec extends ChiselFlatSpec with Utils {
forceInitial(dut.b.refs.reg, cycle)
// Additionally, 'initial force ...' doesn't seem to work here (?).
// So do this on cycle zero explicitly for compatibility.
force(clock, cycle === 0.U, dut.b.refs.reg, cycle)
when(cycle === 0.U) { force(dut.b.refs.reg, cycle) }

when(0.U < cycle && cycle <= 10.U) {
// Force cycle and check we observe it on output a cycle later.
chisel3.assert(dut.out === cycle - 1.U)
force(clock, true.B, dut.b.refs.reg, cycle)
force(dut.b.refs.reg, cycle)
}.elsewhen(cycle === 11.U) {
// Check last value, release.
chisel3.assert(dut.out === 10.U)
release(clock, true.B, dut.b.refs.reg)
release(dut.b.refs.reg)
}.elsewhen(cycle === 12.U) {
// Check original value is restored.
chisel3.assert(dut.out === 42.U)
}
// Force the register and the output port.
force(clock, cycle >= 13.U, dut.b.refs.reg, cycle)
force(clock, cycle >= 13.U, dut.b.refs.out, 123.U)
when(cycle >= 13.U) {
force(dut.b.refs.reg, cycle)
force(dut.b.refs.out, 123.U)
}
when(cycle > 13.U) {
// Register reads the value forced to it.
chisel3.assert(read(dut.b.refs.reg) === cycle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class TappedInterfaceSpec extends AnyFunSpec with Matchers {
b := baz.io.b

forceInitial(baz.io.c, true.B)
force(clock, reset.asBool, baz.io.d, false.B)
force(baz.io.d, false.B)
}
}

Expand Down