fix: pass remaining riscv isa tests

This commit is contained in:
abnerhexu
2026-06-27 07:07:07 +00:00
parent a2e0126199
commit a32db39c80
38 changed files with 81187 additions and 19321 deletions

View File

@@ -26,6 +26,7 @@ class Core(p: CoreParams = CoreParams()) extends Module {
frontend.io.redirectValid := backend.io.flush
frontend.io.redirectPc := backend.io.redirectPc
frontend.io.invalidateICache := backend.io.invalidateICache
frontend.io.imemRespValid := io.imem_resp_valid
frontend.io.imemRespBits(0) := io.imem_resp_bits_0
frontend.io.imemRespBits(1) := io.imem_resp_bits_1

View File

@@ -15,6 +15,7 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val commitEntry = Output(Vec(p.issueWidth, new RobEntry(p)))
val flush = Output(Bool())
val redirectPc = Output(UInt(p.xlen.W))
val invalidateICache = Output(Bool())
val dmemReqValid = Output(Bool())
val dmemReq = Output(new MemRequest(p))
@@ -81,7 +82,14 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val loadPendingRob = Reg(UInt(robBits.W))
val loadPendingPhys = Reg(UInt(physBits.W))
val loadPendingLq = Reg(UInt(log2Ceil(p.loadQueueEntries).W))
val loadRespValid = lsu.io.respValid && loadPending
val forwardPending = RegInit(false.B)
val forwardPendingRob = Reg(UInt(robBits.W))
val forwardPendingPhys = Reg(UInt(physBits.W))
val forwardPendingLq = Reg(UInt(log2Ceil(p.loadQueueEntries).W))
val forwardPendingData = Reg(UInt(p.xlen.W))
val loadRespValid = (lsu.io.respValid && loadPending) || forwardPending
val loadRespData = Mux(forwardPending, forwardPendingData, lsu.io.respData)
val loadRespPageFault = !forwardPending && lsu.io.pageFault
val memIssue = Wire(Vec(p.issueWidth, Bool()))
for (i <- 0 until p.issueWidth) {
memIssue(i) := issue.io.outValid(i) && (issue.io.out(i).decoded.isLoad || issue.io.out(i).decoded.isStore)
@@ -95,15 +103,20 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val memSlot0 = memIssue(0)
val memSlot1 = !memSlot0 && memIssue(1)
val memSlot = Mux(memSlot0, 0.U, 1.U)
val canIssueMem = !loadPending
val canIssueMem = !loadPending && !forwardPending
val issue_io_outReady_0 = Wire(Bool())
val issue_io_outReady_1 = Wire(Bool())
dontTouch(issue_io_outReady_0)
dontTouch(issue_io_outReady_1)
val isMem0 = issue.io.out(0).decoded.isLoad || issue.io.out(0).decoded.isStore
val isMem1 = issue.io.out(1).decoded.isLoad || issue.io.out(1).decoded.isStore
val memReady0 = !isMem0 || (lsu.io.reqReady && canIssueMem)
val memReady1 = !isMem1 || (lsu.io.reqReady && canIssueMem && !memSlot0)
val loadBlocked0 = issue.io.out(0).decoded.isLoad && sq.io.forwardBlock
val loadBlocked1 = issue.io.out(1).decoded.isLoad && sq.io.forwardBlock
val amoBlocked0 = issue.io.out(0).decoded.isAmo && (sq.io.olderStoreValid || sq.io.drainValid)
val amoBlocked1 = issue.io.out(1).decoded.isAmo && (sq.io.olderStoreValid || sq.io.drainValid)
val memReady0 = (!isMem0 || (lsu.io.reqReady && canIssueMem && !amoBlocked0 && !loadBlocked0)) &&
!loadPending && !forwardPending
val memReady1 = !isMem1 || (lsu.io.reqReady && canIssueMem && !memSlot0 && !amoBlocked1 && !loadBlocked1)
issue_io_outReady_0 := memReady0
issue_io_outReady_1 := memReady1 && !stallSecondCsrRead
issue.io.outReady := VecInit(Seq(issue_io_outReady_0, issue_io_outReady_1))
@@ -118,11 +131,22 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val memDecoded = issue.io.out(memSlot).decoded
val memSrc1 = Mux(memSlot0, prf.io.rdata(0), prf.io.rdata(2))
val memSrc2 = Mux(memSlot0, prf.io.rdata(1), prf.io.rdata(3))
val memAddr = memSrc1 + Mux(memDecoded.isStore, memDecoded.immS, memDecoded.immI)
val memAddr = memSrc1 + Mux(memDecoded.isAmo, 0.U, Mux(memDecoded.isStore, memDecoded.immS, memDecoded.immI))
val loadEnq = (memSlot0 || memSlot1) && memDecoded.isLoad && issue.io.outReady(memSlot)
val storeEnq = (memSlot0 || memSlot1) && memDecoded.isStore && issue.io.outReady(memSlot)
val lsuLoadReq = loadEnq && !sq.io.forwardValid
val sqForwardValid = sq.io.forwardValid && !memDecoded.isAmo
val forwardLoad = loadEnq && sqForwardValid
val lsuLoadReq = loadEnq && !sqForwardValid
val forwardByte = sq.io.forwardData(7, 0)
val forwardHalf = sq.io.forwardData(15, 0)
val forwardWord = sq.io.forwardData(31, 0)
val forwardSelected = MuxLookup(memDecoded.memWidth, sq.io.forwardData)(Seq(
0.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardByte, 8), forwardByte),
1.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardHalf, 16), forwardHalf),
2.U -> Mux(memDecoded.memSigned, Consts.signExtend(forwardWord, 32), forwardWord),
3.U -> sq.io.forwardData
))
lq.io.enqValid := loadEnq
lq.io.enqRobIdx := issue.io.out(memSlot).robIdx
@@ -131,7 +155,11 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
lq.io.addr := memAddr
lq.io.size := memDecoded.memWidth
lq.io.complete := loadRespValid
lq.io.completeIdx := loadPendingLq
lq.io.completeIdx := Mux(forwardPending, forwardPendingLq, loadPendingLq)
lq.io.commitValid := VecInit((0 until p.issueWidth).map(i =>
commit.io.commitReady(i) && rename.io.commitValid(i) &&
rename.io.commitEntry(i).opClass === Consts.OP_LOAD))
lq.io.commitRobIdx := VecInit((0 until p.issueWidth).map(i => rename.io.commitEntry(i).robIdx))
lq.io.storeAddrValid := storeEnq
lq.io.storeRobIdx := issue.io.out(memSlot).robIdx
lq.io.storeAddr := memAddr
@@ -159,13 +187,15 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
sq.io.flush := commit.io.flush
lsu.io.reqValid := lsuLoadReq || sq.io.drainValid
lsu.io.req := Mux(sq.io.drainValid, sq.io.drain, 0.U.asTypeOf(new MemRequest(p)))
when(lsuLoadReq) {
lsu.io.req.addr := memAddr
lsu.io.req.data := 0.U
lsu.io.req.isStore := false.B
lsu.io.req.size := memDecoded.memWidth
}
val loadReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
loadReq.addr := memAddr
loadReq.data := memSrc2
loadReq.isStore := false.B
loadReq.isSigned := memDecoded.memSigned || memDecoded.isAmo
loadReq.isAmo := memDecoded.isAmo
loadReq.amoOp := memDecoded.amoOp
loadReq.size := memDecoded.memWidth
lsu.io.req := Mux(lsuLoadReq, loadReq, sq.io.drain)
lsu.io.dmemRespValid := io.dmemRespValid
lsu.io.dmemRespData := io.dmemRespData
lsu.io.satp := csr.io.satp
@@ -190,7 +220,16 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
when(commit.io.flush) {
loadPending := false.B
}.elsewhen(loadEnq && !sq.io.forwardValid) {
forwardPending := false.B
}.elsewhen(forwardLoad) {
forwardPending := true.B
forwardPendingRob := issue.io.out(memSlot).robIdx
forwardPendingPhys := issue.io.out(memSlot).prd
forwardPendingLq := lq.io.enqIdx
forwardPendingData := forwardSelected
}.elsewhen(forwardPending) {
forwardPending := false.B
}.elsewhen(loadEnq && !sqForwardValid) {
loadPending := true.B
loadPendingRob := issue.io.out(memSlot).robIdx
loadPendingPhys := issue.io.out(memSlot).prd
@@ -218,8 +257,8 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val isLoadRespSlot = i.U === 0.U && loadRespValid
val useExecWb = exec(i).io.outValid && decoded.writesRd && !decoded.isLoad
wb(i).io.valid := useExecWb || isLoadRespSlot
wb(i).io.physDest := Mux(isLoadRespSlot, loadPendingPhys, issue.io.out(i).prd)
wb(i).io.data := Mux(isLoadRespSlot, lsu.io.respData, Mux(decoded.isLui, decoded.immU,
wb(i).io.physDest := Mux(isLoadRespSlot, Mux(forwardPending, forwardPendingPhys, loadPendingPhys), issue.io.out(i).prd)
wb(i).io.data := Mux(isLoadRespSlot, loadRespData, Mux(decoded.isLui, decoded.immU,
Mux(decoded.isAuipc, decoded.pc + decoded.immU,
Mux(decoded.isJal || decoded.isJalr, decoded.pc + 4.U,
Mux(decoded.isSystem && decoded.funct3 =/= 0.U, csrRData(i), exec(i).io.result)))))
@@ -244,16 +283,17 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
val completeLoadResp = i.U === 0.U && loadRespValid
completeValid(i) := (issueFire(i) && !decoded.isLoad) || completeLoadResp
completeIdx(i) := Mux(completeLoadResp, loadPendingRob, issue.io.out(i).robIdx)
completeIdx(i) := Mux(completeLoadResp, Mux(forwardPending, forwardPendingRob, loadPendingRob), issue.io.out(i).robIdx)
completeException(i) := (issueFire(i) && (decoded.illegal || isEcall || isEbreak || lq.io.violation)) ||
(completeLoadResp && lsu.io.pageFault)
completeCause(i) := Mux(completeLoadResp && lsu.io.pageFault, 13.U,
(completeLoadResp && loadRespPageFault)
completeCause(i) := Mux(completeLoadResp && loadRespPageFault, 13.U,
Mux(issueFire(i) && isEbreak, 3.U,
Mux(issueFire(i) && isEcall, 11.U,
Mux(issueFire(i) && decoded.illegal, 2.U, 0.U))))
completeBadAddr(i) := decoded.pc
completeMispredict(i) := issueFire(i) &&
(decoded.isJal || decoded.isJalr || isMret || (decoded.isBranch && exec(i).io.branchTaken))
(decoded.isJal || decoded.isJalr || isMret || decoded.isFenceI ||
(decoded.isBranch && exec(i).io.branchTaken))
completeRedirectPc(i) := Mux(isEcall || isEbreak, csr.io.mtvec, Mux(isMret, csr.io.mepc, branchRedirect))
completeCsrValid(i) := issueFire(i) && decoded.isSystem && decoded.funct3 =/= 0.U &&
!(decoded.funct3(1) && decoded.rs1 === 0.U)
@@ -271,6 +311,7 @@ class OoOBackend(p: CoreParams = CoreParams()) extends Module {
io.commitEntry := rename.io.commitEntry
io.flush := commit.io.flush
io.redirectPc := Mux(commit.io.exception, csr.io.mtvec, commit.io.redirectPc)
io.invalidateICache := commit.io.fenceI
}
object OoOBackend extends App {

View File

@@ -18,6 +18,7 @@ class CommitStage(p: CoreParams = CoreParams()) extends Module {
val exception = Output(Bool())
val exceptionCause = Output(UInt(p.xlen.W))
val badAddr = Output(UInt(p.xlen.W))
val fenceI = Output(Bool())
})
val firstTrap = io.robValid(0) && (io.robEntry(0).exception || io.robEntry(0).branchMispredict)
@@ -49,4 +50,6 @@ class CommitStage(p: CoreParams = CoreParams()) extends Module {
Mux(secondTrapSelected, io.robEntry(1).exceptionCause, 0.U))
io.badAddr := Mux(firstTrap, io.robEntry(0).badAddr,
Mux(secondTrapSelected, io.robEntry(1).badAddr, 0.U))
io.fenceI := io.commitReady(0) && io.robEntry(0).fenceI ||
io.commitReady(1) && io.robEntry(1).fenceI
}

View File

@@ -47,6 +47,9 @@ class DecodedInst(p: CoreParams = CoreParams()) extends Bundle {
val isOp = Bool()
val isWord = Bool()
val isSystem = Bool()
val isFenceI = Bool()
val isAmo = Bool()
val amoOp = UInt(5.W)
val writesRd = Bool()
val illegal = Bool()
}
@@ -73,6 +76,9 @@ class MemRequest(p: CoreParams = CoreParams()) extends Bundle {
val addr = UInt(p.xlen.W)
val data = UInt(p.xlen.W)
val isStore = Bool()
val isSigned = Bool()
val isAmo = Bool()
val amoOp = UInt(5.W)
val size = UInt(3.W)
}

View File

@@ -29,6 +29,9 @@ object Consts {
val ALU_REM = 13.U(5.W)
val ALU_REMU = 14.U(5.W)
val ALU_COPY_B = 15.U(5.W)
val ALU_MULH = 16.U(5.W)
val ALU_MULHSU = 17.U(5.W)
val ALU_MULHU = 18.U(5.W)
def signExtend(value: UInt, from: Int, to: Int = 64): UInt =
Cat(Fill(to - from, value(from - 1)), value(from - 1, 0))

View File

@@ -30,6 +30,7 @@ class Decoder(p: CoreParams = CoreParams()) extends Module {
d.rd := rd
d.funct3 := funct3
d.funct7 := funct7
d.amoOp := io.inst(31, 27)
d.immI := immI
d.immS := immS
d.immB := immB
@@ -106,6 +107,9 @@ class Decoder(p: CoreParams = CoreParams()) extends Module {
d.opClass := Consts.OP_ALU
d.aluFn := Mux(funct7 === "b0000001".U, MuxLookup(funct3, Consts.ALU_MUL)(Seq(
"b000".U -> Consts.ALU_MUL,
"b001".U -> Consts.ALU_MULH,
"b010".U -> Consts.ALU_MULHSU,
"b011".U -> Consts.ALU_MULHU,
"b100".U -> Consts.ALU_DIV,
"b101".U -> Consts.ALU_DIVU,
"b110".U -> Consts.ALU_REM,
@@ -123,6 +127,7 @@ class Decoder(p: CoreParams = CoreParams()) extends Module {
}
is("b0001111".U) {
d.opClass := Consts.OP_SYSTEM
d.isFenceI := funct3 === "b001".U
}
is("b1110011".U) {
d.isSystem := true.B
@@ -131,7 +136,7 @@ class Decoder(p: CoreParams = CoreParams()) extends Module {
}
is("b0101111".U) {
d.isLoad := true.B
d.isStore := true.B
d.isAmo := true.B
d.writesRd := rd =/= 0.U
d.memWidth := Mux(funct3 === "b010".U, 2.U, 3.U)
d.opClass := Consts.OP_LOAD

View File

@@ -11,19 +11,27 @@ class ALU(p: CoreParams = CoreParams()) extends Module {
})
val shamt = Mux(io.isWord, io.b(4, 0), io.b(5, 0))
val wordShamt = io.b(4, 0)
val wordA = io.a(31, 0)
val signedProduct = (io.a.asSInt * io.b.asSInt).asUInt
val signedUnsignedProduct = (io.a.asSInt * Cat(0.U(1.W), io.b).asSInt).asUInt
val unsignedProduct = io.a * io.b
val raw = WireDefault(0.U(p.xlen.W))
switch(io.fn) {
is(Consts.ALU_ADD) { raw := io.a + io.b }
is(Consts.ALU_SUB) { raw := io.a - io.b }
is(Consts.ALU_SLL) { raw := io.a << shamt }
is(Consts.ALU_SLL) { raw := Mux(io.isWord, wordA << wordShamt, io.a << shamt) }
is(Consts.ALU_SLT) { raw := (io.a.asSInt < io.b.asSInt).asUInt }
is(Consts.ALU_SLTU) { raw := io.a < io.b }
is(Consts.ALU_XOR) { raw := io.a ^ io.b }
is(Consts.ALU_SRL) { raw := io.a >> shamt }
is(Consts.ALU_SRA) { raw := (io.a.asSInt >> shamt).asUInt }
is(Consts.ALU_SRL) { raw := Mux(io.isWord, wordA >> wordShamt, io.a >> shamt) }
is(Consts.ALU_SRA) { raw := Mux(io.isWord, (wordA.asSInt >> wordShamt).asUInt, (io.a.asSInt >> shamt).asUInt) }
is(Consts.ALU_OR) { raw := io.a | io.b }
is(Consts.ALU_AND) { raw := io.a & io.b }
is(Consts.ALU_MUL) { raw := (io.a * io.b)(p.xlen - 1, 0) }
is(Consts.ALU_MULH) { raw := signedProduct(2 * p.xlen - 1, p.xlen) }
is(Consts.ALU_MULHSU) { raw := signedUnsignedProduct(2 * p.xlen - 1, p.xlen) }
is(Consts.ALU_MULHU) { raw := unsignedProduct(2 * p.xlen - 1, p.xlen) }
is(Consts.ALU_DIV) { raw := Mux(io.b === 0.U, Fill(p.xlen, 1.U), (io.a.asSInt / io.b.asSInt).asUInt) }
is(Consts.ALU_DIVU) { raw := Mux(io.b === 0.U, Fill(p.xlen, 1.U), io.a / io.b) }
is(Consts.ALU_REM) { raw := Mux(io.b === 0.U, io.a, (io.a.asSInt % io.b.asSInt).asUInt) }
@@ -33,4 +41,3 @@ class ALU(p: CoreParams = CoreParams()) extends Module {
io.out := Mux(io.isWord, Consts.signExtend(raw(31, 0), 32), raw)
}

View File

@@ -5,6 +5,7 @@ class Frontend(p: CoreParams = CoreParams()) extends Module {
val io = IO(new Bundle {
val redirectValid = Input(Bool())
val redirectPc = Input(UInt(p.xlen.W))
val invalidateICache = Input(Bool())
val imemReqValid = Output(Bool())
val imemReqAddr = Output(UInt(p.xlen.W))
val imemRespValid = Input(Bool())
@@ -36,6 +37,7 @@ class Frontend(p: CoreParams = CoreParams()) extends Module {
icache.io.reqAddr := Mux(itlb.io.resp.hit, itlb.io.resp.paddr, pc)
icache.io.reqPc := pc
icache.io.flush := io.redirectValid
icache.io.invalidate := io.invalidateICache
icache.io.respReady := io.outReady
icache.io.memRespValid := io.imemRespValid
icache.io.memRespBits := io.imemRespBits

View File

@@ -14,6 +14,7 @@ class ICache(p: CoreParams = CoreParams()) extends Module {
val reqAddr = Input(UInt(p.xlen.W))
val reqPc = Input(UInt(p.xlen.W))
val flush = Input(Bool())
val invalidate = Input(Bool())
val respReady = Input(Bool())
val memReqValid = Output(Bool())
val memReqAddr = Output(UInt(p.xlen.W))
@@ -102,7 +103,12 @@ class ICache(p: CoreParams = CoreParams()) extends Module {
Mux(state === sMiss && io.memRespValid, missResp, lookupResp))
io.miss := state === sLookup && !hit || state === sMiss
when(io.flush) {
when(io.invalidate) {
valid := VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.iCacheWays)(
VecInit(Seq.fill(lineInsts)(false.B))))))
state := sIdle
missReqSent := false.B
}.elsewhen(io.flush) {
state := sIdle
missReqSent := false.B
}.elsewhen(state === sIdle) {

View File

@@ -16,6 +16,11 @@ class ReservationStation(p: CoreParams = CoreParams(), entries: Int = 16) extend
val valid = RegInit(VecInit(Seq.fill(entries)(false.B)))
val slots = Reg(Vec(entries, new RenamePacket(p)))
def isOlder(a: UInt, b: UInt): Bool = {
val diff = b - a
diff =/= 0.U && !diff(log2Ceil(p.robEntries) - 1)
}
val freeMask = VecInit(valid.map(!_.asBool)).asUInt
val enq0OH = PriorityEncoderOH(freeMask)
val enq1OH = PriorityEncoderOH(freeMask & ~enq0OH)
@@ -28,7 +33,11 @@ class ReservationStation(p: CoreParams = CoreParams(), entries: Int = 16) extend
val src2Wake = io.wakeup.map(w => w.valid && w.phys === slots(i).prs2).reduce(_ || _)
val src1ReadyNow = slots(i).src1Ready || src1Wake || slots(i).decoded.rs1 === 0.U
val src2ReadyNow = slots(i).src2Ready || src2Wake || slots(i).decoded.rs2 === 0.U
readyVec(i) := valid(i) && src1ReadyNow && src2ReadyNow
val olderStorePending = VecInit((0 until entries).map(j =>
valid(j) && slots(j).decoded.isStore && isOlder(slots(j).robIdx, slots(i).robIdx)
)).asUInt.orR
val waitsForOlderStore = (slots(i).decoded.isLoad || slots(i).decoded.isAmo) && olderStorePending
readyVec(i) := valid(i) && src1ReadyNow && src2ReadyNow && !waitsForOlderStore
}
val issue0OH = PriorityEncoderOH(readyVec.asUInt)

View File

@@ -26,8 +26,16 @@ class DCache(p: CoreParams = CoreParams()) extends Module {
def setIndex(addr: UInt): UInt = addr(offsetBits + setBits - 1, offsetBits)
def wordIndex(addr: UInt): UInt = addr(offsetBits - 1, byteBits)
def tag(addr: UInt): UInt = addr(p.xlen - 1, offsetBits + setBits)
def alignedWordAddr(addr: UInt): UInt = Cat(addr(p.xlen - 1, byteBits), 0.U(byteBits.W))
def accessBytes(size: UInt): UInt = MuxLookup(size, 8.U(4.W))(Seq(
0.U -> 1.U(4.W),
1.U -> 2.U(4.W),
2.U -> 4.U(4.W),
3.U -> 8.U(4.W)
))
def crossesWord(addr: UInt, size: UInt): Bool = addr(byteBits - 1, 0) +& accessBytes(size) > 8.U
def loadSelect(word: UInt, addr: UInt, size: UInt, signed: Bool = true.B): UInt = {
def loadSelect(word: UInt, addr: UInt, size: UInt, signed: Bool): UInt = {
val byteShift = addr(byteBits - 1, 0) << 3
val shifted = word >> byteShift
val b = shifted(7, 0)
@@ -41,12 +49,45 @@ class DCache(p: CoreParams = CoreParams()) extends Module {
))
}
def amoResult(oldValue: UInt, src: UInt, size: UInt, op: UInt): UInt = {
val isWord = size === 2.U
val oldW = oldValue(31, 0)
val srcW = src(31, 0)
val wordResult = WireDefault(oldW + srcW)
switch(op) {
is("b00001".U) { wordResult := srcW }
is("b00100".U) { wordResult := oldW ^ srcW }
is("b01100".U) { wordResult := oldW & srcW }
is("b01000".U) { wordResult := oldW | srcW }
is("b10000".U) { wordResult := Mux(oldW.asSInt < srcW.asSInt, oldW, srcW) }
is("b10100".U) { wordResult := Mux(oldW.asSInt > srcW.asSInt, oldW, srcW) }
is("b11000".U) { wordResult := Mux(oldW < srcW, oldW, srcW) }
is("b11100".U) { wordResult := Mux(oldW > srcW, oldW, srcW) }
}
val xlenResult = WireDefault(oldValue + src)
switch(op) {
is("b00001".U) { xlenResult := src }
is("b00100".U) { xlenResult := oldValue ^ src }
is("b01100".U) { xlenResult := oldValue & src }
is("b01000".U) { xlenResult := oldValue | src }
is("b10000".U) { xlenResult := Mux(oldValue.asSInt < src.asSInt, oldValue, src) }
is("b10100".U) { xlenResult := Mux(oldValue.asSInt > src.asSInt, oldValue, src) }
is("b11000".U) { xlenResult := Mux(oldValue < src, oldValue, src) }
is("b11100".U) { xlenResult := Mux(oldValue > src, oldValue, src) }
}
Mux(isWord, Consts.signExtend(wordResult, 32), xlenResult)
}
val valid = RegInit(VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.dCacheWays)(false.B)))))
val wordValid = RegInit(VecInit(Seq.fill(sets)(VecInit(Seq.fill(p.dCacheWays)(
VecInit(Seq.fill(lineWords)(false.B)))))))
val tags = SyncReadMem(sets, Vec(p.dCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
val data = SyncReadMem(sets, Vec(p.dCacheWays, Vec(lineWords, UInt(p.xlen.W))))
val repl = RegInit(VecInit(Seq.fill(sets)(0.U(log2Ceil(p.dCacheWays).W))))
val sIdle :: sLookup :: sMiss :: Nil = Enum(3)
val sIdle :: sLookup :: sMiss :: sAmoRead :: sAmoWrite :: sMisalignReadLo :: sMisalignReadHi :: sMisalignResp :: Nil = Enum(8)
val state = RegInit(sIdle)
val reqReg = Reg(new MemRequest(p))
val reqSet = Reg(UInt(setBits.W))
@@ -55,40 +96,127 @@ class DCache(p: CoreParams = CoreParams()) extends Module {
val missWay = Reg(UInt(log2Ceil(p.dCacheWays).W))
val missTagRow = Reg(Vec(p.dCacheWays, UInt((p.xlen - offsetBits - setBits).W)))
val missDataRow = Reg(Vec(p.dCacheWays, Vec(lineWords, UInt(p.xlen.W))))
val amoOldData = Reg(UInt(p.xlen.W))
val amoStoreData = Reg(UInt(p.xlen.W))
val scStore = RegInit(false.B)
val reservationValid = RegInit(false.B)
val reservationAddr = Reg(UInt(p.xlen.W))
val misalignLo = Reg(UInt(p.xlen.W))
val misalignHi = Reg(UInt(p.xlen.W))
def reservationGranule(addr: UInt): UInt = addr(p.xlen - 1, 2)
val set = setIndex(io.req.addr)
val storeEndSet = setIndex(io.req.addr + accessBytes(io.req.size) - 1.U)
val word = wordIndex(io.req.addr)
val readFire = state === sIdle && io.reqValid && !io.req.isStore
val readFire = state === sIdle && io.reqValid && !io.req.isStore && !io.req.isAmo
val readTags = tags.read(set, readFire)
val readData = data.read(set, readFire)
val hitVec = VecInit((0 until p.dCacheWays).map(w => reqValidRow(w) && readTags(w) === tag(reqReg.addr)))
val hitVec = VecInit((0 until p.dCacheWays).map(w =>
reqValidRow(w) && wordValid(reqSet)(w)(reqWord) && readTags(w) === tag(reqReg.addr)))
val hit = hitVec.asUInt.orR
val hitWay = OHToUInt(hitVec)
val hitWord = readData(hitWay)(reqWord)
val hitResp = loadSelect(hitWord, reqReg.addr, reqReg.size)
val hitResp = loadSelect(hitWord, reqReg.addr, reqReg.size, reqReg.isSigned)
val storeBypass = state === sIdle && io.reqValid && io.req.isStore
val memReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
memReq.addr := lineAddr(reqReg.addr) + (reqWord << byteBits)
memReq.addr := alignedWordAddr(reqReg.addr)
memReq.data := reqReg.data
memReq.isStore := reqReg.isStore
memReq.isSigned := reqReg.isSigned
memReq.isAmo := false.B
memReq.amoOp := reqReg.amoOp
memReq.size := 3.U
val misalignLoReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
misalignLoReq.addr := alignedWordAddr(reqReg.addr)
misalignLoReq.data := 0.U
misalignLoReq.isStore := false.B
misalignLoReq.isSigned := reqReg.isSigned
misalignLoReq.isAmo := false.B
misalignLoReq.amoOp := reqReg.amoOp
misalignLoReq.size := 3.U
val misalignHiReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
misalignHiReq.addr := alignedWordAddr(reqReg.addr) + 8.U
misalignHiReq.data := 0.U
misalignHiReq.isStore := false.B
misalignHiReq.isSigned := reqReg.isSigned
misalignHiReq.isAmo := false.B
misalignHiReq.amoOp := reqReg.amoOp
misalignHiReq.size := 3.U
val amoReadReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
amoReadReq.addr := lineAddr(reqReg.addr) + (reqWord << byteBits)
amoReadReq.data := 0.U
amoReadReq.isStore := false.B
amoReadReq.isSigned := true.B
amoReadReq.isAmo := false.B
amoReadReq.amoOp := reqReg.amoOp
amoReadReq.size := 3.U
val amoWriteReq = WireDefault(0.U.asTypeOf(new MemRequest(p)))
amoWriteReq.addr := reqReg.addr
amoWriteReq.data := amoStoreData
amoWriteReq.isStore := true.B
amoWriteReq.isSigned := true.B
amoWriteReq.isAmo := false.B
amoWriteReq.amoOp := reqReg.amoOp
amoWriteReq.size := reqReg.size
io.reqReady := state === sIdle
io.memReqValid := state === sMiss || storeBypass
io.memReq := Mux(storeBypass, io.req, memReq)
io.memReqValid := state === sMiss || storeBypass || state === sMisalignReadLo ||
state === sMisalignReadHi || state === sAmoRead ||
state === sAmoWrite && scStore
io.memReq := Mux(storeBypass, io.req,
Mux(state === sMisalignReadLo, misalignLoReq,
Mux(state === sMisalignReadHi, misalignHiReq,
Mux(state === sAmoRead, amoReadReq,
Mux(state === sAmoWrite, amoWriteReq, memReq)))))
io.respValid := state === sLookup && hit && !reqReg.isStore ||
state === sMiss && io.memRespValid && !reqReg.isStore
io.respData := Mux(state === sMiss, loadSelect(io.memRespData, reqReg.addr, reqReg.size), hitResp)
state === sMiss && io.memRespValid && !reqReg.isStore ||
state === sAmoWrite || state === sMisalignResp
val misalignMerged = (Cat(misalignHi, misalignLo) >> (reqReg.addr(byteBits - 1, 0) << 3))(p.xlen - 1, 0)
io.respData := Mux(state === sAmoWrite, amoOldData,
Mux(state === sMisalignResp, loadSelect(misalignMerged, 0.U, reqReg.size, reqReg.isSigned),
Mux(state === sMiss, loadSelect(io.memRespData, reqReg.addr, reqReg.size, reqReg.isSigned), hitResp)))
io.miss := state === sLookup && !hit || state === sMiss
when(storeBypass) {
valid(set) := VecInit(Seq.fill(p.dCacheWays)(false.B))
wordValid(set) := VecInit(Seq.fill(p.dCacheWays)(VecInit(Seq.fill(lineWords)(false.B))))
when(storeEndSet =/= set) {
valid(storeEndSet) := VecInit(Seq.fill(p.dCacheWays)(false.B))
wordValid(storeEndSet) := VecInit(Seq.fill(p.dCacheWays)(VecInit(Seq.fill(lineWords)(false.B))))
}
when(reservationValid && reservationGranule(reservationAddr) === reservationGranule(io.req.addr)) {
reservationValid := false.B
}
}
when(state === sAmoWrite) {
valid(reqSet) := VecInit(Seq.fill(p.dCacheWays)(false.B))
wordValid(reqSet) := VecInit(Seq.fill(p.dCacheWays)(VecInit(Seq.fill(lineWords)(false.B))))
when(scStore || reqReg.amoOp =/= "b00010".U) {
when(reservationValid && reservationGranule(reservationAddr) === reservationGranule(reqReg.addr)) {
reservationValid := false.B
}
}
}
when(state === sIdle) {
when(io.reqValid && !io.req.isStore) {
when(io.reqValid && io.req.isAmo) {
reqReg := io.req
reqSet := set
reqWord := word
state := sAmoRead
}.elsewhen(io.reqValid && !io.req.isStore && crossesWord(io.req.addr, io.req.size)) {
reqReg := io.req
reqSet := set
reqWord := word
state := sMisalignReadLo
}.elsewhen(io.reqValid && !io.req.isStore) {
reqReg := io.req
reqSet := set
reqWord := word
@@ -115,10 +243,46 @@ class DCache(p: CoreParams = CoreParams()) extends Module {
tagWrite(missWay) := tag(reqReg.addr)
dataWrite(missWay)(reqWord) := io.memRespData
valid(reqSet)(missWay) := true.B
for (i <- 0 until lineWords) {
wordValid(reqSet)(missWay)(i) := false.B
}
wordValid(reqSet)(missWay)(reqWord) := true.B
tags.write(reqSet, tagWrite)
data.write(reqSet, dataWrite)
repl(reqSet) := missWay + 1.U
state := sIdle
}
}.elsewhen(state === sAmoRead) {
when(io.memRespValid) {
val oldSelected = loadSelect(io.memRespData, reqReg.addr, reqReg.size, true.B)
val scSuccess = reservationValid &&
reservationGranule(reservationAddr) === reservationGranule(reqReg.addr)
amoOldData := Mux(reqReg.amoOp === "b00011".U, Mux(scSuccess, 0.U, 1.U), oldSelected)
amoStoreData := Mux(reqReg.amoOp === "b00010".U, oldSelected,
Mux(reqReg.amoOp === "b00011".U, reqReg.data, amoResult(oldSelected, reqReg.data, reqReg.size, reqReg.amoOp)))
scStore := reqReg.amoOp =/= "b00010".U && (reqReg.amoOp =/= "b00011".U || scSuccess)
when(reqReg.amoOp === "b00010".U) {
reservationValid := true.B
reservationAddr := reqReg.addr
}.elsewhen(reqReg.amoOp === "b00011".U) {
reservationValid := false.B
}
state := sAmoWrite
}
}.elsewhen(state === sAmoWrite) {
scStore := false.B
state := sIdle
}.elsewhen(state === sMisalignReadLo) {
when(io.memRespValid) {
misalignLo := io.memRespData
state := sMisalignReadHi
}
}.elsewhen(state === sMisalignReadHi) {
when(io.memRespValid) {
misalignHi := io.memRespData
state := sMisalignResp
}
}.elsewhen(state === sMisalignResp) {
state := sIdle
}
}

View File

@@ -58,6 +58,9 @@ class LSU(p: CoreParams = CoreParams()) extends Module {
ptwReqAsMem.addr := mmu.io.ptwMemReq.addr
ptwReqAsMem.data := 0.U
ptwReqAsMem.isStore := false.B
ptwReqAsMem.isSigned := false.B
ptwReqAsMem.isAmo := false.B
ptwReqAsMem.amoOp := 0.U
ptwReqAsMem.size := 3.U
io.dmemReqValid := mmu.io.ptwMemReq.valid || dcache.io.memReqValid

View File

@@ -18,6 +18,8 @@ class LoadQueue(p: CoreParams = CoreParams()) extends Module {
val complete = Input(Bool())
val completeIdx = Input(UInt(idxBits.W))
val commitValid = Input(Vec(p.issueWidth, Bool()))
val commitRobIdx = Input(Vec(p.issueWidth, UInt(robBits.W)))
val storeAddrValid = Input(Bool())
val storeRobIdx = Input(UInt(robBits.W))
@@ -41,12 +43,17 @@ class LoadQueue(p: CoreParams = CoreParams()) extends Module {
a0 === b0 && ((a(2, 0) | am) >= b(2, 0)) && ((b(2, 0) | bm) >= a(2, 0))
}
def isOlder(a: UInt, b: UInt): Bool = {
val diff = b - a
diff =/= 0.U && !diff(robBits - 1)
}
io.enqReady := freeMask.orR
io.enqIdx := enqIdx
val violationVec = Wire(Vec(p.loadQueueEntries, Bool()))
for (i <- 0 until p.loadQueueEntries) {
val youngerLoad = entries(i).robIdx > io.storeRobIdx
val youngerLoad = isOlder(io.storeRobIdx, entries(i).robIdx)
violationVec(i) := io.storeAddrValid && entries(i).valid && entries(i).completed &&
entries(i).addrValid && youngerLoad && overlap(entries(i).addr, entries(i).size, io.storeAddr, io.storeSize)
}
@@ -70,6 +77,13 @@ class LoadQueue(p: CoreParams = CoreParams()) extends Module {
when(io.complete) {
entries(io.completeIdx).completed := true.B
}
for (i <- 0 until p.loadQueueEntries) {
for (c <- 0 until p.issueWidth) {
when(io.commitValid(c) && entries(i).valid && entries(i).robIdx === io.commitRobIdx(c)) {
entries(i).valid := false.B
}
}
}
for (i <- 0 until p.loadQueueEntries) {
when(violationVec(i)) {
entries(i).violation := true.B

View File

@@ -23,6 +23,8 @@ class StoreQueue(p: CoreParams = CoreParams()) extends Module {
val loadRobIdx = Input(UInt(robBits.W))
val forwardValid = Output(Bool())
val forwardData = Output(UInt(p.xlen.W))
val forwardBlock = Output(Bool())
val olderStoreValid = Output(Bool())
val commitValid = Input(Bool())
val commitRobIdx = Input(UInt(robBits.W))
@@ -39,16 +41,90 @@ class StoreQueue(p: CoreParams = CoreParams()) extends Module {
def sameWord(a: UInt, b: UInt): Bool = a(p.xlen - 1, 3) === b(p.xlen - 1, 3)
def endAddr(addr: UInt, size: UInt): UInt =
addr + MuxLookup(size, 7.U(p.xlen.W))(Seq(
0.U -> 0.U(p.xlen.W),
1.U -> 1.U(p.xlen.W),
2.U -> 3.U(p.xlen.W),
3.U -> 7.U(p.xlen.W)
))
def byteOverlap(a: UInt, as: UInt, b: UInt, bs: UInt): Bool =
a <= endAddr(b, bs) && b <= endAddr(a, as)
def sizeMask(size: UInt): UInt = MuxLookup(size, "hff".U(8.W))(Seq(
0.U -> "h01".U(8.W),
1.U -> "h03".U(8.W),
2.U -> "h0f".U(8.W),
3.U -> "hff".U(8.W)
))
def byteMask(addr: UInt, size: UInt): UInt = {
val shifted = Wire(UInt(8.W))
shifted := sizeMask(size) << addr(2, 0)
shifted
}
def crossesWord(addr: UInt, size: UInt): Bool =
addr(2, 0) +& (endAddr(0.U, size) + 1.U) > 8.U
def byteAt(data: UInt, byte: UInt): UInt =
((data >> (byte << 3))(7, 0))
def isOlder(a: UInt, b: UInt): Bool = {
val diff = b - a
diff =/= 0.U && !diff(robBits - 1)
}
io.enqReady := freeMask.orR
io.enqIdx := enqIdx
val loadMask = byteMask(io.loadAddr, io.loadSize)
val forwardVec = Wire(Vec(p.storeQueueEntries, Bool()))
val olderVec = Wire(Vec(p.storeQueueEntries, Bool()))
val storeMasks = Wire(Vec(p.storeQueueEntries, UInt(8.W)))
for (i <- 0 until p.storeQueueEntries) {
forwardVec(i) := entries(i).valid && entries(i).addrValid && entries(i).dataValid &&
entries(i).robIdx < io.loadRobIdx && sameWord(entries(i).addr, io.loadAddr)
olderVec(i) := entries(i).valid && isOlder(entries(i).robIdx, io.loadRobIdx)
forwardVec(i) := olderVec(i) && entries(i).addrValid && entries(i).dataValid &&
sameWord(entries(i).addr, io.loadAddr)
storeMasks(i) := byteMask(entries(i).addr, entries(i).size)
}
io.forwardValid := forwardVec.asUInt.orR
io.forwardData := Mux1H(forwardVec, entries.map(_.data))
val forwardBytesValid = Wire(Vec(p.xlen / 8, Bool()))
val forwardBytes = Wire(Vec(p.xlen / 8, UInt(8.W)))
for (b <- 0 until p.xlen / 8) {
var found = false.B
var bestDist = 0.U(robBits.W)
var bestByte = 0.U(8.W)
for (i <- 0 until p.storeQueueEntries) {
val storeByte = (b.U - entries(i).addr(2, 0))(2, 0)
val candidate = forwardVec(i) && storeMasks(i)(b)
val dist = io.loadRobIdx - entries(i).robIdx
val take = candidate && (!found || dist < bestDist)
bestByte = Mux(take, byteAt(entries(i).data, storeByte), bestByte)
bestDist = Mux(take, dist, bestDist)
found = found || candidate
}
forwardBytesValid(b) := found
forwardBytes(b) := bestByte
}
val coveredMask = VecInit((0 until p.xlen / 8).map(b => forwardBytesValid(b) && loadMask(b))).asUInt
val overlaps = VecInit((0 until p.storeQueueEntries).map(i =>
olderVec(i) && entries(i).addrValid && entries(i).dataValid &&
byteOverlap(entries(i).addr, entries(i).size, io.loadAddr, io.loadSize)
)).asUInt.orR
val alignedBytes = Wire(Vec(p.xlen / 8, UInt(8.W)))
for (b <- 0 until p.xlen / 8) {
val lane = io.loadAddr(2, 0) + b.U
alignedBytes(b) := MuxLookup(lane, 0.U(8.W))(
(0 until p.xlen / 8).map(i => i.U -> forwardBytes(i)))
}
io.forwardValid := !crossesWord(io.loadAddr, io.loadSize) &&
loadMask.orR && ((coveredMask & loadMask) === loadMask)
io.forwardData := Cat(alignedBytes.reverse)
io.forwardBlock := overlaps && !io.forwardValid
io.olderStoreValid := olderVec.asUInt.orR
val drainVec = Wire(Vec(p.storeQueueEntries, Bool()))
for (i <- 0 until p.storeQueueEntries) {
@@ -60,6 +136,9 @@ class StoreQueue(p: CoreParams = CoreParams()) extends Module {
io.drain.addr := entries(drainIdx).addr
io.drain.data := entries(drainIdx).data
io.drain.isStore := true.B
io.drain.isSigned := false.B
io.drain.isAmo := false.B
io.drain.amoOp := 0.U
io.drain.size := entries(drainIdx).size
when(io.flush) {

View File

@@ -21,6 +21,7 @@ class RobEntry(p: CoreParams = CoreParams()) extends Bundle {
val csrCmd = UInt(3.W)
val csrRs1 = UInt(p.xlen.W)
val csrZimm = UInt(5.W)
val fenceI = Bool()
}
class ROB(p: CoreParams = CoreParams()) extends Module {

View File

@@ -95,6 +95,7 @@ class RenameStage(p: CoreParams = CoreParams()) extends Module {
e.opClass := io.in(i).opClass
e.dest := Mux(io.in(i).writesRd, freeList.io.allocPhys(i), table.io.oldPrd(i))
e.oldDest := table.io.oldPrd(i)
e.fenceI := io.in(i).isFenceI
rob.io.allocateEntry(i) := e
}
rob.io.completeValid := io.completeValid
@@ -122,14 +123,18 @@ class RenameStage(p: CoreParams = CoreParams()) extends Module {
val src2FromOlder = (0 until i).map(j =>
io.outValid(j) && io.in(j).writesRd && io.in(j).rd =/= 0.U && io.in(j).rd === io.in(i).rs2
).foldLeft(false.B)(_ || _)
val prs1Wake = VecInit((0 until p.issueWidth).map(w => io.wbValid(w) && io.wbPhys(w) === table.io.prs1(i))).asUInt.orR
val prs2Wake = VecInit((0 until p.issueWidth).map(w => io.wbValid(w) && io.wbPhys(w) === table.io.prs2(i))).asUInt.orR
val prs1Ready = readyReg(table.io.prs1(i)) || prs1Wake
val prs2Ready = readyReg(table.io.prs2(i)) || prs2Wake
io.outValid(i) := io.inValid(i) && canRename
io.out(i).valid := io.outValid(i)
io.out(i).decoded := io.in(i)
io.out(i).prs1 := table.io.prs1(i)
io.out(i).prs2 := table.io.prs2(i)
io.out(i).src1Ready := io.in(i).rs1 === 0.U || (!src1FromOlder && readyReg(table.io.prs1(i)))
io.out(i).src2Ready := io.in(i).rs2 === 0.U || (!src2FromOlder && readyReg(table.io.prs2(i)))
io.out(i).src1Ready := io.in(i).rs1 === 0.U || (!src1FromOlder && prs1Ready)
io.out(i).src2Ready := io.in(i).rs2 === 0.U || (!src2FromOlder && prs2Ready)
io.out(i).prd := Mux(io.in(i).writesRd, freeList.io.allocPhys(i), table.io.oldPrd(i))
io.out(i).oldPrd := table.io.oldPrd(i)
io.out(i).robIdx := rob.io.allocateIdx(i)

View File

@@ -22,7 +22,14 @@ class RenameTable(p: CoreParams = CoreParams()) extends Module {
val init = VecInit((0 until p.archRegs).map(_.U(physBits.W)))
val speculative = RegInit(init)
val committed = RegInit(init)
io.committedPhys := committed
val committedNext = WireDefault(committed)
for (i <- 0 until p.issueWidth) {
when(io.commitWen(i) && io.commitRd(i) =/= 0.U) {
committedNext(io.commitRd(i)) := io.commitPhys(i)
}
}
io.committedPhys := committedNext
io.prs1(0) := speculative(io.rs1(0))
io.prs2(0) := speculative(io.rs2(0))
@@ -33,16 +40,14 @@ class RenameTable(p: CoreParams = CoreParams()) extends Module {
io.prs2(1) := Mux(slot0Writes && io.rd(0) === io.rs2(1), io.newPhys(0), speculative(io.rs2(1)))
io.oldPrd(1) := Mux(slot0Writes && io.rd(0) === io.rd(1), io.newPhys(0), speculative(io.rd(1)))
committed := committedNext
when(io.recover) {
speculative := committed
speculative := committedNext
}.otherwise {
for (i <- 0 until p.issueWidth) {
when(io.wen(i) && io.rd(i) =/= 0.U) {
speculative(io.rd(i)) := io.newPhys(i)
}
when(io.commitWen(i) && io.commitRd(i) =/= 0.U) {
committed(io.commitRd(i)) := io.commitPhys(i)
}
}
}
}