提交 706f729c 编写于 作者: W William Wang

Merge remote-tracking branch 'origin/master' into dev-lsu

# This file describes the GitHub Actions workflow for continuous integration of XS Core.
name: XS Core CI
name: EMU Test
on:
push:
branches: [ master, ci-v2]
branches: [ master ]
pull_request:
branches: [ master ]
......@@ -18,7 +18,7 @@ jobs:
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
- name: Build EMU
run: make ./build/emu NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j40
run: make ./build/emu NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
cputest:
runs-on: self-hosted
......
......@@ -9,6 +9,10 @@ MEM_GEN = ./scripts/vlsi_mem_gen
SIMTOP = top.TestMain
IMAGE ?= temp
# remote machine with high frequency to speedup verilog generation
REMOTE ?= localhost
REMOTE_PREFIX ?= /nfs/24/$(abspath .)/
.DEFAULT_GOAL = verilog
help:
......@@ -41,7 +45,11 @@ SIM_TOP = XSSimTop
SIM_TOP_V = $(BUILD_DIR)/$(SIM_TOP).v
$(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE)
mkdir -p $(@D)
ifeq ($(REMOTE),localhost)
mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F)
else
ssh $(REMOTE) "cd $(REMOTE_PREFIX) && mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F)"
endif
EMU_CSRC_DIR = $(abspath ./src/test/csrc)
......@@ -76,7 +84,12 @@ $(EMU_MK): $(SIM_TOP_V) | $(EMU_DEPS)
verilator --cc --exe $(VERILATOR_FLAGS) \
-o $(abspath $(EMU)) -Mdir $(@D) $^ $(EMU_DEPS)
ifeq ($(REMOTE),localhost)
REF_SO := $(NEMU_HOME)/build/riscv64-nemu-so
else
REF_SO := /home/pcl/NEMU/build/riscv64-nemu-so
endif
$(REF_SO):
$(MAKE) -C $(NEMU_HOME) ISA=riscv64 SHARE=1
......@@ -93,7 +106,11 @@ E ?= -1
V ?= ALL
emu: $(EMU)
ifeq ($(REMOTE),localhost)
@$(EMU) -i $(IMAGE) $(SEED) -b $(B) -e $(E) -v $(V)
else
ssh $(REMOTE) "cd $(REMOTE_PREFIX) && $(EMU) -i $(IMAGE) $(SEED) -b $(B) -e $(E) -v $(V)"
endif
cache:
$(MAKE) emu IMAGE=Makefile
......
......@@ -22,7 +22,7 @@ class DistributedMem(memByte: Int, dualPort: Boolean, delayCycles: Int = 0, data
val roIdx = Index(io.ro.req.bits.addr)
val wen = io.rw.isWrite()
val wdataVec = VecInit.tabulate(nBank) { i => io.rw.req.bits.wdata(8 * (i + 1) - 1, 8 * i) }
val wmask = VecInit.tabulate(nBank) { i => io.rw.req.bits.wmask(i).toBool }
val wmask = VecInit.tabulate(nBank) { i => io.rw.req.bits.wmask(i).asBool() }
val rwData = Wire(UInt(XLEN.W))
val roData = Wire(UInt(XLEN.W))
......
......@@ -5,8 +5,8 @@ import chisel3.util._
import bus.simplebus._
import noop.{Cache, CacheConfig, HasExceptionNO, TLB, TLBConfig}
import xiangshan.backend._
import xiangshan.backend.dispatch.DP1Config
import xiangshan.backend.exu.ExuConfig
import xiangshan.backend.dispatch.DP1Parameters
import xiangshan.backend.exu.ExuParameters
import xiangshan.frontend.Frontend
import xiangshan.mem._
import xiangshan.utils._
......@@ -32,6 +32,7 @@ trait HasXSParameter {
val RenameWidth = 6
val CommitWidth = 6
val BrqSize = 16
val IssQueSize = 8
val BrTagWidth = log2Up(BrqSize)
val NRPhyRegs = 128
val PhyRegIdxWidth = log2Up(NRPhyRegs)
......@@ -43,21 +44,21 @@ trait HasXSParameter {
val IntDqDeqWidth = 4
val FpDqDeqWidth = 4
val LsDqDeqWidth = 4
val dp1Config = DP1Config(
val dp1Paremeters = DP1Parameters(
IntDqSize = 16,
FpDqSize = 16,
LsDqSize = 16
)
val exuConfig = ExuConfig(
val exuParameters = ExuParameters(
JmpCnt = 1,
AluCnt = 4,
BruCnt = 1,
MulCnt = 1,
MduCnt = 1,
FmacCnt = 0,
FmiscCnt = 0,
FmiscDivSqrtCnt = 0,
LduCnt = 1,
StuCnt = 0
LduCnt = 0,
StuCnt = 1
)
}
......
......@@ -11,6 +11,7 @@ import xiangshan.backend.rename.Rename
import xiangshan.backend.brq.Brq
import xiangshan.backend.dispatch.Dispatch
import xiangshan.backend.exu._
import xiangshan.backend.fu.FunctionUnit
import xiangshan.backend.issue.IssueQueue
import xiangshan.backend.regfile.{Regfile, RfWritePort}
import xiangshan.backend.roq.Roq
......@@ -21,8 +22,7 @@ import xiangshan.backend.roq.Roq
*/
class Backend(implicit val p: XSConfig) extends XSModule
with HasExeUnits
with NeedImpl
{
with NeedImpl {
val io = IO(new Bundle {
val dmem = new SimpleBusUC(addrBits = VAddrBits)
val memMMU = Flipped(new MemMMUIO)
......@@ -56,41 +56,53 @@ class Backend(implicit val p: XSConfig) extends XSModule
redirectInfo.misPred := !roq.io.redirect.valid && brq.io.redirect.valid
redirectInfo.redirect := redirect.bits
val issueQueues = exeUnits.zipWithIndex.map({ case(eu, i) =>
def needBypass(x: Exu): Boolean = eu.enableBypass
val bypassCnt = exeUnits.count(needBypass)//if(eu.fuTypeInt == FuType.alu.litValue()) exuConfig.AluCnt else 0
def needWakeup(x: Exu): Boolean = (eu.readIntRf && x.writeIntRf) || (eu.readFpRf && x.writeFpRf)
val wakeupCnt = exeUnits.count(needWakeup)
assert(!(needBypass(eu) && !needWakeup(eu))) // needBypass but dont needWakeup is not allowed
val iq = Module(new IssueQueue(eu.fuTypeInt, wakeupCnt, bypassCnt, eu.fixedDelay, fifo = eu.fuTypeInt == FuType.ldu.litValue()))
val issueQueues = exeUnits.zipWithIndex.map({ case (eu, i) =>
def needBypass(cfg: ExuConfig): Boolean = cfg.enableBypass
val bypassCnt = if(eu.config.enableBypass) exeUnits.map(_.config).count(needBypass) else 0
def needWakeup(cfg: ExuConfig): Boolean =
(cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
val wakeupCnt = exeUnits.map(_.config).count(needWakeup)
assert(!(needBypass(eu.config) && !needWakeup(eu.config))) // needBypass but dont needWakeup is not allowed
val iq = Module(new IssueQueue(
eu.config,
wakeupCnt,
bypassCnt,
fifo = eu.config.supportedFuncUnits.contains(FunctionUnit.lsuCfg)
))
iq.io.redirect <> redirect
iq.io.numExist <> dispatch.io.numExist(i)
iq.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
iq.io.enqData <> dispatch.io.enqIQData(i)
val wuUnitsOut = exeUnits.filter(e => needWakeup(e)).map(_.io.out)
for(i <- iq.io.wakeUpPorts.indices) {
val wuUnitsOut = exeUnits.filter(e => needWakeup(e.config)).map(_.io.out)
for (i <- iq.io.wakeUpPorts.indices) {
iq.io.wakeUpPorts(i).bits <> wuUnitsOut(i).bits
iq.io.wakeUpPorts(i).valid := wuUnitsOut(i).valid
}
println(s"[$i] $eu Queue wakeupCnt:$wakeupCnt bypassCnt:$bypassCnt")
println(
s"[$i] ${eu.name} Queue wakeupCnt:$wakeupCnt bypassCnt:$bypassCnt" +
s" Supported Function:[" +
s"${
eu.config.supportedFuncUnits.map(
fu => FuType.functionNameMap(fu.fuType.litValue())).mkString(", "
)
}]"
)
eu.io.in <> iq.io.deq
eu.io.redirect <> redirect
iq
})
val bypassQueues = issueQueues.filter(_.bypassCnt > 0)
val bypassUnits = exeUnits.filter(_.enableBypass)
val bypassUnits = exeUnits.filter(_.config.enableBypass)
bypassQueues.foreach(iq => {
for(i <- iq.io.bypassUops.indices) {
for (i <- iq.io.bypassUops.indices) {
iq.io.bypassData(i).bits := bypassUnits(i).io.out.bits
iq.io.bypassData(i).valid := bypassUnits(i).io.out.valid
}
iq.io.bypassUops <> bypassQueues.map(_.io.selectedUop)
})
// val aluQueues = issueQueues.filter(_.fuTypeInt == FuType.alu.litValue())
// aluQueues.foreach(aluQ => {
// aluQ.io.bypassUops <> aluQueues.map(_.io.selectedUop)
// aluQ.io.bypassData <> aluExeUnits.map(_.io.out)
// })
lsuExeUnits.foreach(_.io.dmem <> io.dmem)
lsuExeUnits.foreach(_.io.scommit <> roq.io.scommit)
......@@ -101,7 +113,7 @@ class Backend(implicit val p: XSConfig) extends XSModule
decode.io.in <> io.frontend.cfVec
brq.io.roqRedirect <> roq.io.redirect
brq.io.enqReqs <> decode.io.toBrq
for((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.hasRedirect))){
for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
x.bits := y.io.out.bits
x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
}
......@@ -129,8 +141,8 @@ class Backend(implicit val p: XSConfig) extends XSModule
val exeWbReqs = exeUnits.map(_.io.out)
val wbIntIdx = exeUnits.zipWithIndex.filter(_._1.writeIntRf).map(_._2)
val wbFpIdx = exeUnits.zipWithIndex.filter(_._1.writeFpRf).map(_._2)
val wbIntIdx = exeUnits.zipWithIndex.filter(_._1.config.writeIntRf).map(_._2)
val wbFpIdx = exeUnits.zipWithIndex.filter(_._1.config.writeFpRf).map(_._2)
val wbu = Module(new Wbu(wbIntIdx, wbFpIdx))
wbu.io.in <> exeWbReqs
......@@ -172,13 +184,15 @@ class Backend(implicit val p: XSConfig) extends XSModule
"perfCntCondMdcacheReq",
"meip"
)
for (s <- sinks){ BoringUtils.addSink(tmp, s) }
for (s <- sinks) {
BoringUtils.addSink(tmp, s)
}
val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W))))
BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG")
BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG")
val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
if(!p.FPGAPlatform){
if (!p.FPGAPlatform) {
BoringUtils.addSource(debugArchReg, "difftestRegs")
}
......
......@@ -53,7 +53,7 @@ class BrqIO extends XSBundle{
// interrupt/exception happen, flush Brq
val roqRedirect = Input(Valid(new Redirect))
// receive branch/jump calculated target
val exuRedirect = Vec(exuConfig.AluCnt + exuConfig.BruCnt, Flipped(ValidIO(new ExuOutput)))
val exuRedirect = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput)))
// from decode, branch insts enq
val enqReqs = Vec(DecodeWidth, Flipped(DecoupledIO(new CfCtrl)))
// to decode
......@@ -171,7 +171,7 @@ class Brq extends XSModule {
val wbIdx = exuWb.bits.redirect.brTag.value
XSInfo(
p"exu write back: brTag:${exuWb.bits.redirect.brTag}" +
p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)}\n"
p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} pnpc=${Hexadecimal(brQueue(wbIdx).npc)} target=${Hexadecimal(exuWb.bits.redirect.target)}\n"
)
stateQueue(wbIdx) := s_wb
brQueue(wbIdx).exuOut := exuWb.bits
......
......@@ -27,8 +27,8 @@ class Decoder extends XSModule with HasInstrType {
// todo: remove this when fetch stage can decide if an instr is br/jmp
io.out.cf.isBr := (instrType === InstrB ||
(fuOpType === BRUOpType.jal && instrType === InstrJ && fuType === FuType.bru) ||
(fuOpType === BRUOpType.jalr && instrType === InstrI && fuType === FuType.bru))
(fuOpType === BRUOpType.jal && instrType === InstrJ && fuType === FuType.jmp) ||
(fuOpType === BRUOpType.jalr && instrType === InstrI && fuType === FuType.jmp))
// val isRVC = instr(1, 0) =/= "b11".U
// val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
......
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend.decode._
import xiangshan.backend.{ALUOpType, BTBtype, BRUOpType, LDUOpType, STUOpType}
import xiangshan.backend._
object RV32I_ALUInstr extends HasInstrType with HasXSParameter {
def ADDI = BitPat("b????????????_?????_000_?????_0010011")
......@@ -73,8 +73,8 @@ object RV32I_BRUInstr extends HasInstrType {
def BGEU = BitPat("b???????_?????_?????_111_?????_1100011")
val table = Array(
JAL -> List(InstrJ, FuType.bru, BRUOpType.jal),
JALR -> List(InstrI, FuType.bru, BRUOpType.jalr),
JAL -> List(InstrJ, FuType.jmp, BRUOpType.jal),
JALR -> List(InstrI, FuType.jmp, BRUOpType.jalr),
BEQ -> List(InstrB, FuType.alu, ALUOpType.beq),
BNE -> List(InstrB, FuType.alu, ALUOpType.bne),
......@@ -109,15 +109,15 @@ object RV32I_LSUInstr extends HasInstrType {
def SW = BitPat("b???????_?????_?????_010_?????_0100011")
val table = Array(
LB -> List(InstrI, FuType.ldu, LDUOpType.lb ),
LH -> List(InstrI, FuType.ldu, LDUOpType.lh ),
LW -> List(InstrI, FuType.ldu, LDUOpType.lw ),
LBU -> List(InstrI, FuType.ldu, LDUOpType.lbu),
LHU -> List(InstrI, FuType.ldu, LDUOpType.lhu),
SB -> List(InstrS, FuType.stu, STUOpType.sb ),
SH -> List(InstrS, FuType.stu, STUOpType.sh ),
SW -> List(InstrS, FuType.stu, STUOpType.sw )
LB -> List(InstrI, FuType.ldu, LSUOpType.lb ),
LH -> List(InstrI, FuType.ldu, LSUOpType.lh ),
LW -> List(InstrI, FuType.ldu, LSUOpType.lw ),
LBU -> List(InstrI, FuType.ldu, LSUOpType.lbu),
LHU -> List(InstrI, FuType.ldu, LSUOpType.lhu),
SB -> List(InstrS, FuType.stu, LSUOpType.sb ),
SH -> List(InstrS, FuType.stu, LSUOpType.sh ),
SW -> List(InstrS, FuType.stu, LSUOpType.sw )
)
}
......@@ -147,9 +147,9 @@ object RV64IInstr extends HasInstrType {
ADDW -> List(InstrR, FuType.alu, ALUOpType.addw),
SUBW -> List(InstrR, FuType.alu, ALUOpType.subw),
LWU -> List(InstrI, FuType.ldu, LDUOpType.lwu),
LD -> List(InstrI, FuType.ldu, LDUOpType.ld ),
SD -> List(InstrS, FuType.stu, STUOpType.sd)
LWU -> List(InstrI, FuType.ldu, LSUOpType.lwu),
LD -> List(InstrI, FuType.ldu, LSUOpType.ld ),
SD -> List(InstrS, FuType.stu, LSUOpType.sd)
)
}
......
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend.decode._
import xiangshan.backend.{MDUOpType, MULOpType}
import xiangshan.backend.MDUOpType
object RV32MInstr extends HasInstrType with HasXSParameter {
def MUL = BitPat("b0000001_?????_?????_000_?????_0110011")
......@@ -22,16 +22,16 @@ object RV32MInstr extends HasInstrType with HasXSParameter {
def REMUW = BitPat("b0000001_?????_?????_111_?????_0111011")
val mulTable = Array(
MUL -> List(InstrR, FuType.mul, MULOpType.mul),
MULH -> List(InstrR, FuType.mul, MULOpType.mulh),
MULHSU -> List(InstrR, FuType.mul, MULOpType.mulhsu),
MULHU -> List(InstrR, FuType.mul, MULOpType.mulhu)
MUL -> List(InstrR, FuType.mul, MDUOpType.mul),
MULH -> List(InstrR, FuType.mul, MDUOpType.mulh),
MULHSU -> List(InstrR, FuType.mul, MDUOpType.mulhsu),
MULHU -> List(InstrR, FuType.mul, MDUOpType.mulhu)
)
val divTable = Array(
DIV -> List(InstrR, FuType.mdu, MDUOpType.div),
DIVU -> List(InstrR, FuType.mdu, MDUOpType.divu),
REM -> List(InstrR, FuType.mdu, MDUOpType.rem),
REMU -> List(InstrR, FuType.mdu, MDUOpType.remu)
DIV -> List(InstrR, FuType.div, MDUOpType.div),
DIVU -> List(InstrR, FuType.div, MDUOpType.divu),
REM -> List(InstrR, FuType.div, MDUOpType.rem),
REMU -> List(InstrR, FuType.div, MDUOpType.remu)
)
val table = mulTable ++ (if (HasDiv) divTable else Nil)
}
......@@ -44,13 +44,13 @@ object RV64MInstr extends HasInstrType with HasXSParameter {
def REMUW = BitPat("b0000001_?????_?????_111_?????_0111011")
val mulTable = Array(
MULW -> List(InstrR, FuType.mul, MULOpType.mulw)
MULW -> List(InstrR, FuType.mul, MDUOpType.mulw)
)
val divTable = Array(
DIVW -> List(InstrR, FuType.mdu, MDUOpType.divw),
DIVUW -> List(InstrR, FuType.mdu, MDUOpType.divuw),
REMW -> List(InstrR, FuType.mdu, MDUOpType.remw),
REMUW -> List(InstrR, FuType.mdu, MDUOpType.remuw)
DIVW -> List(InstrR, FuType.div, MDUOpType.divw),
DIVUW -> List(InstrR, FuType.div, MDUOpType.divuw),
REMW -> List(InstrR, FuType.div, MDUOpType.remw),
REMUW -> List(InstrR, FuType.div, MDUOpType.remuw)
)
val table = mulTable ++ (if (HasDiv) divTable else Nil)
}
......
......@@ -21,18 +21,19 @@ class Dispatch extends XSModule {
// read reg status (busy/ready)
val intPregRdy = Vec(NRReadPorts, Input(Bool()))
val fpPregRdy = Vec(NRReadPorts, Input(Bool()))
// ro reservation stations
val enqIQCtrl = Vec(exuConfig.ExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuConfig.ExuCnt, ValidIO(new ExuInput))
// to reservation stations
val numExist = Input(Vec(exuParameters.ExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.ExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuParameters.ExuCnt, ValidIO(new ExuInput))
})
// pipeline between rename and dispatch
val dispatch1 = Module(new Dispatch1())
for (i <- 0 until RenameWidth) {
PipelineConnect(io.fromRename(i), dispatch1.io.fromRename(i), dispatch1.io.recv(i), false.B)
}
val intDq = Module(new DispatchQueue(dp1Config.IntDqSize, RenameWidth, IntDqDeqWidth, "IntDpQ"))
val fpDq = Module(new DispatchQueue(dp1Config.FpDqSize, RenameWidth, FpDqDeqWidth, "FpDpQ"))
val lsDq = Module(new DispatchQueue(dp1Config.LsDqSize, RenameWidth, LsDqDeqWidth, "LsDpQ"))
val intDq = Module(new DispatchQueue(dp1Paremeters.IntDqSize, RenameWidth, IntDqDeqWidth, "IntDpQ"))
val fpDq = Module(new DispatchQueue(dp1Paremeters.FpDqSize, RenameWidth, FpDqDeqWidth, "FpDpQ"))
val lsDq = Module(new DispatchQueue(dp1Paremeters.LsDqSize, RenameWidth, LsDqDeqWidth, "LsDpQ"))
val dispatch2 = Module(new Dispatch2())
dispatch1.io.redirect <> io.redirect
......@@ -57,4 +58,5 @@ class Dispatch extends XSModule {
dispatch2.io.fpPregRdy <> io.fpPregRdy
dispatch2.io.enqIQCtrl <> io.enqIQCtrl
dispatch2.io.enqIQData <> io.enqIQData
dispatch2.io.numExist <> io.numExist
}
......@@ -5,7 +5,7 @@ import chisel3.util._
import xiangshan._
import xiangshan.utils.{XSDebug, XSInfo, XSWarn}
case class DP1Config
case class DP1Parameters
(
IntDqSize: Int,
FpDqSize: Int,
......
......@@ -6,7 +6,7 @@ import xiangshan._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.utils.{XSDebug, XSInfo}
class Dispatch2 extends XSModule {
class Dispatch2 extends XSModule{
val io = IO(new Bundle() {
// from dispatch queues
val fromIntDq = Flipped(Vec(IntDqDeqWidth, DecoupledIO(new MicroOp)))
......@@ -21,145 +21,79 @@ class Dispatch2 extends XSModule {
val fpPregRdy = Vec(NRReadPorts, Input(Bool()))
// enq Issue Queue
val enqIQCtrl = Vec(exuConfig.ExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuConfig.ExuCnt, ValidIO(new ExuInput))
val numExist = Input(Vec(exuParameters.ExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.ExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuParameters.ExuCnt, ValidIO(new ExuInput))
})
// inst indexes for reservation stations
// append a true.B to avoid PriorityEncode(0000) -> 3
// if find a target uop, index[2] == 0, else index[2] == 1
val bruInstIdx = PriorityEncoder(io.fromIntDq.map(deq => deq.bits.ctrl.fuType === FuType.bru && deq.valid) :+ true.B)
val aluInstIdxsTry = RegInit(VecInit(Seq.tabulate(exuConfig.AluCnt)(i => i.U(2.W))))
val aluInstIdxs = Wire(Vec(exuConfig.AluCnt, UInt(3.W)))
for (i <- 0 until exuConfig.AluCnt) {
assert(exuConfig.AluCnt == IntDqDeqWidth)
// 0 -> 1 -> 2 -> 3 -> 0
aluInstIdxsTry(i) := aluInstIdxsTry(i) + 1.U
val deqAluInvalid = io.fromIntDq(aluInstIdxsTry(i)).bits.ctrl.fuType =/= FuType.alu || !io.fromIntDq(aluInstIdxsTry(i)).valid
aluInstIdxs(i) := Cat(deqAluInvalid.asUInt(), aluInstIdxsTry(i))
}
val mulInstIdx = PriorityEncoder(io.fromIntDq.map(deq => deq.bits.ctrl.fuType === FuType.mul && deq.valid) :+ true.B)
val muldivInstIdx = PriorityEncoder((io.fromIntDq.zipWithIndex map { case (deq, i) =>
((deq.bits.ctrl.fuType === FuType.mul && i.U > mulInstIdx) || deq.bits.ctrl.fuType === FuType.mdu) && deq.valid
}) :+ true.B)
// TODO uncomment when FmacCnt > 0
val fmacInstIdxsTry = Reg(Vec(exuConfig.FmacCnt, UInt(2.W)))
// val fmacInstIdxsTry = RegInit(VecInit(Seq.tabulate(exuConfig.FmacCnt)(i => i.U(2.W))))
val fmacInstIdxs = Wire(Vec(exuConfig.FmacCnt, UInt(3.W)))
// val deqFmacInstIdxs = RegInit(VecInit(Seq.tabulate(exuConfig.FmacCnt)(i => i.U(2.W))))
for (i <- 0 until exuConfig.FmacCnt) {
assert(exuConfig.FmacCnt == FpDqDeqWidth)
// 0 -> 1 -> 2 -> 3 -> 0
fmacInstIdxsTry(i) := fmacInstIdxsTry(i) + 1.U
val deqFmacInvalid = io.fromFpDq(fmacInstIdxsTry(i)).bits.ctrl.fuType =/= FuType.fmac || !io.fromFpDq(fmacInstIdxsTry(i)).valid
fmacInstIdxs(i) := Cat(deqFmacInvalid.asUInt(), fmacInstIdxsTry(i))
for (i <- 0 until IntDqDeqWidth) {
XSDebug(io.fromIntDq(i).valid,
p"int dp queue $i: ${Hexadecimal(io.fromIntDq(i).bits.cf.pc)} type ${Binary(io.fromIntDq(i).bits.ctrl.fuType)}\n")
}
val fmisc0InstIdx = PriorityEncoder(io.fromFpDq.map(deq => deq.bits.ctrl.fuType === FuType.fmisc && deq.valid) :+ true.B)
val fmisc1InstIdx = PriorityEncoder((io.fromFpDq.zipWithIndex map { case (deq, i) =>
((deq.bits.ctrl.fuType === FuType.fmisc && i.U > fmisc0InstIdx) || deq.bits.ctrl.fuType === FuType.fmiscDivSqrt) && deq.valid
}) :+ true.B)
for (i <- 0 until FpDqDeqWidth) {
XSDebug(io.fromFpDq(i).valid,
p"fp dp queue $i: ${Hexadecimal(io.fromFpDq(i).bits.cf.pc)} type ${Binary(io.fromFpDq(i).bits.ctrl.fuType)}\n")
}
for (i <- 0 until LsDqDeqWidth) {
XSDebug(io.fromLsDq(i).valid,
p"ls dp queue $i: ${Hexadecimal(io.fromLsDq(i).bits.cf.pc)} type ${Binary(io.fromLsDq(i).bits.ctrl.fuType)}\n")
}
// inst indexes for reservation stations
val rsIndexGen = Module(new DispatchGen())
rsIndexGen.io.fromIntDq := io.fromIntDq
rsIndexGen.io.fromFpDq := io.fromFpDq
rsIndexGen.io.fromLsDq := io.fromLsDq
rsIndexGen.io.numExist := io.numExist
// TODO: currently there's only one load/store reservation station
val load0InstIdx = PriorityEncoder(io.fromLsDq.map(_.bits.ctrl.fuType === FuType.ldu) :+ true.B)
val load1InstIdx = PriorityEncoder((io.fromLsDq.zipWithIndex map { case (uop, i) =>
uop.bits.ctrl.fuType === FuType.ldu && i.U > load0InstIdx
}) :+ true.B)
// val store0InstIdx = PriorityEncoder(io.fromLsDq.map(_.bits.ctrl.fuType === FuType.stu) :+ true.B)
val store0InstIdx = PriorityEncoder(io.fromLsDq.map(deq => FuType.isMemExu(deq.bits.ctrl.fuType)) :+ true.B)
val store1InstIdx = PriorityEncoder((io.fromLsDq.zipWithIndex map { case (uop, i) =>
uop.bits.ctrl.fuType === FuType.stu && i.U > store0InstIdx
}) :+ true.B)
val instValid = rsIndexGen.io.enqIQIndex.map(_.valid)
val allIndex = rsIndexGen.io.enqIQIndex.map(_.bits)
XSDebug("%d %d %d %d %d %d %d %d\n", bruInstIdx, aluInstIdxs(0), aluInstIdxs(1), aluInstIdxs(2),
aluInstIdxs(3), mulInstIdx, muldivInstIdx, store0InstIdx)
allIndex.zipWithIndex.map({case(index, i) => XSDebug(instValid(i), p"dispatch to iq index $i: $index\n")})
// regfile read ports
// regfile is sync-read, data can used at the next cycle
// BRU, MUL0, MUL1 can use the 8 read ports
// priority: ALU > BRU > MUL
val intExuIndex = WireInit(VecInit(Seq.fill(3)(0.U(2.W))))
val intDeqChoice = Wire(Vec(4, UInt(2.W)))
for (i <- 0 until 4) {
val readPortSrc = Seq(aluInstIdxs(i), bruInstIdx, mulInstIdx, muldivInstIdx)
val wantReadPort = (0 until 4).map(j => (
if (i == 0) !readPortSrc(j)(2)
else {
val prevMax = (0 until i).map(intDeqChoice(_)).reduce((a, b) => Mux(a > b, a, b))
!readPortSrc(j)(2) && (j.U > prevMax || j.U === 0.U)
}))
val readIdxVec = Wire(Vec(4, UInt(2.W)))
for (j <- 0 until 4) {
readIdxVec(j) := readPortSrc(j)(1, 0)
}
intDeqChoice(i) := PriorityEncoder(wantReadPort)
XSDebug("int %d: want %b, deqChoice: %d\n", i.U, Cat(wantReadPort), intDeqChoice(i))
val target = readIdxVec(intDeqChoice(i)(1, 0))
io.readIntRf(2 * i).addr := io.fromIntDq(target).bits.psrc1
io.readIntRf(2 * i + 1).addr := io.fromIntDq(target).bits.psrc2
io.readIntRf <> DontCare
val regfileRPGen = Module(new RegfileReadPortGen())
(0 until exuParameters.IntExuCnt).map(i => regfileRPGen.io.intIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(i))
(0 until exuParameters.FpExuCnt).map(i => regfileRPGen.io.fpIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(exuParameters.IntExuCnt + i))
(0 until exuParameters.LsExuCnt).map(i => regfileRPGen.io.lsIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(exuParameters.IntExuCnt + exuParameters.FpExuCnt + i))
for (i <- 0 until 2 * exuParameters.IntExuCnt) {
val bits = io.fromIntDq(regfileRPGen.io.readIntRf(i)).bits
io.readIntRf(i).addr := (if (i % 2 == 0) bits.psrc1 else bits.psrc2)
XSDebug(p"regfile $i from ${regfileRPGen.io.readIntRf(i)}\n")
}
// intExuIndex: which regfile read ports are assigned to BRU, MUL, MULDIV
for (j <- 0 until 3) {
intExuIndex(j) := PriorityEncoder((0 until 4).map(i => intDeqChoice(i) === (j + 1).U))
for (i <- 0 until 3*exuParameters.FpExuCnt) {
val bits = io.fromFpDq(regfileRPGen.io.readFpRf(i)).bits
io.readFpRf(i).addr := (if (i % 3 == 0) bits.psrc1 else if (i % 3 == 1) bits.psrc2 else bits.psrc3)
}
XSDebug("intExuIndex: %d %d %d\n", intExuIndex(0), intExuIndex(1), intExuIndex(2))
// FMAC, FMISC can use the 12 read ports
// priority: FMAC > FMISC
val fpExuIndex = WireInit(VecInit(Seq.fill(2)(0.U(2.W))))
val fpDeqChoice = Wire(Vec(4, UInt(2.W)))
fpDeqChoice := DontCare
for (i <- 0 until exuConfig.FmacCnt) {
val readPortSrc = Seq(fmacInstIdxs(i), fmisc0InstIdx, fmisc1InstIdx)
val wantReadPort = (0 until 3).map(j => (
if (i == 0) !readPortSrc(j)(2)
else {
val prevMax = (0 until i).map(fpDeqChoice(_)).reduce((a, b) => Mux(a > b, a, b))
!readPortSrc(j)(2) && (j.U > prevMax || j.U === 0.U)
}))
val readIdxVec = Wire(Vec(3, UInt(2.W)))
for (j <- 0 until 3) {
readIdxVec(j) := readPortSrc(j)(1, 0)
}
fpDeqChoice(i) := PriorityEncoder(wantReadPort)
XSDebug("fp %d: want %b, deqChoice: %d\n", i.U, Cat(wantReadPort), fpDeqChoice(i))
val target = readIdxVec(fpDeqChoice(i))
io.readFpRf(3 * i).addr := io.fromFpDq(target).bits.psrc1
io.readFpRf(3 * i + 1).addr := io.fromFpDq(target).bits.psrc2
io.readFpRf(3 * i + 2).addr := io.fromFpDq(target).bits.psrc3
for (i <- 0 until exuParameters.LduCnt) {
val start = 2 * exuParameters.AluCnt
io.readIntRf(start+i).addr := io.fromLsDq(regfileRPGen.io.readIntRf(start+i))
}
// fpExuIndex: which regfile read ports are assigned to FMISC0 FMISC1
for (j <- 0 until (exuConfig.FmiscCnt + exuConfig.FmiscDivSqrtCnt)) {
fpExuIndex(j) := PriorityEncoder((0 until 4).map(i => fpDeqChoice(i) === (j + 1).U))
for (i <- 0 until 2*exuParameters.StuCnt) {
val start = 2 * exuParameters.AluCnt + exuParameters.LduCnt
val bits = io.fromLsDq(regfileRPGen.io.readIntRf(start + i)).bits
io.readIntRf(start + i).addr := (if (i % 2 == 0) bits.psrc1 else bits.psrc2)
}
for (i <- 0 until NRReadPorts) {
XSDebug(p"regfile $i: addr ${io.readIntRf(i).addr}, state ${io.intPregRdy(i)}\n")
}
XSDebug("fpExuIndex: %d %d\n", fpExuIndex(0), fpExuIndex(1))
// TODO uncomment me when fmac > 0
io.readFpRf <> DontCare
io.readIntRf(2*IntDqDeqWidth).addr := io.fromLsDq(load0InstIdx).bits.psrc1
io.readIntRf(2*IntDqDeqWidth + 1).addr := io.fromLsDq(load1InstIdx).bits.psrc1
io.readIntRf(2*IntDqDeqWidth + 2).addr := io.fromLsDq(store0InstIdx).bits.psrc1
io.readIntRf(2*IntDqDeqWidth + 3).addr := io.fromLsDq(store0InstIdx).bits.psrc2
io.readIntRf(2*IntDqDeqWidth + 4).addr := io.fromLsDq(store1InstIdx).bits.psrc1
io.readIntRf(2*IntDqDeqWidth + 5).addr := io.fromLsDq(store1InstIdx).bits.psrc2
io.readFpRf(3*FpDqDeqWidth).addr := io.fromLsDq(store0InstIdx).bits.psrc1
io.readFpRf(3*FpDqDeqWidth + 1).addr := io.fromLsDq(store1InstIdx).bits.psrc1
// insert into reservation station
val instIdxes = Seq(bruInstIdx, aluInstIdxs(0), aluInstIdxs(1), aluInstIdxs(2), aluInstIdxs(3), mulInstIdx, muldivInstIdx,
/*load0InstIdx, */store0InstIdx)
val instIdxes = (0 until exuParameters.ExuCnt).map(i => Cat(!instValid(i), allIndex(i)))
io.enqIQCtrl.zipWithIndex map { case (enq, i) =>
if (i < exuConfig.IntExuCnt) {
if (i < exuParameters.IntExuCnt) {
enq.valid := !instIdxes(i)(2) && io.fromIntDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromIntDq(instIdxes(i)(1, 0)).bits
val startIndex = if (i == 0) 2.U * intExuIndex(0)
else if (i > 4) 2.U * intExuIndex(i - 4)
else (2 * (i - 1)).U
val startIndex = regfileRPGen.io.intIQRfSrc(i)
enq.bits.src1State := io.intPregRdy(startIndex)
enq.bits.src2State := io.intPregRdy(startIndex + 1.U)
}
else if (i < exuConfig.IntExuCnt + exuConfig.FpExuCnt) {
val startIndex = if (i < exuConfig.IntExuCnt + 4) (3 * (i - exuConfig.IntExuCnt)).U
else 3.U * fpExuIndex(i - exuConfig.IntExuCnt - 4)
else if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt) {
val startIndex = regfileRPGen.io.fpIQRfSrc(i - exuParameters.IntExuCnt)
enq.valid := !instIdxes(i)(2) && io.fromFpDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromFpDq(instIdxes(i)(1, 0)).bits
enq.bits.src1State := io.fpPregRdy(startIndex)
......@@ -167,11 +101,17 @@ class Dispatch2 extends XSModule {
enq.bits.src3State := io.fpPregRdy(startIndex + 2.U)
}
else {
// TODO: load store with fp
val startIndex = regfileRPGen.io.lsIQRfSrc(i - exuParameters.IntExuCnt - exuParameters.FpExuCnt)
enq.valid := !instIdxes(i)(2) && io.fromLsDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromLsDq(instIdxes(i)(1, 0)).bits
// TODO load and store
enq.bits.src1State := io.intPregRdy(10)
enq.bits.src2State := io.intPregRdy(11)
if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt + exuParameters.LduCnt) {
enq.bits.src1State := io.intPregRdy(startIndex)
}
else {
enq.bits.src1State := io.intPregRdy(startIndex)
enq.bits.src2State := io.intPregRdy(startIndex + 1.U)
}
}
XSInfo(enq.fire(), "pc 0x%x with type %b srcState(%d %d %d) enters reservation station %d from %d\n",
......@@ -181,7 +121,7 @@ class Dispatch2 extends XSModule {
// responds to dispatch queue
for (i <- 0 until IntDqDeqWidth) {
io.fromIntDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U && (j < exuConfig.IntExuCnt).asBool())
(rs.ready && instIdxes(j) === i.U && (j < exuParameters.IntExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromIntDq(i).fire(), "pc 0x%x leaves Int dispatch queue with nroq %d\n",
io.fromIntDq(i).bits.cf.pc, io.fromIntDq(i).bits.roqIdx)
......@@ -192,7 +132,7 @@ class Dispatch2 extends XSModule {
for (i <- 0 until FpDqDeqWidth) {
io.fromFpDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U
&& (j >= exuConfig.IntExuCnt && j < exuConfig.IntExuCnt + exuConfig.FpExuCnt).asBool())
&& (j >= exuParameters.IntExuCnt && j < exuParameters.IntExuCnt + exuParameters.FpExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromFpDq(i).fire(), "pc 0x%x leaves Fp dispatch queue with nroq %d\n",
io.fromFpDq(i).bits.cf.pc, io.fromFpDq(i).bits.roqIdx)
......@@ -202,8 +142,8 @@ class Dispatch2 extends XSModule {
}
for (i <- 0 until LsDqDeqWidth) {
io.fromLsDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && 0.U === i.U
&& (j >= exuConfig.IntExuCnt + exuConfig.FpExuCnt).asBool())
(rs.ready && instIdxes(j) === i.U
&& (j >= exuParameters.IntExuCnt + exuParameters.FpExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromLsDq(i).fire(), "pc 0x%x leaves Ls dispatch queue with nroq %d\n",
io.fromLsDq(i).bits.cf.pc, io.fromLsDq(i).bits.roqIdx)
......@@ -213,24 +153,24 @@ class Dispatch2 extends XSModule {
}
// TODO: store needs data from FpRegfile
val intExuIndexReg = Reg(Vec(3, UInt(2.W)))
val fpExuIndexReg = Reg(Vec(2, UInt(2.W)))
(0 until 3).map(i => intExuIndexReg(i) := intExuIndex(i))
(0 until 2).map(i => fpExuIndexReg(i) := fpExuIndex(i))
val intExuIndexReg = Reg(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val fpExuIndexReg = Reg(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val lsExuIndexReg = Reg(Vec(exuParameters.LduCnt + exuParameters.StuCnt, UInt(log2Ceil(NRReadPorts).W)))
(0 until exuParameters.IntExuCnt).map(i => intExuIndexReg(i) := regfileRPGen.io.intIQRfSrc(i))
(0 until exuParameters.FpExuCnt).map(i => fpExuIndexReg(i) := regfileRPGen.io.fpIQRfSrc(i))
(0 until exuParameters.LsExuCnt).map(i => lsExuIndexReg(i) := regfileRPGen.io.lsIQRfSrc(i))
// TODO: remove uop when reservation stations deal with imme
val uop_reg = Reg(Vec(exuConfig.ExuCnt, new MicroOp))
val data_valid = Reg(Vec(exuConfig.ExuCnt, Bool()))
for (i <- 0 until exuConfig.ExuCnt) {
val uop_reg = Reg(Vec(exuParameters.ExuCnt, new MicroOp))
val data_valid = Reg(Vec(exuParameters.ExuCnt, Bool()))
for (i <- 0 until exuParameters.ExuCnt) {
data_valid(i) := io.enqIQCtrl(i).fire()
uop_reg(i) := io.enqIQCtrl(i).bits
io.enqIQData(i).valid := DontCare
io.enqIQData(i).bits := DontCare
val srcIndex = Wire(Vec(3, UInt(4.W)))
if (i < exuConfig.IntExuCnt) {
val startIndex = if (i == 0)2.U * intExuIndexReg(0)
else if (i > 4) 2.U * intExuIndexReg(i - 4)
else (2 * (i - 1)).U
if (i < exuParameters.IntExuCnt) {
val startIndex = intExuIndexReg(i)
io.enqIQData(i).bits.src1 := Mux(uop_reg(i).ctrl.src1Type === SrcType.pc,
uop_reg(i).cf.pc, io.readIntRf(startIndex).data)
io.enqIQData(i).bits.src2 := Mux(uop_reg(i).ctrl.src2Type === SrcType.imm,
......@@ -239,9 +179,8 @@ class Dispatch2 extends XSModule {
srcIndex(1) := startIndex + 1.U
srcIndex(2) := 0.U
}
else if (i < exuConfig.IntExuCnt + exuConfig.FpExuCnt) {
val startIndex = if (i < exuConfig.IntExuCnt + 4) (3 * (i - exuConfig.IntExuCnt)).U
else 3.U * fpExuIndexReg(i - exuConfig.IntExuCnt - 4)
else if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt) {
val startIndex = fpExuIndexReg(i - exuParameters.IntExuCnt)
io.enqIQData(i).bits.src1 := io.readFpRf(startIndex).data
io.enqIQData(i).bits.src2 := io.readFpRf(startIndex + 1.U).data
io.enqIQData(i).bits.src3 := io.readFpRf(startIndex + 2.U).data
......@@ -250,12 +189,13 @@ class Dispatch2 extends XSModule {
srcIndex(2) := startIndex + 2.U
}
else {
val startIndex = lsExuIndexReg(i - exuParameters.IntExuCnt - exuParameters.FpExuCnt)
io.enqIQData(i).bits.src1 := Mux(uop_reg(i).ctrl.src1Type === SrcType.pc,
uop_reg(i).cf.pc, io.readIntRf(10).data)
uop_reg(i).cf.pc, io.readIntRf(startIndex).data)
io.enqIQData(i).bits.src2 := Mux(uop_reg(i).ctrl.src2Type === SrcType.imm,
uop_reg(i).ctrl.imm, io.readIntRf(11).data)
srcIndex(0) := 10.U
srcIndex(1) := 11.U
uop_reg(i).ctrl.imm, io.readIntRf(startIndex + 1.U).data)
srcIndex(0) := startIndex
srcIndex(1) := startIndex + 1.U
srcIndex(2) := 0.U
}
......
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.{XSDebug}
class DispatchGen extends XSModule {
val io = IO(new Bundle() {
// from dispatch queues
val fromIntDq = Flipped(Vec(IntDqDeqWidth, ValidIO(new MicroOp)))
val fromFpDq = Flipped(Vec(FpDqDeqWidth, ValidIO(new MicroOp)))
val fromLsDq = Flipped(Vec(LsDqDeqWidth, ValidIO(new MicroOp)))
// enq Issue Queue
val numExist = Input(Vec(exuParameters.ExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQIndex = Vec(exuParameters.ExuCnt, ValidIO(UInt(log2Ceil(IntDqDeqWidth).W)))
})
assert(IntDqDeqWidth >= FpDqDeqWidth)
assert(IntDqDeqWidth >= LsDqDeqWidth)
def PriorityGen(numExist: Seq[UInt]) = {
assert(numExist.length > 1)
val sortedIndex = Wire(Vec(numExist.length, UInt(log2Ceil(numExist.length).W)))
val priority = WireInit(VecInit(Seq.tabulate(numExist.length)(i => 0.U(log2Ceil(numExist.length).W))))
for (i <- 0 until numExist.length) {
sortedIndex(i) := PriorityEncoder((0 until numExist.length).map(each => {
// itself should not be found yet
val equalPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => each.U === sortedIndex(l))).orR())
val largerThanAnyOther = Cat((0 until numExist.length).map(another => {
// no need to be compared with the larger ones
val anotherEqualPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => another.U === sortedIndex(l))).orR())
// need to be no smaller than any other numbers except the previoud found larger ones
(numExist(each) <= numExist(another)) || anotherEqualPrevious
})).andR()
largerThanAnyOther && !equalPrevious
}))
priority(sortedIndex(i)) := i.U
}
for (i <- 0 until numExist.length) {
XSDebug(p"priority: data($i) = ${numExist(i)}, priority = ${priority(i)}\n")
}
priority
}
def genIQIndex(exunum: Int, deqnum: Int, deq: Seq[Bool], numExist: Seq[UInt]) = {
assert(isPow2(deqnum))
assert(exunum == numExist.length)
// index without priority
val IQIndex = Wire(Vec(exunum, UInt((log2Ceil(deqnum) + 1).W)))
var last_deq = deq
for (i <- 0 until exunum) {
IQIndex(i) := PriorityEncoder(last_deq :+ true.B)
val onehot = UIntToOH(IQIndex(i))
last_deq = (0 until deqnum).map(i => !onehot(i) && last_deq(i))
}
// now consider the IQ priority with numExist
val priority = (if (numExist.length > 1) PriorityGen(numExist) else Seq(0.U))
(0 until exunum).map(i => IQIndex(priority(i)))
}
val bruIQIndex = genIQIndex(exuParameters.JmpCnt, IntDqDeqWidth, io.fromIntDq.map(_.bits.ctrl.fuType === FuType.jmp),
(0 until exuParameters.JmpCnt).map(i => io.numExist(i)))
val aluIQIndex = genIQIndex(exuParameters.AluCnt, IntDqDeqWidth, io.fromIntDq.map(_.bits.ctrl.fuType === FuType.alu),
(0 until exuParameters.AluCnt).map(i => io.numExist(exuParameters.JmpCnt+i)))
val mulIQIndex = genIQIndex(exuParameters.MulCnt, IntDqDeqWidth, io.fromIntDq.map(_.bits.ctrl.fuType === FuType.mul),
(0 until exuParameters.MulCnt).map(i => io.numExist(exuParameters.JmpCnt+exuParameters.AluCnt+i)))
val muldivIQIndex = genIQIndex(exuParameters.MduCnt, IntDqDeqWidth, io.fromIntDq.map(_.bits.ctrl.fuType === FuType.div),
(0 until exuParameters.MduCnt).map(i => io.numExist(exuParameters.JmpCnt+exuParameters.AluCnt+exuParameters.MulCnt+i)))
val fmacIQIndex = genIQIndex(exuParameters.FmacCnt, FpDqDeqWidth, io.fromFpDq.map(_.bits.ctrl.fuType === FuType.fmac),
(0 until exuParameters.FmacCnt).map(i => io.numExist(exuParameters.IntExuCnt+i)))
val fmiscIQIndex = genIQIndex(exuParameters.FmiscCnt, FpDqDeqWidth, io.fromFpDq.map(_.bits.ctrl.fuType === FuType.fmisc),
(0 until exuParameters.FmiscCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FmacCnt+i)))
val lduIQIndex = genIQIndex(exuParameters.LduCnt, LsDqDeqWidth, io.fromLsDq.map(_.bits.ctrl.fuType === FuType.ldu),
(0 until exuParameters.LduCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FpExuCnt+i)))
// val stuIQIndex = genIQIndex(exuParameters.StuCnt, LsDqDeqWidth, io.fromLsDq.map(_.bits.ctrl.fuType === FuType.stu))
val stuIQIndex = genIQIndex(exuParameters.StuCnt, LsDqDeqWidth, io.fromLsDq.map(deq => FuType.isMemExu(deq.bits.ctrl.fuType)),
(0 until exuParameters.StuCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FpExuCnt+exuParameters.LduCnt+i)))
val allIndex = Seq(bruIQIndex, aluIQIndex, mulIQIndex, muldivIQIndex,
fmacIQIndex, fmiscIQIndex,
lduIQIndex, stuIQIndex
)
val allCnt = Seq(exuParameters.JmpCnt, exuParameters.AluCnt, exuParameters.MulCnt, exuParameters.MduCnt,
exuParameters.FmacCnt, exuParameters.FmiscCnt,
exuParameters.LduCnt, exuParameters.StuCnt
)
assert(allIndex.length == allCnt.length)
var startIndex = 0
for (i <- 0 until allIndex.length) {
for (j <- 0 until allCnt(i)) {
io.enqIQIndex(startIndex + j).valid := !allIndex(i)(j)(2)
io.enqIQIndex(startIndex + j).bits := allIndex(i)(j)(1, 0)
}
startIndex += allCnt(i)
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.{XSDebug}
class RegfileReadPortGen extends XSModule {
val io = IO(new Bundle() {
// from dispatch queues
val intIQEnqIndex = Flipped(Vec(exuParameters.IntExuCnt, ValidIO(UInt(log2Ceil(IntDqDeqWidth).W))))
val fpIQEnqIndex = Flipped(Vec(exuParameters.FpExuCnt, ValidIO(UInt(log2Ceil(FpDqDeqWidth).W))))
val lsIQEnqIndex = Flipped(Vec(exuParameters.LduCnt + exuParameters.StuCnt, ValidIO(UInt(log2Ceil(LsDqDeqWidth).W))))
// chooses dispatch queue dequeue indexs for regfile read ports
val readIntRf = Output(Vec(NRReadPorts, UInt(log2Ceil(IntDqDeqWidth).W)))
val readFpRf = Output(Vec(NRReadPorts, UInt(log2Ceil(IntDqDeqWidth).W)))
// chooses regfile read ports for reservation stations
val intIQRfSrc = Output(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val fpIQRfSrc = Output(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val lsIQRfSrc = Output(Vec(exuParameters.LsExuCnt, UInt(log2Ceil(NRReadPorts).W)))
})
def RegfileReadPortArbiter(staticMappedValid: Seq[Bool], dynamicMappedValid: Seq[Bool]) = {
val choiceCount = dynamicMappedValid.length + 1
// read port is assigned to readPortSrc
val readPortSrc = Wire(Vec(staticMappedValid.length, UInt(log2Ceil(choiceCount).W)))
var hasAssigned = (0 until choiceCount).map(_ => false.B)
for (i <- 0 until staticMappedValid.length) {
val valid = staticMappedValid(i) +: dynamicMappedValid
val wantReadPort = (0 until choiceCount).map(j => valid(j) && ((j == 0).asBool() || !hasAssigned(j)))
readPortSrc(i) := PriorityEncoder(wantReadPort)
val onehot = UIntToOH(readPortSrc(i))
hasAssigned = (0 until choiceCount).map(i => hasAssigned(i) || onehot(i))
XSDebug("int %d: want %b, deqChoice: %d\n", i.U, Cat(wantReadPort), readPortSrc(i))
}
val dynamicExuSrc = Wire(Vec(dynamicMappedValid.length, UInt(log2Ceil(staticMappedValid.length).W)))
for (i <- 0 until dynamicMappedValid.length) {
val targetMatch = (0 until staticMappedValid.length).map(j => readPortSrc(j) === (i + 1).U)
dynamicExuSrc(i) := PriorityEncoder(targetMatch)
XSDebug(p"dynamicExuSrc $i: ${dynamicExuSrc(i)} ${Binary(Cat(targetMatch))}\n")
}
(readPortSrc, dynamicExuSrc)
}
val intStaticIndex = Seq(1, 2, 3, 4)
val intDynamicIndex = Seq(0, 5, 6)
val intStaticMappedValid = intStaticIndex.map(i => io.intIQEnqIndex(i).valid)
val intDynamicMappedValid = intDynamicIndex.map(i => io.intIQEnqIndex(i).valid)
val (intReadPortSrc, intDynamicExuSrc) = RegfileReadPortArbiter(intStaticMappedValid, intDynamicMappedValid)
val intStaticMapped = intStaticIndex.map(i => io.intIQEnqIndex(i).bits)
val intDynamicMapped = intDynamicIndex.map(i => io.intIQEnqIndex(i).bits)
for (i <- 0 until intStaticIndex.length) {
val index = WireInit(VecInit(intStaticMapped(i) +: intDynamicMapped))
io.readIntRf(2*i) := index(intReadPortSrc(i))
io.readIntRf(2*i + 1) := index(intReadPortSrc(i))
}
intStaticIndex.zipWithIndex.map({case (index, i) => io.intIQRfSrc(index) := (2*i).U})
intDynamicIndex.zipWithIndex.map({case (index, i) => io.intIQRfSrc(index) := 2.U * intDynamicExuSrc(i)})
if (exuParameters.FpExuCnt > 0) {
val fpStaticIndex = 0 until exuParameters.FmacCnt
val fpDynamicIndex = exuParameters.FmacCnt until exuParameters.FpExuCnt
val fpStaticMappedValid = fpStaticIndex.map(i => io.fpIQEnqIndex(i).valid)
val fpDynamicMappedValid = fpDynamicIndex.map(i => io.fpIQEnqIndex(i).valid)
val (fpReadPortSrc, fpDynamicExuSrc) = RegfileReadPortArbiter(fpStaticMappedValid, fpDynamicMappedValid)
val fpStaticMapped = fpStaticIndex.map(i => io.fpIQEnqIndex(i).bits)
val fpDynamicMapped = fpDynamicIndex.map(i => io.fpIQEnqIndex(i).bits)
for (i <- 0 until fpStaticIndex.length) {
val index = WireInit(VecInit(fpStaticMapped(i) +: fpDynamicMapped))
io.readFpRf(i) := index(fpReadPortSrc(i))
io.fpIQRfSrc(fpStaticIndex(i)) := (3 * i).U
}
fpDynamicIndex.zipWithIndex.map({ case (index, i) => io.fpIQRfSrc(index) := 3.U * fpDynamicExuSrc(i) })
}
else {
io.fpIQRfSrc <> DontCare
io.readFpRf <> DontCare
}
val lsStaticIndex = 0 until exuParameters.LsExuCnt
val lsDynamicIndex = 0 until 0
val lsStaticMappedValid = lsStaticIndex.map(i => io.lsIQEnqIndex(i).valid)
val lsDynamicMappedValid = lsDynamicIndex.map(i => io.lsIQEnqIndex(i).valid)
val (lsReadPortSrc, lsDynamicExuSrc) = RegfileReadPortArbiter(lsStaticMappedValid, lsDynamicMappedValid)
val lsStaticMapped = lsStaticIndex.map(i => io.lsIQEnqIndex(i).bits)
val lsDynamicMapped = lsDynamicIndex.map(i => io.lsIQEnqIndex(i).bits)
for (i <- 0 until lsStaticIndex.length) {
val index = WireInit(VecInit(lsStaticMapped(i) +: lsDynamicMapped))
if (i < exuParameters.LduCnt) {
val start = intStaticIndex.length*2
io.readIntRf(start+i) := index(lsReadPortSrc(i))
io.lsIQRfSrc(lsStaticIndex(i)) := (start + i).U
}
else {
val start = intStaticIndex.length*2 + exuParameters.LduCnt
io.readIntRf(start + 2 * i) := index(lsReadPortSrc(i))
io.readIntRf(start + 2 * i + 1) := index(lsReadPortSrc(i))
io.lsIQRfSrc(lsStaticIndex(i)) := (start + 2 * i).U
}
}
assert(lsDynamicIndex.length == 0)
val usedPorts = intStaticIndex.length*2 +exuParameters.LduCnt +exuParameters.StuCnt*2
for (i <- usedPorts until NRReadPorts) {
io.readIntRf(i) := DontCare
}
}
......@@ -6,9 +6,10 @@ import xiangshan._
import xiangshan.FuType._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Alu extends Exu(alu.litValue(), hasRedirect = true) {
override def toString: String = "Alu"
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)
......
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 divInputFunc = (x: UInt) => Mux(
isW,
Mux(isDivSign,
SignExt(x(31,0), XLEN),
ZeroExt(x(31,0), XLEN)
),
x
)
divider.io.redirect := io.redirect
divider.io.in.valid := io.in.valid
divider.io.in.bits.ctrl.uop := io.in.bits.uop
divider.io.in.bits.ctrl.sign := isDivSign
divider.io.in.bits.ctrl.isW := isW
divider.io.in.bits.ctrl.isHi := func(1)
divider.io.in.bits.src1 := divInputFunc(src1)
divider.io.in.bits.src2 := 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.dmem <> DontCare
io.out.bits.debug <> DontCare
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
}
......@@ -4,11 +4,13 @@ import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.FuType._
import xiangshan.utils.XSInfo
import xiangshan.backend.fu.FuConfig
import xiangshan.utils.ParallelOR
import xiangshan.backend.fu.FunctionUnit._
case class ExuConfig
case class ExuParameters
(
BruCnt: Int,
JmpCnt: Int,
AluCnt: Int,
MulCnt: Int,
MduCnt: Int,
......@@ -18,117 +20,63 @@ case class ExuConfig
LduCnt: Int,
StuCnt: Int
){
assert(BruCnt == 1, "Only support 1 Bru now!")
def IntExuCnt = AluCnt + MulCnt + MduCnt + BruCnt
assert(JmpCnt == 1, "Only support 1 JmpUnit now!")
def IntExuCnt = AluCnt + MulCnt + MduCnt + JmpCnt
def FpExuCnt = FmacCnt + FmiscCnt + FmiscDivSqrtCnt
def ExuCnt = IntExuCnt + FpExuCnt + LduCnt
def LsExuCnt = LduCnt + StuCnt
def ExuCnt = IntExuCnt + FpExuCnt + LduCnt + StuCnt
def NRFuType = 9
def FuOpWidth = 7
}
abstract class Exu
case class ExuConfig
(
val fuTypeInt: BigInt,
val readIntRf: Boolean = true,
val readFpRf: Boolean = false,
val writeIntRf: Boolean = true,
val writeFpRf: Boolean = false,
val enableBypass: Boolean = false, // join bypass group or not, require readIntRf & writeIntRf now
val fixedDelay: Int = 1, // IssueQueue's selectUop's delay
val hasRedirect: Boolean = false
) extends XSModule {
name: String,
supportedFuncUnits: Array[FuConfig],
enableBypass: Boolean
){
def max(in: Seq[Int]): Int = in.reduce((x, y) => if(x > y) x else y)
val intSrcCnt = max(supportedFuncUnits.map(_.numIntSrc))
val fpSrcCnt = max(supportedFuncUnits.map(_.numFpSrc))
val readIntRf = intSrcCnt > 0
val readFpRf = fpSrcCnt > 0
val writeIntRf = supportedFuncUnits.map(_.writeIntRf).reduce(_||_)
val writeFpRf = supportedFuncUnits.map(_.writeFpRf).reduce(_||_)
val hasRedirect = supportedFuncUnits.map(_.hasRedirect).reduce(_||_)
def canAccept(fuType: UInt): Bool = {
ParallelOR(supportedFuncUnits.map(_.fuType === fuType)).asBool()
}
}
abstract class Exu(val config: ExuConfig) extends XSModule {
val io = IO(new ExuIO)
io.dmem <> DontCare
io.out.bits.debug.isMMIO := false.B
}
class Fmac extends Exu(
FuType.fmac.litValue(),
readIntRf = false,
readFpRf = true,
writeIntRf = false,
writeFpRf = true
) with NeedImpl {
override def toString: String = "Fmac"
object Exu {
val jmpExeUnitCfg = ExuConfig("JmpExu", Array(jmpCfg, i2fCfg), enableBypass = false)
val aluExeUnitCfg = ExuConfig("AluExu", Array(aluCfg), enableBypass = false)
val mulExeUnitCfg = ExuConfig("MulExu", Array(mulCfg), enableBypass = false)
val divExeUnitCfg = ExuConfig("DivExu",Array(divCfg), enableBypass = false)
val mulDivExeUnitCfg = ExuConfig("MulDivExu", Array(mulCfg, divCfg), enableBypass = false)
val lsuExeUnitCfg = ExuConfig("LsExu", Array(lsuCfg), enableBypass = false)
}
class Fmisc extends Exu(
FuType.fmisc.litValue(),
readIntRf = false,
readFpRf = true,
writeIntRf = true,
writeFpRf = true
) with NeedImpl {
override def toString: String = "Fmisc"
}
class FmiscDivSqrt extends Exu(
FuType.fmiscDivSqrt.litValue(),
readIntRf = false,
readFpRf = true,
writeIntRf = false,
writeFpRf = true
) with NeedImpl {
override def toString: String = "FmiscDivSqrt"
}
// class Lsu extends Exu(
// FuType.ldu.litValue(),
// readIntRf = true,
// readFpRf = true,
// writeIntRf = true,
// writeFpRf = true
// ) with NeedImpl {
// override def toString: String = "Lsu"
// }
trait HasExeUnits{
val aluExeUnits = Array.tabulate(exuConfig.AluCnt)(_ => Module(new Alu))
val bruExeUnit = Module(new Bru)
val mulExeUnits = Array.tabulate(exuConfig.MulCnt)(_ => Module(new Mul))
val mduExeUnits = Array.tabulate(exuConfig.MduCnt)(_ => Module(new Mdu))
val fmacExeUnits = Array.tabulate(exuConfig.FmacCnt)(_ => Module(new Fmac))
val fmiscExeUnits = Array.tabulate(exuConfig.FmiscCnt)(_ => Module(new Fmisc))
val fmiscDivSqrtExeUnits = Array.tabulate(exuConfig.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt))
val lsuExeUnits = Array.tabulate(exuConfig.LduCnt)(_ => Module(new Lsu))
val aluExeUnits = Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
val jmpExeUnit = Module(new JmpExeUnit)
val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
// val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac))
// val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc))
// val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt))
val lsuExeUnits = Array.tabulate(exuParameters.StuCnt)(_ => Module(new LsExeUnit))
val exeUnits = bruExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++
fmacExeUnits ++ fmiscExeUnits ++ fmiscDivSqrtExeUnits ++ lsuExeUnits)
val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ lsuExeUnits)
exeUnits.foreach(_.io.dmem := DontCare)
exeUnits.foreach(_.io.scommit := DontCare)
}
class WriteBackArbMtoN(m: Int, n: Int) extends XSModule {
val io = IO(new Bundle() {
val in = Vec(m, Flipped(DecoupledIO(new ExuOutput)))
val out = Vec(n, ValidIO(new ExuOutput))
})
require(m >= n, "m < n! Why use an arbiter???")
// first n-1 ports, direct connect
for((i, o) <- io.in.take(n-1).zip(io.out)){
o.valid := i.valid
o.bits := i.bits
i.ready := true.B
}
// last m-(n-1) ports, rr arb
val arb = Module(new RRArbiter[ExuOutput](new ExuOutput, m-n+1))
for((arbIn, ioIn) <- arb.io.in.zip(io.in.drop(n-1))){
arbIn <> ioIn
}
io.out.last.bits := arb.io.out.bits
io.out.last.valid := arb.io.out.valid
arb.io.out.ready := true.B
for (i <- 0 until n) {
XSInfo(io.out(i).valid, "out(%d) pc(0x%x) writebacks 0x%x to pdest(%d) ldest(%d)\n", i.U, io.out(i).bits.uop.cf.pc,
io.out(i).bits.data, io.out(i).bits.uop.pdest, io.out(i).bits.uop.ctrl.ldest)
}
}
......@@ -6,12 +6,13 @@ import xiangshan._
import xiangshan.FuType._
import xiangshan.utils._
import xiangshan.backend.regfile.RfWritePort
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.backend.BRUOpType
// NOTE: BRUOpType is at backend/package.scala
class Bru extends Exu(FuType.bru.litValue(), writeFpRf = true, hasRedirect = true) {
override def toString: String = "Bru"
// TODO: add csr
class JmpExeUnit extends Exu(Exu.jmpExeUnitCfg) {
val (iovalid, src1, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, io.in.bits.uop.ctrl.imm, io.in.bits.uop.ctrl.fuOpType, SignExt(io.in.bits.uop.cf.pc, AddrBits), io.in.bits.uop)
......
......@@ -10,39 +10,11 @@ import xiangshan.backend.regfile.RfWritePort
import utils._
import bus.simplebus._
import noop.AddressSpace
import xiangshan.backend._
import xiangshan.backend.brq.BrqPtr
import xiangshan.backend.fu.FunctionUnit._
object LSUOpType {
def lb = "b000000".U
def lh = "b000001".U
def lw = "b000010".U
def ld = "b000011".U
def lbu = "b000100".U
def lhu = "b000101".U
def lwu = "b000110".U
def sb = "b001000".U
def sh = "b001001".U
def sw = "b001010".U
def sd = "b001011".U
def lr = "b100010".U
def sc = "b100011".U
def amoswap = "b100001".U
def amoadd = "b100000".U
def amoxor = "b100100".U
def amoand = "b101100".U
def amoor = "b101000".U
def amomin = "b110000".U
def amomax = "b110100".U
def amominu = "b111000".U
def amomaxu = "b111100".U
def isStore(func: UInt): Bool = func(3)
def isAtom(func: UInt): Bool = func(5)
def atomW = "010".U
def atomD = "011".U
}
class StoreQueueEntry extends XSBundle{
val src1 = UInt(XLEN.W)
......@@ -56,14 +28,7 @@ class StoreQueueEntry extends XSBundle{
}
// Multi-cycle LSU ported from NOOP
class Lsu extends Exu(
FuType.ldu.litValue(),
readIntRf = true,
readFpRf = true,
writeIntRf = true,
writeFpRf = true
){
override def toString: String = "Lsu"
class LsExeUnit extends Exu(Exu.lsuExeUnitCfg){
// store buffer
val stqData = Reg(Vec(8, new StoreQueueEntry))
......
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import utils.{LookupTree, SignExt, ZeroExt, _}
import xiangshan.backend.{MDUOpType, MULOpType}
class Mul extends Exu(FuType.mul.litValue()){
override def toString: String = "Mul"
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(
MULOpType.mul -> (zeroext, zeroext),
MULOpType.mulh -> (signext, signext),
MULOpType.mulhsu -> (signext, zeroext),
MULOpType.mulhu -> (zeroext, zeroext)
)
val isW = MDUOpType.isW(func)
mul.io.redirect := io.redirect
mul.io.in.bits.ctrl.uop := io.in.bits.uop
mul.io.in.bits.ctrl.sign := DontCare //Mul don't use this
mul.io.in.bits.ctrl.isW := isW
mul.io.in.bits.ctrl.isHi := func(1,0) =/= MDUOpType.mul(1,0)
mul.io.in.bits.src1 := LookupTree(
func(1,0),
mulInputFuncTable.map(p => (p._1(1,0), p._2._1(src1)))
)
mul.io.in.bits.src2 := LookupTree(
func(1,0),
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
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
XSDebug(io.redirect.valid, p"redirect: ${io.redirect.bits.brTag}\n")
}
// A wrapper of Divider
class Div extends XSModule {
val io = IO(new ExuIO)
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 divInputFunc = (x: UInt) => Mux(
isW,
Mux(isDivSign,
SignExt(x(31,0), XLEN),
ZeroExt(x(31,0), XLEN)
),
x
)
divider.io.redirect := io.redirect
divider.io.in.valid := io.in.valid
divider.io.in.bits.ctrl.uop := io.in.bits.uop
divider.io.in.bits.ctrl.sign := isDivSign
divider.io.in.bits.ctrl.isW := isW
divider.io.in.bits.ctrl.isHi := func(1)
divider.io.in.bits.src1 := divInputFunc(src1)
divider.io.in.bits.src2 := 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.dmem <> DontCare
io.out.bits.debug <> DontCare
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
}
class Mdu extends Exu(FuType.mdu.litValue()) {
override def toString: String = "MulDiv"
val (src1, src2, uop, func) =
(io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType)
val isDiv = MDUOpType.isDiv(func)
val mul = Module(new Mul)
val div = Module(new Div)
for(x <- Seq(mul.io, div.io)){
x.scommit <> DontCare
x.dmem <> DontCare
x.in.bits := io.in.bits
x.redirect := io.redirect
}
mul.io.in.valid := io.in.valid && !isDiv
div.io.in.valid := io.in.valid && isDiv
io.in.ready := Mux(isDiv, div.io.in.ready, mul.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
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
}
class MulDivCtrl extends Bundle{
val uop = new MicroOp
val sign = Bool()
val isW = Bool()
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))
}
trait HasPipelineReg { this: ArrayMultiplier =>
val validVec = io.in.valid +: Array.fill(latency)(RegInit(false.B))
val rdyVec = Array.fill(latency)(Wire(Bool())) :+ io.out.ready
val ctrlVec = io.in.bits.ctrl +: Array.fill(latency)(Reg(new MulDivCtrl))
val flushVec = ctrlVec.zip(validVec).map(x => x._2 && x._1.uop.brTag.needFlush(io.redirect))
for(i <- 0 until latency){
rdyVec(i) := !validVec(i+1) || rdyVec(i+1)
}
for(i <- 1 to latency){
when(flushVec(i) || rdyVec(i) && !validVec(i-1)){
validVec(i) := false.B
}.elsewhen(rdyVec(i-1) && validVec(i-1) && !flushVec(i-1)){
validVec(i) := validVec(i-1)
ctrlVec(i) := ctrlVec(i-1)
}
}
io.in.ready := rdyVec(0)
io.out.valid := validVec.last && !flushVec.last
io.out.bits.uop := ctrlVec.last.uop
def PipelineReg[T<:Data](i: Int)(next: T) = RegEnable(next, enable = validVec(i-1) && rdyVec(i-1))
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)
}
abstract class Multiplier
(
val len: Int,
val latency: Int = 3
) extends Module {
val io = IO(new MulDivIO(len))
}
class ArrayMultiplier
(
len: Int,
latency: Int = 3,
realArray: Boolean = false
) extends Multiplier(len, latency) with HasPipelineReg {
val mulRes = io.in.bits.src1.asSInt() * io.in.bits.src2.asSInt()
var dataVec = Seq(mulRes.asUInt())
for(i <- 1 to latency){
dataVec = dataVec :+ PipelineReg(i)(dataVec(i-1))
}
val xlen = io.out.bits.data.getWidth
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")
}
class Divider(len: Int) extends Module {
val io = IO(new MulDivIO(len))
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
(s, Mux(s, -a, a))
}
val s_idle :: s_log2 :: s_shift :: s_compute :: s_finish :: Nil = Enum(5)
val state = RegInit(s_idle)
val newReq = (state === s_idle) && io.in.fire()
val (a, b) = (io.in.bits.src1, io.in.bits.src2)
val divBy0 = b === 0.U(len.W)
val shiftReg = Reg(UInt((1 + len * 2).W))
val hi = shiftReg(len * 2, len)
val lo = shiftReg(len - 1, 0)
val (aSign, aVal) = abs(a, io.in.bits.ctrl.sign)
val (bSign, bVal) = abs(b, io.in.bits.ctrl.sign)
val aSignReg = RegEnable(aSign, newReq)
val qSignReg = RegEnable((aSign ^ bSign) && !divBy0, newReq)
val bReg = RegEnable(bVal, newReq)
val aValx2Reg = RegEnable(Cat(aVal, "b0".U), newReq)
val ctrlReg = RegEnable(io.in.bits.ctrl, newReq)
val cnt = Counter(len)
when (newReq) {
state := s_log2
} .elsewhen (state === s_log2) {
// `canSkipShift` is calculated as following:
// bEffectiveBit = Log2(bVal, XLEN) + 1.U
// aLeadingZero = 64.U - aEffectiveBit = 64.U - (Log2(aVal, XLEN) + 1.U)
// canSkipShift = aLeadingZero + bEffectiveBit
// = 64.U - (Log2(aVal, XLEN) + 1.U) + Log2(bVal, XLEN) + 1.U
// = 64.U + Log2(bVal, XLEN) - Log2(aVal, XLEN)
// = (64.U | Log2(bVal, XLEN)) - Log2(aVal, XLEN) // since Log2(bVal, XLEN) < 64.U
val canSkipShift = (64.U | Log2(bReg)) - Log2(aValx2Reg)
// When divide by 0, the quotient should be all 1's.
// Therefore we can not shift in 0s here.
// We do not skip any shift to avoid this.
cnt.value := Mux(divBy0, 0.U, Mux(canSkipShift >= (len-1).U, (len-1).U, canSkipShift))
state := s_shift
} .elsewhen (state === s_shift) {
shiftReg := aValx2Reg << cnt.value
state := s_compute
} .elsewhen (state === s_compute) {
val enough = hi.asUInt >= bReg.asUInt
shiftReg := Cat(Mux(enough, hi - bReg, hi)(len - 1, 0), lo, enough)
cnt.inc()
when (cnt.value === (len-1).U) { state := s_finish }
} .elsewhen (state === s_finish) {
when(io.out.ready){
state := s_idle
}
}
when(state=/=s_idle && ctrlReg.uop.brTag.needFlush(io.redirect)){
state := s_idle
}
val r = hi(len, 1)
val resQ = Mux(qSignReg, -lo, lo)
val resR = Mux(aSignReg, -r, r)
val xlen = io.out.bits.data.getWidth
val res = Mux(ctrlReg.isHi, resR, resQ)
io.out.bits.data := Mux(ctrlReg.isW, SignExt(res(31,0),xlen), res)
io.out.bits.uop := ctrlReg.uop
io.out.valid := state === s_finish
io.in.ready := state === s_idle
}
\ No newline at end of file
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend.MDUOpType
import xiangshan.backend.fu.FunctionUnit._
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 isDiv = MDUOpType.isDiv(func)
val mul = Module(new MulExeUnit)
val div = Module(new DivExeUnit)
for(x <- Seq(mul.io, div.io)){
x.scommit <> DontCare
x.dmem <> DontCare
x.in.bits := io.in.bits
x.redirect := io.redirect
}
mul.io.in.valid := io.in.valid && !isDiv
div.io.in.valid := io.in.valid && isDiv
io.in.ready := Mux(isDiv, div.io.in.ready, mul.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
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
}
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)
mul.io.redirect := io.redirect
mul.io.in.bits.ctrl.uop := io.in.bits.uop
mul.io.in.bits.ctrl.sign := DontCare //Mul don't use this
mul.io.in.bits.ctrl.isW := isW
mul.io.in.bits.ctrl.isHi := func(1,0) =/= MDUOpType.mul(1,0)
mul.io.in.bits.src1 := LookupTree(
func(1,0),
mulInputFuncTable.map(p => (p._1(1,0), p._2._1(src1)))
)
mul.io.in.bits.src2 := LookupTree(
func(1,0),
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
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%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.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.in.bits.uop.cf.pc)
XSDebug(io.out.valid, "Out(%d %d) res:%x pc:%x\n",
io.out.valid, io.out.ready, io.out.bits.data, io.out.bits.uop.cf.pc
)
XSDebug(io.redirect.valid, p"redirect: ${io.redirect.bits.brTag}\n")
}
......@@ -2,13 +2,47 @@ package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan.{ExuOutput, XSModule}
import xiangshan._
import xiangshan.utils._
class WriteBackArbMtoN(m: Int, n: Int) extends XSModule {
val io = IO(new Bundle() {
val in = Vec(m, Flipped(DecoupledIO(new ExuOutput)))
val out = Vec(n, ValidIO(new ExuOutput))
})
require(m >= n, "m < n! Why use an arbiter???")
// first n-1 ports, direct connect
for((i, o) <- io.in.take(n-1).zip(io.out)){
o.valid := i.valid
o.bits := i.bits
i.ready := true.B
}
// last m-(n-1) ports, rr arb
val arb = Module(new RRArbiter[ExuOutput](new ExuOutput, m-n+1))
for((arbIn, ioIn) <- arb.io.in.zip(io.in.drop(n-1))){
arbIn <> ioIn
}
io.out.last.bits := arb.io.out.bits
io.out.last.valid := arb.io.out.valid
arb.io.out.ready := true.B
for (i <- 0 until n) {
XSInfo(io.out(i).valid, "out(%d) pc(0x%x) writebacks 0x%x to pdest(%d) ldest(%d)\n", i.U, io.out(i).bits.uop.cf.pc,
io.out(i).bits.data, io.out(i).bits.uop.pdest, io.out(i).bits.uop.ctrl.ldest)
}
}
class Wbu(wbIntIdx: Array[Int], wbFpIdx: Array[Int]) extends XSModule{
val io = IO(new Bundle() {
val in = Vec(exuConfig.ExuCnt, Flipped(DecoupledIO(new ExuOutput)))
val toRoq = Vec(exuConfig.ExuCnt, ValidIO(new ExuOutput))
val in = Vec(exuParameters.ExuCnt, Flipped(DecoupledIO(new ExuOutput)))
val toRoq = Vec(exuParameters.ExuCnt, ValidIO(new ExuOutput))
val toIntRf, toFpRf = Vec(NRWritePorts, ValidIO(new ExuOutput))
})
......
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Alu extends FunctionUnit(aluCfg) {
val io = IO(new ExuIO)
override def toString: String = "Alu"
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.brTag.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw) && !ALUOpType.isJump(func)
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 isBru = ALUOpType.isBru(func)
// val isBranch = io.in.bits.uop.cf.isBr// ALUOpType.isBranch(func)
val isBranch = ALUOpType.isBranch(func)
val isJump = ALUOpType.isJump(func)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, pc + offset, adderRes)(VAddrBits-1,0)
val isRVC = uop.cf.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
io.in.ready := io.out.ready
val pcLatchSlot = Mux(isRVC, pc + 2.U, pc + 4.U)
io.out.bits.redirectValid := io.out.valid && isBru//isBranch
io.out.bits.redirect.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := DontCare // false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.redirect.freelistAllocPtr := uop.freelistAllocPtr
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := Mux(isJump, pcLatchSlot, aluRes)
XSDebug(io.in.valid,
"In(%d %d) Out(%d %d) Redirect:(%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,
redirectHit,
io.redirect.bits.brTag.flag,
io.redirect.bits.brTag.value
)
XSDebug(io.in.valid, "src1:%x src2:%x offset:%x func:%b pc:%x\n",
src1, src2, offset, func, pc)
XSDebug(io.out.valid, "res:%x aluRes:%x isRVC:%d isBru:%d isBranch:%d isJump:%d target:%x taken:%d flptr:%x\n",
io.out.bits.data, aluRes, isRVC, isBru, isBranch, isJump, target, taken, io.out.bits.uop.freelistAllocPtr.value)
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Divider(len: Int) extends FunctionUnit(divCfg) {
val io = IO(new MulDivIO(len))
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
(s, Mux(s, -a, a))
}
val s_idle :: s_log2 :: s_shift :: s_compute :: s_finish :: Nil = Enum(5)
val state = RegInit(s_idle)
val newReq = (state === s_idle) && io.in.fire()
val (a, b) = (io.in.bits.src1, io.in.bits.src2)
val divBy0 = b === 0.U(len.W)
val shiftReg = Reg(UInt((1 + len * 2).W))
val hi = shiftReg(len * 2, len)
val lo = shiftReg(len - 1, 0)
val (aSign, aVal) = abs(a, io.in.bits.ctrl.sign)
val (bSign, bVal) = abs(b, io.in.bits.ctrl.sign)
val aSignReg = RegEnable(aSign, newReq)
val qSignReg = RegEnable((aSign ^ bSign) && !divBy0, newReq)
val bReg = RegEnable(bVal, newReq)
val aValx2Reg = RegEnable(Cat(aVal, "b0".U), newReq)
val ctrlReg = RegEnable(io.in.bits.ctrl, newReq)
val cnt = Counter(len)
when (newReq) {
state := s_log2
} .elsewhen (state === s_log2) {
// `canSkipShift` is calculated as following:
// bEffectiveBit = Log2(bVal, XLEN) + 1.U
// aLeadingZero = 64.U - aEffectiveBit = 64.U - (Log2(aVal, XLEN) + 1.U)
// canSkipShift = aLeadingZero + bEffectiveBit
// = 64.U - (Log2(aVal, XLEN) + 1.U) + Log2(bVal, XLEN) + 1.U
// = 64.U + Log2(bVal, XLEN) - Log2(aVal, XLEN)
// = (64.U | Log2(bVal, XLEN)) - Log2(aVal, XLEN) // since Log2(bVal, XLEN) < 64.U
val canSkipShift = (64.U | Log2(bReg)) - Log2(aValx2Reg)
// When divide by 0, the quotient should be all 1's.
// Therefore we can not shift in 0s here.
// We do not skip any shift to avoid this.
cnt.value := Mux(divBy0, 0.U, Mux(canSkipShift >= (len-1).U, (len-1).U, canSkipShift))
state := s_shift
} .elsewhen (state === s_shift) {
shiftReg := aValx2Reg << cnt.value
state := s_compute
} .elsewhen (state === s_compute) {
val enough = hi.asUInt >= bReg.asUInt
shiftReg := Cat(Mux(enough, hi - bReg, hi)(len - 1, 0), lo, enough)
cnt.inc()
when (cnt.value === (len-1).U) { state := s_finish }
} .elsewhen (state === s_finish) {
when(io.out.ready){
state := s_idle
}
}
when(state=/=s_idle && ctrlReg.uop.brTag.needFlush(io.redirect)){
state := s_idle
}
val r = hi(len, 1)
val resQ = Mux(qSignReg, -lo, lo)
val resR = Mux(aSignReg, -r, r)
val xlen = io.out.bits.data.getWidth
val res = Mux(ctrlReg.isHi, resR, resQ)
io.out.bits.data := Mux(ctrlReg.isW, SignExt(res(31,0),xlen), res)
io.out.bits.uop := ctrlReg.uop
io.out.valid := state === s_finish
io.in.ready := state === s_idle
}
\ No newline at end of file
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class FDivSqrt extends FunctionUnit(fDivSqrtCfg){
val io = IO(new Bundle() {})
override def toString: String = "FDivSqrt"
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Fmac extends FunctionUnit(fmacCfg){
val io = IO(new Bundle() {})
override def toString: String = "Fmac"
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Fmisc extends FunctionUnit(fmiscCfg){
val io = IO(new Bundle() {})
override def toString: String = "Fmisc"
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import FunctionUnit._
/*
XiangShan Function Unit
A Exu can have one or more function units
*/
case class FuConfig
(
fuType: UInt,
numIntSrc: Int,
numFpSrc: Int,
writeIntRf: Boolean,
writeFpRf: Boolean,
hasRedirect: Boolean
)
abstract class FunctionUnit(cfg: FuConfig) extends XSModule
object FunctionUnit {
val jmpCfg =
FuConfig(FuType.jmp, 1, 0, writeIntRf = true, writeFpRf = false, hasRedirect = true)
val i2fCfg =
FuConfig(FuType.i2f, 1, 0, writeIntRf = false, writeFpRf = true, hasRedirect = false)
val aluCfg =
FuConfig(FuType.alu, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = true)
val mulCfg =
FuConfig(FuType.mul, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false)
val divCfg =
FuConfig(FuType.div, 2, 0, writeIntRf = true, writeFpRf = false, hasRedirect = false)
val lsuCfg =
FuConfig(FuType.ldu, 2, 1, writeIntRf = true, writeFpRf = true, hasRedirect = false)
val fmacCfg =
FuConfig(FuType.fmac, 0, 3, writeIntRf = false, writeFpRf = true, hasRedirect = false)
val fmiscCfg =
FuConfig(FuType.fmisc, 0, 2, writeIntRf = false, writeFpRf = true, hasRedirect = false)
val fDivSqrtCfg =
FuConfig(FuType.fDivSqrt, 0, 2, writeIntRf = false, writeFpRf = true, hasRedirect = false)
}
\ No newline at end of file
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class I2f extends FunctionUnit(i2fCfg){
val io = IO(new Bundle() {})
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class Jump extends FunctionUnit(jmpCfg){
val io = IO(new ExuIO)
override def toString: String = "Bru"
val (iovalid, src1, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, 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.brTag.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isCSR = BRUOpType.isCSR(func)
val isFMV = BRUOpType.isFMV(func)
val isMOU = BRUOpType.isMOU(func)
val isJUMP = BRUOpType.isJUMP(func)
// JUMP
val isRVC = uop.cf.isRVC
val pcDelaySlot = Mux(isRVC, pc + 2.U, pc + 4.U)
val target = src1 + offset // NOTE: src1 is (pc/rf(rs1)), src2 is (offset)
io.out.bits.redirectValid := valid && isJUMP
io.out.bits.redirect.target := target
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.redirect.freelistAllocPtr := uop.freelistAllocPtr
// Output
val resCSR = WireInit(0.U(XLEN.W)) // TODO: implement it
val resFMV = WireInit(0.U(XLEN.W)) // TODO: implement it
val resMOU = WireInit(0.U(XLEN.W)) // TODO: implement it
val resJMP = pcDelaySlot
val res = ParallelMux(
VecInit(isCSR, isFMV, isMOU, isJUMP) zip
VecInit(resCSR, resFMV, resMOU, resJMP)
)
io.in.ready := io.out.ready
io.out.valid := valid // TODO: CSR/MOU/FMV may need change it
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := res
// NOTE: the debug info is for one-cycle exec, if FMV needs multi-cycle, may needs change it
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, redirectHit, io.redirect.bits.brTag.value)
XSDebug(io.in.valid && isCSR, "src1:%x offset:%x func:%b type:CSR pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isFMV, "src1:%x offset:%x func:%b type:FMV pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isMOU, "src1:%x offset:%x func:%b type:MOU pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isJUMP, "src1:%x offset:%x func:%b type:JUMP pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid, "Res:%x` CsrRes:%x FMV:%x Mou:%x Jmp:%x\n", res, resCSR, resFMV, resMOU, resJMP)
}
package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
class MulDivCtrl extends Bundle{
val uop = new MicroOp
val sign = Bool()
val isW = Bool()
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,
val latency: Int = 3
) extends FunctionUnit(mulCfg) {
val io = IO(new MulDivIO(len))
}
trait HasPipelineReg { this: ArrayMultiplier =>
val validVec = io.in.valid +: Array.fill(latency)(RegInit(false.B))
val rdyVec = Array.fill(latency)(Wire(Bool())) :+ io.out.ready
val ctrlVec = io.in.bits.ctrl +: Array.fill(latency)(Reg(new MulDivCtrl))
val flushVec = ctrlVec.zip(validVec).map(x => x._2 && x._1.uop.brTag.needFlush(io.redirect))
for(i <- 0 until latency){
rdyVec(i) := !validVec(i+1) || rdyVec(i+1)
}
for(i <- 1 to latency){
when(flushVec(i) || rdyVec(i) && !validVec(i-1)){
validVec(i) := false.B
}.elsewhen(rdyVec(i-1) && validVec(i-1) && !flushVec(i-1)){
validVec(i) := validVec(i-1)
ctrlVec(i) := ctrlVec(i-1)
}
}
io.in.ready := rdyVec(0)
io.out.valid := validVec.last && !flushVec.last
io.out.bits.uop := ctrlVec.last.uop
def PipelineReg[T<:Data](i: Int)(next: T) = RegEnable(
next,
enable = validVec(i-1) && rdyVec(i-1) && !flushVec(i-1)
)
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)
}
class ArrayMultiplier
(
len: Int,
latency: Int = 3,
realArray: Boolean = false
) extends Multiplier(len, latency) with HasPipelineReg {
val mulRes = io.in.bits.src1.asSInt() * io.in.bits.src2.asSInt()
var dataVec = Seq(mulRes.asUInt())
for(i <- 1 to latency){
dataVec = dataVec :+ PipelineReg(i)(dataVec(i-1))
}
val xlen = io.out.bits.data.getWidth
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")
}
\ No newline at end of file
......@@ -3,24 +3,39 @@ package xiangshan.backend.issue
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.exu.{Exu, ExuConfig}
import xiangshan.backend.rename.FreeListPtr
import xiangshan.utils._
import xiangshan.backend.fu.FunctionUnit._
trait IQConst{
val iqSize = 8
trait IQConst extends HasXSParameter{
val iqSize = IssQueSize
val iqIdxWidth = log2Up(iqSize)
}
sealed abstract class IQBundle extends XSBundle with IQConst
sealed abstract class IQModule extends XSModule with IQConst
class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int = 0, val fixedDelay: Int = 1, val fifo: Boolean = false) extends IQModule {
object OneCycleFire {
def apply(fire: Bool) = {
val valid = RegInit(false.B)
when (valid) { valid := false.B }
when (fire) { valid := true.B }
valid
}
}
class IssueQueue
(
exuCfg: ExuConfig, val wakeupCnt: Int, val bypassCnt: Int = 0, val fifo: Boolean = false
) extends IQModule {
val useBypass = bypassCnt > 0
val src2Use = true
val src3Use = fuTypeInt==FuType.fmac.litValue()
val src3Use = (exuCfg.intSrcCnt > 2) || (exuCfg.fpSrcCnt > 2)
val src2Listen = true
val src3Listen = fuTypeInt==FuType.fmac.litValue()
val src3Listen = (exuCfg.intSrcCnt > 2) || (exuCfg.fpSrcCnt > 2)
val io = IO(new Bundle() {
// flush Issue Queue
......@@ -43,6 +58,9 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
// use bypass uops to speculative wake-up
val bypassUops = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new MicroOp))) else null
val bypassData = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new ExuOutput))) else null
// to Dispatch
val numExist = Output(UInt(iqIdxWidth.W))
})
val srcAllNum = 3
......@@ -78,7 +96,7 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
srcDataWire := srcData
srcData := srcDataWire
// there is three stage
// there are three stages
// |-------------|--------------------|--------------|
// |Enq:get state|Deq: select/get data| fire stage |
// |-------------|--------------------|--------------|
......@@ -92,7 +110,9 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
val popOne = Wire(Bool())
io.enqCtrl.ready := !full || popOne
val enqSelIq = Wire(UInt(iqIdxWidth.W))
val enqSrcRdy = List(Mux(SrcType.isPcImm(io.enqCtrl.bits.src1State), true.B, io.enqCtrl.bits.src1State === SrcState.rdy), Mux(SrcType.isPcImm(io.enqCtrl.bits.src2State), true.B, io.enqCtrl.bits.src2State === SrcState.rdy), Mux(SrcType.isPcImm(io.enqCtrl.bits.src3State), true.B, io.enqCtrl.bits.src3State === SrcState.rdy))
val enqSrcRdy = List(Mux(SrcType.isPcImm(io.enqCtrl.bits.ctrl.src1Type), true.B, io.enqCtrl.bits.src1State === SrcState.rdy),
Mux(SrcType.isPcImm(io.enqCtrl.bits.ctrl.src2Type), true.B, io.enqCtrl.bits.src2State === SrcState.rdy),
Mux(SrcType.isPcImm(io.enqCtrl.bits.ctrl.src3Type), true.B, io.enqCtrl.bits.src3State === SrcState.rdy))
// state enq
when (enqFire) {
......@@ -184,7 +204,7 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
// redirect issQue
val redHitVec = List.tabulate(iqSize)(i => issQue(i).uop.brTag.needFlush(io.redirect))
for (i <- 0 until iqSize) {
for (i <- validQue.indices) {
when (redHitVec(i) && validQue(i)) {
validQue(i) := false.B
}
......@@ -199,7 +219,7 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
val issueToExu = Reg(new ExuInput)
val issueToExuValid = RegInit(false.B)
val deqFlushHit = issueToExu.uop.brTag.needFlush(io.redirect)
val deqCanIn = !issueToExuValid || deqFire || deqFlushHit
val deqCanIn = !issueToExuValid || io.deq.ready || deqFlushHit
val toIssFire = deqCanIn && has1Rdy && !isPop && !selIsRed
popOne := deqCanIn && (has1Rdy || isPop) // send a empty or valid term to issueStage
......@@ -220,7 +240,6 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
io.deq.valid := issueToExuValid && !deqFlushHit
io.deq.bits := issueToExu
enqSelIq := Mux(full,
Mux(isPop,
idQue(popSel),
......@@ -229,19 +248,43 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
idQue(tail)
) // Note: direct by IQue's idx, different from deqSel
io.numExist := Mux(tailAll === iqSize.U, (iqSize-1).U, tailAll)
assert(tailAll < 9.U)
//-----------------------------------------
// Issue with No Delay
//-----------------------------------------
// when enq is ready && no other rdy && no pop && fireStage is ready && no flush
// send out directly without store the data
val enqAlreadyRdy = if(src3Listen) { if(src2Listen) enqSrcRdy(0)&&enqSrcRdy(1)&&enqSrcRdy(2) else enqSrcRdy(0)&&enqSrcRdy(2) } else { if(src2Listen) enqSrcRdy(0)&&enqSrcRdy(1) else enqSrcRdy(0) }
val enqALRdyNext = OneCycleFire(enqAlreadyRdy && enqFire)
val enqSendFlushHit = issQue(enqSelIqNext).uop.brTag.needFlush(io.redirect)
val enqSendEnable = if(fifo) { RegNext(tailAll===0.U) && enqALRdyNext && (!issueToExuValid || deqFlushHit) && (enqSelIqNext === deqSelIq) && !isPop && !enqSendFlushHit/* && has1Rdy*//* && io.deq.ready*/ } else { enqALRdyNext && (!issueToExuValid || deqFlushHit) && (enqSelIqNext === deqSelIq) && !isPop && !enqSendFlushHit/* && has1Rdy*//* && io.deq.ready*/ } // FIXME: has1Rdy has combination loop
when (enqSendEnable) {
io.deq.valid := true.B
io.deq.bits := issQue(enqSelIqNext)
io.deq.bits.src1 := enqDataVec(0)
if (src2Use) { io.deq.bits.src2 := enqDataVec(1) }
if (src3Use) { io.deq.bits.src3 := enqDataVec(2) }
issueToExuValid := false.B
when (!io.deq.ready) { // if Func Unit is not ready, store it to FireStage
issueToExuValid := true.B
}
}
//-----------------------------------------
// Wakeup and Bypass
//-----------------------------------------
if (wakeupCnt > 0) {
val cdbValid = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).valid)
val cdbData = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.data)
val cdbPdest = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.uop.pdest)
val cdbrfWen = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.uop.ctrl.rfWen)
val cdbfpWen = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.uop.ctrl.fpWen)
val cdbValid = io.wakeUpPorts.map(_.valid)
val cdbData = io.wakeUpPorts.map(_.bits.data)
val cdbPdest = io.wakeUpPorts.map(_.bits.uop.pdest)
val cdbrfWen = io.wakeUpPorts.map(_.bits.uop.ctrl.rfWen)
val cdbfpWen = io.wakeUpPorts.map(_.bits.uop.ctrl.fpWen)
for(i <- 0 until iqSize) {
for(i <- idQue.indices) { // Should be IssQue.indices but Mem() does not support
for(j <- 0 until srcListenNum) {
val hitVec = List.tabulate(wakeupCnt)(k => psrc(i)(j) === cdbPdest(k) && cdbValid(k) && (srcType(i)(j)===SrcType.reg && cdbrfWen(k) || srcType(i)(j)===SrcType.fp && cdbfpWen(k)))
val hitVec = cdbValid.indices.map(k => psrc(i)(j) === cdbPdest(k) && cdbValid(k) && (srcType(i)(j)===SrcType.reg && cdbrfWen(k) || srcType(i)(j)===SrcType.fp && cdbfpWen(k)))
val hit = ParallelOR(hitVec).asBool
val data = ParallelMux(hitVec zip cdbData)
when (validQue(i) && !srcRdyVec(i)(j) && hit) {
......@@ -249,36 +292,36 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
srcRdyVec(i)(j) := true.B
}
// XSDebug(validQue(i) && !srcRdyVec(i)(j) && hit, "WakeUp: Sel:%d Src:(%d|%d) Rdy:%d Hit:%d HitVec:%b Data:%x\n", i.U, j.U, psrc(i)(j), srcRdyVec(i)(j), hit, VecInit(hitVec).asUInt, data)
for (k <- 0 until wakeupCnt) {
for (k <- cdbValid.indices) {
XSDebug(validQue(i) && !srcRdyVec(i)(j) && hit && hitVec(k), "WakeUpHit: IQIdx:%d Src%d:%d Ports:%d Data:%x Pc:%x RoqIdx:%x\n", i.U, j.U, psrc(i)(j), k.U, cdbData(k), io.wakeUpPorts(k).bits.uop.cf.pc, io.wakeUpPorts(k).bits.uop.roqIdx)
}
}
}
}
if (useBypass) {
val bpPdest = List.tabulate(bypassCnt)(i => io.bypassUops(i).bits.pdest)
val bpValid = List.tabulate(bypassCnt)(i => io.bypassUops(i).valid)
val bpData = List.tabulate(bypassCnt)(i => io.bypassData(i).bits.data)
val bprfWen = List.tabulate(bypassCnt)(i => io.bypassUops(i).bits.ctrl.rfWen)
val bpfpWen = List.tabulate(bypassCnt)(i => io.bypassUops(i).bits.ctrl.fpWen)
val bpPdest = io.bypassUops.map(_.bits.pdest)
val bpValid = io.bypassUops.map(_.valid)
val bpData = io.bypassData.map(_.bits.data)
val bprfWen = io.bypassUops.map(_.bits.ctrl.rfWen)
val bpfpWen = io.bypassUops.map(_.bits.ctrl.fpWen)
for (i <- 0 until iqSize) {
for (i <- idQue.indices) { // Should be IssQue.indices but Mem() does not support
for (j <- 0 until srcListenNum) {
val hitVec = List.tabulate(bypassCnt)(k => psrc(i)(j) === bpPdest(k) && bpValid(k) && (srcType(i)(j)===SrcType.reg && bprfWen(k) || srcType(i)(j)===SrcType.fp && bpfpWen(k)))
val hitVec = bpValid.indices.map(k => psrc(i)(j) === bpPdest(k) && bpValid(k) && (srcType(i)(j)===SrcType.reg && bprfWen(k) || srcType(i)(j)===SrcType.fp && bpfpWen(k)))
val hitVecNext = hitVec.map(RegNext(_))
val hit = ParallelOR(hitVec).asBool
when (validQue(i) && !srcRdyVec(i)(j) && hit) {
srcRdyVec(i)(j) := true.B // FIXME: if uncomment the up comment, will cause combiantional loop, but it is Mem type??
srcRdyVec(i)(j) := true.B
}
when (RegNext(validQue(i) && !srcRdyVec(i)(j) && hit)) {
srcDataWire(i)(j) := PriorityMux(hitVecNext zip bpData)
}
// XSDebug(validQue(i) && !srcRdyVec(i)(j) && hit, "BypassCtrl: Sel:%d Src:(%d|%d) Rdy:%d Hit:%d HitVec:%b\n", i.U, j.U, psrc(i)(j), srcRdyVec(i)(j), hit, VecInit(hitVec).asUInt)
for (k <- 0 until bypassCnt) {
for (k <- bpValid.indices) {
XSDebug(validQue(i) && !srcRdyVec(i)(j) && hit && hitVec(k), "BypassCtrlHit: IQIdx:%d Src%d:%d Ports:%d Pc:%x RoqIdx:%x\n", i.U, j.U, psrc(i)(j), k.U, io.bypassUops(k).bits.cf.pc, io.bypassUops(k).bits.roqIdx)
}
// XSDebug(RegNext(validQue(i) && !srcRdyVec(i)(j) && hit), "BypassData: Sel:%d Src:(%d|%d) HitVecNext:%b Data:%x (for last cycle's Ctrl)\n", i.U, j.U, psrc(i)(j), VecInit(hitVecNext).asUInt, ParallelMux(hitVecNext zip bpData))
for (k <- 0 until bypassCnt) {
for (k <- bpValid.indices) {
XSDebug(RegNext(validQue(i) && !srcRdyVec(i)(j) && hit && hitVec(k)), "BypassDataHit: IQIdx:%d Src%d:%d Ports:%d Data:%x Pc:%x RoqIdx:%x\n", i.U, j.U, psrc(i)(j), k.U, bpData(k), io.bypassUops(k).bits.cf.pc, io.bypassUops(k).bits.roqIdx)
}
}
......@@ -289,7 +332,7 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
val enqPsrc = List(enqCtrl.bits.psrc1, enqCtrl.bits.psrc2, enqCtrl.bits.psrc3)
val enqSrcType = List(enqCtrl.bits.ctrl.src1Type, enqCtrl.bits.ctrl.src2Type, enqCtrl.bits.ctrl.src3Type)
for (i <- 0 until srcListenNum) {
val hitVec = List.tabulate(bypassCnt)(j => enqPsrc(i)===bpPdest(j) && bpValid(j) && (enqSrcType(i)===SrcType.reg && bprfWen(j) || enqSrcType(i)===SrcType.fp && bpfpWen(j)))
val hitVec = bpValid.indices.map(j => enqPsrc(i)===bpPdest(j) && bpValid(j) && (enqSrcType(i)===SrcType.reg && bprfWen(j) || enqSrcType(i)===SrcType.fp && bpfpWen(j)))
val hitVecNext = hitVec.map(RegNext(_))
val hit = ParallelOR(hitVec).asBool
when (enqFire && hit && !enqSrcRdy(i)) {
......@@ -299,17 +342,16 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
srcDataWire(enqSelIqNext)(i) := ParallelMux(hitVecNext zip bpData)
}
// XSDebug(enqFire && hit, "EnqBypassCtrl: enqSelIq:%d Src:(%d|%d) Hit:%d HitVec:%b \n", enqSelIq, i.U, enqPsrc(i), hit, VecInit(hitVec).asUInt)
for (k <- 0 until bypassCnt) {
for (k <- bpValid.indices) {
XSDebug(enqFire && hit && !enqSrcRdy(i) && hitVec(k), "EnqBypassCtrlHit: enqSelIq:%d Src%d:%d Ports:%d Pc:%x RoqIdx:%x\n", enqSelIq, i.U, enqPsrc(i), k.U, io.bypassUops(k).bits.cf.pc, io.bypassUops(k).bits.roqIdx)
}
// XSDebug(RegNext(enqFire && hit), "EnqBypassData: enqSelIqNext:%d Src:(%d|%d) HitVecNext:%b Data:%x (for last cycle's Ctrl)\n", enqSelIqNext, i.U, enqPsrc(i), VecInit(hitVecNext).asUInt, ParallelMux(hitVecNext zip bpData))
for (k <- 0 until bypassCnt) {
for (k <- bpValid.indices) {
XSDebug(RegNext(enqFire && hit && !enqSrcRdy(i) && hitVec(k)), "EnqBypassDataHit: enqSelIq:%d Src%d:%d Ports:%d Data:%x Pc:%x RoqIdx:%x\n", enqSelIq, i.U, enqPsrc(i), k.U, bpData(k), io.bypassUops(k).bits.cf.pc, io.bypassUops(k).bits.roqIdx)
}
}
// send out bypass
assert(fixedDelay==1) // only support fixedDelay is 1 now
val sel = io.selectedUop
sel.valid := toIssFire
sel.bits := DontCare
......@@ -331,7 +373,10 @@ class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int =
} else {
XSDebug("popOne:%d isPop:%d popSel:%d deqSel:%d deqCanIn:%d toIssFire:%d has1Rdy:%d selIsRed:%d nonValid:%b\n", popOne, isPop, popSel, deqSel, deqCanIn, toIssFire, has1Rdy, selIsRed, nonValid)
}
XSDebug("id|v|r|psrc|r| src1 |psrc|r| src2 |psrc|r| src3 |brTag| pc |roqIdx FuType:%x\n", fuTypeInt.U)
XSDebug(enqSendEnable, p"NoDelayIss: enqALRdy:${enqAlreadyRdy} *Next:${enqALRdyNext} En:${enqSendEnable} flush:${enqSendFlushHit} enqSelIqNext:${enqSelIqNext} deqSelIq:${deqSelIq} deqReady:${io.deq.ready}\n")
XSDebug(s"id|v|r|psrc|r| src1 |psrc|r| src2 |psrc|r| src3 |brTag| pc |roqIdx Exu:${exuCfg.name}\n")
for (i <- 0 until iqSize) {
when (i.U===tail && tailAll=/=8.U) {
XSDebug("%d |%d|%d| %d|%b|%x| %d|%b|%x| %d|%b|%x| %x |%x|%x <-\n",
......
......@@ -83,15 +83,6 @@ package object backend {
def isBranchInvert(func: UInt) = func(0)
}
object MULOpType {
def mul = "b0000".U
def mulh = "b0001".U
def mulhsu = "b0010".U
def mulhu = "b0011".U
def mulw = "b1000".U
}
object MDUOpType {
def mul = "b0000".U
def mulh = "b0001".U
......@@ -114,7 +105,7 @@ package object backend {
def isW(op: UInt) = op(3)
}
object LDUOpType {
object LSUOpType {
def lb = "b000000".U
def lh = "b000001".U
def lw = "b000010".U
......@@ -122,37 +113,28 @@ package object backend {
def lbu = "b000100".U
def lhu = "b000101".U
def lwu = "b000110".U
def flw = "b010110".U // box 32-bit data to 64-bit with 1s
// def lr = "b100000".U
// def sc = "b100001".U
// def amoswap = "b100010".U
// def amoadd = "b100011".U
// def amoxor = "b100100".U
// def amoand = "b100101".U
// def amoor = "b100110".U
// def amomin = "b110111".U
// def amomax = "b110000".U
// def amominu = "b110001".U
// def amomaxu = "b110010".U
def isStore(func: UInt): Bool = func(3)
def isAtom(func: UInt): Bool = func(5)
def isLoad(func: UInt): Bool = !isStore(func) & !isAtom(func)
// def isLR(func: UInt): Bool = func === lr
// def isSC(func: UInt): Bool = func === sc
// def isAMO(func: UInt): Bool = isAtom(func) && !isLR(func) && !isSC(func)
// def atomW = "010".U
// def atomD = "011".U
}
object STUOpType {
def sb = "b001000".U
def sh = "b001001".U
def sw = "b001010".U
def sd = "b001011".U
def lr = "b100010".U
def sc = "b100011".U
def amoswap = "b100001".U
def amoadd = "b100000".U
def amoxor = "b100100".U
def amoand = "b101100".U
def amoor = "b101000".U
def amomin = "b110000".U
def amomax = "b110100".U
def amominu = "b111000".U
def amomaxu = "b111100".U
def isStore(func: UInt): Bool = func(3)
def isAtom(func: UInt): Bool = func(5)
def atomW = "010".U
def atomD = "011".U
}
......
......@@ -15,7 +15,7 @@ class Roq(implicit val p: XSConfig) extends XSModule {
val roqIdxs = Output(Vec(RenameWidth, UInt(RoqIdxWidth.W)))
val redirect = Output(Valid(new Redirect))
// exu + brq
val exeWbResults = Vec(exuConfig.ExuCnt + 1, Flipped(ValidIO(new ExuOutput)))
val exeWbResults = Vec(exuParameters.ExuCnt + 1, Flipped(ValidIO(new ExuOutput)))
val commits = Vec(CommitWidth, Valid(new RoqCommit))
val scommit = Output(UInt(3.W))
})
......
package xiangshan.frontend
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
class Ibuffer extends XSModule {
val io = IO(new Bundle() {
val flush = Input(Bool())
val in = Flipped(DecoupledIO(new FetchPacket))
val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
})
// ignore
for(i <- 0 until DecodeWidth) {
io.out(i).bits.exceptionVec := DontCare
io.out(i).bits.intrVec := DontCare
io.out(i).bits.isBr := DontCare
}
//mask initial
// val mask = Wire(Vec(FetchWidth*2, false.B))
// (0 until 16).map(i => mask(i.U) := (io.in.bits.pc(4,1) <= i.U))
// ibuf define
val ibuf = Reg(Vec(IBufSize*2, UInt(16.W)))
val ibuf_pc = Reg(Vec(IBufSize*2, UInt(VAddrBits.W)))
val ibuf_valid = RegInit(VecInit(Seq.fill(IBufSize*2)(false.B)))
val head_ptr = RegInit(0.U(log2Up(IBufSize*2).W))
val tail_ptr = RegInit(0.U(log2Up(IBufSize*2).W))
// true: Last operation is enqueue
// false: Last operation is deq_ueue
val last_enq = RegInit(false.B)
val full = head_ptr === tail_ptr && last_enq
val empty = head_ptr === tail_ptr && !last_enq
val enqValid = !io.flush && io.in.valid && !full && !ibuf_valid(tail_ptr + (FetchWidth*2).U)
val deqValid = !io.flush && !empty //&& io.out.map(_.ready).reduce(_||_)
io.in.ready := enqValid
// enque
when(enqValid) {
var enq_idx = 0.U(log2Up(FetchWidth*2+1).W)
for(i <- 0 until FetchWidth*2) {
when(io.in.bits.mask(i)) {
ibuf(tail_ptr + enq_idx) := Mux(i.U(0), io.in.bits.instrs(i>>1)(31,16), io.in.bits.instrs(i>>1)(15,0))
ibuf_pc(tail_ptr + enq_idx) := io.in.bits.pc + (enq_idx<<1).asUInt
ibuf_valid(tail_ptr + enq_idx) := true.B
}
enq_idx = enq_idx + io.in.bits.mask(i)
}
tail_ptr := tail_ptr + enq_idx
last_enq := true.B
}
// deque
when(deqValid) {
var deq_idx = 0.U(log2Up(DecodeWidth*2+1).W)
for(i <- 0 until DecodeWidth) {
when(io.out(i).ready && ibuf_valid(head_ptr + deq_idx)) {
when(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) {
// is RVC
io.out(i).bits.instr := Cat(0.U(16.W), ibuf(head_ptr + deq_idx))
io.out(i).bits.pc := ibuf_pc(head_ptr + deq_idx)
io.out(i).bits.isRVC := true.B
io.out(i).valid := true.B
ibuf_valid(head_ptr + deq_idx) := false.B
}.elsewhen(ibuf_valid(head_ptr + deq_idx + 1.U)) {
// isn't RVC
io.out(i).bits.instr := Cat(ibuf(head_ptr + deq_idx+1.U), ibuf(head_ptr + deq_idx))
io.out(i).bits.pc := ibuf_pc(head_ptr + deq_idx)
io.out(i).bits.isRVC := false.B
io.out(i).valid := true.B
ibuf_valid(head_ptr + deq_idx) := false.B
ibuf_valid(head_ptr + deq_idx+1.U) := false.B
}.otherwise {
// half inst keep in buffer
io.out(i).bits.instr := 0.U(32.W)
io.out(i).bits.pc := 0.U(VAddrBits.W)
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
}.otherwise {
io.out(i).bits.instr := Cat(ibuf(head_ptr + (i<<1).U + 1.U), ibuf(head_ptr + (i<<1).U))
io.out(i).bits.pc := ibuf_pc(head_ptr + (i<<1).U)
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
// When can't deque, deq_idx+0
// when RVC deque, deq_idx+1
// when not RVC deque, deq_idx+2
// when only have half inst, keep it in buffer
deq_idx = deq_idx + PriorityMux(Seq(
!(io.out(i).ready && ibuf_valid(head_ptr + deq_idx)) -> 0.U,
(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) -> 1.U,
ibuf_valid(head_ptr + deq_idx + 1.U) -> 2.U
))
}
head_ptr := head_ptr + deq_idx
last_enq := false.B
}.otherwise {
for(i <- 0 until DecodeWidth) {
io.out(i).bits.instr := 0.U
io.out(i).bits.pc := 0.U
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
}
// flush
when(io.flush) {
for(i <- 0 until IBufSize*2) {
ibuf_valid(i) := false.B
}
head_ptr := 0.U
tail_ptr := 0.U
for(i <- 0 until DecodeWidth) {
io.out(i).valid := false.B
}
}
//Debug Info
XSDebug(enqValid, "Enque:\n")
for(i <- 0 until FetchWidth) {
XSDebug(enqValid, p"${Binary(io.in.bits.instrs(i))}\n")
}
XSInfo(io.flush, "Flush signal received, clear buffer\n")
XSDebug(deqValid, "Deque:\n")
for(i <- 0 until DecodeWidth) {
XSDebug(deqValid, p"${Binary(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)} v=${io.out(i).valid} r=${io.out(i).ready}\n")
}
XSDebug(enqValid, p"last_head_ptr=$head_ptr last_tail_ptr=$tail_ptr\n")
// XSInfo(full, "Queue is full\n")
}
package xiangshan.frontend
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
class Ibuffer extends XSModule {
val io = IO(new Bundle() {
val flush = Input(Bool())
val in = Flipped(DecoupledIO(new FetchPacket))
val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
})
// ignore
for(i <- 0 until DecodeWidth) {
io.out(i).bits.exceptionVec := DontCare
io.out(i).bits.intrVec := DontCare
io.out(i).bits.isBr := DontCare
}
//mask initial
// val mask = Wire(Vec(FetchWidth*2, false.B))
// (0 until 16).map(i => mask(i.U) := (io.in.bits.pc(4,1) <= i.U))
// ibuf define
val ibuf = Reg(Vec(IBufSize*2, UInt(16.W)))
val ibuf_pc = Reg(Vec(IBufSize*2, UInt(VAddrBits.W)))
val ibuf_valid = RegInit(VecInit(Seq.fill(IBufSize*2)(false.B)))
val head_ptr = RegInit(0.U(log2Up(IBufSize*2).W))
val tail_ptr = RegInit(0.U(log2Up(IBufSize*2).W))
// true: Last operation is enqueue
// false: Last operation is deq_ueue
val last_enq = RegInit(false.B)
val full = head_ptr === tail_ptr && last_enq
val empty = head_ptr === tail_ptr && !last_enq
val enqValid = !io.flush && io.in.valid && !full && !ibuf_valid(tail_ptr + (FetchWidth*2).U)
val deqValid = !io.flush && !empty //&& io.out.map(_.ready).reduce(_||_)
io.in.ready := enqValid
// enque
when(enqValid) {
var enq_idx = 0.U(log2Up(FetchWidth*2+1).W)
for(i <- 0 until FetchWidth*2) {
when(io.in.bits.mask(i)) {
ibuf(tail_ptr + enq_idx) := Mux(i.U(0), io.in.bits.instrs(i>>1)(31,16), io.in.bits.instrs(i>>1)(15,0))
ibuf_pc(tail_ptr + enq_idx) := io.in.bits.pc + (enq_idx<<1).asUInt
ibuf_valid(tail_ptr + enq_idx) := true.B
}
enq_idx = enq_idx + io.in.bits.mask(i)
}
tail_ptr := tail_ptr + enq_idx
last_enq := true.B
}
// deque
when(deqValid) {
var deq_idx = 0.U(log2Up(DecodeWidth*2+1).W)
for(i <- 0 until DecodeWidth) {
when(io.out(i).ready && ibuf_valid(head_ptr + deq_idx)) {
when(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) {
// is RVC
io.out(i).bits.instr := Cat(0.U(16.W), ibuf(head_ptr + deq_idx))
io.out(i).bits.pc := ibuf_pc(head_ptr + deq_idx)
io.out(i).bits.isRVC := true.B
io.out(i).valid := true.B
ibuf_valid(head_ptr + deq_idx) := false.B
}.elsewhen(ibuf_valid(head_ptr + deq_idx + 1.U)) {
// isn't RVC
io.out(i).bits.instr := Cat(ibuf(head_ptr + deq_idx+1.U), ibuf(head_ptr + deq_idx))
io.out(i).bits.pc := ibuf_pc(head_ptr + deq_idx)
io.out(i).bits.isRVC := false.B
io.out(i).valid := true.B
ibuf_valid(head_ptr + deq_idx) := false.B
ibuf_valid(head_ptr + deq_idx+1.U) := false.B
}.otherwise {
// half inst keep in buffer
io.out(i).bits.instr := 0.U(32.W)
io.out(i).bits.pc := 0.U(VAddrBits.W)
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
}.otherwise {
io.out(i).bits.instr := Cat(ibuf(head_ptr + (i<<1).U + 1.U), ibuf(head_ptr + (i<<1).U))
io.out(i).bits.pc := ibuf_pc(head_ptr + (i<<1).U)
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
// When can't deque, deq_idx+0
// when RVC deque, deq_idx+1
// when not RVC deque, deq_idx+2
// when only have half inst, keep it in buffer
deq_idx = deq_idx + PriorityMux(Seq(
!(io.out(i).ready && ibuf_valid(head_ptr + deq_idx)) -> 0.U,
(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) -> 1.U,
ibuf_valid(head_ptr + deq_idx + 1.U) -> 2.U
))
}
head_ptr := head_ptr + deq_idx
last_enq := false.B
}.otherwise {
for(i <- 0 until DecodeWidth) {
io.out(i).bits.instr := 0.U
io.out(i).bits.pc := 0.U
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
}
// flush
when(io.flush) {
for(i <- 0 until IBufSize*2) {
ibuf_valid(i) := false.B
}
head_ptr := 0.U
tail_ptr := 0.U
for(i <- 0 until DecodeWidth) {
io.out(i).valid := false.B
}
}
//Debug Info
XSDebug(enqValid, "Enque:\n")
for(i <- 0 until FetchWidth) {
XSDebug(enqValid, p"${Binary(io.in.bits.instrs(i))}\n")
}
XSInfo(io.flush, "Flush signal received, clear buffer\n")
XSDebug(deqValid, "Deque:\n")
for(i <- 0 until DecodeWidth) {
XSDebug(deqValid, p"${Binary(io.out(i).bits.instr)} PC=${Hexadecimal(io.out(i).bits.pc)} v=${io.out(i).valid} r=${io.out(i).ready}\n")
}
XSDebug(enqValid, p"last_head_ptr=$head_ptr last_tail_ptr=$tail_ptr\n")
// XSInfo(full, "Queue is full\n")
}
......@@ -26,25 +26,45 @@ package object xiangshan {
}
object FuType extends HasXSParameter {
def num = exuConfig.NRFuType
def bru = "b0000".U
def alu = "b0001".U
def mul = "b0010".U
def mdu = "b0011".U
def fmac = "b0100".U
def fmisc = "b0101".U
def fmiscDivSqrt = "b0110".U
def ldu = "b1001".U
def stu = "b1000".U
def num = exuParameters.NRFuType
def jmp = "b0000".U
def i2f = "b0001".U
def csr = "b0010".U
def alu = "b0011".U
def mul = "b0100".U
def div = "b0101".U
def fmac = "b1000".U
def fmisc = "b1001".U
def fDivSqrt = "b1010".U
def ldu = "b1100".U
def stu = "b1101".U
def apply() = UInt(log2Up(num).W)
def isIntExu(fuType: UInt) = fuType(3, 2) === "b00".U
def isFpExu(fuType: UInt) = fuType(2)
def isMemExu(fuType: UInt) = fuType(3)
def isIntExu(fuType: UInt) = !fuType(3)
def isFpExu(fuType: UInt) = fuType(3, 2) === "b10".U
def isMemExu(fuType: UInt) = fuType(3, 2) === "b11".U
val functionNameMap = Map(
jmp.litValue() -> "jmp",
i2f.litValue() -> "int to float",
csr.litValue() -> "csr",
alu.litValue() -> "alu",
mul.litValue() -> "mul",
div.litValue() -> "div",
fmac.litValue() -> "fmac",
fmisc.litValue() -> "fmisc",
fDivSqrt.litValue() -> "fdiv/fsqrt",
ldu.litValue() -> "load",
stu.litValue() -> "store"
)
}
object FuOpType extends HasXSParameter {
def apply() = UInt(exuConfig.FuOpWidth.W)
def apply() = UInt(exuParameters.FuOpWidth.W)
}
}
......@@ -149,7 +149,7 @@ class Emulator {
tfp->open("vlt_dump.vcd"); // Open the dump file
#endif
while (n > 0) {
while (!is_finish() && n > 0) {
single_cycle();
n --;
......
......@@ -97,3 +97,7 @@ object TestMain extends App {
Seq(ChiselGeneratorAnnotation(() => new XSSimTop))
)
}
object FirMain extends App{
firrtl.stage.FirrtlMain.stage.execute(args, Seq(ChiselGeneratorAnnotation(() => new XSSimTop)))
}
......@@ -19,7 +19,7 @@ class AluTest extends FlatSpec
with HasPartialDecoupledDriver
{
it should "do simple test corrcetly" in {
test(new Alu){c =>
test(new AluExeUnit){c =>
c.io.in.initSource().setSourceClock(c.clock)
c.io.out.initSink().setSinkClock(c.clock)
......@@ -32,7 +32,7 @@ class AluTest extends FlatSpec
}
it should "do random add correctly" in {
test(new Alu){c =>
test(new AluExeUnit){c =>
c.io.in.initSource().setSourceClock(c.clock)
c.io.out.initSink().setSinkClock(c.clock)
......
......@@ -6,30 +6,23 @@ import chisel3._
import chisel3.experimental.BundleLiterals._
import chiseltest.experimental.TestOptionBuilder._
import chiseltest.internal.VerilatorBackendAnnotation
import bus.axi4.AXI4Delayer
import bus.simplebus.{SimpleBusCrossbarNto1, SimpleBusUC}
import device.AXI4RAM
import noop.{Cache, CacheConfig, MemMMUIO, TLB, TLBConfig}
import system.CoherenceManager
import xiangshan._
import xiangshan.backend.fu.FunctionUnit.lsuCfg
import xiangshan.testutils._
import xiangshan.testutils.TestCaseGenerator._
import scala.util.Random
class LsuDut(dispBegin: Int, dispEnd: Int) extends Exu(
FuType.ldu.litValue(),
readIntRf = true,
readFpRf = true,
writeIntRf = true,
writeFpRf = true
) {
class LsuDut(dispBegin: Int, dispEnd: Int) extends Exu(Exu.lsuExeUnitCfg) {
io.dmem <> DontCare
val lsu = Module(new Lsu)
val lsu = Module(new LsExeUnit)
lsu.io.in <> io.in
lsu.io.redirect <> io.redirect
......
......@@ -24,7 +24,7 @@ class MduTest extends FlatSpec
with HasPartialDecoupledDriver
{
"MUL" should "random enq and deq correctly" in {
test(new Mul{
test(new MulExeUnit{
val disp_begin = WireInit(0.S(64.W).asUInt())
val disp_end = WireInit((-1).S(64.W).asUInt())
BoringUtils.addSource(disp_begin, "DISPLAY_LOG_START")
......@@ -52,7 +52,7 @@ class MduTest extends FlatSpec
"MUL" should "dont flush same br tag" in {
test(new Mul{
test(new MulExeUnit{
val disp_begin = WireInit(0.S(64.W).asUInt())
val disp_end = WireInit((-1).S(64.W).asUInt())
BoringUtils.addSource(disp_begin, "DISPLAY_LOG_START")
......@@ -93,7 +93,7 @@ class MduTest extends FlatSpec
"MDU" should "random enq and deq correctly" in {
test(new Mdu{
test(new MulDivExeUnit{
val disp_begin = WireInit(0.S(64.W).asUInt())
val disp_end = WireInit((-1).S(64.W).asUInt())
BoringUtils.addSource(disp_begin, "DISPLAY_LOG_START")
......
package xiangshan.backend.issue
import org.scalatest._
import chiseltest._
import chisel3._
import chisel3.util._
import chisel3.experimental.BundleLiterals._
import chiseltest.experimental.TestOptionBuilder._
import chiseltest.internal.VerilatorBackendAnnotation
import xiangshan._
import xiangshan.backend.exu.Exu
import xiangshan.testutils._
import xiangshan.testutils.TestCaseGenerator._
import scala.util.Random
class IssueQueueTest extends FlatSpec
with ChiselScalatestTester
with Matchers
with ParallelTestExecution
with HasPartialDecoupledDriver
{
it should "do enq issue with no delay correctly" in {
test(new IssueQueue(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
......@@ -61,15 +61,15 @@ object TestCaseGenerator {
}
def genLsuLd(x: => ExuInput, base: Long, offset: Long) =
genLsuInput(LDUOpType.ld)(x, base, offset, 0)
genLsuInput(LSUOpType.ld)(x, base, offset, 0)
def genLsuLw(x: => ExuInput, base: Long, offset: Long) =
genLsuInput(LDUOpType.lw)(x, base, offset, 0)
genLsuInput(LSUOpType.lw)(x, base, offset, 0)
def genLsuSd(x: => ExuInput, base: Long, offset: Long, stData: Long) =
genLsuInput(STUOpType.sd)(x, base, offset, stData)
genLsuInput(LSUOpType.sd)(x, base, offset, stData)
def genLsuSw(x: => ExuInput, base: Long, offset: Long, stData: Long) =
genLsuInput(STUOpType.sw)(x, base, offset, stData)
genLsuInput(LSUOpType.sw)(x, base, offset, stData)
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册