1c89b4642SGuokai Chen/*************************************************************************************** 2e3da8badSTang Haojin* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3e3da8badSTang Haojin* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences 4c89b4642SGuokai Chen* Copyright (c) 2020-2021 Peng Cheng Laboratory 5c89b4642SGuokai Chen* 6c89b4642SGuokai Chen* XiangShan is licensed under Mulan PSL v2. 7c89b4642SGuokai Chen* You can use this software according to the terms and conditions of the Mulan PSL v2. 8c89b4642SGuokai Chen* You may obtain a copy of Mulan PSL v2 at: 9c89b4642SGuokai Chen* http://license.coscl.org.cn/MulanPSL2 10c89b4642SGuokai Chen* 11c89b4642SGuokai Chen* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12c89b4642SGuokai Chen* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13c89b4642SGuokai Chen* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14c89b4642SGuokai Chen* 15c89b4642SGuokai Chen* See the Mulan PSL v2 for more details. 16c49ebec8SHaoyuan Feng* 17c49ebec8SHaoyuan Feng* 18c49ebec8SHaoyuan Feng* Acknowledgement 19c49ebec8SHaoyuan Feng* 20c49ebec8SHaoyuan Feng* This implementation is inspired by several key papers: 21c49ebec8SHaoyuan Feng* [1] Kevin Skadron, Pritpal S. Ahuja, Margaret Martonosi, and Douglas W. Clark. "[Improving prediction for procedure 22c49ebec8SHaoyuan Feng* returns with return-address-stack repair mechanisms.](https://doi.org/10.1109/MICRO.1998.742787)" 31st Annual 23c49ebec8SHaoyuan Feng* ACM/IEEE International Symposium on Microarchitecture (MICRO). 1998. 24c49ebec8SHaoyuan Feng* [2] Tan Hongze, and Wang Jian. "[A Return Address Predictor Based on Persistent Stack.] 25c49ebec8SHaoyuan Feng* (https://crad.ict.ac.cn/en/article/doi/10.7544/issn1000-1239.202111274)" Journal of Computer Research and Development 26c49ebec8SHaoyuan Feng* (CRAD) 60.6: 1337-1345. 2023. 27c89b4642SGuokai Chen***************************************************************************************/ 28c89b4642SGuokai Chenpackage xiangshan.frontend 29c89b4642SGuokai Chen 30c89b4642SGuokai Chenimport chisel3._ 31c89b4642SGuokai Chenimport chisel3.util._ 32cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters 33c89b4642SGuokai Chenimport utility._ 34cf7d6b7aSMuziimport utils._ 35c89b4642SGuokai Chenimport xiangshan._ 36c89b4642SGuokai Chenimport xiangshan.frontend._ 37c89b4642SGuokai Chen 38c89b4642SGuokai Chenclass RASEntry()(implicit p: Parameters) extends XSBundle { 39c89b4642SGuokai Chen val retAddr = UInt(VAddrBits.W) 40e3704ae5Smy-mayfly val ctr = UInt(RasCtrSize.W) // layer of nested call functions 41c89b4642SGuokai Chen def =/=(that: RASEntry) = this.retAddr =/= that.retAddr || this.ctr =/= that.ctr 42c89b4642SGuokai Chen} 43c89b4642SGuokai Chen 44cf7d6b7aSMuziclass RASPtr(implicit p: Parameters) extends CircularQueuePtr[RASPtr](p => p(XSCoreParamsKey).RasSpecSize) {} 45c89b4642SGuokai Chen 46c89b4642SGuokai Chenobject RASPtr { 47c89b4642SGuokai Chen def apply(f: Bool, v: UInt)(implicit p: Parameters): RASPtr = { 48c89b4642SGuokai Chen val ptr = Wire(new RASPtr) 49c89b4642SGuokai Chen ptr.flag := f 50c89b4642SGuokai Chen ptr.value := v 51c89b4642SGuokai Chen ptr 52c89b4642SGuokai Chen } 53cf7d6b7aSMuzi def inverse(ptr: RASPtr)(implicit p: Parameters): RASPtr = 54c89b4642SGuokai Chen apply(!ptr.flag, ptr.value) 55c89b4642SGuokai Chen} 56c89b4642SGuokai Chen 57deb3a97eSGao-Zeyuclass RASInternalMeta(implicit p: Parameters) extends XSBundle { 58c89b4642SGuokai Chen val ssp = UInt(log2Up(RasSize).W) 5977bef50aSGuokai Chen val sctr = UInt(RasCtrSize.W) 60c89b4642SGuokai Chen val TOSW = new RASPtr 61c89b4642SGuokai Chen val TOSR = new RASPtr 62c89b4642SGuokai Chen val NOS = new RASPtr 63c89b4642SGuokai Chen} 64c89b4642SGuokai Chen 65deb3a97eSGao-Zeyuobject RASInternalMeta { 66deb3a97eSGao-Zeyu def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASInternalMeta = { 67deb3a97eSGao-Zeyu val e = Wire(new RASInternalMeta) 68deb3a97eSGao-Zeyu e.ssp := ssp 69deb3a97eSGao-Zeyu e.TOSW := TOSW 70deb3a97eSGao-Zeyu e.TOSR := TOSR 71deb3a97eSGao-Zeyu e.NOS := NOS 72deb3a97eSGao-Zeyu e 73deb3a97eSGao-Zeyu } 74deb3a97eSGao-Zeyu} 75deb3a97eSGao-Zeyu 76deb3a97eSGao-Zeyuclass RASMeta(implicit p: Parameters) extends XSBundle { 77deb3a97eSGao-Zeyu val ssp = UInt(log2Up(RasSize).W) 78deb3a97eSGao-Zeyu val TOSW = new RASPtr 79deb3a97eSGao-Zeyu} 80deb3a97eSGao-Zeyu 81c89b4642SGuokai Chenobject RASMeta { 82c89b4642SGuokai Chen def apply(ssp: UInt, sctr: UInt, TOSW: RASPtr, TOSR: RASPtr, NOS: RASPtr)(implicit p: Parameters): RASMeta = { 83c89b4642SGuokai Chen val e = Wire(new RASMeta) 84c89b4642SGuokai Chen e.ssp := ssp 85c89b4642SGuokai Chen e.TOSW := TOSW 86c89b4642SGuokai Chen e 87c89b4642SGuokai Chen } 88c89b4642SGuokai Chen} 89c89b4642SGuokai Chen 90c89b4642SGuokai Chenclass RASDebug(implicit p: Parameters) extends XSBundle { 91c89b4642SGuokai Chen val spec_queue = Output(Vec(RasSpecSize, new RASEntry)) 92c89b4642SGuokai Chen val spec_nos = Output(Vec(RasSpecSize, new RASPtr)) 93c89b4642SGuokai Chen val commit_stack = Output(Vec(RasSize, new RASEntry)) 94c89b4642SGuokai Chen} 95c89b4642SGuokai Chen 96*9928cec7Szhou taoclass RAS(implicit p: Parameters) extends BasePredictor with HasCircularQueuePtrHelper { 97c89b4642SGuokai Chen override val meta_size = WireInit(0.U.asTypeOf(new RASMeta)).getWidth 98c89b4642SGuokai Chen 99c89b4642SGuokai Chen object RASEntry { 100c89b4642SGuokai Chen def apply(retAddr: UInt, ctr: UInt): RASEntry = { 101c89b4642SGuokai Chen val e = Wire(new RASEntry) 102c89b4642SGuokai Chen e.retAddr := retAddr 103c89b4642SGuokai Chen e.ctr := ctr 104c89b4642SGuokai Chen e 105c89b4642SGuokai Chen } 106c89b4642SGuokai Chen } 107c89b4642SGuokai Chen 108c89b4642SGuokai Chen class RASStack(rasSize: Int, rasSpecSize: Int) extends XSModule with HasCircularQueuePtrHelper { 109c89b4642SGuokai Chen val io = IO(new Bundle { 110c89b4642SGuokai Chen val spec_push_valid = Input(Bool()) 111c89b4642SGuokai Chen val spec_pop_valid = Input(Bool()) 112c89b4642SGuokai Chen val spec_push_addr = Input(UInt(VAddrBits.W)) 113c89b4642SGuokai Chen // for write bypass between s2 and s3 114c89b4642SGuokai Chen 115c89b4642SGuokai Chen val s2_fire = Input(Bool()) 116c89b4642SGuokai Chen val s3_fire = Input(Bool()) 117c89b4642SGuokai Chen val s3_cancel = Input(Bool()) 118deb3a97eSGao-Zeyu val s3_meta = Input(new RASInternalMeta) 119c89b4642SGuokai Chen val s3_missed_pop = Input(Bool()) 120c89b4642SGuokai Chen val s3_missed_push = Input(Bool()) 121c89b4642SGuokai Chen val s3_pushAddr = Input(UInt(VAddrBits.W)) 122c89b4642SGuokai Chen val spec_pop_addr = Output(UInt(VAddrBits.W)) 123c89b4642SGuokai Chen 124c776f0d5Smy-mayfly val commit_valid = Input(Bool()) 125c89b4642SGuokai Chen val commit_push_valid = Input(Bool()) 126c89b4642SGuokai Chen val commit_pop_valid = Input(Bool()) 127c89b4642SGuokai Chen val commit_push_addr = Input(UInt(VAddrBits.W)) 128c89b4642SGuokai Chen val commit_meta_TOSW = Input(new RASPtr) 129c89b4642SGuokai Chen // for debug purpose only 130c89b4642SGuokai Chen val commit_meta_ssp = Input(UInt(log2Up(RasSize).W)) 131c89b4642SGuokai Chen 132c89b4642SGuokai Chen val redirect_valid = Input(Bool()) 133c89b4642SGuokai Chen val redirect_isCall = Input(Bool()) 134c89b4642SGuokai Chen val redirect_isRet = Input(Bool()) 135c89b4642SGuokai Chen val redirect_meta_ssp = Input(UInt(log2Up(RasSize).W)) 13677bef50aSGuokai Chen val redirect_meta_sctr = Input(UInt(RasCtrSize.W)) 137c89b4642SGuokai Chen val redirect_meta_TOSW = Input(new RASPtr) 138c89b4642SGuokai Chen val redirect_meta_TOSR = Input(new RASPtr) 139c89b4642SGuokai Chen val redirect_meta_NOS = Input(new RASPtr) 140c89b4642SGuokai Chen val redirect_callAddr = Input(UInt(VAddrBits.W)) 141c89b4642SGuokai Chen 142c89b4642SGuokai Chen val ssp = Output(UInt(log2Up(RasSize).W)) 14377bef50aSGuokai Chen val sctr = Output(UInt(RasCtrSize.W)) 144c89b4642SGuokai Chen val nsp = Output(UInt(log2Up(RasSize).W)) 145c89b4642SGuokai Chen val TOSR = Output(new RASPtr) 146c89b4642SGuokai Chen val TOSW = Output(new RASPtr) 147c89b4642SGuokai Chen val NOS = Output(new RASPtr) 148c89b4642SGuokai Chen val BOS = Output(new RASPtr) 149c89b4642SGuokai Chen 150a8810fc6Smy-mayfly val spec_near_overflow = Output(Bool()) 151a8810fc6Smy-mayfly 152c89b4642SGuokai Chen val debug = new RASDebug 153c89b4642SGuokai Chen }) 154c89b4642SGuokai Chen 155c89b4642SGuokai Chen val commit_stack = RegInit(VecInit(Seq.fill(RasSize)(RASEntry(0.U, 0.U)))) 156c89b4642SGuokai Chen val spec_queue = RegInit(VecInit(Seq.fill(rasSpecSize)(RASEntry(0.U, 0.U)))) 157c89b4642SGuokai Chen val spec_nos = RegInit(VecInit(Seq.fill(rasSpecSize)(RASPtr(false.B, 0.U)))) 158c89b4642SGuokai Chen 159c89b4642SGuokai Chen val nsp = RegInit(0.U(log2Up(rasSize).W)) 160c89b4642SGuokai Chen val ssp = RegInit(0.U(log2Up(rasSize).W)) 161c89b4642SGuokai Chen 162c89b4642SGuokai Chen val sctr = RegInit(0.U(RasCtrSize.W)) 163c89b4642SGuokai Chen val TOSR = RegInit(RASPtr(true.B, (RasSpecSize - 1).U)) 164c89b4642SGuokai Chen val TOSW = RegInit(RASPtr(false.B, 0.U)) 165c89b4642SGuokai Chen val BOS = RegInit(RASPtr(false.B, 0.U)) 166c89b4642SGuokai Chen 167a8810fc6Smy-mayfly val spec_near_overflowed = RegInit(false.B) 168c89b4642SGuokai Chen 169c89b4642SGuokai Chen val writeBypassEntry = Reg(new RASEntry) 170c89b4642SGuokai Chen val writeBypassNos = Reg(new RASPtr) 171c89b4642SGuokai Chen 172c89b4642SGuokai Chen val writeBypassValid = RegInit(0.B) 173c89b4642SGuokai Chen val writeBypassValidWire = Wire(Bool()) 174c89b4642SGuokai Chen 175c89b4642SGuokai Chen def TOSRinRange(currentTOSR: RASPtr, currentTOSW: RASPtr) = { 176c89b4642SGuokai Chen val inflightValid = WireInit(false.B) 177c89b4642SGuokai Chen // if in range, TOSR should be no younger than BOS and strictly younger than TOSW 178c89b4642SGuokai Chen when(!isBefore(currentTOSR, BOS) && isBefore(currentTOSR, currentTOSW)) { 179c89b4642SGuokai Chen inflightValid := true.B 180c89b4642SGuokai Chen } 181c89b4642SGuokai Chen inflightValid 182c89b4642SGuokai Chen } 183c89b4642SGuokai Chen 184cf7d6b7aSMuzi def getCommitTop(currentSsp: UInt) = 185c89b4642SGuokai Chen commit_stack(currentSsp) 186c89b4642SGuokai Chen 187c89b4642SGuokai Chen def getTopNos(currentTOSR: RASPtr, allowBypass: Boolean): RASPtr = { 188c89b4642SGuokai Chen val ret = Wire(new RASPtr) 189c89b4642SGuokai Chen if (allowBypass) { 190c89b4642SGuokai Chen when(writeBypassValid) { 191c89b4642SGuokai Chen ret := writeBypassNos 192c89b4642SGuokai Chen }.otherwise { 193c89b4642SGuokai Chen ret := spec_nos(TOSR.value) 194c89b4642SGuokai Chen } 195c89b4642SGuokai Chen } else { 196c89b4642SGuokai Chen ret := spec_nos(TOSR.value) // invalid when TOSR is not in range 197c89b4642SGuokai Chen } 198c89b4642SGuokai Chen ret 199c89b4642SGuokai Chen } 200c89b4642SGuokai Chen 201cf7d6b7aSMuzi def getTop( 202cf7d6b7aSMuzi currentSsp: UInt, 203cf7d6b7aSMuzi currentSctr: UInt, 204cf7d6b7aSMuzi currentTOSR: RASPtr, 205cf7d6b7aSMuzi currentTOSW: RASPtr, 206cf7d6b7aSMuzi allowBypass: Boolean 207cf7d6b7aSMuzi ): RASEntry = { 208c89b4642SGuokai Chen val ret = Wire(new RASEntry) 209c89b4642SGuokai Chen if (allowBypass) { 210c89b4642SGuokai Chen when(writeBypassValid) { 211c89b4642SGuokai Chen ret := writeBypassEntry 212c89b4642SGuokai Chen }.elsewhen(TOSRinRange(currentTOSR, currentTOSW)) { 213c89b4642SGuokai Chen ret := spec_queue(currentTOSR.value) 214c89b4642SGuokai Chen }.otherwise { 215c89b4642SGuokai Chen ret := getCommitTop(currentSsp) 216c89b4642SGuokai Chen } 217c89b4642SGuokai Chen } else { 218c89b4642SGuokai Chen when(TOSRinRange(currentTOSR, currentTOSW)) { 219c89b4642SGuokai Chen ret := spec_queue(currentTOSR.value) 220c89b4642SGuokai Chen }.otherwise { 221c89b4642SGuokai Chen ret := getCommitTop(currentSsp) 222c89b4642SGuokai Chen } 223c89b4642SGuokai Chen } 224c89b4642SGuokai Chen 225c89b4642SGuokai Chen ret 226c89b4642SGuokai Chen } 227c89b4642SGuokai Chen 228c89b4642SGuokai Chen // it would be unsafe for specPtr manipulation if specSize is not power of 2 229c89b4642SGuokai Chen assert(log2Up(RasSpecSize) == log2Floor(RasSpecSize)) 230e3da8badSTang Haojin def ctrMax = ((1L << RasCtrSize) - 1).U 231c89b4642SGuokai Chen def ptrInc(ptr: UInt) = ptr + 1.U 232c89b4642SGuokai Chen def ptrDec(ptr: UInt) = ptr - 1.U 233c89b4642SGuokai Chen 234c89b4642SGuokai Chen def specPtrInc(ptr: RASPtr) = ptr + 1.U 235c89b4642SGuokai Chen def specPtrDec(ptr: RASPtr) = ptr - 1.U 236c89b4642SGuokai Chen 237c89b4642SGuokai Chen when(io.redirect_valid && io.redirect_isCall) { 238c89b4642SGuokai Chen writeBypassValidWire := true.B 239c89b4642SGuokai Chen writeBypassValid := true.B 240c89b4642SGuokai Chen }.elsewhen(io.redirect_valid) { 241c89b4642SGuokai Chen // clear current top writeBypass if doing redirect 242c89b4642SGuokai Chen writeBypassValidWire := false.B 243c89b4642SGuokai Chen writeBypassValid := false.B 244c89b4642SGuokai Chen }.elsewhen(io.s2_fire) { 245c89b4642SGuokai Chen writeBypassValidWire := io.spec_push_valid 246c89b4642SGuokai Chen writeBypassValid := io.spec_push_valid 247c89b4642SGuokai Chen }.elsewhen(io.s3_fire) { 248c89b4642SGuokai Chen writeBypassValidWire := false.B 249c89b4642SGuokai Chen writeBypassValid := false.B 250c89b4642SGuokai Chen }.otherwise { 251c89b4642SGuokai Chen writeBypassValidWire := writeBypassValid 252c89b4642SGuokai Chen } 253c89b4642SGuokai Chen 254c89b4642SGuokai Chen val topEntry = getTop(ssp, sctr, TOSR, TOSW, true) 255c89b4642SGuokai Chen val topNos = getTopNos(TOSR, true) 256cf7d6b7aSMuzi val redirectTopEntry = 257cf7d6b7aSMuzi getTop(io.redirect_meta_ssp, io.redirect_meta_sctr, io.redirect_meta_TOSR, io.redirect_meta_TOSW, false) 258c89b4642SGuokai Chen val redirectTopNos = io.redirect_meta_NOS 259c89b4642SGuokai Chen val s3TopEntry = getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false) 260c89b4642SGuokai Chen val s3TopNos = io.s3_meta.NOS 261c89b4642SGuokai Chen 262c89b4642SGuokai Chen val writeEntry = Wire(new RASEntry) 263c89b4642SGuokai Chen val writeNos = Wire(new RASPtr) 264c89b4642SGuokai Chen writeEntry.retAddr := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_callAddr, io.spec_push_addr) 265cf7d6b7aSMuzi writeEntry.ctr := Mux( 266cf7d6b7aSMuzi io.redirect_valid && io.redirect_isCall, 267cf7d6b7aSMuzi Mux( 268cf7d6b7aSMuzi redirectTopEntry.retAddr === io.redirect_callAddr && redirectTopEntry.ctr < ctrMax, 269cf7d6b7aSMuzi io.redirect_meta_sctr + 1.U, 270cf7d6b7aSMuzi 0.U 271cf7d6b7aSMuzi ), 272cf7d6b7aSMuzi Mux(topEntry.retAddr === io.spec_push_addr && topEntry.ctr < ctrMax, sctr + 1.U, 0.U) 273cf7d6b7aSMuzi ) 274c89b4642SGuokai Chen 275cf7d6b7aSMuzi writeNos := Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR) 276c89b4642SGuokai Chen 277c89b4642SGuokai Chen when(io.spec_push_valid || (io.redirect_valid && io.redirect_isCall)) { 278c89b4642SGuokai Chen writeBypassEntry := writeEntry 279c89b4642SGuokai Chen writeBypassNos := writeNos 280c89b4642SGuokai Chen } 281c89b4642SGuokai Chen 282c89b4642SGuokai Chen val realPush = Wire(Bool()) 283c89b4642SGuokai Chen val realWriteEntry = Wire(new RASEntry) 284c89b4642SGuokai Chen val timingTop = RegInit(0.U.asTypeOf(new RASEntry)) 285c89b4642SGuokai Chen val timingNos = RegInit(0.U.asTypeOf(new RASPtr)) 286c89b4642SGuokai Chen 287c89b4642SGuokai Chen when(writeBypassValidWire) { 288c89b4642SGuokai Chen when((io.redirect_valid && io.redirect_isCall) || io.spec_push_valid) { 289c89b4642SGuokai Chen timingTop := writeEntry 290c89b4642SGuokai Chen timingNos := writeNos 291c89b4642SGuokai Chen }.otherwise { 292c89b4642SGuokai Chen timingTop := writeBypassEntry 293c89b4642SGuokai Chen timingNos := writeBypassNos 294c89b4642SGuokai Chen } 295c89b4642SGuokai Chen 296c89b4642SGuokai Chen }.elsewhen(io.redirect_valid && io.redirect_isRet) { 297c89b4642SGuokai Chen // getTop using redirect Nos as TOSR 298c89b4642SGuokai Chen val popRedSsp = Wire(UInt(log2Up(rasSize).W)) 29977bef50aSGuokai Chen val popRedSctr = Wire(UInt(RasCtrSize.W)) 300c89b4642SGuokai Chen val popRedTOSR = io.redirect_meta_NOS 301c89b4642SGuokai Chen val popRedTOSW = io.redirect_meta_TOSW 302c89b4642SGuokai Chen 303c89b4642SGuokai Chen when(io.redirect_meta_sctr > 0.U) { 304c89b4642SGuokai Chen popRedSctr := io.redirect_meta_sctr - 1.U 305c89b4642SGuokai Chen popRedSsp := io.redirect_meta_ssp 306c89b4642SGuokai Chen }.elsewhen(TOSRinRange(popRedTOSR, TOSW)) { 307c89b4642SGuokai Chen popRedSsp := ptrDec(io.redirect_meta_ssp) 308c89b4642SGuokai Chen popRedSctr := spec_queue(popRedTOSR.value).ctr 309c89b4642SGuokai Chen }.otherwise { 310c89b4642SGuokai Chen popRedSsp := ptrDec(io.redirect_meta_ssp) 311c89b4642SGuokai Chen popRedSctr := getCommitTop(ptrDec(io.redirect_meta_ssp)).ctr 312c89b4642SGuokai Chen } 313c89b4642SGuokai Chen // We are deciding top for the next cycle, no need to use bypass here 314c89b4642SGuokai Chen timingTop := getTop(popRedSsp, popRedSctr, popRedTOSR, popRedTOSW, false) 315c89b4642SGuokai Chen }.elsewhen(io.redirect_valid) { 316c89b4642SGuokai Chen // Neither call nor ret 317c89b4642SGuokai Chen val popSsp = io.redirect_meta_ssp 318c89b4642SGuokai Chen val popSctr = io.redirect_meta_sctr 319c89b4642SGuokai Chen val popTOSR = io.redirect_meta_TOSR 320c89b4642SGuokai Chen val popTOSW = io.redirect_meta_TOSW 321c89b4642SGuokai Chen 322c89b4642SGuokai Chen timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false) 323c89b4642SGuokai Chen 324c89b4642SGuokai Chen }.elsewhen(io.spec_pop_valid) { 325c89b4642SGuokai Chen // getTop using current Nos as TOSR 326c89b4642SGuokai Chen val popSsp = Wire(UInt(log2Up(rasSize).W)) 32777bef50aSGuokai Chen val popSctr = Wire(UInt(RasCtrSize.W)) 328c89b4642SGuokai Chen val popTOSR = topNos 329c89b4642SGuokai Chen val popTOSW = TOSW 330c89b4642SGuokai Chen 331c89b4642SGuokai Chen when(sctr > 0.U) { 332c89b4642SGuokai Chen popSctr := sctr - 1.U 333c89b4642SGuokai Chen popSsp := ssp 334c89b4642SGuokai Chen }.elsewhen(TOSRinRange(popTOSR, TOSW)) { 335c89b4642SGuokai Chen popSsp := ptrDec(ssp) 336c89b4642SGuokai Chen popSctr := spec_queue(popTOSR.value).ctr 337c89b4642SGuokai Chen }.otherwise { 338c89b4642SGuokai Chen popSsp := ptrDec(ssp) 339c89b4642SGuokai Chen popSctr := getCommitTop(ptrDec(ssp)).ctr 340c89b4642SGuokai Chen } 341c89b4642SGuokai Chen // We are deciding top for the next cycle, no need to use bypass here 342c89b4642SGuokai Chen timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false) 343c89b4642SGuokai Chen }.elsewhen(realPush) { 344c89b4642SGuokai Chen // just updating spec queue, cannot read from there 345c89b4642SGuokai Chen timingTop := realWriteEntry 346c89b4642SGuokai Chen }.elsewhen(io.s3_cancel) { 347c89b4642SGuokai Chen // s3 is different with s2 348c89b4642SGuokai Chen timingTop := getTop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, false) 349c89b4642SGuokai Chen when(io.s3_missed_push) { 350c89b4642SGuokai Chen val writeEntry_s3 = Wire(new RASEntry) 351c89b4642SGuokai Chen timingTop := writeEntry_s3 352c89b4642SGuokai Chen writeEntry_s3.retAddr := io.s3_pushAddr 353cf7d6b7aSMuzi writeEntry_s3.ctr := Mux( 354cf7d6b7aSMuzi timingTop.retAddr === io.s3_pushAddr && io.s3_meta.sctr < ctrMax, 355cf7d6b7aSMuzi io.s3_meta.sctr + 1.U, 356cf7d6b7aSMuzi 0.U 357cf7d6b7aSMuzi ) 358c89b4642SGuokai Chen }.elsewhen(io.s3_missed_pop) { 359c89b4642SGuokai Chen val popRedSsp_s3 = Wire(UInt(log2Up(rasSize).W)) 36077bef50aSGuokai Chen val popRedSctr_s3 = Wire(UInt(RasCtrSize.W)) 361c89b4642SGuokai Chen val popRedTOSR_s3 = io.s3_meta.NOS 362c89b4642SGuokai Chen val popRedTOSW_s3 = io.s3_meta.TOSW 363c89b4642SGuokai Chen 364c89b4642SGuokai Chen when(io.s3_meta.sctr > 0.U) { 365c89b4642SGuokai Chen popRedSctr_s3 := io.s3_meta.sctr - 1.U 366c89b4642SGuokai Chen popRedSsp_s3 := io.s3_meta.ssp 367c89b4642SGuokai Chen }.elsewhen(TOSRinRange(popRedTOSR_s3, popRedTOSW_s3)) { 368c89b4642SGuokai Chen popRedSsp_s3 := ptrDec(io.s3_meta.ssp) 369c89b4642SGuokai Chen popRedSctr_s3 := spec_queue(popRedTOSR_s3.value).ctr 370c89b4642SGuokai Chen }.otherwise { 371c89b4642SGuokai Chen popRedSsp_s3 := ptrDec(io.s3_meta.ssp) 372c89b4642SGuokai Chen popRedSctr_s3 := getCommitTop(ptrDec(io.s3_meta.ssp)).ctr 373c89b4642SGuokai Chen } 374c89b4642SGuokai Chen // We are deciding top for the next cycle, no need to use bypass here 375c89b4642SGuokai Chen timingTop := getTop(popRedSsp_s3, popRedSctr_s3, popRedTOSR_s3, popRedTOSW_s3, false) 376c89b4642SGuokai Chen } 377c89b4642SGuokai Chen }.otherwise { 378c89b4642SGuokai Chen // easy case 379c89b4642SGuokai Chen val popSsp = ssp 380c89b4642SGuokai Chen val popSctr = sctr 381c89b4642SGuokai Chen val popTOSR = TOSR 382c89b4642SGuokai Chen val popTOSW = TOSW 383c89b4642SGuokai Chen timingTop := getTop(popSsp, popSctr, popTOSR, popTOSW, false) 384c89b4642SGuokai Chen } 385c89b4642SGuokai Chen val diffTop = Mux(writeBypassValid, writeBypassEntry.retAddr, topEntry.retAddr) 386c89b4642SGuokai Chen 387c89b4642SGuokai Chen XSPerfAccumulate("ras_top_mismatch", diffTop =/= timingTop.retAddr); 388c89b4642SGuokai Chen // could diff when more pop than push and a commit stack is updated with inflight info 389c89b4642SGuokai Chen 390c89b4642SGuokai Chen val realWriteEntry_next = RegEnable(writeEntry, io.s2_fire || io.redirect_isCall) 391c89b4642SGuokai Chen val s3_missPushEntry = Wire(new RASEntry) 392c89b4642SGuokai Chen val s3_missPushAddr = Wire(new RASPtr) 393c89b4642SGuokai Chen val s3_missPushNos = Wire(new RASPtr) 394c89b4642SGuokai Chen 395c89b4642SGuokai Chen s3_missPushEntry.retAddr := io.s3_pushAddr 396cf7d6b7aSMuzi s3_missPushEntry.ctr := Mux( 397cf7d6b7aSMuzi s3TopEntry.retAddr === io.s3_pushAddr && s3TopEntry.ctr < ctrMax, 398cf7d6b7aSMuzi io.s3_meta.sctr + 1.U, 399cf7d6b7aSMuzi 0.U 400cf7d6b7aSMuzi ) 401c89b4642SGuokai Chen s3_missPushAddr := io.s3_meta.TOSW 402c89b4642SGuokai Chen s3_missPushNos := io.s3_meta.TOSR 403c89b4642SGuokai Chen 404cf7d6b7aSMuzi realWriteEntry := Mux( 405cf7d6b7aSMuzi io.redirect_isCall, 406cf7d6b7aSMuzi realWriteEntry_next, 407cf7d6b7aSMuzi Mux(io.s3_missed_push, s3_missPushEntry, realWriteEntry_next) 408cf7d6b7aSMuzi ) 409c89b4642SGuokai Chen 410cf7d6b7aSMuzi val realWriteAddr_next = RegEnable( 411cf7d6b7aSMuzi Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSW, TOSW), 412cf7d6b7aSMuzi io.s2_fire || (io.redirect_valid && io.redirect_isCall) 413cf7d6b7aSMuzi ) 414cf7d6b7aSMuzi val realWriteAddr = 415cf7d6b7aSMuzi Mux(io.redirect_isCall, realWriteAddr_next, Mux(io.s3_missed_push, s3_missPushAddr, realWriteAddr_next)) 416cf7d6b7aSMuzi val realNos_next = RegEnable( 417cf7d6b7aSMuzi Mux(io.redirect_valid && io.redirect_isCall, io.redirect_meta_TOSR, TOSR), 418cf7d6b7aSMuzi io.s2_fire || (io.redirect_valid && io.redirect_isCall) 419cf7d6b7aSMuzi ) 420cf7d6b7aSMuzi val realNos = Mux(io.redirect_isCall, realNos_next, Mux(io.s3_missed_push, s3_missPushNos, realNos_next)) 421c89b4642SGuokai Chen 422cf7d6b7aSMuzi realPush := (io.s3_fire && (!io.s3_cancel && RegEnable( 423cf7d6b7aSMuzi io.spec_push_valid, 424cf7d6b7aSMuzi io.s2_fire 425cf7d6b7aSMuzi ) || io.s3_missed_push)) || RegNext(io.redirect_valid && io.redirect_isCall) 426c89b4642SGuokai Chen 427c89b4642SGuokai Chen when(realPush) { 428c89b4642SGuokai Chen spec_queue(realWriteAddr.value) := realWriteEntry 429c89b4642SGuokai Chen spec_nos(realWriteAddr.value) := realNos 430c89b4642SGuokai Chen } 431c89b4642SGuokai Chen 432cf7d6b7aSMuzi def specPush( 433cf7d6b7aSMuzi retAddr: UInt, 434cf7d6b7aSMuzi currentSsp: UInt, 435cf7d6b7aSMuzi currentSctr: UInt, 436cf7d6b7aSMuzi currentTOSR: RASPtr, 437cf7d6b7aSMuzi currentTOSW: RASPtr, 438cf7d6b7aSMuzi topEntry: RASEntry 439cf7d6b7aSMuzi ) = { 440c89b4642SGuokai Chen TOSR := currentTOSW 441c89b4642SGuokai Chen TOSW := specPtrInc(currentTOSW) 442c89b4642SGuokai Chen // spec sp and ctr should always be maintained 443c89b4642SGuokai Chen when(topEntry.retAddr === retAddr && currentSctr < ctrMax) { 444c89b4642SGuokai Chen sctr := currentSctr + 1.U 445c89b4642SGuokai Chen }.otherwise { 446c89b4642SGuokai Chen ssp := ptrInc(currentSsp) 447c89b4642SGuokai Chen sctr := 0.U 448c89b4642SGuokai Chen } 449c89b4642SGuokai Chen } 450c89b4642SGuokai Chen 451c89b4642SGuokai Chen when(io.spec_push_valid) { 452c89b4642SGuokai Chen specPush(io.spec_push_addr, ssp, sctr, TOSR, TOSW, topEntry) 453c89b4642SGuokai Chen } 454cf7d6b7aSMuzi def specPop( 455cf7d6b7aSMuzi currentSsp: UInt, 456cf7d6b7aSMuzi currentSctr: UInt, 457cf7d6b7aSMuzi currentTOSR: RASPtr, 458cf7d6b7aSMuzi currentTOSW: RASPtr, 459cf7d6b7aSMuzi currentTopNos: RASPtr 460cf7d6b7aSMuzi ) = { 461c89b4642SGuokai Chen // TOSR is only maintained when spec queue is not empty 462c89b4642SGuokai Chen when(TOSRinRange(currentTOSR, currentTOSW)) { 463c89b4642SGuokai Chen TOSR := currentTopNos 464c89b4642SGuokai Chen } 465c89b4642SGuokai Chen // spec sp and ctr should always be maintained 466c89b4642SGuokai Chen when(currentSctr > 0.U) { 467c89b4642SGuokai Chen sctr := currentSctr - 1.U 468c89b4642SGuokai Chen }.elsewhen(TOSRinRange(currentTopNos, currentTOSW)) { 469c89b4642SGuokai Chen // in range, use inflight data 470c89b4642SGuokai Chen ssp := ptrDec(currentSsp) 471c89b4642SGuokai Chen sctr := spec_queue(currentTopNos.value).ctr 472c89b4642SGuokai Chen }.otherwise { 473c89b4642SGuokai Chen // NOS not in range, use commit data 474c89b4642SGuokai Chen ssp := ptrDec(currentSsp) 475c89b4642SGuokai Chen sctr := getCommitTop(ptrDec(currentSsp)).ctr 476c89b4642SGuokai Chen // in overflow state, we cannot determine the next sctr, sctr here is not accurate 477c89b4642SGuokai Chen } 478c89b4642SGuokai Chen } 479c89b4642SGuokai Chen when(io.spec_pop_valid) { 480c89b4642SGuokai Chen specPop(ssp, sctr, TOSR, TOSW, topNos) 481c89b4642SGuokai Chen } 482c89b4642SGuokai Chen 483c89b4642SGuokai Chen // io.spec_pop_addr := Mux(writeBypassValid, writeBypassEntry.retAddr, topEntry.retAddr) 484c89b4642SGuokai Chen 485c89b4642SGuokai Chen io.spec_pop_addr := timingTop.retAddr 486c89b4642SGuokai Chen io.BOS := BOS 487c89b4642SGuokai Chen io.TOSW := TOSW 488c89b4642SGuokai Chen io.TOSR := TOSR 489c89b4642SGuokai Chen io.NOS := topNos 490c89b4642SGuokai Chen io.ssp := ssp 491c89b4642SGuokai Chen io.sctr := sctr 492c89b4642SGuokai Chen io.nsp := nsp 493c89b4642SGuokai Chen 494c89b4642SGuokai Chen when(io.s3_cancel) { 495c89b4642SGuokai Chen // recovery of all related pointers 496c89b4642SGuokai Chen TOSR := io.s3_meta.TOSR 497c89b4642SGuokai Chen TOSW := io.s3_meta.TOSW 498c89b4642SGuokai Chen ssp := io.s3_meta.ssp 499c89b4642SGuokai Chen sctr := io.s3_meta.sctr 500c89b4642SGuokai Chen 501c89b4642SGuokai Chen // for missing pop, we also need to do a pop here 502c89b4642SGuokai Chen when(io.s3_missed_pop) { 503c89b4642SGuokai Chen specPop(io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, io.s3_meta.NOS) 504c89b4642SGuokai Chen } 505c89b4642SGuokai Chen when(io.s3_missed_push) { 506c89b4642SGuokai Chen // do not use any bypass from f2 507c89b4642SGuokai Chen specPush(io.s3_pushAddr, io.s3_meta.ssp, io.s3_meta.sctr, io.s3_meta.TOSR, io.s3_meta.TOSW, s3TopEntry) 508c89b4642SGuokai Chen } 509c89b4642SGuokai Chen } 510c89b4642SGuokai Chen 511c89b4642SGuokai Chen val commitTop = commit_stack(nsp) 512c89b4642SGuokai Chen 513c89b4642SGuokai Chen when(io.commit_pop_valid) { 514c89b4642SGuokai Chen 515c89b4642SGuokai Chen val nsp_update = Wire(UInt(log2Up(rasSize).W)) 516c89b4642SGuokai Chen when(io.commit_meta_ssp =/= nsp) { 517c89b4642SGuokai Chen // force set nsp to commit ssp to avoid permanent errors 518c89b4642SGuokai Chen nsp_update := io.commit_meta_ssp 519c89b4642SGuokai Chen }.otherwise { 520c89b4642SGuokai Chen nsp_update := nsp 521c89b4642SGuokai Chen } 522c89b4642SGuokai Chen 523c89b4642SGuokai Chen // if ctr > 0, --ctr in stack, otherwise --nsp 524c89b4642SGuokai Chen when(commitTop.ctr > 0.U) { 525c89b4642SGuokai Chen commit_stack(nsp_update).ctr := commitTop.ctr - 1.U 526c89b4642SGuokai Chen nsp := nsp_update 527c89b4642SGuokai Chen }.otherwise { 528c89b4642SGuokai Chen nsp := ptrDec(nsp_update); 529c89b4642SGuokai Chen } 530c89b4642SGuokai Chen // XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp") 531c89b4642SGuokai Chen } 532c89b4642SGuokai Chen 533c89b4642SGuokai Chen val commit_push_addr = spec_queue(io.commit_meta_TOSW.value).retAddr 534c89b4642SGuokai Chen 535c89b4642SGuokai Chen when(io.commit_push_valid) { 536c89b4642SGuokai Chen val nsp_update = Wire(UInt(log2Up(rasSize).W)) 537c89b4642SGuokai Chen when(io.commit_meta_ssp =/= nsp) { 538c89b4642SGuokai Chen // force set nsp to commit ssp to avoid permanent errors 539c89b4642SGuokai Chen nsp_update := io.commit_meta_ssp 540c89b4642SGuokai Chen }.otherwise { 541c89b4642SGuokai Chen nsp_update := nsp 542c89b4642SGuokai Chen } 543c89b4642SGuokai Chen // if ctr < max && topAddr == push addr, ++ctr, otherwise ++nsp 544c89b4642SGuokai Chen when(commitTop.ctr < ctrMax && commitTop.retAddr === commit_push_addr) { 545c89b4642SGuokai Chen commit_stack(nsp_update).ctr := commitTop.ctr + 1.U 546c89b4642SGuokai Chen nsp := nsp_update 547c89b4642SGuokai Chen }.otherwise { 548c89b4642SGuokai Chen nsp := ptrInc(nsp_update) 549c89b4642SGuokai Chen commit_stack(ptrInc(nsp_update)).retAddr := commit_push_addr 550c89b4642SGuokai Chen commit_stack(ptrInc(nsp_update)).ctr := 0.U 551c89b4642SGuokai Chen } 552a8810fc6Smy-mayfly 553c89b4642SGuokai Chen // XSError(io.commit_meta_ssp =/= nsp, "nsp mismatch with expected ssp") 554c89b4642SGuokai Chen // XSError(io.commit_push_addr =/= commit_push_addr, "addr from commit mismatch with addr from spec") 555c89b4642SGuokai Chen } 556c89b4642SGuokai Chen 557c776f0d5Smy-mayfly when(io.commit_push_valid) { 558c776f0d5Smy-mayfly BOS := io.commit_meta_TOSW 559c776f0d5Smy-mayfly }.elsewhen(io.commit_valid && (distanceBetween(io.commit_meta_TOSW, BOS) > 2.U)) { 560c776f0d5Smy-mayfly BOS := specPtrDec(io.commit_meta_TOSW) 561c776f0d5Smy-mayfly } 562c3d62b63SEaston Man XSError( 563c3d62b63SEaston Man io.commit_valid && (distanceBetween(io.commit_meta_TOSW, BOS) > 2.U), 564c3d62b63SEaston Man "The use of inference queue of the RAS module has unexpected situations" 565c3d62b63SEaston Man ) 566c776f0d5Smy-mayfly 567c89b4642SGuokai Chen when(io.redirect_valid) { 568c89b4642SGuokai Chen TOSR := io.redirect_meta_TOSR 569c89b4642SGuokai Chen TOSW := io.redirect_meta_TOSW 570c89b4642SGuokai Chen ssp := io.redirect_meta_ssp 571c89b4642SGuokai Chen sctr := io.redirect_meta_sctr 572c89b4642SGuokai Chen 573c89b4642SGuokai Chen when(io.redirect_isCall) { 574cf7d6b7aSMuzi specPush( 575cf7d6b7aSMuzi io.redirect_callAddr, 576cf7d6b7aSMuzi io.redirect_meta_ssp, 577cf7d6b7aSMuzi io.redirect_meta_sctr, 578cf7d6b7aSMuzi io.redirect_meta_TOSR, 579cf7d6b7aSMuzi io.redirect_meta_TOSW, 580cf7d6b7aSMuzi redirectTopEntry 581cf7d6b7aSMuzi ) 582c89b4642SGuokai Chen } 583c89b4642SGuokai Chen when(io.redirect_isRet) { 584cf7d6b7aSMuzi specPop( 585cf7d6b7aSMuzi io.redirect_meta_ssp, 586cf7d6b7aSMuzi io.redirect_meta_sctr, 587cf7d6b7aSMuzi io.redirect_meta_TOSR, 588cf7d6b7aSMuzi io.redirect_meta_TOSW, 589cf7d6b7aSMuzi redirectTopNos 590cf7d6b7aSMuzi ) 591c89b4642SGuokai Chen } 592c89b4642SGuokai Chen } 593c89b4642SGuokai Chen 594*9928cec7Szhou tao when(distanceBetween(TOSW, BOS) > (rasSpecSize - 2).U) { 595a8810fc6Smy-mayfly spec_near_overflowed := true.B 596a8810fc6Smy-mayfly }.otherwise { 597a8810fc6Smy-mayfly spec_near_overflowed := false.B 598a8810fc6Smy-mayfly } 599a8810fc6Smy-mayfly 600a8810fc6Smy-mayfly io.spec_near_overflow := spec_near_overflowed 601a8810fc6Smy-mayfly XSPerfAccumulate("spec_near_overflow", spec_near_overflowed) 602c89b4642SGuokai Chen io.debug.commit_stack.zipWithIndex.foreach { case (a, i) => a := commit_stack(i) } 603c89b4642SGuokai Chen io.debug.spec_nos.zipWithIndex.foreach { case (a, i) => a := spec_nos(i) } 604c89b4642SGuokai Chen io.debug.spec_queue.zipWithIndex.foreach { case (a, i) => a := spec_queue(i) } 605c89b4642SGuokai Chen } 606c89b4642SGuokai Chen 607c89b4642SGuokai Chen val stack = Module(new RASStack(RasSize, RasSpecSize)).io 608c89b4642SGuokai Chen 609*9928cec7Szhou tao val stack_near_overflow = stack.spec_near_overflow 610c89b4642SGuokai Chen val s2_spec_push = WireInit(false.B) 611c89b4642SGuokai Chen val s2_spec_pop = WireInit(false.B) 612c89b4642SGuokai Chen val s2_full_pred = io.in.bits.resp_in(0).s2.full_pred(2) 613c89b4642SGuokai Chen // when last inst is an rvi call, fall through address would be set to the middle of it, so an addition is needed 614c89b4642SGuokai Chen val s2_spec_new_addr = s2_full_pred.fallThroughAddr + Mux(s2_full_pred.last_may_be_rvi_call, 2.U, 0.U) 615*9928cec7Szhou tao stack.spec_push_valid := s2_spec_push && !stack_near_overflow 616*9928cec7Szhou tao stack.spec_pop_valid := s2_spec_pop && !stack_near_overflow 617c89b4642SGuokai Chen stack.spec_push_addr := s2_spec_new_addr 618c89b4642SGuokai Chen 619c89b4642SGuokai Chen // confirm that the call/ret is the taken cfi 620c89b4642SGuokai Chen s2_spec_push := io.s2_fire(2) && s2_full_pred.hit_taken_on_call && !io.s3_redirect(2) 621c89b4642SGuokai Chen s2_spec_pop := io.s2_fire(2) && s2_full_pred.hit_taken_on_ret && !io.s3_redirect(2) 622c89b4642SGuokai Chen 623c89b4642SGuokai Chen // val s2_jalr_target = io.out.s2.full_pred.jalr_target 624c89b4642SGuokai Chen // val s2_last_target_in = s2_full_pred.targets.last 625c89b4642SGuokai Chen // val s2_last_target_out = io.out.s2.full_pred(2).targets.last 626c89b4642SGuokai Chen val s2_is_jalr = s2_full_pred.is_jalr 627c89b4642SGuokai Chen val s2_is_ret = s2_full_pred.is_ret 628c89b4642SGuokai Chen val s2_top = stack.spec_pop_addr 629c89b4642SGuokai Chen // assert(is_jalr && is_ret || !is_ret) 630c89b4642SGuokai Chen when(s2_is_ret && io.ctrl.ras_enable) { 631c89b4642SGuokai Chen io.out.s2.full_pred.map(_.jalr_target).foreach(_ := s2_top) 632c89b4642SGuokai Chen // FIXME: should use s1 globally 633c89b4642SGuokai Chen } 634c89b4642SGuokai Chen // s2_last_target_out := Mux(s2_is_jalr, s2_jalr_target, s2_last_target_in) 635c89b4642SGuokai Chen io.out.s2.full_pred.zipWithIndex.foreach { case (a, i) => 636cf7d6b7aSMuzi a.targets.last := Mux( 637cf7d6b7aSMuzi s2_is_jalr, 638cf7d6b7aSMuzi io.out.s2.full_pred(i).jalr_target, 639cf7d6b7aSMuzi io.in.bits.resp_in(0).s2.full_pred(i).targets.last 640cf7d6b7aSMuzi ) 641c89b4642SGuokai Chen } 642c89b4642SGuokai Chen 643deb3a97eSGao-Zeyu val s2_meta = Wire(new RASInternalMeta) 644c89b4642SGuokai Chen s2_meta.ssp := stack.ssp 645c89b4642SGuokai Chen s2_meta.sctr := stack.sctr 646c89b4642SGuokai Chen s2_meta.TOSR := stack.TOSR 647c89b4642SGuokai Chen s2_meta.TOSW := stack.TOSW 648c89b4642SGuokai Chen s2_meta.NOS := stack.NOS 649c89b4642SGuokai Chen 650c89b4642SGuokai Chen val s3_top = RegEnable(stack.spec_pop_addr, io.s2_fire(2)) 651c89b4642SGuokai Chen val s3_spec_new_addr = RegEnable(s2_spec_new_addr, io.s2_fire(2)) 652c89b4642SGuokai Chen 653c6a44c35Smy-mayfly // val s3_jalr_target = io.out.s3.full_pred.jalr_target 654c6a44c35Smy-mayfly // val s3_last_target_in = io.in.bits.resp_in(0).s3.full_pred(2).targets.last 655c6a44c35Smy-mayfly // val s3_last_target_out = io.out.s3.full_pred(2).targets.last 656cf7d6b7aSMuzi val s3_is_jalr = 657cf7d6b7aSMuzi io.in.bits.resp_in(0).s3.full_pred(2).is_jalr && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr 658a1c30bb9Smy-mayfly val s3_is_ret = io.in.bits.resp_in(0).s3.full_pred(2).is_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr 659c89b4642SGuokai Chen // assert(is_jalr && is_ret || !is_ret) 660c89b4642SGuokai Chen when(s3_is_ret && io.ctrl.ras_enable) { 661c89b4642SGuokai Chen io.out.s3.full_pred.map(_.jalr_target).foreach(_ := s3_top) 662c89b4642SGuokai Chen // FIXME: should use s1 globally 663c89b4642SGuokai Chen } 664c89b4642SGuokai Chen // s3_last_target_out := Mux(s3_is_jalr, s3_jalr_target, s3_last_target_in) 665c89b4642SGuokai Chen io.out.s3.full_pred.zipWithIndex.foreach { case (a, i) => 666cf7d6b7aSMuzi a.targets.last := Mux( 667cf7d6b7aSMuzi s3_is_jalr, 668cf7d6b7aSMuzi io.out.s3.full_pred(i).jalr_target, 669cf7d6b7aSMuzi io.in.bits.resp_in(0).s3.full_pred(i).targets.last 670cf7d6b7aSMuzi ) 671c89b4642SGuokai Chen } 672c89b4642SGuokai Chen 673c89b4642SGuokai Chen val s3_pushed_in_s2 = RegEnable(s2_spec_push, io.s2_fire(2)) 674c89b4642SGuokai Chen val s3_popped_in_s2 = RegEnable(s2_spec_pop, io.s2_fire(2)) 675cf7d6b7aSMuzi val s3_push = 676cf7d6b7aSMuzi io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_call && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr 677cf7d6b7aSMuzi val s3_pop = 678cf7d6b7aSMuzi io.in.bits.resp_in(0).s3.full_pred(2).hit_taken_on_ret && !io.in.bits.resp_in(0).s3.full_pred(2).fallThroughErr 679c89b4642SGuokai Chen 680c89b4642SGuokai Chen val s3_cancel = io.s3_fire(2) && (s3_pushed_in_s2 =/= s3_push || s3_popped_in_s2 =/= s3_pop) 681c89b4642SGuokai Chen stack.s2_fire := io.s2_fire(2) 682c89b4642SGuokai Chen stack.s3_fire := io.s3_fire(2) 683c89b4642SGuokai Chen 684*9928cec7Szhou tao stack.s3_cancel := s3_cancel && !stack_near_overflow 685c89b4642SGuokai Chen 686c89b4642SGuokai Chen val s3_meta = RegEnable(s2_meta, io.s2_fire(2)) 687c89b4642SGuokai Chen 688c89b4642SGuokai Chen stack.s3_meta := s3_meta 689c89b4642SGuokai Chen stack.s3_missed_pop := s3_pop && !s3_popped_in_s2 690c89b4642SGuokai Chen stack.s3_missed_push := s3_push && !s3_pushed_in_s2 691c89b4642SGuokai Chen stack.s3_pushAddr := s3_spec_new_addr 692c89b4642SGuokai Chen 693c89b4642SGuokai Chen // no longer need the top Entry, but TOSR, TOSW, ssp sctr 694c89b4642SGuokai Chen // TODO: remove related signals 695deb3a97eSGao-Zeyu 696deb3a97eSGao-Zeyu val last_stage_meta = Wire(new RASMeta) 697deb3a97eSGao-Zeyu last_stage_meta.ssp := s3_meta.ssp 698deb3a97eSGao-Zeyu last_stage_meta.TOSW := s3_meta.TOSW 699deb3a97eSGao-Zeyu 700c89b4642SGuokai Chen io.out.last_stage_spec_info.sctr := s3_meta.sctr 701c89b4642SGuokai Chen io.out.last_stage_spec_info.ssp := s3_meta.ssp 702c89b4642SGuokai Chen io.out.last_stage_spec_info.TOSW := s3_meta.TOSW 703c89b4642SGuokai Chen io.out.last_stage_spec_info.TOSR := s3_meta.TOSR 704c89b4642SGuokai Chen io.out.last_stage_spec_info.NOS := s3_meta.NOS 705c89b4642SGuokai Chen io.out.last_stage_spec_info.topAddr := s3_top 706deb3a97eSGao-Zeyu io.out.last_stage_meta := last_stage_meta.asUInt 707c89b4642SGuokai Chen 7087af6acb0SEaston Man val redirect = RegNextWithEnable(io.redirect) 709c89b4642SGuokai Chen val do_recover = redirect.valid 710c89b4642SGuokai Chen val recover_cfi = redirect.bits.cfiUpdate 711c89b4642SGuokai Chen 712d1394225Szhou tao val retMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isRet && recover_cfi.pd.valid 713d1394225Szhou tao val callMissPred = do_recover && redirect.bits.level === 0.U && recover_cfi.pd.isCall && recover_cfi.pd.valid 714c89b4642SGuokai Chen // when we mispredict a call, we must redo a push operation 715c89b4642SGuokai Chen // similarly, when we mispredict a return, we should redo a pop 716*9928cec7Szhou tao val stack_TOSW = stack.TOSW 717*9928cec7Szhou tao val redirect_TOSW = recover_cfi.TOSW 718*9928cec7Szhou tao stack.redirect_valid := do_recover && (isBefore(redirect_TOSW, stack_TOSW) || !stack_near_overflow) 719c89b4642SGuokai Chen stack.redirect_isCall := callMissPred 720c89b4642SGuokai Chen stack.redirect_isRet := retMissPred 721c89b4642SGuokai Chen stack.redirect_meta_ssp := recover_cfi.ssp 722c89b4642SGuokai Chen stack.redirect_meta_sctr := recover_cfi.sctr 723c89b4642SGuokai Chen stack.redirect_meta_TOSW := recover_cfi.TOSW 724c89b4642SGuokai Chen stack.redirect_meta_TOSR := recover_cfi.TOSR 725c89b4642SGuokai Chen stack.redirect_meta_NOS := recover_cfi.NOS 726c89b4642SGuokai Chen stack.redirect_callAddr := recover_cfi.pc + Mux(recover_cfi.pd.isRVC, 2.U, 4.U) 727c89b4642SGuokai Chen 72803426fe2Spengxiao val updateValid = RegNext(io.update.valid, init = false.B) 72903426fe2Spengxiao val update = Wire(new BranchPredictionUpdate) 73003426fe2Spengxiao update := RegEnable(io.update.bits, io.update.valid) 73103426fe2Spengxiao 73203426fe2Spengxiao // The pc register has been moved outside of predictor, pc field of update bundle and other update data are not in the same stage 73303426fe2Spengxiao // so io.update.bits.pc is used directly here 73403426fe2Spengxiao val update_pc = io.update.bits.pc 73503426fe2Spengxiao 736a6696f06Szhou tao // full core power down sequence need 'val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid)' to be 737a6696f06Szhou tao // 'val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid && (io.update.bits.is_call || io.update.bits.is_ret))', 738a6696f06Szhou tao // but the fault-tolerance mechanism of the return stack needs to be updated in time. Using an unexpected old value on reset will cause errors. 739a6696f06Szhou tao // Only 9 registers have clock gate efficiency affected, so we relaxed the control signals. 740a6696f06Szhou tao val updateMeta = RegEnable(io.update.bits.meta.asTypeOf(new RASMeta), io.update.valid) 741c89b4642SGuokai Chen 742c776f0d5Smy-mayfly stack.commit_valid := updateValid 743c89b4642SGuokai Chen stack.commit_push_valid := updateValid && update.is_call_taken 744c89b4642SGuokai Chen stack.commit_pop_valid := updateValid && update.is_ret_taken 74503426fe2Spengxiao stack.commit_push_addr := update.ftb_entry.getFallThrough(update_pc) + Mux( 746cf7d6b7aSMuzi update.ftb_entry.last_may_be_rvi_call, 747cf7d6b7aSMuzi 2.U, 748cf7d6b7aSMuzi 0.U 749cf7d6b7aSMuzi ) 750c89b4642SGuokai Chen stack.commit_meta_TOSW := updateMeta.TOSW 751c89b4642SGuokai Chen stack.commit_meta_ssp := updateMeta.ssp 752c89b4642SGuokai Chen 753c89b4642SGuokai Chen XSPerfAccumulate("ras_s3_cancel", s3_cancel) 754c89b4642SGuokai Chen XSPerfAccumulate("ras_redirect_recover", redirect.valid) 755c89b4642SGuokai Chen XSPerfAccumulate("ras_s3_and_redirect_recover_at_the_same_time", s3_cancel && redirect.valid) 756c89b4642SGuokai Chen 757c89b4642SGuokai Chen val spec_debug = stack.debug 758c89b4642SGuokai Chen XSDebug(io.s2_fire(2), "----------------RAS----------------\n") 759c89b4642SGuokai Chen XSDebug(io.s2_fire(2), " TopRegister: 0x%x\n", stack.spec_pop_addr) 760c89b4642SGuokai Chen XSDebug(io.s2_fire(2), " index addr ctr nos (spec part)\n") 761c89b4642SGuokai Chen for (i <- 0 until RasSpecSize) { 762cf7d6b7aSMuzi XSDebug( 763cf7d6b7aSMuzi io.s2_fire(2), 764cf7d6b7aSMuzi " (%d) 0x%x %d %d", 765cf7d6b7aSMuzi i.U, 766cf7d6b7aSMuzi spec_debug.spec_queue(i).retAddr, 767cf7d6b7aSMuzi spec_debug.spec_queue(i).ctr, 768cf7d6b7aSMuzi spec_debug.spec_nos(i).value 769cf7d6b7aSMuzi ) 7708b33cd30Sklin02 XSDebug(io.s2_fire(2) && i.U === stack.TOSW.value, " <----TOSW") 7718b33cd30Sklin02 XSDebug(io.s2_fire(2) && i.U === stack.TOSR.value, " <----TOSR") 7728b33cd30Sklin02 XSDebug(io.s2_fire(2) && i.U === stack.BOS.value, " <----BOS") 773c89b4642SGuokai Chen XSDebug(io.s2_fire(2), "\n") 774c89b4642SGuokai Chen } 775c89b4642SGuokai Chen XSDebug(io.s2_fire(2), " index addr ctr (committed part)\n") 776c89b4642SGuokai Chen for (i <- 0 until RasSize) { 777cf7d6b7aSMuzi XSDebug( 778cf7d6b7aSMuzi io.s2_fire(2), 779cf7d6b7aSMuzi " (%d) 0x%x %d", 780cf7d6b7aSMuzi i.U, 781cf7d6b7aSMuzi spec_debug.commit_stack(i).retAddr, 782cf7d6b7aSMuzi spec_debug.commit_stack(i).ctr 783cf7d6b7aSMuzi ) 7848b33cd30Sklin02 XSDebug(io.s2_fire(2) && i.U === stack.ssp, " <----ssp") 7858b33cd30Sklin02 XSDebug(io.s2_fire(2) && i.U === stack.nsp, " <----nsp") 786c89b4642SGuokai Chen XSDebug(io.s2_fire(2), "\n") 787c89b4642SGuokai Chen } 788c89b4642SGuokai Chen /* 789c89b4642SGuokai Chen XSDebug(s2_spec_push, "s2_spec_push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n", 790c89b4642SGuokai Chen s2_spec_new_addr,spec_debug.spec_push_entry.ctr,spec_debug.spec_alloc_new,spec_debug.sp.asUInt) 791c89b4642SGuokai Chen XSDebug(s2_spec_pop, "s2_spec_pop outAddr: 0x%x \n",io.out.s2.getTarget) 792c89b4642SGuokai Chen val s3_recover_entry = spec_debug.recover_push_entry 793c89b4642SGuokai Chen XSDebug(s3_recover && s3_push, "s3_recover_push inAddr: 0x%x inCtr: %d | allocNewEntry:%d | sp:%d \n", 794c89b4642SGuokai Chen s3_recover_entry.retAddr, s3_recover_entry.ctr, spec_debug.recover_alloc_new, s3_sp.asUInt) 795c89b4642SGuokai Chen XSDebug(s3_recover && s3_pop, "s3_recover_pop outAddr: 0x%x \n",io.out.s3.getTarget) 796c89b4642SGuokai Chen val redirectUpdate = redirect.bits.cfiUpdate 797c89b4642SGuokai Chen XSDebug(do_recover && callMissPred, "redirect_recover_push\n") 798c89b4642SGuokai Chen XSDebug(do_recover && retMissPred, "redirect_recover_pop\n") 799c89b4642SGuokai Chen XSDebug(do_recover, "redirect_recover(SP:%d retAddr:%x ctr:%d) \n", 800c89b4642SGuokai Chen redirectUpdate.rasSp,redirectUpdate.rasEntry.retAddr,redirectUpdate.rasEntry.ctr) 801c89b4642SGuokai Chen */ 802c89b4642SGuokai Chen 803c89b4642SGuokai Chen generatePerfEvent() 804c89b4642SGuokai Chen} 805