Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
url = git@github.com:ucb-bar/saturn-vectors.git
[submodule "rocket-chip"]
path = rocket-chip
url = https://github.com/chipsalliance/rocket-chip.git
url = git@github.com:ucb-bar/rocket-chip.git
[submodule "testchipip"]
path = testchipip
url = git@github.com:ucb-bar/testchipip.git
Expand Down
2 changes: 1 addition & 1 deletion shuttle
4 changes: 3 additions & 1 deletion software/tacit-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ static void tacit_stop_trace(unsigned tile)
{
uintptr_t ctrl = TRACE_CTRL_BASE(tile);
reg_write32(ctrl + TRACE_CTRL_CONTROL, 1);
delay_cycles(1024);
// The DMA writes 64-byte bursts and only flushes a partial one after 4096 idle
// cycles, so wait at least that long before reading the byte count.
delay_cycles(4096);
__asm__ volatile ("fence" ::: "memory");
}

Expand Down
6 changes: 5 additions & 1 deletion src/Iris.scala
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,11 @@ object IrisNoCParams {
/** Tacit trace encoder and trace sinks. */
class WithIrisTacitTrace
extends Config(
new tacit.WithTraceSinkDMA(1) ++
// One DMA sink per tile with a port on each bus, chosen by its bus_select
// register (soft-reset the DMA before changing it):
// 0 (reset): FBUS -> SBUS, reaches the SBUS scratchpad, or DRAM through the L2
// 1: MBUS -> DRAM below the L2 (bypasses it)
new tacit.WithTraceSinkDMA(1, buses = Some(Seq(FBUS, MBUS))) ++
new tacit.WithTraceSinkAlways(0) ++
new WithTacitTraceArbiterMonitor ++
new WithTacitParallelEncoder
Expand Down
15 changes: 13 additions & 2 deletions src/TacitConfigs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ class WithTacitParallelEncoder(
new TraceCoreParams(nGroups = 1, xlen = xlen, iaddrWidth = xlen),
bufferDepth = bufferDepth,
coreStages = 5,
queueImpl = queueImpl)(p)),
queueImpl = queueImpl,
// Retire groups still reaching the queue after io.stall: ex/mem/wb
// past the decode gate, plus one interrupt that bypasses it (4),
// plus 2 cycles of margin. coreStages is unused by the SRAM queue.
stallQuiescenceCycles = 6)(p)),
useArbiterMonitor = false,
buildSinks = tp.tileParams.traceParams.map(_.buildSinks).getOrElse(Seq.empty)
)),
Expand All @@ -83,7 +87,14 @@ class WithTacitParallelEncoder(
iaddrWidth = xlen),
bufferDepth = bufferDepth,
coreStages = 7,
queueImpl = queueImpl)(p)),
queueImpl = queueImpl,
// Retire groups still reaching the queue after io.stall: ex/mem/com
// past the register-read gate (3), plus 2 cycles of margin.
stallQuiescenceCycles = 5,
// At most one control-flow packet per commit group: one brjmp per
// issue group, traps and xRET only on lane 0 (needs the shuttle
// lane-0 trace exception gate).
maxPacketsPerCycle = Some(1))(p)),
useArbiterMonitor = false,
buildSinks = tp.tileParams.traceParams.map(_.buildSinks).getOrElse(Seq.empty)
)),
Expand Down
2 changes: 1 addition & 1 deletion tacit_decoder
Submodule tacit_decoder updated 255 files
100 changes: 100 additions & 0 deletions test/src/IrisExperiments.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package edu.berkeley.cs.iris

import chisel3._
import org.chipsalliance.cde.config.{Config, Parameters}
import org.scalatest.funspec.AnyFunSpec
import freechips.rocketchip.subsystem._

// ============================================================================
// EXPERIMENTS ONLY. Nothing in this file is part of the tapeout configuration.
//
// The tapeout configuration is whatever IrisConfig (src/Iris.scala) builds; the
// IrisSpec tests elaborate it. Everything below layers sim-only overrides on top
// of IrisConfig(sim = false) to answer a performance question, and every
// experiment builds into a build/Experiment_* directory so its RTL and results
// cannot be mistaken for the tapeout ones.
// ============================================================================

/** Trace DMA sinks get `n` TileLink source IDs (outstanding writes) instead of 16. */
class WithExperimentTraceDMASources(n: Int) extends Config((site, here, up) => {
case tacit.TraceSinkDMASourcesKey => n
})

/** Shrinks the L2 by `divisor` (fewer sets; ways and banks unchanged) so a trace
* outgrows it in a short simulation. */
class WithExperimentSmallL2(divisor: Int) extends Config((site, here, up) => {
case InclusiveCacheKey => up(InclusiveCacheKey).copy(sets = up(InclusiveCacheKey).sets / divisor)
})

/** Sizes the L2's outer MSHRs for an `cycles`-cycle memory round trip instead of
* the tapeout value. */
class WithExperimentL2OuterLatency(cycles: Int) extends Config((site, here, up) => {
case InclusiveCacheKey => up(InclusiveCacheKey).copy(memCycles = cycles)
})

/** Sim-only probe of the harness memory (FastRAM's TL->AXI4 port, i.e. below
* serial TL): counts AXI read/write requests and data beats and prints them at
* the end of simulation. Uses hierarchical references, so it only works in the
* single-chip fast harness. */
class MemTrafficMonitor extends chisel3.experimental.ExtModule {
setInline(
"MemTrafficMonitor.sv",
"""module MemTrafficMonitor;
|`ifndef SYNTHESIS
| `define MTM_P SimTop.harness.chips_success_ram.tl2axi4
| longint unsigned ar = 0, aw = 0, r_beats = 0, w_beats = 0;
| always @(posedge `MTM_P.clock) begin
| if (`MTM_P.auto_out_ar_valid && `MTM_P.auto_out_ar_ready) ar <= ar + 1;
| if (`MTM_P.auto_out_aw_valid && `MTM_P.auto_out_aw_ready) aw <= aw + 1;
| if (`MTM_P.auto_out_r_valid && `MTM_P.auto_out_r_ready) r_beats <= r_beats + 1;
| if (`MTM_P.auto_out_w_valid && `MTM_P.auto_out_w_ready) w_beats <= w_beats + 1;
| end
| final $display("MEMTRAFFIC reads=%0d read_beats=%0d writes=%0d write_beats=%0d", ar, r_beats, aw, w_beats);
| `undef MTM_P
|`endif
|endmodule
|""".stripMargin
)
}

class IrisExperimentsSpec extends AnyFunSpec {
// Tapeout RTL (16b serial TL, no TL monitors) with the link at 100 MHz, plus the
// given experimental overrides.
def tapeoutWith(overrides: Config*): Parameters =
overrides.foldRight(new IrisConfig(sim = false): Config)((o, acc) => new Config(o ++ acc))

def run(name: String, p: Parameters): Unit = {
implicit val params: Parameters = p
Utils.simulateTopWithBinaries(
Utils.buildRoot / s"Experiment_$name",
nChips = 1,
binaryPaths = Seq(Utils.root / "software/tacit-dma.riscv"),
fast = true,
serialTLFreqMHz = Some(100),
memTrafficMonitor = true
)
}

describe("Experiment (not tapeout)") {
it("tapeout config, memory traffic monitor only") {
run("tapeout_memmon", tapeoutWith())
}
it("64 trace DMA sources") {
run("dma_src64_memmon", tapeoutWith(new WithExperimentTraceDMASources(64)))
}
it("32KB L2") {
run("l2_32k_memmon", tapeoutWith(new WithExperimentSmallL2(16)))
}
it("32KB L2 and 64 trace DMA sources") {
run("l2_32k_dma_src64_memmon", tapeoutWith(new WithExperimentSmallL2(16), new WithExperimentTraceDMASources(64)))
}
// Informational only: the L2 is frozen for tapeout. Sizes the L2's outer MSHRs
// for a 64-cycle memory round trip instead of the configured 4 (128 needs more outer source IDs than the 8-bit serial-TL source field allows).
it("L2 sized for a 64-cycle memory") {
run("l2_mem64_memmon", tapeoutWith(new WithExperimentL2OuterLatency(64)))
}
it("32KB L2 sized for a 64-cycle memory") {
run("l2_32k_mem64_memmon", tapeoutWith(new WithExperimentSmallL2(16), new WithExperimentL2OuterLatency(64)))
}
}
}
76 changes: 57 additions & 19 deletions test/src/IrisSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,19 @@ class ClockSourceAtFreqMHz(val freqMHz: Double)
)
}

class SimTop(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String]] = Seq.empty, fast: Boolean = false)(implicit
class SimTop(
nChips: Int,
binaryPaths: Seq[Path],
plusArgs: Seq[Seq[String]] = Seq.empty,
fast: Boolean = false,
serialTLFreqMHz: Option[Double] = None,
memTrafficMonitor: Boolean = false // experiments only, see IrisExperiments.scala
)(implicit
p: Parameters
) extends RawModule {
val driver = Module(new TestDriver)
val harness = Module(new TestHarness(nChips, binaryPaths, plusArgs, fast))
val harness = Module(new TestHarness(nChips, binaryPaths, plusArgs, fast, serialTLFreqMHz))
if (memTrafficMonitor) Module(new MemTrafficMonitor)
harness.io.reset := driver.reset
driver.success := harness.io.success
}
Expand Down Expand Up @@ -120,7 +128,18 @@ class TestDriver extends ExtModule {
)
}

class TestHarness(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String]] = Seq.empty, fast: Boolean = false)(implicit
/** @param serialTLFreqMHz
* clock for the serial-TL link and the off-chip memory model behind it. None
* keeps the link on the 500 MHz chip clock; on silicon it is an external
* clock, typically much slower than the core.
*/
class TestHarness(
nChips: Int,
binaryPaths: Seq[Path],
plusArgs: Seq[Seq[String]] = Seq.empty,
fast: Boolean = false,
serialTLFreqMHz: Option[Double] = None
)(implicit
p: Parameters
) extends RawModule {
require(nChips >= 1, s"nChips must be at least 1, got $nChips")
Expand Down Expand Up @@ -156,6 +175,7 @@ class TestHarness(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String]
val ucieSidebandBypassClock = freeRunningClock(800)
// The clocking tile's PLL reference, as in the UCIe repo's own harness.
val ucieRefClock = freeRunningClock(100)
val serialTLClock = serialTLFreqMHz.map(freeRunningClock).getOrElse(digitalClock)

implicit def view[A <: Data, B <: Data]
: DataView[testchipip.tsi.TSIIO, TSIIO] =
Expand Down Expand Up @@ -195,22 +215,26 @@ class TestHarness(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String]
dtm_success
)

chiptop.serial_tl.clock_in := digitalClock

val success = if (fast) {
val ram = Module(LazyModule(new FastRAM(chiptop_lazy.system.serdessers(0), p(SerialTLKey)(0), chipId = chipId)(
chiptop_lazy.system.serdessers(0).p
)).module)
ram.io.ser.in <> chiptop.serial_tl.out
chiptop.serial_tl.in <> ram.io.ser.out
SimTSI.connect(ram.io.tsi.map(_.viewAs[TSIIO]), digitalClock, io.reset, binaryPath, allPlusArgs)
} else {
val ram = Module(LazyModule(new SerialRAM(chiptop_lazy.system.serdessers(0), p(SerialTLKey)(0))(
chiptop_lazy.system.serdessers(0).p
)).module)
ram.io.ser.in <> chiptop.serial_tl.out
chiptop.serial_tl.in <> ram.io.ser.out
SimTSI.connect(ram.io.tsi.map(_.viewAs[TSIIO]), digitalClock, io.reset, binaryPath, allPlusArgs)
chiptop.serial_tl.clock_in := serialTLClock

// The memory model and TSI bridge sit on the far side of the link, so they
// run on the link clock.
val success = withClockAndReset(serialTLClock, io.reset) {
if (fast) {
val ram = Module(LazyModule(new FastRAM(chiptop_lazy.system.serdessers(0), p(SerialTLKey)(0), chipId = chipId)(
chiptop_lazy.system.serdessers(0).p
)).module)
ram.io.ser.in <> chiptop.serial_tl.out
chiptop.serial_tl.in <> ram.io.ser.out
SimTSI.connect(ram.io.tsi.map(_.viewAs[TSIIO]), serialTLClock, io.reset, binaryPath, allPlusArgs)
} else {
val ram = Module(LazyModule(new SerialRAM(chiptop_lazy.system.serdessers(0), p(SerialTLKey)(0))(
chiptop_lazy.system.serdessers(0).p
)).module)
ram.io.ser.in <> chiptop.serial_tl.out
chiptop.serial_tl.in <> ram.io.ser.out
SimTSI.connect(ram.io.tsi.map(_.viewAs[TSIIO]), serialTLClock, io.reset, binaryPath, allPlusArgs)
}
}
val chipSuccessReg = withReset(io.reset.asAsyncReset)(RegInit(false.B))
when(dtm_success || success) { chipSuccessReg := true.B }
Expand Down Expand Up @@ -482,6 +506,20 @@ class IrisSpec extends AnyFunSpec {
fast = true
)
}

it("should run tacit dma trace workload on the tapeout serial TL") {
// Tapeout config (16b serial TL, no TL monitors) with the link at 100 MHz.
implicit val p = new IrisConfig(sim = false)
val workDir = Utils.buildRoot / "Iris_should_run_tacit_dma_trace_tapeout_serial_tl"

Utils.simulateTopWithBinaries(
workDir,
nChips = 1,
binaryPaths = Seq(Utils.root / "software/tacit-dma.riscv"),
fast = true,
serialTLFreqMHz = Some(100)
)
}
}

describe("IrisDryRun") {
Expand Down
6 changes: 4 additions & 2 deletions test/src/Utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ script -e -f -c "./simulation +permissive +vcs+thread+16 +dramsim +dramsim_ini_d
binaryPaths: Seq[Path],
plusArgs: Seq[Seq[String]] = Seq.empty,
fast: Boolean = false,
debug: Boolean = false
debug: Boolean = false,
serialTLFreqMHz: Option[Double] = None,
memTrafficMonitor: Boolean = false
)(implicit p: Parameters) = {
binaryPaths.zipWithIndex.foreach { case (path, i) =>
assert(
Expand All @@ -133,7 +135,7 @@ script -e -f -c "./simulation +permissive +vcs+thread+16 +dramsim +dramsim_ini_d
os.makeDir.all(artifactsDir)

ChiselStage.emitSystemVerilogFile(
new SimTop(nChips, binaryPaths, plusArgs, fast),
new SimTop(nChips, binaryPaths, plusArgs, fast, serialTLFreqMHz, memTrafficMonitor),
args = Array(
"--target-dir",
sourceDir.toString
Expand Down
Loading