Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

ADD: Timing-Accurate Core Instruction Tracing #3706

Merged
merged 15 commits into from
Jan 29, 2025

Conversation

iansseijelly
Copy link
Contributor

@iansseijelly iansseijelly commented Jan 15, 2025

Related issue:

Type of change: feature request

Impact: API addition (no impact on existing code)

Development Phase: implementation

Release Notes

Added feature for:

  1. rocket core to drive the trace ingress bundle, which is a standard interface for different trace encoder standards.
  2. trace encoder builder in rockettile. This allows the building of trace encoders within the tile, whether it is N-trace, E-trace, or custom.
  3. trace sink builder in rockettile. This allows the building of a sequence of trace sinks. Also supports monitoring the data sinking into the arbiter to cross-check the encoding.
  4. arbiter and controller instantiation in rockettile. This instantiates an arbiter that chooses the different trace sinks, and a trace controller that instantiates the necessary MMIO register routings to control encoders.

Copy link

linux-foundation-easycla bot commented Jan 15, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

@iansseijelly iansseijelly changed the title Tacit pr ADD: Timing-Accurate Core Instruction Tracing Jan 15, 2025
src/main/scala/util/TraceCoreIngressGen.scala Outdated Show resolved Hide resolved
src/main/scala/util/TraceCoreInterface.scala Outdated Show resolved Hide resolved
src/main/scala/util/TraceCoreIngressGen.scala Outdated Show resolved Hide resolved
src/main/scala/rocket/RocketCore.scala Outdated Show resolved Hide resolved
src/main/scala/subsystem/HasTiles.scala Outdated Show resolved Hide resolved
src/main/scala/util/TraceEncoderController.scala Outdated Show resolved Hide resolved
src/main/scala/util/TraceSink.scala Outdated Show resolved Hide resolved
})
}

class TraceSinkPrint(bb_name: String)(implicit p: Parameters) extends LazyModule {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is bb_name?

src/main/scala/util/TraceSink.scala Outdated Show resolved Hide resolved
src/main/scala/util/TraceSink.scala Outdated Show resolved Hide resolved
input[7:0] in_byte
);

`ifdef VCS
Copy link
Contributor

Choose a reason for hiding this comment

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

This should work in all RTL simulators. I think ifndef SYNTHESIS is what you want

val trace_in = Flipped(Decoupled(UInt(8.W)))
})
withClockAndReset(clock, reset) {
io.trace_in.ready := true.B
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need withClockAndReset here... there is no synchronous logic

import org.chipsalliance.cde.config.{Parameters, Config, Field}
import freechips.rocketchip.tile._
import freechips.rocketchip.subsystem._
case object TraceSinkAlwaysKey extends Field[Option[Int]](None)
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this Int indicate?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can be removed now

trace_encoder_controller
}

val (trace_sinks, trace_sink_ids) = rocketParams.ltrace match {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
val (trace_sinks, trace_sink_ids) = rocketParams.ltrace match {
val (trace_sinks, traceSinkIds) = rocketParams.ltrace match {

Informal convention is snake_case for HW vars, camelCase for SW vars

}

val (trace_sinks, trace_sink_ids) = rocketParams.ltrace match {
case Some(t) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

I

Suggested change
case Some(t) =>
case Some(t) => t.buildSinks.map {(p)}.unzip

Does this work?

case Some(t) =>
val sequence = t.buildSinks.map {_(p)}
(sequence.map(_._1), sequence.map(_._2))
case None => (Seq.empty, Seq.empty)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
case None => (Seq.empty, Seq.empty)
case None => (Nil, Nil)

bufferDepth: Int,
encoderBaseAddr: BigInt,
useArbiterMonitor: Boolean,
// a seq of functions that takes a parameter and returns a lazymodule and a target id
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain what the target id is for in a comment? I thnk that is not obvious

val MAX_DELTA_TIME_COMP = 0xCF // 63, 6 bits

when (io.stall) {
printf("TraceEncoder stall detected\n")
Copy link
Contributor

Choose a reason for hiding this comment

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

This printf should probably not be here

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 think this RTL printf is somewhat important, so in simulation we can kind of know when stalls happen. I would prefer to keep it.

Copy link
Contributor

Choose a reason for hiding this comment

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

It messes up the commit log, and I think there's a compelling reason to include the trace stuff by default in some designs.

You can add a PlusArg flag - PlusArg("trace_debug"), for example, which can generate a HW bool that you can use to gate the printf.

Then at run-time, to enable the TraceEncode prints, you just pass (in CY) EXTRA_SIM_FLAGS="+trace_debug=1"

import freechips.rocketchip.regmapper.{RegField, RegFieldDesc}

class TraceSinkArbiter(nSeq : Seq[Int], use_monitor: Boolean = false, monitor_name: String = "unknown")(implicit p: Parameters) extends LazyModule {
println(s"TraceSinkArbiter nSeq: $nSeq")
Copy link
Contributor

Choose a reason for hiding this comment

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

Prints should be removed.

Copy link
Contributor

@jerryz123 jerryz123 left a comment

Choose a reason for hiding this comment

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

High level request, can you add in a comment at the beginning of the files you added pointing out what spec exactly you implemented? Like "This is an implementation of the TraceXXX as defined in the RISC-V Trace-XXX spec"

val MAX_DELTA_TIME_COMP = 0xCF // 63, 6 bits

when (io.stall) {
printf("TraceEncoder stall detected\n")
Copy link
Contributor

Choose a reason for hiding this comment

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

It messes up the commit log, and I think there's a compelling reason to include the trace stuff by default in some designs.

You can add a PlusArg flag - PlusArg("trace_debug"), for example, which can generate a HW bool that you can use to gate the printf.

Then at run-time, to enable the TraceEncode prints, you just pass (in CY) EXTRA_SIM_FLAGS="+trace_debug=1"

import freechips.rocketchip.regmapper.{RegField, RegFieldDesc}
import freechips.rocketchip.tile._

case object TraceSinkDMAKey extends Field[Option[Int]](None)
Copy link
Contributor

Choose a reason for hiding this comment

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

We are not putting this in RC, right?

}

if (use_monitor) {
val monitor = Module(new TraceSinkMonitor(s"trace_monitor_$monitor_name.out"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should monitor_name reflect the hartId of the core that is being traced? In a multicore, each core should generate its own trace file, right?

case None => (Nil, Nil)
}

val trace_sink_arbiter = rocketParams.traceParams.map { t =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you just merge the arbiter and encoder modules?

Copy link
Contributor

@jerryz123 jerryz123 left a comment

Choose a reason for hiding this comment

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

I'll pass through this again once you remove all the things that will not be upstreamed @iansseijelly

trace_encoder_controller
}

val trace_encoder = rocketParams.traceParams match {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
val trace_encoder = rocketParams.traceParams match {
val trace_encoder = rocketParams.traceParams.map(_.buildEncoder(p))

@@ -177,7 +223,7 @@ class RocketTileModuleImp(outer: RocketTile) extends BaseTileModuleImp(outer)

// Pass through various external constants and reports that were bundle-bridged into the tile
outer.traceSourceNode.bundle <> core.io.trace
core.io.traceStall := outer.traceAuxSinkNode.bundle.stall
// core.io.traceStall := outer.traceAuxSinkNode.bundle.stall
Copy link
Contributor

Choose a reason for hiding this comment

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

import chisel3.util._
import scala.math.min

import org.chipsalliance.cde.config.Parameters
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be removed from RC then? The abstract encoder is in RC, but the custom encoder should be elsewhere?


class TraceSinkMonitor(name: String) extends BlackBox(
Map(
"FILE_NAME" -> StringParam(s"tacit_${name}_trace.out")
Copy link
Contributor

Choose a reason for hiding this comment

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

Clean tacit from the naming

@iansseijelly
Copy link
Contributor Author

Hi, I have removed the non-standard components, and addressed the above items.

Copy link
Contributor

@jerryz123 jerryz123 left a comment

Choose a reason for hiding this comment

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

Only one minor request, TraceSinkArbiter can be a Module, not a LazyModule

import freechips.rocketchip.tile._
import freechips.rocketchip.regmapper.{RegField, RegFieldDesc}

class TraceSinkArbiter(nSeq : Seq[Int], use_monitor: Boolean = false, monitor_name: String = "unknown")(implicit p: Parameters) extends LazyModule {
Copy link
Contributor

Choose a reason for hiding this comment

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

This should just be a Module, not a LazyModule

outer.trace_encoder_controller.foreach { lm =>
outer.trace_encoder.get.module.io.control <> lm.module.io.control
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't construct the arbiter outside this if block... just do it inside.... then you don't need a Option[Arbiter]

@jerryz123 jerryz123 merged commit 0b37602 into chipsalliance:master Jan 29, 2025
2 checks passed
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants