From 31f8e1ef38a98cb58740f3a5b74eef6d56249016 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 17 Jul 2024 00:21:02 -0700 Subject: [PATCH 01/12] add pattern writer, error count --- src/main/scala/logphy/ErrorCounter.scala | 80 ++++++++ src/main/scala/logphy/Lanes.scala | 141 +++++++++++--- src/main/scala/logphy/LinkTrainingFSM.scala | 14 +- src/main/scala/logphy/LogPhyTypes.scala | 2 +- src/main/scala/logphy/LogicalPhy.scala | 7 +- src/main/scala/logphy/PatternGenerator.scala | 123 +++--------- src/main/scala/logphy/PatternReader.scala | 84 +++++++++ src/main/scala/logphy/PatternWriter.scala | 133 +++++++++++++ src/main/scala/logphy/RdiBringup.scala | 1 - src/main/scala/{ => logphy}/Scrambler.scala | 36 ++-- src/test/scala/logphy/ErrorCounterTest.scala | 124 ++++++++++++ src/test/scala/logphy/LogPhyLaneTest.scala | 177 +++++++++++++++--- .../scala/logphy/PatternGeneratorTest.scala | 30 ++- src/test/scala/logphy/PatternReaderTest.scala | 53 ++++++ src/test/scala/logphy/PatternWriterTest.scala | 167 +++++++++++++++++ .../ScramblerTest.scala} | 23 ++- 16 files changed, 1003 insertions(+), 192 deletions(-) create mode 100644 src/main/scala/logphy/ErrorCounter.scala create mode 100644 src/main/scala/logphy/PatternReader.scala create mode 100644 src/main/scala/logphy/PatternWriter.scala rename src/main/scala/{ => logphy}/Scrambler.scala (59%) create mode 100644 src/test/scala/logphy/ErrorCounterTest.scala create mode 100644 src/test/scala/logphy/PatternReaderTest.scala create mode 100644 src/test/scala/logphy/PatternWriterTest.scala rename src/test/scala/{Scrambler.scala => logphy/ScramblerTest.scala} (65%) diff --git a/src/main/scala/logphy/ErrorCounter.scala b/src/main/scala/logphy/ErrorCounter.scala new file mode 100644 index 0000000..e3c79e2 --- /dev/null +++ b/src/main/scala/logphy/ErrorCounter.scala @@ -0,0 +1,80 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import interfaces.AfeParams + +class ErrorCounter(afeParams: AfeParams) extends Module { + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + + val io = IO(new Bundle { + val req = Flipped(Valid(new Bundle { + val pattern = TransmitPattern() + val input = Input(UInt(width.W)) + })) + val errorCount = Output(UInt(log2Ceil(width + 1).W)) + }) + + val lfsr = Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) + + lfsr.io.valid := io.req.valid && io.req.bits.pattern === TransmitPattern.LFSR + lfsr.io.data_in := VecInit( + Seq.fill(afeParams.mbLanes)(0.U(afeParams.mbSerializerRatio.W)), + ) + + val expected = WireInit(0.U(width.W)) + + /** Assign expected value */ + switch(io.req.bits.pattern) { + is(TransmitPattern.CLOCK) { + assert(!io.req.valid, "Cannot do error count with sideband clock pattern") + } + is(TransmitPattern.LFSR) { + val ratioBytes = afeParams.mbSerializerRatio / 8 + val patternBytes = VecInit( + Seq.fill(afeParams.mbLanes * ratioBytes)(0.U(8.W)), + ) + for (i <- 0 until ratioBytes) { + for (j <- 0 until afeParams.mbLanes) { + patternBytes(i * afeParams.mbLanes + j) := lfsr.io + .data_out(j) + .asTypeOf(VecInit(Seq.fill(ratioBytes)(0.U(8.W))))(i) + } + } + expected := patternBytes.asUInt + } + is(TransmitPattern.PER_LANE_ID) { + val perLaneId = VecInit(Seq.fill(afeParams.mbLanes)(0.U(16.W))) + for (i <- 0 until afeParams.mbLanes) { + perLaneId(i) := Cat("b1010".U(4.W), i.U(8.W), "b1010".U(4.W)) + } + val ratio16 = afeParams.mbSerializerRatio / 16 + val patternVec = VecInit.tabulate(afeParams.mbLanes, ratio16) { (_, _) => + 0.U(16.W) + } + for (i <- 0 until afeParams.mbLanes) { + for (j <- 0 until ratio16) { + patternVec(i)(j) := perLaneId(i) + } + } + expected := patternVec.asUInt + } + is(TransmitPattern.VALTRAIN) { + val valtrain = VecInit( + Seq.fill(afeParams.mbLanes * afeParams.mbSerializerRatio / 8)( + "b1111_0000".U(8.W), + ), + ) + expected := valtrain.asUInt + } + } + + /** count errors */ + val diffVec = Wire(Vec(width, UInt(1.W))) + diffVec := (expected ^ io.req.bits.input).asTypeOf(diffVec) + io.errorCount := diffVec.reduceTree(_ +& _) + +} diff --git a/src/main/scala/logphy/Lanes.scala b/src/main/scala/logphy/Lanes.scala index 7be48ce..f3b398a 100644 --- a/src/main/scala/logphy/Lanes.scala +++ b/src/main/scala/logphy/Lanes.scala @@ -5,12 +5,14 @@ import interfaces._ import chisel3._ import chisel3.util._ import freechips.rocketchip.util.{AsyncQueue, AsyncQueueParams} +import logphy.Scrambler class Lanes( afeParams: AfeParams, queueParams: AsyncQueueParams, ) extends Module { val io = IO(new Bundle() { + val scramble = Input(Bool()) val mainbandIo = new MainbandIO(afeParams) val mainbandLaneIO = new MainbandLaneIO(afeParams) }) @@ -29,6 +31,15 @@ class Lanes( queueParams, ), ) + val rxScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) + + val txScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) rxMBFifo.io.enq <> io.mainbandIo.rxData rxMBFifo.io.deq_clock := clock @@ -41,33 +52,67 @@ class Lanes( txMBFifo.io.deq_clock := io.mainbandIo.fifoParams.clk txMBFifo.io.deq_reset := io.mainbandIo.fifoParams.reset - txMBFifo.io.enq.valid := io.mainbandLaneIO.txData.valid - io.mainbandLaneIO.rxData.valid := rxMBFifo.io.deq.valid assert( afeParams.mbSerializerRatio > 8 && afeParams.mbSerializerRatio % 8 == 0, ) + + val ratioBytes = afeParams.mbSerializerRatio / 8 val txDataVec = Wire( - Vec(afeParams.mbLanes, Vec(afeParams.mbSerializerRatio / 8, UInt(8.W))), + Vec(afeParams.mbLanes, Vec(ratioBytes, UInt(8.W))), ) - val ratioBytes = afeParams.mbSerializerRatio / 8 val rxDataVec = Wire( Vec(ratioBytes, Vec(afeParams.mbLanes, UInt(8.W))), ) + val txDataBytes = Wire( + Vec(afeParams.mbLanes * ratioBytes, UInt(8.W)), + ) + txDataBytes := io.mainbandLaneIO.txData.asTypeOf(txDataBytes) + + for (i <- 0 until afeParams.mbLanes) { + for (j <- 0 until ratioBytes) { + txDataVec(i)(j) := txDataBytes(afeParams.mbLanes * j + i) + } + } + + val scrambledTx = Wire(chiselTypeOf(txMBFifo.io.enq.bits)) + val descrambledRx = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) + + val rxDataInput = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) + rxDataInput := Mux(io.scramble, descrambledRx, rxMBFifo.io.deq.bits) + for (i <- 0 until afeParams.mbLanes) { for (j <- 0 until ratioBytes) { - txDataVec(afeParams.mbLanes - 1 - i)(j) := io.mainbandLaneIO.txData - .bits( - afeParams.mbLanes * 8 * j + (i * 8) + 7, - afeParams.mbLanes * 8 * j + (i * 8), - ) - rxDataVec(j)(afeParams.mbLanes - 1 - i) := rxMBFifo.io.deq - .bits(i)((j + 1) * 8 - 1, j * 8) + rxDataVec(j)(i) := rxDataInput(i).asTypeOf( + VecInit(Seq.fill(ratioBytes)(0.U(8.W))), + )(j) } - txMBFifo.io.enq.bits(i) := txDataVec(i).asUInt } + + /** Data Scrambling / De-scrambling */ + + rxScrambler.io.data_in := rxMBFifo.io.deq.bits + rxScrambler.io.valid := rxMBFifo.io.deq.fire + descrambledRx := rxScrambler.io.data_out + + for (i <- 0 until afeParams.mbLanes) { + txScrambler.io.data_in(i) := txDataVec(i).asUInt + } + txScrambler.io.valid := io.mainbandLaneIO.txData.fire + scrambledTx := txScrambler.io.data_out + + /** Queue data into FIFOs */ + + txMBFifo.io.enq.valid := io.mainbandLaneIO.txData.valid + io.mainbandLaneIO.txData.ready := txMBFifo.io.enq.ready + txMBFifo.io.enq.bits := Mux( + io.scramble, + scrambledTx, + txScrambler.io.data_in, + ) + + io.mainbandLaneIO.rxData.valid := rxMBFifo.io.deq.valid io.mainbandLaneIO.rxData.bits := rxDataVec.asUInt rxMBFifo.io.deq.ready := true.B - io.mainbandLaneIO.txData.ready := txMBFifo.io.enq.ready } class MainbandSimIO(afeParams: AfeParams) extends Bundle { @@ -85,10 +130,21 @@ class SimLanes( ) extends Module { val io = IO(new Bundle() { + val scramble = Input(Bool()) val mainbandIo = new MainbandSimIO(afeParams) val mainbandLaneIO = new MainbandLaneIO(afeParams) }) + val rxScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) + + val txScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) + val txMBFifo = Module( new Queue( @@ -112,27 +168,62 @@ class SimLanes( assert( afeParams.mbSerializerRatio > 8 && afeParams.mbSerializerRatio % 8 == 0, ) + + val ratioBytes = afeParams.mbSerializerRatio / 8 val txDataVec = Wire( - Vec(afeParams.mbLanes, Vec(afeParams.mbSerializerRatio / 8, UInt(8.W))), + Vec(afeParams.mbLanes, Vec(ratioBytes, UInt(8.W))), ) - val ratioBytes = afeParams.mbSerializerRatio / 8 val rxDataVec = Wire( Vec(ratioBytes, Vec(afeParams.mbLanes, UInt(8.W))), ) + val txDataBytes = Wire( + Vec(afeParams.mbLanes * ratioBytes, UInt(8.W)), + ) + txDataBytes := io.mainbandLaneIO.txData.asTypeOf(txDataBytes) + for (i <- 0 until afeParams.mbLanes) { for (j <- 0 until ratioBytes) { - txDataVec(afeParams.mbLanes - 1 - i)(j) := io.mainbandLaneIO.txData - .bits( - afeParams.mbLanes * 8 * j + (i * 8) + 7, - afeParams.mbLanes * 8 * j + (i * 8), - ) - rxDataVec(j)(afeParams.mbLanes - 1 - i) := rxMBFifo.io.deq - .bits(i)((j + 1) * 8 - 1, j * 8) + txDataVec(i)(j) := txDataBytes(afeParams.mbLanes * j + i) } - txMBFifo.io.enq.bits(i) := txDataVec(i).asUInt } - io.mainbandLaneIO.rxData.bits := rxDataVec.asUInt - rxMBFifo.io.deq.ready := true.B + + val scrambledTx = Wire(chiselTypeOf(txMBFifo.io.enq.bits)) + val descrambledRx = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) + + val rxDataInput = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) + rxDataInput := Mux(io.scramble, descrambledRx, rxMBFifo.io.deq.bits) + + for (i <- 0 until afeParams.mbLanes) { + for (j <- 0 until ratioBytes) { + rxDataVec(j)(i) := rxDataInput(i).asTypeOf( + VecInit(Seq.fill(ratioBytes)(0.U(8.W))), + )(j) + } + } + + /** Data Scrambling / De-scrambling */ + + rxScrambler.io.data_in := rxMBFifo.io.deq.bits + rxScrambler.io.valid := rxMBFifo.io.deq.fire + descrambledRx := rxScrambler.io.data_out + + for (i <- 0 until afeParams.mbLanes) { + txScrambler.io.data_in(i) := txDataVec(i).asUInt + } + txScrambler.io.valid := io.mainbandLaneIO.txData.fire + scrambledTx := txScrambler.io.data_out + + /** Queue data into FIFOs */ + + txMBFifo.io.enq.valid := io.mainbandLaneIO.txData.valid io.mainbandLaneIO.txData.ready := txMBFifo.io.enq.ready + txMBFifo.io.enq.bits := Mux( + io.scramble, + scrambledTx, + txScrambler.io.data_in, + ) + io.mainbandLaneIO.rxData.valid := rxMBFifo.io.deq.valid + io.mainbandLaneIO.rxData.bits := rxDataVec.asUInt + rxMBFifo.io.deq.ready := true.B } diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index 699c1eb..47a00d1 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -9,7 +9,6 @@ import chisel3.util._ /** Implementation TODOs: * - investigate multiple message source issue * - implement plStallReq - * - implement lpStateReq */ case class LinkTrainingParams( @@ -61,7 +60,9 @@ class LinkTrainingFSM( val currentState = Output(LinkTrainingState()) }) - val patternGenerator = Module(new PatternGenerator(afeParams, sbParams)) + val patternGenerator = Module( + new PatternGenerator(afeParams, sbParams, maxPatternCount = 1024), + ) val sbMsgWrapper = Module(new SBMsgWrapper(sbParams)) private val msgSource = WireInit(MsgSource.PATTERN_GENERATOR) @@ -120,7 +121,6 @@ class LinkTrainingFSM( rdiBringup.io.sbTrainIO.msgReqStatus.noenq() val plStateStatus = WireInit(rdiBringup.io.rdiIO.plStateStatus) - // TODO: incorporate lpstatereq currentState := PriorityMux( Seq( (rdiBringup.io.rdiIO.plStateStatus === PhyState.reset, nextState), @@ -138,12 +138,6 @@ class LinkTrainingFSM( ), ), ) - // currentState := Mux( - // plStateStatus === PhyState.reset, - // nextState, - /* Mux(plStateStatus === PhyState.linkError, LinkTrainingState.linkError, - * Mux(plStateStatus === )), */ - // ) io.sidebandFSMIO.rxMode := Mux( currentState === LinkTrainingState.sbInit && (sbInitSubState === SBInitSubState.SEND_CLOCK || @@ -229,7 +223,7 @@ class LinkTrainingFSM( switch(sbInitSubState) { is(SBInitSubState.SEND_CLOCK) { - patternGenerator.io.patternGeneratorIO.transmitReq.bits.pattern := TransmitPattern.CLOCK_64_LOW_32 + patternGenerator.io.patternGeneratorIO.transmitReq.bits.pattern := TransmitPattern.CLOCK patternGenerator.io.patternGeneratorIO.transmitReq.bits.sideband := true.B /** Timeout occurs after 8ms */ diff --git a/src/main/scala/logphy/LogPhyTypes.scala b/src/main/scala/logphy/LogPhyTypes.scala index 0cc764c..1220529 100644 --- a/src/main/scala/logphy/LogPhyTypes.scala +++ b/src/main/scala/logphy/LogPhyTypes.scala @@ -47,7 +47,7 @@ object ClockModeParam extends ChiselEnum { } object TransmitPattern extends ChiselEnum { - val CLOCK_64_LOW_32 = Value(0.U) + val CLOCK, VALTRAIN, LFSR, PER_LANE_ID = Value } class SBIO(params: AfeParams) extends Bundle { diff --git a/src/main/scala/logphy/LogicalPhy.scala b/src/main/scala/logphy/LogicalPhy.scala index 75f3409..b4a1cfd 100644 --- a/src/main/scala/logphy/LogicalPhy.scala +++ b/src/main/scala/logphy/LogicalPhy.scala @@ -75,6 +75,8 @@ class LogicalPhy( lanes.io.mainbandIo.fifoParams <> io.mbAfe.fifoParams rdiDataMapper.io.mainbandLaneIO <> lanes.io.mainbandLaneIO + /** TODO: need to hook up lane scrambling boolean to states */ + /** Connect RDI to Mainband IO */ rdiDataMapper.io.rdi.lpData <> io.rdi.lpData io.rdi.plData <> rdiDataMapper.io.rdi.plData @@ -86,7 +88,6 @@ class LogicalPhy( "connecting sideband module directly to training module, sb serializer ratio must be 1!", ) - /** TODO: Double check that this is the right direction */ sidebandChannel.io.to_upper_layer.tx.bits <> io.rdi.plConfig.bits sidebandChannel.io.to_upper_layer.tx.valid <> io.rdi.plConfig.valid sidebandChannel.io.to_upper_layer.tx.credit <> io.rdi.plConfigCredit @@ -101,9 +102,7 @@ class LogicalPhy( sidebandChannel.io.inner.inputMode := trainingModule.io.sidebandFSMIO.txMode sidebandChannel.io.inner.rxMode := trainingModule.io.sidebandFSMIO.rxMode - /** TODO: layer to node above not connected? Not sure when might receive SB - * packet from above layer - */ + /** Currently no situation where would receive SB packet from above layer. */ sidebandChannel.io.inner.switcherBundle.layer_to_node_above.noenq() sidebandChannel.io.inner.switcherBundle.node_to_layer_above.nodeq() diff --git a/src/main/scala/logphy/PatternGenerator.scala b/src/main/scala/logphy/PatternGenerator.scala index 858cac1..bc9dc17 100644 --- a/src/main/scala/logphy/PatternGenerator.scala +++ b/src/main/scala/logphy/PatternGenerator.scala @@ -11,146 +11,75 @@ class PatternGeneratorIO extends Bundle { val pattern = TransmitPattern() val timeoutCycles = UInt(32.W) val sideband = Bool() - })) // data to transmit & receive over SB + val patternCountMax = UInt(32.W) + val patternDetectedCountMax = UInt(32.W) + })) val transmitPatternStatus = Decoupled(MessageRequestStatusType()) + } +/** TODO: incorporate reader and writer */ class PatternGenerator( afeParams: AfeParams, sbParams: SidebandParams, + maxPatternCount: Int, ) extends Module { val io = IO(new Bundle { val patternGeneratorIO = new PatternGeneratorIO() - /** for now, assume want to transmit on sideband IO only */ - // val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) + val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) val sidebandLaneIO = Flipped(new SidebandLaneIO(sbParams)) }) - /** TODO: remove */ - // io.mainbandLaneIO.txData.noenq() + val patternWriter = Module(new PatternWriter(sbParams, afeParams)) + val patternReader = Module( + new PatternReader(sbParams, afeParams, maxPatternCount), + ) - private val writeInProgress = RegInit(false.B) - private val readInProgress = RegInit(false.B) - private val inProgress = WireInit(writeInProgress || readInProgress) - private val pattern = RegInit(TransmitPattern.CLOCK_64_LOW_32) + private val inProgress = WireInit( + patternWriter.io.resp.inProgress || patternReader.io.resp.inProgress, + ) + private val pattern = RegInit(TransmitPattern.CLOCK) private val sideband = RegInit(true.B) private val timeoutCycles = RegInit(0.U(32.W)) private val status = RegInit(MessageRequestStatusType.SUCCESS) private val statusValid = RegInit(false.B) + private val patternCountMax = RegInit(0.U(32.W)) + private val patternDetectedCountMax = RegInit(0.U(32.W)) + io.patternGeneratorIO.transmitReq.ready := (inProgress === false.B) io.patternGeneratorIO.transmitPatternStatus.valid := statusValid io.patternGeneratorIO.transmitPatternStatus.bits := status when(io.patternGeneratorIO.transmitReq.fire) { - writeInProgress := true.B - readInProgress := true.B pattern := io.patternGeneratorIO.transmitReq.bits.pattern sideband := io.patternGeneratorIO.transmitReq.bits.sideband timeoutCycles := io.patternGeneratorIO.transmitReq.bits.timeoutCycles + patternCountMax := io.patternGeneratorIO.transmitReq.bits.patternCountMax + patternDetectedCountMax := io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax statusValid := false.B } - /** clock gating is not implemented, so for now, just send 128 bits of regular - * clock data - */ - val clockPatternShiftReg = RegInit( - "h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U, - ) - val patternToTransmit = WireInit(0.U(sbParams.sbNodeMsgWidth.W)) - val patternDetectedCount = RegInit(0.U(log2Ceil(128 * 2 + 1).W)) - val patternWrittenCount = RegInit(0.U(log2Ceil(2 + 1).W)) - - val patternWrittenCountMax = Seq( - TransmitPattern.CLOCK_64_LOW_32 -> 2.U, - ) - - val patternDetectedCountMax = Seq( - TransmitPattern.CLOCK_64_LOW_32 -> 128.U, - ) - - io.sidebandLaneIO.txData.valid := writeInProgress - io.sidebandLaneIO.txData.bits := patternToTransmit - io.sidebandLaneIO.rxData.ready := readInProgress - when(io.patternGeneratorIO.transmitPatternStatus.fire) { statusValid := false.B } + /** handle timeouts and completion */ when(inProgress) { timeoutCycles := timeoutCycles - 1.U when(timeoutCycles === 0.U) { status := MessageRequestStatusType.ERR statusValid := true.B - writeInProgress := false.B - readInProgress := false.B - patternWrittenCount := 0.U - patternDetectedCount := 0.U + patternWriter.reset := true.B + patternReader.reset := true.B }.elsewhen( - (patternWrittenCount >= MuxLookup(pattern, 0.U)( - patternWrittenCountMax, - )) && (patternDetectedCount >= MuxLookup(pattern, 0.U)( - patternDetectedCountMax, - )), + patternWriter.io.resp.complete && patternReader.io.resp.complete, ) { statusValid := true.B status := MessageRequestStatusType.SUCCESS - writeInProgress := false.B - readInProgress := false.B - patternWrittenCount := 0.U - patternDetectedCount := 0.U - } - } - - when(writeInProgress) { - switch(pattern) { - - /** Patterns may be different lengths, etc. so may be best to handle - * separately, for now - */ - is(TransmitPattern.CLOCK_64_LOW_32) { - patternToTransmit := clockPatternShiftReg( - sbParams.sbNodeMsgWidth - 1, - 0, - ) - when(io.sidebandLaneIO.txData.fire) { - /* clockPatternShiftReg := (clockPatternShiftReg >> - * sbParams.sbNodeMsgWidth.U).asUInt & */ - // (clockPatternShiftReg << - // (clockPatternShiftReg.getWidth.U - sbParams.sbNodeMsgWidth.U)) - printf("pattern written count: %d\n", patternWrittenCount) - patternWrittenCount := patternWrittenCount + 1.U - } - } - } - - } - - when(readInProgress) { - switch(pattern) { - - is(TransmitPattern.CLOCK_64_LOW_32) { - - assert( - sbParams.sbNodeMsgWidth == 128, - "comparing with 128 bit clock pattern", - ) - val patternToDetect = "h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U( - sbParams.sbNodeMsgWidth.W, - ) - when(io.sidebandLaneIO.rxData.fire) { - - /** detect clock UI pattern -- as long as the pattern is correctly - * aligned, this is simple - */ - when(io.sidebandLaneIO.rxData.bits === patternToDetect) { - patternDetectedCount := patternDetectedCount + sbParams.sbNodeMsgWidth.U - } - } - - } + patternWriter.reset := true.B + patternReader.reset := true.B } - } } diff --git a/src/main/scala/logphy/PatternReader.scala b/src/main/scala/logphy/PatternReader.scala new file mode 100644 index 0000000..c3affab --- /dev/null +++ b/src/main/scala/logphy/PatternReader.scala @@ -0,0 +1,84 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import interfaces.AfeParams +import sideband.SidebandParams + +/** TODO: implementation */ +class PatternReader( + sbParams: SidebandParams, + afeParams: AfeParams, + maxPatternCount: Int, +) extends Module { + private val maxPatternWidth = log2Ceil(maxPatternCount + 1) + val io = IO(new Bundle { + val request = Flipped(Valid(new Bundle { + val pattern = TransmitPattern() + val sideband = Bool() + val patternCountMax = UInt(maxPatternWidth.W) + })) + val resp = new Bundle { + val complete = Output(Bool()) + val inProgress = Output(Bool()) + val errorCount = Output(UInt(maxPatternWidth.W)) + } + val sbRxData = Flipped(Decoupled(Bits(sbParams.sbNodeMsgWidth.W))) + val mbRxData = + Flipped( + Decoupled(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)), + ) + }) + + private val readInProgress = RegInit(false.B) + val patternDetectedCount = RegInit(0.U(maxPatternWidth.W)) + io.resp.inProgress := readInProgress + io.resp.complete := patternDetectedCount >= io.request.bits.patternCountMax + + when(io.request.valid && !readInProgress) { + readInProgress := true.B + } + when(readInProgress) {} + + /** increment error count */ + val errorCount = RegInit(0.U(maxPatternWidth.W)) + io.resp.errorCount := errorCount + val errorCounter = Module(new ErrorCounter(afeParams)) + errorCounter.io.req.valid := false.B + errorCounter.io.req.bits := DontCare + when(readInProgress) { + when(errorCounter.io.req.valid) { + errorCount := errorCount + errorCounter.io.errorCount + } + } + + io.mbRxData.nodeq() + io.sbRxData.nodeq() + when(readInProgress) { + when(io.request.bits.sideband) { + io.sbRxData.ready := true.B + when(io.sbRxData.fire) { + assert(io.request.bits.pattern === TransmitPattern.CLOCK) + + val patternToDetect = WireInit( + ("h" + "aaaa" * (sbParams.sbNodeMsgWidth / 16)).U( + sbParams.sbNodeMsgWidth.W, + ), + ) + + /** just do an exact comparison */ + when(io.sbRxData.bits === patternToDetect) { + patternDetectedCount := patternDetectedCount + sbParams.sbNodeMsgWidth.U + } + } + }.otherwise { + io.mbRxData.ready := true.B + when(io.mbRxData.fire) { + errorCounter.io.req.bits.input := io.mbRxData.bits + errorCounter.io.req.bits.pattern := io.request.bits.pattern + errorCounter.io.req.valid := true.B + } + } + } +} diff --git a/src/main/scala/logphy/PatternWriter.scala b/src/main/scala/logphy/PatternWriter.scala new file mode 100644 index 0000000..66c7229 --- /dev/null +++ b/src/main/scala/logphy/PatternWriter.scala @@ -0,0 +1,133 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import sideband.SidebandParams +import interfaces._ + +class PatternWriter(sbParams: SidebandParams, afeParams: AfeParams) + extends Module { + val io = IO(new Bundle { + val request = Flipped(Valid(new Bundle { + val pattern = TransmitPattern() + val sideband = Bool() + val patternCountMax = UInt(32.W) + })) + val resp = Output(new Bundle { + val complete = Bool() + val inProgress = Bool() + }) + val sbTxData = Decoupled(Bits(sbParams.sbNodeMsgWidth.W)) + val mbTxData = + Decoupled(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)) + }) + + private val writeInProgress = RegInit(false.B) + io.resp.inProgress := writeInProgress + when(io.request.valid && !writeInProgress) { + writeInProgress := true.B + } + + val patternToTransmit = WireInit( + 0.U( + (afeParams.mbLanes * afeParams.mbSerializerRatio) + .max(sbParams.sbNodeMsgWidth) + .W, + ), + ) + + val patternWrittenCount = RegInit(0.U(32.W)) + io.resp.complete := patternWrittenCount >= io.request.bits.patternCountMax + val patternWritten = WireInit(false.B) + + io.sbTxData.noenq() + io.mbTxData.noenq() + when(!io.request.bits.sideband) { + io.mbTxData.valid := writeInProgress + io.mbTxData.bits := patternToTransmit + when(io.mbTxData.fire) { + patternWrittenCount := patternWrittenCount + (afeParams.mbLanes * afeParams.mbSerializerRatio).U + patternWritten := true.B + } + }.otherwise { + io.sbTxData.valid := writeInProgress + io.sbTxData.bits := patternToTransmit + when(io.sbTxData.fire) { + patternWrittenCount := patternWrittenCount + sbParams.sbNodeMsgWidth.U + patternWritten := true.B + } + + } + + val lfsrPatternGenerator = + Module( + new UCIeScrambler(afeParams, numLanes = afeParams.mbLanes), + ) + lfsrPatternGenerator.io.data_in := VecInit(Seq.fill(afeParams.mbLanes)(0.U)) + lfsrPatternGenerator.io.valid := false.B + + when(writeInProgress) { + switch(io.request.bits.pattern) { + + /** Patterns may be different lengths, etc. so may be best to handle + * separately, for now + */ + + is(TransmitPattern.CLOCK) { + + /** SB clock gating is implemented in the serializer, so just send 128 + * bits of regular clock data TODO: currently not long enough to use in + * MB, if ever used in MB need to make longer + */ + patternToTransmit := "haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U + } + is(TransmitPattern.LFSR) { + assert(io.request.bits.sideband === false.B) + val ratioBytes = afeParams.mbSerializerRatio / 8 + val patternBytes = VecInit( + Seq.fill(afeParams.mbLanes * ratioBytes)(0.U(8.W)), + ) + for (i <- 0 until ratioBytes) { + for (j <- 0 until afeParams.mbLanes) { + patternBytes(i * afeParams.mbLanes + j) := lfsrPatternGenerator.io + .data_out(j) + .asTypeOf(VecInit(Seq.fill(ratioBytes)(0.U(8.W))))(i) + } + } + printf(cf"patternBytes = $patternBytes\n") + patternToTransmit := patternBytes.asUInt + when(patternWritten) { + lfsrPatternGenerator.io.valid := true.B + } + } + is(TransmitPattern.VALTRAIN) { + val valtrain = VecInit( + Seq.fill(afeParams.mbLanes * afeParams.mbSerializerRatio / 8)( + "b1111_0000".U(8.W), + ), + ) + patternToTransmit := valtrain.asUInt + } + is(TransmitPattern.PER_LANE_ID) { + val perLaneId = VecInit(Seq.fill(afeParams.mbLanes)(0.U(16.W))) + for (i <- 0 until afeParams.mbLanes) { + perLaneId(i) := Cat("b1010".U(4.W), i.U(8.W), "b1010".U(4.W)) + } + val ratio16 = afeParams.mbSerializerRatio / 16 + val patternVec = VecInit.tabulate(afeParams.mbLanes, ratio16) { + (_, _) => 0.U(16.W) + } + for (i <- 0 until afeParams.mbLanes) { + for (j <- 0 until ratio16) { + patternVec(i)(j) := perLaneId(i) + } + } + patternToTransmit := patternVec.asUInt + } + + } + + } + +} diff --git a/src/main/scala/logphy/RdiBringup.scala b/src/main/scala/logphy/RdiBringup.scala index 6c98fc7..c2032c5 100644 --- a/src/main/scala/logphy/RdiBringup.scala +++ b/src/main/scala/logphy/RdiBringup.scala @@ -21,7 +21,6 @@ class RdiBringupIO extends Bundle { val plStallReq = Output(Bool()) val lpStallAck = Input(Bool()) - /** TODO: need to support lp link error */ val lpLinkError = Input(Bool()) } diff --git a/src/main/scala/Scrambler.scala b/src/main/scala/logphy/Scrambler.scala similarity index 59% rename from src/main/scala/Scrambler.scala rename to src/main/scala/logphy/Scrambler.scala index 2455757..afcb2fd 100644 --- a/src/main/scala/Scrambler.scala +++ b/src/main/scala/logphy/Scrambler.scala @@ -1,12 +1,13 @@ package edu.berkeley.cs.ucie.digital -package interfaces +package logphy +import chisel3.util._ import chisel3._ import chisel3.util.random._ +import edu.berkeley.cs.ucie.digital.interfaces.AfeParams class Scrambler( afeParams: AfeParams, - width: Int, seed: BigInt, ) extends Module { val io = IO(new Bundle { @@ -18,22 +19,24 @@ class Scrambler( val LFSR = Module( new FibonacciLFSR( 23, - Set(23, 21, 18, 15, 7, 2, 1), + Set(23, 21, 16, 8, 5, 2), Some(seed), XOR, - width, + afeParams.mbSerializerRatio, false, ), ) LFSR.io.increment := io.valid LFSR.io.seed.bits := VecInit(io.seed.asBools) LFSR.io.seed.valid := (reset.asBool) - io.data_out := LFSR.io.out.asUInt ^ io.data_in + val LFSR_flipped = Wire(UInt(16.W)) + LFSR_flipped := Reverse(LFSR.io.out.asUInt(22, 23 - 16)) + + io.data_out := LFSR_flipped ^ io.data_in } class UCIeScrambler( afeParams: AfeParams, - width: Int, numLanes: Int, ) extends Module { val io = IO(new Bundle { @@ -42,24 +45,25 @@ class UCIeScrambler( val data_out = Output(Vec(numLanes, UInt(afeParams.mbSerializerRatio.W))) }) val UCIe_seeds = List( - "1dbfbc", - "0607bb", - "1ec760", - "18c0db", - "010f12", - "19cfc9", - "0277ce", - "1bb807", + /** seeds have to be reversed so that LSB ends up in rightmost position */ + "00111101111111011011100", // "1dbfbc", + "11011101111000000110000", // "0607bb", + "00000110111000110111100", // "1ec760", + "11011011000000110001100", // "18c0db", + "01001000111100001000000", // "010f12", + "10010011111100111001100", // "19cfc9", + "01110011111011100100000", // "0277ce", + "11100000000111011101100", // "1bb807", ) val seeds = (for (i <- 0 until numLanes) yield UCIe_seeds(i % 8)).toList val scramblers = - seeds.map(seed => Module(new Scrambler(afeParams, width, BigInt(seed, 16)))) + seeds.map(seed => Module(new Scrambler(afeParams, BigInt(seed, 2)))) for (i <- 0 until scramblers.length) { scramblers(i).io.data_in := io.data_in(i) scramblers(i).io.valid := io.valid scramblers(i).reset := reset scramblers(i).clock := clock - scramblers(i).io.seed := ("h" + seeds(i)).U(23.W) + scramblers(i).io.seed := ("b" + seeds(i)).U(23.W) io.data_out(i) := scramblers(i).io.data_out } } diff --git a/src/test/scala/logphy/ErrorCounterTest.scala b/src/test/scala/logphy/ErrorCounterTest.scala new file mode 100644 index 0000000..3bcbc4f --- /dev/null +++ b/src/test/scala/logphy/ErrorCounterTest.scala @@ -0,0 +1,124 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +import interfaces.AfeParams + +class ErrorCounterTest extends AnyFlatSpec with ChiselScalatestTester { + val afeParams = AfeParams() + behavior of "error counter" + it should "correctly count errors for lfsr pattern" in { + test(new ErrorCounter(afeParams)) { c => + c.io.req.valid.poke(true.B) + c.io.req.bits.pattern.poke(TransmitPattern.LFSR) + + /** No errors */ + c.io.req.bits.input.poke( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc".U, + ) + c.io.errorCount.expect(0.U) + c.clock.step() + + /** 4 errors */ + c.io.req.bits.input.poke( + "h85d6_5241_12be_ad28_85d7_5241_13be_ad28_9b02_9901_9816_861d_9b02_9900_981e_861d".U, + ) + c.io.errorCount.expect(4.U) + c.clock.step() + + /** 7 errors */ + c.io.req.bits.input.poke( + "hac7c_d3b4_60e4_8428_ac7c_d0b0_66e4_8428_6bad_c683_4596_d3b8_6bfd_c683_4596_d3b8".U, + ) + c.io.errorCount.expect(7.U) + c.clock.step() + + c.io.req.valid.poke(false.B) + for (_ <- 0 until 10) { + c.clock.step() + } + + /** 0 errors */ + c.io.req.bits.input.poke( + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54".U, + ) + c.io.req.valid.poke(true.B) + c.io.errorCount.expect(0.U) + } + } + it should "correctly count errors for valtrain pattern" in { + test(new ErrorCounter(afeParams)) { c => + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + c.io.req.valid.poke(true.B) + c.io.req.bits.pattern.poke(TransmitPattern.VALTRAIN) + + /** No errors */ + c.io.req.bits.input.poke( + ("b" + "1111_0000" * (width / 8)).U, + ) + c.io.errorCount.expect(0.U) + c.clock.step() + + /** 4 errors */ + c.io.req.bits.input.poke( + ("b" + "1011_0100" + "1111_0000" * (width / 8 - 2) + "0111_0001").U, + ) + c.io.errorCount.expect(4.U) + c.clock.step() + + } + } + it should "correctly count errors for per-lane ID pattern" in { + test(new ErrorCounter(afeParams)) { c => + c.io.req.valid.poke(true.B) + c.io.req.bits.pattern.poke(TransmitPattern.PER_LANE_ID) + + /** No errors */ + c.io.req.bits.input.poke( + ("b" + + "1010_0000_1111_1010" + + "1010_0000_1110_1010" + + "1010_0000_1101_1010" + + "1010_0000_1100_1010" + + "1010_0000_1011_1010" + + "1010_0000_1010_1010" + + "1010_0000_1001_1010" + + "1010_0000_1000_1010" + + "1010_0000_0111_1010" + + "1010_0000_0110_1010" + + "1010_0000_0101_1010" + + "1010_0000_0100_1010" + + "1010_0000_0011_1010" + + "1010_0000_0010_1010" + + "1010_0000_0001_1010" + + "1010_0000_0000_1010").U, + ) + c.io.errorCount.expect(0.U) + c.clock.step() + + c.io.req.bits.input.poke( + ("b" + + "1010_0000_1111_1010" + + "1010_0000_1110_1010" + + "1010_0010_1101_1010" + + "1010_0000_1100_1010" + + "1010_0000_0011_1010" + + "1010_0000_1010_1010" + + "1010_0000_1001_1010" + + "1010_0000_1000_1010" + + "1010_0000_0111_1010" + + "1010_0000_0110_1010" + + "1010_0000_0100_1010" + + "1010_0000_0100_1010" + + "1010_0000_0011_1010" + + "1010_0000_0010_1010" + + "1010_0000_0001_1010" + + "0010_0000_0000_1010").U, + ) + c.io.errorCount.expect(4.U) + c.clock.step() + } + } +} diff --git a/src/test/scala/logphy/LogPhyLaneTest.scala b/src/test/scala/logphy/LogPhyLaneTest.scala index e8bb8ee..8039c4d 100644 --- a/src/test/scala/logphy/LogPhyLaneTest.scala +++ b/src/test/scala/logphy/LogPhyLaneTest.scala @@ -8,16 +8,15 @@ import freechips.rocketchip.util.AsyncQueueParams import org.scalatest.flatspec.AnyFlatSpec import interfaces._ +import scala.util.Random + class LogPhyLaneTest extends AnyFlatSpec with ChiselScalatestTester { val afeParams = AfeParams() val queueParams = new AsyncQueueParams() - behavior of "log phy TX lanes" + behavior of "log phy TX lanes no scramble" it should "correctly map TX bytes to their lanes" in { test(new SimLanes(afeParams, queueParams)) { c => - c.io.mainbandLaneIO.txData.initSource() - c.io.mainbandLaneIO.txData.setSourceClock(c.clock) - c.io.mainbandIo.txData.initSink() - c.io.mainbandIo.txData.setSinkClock(c.clock) + initPorts(c, false) c.io.mainbandLaneIO.txData.enqueueNow( "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888".U, @@ -25,34 +24,31 @@ class LogPhyLaneTest extends AnyFlatSpec with ChiselScalatestTester { c.io.mainbandIo.txData .expectDequeueNow( Vec.Lit( - "h1211".U, - "h3411".U, - "h5622".U, - "h7822".U, - "h9a33".U, - "hbc33".U, - "hde44".U, - "hf044".U, - "h0f55".U, - "hed55".U, - "hcb66".U, - "ha966".U, - "h8777".U, - "h6577".U, - "h4388".U, "h2188".U, + "h4388".U, + "h6577".U, + "h8777".U, + "ha966".U, + "hcb66".U, + "hed55".U, + "h0f55".U, + "hf044".U, + "hde44".U, + "hbc33".U, + "h9a33".U, + "h7822".U, + "h5622".U, + "h3411".U, + "h1211".U, ), ) } } - behavior of "log phy RX lanes" + behavior of "log phy RX lanes no scramble" it should "correctly map RX bytes to their lanes" in { test(new SimLanes(afeParams, queueParams)) { c => - c.io.mainbandIo.rxData.initSource() - c.io.mainbandIo.rxData.setSourceClock(c.clock) - c.io.mainbandLaneIO.rxData.initSink() - c.io.mainbandLaneIO.rxData.setSinkClock(c.clock) + initPorts(c, scramble = false) c.io.mainbandIo.rxData .enqueueNow( @@ -75,12 +71,141 @@ class LogPhyLaneTest extends AnyFlatSpec with ChiselScalatestTester { "h2188".U, ), ) - c.io.mainbandLaneIO.rxData.expectDequeueNow( + "h2143_6587_a9cb_ed0f_f0de_bc9a_7856_3412_8888_7777_6666_5555_4444_3333_2222_1111".U, + ) + + } + } + + behavior of "log phy TX lanes scramble" + it should "correctly map TX bytes to their lanes" in { + test(new SimLanes(afeParams, queueParams)) { c => + initPorts(c, scramble = true) + + c.io.mainbandLaneIO.txData.enqueueNow( "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888".U, ) + c.clock.step() + + c.io.mainbandIo.txData + .expectDequeueNow( + Vec.Lit( + "b1001111000110100".U, // "h2188".U ^ "1011_1111_1011_1100".U, + "b100010000110011".U, // "h4388".U ^ "b0000_0111_1011_1011".U, + "b1010001000010111".U, // "h6577".U ^ "b1100011101100000".U + "b100011110101100".U, // "h8777".U ^ "0b1100000011011011".U + "b1010011001110100".U, // "ha966".U ^ "0b0000111100010010".U + "b10010101111".U, // "hcb66".U ^ "0b1100111111001001".U + "b1001101010011011".U, // "hed55".U ^ "0b0111011111001110".U + "b1011011101010010".U, // "h0f55".U ^ "0b1011100000000111".U + + "b100111111111000".U, // "hf044".U ^ "b1011_1111_1011_1100" + "b1101100111111111".U, // "hde44".U ^ "b0000_0111_1011_1011" + "b111101101010011".U, // "hbc33".U, ^ "b1100011101100000".U + "b101101011101000".U, // "h9a33".U ^ "0b1100000011011011".U + "b111011100110000".U, // "h7822".U, ^ "0b0000111100010010".U + "b1001100111101011".U, // "h5622".U, ^ "0b1100111111001001".U + "b100001111011111".U, // "h3411".U, ^ "0b0111011111001110".U + "b1010101000010110".U, // "h1211".U, ^ "0b1011100000000111".U + ), + ) + + println() + println() + println() + + c.io.mainbandLaneIO.txData.enqueueNow( + "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888".U, + ) + + c.clock.step() + + c.io.mainbandIo.txData + .expectDequeueNow( + Vec.Lit( + "b100110010101".U, // "h2188".U ^ "0b0010100000011101".U + "b1110111000001110".U, // "h4388".U ^ "0b1010110110000110".U + "b1101101101101001".U, // "h6577".U ^ "1011_1110_0001_1110".U + "b1001010011101111".U, // "h8777".U ^ "0001_0011_1001_1000".U + "b1110100001100111".U, // "ha966".U ^ "0100_0001_0000_0001".U + "b1001100111111111".U, // "hcb66".U ^ "0101001010011001".U + "b11101001010111".U, // "hed55".U ^ "1101011100000010".U + "b1000101011001110".U, // "h0f55".U ^ "1000010110011011".U + + "b1101100001011001".U, // "hf044".U ^ "0b0010100000011101" + "b111001111000010".U, // "hde44".U ^ "0b1010110110000110" + "b1000101101".U, // "hbc33".U, ^ "1011_1110_0001_1110".U + "b1000100110101011".U, // "h9a33".U ^ "0001_0011_1001_1000".U + "b11100100100011".U, // "h7822".U, ^ "0100_0001_0000_0001".U + "b10010111011".U, // "h5622".U, ^ "0101001010011001".U + "b1110001100010011".U, // "h3411".U, ^ "1101011100000010".U + "b1001011110001010".U, // "h1211".U, ^ "1000010110011011".U + ), + ) + } + } + it should "tx data matches rx data" in { + test(new LanesLoopBack(afeParams, queueParams)) { c => + c.io.mainbandLaneIO.txData.initSource() + c.io.mainbandLaneIO.txData.setSourceClock(c.clock) + c.io.mainbandLaneIO.rxData.initSink() + c.io.mainbandLaneIO.rxData.setSinkClock(c.clock) + c.io.scramble.poke(true.B) + + val rand = new Random() + for (i <- 0 until 20) { + println("i: ", i) + val dataEnqueued = + BigInt(afeParams.mbLanes * afeParams.mbSerializerRatio, rand) + .U((afeParams.mbLanes * afeParams.mbSerializerRatio).W) + c.io.mainbandLaneIO.txData.enqueueNow( + dataEnqueued, + ) + c.clock.step() + c.io.mainbandLaneIO.rxData.expectDequeueNow( + dataEnqueued, + ) + c.clock.step() + + } + + } + } + + private def initPorts(c: SimLanes, scramble: Boolean): Unit = { + c.io.mainbandLaneIO.txData.initSource() + c.io.mainbandLaneIO.txData.setSourceClock(c.clock) + c.io.mainbandLaneIO.rxData.initSink() + c.io.mainbandLaneIO.rxData.setSinkClock(c.clock) + c.io.mainbandIo.txData.initSink() + c.io.mainbandIo.txData.setSinkClock(c.clock) + c.io.mainbandIo.rxData.initSource() + c.io.mainbandIo.rxData.setSourceClock(c.clock) + c.io.scramble.poke(scramble.B) + } + +} + +class LanesLoopBack( + afeParams: AfeParams, + queueParams: AsyncQueueParams, +) extends Module { + val io = IO(new Bundle { + val scramble = Input(Bool()) + val mainbandLaneIO = new MainbandLaneIO(afeParams) + }) + val lanes = Module(new SimLanes(afeParams, queueParams)) + lanes.io.scramble := io.scramble + lanes.io.mainbandLaneIO <> io.mainbandLaneIO + lanes.io.mainbandIo.txData <> lanes.io.mainbandIo.rxData + when(io.mainbandLaneIO.rxData.fire) { + printf("rxDataBits: %x\n", io.mainbandLaneIO.rxData.bits) + } + when(io.mainbandLaneIO.txData.fire) { + printf("txDataBits: %x\n", io.mainbandLaneIO.txData.bits) } } diff --git a/src/test/scala/logphy/PatternGeneratorTest.scala b/src/test/scala/logphy/PatternGeneratorTest.scala index 2e158ee..e9986b4 100644 --- a/src/test/scala/logphy/PatternGeneratorTest.scala +++ b/src/test/scala/logphy/PatternGeneratorTest.scala @@ -13,19 +13,29 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { val sbParams = SidebandParams() behavior of "sideband pattern generator" it should "detect clock pattern no delay" in { - test(new PatternGenerator(afeParams = afeParams, sbParams = sbParams)) { - c => - initPorts(c) - testClockPatternSideband(c) + test( + new PatternGenerator( + afeParams = afeParams, + sbParams = sbParams, + maxPatternCount = 1024, + ), + ) { c => + initPorts(c) + testClockPatternSideband(c) } } it should "detect clock pattern no delay twice" in { - test(new PatternGenerator(afeParams = afeParams, sbParams = sbParams)) { - c => - initPorts(c) - testClockPatternSideband(c) - testClockPatternSideband(c) + test( + new PatternGenerator( + afeParams = afeParams, + sbParams = sbParams, + maxPatternCount = 1024, + ), + ) { c => + initPorts(c) + testClockPatternSideband(c) + testClockPatternSideband(c) } } @@ -53,7 +63,7 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.patternGeneratorIO.transmitReq.enqueueNow( chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits).Lit( - _.pattern -> TransmitPattern.CLOCK_64_LOW_32, + _.pattern -> TransmitPattern.CLOCK, _.timeoutCycles -> 80.U, _.sideband -> true.B, ), diff --git a/src/test/scala/logphy/PatternReaderTest.scala b/src/test/scala/logphy/PatternReaderTest.scala new file mode 100644 index 0000000..7fd97c3 --- /dev/null +++ b/src/test/scala/logphy/PatternReaderTest.scala @@ -0,0 +1,53 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import sideband.SidebandParams +import interfaces._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec +class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { + val afeParams = AfeParams() + val sbParams = SidebandParams() + behavior of "pattern reader" + it should "detect SB clock pattern" in { + test(new PatternReader(sbParams, afeParams, 1024)) { c => + initPorts(c) + + c.io.request.bits.pattern.poke(TransmitPattern.CLOCK) + c.io.request.bits.patternCountMax.poke(sbParams.sbNodeMsgWidth * 4) + c.io.request.bits.sideband.poke(true.B) + c.io.request.valid.poke(true.B) + c.io.resp.complete.expect(false.B) + c.io.resp.errorCount.expect(0.U) + c.io.resp.inProgress.expect(false.B) + c.clock.step() + + val testVector = + Seq.fill(4)("haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) + + testVector.foreach(vec => { + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.sbRxData.enqueueNow(vec) + }) + + c.io.resp.complete.expect(true.B) + } + } + + private def initPorts(c: PatternReader): Unit = { + c.io.sbRxData.initSource() + c.io.sbRxData.setSourceClock(c.clock) + c.io.mbRxData.initSource() + c.io.mbRxData.setSourceClock(c.clock) + } + + it should "detect MB LFSR pattern" in {} + it should "detect MB LFSR pattern error count" in {} + it should "detect MB valtrain pattern" in {} + it should "detect MB valtrain pattern error count" in {} + it should "detect MB per-lane ID pattern" in {} + it should "detect MB per-lane ID pattern error count" in {} + +} diff --git a/src/test/scala/logphy/PatternWriterTest.scala b/src/test/scala/logphy/PatternWriterTest.scala new file mode 100644 index 0000000..74e0a40 --- /dev/null +++ b/src/test/scala/logphy/PatternWriterTest.scala @@ -0,0 +1,167 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import sideband.SidebandParams +import interfaces._ +import chiseltest._ +import org.scalatest.flatspec.AnyFlatSpec + +class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { + val afeParams = AfeParams() + val sbParams = SidebandParams() + behavior of "sideband pattern writer" + it should "send SB clock pattern" in { + test(new PatternWriter(sbParams, afeParams)) { c => + initPorts(c) + createRequest( + c, + TransmitPattern.CLOCK, + sideband = true, + patternCountMax = 512, + ) + + c.clock.step() + for (_ <- 0 until 512 / sbParams.sbNodeMsgWidth) { + c.io.mbTxData.expectInvalid() + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.sbTxData.expectDequeueNow( + ("h" + "aaaa" * (sbParams.sbNodeMsgWidth / 16)).U, + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + it should "send MB LFSR pattern" in { + test(new PatternWriter(sbParams, afeParams)) { c => + initPorts(c) + createRequest( + c, + TransmitPattern.LFSR, + false, + afeParams.mbSerializerRatio * afeParams.mbLanes * 4, + ) + + c.clock.step() + val mbWidth = afeParams.mbSerializerRatio * afeParams.mbLanes + val lfsrValues = + Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" + .U(mbWidth.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" + .U(mbWidth.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" + .U(mbWidth.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(mbWidth.W), + ) + for (i <- 0 until 4) { + c.io.sbTxData.expectInvalid() + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.mbTxData.expectDequeueNow( + lfsrValues(i), + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + it should "send MB valtrain pattern" in { + test(new PatternWriter(sbParams, afeParams)) { c => + initPorts(c) + createRequest( + c, + TransmitPattern.VALTRAIN, + sideband = false, + patternCountMax = 512, + ) + + c.clock.step() + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + for (_ <- 0 until 512 / width) { + c.io.sbTxData.expectInvalid() + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.mbTxData.expectDequeueNow( + ("b" + "1111_0000" * (width / 8)).U, + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + it should "send MB per-lane ID pattern" in { + test(new PatternWriter(sbParams, afeParams)) { c => + initPorts(c) + createRequest( + c, + TransmitPattern.PER_LANE_ID, + false, + 512, + ) + + c.clock.step() + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + for (_ <- 0 until 512 / width) { + c.io.sbTxData.expectInvalid() + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.mbTxData.expectDequeueNow( + ("b" + + "1010_0000_1111_1010" + + "1010_0000_1110_1010" + + "1010_0000_1101_1010" + + "1010_0000_1100_1010" + + "1010_0000_1011_1010" + + "1010_0000_1010_1010" + + "1010_0000_1001_1010" + + "1010_0000_1000_1010" + + "1010_0000_0111_1010" + + "1010_0000_0110_1010" + + "1010_0000_0101_1010" + + "1010_0000_0100_1010" + + "1010_0000_0011_1010" + + "1010_0000_0010_1010" + + "1010_0000_0001_1010" + + "1010_0000_0000_1010").U, + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + private def createRequest( + c: PatternWriter, + transmitPattern: TransmitPattern.Type, + sideband: Boolean, + patternCountMax: Int, + ): Unit = { + c.io.request.valid.poke(true.B) + c.io.request.bits.pattern.poke(transmitPattern) + c.io.request.bits.sideband.poke(sideband.B) + c.io.request.bits.patternCountMax.poke(patternCountMax.U) + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(false.B) + c.io.sbTxData.expectInvalid() + c.io.mbTxData.expectInvalid() + } + + private def initPorts(c: PatternWriter) = { + c.io.mbTxData.initSink() + c.io.mbTxData.setSinkClock(c.clock) + c.io.sbTxData.initSink() + c.io.sbTxData.setSinkClock(c.clock) + } + +} diff --git a/src/test/scala/Scrambler.scala b/src/test/scala/logphy/ScramblerTest.scala similarity index 65% rename from src/test/scala/Scrambler.scala rename to src/test/scala/logphy/ScramblerTest.scala index 80a4d14..e22ae53 100644 --- a/src/test/scala/Scrambler.scala +++ b/src/test/scala/logphy/ScramblerTest.scala @@ -1,15 +1,33 @@ package edu.berkeley.cs.ucie.digital -package interfaces +package logphy import chisel3._ import chiseltest._ +import edu.berkeley.cs.ucie.digital.interfaces.AfeParams import org.scalatest.funspec.AnyFunSpec class ScramblerTest extends AnyFunSpec with ChiselScalatestTester { describe("Scrambler") { + it("dummy test") { + test(new UCIeScrambler(afeParams = AfeParams(), numLanes = 16)) { c => + c.io.valid.poke(true.B) + for (i <- 0 until 16) { + c.io.data_in(i).poke(0.U) + } + for (_ <- 0 until 4) { + println() + c.io.valid.poke(true.B) + for (i <- 0 until 16) { + println(c.io.data_out(i).peek().litValue.toString(16)) + } + c.clock.step() + } + } + } + it("4 lane scrambler test") { - test(new UCIeScrambler(new AfeParams(), 16, 4)) { c => + test(new UCIeScrambler(afeParams = AfeParams(), numLanes = 4)) { c => c.reset.poke(true.B) c.clock.step() c.clock.step() @@ -21,6 +39,7 @@ class ScramblerTest extends AnyFunSpec with ChiselScalatestTester { c.io.data_in(1).poke(1012.U(16.W)) c.io.data_in(2).poke(823.U(16.W)) c.io.data_in(3).poke(134.U(16.W)) + c.io.data_out(0).expect(49085.U(16.W)) c.io.data_out(1).expect(1103.U(16.W)) c.io.data_out(2).expect(50263.U(16.W)) From 60f2eb16e20a9c7f015d7e88443b01e1b883908b Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 17 Jul 2024 18:34:41 -0700 Subject: [PATCH 02/12] finish patternreader --- src/main/scala/logphy/PatternReader.scala | 2 +- src/test/scala/logphy/PatternReaderTest.scala | 229 ++++++++++++++++-- 2 files changed, 214 insertions(+), 17 deletions(-) diff --git a/src/main/scala/logphy/PatternReader.scala b/src/main/scala/logphy/PatternReader.scala index c3affab..0a8a676 100644 --- a/src/main/scala/logphy/PatternReader.scala +++ b/src/main/scala/logphy/PatternReader.scala @@ -39,7 +39,6 @@ class PatternReader( when(io.request.valid && !readInProgress) { readInProgress := true.B } - when(readInProgress) {} /** increment error count */ val errorCount = RegInit(0.U(maxPatternWidth.W)) @@ -78,6 +77,7 @@ class PatternReader( errorCounter.io.req.bits.input := io.mbRxData.bits errorCounter.io.req.bits.pattern := io.request.bits.pattern errorCounter.io.req.valid := true.B + patternDetectedCount := patternDetectedCount + (afeParams.mbLanes * afeParams.mbSerializerRatio).U } } } diff --git a/src/test/scala/logphy/PatternReaderTest.scala b/src/test/scala/logphy/PatternReaderTest.scala index 7fd97c3..678072b 100644 --- a/src/test/scala/logphy/PatternReaderTest.scala +++ b/src/test/scala/logphy/PatternReaderTest.scala @@ -13,15 +13,8 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { it should "detect SB clock pattern" in { test(new PatternReader(sbParams, afeParams, 1024)) { c => initPorts(c) - - c.io.request.bits.pattern.poke(TransmitPattern.CLOCK) - c.io.request.bits.patternCountMax.poke(sbParams.sbNodeMsgWidth * 4) - c.io.request.bits.sideband.poke(true.B) - c.io.request.valid.poke(true.B) - c.io.resp.complete.expect(false.B) - c.io.resp.errorCount.expect(0.U) - c.io.resp.inProgress.expect(false.B) - c.clock.step() + createRequest(c, TransmitPattern.CLOCK, sbParams.sbNodeMsgWidth * 4, true) + c.io.mbRxData.ready.expect(false.B) val testVector = Seq.fill(4)("haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) @@ -29,12 +22,223 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { testVector.foreach(vec => { c.io.resp.complete.expect(false.B) c.io.resp.inProgress.expect(true.B) + c.io.mbRxData.ready.expect(false.B) c.io.sbRxData.enqueueNow(vec) }) + c.io.mbRxData.ready.expect(false.B) c.io.resp.complete.expect(true.B) } } + it should "detect MB LFSR pattern no errors" in { + test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + val testVector = + Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + makeMBTest(c, TransmitPattern.LFSR, testVector, 0) + } + } + it should "detect MB LFSR pattern error count" in { + test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + var testVector = Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_df60_bbbc_07ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b12_9911_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d3b0_60e4_f428_6bad_c683_4596_d3f8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a7b1_142b_3f8c_f317_a4b0_142b_3f8c_fa16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + makeMBTest(c, TransmitPattern.LFSR, testVector, 17) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + "hb877_cf0f_c0c7_07bf_b877_cf00_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_0901_981e_861d_9b02_9901_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c682_4596_d3b8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + makeMBTest(c, TransmitPattern.LFSR, testVector, 7) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_00ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b32_9901_981e_861d_9b02_9911_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_60ad_c683_4596_d3b8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a06_1c83_9fc1_5e5f_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + makeMBTest(c, TransmitPattern.LFSR, testVector, 13) + } + } + it should "detect MB valtrain pattern" in { + test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + var testVector = Seq( + BigInt("11110000" * (width / 8), 2).U, + BigInt("11110000" * (width / 8), 2).U, + BigInt("11110000" * (width / 8), 2).U, + BigInt("11110000" * (width / 8), 2).U, + ) + makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 0) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + toggleBits(BigInt("11110000" * (width / 8), 2), 0, 31, 249, 2).U, + toggleBits(BigInt("11110000" * (width / 8), 2), 1, 8, 9).U, + toggleBits(BigInt("11110000" * (width / 8), 2), 0, 2, 49, 9).U, + toggleBits(BigInt("11110000" * (width / 8), 2), 1).U, + ) + makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 12) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + toggleBits(BigInt("11110000" * (width / 8), 2), 3, 241).U, + toggleBits(BigInt("11110000" * (width / 8), 2), 9).U, + toggleBits(BigInt("11110000" * (width / 8), 2), 49, 0).U, + toggleBits(BigInt("11110000" * (width / 8), 2)).U, + ) + makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 5) + } + } + it should "detect MB per-lane ID pattern" in { + test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => + val pattern = BigInt( + "1010000011111010" + + "1010000011101010" + + "1010000011011010" + + "1010000011001010" + + "1010000010111010" + + "1010000010101010" + + "1010000010011010" + + "1010000010001010" + + "1010000001111010" + + "1010000001101010" + + "1010000001011010" + + "1010000001001010" + + "1010000000111010" + + "1010000000101010" + + "1010000000011010" + + "1010000000001010", + 2, + ) + + var testVector = Seq( + pattern.U, + pattern.U, + pattern.U, + pattern.U, + ) + makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 0) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + toggleBits(pattern, 0).U, + toggleBits(pattern, 240, 8, 9).U, + toggleBits(pattern, 0, 2, 49, 9).U, + toggleBits(pattern, 1, 200).U, + toggleBits(pattern, 1).U, + ) + makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 11) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + testVector = Seq( + toggleBits(pattern, 0).U, + toggleBits(pattern, 1, 240, 9).U, + ) + makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 4) + } + } + + private def toggleBits( + input: BigInt, + bits: Int*, + ): BigInt = { + var result = input + for (bit <- bits) { + result ^= BigInt(1) << bit + } + BigInt(result.toString(2), 2) + } + + private def makeMBTest( + c: PatternReader, + transmitPattern: TransmitPattern.Type, + testVector: Seq[UInt], + errorCountExpected: Int, + ): Unit = { + initPorts(c) + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + createRequest( + c, + transmitPattern, + patternCountMax = width * testVector.length, + sideband = false, + ) + c.io.sbRxData.ready.expect(false.B) + + testVector.foreach(vec => { + c.io.resp.complete.expect(false.B) + c.io.resp.inProgress.expect(true.B) + c.io.sbRxData.ready.expect(false.B) + c.io.mbRxData.enqueueNow(vec) + }) + + c.io.sbRxData.ready.expect(false.B) + c.io.resp.complete.expect(true.B) + c.io.resp.errorCount.expect(errorCountExpected.U) + } + private def createRequest( + c: PatternReader, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + sideband: Boolean, + ): Unit = { + c.io.request.bits.pattern.poke(transmitPattern) + c.io.request.bits.patternCountMax.poke(patternCountMax) + c.io.request.bits.sideband.poke(sideband.B) + c.io.request.valid.poke(true.B) + c.io.resp.complete.expect(false.B) + c.io.resp.errorCount.expect(0.U) + c.io.resp.inProgress.expect(false.B) + c.clock.step() + } private def initPorts(c: PatternReader): Unit = { c.io.sbRxData.initSource() @@ -43,11 +247,4 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { c.io.mbRxData.setSourceClock(c.clock) } - it should "detect MB LFSR pattern" in {} - it should "detect MB LFSR pattern error count" in {} - it should "detect MB valtrain pattern" in {} - it should "detect MB valtrain pattern error count" in {} - it should "detect MB per-lane ID pattern" in {} - it should "detect MB per-lane ID pattern error count" in {} - } From 10d803c9f0d9d54f03bdc98376b2cbbc37ca7137 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 17 Jul 2024 21:43:07 -0700 Subject: [PATCH 03/12] update pattern generator to use reader/writer --- src/main/scala/logphy/LinkTrainingFSM.scala | 2 + src/main/scala/logphy/LogPhyTypes.scala | 2 +- src/main/scala/logphy/MBInitFSM.scala | 3 +- src/main/scala/logphy/PatternGenerator.scala | 41 ++++++++++++++----- src/main/scala/logphy/PatternWriter.scala | 12 ++++-- src/test/scala/logphy/MBInitFSMTest.scala | 6 +-- .../scala/logphy/PatternGeneratorTest.scala | 9 ++-- src/test/scala/logphy/PatternWriterTest.scala | 8 ++-- 8 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index 47a00d1..09d3def 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -17,6 +17,7 @@ case class LinkTrainingParams( maxSBMessageSize: Int = 128, mbTrainingParams: MBTrainingParams = MBTrainingParams(), sbClockFreqAnalog: Int = 800_000_000, + maxPatternCount: Int = 1 << 32, ) class SidebandFSMIO( @@ -111,6 +112,7 @@ class LinkTrainingFSM( new MBInitFSM( linkTrainingParams, afeParams, + maxPatternCount = linkTrainingParams.maxPatternCount, ), ) mbInit.reset := ((nextState === LinkTrainingState.mbInit) && (currentState =/= LinkTrainingState.mbInit)) || reset.asBool diff --git a/src/main/scala/logphy/LogPhyTypes.scala b/src/main/scala/logphy/LogPhyTypes.scala index 1220529..af4eab7 100644 --- a/src/main/scala/logphy/LogPhyTypes.scala +++ b/src/main/scala/logphy/LogPhyTypes.scala @@ -106,7 +106,7 @@ class MainbandLaneIO( ) val rxData = - Valid(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)) + Decoupled(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)) } class SidebandLaneIO( diff --git a/src/main/scala/logphy/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index 1b88d61..754950e 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -18,11 +18,12 @@ case class MBTrainingParams( class MBInitFSM( linkTrainingParams: LinkTrainingParams, afeParams: AfeParams, + maxPatternCount: Int, ) extends Module { val io = IO(new Bundle { val sbTrainIO = Flipped(new SBMsgWrapperTrainIO) - val patternGeneratorIO = Flipped(new PatternGeneratorIO) + val patternGeneratorIO = Flipped(new PatternGeneratorIO(maxPatternCount)) val transition = Output(Bool()) val error = Output(Bool()) }) diff --git a/src/main/scala/logphy/PatternGenerator.scala b/src/main/scala/logphy/PatternGenerator.scala index bc9dc17..378e7fd 100644 --- a/src/main/scala/logphy/PatternGenerator.scala +++ b/src/main/scala/logphy/PatternGenerator.scala @@ -6,46 +6,64 @@ import chisel3.util._ import sideband.SidebandParams import interfaces._ -class PatternGeneratorIO extends Bundle { +class PatternGeneratorIO(maxPatternCount: Int) extends Bundle { + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val transmitReq = Flipped(Decoupled(new Bundle { val pattern = TransmitPattern() - val timeoutCycles = UInt(32.W) + val timeoutCycles = UInt(maxPatternCountWidth.W) val sideband = Bool() - val patternCountMax = UInt(32.W) - val patternDetectedCountMax = UInt(32.W) + val patternCountMax = UInt(maxPatternCountWidth.W) + val patternDetectedCountMax = UInt(maxPatternCountWidth.W) })) val transmitPatternStatus = Decoupled(MessageRequestStatusType()) } -/** TODO: incorporate reader and writer */ class PatternGenerator( afeParams: AfeParams, sbParams: SidebandParams, maxPatternCount: Int, ) extends Module { + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val io = IO(new Bundle { - val patternGeneratorIO = new PatternGeneratorIO() + val patternGeneratorIO = new PatternGeneratorIO(maxPatternCount) val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) val sidebandLaneIO = Flipped(new SidebandLaneIO(sbParams)) }) - val patternWriter = Module(new PatternWriter(sbParams, afeParams)) + val patternWriter = Module( + new PatternWriter(sbParams, afeParams, maxPatternCount), + ) val patternReader = Module( new PatternReader(sbParams, afeParams, maxPatternCount), ) + patternWriter.io.sbTxData <> io.sidebandLaneIO.txData + patternWriter.io.mbTxData <> io.mainbandLaneIO.txData + patternReader.io.sbRxData <> io.sidebandLaneIO.rxData + patternReader.io.mbRxData <> io.mainbandLaneIO.rxData + private val inProgress = WireInit( patternWriter.io.resp.inProgress || patternReader.io.resp.inProgress, ) + private val inputsValid = RegInit(false.B) private val pattern = RegInit(TransmitPattern.CLOCK) private val sideband = RegInit(true.B) - private val timeoutCycles = RegInit(0.U(32.W)) + private val timeoutCycles = RegInit(0.U(maxPatternCountWidth.W)) private val status = RegInit(MessageRequestStatusType.SUCCESS) private val statusValid = RegInit(false.B) - private val patternCountMax = RegInit(0.U(32.W)) - private val patternDetectedCountMax = RegInit(0.U(32.W)) + private val patternCountMax = RegInit(0.U(maxPatternCountWidth.W)) + private val patternDetectedCountMax = RegInit(0.U(maxPatternCountWidth.W)) + + patternWriter.io.request.bits.pattern := pattern + patternWriter.io.request.bits.patternCountMax := patternCountMax + patternWriter.io.request.bits.sideband := sideband + patternReader.io.request.bits.pattern := pattern + patternReader.io.request.bits.patternCountMax := patternDetectedCountMax + patternReader.io.request.bits.sideband := sideband + patternWriter.io.request.valid := inputsValid + patternReader.io.request.valid := inputsValid io.patternGeneratorIO.transmitReq.ready := (inProgress === false.B) io.patternGeneratorIO.transmitPatternStatus.valid := statusValid @@ -57,6 +75,7 @@ class PatternGenerator( timeoutCycles := io.patternGeneratorIO.transmitReq.bits.timeoutCycles patternCountMax := io.patternGeneratorIO.transmitReq.bits.patternCountMax patternDetectedCountMax := io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax + inputsValid := true.B statusValid := false.B } @@ -72,6 +91,7 @@ class PatternGenerator( statusValid := true.B patternWriter.reset := true.B patternReader.reset := true.B + inputsValid := false.B }.elsewhen( patternWriter.io.resp.complete && patternReader.io.resp.complete, ) { @@ -79,6 +99,7 @@ class PatternGenerator( status := MessageRequestStatusType.SUCCESS patternWriter.reset := true.B patternReader.reset := true.B + inputsValid := false.B } } diff --git a/src/main/scala/logphy/PatternWriter.scala b/src/main/scala/logphy/PatternWriter.scala index 66c7229..4a15f86 100644 --- a/src/main/scala/logphy/PatternWriter.scala +++ b/src/main/scala/logphy/PatternWriter.scala @@ -6,13 +6,17 @@ import chisel3.util._ import sideband.SidebandParams import interfaces._ -class PatternWriter(sbParams: SidebandParams, afeParams: AfeParams) - extends Module { +class PatternWriter( + sbParams: SidebandParams, + afeParams: AfeParams, + maxPatternCount: Int, +) extends Module { + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val io = IO(new Bundle { val request = Flipped(Valid(new Bundle { val pattern = TransmitPattern() val sideband = Bool() - val patternCountMax = UInt(32.W) + val patternCountMax = UInt(maxPatternCountWidth.W) })) val resp = Output(new Bundle { val complete = Bool() @@ -37,7 +41,7 @@ class PatternWriter(sbParams: SidebandParams, afeParams: AfeParams) ), ) - val patternWrittenCount = RegInit(0.U(32.W)) + val patternWrittenCount = RegInit(0.U(maxPatternCountWidth.W)) io.resp.complete := patternWrittenCount >= io.request.bits.patternCountMax val patternWritten = WireInit(false.B) diff --git a/src/test/scala/logphy/MBInitFSMTest.scala b/src/test/scala/logphy/MBInitFSMTest.scala index 12fed83..1a03dca 100644 --- a/src/test/scala/logphy/MBInitFSMTest.scala +++ b/src/test/scala/logphy/MBInitFSMTest.scala @@ -96,7 +96,7 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { behavior of "MBInitFSM" it should "perform parameter exchange -- basic sim" in { test( - new MBInitFSM(linkTrainingParams, afeParams), + new MBInitFSM(linkTrainingParams, afeParams, maxPatternCount = 1 << 32), ) { c => initializePorts(c) initialCheck(c) @@ -113,7 +113,7 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { behavior of "MBInitFSM" it should "perform parameter exchange with delays" in { test( - new MBInitFSM(linkTrainingParams, afeParams), + new MBInitFSM(linkTrainingParams, afeParams, maxPatternCount = 1 << 32), ) { c => initializePorts(c) initialCheck(c) @@ -139,7 +139,7 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { behavior of "MBInitFSM" it should "timeout" in { test( - new MBInitFSM(linkTrainingParams, afeParams), + new MBInitFSM(linkTrainingParams, afeParams, maxPatternCount = 1 << 32), ) { c => c.clock.setTimeout((0.008 * sbClockFreq).toInt + 20) initializePorts(c) diff --git a/src/test/scala/logphy/PatternGeneratorTest.scala b/src/test/scala/logphy/PatternGeneratorTest.scala index e9986b4..1bdfba6 100644 --- a/src/test/scala/logphy/PatternGeneratorTest.scala +++ b/src/test/scala/logphy/PatternGeneratorTest.scala @@ -24,7 +24,6 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { testClockPatternSideband(c) } } - it should "detect clock pattern no delay twice" in { test( new PatternGenerator( @@ -55,15 +54,19 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { } private def testClockPatternSideband(c: PatternGenerator): Unit = { + val length = 2 + c.io.patternGeneratorIO.transmitReq.ready.expect(true) c.io.sidebandLaneIO.rxData.ready.expect(false) + c.io.mainbandLaneIO.rxData.ready.expect(false) c.io.sidebandLaneIO.txData.expectInvalid() + c.io.mainbandLaneIO.txData.expectInvalid() c.io.patternGeneratorIO.transmitPatternStatus.expectInvalid() - c.clock.step() - c.io.patternGeneratorIO.transmitReq.enqueueNow( chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits).Lit( _.pattern -> TransmitPattern.CLOCK, + _.patternCountMax -> (length * sbParams.sbNodeMsgWidth).U, + _.patternDetectedCountMax -> (length * sbParams.sbNodeMsgWidth).U, _.timeoutCycles -> 80.U, _.sideband -> true.B, ), diff --git a/src/test/scala/logphy/PatternWriterTest.scala b/src/test/scala/logphy/PatternWriterTest.scala index 74e0a40..75aa630 100644 --- a/src/test/scala/logphy/PatternWriterTest.scala +++ b/src/test/scala/logphy/PatternWriterTest.scala @@ -12,7 +12,7 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { val sbParams = SidebandParams() behavior of "sideband pattern writer" it should "send SB clock pattern" in { - test(new PatternWriter(sbParams, afeParams)) { c => + test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) createRequest( c, @@ -37,7 +37,7 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { } it should "send MB LFSR pattern" in { - test(new PatternWriter(sbParams, afeParams)) { c => + test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) createRequest( c, @@ -74,7 +74,7 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { } it should "send MB valtrain pattern" in { - test(new PatternWriter(sbParams, afeParams)) { c => + test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) createRequest( c, @@ -100,7 +100,7 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { } it should "send MB per-lane ID pattern" in { - test(new PatternWriter(sbParams, afeParams)) { c => + test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) createRequest( c, From d6b0a81e059dd8feeb5a83eb6899475ef9b22f74 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 17 Jul 2024 22:43:13 -0700 Subject: [PATCH 04/12] add MB pattern generator tests --- src/main/scala/logphy/ErrorCounter.scala | 1 + src/main/scala/logphy/LinkTrainingFSM.scala | 10 +- src/main/scala/logphy/MBInitFSM.scala | 2 +- src/main/scala/logphy/PatternGenerator.scala | 12 +- src/main/scala/logphy/PatternWriter.scala | 1 - src/test/scala/logphy/MBInitFSMTest.scala | 2 +- .../scala/logphy/PatternGeneratorTest.scala | 152 ++++++++++++++++-- 7 files changed, 156 insertions(+), 24 deletions(-) diff --git a/src/main/scala/logphy/ErrorCounter.scala b/src/main/scala/logphy/ErrorCounter.scala index e3c79e2..b0d9e21 100644 --- a/src/main/scala/logphy/ErrorCounter.scala +++ b/src/main/scala/logphy/ErrorCounter.scala @@ -5,6 +5,7 @@ import chisel3._ import chisel3.util._ import interfaces.AfeParams +/** TODO: need to do per-lane, not just aggregate */ class ErrorCounter(afeParams: AfeParams) extends Module { val width = afeParams.mbLanes * afeParams.mbSerializerRatio diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index 09d3def..b22f54a 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -70,7 +70,7 @@ class LinkTrainingFSM( // io.mainbandLaneIO <> patternGenerator.io.mainbandLaneIO patternGenerator.io.patternGeneratorIO.transmitReq.noenq() - patternGenerator.io.patternGeneratorIO.transmitPatternStatus.nodeq() + patternGenerator.io.patternGeneratorIO.resp.nodeq() sbMsgWrapper.io.trainIO.msgReq.noenq() sbMsgWrapper.io.trainIO.msgReqStatus.nodeq() @@ -155,7 +155,7 @@ class LinkTrainingFSM( mbInit.io.sbTrainIO.msgReq.nodeq() mbInit.io.sbTrainIO.msgReqStatus.noenq() mbInit.io.patternGeneratorIO.transmitReq.nodeq() - mbInit.io.patternGeneratorIO.transmitPatternStatus.noenq() + mbInit.io.patternGeneratorIO.resp.noenq() /** TODO: should these ever be false? */ io.sidebandFSMIO.rxEn := true.B @@ -240,13 +240,13 @@ class LinkTrainingFSM( } } is(SBInitSubState.WAIT_CLOCK) { - patternGenerator.io.patternGeneratorIO.transmitPatternStatus.ready := true.B + patternGenerator.io.patternGeneratorIO.resp.ready := true.B msgSource := MsgSource.PATTERN_GENERATOR when( - patternGenerator.io.patternGeneratorIO.transmitPatternStatus.fire, + patternGenerator.io.patternGeneratorIO.resp.fire, ) { switch( - patternGenerator.io.patternGeneratorIO.transmitPatternStatus.bits, + patternGenerator.io.patternGeneratorIO.resp.bits.status, ) { is(MessageRequestStatusType.SUCCESS) { sbInitSubState := SBInitSubState.SB_OUT_OF_RESET_EXCH diff --git a/src/main/scala/logphy/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index 754950e..44a02e9 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -55,7 +55,7 @@ class MBInitFSM( io.sbTrainIO.msgReq.noenq() io.sbTrainIO.msgReqStatus.nodeq() io.patternGeneratorIO.transmitReq.noenq() - io.patternGeneratorIO.transmitPatternStatus.nodeq() + io.patternGeneratorIO.resp.nodeq() /** Initialize params */ private val voltageSwing = RegInit( diff --git a/src/main/scala/logphy/PatternGenerator.scala b/src/main/scala/logphy/PatternGenerator.scala index 378e7fd..e34f6a0 100644 --- a/src/main/scala/logphy/PatternGenerator.scala +++ b/src/main/scala/logphy/PatternGenerator.scala @@ -15,7 +15,10 @@ class PatternGeneratorIO(maxPatternCount: Int) extends Bundle { val patternCountMax = UInt(maxPatternCountWidth.W) val patternDetectedCountMax = UInt(maxPatternCountWidth.W) })) - val transmitPatternStatus = Decoupled(MessageRequestStatusType()) + val resp = Decoupled(new Bundle { + val status = MessageRequestStatusType() + val errorCount = UInt(maxPatternCountWidth.W) + }) } @@ -66,8 +69,9 @@ class PatternGenerator( patternReader.io.request.valid := inputsValid io.patternGeneratorIO.transmitReq.ready := (inProgress === false.B) - io.patternGeneratorIO.transmitPatternStatus.valid := statusValid - io.patternGeneratorIO.transmitPatternStatus.bits := status + io.patternGeneratorIO.resp.valid := statusValid + io.patternGeneratorIO.resp.bits.status := status + io.patternGeneratorIO.resp.bits.errorCount := patternReader.io.resp.errorCount when(io.patternGeneratorIO.transmitReq.fire) { pattern := io.patternGeneratorIO.transmitReq.bits.pattern @@ -79,7 +83,7 @@ class PatternGenerator( statusValid := false.B } - when(io.patternGeneratorIO.transmitPatternStatus.fire) { + when(io.patternGeneratorIO.resp.fire) { statusValid := false.B } diff --git a/src/main/scala/logphy/PatternWriter.scala b/src/main/scala/logphy/PatternWriter.scala index 4a15f86..de67a43 100644 --- a/src/main/scala/logphy/PatternWriter.scala +++ b/src/main/scala/logphy/PatternWriter.scala @@ -99,7 +99,6 @@ class PatternWriter( .asTypeOf(VecInit(Seq.fill(ratioBytes)(0.U(8.W))))(i) } } - printf(cf"patternBytes = $patternBytes\n") patternToTransmit := patternBytes.asUInt when(patternWritten) { lfsrPatternGenerator.io.valid := true.B diff --git a/src/test/scala/logphy/MBInitFSMTest.scala b/src/test/scala/logphy/MBInitFSMTest.scala index 1a03dca..1bd138b 100644 --- a/src/test/scala/logphy/MBInitFSMTest.scala +++ b/src/test/scala/logphy/MBInitFSMTest.scala @@ -249,7 +249,7 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sbTrainIO.msgReq.initSink().setSinkClock(c.clock) c.io.sbTrainIO.msgReqStatus.initSource().setSourceClock(c.clock) c.io.patternGeneratorIO.transmitReq.initSink().setSinkClock(c.clock) - c.io.patternGeneratorIO.transmitPatternStatus + c.io.patternGeneratorIO.resp .initSource() .setSourceClock(c.clock) } diff --git a/src/test/scala/logphy/PatternGeneratorTest.scala b/src/test/scala/logphy/PatternGeneratorTest.scala index 1bdfba6..f75092f 100644 --- a/src/test/scala/logphy/PatternGeneratorTest.scala +++ b/src/test/scala/logphy/PatternGeneratorTest.scala @@ -37,12 +37,74 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { testClockPatternSideband(c) } } + behavior of "mainband pattern generator" + it should "detect MB LFSR pattern" in { + test( + new PatternGenerator( + afeParams = afeParams, + sbParams = sbParams, + maxPatternCount = 1024, + ), + ) { c => + initPorts(c) + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + + val rxReceived = Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + + val expectedTx = Seq( + "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" + .U(width.W), + "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" + .U(width.W), + "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" + .U(width.W), + "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" + .U(width.W), + ) + + /** expected case with no errors */ + testMainband( + c = c, + transmitPattern = TransmitPattern.LFSR, + patternCountMax = 4, + patternDetectedCountMax = 4, + timeoutCycles = 80, + mainbandRx = rxReceived, + mainbandTx = expectedTx, + expectedResult = MessageRequestStatusType.SUCCESS, + expectedErrorCount = 0, + ) + + } + } + + it should "handle MB timeouts" in { + test( + new PatternGenerator( + afeParams = afeParams, + sbParams = sbParams, + maxPatternCount = 1024, + ), + ) { c => + initPorts(c) + assert(false, "TODO") + } + } private def initPorts(c: PatternGenerator) = { c.io.patternGeneratorIO.transmitReq .initSource() .setSourceClock(c.clock) - c.io.patternGeneratorIO.transmitPatternStatus + c.io.patternGeneratorIO.resp .initSink() .setSinkClock(c.clock) c.io.sidebandLaneIO.rxData @@ -51,26 +113,50 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData .initSink() .setSinkClock(c.clock) + c.io.mainbandLaneIO.rxData + .initSource() + .setSourceClock(c.clock) + c.io.mainbandLaneIO.txData + .initSink() + .setSinkClock(c.clock) } - private def testClockPatternSideband(c: PatternGenerator): Unit = { - val length = 2 - + private def createRequest( + c: PatternGenerator, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + patternDetectedCountMax: Int, + timeoutCycles: Int, + sideband: Boolean, + ): Unit = { c.io.patternGeneratorIO.transmitReq.ready.expect(true) c.io.sidebandLaneIO.rxData.ready.expect(false) c.io.mainbandLaneIO.rxData.ready.expect(false) c.io.sidebandLaneIO.txData.expectInvalid() c.io.mainbandLaneIO.txData.expectInvalid() - c.io.patternGeneratorIO.transmitPatternStatus.expectInvalid() + c.io.patternGeneratorIO.resp.expectInvalid() c.io.patternGeneratorIO.transmitReq.enqueueNow( chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits).Lit( - _.pattern -> TransmitPattern.CLOCK, - _.patternCountMax -> (length * sbParams.sbNodeMsgWidth).U, - _.patternDetectedCountMax -> (length * sbParams.sbNodeMsgWidth).U, - _.timeoutCycles -> 80.U, - _.sideband -> true.B, + _.pattern -> transmitPattern, + _.patternCountMax -> patternCountMax.U, + _.patternDetectedCountMax -> patternDetectedCountMax.U, + _.timeoutCycles -> timeoutCycles.U, + _.sideband -> sideband.B, ), ) + } + + private def testClockPatternSideband(c: PatternGenerator): Unit = { + val length = 2 + + createRequest( + c, + TransmitPattern.CLOCK, + length * sbParams.sbNodeMsgWidth, + length * sbParams.sbNodeMsgWidth, + 80, + true, + ) val testVector = Seq.fill(2)("haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) @@ -81,7 +167,49 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData.expectDequeueSeq(testVector) }.join() - c.io.patternGeneratorIO.transmitPatternStatus - .expectDequeue(MessageRequestStatusType.SUCCESS) + c.io.patternGeneratorIO.resp + .expectDequeue( + chiselTypeOf(c.io.patternGeneratorIO.resp.bits).Lit( + _.status -> MessageRequestStatusType.SUCCESS, + _.errorCount -> 0.U, + ), + ) + } + + private def testMainband( + c: PatternGenerator, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + patternDetectedCountMax: Int, + timeoutCycles: Int, + mainbandRx: Seq[UInt], + mainbandTx: Seq[UInt], + expectedResult: MessageRequestStatusType.Type, + expectedErrorCount: Int, + ): Unit = { + + createRequest( + c, + transmitPattern, + patternCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, + patternDetectedCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, + timeoutCycles, + false, + ) + + fork { + c.io.mainbandLaneIO.rxData.enqueueSeq(mainbandRx) + }.fork { + c.io.mainbandLaneIO.txData.expectDequeueSeq(mainbandTx) + }.join() + + c.io.patternGeneratorIO.resp + .expectDequeue( + chiselTypeOf(c.io.patternGeneratorIO.resp.bits).Lit( + _.status -> expectedResult, + _.errorCount -> expectedErrorCount.U, + ), + ) + } } From 175d8c080ad4e88ee335d1ed9d692598e19332af Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Thu, 25 Jul 2024 11:01:27 -0700 Subject: [PATCH 05/12] make per-lane error counting, change RDI data mapper to be LSB-first, begin to integrate with FSM --- src/main/scala/logphy/DataWidthCoupler.scala | 4 +- src/main/scala/logphy/ErrorCounter.scala | 42 +-- src/main/scala/logphy/Lanes.scala | 90 +++-- src/main/scala/logphy/LinkTrainingFSM.scala | 74 ++-- src/main/scala/logphy/LogPhyTypes.scala | 10 +- src/main/scala/logphy/MBInitFSM.scala | 9 +- src/main/scala/logphy/MBTrainer.scala | 118 +++++++ src/main/scala/logphy/PatternGenerator.scala | 55 +-- src/main/scala/logphy/PatternReader.scala | 32 +- src/main/scala/logphy/PatternWriter.scala | 45 +-- src/main/scala/logphy/RdiDataMapper.scala | 7 +- src/main/scala/logphy/SBMsgWrapper.scala | 205 ++++++----- src/main/scala/sideband/sb-msg-encoding.scala | 6 + src/test/scala/logphy/ErrorCounterTest.scala | 217 +++++++++--- .../scala/logphy/LinkTrainingFSMTest.scala | 19 +- src/test/scala/logphy/LogPhyLaneTest.scala | 2 +- src/test/scala/logphy/MBTrainerTest.scala | 11 + .../scala/logphy/PatternGeneratorTest.scala | 240 ++++++++++--- src/test/scala/logphy/PatternReaderTest.scala | 324 ++++++++++++------ src/test/scala/logphy/PatternWriterTest.scala | 149 +++++--- src/test/scala/logphy/RdiDataMapperTest.scala | 22 +- src/test/scala/logphy/SBMsgWrapperTest.scala | 10 +- src/test/scala/logphy/TestUtils.scala | 113 ++++++ 23 files changed, 1251 insertions(+), 553 deletions(-) create mode 100644 src/main/scala/logphy/MBTrainer.scala create mode 100644 src/test/scala/logphy/MBTrainerTest.scala create mode 100644 src/test/scala/logphy/TestUtils.scala diff --git a/src/main/scala/logphy/DataWidthCoupler.scala b/src/main/scala/logphy/DataWidthCoupler.scala index 0b6aef3..1390905 100644 --- a/src/main/scala/logphy/DataWidthCoupler.scala +++ b/src/main/scala/logphy/DataWidthCoupler.scala @@ -51,7 +51,7 @@ class DataWidthCoupler(params: DataWidthCouplerParams) extends Module { is(State.CHUNK_OR_COLLECT) { io.out.bits := inData .asTypeOf(Vec(ratio, Bits(params.outWidth.W)))( - (ratio - 1).U - chunkCounter, + chunkCounter, ) io.out.valid := true.B when(io.out.fire) { @@ -86,7 +86,7 @@ class DataWidthCoupler(params: DataWidthCouplerParams) extends Module { is(State.IDLE) { io.in.ready := true.B when(io.in.fire) { - inData((ratio - 1).U - inSliceCounter) := io.in.bits + inData(inSliceCounter) := io.in.bits inSliceCounter := inSliceCounter + 1.U } when(inSliceCounter === (ratio - 1).U) { diff --git a/src/main/scala/logphy/ErrorCounter.scala b/src/main/scala/logphy/ErrorCounter.scala index b0d9e21..508f893 100644 --- a/src/main/scala/logphy/ErrorCounter.scala +++ b/src/main/scala/logphy/ErrorCounter.scala @@ -7,14 +7,17 @@ import interfaces.AfeParams /** TODO: need to do per-lane, not just aggregate */ class ErrorCounter(afeParams: AfeParams) extends Module { - val width = afeParams.mbLanes * afeParams.mbSerializerRatio val io = IO(new Bundle { val req = Flipped(Valid(new Bundle { val pattern = TransmitPattern() - val input = Input(UInt(width.W)) + val input = Input( + Vec(afeParams.mbLanes, UInt(afeParams.mbSerializerRatio.W)), + ) })) - val errorCount = Output(UInt(log2Ceil(width + 1).W)) + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(log2Ceil(afeParams.mbSerializerRatio + 1).W)), + ) }) val lfsr = Module( @@ -26,7 +29,11 @@ class ErrorCounter(afeParams: AfeParams) extends Module { Seq.fill(afeParams.mbLanes)(0.U(afeParams.mbSerializerRatio.W)), ) - val expected = WireInit(0.U(width.W)) + val expected = WireInit( + VecInit( + Seq.fill(afeParams.mbLanes)(0.U(afeParams.mbSerializerRatio.W)), + ), + ) /** Assign expected value */ switch(io.req.bits.pattern) { @@ -34,18 +41,7 @@ class ErrorCounter(afeParams: AfeParams) extends Module { assert(!io.req.valid, "Cannot do error count with sideband clock pattern") } is(TransmitPattern.LFSR) { - val ratioBytes = afeParams.mbSerializerRatio / 8 - val patternBytes = VecInit( - Seq.fill(afeParams.mbLanes * ratioBytes)(0.U(8.W)), - ) - for (i <- 0 until ratioBytes) { - for (j <- 0 until afeParams.mbLanes) { - patternBytes(i * afeParams.mbLanes + j) := lfsr.io - .data_out(j) - .asTypeOf(VecInit(Seq.fill(ratioBytes)(0.U(8.W))))(i) - } - } - expected := patternBytes.asUInt + expected := lfsr.io.data_out } is(TransmitPattern.PER_LANE_ID) { val perLaneId = VecInit(Seq.fill(afeParams.mbLanes)(0.U(16.W))) @@ -61,7 +57,7 @@ class ErrorCounter(afeParams: AfeParams) extends Module { patternVec(i)(j) := perLaneId(i) } } - expected := patternVec.asUInt + expected := patternVec.asTypeOf(expected) } is(TransmitPattern.VALTRAIN) { val valtrain = VecInit( @@ -69,13 +65,17 @@ class ErrorCounter(afeParams: AfeParams) extends Module { "b1111_0000".U(8.W), ), ) - expected := valtrain.asUInt + expected := valtrain.asTypeOf(expected) } } /** count errors */ - val diffVec = Wire(Vec(width, UInt(1.W))) - diffVec := (expected ^ io.req.bits.input).asTypeOf(diffVec) - io.errorCount := diffVec.reduceTree(_ +& _) + val diffVec = Wire( + Vec(afeParams.mbLanes, Vec(afeParams.mbSerializerRatio, UInt(1.W))), + ) + for (i <- 0 until afeParams.mbLanes) { + diffVec(i) := (expected(i) ^ io.req.bits.input(i)).asTypeOf(diffVec(i)) + io.errorCount(i) := diffVec(i).reduceTree(_ +& _) + } } diff --git a/src/main/scala/logphy/Lanes.scala b/src/main/scala/logphy/Lanes.scala index f3b398a..079d56f 100644 --- a/src/main/scala/logphy/Lanes.scala +++ b/src/main/scala/logphy/Lanes.scala @@ -7,14 +7,59 @@ import chisel3.util._ import freechips.rocketchip.util.{AsyncQueue, AsyncQueueParams} import logphy.Scrambler +object LanesToOne { + def apply( + laneData: Vec[UInt], + numLanes: Int, + serializerRatio: Int, + ): Bits = { + val ratioBytes = serializerRatio / 8 + val rxDataVec = Wire( + Vec(ratioBytes, Vec(numLanes, UInt(8.W))), + ) + for (i <- 0 until numLanes) { + for (j <- 0 until ratioBytes) { + rxDataVec(j)(i) := laneData(i).asTypeOf( + VecInit(Seq.fill(ratioBytes)(0.U(8.W))), + )(j) + } + } + rxDataVec.asUInt + } +} + +object OneToLanes { + def apply( + bits: Bits, + numLanes: Int, + serializerRatio: Int, + ): Vec[UInt] = { + val ratioBytes = serializerRatio / 8 + val result = Wire(Vec(numLanes, UInt(serializerRatio.W))) + val txDataVec = Wire(Vec(numLanes, Vec(ratioBytes, UInt(8.W)))) + val txDataBytes = Wire(Vec(numLanes * ratioBytes, UInt(8.W))) + txDataBytes := bits.asTypeOf(txDataBytes) + for (i <- 0 until numLanes) { + for (j <- 0 until ratioBytes) { + txDataVec(i)(j) := txDataBytes(numLanes * j + i) + } + } + for (i <- 0 until numLanes) { + result(i) := txDataVec(i).asUInt + } + result + } +} + class Lanes( afeParams: AfeParams, queueParams: AsyncQueueParams, ) extends Module { + val io = IO(new Bundle() { val scramble = Input(Bool()) - val mainbandIo = new MainbandIO(afeParams) - val mainbandLaneIO = new MainbandLaneIO(afeParams) + val mainbandIo = new MainbandLaneIO(afeParams) + val mainbandLaneIO = new MainbandIO(afeParams) }) val txMBFifo = @@ -57,22 +102,6 @@ class Lanes( ) val ratioBytes = afeParams.mbSerializerRatio / 8 - val txDataVec = Wire( - Vec(afeParams.mbLanes, Vec(ratioBytes, UInt(8.W))), - ) - val rxDataVec = Wire( - Vec(ratioBytes, Vec(afeParams.mbLanes, UInt(8.W))), - ) - val txDataBytes = Wire( - Vec(afeParams.mbLanes * ratioBytes, UInt(8.W)), - ) - txDataBytes := io.mainbandLaneIO.txData.asTypeOf(txDataBytes) - - for (i <- 0 until afeParams.mbLanes) { - for (j <- 0 until ratioBytes) { - txDataVec(i)(j) := txDataBytes(afeParams.mbLanes * j + i) - } - } val scrambledTx = Wire(chiselTypeOf(txMBFifo.io.enq.bits)) val descrambledRx = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) @@ -80,23 +109,16 @@ class Lanes( val rxDataInput = Wire(chiselTypeOf(rxMBFifo.io.deq.bits)) rxDataInput := Mux(io.scramble, descrambledRx, rxMBFifo.io.deq.bits) - for (i <- 0 until afeParams.mbLanes) { - for (j <- 0 until ratioBytes) { - rxDataVec(j)(i) := rxDataInput(i).asTypeOf( - VecInit(Seq.fill(ratioBytes)(0.U(8.W))), - )(j) - } - } - /** Data Scrambling / De-scrambling */ rxScrambler.io.data_in := rxMBFifo.io.deq.bits rxScrambler.io.valid := rxMBFifo.io.deq.fire descrambledRx := rxScrambler.io.data_out - - for (i <- 0 until afeParams.mbLanes) { - txScrambler.io.data_in(i) := txDataVec(i).asUInt - } + txScrambler.io.data_in := OneToLanes( + io.mainbandLaneIO.txData.bits, + afeParams.mbLanes, + afeParams.mbSerializerRatio, + ) txScrambler.io.valid := io.mainbandLaneIO.txData.fire scrambledTx := txScrambler.io.data_out @@ -111,7 +133,11 @@ class Lanes( ) io.mainbandLaneIO.rxData.valid := rxMBFifo.io.deq.valid - io.mainbandLaneIO.rxData.bits := rxDataVec.asUInt + io.mainbandLaneIO.rxData.bits := LanesToOne( + rxDataInput, + afeParams.mbLanes, + afeParams.mbSerializerRatio, + ) rxMBFifo.io.deq.ready := true.B } @@ -132,7 +158,7 @@ class SimLanes( val io = IO(new Bundle() { val scramble = Input(Bool()) val mainbandIo = new MainbandSimIO(afeParams) - val mainbandLaneIO = new MainbandLaneIO(afeParams) + val mainbandLaneIO = new MainbandIO(afeParams) }) val rxScrambler = diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index b22f54a..91354df 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -37,10 +37,12 @@ class SidebandFSMIO( } class MainbandFSMIO( + afeParams: AfeParams, ) extends Bundle { val rxEn = Input(Bool()) val pllLock = Output(Bool()) val txFreqSel = Input(SpeedMode()) + val mainbandIO = new MainbandIO(afeParams) } class LinkTrainingFSM( @@ -53,7 +55,7 @@ class LinkTrainingFSM( linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio val io = IO(new Bundle { - val mainbandFSMIO = Flipped(new MainbandFSMIO) + val mainbandFSMIO = Flipped(new MainbandFSMIO(afeParams)) val sidebandFSMIO = Flipped(new SidebandFSMIO(sbParams)) val rdi = new Bundle { val rdiBringupIO = new RdiBringupIO @@ -67,7 +69,7 @@ class LinkTrainingFSM( val sbMsgWrapper = Module(new SBMsgWrapper(sbParams)) private val msgSource = WireInit(MsgSource.PATTERN_GENERATOR) - // io.mainbandLaneIO <> patternGenerator.io.mainbandLaneIO + io.mainbandFSMIO.mainbandIO <> patternGenerator.io.mainbandIO patternGenerator.io.patternGeneratorIO.transmitReq.noenq() patternGenerator.io.patternGeneratorIO.resp.nodeq() @@ -226,12 +228,13 @@ class LinkTrainingFSM( switch(sbInitSubState) { is(SBInitSubState.SEND_CLOCK) { patternGenerator.io.patternGeneratorIO.transmitReq.bits.pattern := TransmitPattern.CLOCK - patternGenerator.io.patternGeneratorIO.transmitReq.bits.sideband := true.B /** Timeout occurs after 8ms */ patternGenerator.io.patternGeneratorIO.transmitReq.bits.timeoutCycles := ( 0.008 * sbClockFreq, ).toInt.U + patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternCountMax := (128 + 64 * 4).U + patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax := (128).U patternGenerator.io.patternGeneratorIO.transmitReq.valid := true.B msgSource := MsgSource.PATTERN_GENERATOR @@ -258,21 +261,11 @@ class LinkTrainingFSM( } } is(SBInitSubState.SB_OUT_OF_RESET_EXCH) { - sbMsgWrapper.io.trainIO.msgReq.bits.msg := SBMessage_factory( - SBM.SBINIT_OUT_OF_RESET, - "PHY", - true, - "PHY", - ) - /* sbMsgWrapper.io.trainIO.msgReq.bits.reqType := - * MessageRequestType.MSG_EXCH */ - // sbMsgWrapper.io.trainIO.msgReq.bits.msgTypeHasData := false.B - sbMsgWrapper.io.trainIO.msgReq.valid := true.B + val bitPat = SBM.SBINIT_OUT_OF_RESET + val reqType = MessageRequestType.EXCHANGE + val timeout = (0.008 * sbClockFreq).toInt + sendSidebandReq(bitPat, reqType, timeout) - sbMsgWrapper.io.trainIO.msgReq.bits.timeoutCycles := ( - 0.008 * sbClockFreq, - ).toInt.U - msgSource := MsgSource.SB_MSG_WRAPPER when(sbMsgWrapper.io.trainIO.msgReq.fire) { sbInitSubState := SBInitSubState.SB_OUT_OF_RESET_WAIT } @@ -292,20 +285,11 @@ class LinkTrainingFSM( } } is(SBInitSubState.SB_DONE_REQ) { - sbMsgWrapper.io.trainIO.msgReq.bits.msg := SBMessage_factory( + sendSidebandReq( SBM.SBINIT_DONE_REQ, - "PHY", - true, - "PHY", + MessageRequestType.EXCHANGE, + (0.008 * sbClockFreq).toInt, ) - /* sbMsgWrapper.io.trainIO.msgReq.bits.reqType := - * MessageRequestType.MSG_REQ */ - // sbMsgWrapper.io.trainIO.msgReq.bits.msgTypeHasData := false.B - sbMsgWrapper.io.trainIO.msgReq.valid := true.B - sbMsgWrapper.io.trainIO.msgReq.bits.timeoutCycles := ( - 0.008 * sbClockFreq, - ).toInt.U - msgSource := MsgSource.SB_MSG_WRAPPER when(sbMsgWrapper.io.trainIO.msgReq.fire) { sbInitSubState := SBInitSubState.SB_DONE_REQ_WAIT } @@ -325,20 +309,11 @@ class LinkTrainingFSM( } } is(SBInitSubState.SB_DONE_RESP) { - sbMsgWrapper.io.trainIO.msgReq.bits.msg := SBMessage_factory( + sendSidebandReq( SBM.SBINIT_DONE_RESP, - "PHY", - remote = true, - "PHY", + MessageRequestType.EXCHANGE, + (0.008 * sbClockFreq).toInt, ) - /* sbMsgWrapper.io.trainIO.msgReq.bits.reqType := - * MessageRequestType.MSG_RESP */ - sbMsgWrapper.io.trainIO.msgReq.valid := true.B - // sbMsgWrapper.io.trainIO.msgReq.bits.msgTypeHasData := false.B - msgSource := MsgSource.SB_MSG_WRAPPER - sbMsgWrapper.io.trainIO.msgReq.bits.timeoutCycles := ( - 0.008 * sbClockFreq, - ).toInt.U when(sbMsgWrapper.io.trainIO.msgReq.fire) { sbInitSubState := SBInitSubState.SB_DONE_RESP_WAIT } @@ -361,7 +336,6 @@ class LinkTrainingFSM( } is(LinkTrainingState.mbInit) { - /** TODO: can't use two message sources at the same time */ mbInit.io.sbTrainIO <> sbMsgWrapper.io.trainIO mbInit.io.patternGeneratorIO <> patternGenerator.io.patternGeneratorIO msgSource := MsgSource.SB_MSG_WRAPPER @@ -393,4 +367,20 @@ class LinkTrainingFSM( } } + private def sendSidebandReq( + bitPat: BitPat, + reqType: MessageRequestType.Type, + timeout: Int, + ): Unit = { + sbMsgWrapper.io.trainIO.msgReq.bits.msg := SBMessage_factory( + bitPat, + "PHY", + true, + "PHY", + ) + sbMsgWrapper.io.trainIO.msgReq.bits.reqType := reqType + sbMsgWrapper.io.trainIO.msgReq.valid := true.B + sbMsgWrapper.io.trainIO.msgReq.bits.timeoutCycles := timeout.U + msgSource := MsgSource.SB_MSG_WRAPPER + } } diff --git a/src/main/scala/logphy/LogPhyTypes.scala b/src/main/scala/logphy/LogPhyTypes.scala index af4eab7..2931553 100644 --- a/src/main/scala/logphy/LogPhyTypes.scala +++ b/src/main/scala/logphy/LogPhyTypes.scala @@ -28,10 +28,14 @@ class SBReqMsg extends Bundle { val msg = UInt(128.W) } +object MessageRequestType extends ChiselEnum { + val EXCHANGE, RECEIVE = Value +} + class MessageRequest extends Bundle { val msg = UInt(128.W) val timeoutCycles = UInt(64.W) - // val msgTypeHasData = Bool() + val reqType = MessageRequestType() } class MessageRequestStatus extends Bundle { @@ -68,7 +72,7 @@ class SBIO(params: AfeParams) extends Bundle { val rxData = Flipped(Decoupled(Bits(params.sbSerializerRatio.W))) } -class MainbandIO( +class MainbandLaneIO( afeParams: AfeParams, ) extends Bundle { @@ -95,7 +99,7 @@ class MainbandIO( ) } -class MainbandLaneIO( +class MainbandIO( afeParams: AfeParams, ) extends Bundle { diff --git a/src/main/scala/logphy/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index 44a02e9..7f73a47 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -23,7 +23,8 @@ class MBInitFSM( val io = IO(new Bundle { val sbTrainIO = Flipped(new SBMsgWrapperTrainIO) - val patternGeneratorIO = Flipped(new PatternGeneratorIO(maxPatternCount)) + val patternGeneratorIO = + Flipped(new PatternGeneratorIO(afeParams, maxPatternCount)) val transition = Output(Bool()) val error = Output(Bool()) }) @@ -110,15 +111,13 @@ class MBInitFSM( if (req) SBM.MBINIT_PARAM_CONFIG_REQ else SBM.MBINIT_PARAM_CONFIG_RESP, "PHY", - false, + true, "PHY", data, ) - // msgReq.msgTypeHasData := true.B msgReq.timeoutCycles := (0.008 * sbClockFreq).toInt.U - // msgReq.reqType := (if (req) MessageRequestType.MSG_REQ - // else MessageRequestType.MSG_RESP) + msgReq.reqType := MessageRequestType.EXCHANGE msgReq } diff --git a/src/main/scala/logphy/MBTrainer.scala b/src/main/scala/logphy/MBTrainer.scala new file mode 100644 index 0000000..883a4a2 --- /dev/null +++ b/src/main/scala/logphy/MBTrainer.scala @@ -0,0 +1,118 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import interfaces._ +import chisel3._ +import chisel3.util._ +import sideband.{SBM, SBMessage_factory} + +class TrainingOperation extends Bundle { + val pattern = TransmitPattern() +} + +class MBTrainer( + linkTrainingParams: LinkTrainingParams, + afeParams: AfeParams, + maxPatternCount: Int, +) extends Module { + + val sbClockFreq = + linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio + + val io = IO(new Bundle { + val trainingOperationIO = Valid(new TrainingOperation) + val sbTrainIO = Flipped(new SBMsgWrapperTrainIO) + val sbMsgWrapperReset = Output(Bool()) + val patternGeneratorIO = + Flipped(new PatternGeneratorIO(afeParams, maxPatternCount)) + }) + + private object State extends ChiselEnum { + val WAIT_PTTEST_REQ_SEND, WAIT_PTTEST_REQ, SEND_PTTEST_REQ, + WAIT_AND_SEND_PTTEST_RESP, ERR = Value + } + private val currentState = RegInit(State.WAIT_PTTEST_REQ_SEND) + val operation = Reg(new TrainingOperation) + private val txDtoCPointReq = RegInit(0.U.asTypeOf(new TxDtoCPointReq)) + + io.sbMsgWrapperReset := false.B + when(io.trainingOperationIO.valid) { + currentState := State.SEND_PTTEST_REQ + io.sbMsgWrapperReset := true.B + + txDtoCPointReq.dataPattern := + } + + private class TxDtoCPointReq extends Bundle { + val reserved = 0.U(4.W) + val comparisonMode = UInt(1.W) + val iterationCount = UInt(16.W) + val idleCount = UInt(16.W) + val burstCount = UInt(16.W) + val patternMode = UInt(1.W) + val clockPhaseControl = UInt(4.W) + val validPattern = UInt(3.W) + val dataPattern = UInt(3.W) + } + + def formStartTxDtoCPointReq( + maxErrors: UInt, + req: TxDtoCPointReq, + reqType: MessageRequestType.Type, + ): MessageRequest = { + val data = Wire(UInt(64.W)) + val msgReq = Wire(new MessageRequest) + data := req.asTypeOf(UInt(64.W)) + msgReq.msg := SBMessage_factory( + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_REQ, + src = "PHY", + remote = false, + dst = "PHY", + data, + msgInfo = maxErrors(15, 0), + ) + msgReq.timeoutCycles := (0.008 * sbClockFreq).toInt.U + msgReq.reqType := reqType + msgReq + } + + + switch(currentState) { + is(State.WAIT_PTTEST_REQ_SEND) { + io.sbTrainIO.msgReq.valid := true.B + val txDtoCPointReq = new TxDtoCPointReq + txDtoCPointReq := DontCare + io.sbTrainIO.msgReq.bits.msg := formStartTxDtoCPointReq( + 0.U, + txDtoCPointReq, + MessageRequestType.RECEIVE, + ) + when(io.sbTrainIO.msgReq.fire) { + currentState := State.WAIT_PTTEST_REQ + } + } + is(State.WAIT_PTTEST_REQ) { + io.sbTrainIO.msgReqStatus.ready := true.B + when(io.sbTrainIO.msgReqStatus.fire) { + txDtoCPointReq := io.sbTrainIO.msgReqStatus.bits.data + .asTypeOf(new TxDtoCPointReq) + + when( + io.sbTrainIO.msgReqStatus.bits.status === MessageRequestStatusType.ERR, + ) { + assert( + false.B, + "SB Message wrapper should not throw error in MB trainer", + ) + }.otherwise { + currentState := State.WAIT_AND_SEND_PTTEST_RESP + } + } + } + is(State.SEND_PTTEST_REQ) { + + } + is(State.WAIT_AND_SEND_PTTEST_RESP) {} + } + +} diff --git a/src/main/scala/logphy/PatternGenerator.scala b/src/main/scala/logphy/PatternGenerator.scala index e34f6a0..c42ad33 100644 --- a/src/main/scala/logphy/PatternGenerator.scala +++ b/src/main/scala/logphy/PatternGenerator.scala @@ -6,18 +6,20 @@ import chisel3.util._ import sideband.SidebandParams import interfaces._ -class PatternGeneratorIO(maxPatternCount: Int) extends Bundle { +class PatternGeneratorIO(afeParams: AfeParams, maxPatternCount: Int) + extends Bundle { val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val transmitReq = Flipped(Decoupled(new Bundle { val pattern = TransmitPattern() - val timeoutCycles = UInt(maxPatternCountWidth.W) - val sideband = Bool() + val timeoutCycles = UInt(32.W) val patternCountMax = UInt(maxPatternCountWidth.W) val patternDetectedCountMax = UInt(maxPatternCountWidth.W) })) val resp = Decoupled(new Bundle { val status = MessageRequestStatusType() - val errorCount = UInt(maxPatternCountWidth.W) + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(maxPatternCountWidth.W)), + ) }) } @@ -29,9 +31,9 @@ class PatternGenerator( ) extends Module { val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val io = IO(new Bundle { - val patternGeneratorIO = new PatternGeneratorIO(maxPatternCount) + val patternGeneratorIO = new PatternGeneratorIO(afeParams, maxPatternCount) - val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) + val mainbandIO = Flipped(new MainbandIO(afeParams)) val sidebandLaneIO = Flipped(new SidebandLaneIO(sbParams)) }) @@ -43,39 +45,43 @@ class PatternGenerator( ) patternWriter.io.sbTxData <> io.sidebandLaneIO.txData - patternWriter.io.mbTxData <> io.mainbandLaneIO.txData + patternWriter.io.mbTxData.map( + LanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) <> io.mainbandIO.txData patternReader.io.sbRxData <> io.sidebandLaneIO.rxData - patternReader.io.mbRxData <> io.mainbandLaneIO.rxData + patternReader.io.mbRxData <> io.mainbandIO.rxData.map( + OneToLanes(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) private val inProgress = WireInit( patternWriter.io.resp.inProgress || patternReader.io.resp.inProgress, ) + private val inputsValid = RegInit(false.B) private val pattern = RegInit(TransmitPattern.CLOCK) - private val sideband = RegInit(true.B) - private val timeoutCycles = RegInit(0.U(maxPatternCountWidth.W)) + private val timeoutCycles = RegInit(0.U(32.W)) private val status = RegInit(MessageRequestStatusType.SUCCESS) + private val errorCount = RegInit( + VecInit(Seq.fill(afeParams.mbLanes)(0.U(maxPatternCount.W))), + ) private val statusValid = RegInit(false.B) private val patternCountMax = RegInit(0.U(maxPatternCountWidth.W)) private val patternDetectedCountMax = RegInit(0.U(maxPatternCountWidth.W)) patternWriter.io.request.bits.pattern := pattern patternWriter.io.request.bits.patternCountMax := patternCountMax - patternWriter.io.request.bits.sideband := sideband patternReader.io.request.bits.pattern := pattern patternReader.io.request.bits.patternCountMax := patternDetectedCountMax - patternReader.io.request.bits.sideband := sideband patternWriter.io.request.valid := inputsValid patternReader.io.request.valid := inputsValid io.patternGeneratorIO.transmitReq.ready := (inProgress === false.B) io.patternGeneratorIO.resp.valid := statusValid io.patternGeneratorIO.resp.bits.status := status - io.patternGeneratorIO.resp.bits.errorCount := patternReader.io.resp.errorCount + io.patternGeneratorIO.resp.bits.errorCount := errorCount when(io.patternGeneratorIO.transmitReq.fire) { pattern := io.patternGeneratorIO.transmitReq.bits.pattern - sideband := io.patternGeneratorIO.transmitReq.bits.sideband timeoutCycles := io.patternGeneratorIO.transmitReq.bits.timeoutCycles patternCountMax := io.patternGeneratorIO.transmitReq.bits.patternCountMax patternDetectedCountMax := io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax @@ -90,20 +96,21 @@ class PatternGenerator( /** handle timeouts and completion */ when(inProgress) { timeoutCycles := timeoutCycles - 1.U - when(timeoutCycles === 0.U) { - status := MessageRequestStatusType.ERR - statusValid := true.B - patternWriter.reset := true.B - patternReader.reset := true.B - inputsValid := false.B - }.elsewhen( - patternWriter.io.resp.complete && patternReader.io.resp.complete, - ) { + val timeout = timeoutCycles === 0.U + val complete = + patternWriter.io.resp.complete && patternReader.io.resp.complete + + when(timeout || complete) { + status := Mux( + timeout, + MessageRequestStatusType.ERR, + MessageRequestStatusType.SUCCESS, + ) statusValid := true.B - status := MessageRequestStatusType.SUCCESS patternWriter.reset := true.B patternReader.reset := true.B inputsValid := false.B + errorCount := patternReader.io.resp.errorCount } } diff --git a/src/main/scala/logphy/PatternReader.scala b/src/main/scala/logphy/PatternReader.scala index 0a8a676..1b4973f 100644 --- a/src/main/scala/logphy/PatternReader.scala +++ b/src/main/scala/logphy/PatternReader.scala @@ -6,7 +6,6 @@ import chisel3.util._ import interfaces.AfeParams import sideband.SidebandParams -/** TODO: implementation */ class PatternReader( sbParams: SidebandParams, afeParams: AfeParams, @@ -16,23 +15,23 @@ class PatternReader( val io = IO(new Bundle { val request = Flipped(Valid(new Bundle { val pattern = TransmitPattern() - val sideband = Bool() val patternCountMax = UInt(maxPatternWidth.W) })) val resp = new Bundle { val complete = Output(Bool()) val inProgress = Output(Bool()) - val errorCount = Output(UInt(maxPatternWidth.W)) + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(maxPatternWidth.W)), + ) } val sbRxData = Flipped(Decoupled(Bits(sbParams.sbNodeMsgWidth.W))) - val mbRxData = - Flipped( - Decoupled(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)), - ) + val mbRxData = Flipped( + Decoupled(Vec(afeParams.mbLanes, UInt(afeParams.mbSerializerRatio.W))), + ) }) private val readInProgress = RegInit(false.B) - val patternDetectedCount = RegInit(0.U(maxPatternWidth.W)) + private val patternDetectedCount = RegInit(0.U(maxPatternWidth.W)) io.resp.inProgress := readInProgress io.resp.complete := patternDetectedCount >= io.request.bits.patternCountMax @@ -41,25 +40,30 @@ class PatternReader( } /** increment error count */ - val errorCount = RegInit(0.U(maxPatternWidth.W)) + private val errorCount = RegInit( + VecInit(Seq.fill(afeParams.mbLanes)(0.U(maxPatternWidth.W))), + ) io.resp.errorCount := errorCount - val errorCounter = Module(new ErrorCounter(afeParams)) + private val errorCounter = Module( + new ErrorCounter(afeParams), + ) errorCounter.io.req.valid := false.B errorCounter.io.req.bits := DontCare when(readInProgress) { when(errorCounter.io.req.valid) { - errorCount := errorCount + errorCounter.io.errorCount + for (i <- 0 until afeParams.mbLanes) { + errorCount(i) := errorCount(i) + errorCounter.io.errorCount(i) + } } } io.mbRxData.nodeq() io.sbRxData.nodeq() + val sideband = io.request.bits.pattern === TransmitPattern.CLOCK when(readInProgress) { - when(io.request.bits.sideband) { + when(sideband) { io.sbRxData.ready := true.B when(io.sbRxData.fire) { - assert(io.request.bits.pattern === TransmitPattern.CLOCK) - val patternToDetect = WireInit( ("h" + "aaaa" * (sbParams.sbNodeMsgWidth / 16)).U( sbParams.sbNodeMsgWidth.W, diff --git a/src/main/scala/logphy/PatternWriter.scala b/src/main/scala/logphy/PatternWriter.scala index de67a43..391a3d1 100644 --- a/src/main/scala/logphy/PatternWriter.scala +++ b/src/main/scala/logphy/PatternWriter.scala @@ -15,7 +15,6 @@ class PatternWriter( val io = IO(new Bundle { val request = Flipped(Valid(new Bundle { val pattern = TransmitPattern() - val sideband = Bool() val patternCountMax = UInt(maxPatternCountWidth.W) })) val resp = Output(new Bundle { @@ -24,7 +23,7 @@ class PatternWriter( }) val sbTxData = Decoupled(Bits(sbParams.sbNodeMsgWidth.W)) val mbTxData = - Decoupled(Bits((afeParams.mbLanes * afeParams.mbSerializerRatio).W)) + Decoupled(Vec(afeParams.mbLanes, Bits(afeParams.mbSerializerRatio.W))) }) private val writeInProgress = RegInit(false.B) @@ -33,30 +32,33 @@ class PatternWriter( writeInProgress := true.B } - val patternToTransmit = WireInit( - 0.U( - (afeParams.mbLanes * afeParams.mbSerializerRatio) - .max(sbParams.sbNodeMsgWidth) - .W, - ), + val sbPatternToTransmit = WireInit( + 0.U(sbParams.sbNodeMsgWidth.W), + ) + + val mbPatternToTransmit = VecInit( + Seq.fill(afeParams.mbLanes)(0.U(afeParams.mbSerializerRatio.W)), ) val patternWrittenCount = RegInit(0.U(maxPatternCountWidth.W)) io.resp.complete := patternWrittenCount >= io.request.bits.patternCountMax val patternWritten = WireInit(false.B) + /** Only sideband pattern is clock */ + val sideband = io.request.bits.pattern === TransmitPattern.CLOCK + io.sbTxData.noenq() io.mbTxData.noenq() - when(!io.request.bits.sideband) { + when(!sideband) { io.mbTxData.valid := writeInProgress - io.mbTxData.bits := patternToTransmit + io.mbTxData.bits := mbPatternToTransmit when(io.mbTxData.fire) { patternWrittenCount := patternWrittenCount + (afeParams.mbLanes * afeParams.mbSerializerRatio).U patternWritten := true.B } }.otherwise { io.sbTxData.valid := writeInProgress - io.sbTxData.bits := patternToTransmit + io.sbTxData.bits := sbPatternToTransmit when(io.sbTxData.fire) { patternWrittenCount := patternWrittenCount + sbParams.sbNodeMsgWidth.U patternWritten := true.B @@ -84,22 +86,11 @@ class PatternWriter( * bits of regular clock data TODO: currently not long enough to use in * MB, if ever used in MB need to make longer */ - patternToTransmit := "haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U + + sbPatternToTransmit := "haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U } is(TransmitPattern.LFSR) { - assert(io.request.bits.sideband === false.B) - val ratioBytes = afeParams.mbSerializerRatio / 8 - val patternBytes = VecInit( - Seq.fill(afeParams.mbLanes * ratioBytes)(0.U(8.W)), - ) - for (i <- 0 until ratioBytes) { - for (j <- 0 until afeParams.mbLanes) { - patternBytes(i * afeParams.mbLanes + j) := lfsrPatternGenerator.io - .data_out(j) - .asTypeOf(VecInit(Seq.fill(ratioBytes)(0.U(8.W))))(i) - } - } - patternToTransmit := patternBytes.asUInt + mbPatternToTransmit := lfsrPatternGenerator.io.data_out when(patternWritten) { lfsrPatternGenerator.io.valid := true.B } @@ -110,7 +101,7 @@ class PatternWriter( "b1111_0000".U(8.W), ), ) - patternToTransmit := valtrain.asUInt + mbPatternToTransmit := valtrain.asTypeOf(mbPatternToTransmit) } is(TransmitPattern.PER_LANE_ID) { val perLaneId = VecInit(Seq.fill(afeParams.mbLanes)(0.U(16.W))) @@ -126,7 +117,7 @@ class PatternWriter( patternVec(i)(j) := perLaneId(i) } } - patternToTransmit := patternVec.asUInt + mbPatternToTransmit := patternVec.asTypeOf(mbPatternToTransmit) } } diff --git a/src/main/scala/logphy/RdiDataMapper.scala b/src/main/scala/logphy/RdiDataMapper.scala index 6c1a063..84a6598 100644 --- a/src/main/scala/logphy/RdiDataMapper.scala +++ b/src/main/scala/logphy/RdiDataMapper.scala @@ -29,7 +29,7 @@ class RdiDataMapper( val io = IO(new Bundle { val rdi = Flipped(new RdiDataMapperIO(rdiParams)) - val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) + val mainbandLaneIO = Flipped(new MainbandIO(afeParams)) }) assert(afeParams.mbSerializerRatio * afeParams.mbLanes < rdiParams.width * 8) @@ -54,7 +54,7 @@ class RdiDataMapper( when(io.mainbandLaneIO.rxData.fire) { /** chunk */ - rxData((ratio - 1).U - rxSliceCounter) := io.mainbandLaneIO.rxData.bits + rxData(rxSliceCounter) := io.mainbandLaneIO.rxData.bits rxSliceCounter := rxSliceCounter + 1.U when(rxSliceCounter === (ratio - 1).U) { hasRxData := true.B @@ -79,4 +79,7 @@ class RdiDataMapper( txWidthCoupler.io.in.valid := io.rdi.lpData.valid & io.rdi.lpData.irdy txWidthCoupler.io.in.bits := io.rdi.lpData.bits + /** RDI has no backpressure mechanism */ + io.mainbandLaneIO.rxData.ready := true.B + } diff --git a/src/main/scala/logphy/SBMsgWrapper.scala b/src/main/scala/logphy/SBMsgWrapper.scala index 79a6bbe..3d2d7d1 100644 --- a/src/main/scala/logphy/SBMsgWrapper.scala +++ b/src/main/scala/logphy/SBMsgWrapper.scala @@ -11,6 +11,73 @@ class SBMsgWrapperTrainIO( val msgReqStatus = Decoupled(new MessageRequestStatus) } +class SBMsgWriter(sbParams: SidebandParams) extends Module { + val io = IO(new Bundle { + val req = Flipped(Valid(UInt(128.W))) + val result = Valid(MessageRequestStatusType()) + val txData = Decoupled(Bits(sbParams.sbNodeMsgWidth.W)) + }) + val inProgress = RegInit(false.B) + val complete = RegInit(false.B) + when(io.req.fire && !inProgress) { + inProgress := true.B + complete := false.B + } + io.txData.valid := inProgress + io.txData.bits := io.req.bits + when(inProgress && io.txData.fire) { + + /** continuously resend */ + complete := true.B + } + io.result.valid := complete || io.txData.fire + io.result.bits := MessageRequestStatusType.SUCCESS +} + +class SBMsgReader(sbParams: SidebandParams) extends Module { + val io = IO(new Bundle { + val req = Flipped(Valid(UInt(128.W))) + val result = Valid(new MessageRequestStatus) + val rxData = Flipped(Decoupled(Bits(sbParams.sbNodeMsgWidth.W))) + }) + + def messageIsEqual(m1: UInt, m2: UInt): Bool = { + + /** opcode */ + (m1(4, 0) === m2(4, 0)) && + /** subcode */ + (m1(21, 14) === m2(21, 14)) && + /** code */ + (m1(39, 32) === m2(39, 32)) + } + + val inProgress = RegInit(false.B) + val complete = RegInit(false.B) + when(io.req.fire && !inProgress) { + inProgress := true.B + complete := false.B + } + + /** if receive message, move on */ + io.rxData.ready := inProgress + val data = RegInit(0.U(64.W)) + val justReceivedMsg = Wire(Bool()) + justReceivedMsg := io.rxData.fire && + messageIsEqual( + io.rxData.bits, + io.req.bits, + ) + + when(inProgress && justReceivedMsg) { + data := io.rxData.bits(127, 64) + complete := true.B + } + + io.result.valid := complete + io.result.bits.status := MessageRequestStatusType.SUCCESS + io.result.bits.data := data +} + class SBMsgWrapper( sbParams: SidebandParams, ) extends Module { @@ -19,156 +86,82 @@ class SBMsgWrapper( val laneIO = Flipped(new SidebandLaneIO(sbParams)) }) + val sbMsgWriter = Module(new SBMsgWriter(sbParams)) + val sbMsgReader = Module(new SBMsgReader(sbParams)) + private object State extends ChiselEnum { - val IDLE, EXCHANGE, WAIT_ACK = Value + val IDLE, EXCHANGE, RECEIVE_ONLY, WAIT_ACK = Value } - // private object SubState extends ChiselEnum { - // val SEND_OR_RECEIVE_MESSAGE, SEND_OR_RECEIVE_DATA = Value - // } - private val currentState = RegInit(State.IDLE) - // private val sendSubState = RegInit(SubState.SEND_OR_RECEIVE_MESSAGE) - // private val receiveSubState = RegInit(SubState.SEND_OR_RECEIVE_MESSAGE) private val timeoutCounter = RegInit(0.U(64.W)) private val nextState = WireInit(currentState) currentState := nextState - private val sentMsg = RegInit(false.B) - private val receivedMsg = RegInit(false.B) + when(currentState =/= nextState) { - // sendSubState := SubState.SEND_OR_RECEIVE_MESSAGE - // receiveSubState := SubState.SEND_OR_RECEIVE_MESSAGE timeoutCounter := 0.U - sentMsg := false.B - receivedMsg := false.B + sbMsgReader.reset := true.B + sbMsgWriter.reset := true.B } private val currentReq = RegInit(0.U((new MessageRequest).msg.getWidth.W)) - // private val currentReqHasData = RegInit(false.B) private val currentReqTimeoutMax = RegInit(0.U(64.W)) private val currentStatus = RegInit(MessageRequestStatusType.ERR) private val dataOut = RegInit(0.U(64.W)) io.trainIO.msgReqStatus.bits.data := dataOut io.trainIO.msgReqStatus.bits.status := currentStatus - io.laneIO.rxData.nodeq() - io.laneIO.txData.noenq() io.trainIO.msgReqStatus.noenq() io.trainIO.msgReq.nodeq() + sbMsgReader.io.rxData <> io.laneIO.rxData + sbMsgWriter.io.txData <> io.laneIO.txData + sbMsgReader.io.req.bits := currentReq + sbMsgWriter.io.req.bits := currentReq + sbMsgReader.io.req.valid := false.B + sbMsgWriter.io.req.valid := false.B + switch(currentState) { is(State.IDLE) { io.trainIO.msgReq.ready := true.B when(io.trainIO.msgReq.fire) { currentReq := io.trainIO.msgReq.bits.msg - // currentReqHasData := io.trainIO.msgReq.bits.msgTypeHasData currentReqTimeoutMax := io.trainIO.msgReq.bits.timeoutCycles - nextState := State.EXCHANGE - // switch(io.trainIO.msgReq.bits.reqType) { - // is(MessageRequestType.MSG_REQ) { - // nextState := State.EXCHANGE - // } - // is(MessageRequestType.MSG_RESP) { - // nextState := State.EXCHANGE - // } - // is(MessageRequestType.MSG_EXCH) { - // nextState := State.EXCHANGE - // } - // } + nextState := Mux(io.trainIO.msgReq.bits.reqType === MessageRequestType.EXCHANGE, State.EXCHANGE, State.RECEIVE_ONLY) } } is(State.EXCHANGE) { + sbMsgReader.io.req.valid := true.B + sbMsgWriter.io.req.valid := true.B - /** TODO: incorrect, this logic needs to send message before receiving, - * when in reality both just need to happen - */ - - def messageIsEqual(m1: UInt, m2: UInt): Bool = { + when(sbMsgWriter.io.result.valid && sbMsgReader.io.result.valid) { + dataOut := sbMsgReader.io.result.bits.data + currentStatus := MessageRequestStatusType.SUCCESS + nextState := State.WAIT_ACK + } - /** opcode */ - (m1(4, 0) === m2(4, 0)) && - /** subcode */ - (m1(21, 14) === m2(21, 14)) && - /** code */ - (m1(39, 32) === m2(39, 32)) + /** timeout logic */ + timeoutCounter := timeoutCounter + 1.U + when(timeoutCounter === currentReqTimeoutMax) { + nextState := State.WAIT_ACK + currentStatus := MessageRequestStatusType.ERR } + } + is(State.RECEIVE_ONLY) { + sbMsgReader.io.req.valid := true.B - /** send message over sideband */ - io.laneIO.txData.valid := true.B - io.laneIO.txData.bits := currentReq - val hasSentMsg = WireInit(io.laneIO.txData.fire || sentMsg) - val justReceivedMsg = Wire(Bool()) - val hasReceivedMsg = Wire(Bool()) - sentMsg := hasSentMsg - - /** if receive message, move on */ - io.laneIO.rxData.ready := true.B - justReceivedMsg := io.laneIO.rxData.fire && - messageIsEqual( - io.laneIO.rxData.bits(64, 0), - currentReq(64, 0), - ) - hasReceivedMsg := justReceivedMsg || receivedMsg - receivedMsg := hasReceivedMsg - - when(hasReceivedMsg && hasSentMsg) { - dataOut := io.laneIO.rxData.bits(127, 64) + when(sbMsgReader.io.result.valid) { + dataOut := sbMsgReader.io.result.bits.data currentStatus := MessageRequestStatusType.SUCCESS nextState := State.WAIT_ACK } - // switch(sendSubState) { - // is(SubState.SEND_OR_RECEIVE_MESSAGE) { - // sidebandTxWidthCoupler64.io.in.valid := true.B - // sidebandTxWidthCoupler64.io.in.bits := currentReq(64, 0) - // when(sidebandTxWidthCoupler64.io.in.fire && currentReqHasData) { - // sendSubState := SubState.SEND_OR_RECEIVE_DATA - // } - // } - // is(SubState.SEND_OR_RECEIVE_DATA) { - // sidebandTxWidthCoupler64.io.in.valid := true.B - // sidebandTxWidthCoupler64.io.in.bits := currentReq(128, 64) - // when(sidebandTxWidthCoupler64.io.in.fire) { - // sendSubState := SubState.SEND_OR_RECEIVE_MESSAGE - // } - // } - // } - - // switch(receiveSubState) { - // is(SubState.SEND_OR_RECEIVE_MESSAGE) { - // sidebandRxWidthCoupler64.io.out.ready := true.B - // when(sidebandRxWidthCoupler64.io.out.fire) { - // when( - // messageIsEqual( - // sidebandRxWidthCoupler64.io.out.bits, - // currentReq(64, 0), - // ), - // ) { - // when(currentReqHasData) { - // receiveSubState := SubState.SEND_OR_RECEIVE_DATA - // }.otherwise { - // nextState := State.WAIT_ACK_SUCCESS - // } - // } - // } - // } - // is(SubState.SEND_OR_RECEIVE_DATA) { - // sidebandRxWidthCoupler64.io.out.ready := true.B - // when(sidebandRxWidthCoupler64.io.out.fire) { - // dataOut := sidebandRxWidthCoupler64.io.out.bits - // nextState := State.WAIT_ACK_SUCCESS - // } - // } - // } - - /** timeout logic */ timeoutCounter := timeoutCounter + 1.U when(timeoutCounter === currentReqTimeoutMax) { nextState := State.WAIT_ACK currentStatus := MessageRequestStatusType.ERR } - } is(State.WAIT_ACK) { printf("ack\n") diff --git a/src/main/scala/sideband/sb-msg-encoding.scala b/src/main/scala/sideband/sb-msg-encoding.scala index 9409c69..afe0ece 100644 --- a/src/main/scala/sideband/sb-msg-encoding.scala +++ b/src/main/scala/sideband/sb-msg-encoding.scala @@ -352,6 +352,12 @@ object SBM { def MBINIT_PARAM_CONFIG_RESP = BitPat( "b????????????????????????????????????????????????????????????????????????000000000000000010101010??????????00000000?????????11011", ) + def MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_REQ = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000001??????????10000101?????????00000", + ) + def MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_RESP = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000001??????????10001010?????????00000", + ) def MBTRAIN_VALVREF_START_REQ = BitPat( "b????????????????????????????????????????????????????????????????????????????????????????00000000??????????10110101?????????00000", ) diff --git a/src/test/scala/logphy/ErrorCounterTest.scala b/src/test/scala/logphy/ErrorCounterTest.scala index 3bcbc4f..7cd1eec 100644 --- a/src/test/scala/logphy/ErrorCounterTest.scala +++ b/src/test/scala/logphy/ErrorCounterTest.scala @@ -2,37 +2,120 @@ package edu.berkeley.cs.ucie.digital package logphy import chisel3._ +import chisel3.util._ import chiseltest._ +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor import org.scalatest.flatspec.AnyFlatSpec import interfaces.AfeParams +import scala.util.Random class ErrorCounterTest extends AnyFlatSpec with ChiselScalatestTester { val afeParams = AfeParams() + val width = afeParams.mbSerializerRatio * afeParams.mbLanes * 4 behavior of "error counter" it should "correctly count errors for lfsr pattern" in { test(new ErrorCounter(afeParams)) { c => c.io.req.valid.poke(true.B) c.io.req.bits.pattern.poke(TransmitPattern.LFSR) + var lfsrVals = Seq( + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + ) + /** No errors */ c.io.req.bits.input.poke( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc".U, + Vec.Lit(lfsrVals.map(_.U): _*), + ) + + val errWidth = log2Ceil(afeParams.mbSerializerRatio + 1) + c.io.errorCount.expect( + Vec.Lit( + Seq.fill(afeParams.mbLanes)( + 0.U(errWidth.W), + ): _*, + ), ) - c.io.errorCount.expect(0.U) c.clock.step() - /** 4 errors */ + val rand = new Random() + val bitWidth = afeParams.mbSerializerRatio + var numErrors = Seq.fill(16)(rand.nextInt(bitWidth)) + lfsrVals = Seq( + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + ) + println(f"numErrors: $numErrors") + c.io.req.bits.input.poke( - "h85d6_5241_12be_ad28_85d7_5241_13be_ad28_9b02_9901_9816_861d_9b02_9900_981e_861d".U, + Vec.Lit( + TestUtils + .makeRandomErrors(lfsrVals, numErrors, bitWidth) + .toSeq + .map(_.U(afeParams.mbSerializerRatio.W)): _*, + ), ) - c.io.errorCount.expect(4.U) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) c.clock.step() - /** 7 errors */ + numErrors = Seq.fill(16)(rand.nextInt(bitWidth)) + lfsrVals = Seq( + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + ) + println(f"numErrors: $numErrors") + c.io.req.bits.input.poke( - "hac7c_d3b4_60e4_8428_ac7c_d0b0_66e4_8428_6bad_c683_4596_d3b8_6bfd_c683_4596_d3b8".U, + Vec.Lit( + TestUtils + .makeRandomErrors(lfsrVals, numErrors, bitWidth) + .toSeq + .map(_.U(afeParams.mbSerializerRatio.W)): _*, + ), ) - c.io.errorCount.expect(7.U) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) c.clock.step() c.io.req.valid.poke(false.B) @@ -40,32 +123,66 @@ class ErrorCounterTest extends AnyFlatSpec with ChiselScalatestTester { c.clock.step() } - /** 0 errors */ + lfsrVals = Seq( + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + ) + c.io.req.bits.input.poke( - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54".U, + Vec.Lit(lfsrVals.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + c.io.errorCount.expect( + Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(errWidth.W)): _*, + ), ) - c.io.req.valid.poke(true.B) - c.io.errorCount.expect(0.U) } } it should "correctly count errors for valtrain pattern" in { test(new ErrorCounter(afeParams)) { c => - val width = afeParams.mbSerializerRatio * afeParams.mbLanes c.io.req.valid.poke(true.B) c.io.req.bits.pattern.poke(TransmitPattern.VALTRAIN) + val valtrain = Seq.fill(afeParams.mbLanes)( + BigInt("11110000" * (afeParams.mbSerializerRatio / 8), 2), + ) + val errWidth = log2Ceil(afeParams.mbSerializerRatio + 1) + val bitWidth = afeParams.mbSerializerRatio + /** No errors */ c.io.req.bits.input.poke( - ("b" + "1111_0000" * (width / 8)).U, + Vec.Lit(valtrain.map(_.U(bitWidth.W)): _*), + ) + c.io.errorCount.expect( + Vec.Lit(Seq.fill(afeParams.mbLanes)(0.U(errWidth.W)): _*), ) - c.io.errorCount.expect(0.U) c.clock.step() - /** 4 errors */ + val rand = new Random() + val numErrors = Seq.fill(16)(rand.nextInt(bitWidth)) c.io.req.bits.input.poke( - ("b" + "1011_0100" + "1111_0000" * (width / 8 - 2) + "0111_0001").U, + Vec.Lit( + TestUtils + .makeRandomErrors(valtrain, numErrors, bitWidth) + .toSeq + .map(_.U(bitWidth.W)): _*, + ), ) - c.io.errorCount.expect(4.U) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) c.clock.step() } @@ -74,50 +191,38 @@ class ErrorCounterTest extends AnyFlatSpec with ChiselScalatestTester { test(new ErrorCounter(afeParams)) { c => c.io.req.valid.poke(true.B) c.io.req.bits.pattern.poke(TransmitPattern.PER_LANE_ID) + val errWidth = log2Ceil(afeParams.mbSerializerRatio + 1) + val bitWidth = afeParams.mbSerializerRatio + + val perLaneId = + Seq.tabulate(afeParams.mbLanes)(i => BigInt("A" + f"$i%02X" + "A", 16)) /** No errors */ c.io.req.bits.input.poke( - ("b" + - "1010_0000_1111_1010" + - "1010_0000_1110_1010" + - "1010_0000_1101_1010" + - "1010_0000_1100_1010" + - "1010_0000_1011_1010" + - "1010_0000_1010_1010" + - "1010_0000_1001_1010" + - "1010_0000_1000_1010" + - "1010_0000_0111_1010" + - "1010_0000_0110_1010" + - "1010_0000_0101_1010" + - "1010_0000_0100_1010" + - "1010_0000_0011_1010" + - "1010_0000_0010_1010" + - "1010_0000_0001_1010" + - "1010_0000_0000_1010").U, - ) - c.io.errorCount.expect(0.U) + Vec.Lit(perLaneId.map(_.U(bitWidth.W)): _*), + ) + c.io.errorCount.expect( + Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(errWidth.W)): _*, + ), + ) c.clock.step() + val rand = new Random() + val numErrors = Seq.fill(16)(rand.nextInt(bitWidth)) c.io.req.bits.input.poke( - ("b" + - "1010_0000_1111_1010" + - "1010_0000_1110_1010" + - "1010_0010_1101_1010" + - "1010_0000_1100_1010" + - "1010_0000_0011_1010" + - "1010_0000_1010_1010" + - "1010_0000_1001_1010" + - "1010_0000_1000_1010" + - "1010_0000_0111_1010" + - "1010_0000_0110_1010" + - "1010_0000_0100_1010" + - "1010_0000_0100_1010" + - "1010_0000_0011_1010" + - "1010_0000_0010_1010" + - "1010_0000_0001_1010" + - "0010_0000_0000_1010").U, - ) - c.io.errorCount.expect(4.U) + Vec.Lit( + TestUtils + .makeRandomErrors(perLaneId, numErrors, bitWidth) + .toSeq + .map(_.U(bitWidth.W)): _*, + ), + ) + c.io.errorCount.expect( + Vec.Lit( + numErrors.map(_.U(errWidth.W)): _*, + ), + ) c.clock.step() } } diff --git a/src/test/scala/logphy/LinkTrainingFSMTest.scala b/src/test/scala/logphy/LinkTrainingFSMTest.scala index 53f700f..c13bec2 100644 --- a/src/test/scala/logphy/LinkTrainingFSMTest.scala +++ b/src/test/scala/logphy/LinkTrainingFSMTest.scala @@ -24,8 +24,11 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { ) { c => initPorts(c) testTransitionOutOfReset(c) + println("Exited Reset") initSB(c) + println("Successfully initialized sideband") initMB(c) + println("Successfully initialized mainband") c.io.currentState.expect(LinkTrainingState.linkInit) @@ -52,13 +55,16 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { private def initSB(c: LinkTrainingFSM): Unit = { c.io.currentState.expect(LinkTrainingState.sbInit) - c.io.sidebandFSMIO.patternTxData - .expectDequeue("h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) - c.io.sidebandFSMIO.patternTxData - .expectDequeue("h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) - c.io.sidebandFSMIO.rxData - .enqueueNow("h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) + val txData = Seq.fill(3)("h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) + val rxData = Seq.fill(1)("h_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) + fork { + c.io.sidebandFSMIO.rxData.enqueueSeq(rxData) + }.fork { + c.io.sidebandFSMIO.patternTxData.expectDequeueSeq(txData) + }.join() + c.clock.step(5) + println("Exchanged clock patterns") c.io.sidebandFSMIO.rxData.enqueueNow( SBMessage_factory(SBM.SBINIT_OUT_OF_RESET, "PHY", true, "PHY", 0, 0).U, ) @@ -72,6 +78,7 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandFSMIO.rxData.enqueue( SBMessage_factory(SBM.SBINIT_OUT_OF_RESET, "PHY", true, "PHY", 0, 0).U, ) + println("Exchanged out of reset sb packets") c.clock.step(2) c.io.sidebandFSMIO.rxData .enqueueNow( diff --git a/src/test/scala/logphy/LogPhyLaneTest.scala b/src/test/scala/logphy/LogPhyLaneTest.scala index 8039c4d..562835f 100644 --- a/src/test/scala/logphy/LogPhyLaneTest.scala +++ b/src/test/scala/logphy/LogPhyLaneTest.scala @@ -196,7 +196,7 @@ class LanesLoopBack( ) extends Module { val io = IO(new Bundle { val scramble = Input(Bool()) - val mainbandLaneIO = new MainbandLaneIO(afeParams) + val mainbandLaneIO = new MainbandIO(afeParams) }) val lanes = Module(new SimLanes(afeParams, queueParams)) lanes.io.scramble := io.scramble diff --git a/src/test/scala/logphy/MBTrainerTest.scala b/src/test/scala/logphy/MBTrainerTest.scala new file mode 100644 index 0000000..cdf845e --- /dev/null +++ b/src/test/scala/logphy/MBTrainerTest.scala @@ -0,0 +1,11 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import interfaces._ +import chisel3._ +import chisel3.util._ +import sideband.{SBM, SBMessage_factory} +class MBTrainFSMTest extends Module { + val io = IO(new Bundle {}) + +} diff --git a/src/test/scala/logphy/PatternGeneratorTest.scala b/src/test/scala/logphy/PatternGeneratorTest.scala index f75092f..b1b4894 100644 --- a/src/test/scala/logphy/PatternGeneratorTest.scala +++ b/src/test/scala/logphy/PatternGeneratorTest.scala @@ -2,8 +2,10 @@ package edu.berkeley.cs.ucie.digital package logphy import chisel3._ -import chisel3.experimental.BundleLiterals._ +import chisel3.util._ import chiseltest._ +import chisel3.experimental.BundleLiterals._ +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor import sideband.SidebandParams import interfaces._ import org.scalatest.flatspec.AnyFlatSpec @@ -11,6 +13,81 @@ import org.scalatest.flatspec.AnyFlatSpec class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { val afeParams = AfeParams() val sbParams = SidebandParams() + val lfsrVals = Seq( + Seq( + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + ), + Seq( + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + ), + Seq( + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + ), + Seq( + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + ), + ) + behavior of "sideband pattern generator" it should "detect clock pattern no delay" in { test( @@ -39,37 +116,29 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { } behavior of "mainband pattern generator" it should "detect MB LFSR pattern" in { + val maxPatternCount = 1024 test( new PatternGenerator( afeParams = afeParams, sbParams = sbParams, - maxPatternCount = 1024, + maxPatternCount = maxPatternCount, ), ) { c => initPorts(c) + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val width = afeParams.mbSerializerRatio * afeParams.mbLanes - val rxReceived = Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(width.W), - ) - - val expectedTx = Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(width.W), - ) + val expectedTx = lfsrVals + .map( + TestUtils + .lanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) + .map(_.U(width.W)) + var rxReceived = lfsrVals + .map( + TestUtils + .lanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) /** expected case with no errors */ testMainband( @@ -78,25 +147,80 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { patternCountMax = 4, patternDetectedCountMax = 4, timeoutCycles = 80, - mainbandRx = rxReceived, + mainbandRx = rxReceived.map(f => f.U(width.W)), mainbandTx = expectedTx, expectedResult = MessageRequestStatusType.SUCCESS, - expectedErrorCount = 0, + expectedErrorCount = Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(maxPatternCountWidth.W)): _*, + ), ) + val numTests = 4 + for (_ <- 0 until numTests) { + val (rxRecv, err) = + TestUtils.createExpErrVecs(lfsrVals, afeParams.mbSerializerRatio) + testMainband( + c = c, + transmitPattern = TransmitPattern.LFSR, + patternCountMax = 4, + patternDetectedCountMax = 4, + timeoutCycles = 80, + mainbandTx = expectedTx, + mainbandRx = rxRecv + .map(f => + TestUtils + .lanesToOne( + f.toSeq, + afeParams.mbLanes, + afeParams.mbSerializerRatio, + ), + ) + .map(_.U), + expectedResult = MessageRequestStatusType.SUCCESS, + expectedErrorCount = Vec.Lit(err.map(_.U(maxPatternCountWidth.W)): _*), + ) + } } } - it should "handle MB timeouts" in { + val maxPatternCount = 1024 test( new PatternGenerator( afeParams = afeParams, sbParams = sbParams, - maxPatternCount = 1024, + maxPatternCount = maxPatternCount, ), ) { c => initPorts(c) - assert(false, "TODO") + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) + + val expectedTx = lfsrVals + .map( + TestUtils + .lanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) + .map(_.U(width.W)) + val rxReceived = lfsrVals + .map( + TestUtils + .lanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) + + /** expected case with no errors */ + testMainband( + c = c, + transmitPattern = TransmitPattern.LFSR, + patternCountMax = 4, + patternDetectedCountMax = 4, + timeoutCycles = 4, + mainbandRx = rxReceived.map(f => f.U(width.W)), + mainbandTx = expectedTx, + expectedResult = MessageRequestStatusType.ERR, + expectedErrorCount = Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(maxPatternCountWidth.W)): _*, + ), + ) } } @@ -113,10 +237,10 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData .initSink() .setSinkClock(c.clock) - c.io.mainbandLaneIO.rxData + c.io.mainbandIO.rxData .initSource() .setSourceClock(c.clock) - c.io.mainbandLaneIO.txData + c.io.mainbandIO.txData .initSink() .setSinkClock(c.clock) } @@ -127,13 +251,12 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { patternCountMax: Int, patternDetectedCountMax: Int, timeoutCycles: Int, - sideband: Boolean, ): Unit = { c.io.patternGeneratorIO.transmitReq.ready.expect(true) c.io.sidebandLaneIO.rxData.ready.expect(false) - c.io.mainbandLaneIO.rxData.ready.expect(false) + c.io.mainbandIO.rxData.ready.expect(false) c.io.sidebandLaneIO.txData.expectInvalid() - c.io.mainbandLaneIO.txData.expectInvalid() + c.io.mainbandIO.txData.expectInvalid() c.io.patternGeneratorIO.resp.expectInvalid() c.io.patternGeneratorIO.transmitReq.enqueueNow( chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits).Lit( @@ -141,7 +264,6 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { _.patternCountMax -> patternCountMax.U, _.patternDetectedCountMax -> patternDetectedCountMax.U, _.timeoutCycles -> timeoutCycles.U, - _.sideband -> sideband.B, ), ) } @@ -155,7 +277,6 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { length * sbParams.sbNodeMsgWidth, length * sbParams.sbNodeMsgWidth, 80, - true, ) val testVector = @@ -167,13 +288,23 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData.expectDequeueSeq(testVector) }.join() - c.io.patternGeneratorIO.resp - .expectDequeue( - chiselTypeOf(c.io.patternGeneratorIO.resp.bits).Lit( - _.status -> MessageRequestStatusType.SUCCESS, - _.errorCount -> 0.U, - ), - ) + c.io.patternGeneratorIO.resp.ready.poke(true.B) + + val resp = c.io.patternGeneratorIO.resp + val statusExpected = MessageRequestStatusType.SUCCESS + fork + .withRegion(Monitor) { + while (!resp.valid.peek().litToBoolean) { + c.clock.step(1) + } + resp.valid.expect(true.B) + resp.bits.expectPartial( + chiselTypeOf(resp.bits).Lit( + _.status -> statusExpected, + ), + ) + } + .joinAndStep(c.clock) } private def testMainband( @@ -185,7 +316,7 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { mainbandRx: Seq[UInt], mainbandTx: Seq[UInt], expectedResult: MessageRequestStatusType.Type, - expectedErrorCount: Int, + expectedErrorCount: Vec[UInt], ): Unit = { createRequest( @@ -194,22 +325,37 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { patternCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, patternDetectedCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, timeoutCycles, - false, ) fork { - c.io.mainbandLaneIO.rxData.enqueueSeq(mainbandRx) + c.io.mainbandIO.rxData.enqueueSeq(mainbandRx) }.fork { - c.io.mainbandLaneIO.txData.expectDequeueSeq(mainbandTx) + c.io.mainbandIO.txData.expectDequeueSeq(mainbandTx) }.join() c.io.patternGeneratorIO.resp .expectDequeue( chiselTypeOf(c.io.patternGeneratorIO.resp.bits).Lit( _.status -> expectedResult, - _.errorCount -> expectedErrorCount.U, + _.errorCount -> expectedErrorCount, ), ) } } + +class PatternGeneratorLoopback( + afeParams: AfeParams, + sbParams: SidebandParams, + maxPatternCount: Int, +) extends Module { + + val io = IO(new Bundle { + val patternGeneratorIO = new PatternGeneratorIO(afeParams, maxPatternCount) + }) + + val patternGenerator = Module( + new PatternGenerator(afeParams, sbParams, maxPatternCount), + ) + +} diff --git a/src/test/scala/logphy/PatternReaderTest.scala b/src/test/scala/logphy/PatternReaderTest.scala index 678072b..6affe28 100644 --- a/src/test/scala/logphy/PatternReaderTest.scala +++ b/src/test/scala/logphy/PatternReaderTest.scala @@ -2,18 +2,105 @@ package edu.berkeley.cs.ucie.digital package logphy import chisel3._ +import chisel3.util._ +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor import sideband.SidebandParams import interfaces._ import chiseltest._ import org.scalatest.flatspec.AnyFlatSpec + +import scala.collection.mutable + class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { val afeParams = AfeParams() val sbParams = SidebandParams() + + val lfsrVals = Seq( + Seq( + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + ), + Seq( + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + ), + Seq( + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + ), + Seq( + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + ), + ) behavior of "pattern reader" it should "detect SB clock pattern" in { test(new PatternReader(sbParams, afeParams, 1024)) { c => + val maxPatternWidth = log2Ceil(1024 + 1) initPorts(c) - createRequest(c, TransmitPattern.CLOCK, sbParams.sbNodeMsgWidth * 4, true) + createRequest( + c, + TransmitPattern.CLOCK, + sbParams.sbNodeMsgWidth * 4, + true, + maxPatternWidth, + ) c.io.mbRxData.ready.expect(false.B) val testVector = @@ -32,157 +119,164 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { } it should "detect MB LFSR pattern no errors" in { test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => - val width = afeParams.mbLanes * afeParams.mbSerializerRatio - val testVector = - Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(width.W), - ) - makeMBTest(c, TransmitPattern.LFSR, testVector, 0) + val maxPatternWidth = log2Ceil(2048 + 1) + + makeMBTest( + c, + TransmitPattern.LFSR, + lfsrVals.map(f => + Vec.Lit(f.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + errorCountExpected = + Vec.Lit(Seq.fill(afeParams.mbLanes)(0.U(maxPatternWidth.W)): _*), + maxErrorCountWidth = maxPatternWidth, + ) } } it should "detect MB LFSR pattern error count" in { test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => val width = afeParams.mbLanes * afeParams.mbSerializerRatio - var testVector = Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_df60_bbbc_07ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b12_9911_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d3b0_60e4_f428_6bad_c683_4596_d3f8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a7b1_142b_3f8c_f317_a4b0_142b_3f8c_fa16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(width.W), + val maxPatternCountWidth = log2Ceil(2048 + 1) + var (testVecs, errVecs) = createExpErrVecs(lfsrVals) + + println(f"errVecs= $errVecs") + makeMBTest( + c, + TransmitPattern.LFSR, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.LFSR, testVector, 17) c.reset.poke(true.B) c.clock.step() c.reset.poke(false.B) - testVector = Seq( - "hb877_cf0f_c0c7_07bf_b877_cf00_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_0901_981e_861d_9b02_9901_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c682_4596_d3b8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(width.W), + var res = createExpErrVecs(lfsrVals) + testVecs = res._1 + errVecs = res._2 + println(f"errVecs= $errVecs") + + makeMBTest( + c, + TransmitPattern.LFSR, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.LFSR, testVector, 7) c.reset.poke(true.B) c.clock.step() c.reset.poke(false.B) - testVector = Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_00ce_c912_db60_bbbc" - .U(width.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b32_9901_981e_861d_9b02_9911_981e_861d" - .U(width.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_60ad_c683_4596_d3b8_6bad_c683_4596_d3b8" - .U(width.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a06_1c83_9fc1_5e5f_0a16_1c83_9fc1_5e54" - .U(width.W), + res = createExpErrVecs(lfsrVals) + testVecs = res._1 + errVecs = res._2 + println(f"errVecs= $errVecs") + makeMBTest( + c, + TransmitPattern.LFSR, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.LFSR, testVector, 13) + } } it should "detect MB valtrain pattern" in { test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => - val width = afeParams.mbLanes * afeParams.mbSerializerRatio - var testVector = Seq( - BigInt("11110000" * (width / 8), 2).U, - BigInt("11110000" * (width / 8), 2).U, - BigInt("11110000" * (width / 8), 2).U, - BigInt("11110000" * (width / 8), 2).U, + var numVecs = 4 + val maxPatternCountWidth = log2Ceil(2048 + 1) + var testVector = Seq.fill(numVecs)( + Seq.fill(afeParams.mbLanes)( + BigInt("11110000" * (afeParams.mbSerializerRatio / 8), 2), + ), + ) + var (testVecs, errVecs) = createExpErrVecs(testVector) + + println(f"errVecs= $errVecs") + makeMBTest( + c, + TransmitPattern.VALTRAIN, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 0) c.reset.poke(true.B) c.clock.step() c.reset.poke(false.B) - testVector = Seq( - toggleBits(BigInt("11110000" * (width / 8), 2), 0, 31, 249, 2).U, - toggleBits(BigInt("11110000" * (width / 8), 2), 1, 8, 9).U, - toggleBits(BigInt("11110000" * (width / 8), 2), 0, 2, 49, 9).U, - toggleBits(BigInt("11110000" * (width / 8), 2), 1).U, + numVecs = 10 + testVector = Seq.fill(numVecs)( + Seq.fill(afeParams.mbLanes)( + BigInt("11110000" * (afeParams.mbSerializerRatio / 8), 2), + ), ) - makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 12) - c.reset.poke(true.B) - c.clock.step() - c.reset.poke(false.B) + val res = createExpErrVecs(testVector) + testVecs = res._1 + errVecs = res._2 - testVector = Seq( - toggleBits(BigInt("11110000" * (width / 8), 2), 3, 241).U, - toggleBits(BigInt("11110000" * (width / 8), 2), 9).U, - toggleBits(BigInt("11110000" * (width / 8), 2), 49, 0).U, - toggleBits(BigInt("11110000" * (width / 8), 2)).U, + println(f"errVecs= $errVecs") + makeMBTest( + c, + TransmitPattern.VALTRAIN, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.VALTRAIN, testVector, 5) + } } + + private def createExpErrVecs( + testVector: Seq[Seq[BigInt]], + ): (Seq[mutable.Seq[BigInt]], Seq[Int]) = { + val testErrSeq = testVector.map(vec => + TestUtils.makeRandomErrors(vec, afeParams.mbSerializerRatio), + ) + val testVecs = testErrSeq.map(_._1) + val errVecs = + testErrSeq.map(_._2).reduce((x, y) => x.zip(y).map(f => f._1 + f._2)) + (testVecs, errVecs) + } + it should "detect MB per-lane ID pattern" in { test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => - val pattern = BigInt( - "1010000011111010" + - "1010000011101010" + - "1010000011011010" + - "1010000011001010" + - "1010000010111010" + - "1010000010101010" + - "1010000010011010" + - "1010000010001010" + - "1010000001111010" + - "1010000001101010" + - "1010000001011010" + - "1010000001001010" + - "1010000000111010" + - "1010000000101010" + - "1010000000011010" + - "1010000000001010", - 2, + val numVecs = 5 + val maxPatternCountWidth = log2Ceil(2048 + 1) + val testVector = Seq.fill(numVecs)( + Seq.tabulate(afeParams.mbLanes)(i => BigInt("A" + f"$i%02X" + "A", 16)), ) - var testVector = Seq( - pattern.U, - pattern.U, - pattern.U, - pattern.U, - ) - makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 0) + val (testVecs, errVecs) = createExpErrVecs(testVector) - c.reset.poke(true.B) - c.clock.step() - c.reset.poke(false.B) - - testVector = Seq( - toggleBits(pattern, 0).U, - toggleBits(pattern, 240, 8, 9).U, - toggleBits(pattern, 0, 2, 49, 9).U, - toggleBits(pattern, 1, 200).U, - toggleBits(pattern, 1).U, + println(f"errVecs= $errVecs") + makeMBTest( + c, + TransmitPattern.PER_LANE_ID, + testVecs.map(vec => + Vec.Lit(vec.toSeq.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ), + Vec.Lit(errVecs.map(_.U(maxPatternCountWidth.W)): _*), + maxPatternCountWidth, ) - makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 11) c.reset.poke(true.B) c.clock.step() c.reset.poke(false.B) - testVector = Seq( - toggleBits(pattern, 0).U, - toggleBits(pattern, 1, 240, 9).U, - ) - makeMBTest(c, TransmitPattern.PER_LANE_ID, testVector, 4) } } @@ -200,8 +294,9 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { private def makeMBTest( c: PatternReader, transmitPattern: TransmitPattern.Type, - testVector: Seq[UInt], - errorCountExpected: Int, + testVector: Seq[Vec[UInt]], + errorCountExpected: Vec[UInt], + maxErrorCountWidth: Int, ): Unit = { initPorts(c) val width = afeParams.mbLanes * afeParams.mbSerializerRatio @@ -210,6 +305,7 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { transmitPattern, patternCountMax = width * testVector.length, sideband = false, + maxErrorCountWidth, ) c.io.sbRxData.ready.expect(false.B) @@ -222,20 +318,24 @@ class PatternReaderTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sbRxData.ready.expect(false.B) c.io.resp.complete.expect(true.B) - c.io.resp.errorCount.expect(errorCountExpected.U) + c.io.resp.errorCount.expect(errorCountExpected) } private def createRequest( c: PatternReader, transmitPattern: TransmitPattern.Type, patternCountMax: Int, sideband: Boolean, + maxPatternWidth: Int, ): Unit = { c.io.request.bits.pattern.poke(transmitPattern) c.io.request.bits.patternCountMax.poke(patternCountMax) - c.io.request.bits.sideband.poke(sideband.B) c.io.request.valid.poke(true.B) c.io.resp.complete.expect(false.B) - c.io.resp.errorCount.expect(0.U) + c.io.resp.errorCount.expect( + Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(maxPatternWidth.W)): _*, + ), + ) c.io.resp.inProgress.expect(false.B) c.clock.step() } diff --git a/src/test/scala/logphy/PatternWriterTest.scala b/src/test/scala/logphy/PatternWriterTest.scala index 75aa630..c2246a2 100644 --- a/src/test/scala/logphy/PatternWriterTest.scala +++ b/src/test/scala/logphy/PatternWriterTest.scala @@ -2,6 +2,7 @@ package edu.berkeley.cs.ucie.digital package logphy import chisel3._ +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor import sideband.SidebandParams import interfaces._ import chiseltest._ @@ -17,7 +18,6 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { createRequest( c, TransmitPattern.CLOCK, - sideband = true, patternCountMax = 512, ) @@ -36,35 +36,100 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { } } + val lfsrVals = Seq( + Seq( + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + BigInt("bfbc", 16), + BigInt("07bb", 16), + BigInt("c760", 16), + BigInt("c0db", 16), + BigInt("0f12", 16), + BigInt("cfc9", 16), + BigInt("77ce", 16), + BigInt("b807", 16), + ), + Seq( + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + BigInt("281d", 16), + BigInt("ad86", 16), + BigInt("be1e", 16), + BigInt("1398", 16), + BigInt("4101", 16), + BigInt("5299", 16), + BigInt("d702", 16), + BigInt("859b", 16), + ), + Seq( + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + BigInt("28b8", 16), + BigInt("84d3", 16), + BigInt("e496", 16), + BigInt("6045", 16), + BigInt("b083", 16), + BigInt("d0c6", 16), + BigInt("7cad", 16), + BigInt("ac6b", 16), + ), + Seq( + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + BigInt("8c54", 16), + BigInt("3f5e", 16), + BigInt("2bc1", 16), + BigInt("149f", 16), + BigInt("b083", 16), + BigInt("a41c", 16), + BigInt("1716", 16), + BigInt("b30a", 16), + ), + ) it should "send MB LFSR pattern" in { test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) createRequest( c, TransmitPattern.LFSR, - false, afeParams.mbSerializerRatio * afeParams.mbLanes * 4, ) + val lfsrValVecs = lfsrVals.map(f => + Vec.Lit(f.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + c.clock.step() - val mbWidth = afeParams.mbSerializerRatio * afeParams.mbLanes - val lfsrValues = - Seq( - "hb877_cf0f_c0c7_07bf_b877_cf0f_c0c7_07bf_07ce_c912_db60_bbbc_07ce_c912_db60_bbbc" - .U(mbWidth.W), - "h85d7_5241_13be_ad28_85d7_5241_13be_ad28_9b02_9901_981e_861d_9b02_9901_981e_861d" - .U(mbWidth.W), - "hac7c_d0b0_60e4_8428_ac7c_d0b0_60e4_8428_6bad_c683_4596_d3b8_6bad_c683_4596_d3b8" - .U(mbWidth.W), - "hb317_a4b0_142b_3f8c_b317_a4b0_142b_3f8c_0a16_1c83_9fc1_5e54_0a16_1c83_9fc1_5e54" - .U(mbWidth.W), - ) for (i <- 0 until 4) { c.io.sbTxData.expectInvalid() c.io.resp.complete.expect(false.B) c.io.resp.inProgress.expect(true.B) c.io.mbTxData.expectDequeueNow( - lfsrValues(i), + lfsrValVecs(i), ) } @@ -74,23 +139,34 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { } it should "send MB valtrain pattern" in { - test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => + val maxPatternCount = 2048 + test( + new PatternWriter(sbParams, afeParams, maxPatternCount = maxPatternCount), + ) { c => initPorts(c) + val patternCountMax = 512 createRequest( c, TransmitPattern.VALTRAIN, - sideband = false, - patternCountMax = 512, + patternCountMax = patternCountMax, + ) + + val numVecs = + patternCountMax / (afeParams.mbLanes * afeParams.mbSerializerRatio) + + val valtrain = Seq.fill(numVecs)( + Seq.fill(afeParams.mbLanes)( + BigInt("11110000" * (afeParams.mbSerializerRatio / 8), 2), + ), ) c.clock.step() - val width = afeParams.mbSerializerRatio * afeParams.mbLanes - for (_ <- 0 until 512 / width) { + for (i <- 0 until numVecs) { c.io.sbTxData.expectInvalid() c.io.resp.complete.expect(false.B) c.io.resp.inProgress.expect(true.B) c.io.mbTxData.expectDequeueNow( - ("b" + "1111_0000" * (width / 8)).U, + Vec.Lit(valtrain(i).map(_.U(afeParams.mbSerializerRatio.W)): _*), ) } @@ -102,37 +178,24 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { it should "send MB per-lane ID pattern" in { test(new PatternWriter(sbParams, afeParams, maxPatternCount = 2048)) { c => initPorts(c) + val numVecs = 5 + val perLaneVec = Seq.fill(numVecs)( + Seq.tabulate(afeParams.mbLanes)(i => BigInt("A" + f"$i%02X" + "A", 16)), + ) + createRequest( c, TransmitPattern.PER_LANE_ID, - false, - 512, + numVecs * afeParams.mbSerializerRatio * afeParams.mbLanes, ) c.clock.step() - val width = afeParams.mbSerializerRatio * afeParams.mbLanes - for (_ <- 0 until 512 / width) { + for (i <- 0 until numVecs) { c.io.sbTxData.expectInvalid() c.io.resp.complete.expect(false.B) c.io.resp.inProgress.expect(true.B) c.io.mbTxData.expectDequeueNow( - ("b" + - "1010_0000_1111_1010" + - "1010_0000_1110_1010" + - "1010_0000_1101_1010" + - "1010_0000_1100_1010" + - "1010_0000_1011_1010" + - "1010_0000_1010_1010" + - "1010_0000_1001_1010" + - "1010_0000_1000_1010" + - "1010_0000_0111_1010" + - "1010_0000_0110_1010" + - "1010_0000_0101_1010" + - "1010_0000_0100_1010" + - "1010_0000_0011_1010" + - "1010_0000_0010_1010" + - "1010_0000_0001_1010" + - "1010_0000_0000_1010").U, + Vec.Lit(perLaneVec(i).map(_.U(afeParams.mbSerializerRatio.W)): _*), ) } @@ -144,12 +207,10 @@ class PatternWriterTest extends AnyFlatSpec with ChiselScalatestTester { private def createRequest( c: PatternWriter, transmitPattern: TransmitPattern.Type, - sideband: Boolean, patternCountMax: Int, ): Unit = { c.io.request.valid.poke(true.B) c.io.request.bits.pattern.poke(transmitPattern) - c.io.request.bits.sideband.poke(sideband.B) c.io.request.bits.patternCountMax.poke(patternCountMax.U) c.io.resp.complete.expect(false.B) c.io.resp.inProgress.expect(false.B) diff --git a/src/test/scala/logphy/RdiDataMapperTest.scala b/src/test/scala/logphy/RdiDataMapperTest.scala index eaebcde..a01359b 100644 --- a/src/test/scala/logphy/RdiDataMapperTest.scala +++ b/src/test/scala/logphy/RdiDataMapperTest.scala @@ -13,28 +13,31 @@ class RdiDataMapperTest extends AnyFlatSpec with ChiselScalatestTester { behavior of "rdi data mapper" it should "correctly output rx lane data" in { test(new RdiDataMapper(rdiParams, afeParams)) { c => - val data = Vec.Lit( + val data = Seq( "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888".U, "h2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322".U, "h1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888".U, "h1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331".U, ) - val dataUInt = - "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888_2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322_1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888_1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331".U + val dataUInt = ("h" + + "1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331" + + "1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888" + + "2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322" + + "1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888").U + c.io.mainbandLaneIO.rxData.initSource() c.io.mainbandLaneIO.rxData.setSourceClock(c.clock) c.io.mainbandLaneIO.rxData.valid.poke(false) c.clock.step() for (i: Int <- 0 until 4) { - c.io.mainbandLaneIO.rxData.valid.poke(false) for (_: Int <- 0 until 10) { c.io.rdi.plData.valid.expect(false) c.clock.step() } c.io.mainbandLaneIO.rxData.enqueueNow(data(i)) } - c.io.rdi.plData.valid.expect(true) + c.io.rdi.plData.valid.expect(true.B) c.io.rdi.plData.bits.expect(dataUInt) c.clock.step() for (_ <- 0 until 10) { @@ -46,14 +49,17 @@ class RdiDataMapperTest extends AnyFlatSpec with ChiselScalatestTester { it should "correctly output tx lane data" in { test(new RdiDataMapper(rdiParams, afeParams)) { c => - val data = Vec.Lit( + val data = Seq( "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888".U, "h2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322".U, "h1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888".U, "h1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331".U, ) - val dataUInt = - "h1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888_2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322_1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888_1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331".U + val dataUInt = ("h" + + "1111_3333_3333_4444_5555_6666_7777_8888_1334_5678_9aac_def0_0fed_caa9_8765_4331" + + "1244_6678_9abc_def0_0fed_cba9_8766_4421_1111_2222_4444_4444_6666_6666_7777_8888" + + "2222_2222_3333_4444_5555_6666_8888_8888_2234_5688_9abc_def0_0fed_cba9_8865_4322" + + "1234_5678_9abc_def0_0fed_cba9_8765_4321_1111_2222_3333_4444_5555_6666_7777_8888").U c.io.mainbandLaneIO.txData.initSink() c.io.mainbandLaneIO.txData.setSinkClock(c.clock) diff --git a/src/test/scala/logphy/SBMsgWrapperTest.scala b/src/test/scala/logphy/SBMsgWrapperTest.scala index 1bc6878..d6a9121 100644 --- a/src/test/scala/logphy/SBMsgWrapperTest.scala +++ b/src/test/scala/logphy/SBMsgWrapperTest.scala @@ -32,6 +32,14 @@ class SBMsgWrapperTest extends AnyFlatSpec with ChiselScalatestTester { } } + it should "correctly receive only" in { + test(new SBMsgWrapper(sbParams)) { c => + /** TODO */ + assert(false) + } + + } + private def testSBInitOutOfReset(c: SBMsgWrapper): Unit = { c.io.laneIO.rxData.ready.expect(false) c.io.laneIO.txData.expectInvalid() @@ -50,7 +58,7 @@ class SBMsgWrapperTest extends AnyFlatSpec with ChiselScalatestTester { c.io.trainIO.msgReq.enqueueNow( (new MessageRequest).Lit( _.msg -> sbMsg.U, - // _.reqType -> MessageRequestType.MSG_EXCH, + _.reqType -> MessageRequestType.EXCHANGE, _.timeoutCycles -> 80.U, ), ) diff --git a/src/test/scala/logphy/TestUtils.scala b/src/test/scala/logphy/TestUtils.scala new file mode 100644 index 0000000..8aa6db1 --- /dev/null +++ b/src/test/scala/logphy/TestUtils.scala @@ -0,0 +1,113 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import scala.collection.mutable +import scala.util.Random + +object TestUtils { + + def createExpErrVecs( + testVector: Seq[Seq[BigInt]], + serializerRatio: Int, + ): (Seq[mutable.Seq[BigInt]], Seq[Int]) = { + val testErrSeq = + testVector.map(vec => TestUtils.makeRandomErrors(vec, serializerRatio)) + val testVecs = testErrSeq.map(_._1) + val errVecs = + testErrSeq.map(_._2).reduce((x, y) => x.zip(y).map(f => f._1 + f._2)) + (testVecs, errVecs) + } + + def oneToLanes( + input: BigInt, + numLanes: Int, + serializerRatio: Int, + ): Seq[BigInt] = { + val result = mutable.Seq.fill(numLanes)(BigInt(0)) + var one = input + for (i <- 0 until serializerRatio / 8) { + for (j <- 0 until numLanes) { + result(j) |= (one & 0xff) << (i * 8) + one >>= 8 + } + } + result.toSeq + } + + def lanesToOne( + input: Seq[BigInt], + numLanes: Int, + serializerRatio: Int, + ): BigInt = { + var result = BigInt(0) + val lanes = mutable.Seq(input: _*) + for (i <- 0 until serializerRatio / 8) { + for (j <- 0 until numLanes) { + result |= (lanes(j) & 0xff) << ((i * numLanes + j) * 8) + lanes(j) >>= 8 + } + } + result + } + + def makeRandomErrors( + input: Seq[BigInt], + width: Int, + ): (mutable.Seq[BigInt], Seq[Int]) = { + val result = mutable.Seq(input: _*) + val rand = new Random() + val numErrors = Seq.fill(input.length)(rand.nextInt(width)) + for (i <- 0 until input.length) { + val errorBits = mutable.Set[Int]() + val numError = numErrors(i) + while (errorBits.size < numError) { + val bit = rand.nextInt(width) + if (!errorBits.contains(bit)) { + result(i) ^= BigInt(1) << bit + errorBits += bit + } + } + } + (result, numErrors) + } + + def makeRandomErrors( + input: Seq[BigInt], + numErrors: Seq[Int], + width: Int, + ): mutable.Seq[BigInt] = { + val result = mutable.Seq(input: _*) + val rand = new Random() + for (i <- 0 until input.length) { + val errorBits = mutable.Set[Int]() + val numError = numErrors(i) + while (errorBits.size < numError) { + val bit = rand.nextInt(width) + if (!errorBits.contains(bit)) { + result(i) ^= BigInt(1) << bit + errorBits += bit + } + } + } + result + } + def makeRandomErrors( + input: Seq[BigInt], + numErrors: Int, + width: Int, + ): mutable.Seq[BigInt] = { + val result = mutable.Seq(input: _*) + val errorBits = mutable.Set[(Int, Int)]() + + val rand = new Random() + while (errorBits.size < numErrors) { + val i = rand.nextInt(input.length) + val bit = rand.nextInt(width) + if (!errorBits.contains((i, bit))) { + result(i) ^= BigInt(1) << bit + errorBits += ((i, bit)) + } + } + result + } +} From a3f15886a099182fe2f4db9fbd5b67f05e5cd29d Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Tue, 30 Jul 2024 00:48:25 -0700 Subject: [PATCH 06/12] logphy toplevel compilation, more progress on mb trainer test --- src/main/scala/logphy/Lanes.scala | 28 +- src/main/scala/logphy/LogPhyTypes.scala | 7 +- src/main/scala/logphy/LogicalPhy.scala | 19 +- src/main/scala/logphy/MBInitFSM.scala | 2 +- src/main/scala/logphy/MBTrainer.scala | 275 ++++++++++++++++++- src/main/scala/logphy/SBMsgWrapper.scala | 23 +- src/test/scala/logphy/MBInitFSMTest.scala | 7 +- src/test/scala/logphy/MBTrainerTest.scala | 167 ++++++++++- src/test/scala/logphy/SBMsgWrapperTest.scala | 51 +++- src/test/scala/logphy/ScramblerTest.scala | 54 ++-- 10 files changed, 558 insertions(+), 75 deletions(-) diff --git a/src/main/scala/logphy/Lanes.scala b/src/main/scala/logphy/Lanes.scala index 079d56f..b79e469 100644 --- a/src/main/scala/logphy/Lanes.scala +++ b/src/main/scala/logphy/Lanes.scala @@ -58,8 +58,8 @@ class Lanes( val io = IO(new Bundle() { val scramble = Input(Bool()) - val mainbandIo = new MainbandLaneIO(afeParams) - val mainbandLaneIO = new MainbandIO(afeParams) + val mainbandLaneIO = new MainbandLaneIO(afeParams) + val mainbandIO = new MainbandIO(afeParams) }) val txMBFifo = @@ -86,16 +86,16 @@ class Lanes( new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), ) - rxMBFifo.io.enq <> io.mainbandIo.rxData + rxMBFifo.io.enq <> io.mainbandLaneIO.rxData rxMBFifo.io.deq_clock := clock rxMBFifo.io.deq_reset := reset - rxMBFifo.io.enq_clock := io.mainbandIo.fifoParams.clk - rxMBFifo.io.enq_reset := io.mainbandIo.fifoParams.reset - txMBFifo.io.deq <> io.mainbandIo.txData + rxMBFifo.io.enq_clock := io.mainbandLaneIO.fifoParams.clk + rxMBFifo.io.enq_reset := io.mainbandLaneIO.fifoParams.reset + txMBFifo.io.deq <> io.mainbandLaneIO.txData txMBFifo.io.enq_clock := clock txMBFifo.io.enq_reset := reset - txMBFifo.io.deq_clock := io.mainbandIo.fifoParams.clk - txMBFifo.io.deq_reset := io.mainbandIo.fifoParams.reset + txMBFifo.io.deq_clock := io.mainbandLaneIO.fifoParams.clk + txMBFifo.io.deq_reset := io.mainbandLaneIO.fifoParams.reset assert( afeParams.mbSerializerRatio > 8 && afeParams.mbSerializerRatio % 8 == 0, @@ -115,25 +115,25 @@ class Lanes( rxScrambler.io.valid := rxMBFifo.io.deq.fire descrambledRx := rxScrambler.io.data_out txScrambler.io.data_in := OneToLanes( - io.mainbandLaneIO.txData.bits, + io.mainbandIO.txData.bits, afeParams.mbLanes, afeParams.mbSerializerRatio, ) - txScrambler.io.valid := io.mainbandLaneIO.txData.fire + txScrambler.io.valid := io.mainbandIO.txData.fire scrambledTx := txScrambler.io.data_out /** Queue data into FIFOs */ - txMBFifo.io.enq.valid := io.mainbandLaneIO.txData.valid - io.mainbandLaneIO.txData.ready := txMBFifo.io.enq.ready + txMBFifo.io.enq.valid := io.mainbandIO.txData.valid + io.mainbandIO.txData.ready := txMBFifo.io.enq.ready txMBFifo.io.enq.bits := Mux( io.scramble, scrambledTx, txScrambler.io.data_in, ) - io.mainbandLaneIO.rxData.valid := rxMBFifo.io.deq.valid - io.mainbandLaneIO.rxData.bits := LanesToOne( + io.mainbandIO.rxData.valid := rxMBFifo.io.deq.valid + io.mainbandIO.rxData.bits := LanesToOne( rxDataInput, afeParams.mbLanes, afeParams.mbSerializerRatio, diff --git a/src/main/scala/logphy/LogPhyTypes.scala b/src/main/scala/logphy/LogPhyTypes.scala index 2931553..6ccf82c 100644 --- a/src/main/scala/logphy/LogPhyTypes.scala +++ b/src/main/scala/logphy/LogPhyTypes.scala @@ -29,7 +29,7 @@ class SBReqMsg extends Bundle { } object MessageRequestType extends ChiselEnum { - val EXCHANGE, RECEIVE = Value + val EXCHANGE, RECEIVE, SEND = Value } class MessageRequest extends Bundle { @@ -51,7 +51,10 @@ object ClockModeParam extends ChiselEnum { } object TransmitPattern extends ChiselEnum { - val CLOCK, VALTRAIN, LFSR, PER_LANE_ID = Value + val LFSR = Value(0.U) + val PER_LANE_ID = Value(1.U) + val VALTRAIN = Value(2.U) + val CLOCK = Value(3.U) } class SBIO(params: AfeParams) extends Bundle { diff --git a/src/main/scala/logphy/LogicalPhy.scala b/src/main/scala/logphy/LogicalPhy.scala index b4a1cfd..db79934 100644 --- a/src/main/scala/logphy/LogicalPhy.scala +++ b/src/main/scala/logphy/LogicalPhy.scala @@ -69,11 +69,22 @@ class LogicalPhy( val lanes = Module(new Lanes(afeParams, laneAsyncQueueParams)) + /** TODO: need to drive this from state machine */ + lanes.io.scramble := true.B + /** Connect internal FIFO to AFE */ - lanes.io.mainbandIo.txData <> io.mbAfe.txData - lanes.io.mainbandIo.rxData <> io.mbAfe.rxData - lanes.io.mainbandIo.fifoParams <> io.mbAfe.fifoParams - rdiDataMapper.io.mainbandLaneIO <> lanes.io.mainbandLaneIO + when(trainingModule.io.currentState === LinkTrainingState.active) { + rdiDataMapper.io.mainbandLaneIO <> lanes.io.mainbandIO + trainingModule.io.mainbandFSMIO.mainbandIO.rxData.noenq() + trainingModule.io.mainbandFSMIO.mainbandIO.txData.nodeq() + }.otherwise { + rdiDataMapper.io.mainbandLaneIO.rxData.noenq() + rdiDataMapper.io.mainbandLaneIO.txData.nodeq() + trainingModule.io.mainbandFSMIO.mainbandIO <> lanes.io.mainbandIO + } + lanes.io.mainbandLaneIO.txData <> io.mbAfe.txData + lanes.io.mainbandLaneIO.rxData <> io.mbAfe.rxData + lanes.io.mainbandLaneIO.fifoParams <> io.mbAfe.fifoParams /** TODO: need to hook up lane scrambling boolean to states */ diff --git a/src/main/scala/logphy/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index 7f73a47..acad82d 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -111,7 +111,7 @@ class MBInitFSM( if (req) SBM.MBINIT_PARAM_CONFIG_REQ else SBM.MBINIT_PARAM_CONFIG_RESP, "PHY", - true, + remote = true, "PHY", data, ) diff --git a/src/main/scala/logphy/MBTrainer.scala b/src/main/scala/logphy/MBTrainer.scala index 883a4a2..7d0cd3b 100644 --- a/src/main/scala/logphy/MBTrainer.scala +++ b/src/main/scala/logphy/MBTrainer.scala @@ -6,8 +6,13 @@ import chisel3._ import chisel3.util._ import sideband.{SBM, SBMessage_factory} -class TrainingOperation extends Bundle { +/** TODO: make timeout cycles optional */ +class TrainingOperation(maxPatternCount: Int) extends Bundle { + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) val pattern = TransmitPattern() + val patternUICount = UInt(maxPatternCountWidth.W) + val triggerNew = Bool() + val triggerExit = Bool() } class MBTrainer( @@ -20,31 +25,55 @@ class MBTrainer( linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio val io = IO(new Bundle { - val trainingOperationIO = Valid(new TrainingOperation) + val trainingOperationIO = Input(new TrainingOperation(maxPatternCount)) val sbTrainIO = Flipped(new SBMsgWrapperTrainIO) val sbMsgWrapperReset = Output(Bool()) val patternGeneratorIO = Flipped(new PatternGeneratorIO(afeParams, maxPatternCount)) + val complete = Output(Bool()) + val err = Output(Bool()) }) + io.sbTrainIO.msgReq.noenq() + io.sbTrainIO.msgReqStatus.nodeq() + io.patternGeneratorIO.transmitReq.noenq() + io.patternGeneratorIO.resp.nodeq() + private object State extends ChiselEnum { val WAIT_PTTEST_REQ_SEND, WAIT_PTTEST_REQ, SEND_PTTEST_REQ, - WAIT_AND_SEND_PTTEST_RESP, ERR = Value + SEND_PTTEST_REQ_WAIT, SEND_PTTEST_RESP, SEND_PTTEST_RESP_WAIT, + TRAIN_SEND_PATTERN_REQ, TRAIN_WAIT_PATTERN_RESP, + TRAIN_PATTERN_FINISHED_SEND, TRAIN_PATTERN_FINISHED_WAIT, + PTTEST_RESULTS_REQ_SEND, PTTEST_RESULTS_REQ_WAIT, + PTTEST_RESULTS_RESP_SEND, PTTEST_RESULTS_RESP_WAIT, + PTTEST_END_TEST_REQ_SEND, PTTEST_END_TEST_REQ_WAIT, + PTTEST_END_TEST_RESP_SEND, PTTEST_END_TEST_RESP_WAIT, COMPLETE, ERR = + Value } private val currentState = RegInit(State.WAIT_PTTEST_REQ_SEND) - val operation = Reg(new TrainingOperation) + + io.complete := currentState === State.COMPLETE || currentState === State.ERR + io.err := currentState === State.ERR + private val txDtoCPointReq = RegInit(0.U.asTypeOf(new TxDtoCPointReq)) io.sbMsgWrapperReset := false.B - when(io.trainingOperationIO.valid) { + when(io.trainingOperationIO.triggerNew) { currentState := State.SEND_PTTEST_REQ io.sbMsgWrapperReset := true.B - txDtoCPointReq.dataPattern := + val pointReq = Wire(new TxDtoCPointReq) + pointReq := DontCare + pointReq.dataPattern := io.trainingOperationIO.pattern.asUInt + pointReq.iterationCount := io.trainingOperationIO.patternUICount + txDtoCPointReq := pointReq + }.elsewhen(io.trainingOperationIO.triggerExit) { + currentState := State.PTTEST_END_TEST_REQ_SEND + io.sbMsgWrapperReset := true.B } private class TxDtoCPointReq extends Bundle { - val reserved = 0.U(4.W) + val reserved = UInt(4.W) val comparisonMode = UInt(1.W) val iterationCount = UInt(16.W) val idleCount = UInt(16.W) @@ -55,6 +84,19 @@ class MBTrainer( val dataPattern = UInt(3.W) } + private class TxDtoCResultsResp extends Bundle { + val msgInfo = new Bundle { + val reserved = UInt(10.W) + val validLaneComparisonResults = UInt(1.W) + val cumulativeResults = UInt(1.W) + val redundantLaneComparison = UInt(4.W) + } + val data = new Bundle { + val reserved = UInt(48.W) + val lanePassResults = Vec(afeParams.mbLanes, Bool()) + } + } + def formStartTxDtoCPointReq( maxErrors: UInt, req: TxDtoCPointReq, @@ -66,7 +108,7 @@ class MBTrainer( msgReq.msg := SBMessage_factory( SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_REQ, src = "PHY", - remote = false, + remote = true, dst = "PHY", data, msgInfo = maxErrors(15, 0), @@ -76,13 +118,33 @@ class MBTrainer( msgReq } + def formStartTxDtoCPointResp( + reqType: MessageRequestType.Type, + ): MessageRequest = { + val msgReq = Wire(new MessageRequest) + msgReq.msg := SBMessage_factory( + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_RESP, + src = "PHY", + remote = true, + dst = "PHY", + ) + msgReq.timeoutCycles := (0.008 * sbClockFreq).toInt.U + msgReq.reqType := reqType + msgReq + } + + private val errorCount = Reg( + chiselTypeOf(io.patternGeneratorIO.resp.bits.errorCount), + ) switch(currentState) { is(State.WAIT_PTTEST_REQ_SEND) { + + /** Send the request to the SB trainer to wait for the Pt Test Req msg */ io.sbTrainIO.msgReq.valid := true.B - val txDtoCPointReq = new TxDtoCPointReq + val txDtoCPointReq = Wire(new TxDtoCPointReq) txDtoCPointReq := DontCare - io.sbTrainIO.msgReq.bits.msg := formStartTxDtoCPointReq( + io.sbTrainIO.msgReq.bits := formStartTxDtoCPointReq( 0.U, txDtoCPointReq, MessageRequestType.RECEIVE, @@ -92,6 +154,9 @@ class MBTrainer( } } is(State.WAIT_PTTEST_REQ) { + + /** Wait for SB trainer to indicate that Pt Test Req message was received + */ io.sbTrainIO.msgReqStatus.ready := true.B when(io.sbTrainIO.msgReqStatus.fire) { txDtoCPointReq := io.sbTrainIO.msgReqStatus.bits.data @@ -105,14 +170,200 @@ class MBTrainer( "SB Message wrapper should not throw error in MB trainer", ) }.otherwise { - currentState := State.WAIT_AND_SEND_PTTEST_RESP + currentState := State.SEND_PTTEST_RESP } } } is(State.SEND_PTTEST_REQ) { + /** Send Pt Test Req message (skip if already received Pt Test Req) */ + io.sbTrainIO.msgReq.valid := true.B + io.sbTrainIO.msgReq.bits := formStartTxDtoCPointReq( + 0.U, + txDtoCPointReq, + MessageRequestType.SEND, + ) + when(io.sbTrainIO.msgReq.fire) { + currentState := State.SEND_PTTEST_REQ_WAIT + } + } + is(State.SEND_PTTEST_REQ_WAIT) { + + /** Wait for Pt Test Request to be received (skip if already received pt + * test request) + */ + receiveSBMsg(State.SEND_PTTEST_RESP) + } + is(State.SEND_PTTEST_RESP) { + + /** Have SB Trainer send a response */ + sendSBReq( + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_RESP, + MessageRequestType.EXCHANGE, + State.SEND_PTTEST_RESP_WAIT, + ) + } + is(State.SEND_PTTEST_RESP_WAIT) { + + /** Wait for SB trainer to indicate Start Pt Test response was a success + */ + receiveSBMsg(State.TRAIN_SEND_PATTERN_REQ) + } + is(State.TRAIN_SEND_PATTERN_REQ) { + + /** Request pattern generator to complete the pattern test */ + io.patternGeneratorIO.transmitReq.bits.pattern := txDtoCPointReq.dataPattern + .asUInt(1, 0) + .asTypeOf(TransmitPattern()) + io.patternGeneratorIO.transmitReq.bits.timeoutCycles := (0.008 * sbClockFreq).toInt.U + io.patternGeneratorIO.transmitReq.bits.patternCountMax := txDtoCPointReq.iterationCount + io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax := txDtoCPointReq.iterationCount + io.patternGeneratorIO.transmitReq.valid := true.B + when(io.patternGeneratorIO.transmitReq.fire) { + currentState := State.TRAIN_WAIT_PATTERN_RESP + } + } + is(State.TRAIN_WAIT_PATTERN_RESP) { + + /** Wait for pattern generator to indicate that test is complete */ + io.patternGeneratorIO.resp.ready := true.B + when(io.patternGeneratorIO.resp.fire) { + when( + io.patternGeneratorIO.resp.bits.status === MessageRequestStatusType.ERR, + ) { + currentState := State.ERR + } + .otherwise { + errorCount := io.patternGeneratorIO.resp.bits.errorCount + currentState := State.PTTEST_RESULTS_REQ_SEND + } + } + } + is(State.PTTEST_RESULTS_REQ_SEND) { + + /** Request SB trainer to send results request message */ + io.sbTrainIO.msgReq.valid := true.B + io.sbTrainIO.msgReq.bits.msg := SBMessage_factory( + SBM.MBTRAIN_TX_INIT_D_TO_C_RESULTS_REQ, + "PHY", + true, + "PHY", + ) + io.sbTrainIO.msgReq.bits.reqType := MessageRequestType.EXCHANGE + io.sbTrainIO.msgReq.bits.timeoutCycles := (0.008 * sbClockFreq).toInt.U + when(io.sbTrainIO.msgReq.fire) { + + /** Received result req, no need to send result req */ + currentState := State.PTTEST_RESULTS_REQ_WAIT + } + } + is(State.PTTEST_RESULTS_REQ_WAIT) { + + /** Wait for SB trainer to indicate that results was a success */ + receiveSBMsg(State.PTTEST_RESULTS_RESP_SEND) + } + is(State.PTTEST_RESULTS_RESP_SEND) { + + /** Request SB messenger to exchange results resp */ + val resultsResp = Wire(new TxDtoCResultsResp) + resultsResp := DontCare + io.sbTrainIO.msgReq.bits.msg := SBMessage_factory( + SBM.MBTRAIN_TX_INIT_D_TO_C_RESULTS_RESP, + "PHY", + true, + "PHY", + resultsResp.data.asUInt, + resultsResp.msgInfo.asUInt, + ) + io.sbTrainIO.msgReq.bits.reqType := MessageRequestType.EXCHANGE + io.sbTrainIO.msgReq.bits.timeoutCycles := (0.008 * sbClockFreq).toInt.U + io.sbTrainIO.msgReq.valid := true.B + when(io.sbTrainIO.msgReq.fire) { + currentState := State.PTTEST_RESULTS_RESP_WAIT + } + } + is(State.PTTEST_RESULTS_RESP_WAIT) { + receiveSBMsg(State.TRAIN_PATTERN_FINISHED_WAIT) + } + is(State.TRAIN_PATTERN_FINISHED_SEND) { + + /** From here, wait for a few things: (1) re-trigger training (2) finish + * training trigger (3) SB message indicating training is finished + */ + + io.sbTrainIO.msgReq.valid := true.B + io.sbTrainIO.msgReq.bits.msg := SBMessage_factory( + SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ, + "PHY", + true, + "PHY", + ) + io.sbTrainIO.msgReq.bits.reqType := MessageRequestType.RECEIVE + io.sbTrainIO.msgReq.bits.timeoutCycles := (0.008 * sbClockFreq).toInt.U + when(io.sbTrainIO.msgReq.fire) { + currentState := State.TRAIN_PATTERN_FINISHED_WAIT + } + } + is(State.TRAIN_PATTERN_FINISHED_WAIT) { + val nextState = State.PTTEST_END_TEST_RESP_SEND + receiveSBMsg(nextState) + } + is(State.PTTEST_END_TEST_REQ_SEND) { + val reqType = MessageRequestType.EXCHANGE + sendSBReq( + SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ, + reqType, + State.PTTEST_END_TEST_REQ_WAIT, + ) + } + is(State.PTTEST_END_TEST_REQ_WAIT) { + receiveSBMsg(State.PTTEST_END_TEST_RESP_SEND) + } + is(State.PTTEST_END_TEST_RESP_SEND) { + sendSBReq( + SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_RESP, + MessageRequestType.EXCHANGE, + State.PTTEST_END_TEST_RESP_WAIT, + ) + } + is(State.PTTEST_END_TEST_RESP_WAIT) { + receiveSBMsg(State.COMPLETE) + } + is(State.COMPLETE) {} + is(State.ERR) {} + + } + + private def receiveSBMsg(nextState: State.Type) = { + io.sbTrainIO.msgReqStatus.ready := true.B + when(io.sbTrainIO.msgReqStatus.fire) { + when( + io.sbTrainIO.msgReqStatus.bits.status === MessageRequestStatusType.ERR, + ) { + currentState := State.ERR + }.otherwise { + currentState := nextState + } + } + } + + private def sendSBReq( + message: BitPat, + reqType: MessageRequestType.Type, + nextState: State.Type, + ): Unit = { + io.sbTrainIO.msgReq.bits.msg := SBMessage_factory( + message, + "PHY", + remote = true, + "PHY", + ) + io.sbTrainIO.msgReq.bits.reqType := reqType + io.sbTrainIO.msgReq.bits.timeoutCycles := (0.008 * sbClockFreq).toInt.U + io.sbTrainIO.msgReq.valid := true.B + when(io.sbTrainIO.msgReq.fire) { + currentState := nextState } - is(State.WAIT_AND_SEND_PTTEST_RESP) {} } } diff --git a/src/main/scala/logphy/SBMsgWrapper.scala b/src/main/scala/logphy/SBMsgWrapper.scala index 3d2d7d1..ce86b73 100644 --- a/src/main/scala/logphy/SBMsgWrapper.scala +++ b/src/main/scala/logphy/SBMsgWrapper.scala @@ -71,6 +71,7 @@ class SBMsgReader(sbParams: SidebandParams) extends Module { when(inProgress && justReceivedMsg) { data := io.rxData.bits(127, 64) complete := true.B + inProgress := false.B } io.result.valid := complete @@ -90,7 +91,7 @@ class SBMsgWrapper( val sbMsgReader = Module(new SBMsgReader(sbParams)) private object State extends ChiselEnum { - val IDLE, EXCHANGE, RECEIVE_ONLY, WAIT_ACK = Value + val IDLE, EXCHANGE, RECEIVE_ONLY, SEND_ONLY, WAIT_ACK = Value } private val currentState = RegInit(State.IDLE) @@ -112,7 +113,7 @@ class SBMsgWrapper( private val dataOut = RegInit(0.U(64.W)) io.trainIO.msgReqStatus.bits.data := dataOut io.trainIO.msgReqStatus.bits.status := currentStatus - io.trainIO.msgReqStatus.noenq() + io.trainIO.msgReqStatus.valid := false.B io.trainIO.msgReq.nodeq() sbMsgReader.io.rxData <> io.laneIO.rxData @@ -121,6 +122,11 @@ class SBMsgWrapper( sbMsgWriter.io.req.bits := currentReq sbMsgReader.io.req.valid := false.B sbMsgWriter.io.req.valid := false.B + private val requestToState = Seq( + MessageRequestType.EXCHANGE -> State.EXCHANGE, + MessageRequestType.SEND -> State.SEND_ONLY, + MessageRequestType.RECEIVE -> State.RECEIVE_ONLY, + ) switch(currentState) { is(State.IDLE) { @@ -128,7 +134,9 @@ class SBMsgWrapper( when(io.trainIO.msgReq.fire) { currentReq := io.trainIO.msgReq.bits.msg currentReqTimeoutMax := io.trainIO.msgReq.bits.timeoutCycles - nextState := Mux(io.trainIO.msgReq.bits.reqType === MessageRequestType.EXCHANGE, State.EXCHANGE, State.RECEIVE_ONLY) + nextState := MuxLookup(io.trainIO.msgReq.bits.reqType, State.EXCHANGE)( + requestToState, + ) } } is(State.EXCHANGE) { @@ -150,21 +158,26 @@ class SBMsgWrapper( } is(State.RECEIVE_ONLY) { sbMsgReader.io.req.valid := true.B - when(sbMsgReader.io.result.valid) { dataOut := sbMsgReader.io.result.bits.data currentStatus := MessageRequestStatusType.SUCCESS nextState := State.WAIT_ACK } + } + is(State.SEND_ONLY) { + sbMsgWriter.io.req.valid := true.B + when(sbMsgWriter.io.result.valid) { + currentStatus := MessageRequestStatusType.SUCCESS + } timeoutCounter := timeoutCounter + 1.U when(timeoutCounter === currentReqTimeoutMax) { nextState := State.WAIT_ACK currentStatus := MessageRequestStatusType.ERR } + } is(State.WAIT_ACK) { - printf("ack\n") io.trainIO.msgReqStatus.valid := true.B when(io.trainIO.msgReqStatus.fire) { nextState := State.IDLE diff --git a/src/test/scala/logphy/MBInitFSMTest.scala b/src/test/scala/logphy/MBInitFSMTest.scala index 1bd138b..abf018b 100644 --- a/src/test/scala/logphy/MBInitFSMTest.scala +++ b/src/test/scala/logphy/MBInitFSMTest.scala @@ -33,7 +33,7 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { if (req) SBM.MBINIT_PARAM_CONFIG_REQ else SBM.MBINIT_PARAM_CONFIG_RESP, src = "PHY", - remote = false, + remote = true, dst = "PHY", data = data, msgInfo = 0, @@ -63,14 +63,13 @@ class MBInitFSMTest extends AnyFlatSpec with ChiselScalatestTester { if (req) SBM.MBINIT_PARAM_CONFIG_REQ else SBM.MBINIT_PARAM_CONFIG_RESP, src = "PHY", - remote = false, + remote = true, dst = "PHY", data = data, msgInfo = 0, ).U, _.timeoutCycles -> (0.008 * sbClockFreq).toInt.U, - // _.reqType -> (if (req) MessageRequestType.MSG_REQ - // else MessageRequestType.MSG_RESP), + _.reqType -> MessageRequestType.EXCHANGE, ) msgReq } diff --git a/src/test/scala/logphy/MBTrainerTest.scala b/src/test/scala/logphy/MBTrainerTest.scala index cdf845e..e4b078b 100644 --- a/src/test/scala/logphy/MBTrainerTest.scala +++ b/src/test/scala/logphy/MBTrainerTest.scala @@ -4,8 +4,169 @@ package logphy import interfaces._ import chisel3._ import chisel3.util._ -import sideband.{SBM, SBMessage_factory} -class MBTrainFSMTest extends Module { - val io = IO(new Bundle {}) +import chisel3.experimental.BundleLiterals.AddBundleLiteralConstructor +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor +import chiseltest._ +import edu.berkeley.cs.ucie.digital.sideband.{SBM, SBMessage_factory} +import org.scalatest.flatspec.AnyFlatSpec +class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { + + val linkTrainingParams = LinkTrainingParams() + val afeParams = AfeParams() + val maxPatternCount = 1024 + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) + behavior of "mainband trainer test" + it should "correctly exchange SB out of reset message external trigger" in { + test(new MBTrainer(linkTrainingParams, afeParams, maxPatternCount)) { c => + initPorts(c) + val transmitPattern = TransmitPattern.LFSR + val sbClockFreq = + linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio + val timeoutCyclesDefault = (0.008 * sbClockFreq).toInt + val patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio * 4 + + /** Initial expected values */ + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + c.io.sbTrainIO.msgReqStatus.ready.expect(false.B) + c.io.complete.expect(false.B) + c.io.err.expect(false.B) + c.io.sbMsgWrapperReset.expect(false.B) + c.clock.step() + + /** Trigger externally */ + c.io.trainingOperationIO.triggerNew.poke(true.B) + c.io.trainingOperationIO.pattern.poke(transmitPattern) + c.io.trainingOperationIO.patternUICount.poke(patternUICount.U) + c.clock.step() + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + + /** Expect PTTest SB request */ + val maxErrors = 0 + val data = 0 | transmitPattern.litValue | (BigInt(patternUICount) << 43) + expectSBReq( + c, + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_REQ, + reqType = MessageRequestType.SEND, + timeoutCyclesDefault, + maxErrors, + data, + ) + + /** Complete PTTest SB request */ + sbMsgSuccess(c) + + /** Expect PTTest SB response */ + expectSBReq( + c, + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_RESP, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + + /** Complete PTTest SB response */ + sbMsgSuccess(c) + + /** Expect pattern generator request */ + c.io.sbTrainIO.msgReqStatus.ready.expect(false.B) + c.io.sbTrainIO.msgReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + c.io.patternGeneratorIO.transmitReq + .expectDequeue( + (chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits)).Lit( + _.pattern -> transmitPattern, + _.timeoutCycles -> timeoutCyclesDefault.U, + _.patternCountMax -> patternUICount.U, + _.patternDetectedCountMax -> patternUICount.U, + ), + ) + + /** Complete pattern generator request */ + val errorCount = Vec.Lit( + Seq.fill(afeParams.mbLanes)(1.U(maxPatternCountWidth.W)): _*, + ) + c.io.sbTrainIO.msgReqStatus.ready.expect(false.B) + c.io.sbTrainIO.msgReq.expectInvalid() + c.io.patternGeneratorIO.resp.enqueueNow( + (chiselTypeOf(c.io.patternGeneratorIO.resp.bits)).Lit( + _.status -> MessageRequestStatusType.SUCCESS, + _.errorCount -> errorCount, + ), + ) + + /** Expect Results Req req */ + expectSBReq( + c, + SBM.MBTRAIN_TX_INIT_D_TO_C_RESULTS_REQ, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + + /** Complete Results req */ + sbMsgSuccess(c) + + // TODO: finish + + } + } + + private def expectSBReq( + c: MBTrainer, + bitPat: BitPat, + reqType: MessageRequestType.Type, + timeoutCyclesDefault: Int, + msgInfo: Int, + data: BigInt, + ): Unit = { + c.io.sbTrainIO.msgReqStatus.ready.expect(false.B) + c.io.sbTrainIO.msgReq.expectDequeue( + (new MessageRequest).Lit( + _.msg -> (SBMessage_factory( + bitPat, + src = "PHY", + remote = true, + dst = "PHY", + data, + msgInfo = msgInfo, + )).U, + _.reqType -> reqType, + _.timeoutCycles -> timeoutCyclesDefault.U, + ), + ) + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + } + + private def sbMsgSuccess(c: MBTrainer): Unit = { + c.io.sbTrainIO.msgReqStatus.enqueueNow( + (new MessageRequestStatus).Lit( + _.data -> 0.U, + _.status -> MessageRequestStatusType.SUCCESS, + ), + ) + } + + it should "correctly exchange SB out of reset message sideband trigger" in { + test(new MBTrainer(linkTrainingParams, afeParams, maxPatternCount)) { c => + initPorts(c) + + } + } + + private def initPorts(c: MBTrainer): Unit = { + c.io.sbTrainIO.msgReq.initSink().setSinkClock(c.clock) + c.io.sbTrainIO.msgReqStatus.initSource().setSourceClock(c.clock) + c.io.patternGeneratorIO.transmitReq + .initSink() + .setSinkClock(c.clock) + c.io.patternGeneratorIO.resp + .initSource() + .setSourceClock(c.clock) + } } diff --git a/src/test/scala/logphy/SBMsgWrapperTest.scala b/src/test/scala/logphy/SBMsgWrapperTest.scala index d6a9121..faf8b77 100644 --- a/src/test/scala/logphy/SBMsgWrapperTest.scala +++ b/src/test/scala/logphy/SBMsgWrapperTest.scala @@ -4,10 +4,11 @@ package logphy import chisel3._ import chisel3.experimental.BundleLiterals._ import chiseltest._ -import edu.berkeley.cs.ucie.digital.sideband.SidebandParams import org.scalatest.flatspec.AnyFlatSpec import sideband._ +import scala.util.Random + class SBMsgWrapperTest extends AnyFlatSpec with ChiselScalatestTester { val sbParams = SidebandParams() behavior of "sb message wrapper" @@ -34,12 +35,56 @@ class SBMsgWrapperTest extends AnyFlatSpec with ChiselScalatestTester { it should "correctly receive only" in { test(new SBMsgWrapper(sbParams)) { c => - /** TODO */ - assert(false) + initPorts(c) + testSBInitReceiveOnly(c) + testSBInitReceiveOnly(c) } } + private def testSBInitReceiveOnly(c: SBMsgWrapper): Unit = { + c.io.laneIO.rxData.ready.expect(false) + c.io.laneIO.txData.expectInvalid() + c.io.trainIO.msgReq.ready.expect(true) + c.io.trainIO.msgReqStatus.expectInvalid() + c.clock.step() + val rand = new Random() + val data = BigInt(64, rand) + val sbMsg = SBMessage_factory( + SBM.SBINIT_OUT_OF_RESET, + "PHY", + true, + "PHY", + data = data, + msgInfo = 0, + ) + c.io.trainIO.msgReq.enqueueNow( + (new MessageRequest).Lit( + _.msg -> sbMsg.U, + _.reqType -> MessageRequestType.RECEIVE, + _.timeoutCycles -> 80.U, + ), + ) + + c.io.trainIO.msgReq.ready.expect(false) + for (_ <- 0 until 4) { + c.clock.step() + c.io.laneIO.txData.expectInvalid() + } + c.io.laneIO.rxData.enqueueNow(sbMsg.U) + for (_ <- 0 until 4) { + c.clock.step() + c.io.trainIO.msgReqStatus.valid.expect(true.B) + c.io.laneIO.txData.expectInvalid() + } + c.io.trainIO.msgReqStatus.expectDequeue( + (new MessageRequestStatus).Lit( + _.status -> + MessageRequestStatusType.SUCCESS, + _.data -> data.U, + ), + ) + } private def testSBInitOutOfReset(c: SBMsgWrapper): Unit = { c.io.laneIO.rxData.ready.expect(false) c.io.laneIO.txData.expectInvalid() diff --git a/src/test/scala/logphy/ScramblerTest.scala b/src/test/scala/logphy/ScramblerTest.scala index e22ae53..9eb37b3 100644 --- a/src/test/scala/logphy/ScramblerTest.scala +++ b/src/test/scala/logphy/ScramblerTest.scala @@ -26,34 +26,34 @@ class ScramblerTest extends AnyFunSpec with ChiselScalatestTester { } } - it("4 lane scrambler test") { - test(new UCIeScrambler(afeParams = AfeParams(), numLanes = 4)) { c => - c.reset.poke(true.B) - c.clock.step() - c.clock.step() - c.reset.poke(false.B) - c.clock.step() - c.io.valid.poke(true.B) + // it("4 lane scrambler test") { + // test(new UCIeScrambler(afeParams = AfeParams(), numLanes = 4)) { c => + // c.reset.poke(true.B) + // c.clock.step() + // c.clock.step() + // c.reset.poke(false.B) + // c.clock.step() + // c.io.valid.poke(true.B) - c.io.data_in(0).poke(1.U(16.W)) - c.io.data_in(1).poke(1012.U(16.W)) - c.io.data_in(2).poke(823.U(16.W)) - c.io.data_in(3).poke(134.U(16.W)) + // c.io.data_in(0).poke(1.U(16.W)) + // c.io.data_in(1).poke(1012.U(16.W)) + // c.io.data_in(2).poke(823.U(16.W)) + // c.io.data_in(3).poke(134.U(16.W)) - c.io.data_out(0).expect(49085.U(16.W)) - c.io.data_out(1).expect(1103.U(16.W)) - c.io.data_out(2).expect(50263.U(16.W)) - c.io.data_out(3).expect(49245.U(16.W)) - c.clock.step() - c.io.data_in(0).poke(203.U(16.W)) - c.io.data_in(1).poke(176.U(16.W)) - c.io.data_in(2).poke(21.U(16.W)) - c.io.data_in(3).poke(5847.U(16.W)) - c.io.data_out(0).expect(65321.U(16.W)) - c.io.data_out(1).expect(56489.U(16.W)) - c.io.data_out(2).expect(11245.U(16.W)) - c.io.data_out(3).expect(57654.U(16.W)) - } - } + // c.io.data_out(0).expect(49085.U(16.W)) + // c.io.data_out(1).expect(1103.U(16.W)) + // c.io.data_out(2).expect(50263.U(16.W)) + // c.io.data_out(3).expect(49245.U(16.W)) + // c.clock.step() + // c.io.data_in(0).poke(203.U(16.W)) + // c.io.data_in(1).poke(176.U(16.W)) + // c.io.data_in(2).poke(21.U(16.W)) + // c.io.data_in(3).poke(5847.U(16.W)) + // c.io.data_out(0).expect(65321.U(16.W)) + // c.io.data_out(1).expect(56489.U(16.W)) + // c.io.data_out(2).expect(11245.U(16.W)) + // c.io.data_out(3).expect(57654.U(16.W)) + // } + // } } } From f39e2ad929a71ffddc533430da10a93fecd7addc Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Thu, 1 Aug 2024 21:45:12 -0700 Subject: [PATCH 07/12] make STANDALONE work --- src/main/scala/logphy/LinkTrainingFSM.scala | 7 +- src/main/scala/logphy/LogicalPhy.scala | 4 +- .../scala/logphy/LinkTrainingFSMTest.scala | 9 +- src/test/scala/logphy/MBTrainerTest.scala | 140 +++++++++++++----- 4 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index b9bf7c7..f231ea1 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -61,9 +61,7 @@ class LinkTrainingFSM( val rdiBringupIO = new RdiBringupIO } val trainingOperationIO = - Input( - new TrainingOperation(afeParams, linkTrainingParams.maxPatternCount), - ) + new TrainingOperation(afeParams, linkTrainingParams.maxPatternCount) val currentState = Output(LinkTrainingState()) }) @@ -363,7 +361,8 @@ class LinkTrainingFSM( nextState := Mux( mbInit.io.error, LinkTrainingState.linkError, - LinkTrainingState.mbTrain, + if (afeParams.STANDALONE) { LinkTrainingState.linkInit } + else { LinkTrainingState.mbTrain }, ) } } diff --git a/src/main/scala/logphy/LogicalPhy.scala b/src/main/scala/logphy/LogicalPhy.scala index 109fc7d..c6912e0 100644 --- a/src/main/scala/logphy/LogicalPhy.scala +++ b/src/main/scala/logphy/LogicalPhy.scala @@ -31,6 +31,9 @@ class LogicalPhy( ) } + /** TODO: replace this with MMIO module instantiations */ + trainingModule.io.trainingOperationIO := DontCare + if (afeParams.STANDALONE) { trainingModule.io.mainbandFSMIO.pllLock <> io.mbAfe.get.pllLock } else { trainingModule.io.mainbandFSMIO.pllLock := 0.U } @@ -82,7 +85,6 @@ class LogicalPhy( lanes.io.scramble := true.B /** Connect internal FIFO to AFE */ - if (afeParams.STANDALONE) { lanes.io.mainbandLaneIO.txData <> io.mbAfe.get.txData lanes.io.mainbandLaneIO.rxData <> io.mbAfe.get.rxData diff --git a/src/test/scala/logphy/LinkTrainingFSMTest.scala b/src/test/scala/logphy/LinkTrainingFSMTest.scala index f64f424..1c10761 100644 --- a/src/test/scala/logphy/LinkTrainingFSMTest.scala +++ b/src/test/scala/logphy/LinkTrainingFSMTest.scala @@ -29,7 +29,7 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { println("Successfully initialized sideband") initMB(c) println("Successfully initialized mainband") - trainMB(c) + // trainMB(c) println("Successfully trained mainband") c.io.currentState.expect(LinkTrainingState.linkInit) @@ -109,10 +109,9 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { c.clock.step(3) } - private def trainMB(c: LinkTrainingFSM): Unit = { - c.io.currentState.expect(LinkTrainingState.mbTrain) - - } + // private def trainMB(c: LinkTrainingFSM): Unit = { + // c.io.currentState.expect(LinkTrainingState.mbTrain) + // } private def testTransitionOutOfReset(c: LinkTrainingFSM): Unit = { c.io.currentState.expect(LinkTrainingState.reset) diff --git a/src/test/scala/logphy/MBTrainerTest.scala b/src/test/scala/logphy/MBTrainerTest.scala index caa52de..33850c7 100644 --- a/src/test/scala/logphy/MBTrainerTest.scala +++ b/src/test/scala/logphy/MBTrainerTest.scala @@ -25,11 +25,17 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio val timeoutCyclesDefault = (0.008 * sbClockFreq).toInt var patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio * 4 + val maxErrors = 0 initialExpectedValues(c) - triggerOperation(c, transmitPattern, patternUICount) + triggerOperation( + c, + transmitPattern, + patternUICount, + timeoutCyclesDefault, + maxErrors, + ) - val maxErrors = 0 var errorCount = Vec.Lit( Seq.fill(afeParams.mbLanes)(1.U(maxPatternCountWidth.W)): _*, ) @@ -38,7 +44,6 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { transmitPattern, timeoutCyclesDefault, patternUICount, - maxErrors, errorCount, ) @@ -48,17 +53,23 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { Seq.tabulate(afeParams.mbLanes)(x => x.U(maxPatternCountWidth.W)): _*, ) - triggerOperation(c, transmitPattern, patternUICount) + triggerOperation( + c, + transmitPattern, + patternUICount, + timeoutCyclesDefault, + maxErrors, + ) completeTrainingOperation( c, transmitPattern, timeoutCyclesDefault, patternUICount, - maxErrors, errorCount, ) + triggerExit(c, timeoutCyclesDefault) exitTraining(c, timeoutCyclesDefault) } @@ -71,20 +82,28 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio val timeoutCyclesDefault = (0.008 * sbClockFreq).toInt var patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio * 4 + val maxErrors = 0 initialExpectedValues(c) - triggerOperation(c, transmitPattern, patternUICount) - val maxErrors = 0 + /** Trigger operation via sideband */ + triggerOperationSB( + c, + timeoutCyclesDefault, + transmitPattern, + patternUICount, + maxErrors, + ) + var errorCount = Vec.Lit( Seq.fill(afeParams.mbLanes)(1.U(maxPatternCountWidth.W)): _*, ) + completeTrainingOperation( c, transmitPattern, timeoutCyclesDefault, patternUICount, - maxErrors, errorCount, ) @@ -94,22 +113,65 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { Seq.tabulate(afeParams.mbLanes)(x => x.U(maxPatternCountWidth.W)): _*, ) - triggerOperation(c, transmitPattern, patternUICount) + /** NOTE: cannot re-trigger operation with sideband as sideband is not + * expecting a begin training request + */ + triggerOperation( + c, + transmitPattern, + patternUICount, + timeoutCyclesDefault, + maxErrors, + ) completeTrainingOperation( c, transmitPattern, timeoutCyclesDefault, patternUICount, - maxErrors, errorCount, ) + /** Trigger exit via sideband */ + triggerExitSB(c, timeoutCyclesDefault) + exitTraining(c, timeoutCyclesDefault) } } + private def triggerExitSB(c: MBTrainer, timeoutCyclesDefault: Int): Unit = { + + expectSBReq( + c = c, + bitPat = SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ, + MessageRequestType.RECEIVE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + sbMsgSuccess(c) + } + + private def triggerOperationSB( + c: MBTrainer, + timeoutCyclesDefault: Int, + transmitPattern: TransmitPattern.Type, + patternUICount: Int, + maxErrors: Int, + ): Unit = { + val data = 0 | transmitPattern.litValue | (BigInt(patternUICount) << 43) + expectSBReq( + c, + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_REQ, + MessageRequestType.RECEIVE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + sbMsgSuccess(c, data) + } + private def initialExpectedValues(c: MBTrainer): Unit = { c.io.patternGeneratorIO.transmitReq.expectInvalid() c.io.patternGeneratorIO.resp.ready.expect(false.B) @@ -123,21 +185,6 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { private def exitTraining(c: MBTrainer, timeoutCyclesDefault: Int): Unit = { - /** Trigger exit */ - triggerExit(c) - - /** Expect Pt Test End Test Req */ - expectSBReq( - c = c, - bitPat = SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ, - reqType = MessageRequestType.SEND, - timeoutCyclesDefault = timeoutCyclesDefault, - msgInfo = 0, - data = 0, - ) - - sbMsgSuccess(c) - expectSBReq( c = c, bitPat = SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_RESP, @@ -154,16 +201,30 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { c.io.err.expect(false.B) } - private def triggerExit(c: MBTrainer): Unit = { + private def triggerExit(c: MBTrainer, timeoutCyclesDefault: Int): Unit = { c.io.trainingOperationIO.triggerExit.poke(true.B) c.clock.step() c.io.trainingOperationIO.triggerExit.poke(false.B) + + /** Expect Pt Test End Test Req */ + expectSBReq( + c = c, + bitPat = SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ, + reqType = MessageRequestType.SEND, + timeoutCyclesDefault = timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + + sbMsgSuccess(c) } private def triggerOperation( c: MBTrainer, transmitPattern: TransmitPattern.Type, patternUICount: Int, + timeoutCyclesDefault: Int, + maxErrors: Int, ): Unit = { c.io.trainingOperationIO.triggerNew.poke(true.B) c.io.trainingOperationIO.pattern.poke(transmitPattern) @@ -174,18 +235,6 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { c.io.patternGeneratorIO.transmitReq.expectInvalid() c.io.patternGeneratorIO.resp.ready.expect(false.B) println("External trigger") - } - - private def completeTrainingOperation( - c: MBTrainer, - transmitPattern: TransmitPattern.Type, - timeoutCyclesDefault: Int, - patternUICount: Int, - maxErrors: Int, - errorCount: Vec[UInt], - ): Unit = { - - println("********** BEGIN TRAINING OPERATION ***********") val data = 0 | transmitPattern.litValue | (BigInt(patternUICount) << 43) expectSBReq( @@ -200,6 +249,17 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { /** Complete PTTest SB request */ sbMsgSuccess(c) + } + + private def completeTrainingOperation( + c: MBTrainer, + transmitPattern: TransmitPattern.Type, + timeoutCyclesDefault: Int, + patternUICount: Int, + errorCount: Vec[UInt], + ): Unit = { + + println("********** BEGIN TRAINING OPERATION ***********") /** Expect PTTest SB response */ expectSBReq( @@ -313,10 +373,10 @@ class MBTrainerTest extends AnyFlatSpec with ChiselScalatestTester { c.io.patternGeneratorIO.resp.ready.expect(false.B) } - private def sbMsgSuccess(c: MBTrainer): Unit = { + private def sbMsgSuccess(c: MBTrainer, data: BigInt = 0): Unit = { c.io.sbTrainIO.msgReqStatus.enqueueNow( (new MessageRequestStatus).Lit( - _.data -> 0.U, + _.data -> data.U, _.status -> MessageRequestStatusType.SUCCESS, ), ) From 888319449a9c95b3fe07c04f578447f9e26c70f5 Mon Sep 17 00:00:00 2001 From: Vikram Jain Date: Fri, 2 Aug 2024 15:03:09 -0700 Subject: [PATCH 08/12] buffers to fix timing --- src/main/scala/tilelink/Configs.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/tilelink/Configs.scala b/src/main/scala/tilelink/Configs.scala index d2f89bd..7e09818 100644 --- a/src/main/scala/tilelink/Configs.scala +++ b/src/main/scala/tilelink/Configs.scala @@ -47,10 +47,10 @@ trait CanHaveTLUCIAdapter { this: BaseSubsystem => )) uciTL.clockNode := sbus.fixedClockNode obus.coupleTo(s"ucie_tl_man_port") { - uciTL.managerNode := TLWidthWidget(obus.beatBytes) := TLBuffer() := TLSourceShrinker(params.tlParams.sourceIDWidth) := TLFragmenter(obus.beatBytes, p(CacheBlockBytes)) := _ + uciTL.managerNode := TLWidthWidget(obus.beatBytes) := TLBuffer() := TLSourceShrinker(params.tlParams.sourceIDWidth) := TLFragmenter(obus.beatBytes, p(CacheBlockBytes)) := TLBuffer() := _ } //manager node because SBUS is making request? - sbus.coupleFrom(s"ucie_tl_cl_port") { _ := TLWidthWidget(sbus.beatBytes) := TLBuffer() := uciTL.clientNode } - sbus.coupleTo(s"ucie_tl_ctrl_port") { uciTL.regNode.node := TLWidthWidget(sbus.beatBytes) := TLFragmenter(sbus.beatBytes, sbus.blockBytes) := _ } + sbus.coupleFrom(s"ucie_tl_cl_port") { _ := TLBuffer() := TLWidthWidget(sbus.beatBytes) := TLBuffer() := uciTL.clientNode } + sbus.coupleTo(s"ucie_tl_ctrl_port") { uciTL.regNode.node := TLWidthWidget(sbus.beatBytes) := TLFragmenter(sbus.beatBytes, sbus.blockBytes) := TLBuffer() := _ } Some(uciTL) } case None => None From 50f45bae0415dc7d4868e6e35ecec1117bb65375 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 7 Aug 2024 00:28:22 -0700 Subject: [PATCH 09/12] try same clock length --- src/main/scala/logphy/LinkTrainingFSM.scala | 3 ++- src/test/scala/sideband/sidebandLinkNodeSerDesTest.scala | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index f231ea1..23ae714 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -249,8 +249,9 @@ class LinkTrainingFSM( patternGenerator.io.patternGeneratorIO.transmitReq.bits.timeoutCycles := ( 0.008 * sbClockFreq, ).toInt.U + /** TODO: can't make these different lengths for some reason */ patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternCountMax := (128 + 64 * 4).U - patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax := (128).U + patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax := (128 + 64 * 4).U patternGenerator.io.patternGeneratorIO.transmitReq.valid := true.B msgSource := MsgSource.PATTERN_GENERATOR diff --git a/src/test/scala/sideband/sidebandLinkNodeSerDesTest.scala b/src/test/scala/sideband/sidebandLinkNodeSerDesTest.scala index 3708e5e..c703132 100644 --- a/src/test/scala/sideband/sidebandLinkNodeSerDesTest.scala +++ b/src/test/scala/sideband/sidebandLinkNodeSerDesTest.scala @@ -90,6 +90,7 @@ class LinkSerDesTest extends AnyFlatSpec with ChiselScalatestTester { // Check serialized data c.io.in.valid.poke(false.B) + c.clock.step() for (i <- 0 until (c.msg_w / c.sb_w)) { val serialized_data = data((i + 1) * c.sb_w - 1, i * c.sb_w) c.io.in.ready.expect(false.B) @@ -99,6 +100,7 @@ class LinkSerDesTest extends AnyFlatSpec with ChiselScalatestTester { // make sure it does not take anything for 32 cycles for (i <- 0 until 32) { + println(i) c.io.in.ready.expect(false.B) c.clock.step() } From ba9eb5ae4d9e893a060dba72d143ea879184ab98 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 7 Aug 2024 15:55:08 -0700 Subject: [PATCH 10/12] restore rxMode/txMode changes from newer logphy --- src/main/scala/logphy/LinkTrainingFSM.scala | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/scala/logphy/LinkTrainingFSM.scala b/src/main/scala/logphy/LinkTrainingFSM.scala index 23ae714..57b8a4c 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -78,14 +78,23 @@ class LinkTrainingFSM( sbMsgWrapper.io.trainIO.msgReq.noenq() sbMsgWrapper.io.trainIO.msgReqStatus.nodeq() - io.sidebandFSMIO.patternTxData <> patternGenerator.io.sidebandLaneIO.txData - io.sidebandFSMIO.packetTxData <> sbMsgWrapper.io.laneIO.txData when(msgSource === MsgSource.PATTERN_GENERATOR) { io.sidebandFSMIO.rxData <> patternGenerator.io.sidebandLaneIO.rxData sbMsgWrapper.io.laneIO.rxData.noenq() + sbMsgWrapper.io.laneIO.txData.nodeq() + io.sidebandFSMIO.patternTxData <> patternGenerator.io.sidebandLaneIO.txData + io.sidebandFSMIO.packetTxData.noenq() }.otherwise { io.sidebandFSMIO.rxData <> sbMsgWrapper.io.laneIO.rxData patternGenerator.io.sidebandLaneIO.rxData.noenq() + patternGenerator.io.sidebandLaneIO.txData.nodeq() + when(io.sidebandFSMIO.rxMode === RXTXMode.RAW) { + io.sidebandFSMIO.patternTxData <> sbMsgWrapper.io.laneIO.txData + io.sidebandFSMIO.packetTxData.noenq() + }.otherwise { + io.sidebandFSMIO.patternTxData.noenq() + io.sidebandFSMIO.packetTxData <> sbMsgWrapper.io.laneIO.txData + } } private val currentState = RegInit(LinkTrainingState.reset) @@ -249,6 +258,7 @@ class LinkTrainingFSM( patternGenerator.io.patternGeneratorIO.transmitReq.bits.timeoutCycles := ( 0.008 * sbClockFreq, ).toInt.U + /** TODO: can't make these different lengths for some reason */ patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternCountMax := (128 + 64 * 4).U patternGenerator.io.patternGeneratorIO.transmitReq.bits.patternDetectedCountMax := (128 + 64 * 4).U From e13195067a9628ff2e76938a98ee027d08235a50 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 7 Aug 2024 16:02:44 -0700 Subject: [PATCH 11/12] remove print statement --- src/main/scala/logphy/MBInitFSM.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/logphy/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index aadc4ee..b79c1b1 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -141,7 +141,6 @@ class MBInitFSM( } } is(ParamSubState.WAIT_REQ) { - printf("in MB init wait req\n") io.sbTrainIO.msgReqStatus.ready := true.B when(io.sbTrainIO.msgReqStatus.fire) { reqData := io.sbTrainIO.msgReqStatus.bits.data From 88cf816c331d53b5c451a8d13ca642110da2bec8 Mon Sep 17 00:00:00 2001 From: Viansa Schmulbach Date: Wed, 7 Aug 2024 16:14:30 -0700 Subject: [PATCH 12/12] fix syntax issue --- src/main/scala/tilelink/Configs.scala | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/scala/tilelink/Configs.scala b/src/main/scala/tilelink/Configs.scala index affd0c7..e8d9a8c 100644 --- a/src/main/scala/tilelink/Configs.scala +++ b/src/main/scala/tilelink/Configs.scala @@ -54,14 +54,6 @@ trait CanHaveTLUCIAdapter { this: BaseSubsystem => sbus.coupleFrom(s"ucie_tl_cl_port") { _ := TLBuffer() := TLWidthWidget(sbus.beatBytes) := TLBuffer() := uciTL.clientNode } sbus.coupleTo(s"ucie_tl_ctrl_port") { uciTL.regNode.node := TLWidthWidget(sbus.beatBytes) := TLFragmenter(sbus.beatBytes, sbus.blockBytes) := TLBuffer() := _ } Some(uciTL) - } - sbus.coupleTo(s"ucie_tl_ctrl_port") { - uciTL.regNode.node := TLWidthWidget(sbus.beatBytes) := TLFragmenter( - sbus.beatBytes, - sbus.blockBytes, - ) := _ - } - Some(uciTL) } case None => None }