提交 f6235c24 编写于 作者: Y YikeZhou

Merge branch 'master' into decoder-dev

......@@ -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,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,57 @@ package xiangshan.backend.issue
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
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))
}
sealed class CompareCircuitUnit(layer: Int = 0, id: Int = 0) 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
}
if(debug && (layer==3)) {
printf("(%d)[CCU(L%did%d)] in1.ready:%d in1.index:%d || in1.ready:%d in1.index:%d || out.ready:%d out.index:%d\n",GTimer(),layer.asUInt,id.asUInt,inst1Rdy,iqIdx1,inst2Rdy,iqIdx2,io.out.instRdy,io.out.iqIdx)
}
class IssueQueue(val fuTypeInt: BigInt, wakeupCnt: Int, val bypassCnt: Int) extends XSModule with NeedImpl {
}
class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int = 0, val fixedDelay: Int = 1) extends IQModule {
val useBypass = bypassCnt > 0
......@@ -18,16 +67,297 @@ 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 validFire= WireInit(VecInit(Seq.fill(iqSize)(false.B)))
val valid = validReg.asUInt & ~validFire.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")
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) := Mux(io.enqCtrl.bits.ctrl.src1Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src1State === SrcState.rdy)
src2Rdy(enqueueSelect) := Mux(io.enqCtrl.bits.ctrl.src2Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src2State === SrcState.rdy)
src3Rdy(enqueueSelect) := Mux(io.enqCtrl.bits.ctrl.src3Type =/= SrcType.reg , true.B ,io.enqCtrl.bits.src3State === SrcState.rdy)
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) {printf("(%d)[IQ enq]: enqSelect:%d | s1Rd:%d s2Rd:%d s3Rd:%d\n",GTimer(),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) {
printf("(%d)[Reg info] enqSelNext:%d | enqFireNext:%d \n",GTimer(),enqSelNext,enqFireNext)
printf("(%d)[IQ content] valid | src1rdy src1 | src2Rdy src2 pdest \n",GTimer())
for(i <- 0 to (iqSize -1)){
printf("(%d)[IQ content][%d] %d%d%d | %x %x | %x %x | %d",GTimer(),i.asUInt, valid(i), validReg(i), validFire(i), src1Rdy(i), src1Data(i), src2Rdy(i), src2Data(i),prfDest(i))
when(valid(i)){printf(" valid")}
printf(" |\n")
}
}
// 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)}
}}
}
}
}
//---------------------------------------------------------
// Select Circuit
//---------------------------------------------------------
//layer 1
val layer1CCUs = (0 until layer1Size by 2) map { i =>
val CCU_1 = Module(new CompareCircuitUnit(layer = 1, id = i/2))
CCU_1.io.in1.instRdy := instRdy(i)
CCU_1.io.in1.roqIdx := roqIdx(i)
CCU_1.io.in1.iqIdx := i.U
CCU_1.io.in2.instRdy := instRdy(i+1)
CCU_1.io.in2.roqIdx := roqIdx(i+1)
CCU_1.io.in2.iqIdx := (i+1).U
CCU_1
}
//layer 2
val layer2CCUs = (0 until layer2Size by 2) map { i =>
val CCU_2 = Module(new CompareCircuitUnit(layer = 2, id = i/2))
CCU_2.io.in1.instRdy := layer1CCUs(i).io.out.instRdy
CCU_2.io.in1.roqIdx := layer1CCUs(i).io.out.roqIdx
CCU_2.io.in1.iqIdx := layer1CCUs(i).io.out.iqIdx
CCU_2.io.in2.instRdy := layer1CCUs(i+1).io.out.instRdy
CCU_2.io.in2.roqIdx := layer1CCUs(i+1).io.out.roqIdx
CCU_2.io.in2.iqIdx := layer1CCUs(i+1).io.out.iqIdx
CCU_2
}
//layer 3
val CCU_3 = Module(new CompareCircuitUnit(layer = 3, id = 0))
CCU_3.io.in1.instRdy := layer2CCUs(0).io.out.instRdy
CCU_3.io.in1.roqIdx := layer2CCUs(0).io.out.roqIdx
CCU_3.io.in1.iqIdx := layer2CCUs(0).io.out.iqIdx
CCU_3.io.in2.instRdy := layer2CCUs(1).io.out.instRdy
CCU_3.io.in2.roqIdx := layer2CCUs(1).io.out.roqIdx
CCU_3.io.in2.iqIdx := layer2CCUs(1).io.out.iqIdx
//---------------------------------------------------------
// 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 && valid(i) ){
validReg(i) := false.B
} .elsewhen(expRedirect) {
validReg(i) := false.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) {
printf("(%d)[Sel Reg] selInstRdy:%d || selIdx:%d\n",GTimer(),selInstRdy,selInstIdx.asUInt)
when(IQreadyGo){printf("(%d)[IQ dequeue] **fire:%d** roqIdx:%d dequeueSel:%d | src1Rd:%d src1:%d | src2Rd:%d src2:%d\n",GTimer(), 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
validFire(dequeueSelect) := true.B
}
val selRegflush = expRedirect || (brRedirect && brRedirectMaskMatch)
selInstRdy := Mux(selRegflush,false.B,CCU_3.io.out.instRdy)
selInstIdx := Mux(selRegflush,0.U,CCU_3.io.out.iqIdx)
// SelectedUop (bypass / speculative)
if(useBypass) {
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 = CCU_3.io.out.iqIdx
val delayPipe = DelayPipe(VecInit(CCU_3.io.out.instRdy, prfDest(selIQIdx)), fixedDelay-1)
sel.valid := delayPipe(fixedDelay-1)(0)
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.ParallelOR
class BusyTable extends XSModule {
val io = IO(new Bundle() {
......@@ -19,7 +20,7 @@ class BusyTable extends XSModule {
val table = RegInit(VecInit(Seq.fill(NRPhyRegs)(false.B)))
for((raddr, rdy) <- io.rfReadAddr.zip(io.pregRdy)){
rdy := !table(raddr)
rdy := !table(raddr) || ParallelOR(io.wbPregs.map(wb => wb.valid && (wb.bits===raddr))).asBool()
}
for((alloc, i) <- io.allocPregs.zipWithIndex){
......
......@@ -3,9 +3,10 @@ package xiangshan.backend.roq
import chisel3._
import chisel3.util._
import xiangshan._
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 +21,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))
......@@ -57,6 +60,8 @@ class Roq extends XSModule {
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
}
}
......@@ -65,6 +70,7 @@ class Roq extends XSModule {
when(state === s_idle){
io.commits(i).valid := valid(ringBufferTail+i.U) && writebacked(ringBufferTail+i.U)
io.commits(i).bits.uop := microOp(ringBufferTail+i.U)
when(microOp(i).ctrl.rfWen){ archRF(microOp(i).ctrl.ldest) := exuData(i) }
when(valid(ringBufferTail+i.U)){valid(ringBufferTail+i.U) := false.B}//FIXIT
}.otherwise{//state === s_walk
io.commits(i).valid := valid(ringBufferWalk+i.U) && writebacked(ringBufferWalk+i.U)
......@@ -78,6 +84,7 @@ class Roq extends XSModule {
when(state === s_idle){
ringBufferTailExtended := ringBufferTailExtended + PopCount(validCommit)
}
val retireCounter = Mux(state === s_idle, PopCount(validCommit), 0.U)
val walkFinished = (0 until CommitWidth).map(i => (ringBufferWalk + i.U) === ringBufferWalkTarget).reduce(_||_)
......@@ -102,4 +109,29 @@ class Roq extends XSModule {
// roq redirect only used for exception
io.redirect := DontCare //TODO
io.redirect.valid := false.B //TODO
//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")
}
}
package xiangshan.frontend
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
class Ibuffer extends XSModule with NeedImpl {
val io = IO(new Bundle() {
val flush = Input(Bool())
val in = Flipped(DecoupledIO(new FetchPacket))
val out = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
})
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))
})
val debug = false
if(debug){
// printf("\n------New Cycle------\n")
when(io.in.valid) {
printf("cache data:\n")
for (i <- 0 until FetchWidth) {
printf("%b\n", io.in.bits.instrs(i))
}
printf("\n")
}
}
// ignore
for(i <- 0 until DecodeWidth) {
io.out(i).bits.exceptionVec := DontCare
io.out(i).bits.intrVec := DontCare
io.out(i).bits.isBr := DontCare
}
// ibuf define
val ibuf = RegInit(VecInit(Seq.fill(IBufSize*2)(0.U(16.W))))
val ibuf_pc = RegInit(VecInit(Seq.fill(IBufSize*2)(0.U(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) {
if(debug) {
printf("\n*****Enque start*****\n")
}
var enq_idx = 0.U(log2Up(FetchWidth*2+1).W)
for(i <- 0 until FetchWidth) {
when(io.in.bits.mask(i)) {
ibuf(tail_ptr + enq_idx) := io.in.bits.instrs(i)(15,0)
ibuf_pc(tail_ptr + enq_idx) := io.in.bits.pc + enq_idx + enq_idx
ibuf_valid(tail_ptr + enq_idx) := true.B
ibuf(tail_ptr + enq_idx+1.U) := io.in.bits.instrs(i)(31,16)
ibuf_pc(tail_ptr + enq_idx+1.U) := io.in.bits.pc + enq_idx + enq_idx + 2.U
ibuf_valid(tail_ptr + enq_idx+1.U) := true.B
if(debug) {
printf("%b\n", io.in.bits.instrs(i)(15,0))
printf("%b\n", io.in.bits.instrs(i)(31,16))
}
}
enq_idx = enq_idx + io.in.bits.mask(i) + io.in.bits.mask(i)
}
tail_ptr := tail_ptr + enq_idx
last_enq := true.B
if(debug) {
printf("tail_ptr: %d\n", tail_ptr + enq_idx)
}
}
// deque
when(deqValid) {
if(debug) {
printf("\n*****Deque start*****\n")
printf("Last head_ptr: %d, tail_ptr: %d\n", head_ptr, tail_ptr)
}
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)
if(debug) {
printf("RCV: %b ", Cat(0.U(16.W), ibuf(head_ptr + deq_idx)))
printf("PC: %d\n", 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)
if(debug) {
printf("NOT RVC: %b ", Cat(ibuf(head_ptr + deq_idx+1.U), ibuf(head_ptr + deq_idx)))
printf("PC: %d\n", 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)
if(debug) {
printf("This is half inst\n")
}
io.out(i).bits.pc := 0.U(VAddrBits.W)
io.out(i).bits.isRVC := false.B
io.out(i).valid := false.B
}
}.otherwise {
if(debug) {
printf("This output is not ready, or buffer is empty\n")
}
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
}
if(debug) {
printf("deq_idx: %d\n", deq_idx)
}
// 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 +
(io.out(i).ready && ibuf_valid(head_ptr + deq_idx) && ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) +
(io.out(i).ready && ibuf_valid(head_ptr + deq_idx) && !(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) && ibuf_valid(head_ptr + deq_idx + 1.U)) +
(io.out(i).ready && ibuf_valid(head_ptr + deq_idx) && !(ibuf(head_ptr + deq_idx)(1,0) =/= "b11".U) && ibuf_valid(head_ptr + deq_idx + 1.U))
}
head_ptr := head_ptr + deq_idx
if(debug) {
printf("head_ptr: %d\n", 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) {
ibuf_valid(i) := false.B
head_ptr := 0.U
tail_ptr := 0.U
}
for(i <- 0 until DecodeWidth) {
io.out(i).valid := false.B
}
}
}
\ No newline at end of file
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.
先完成此消息的编辑!
想要评论请 注册