提交 8c0bf90f 编写于 作者: Y Your Name

Merge branch 'master' into ibuf

......@@ -68,7 +68,7 @@ class Dp1ToDp2IO extends XSBundle {
}
class DebugBundle extends XSBundle{
val isMMIO = Output(Bool())
val isMMIO = Bool()
}
class ExuInput extends XSBundle {
......
......@@ -8,8 +8,10 @@ import xiangshan.backend._
import xiangshan.backend.dispatch.DP1Config
import xiangshan.backend.exu.ExuConfig
import xiangshan.frontend.Frontend
import xiangshan.utils._
trait HasXSParameter {
val LogLevel = XSLogLevel.ALL
val XLEN = 64
val HasMExtension = true
val HasCExtension = true
......@@ -60,9 +62,14 @@ trait HasXSParameter {
)
}
trait HasXSLog { this: Module =>
implicit val _implict_module = this
}
abstract class XSModule extends Module
with HasXSParameter
with HasExceptionNO
with HasXSLog
//remove this trait after impl module logic
trait NeedImpl { this: Module =>
......
......@@ -48,25 +48,40 @@ class Backend(implicit val p: XSConfig) extends XSModule
))
val redirect = Mux(roq.io.redirect.valid, roq.io.redirect, brq.io.redirect)
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)
val bypassCnt = if(eu.fuTypeInt == FuType.alu.litValue()) exuConfig.AluCnt else 0
val iq = Module(new IssueQueue(eu.fuTypeInt, wakeupCnt, bypassCnt))
assert(!(needBypass(eu) && !needWakeup(eu))) // needBypass but dont needWakeup is not allowed
val iq = Module(new IssueQueue(eu.fuTypeInt, wakeupCnt, bypassCnt, eu.fixedDelay))
iq.io.redirect <> redirect
iq.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
iq.io.enqData <> dispatch.io.enqIQData(i)
iq.io.wakeUpPorts <> exeUnits.filter(needWakeup).map(_.io.out)
val wuUnitsOut = exeUnits.filter(e => needWakeup(e)).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")
eu.io.in <> iq.io.deq
eu.io.redirect <> redirect
iq
})
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)
val bypassQueues = issueQueues.filter(_.bypassCnt > 0)
val bypassUnits = exeUnits.filter(_.enableBypass)
bypassQueues.foreach(iq => {
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)
......@@ -104,7 +119,7 @@ class Backend(implicit val p: XSConfig) extends XSModule
fpRf.io.readPorts <> dispatch.io.readFpRf
val exeWbReqs = exeUnits.map(_.io.out)
val wbIntReqs = (bruExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits)).map(_.io.out)
val wbIntReqs = (bruExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ lsuExeUnits)).map(_.io.out)
val wbFpReqs = (fmacExeUnits ++ fmiscExeUnits ++ fmiscDivSqrtExeUnits).map(_.io.out)
val intWbArb = Module(new WriteBackArbMtoN(wbIntReqs.length, NRWritePorts))
val fpWbArb = Module(new WriteBackArbMtoN(wbFpReqs.length, NRWritePorts))
......@@ -152,27 +167,4 @@ class Backend(implicit val p: XSConfig) extends XSModule
)
for (s <- sinks){ BoringUtils.addSink(tmp, s) }
// A fake commit
// TODO: difftest 6 insts per cycle
val commit = RegNext(RegNext(RegNext(true.B)))
val pc = WireInit("h80000000".U)
val inst = WireInit("h66666666".U)
if(!p.FPGAPlatform){
BoringUtils.addSource(commit, "difftestCommit")
BoringUtils.addSource(pc, "difftestThisPC")
BoringUtils.addSource(inst, "difftestThisINST")
BoringUtils.addSource(tmp, "difftestIsMMIO")
BoringUtils.addSource(tmp, "difftestIsRVC")
BoringUtils.addSource(tmp, "difftestIntrNO")
BoringUtils.addSource(VecInit(Seq.fill(64)(tmp)), "difftestRegs")
BoringUtils.addSource(tmp, "difftestMode")
BoringUtils.addSource(tmp, "difftestMstatus")
BoringUtils.addSource(tmp, "difftestSstatus")
BoringUtils.addSource(tmp, "difftestMepc")
BoringUtils.addSource(tmp, "difftestSepc")
BoringUtils.addSource(tmp, "difftestMcause")
BoringUtils.addSource(tmp, "difftestScause")
}
}
......@@ -3,6 +3,7 @@ package xiangshan.backend.brq
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.XSInfo
......@@ -78,4 +79,23 @@ class Brq extends XSModule {
headPtr := 0.U
tailPtr := 0.U
}
// Debug info
val debug_roq_redirect = io.roqRedirect.valid
val debug_brq_redirect = io.redirect.valid && !debug_roq_redirect
val debug_normal_mode = !(debug_roq_redirect || debug_brq_redirect)
for(i <- 0 until DecodeWidth){
XSInfo(
debug_normal_mode,
p"enq v:${io.enqReqs(i).valid} rdy:${io.enqReqs(i).ready} pc:${Hexadecimal(io.enqReqs(i).bits.cf.pc)}" +
p" brMask:${Binary(io.brMasks(i))} brTag:${io.brTags(i)}\n"
)
}
XSInfo(debug_roq_redirect, "roq redirect, flush brq\n")
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirect.bits.target)}\n")
}
......@@ -3,6 +3,7 @@ package xiangshan.backend.decode
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
class DecodeStage extends XSModule {
val io = IO(new Bundle() {
......@@ -24,7 +25,7 @@ class DecodeStage extends XSModule {
// Handshake ---------------------
// 1. if current instruction is valid, then:
// First, assert toBrq(i).valid and present toBrq(i).bits
// First, assert toBrq(i).valid if (in.valid and out.ready and isBr) and present toBrq(i).bits
// Second, check toBrq(i).ready and connect it to io.out(i).valid
// 2. To Decode Buffer:
// First, assert in(i).ready if out(i).ready
......@@ -34,12 +35,17 @@ class DecodeStage extends XSModule {
decoders(i).io.in <> io.in(i).bits
decoderToBrq(i) := decoders(i).io.out // CfCtrl without bfTag and brMask
// send CfCtrl without brTags and brMasks to brq
io.toBrq(i).valid := io.in(i).valid
io.toBrq(i).valid := io.in(i).valid && io.out(i).ready && decoders(i).io.out.cf.isBr
XSDebug(io.toBrq(i).valid && io.toBrq(i).ready, p"Branch instr detected. Sending it to BRQ.")
XSDebug(io.toBrq(i).valid && !io.toBrq(i).ready, p"Branch instr detected. BRQ full...waiting")
XSDebug(io.in(i).valid && !io.out(i).ready, p"DecBuf full...waiting")
decoderToBrq(i).brMask := DontCare
decoderToBrq(i).brTag := DontCare
io.toBrq(i).bits := decoderToBrq(i)
// if brq returns ready, then assert valid and send CfCtrl with bfTag and brMask to DecBuffer
io.out(i).valid := io.toBrq(i).ready && io.in(i).valid
XSDebug(io.out(i).valid && decoders(i).io.out.cf.isBr && io.out(i).ready, p"Sending branch instr to DecBuf")
XSDebug(io.out(i).valid && !decoders(i).io.out.cf.isBr && io.out(i).ready, p"Sending non-branch instr to DecBuf")
decoderToDecBuffer(i) := decoders(i).io.out
decoderToDecBuffer(i).brTag := io.brTags(i)
decoderToDecBuffer(i).brMask := io.brMasks(i)
......
......@@ -21,6 +21,11 @@ class Decoder extends XSModule with HasInstrType {
val decodeList = ListLookup(instr, Instructions.DecodeDefault, Instructions.DecodeTable)
val instrType :: fuType :: fuOpType :: Nil = decodeList
// 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))
// val isRVC = instr(1, 0) =/= "b11".U
// val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
// ListLookup(instr, CInstructions.DecodeDefault, CInstructions.CExtraDecodeTable)
......
......@@ -3,7 +3,7 @@ package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import utils.{GTimer}
import xiangshan.utils.{XSDebug, XSInfo}
case class DP1Config
(
......@@ -43,14 +43,10 @@ class Dispatch1 extends XSModule{
(io.toLsDq(i).ready && FuType.isMemExu(io.fromRename(i).bits.ctrl.fuType))
enq_valid(i) := io.toIntDq(i).valid || io.toFpDq(i).valid || io.toLsDq(i).valid
io.recv(i) := (enq_ready(i) && enq_valid(i)) || cancelled(i)
when (io.recv(i) && !cancelled(i)) {
printf("[Cycle:%d][Dispatch1] instruction 0x%x accepted by queue %x %x %x\n",
GTimer(), io.fromRename(i).bits.cf.pc, io.toIntDq(i).valid, io.toFpDq(i).valid, io.toLsDq(i).valid)
}
when (io.recv(i) && cancelled(i)) {
printf("[Cycle:%d][Dispatch1] instruction 0x%x with brMask %x brTag %x cancelled\n",
GTimer(), io.fromRename(i).bits.cf.pc, io.fromRename(i).bits.brMask, io.redirect.bits.brTag)
}
XSInfo(io.recv(i) && !cancelled(i), "instruction 0x%x accepted by queue %x %x %x\n",
io.fromRename(i).bits.cf.pc, io.toIntDq(i).valid, io.toFpDq(i).valid, io.toLsDq(i).valid)
XSInfo(io.recv(i) && cancelled(i), "instruction 0x%x with brMask %x brTag %x cancelled\n",
io.fromRename(i).bits.cf.pc, io.fromRename(i).bits.brMask, io.redirect.bits.brTag)
}
// latch indexes from roq in case of DQ not fire
......@@ -62,13 +58,13 @@ class Dispatch1 extends XSModule{
when (io.toRoq(i).fire() && !io.recv(i)) {
roqIndexReg(i) := io.roqIdxs(i)
roqIndexRegValid(i) := true.B
printf("[Cycle:%d][Dispatch1] instruction 0x%x receives nboq %x but not accepted by queue (and it waits)\n",
GTimer(), io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
}
.elsewhen (io.recv(i)) {
roqIndexRegValid(i) := false.B
printf("[Cycle:%d][Dispatch1] waiting instruction 0x%x is accepted by queue\n", GTimer(), io.fromRename(i).bits.cf.pc)
}
XSDebug(io.toRoq(i).fire() && !io.recv(i),
"instruction 0x%x receives nboq %x but not accepted by queue (and it waits)\n",
io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
}
// append nroq to uop
......@@ -76,9 +72,7 @@ class Dispatch1 extends XSModule{
for (i <- 0 until RenameWidth) {
uop_nroq(i) := io.fromRename(i).bits
uop_nroq(i).roqIdx := Mux(io.toRoq(i).ready, io.roqIdxs(i), roqIndexReg(i))
when (io.toRoq(i).fire()) {
printf("[Cycle:%d][Dispatch1] instruction 0x%x receives nroq %d\n", GTimer(), io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
}
XSDebug(io.toRoq(i).fire(), "instruction 0x%x receives nroq %d\n", io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
}
// uop can enqueue when rename.valid and roq.valid
......@@ -100,9 +94,7 @@ class Dispatch1 extends XSModule{
io.toRoq(i).bits <> io.fromRename(i).bits
io.toRoq(i).valid := io.fromRename(i).valid && !roqIndexRegValid(i)
io.fromRename(i).ready := all_recv
when (io.fromRename(i).valid) {
printf("[Cycle:%d][Dispatch1] instruction 0x%x of type %b is in %d-th slot\n",
GTimer(), io.fromRename(i).bits.cf.pc, io.fromRename(i).bits.ctrl.fuType, i.U)
}
XSDebug(io.fromRename(i).valid, "instruction 0x%x of type %b is in %d-th slot\n",
io.fromRename(i).bits.cf.pc, io.fromRename(i).bits.ctrl.fuType, i.U)
}
}
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.utils.GTimer
import xiangshan.utils.{XSDebug, XSInfo}
class Dispatch2 extends XSModule with NeedImpl {
val io = IO(new Bundle() {
......@@ -59,7 +59,7 @@ class Dispatch2 extends XSModule with NeedImpl {
(uop.bits.ctrl.fuType === FuType.fmisc && i.U > fmisc0InstIdx) || uop.bits.ctrl.fuType === FuType.fmiscDivSqrt
}) :+ true.B)
// TODO: currently there's only one LSU
// TODO: currently there's only one load/store reservation station
// val load0InstIdx = PriorityEncoder(io.fromLsDq.map(deq => (deq.bits.ctrl.fuType === FuType.ldu)) :+ true.B)
val load0InstIdx = PriorityEncoder(io.fromLsDq.map(deq => FuType.isMemExu(deq.bits.ctrl.fuType)) :+ true.B)
val load1InstIdx = PriorityEncoder((io.fromLsDq.zipWithIndex map { case (uop, i) =>
......@@ -93,25 +93,31 @@ class Dispatch2 extends XSModule with NeedImpl {
// insert into reservation station
val instIdxes = Seq(bruInstIdx, alu0InstIdx, alu1InstIdx, alu2InstIdx, alu3InstIdx, mulInstIdx, muldivInstIdx,
fmac0InstIdx, fmac1InstIdx, fmac2InstIdx, fmac3InstIdx, fmisc0InstIdx, fmisc1InstIdx,
load0InstIdx, store0InstIdx)
load0InstIdx)//, store0InstIdx)
io.enqIQCtrl.zipWithIndex map { case (enq, i) =>
if (i < exuConfig.IntExuCnt) {
enq.valid := !instIdxes(i)(2) && io.fromIntDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromIntDq(instIdxes(i)(1, 0)).bits
enq.bits.src1State := io.intPregRdy((instIdxes(i) << 1).asUInt())
enq.bits.src2State := io.intPregRdy((instIdxes(i) << 1).asUInt() + 1.U)
}
else if (i < exuConfig.IntExuCnt + exuConfig.FpExuCnt) {
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(instIdxes(i) * 3.U)
enq.bits.src2State := io.fpPregRdy(instIdxes(i) * 3.U + 1.U)
enq.bits.src3State := io.fpPregRdy(instIdxes(i) * 3.U + 2.U)
}
else {
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 := Mux(enq.bits.ctrl.fuType === FuType.ldu, io.intPregRdy(8), io.intPregRdy(10))
enq.bits.src2State := io.intPregRdy(11)
}
when (enq.fire()) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x with type %b enters reservation station %d from %d\n",
GTimer(), enq.bits.cf.pc, enq.bits.ctrl.fuType, i.U, instIdxes(i))
}
XSInfo(enq.fire(), "instruction 0x%x with type %b enters reservation station %d from %d\n",
enq.bits.cf.pc, enq.bits.ctrl.fuType, i.U, instIdxes(i))
}
// responds to dispatch queue
......@@ -119,42 +125,33 @@ class Dispatch2 extends XSModule with NeedImpl {
io.fromIntDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U && (j < exuConfig.IntExuCnt).asBool())
}).reduce((l, r) => l || r)
when (io.fromIntDq(i).fire()) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x leaves Int dispatch queue with nroq %d\n",
GTimer(), io.fromIntDq(i).bits.cf.pc, io.fromIntDq(i).bits.roqIdx)
}
when (io.fromIntDq(i).valid && !io.fromIntDq(i).ready) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x waits at Int dispatch queue with index %d\n",
GTimer(), io.fromIntDq(i).bits.cf.pc, i.U)
}
XSInfo(io.fromIntDq(i).fire(), "instruction 0x%x leaves Int dispatch queue with nroq %d\n",
io.fromIntDq(i).bits.cf.pc, io.fromIntDq(i).bits.roqIdx)
XSDebug(io.fromIntDq(i).valid && !io.fromIntDq(i).ready,
"instruction 0x%x waits at Int dispatch queue with index %d\n",
io.fromIntDq(i).bits.cf.pc, i.U)
}
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())
}).reduce((l, r) => l || r)
when (io.fromFpDq(i).fire()) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x leaves Fp dispatch queue with nroq %d\n",
GTimer(), io.fromFpDq(i).bits.cf.pc, io.fromFpDq(i).bits.roqIdx)
}
when (io.fromFpDq(i).valid && !io.fromFpDq(i).ready) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x waits at Fp dispatch queue with index %d\n",
GTimer(), io.fromFpDq(i).bits.cf.pc, i.U)
}
XSInfo(io.fromFpDq(i).fire(), "instruction 0x%x leaves Fp dispatch queue with nroq %d\n",
io.fromFpDq(i).bits.cf.pc, io.fromFpDq(i).bits.roqIdx)
XSDebug(io.fromFpDq(i).valid && !io.fromFpDq(i).ready,
"instruction 0x%x waits at Fp dispatch queue with index %d\n",
io.fromFpDq(i).bits.cf.pc, i.U)
}
for (i <- 0 until LsDqDeqWidth) {
io.fromLsDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U
&& (j >= exuConfig.IntExuCnt + exuConfig.FpExuCnt).asBool())
}).reduce((l, r) => l || r)
when (io.fromLsDq(i).fire()) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x leaves Ls dispatch queue with nroq %d\n",
GTimer(), io.fromLsDq(i).bits.cf.pc, io.fromLsDq(i).bits.roqIdx)
}
when (io.fromLsDq(i).valid && !io.fromLsDq(i).ready) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x waits at Ls dispatch queue with index %d\n",
GTimer(), io.fromLsDq(i).bits.cf.pc, i.U)
}
XSInfo(io.fromLsDq(i).fire(), "instruction 0x%x leaves Ls dispatch queue with nroq %d\n",
io.fromLsDq(i).bits.cf.pc, io.fromLsDq(i).bits.roqIdx)
XSDebug(io.fromLsDq(i).valid && !io.fromLsDq(i).ready,
"instruction 0x%x waits at Ls dispatch queue with index %d\n",
io.fromLsDq(i).bits.cf.pc, i.U)
}
// next stage: insert data
......@@ -207,12 +204,12 @@ class Dispatch2 extends XSModule with NeedImpl {
io.enqIQData(i).valid := data_valid(i)
io.enqIQData(i).bits.uop := uop_reg(i)
io.enqIQData(i).bits.uop.src1State := Mux(src1Type(i)(1), SrcState.rdy,
Mux(src1Type(i)(0), io.intPregRdy(src1Index(i)), io.fpPregRdy(src1Index(i))))
io.enqIQData(i).bits.uop.src2State := Mux(src2Type(i)(1), SrcState.rdy,
Mux(src2Type(i)(0), io.intPregRdy(src2Index(i)), io.fpPregRdy(src2Index(i))))
io.enqIQData(i).bits.uop.src3State := Mux(src3Type(i)(1), SrcState.rdy,
Mux(src3Type(i)(0), io.intPregRdy(src3Index(i)), io.fpPregRdy(src3Index(i))))
// io.enqIQData(i).bits.uop.src1State := Mux(src1Type(i)(1), SrcState.rdy,
// Mux(src1Type(i)(0), io.intPregRdy(src1Index(i)), io.fpPregRdy(src1Index(i))))
// io.enqIQData(i).bits.uop.src2State := Mux(src2Type(i)(1), SrcState.rdy,
// Mux(src2Type(i)(0), io.intPregRdy(src2Index(i)), io.fpPregRdy(src2Index(i))))
// io.enqIQData(i).bits.uop.src3State := Mux(src3Type(i)(1), SrcState.rdy,
// Mux(src3Type(i)(0), io.intPregRdy(src3Index(i)), io.fpPregRdy(src3Index(i))))
val src1 = Mux(src1Type(i)(1), 0.U,
Mux(src1Type(i)(0), io.readFpRf(src1Index(i)).data, io.readIntRf(src1Index(i)).data))
io.enqIQData(i).bits.src1 := Mux(index_reg(i)(2), 0.U, src1)
......@@ -223,11 +220,10 @@ class Dispatch2 extends XSModule with NeedImpl {
Mux(src3Type(i)(0), io.readFpRf(src3Index(i)).data, io.readIntRf(src3Index(i)).data))
io.enqIQData(i).bits.src3 := Mux(index_reg(i)(2), 0.U, src3)
when (io.enqIQData(i).valid) {
printf("[Cycle:%d][Dispatch2] instruction 0x%x reads operands from (%d, %d, %x), (%d, %d, %x), (%d, %d, %x)\n",
GTimer(), io.enqIQData(i).bits.uop.cf.pc,
src1Type(i), src1Index(i), src1, src2Type(i), src2Index(i), src2, src3Type(i), src3Index(i), src3)
}
XSDebug(io.enqIQData(i).valid,
"instruction 0x%x reads operands from (%d, %d, %x), (%d, %d, %x), (%d, %d, %x)\n",
io.enqIQData(i).bits.uop.cf.pc, src1Type(i), src1Index(i), src1,
src2Type(i), src2Index(i), src2, src3Type(i), src3Index(i), src3)
}
}
......@@ -2,7 +2,7 @@ package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan.utils.GTimer
import xiangshan.utils.{XSDebug, XSInfo}
import xiangshan.{MicroOp, Redirect, XSBundle, XSModule}
......@@ -61,9 +61,10 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int, name: String) extends X
for (i <- 0 until size) {
when (cancelled(i) && entriesValid(i)) {
entriesValid(i) := false.B
printf("[Cycle:%d][" + name + "] valid entry(%d)(pc = %x) cancelled with brMask %x brTag %x\n",
GTimer(), i.U, entries(i).cf.pc, entries(i).brMask, io.redirect.bits.brTag)
}
XSInfo(cancelled(i) && entriesValid(i),
name + ": valid entry(%d)(pc = %x) cancelled with brMask %x brTag %x\n",
i.U, entries(i).cf.pc, entries(i).brMask, io.redirect.bits.brTag)
}
// enqueue
......@@ -87,16 +88,10 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int, name: String) extends X
head := (head + num_deq) % size.U
head_direction := ((Cat(0.U(1.W), head) + num_deq) >= size.U).asUInt() ^ head_direction
when (num_deq > 0.U) {
printf("[Cycle:%d][" + name + "] num_deq = %d, head = (%d -> %d)\n",
GTimer(), num_deq, head, (head + num_deq) % size.U)
}
when (num_enq > 0.U) {
printf("[Cycle:%d][" + name + "] num_enq = %d, tail = (%d -> %d)\n",
GTimer(), num_enq, tail, (tail + num_enq) % size.U)
}
when (valid_entries > 0.U) {
printf("[Cycle:%d][" + name + "] valid_entries = %d, head = (%d, %d), tail = (%d, %d), \n",
GTimer(), valid_entries, head_direction, head, tail_direction, tail)
}
XSDebug(num_deq > 0.U, name + ": num_deq = %d, head = (%d -> %d)\n",
num_deq, head, (head + num_deq) % size.U)
XSDebug(num_enq > 0.U, name + "] num_enq = %d, tail = (%d -> %d)\n",
num_enq, tail, (tail + num_enq) % size.U)
XSDebug(valid_entries > 0.U, name + "] valid_entries = %d, head = (%d, %d), tail = (%d, %d), \n",
valid_entries, head_direction, head, tail_direction, tail)
}
\ No newline at end of file
......@@ -31,7 +31,9 @@ abstract class Exu
val readIntRf: Boolean = true,
val readFpRf: Boolean = false,
val writeIntRf: Boolean = true,
val writeFpRf: Boolean = false
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
) extends Module {
val io = IO(new ExuIO)
}
......
......@@ -3,8 +3,80 @@ package xiangshan.backend.issue
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
class IssueQueue(val fuTypeInt: BigInt, wakeupCnt: Int, val bypassCnt: Int) extends XSModule with NeedImpl {
trait IQConst{
val iqSize = 8
val iqIdxWidth = log2Up(iqSize)
val layer1Size = iqSize
val layer2Size = iqSize/2
val debug = false
}
sealed abstract class IQBundle extends XSBundle with IQConst
sealed abstract class IQModule extends XSModule with IQConst //with NeedImpl
sealed class CmpInputBundle extends IQBundle{
val instRdy = Input(Bool())
val roqIdx = Input(UInt(RoqIdxWidth.W))
val iqIdx = Input(UInt(iqIdxWidth.W))
def apply(instRdy: Bool,roqIdx: UInt,iqIdx: UInt ) = {
this.instRdy := instRdy
this.roqIdx := roqIdx
this.iqIdx := iqIdx
this
}
}
sealed class CompareCircuitUnit extends IQModule {
val io = IO(new Bundle(){
val in1 = new CmpInputBundle
val in2 = new CmpInputBundle
val out = Flipped(new CmpInputBundle)
})
val roqIdx1 = io.in1.roqIdx
val roqIdx2 = io.in2.roqIdx
val iqIdx1 = io.in1.iqIdx
val iqIdx2 = io.in2.iqIdx
val inst1Rdy = io.in1.instRdy
val inst2Rdy = io.in2.instRdy
io.out.instRdy := inst1Rdy | inst2Rdy
io.out.roqIdx := roqIdx2
io.out.iqIdx := iqIdx2
when((inst1Rdy && !inst2Rdy) || (inst1Rdy && inst2Rdy && (roqIdx1 < roqIdx2))){
io.out.roqIdx := roqIdx1
io.out.iqIdx := iqIdx1
}
}
object CCU{
def apply(in1: CmpInputBundle, in2: CmpInputBundle) = {
val CCU = Module(new CompareCircuitUnit)
CCU.io.in1 <> in1
CCU.io.in2 <> in2
CCU.io.out
}
}
object ParallelSel {
def apply(iq: Seq[CmpInputBundle]): CmpInputBundle = {
iq match {
case Seq(a) => a
case Seq(a, b) => CCU(a, b)
case _ =>
apply(Seq(apply(iq take iq.size/2), apply(iq drop iq.size/2)))
}
}
}
class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int = 0, val fixedDelay: Int = 1) extends IQModule {
val useBypass = bypassCnt > 0
......@@ -18,16 +90,296 @@ class IssueQueue(val fuTypeInt: BigInt, wakeupCnt: Int, val bypassCnt: Int) exte
val enqData = Flipped(ValidIO(new ExuInput))
// broadcast selected uop to other issue queues which has bypasses
val selectedUop = if(useBypass) DecoupledIO(new MicroOp) else null
val selectedUop = if(useBypass) ValidIO(new MicroOp) else null
// send to exu
val deq = DecoupledIO(new ExuInput)
// listen to write back bus
val wakeUpPorts = Vec(wakeupCnt, Flipped(DecoupledIO(new ExuOutput)))
val wakeUpPorts = Vec(wakeupCnt, Flipped(ValidIO(new ExuOutput)))
// use bypass uops to speculative wake-up
val bypassUops = if(useBypass) Vec(bypassCnt, Flipped(DecoupledIO(new MicroOp))) else null
val bypassData = if(useBypass) Vec(bypassCnt, Flipped(DecoupledIO(new ExuOutput))) else null
val bypassUops = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new MicroOp))) else null
val bypassData = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new ExuOutput))) else null
})
//---------------------------------------------------------
// Issue Queue
//---------------------------------------------------------
//Tag Queue
val ctrlFlow = Mem(iqSize,new CtrlFlow)
val ctrlSig = Mem(iqSize,new CtrlSignals)
val brMask = RegInit(VecInit(Seq.fill(iqSize)(0.U(BrqSize.W))))
val brTag = RegInit(VecInit(Seq.fill(iqSize)(0.U(BrTagWidth.W))))
val validReg = RegInit(VecInit(Seq.fill(iqSize)(false.B)))
val validWillFalse= WireInit(VecInit(Seq.fill(iqSize)(false.B)))
val valid = validReg.asUInt & ~validWillFalse.asUInt
val src1Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B)))
val src2Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B)))
val src3Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B)))
val prfSrc1 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val prfSrc2 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val prfSrc3 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val prfDest = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val oldPDest = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val freelistAllocPtr = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W)))
val roqIdx = Reg(Vec(iqSize, UInt(RoqIdxWidth.W)))
val instRdy = WireInit(VecInit(List.tabulate(iqSize)(i => src1Rdy(i) && src2Rdy(i) && src3Rdy(i)&& valid(i))))
//tag enqueue
val iqEmty = !valid.asUInt.orR
val iqFull = valid.asUInt.andR
val iqAllowIn = !iqFull
io.enqCtrl.ready := iqAllowIn
//enqueue pointer
val emptySlot = ~valid.asUInt
val enqueueSelect = PriorityEncoder(emptySlot)
//assert(!(io.enqCtrl.valid && io.redirect.valid),"enqueue valid should be false when redirect valid")
XSError(io.enqCtrl.valid && io.redirect.valid,"enqueue valid should be false when redirect valid")
val srcEnqRdy = WireInit(VecInit(false.B, false.B, false.B))
srcEnqRdy(0) := Mux(io.enqCtrl.bits.ctrl.src1Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src1State === SrcState.rdy)
srcEnqRdy(1) := Mux(io.enqCtrl.bits.ctrl.src2Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src2State === SrcState.rdy)
srcEnqRdy(2) := Mux(io.enqCtrl.bits.ctrl.src3Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src3State === SrcState.rdy)
when (io.enqCtrl.fire()) {
ctrlFlow(enqueueSelect) := io.enqCtrl.bits.cf
ctrlSig(enqueueSelect) := io.enqCtrl.bits.ctrl
brMask(enqueueSelect) := io.enqCtrl.bits.brMask
brTag(enqueueSelect) := io.enqCtrl.bits.brTag
validReg(enqueueSelect) := true.B
src1Rdy(enqueueSelect) := srcEnqRdy(0)
src2Rdy(enqueueSelect) := srcEnqRdy(1)
src3Rdy(enqueueSelect) := srcEnqRdy(2)
prfSrc1(enqueueSelect) := io.enqCtrl.bits.psrc1
prfSrc2(enqueueSelect) := io.enqCtrl.bits.psrc2
prfSrc3(enqueueSelect) := io.enqCtrl.bits.psrc3
prfDest(enqueueSelect) := io.enqCtrl.bits.pdest
oldPDest(enqueueSelect) := io.enqCtrl.bits.old_pdest
freelistAllocPtr(enqueueSelect) := io.enqCtrl.bits.freelistAllocPtr
roqIdx(enqueueSelect) := io.enqCtrl.bits.roqIdx
if(debug) {XSDebug("[IQ enq]: enqSelect:%d | s1Rd:%d s2Rd:%d s3Rd:%d\n",enqueueSelect.asUInt,
(io.enqCtrl.bits.src1State === SrcState.rdy),
(io.enqCtrl.bits.src2State === SrcState.rdy),
(io.enqCtrl.bits.src3State === SrcState.rdy))}
}
//Data Queue
val src1Data = Reg(Vec(iqSize, UInt(XLEN.W)))
val src2Data = Reg(Vec(iqSize, UInt(XLEN.W)))
val src3Data = Reg(Vec(iqSize, UInt(XLEN.W)))
val enqSelNext = RegNext(enqueueSelect)
val enqFireNext = RegNext(io.enqCtrl.fire())
// Read RegFile
//Ready data will written at next cycle
when (enqFireNext) {
when(src1Rdy(enqSelNext)){src1Data(enqSelNext) := io.enqData.bits.src1}
when(src2Rdy(enqSelNext)){src2Data(enqSelNext) := io.enqData.bits.src2}
when(src3Rdy(enqSelNext)){src3Data(enqSelNext) := io.enqData.bits.src3}
}
if(debug) {
XSDebug("[Reg info-ENQ] enqSelNext:%d | enqFireNext:%d \n",enqSelNext,enqFireNext)
XSDebug("[IQ content] valid vr vf| pc insruction | src1rdy src1 | src2Rdy src2 pdest \n")
for(i <- 0 to (iqSize -1)){
val ins = ctrlFlow(i).instr
val pc = ctrlFlow(i).pc
when(valid(i)){XSDebug("[IQ content][%d] %d%d%d |%x %x| %x %x | %x %x | %d valid|\n",i.asUInt, valid(i), validReg(i), validWillFalse(i), pc,ins,src1Rdy(i), src1Data(i), src2Rdy(i), src2Data(i),prfDest(i))}
.elsewhen(validReg(i) && validWillFalse(i)){XSDebug("[IQ content][%d] %d%d%d |%x %x| %x %x | %x %x | %d valid will be False|\n",i.asUInt, valid(i), validReg(i), validWillFalse(i),pc,ins, src1Rdy(i), src1Data(i), src2Rdy(i), src2Data(i),prfDest(i))}
.otherwise {XSDebug("[IQ content][%d] %d%d%d |%x %x| %x %x | %x %x | %d\n",i.asUInt, valid(i), validReg(i), validWillFalse(i),pc,ins, src1Rdy(i), src1Data(i), src2Rdy(i), src2Data(i),prfDest(i))}
}
}
// From Common Data Bus(wakeUpPort)
// chisel claims that firrtl will optimize Mux1H to and/or tree
// TODO: ignore ALU'cdb srcRdy, for byPass has done it
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 srcNum = 3
val prfSrc = List(prfSrc1, prfSrc2, prfSrc3)
val srcRdy = List(src1Rdy, src2Rdy, src3Rdy)
val srcData = List(src1Data, src2Data, src3Data)
val srcHitVec = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
List.tabulate(wakeupCnt)(j =>
(prfSrc(k)(i) === cdbPdest(j)) && cdbValid(j))))
val srcHit = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
ParallelOR(srcHitVec(k)(i)).asBool()))
// VecInit(srcHitVec(k)(i)).asUInt.orR))
for(k <- 0 until srcNum){
for(i <- 0 until iqSize)( when (valid(i)) {
when(!srcRdy(k)(i) && srcHit(k)(i)) {
srcRdy(k)(i) := true.B
// srcData(k)(i) := Mux1H(srcHitVec(k)(i), cdbData)
srcData(k)(i) := ParallelMux(srcHitVec(k)(i) zip cdbData)
}
})
}
// From byPass [speculative] (just for ALU to listen to other ALU's res, include itself)
// just need Tag(Ctrl). send out Tag when Tag is decided. other ALUIQ listen to them and decide Tag
// byPassUops is one cycle before byPassDatas
if (bypassCnt > 0) {
val bypassPdest = List.tabulate(bypassCnt)(i => io.bypassUops(i).bits.pdest)
val bypassValid = List.tabulate(bypassCnt)(i => io.bypassUops(i).valid) // may only need valid not fire()
val bypassData = List.tabulate(bypassCnt)(i => io.bypassData(i).bits.data)
val srcBpHitVec = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
List.tabulate(bypassCnt)(j =>
(prfSrc(k)(i) === bypassPdest(j)) && bypassValid(j))))
val srcBpHit = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
ParallelOR(srcBpHitVec(k)(i)).asBool()))
// VecInit(srcBpHitVec(k)(i)).asUInt.orR))
val srcBpHitVecNext = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
List.tabulate(bypassCnt)(j => RegNext(srcBpHitVec(k)(i)(j)))))
val srcBpHitNext = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
RegNext(srcBpHit(k)(i))))
val srcBpData = List.tabulate(srcNum)(k =>
List.tabulate(iqSize)(i =>
ParallelMux(srcBpHitVecNext(k)(i) zip bypassData)))
// Mux1H(srcBpHitVecNext(k)(i), bypassData)))
for(k <- 0 until srcNum){
for(i <- 0 until iqSize){ when (valid(i)) {
when(valid(i) && !srcRdy(k)(i) && srcBpHit(k)(i)) { srcRdy(k)(i) := true.B }
when(srcBpHitNext(k)(i)) { srcData(k)(i) := srcBpData(k)(i)}
}}
}
// Enqueue Bypass
val enqBypass = WireInit(VecInit(false.B, false.B, false.B))
val enqBypassHitVec = List(List.tabulate(bypassCnt)(j => io.enqCtrl.bits.psrc1 === bypassPdest(j) && bypassValid(j) && io.enqCtrl.fire()),
List.tabulate(bypassCnt)(j => io.enqCtrl.bits.psrc2 === bypassPdest(j) && bypassValid(j) && io.enqCtrl.fire()),
List.tabulate(bypassCnt)(j => io.enqCtrl.bits.psrc3 === bypassPdest(j) && bypassValid(j) && io.enqCtrl.fire()))
val enqBypassHitVecNext = enqBypassHitVec.map(i => i.map(j => RegNext(j)))
enqBypass(0) := ParallelOR(enqBypassHitVec(0))
enqBypass(1) := ParallelOR(enqBypassHitVec(1))
enqBypass(2) := ParallelOR(enqBypassHitVec(2))
when(enqBypass(0)) { src1Rdy(enqueueSelect) := true.B }
when(enqBypass(1)) { src2Rdy(enqueueSelect) := true.B }
when(enqBypass(2)) { src3Rdy(enqueueSelect) := true.B }
when(RegNext(enqBypass(0))) { src1Data(enqSelNext) := ParallelMux(enqBypassHitVecNext(0) zip bypassData)}
when(RegNext(enqBypass(1))) { src2Data(enqSelNext) := ParallelMux(enqBypassHitVecNext(1) zip bypassData)}
when(RegNext(enqBypass(2))) { src3Data(enqSelNext) := ParallelMux(enqBypassHitVecNext(2) zip bypassData)}
}
}
//---------------------------------------------------------
// Select Circuit
//---------------------------------------------------------
val selVec = List.tabulate(iqSize){ i =>
Wire(new CmpInputBundle).apply(instRdy(i),roqIdx(i),i.U)
}
val selResult = ParallelSel(selVec)
if(debug) {
XSDebug("[Sel Result] ResReady:%d || ResultId:%d\n",selResult.instRdy,selResult.iqIdx.asUInt)
}
//---------------------------------------------------------
// Redirect Logic
//---------------------------------------------------------
val expRedirect = io.redirect.valid && io.redirect.bits.isException
val brRedirect = io.redirect.valid && !io.redirect.bits.isException
List.tabulate(iqSize)( i =>
when(brRedirect && (UIntToOH(io.redirect.bits.brTag) & brMask(i)).orR && validReg(i) ){
validReg(i) := false.B
validWillFalse(i) := true.B
} .elsewhen(expRedirect) {
validReg(i) := false.B
validWillFalse(i) := true.B
}
)
//---------------------------------------------------------
// Dequeue Logic
//---------------------------------------------------------
//hold the sel-index to wait for data
val selInstIdx = RegInit(0.U(iqIdxWidth.W))
val selInstRdy = RegInit(false.B)
//issue the select instruction
val dequeueSelect = Wire(UInt(iqIdxWidth.W))
dequeueSelect := selInstIdx
val brRedirectMaskMatch = (UIntToOH(io.redirect.bits.brTag) & brMask(dequeueSelect)).orR
val IQreadyGo = selInstRdy && !expRedirect && (!brRedirect || !brRedirectMaskMatch)
io.deq.valid := IQreadyGo
io.deq.bits.uop.cf := ctrlFlow(dequeueSelect)
io.deq.bits.uop.ctrl := ctrlSig(dequeueSelect)
io.deq.bits.uop.brMask := brMask(dequeueSelect)
io.deq.bits.uop.brTag := brTag(dequeueSelect)
io.deq.bits.uop.psrc1 := prfSrc1(dequeueSelect)
io.deq.bits.uop.psrc2 := prfSrc2(dequeueSelect)
io.deq.bits.uop.psrc3 := prfSrc3(dequeueSelect)
io.deq.bits.uop.pdest := prfDest(dequeueSelect)
io.deq.bits.uop.old_pdest := oldPDest(dequeueSelect)
io.deq.bits.uop.src1State := SrcState.rdy
io.deq.bits.uop.src2State := SrcState.rdy
io.deq.bits.uop.src3State := SrcState.rdy
io.deq.bits.uop.freelistAllocPtr := freelistAllocPtr(dequeueSelect)
io.deq.bits.uop.roqIdx := roqIdx(dequeueSelect)
io.deq.bits.src1 := src1Data(dequeueSelect)
io.deq.bits.src2 := src2Data(dequeueSelect)
io.deq.bits.src3 := src3Data(dequeueSelect)
if(debug) {
XSDebug("[Reg Info-Sel] selInstRdy:%d || selIdx:%d\n",selInstRdy,selInstIdx.asUInt)
XSDebug(IQreadyGo,"[IQ dequeue] **dequeue fire:%d** roqIdx:%d dequeueSel:%d | src1Rd:%d src1:%d | src2Rd:%d src2:%d\n", io.deq.fire(), io.deq.bits.uop.roqIdx, dequeueSelect.asUInt,
(io.deq.bits.uop.src1State === SrcState.rdy), io.deq.bits.uop.psrc1,
(io.deq.bits.uop.src2State === SrcState.rdy), io.deq.bits.uop.psrc2
)
}
//update the index register of instruction that can be issue, unless function unit not allow in
//then the issue will be stopped to wait the function unit
//clear the validBit of dequeued instruction in issuequeue
when(io.deq.fire()){
validReg(dequeueSelect) := false.B
validWillFalse(dequeueSelect) := true.B
}
val selRegflush = expRedirect || (brRedirect && brRedirectMaskMatch)
selInstRdy := Mux(selRegflush,false.B,selResult.instRdy)
selInstIdx := Mux(selRegflush,0.U,selResult.iqIdx)
// SelectedUop (bypass / speculative)
if(useBypass) {
assert(fixedDelay==1) // only support fixedDelay is 1 now
def DelayPipe[T <: Data](a: T, delay: Int = 0) = {
// println(delay)
if(delay == 0) a
else {
val storage = Wire(VecInit(Seq.fill(delay+1)(a)))
// storage(0) := a
for(i <- 1 until delay) {
storage(i) := RegNext(storage(i-1))
}
storage(delay)
}
}
val sel = io.selectedUop
val selIQIdx = selResult.iqIdx
val delayPipe = DelayPipe(VecInit(selResult.instRdy, prfDest(selIQIdx)), fixedDelay-1)
sel.bits := DontCare
sel.bits.pdest := delayPipe(fixedDelay-1)(1)
}
}
......@@ -3,6 +3,7 @@ package xiangshan.backend.rename
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.XSInfo
class Rename extends XSModule {
val io = IO(new Bundle() {
......@@ -20,6 +21,26 @@ class Rename extends XSModule {
val out = Vec(RenameWidth, DecoupledIO(new MicroOp))
})
val debug_exception = io.redirect.valid && io.redirect.bits.isException
val debug_walk = io.roqCommits.map(_.bits.isWalk).reduce(_ || _)
val debug_norm = !(debug_exception || debug_walk)
def printRenameInfo(in: DecoupledIO[CfCtrl], out: DecoupledIO[MicroOp]) = {
XSInfo(
debug_norm,
p"pc:${Hexadecimal(in.bits.cf.pc)} v:${in.valid} rdy:${in.ready} " +
p"lsrc1:${in.bits.ctrl.lsrc1} -> psrc1:${out.bits.psrc1} " +
p"lsrc2:${in.bits.ctrl.lsrc2} -> psrc2:${out.bits.psrc2} " +
p"lsrc3:${in.bits.ctrl.lsrc3} -> psrc3:${out.bits.psrc3} " +
p"ldest:${in.bits.ctrl.ldest} -> pdest:${out.bits.pdest} " +
p"old_pdest:${out.bits.old_pdest}\n"
)
}
for((x,y) <- io.in.zip(io.out)){
printRenameInfo(x, y)
}
val fpFreeList, intFreeList = Module(new FreeList).io
val fpRat = Module(new RenameTable(float = true)).io
val intRat = Module(new RenameTable(float = false)).io
......@@ -85,10 +106,20 @@ class Rename extends XSModule {
rat.specWritePorts(i).addr := Mux(specWen, uops(i).ctrl.ldest, io.roqCommits(i).bits.uop.ctrl.ldest)
rat.specWritePorts(i).wdata := Mux(specWen, freeList.pdests(i), io.roqCommits(i).bits.uop.old_pdest)
XSInfo(walkWen,
{if(fp) "fp" else "int "} + p"walk: pc:${Hexadecimal(uops(i).cf.pc)}" +
p" ldst:${rat.specWritePorts(i).addr} old_pdest:${rat.specWritePorts(i).wdata}\n"
)
rat.archWritePorts(i).wen := commitDestValid && !io.roqCommits(i).bits.isWalk
rat.archWritePorts(i).addr := io.roqCommits(i).bits.uop.ctrl.ldest
rat.archWritePorts(i).wdata := io.roqCommits(i).bits.uop.pdest
XSInfo(rat.archWritePorts(i).wen,
{if(fp) "fp" else "int "} + p" rat arch: ldest:${rat.archWritePorts(i).addr}" +
p" pdest:${rat.archWritePorts(i).wdata}\n"
)
freeList.deallocReqs(i) := rat.archWritePorts(i).wen
freeList.deallocPregs(i) := io.roqCommits(i).bits.uop.old_pdest
......
......@@ -3,9 +3,11 @@ package xiangshan.backend.roq
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import chisel3.util.experimental.BoringUtils
// A "just-enough" Roq
class Roq extends XSModule {
class Roq(implicit val p: XSConfig) extends XSModule {
val io = IO(new Bundle() {
val brqRedirect = Input(Valid(new Redirect))
val dp1Req = Vec(RenameWidth, Flipped(DecoupledIO(new MicroOp)))
......@@ -20,8 +22,10 @@ class Roq extends XSModule {
val valid = RegInit(VecInit(List.fill(RoqSize)(false.B)))
val writebacked = Reg(Vec(RoqSize, Bool()))
val redirect = Reg(Vec(RoqSize, new Redirect))
val isMMIO = Reg(Vec(RoqSize, Bool()))//for debug
val intrNO = Reg(Vec(RoqSize, UInt(XLEN.W)))//for debug
val exuData = Reg(Vec(RoqSize, UInt(XLEN.W)))//for debug
val exuDebug = Reg(Vec(RoqSize, new DebugBundle))//for debug
val archRF = RegInit(VecInit(List.fill(64)(0.U(32.W))))//for debug, fp regs included
val ringBufferHeadExtended = RegInit(0.U(ExtendedRoqIdxWidth.W))
val ringBufferTailExtended = RegInit(0.U(ExtendedRoqIdxWidth.W))
......@@ -39,33 +43,47 @@ class Roq extends XSModule {
// Dispatch
val validDispatch = VecInit((0 until RenameWidth).map(io.dp1Req(_).valid)).asUInt
XSDebug("(ready, valid): ")
for(i <- 0 until RenameWidth){
val offset = if(i==0) 0.U else PopCount(validDispatch(i-1,0))
when(io.dp1Req(i).fire()){
microOp(ringBufferHead+offset) := io.dp1Req(i).bits
valid(ringBufferHead+offset) := true.B
writebacked(ringBufferHead+offset) := false.B
}
io.dp1Req(i).ready := ringBufferAllowin && !valid(ringBufferHead+offset) && state === s_idle
io.roqIdxs(i) := ringBufferHeadExtended+offset
XSDebug(){printf("(%d, %d) ", io.dp1Req(i).ready, io.dp1Req(i).valid)}
}
XSDebug(){printf("\n")}
val firedDispatch = VecInit((0 until CommitWidth).map(io.dp1Req(_).fire())).asUInt
when(validDispatch.orR){
ringBufferHeadExtended := ringBufferHeadExtended + PopCount(validDispatch)
when(firedDispatch.orR){
ringBufferHeadExtended := ringBufferHeadExtended + PopCount(firedDispatch)
XSInfo("dispatched %d insts\n", PopCount(firedDispatch))
}
// Writeback
for(i <- 0 until exuConfig.ExuCnt){
when(io.exeWbResults(i).fire()){
writebacked(io.exeWbResults(i).bits.uop.roqIdx) := true.B
exuData(io.exeWbResults(i).bits.uop.roqIdx) := io.exeWbResults(i).bits.data
exuDebug(io.exeWbResults(i).bits.uop.roqIdx) := io.exeWbResults(i).bits.debug
}
}
val firedWriteback = VecInit((0 until exuConfig.ExuCnt).map(io.exeWbResults(_).fire())).asUInt
when(PopCount(firedWriteback) > 0.U){
XSInfo("writebacked %d insts\n", PopCount(firedWriteback))
}
// Commit uop to Rename
for(i <- 0 until CommitWidth){
when(state === s_idle){
io.commits(i).valid := valid(ringBufferTail+i.U) && writebacked(ringBufferTail+i.U)
val canCommit = if(i!=0) io.commits(i-1).valid else true.B
io.commits(i).valid := valid(ringBufferTail+i.U) && writebacked(ringBufferTail+i.U) && canCommit
io.commits(i).bits.uop := microOp(ringBufferTail+i.U)
when(valid(ringBufferTail+i.U)){valid(ringBufferTail+i.U) := false.B}//FIXIT
when(microOp(i).ctrl.rfWen){ archRF(microOp(i).ctrl.ldest) := exuData(i) }
when(io.commits(i).valid){valid(ringBufferTail+i.U) := false.B}
}.otherwise{//state === s_walk
io.commits(i).valid := valid(ringBufferWalk+i.U) && writebacked(ringBufferWalk+i.U)
io.commits(i).bits.uop := microOp(ringBufferWalk+i.U)
......@@ -78,6 +96,9 @@ class Roq extends XSModule {
when(state === s_idle){
ringBufferTailExtended := ringBufferTailExtended + PopCount(validCommit)
}
val retireCounter = Mux(state === s_idle, PopCount(validCommit), 0.U)
// TODO: commit store
XSInfo(retireCounter > 0.U, "retired %d insts\n", retireCounter)
val walkFinished = (0 until CommitWidth).map(i => (ringBufferWalk + i.U) === ringBufferWalkTarget).reduce(_||_)
......@@ -87,9 +108,7 @@ class Roq extends XSModule {
state := s_idle
}
ringBufferWalkExtended := ringBufferWalkExtended + CommitWidth.U
// Debug(){
printf("[ROQ] rolling back: head %d tail %d walk %d\n", ringBufferHead, ringBufferTail, ringBufferWalk)
// }
XSInfo("rolling back: head %d tail %d walk %d\n", ringBufferHead, ringBufferTail, ringBufferWalk)
}
when(io.brqRedirect.valid){
......@@ -102,4 +121,41 @@ class Roq extends XSModule {
// roq redirect only used for exception
io.redirect := DontCare //TODO
io.redirect.valid := false.B //TODO
// debug info
XSDebug("head %d tail %d\n", ringBufferHead, ringBufferTail)
XSDebug("")
XSDebug(){
for(i <- 0 until RoqSize){
when(!valid(i)){printf("-")}
when(valid(i) && writebacked(i)){printf("w")}
when(valid(i) && !writebacked(i)){printf("v")}
}
printf("\n")
}
//difftest signals
val firstValidCommit = ringBufferTail + PriorityMux(validCommit, VecInit(List.tabulate(CommitWidth)(_.U)))
val emptyCsr = WireInit(0.U(64.W))
if(!p.FPGAPlatform){
BoringUtils.addSink(RegNext(retireCounter), "difftestCommit")
BoringUtils.addSink(RegNext(microOp(firstValidCommit).cf.pc), "difftestThisPC")//first valid PC
BoringUtils.addSink(RegNext(microOp(firstValidCommit).cf.instr), "difftestThisINST")//first valid inst
BoringUtils.addSink(archRF, "difftestRegs")//arch RegFile
BoringUtils.addSink(RegNext(false.B), "difftestSkip")//SKIP
BoringUtils.addSink(RegNext(false.B), "difftestIsRVC")//FIXIT
BoringUtils.addSink(RegNext(0.U), "difftestIntrNO")
//TODO: skip insts that commited in the same cycle ahead of exception
//csr debug signals
val ModeM = WireInit(0x3.U)
BoringUtils.addSource(ModeM, "difftestMode")
BoringUtils.addSource(emptyCsr, "difftestMstatus")
BoringUtils.addSource(emptyCsr, "difftestSstatus")
BoringUtils.addSource(emptyCsr, "difftestMepc")
BoringUtils.addSource(emptyCsr, "difftestSepc")
BoringUtils.addSource(emptyCsr, "difftestMcause")
BoringUtils.addSource(emptyCsr, "difftestScause")
}
}
......@@ -4,6 +4,7 @@ import chisel3._
import chisel3.util._
import utils.PipelineConnect
import xiangshan._
import xiangshan.utils.XSInfo
class Frontend extends XSModule {
val io = IO(new Bundle() {
......@@ -19,4 +20,11 @@ class Frontend extends XSModule {
ibuffer.io.flush := io.backend.redirect.valid
io.backend.cfVec <> ibuffer.io.out
for(out <- ibuffer.io.out){
XSInfo(out.fire(),
p"inst:${Hexadecimal(out.bits.instr)} pc:${Hexadecimal(out.bits.pc)}\n"
)
}
}
package xiangshan.utils
import chisel3._
import xiangshan.HasXSParameter
import xiangshan.utils.XSLogLevel.XSLogLevel
object XSLogLevel extends Enumeration {
type XSLogLevel = Value
val ALL = Value("ALL")
val DEBUG = Value("DEBUG")
val INFO = Value("INFO")
val WARN = Value("WARN")
val ERROR = Value("ERROR")
val OFF = Value("OFF")
}
object XSLog extends HasXSParameter{
def apply(debugLevel: XSLogLevel)
(cond: Bool, pable: Printable)
(implicit m: Module): Any = {
if (debugLevel >= LogLevel) {
when (cond) {
val commonInfo = p"[$debugLevel][time=${GTimer()}] ${m.name}: "
printf(commonInfo + pable)
}
}
}
}
sealed abstract class LogHelper(val logLevel: XSLogLevel) extends HasXSParameter {
def apply(cond: Bool, fmt: String, data: Bits*)(implicit m: Module): Any =
apply(cond, Printable.pack(fmt, data:_*))
def apply(cond: Bool, pable: Printable)(implicit m: Module): Any = XSLog(logLevel)(cond, pable)
def apply(fmt: String, data: Bits*)(implicit m: Module): Any =
apply(true.B, Printable.pack(fmt, data:_*))
def apply(pable: Printable)(implicit m: Module): Any = XSLog(logLevel)(true.B, pable)
// Do not use that unless you have valid reasons
def apply(cond: Bool = true.B)(body: => Unit): Any =
if (logLevel >= LogLevel) { when (cond) { body } }
}
object XSDebug extends LogHelper(XSLogLevel.DEBUG)
object XSInfo extends LogHelper(XSLogLevel.INFO)
object XSWarn extends LogHelper(XSLogLevel.WARN)
object XSError extends LogHelper(XSLogLevel.ERROR)
......@@ -83,9 +83,10 @@ static const char *reg_name[DIFFTEST_NR_REG] = {
"sstatus", "scause", "sepc"
};
int difftest_step(uint64_t *reg_scala, uint32_t this_inst,
int isMMIO, int isRVC, uint64_t intrNO, int priviledgeMode) {
int difftest_step(int commit, uint64_t *reg_scala, uint32_t this_inst,
int skip, int isRVC, uint64_t intrNO, int priviledgeMode) {
assert(!skip && !isRVC && intrNO == 0);
#define DEBUG_RETIRE_TRACE_SIZE 16
uint64_t ref_r[DIFFTEST_NR_REG];
......@@ -97,7 +98,7 @@ int difftest_step(uint64_t *reg_scala, uint32_t this_inst,
static uint32_t inst_retire_queue[DEBUG_RETIRE_TRACE_SIZE] = {0};
static int pc_retire_pointer = 7;
if (isMMIO) {
if (skip) {
// printf("diff pc: %x isRVC %x\n", this_pc, isRVC);
// MMIO accessing should not be a branch or jump, just +2/+4 to get the next pc
reg_scala[DIFFTEST_THIS_PC] += isRVC ? 2 : 4;
......@@ -112,10 +113,11 @@ int difftest_step(uint64_t *reg_scala, uint32_t this_inst,
if (intrNO) {
ref_difftest_raise_intr(intrNO);
} else {
ref_difftest_exec(1);
ref_difftest_exec(1);//TODO
}
assert(commit > 0 && commit <= 6);
ref_difftest_exec(commit);
ref_difftest_getregs(&ref_r);
uint64_t next_pc = ref_r[DIFFTEST_THIS_PC];
......@@ -123,17 +125,18 @@ int difftest_step(uint64_t *reg_scala, uint32_t this_inst,
pc_retire_queue[pc_retire_pointer] = this_pc;
inst_retire_queue[pc_retire_pointer] = this_inst;
int isCSR = ((this_inst & 0x7f) == 0x73);
int isCSRMip = ((this_inst >> 20) == 0x344) && isCSR;
if (isCSRMip) {
// We can not handle NEMU.mip.mtip since it is driven by CLINT,
// which is not accessed in NEMU due to MMIO.
// Just sync the state of NEMU from NOOP.
reg_scala[DIFFTEST_THIS_PC] = next_pc;
nemu_this_pc = next_pc;
ref_difftest_setregs(reg_scala);
return 0;
}
// TODO: fix mip.mtip
// int isCSR = ((this_inst & 0x7f) == 0x73);
// int isCSRMip = ((this_inst >> 20) == 0x344) && isCSR;
// if (isCSRMip) {
// // We can not handle NEMU.mip.mtip since it is driven by CLINT,
// // which is not accessed in NEMU due to MMIO.
// // Just sync the state of NEMU from NOOP.
// reg_scala[DIFFTEST_THIS_PC] = next_pc;
// nemu_this_pc = next_pc;
// ref_difftest_setregs(reg_scala);
// return 0;
// }
// replace with "this pc" for checking
ref_r[DIFFTEST_THIS_PC] = nemu_this_pc;
......
......@@ -148,10 +148,10 @@ class Emulator {
uint64_t reg[DIFFTEST_NR_REG];
read_emu_regs(reg);
extern int difftest_step(uint64_t *reg_scala, uint32_t this_inst,
int isMMIO, int isRVC, uint64_t intrNO, int priviledgeMode);
if (difftest_step(reg, dut_ptr->io_difftest_thisINST,
dut_ptr->io_difftest_isMMIO, dut_ptr->io_difftest_isRVC,
extern int difftest_step(int commit, uint64_t *reg_scala, uint32_t this_inst,
int skip, int isRVC, uint64_t intrNO, int priviledgeMode);
if (difftest_step(dut_ptr->io_difftest_commit, reg, dut_ptr->io_difftest_thisINST,
dut_ptr->io_difftest_skip, dut_ptr->io_difftest_isRVC,
dut_ptr->io_difftest_intrNO, dut_ptr->io_difftest_priviledgeMode)) {
#if VM_TRACE
tfp->close();
......
......@@ -11,10 +11,10 @@ import xiangshan._
class DiffTestIO extends Bundle {
val r = Output(Vec(64, UInt(64.W)))
val commit = Output(Bool())
val commit = Output(UInt(32.W))
val thisPC = Output(UInt(64.W))
val thisINST = Output(UInt(32.W))
val isMMIO = Output(Bool())
val skip = Output(Bool())
val isRVC = Output(Bool())
val intrNO = Output(UInt(64.W))
......@@ -54,7 +54,7 @@ class XSSimTop extends Module {
BoringUtils.addSink(difftest.commit, "difftestCommit")
BoringUtils.addSink(difftest.thisPC, "difftestThisPC")
BoringUtils.addSink(difftest.thisINST, "difftestThisINST")
BoringUtils.addSink(difftest.isMMIO, "difftestIsMMIO")
BoringUtils.addSink(difftest.skip, "difftestSkip")
BoringUtils.addSink(difftest.isRVC, "difftestIsRVC")
BoringUtils.addSink(difftest.intrNO, "difftestIntrNO")
BoringUtils.addSink(difftest.r, "difftestRegs")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册