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 new file mode 100644 index 0000000..508f893 --- /dev/null +++ b/src/main/scala/logphy/ErrorCounter.scala @@ -0,0 +1,81 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import interfaces.AfeParams + +/** TODO: need to do per-lane, not just aggregate */ +class ErrorCounter(afeParams: AfeParams) extends Module { + + val io = IO(new Bundle { + val req = Flipped(Valid(new Bundle { + val pattern = TransmitPattern() + val input = Input( + Vec(afeParams.mbLanes, UInt(afeParams.mbSerializerRatio.W)), + ) + })) + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(log2Ceil(afeParams.mbSerializerRatio + 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( + VecInit( + Seq.fill(afeParams.mbLanes)(0.U(afeParams.mbSerializerRatio.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) { + expected := lfsr.io.data_out + } + 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.asTypeOf(expected) + } + is(TransmitPattern.VALTRAIN) { + val valtrain = VecInit( + Seq.fill(afeParams.mbLanes * afeParams.mbSerializerRatio / 8)( + "b1111_0000".U(8.W), + ), + ) + expected := valtrain.asTypeOf(expected) + } + } + + /** count errors */ + 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 c8ccd09..f7db1fa 100644 --- a/src/main/scala/logphy/Lanes.scala +++ b/src/main/scala/logphy/Lanes.scala @@ -5,14 +5,60 @@ import interfaces._ import chisel3._ 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 mainbandIo = new MainbandIO(afeParams) + val scramble = Input(Bool()) val mainbandLaneIO = new MainbandLaneIO(afeParams) + val mainbandIO = new MainbandIO(afeParams) }) val txMBFifo = @@ -29,45 +75,69 @@ class Lanes( queueParams, ), ) + val rxScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) - rxMBFifo.io.enq <> io.mainbandIo.rxData + val txScrambler = + Module( + new UCIeScrambler(afeParams = afeParams, numLanes = afeParams.mbLanes), + ) + + 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 - 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 txDataVec = Wire( - Vec(afeParams.mbLanes, Vec(afeParams.mbSerializerRatio / 8, UInt(8.W))), - ) + val ratioBytes = afeParams.mbSerializerRatio / 8 - val rxDataVec = Wire( - Vec(ratioBytes, Vec(afeParams.mbLanes, UInt(8.W))), + + 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) + + /** Data Scrambling / De-scrambling */ + + rxScrambler.io.data_in := rxMBFifo.io.deq.bits + rxScrambler.io.valid := rxMBFifo.io.deq.fire + descrambledRx := rxScrambler.io.data_out + txScrambler.io.data_in := OneToLanes( + io.mainbandIO.txData.bits, + afeParams.mbLanes, + afeParams.mbSerializerRatio, + ) + txScrambler.io.valid := io.mainbandIO.txData.fire + scrambledTx := txScrambler.io.data_out + + /** Queue data into FIFOs */ + + 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.mainbandIO.rxData.valid := rxMBFifo.io.deq.valid + io.mainbandIO.rxData.bits := LanesToOne( + rxDataInput, + afeParams.mbLanes, + afeParams.mbSerializerRatio, ) - for (i <- 0 until afeParams.mbLanes) { - for (j <- 0 until ratioBytes) { - txDataVec(i)(ratioBytes - 1 - j) := io.mainbandLaneIO.txData - .bits( - afeParams.mbLanes * 8 * j + (i * 8) + 7, - afeParams.mbLanes * 8 * j + (i * 8), - ) - rxDataVec(ratioBytes - 1 - j)(i) := rxMBFifo.io.deq - .bits(i)((j + 1) * 8 - 1, j * 8) - } - txMBFifo.io.enq.bits(i) := txDataVec(i).asUInt - } - 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 +155,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 mainbandLaneIO = new MainbandIO(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 +193,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(i)(ratioBytes - 1 - j) := io.mainbandLaneIO.txData - .bits( - afeParams.mbLanes * 8 * j + (i * 8) + 7, - afeParams.mbLanes * 8 * j + (i * 8), - ) - rxDataVec(ratioBytes - 1 - j)(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 09f6d7d..57b8a4c 100644 --- a/src/main/scala/logphy/LinkTrainingFSM.scala +++ b/src/main/scala/logphy/LinkTrainingFSM.scala @@ -7,9 +7,8 @@ import chisel3._ import chisel3.util._ /** Implementation TODOs: - * - investigate multiple message source issue * - implement plStallReq - * - implement lpStateReq + * - retrain state */ case class LinkTrainingParams( @@ -18,6 +17,7 @@ case class LinkTrainingParams( maxSBMessageSize: Int = 128, mbTrainingParams: MBTrainingParams = MBTrainingParams(), sbClockFreqAnalog: Int = 800_000_000, + maxPatternCount: Int = 1 << 32, ) class SidebandFSMIO( @@ -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,22 +55,26 @@ 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 } + val trainingOperationIO = + new TrainingOperation(afeParams, linkTrainingParams.maxPatternCount) 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) - // io.mainbandLaneIO <> patternGenerator.io.mainbandLaneIO + io.mainbandFSMIO.mainbandIO <> patternGenerator.io.mainbandIO 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() @@ -119,17 +125,37 @@ class LinkTrainingFSM( new MBInitFSM( linkTrainingParams, afeParams, + maxPatternCount = linkTrainingParams.maxPatternCount, ), ) mbInit.reset := ((nextState === LinkTrainingState.mbInit) && (currentState =/= LinkTrainingState.mbInit)) || reset.asBool + /** initialize MBInit IOs */ + mbInit.io.sbTrainIO.msgReq.nodeq() + mbInit.io.sbTrainIO.msgReqStatus.noenq() + mbInit.io.patternGeneratorIO.transmitReq.nodeq() + mbInit.io.patternGeneratorIO.resp.noenq() + + private val mbTrainer = Module( + new MBTrainer( + linkTrainingParams = linkTrainingParams, + afeParams = afeParams, + maxPatternCount = linkTrainingParams.maxPatternCount, + ), + ) + mbTrainer.reset := ((nextState === LinkTrainingState.mbTrain) && (currentState =/= LinkTrainingState.mbTrain)) || reset.asBool + mbTrainer.io.sbTrainIO.msgReq.nodeq() + mbTrainer.io.sbTrainIO.msgReqStatus.noenq() + mbTrainer.io.patternGeneratorIO.transmitReq.nodeq() + mbTrainer.io.patternGeneratorIO.resp.noenq() + mbTrainer.io.trainingOperationIO <> io.trainingOperationIO + private val rdiBringup = Module(new RdiBringup) rdiBringup.io.rdiIO <> io.rdi.rdiBringupIO rdiBringup.io.sbTrainIO.msgReq.nodeq() 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), @@ -147,12 +173,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 || @@ -164,12 +184,6 @@ class LinkTrainingFSM( ) io.sidebandFSMIO.txMode := io.sidebandFSMIO.rxMode - /** initialize MBInit IOs */ - mbInit.io.sbTrainIO.msgReq.nodeq() - mbInit.io.sbTrainIO.msgReqStatus.noenq() - mbInit.io.patternGeneratorIO.transmitReq.nodeq() - mbInit.io.patternGeneratorIO.transmitPatternStatus.noenq() - /** TODO: should these ever be false? */ io.sidebandFSMIO.rxEn := true.B io.mainbandFSMIO.rxEn := (currentState =/= LinkTrainingState.reset) @@ -238,14 +252,17 @@ class LinkTrainingFSM( switch(sbInitSubState) { is(SBInitSubState.SEND_CLOCK) { - patternGenerator.io.patternGeneratorIO.transmitReq.bits.pattern := TransmitPattern.CLOCK_64_LOW_32 - patternGenerator.io.patternGeneratorIO.transmitReq.bits.sideband := true.B + patternGenerator.io.patternGeneratorIO.transmitReq.bits.pattern := TransmitPattern.CLOCK /** Timeout occurs after 8ms */ 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 + patternGenerator.io.patternGeneratorIO.transmitReq.valid := true.B msgSource := MsgSource.PATTERN_GENERATOR when(patternGenerator.io.patternGeneratorIO.transmitReq.fire) { @@ -253,13 +270,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 @@ -271,22 +288,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.repeat := true.B - /* 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, true, 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 } @@ -306,18 +312,12 @@ 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, + false, + (0.008 * sbClockFreq).toInt, ) - sbMsgWrapper.io.trainIO.msgReq.bits.repeat := 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 } @@ -337,19 +337,12 @@ 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, + false, + (0.008 * sbClockFreq).toInt, ) - sbMsgWrapper.io.trainIO.msgReq.bits.repeat := false.B - 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 } @@ -372,17 +365,32 @@ 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 - when(mbInit.io.transition.asBool) { + when(mbInit.io.transition) { nextState := Mux( mbInit.io.error, LinkTrainingState.linkError, + if (afeParams.STANDALONE) { LinkTrainingState.linkInit } + else { LinkTrainingState.mbTrain }, + ) + } + } + is(LinkTrainingState.mbTrain) { + + mbTrainer.io.sbTrainIO <> sbMsgWrapper.io.trainIO + sbMsgWrapper.reset := mbTrainer.io.sbMsgWrapperReset + mbTrainer.io.patternGeneratorIO <> patternGenerator.io.patternGeneratorIO + msgSource := MsgSource.SB_MSG_WRAPPER + when(mbTrainer.io.complete) { + nextState := Mux( + mbTrainer.io.err, + LinkTrainingState.linkError, LinkTrainingState.linkInit, ) } + } is(LinkTrainingState.linkInit) { rdiBringup.io.sbTrainIO <> sbMsgWrapper.io.trainIO @@ -404,4 +412,22 @@ class LinkTrainingFSM( } } + private def sendSidebandReq( + bitPat: BitPat, + reqType: MessageRequestType.Type, + repeat: Boolean, + 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 + sbMsgWrapper.io.trainIO.msgReq.bits.repeat := repeat.B + msgSource := MsgSource.SB_MSG_WRAPPER + } } diff --git a/src/main/scala/logphy/LogPhyTypes.scala b/src/main/scala/logphy/LogPhyTypes.scala index 3ac9e3b..3403392 100644 --- a/src/main/scala/logphy/LogPhyTypes.scala +++ b/src/main/scala/logphy/LogPhyTypes.scala @@ -7,7 +7,8 @@ import sideband.SidebandParams import interfaces._ object LinkTrainingState extends ChiselEnum { - val reset, sbInit, mbInit, linkInit, active, linkError, retrain = Value + val reset, sbInit, mbInit, mbTrain, linkInit, active, linkError, retrain = + Value } object MsgSource extends ChiselEnum { @@ -28,9 +29,14 @@ class SBReqMsg extends Bundle { val msg = UInt(128.W) } +object MessageRequestType extends ChiselEnum { + val EXCHANGE, RECEIVE, SEND = Value +} + class MessageRequest extends Bundle { val msg = UInt(128.W) val timeoutCycles = UInt(64.W) + val reqType = MessageRequestType() val repeat = Bool() } @@ -47,7 +53,10 @@ object ClockModeParam extends ChiselEnum { } object TransmitPattern extends ChiselEnum { - val CLOCK_64_LOW_32 = Value(0.U) + 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 { @@ -68,7 +77,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 +104,7 @@ class MainbandIO( ) } -class MainbandLaneIO( +class MainbandIO( afeParams: AfeParams, ) extends Bundle { @@ -106,7 +115,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/LogicalPhy.scala b/src/main/scala/logphy/LogicalPhy.scala index 075760e..c6912e0 100644 --- a/src/main/scala/logphy/LogicalPhy.scala +++ b/src/main/scala/logphy/LogicalPhy.scala @@ -17,8 +17,11 @@ class LogicalPhy( val io = IO(new Bundle { val rdi = Flipped(new Rdi(rdiParams)) - val mbAfe = if (afeParams.STANDALONE) Some(new MainbandAfeIo(afeParams)) else None - val phyAfe = if (afeParams.STANDALONE) None else Some(Flipped(new MainbandLaneIO(afeParams))) + val mbAfe = + if (afeParams.STANDALONE) Some(new MainbandAfeIo(afeParams)) else None + val phyAfe = + if (afeParams.STANDALONE) None + else Some(Flipped(new MainbandLaneIO(afeParams))) val sbAfe = new SidebandAfeIo(afeParams) }) @@ -28,9 +31,16 @@ class LogicalPhy( ) } - if (afeParams.STANDALONE) {trainingModule.io.mainbandFSMIO.pllLock <> io.mbAfe.get.pllLock } else {trainingModule.io.mainbandFSMIO.pllLock := 0.U} + /** 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 } trainingModule.io.sidebandFSMIO.pllLock <> io.sbAfe.pllLock - if (afeParams.STANDALONE) {trainingModule.io.mainbandFSMIO.rxEn <> io.mbAfe.get.rxEn } + if (afeParams.STANDALONE) { + trainingModule.io.mainbandFSMIO.rxEn <> io.mbAfe.get.rxEn + } trainingModule.io.sidebandFSMIO.rxEn <> io.sbAfe.rxEn trainingModule.io.rdi.rdiBringupIO.lpStateReq <> io.rdi.lpStateReq @@ -51,7 +61,9 @@ class LogicalPhy( io.rdi.plPhyInRecenter := io.rdi.plStateStatus === PhyState.retrain io.rdi.plSpeedMode <> trainingModule.io.mainbandFSMIO.txFreqSel - if (afeParams.STANDALONE) { io.mbAfe.get.txFreqSel <> trainingModule.io.mainbandFSMIO.txFreqSel } + if (afeParams.STANDALONE) { + io.mbAfe.get.txFreqSel <> trainingModule.io.mainbandFSMIO.txFreqSel + } io.rdi.plLinkWidth := PhyWidth.width16 io.rdi.plClkReq <> trainingModule.io.rdi.rdiBringupIO.plClkReq io.rdi.plWakeAck <> trainingModule.io.rdi.rdiBringupIO.plWakeAck @@ -69,22 +81,38 @@ 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 */ - if (afeParams.STANDALONE) { - lanes.io.mainbandIo.txData <> io.mbAfe.get.txData - lanes.io.mainbandIo.rxData <> io.mbAfe.get.rxData - lanes.io.mainbandIo.fifoParams <> io.mbAfe.get.fifoParams - rdiDataMapper.io.mainbandLaneIO <> lanes.io.mainbandLaneIO } - else { + if (afeParams.STANDALONE) { + lanes.io.mainbandLaneIO.txData <> io.mbAfe.get.txData + lanes.io.mainbandLaneIO.rxData <> io.mbAfe.get.rxData + lanes.io.mainbandLaneIO.fifoParams <> io.mbAfe.get.fifoParams + 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 + } + } else { rdiDataMapper.io.mainbandLaneIO <> io.phyAfe.get // defaults to zero - lanes.io.mainbandIo.fifoParams.clk := 0.U.asTypeOf(Clock()) - lanes.io.mainbandIo.fifoParams.reset := 0.U - lanes.io.mainbandIo.txData.ready := 0.U - lanes.io.mainbandIo.rxData.valid := 0.U - lanes.io.mainbandIo.rxData.bits := 0.U.asTypeOf(lanes.io.mainbandIo.rxData.bits) + /** TODO: not sure what is going on here */ + lanes.io.mainbandLaneIO.fifoParams.clk := 0.U.asTypeOf(Clock()) + lanes.io.mainbandLaneIO.fifoParams.reset := 0.U + lanes.io.mainbandLaneIO.txData.ready := 0.U + lanes.io.mainbandLaneIO.rxData.valid := 0.U + lanes.io.mainbandLaneIO.rxData.bits := 0.U.asTypeOf( + lanes.io.mainbandIO.rxData.bits, + ) lanes.io.mainbandLaneIO.txData.valid := 0.U - lanes.io.mainbandLaneIO.txData.bits := 0.U.asTypeOf(lanes.io.mainbandLaneIO.txData.bits) + lanes.io.mainbandLaneIO.txData.bits := 0.U.asTypeOf( + lanes.io.mainbandIO.txData.bits, + ) } /** Connect RDI to Mainband IO */ @@ -98,7 +126,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 @@ -113,9 +140,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/MBInitFSM.scala b/src/main/scala/logphy/MBInitFSM.scala index 8d28601..b79c1b1 100644 --- a/src/main/scala/logphy/MBInitFSM.scala +++ b/src/main/scala/logphy/MBInitFSM.scala @@ -18,11 +18,13 @@ 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(afeParams, maxPatternCount)) val transition = Output(Bool()) val error = Output(Bool()) }) @@ -54,7 +56,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( @@ -109,16 +111,14 @@ class MBInitFSM( if (req) SBM.MBINIT_PARAM_CONFIG_REQ else SBM.MBINIT_PARAM_CONFIG_RESP, "PHY", - false, + remote = true, "PHY", data, ) msgReq.repeat := false.B - // 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 } @@ -154,6 +154,7 @@ class MBInitFSM( } } is(ParamSubState.SEND_RESP) { + printf("in MB init send resp\n") io.sbTrainIO.msgReq.valid := true.B val exchangedMaxDataRate = Wire(UInt(4.W)) exchangedMaxDataRate := Mux( @@ -177,6 +178,7 @@ class MBInitFSM( } } is(ParamSubState.WAIT_RESP) { + printf("in MB init wait resp\n") io.sbTrainIO.msgReqStatus.ready := true.B when(io.sbTrainIO.msgReqStatus.fire) { when( diff --git a/src/main/scala/logphy/MBTrainer.scala b/src/main/scala/logphy/MBTrainer.scala new file mode 100644 index 0000000..c5d6ca3 --- /dev/null +++ b/src/main/scala/logphy/MBTrainer.scala @@ -0,0 +1,379 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import interfaces._ +import chisel3._ +import chisel3.util._ +import sideband.{SBM, SBMessage_factory} + +/** TODO: make timeout cycles optional */ +class TrainingOperation(afeParams: AfeParams, maxPatternCount: Int) + extends Bundle { + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) + val pattern = Input(TransmitPattern()) + val patternUICount = Input(UInt(maxPatternCountWidth.W)) + val triggerNew = Input(Bool()) + val triggerExit = Input(Bool()) + val outputValid = Output(Bool()) + val errorCounts = Output(Vec(afeParams.mbLanes, UInt(maxPatternCountWidth.W))) +} + +class MBTrainer( + linkTrainingParams: LinkTrainingParams, + afeParams: AfeParams, + maxPatternCount: Int, +) extends Module { + + val sbClockFreq = + linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio + + val io = IO(new Bundle { + val trainingOperationIO = new TrainingOperation(afeParams, 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.sbTrainIO.msgReq.bits.repeat := false.B + io.patternGeneratorIO.transmitReq.noenq() + io.patternGeneratorIO.resp.nodeq() + + private object State extends ChiselEnum { + val WAIT_PTTEST_REQ_SEND, WAIT_PTTEST_REQ, SEND_PTTEST_REQ, + 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) + + 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.triggerNew) { + currentState := State.SEND_PTTEST_REQ + io.sbMsgWrapperReset := true.B + + 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 = UInt(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) + } + + 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, + 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 = true, + dst = "PHY", + data, + msgInfo = maxErrors(15, 0), + ) + msgReq.timeoutCycles := (0.008 * sbClockFreq).toInt.U + msgReq.reqType := reqType + msgReq.repeat := false.B + 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.repeat := false.B + msgReq + } + + private val errorCount = Reg( + chiselTypeOf(io.patternGeneratorIO.resp.bits.errorCount), + ) + private val errorCountValid = RegInit(false.B) + io.trainingOperationIO.errorCounts := errorCount + io.trainingOperationIO.outputValid := errorCountValid + + 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 = Wire(new TxDtoCPointReq) + txDtoCPointReq := DontCare + io.sbTrainIO.msgReq.bits := formStartTxDtoCPointReq( + 0.U, + txDtoCPointReq, + MessageRequestType.RECEIVE, + ) + when(io.sbTrainIO.msgReq.fire) { + currentState := State.WAIT_PTTEST_REQ + } + } + 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 + .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.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_SEND) + } + 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 + errorCountValid := 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.SEND + 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 + } + } + +} diff --git a/src/main/scala/logphy/PatternGenerator.scala b/src/main/scala/logphy/PatternGenerator.scala index 858cac1..c42ad33 100644 --- a/src/main/scala/logphy/PatternGenerator.scala +++ b/src/main/scala/logphy/PatternGenerator.scala @@ -6,151 +6,112 @@ import chisel3.util._ import sideband.SidebandParams import interfaces._ -class PatternGeneratorIO 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(32.W) - val sideband = Bool() - })) // data to transmit & receive over SB - val transmitPatternStatus = Decoupled(MessageRequestStatusType()) + val patternCountMax = UInt(maxPatternCountWidth.W) + val patternDetectedCountMax = UInt(maxPatternCountWidth.W) + })) + val resp = Decoupled(new Bundle { + val status = MessageRequestStatusType() + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(maxPatternCountWidth.W)), + ) + }) + } 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(afeParams, maxPatternCount) - /** for now, assume want to transmit on sideband IO only */ - // val mainbandLaneIO = Flipped(new MainbandLaneIO(afeParams)) + val mainbandIO = Flipped(new MainbandIO(afeParams)) val sidebandLaneIO = Flipped(new SidebandLaneIO(sbParams)) }) - /** TODO: remove */ - // io.mainbandLaneIO.txData.noenq() + 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.map( + LanesToOne(_, afeParams.mbLanes, afeParams.mbSerializerRatio), + ) <> io.mainbandIO.txData + patternReader.io.sbRxData <> io.sidebandLaneIO.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 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 sideband = RegInit(true.B) + private val inputsValid = RegInit(false.B) + private val pattern = RegInit(TransmitPattern.CLOCK) 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 + patternReader.io.request.bits.pattern := pattern + patternReader.io.request.bits.patternCountMax := patternDetectedCountMax + patternWriter.io.request.valid := inputsValid + 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 := errorCount 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 + inputsValid := true.B 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) { + when(io.patternGeneratorIO.resp.fire) { statusValid := false.B } + /** handle timeouts and completion */ when(inProgress) { timeoutCycles := timeoutCycles - 1.U - when(timeoutCycles === 0.U) { - status := MessageRequestStatusType.ERR + 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 - writeInProgress := false.B - readInProgress := false.B - patternWrittenCount := 0.U - patternDetectedCount := 0.U - }.elsewhen( - (patternWrittenCount >= MuxLookup(pattern, 0.U)( - patternWrittenCountMax, - )) && (patternDetectedCount >= MuxLookup(pattern, 0.U)( - patternDetectedCountMax, - )), - ) { - statusValid := true.B - status := MessageRequestStatusType.SUCCESS - writeInProgress := false.B - readInProgress := false.B - patternWrittenCount := 0.U - patternDetectedCount := 0.U + patternWriter.reset := true.B + patternReader.reset := true.B + inputsValid := false.B + errorCount := patternReader.io.resp.errorCount } } - 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 - } - } - - } - } - - } - } diff --git a/src/main/scala/logphy/PatternReader.scala b/src/main/scala/logphy/PatternReader.scala new file mode 100644 index 0000000..1b4973f --- /dev/null +++ b/src/main/scala/logphy/PatternReader.scala @@ -0,0 +1,88 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import interfaces.AfeParams +import sideband.SidebandParams + +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 patternCountMax = UInt(maxPatternWidth.W) + })) + val resp = new Bundle { + val complete = Output(Bool()) + val inProgress = Output(Bool()) + val errorCount = Output( + Vec(afeParams.mbLanes, UInt(maxPatternWidth.W)), + ) + } + val sbRxData = Flipped(Decoupled(Bits(sbParams.sbNodeMsgWidth.W))) + val mbRxData = Flipped( + Decoupled(Vec(afeParams.mbLanes, UInt(afeParams.mbSerializerRatio.W))), + ) + }) + + private val readInProgress = RegInit(false.B) + private 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 + } + + /** increment error count */ + private val errorCount = RegInit( + VecInit(Seq.fill(afeParams.mbLanes)(0.U(maxPatternWidth.W))), + ) + io.resp.errorCount := errorCount + 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) { + 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(sideband) { + io.sbRxData.ready := true.B + when(io.sbRxData.fire) { + 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 + patternDetectedCount := patternDetectedCount + (afeParams.mbLanes * afeParams.mbSerializerRatio).U + } + } + } +} diff --git a/src/main/scala/logphy/PatternWriter.scala b/src/main/scala/logphy/PatternWriter.scala new file mode 100644 index 0000000..391a3d1 --- /dev/null +++ b/src/main/scala/logphy/PatternWriter.scala @@ -0,0 +1,127 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.util._ +import sideband.SidebandParams +import interfaces._ + +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 patternCountMax = UInt(maxPatternCountWidth.W) + })) + val resp = Output(new Bundle { + val complete = Bool() + val inProgress = Bool() + }) + val sbTxData = Decoupled(Bits(sbParams.sbNodeMsgWidth.W)) + val mbTxData = + Decoupled(Vec(afeParams.mbLanes, Bits(afeParams.mbSerializerRatio.W))) + }) + + private val writeInProgress = RegInit(false.B) + io.resp.inProgress := writeInProgress + when(io.request.valid && !writeInProgress) { + writeInProgress := true.B + } + + 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(!sideband) { + io.mbTxData.valid := writeInProgress + 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 := sbPatternToTransmit + 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 + */ + + sbPatternToTransmit := "haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U + } + is(TransmitPattern.LFSR) { + mbPatternToTransmit := lfsrPatternGenerator.io.data_out + 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), + ), + ) + mbPatternToTransmit := valtrain.asTypeOf(mbPatternToTransmit) + } + 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) + } + } + mbPatternToTransmit := patternVec.asTypeOf(mbPatternToTransmit) + } + + } + + } + +} diff --git a/src/main/scala/logphy/RdiBringup.scala b/src/main/scala/logphy/RdiBringup.scala index 3854389..a6f6a65 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/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 e18039a..6f9c6e6 100644 --- a/src/main/scala/logphy/SBMsgWrapper.scala +++ b/src/main/scala/logphy/SBMsgWrapper.scala @@ -11,6 +11,84 @@ class SBMsgWrapperTrainIO( val msgReqStatus = Decoupled(new MessageRequestStatus) } +class SBMsgWriter(sbParams: SidebandParams) extends Module { + val io = IO(new Bundle { + val req = Flipped(Valid(new Bundle { + val data = UInt(128.W) + val repeat = Bool() + })) + val result = Valid(MessageRequestStatusType()) + val txData = Decoupled(Bits(sbParams.sbNodeMsgWidth.W)) + }) + val canReceiveReq = RegInit(true.B) + val inProgress = RegInit(false.B) + val complete = RegInit(false.B) + when(io.req.fire && canReceiveReq) { + inProgress := true.B + canReceiveReq := false.B + complete := false.B + } + io.txData.valid := inProgress + io.txData.bits := io.req.bits.data + when(inProgress && io.txData.fire) { + + /** continuously resend */ + complete := true.B + when(!io.req.bits.repeat) { + inProgress := false.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 canReceiveReq = RegInit(true.B) + val inProgress = RegInit(false.B) + val complete = RegInit(false.B) + when(io.req.fire && canReceiveReq) { + inProgress := true.B + complete := false.B + canReceiveReq := 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 + inProgress := false.B + } + + io.result.valid := complete + io.result.bits.status := MessageRequestStatusType.SUCCESS + io.result.bits.data := data +} + class SBMsgWrapper( sbParams: SidebandParams, ) extends Module { @@ -19,33 +97,26 @@ 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, SEND_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 repeat = RegInit(false.B) @@ -53,106 +124,65 @@ class SBMsgWrapper( 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.msgReqStatus.valid := false.B 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.data := currentReq + sbMsgWriter.io.req.bits.repeat := repeat + 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) { io.trainIO.msgReq.ready := true.B when(io.trainIO.msgReq.fire) { currentReq := io.trainIO.msgReq.bits.msg currentReqTimeoutMax := io.trainIO.msgReq.bits.timeoutCycles + nextState := MuxLookup(io.trainIO.msgReq.bits.reqType, State.EXCHANGE)( + requestToState, + ) repeat := io.trainIO.msgReq.bits.repeat - nextState := State.EXCHANGE } } 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 = { - - /** opcode */ - (m1(4, 0) === m2(4, 0)) && - /** subcode */ - (m1(21, 14) === m2(21, 14)) && - /** code */ - (m1(39, 32) === m2(39, 32)) + when(sbMsgWriter.io.result.valid && sbMsgReader.io.result.valid) { + dataOut := sbMsgReader.io.result.bits.data + currentStatus := MessageRequestStatusType.SUCCESS + nextState := State.WAIT_ACK } - /** send message over sideband */ - io.laneIO.txData.valid := !sentMsg || repeat - 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) + /** 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 + 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 + } - // 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 @@ -161,7 +191,6 @@ class SBMsgWrapper( } 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/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/main/scala/sideband/sb-msg-encoding.scala b/src/main/scala/sideband/sb-msg-encoding.scala index 9409c69..1fe9a85 100644 --- a/src/main/scala/sideband/sb-msg-encoding.scala +++ b/src/main/scala/sideband/sb-msg-encoding.scala @@ -352,6 +352,27 @@ 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_TX_INIT_D_TO_C_RESULTS_REQ = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000011??????????10000101?????????00000", + ) + def MBTRAIN_TX_INIT_D_TO_C_RESULTS_RESP = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000011??????????10001010?????????00000", + ) + + def MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_REQ = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000100??????????10000101?????????00000", + ) + def MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_RESP = BitPat( + "b????????????????????????????????????????????????????????????????????????????????????????00000100??????????10001010?????????00000", + ) + def MBTRAIN_VALVREF_START_REQ = BitPat( "b????????????????????????????????????????????????????????????????????????????????????????00000000??????????10110101?????????00000", ) @@ -402,7 +423,7 @@ object SBMessage_factory { dst_num = dst_num << 26 msg += dst_num // println("SBMessage_factory: " + msg) - val new_msg = Cat(data, (msg.U(64.W) | (msgInfo << (32 + 8).U))) + val new_msg = Cat(data, (msg.U(64.W) | msgInfo << (32 + 8).U)(63, 0)) // printf("SBMessage_factory: %x\n", new_msg) new_msg } @@ -411,8 +432,8 @@ object SBMessage_factory { src: String, remote: Boolean, dst: String, - data: Int, - msgInfo: Int, + data: BigInt, + msgInfo: BigInt, ): BigInt = { // take the bottom 64 bits of the base by modulo var msg: BigInt = base.value % (BigInt(1) << 64) diff --git a/src/main/scala/tilelink/Configs.scala b/src/main/scala/tilelink/Configs.scala index 2d90cf2..e8d9a8c 100644 --- a/src/main/scala/tilelink/Configs.scala +++ b/src/main/scala/tilelink/Configs.scala @@ -8,7 +8,7 @@ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import org.chipsalliance.cde.config.{Field, Config, Parameters} import freechips.rocketchip.subsystem._ -import testchipip.soc.{OBUS} +// import testchipip.soc.{OBUS} //import freechips.rocketchip.subsystem.{BaseSubsystem, CacheBlockBytes} import freechips.rocketchip.regmapper.{HasRegMap, RegField} import interfaces._ @@ -16,15 +16,15 @@ import protocol._ import sideband.{SidebandParams} import logphy.{LinkTrainingParams} -case class UCITLParams ( - val protoParams: ProtocolLayerParams, - val tlParams: TileLinkParams, - val fdiParams: FdiParams, - val rdiParams: RdiParams, - val sbParams: SidebandParams, - val linkTrainingParams: LinkTrainingParams, - val afeParams: AfeParams, - val laneAsyncQueueParams: AsyncQueueParams +case class UCITLParams( + val protoParams: ProtocolLayerParams, + val tlParams: TileLinkParams, + val fdiParams: FdiParams, + val rdiParams: RdiParams, + val sbParams: SidebandParams, + val linkTrainingParams: LinkTrainingParams, + val afeParams: AfeParams, + val laneAsyncQueueParams: AsyncQueueParams, ) case object UCITLKey extends Field[Option[UCITLParams]](None) @@ -32,36 +32,41 @@ case object UCITLKey extends Field[Option[UCITLParams]](None) trait CanHaveTLUCIAdapter { this: BaseSubsystem => val uciTL = p(UCITLKey) match { case Some(params) => { - val obus = locateTLBusWrapper(OBUS) //TODO: make parameterizable? + val obus = locateTLBusWrapper(SBUS) // TODO: make parameterizable? val sbus = locateTLBusWrapper(SBUS) - val uciTL = LazyModule(new UCITLFront( - tlParams = params.tlParams, - protoParams = params.protoParams, - fdiParams = params.fdiParams, - rdiParams = params.rdiParams, - sbParams = params.sbParams, - //myId = params.myId, - linkTrainingParams = params.linkTrainingParams, - afeParams = params.afeParams, - laneAsyncQueueParams = params.laneAsyncQueueParams - )) + val uciTL = LazyModule( + new UCITLFront( + tlParams = params.tlParams, + protoParams = params.protoParams, + fdiParams = params.fdiParams, + rdiParams = params.rdiParams, + sbParams = params.sbParams, + // myId = params.myId, + linkTrainingParams = params.linkTrainingParams, + afeParams = params.afeParams, + laneAsyncQueueParams = params.laneAsyncQueueParams, + ), + ) 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 } - val ucie_io = uciTL.map { uci => InModuleBody { - val ucie_io = IO(new UcieDigitalTopIO()) - ucie_io <> uci.module.io - ucie_io -}} + val ucie_io = uciTL.map { uci => + InModuleBody { + val ucie_io = IO(new UcieDigitalTopIO()) + ucie_io <> uci.module.io + ucie_io + } + } } -class WithUCITLAdapter(params: UCITLParams) extends Config((site, here, up) => { - case UCITLKey => Some(params) -}) +class WithUCITLAdapter(params: UCITLParams) + extends Config((site, here, up) => { case UCITLKey => + Some(params) + }) diff --git a/src/test/scala/Scrambler.scala b/src/test/scala/Scrambler.scala deleted file mode 100644 index 80a4d14..0000000 --- a/src/test/scala/Scrambler.scala +++ /dev/null @@ -1,40 +0,0 @@ -package edu.berkeley.cs.ucie.digital -package interfaces - -import chisel3._ -import chiseltest._ -import org.scalatest.funspec.AnyFunSpec - -class ScramblerTest extends AnyFunSpec with ChiselScalatestTester { - - describe("Scrambler") { - it("4 lane scrambler test") { - test(new UCIeScrambler(new AfeParams(), 16, 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_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)) - } - } - } -} diff --git a/src/test/scala/e2e/AfeLoopbackTest.scala b/src/test/scala/e2e/AfeLoopbackTest.scala index 40667fb..107abf6 100644 --- a/src/test/scala/e2e/AfeLoopbackTest.scala +++ b/src/test/scala/e2e/AfeLoopbackTest.scala @@ -83,10 +83,10 @@ class AfeLoopbackTester(implicit p: Parameters) extends LazyModule { io.uci_clock <> clockSourceNode.out(0)._1 // inputs to tlUcieDie1 // tlUcieDie1.module.io.mbAfe <> AfeLoopback.io.mbAfe - tlUcieDie1.module.io.mbAfe_tx <> AfeLoopback.io.mbAfe_tx - tlUcieDie1.module.io.mbAfe_rx <> AfeLoopback.io.mbAfe_rx - tlUcieDie1.module.io.sbTxIo <> AfeLoopback.io.sbAfe_tx - tlUcieDie1.module.io.sbRxIo <> AfeLoopback.io.sbAfe_rx + tlUcieDie1.module.io.mbAfe_tx.get <> AfeLoopback.io.mbAfe_tx + tlUcieDie1.module.io.mbAfe_rx.get <> AfeLoopback.io.mbAfe_rx + tlUcieDie1.module.io.txSbAfe <> AfeLoopback.io.sbAfe_tx + tlUcieDie1.module.io.rxSbAfe <> AfeLoopback.io.sbAfe_rx } } diff --git a/src/test/scala/logphy/ErrorCounterTest.scala b/src/test/scala/logphy/ErrorCounterTest.scala new file mode 100644 index 0000000..7cd1eec --- /dev/null +++ b/src/test/scala/logphy/ErrorCounterTest.scala @@ -0,0 +1,229 @@ +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( + 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.clock.step() + + 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( + Vec.Lit( + TestUtils + .makeRandomErrors(lfsrVals, numErrors, bitWidth) + .toSeq + .map(_.U(afeParams.mbSerializerRatio.W)): _*, + ), + ) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) + c.clock.step() + + 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( + Vec.Lit( + TestUtils + .makeRandomErrors(lfsrVals, numErrors, bitWidth) + .toSeq + .map(_.U(afeParams.mbSerializerRatio.W)): _*, + ), + ) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) + c.clock.step() + + c.io.req.valid.poke(false.B) + for (_ <- 0 until 10) { + c.clock.step() + } + + 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( + Vec.Lit(lfsrVals.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + c.io.errorCount.expect( + Vec.Lit( + Seq.fill(afeParams.mbLanes)(0.U(errWidth.W)): _*, + ), + ) + } + } + it should "correctly count errors for valtrain pattern" in { + test(new ErrorCounter(afeParams)) { c => + 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( + Vec.Lit(valtrain.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( + Vec.Lit( + TestUtils + .makeRandomErrors(valtrain, numErrors, bitWidth) + .toSeq + .map(_.U(bitWidth.W)): _*, + ), + ) + c.io.errorCount.expect(Vec.Lit(numErrors.map(_.U(errWidth.W)): _*)) + 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) + 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( + 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( + 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..1c10761 100644 --- a/src/test/scala/logphy/LinkTrainingFSMTest.scala +++ b/src/test/scala/logphy/LinkTrainingFSMTest.scala @@ -24,8 +24,13 @@ 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") + // trainMB(c) + println("Successfully trained mainband") c.io.currentState.expect(LinkTrainingState.linkInit) @@ -52,13 +57,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 +80,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( @@ -100,6 +109,10 @@ class LinkTrainingFSMTest extends AnyFlatSpec with ChiselScalatestTester { c.clock.step(3) } + // private def trainMB(c: LinkTrainingFSM): Unit = { + // c.io.currentState.expect(LinkTrainingState.mbTrain) + // } + private def testTransitionOutOfReset(c: LinkTrainingFSM): Unit = { c.io.currentState.expect(LinkTrainingState.reset) c.io.mainbandFSMIO.txFreqSel.expect(SpeedMode.speed4) diff --git a/src/test/scala/logphy/LogPhyLaneTest.scala b/src/test/scala/logphy/LogPhyLaneTest.scala index 90ee798..562835f 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,40 +24,34 @@ class LogPhyLaneTest extends AnyFlatSpec with ChiselScalatestTester { c.io.mainbandIo.txData .expectDequeueNow( Vec.Lit( - "h8821".U, - "h8843".U, - "h7765".U, - "h7787".U, - "h66a9".U, - "h66cb".U, - "h55ed".U, - "h550f".U, - "h44f0".U, - "h44de".U, - "h33bc".U, - "h339a".U, - "h2278".U, - "h2256".U, - "h1134".U, - "h1112".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 TX lanes" - ignore should "correctly map TX bytes to their lanes - test 2" in { + 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.mainbandLaneIO.txData.initSource() - c.io.mainbandLaneIO.txData.setSourceClock(c.clock) - c.io.mainbandIo.txData.initSink() - c.io.mainbandIo.txData.setSinkClock(c.clock) + initPorts(c, scramble = false) - c.io.mainbandLaneIO.txData.enqueueNow( - "h7840_80a0_001f_ffff_ffe0_0000_0000_0000_0000".U, - ) - c.io.mainbandIo.txData - .expectDequeueNow( + c.io.mainbandIo.rxData + .enqueueNow( Vec.Lit( "h1211".U, "h3411".U, @@ -78,45 +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 RX lanes" - it should "correctly map RX bytes to their lanes" in { + behavior of "log phy TX lanes scramble" + it should "correctly map TX 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 = true) - c.io.mainbandIo.rxData - .enqueueNow( + 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( - "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, + "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 ), ) - c.io.mainbandLaneIO.rxData.expectDequeueNow( + 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 MainbandIO(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/MBInitFSMTest.scala b/src/test/scala/logphy/MBInitFSMTest.scala index 12fed83..128221e 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,14 @@ 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, + _.repeat -> false.B, ) msgReq } @@ -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) @@ -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/MBTrainerTest.scala b/src/test/scala/logphy/MBTrainerTest.scala new file mode 100644 index 0000000..33850c7 --- /dev/null +++ b/src/test/scala/logphy/MBTrainerTest.scala @@ -0,0 +1,395 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import interfaces._ +import chisel3._ +import chisel3.util._ +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) + var transmitPattern = TransmitPattern.LFSR + val sbClockFreq = + 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, + timeoutCyclesDefault, + maxErrors, + ) + + var errorCount = Vec.Lit( + Seq.fill(afeParams.mbLanes)(1.U(maxPatternCountWidth.W)): _*, + ) + completeTrainingOperation( + c, + transmitPattern, + timeoutCyclesDefault, + patternUICount, + errorCount, + ) + + transmitPattern = TransmitPattern.PER_LANE_ID + patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio + errorCount = Vec.Lit( + Seq.tabulate(afeParams.mbLanes)(x => x.U(maxPatternCountWidth.W)): _*, + ) + + triggerOperation( + c, + transmitPattern, + patternUICount, + timeoutCyclesDefault, + maxErrors, + ) + + completeTrainingOperation( + c, + transmitPattern, + timeoutCyclesDefault, + patternUICount, + errorCount, + ) + + triggerExit(c, timeoutCyclesDefault) + exitTraining(c, timeoutCyclesDefault) + + } + } + it should "correctly exchange SB out of reset message sideband trigger" in { + test(new MBTrainer(linkTrainingParams, afeParams, maxPatternCount)) { c => + initPorts(c) + var transmitPattern = TransmitPattern.LFSR + val sbClockFreq = + linkTrainingParams.sbClockFreqAnalog / afeParams.sbSerializerRatio + val timeoutCyclesDefault = (0.008 * sbClockFreq).toInt + var patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio * 4 + val maxErrors = 0 + + initialExpectedValues(c) + + /** 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, + errorCount, + ) + + transmitPattern = TransmitPattern.PER_LANE_ID + patternUICount = afeParams.mbLanes * afeParams.mbSerializerRatio + errorCount = Vec.Lit( + Seq.tabulate(afeParams.mbLanes)(x => x.U(maxPatternCountWidth.W)): _*, + ) + + /** 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, + 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) + c.io.sbTrainIO.msgReqStatus.ready.expect(false.B) + c.io.complete.expect(false.B) + c.io.trainingOperationIO.outputValid.expect(false.B) + c.io.err.expect(false.B) + c.io.sbMsgWrapperReset.expect(false.B) + c.clock.step() + } + + private def exitTraining(c: MBTrainer, timeoutCyclesDefault: Int): Unit = { + + expectSBReq( + c = c, + bitPat = SBM.MBTRAIN_END_TX_INIT_D_TO_C_POINT_TEST_RESP, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault = timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + + sbMsgSuccess(c) + + c.clock.step() + c.io.complete.expect(true.B) + c.io.err.expect(false.B) + } + + 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) + c.io.trainingOperationIO.patternUICount.poke(patternUICount.U) + c.io.trainingOperationIO.triggerExit.poke(false.B) + c.clock.step() + c.io.trainingOperationIO.triggerNew.poke(false.B) + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + println("External trigger") + + 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, + ) + println("Received SB request for Point Test Start Req") + + /** 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( + c, + SBM.MBTRAIN_START_TX_INIT_D_TO_C_POINT_TEST_RESP, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + println("Received SB request for Point Test Start Resp") + + /** 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, + ), + ) + println("Received Pattern Generator request") + + /** Complete pattern generator request */ + 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, + ), + ) + + c.io.trainingOperationIO.errorCounts.expect(errorCount) + + /** Expect Results Req req */ + expectSBReq( + c, + SBM.MBTRAIN_TX_INIT_D_TO_C_RESULTS_REQ, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + println("Received SB request for Results request") + + /** Complete Results req */ + sbMsgSuccess(c) + + /** Expect Results Resp req */ + expectSBReq( + c, + SBM.MBTRAIN_TX_INIT_D_TO_C_RESULTS_RESP, + reqType = MessageRequestType.EXCHANGE, + timeoutCyclesDefault, + msgInfo = 0, + data = 0, + ) + println("Received SB request for Results response") + + sbMsgSuccess(c) + + /** Now, the test should be waiting for either external intervention or a SB + * request... + */ + for (_ <- 0 until 10) { + c.clock.step() + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + c.io.complete.expect(false.B) + c.io.err.expect(false.B) + c.io.sbMsgWrapperReset.expect(false.B) + c.io.trainingOperationIO.outputValid.expect(true.B) + c.io.trainingOperationIO.errorCounts.expect(errorCount) + } + + } + + 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, + _.repeat -> false.B, + ), + ) + c.io.patternGeneratorIO.transmitReq.expectInvalid() + c.io.patternGeneratorIO.resp.ready.expect(false.B) + } + + private def sbMsgSuccess(c: MBTrainer, data: BigInt = 0): Unit = { + c.io.sbTrainIO.msgReqStatus.enqueueNow( + (new MessageRequestStatus).Lit( + _.data -> data.U, + _.status -> MessageRequestStatusType.SUCCESS, + ), + ) + } + + 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/PatternGeneratorTest.scala b/src/test/scala/logphy/PatternGeneratorTest.scala index 2e158ee..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,21 +13,214 @@ 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(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) + } + } + behavior of "mainband pattern generator" + it should "detect MB LFSR pattern" in { + val maxPatternCount = 1024 + test( + new PatternGenerator( + afeParams = afeParams, + sbParams = sbParams, + maxPatternCount = maxPatternCount, + ), + ) { c => + initPorts(c) + val maxPatternCountWidth = log2Ceil(maxPatternCount + 1) + val width = afeParams.mbSerializerRatio * afeParams.mbLanes + + 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( + c = c, + transmitPattern = TransmitPattern.LFSR, + patternCountMax = 4, + patternDetectedCountMax = 4, + timeoutCycles = 80, + mainbandRx = rxReceived.map(f => f.U(width.W)), + mainbandTx = expectedTx, + expectedResult = MessageRequestStatusType.SUCCESS, + 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 = maxPatternCount, + ), + ) { c => + initPorts(c) + 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)): _*, + ), + ) } } @@ -33,7 +228,7 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.patternGeneratorIO.transmitReq .initSource() .setSourceClock(c.clock) - c.io.patternGeneratorIO.transmitPatternStatus + c.io.patternGeneratorIO.resp .initSink() .setSinkClock(c.clock) c.io.sidebandLaneIO.rxData @@ -42,22 +237,47 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData .initSink() .setSinkClock(c.clock) + c.io.mainbandIO.rxData + .initSource() + .setSourceClock(c.clock) + c.io.mainbandIO.txData + .initSink() + .setSinkClock(c.clock) } - private def testClockPatternSideband(c: PatternGenerator): Unit = { + private def createRequest( + c: PatternGenerator, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + patternDetectedCountMax: Int, + timeoutCycles: Int, + ): Unit = { c.io.patternGeneratorIO.transmitReq.ready.expect(true) c.io.sidebandLaneIO.rxData.ready.expect(false) + c.io.mainbandIO.rxData.ready.expect(false) c.io.sidebandLaneIO.txData.expectInvalid() - c.io.patternGeneratorIO.transmitPatternStatus.expectInvalid() - c.clock.step() - + c.io.mainbandIO.txData.expectInvalid() + c.io.patternGeneratorIO.resp.expectInvalid() c.io.patternGeneratorIO.transmitReq.enqueueNow( chiselTypeOf(c.io.patternGeneratorIO.transmitReq.bits).Lit( - _.pattern -> TransmitPattern.CLOCK_64_LOW_32, - _.timeoutCycles -> 80.U, - _.sideband -> true.B, + _.pattern -> transmitPattern, + _.patternCountMax -> patternCountMax.U, + _.patternDetectedCountMax -> patternDetectedCountMax.U, + _.timeoutCycles -> timeoutCycles.U, ), ) + } + + private def testClockPatternSideband(c: PatternGenerator): Unit = { + val length = 2 + + createRequest( + c, + TransmitPattern.CLOCK, + length * sbParams.sbNodeMsgWidth, + length * sbParams.sbNodeMsgWidth, + 80, + ) val testVector = Seq.fill(2)("haaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa".U) @@ -68,7 +288,74 @@ class PatternGeneratorTest extends AnyFlatSpec with ChiselScalatestTester { c.io.sidebandLaneIO.txData.expectDequeueSeq(testVector) }.join() - c.io.patternGeneratorIO.transmitPatternStatus - .expectDequeue(MessageRequestStatusType.SUCCESS) + 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( + c: PatternGenerator, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + patternDetectedCountMax: Int, + timeoutCycles: Int, + mainbandRx: Seq[UInt], + mainbandTx: Seq[UInt], + expectedResult: MessageRequestStatusType.Type, + expectedErrorCount: Vec[UInt], + ): Unit = { + + createRequest( + c, + transmitPattern, + patternCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, + patternDetectedCountMax * afeParams.mbSerializerRatio * afeParams.mbLanes, + timeoutCycles, + ) + + fork { + c.io.mainbandIO.rxData.enqueueSeq(mainbandRx) + }.fork { + c.io.mainbandIO.txData.expectDequeueSeq(mainbandTx) + }.join() + + c.io.patternGeneratorIO.resp + .expectDequeue( + chiselTypeOf(c.io.patternGeneratorIO.resp.bits).Lit( + _.status -> expectedResult, + _.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 new file mode 100644 index 0000000..6affe28 --- /dev/null +++ b/src/test/scala/logphy/PatternReaderTest.scala @@ -0,0 +1,350 @@ +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, + maxPatternWidth, + ) + c.io.mbRxData.ready.expect(false.B) + + 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.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 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 + 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, + ) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + 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, + ) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + 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, + ) + + } + } + it should "detect MB valtrain pattern" in { + test(new PatternReader(sbParams, afeParams, maxPatternCount = 2048)) { c => + 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, + ) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + numVecs = 10 + testVector = Seq.fill(numVecs)( + Seq.fill(afeParams.mbLanes)( + BigInt("11110000" * (afeParams.mbSerializerRatio / 8), 2), + ), + ) + + val res = createExpErrVecs(testVector) + testVecs = res._1 + errVecs = res._2 + + 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, + ) + + } + } + + 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 numVecs = 5 + val maxPatternCountWidth = log2Ceil(2048 + 1) + val testVector = Seq.fill(numVecs)( + Seq.tabulate(afeParams.mbLanes)(i => BigInt("A" + f"$i%02X" + "A", 16)), + ) + + val (testVecs, errVecs) = createExpErrVecs(testVector) + + 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, + ) + + c.reset.poke(true.B) + c.clock.step() + c.reset.poke(false.B) + + } + } + + 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[Vec[UInt]], + errorCountExpected: Vec[UInt], + maxErrorCountWidth: Int, + ): Unit = { + initPorts(c) + val width = afeParams.mbLanes * afeParams.mbSerializerRatio + createRequest( + c, + transmitPattern, + patternCountMax = width * testVector.length, + sideband = false, + maxErrorCountWidth, + ) + 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) + } + 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.valid.poke(true.B) + c.io.resp.complete.expect(false.B) + 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() + } + + 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) + } + +} diff --git a/src/test/scala/logphy/PatternWriterTest.scala b/src/test/scala/logphy/PatternWriterTest.scala new file mode 100644 index 0000000..c2246a2 --- /dev/null +++ b/src/test/scala/logphy/PatternWriterTest.scala @@ -0,0 +1,228 @@ +package edu.berkeley.cs.ucie.digital +package logphy + +import chisel3._ +import chisel3.experimental.VecLiterals.AddObjectLiteralConstructor +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, maxPatternCount = 2048)) { c => + initPorts(c) + createRequest( + c, + TransmitPattern.CLOCK, + 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) + + } + } + + 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, + afeParams.mbSerializerRatio * afeParams.mbLanes * 4, + ) + + val lfsrValVecs = lfsrVals.map(f => + Vec.Lit(f.map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + + c.clock.step() + 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( + lfsrValVecs(i), + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + it should "send MB valtrain pattern" in { + val maxPatternCount = 2048 + test( + new PatternWriter(sbParams, afeParams, maxPatternCount = maxPatternCount), + ) { c => + initPorts(c) + val patternCountMax = 512 + createRequest( + c, + TransmitPattern.VALTRAIN, + 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() + 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( + Vec.Lit(valtrain(i).map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + 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, + numVecs * afeParams.mbSerializerRatio * afeParams.mbLanes, + ) + + c.clock.step() + 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( + Vec.Lit(perLaneVec(i).map(_.U(afeParams.mbSerializerRatio.W)): _*), + ) + } + + c.io.resp.complete.expect(true.B) + + } + } + + private def createRequest( + c: PatternWriter, + transmitPattern: TransmitPattern.Type, + patternCountMax: Int, + ): Unit = { + c.io.request.valid.poke(true.B) + c.io.request.bits.pattern.poke(transmitPattern) + 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/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..f2979dd 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" @@ -32,6 +33,59 @@ class SBMsgWrapperTest extends AnyFlatSpec with ChiselScalatestTester { } } + it should "correctly receive only" in { + test(new SBMsgWrapper(sbParams)) { c => + 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, + _.repeat -> true.B, + ), + ) + + 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() @@ -50,8 +104,9 @@ 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, + _.repeat -> true.B, ), ) diff --git a/src/test/scala/logphy/ScramblerTest.scala b/src/test/scala/logphy/ScramblerTest.scala new file mode 100644 index 0000000..9eb37b3 --- /dev/null +++ b/src/test/scala/logphy/ScramblerTest.scala @@ -0,0 +1,59 @@ +package edu.berkeley.cs.ucie.digital +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(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_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)) + // } + // } + } +} 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 + } +} 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() }