diff --git a/src/main/scala/xiangshan/backend/Backend.scala b/src/main/scala/xiangshan/backend/Backend.scala index cd2af4b369cb3c1ed413fbb41cc3c96c09bc954c..81c73b9605ceaa4866dd888b66a12c59b2d606dc 100644 --- a/src/main/scala/xiangshan/backend/Backend.scala +++ b/src/main/scala/xiangshan/backend/Backend.scala @@ -208,10 +208,8 @@ class Backend(implicit val p: XSConfig) extends XSModule fpRf.io.readPorts <> dispatch.io.readFpRf ++ issueQueues.flatMap(_.io.readFpRf) memRf.io.readPorts <> issueQueues.flatMap(_.io.readIntRf) - val wbIntIdx = exuConfigs.zipWithIndex.filter(_._1.writeIntRf).map(_._2) - val wbFpIdx = exuConfigs.zipWithIndex.filter(_._1.writeFpRf).map(_._2) - val wbu = Module(new Wbu(wbIntIdx, wbFpIdx)) + val wbu = Module(new Wbu(exuConfigs)) wbu.io.in <> exeWbReqs val wbIntResults = wbu.io.toIntRf diff --git a/src/main/scala/xiangshan/backend/exu/Exu.scala b/src/main/scala/xiangshan/backend/exu/Exu.scala index 8dbc5e2a7364520c14ac2668634b2ba091bacc14..ad4665f247e1fa31ed382433f75a840d13f201a8 100644 --- a/src/main/scala/xiangshan/backend/exu/Exu.scala +++ b/src/main/scala/xiangshan/backend/exu/Exu.scala @@ -64,4 +64,7 @@ object Exu { val mulDivExeUnitCfg = ExuConfig("MulDivExu", Array(mulCfg, divCfg), enableBypass = false) val ldExeUnitCfg = ExuConfig("LoadExu", Array(lduCfg), enableBypass = false) val stExeUnitCfg =ExuConfig("StoreExu", Array(stuCfg), enableBypass = false) + val fmacExeUnitCfg = ExuConfig("FmacExu", Array(fmacCfg), enableBypass = false) + val fmiscExeUnitCfg = ExuConfig("FmiscExu", Array(fmiscCfg), enableBypass = false) + val fmiscDivExeUnitCfg = ExuConfig("FmiscDivExu", Array(fmiscCfg, fDivSqrtCfg), enableBypass = false) } diff --git a/src/main/scala/xiangshan/backend/exu/Wbu.scala b/src/main/scala/xiangshan/backend/exu/Wbu.scala index 294e31f12b8074176df32249d0571b3c8b6e8957..34b258b092e1d8354c32da7cee4d22da4b28f04b 100644 --- a/src/main/scala/xiangshan/backend/exu/Wbu.scala +++ b/src/main/scala/xiangshan/backend/exu/Wbu.scala @@ -38,7 +38,7 @@ class WriteBackArbMtoN(m: Int, n: Int) extends XSModule { } -class Wbu(wbIntIdx: Array[Int], wbFpIdx: Array[Int]) extends XSModule{ +class Wbu(exuConfigs: Array[ExuConfig]) extends XSModule{ val io = IO(new Bundle() { val in = Vec(exuParameters.ExuCnt, Flipped(DecoupledIO(new ExuOutput))) @@ -47,33 +47,42 @@ class Wbu(wbIntIdx: Array[Int], wbFpIdx: Array[Int]) extends XSModule{ val toFpRf = Vec(NRFpWritePorts, ValidIO(new ExuOutput)) }) + require(io.in.length == exuConfigs.length) + + def exuOutToRfReq - (exuOutVec: Vec[DecoupledIO[ExuOutput]], fp: Boolean): Seq[(DecoupledIO[ExuOutput], Int)] = { - val wbIdxSet = if(fp) wbFpIdx else wbIntIdx - exuOutVec.zipWithIndex.filter(x => wbIdxSet.contains(x._2)).map({ - case(exuOut, idx) => - val req = Wire(Decoupled(new ExuOutput)) - req.valid := exuOut.valid && {if(fp) exuOut.bits.uop.ctrl.fpWen else exuOut.bits.uop.ctrl.rfWen} - req.bits := exuOut.bits - (req, idx) - }) + (exuOut: DecoupledIO[ExuOutput], fp: Boolean): DecoupledIO[ExuOutput] = { + val req = Wire(Decoupled(new ExuOutput)) + req.valid := exuOut.valid && { + if(fp) exuOut.bits.uop.ctrl.fpWen else exuOut.bits.uop.ctrl.rfWen + } + req.bits := exuOut.bits + req } - val wbIntReq = exuOutToRfReq(io.in, fp = false) + // ((ExuOutput, ExuConfig), index) => ((WbReq, ExuConfig), index) + val wbInt = io.in.zip(exuConfigs).zipWithIndex. + filter(_._1._2.writeIntRf).map(x => + ((exuOutToRfReq(x._1._1, fp = false), x._1._2), x._2)) - val wbFpReq = exuOutToRfReq(io.in, fp = true) + val wbIntReq = wbInt.map(_._1) - for(i <- io.in.indices){ - val intReqIdx = wbIntReq.map(_._2).indexOf(i) - val fpReqIdx = wbFpReq.map(_._2).indexOf(i) + val wbFp = io.in.zip(exuConfigs).zipWithIndex. + filter(_._1._2.writeFpRf).map(x => + ((exuOutToRfReq(x._1._1, fp = true), x._1._2), x._2)) + + val wbFpReq = wbFp.map(_._1) - val wbInt = intReqIdx >= 0 - val wbFp = fpReqIdx >= 0 + for(i <- io.in.indices){ + val writeIntReqIdx = wbInt.map(_._2).indexOf(i) + val writeFpReqIdx = wbFp.map(_._2).indexOf(i) + val writeIntRf = writeIntReqIdx >= 0 + val writeFpRf = writeFpReqIdx >= 0 - val iReq = if(wbInt) wbIntReq(intReqIdx)._1 else null - val fReq = if(wbFp) wbFpReq(fpReqIdx)._1 else null + val iReq = if(writeIntRf) wbIntReq(writeIntReqIdx)._1 else null + val fReq = if(writeFpRf) wbFpReq(writeFpReqIdx)._1 else null - if(wbInt && wbFp){ + if(writeIntRf && writeFpRf){ io.in(i).ready := Mux(iReq.valid, iReq.ready, Mux(fReq.valid, @@ -82,46 +91,104 @@ class Wbu(wbIntIdx: Array[Int], wbFpIdx: Array[Int]) extends XSModule{ ) ) assert(!(iReq.valid && fReq.valid), s"Error: iReq and fReq valid at same time, idx=$i") - } else if(wbInt){ - io.in(i).ready := Mux(iReq.valid, iReq.ready, true.B) - } else if(wbFp){ - io.in(i).ready := Mux(fReq.valid, fReq.ready, true.B) + } else if(writeIntRf){ + io.in(i).ready := iReq.ready + } else if(writeFpRf){ + io.in(i).ready := fReq.ready } else { - // store io.in(i).ready := true.B } + + exuConfigs(i) match { + case Exu.aluExeUnitCfg => + io.toRoq(i).valid := io.in(i).fire() && !io.in(i).bits.redirectValid + case Exu.jmpExeUnitCfg => + io.toRoq(i).valid := io.in(i).fire() && !io.in(i).bits.redirectValid + case _ => + io.toRoq(i).valid := io.in(i).fire() + } + io.toRoq(i).bits := io.in(i).bits } - if(wbIntIdx.length < NRIntWritePorts){ - io.toIntRf.take(wbIntIdx.length).zip(wbIntReq.map(_._1)).foreach(x => { - x._1.bits := x._2.bits - x._1.valid := x._2.valid - x._2.ready := true.B - }) - io.toIntRf.drop(wbIntIdx.length).foreach(_ <> DontCare) - } else { - val intArb = Module(new WriteBackArbMtoN(wbIntIdx.length, NRIntWritePorts)) - intArb.io.in <> wbIntReq.map(_._1) - io.toIntRf <> intArb.io.out + def directConnect(rfWrite: Valid[ExuOutput], wbReq: DecoupledIO[ExuOutput]) = { + rfWrite.bits := wbReq.bits + rfWrite.valid := wbReq.valid + wbReq.ready := true.B + } + + def splitN[T](in: Seq[T], n: Int): Seq[Option[Seq[T]]] = { + require(n > 0) + if(in.size < n) Seq(Some(in)) ++ Seq.fill(n-1)(None) + else { + val m = in.size/n + Some(in.take(m)) +: splitN(in.drop(m), n-1) + } } - if(wbFpIdx.length < NRFpWritePorts){ - io.toFpRf.take(wbFpIdx.length).zip(wbFpReq.map(_._1)).foreach(x => { - x._1.bits := x._2.bits - x._1.valid := x._2.valid - x._2.ready := true.B - }) - io.toFpRf.drop(wbFpIdx.length).foreach(_ <> DontCare) + if(wbIntReq.size <= NRIntWritePorts){ // write ports are enough + io.toIntRf. + take(wbIntReq.size). + zip(wbIntReq). + foreach(x => directConnect(x._1, x._2._1)) + + if(wbIntReq.size < NRIntWritePorts){ + println(s"Warrning: ${NRIntWritePorts-wbIntReq.size} int write ports are not used!") + io.toIntRf.drop(wbIntReq.size).foreach(_ <> DontCare) + } } else { - val fpArb = Module(new WriteBackArbMtoN(wbFpIdx.length, NRFpWritePorts)) - fpArb.io.in <> wbFpReq.map(_._1) - io.toFpRf <> fpArb.io.out + val directReq = wbIntReq.filter(w => Seq(Exu.ldExeUnitCfg, Exu.aluExeUnitCfg).contains(w._2)) + val mulReq = wbIntReq.filter(w => Seq(Exu.mulExeUnitCfg, Exu.mulDivExeUnitCfg).contains(w._2)) + val otherReq = splitN( + wbIntReq.filterNot(w => Seq( + Exu.ldExeUnitCfg, Exu.aluExeUnitCfg, Exu.mulDivExeUnitCfg, Exu.mulExeUnitCfg + ).contains(w._2)), + mulReq.size + ) + require(directReq.size + mulReq.size <= NRIntWritePorts) + // alu && load: direct connect + io.toIntRf.take(directReq.size).zip(directReq).foreach(x => directConnect(x._1, x._2._1)) + for( i <- mulReq.indices){ + val arbiter = Module(new Arbiter(new ExuOutput, 1+otherReq(i).getOrElse(Seq()).size)) + arbiter.io.in <> (mulReq(i) +: otherReq(i).getOrElse(Seq())).map(_._1) + io.toIntRf.drop(directReq.size)(i) := arbiter.io.out + arbiter.io.out.ready := true.B + } + if(directReq.size + mulReq.size < NRIntWritePorts){ + println(s"Warrning: ${NRIntWritePorts-directReq.size-mulReq.size} int write ports are not used!") + io.toIntRf.drop(directReq.size + mulReq.size).foreach(_ <> DontCare) + } } - io.toRoq.zip(io.in).foreach({ - case(roq, in) => - roq.valid := in.fire() && !in.bits.redirectValid - roq.bits := in.bits - }) + if(wbFpReq.size <= NRFpWritePorts){ + io.toFpRf. + take(wbFpReq.size). + zip(wbFpReq). + foreach(x => directConnect(x._1, x._2._1)) + if(wbFpReq.size < NRFpWritePorts){ + println(s"Warrning: ${NRFpWritePorts-wbFpReq.size} fp write ports are not used!") + io.toFpRf.drop(wbFpReq.size).foreach(_ <> DontCare) + } + } else { + val directReq = wbFpReq.filter(w => Seq(Exu.ldExeUnitCfg, Exu.fmacExeUnitCfg).contains(w._2)) + val fmiscReq = wbFpReq.filter(w => Seq(Exu.fmiscExeUnitCfg, Exu.fmiscDivExeUnitCfg).contains(w._2)) + val otherReq = splitN( + wbFpReq.filterNot(w => Seq( + Exu.ldExeUnitCfg, Exu.fmacExeUnitCfg, Exu.fmiscExeUnitCfg, Exu.fmiscDivExeUnitCfg + ).contains(w._2)), + fmiscReq.size + ) + require(directReq.size + fmiscReq.size <= NRFpWritePorts) + io.toFpRf.take(directReq.size).zip(directReq).foreach(x => directConnect(x._1, x._2._1)) + for( i <- fmiscReq.indices){ + val arbiter = Module(new Arbiter(new ExuOutput, 1+otherReq(i).getOrElse(Seq()).size)) + arbiter.io.in <> (fmiscReq(i) +: otherReq(i).getOrElse(Seq())).map(_._1) + io.toFpRf.drop(directReq.size)(i) := arbiter.io.out + arbiter.io.out.ready := true.B + } + if(directReq.size + fmiscReq.size < NRFpWritePorts){ + println(s"Warrning: ${NRFpWritePorts-directReq.size-fmiscReq.size} fp write ports are not used!") + io.toFpRf.drop(directReq.size + fmiscReq.size).foreach(_ <> DontCare) + } + } }