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

D2D Dummy Loopback Module #49

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ project/**/metals.sbt

### Chiseltest ###
test_run_dir/
vlog/

### IDEs ###
.vscode/
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ If you are running `sbt` commands frequently, you may find it useful
to leave the sbt shell (launched by running `sbt` with no arguments) open.
You can then compile/test the code from the sbt shell.

`sbt` can not [compile the Scala compiler bridge under JDK21](https://github.com/sbt/sbt/issues/7235) (without bumping the Scala minor version - for which the chisel compiler plugin is unavailable).
To work around this, install an older JDK and pass its path to sbt (e.g. `sbt --java-home /usr/lib/jvm/java-17-openjdk/`).

## Documentation

See the [API documentation](https://ucb-ucie.github.io/uciedigital/edu/berkeley/cs/ucie/digital/index.html).
Expand All @@ -29,7 +32,7 @@ If you'd like to contribute, please let us know. You can:

- Open an issue.
- Email [email protected] and [email protected].

Documentation updates, tests, and bugfixes are always welcome.
For larger feature additions, please discuss your ideas with us before implementing them.

Expand Down
1 change: 1 addition & 0 deletions src/main/scala/interfaces/Fdi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Fdi(params: FdiParams) extends Bundle {
*
* Encompasses `lp_dllp` and `lp_dllp_valid` from the UCIe specification.
*/
// TODO: we don't use dllp's at all, make these IOs optional
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should keep the IOs in the bundle even if we are never using them, and drive them with constants / add assertions instead; this way our IO is always spec-compliant.

val lpDllp = Valid(Bits(params.dllpWidth.W))

/** Indicates that the corresponding DLLP bytes on lp_dllp follow the
Expand Down
94 changes: 94 additions & 0 deletions src/test/scala/D2DDummyLoopback.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package edu.berkeley.cs.ucie.digital
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this should go in the main build, in the interfaces package - it could conceivably be used by other consumers of this repo to test their own IP. We're putting other verification-related IP for FDI and RDI in the interfaces package as well.


import chisel3._
import chisel3.util._
import chisel3.experimental.FlatIO
import interfaces._

import chisel3.stage.ChiselStage

// LatencyPipe from rocket-chip
// https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/util/LatencyPipe.scala
Comment on lines +10 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

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

We may want to vendor utils from rocket-chip in a dedicated package / directory (there are definitely more things we want to steal, e.g. AsyncQueue)

class LatencyPipe[T <: Data](typ: T, latency: Int) extends Module {
val io = IO(new Bundle {
val in = Flipped(Decoupled(typ))
val out = Decoupled(typ)
})

def doN[S](n: Int, func: S => S, in: S): S =
(0 until n).foldLeft(in)((last, _) => func(last))

io.out <> doN(latency, (last: DecoupledIO[T]) => Queue(last, 1, true), io.in)
}

object LatencyPipe {
def apply[T <: Data](in: DecoupledIO[T], latency: Int): DecoupledIO[T] = {
val pipe = Module(new LatencyPipe(chiselTypeOf(in.bits), latency))
pipe.io.in <> in
pipe.io.out
}
}

class D2DDummyLoopback(latency: Int = 8) extends Module {
// 64 bit wide data bus, 8 bit wide side channel bus
val fdiParams = FdiParams(width = 8, dllpWidth = 8, sbWidth = 8)

val io = FlatIO(Flipped(new Fdi(fdiParams))) // implicit module clock = lclk

when(io.lpData.valid) {
/* For now, the protocol layer must assert lpData.valid and lpData.irdy
* together */
chisel3.assert(
io.lpData.irdy,
"lpData.valid was asserted without lpData.irdy",
)
}

// Restructure lpData as Decoupled[UInt]
val lpDataDecoupled = Wire(DecoupledIO(chiselTypeOf(io.lpData.bits)))
lpDataDecoupled.bits := io.lpData.bits
lpDataDecoupled.valid := io.lpData.valid
io.lpData.ready := lpDataDecoupled.ready

// Loopback lpData to plData with some fixed latency
val pipe = Module(new LatencyPipe(chiselTypeOf(io.lpData.bits), latency))
pipe.io.in <> lpDataDecoupled
pipe.io.out.ready := true.B // immediately fetch the data after <latency> cycles
io.plData.valid := pipe.io.out.valid
io.plData.bits := pipe.io.out.bits

// Tieoffs
io.plProtocol := Protocol.streaming
io.plProtocolFlitFormat := FlitFormat.raw
io.plProtocolValid := true.B // TODO: need to model this signal changing from false to true upon training completion
io.plInbandPres := false.B // TODO: this depends on the FSM state
io.plCerror := false.B
io.plFlitCancel := false.B
io.plRxActiveReq := false.B // TODO: this signal indicates when the protocol layer can receive bits
io.plClkReq := true.B // we don't support dynamic clock gating
io.plRetimerCrd := false.B // this is an optional signal anyways
io.plStream.protoStack := ProtoStack.stack0
io.plStream.protoType := ProtoStreamType.Stream
io.plNfError := false.B // TODO: we want to be able to inject errors from the adapter to protocol layer
io.plDllp.valid := false.B // we don't use the DLLP interface due to no PCIe support
io.plDllp.bits := 0.U
io.plDllpOfc := false.B
io.plPhyInL1 := false.B // TODO: need to use these if the D2D adapter handles multiple power states
io.plPhyInL2 := false.B
io.plConfigCredit := false.B // TODO: need to handle sideband packets
io.plConfig.valid := false.B
io.plConfig.bits := 0.U
io.plStallReq := false.B // TODO: need to model D2D adapter requesting protocol layer to flush flits
io.plWakeAck := RegNext(io.lpWakeReq)
io.plLinkWidth := PhyWidth.width64 // TODO: this is a PHY-level parameter
io.plSpeedMode := SpeedMode.speed4 // TODO: this is a runtime PHY knob
io.plPhyInRecenter := false.B // TODO: this is part of the FDI state machine
io.plTrainError := false.B // TODO: need to model fatal errors of the PHY
io.plError := false.B // TODO: need to model framing errors
io.plStateStatus := PhyState.active // TODO: this is part of the FDI state machine
}

object D2DDummyLoopbackMain extends App {
Copy link
Collaborator

Choose a reason for hiding this comment

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

To suppress the SFC deprecation warning:

Suggested change
object D2DDummyLoopbackMain extends App {
@annotation.nowarn("cat=deprecation&origin=chisel3.stage.ChiselStage")
object D2DDummyLoopbackMain extends App {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, we will just disable the warning. CirctStage is only a thing in Chisel 5+ and Chipyard will be stuck on Chisel 3.6 for a while. This is also not maintained anymore, so there's no point in using it (https://github.com/sifive/chisel-circt).

Copy link
Collaborator

Choose a reason for hiding this comment

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

circt.stage.CirctStage does exist (and works) in Chisel 3.6; using SFC is an option though to avoid non-Scala dependencies to elaborate.

new ChiselStage()
.emitVerilog(new D2DDummyLoopback(), args = Array("--target-dir", "vlog"))
}
12 changes: 12 additions & 0 deletions src/test/scala/D2DTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package edu.berkeley.cs.ucie.digital

import chiseltest._
import org.scalatest.freespec.AnyFreeSpec

class D2DTest extends AnyFreeSpec with ChiselScalatestTester {
"D2D Dummy Loopback module should elaborate" in {
test(new D2DDummyLoopback()) { c =>
c.clock.step()
}
}
}
16 changes: 0 additions & 16 deletions src/test/scala/DummyModule.scala

This file was deleted.