提交 e18c367f 编写于 作者: L LinJiawei

[Backend]: Optimize exu and fu

上级 53271d0c
......@@ -13,6 +13,7 @@ import xiangshan.backend.regfile.{Regfile, RfWritePort}
import xiangshan.backend.roq.Roq
import xiangshan.mem._
import utils.ParallelOR
import xiangshan.backend.fu.FunctionUnit.{lduCfg, mouCfg, stuCfg}
/** Backend Pipeline:
* Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
......@@ -30,24 +31,29 @@ class Backend extends XSModule
val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
val jmpExeUnit = Module(new JmpExeUnit)
val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
val jmpExeUnit = Module(new JumpExeUnit)
val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new FmacExeUnit))
val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new FmiscExeUnit))
// val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrtExeUnit))
val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits)
val exeUnits = jmpExeUnit +: (aluExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits)
exeUnits.foreach(_.io.csrOnly := DontCare)
exeUnits.foreach(_.io.mcommit := DontCare)
fmacExeUnits.foreach(_.frm := jmpExeUnit.frm)
fmiscExeUnits.foreach(_.frm := jmpExeUnit.frm)
val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), wbIntPriority = 0, wbFpPriority = 0)
val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), wbIntPriority = Int.MaxValue, wbFpPriority = Int.MaxValue)
val decode = Module(new DecodeStage)
val brq = Module(new Brq)
val decBuf = Module(new DecodeBuffer)
val rename = Module(new Rename)
val dispatch = Module(new Dispatch)
val dispatch = Module(new Dispatch(
jmpExeUnit.config, aluExeUnits(0).config, mduExeUnits(0).config,
fmacExeUnits(0).config, fmiscExeUnits(0).config,
ldExeUnitCfg, stExeUnitCfg
))
val roq = Module(new Roq)
val intRf = Module(new Regfile(
numReadPorts = NRIntReadPorts,
......@@ -74,9 +80,11 @@ class Backend extends XSModule
io.frontend.redirect := redirect
io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay
val memConfigs =
Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++
Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg)
Seq.fill(exuParameters.LduCnt)(ldExeUnitCfg) ++
Seq.fill(exuParameters.StuCnt)(stExeUnitCfg)
val exuConfigs = exeUnits.map(_.config) ++ memConfigs
......@@ -104,7 +112,7 @@ class Backend extends XSModule
.map(_._2)
val extraListenPortsCnt = extraListenPorts.length
val feedback = (cfg == Exu.ldExeUnitCfg) || (cfg == Exu.stExeUnitCfg)
val feedback = (cfg == ldExeUnitCfg) || (cfg == stExeUnitCfg)
println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}")
......@@ -122,14 +130,16 @@ class Backend extends XSModule
}
cfg match {
case Exu.ldExeUnitCfg =>
case Exu.stExeUnitCfg =>
case `ldExeUnitCfg` =>
case `stExeUnitCfg` =>
case otherCfg =>
exeUnits(i).io.in <> rs.io.deq
exeUnits(i).io.redirect <> redirect
rs.io.tlbFeedback := DontCare
}
rs.suggestName(s"rs_${cfg.name}")
rs
})
......@@ -142,8 +152,8 @@ class Backend extends XSModule
io.mem.commits <> roq.io.commits
io.mem.roqDeqPtr := roq.io.roqDeqPtr
io.mem.ldin <> reservedStations.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq)
io.mem.stin <> reservedStations.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq)
io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)
io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)
jmpExeUnit.io.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException
jmpExeUnit.io.csrOnly.exception.bits := roq.io.exception
jmpExeUnit.fflags := roq.io.fflags
......@@ -160,7 +170,7 @@ class Backend extends XSModule
io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType)
io.mem.tlbFeedback <> reservedStations.filter(
x => x.exuCfg == Exu.ldExeUnitCfg || x.exuCfg == Exu.stExeUnitCfg
x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg
).map(_.io.tlbFeedback)
io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
......
......@@ -6,6 +6,7 @@ import xiangshan._
import utils._
import xiangshan.backend.regfile.RfReadPort
import chisel3.ExcitingUtils._
import xiangshan.backend.exu.ExuConfig
import xiangshan.backend.roq.RoqPtr
case class DispatchParameters
......@@ -22,7 +23,16 @@ case class DispatchParameters
LsDqReplayWidth: Int
)
class Dispatch extends XSModule {
class Dispatch
(
jmpCfg: ExuConfig,
aluCfg: ExuConfig,
mduCfg: ExuConfig,
fmacCfg: ExuConfig,
fmiscCfg: ExuConfig,
ldCfg: ExuConfig,
stCfg: ExuConfig
) extends XSModule {
val io = IO(new Bundle() {
// flush or replay
val redirect = Flipped(ValidIO(new Redirect))
......@@ -106,7 +116,7 @@ class Dispatch extends XSModule {
}
// Int dispatch queue to Int reservation stations
val intDispatch = Module(new Dispatch2Int)
val intDispatch = Module(new Dispatch2Int(jmpCfg, aluCfg, mduCfg))
intDispatch.io.fromDq <> intDq.io.deq
intDispatch.io.readRf <> io.readIntRf
intDispatch.io.regRdy := io.intPregRdy
......@@ -116,7 +126,7 @@ class Dispatch extends XSModule {
// TODO: Fp dispatch queue to Fp reservation stations
if (exuParameters.FpExuCnt > 0) {
val fpDispatch = Module(new Dispatch2Fp)
val fpDispatch = Module(new Dispatch2Fp(fmacCfg, fmiscCfg))
fpDispatch.io.fromDq <> fpDq.io.deq
fpDispatch.io.readRf <> io.readFpRf
fpDispatch.io.regRdy <> io.fpPregRdy
......@@ -130,7 +140,7 @@ class Dispatch extends XSModule {
}
// Load/store dispatch queue to load/store issue queues
val lsDispatch = Module(new Dispatch2Ls)
val lsDispatch = Module(new Dispatch2Ls(ldCfg, stCfg))
lsDispatch.io.fromDq <> lsDq.io.deq
lsDispatch.io.readIntRf <> io.memIntRf
lsDispatch.io.readFpRf <> io.memFpRf
......
......@@ -7,7 +7,7 @@ import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Fp extends XSModule {
class Dispatch2Fp(fmacCfg: ExuConfig, fmiscCfg: ExuConfig) extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.FpDqDeqWidth, DecoupledIO(new MicroOp)))
val readRf = Vec(NRFpReadPorts - exuParameters.StuCnt, Flipped(new RfReadPort))
......@@ -26,8 +26,8 @@ class Dispatch2Fp extends XSModule {
val fmacPriority = PriorityGen((0 until exuParameters.FmacCnt).map(i => io.numExist(i)))
val fmiscPriority = PriorityGen((0 until exuParameters.FmiscCnt).map(i => io.numExist(i+exuParameters.FmacCnt)))
for (i <- 0 until dpParams.FpDqDeqWidth) {
fmacIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.fmacExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
fmiscIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.fmiscExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
fmacIndexGen.io.validBits(i) := io.fromDq(i).valid && fmacCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
fmiscIndexGen.io.validBits(i) := io.fromDq(i).valid && fmiscCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
// XSDebug(io.fromDq(i).valid,
// p"fp dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
......
......@@ -7,7 +7,7 @@ import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Int extends XSModule {
class Dispatch2Int(jmpCfg: ExuConfig, aluCfg: ExuConfig, mduCfg: ExuConfig) extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.IntDqDeqWidth, DecoupledIO(new MicroOp)))
val readRf = Vec(NRIntReadPorts - NRMemReadPorts, Flipped(new RfReadPort))
......@@ -27,9 +27,9 @@ class Dispatch2Int extends XSModule {
val aluPriority = PriorityGen((0 until exuParameters.AluCnt).map(i => io.numExist(i+exuParameters.JmpCnt)))
val mduPriority = PriorityGen((0 until exuParameters.MduCnt).map(i => io.numExist(i+exuParameters.JmpCnt+exuParameters.AluCnt)))
for (i <- 0 until dpParams.IntDqDeqWidth) {
jmpIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.jmpExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
aluIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.aluExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
mduIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.mulDivExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
jmpIndexGen.io.validBits(i) := io.fromDq(i).valid && jmpCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
aluIndexGen.io.validBits(i) := io.fromDq(i).valid && aluCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
mduIndexGen.io.validBits(i) := io.fromDq(i).valid && mduCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
// XSDebug(io.fromDq(i).valid,
// p"int dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
}
......
......@@ -7,7 +7,7 @@ import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Ls extends XSModule {
class Dispatch2Ls(ldCfg: ExuConfig, stCfg: ExuConfig) extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.LsDqDeqWidth, DecoupledIO(new MicroOp)))
val readIntRf = Vec(NRMemReadPorts, Flipped(new RfReadPort))
......@@ -29,8 +29,8 @@ class Dispatch2Ls extends XSModule {
val loadPriority = PriorityGen((0 until exuParameters.LduCnt).map(i => io.numExist(i)))
val storePriority = PriorityGen((0 until exuParameters.StuCnt).map(i => io.numExist(i+exuParameters.LduCnt)))
for (i <- 0 until dpParams.LsDqDeqWidth) {
loadIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.ldExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
storeIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.stExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
loadIndexGen.io.validBits(i) := io.fromDq(i).valid && ldCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
storeIndexGen.io.validBits(i) := io.fromDq(i).valid && stCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
// XSDebug(io.fromDq(i).valid,
// p"ls dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
......
......@@ -6,91 +6,22 @@ import xiangshan._
import xiangshan.FuType._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.{Alu, FunctionUnit}
import xiangshan.backend.fu.FunctionUnit._
class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
val (iovalid, src1, src2, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, io.in.bits.src2,
io.in.bits.uop.ctrl.imm, io.in.bits.uop.ctrl.fuOpType, SignExt(io.in.bits.uop.cf.pc, AddrBits), io.in.bits.uop)
val redirectHit = uop.roqIdx.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw)
val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
val xorRes = src1 ^ src2
val sltu = !adderRes(XLEN)
val slt = xorRes(XLEN-1) ^ sltu
val shsrc1 = LookupTreeDefault(func, src1, List(
ALUOpType.srlw -> ZeroExt(src1(31,0), 64),
ALUOpType.sraw -> SignExt(src1(31,0), 64)
))
val shamt = Mux(ALUOpType.isWordOp(func), src2(4, 0), src2(5, 0))
val res = LookupTreeDefault(func(3, 0), adderRes, List(
ALUOpType.sll -> ((shsrc1 << shamt)(XLEN-1, 0)),
ALUOpType.slt -> ZeroExt(slt, XLEN),
ALUOpType.sltu -> ZeroExt(sltu, XLEN),
ALUOpType.xor -> xorRes,
ALUOpType.srl -> (shsrc1 >> shamt),
ALUOpType.or -> (src1 | src2),
ALUOpType.and -> (src1 & src2),
ALUOpType.sra -> ((shsrc1.asSInt >> shamt).asUInt)
))
val aluRes = Mux(ALUOpType.isWordOp(func), SignExt(res(31,0), 64), res)
val branchOpTable = List(
ALUOpType.getBranchType(ALUOpType.beq) -> !xorRes.orR,
ALUOpType.getBranchType(ALUOpType.blt) -> slt,
ALUOpType.getBranchType(ALUOpType.bltu) -> sltu
)
val isBranch = uop.cf.brUpdate.pd.isBr// ALUOpType.isBranch(func)
val isRVC = uop.cf.brUpdate.pd.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, pc + offset, adderRes)(VAddrBits-1,0)
val pcLatchSlot = Mux(isRVC, pc + 2.U, pc + 4.U)
io.out.bits.redirectValid := io.out.valid && isBranch
io.out.bits.redirect.pc := uop.cf.pc
io.out.bits.redirect.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := false.B
io.out.bits.redirect.isMisPred := DontCare // check this in brq
io.out.bits.redirect.isFlushPipe := false.B
io.out.bits.redirect.isReplay := false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.brUpdate := uop.cf.brUpdate
// override brUpdate
io.out.bits.brUpdate.pc := uop.cf.pc
io.out.bits.brUpdate.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.brUpdate.brTarget := target
// io.out.bits.brUpdate.btbType := "b00".U
io.out.bits.brUpdate.taken := isBranch && taken
// io.out.bits.brUpdate.fetchIdx := uop.cf.brUpdate.fetchOffset >> 1.U //TODO: consider RVC
io.out.bits.brUpdate.brTag := uop.brTag
io.in.ready := io.out.ready
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := aluRes
io.csrOnly <> DontCare
XSDebug(io.in.valid || io.redirect.valid,
"In(%d %d) Out(%d %d) Redirect:(%d %d %d %d) brTag:f:%d v:%d\n",
io.in.valid,
io.in.ready,
io.out.valid,
io.out.ready,
io.redirect.valid,
io.redirect.bits.isException,
io.redirect.bits.isFlushPipe,
redirectHit,
io.redirect.bits.brTag.flag,
io.redirect.bits.brTag.value
)
XSDebug(io.in.valid, p"src1:${Hexadecimal(src1)} src2:${Hexadecimal(src2)} offset:${Hexadecimal(offset)} func:${Binary(func)} pc:${Hexadecimal(pc)} roqIdx:${uop.roqIdx}\n")
XSDebug(io.out.valid, p"res:${Hexadecimal(io.out.bits.data)} aluRes:${Hexadecimal(aluRes)} isRVC:${isRVC} isBranch:${isBranch} target:${Hexadecimal(target)} taken:${taken}\n")
class AluExeUnit extends Exu(
exuName = "AluExeUnit",
fuGen = Seq((FunctionUnit.alu _, (_: FunctionUnit) => true.B)),
wbIntPriority = 0,
wbFpPriority = Int.MaxValue
)
{
val alu = supportedFunctionUnits.collectFirst{
case a: Alu => a
}.get
io.out.bits.redirectValid := alu.redirectOutValid
io.out.bits.redirect := alu.redirectOut
io.out.bits.brUpdate := alu.brUpdate
}
\ No newline at end of file
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.fu.Divider
import xiangshan.backend.MDUOpType
class DivExeUnit extends Exu(Exu.divExeUnitCfg) {
val (src1, src2, uop, func) =
(io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType)
val divider = Module(new Divider(XLEN))
val isDiv = MDUOpType.isDiv(func)
val isDivSign = MDUOpType.isDivSign(func)
val isW = MDUOpType.isW(func)
val isH = MDUOpType.isH(func)
val divInputFunc = (x: UInt) => Mux(
isW,
Mux(isDivSign,
SignExt(x(31,0), XLEN),
ZeroExt(x(31,0), XLEN)
),
x
)
val dividerInputBits = divider.io.in.bits
val dividerInputCtrl = dividerInputBits.ext.get
divider.io.redirectIn := io.redirect
divider.io.in.valid := io.in.valid
dividerInputBits.uop := io.in.bits.uop
dividerInputCtrl.sign := isDivSign
dividerInputCtrl.isW := isW
dividerInputCtrl.isHi := isH
dividerInputBits.src(0) := divInputFunc(src1)
dividerInputBits.src(1) := divInputFunc(src2)
divider.io.out.ready := io.out.ready
io.in.ready := divider.io.in.ready
io.out.valid := divider.io.out.valid
io.out.bits.uop := divider.io.out.bits.uop
io.out.bits.data := divider.io.out.bits.data
io.out.bits.redirectValid := false.B
io.out.bits.redirect <> DontCare
io.csrOnly <> DontCare
io.out.bits.debug <> DontCare
XSDebug(io.in.valid || io.redirect.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
io.in.valid, io.in.ready,
io.out.valid, io.out.ready,
io.redirect.valid,
io.redirect.bits.isException,
io.redirect.bits.isFlushPipe,
io.redirect.bits.brTag.value
)
XSDebug(io.in.valid, p"src1: 0x${Hexadecimal(src1)} src2: 0x${Hexadecimal(src2)} func: ${Binary(func)} " +
p"pc: ${io.in.bits.uop.cf.pc} roqIdx: ${io.in.bits.uop.roqIdx}\n")
XSDebug(io.out.valid, p"Out(${io.out.valid} ${io.out.ready}) res: ${Hexadecimal(io.out.bits.data)} " +
p"func: ${Binary(io.out.bits.uop.ctrl.fuOpType)} pc: ${Hexadecimal(io.out.bits.uop.cf.pc)} roqIdx: ${io.out.bits.uop.roqIdx}\n"
)
}
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.FuType._
import xiangshan.backend.fu.{CertainLatency, FuConfig, HasFuLatency, NexusLatency, UncertainLatency}
import xiangshan.backend.fu.{CertainLatency, FuConfig, FuOutput, FunctionUnit, HasFuLatency, UncertainLatency}
import utils.ParallelOR
import xiangshan.backend.fu.FunctionUnit._
......@@ -32,8 +32,9 @@ case class ExuParameters
case class ExuConfig
(
name: String,
supportedFuncUnits: Array[FuConfig],
enableBypass: Boolean
supportedFuncUnits: Seq[FuConfig],
wbIntPriority: Int,
wbFpPriority: Int
){
def max(in: Seq[Int]): Int = in.reduce((x, y) => if(x > y) x else y)
val intSrcCnt = max(supportedFuncUnits.map(_.numIntSrc))
......@@ -46,49 +47,125 @@ case class ExuConfig
val latency: HasFuLatency = {
val lats = supportedFuncUnits.map(_.latency)
val latencyValue = lats.collectFirst{
case x if x.latencyVal.nonEmpty =>
x.latencyVal.get
if(lats.exists(x => x.latencyVal.isEmpty)){
UncertainLatency()
} else {
val x = lats.head
for(l <- lats.drop(1)){
require(x.latencyVal.get == l.latencyVal.get)
}
x
}
val hasUncertain = lats.exists(x => x.latencyVal.isEmpty)
if(latencyValue.nonEmpty){
if(hasUncertain) NexusLatency(latencyValue.get) else CertainLatency(latencyValue.get)
} else UncertainLatency()
}
val hasCertainLatency = latency.latencyVal.nonEmpty
val hasUncertainlatency = latency match {
case _: UncertainLatency =>
true
case _: NexusLatency =>
true
case _ =>
false
}
val hasUncertainlatency = latency.latencyVal.isEmpty
def canAccept(fuType: UInt): Bool = {
ParallelOR(supportedFuncUnits.map(_.fuType === fuType))
Cat(supportedFuncUnits.map(_.fuType === fuType)).orR()
}
}
abstract class Exu(val config: ExuConfig) extends XSModule {
abstract class Exu[T <: FunctionUnit]
(
val exuName: String,
val fuGen: Seq[(() => T, T => Bool)],
val wbIntPriority: Int,
val wbFpPriority: Int
) extends XSModule {
val io = IO(new ExuIO)
val src1 = io.in.bits.src1
val src2 = io.in.bits.src2
val src3 = io.in.bits.src3
val func = io.in.bits.uop.ctrl.fuOpType
val supportedFunctionUnits = fuGen.map(_._1).map(gen => Module(gen()))
val fuSel = supportedFunctionUnits.zip(fuGen.map(_._2)).map(x => x._2(x._1))
def fuConfigs = supportedFunctionUnits.map(_.cfg)
def config: ExuConfig = {
ExuConfig(exuName, fuConfigs, wbIntPriority, wbFpPriority)
}
require(fuGen.nonEmpty)
require(fuSel.size == fuGen.length)
if(fuSel == null){
println("fu sel is null")
}
if(supportedFunctionUnits == null){
println("supported fu is null")
}
for((fu, sel) <- supportedFunctionUnits.zip(fuSel)){
if(fu == null) println("aaa")
if(sel == null) println("bbb")
fu.io.in.valid := io.in.valid && sel
fu.io.in.bits.uop := io.in.bits.uop
if(fu.cfg.srcCnt > 0){
fu.io.in.bits.src(0) := src1
}
if(fu.cfg.srcCnt > 1){
fu.io.in.bits.src(1) := src2
}
if(fu.cfg.srcCnt > 2){
fu.io.in.bits.src(2) := src3
}
fu.io.redirectIn := io.redirect
}
val outputArb = if(config.latency.latencyVal.nonEmpty && (config.latency.latencyVal.get == 0)){
// do not need an arbiter
println(config.name)
io.in.ready := Cat(supportedFunctionUnits.map(_.io.in.ready)).andR()
for(fu <- supportedFunctionUnits){
fu.io.out.ready := io.out.ready
}
val out = Mux1H(supportedFunctionUnits.map(x => x.io.out.valid -> x.io.out))
io.out.bits.data := out.bits.data
io.out.bits.uop := out.bits.uop
io.out.valid := out.valid
None
} else {
io.in.ready := (if(supportedFunctionUnits.length > 1) {
Cat(
fuSel.zip(supportedFunctionUnits).map(x => x._1 && x._2.io.in.ready)
).orR()
} else {
supportedFunctionUnits.head.io.in.ready
})
val outputArb = Module(new Arbiter(new FuOutput, supportedFunctionUnits.length))
outputArb.io.in <> VecInit(supportedFunctionUnits.map(_.io.out))
io.out.bits.data := outputArb.io.out.bits.data
io.out.bits.uop := outputArb.io.out.bits.uop
io.out.valid := outputArb.io.out.valid
outputArb.io.out.ready := io.out.ready
Some(outputArb)
}
io.out.bits.brUpdate <> DontCare
io.out.bits.fflags <> DontCare
io.out.bits.debug.isMMIO := false.B
io.out.bits.debug <> DontCare
io.out.bits.redirect <> DontCare
io.out.bits.redirectValid := false.B
io.csrOnly <> DontCare
}
object Exu {
val jmpExeUnitCfg = ExuConfig("JmpExu", Array(jmpCfg, i2fCfg, csrCfg, fenceCfg), enableBypass = false)
val aluExeUnitCfg = ExuConfig("AluExu", Array(aluCfg), enableBypass = true)
val mulExeUnitCfg = ExuConfig("MulExu", Array(mulCfg), enableBypass = false)
val divExeUnitCfg = ExuConfig("DivExu", Array(divCfg), enableBypass = false)
val fenceExeUnitCfg = ExuConfig("FenceCfg", Array(fenceCfg), enableBypass = false)
val i2fExeUnitCfg = ExuConfig("I2fExu", Array(i2fCfg), enableBypass = false)
val mulDivExeUnitCfg = ExuConfig("MulDivExu", Array(mulCfg, divCfg), enableBypass = false)
val mulDivFenceExeUnitCfg = ExuConfig("MulDivFenceExu", Array(mulCfg, divCfg, fenceCfg), enableBypass = false)
val ldExeUnitCfg = ExuConfig("LoadExu", Array(lduCfg), enableBypass = false)
val stExeUnitCfg =ExuConfig("StoreExu", Array(stuCfg, mouCfg), 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)
}
//object Exu {
// val jmpExeUnitCfg = ExuConfig("JmpExu", Array(jmpCfg, i2fCfg, csrCfg, fenceCfg))
// val aluExeUnitCfg = ExuConfig("AluExu", Array(aluCfg))
// val mulExeUnitCfg = ExuConfig("MulExu", Array(mulCfg))
// val divExeUnitCfg = ExuConfig("DivExu", Array(divCfg))
// val fenceExeUnitCfg = ExuConfig("FenceCfg", Array(fenceCfg))
// val i2fExeUnitCfg = ExuConfig("I2fExu", Array(i2fCfg))
// val mulDivExeUnitCfg = ExuConfig("MulDivExu", Array(mulCfg, divCfg))
// val mulDivFenceExeUnitCfg = ExuConfig("MulDivFenceExu", Array(mulCfg, divCfg, fenceCfg))
// val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), requestFastWriteBack = true, uniqueInArbiter = false)
// val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), requestFastWriteBack = false, uniqueInArbiter = false)
// val fmacExeUnitCfg = ExuConfig("FmacExu", Array(fmacCfg))
// val fmiscExeUnitCfg = ExuConfig("FmiscExu", Array(fmiscCfg))
// val fmiscDivExeUnitCfg = ExuConfig("FmiscDivExu", Array(fmiscCfg, fDivSqrtCfg))
//}
\ No newline at end of file
......@@ -2,38 +2,34 @@ package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan.backend.exu.Exu.fmacExeUnitCfg
import xiangshan.backend.fu.fpu.fma.FMA
import xiangshan.backend.fu.FunctionUnit
import xiangshan.backend.fu.fpu._
class FmacExeUnit extends Exu(fmacExeUnitCfg) {
class FmacExeUnit extends Exu(
exuName = "FmacExeUnit",
fuGen = Seq(
(FunctionUnit.fmac _, (_:FunctionUnit) => true.B)
),
wbIntPriority = Int.MaxValue,
wbFpPriority = 0
)
{
val frm = IO(Input(UInt(3.W)))
val fma = Module(new FMA)
val fma = supportedFunctionUnits.head
fma.io.in.valid := io.in.valid
val input = io.in.bits
val fmaOut = fma.io.out.bits
val isRVD = !io.in.bits.uop.ctrl.isRVF
fma.io.in.bits.src := VecInit(Seq(input.src1, input.src2, input.src3).map(src => Mux(isRVD, src, unboxF64ToF32(src))))
fma.io.in.bits.uop := io.in.bits.uop
val extraInput = fma.io.in.bits.ext.get
fma.io.in.bits.src := VecInit(Seq(input.src1, input.src2, input.src3).map(
src => Mux(isRVD, src, unboxF64ToF32(src))
))
val instr_rm = io.in.bits.uop.cf.instr(14, 12)
extraInput.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
extraInput.op := io.in.bits.uop.ctrl.fuOpType(2, 0)
extraInput.isDouble := isRVD
fma.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
fma.io.redirectIn := io.redirect
fma.io.out.ready := io.out.ready
io.in.ready := fma.io.in.ready
io.out.valid := fma.io.out.valid
io.out.bits.uop := fmaOut.uop
io.out.bits.data := Mux(fmaOut.uop.ctrl.isRVF, boxF32ToF64(fmaOut.data), fmaOut.data)
io.out.bits.fflags := fma.io.out.bits.ext.get
io.out.bits.redirectValid := false.B
io.out.bits.redirect <> DontCare
io.csrOnly <> DontCare
io.out.bits.fflags := fma.fflags
}
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import utils._
import xiangshan.backend.exu.Exu.fmiscExeUnitCfg
import xiangshan.backend.fu.fpu.{F32toF64, F64toF32, FCMP, FMV, FPUSubModuleOutput, FloatToInt}
import xiangshan.backend.fu.fpu.divsqrt.DivSqrt
import xiangshan.backend.fu.FunctionUnit
import xiangshan.backend.fu.FunctionUnit.fmiscSel
import xiangshan.backend.fu.fpu.FPUOpType._
import xiangshan.backend.fu.fpu._
class FmiscExeUnit extends Exu(fmiscExeUnitCfg){
class FmiscExeUnit extends Exu(
exuName = "FmiscExeUnit",
fuGen = {
Seq[(() => FPUSubModule, FPUSubModule => Bool)](
(FunctionUnit.fcmp _, fmiscSel(FU_FCMP)),
(FunctionUnit.fmv _, fmiscSel(FU_FMV)),
(FunctionUnit.f2i _, fmiscSel(FU_F2I)),
(FunctionUnit.f32toF64 _, fmiscSel(FU_S2D)),
(FunctionUnit.f64toF32 _, fmiscSel(FU_D2S)),
(FunctionUnit.fdivSqrt _, fmiscSel(FU_DIVSQRT))
)
},
wbIntPriority = Int.MaxValue,
wbFpPriority = 1
){
val frm = IO(Input(UInt(3.W)))
val fcmp = Module(new FCMP)
val fmv = Module(new FMV(XLEN))
val f2i = Module(new FloatToInt)
val f32toF64 = Module(new F32toF64)
val f64toF32 = Module(new F64toF32)
val fdivSqrt = Module(new DivSqrt)
val subModules = Array(
(fcmp, FU_FCMP),
(fmv, FU_FMV),
(f2i, FU_F2I),
(f32toF64, FU_S2D),
(f64toF32, FU_D2S),
(fdivSqrt, FU_DIVSQRT)
).map(x => (x._1, ("b" + x._2).U))
val fcmp :: fmv :: f2i :: f32toF64 :: f64toF32 :: fdivSqrt :: Nil = supportedFunctionUnits
val fuOp = io.in.bits.uop.ctrl.fuOpType
assert(fuOp.getWidth == 7) // when fuOp's WIDTH change, here must change too
val fu = fuOp.head(4)
val op = fuOp.tail(4)
val isRVF = io.in.bits.uop.ctrl.isRVF
val (src1, src2) = (io.in.bits.src1, io.in.bits.src2)
io.in.ready := Cat(subModules.map(x => fu===x._2 && x._1.io.in.ready)).orR()
val instr_rm = io.in.bits.uop.cf.instr(14, 12)
subModules.foreach{
case (module, fuSel) =>
module.io.in.valid := io.in.valid && fu===fuSel
module.io.in.bits.uop := io.in.bits.uop
module.io.in.bits.src(0) := Mux(
(isRVF && fuOp=/=d2s && fuOp=/=fmv_f2i) || fuOp===s2d,
unboxF64ToF32(src1),
src1
)
supportedFunctionUnits.foreach{ module =>
module.io.in.bits.src(0) := Mux(
(isRVF && fuOp=/=d2s && fuOp=/=fmv_f2i) || fuOp===s2d,
unboxF64ToF32(src1),
src1
)
if(module.cfg.srcCnt > 1){
module.io.in.bits.src(1) := Mux(isRVF, unboxF64ToF32(src2), src2)
val extraInput = module.io.in.bits.ext.get
extraInput.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
extraInput.isDouble := !isRVF
extraInput.op := op
module.io.redirectIn := io.redirect
}
module.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
}
val wbArb = Module(new Arbiter(chiselTypeOf(subModules(0)._1.io.out.bits), subModules.length))
wbArb.io.in <> VecInit(subModules.map(_._1.io.out))
val out = wbArb.io.out
val arbiter = outputArb.get
out.ready := io.out.ready
io.out.valid := out.valid
io.out.bits.uop := out.bits.uop
io.out.bits.fflags := out.bits.ext.get
val outCtrl = out.bits.uop.ctrl
io.out.bits.data := Mux(outCtrl.isRVF && outCtrl.fpWen,
boxF32ToF64(out.bits.data),
io.out.bits.fflags := Mux1H(arbiter.io.in.zip(supportedFunctionUnits).map(
x => x._1.fire() -> x._2.fflags
))
val outCtrl = io.out.bits.uop.ctrl
io.out.bits.data := Mux(outCtrl.isRVF && outCtrl.fpWen,
boxF32ToF64(arbiter.io.out.bits.data),
Mux( (outCtrl.isRVF && outCtrl.fuOpType===fmv_f2i) || outCtrl.fuOpType===f2w || outCtrl.fuOpType===f2wu,
SignExt(out.bits.data(31, 0), XLEN),
out.bits.data
SignExt(arbiter.io.out.bits.data(31, 0), XLEN),
arbiter.io.out.bits.data
)
)
io.out.bits.redirectValid := DontCare
io.out.bits.redirect := DontCare
io.csrOnly <> DontCare
}
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan.backend.fu.fpu._
import xiangshan.backend.fu.fpu.IntToFloatSingleCycle
import xiangshan.backend.fu.fpu.FPUOpType._
class I2fExeUnit extends Exu(Exu.i2fExeUnitCfg){
val frm = IO(Input(UInt(3.W)))
val uopIn = io.in.bits.uop
val isDouble = !uopIn.ctrl.isRVF
val fuOp = uopIn.ctrl.fuOpType
val fu = fuOp.head(4)
val op = fuOp.tail(4)
val valid = io.in.valid && !uopIn.roqIdx.needFlush(io.redirect)
val intToFloat = Module(new IntToFloatSingleCycle)
val extraInput = intToFloat.io.in.bits.ext.get
val instr_rm = io.in.bits.uop.cf.instr(14, 12)
extraInput.isDouble := isDouble
extraInput.rm := Mux(instr_rm =/= 7.U, instr_rm, frm)
extraInput.op := op
intToFloat.io.out.ready := io.out.ready
intToFloat.io.in.valid := valid && fu===("b"+FU_I2F).U
intToFloat.io.in.bits.src(0) := io.in.bits.src1
intToFloat.io.in.bits.uop := uopIn
intToFloat.io.redirectIn := io.redirect
io.out.valid := valid
io.out.bits.data := Mux(intToFloat.io.out.valid,
Mux(isDouble, intToFloat.io.out.bits.data, boxF32ToF64(intToFloat.io.out.bits.data)),
Mux(isDouble, io.in.bits.src1, boxF32ToF64(io.in.bits.src1))
)
io.out.bits.fflags := Mux(intToFloat.io.out.valid,
intToFloat.io.out.bits.ext.get,
0.U.asTypeOf(new Fflags)
)
io.in.ready := true.B
io.out.bits.uop := uopIn
io.out.bits.redirect <> DontCare
io.out.bits.redirectValid := false.B
io.out.bits.debug <> DontCare
io.csrOnly <> DontCare
}
package xiangshan.backend.exu
import chisel3._
import xiangshan.{ExuOutput, FuType, SfenceBundle, TlbCsrBundle}
import xiangshan.backend.fu.{CSR, Jump}
import xiangshan.backend.fu.fpu.Fflags
import utils._
class JmpExeUnit extends Exu(Exu.jmpExeUnitCfg) {
val fflags = IO(Input(new Fflags))
val dirty_fs = IO(Input(Bool()))
val frm = IO(Output(UInt(3.W)))
val fenceToSbuffer = IO(new FenceToSbuffer)
val sfence = IO(Output(new SfenceBundle))
val fencei = IO(Output(Bool()))
val tlbCsrIO = IO(Output(new TlbCsrBundle))
val (valid, src1, src2, uop, fuType, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuType, io.in.bits.uop.ctrl.fuOpType)
val jmp = Module(new Jump)
val csr = Module(new CSR)
val fence = Module(new FenceExeUnit)
val i2f = Module(new I2fExeUnit)
fenceToSbuffer <> fence.toSbuffer
sfence <> fence.sfence
fencei := fence.fencei
fence.io.csrOnly <> DontCare
i2f.io.csrOnly <> DontCare
val isJmp = fuType === FuType.jmp
val isCsr = fuType === FuType.csr
val isFence = fuType === FuType.fence
val isI2f = fuType === FuType.i2f
jmp.io <> DontCare
jmp.io.in.valid := io.in.valid && isJmp
jmp.io.out.ready := io.out.ready
jmp.io.in.bits.connectToExuInput(io.in.bits)
jmp.io.redirectIn := io.redirect
val jumpExuOut = Wire(new ExuOutput)
val jumpExtraOut = jmp.io.out.bits.ext.get
jumpExuOut.uop := uop
jumpExuOut.data := jmp.io.out.bits.data
jumpExuOut.brUpdate := jumpExtraOut.brUpdate
jumpExuOut.fflags := DontCare
jumpExuOut.redirect := jumpExtraOut.redirect
jumpExuOut.redirectValid := jumpExtraOut.redirectValid
jumpExuOut.debug := DontCare
frm := csr.io.fpu_csr.frm
tlbCsrIO := csr.io.tlbCsrIO
csr.io.cfIn := io.in.bits.uop.cf
csr.io.fpu_csr.fflags := fflags
csr.io.fpu_csr.isIllegal := false.B // TODO: check illegal rounding mode
csr.io.fpu_csr.dirty_fs := dirty_fs
csr.io.instrValid := DontCare
csr.io.out.ready := io.out.ready
csr.io.in.valid := io.in.valid && isCsr
csr.io.in.bits.ext.get := io.in.bits.uop.ctrl.fuOpType
csr.io.in.bits.connectToExuInput(io.in.bits)
csr.io.redirectIn := io.redirect
val csrOut = csr.io.out.bits.data
csr.io.perf <> DontCare
csr.io.exception := io.csrOnly.exception
csr.io.isInterrupt := io.redirect.bits.isFlushPipe
csr.io.memExceptionVAddr := io.csrOnly.memExceptionVAddr
io.csrOnly.trapTarget := csr.io.trapTarget
csr.io.mtip := io.csrOnly.externalInterrupt.mtip
csr.io.msip := io.csrOnly.externalInterrupt.msip
csr.io.meip := io.csrOnly.externalInterrupt.meip
io.csrOnly.interrupt := csr.io.interrupt
// val uop = io.in.bits.uop
val csrExuOut = Wire(new ExuOutput)
csrExuOut.uop := uop
csrExuOut.uop.cf := csr.io.cfOut
csrExuOut.uop.ctrl.flushPipe := csr.io.flushPipe
csrExuOut.data := csrOut
csrExuOut.fflags := DontCare
csrExuOut.redirectValid := csr.io.redirectOutValid
csrExuOut.redirect.brTag := uop.brTag
csrExuOut.redirect.isException := false.B
csrExuOut.redirect.isMisPred := false.B
csrExuOut.redirect.isFlushPipe := false.B
csrExuOut.redirect.isReplay := false.B
csrExuOut.redirect.roqIdx := uop.roqIdx
csrExuOut.redirect.target := csr.io.redirectOut.target
csrExuOut.redirect.pc := uop.cf.pc
csrExuOut.debug := DontCare
csrExuOut.brUpdate := DontCare
fence.io <> DontCare
fence.io.in.valid := valid && isFence
fence.io.in.bits := io.in.bits
fence.io.redirect <> DontCare // io.redirect // No need for fence is the first instr
fence.io.mcommit <> DontCare
fence.io.out.ready := io.out.ready
i2f.io.in.valid := valid && isI2f
i2f.io.in.bits := io.in.bits
i2f.io.redirect <> io.redirect
i2f.io.mcommit <> DontCare
i2f.io.out.ready := io.out.ready
i2f.frm := frm
// NOTE: just one instr in this module at the same time
io.in.ready := jmp.io.in.ready && csr.io.in.ready && fence.io.in.ready && i2f.io.in.ready
io.out.bits := Mux(jmp.io.out.valid,
jumpExuOut,
Mux(csr.io.out.valid,
csrExuOut,
Mux(fence.io.out.valid,
fence.io.out.bits,
i2f.io.out.bits
)
)
)
io.out.valid := jmp.io.out.valid || csr.io.out.valid || fence.io.out.valid || i2f.io.out.valid
XSDebug(io.in.valid,
p"In(${io.in.valid} ${io.in.ready} ${jmp.io.in.ready}${csr.io.in.ready}${fence.io.in.ready}${i2f.io.in.ready}) " +
p"pc:0x${Hexadecimal(io.in.bits.uop.cf.pc)} roqIdx:${io.in.bits.uop.roqIdx} " +
p"fuType:b${Binary(io.in.bits.uop.ctrl.fuType)} fuOpType:b${Binary(io.in.bits.uop.ctrl.fuOpType)} " +
p"isJmp:$isJmp isCsr$isCsr isFence:$isFence isI2f:$isI2f\n")
XSDebug(io.out.valid,
p"Out(${io.out.valid} ${io.out.ready} ${jmp.io.out.valid}${csr.io.out.valid}${fence.io.out.valid}${i2f.io.out.valid}) " +
p"pc:0x${Hexadecimal(io.out.bits.uop.cf.pc)} roqIdx:${io.out.bits.uop.roqIdx} " +
p"fuType:b${Binary(io.out.bits.uop.ctrl.fuType)} fuOpType:b${Binary(io.out.bits.uop.ctrl.fuOpType)}\n")
}
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan.backend.fu.fpu.FPUOpType.FU_I2F
import xiangshan.backend.fu.{CSR, Fence, FenceToSbuffer, FunctionUnit, Jump}
import xiangshan.{FuType, SfenceBundle, TlbCsrBundle}
import xiangshan.backend.fu.fpu.{Fflags, IntToFloatSingleCycle, boxF32ToF64}
class JumpExeUnit extends Exu(
exuName = "JmpExeUnit",
fuGen = Seq(
(FunctionUnit.jmp _, (x: FunctionUnit) => x.io.in.bits.uop.ctrl.fuType === FuType.jmp),
(FunctionUnit.csr _, (x: FunctionUnit) => x.io.in.bits.uop.ctrl.fuType === FuType.csr),
(FunctionUnit.fence _, (x: FunctionUnit) => x.io.in.bits.uop.ctrl.fuType === FuType.fence),
(FunctionUnit.i2f _, (x: FunctionUnit) => x.io.in.bits.uop.ctrl.fuType === FuType.i2f)
),
wbIntPriority = 2,
wbFpPriority = Int.MaxValue
)
{
val fflags = IO(Input(new Fflags))
val dirty_fs = IO(Input(Bool()))
val frm = IO(Output(UInt(3.W)))
val fenceToSbuffer = IO(new FenceToSbuffer)
val sfence = IO(Output(new SfenceBundle))
val fencei = IO(Output(Bool()))
val tlbCsrIO = IO(Output(new TlbCsrBundle))
val jmp = supportedFunctionUnits.collectFirst{
case j: Jump => j
}.get
val csr = supportedFunctionUnits.collectFirst{
case c: CSR => c
}.get
val fence = supportedFunctionUnits.collectFirst{
case f: Fence => f
}.get
val i2f = supportedFunctionUnits.collectFirst {
case i: IntToFloatSingleCycle => i
}.get
val uop = io.in.bits.uop
fenceToSbuffer <> fence.toSbuffer
sfence <> fence.sfence
fencei := fence.fencei
frm := csr.fpu_csr.frm
tlbCsrIO := csr.tlbCsrIO
csr.fpu_csr.fflags := fflags
csr.fpu_csr.isIllegal := false.B // TODO: check illegal rounding mode
csr.fpu_csr.dirty_fs := dirty_fs
csr.perf <> DontCare
csr.exception := io.csrOnly.exception
csr.isInterrupt := io.redirect.bits.isFlushPipe
csr.memExceptionVAddr := io.csrOnly.memExceptionVAddr
csr.mtip := io.csrOnly.externalInterrupt.mtip
csr.msip := io.csrOnly.externalInterrupt.msip
csr.meip := io.csrOnly.externalInterrupt.meip
io.csrOnly.trapTarget := csr.trapTarget
io.csrOnly.interrupt := csr.interrupt
val instr_rm = uop.cf.instr(14, 12)
i2f.rm := Mux(instr_rm =/= 7.U, instr_rm, csr.fpu_csr.frm)
val isDouble = !uop.ctrl.isRVF
when(i2f.io.in.valid){
when(uop.ctrl.fuOpType.head(4)===s"b$FU_I2F".U){
io.out.bits.data := Mux(isDouble, i2f.io.out.bits.data, boxF32ToF64(i2f.io.out.bits.data))
io.out.bits.fflags := i2f.fflags
}.otherwise({
// a mov.(s/d).x instruction
io.out.bits.data := Mux(isDouble, io.in.bits.src1, boxF32ToF64(io.in.bits.src1))
io.out.bits.fflags := 0.U.asTypeOf(new Fflags)
})
}
when(csr.io.out.valid){
io.out.bits.redirectValid := csr.redirectOutValid
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := false.B
io.out.bits.redirect.isMisPred := false.B
io.out.bits.redirect.isFlushPipe := false.B
io.out.bits.redirect.isReplay := false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.redirect.target := csr.redirectOut.target
io.out.bits.redirect.pc := uop.cf.pc
}.elsewhen(jmp.io.out.valid){
io.out.bits.redirectValid := jmp.redirectOutValid
io.out.bits.redirect := jmp.redirectOut
io.out.bits.brUpdate := jmp.brUpdate
}
}
......@@ -5,93 +5,78 @@ import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.MDUOpType
import xiangshan.backend.fu.FunctionUnit._
class MulDivFenceExeUnit extends Exu(Exu.mulDivFenceExeUnitCfg){
val (src1, src2, uop, func) =
(io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType)
val isMul = MDUOpType.isMul(func)
val isDiv = MDUOpType.isDiv(func)
val isFence = MDUOpType.isFence(func)
val mul = Module(new MulExeUnit)
val div = Module(new DivExeUnit)
val fence = Module(new FenceExeUnit)
for(x <- Seq(mul.io, div.io, fence.io)){
x.mcommit <> DontCare
x.csrOnly <> DontCare
x.in.bits := io.in.bits
x.redirect := io.redirect
}
mul.io.in.valid := io.in.valid && isMul
div.io.in.valid := io.in.valid && isDiv
fence.io.in.valid := io.in.valid && isFence
io.in.ready := false.B
when (isMul) { io.in.ready := mul.io.in.ready }
when (isDiv) { io.in.ready := div.io.in.ready }
when (isFence) { io.in.ready := fence.io.in.ready }
val arb = Module(new Arbiter(new ExuOutput, 3))
arb.io.in(0) <> mul.io.out
arb.io.in(1) <> div.io.out
arb.io.in(2) <> fence.io.out
io.out <> arb.io.out
import xiangshan.backend.fu.{ArrayMultiplier, Divider, FunctionUnit}
class MulDivExeUnit(hasDiv: Boolean = true) extends Exu(
exuName = if(hasDiv) "MulDivExeUnit" else "MulExeUnit",
fuGen = {
Seq(
(
FunctionUnit.multiplier _,
(x: FunctionUnit) =>
if(hasDiv) MDUOpType.isMul(x.io.in.bits.uop.ctrl.fuOpType) else true.B
)
) ++ {
if(hasDiv) Seq(
(FunctionUnit.divider _, (x: FunctionUnit) => MDUOpType.isDiv(x.io.in.bits.uop.ctrl.fuOpType))
) else Nil
}
},
wbIntPriority = 1,
wbFpPriority = Int.MaxValue
)
{
val mul = supportedFunctionUnits.collectFirst {
case m: ArrayMultiplier => m
}.get
val div = supportedFunctionUnits.collectFirst {
case d: Divider => d
}.orNull
// override inputs
val op = MDUOpType.getMulOp(func)
val signext = SignExt(_: UInt, XLEN+1)
val zeroext = ZeroExt(_: UInt, XLEN+1)
val mulInputFuncTable = List(
MDUOpType.mul -> (zeroext, zeroext),
MDUOpType.mulh -> (signext, signext),
MDUOpType.mulhsu -> (signext, zeroext),
MDUOpType.mulhu -> (zeroext, zeroext)
)
XSDebug(io.in.valid || io.redirect.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
io.in.valid, io.in.ready,
io.out.valid, io.out.ready,
io.redirect.valid,
io.redirect.bits.isException,
io.redirect.bits.isFlushPipe,
io.redirect.bits.brTag.value
mul.io.in.bits.src(0) := LookupTree(
op,
mulInputFuncTable.map(p => (p._1(1,0), p._2._1(src1)))
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x fuType:%b fuOpType:%b roqIdx:%d (%d%d%d)\n",
src1, src2, io.in.bits.uop.cf.pc, io.in.bits.uop.ctrl.fuType, io.in.bits.uop.ctrl.fuOpType,
io.in.bits.uop.roqIdx.asUInt, isMul, isDiv, isFence)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x fuType:%b fuOpType:%b roqIdx:%d chosen:%d\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc, io.in.bits.uop.ctrl.fuType,
io.in.bits.uop.ctrl.fuOpType, io.in.bits.uop.roqIdx.asUInt, arb.io.chosen
mul.io.in.bits.src(1) := LookupTree(
op,
mulInputFuncTable.map(p => (p._1(1,0), p._2._2(src2)))
)
}
class MulDivExeUnit extends Exu(Exu.mulDivExeUnitCfg){
val (src1, src2, uop, func) =
(io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType)
val isMul = MDUOpType.isMul(func)
val isDiv = MDUOpType.isDiv(func)
val mul = Module(new MulExeUnit)
val div = Module(new DivExeUnit)
for(x <- Seq(mul.io, div.io)){
x <> DontCare
x.in.bits := io.in.bits
x.redirect := io.redirect
val isW = MDUOpType.isW(func)
val isH = MDUOpType.isH(func)
mul.ctrl.isW := isW
mul.ctrl.isHi := isH
mul.ctrl.sign := DontCare
val isDivSign = MDUOpType.isDivSign(func)
val divInputFunc = (x: UInt) => Mux(
isW,
Mux(isDivSign,
SignExt(x(31,0), XLEN),
ZeroExt(x(31,0), XLEN)
),
x
)
if(hasDiv){
div.io.in.bits.src(0) := divInputFunc(src1)
div.io.in.bits.src(1) := divInputFunc(src2)
div.ctrl.isHi := isH
div.ctrl.isW := isW
div.ctrl.sign := isDivSign
}
mul.io.in.valid := io.in.valid && isMul
div.io.in.valid := io.in.valid && isDiv
io.in.ready := false.B
when (isMul) { io.in.ready := mul.io.in.ready }
when (isDiv) { io.in.ready := div.io.in.ready }
val arb = Module(new Arbiter(new ExuOutput, 2))
arb.io.in(0) <> mul.io.out
arb.io.in(1) <> div.io.out
io.out <> arb.io.out
io.csrOnly <> DontCare
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
io.in.valid, io.in.ready,
io.out.valid, io.out.ready,
......@@ -105,3 +90,5 @@ class MulDivExeUnit extends Exu(Exu.mulDivExeUnitCfg){
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
}
class MulExeUnit extends MulDivExeUnit(hasDiv = false)
\ No newline at end of file
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.MDUOpType
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.backend.fu.ArrayMultiplier
class MulExeUnit extends Exu(Exu.mulExeUnitCfg){
val (src1, src2, uop, func) =
(io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType)
val mul = Module(new ArrayMultiplier(XLEN+1))
val signext = SignExt(_: UInt, XLEN+1)
val zeroext = ZeroExt(_: UInt, XLEN+1)
val mulInputFuncTable = List(
MDUOpType.mul -> (zeroext, zeroext),
MDUOpType.mulh -> (signext, signext),
MDUOpType.mulhsu -> (signext, zeroext),
MDUOpType.mulhu -> (zeroext, zeroext)
)
val isW = MDUOpType.isW(func)
val isH = MDUOpType.isH(func)
val op = MDUOpType.getMulOp(func)
val mulInputCtrl = mul.io.in.bits.ext.get
mul.io.redirectIn := io.redirect
mul.io.in.bits.uop := io.in.bits.uop
mulInputCtrl.sign := DontCare //Mul don't use this
mulInputCtrl.isW := isW
mulInputCtrl.isHi := isH
mul.io.in.bits.src(0) := LookupTree(
op,
mulInputFuncTable.map(p => (p._1(1,0), p._2._1(src1)))
)
mul.io.in.bits.src(1) := LookupTree(
op,
mulInputFuncTable.map(p => (p._1(1,0), p._2._2(src2)))
)
mul.io.in.valid := io.in.valid
mul.io.out.ready := io.out.ready
io.in.ready := mul.io.in.ready
io.out.valid := mul.io.out.valid
io.out.bits.uop := mul.io.out.bits.uop
io.out.bits.data := mul.io.out.bits.data
io.out.bits.redirectValid := false.B
io.out.bits.redirect <> DontCare
io.csrOnly <> DontCare
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
io.in.valid, io.in.ready,
io.out.valid, io.out.ready,
io.redirect.valid,
io.redirect.bits.isException,
io.redirect.bits.isFlushPipe,
io.redirect.bits.brTag.value
)
XSDebug(io.in.valid, p"src1:${Hexadecimal(src1)} src2:${Hexadecimal(src2)} pc:${Hexadecimal(io.in.bits.uop.cf.pc)} roqIdx:${io.in.bits.uop.roqIdx}\n")
XSDebug(io.out.valid, p"Out(${io.out.valid} ${io.out.ready}) res:${Hexadecimal(io.out.bits.data)} pc:${io.out.bits.uop.cf.pc} roqIdx:${io.out.bits.uop.roqIdx}\n")
XSDebug(io.redirect.valid, p"redirect: ${io.redirect.bits.brTag}\n")
}
......@@ -66,14 +66,13 @@ class Wbu(exuConfigs: Array[ExuConfig]) extends XSModule{
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()
if(exuConfigs(i).hasRedirect){
// aluExeUnit, jmpExeUnit
io.toRoq(i).valid := io.in(i).fire() && !io.in(i).bits.redirectValid
} else {
io.toRoq(i).valid := io.in(i).fire()
}
io.toRoq(i).bits := io.in(i).bits
}
......@@ -108,12 +107,10 @@ class Wbu(exuConfigs: Array[ExuConfig]) extends XSModule{
io.toIntRf.drop(wbIntReq.size).foreach(_ <> DontCare)
}
} else {
val directReq = wbIntReq.filter(w => Seq(Exu.ldExeUnitCfg, Exu.aluExeUnitCfg).contains(w._2))
val mulReq = wbIntReq.filter(w => Seq(Exu.mulExeUnitCfg, Exu.mulDivExeUnitCfg, Exu.mulDivFenceExeUnitCfg).contains(w._2))
val directReq = wbIntReq.filter(w => w._2.wbIntPriority == 0)
val mulReq = wbIntReq.filter(w => w._2.wbIntPriority == 1)
val otherReq = splitN(
wbIntReq.filterNot(w => Seq(
Exu.ldExeUnitCfg, Exu.aluExeUnitCfg, Exu.mulDivExeUnitCfg, Exu.mulExeUnitCfg, Exu.mulDivFenceExeUnitCfg
).contains(w._2)),
wbIntReq.filterNot(w => w._2.wbIntPriority <= 1),
mulReq.size
)
require(directReq.size + mulReq.size <= NRIntWritePorts)
......@@ -142,12 +139,10 @@ class Wbu(exuConfigs: Array[ExuConfig]) extends XSModule{
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 directReq = wbFpReq.filter(w => w._2.wbFpPriority == 0)
val fmiscReq = wbFpReq.filter(w => w._2.wbFpPriority == 1)
val otherReq = splitN(
wbFpReq.filterNot(w => Seq(
Exu.ldExeUnitCfg, Exu.fmacExeUnitCfg, Exu.fmiscExeUnitCfg, Exu.fmiscDivExeUnitCfg
).contains(w._2)),
wbFpReq.filterNot(w => w._2.wbFpPriority <= 1),
fmiscReq.size
)
require(directReq.size + fmiscReq.size <= NRFpWritePorts)
......
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import utils.{LookupTree, LookupTreeDefault, SignExt, XSDebug, ZeroExt}
import xiangshan._
import xiangshan.backend.ALUOpType
class Alu extends FunctionUnit(FuConfig(
fuType = FuType.alu,
numIntSrc = 2,
numFpSrc = 0,
writeIntRf = true,
writeFpRf = false,
hasRedirect = true
)) with HasRedirectOut {
val (src1, src2, offset, func, pc, uop) = (
io.in.bits.src(0),
io.in.bits.src(1),
io.in.bits.uop.ctrl.imm,
io.in.bits.uop.ctrl.fuOpType,
SignExt(io.in.bits.uop.cf.pc, AddrBits),
io.in.bits.uop
)
val redirectHit = uop.roqIdx.needFlush(io.redirectIn)
val valid = io.in.valid && !redirectHit
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw)
val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
val xorRes = src1 ^ src2
val sltu = !adderRes(XLEN)
val slt = xorRes(XLEN-1) ^ sltu
val shsrc1 = LookupTreeDefault(func, src1, List(
ALUOpType.srlw -> ZeroExt(src1(31,0), 64),
ALUOpType.sraw -> SignExt(src1(31,0), 64)
))
val shamt = Mux(ALUOpType.isWordOp(func), src2(4, 0), src2(5, 0))
val res = LookupTreeDefault(func(3, 0), adderRes, List(
ALUOpType.sll -> ((shsrc1 << shamt)(XLEN-1, 0)),
ALUOpType.slt -> ZeroExt(slt, XLEN),
ALUOpType.sltu -> ZeroExt(sltu, XLEN),
ALUOpType.xor -> xorRes,
ALUOpType.srl -> (shsrc1 >> shamt),
ALUOpType.or -> (src1 | src2),
ALUOpType.and -> (src1 & src2),
ALUOpType.sra -> ((shsrc1.asSInt >> shamt).asUInt)
))
val aluRes = Mux(ALUOpType.isWordOp(func), SignExt(res(31,0), 64), res)
val branchOpTable = List(
ALUOpType.getBranchType(ALUOpType.beq) -> !xorRes.orR,
ALUOpType.getBranchType(ALUOpType.blt) -> slt,
ALUOpType.getBranchType(ALUOpType.bltu) -> sltu
)
val isBranch = uop.cf.brUpdate.pd.isBr// ALUOpType.isBranch(func)
val isRVC = uop.cf.brUpdate.pd.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, pc + offset, adderRes)(VAddrBits-1,0)
val snpc = Mux(isRVC, pc + 2.U, pc + 4.U)
redirectOutValid := io.out.valid && isBranch
redirectOut.pc := uop.cf.pc
redirectOut.target := Mux(!taken && isBranch, snpc, target)
redirectOut.brTag := uop.brTag
redirectOut.isException := false.B
redirectOut.isMisPred := DontCare // check this in brq
redirectOut.isFlushPipe := false.B
redirectOut.isReplay := false.B
redirectOut.roqIdx := uop.roqIdx
brUpdate := uop.cf.brUpdate
// override brUpdate
brUpdate.pc := uop.cf.pc
brUpdate.target := Mux(!taken && isBranch, snpc, target)
brUpdate.brTarget := target
brUpdate.taken := isBranch && taken
brUpdate.brTag := uop.brTag
io.in.ready := io.out.ready
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := aluRes
XSDebug(io.in.valid || io.redirectIn.valid,
"In(%d %d) Out(%d %d) Redirect:(%d %d %d %d) brTag:f:%d v:%d\n",
io.in.valid,
io.in.ready,
io.out.valid,
io.out.ready,
io.redirectIn.valid,
io.redirectIn.bits.isException,
io.redirectIn.bits.isFlushPipe,
redirectHit,
io.redirectIn.bits.brTag.flag,
io.redirectIn.bits.brTag.value
)
XSDebug(io.in.valid,
p"src1:${Hexadecimal(src1)} src2:${Hexadecimal(src2)} " +
p"offset:${Hexadecimal(offset)} func:${Binary(func)} " +
p"pc:${Hexadecimal(pc)} roqIdx:${uop.roqIdx}\n"
)
XSDebug(io.out.valid,
p"res:${Hexadecimal(io.out.bits.data)} aluRes:${Hexadecimal(aluRes)} " +
p"isRVC:${isRVC} isBranch:${isBranch} " +
p"target:${Hexadecimal(target)} taken:${taken}\n"
)
}
......@@ -7,7 +7,6 @@ import fpu.Fflags
import utils._
import xiangshan._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
import utils.XSDebug
trait HasCSRConst {
......@@ -169,45 +168,46 @@ class PerfCounterIO extends XSBundle {
val value = Input(UInt(XLEN.W))
}
class CSRIO extends FunctionUnitIO[UInt, Null](csrCfg, len=64, extIn= FuOpType()) {
val cfIn = Input(new CtrlFlow)
val redirectOut = Output(new Redirect)
val redirectOutValid = Output(Bool())
val fpu_csr = Flipped(new FpuCsrIO)
val cfOut = Output(new CtrlFlow)
class CSR extends FunctionUnit(FuConfig(
fuType = FuType.csr,
numIntSrc = 1,
numFpSrc = 0,
writeIntRf = true,
writeFpRf = false,
hasRedirect = false
)) with HasCSRConst
{
val redirectOut = IO(Output(new Redirect))
val redirectOutValid = IO(Output(Bool()))
val fpu_csr = IO(Flipped(new FpuCsrIO))
// from rob
val exception = Flipped(ValidIO(new MicroOp))
val isInterrupt = Input(Bool())
val exception = IO(Flipped(ValidIO(new MicroOp)))
val isInterrupt = IO(Input(Bool()))
// for exception check
val instrValid = Input(Bool())
val flushPipe = Output(Bool())
// for differential testing
// val intrNO = Output(UInt(XLEN.W))
val wenFix = Output(Bool())
override def cloneType: CSRIO.this.type =
new CSRIO().asInstanceOf[this.type]
val perf = Vec(NumPerfCounters, new PerfCounterIO)
val memExceptionVAddr = Input(UInt(VAddrBits.W))
val trapTarget = Output(UInt(VAddrBits.W))
val mtip = Input(Bool())
val msip = Input(Bool())
val meip = Input(Bool())
val interrupt = Output(Bool())
val tlbCsrIO = Output(new TlbCsrBundle)
}
class CSR extends XSModule
with HasCSRConst
{
val io = IO(new CSRIO)
io.cfOut := io.cfIn
val (valid, src1, src2, func) =
(io.in.valid, io.in.bits.src(0), io.in.bits.uop.ctrl.imm, io.in.bits.ext.get)
// val intrNO = Output(UInt(XLEN.W))
val wenFix = IO(Output(Bool()))
val perf = IO(Vec(NumPerfCounters, new PerfCounterIO))
val memExceptionVAddr = IO(Input(UInt(VAddrBits.W)))
val trapTarget = IO(Output(UInt(VAddrBits.W)))
val mtip = IO(Input(Bool()))
val msip = IO(Input(Bool()))
val meip = IO(Input(Bool()))
val interrupt = IO(Output(Bool()))
val tlbCsrIO = IO(Output(new TlbCsrBundle))
val cfIn = io.in.bits.uop.cf
val cfOut = Wire(new CtrlFlow)
cfOut := cfIn
val flushPipe = Wire(Bool())
val (valid, src1, src2, func) = (
io.in.valid,
io.in.bits.src(0),
io.in.bits.uop.ctrl.imm,
io.in.bits.uop.ctrl.fuOpType
)
// CSR define
......@@ -361,7 +361,7 @@ class CSR extends XSModule
val tlbBundle = Wire(new TlbCsrBundle)
tlbBundle.satp := satp.asTypeOf(new SatpStruct)
io.tlbCsrIO := tlbBundle
tlbCsrIO := tlbBundle
// User-Level CSRs
val uepc = Reg(UInt(XLEN.W))
......@@ -505,7 +505,7 @@ class CSR extends XSModule
val addr = src2(11, 0)
val rdata = Wire(UInt(XLEN.W))
val csri = ZeroExt(io.cfIn.instr(19,15), XLEN) //unsigned imm for csri. [TODO]
val csri = ZeroExt(cfIn.instr(19,15), XLEN) //unsigned imm for csri. [TODO]
val wdata = LookupTree(func, List(
CSROpType.wrt -> src1,
CSROpType.set -> (rdata | src1),
......@@ -526,6 +526,8 @@ class CSR extends XSModule
MaskedRegMap.generate(mapping, addr, rdata, wen && permitted, wdata)
io.out.bits.data := rdata
io.out.bits.uop := io.in.bits.uop
io.out.bits.uop.cf := cfOut
io.out.bits.uop.ctrl.flushPipe := flushPipe
// Fix Mip/Sip write
val fixMapping = Map(
......@@ -535,17 +537,17 @@ class CSR extends XSModule
val rdataDummy = Wire(UInt(XLEN.W))
MaskedRegMap.generate(fixMapping, addr, rdataDummy, wen, wdata)
when(io.fpu_csr.fflags.asUInt() =/= 0.U){
fcsr := fflags_wfn(io.fpu_csr.fflags.asUInt())
when(fpu_csr.fflags.asUInt() =/= 0.U){
fcsr := fflags_wfn(fpu_csr.fflags.asUInt())
}
// set fs and sd in mstatus
when(csrw_dirty_fp_state || io.fpu_csr.dirty_fs){
when(csrw_dirty_fp_state || fpu_csr.dirty_fs){
val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
mstatusNew.fs := "b11".U
mstatusNew.sd := true.B
mstatus := mstatusNew.asUInt()
}
io.fpu_csr.frm := fcsr.asTypeOf(new FcsrStruct).frm
fpu_csr.frm := fcsr.asTypeOf(new FcsrStruct).frm
// CSR inst decode
val isEbreak = addr === privEbreak && func === CSROpType.jmp
......@@ -554,8 +556,8 @@ class CSR extends XSModule
val isSret = addr === privSret && func === CSROpType.jmp
val isUret = addr === privUret && func === CSROpType.jmp
XSDebug(wen, "csr write: pc %x addr %x rdata %x wdata %x func %x\n", io.cfIn.pc, addr, rdata, wdata, func)
XSDebug(wen, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", io.cfIn.pc, mstatus, mideleg , medeleg, priviledgeMode)
XSDebug(wen, "csr write: pc %x addr %x rdata %x wdata %x func %x\n", cfIn.pc, addr, rdata, wdata, func)
XSDebug(wen, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", cfIn.pc, mstatus, mideleg , medeleg, priviledgeMode)
// Illegal priviledged operation list
val illegalSModeSret = valid && isSret && priviledgeMode === ModeS && mstatusStruct.tsr.asBool
......@@ -594,21 +596,21 @@ class CSR extends XSModule
tlbBundle.priv.imode := priviledgeMode
tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
val hasInstrPageFault = io.exception.bits.cf.exceptionVec(instrPageFault) && io.exception.valid
val hasLoadPageFault = io.exception.bits.cf.exceptionVec(loadPageFault) && io.exception.valid
val hasStorePageFault = io.exception.bits.cf.exceptionVec(storePageFault) && io.exception.valid
val hasStoreAddrMisaligned = io.exception.bits.cf.exceptionVec(storeAddrMisaligned) && io.exception.valid
val hasLoadAddrMisaligned = io.exception.bits.cf.exceptionVec(loadAddrMisaligned) && io.exception.valid
val hasInstrPageFault = exception.bits.cf.exceptionVec(instrPageFault) && exception.valid
val hasLoadPageFault = exception.bits.cf.exceptionVec(loadPageFault) && exception.valid
val hasStorePageFault = exception.bits.cf.exceptionVec(storePageFault) && exception.valid
val hasStoreAddrMisaligned = exception.bits.cf.exceptionVec(storeAddrMisaligned) && exception.valid
val hasLoadAddrMisaligned = exception.bits.cf.exceptionVec(loadAddrMisaligned) && exception.valid
// mtval write logic
val memExceptionAddr = SignExt(io.memExceptionVAddr, XLEN)
val memExceptionAddr = SignExt(memExceptionVAddr, XLEN)
when(hasInstrPageFault || hasLoadPageFault || hasStorePageFault){
val tval = Mux(
hasInstrPageFault,
Mux(
io.exception.bits.cf.crossPageIPFFix,
SignExt(io.exception.bits.cf.pc + 2.U, XLEN),
SignExt(io.exception.bits.cf.pc, XLEN)
exception.bits.cf.crossPageIPFFix,
SignExt(exception.bits.cf.pc + 2.U, XLEN),
SignExt(exception.bits.cf.pc, XLEN)
),
memExceptionAddr
)
......@@ -636,14 +638,14 @@ class CSR extends XSModule
intrVecEnable.zip(ideleg.asBools).map{case(x,y) => x := priviledgedEnableDetect(y)}
val intrVec = mie(11,0) & mip.asUInt & intrVecEnable.asUInt
val intrBitSet = intrVec.orR()
io.interrupt := intrBitSet
interrupt := intrBitSet
val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum))
val raiseIntr = intrBitSet && io.exception.valid && io.isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", io.exception.bits.cf.pc, intrNO)
val raiseIntr = intrBitSet && exception.valid && isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", exception.bits.cf.pc, intrNO)
mipWire.t.m := io.mtip
mipWire.s.m := io.msip
mipWire.e.m := io.meip
mipWire.t.m := mtip
mipWire.s.m := msip
mipWire.e.m := meip
// exceptions
val csrExceptionVec = Wire(Vec(16, Bool()))
......@@ -658,30 +660,43 @@ class CSR extends XSModule
csrExceptionVec(illegalInstr) := (isIllegalAddr || isIllegalAccess) && wen
csrExceptionVec(loadPageFault) := hasLoadPageFault
csrExceptionVec(storePageFault) := hasStorePageFault
val iduExceptionVec = io.cfIn.exceptionVec
val iduExceptionVec = cfIn.exceptionVec
val exceptionVec = csrExceptionVec.asUInt() | iduExceptionVec.asUInt()
io.cfOut.exceptionVec.zipWithIndex.map{case (e, i) => e := exceptionVec(i) }
io.wenFix := DontCare
cfOut.exceptionVec.zipWithIndex.map{case (e, i) => e := exceptionVec(i) }
wenFix := DontCare
val raiseExceptionVec = io.exception.bits.cf.exceptionVec.asUInt()
val raiseExceptionVec = exception.bits.cf.exceptionVec.asUInt()
val exceptionNO = ExcPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(raiseExceptionVec(i), i.U, sum))
val causeNO = (raiseIntr << (XLEN-1)).asUInt() | Mux(raiseIntr, intrNO, exceptionNO)
val difftestIntrNO = Mux(raiseIntr, causeNO, 0.U)
ExcitingUtils.addSource(difftestIntrNO, "difftestIntrNOfromCSR")
ExcitingUtils.addSource(causeNO, "difftestCausefromCSR")
val raiseExceptionIntr = io.exception.valid
val raiseExceptionIntr = exception.valid
val retTarget = Wire(UInt(VAddrBits.W))
val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
io.redirectOut := DontCare
io.redirectOutValid := valid && func === CSROpType.jmp && !isEcall
io.redirectOut.target := retTarget
io.flushPipe := resetSatp
XSDebug(io.redirectOutValid, "redirect to %x, pc=%x\n", io.redirectOut.target, io.cfIn.pc)
XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n",io.exception.bits.cf.pc, intrNO, io.exception.bits.cf.intrVec.asUInt, exceptionNO, raiseExceptionVec.asUInt)
XSDebug(raiseExceptionIntr, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", io.exception.bits.cf.pc, mstatus, mideleg, medeleg, priviledgeMode)
redirectOut := DontCare
redirectOutValid := valid && func === CSROpType.jmp && !isEcall
redirectOut.target := retTarget
flushPipe := resetSatp
XSDebug(redirectOutValid, "redirect to %x, pc=%x\n", redirectOut.target, cfIn.pc)
XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n",
exception.bits.cf.pc,
intrNO,
exception.bits.cf.intrVec.asUInt,
exceptionNO,
raiseExceptionVec.asUInt
)
XSDebug(raiseExceptionIntr,
"pc %x mstatus %x mideleg %x medeleg %x mode %x\n",
exception.bits.cf.pc,
mstatus,
mideleg,
medeleg,
priviledgeMode
)
// Branch control
......@@ -690,7 +705,7 @@ class CSR extends XSModule
val delegS = (deleg(causeNO(3,0))) && (priviledgeMode < ModeM)
val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check
io.trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
retTarget := DontCare
// val illegalEret = TODO
......@@ -737,7 +752,7 @@ class CSR extends XSModule
when (delegS) {
scause := causeNO
sepc := SignExt(io.exception.bits.cf.pc, XLEN)
sepc := SignExt(exception.bits.cf.pc, XLEN)
mstatusNew.spp := priviledgeMode
mstatusNew.pie.s := mstatusOld.ie.s
mstatusNew.ie.s := false.B
......@@ -746,7 +761,7 @@ class CSR extends XSModule
// trapTarget := stvec(VAddrBits-1. 0)
}.otherwise {
mcause := causeNO
mepc := SignExt(io.exception.bits.cf.pc, XLEN)
mepc := SignExt(exception.bits.cf.pc, XLEN)
mstatusNew.mpp := priviledgeMode
mstatusNew.pie.m := mstatusOld.ie.m
mstatusNew.ie.m := false.B
......@@ -762,11 +777,32 @@ class CSR extends XSModule
io.out.valid := valid
XSDebug(io.redirectOutValid, "Rediret %x raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d instrValid:%x \n",
io.redirectOut.target, raiseExceptionIntr, isSret, retTarget, sepc, delegS, deleg, io.cfIn.pc, valid, io.instrValid)
XSDebug(raiseExceptionIntr && delegS, "Red(%d, %x) raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d instrValid:%x \n",
io.redirectOutValid, io.redirectOut.target, raiseExceptionIntr, isSret, retTarget, sepc, delegS, deleg, io.cfIn.pc, valid, io.instrValid)
XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", io.cfIn.pc)
XSDebug(redirectOutValid,
"Rediret %x raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d\n",
redirectOut.target,
raiseExceptionIntr,
isSret,
retTarget,
sepc,
delegS,
deleg,
cfIn.pc,
valid
)
XSDebug(raiseExceptionIntr && delegS,
"Red(%d, %x) raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d\n",
redirectOutValid,
redirectOut.target,
raiseExceptionIntr,
isSret,
retTarget,
sepc,
delegS,
deleg,
cfIn.pc,
valid
)
XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc)
// perfcnt
......
......@@ -4,11 +4,14 @@ import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Divider(len: Int) extends FunctionUnit(
FuConfig(FuType.div, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false, UncertainLatency()),
len
) {
class Divider(len: Int) extends FunctionUnit(divCfg, 64, extIn = new MulDivCtrl) {
val ctrl = IO(Input(new MulDivCtrl))
val sign = ctrl.sign
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
......@@ -27,8 +30,6 @@ class Divider(len: Int) extends FunctionUnit(divCfg, 64, extIn = new MulDivCtrl)
val hi = shiftReg(len * 2, len)
val lo = shiftReg(len - 1, 0)
val ctrl = io.in.bits.ext.get
val sign = io.in.bits.ext.get.sign
val uop = io.in.bits.uop
val (aSign, aVal) = abs(a, sign)
......
package xiangshan.backend.exu
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.FenceOpType
class FenceToSbuffer extends XSBundle {
......@@ -12,14 +11,22 @@ class FenceToSbuffer extends XSBundle {
val sbIsEmpty = Input(Bool())
}
class FenceExeUnit extends Exu(Exu.fenceExeUnitCfg) {
class Fence extends FunctionUnit(FuConfig(
FuType.fence, 1, 0, writeIntRf = false, writeFpRf = false, hasRedirect = false
)){
val sfence = IO(Output(new SfenceBundle))
val fencei = IO(Output(Bool()))
val toSbuffer = IO(new FenceToSbuffer)
val (valid, src1, src2, uop, func, lsrc1, lsrc2) =
(io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType, io.in.bits.uop.ctrl.lsrc1, io.in.bits.uop.ctrl.lsrc2)
val (valid, src1, uop, func, lsrc1, lsrc2) = (
io.in.valid,
io.in.bits.src(0),
io.in.bits.uop,
io.in.bits.uop.ctrl.fuOpType,
io.in.bits.uop.ctrl.lsrc1,
io.in.bits.uop.ctrl.lsrc2
)
val s_sb :: s_tlb :: s_icache :: s_none :: Nil = Enum(4)
val state = RegInit(s_sb)
......@@ -45,10 +52,6 @@ class FenceExeUnit extends Exu(Exu.fenceExeUnitCfg) {
io.out.valid := (state =/= s_sb && sbEmpty) || (state === s_sb && sbEmpty && valid)
io.out.bits.data := DontCare
io.out.bits.uop := Mux(state === s_sb, uop, RegEnable(uop, io.in.fire()))
io.out.bits.redirect <> DontCare
io.out.bits.redirectValid := false.B
io.out.bits.debug <> DontCare
io.csrOnly <> DontCare
assert(!(valid || state =/= s_sb) || io.out.ready) // NOTE: fence instr must be the first(only one) instr, so io.out.ready must be true
......
......@@ -3,6 +3,9 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.fu.fpu.divsqrt.DivSqrt
import xiangshan.backend.fu.fpu._
import xiangshan.backend.fu.fpu.fma.FMA
/*
XiangShan Function Unit
......@@ -21,10 +24,6 @@ case class UncertainLatency() extends HasFuLatency {
override val latencyVal: Option[Int] = None
}
case class NexusLatency(value: Int) extends HasFuLatency {
override val latencyVal: Option[Int] = Some(value)
}
case class FuConfig
......@@ -40,18 +39,23 @@ case class FuConfig
def srcCnt: Int = math.max(numIntSrc, numFpSrc)
}
class FuOutput extends XSBundle {
val data = UInt(XLEN.W)
val uop = new MicroOp
}
class FunctionUnitIO[TI <: Data, TO <: Data]
(
cfg: FuConfig,
len: Int,
extIn: => TI = null,
extOut: => TO = null
len: Int
) extends XSBundle
{
val in = Flipped(DecoupledIO(new Bundle() {
val src = Vec(cfg.srcCnt, UInt(len.W))
val uop = new MicroOp
val ext = if(extIn == null) None else Some(extIn.cloneType)
def connectToExuInput(exuIn: ExuInput): Unit = {
val exuSrcIn = Seq(exuIn.src1, exuIn.src2, exuIn.src3)
......@@ -60,33 +64,28 @@ class FunctionUnitIO[TI <: Data, TO <: Data]
}
}))
val out = DecoupledIO(new Bundle() {
val data = UInt(XLEN.W)
val uop = new MicroOp
val ext = if(extOut == null) None else Some(extOut.cloneType)
})
val out = DecoupledIO(new FuOutput)
val redirectIn = Flipped(ValidIO(new Redirect))
override def cloneType: FunctionUnitIO.this.type =
new FunctionUnitIO(cfg, len, extIn, extOut).asInstanceOf[this.type]
new FunctionUnitIO(cfg, len).asInstanceOf[this.type]
}
abstract class FunctionUnit[TI <: Data, TO <: Data]
abstract class FunctionUnit
(
cfg: FuConfig,
len: Int = 64,
extIn: => TI = null,
extOut: => TO = null,
val latency: Int = 0
val cfg: FuConfig,
val len: Int = 64
) extends XSModule {
val io = IO(new FunctionUnitIO[TI, TO](cfg, len, extIn, extOut))
val io = IO(new FunctionUnitIO(cfg, len))
}
trait HasPipelineReg[TI <: Data, TO <: Data] {
this: FunctionUnit[TI, TO] =>
trait HasPipelineReg { this: FunctionUnit =>
require(cfg.latency.latencyVal.nonEmpty && cfg.latency.latencyVal.get > 0)
val latency = cfg.latency.latencyVal.get
val validVec = io.in.valid +: Array.fill(latency)(RegInit(false.B))
val rdyVec = Array.fill(latency)(Wire(Bool())) :+ io.out.ready
......@@ -128,32 +127,28 @@ trait HasPipelineReg[TI <: Data, TO <: Data] {
def S5Reg[TT <: Data](next: TT): TT = PipelineReg[TT](5)(next)
}
object FunctionUnit {
val csrCfg =
FuConfig(FuType.csr, 1, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false)
val jmpCfg =
FuConfig(FuType.jmp, 1, 0, writeIntRf = true, writeFpRf = false, hasRedirect = true)
object FunctionUnit extends HasXSParameter {
val i2fCfg =
FuConfig(FuType.i2f, 1, 0, writeIntRf = false, writeFpRf = true, hasRedirect = false)
def multiplier = new ArrayMultiplier(XLEN+1)
def divider = new Divider(XLEN)
def alu = new Alu
val aluCfg =
FuConfig(FuType.alu, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = true)
def jmp = new Jump
def fence = new Fence
def csr = new CSR
def i2f = new IntToFloatSingleCycle
val mulCfg =
FuConfig(FuType.mul, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false,
UncertainLatency()// CertainLatency(3)
)
val divCfg =
FuConfig(FuType.div, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false,
UncertainLatency()
)
def fmac = new FMA
def fcmp = new FCMP
def fmv = new FMV(XLEN)
def f2i = new FloatToInt
def f32toF64 = new F32toF64
def f64toF32 = new F64toF32
def fdivSqrt = new DivSqrt
val fenceCfg =
FuConfig(FuType.fence, 2, 0, writeIntRf = false, writeFpRf = false, hasRedirect = false/*NOTE: need redirect but when commit*/)
def fmiscSel(fu: String)(x: FPUSubModule): Bool = {
x.io.in.bits.uop.ctrl.fuOpType.head(4) === s"b$fu".U
}
val lduCfg =
FuConfig(FuType.ldu, 1, 0, writeIntRf = true, writeFpRf = true, hasRedirect = false,
......@@ -169,19 +164,4 @@ object FunctionUnit {
FuConfig(FuType.mou, 2, 0, writeIntRf = false, writeFpRf = false, hasRedirect = false,
UncertainLatency()
)
val fmacCfg =
FuConfig(FuType.fmac, 0, 3, writeIntRf = false, writeFpRf = true, hasRedirect = false,
CertainLatency(5)
)
val fmiscCfg =
FuConfig(FuType.fmisc, 0, 2, writeIntRf = true, writeFpRf = true, hasRedirect = false,
UncertainLatency()
)
val fDivSqrtCfg =
FuConfig(FuType.fDivSqrt, 0, 2, writeIntRf = false, writeFpRf = true, hasRedirect = false,
UncertainLatency()
)
}
......@@ -8,16 +8,17 @@ import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.backend.decode.isa._
class RedirectOut extends XSBundle {
val redirectValid = Bool()
val redirect = new Redirect
val brUpdate = new BranchUpdateInfo
trait HasRedirectOut { this: RawModule =>
val redirectOutValid = IO(Output(Bool()))
val redirectOut = IO(Output(new Redirect))
val brUpdate = IO(Output(new BranchUpdateInfo))
}
class Jump extends FunctionUnit(jmpCfg, extOut = new RedirectOut) {
class Jump extends FunctionUnit(
FuConfig(FuType.jmp, 1, 0, writeIntRf = true, writeFpRf = false, hasRedirect = true)
) with HasRedirectOut {
val (iovalid, src1, offset, func, pc, uop) = (
io.in.valid,
val (src1, offset, func, pc, uop) = (
io.in.bits.src(0),
io.in.bits.uop.ctrl.imm,
io.in.bits.uop.ctrl.fuOpType,
......@@ -26,16 +27,13 @@ class Jump extends FunctionUnit(jmpCfg, extOut = new RedirectOut) {
)
val redirectHit = uop.roqIdx.needFlush(io.redirectIn)
val valid = iovalid && !redirectHit
val valid = io.in.valid && !redirectHit
val isRVC = uop.cf.brUpdate.pd.isRVC
val pcDelaySlot = Mux(isRVC, pc + 2.U, pc + 4.U)
val snpc = Mux(isRVC, pc + 2.U, pc + 4.U)
val target = src1 + offset // NOTE: src1 is (pc/rf(rs1)), src2 is (offset)
val redirectOut = io.out.bits.ext.get.redirect
val brUpdate = io.out.bits.ext.get.brUpdate
io.out.bits.ext.get.redirectValid := valid
redirectOutValid := valid
redirectOut.pc := uop.cf.pc
redirectOut.target := target
redirectOut.brTag := uop.brTag
......@@ -50,13 +48,12 @@ class Jump extends FunctionUnit(jmpCfg, extOut = new RedirectOut) {
brUpdate.target := target
brUpdate.brTarget := target // DontCare
brUpdate.taken := true.B
// io.out.bits.brUpdate.fetchIdx := uop.cf.brUpdate.fetchOffset >> 1.U //TODO: consider RVC
// Output
val res = pcDelaySlot
val res = snpc
io.in.ready := io.out.ready
io.out.valid := valid // TODO: CSR/MOU/FMV may need change it
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := res
......
......@@ -13,42 +13,21 @@ class MulDivCtrl extends Bundle{
val isHi = Bool() // return hi bits of result ?
}
class MulDivOutput extends XSBundle {
val data = UInt(XLEN.W)
val uop = new MicroOp
}
class MulDivIO(val len: Int) extends XSBundle {
val in = Flipped(DecoupledIO(new Bundle() {
val src1, src2 = UInt(len.W)
val ctrl = new MulDivCtrl
}))
val out = DecoupledIO(new MulDivOutput)
val redirect = Flipped(ValidIO(new Redirect))
}
abstract class Multiplier
(
val len: Int,
latency: Int = 3
) extends FunctionUnit(cfg = mulCfg, len, extIn = new MulDivCtrl, latency = latency)
with HasPipelineReg[MulDivCtrl, Null]
class ArrayMultiplier(len: Int, latency: Int = 3)
extends FunctionUnit(
FuConfig(FuType.mul, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false, CertainLatency(latency)),
len
)
with HasPipelineReg
{
val ctrl = IO(Input(new MulDivCtrl))
val (src1, src2) = (io.in.bits.src(0), io.in.bits.src(1))
}
class ArrayMultiplier
(
len: Int,
latency: Int = 3,
realArray: Boolean = false
) extends Multiplier(len, latency) {
val mulRes = src1.asSInt() * src2.asSInt()
var dataVec = Seq(mulRes.asUInt())
var ctrlVec = Seq(io.in.bits.ext.get)
var ctrlVec = Seq(ctrl)
for(i <- 1 to latency){
dataVec = dataVec :+ PipelineReg(i)(dataVec(i-1))
......@@ -59,8 +38,5 @@ class ArrayMultiplier
val res = Mux(ctrlVec.last.isHi, dataVec.last(2*xlen-1, xlen), dataVec.last(xlen-1,0))
io.out.bits.data := Mux(ctrlVec.last.isW, SignExt(res(31,0),xlen), res)
XSDebug(p"validVec:${Binary(Cat(validVec))} flushVec:${Binary(Cat(flushVec))}\n")(this.name)
// printf(p"t=${GTimer()} in: v${io.in.valid} r:${io.in.ready}\n")
// printf(p"t=${GTimer()} out: v:${io.out.valid} r:${io.out.ready} vec:${Binary(Cat(validVec))}\n")
XSDebug(p"validVec:${Binary(Cat(validVec))} flushVec:${Binary(Cat(flushVec))}\n")
}
\ No newline at end of file
......@@ -2,9 +2,13 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.FunctionUnit._
class F32toF64 extends FPUPipelineModule(fmiscCfg, 2) {
class F32toF64 extends FPUPipelineModule(
FuConfig(FuType.fmisc, 0, 1, writeIntRf = false, writeFpRf = true, hasRedirect = false, CertainLatency(2))
) {
val a = io.in.bits.src(0)
val f32 = Float32(a)
......
......@@ -2,10 +2,13 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.backend.fu.FunctionUnit.fmiscCfg
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.fpu.util.ShiftRightJam
class F64toF32 extends FPUPipelineModule(fmiscCfg, 2) {
class F64toF32 extends FPUPipelineModule(
FuConfig(FuType.fmisc, 0, 1, writeIntRf = false, writeFpRf = true, hasRedirect = false, CertainLatency(2))
){
def SEXP_WIDTH = Float64.expWidth + 2
val a = io.in.bits.src(0)
......
......@@ -2,9 +2,13 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.FunctionUnit._
class FCMP extends FPUPipelineModule(fmiscCfg, 2){
class FCMP extends FPUPipelineModule(
FuConfig(FuType.fmisc, 0, 2, writeIntRf = true, writeFpRf = false, hasRedirect = false, CertainLatency(2))
){
val src = io.in.bits.src.map(x => Mux(isDouble, x, extF32ToF64(x)))
val sign = src.map(_(63))
......
......@@ -2,9 +2,12 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
class FMV(XLEN: Int) extends FPUPipelineModule(fmiscCfg, 1) {
class FMV(XLEN: Int) extends FPUPipelineModule(
FuConfig(FuType.fmisc, 0, 2, writeIntRf = true, writeFpRf = true, hasRedirect = false, CertainLatency(1))
) {
val src = io.in.bits.src.map(x =>
Mux(isDouble || op(2,1)==="b00".U, x, extF32ToF64(x))
......
......@@ -22,63 +22,27 @@ class FPUSubModuleIO extends Bundle{
val out = DecoupledIO(new FPUSubModuleOutput)
}
//trait HasPipelineReg { this: FPUSubModule =>
// def latency: Int
//
// val ready = Wire(Bool())
// val cnt = RegInit(0.U((log2Up(latency)+1).W))
//
// ready := (cnt < latency.U) || (cnt === latency.U && io.out.ready)
// cnt := cnt + io.in.fire() - io.out.fire()
//
// val valids = io.in.valid +: Array.fill(latency)(RegInit(false.B))
// for(i <- 1 to latency){
// when(ready){ valids(i) := valids(i-1) }
// }
//
// def PipelineReg[T<:Data](i: Int)(next: T) = RegEnable(next, enable = valids(i-1) && ready)
// def S1Reg[T<:Data](next: T):T = PipelineReg[T](1)(next)
// def S2Reg[T<:Data](next: T):T = PipelineReg[T](2)(next)
// def S3Reg[T<:Data](next: T):T = PipelineReg[T](3)(next)
// def S4Reg[T<:Data](next: T):T = PipelineReg[T](4)(next)
// def S5Reg[T<:Data](next: T):T = PipelineReg[T](5)(next)
//
// io.in.ready := ready
// io.out.valid := valids.last
//}
trait HasUIntToSIntHelper {
implicit class UIntToSIntHelper(x: UInt){
def toSInt: SInt = Cat(0.U(1.W), x).asSInt()
}
}
//abstract class FPUSubModule extends Module with HasUIntToSIntHelper {
// val io = IO(new FPUSubModuleIO)
//}
class FPUExtraInput extends Bundle {
val op = UInt(3.W)
val isDouble = Bool()
val rm = UInt(3.W)
}
trait HasFPUSigs { this: FPUSubModule =>
val extraIn = io.in.bits.ext.get
val op = extraIn.op
val isDouble = extraIn.isDouble
val rm = extraIn.rm
val fflags = io.out.bits.ext.get
val op = io.in.bits.uop.ctrl.fuOpType(2, 0)
// 'op' must change with fuOpType
require(io.in.bits.uop.ctrl.fuOpType.getWidth == 7)
val isDouble = !io.in.bits.uop.ctrl.isRVF
}
abstract class FPUSubModule(cfg: FuConfig, latency: Int = 0) extends FunctionUnit(
cfg,
latency = latency,
extIn = new FPUExtraInput,
extOut = new Fflags
) with HasUIntToSIntHelper
abstract class FPUSubModule(cfg: FuConfig) extends FunctionUnit(cfg)
with HasUIntToSIntHelper
with HasFPUSigs
{
val rm = IO(Input(UInt(3.W)))
val fflags = IO(Output(new Fflags))
}
abstract class FPUPipelineModule(cfg: FuConfig, latency: Int)
extends FPUSubModule(cfg, latency)
with HasPipelineReg[FPUExtraInput, Fflags]
\ No newline at end of file
abstract class FPUPipelineModule(cfg: FuConfig)
extends FPUSubModule(cfg)
with HasPipelineReg
\ No newline at end of file
......@@ -2,15 +2,18 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.fpu.util.{ORTree, ShiftRightJam}
import xiangshan.backend.fu.FunctionUnit._
//def f2w:UInt = FpuOp("011", "000")
//def f2wu:UInt = FpuOp("011", "001")
//def f2l:UInt = FpuOp("011", "010")
//def f2lu:UInt = FpuOp("011", "011")
class FloatToInt extends FPUPipelineModule(fmiscCfg, 2) {
class FloatToInt extends FPUPipelineModule(
FuConfig(FuType.fmisc, 0, 1, writeIntRf = true, writeFpRf = false, hasRedirect = false, CertainLatency(2))
){
def SEXP_WIDTH = Float64.expWidth + 2
......
......@@ -2,10 +2,13 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.fpu.util.ORTree
import xiangshan.backend.fu.FunctionUnit.i2fCfg
class IntToFloat extends FPUPipelineModule(i2fCfg, 2) {
class IntToFloat extends FPUPipelineModule(
FuConfig(FuType.i2f, 1, 0, writeIntRf = false, writeFpRf = true, hasRedirect = false, CertainLatency(2))
) {
/** Stage 1: Count leading zeros and shift
*/
......
......@@ -2,10 +2,13 @@ package xiangshan.backend.fu.fpu
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.fpu.util.ORTree
import xiangshan.backend.fu.FunctionUnit.i2fCfg
class IntToFloatSingleCycle extends FPUSubModule(cfg = i2fCfg) {
class IntToFloatSingleCycle extends FPUSubModule(
FuConfig(FuType.i2f, 1, 0, writeIntRf = false, writeFpRf = true, hasRedirect = false, CertainLatency(0))
) {
val a = io.in.bits.src(0)
val aNeg = (~a).asUInt()
......
......@@ -3,10 +3,13 @@ package xiangshan.backend.fu.fpu.divsqrt
import xiangshan.backend.fu.fpu._
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{FuConfig, UncertainLatency}
import xiangshan.backend.fu.fpu.util.{FPUDebug, ORTree, ShiftRightJam}
import xiangshan.backend.fu.FunctionUnit.fDivSqrtCfg
class DivSqrt extends FPUSubModule(fDivSqrtCfg) {
class DivSqrt extends FPUSubModule(
FuConfig(FuType.fDivSqrt, 0, 2, writeIntRf = false, writeFpRf = true, hasRedirect = false, UncertainLatency())
) {
def SEXP_WIDTH: Int = Float64.expWidth + 2
def D_MANT_WIDTH: Int = Float64.mantWidth + 1
......@@ -18,6 +21,7 @@ class DivSqrt extends FPUSubModule(fDivSqrtCfg) {
val uopReg = RegEnable(io.in.bits.uop, io.in.fire())
val kill = uopReg.roqIdx.needFlush(io.redirectIn)
val rmReg = RegEnable(rm, io.in.fire())
val isDiv = !op(0)
val isDivReg = RegEnable(isDiv, io.in.fire())
......@@ -236,9 +240,12 @@ class DivSqrt extends FPUSubModule(fDivSqrtCfg) {
state := s_finish
}
is(s_finish){
state := s_idle
when(io.out.fire()){
state := s_idle
}
}
}
when(kill){ state := s_idle }
switch(state){
is(s_idle){
......@@ -281,7 +288,7 @@ class DivSqrt extends FPUSubModule(fDivSqrtCfg) {
)
io.in.ready := (state === s_idle) && io.out.ready
io.out.valid := state === s_finish
io.out.valid := (state === s_finish) && !kill
io.out.bits.data := Mux(specialCaseHappenReg,
specialResult,
Mux(overflowReg,
......
......@@ -2,12 +2,15 @@ package xiangshan.backend.fu.fpu.fma
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.fu.{CertainLatency, FuConfig}
import xiangshan.backend.fu.fpu._
import xiangshan.backend.fu.fpu.util.{CSA3_2, FPUDebug, ORTree, ShiftLeftJam, ShiftRightJam}
import xiangshan.backend.fu.FunctionUnit.fmacCfg
class FMA extends FPUPipelineModule(fmacCfg, 5) {
class FMA extends FPUPipelineModule(
FuConfig(FuType.fmac, 0, 3, writeIntRf = false, writeFpRf = true, hasRedirect = false, CertainLatency(5))
) {
def UseRealArraryMult = false
......
package xiangshan.backend.issue
import chisel3.{util, _}
import chisel3.util._
import utils.{ParallelMux, ParallelOR, PriorityEncoderWithFlag, XSDebug, XSInfo}
import xiangshan._
import xiangshan.backend.exu.{Exu, ExuConfig}
import xiangshan.backend.regfile.RfReadPort
class IssueQueue
(
val exuCfg: ExuConfig,
val wakeupCnt: Int,
val bypassCnt: Int = 0
) extends XSModule with HasIQConst {
val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
val enq = Flipped(DecoupledIO(new MicroOp))
val readIntRf = Vec(exuCfg.intSrcCnt, Flipped(new RfReadPort))
val readFpRf = Vec(exuCfg.fpSrcCnt, Flipped(new RfReadPort))
val deq = DecoupledIO(new ExuInput)
val wakeUpPorts = Vec(wakeupCnt, Flipped(ValidIO(new ExuOutput)))
val bypassUops = Vec(bypassCnt, Flipped(ValidIO(new MicroOp)))
val bypassData = Vec(bypassCnt, Flipped(ValidIO(new ExuOutput)))
val numExist = Output(UInt(iqIdxWidth.W))
// tlb hit, inst can deq
val tlbFeedback = Flipped(ValidIO(new TlbFeedback))
})
def qsize: Int = IssQueSize
def idxWidth = log2Up(qsize)
def replayDelay = 16
require(isPow2(qsize))
val tlbHit = io.tlbFeedback.valid && io.tlbFeedback.bits.hit
val tlbMiss = io.tlbFeedback.valid && !io.tlbFeedback.bits.hit
XSDebug(io.tlbFeedback.valid,
"tlb feedback: hit: %d roqIdx: %d\n",
io.tlbFeedback.bits.hit,
io.tlbFeedback.bits.roqIdx.asUInt
)
/*
invalid --[enq]--> valid --[deq]--> wait --[tlbHit]--> invalid
wait --[replay]--> replay --[cnt]--> valid
*/
val s_invalid :: s_valid :: s_wait :: s_replay :: Nil = Enum(4)
val idxQueue = RegInit(VecInit((0 until qsize).map(_.U(idxWidth.W))))
val stateQueue = RegInit(VecInit(Seq.fill(qsize)(s_invalid)))
val readyVec = Wire(Vec(qsize, Bool()))
val uopQueue = Reg(Vec(qsize, new MicroOp))
val cntQueue = Reg(Vec(qsize, UInt(log2Up(replayDelay).W)))
val tailPtr = RegInit(0.U((idxWidth+1).W))
// real deq
/*
example: realDeqIdx = 2 | realDeqIdx=0
moveMask = 11111100 | moveMask=11111111
*/
val (firstBubble, findBubble) = PriorityEncoderWithFlag(stateQueue.map(_ === s_invalid))
val realDeqIdx = firstBubble
val realDeqValid = (firstBubble < tailPtr) && findBubble
val moveMask = {
(Fill(qsize, 1.U(1.W)) << realDeqIdx)(qsize-1, 0)
} & Fill(qsize, realDeqValid)
for(i <- 0 until qsize-1){
when(moveMask(i)){
idxQueue(i) := idxQueue(i+1)
stateQueue(i) := stateQueue(i+1)
}
}
when(realDeqValid){
idxQueue.last := idxQueue(realDeqIdx)
stateQueue.last := s_invalid
}
// wake up
def getSrcSeq(uop: MicroOp): Seq[UInt] = Seq(uop.psrc1, uop.psrc2, uop.psrc3)
def getSrcTypeSeq(uop: MicroOp): Seq[UInt] = Seq(
uop.ctrl.src1Type, uop.ctrl.src2Type, uop.ctrl.src3Type
)
def getSrcStateSeq(uop: MicroOp): Seq[UInt] = Seq(
uop.src1State, uop.src2State, uop.src3State
)
def writeBackHit(src: UInt, srcType: UInt, wbUop: (Bool, MicroOp)): Bool = {
val (v, uop) = wbUop
val isSameType =
(SrcType.isReg(srcType) && uop.ctrl.rfWen && src =/= 0.U) || (SrcType.isFp(srcType) && uop.ctrl.fpWen)
v && isSameType && (src===uop.pdest)
}
//TODO: opt this, do bypass select in 'select' stage not 'issue' stage
val bypassData = RegNext(io.bypassData)
def doBypass(src: UInt, srcType: UInt): (Bool, UInt) = {
val hitVec = bypassData.map(p => (p.valid, p.bits.uop)).
map(wbUop => writeBackHit(src, srcType, wbUop))
val data = ParallelMux(hitVec.zip(bypassData.map(_.bits.data)))
(ParallelOR(hitVec).asBool(), data)
}
def wakeUp(uop: MicroOp): MicroOp = {
def getNewSrcState(i: Int): UInt = {
val src = getSrcSeq(uop)(i)
val srcType = getSrcTypeSeq(uop)(i)
val srcState = getSrcStateSeq(uop)(i)
val hitVec = (
io.wakeUpPorts.map(w => (w.valid, w.bits.uop)) ++
io.bypassUops.map(p => (p.valid, p.bits))
).map(wbUop => writeBackHit(src, srcType, wbUop))
val hit = ParallelOR(hitVec).asBool()
Mux(hit, SrcState.rdy, srcState)
}
val new_uop = WireInit(uop)
new_uop.src1State := getNewSrcState(0)
if(exuCfg==Exu.stExeUnitCfg) new_uop.src2State := getNewSrcState(1)
new_uop
}
def uopIsRdy(uop: MicroOp): Bool = {
def srcIsRdy(srcType: UInt, srcState: UInt): Bool = {
SrcType.isPcImm(srcType) || srcState===SrcState.rdy
}
exuCfg match {
case Exu.ldExeUnitCfg =>
srcIsRdy(uop.ctrl.src1Type, uop.src1State)
case Exu.stExeUnitCfg =>
srcIsRdy(uop.ctrl.src1Type, uop.src1State) && srcIsRdy(uop.ctrl.src2Type, uop.src2State)
}
}
// 1. wake up
for(i <- 0 until qsize){
uopQueue(i) := wakeUp(uopQueue(i))
}
// 2. select
for(i <- 0 until qsize){
readyVec(i) := uopIsRdy(uopQueue(i))
}
val selectedIdxRegOH = Wire(UInt(qsize.W))
val selectMask = WireInit(VecInit(
(0 until qsize).map(i =>
(stateQueue(i)===s_valid) && readyVec(idxQueue(i)) && !(selectedIdxRegOH(i) && io.deq.fire())
)
))
val (selectedIdxWire, sel) = PriorityEncoderWithFlag(selectMask)
val selReg = RegNext(sel)
val selectedIdxReg = RegNext(selectedIdxWire - moveMask(selectedIdxWire))
selectedIdxRegOH := UIntToOH(selectedIdxReg)
XSDebug(
p"selMaskWire:${Binary(selectMask.asUInt())} selected:$selectedIdxWire" +
p" moveMask:${Binary(moveMask)} selectedIdxReg:$selectedIdxReg\n"
)
// read regfile
val selectedUop = uopQueue(idxQueue(selectedIdxWire))
exuCfg match {
case Exu.ldExeUnitCfg =>
io.readIntRf(0).addr := selectedUop.psrc1 // base
XSDebug(p"src1 read addr: ${io.readIntRf(0).addr}\n")
case Exu.stExeUnitCfg =>
io.readIntRf(0).addr := selectedUop.psrc1 // base
io.readIntRf(1).addr := selectedUop.psrc2 // store data (int)
io.readFpRf(0).addr := selectedUop.psrc2 // store data (fp)
XSDebug(
p"src1 read addr: ${io.readIntRf(0).addr} src2 read addr: ${io.readIntRf(1).addr}\n"
)
case _ =>
require(requirement = false, "Error: IssueQueue only support ldu and stu!")
}
// (fake) deq to Load/Store unit
io.deq.valid := (stateQueue(selectedIdxReg)===s_valid) && selReg
io.deq.bits.uop := uopQueue(idxQueue(selectedIdxReg))
val src1Bypass = doBypass(io.deq.bits.uop.psrc1, io.deq.bits.uop.ctrl.src1Type)
io.deq.bits.src1 := Mux(src1Bypass._1, src1Bypass._2, io.readIntRf(0).data)
if(exuCfg == Exu.stExeUnitCfg){
val src2Bypass = doBypass(io.deq.bits.uop.psrc2, io.deq.bits.uop.ctrl.src2Type)
io.deq.bits.src2 := Mux(src2Bypass._1,
src2Bypass._2,
Mux(SrcType.isReg(io.deq.bits.uop.ctrl.src2Type),
io.readIntRf(1).data,
io.readFpRf(0).data
)
)
} else {
io.deq.bits.src2 := DontCare
}
io.deq.bits.src3 := DontCare
when(io.deq.fire()){
stateQueue(selectedIdxReg - moveMask(selectedIdxReg)) := s_wait
assert(stateQueue(selectedIdxReg) === s_valid, "Dequeue a invalid entry to lsu!")
}
// assert(!(tailPtr===0.U && tlbHit), "Error: queue is empty but tlbHit is true!")
val tailAfterRealDeq = tailPtr - moveMask(tailPtr.tail(1))
val isFull = tailAfterRealDeq.head(1).asBool() // tailPtr===qsize.U
// enq
io.enq.ready := !isFull && !io.redirect.valid
when(io.enq.fire()){
stateQueue(tailAfterRealDeq.tail(1)) := s_valid
val uopQIdx = idxQueue(tailPtr.tail(1))
val new_uop = wakeUp(io.enq.bits)
uopQueue(uopQIdx) := new_uop
}
tailPtr := tailAfterRealDeq + io.enq.fire()
XSDebug(
realDeqValid,
p"realDeqIdx:$realDeqIdx\n"
)
XSDebug("State Dump: ")
stateQueue.reverse.foreach(s =>{
XSDebug(false, s===s_invalid, "-")
XSDebug(false, s===s_valid, "v")
XSDebug(false, s===s_wait, "w")
XSDebug(false, s===s_replay, "p")
})
XSDebug(false, true.B, "\n")
XSDebug("State Dump: ")
idxQueue.reverse.foreach(id =>{
XSDebug(false, true.B, p"$id")
})
XSDebug(false, true.B, "\n")
XSDebug("State Dump: ")
for(i <- readyVec.indices.reverse){
val r = (stateQueue(i)=/=s_invalid) && readyVec(idxQueue(i))
XSDebug(false, r, p"r")
XSDebug(false, !r, p"-")
}
XSDebug(false, true.B, "\n")
// assert(!(tlbMiss && realDeqValid), "Error: realDeqValid should be false when replay valid!")
for(i <- 0 until qsize){
val uopQIdx = idxQueue(i)
val uop = uopQueue(uopQIdx)
val cnt = cntQueue(uopQIdx)
val nextIdx = i.U - moveMask(i)
//TODO: support replay
val roqIdxMatch = uop.roqIdx.asUInt === io.tlbFeedback.bits.roqIdx.asUInt
val notEmpty = stateQueue(i)=/=s_invalid
val replayThis = (stateQueue(i)===s_wait) && tlbMiss && roqIdxMatch
val tlbHitThis = notEmpty && tlbHit && roqIdxMatch
val flushThis = notEmpty && uop.roqIdx.needFlush(io.redirect)
when(replayThis){
stateQueue(nextIdx) := s_replay
cnt := (replayDelay-1).U
}
when(stateQueue(i)===s_replay){
when(cnt === 0.U){
stateQueue(nextIdx) := s_valid
}.otherwise({
cnt := cnt - 1.U
})
}
when(flushThis || tlbHitThis){
stateQueue(nextIdx) := s_invalid
}
}
// assign outputs
io.numExist := Mux(isFull, (qsize-1).U, PopCount(stateQueue.map(_ =/= s_invalid)))
// Debug sigs
XSInfo(
io.enq.fire(),
p"enq fire: pc:${Hexadecimal(io.enq.bits.cf.pc)} roqIdx:${io.enq.bits.roqIdx} " +
p"src1: ${io.enq.bits.psrc1} state: ${io.enq.bits.src1State} " +
p"src2: ${io.enq.bits.psrc2} state: ${io.enq.bits.src2State} pdst:${io.enq.bits.pdest}\n"
)
XSInfo(
io.deq.fire(),
p"deq fire: pc:${Hexadecimal(io.deq.bits.uop.cf.pc)} roqIdx:${io.deq.bits.uop.roqIdx} " +
p"src1: ${io.deq.bits.uop.psrc1} data: ${Hexadecimal(io.deq.bits.src1)} " +
p"src2: ${io.deq.bits.uop.psrc2} data: ${Hexadecimal(io.deq.bits.src2)} " +
p"imm : ${Hexadecimal(io.deq.bits.uop.ctrl.imm)}\npdest: ${io.deq.bits.uop.pdest}\n"
)
XSDebug(p"tailPtr:$tailPtr tailAfterDeq:$tailAfterRealDeq tlbHit:$tlbHit\n")
}
......@@ -6,7 +6,7 @@ import xiangshan._
import utils._
import xiangshan.backend.roq.RoqPtr
import xiangshan.cache._
import xiangshan.backend.exu.FenceToSbuffer
import xiangshan.backend.fu.FenceToSbuffer
object genWmask {
def apply(addr: UInt, sizeEncode: UInt): UInt = {
......
package xiangshan.backend.issue
import org.scalatest._
import chiseltest._
import chisel3._
import chisel3.util._
import chisel3.experimental.BundleLiterals._
import top.Parameters
import utils.XSLog
import xiangshan._
import xiangshan.backend.exu.Exu
import xiangshan.testutils._
import scala.util.Random
class IssueQueueTest extends FlatSpec
with ChiselScalatestTester
with Matchers
with ParallelTestExecution
with HasPartialDecoupledDriver
{
it should "enq and deq correctly" in {
test(new IssueQueue(Exu.ldExeUnitCfg, 1, 1){
AddSinks()
}){ c =>
def genEnqRdyReq(x: => DecoupledIO[MicroOp], roqIdx: Long) = {
chiselTypeOf(x.bits).Lit(
_.src1State -> SrcState.rdy,
_.src2State -> SrcState.rdy,
_.src3State -> SrcState.rdy,
_.roqIdx -> roqIdx.U,
_.cf.pc -> roqIdx.U
)
}
c.io.enq.initSource().setSourceClock(c.clock)
c.io.deq.initSink().setSinkClock(c.clock)
fork {
c.io.enq.enqueuePartialSeq((0 until c.qsize).map(i => genEnqRdyReq(c.io.enq, i)))
}.fork {
// c.clock.step(10)
c.io.deq.expectDequeuePartialSeq((0 until c.qsize).map(
i => chiselTypeOf(c.io.deq.bits).Lit(
_.uop.roqIdx -> i.U,
_.uop.cf.pc -> i.U
)
))
}.join()
}
}
it should "only deq ready inst" in {
test(new IssueQueue(Exu.ldExeUnitCfg, 1, 1){
AddSinks()
}){ c =>
def genEnqRdyReq(x: => DecoupledIO[MicroOp], pc: Long, ready: Boolean) = {
chiselTypeOf(x.bits).Lit(
_.src1State -> (if(ready) SrcState.rdy else SrcState.busy),
_.src2State -> SrcState.rdy,
_.src3State -> SrcState.rdy,
_.cf.pc -> pc.U
)
}
c.io.enq.initSource().setSourceClock(c.clock)
c.io.deq.initSink().setSinkClock(c.clock)
fork {
c.io.enq.enqueuePartialSeq((0 until c.qsize).map(i => genEnqRdyReq(c.io.enq, i, i%2==0)))
}.fork {
// c.clock.step(10)
c.io.deq.expectDequeuePartialSeq((0 until c.qsize).filter(i => i%2==0).map(
i => chiselTypeOf(c.io.deq.bits).Lit(
_.uop.cf.pc -> i.U
)
))
}.join()
}
}
it should "enq and deq bubble correctly" in {
test(new IssueQueue(Exu.ldExeUnitCfg, 1, 1){
AddSinks()
}){ c =>
def genEnqRdyReq(x: => DecoupledIO[MicroOp], pc: Long) = {
chiselTypeOf(x.bits).Lit(
_.src1State -> SrcState.rdy,
_.src2State -> SrcState.rdy,
_.src3State -> SrcState.rdy,
_.cf.pc -> pc.U
)
}
c.io.enq.initSource().setSourceClock(c.clock)
c.io.deq.initSink().setSinkClock(c.clock)
def TEST_SIZE = 100
fork {
c.io.enq.enqueuePartialSeq((0 until TEST_SIZE).map(i => genEnqRdyReq(c.io.enq, i)))
}.fork {
c.io.deq.expectDequeuePartialSeq((0 until TEST_SIZE).map(
i => chiselTypeOf(c.io.deq.bits).Lit(
_.uop.cf.pc -> i.U
)
))
}.fork{
c.clock.step(10)
var cnt = 0
while (cnt != TEST_SIZE){
c.io.tlbFeedback.valid.poke(true.B)
c.io.tlbFeedback.bits.hit.poke(true.B)
c.clock.step(1)
cnt += 1
c.io.tlbFeedback.valid.poke(false.B)
c.clock.step(1 + Random.nextInt(10))
}
}.join()
}
}
}
\ No newline at end of file
package xiangshan.backend.issue
import org.scalatest._
import chiseltest._
import chisel3._
import chisel3.util._
import chisel3.experimental.BundleLiterals._
import utils.XSLog
import xiangshan._
import xiangshan.backend.exu.Exu
import xiangshan.testutils._
class ReservationStationTest extends FlatSpec
with ChiselScalatestTester
with Matchers
with ParallelTestExecution
with HasPartialDecoupledDriver
{
it should "do enq issue with no delay correctly" in {
test(new ReservationStation(Exu.aluExeUnitCfg, wakeupCnt = 1, bypassCnt = 1, fifo = false) {
AddSinks()
}) { c =>
def genEnqRdyReq(x: => DecoupledIO[MicroOp], roq: Long) = {
chiselTypeOf(x.bits).Lit(
_.src1State -> SrcState.rdy,
_.src2State -> SrcState.rdy,
_.src3State -> SrcState.rdy,
_.roqIdx -> roq.U
)
}
c.io.enqCtrl.initSource().setSourceClock(c.clock)
c.io.deq.initSink().setSinkClock(c.clock)
def TEST_SIZE = 2
val roqSeq = 0 until TEST_SIZE
val enqPort = c.io.enqCtrl
fork {
c.io.enqCtrl.enqueuePartialSeq(roqSeq.map(roq => genEnqRdyReq(enqPort, roq)))
}.fork {
c.io.deq.expectDequeuePartialSeq(roqSeq.map(
roq => chiselTypeOf(c.io.deq.bits).Lit(
_.uop.roqIdx -> roq.U
)
))
}.join()
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册