From 6a9a0533c9b15f0a190ac95fe1eef7d153301019 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Sun, 29 Nov 2020 13:48:47 +0800 Subject: [PATCH] dispatch1: block valid when blockBackward or noSpecExec --- .../backend/decode/DecodeBuffer.scala | 9 +-- .../xiangshan/backend/dispatch/Dispatch.scala | 1 + .../backend/dispatch/Dispatch1.scala | 62 ++++++++++++------- .../scala/xiangshan/backend/roq/Roq.scala | 33 ++++++---- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/main/scala/xiangshan/backend/decode/DecodeBuffer.scala b/src/main/scala/xiangshan/backend/decode/DecodeBuffer.scala index f1b40c12f..3fb25976b 100644 --- a/src/main/scala/xiangshan/backend/decode/DecodeBuffer.scala +++ b/src/main/scala/xiangshan/backend/decode/DecodeBuffer.scala @@ -43,10 +43,11 @@ class DecodeBuffer extends XSModule { if(i > 0 ){ io.out(i).valid := validVec(i) && !flush && - Mux(r.ctrl.noSpecExec, - !ParallelOR(validVec.take(i)), - !ParallelOR(io.out.zip(validVec).take(i).map(x => x._2 && x._1.bits.ctrl.noSpecExec)) - ) && !io.isWalking + // Mux(r.ctrl.noSpecExec, + !ParallelOR(validVec.take(i))//, + // !ParallelOR(io.out.zip(validVec).take(i).map(x => x._2 && x._1.bits.ctrl.noSpecExec)) + //) && + !io.isWalking } else { require( i == 0) io.out(i).valid := validVec(i) && !flush && !io.isWalking diff --git a/src/main/scala/xiangshan/backend/dispatch/Dispatch.scala b/src/main/scala/xiangshan/backend/dispatch/Dispatch.scala index 9fbb77f61..23b6b05f7 100644 --- a/src/main/scala/xiangshan/backend/dispatch/Dispatch.scala +++ b/src/main/scala/xiangshan/backend/dispatch/Dispatch.scala @@ -31,6 +31,7 @@ class Dispatch extends XSModule { // enq Roq val enqRoq = new Bundle { val canAccept = Input(Bool()) + val isEmpty = Input(Bool()) val extraWalk = Vec(RenameWidth, Output(Bool())) val req = Vec(RenameWidth, ValidIO(new MicroOp)) val resp = Vec(RenameWidth, Input(new RoqPtr)) diff --git a/src/main/scala/xiangshan/backend/dispatch/Dispatch1.scala b/src/main/scala/xiangshan/backend/dispatch/Dispatch1.scala index 07b9c8da8..40dd8d921 100644 --- a/src/main/scala/xiangshan/backend/dispatch/Dispatch1.scala +++ b/src/main/scala/xiangshan/backend/dispatch/Dispatch1.scala @@ -17,6 +17,7 @@ class Dispatch1 extends XSModule { // enq Roq val enqRoq = new Bundle { val canAccept = Input(Bool()) + val isEmpty = Input(Bool()) // if set, Roq needs extra walk val extraWalk = Vec(RenameWidth, Output(Bool())) val req = Vec(RenameWidth, ValidIO(new MicroOp)) @@ -41,10 +42,12 @@ class Dispatch1 extends XSModule { * Part 1: choose the target dispatch queue and the corresponding write ports */ // valid bits for different dispatch queues - val isInt = WireInit(VecInit(io.fromRename.map(uop => FuType.isIntExu(uop.bits.ctrl.fuType)))) - val isFp = WireInit(VecInit(io.fromRename.map(uop => FuType.isFpExu (uop.bits.ctrl.fuType)))) - val isLs = WireInit(VecInit(io.fromRename.map(uop => FuType.isMemExu(uop.bits.ctrl.fuType)))) - val isStore = WireInit(VecInit(io.fromRename.map(uop => FuType.isStoreExu(uop.bits.ctrl.fuType)))) + val isInt = VecInit(io.fromRename.map(req => FuType.isIntExu(req.bits.ctrl.fuType))) + val isFp = VecInit(io.fromRename.map(req => FuType.isFpExu (req.bits.ctrl.fuType))) + val isLs = VecInit(io.fromRename.map(req => FuType.isMemExu(req.bits.ctrl.fuType))) + val isStore = VecInit(io.fromRename.map(req => FuType.isStoreExu(req.bits.ctrl.fuType))) + val isBlockBackward = VecInit(io.fromRename.map(_.bits.ctrl.blockBackward)) + val isNoSpecExec = VecInit(io.fromRename.map(_.bits.ctrl.noSpecExec)) // generate index mapping val intIndex = Module(new IndexMapping(RenameWidth, dpParams.DqEnqWidth, false)) @@ -79,24 +82,30 @@ class Dispatch1 extends XSModule { // Thus, for i >= dpParams.DqEnqWidth, we have to check whether it's previous instructions (and the instruction itself) can enqueue. // However, since, for instructions with indices less than dpParams.DqEnqWidth, // they can always enter dispatch queue when ROB and LSQ are ready, we don't need to check whether they can enqueue. - // prevCanOut: previous instructions can enqueue + // thisIsBlocked: this instruction is blocked by itself // thisCanOut: this instruction can enqueue - val thisCanOut = (0 until RenameWidth).map(i => + // nextCanOut: next instructions can out + // notBlockedByPrevious: previous instructions can enqueue + val thisIsBlocked = VecInit((0 until RenameWidth).map(i => + isNoSpecExec(i) && !io.enqRoq.isEmpty + )) + val thisCanOut = VecInit((0 until RenameWidth).map(i => { // For i in [0, DqEnqWidth), they can always enqueue when ROB and LSQ are ready - if (i < dpParams.DqEnqWidth) true.B - else Cat(Seq(intIndex, fpIndex, lsIndex).map(_.io.reverseMapping(i).valid)).orR - ) - val prevCanOut = VecInit((0 until RenameWidth).map(i => - // For i in [0, DqEnqWidth], previous instructions can always enqueue when ROB and LSQ are ready - if (i <= dpParams.DqEnqWidth) true.B - // They need to check their previous ones - else Cat((dpParams.DqEnqWidth until i).map(j => thisCanOut(j) || !io.fromRename(j).valid)).andR + if (i < dpParams.DqEnqWidth) !thisIsBlocked(i) + else Cat(Seq(intIndex, fpIndex, lsIndex).map(_.io.reverseMapping(i).valid)).orR && !thisIsBlocked(i) + })) + val nextCanOut = VecInit((0 until RenameWidth).map(i => + (thisCanOut(i) && !isBlockBackward(i)) || !io.fromRename(i).valid + )) + val notBlockedByPrevious = VecInit((0 until RenameWidth).map(i => + if (i == 0) true.B + else Cat((0 until i).map(j => nextCanOut(j))).andR )) // this instruction can actually dequeue: 3 conditions // (1) resources are ready // (2) previous instructions are ready - val thisCanActualOut = (0 until RenameWidth).map(i => allResourceReady && thisCanOut(i) && prevCanOut(i)) + val thisCanActualOut = (0 until RenameWidth).map(i => allResourceReady && thisCanOut(i) && notBlockedByPrevious(i)) val uopWithIndex = Wire(Vec(RenameWidth, new MicroOp)) @@ -129,17 +138,22 @@ class Dispatch1 extends XSModule { // send uops with correct indexes to dispatch queues // Note that if one of their previous instructions cannot enqueue, they should not enter dispatch queue. - // We use prevCanOut here since mapping(i).valid implies there's a valid instruction that can enqueue, + // We use notBlockedByPrevious here since mapping(i).valid implies there's a valid instruction that can enqueue, // thus we don't need to check thisCanOut. for (i <- 0 until dpParams.DqEnqWidth) { - io.toIntDq(i).bits := uopWithIndex(intIndex.io.mapping(i).bits) - io.toIntDq(i).valid := intIndex.io.mapping(i).valid && allResourceReady && prevCanOut(intIndex.io.mapping(i).bits) - - io.toFpDq(i).bits := uopWithIndex(fpIndex.io.mapping(i).bits) - io.toFpDq(i).valid := fpIndex.io.mapping(i).valid && allResourceReady && prevCanOut(fpIndex.io.mapping(i).bits) - - io.toLsDq(i).bits := uopWithIndex(lsIndex.io.mapping(i).bits) - io.toLsDq(i).valid := lsIndex.io.mapping(i).valid && allResourceReady && prevCanOut(lsIndex.io.mapping(i).bits) + io.toIntDq(i).bits := uopWithIndex(intIndex.io.mapping(i).bits) + io.toIntDq(i).valid := intIndex.io.mapping(i).valid && allResourceReady && + !thisIsBlocked(intIndex.io.mapping(i).bits) && notBlockedByPrevious(intIndex.io.mapping(i).bits) + + // NOTE: floating point instructions are not noSpecExec currently + // remove commit /**/ when fp instructions are possible to be noSpecExec + io.toFpDq(i).bits := uopWithIndex(fpIndex.io.mapping(i).bits) + io.toFpDq(i).valid := fpIndex.io.mapping(i).valid && allResourceReady && + /*!thisIsBlocked(fpIndex.io.mapping(i).bits) && */notBlockedByPrevious(fpIndex.io.mapping(i).bits) + + io.toLsDq(i).bits := uopWithIndex(lsIndex.io.mapping(i).bits) + io.toLsDq(i).valid := lsIndex.io.mapping(i).valid && allResourceReady && + !thisIsBlocked(lsIndex.io.mapping(i).bits) && notBlockedByPrevious(lsIndex.io.mapping(i).bits) XSDebug(io.toIntDq(i).valid, p"pc 0x${Hexadecimal(io.toIntDq(i).bits.cf.pc)} int index $i\n") XSDebug(io.toFpDq(i).valid , p"pc 0x${Hexadecimal(io.toFpDq(i).bits.cf.pc )} fp index $i\n") diff --git a/src/main/scala/xiangshan/backend/roq/Roq.scala b/src/main/scala/xiangshan/backend/roq/Roq.scala index 9ef31910a..6355bb3c1 100644 --- a/src/main/scala/xiangshan/backend/roq/Roq.scala +++ b/src/main/scala/xiangshan/backend/roq/Roq.scala @@ -44,6 +44,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper { val memRedirect = Input(Valid(new Redirect)) val enq = new Bundle { val canAccept = Output(Bool()) + val isEmpty = Output(Bool()) val extraWalk = Vec(RenameWidth, Input(Bool())) val req = Vec(RenameWidth, Flipped(ValidIO(new MicroOp))) val resp = Vec(RenameWidth, Output(new RoqPtr)) @@ -85,14 +86,13 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper { io.roqDeqPtr := deqPtrExt // Dispatch - val validEntries = distanceBetween(enqPtrExt, deqPtrExt) - val firedDispatch = Cat(io.enq.req.map(_.valid)) - io.enq.canAccept := validEntries <= (RoqSize - RenameWidth).U - XSDebug(p"(ready, valid): ${io.enq.canAccept}, ${Binary(firedDispatch)}\n") + val hasBlockBackward = RegInit(false.B) + val hasNoSpecExec = RegInit(false.B) + val blockBackwardCommit = Cat(io.commits.map(c => c.valid && !c.bits.isWalk && c.bits.uop.ctrl.blockBackward)).orR + val noSpecExecCommit = Cat(io.commits.map(c => c.valid && !c.bits.isWalk && c.bits.uop.ctrl.noSpecExec)).orR + when(blockBackwardCommit){ hasBlockBackward:= false.B } + when(noSpecExecCommit){ hasNoSpecExec:= false.B } - val noSpecEnq = io.enq.req.map(i => i.bits.ctrl.blockBackward) - val hasNoSpec = RegInit(false.B) - when(isEmpty){ hasNoSpec:= false.B } val validDispatch = io.enq.req.map(_.valid) XSDebug("(ready, valid): ") for (i <- 0 until RenameWidth) { @@ -100,19 +100,30 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper { val roqIdxExt = enqPtrExt + offset val roqIdx = roqIdxExt.value - when(io.enq.req(i).valid){ + when(io.enq.req(i).valid) { microOp(roqIdx) := io.enq.req(i).bits valid(roqIdx) := true.B flag(roqIdx) := roqIdxExt.flag writebacked(roqIdx) := false.B - when(noSpecEnq(i)){ hasNoSpec := true.B } + when(io.enq.req(i).bits.ctrl.blockBackward) { + hasBlockBackward := true.B + } + when(io.enq.req(i).bits.ctrl.noSpecExec) { + hasNoSpecExec := true.B + } } io.enq.resp(i) := roqIdxExt } + val validEntries = distanceBetween(enqPtrExt, deqPtrExt) + val firedDispatch = Cat(io.enq.req.map(_.valid)) + io.enq.canAccept := (validEntries <= (RoqSize - RenameWidth).U) && !hasBlockBackward + io.enq.isEmpty := isEmpty + XSDebug(p"(ready, valid): ${io.enq.canAccept}, ${Binary(firedDispatch)}\n") + val dispatchCnt = PopCount(firedDispatch) + enqPtrExt := enqPtrExt + PopCount(firedDispatch) when (firedDispatch.orR) { - enqPtrExt := enqPtrExt + dispatchCnt XSInfo("dispatched %d insts\n", dispatchCnt) } @@ -144,7 +155,7 @@ class Roq(numWbPorts: Int) extends XSModule with HasCircularQueuePtrHelper { val deqUop = microOp(deqPtr) val deqPtrWritebacked = writebacked(deqPtr) && valid(deqPtr) - val intrEnable = io.csr.intrBitSet && !isEmpty && !hasNoSpec && + val intrEnable = io.csr.intrBitSet && !isEmpty && !hasNoSpecExec && deqUop.ctrl.commitType =/= CommitType.STORE && deqUop.ctrl.commitType =/= CommitType.LOAD// TODO: wanna check why has hasCsr(hasNoSpec) val exceptionEnable = deqPtrWritebacked && Cat(deqUop.cf.exceptionVec).orR() val isFlushPipe = deqPtrWritebacked && deqUop.ctrl.flushPipe -- GitLab