1package xiangshan.frontend 2 3import chisel3._ 4import chisel3.util._ 5import device.RAMHelper 6import xiangshan._ 7import utils._ 8 9trait HasIFUConst { this: XSModule => 10 val resetVector = 0x80000000L//TODO: set reset vec 11 val groupAlign = log2Up(FetchWidth * 4) 12 def groupPC(pc: UInt): UInt = Cat(pc(VAddrBits-1, groupAlign), 0.U(groupAlign.W)) 13 def snpc(pc: UInt): UInt = pc + (1 << groupAlign).U 14 def maskExp(mask: UInt): UInt = Cat(mask.asBools.map(Fill(2,_)).reverse) 15 16} 17 18class IFUIO extends XSBundle 19{ 20 val fetchPacket = DecoupledIO(new FetchPacket) 21 val redirectInfo = Input(new RedirectInfo) 22 val icacheReq = DecoupledIO(new FakeIcacheReq) 23 val icacheResp = Flipped(DecoupledIO(new FakeIcacheResp)) 24} 25 26 27class FakeBPU extends XSModule{ 28 val io = IO(new Bundle() { 29 val redirectInfo = Input(new RedirectInfo) 30 val in = new Bundle { val pc = Flipped(Valid(UInt(VAddrBits.W))) } 31 val btbOut = ValidIO(new BranchPrediction) 32 val tageOut = Decoupled(new BranchPrediction) 33 val predecode = Flipped(ValidIO(new Predecode)) 34 }) 35 36 io.btbOut.valid := true.B 37 io.btbOut.bits <> DontCare 38 io.btbOut.bits.redirect := false.B 39 io.tageOut.valid := false.B 40 io.tageOut.bits <> DontCare 41} 42 43 44class IFU extends XSModule with HasIFUConst 45{ 46 val io = IO(new IFUIO) 47 val bpu = if(EnableBPU) Module(new BPU) else Module(new FakeBPU) 48 49 //------------------------- 50 // IF1 PC update 51 //------------------------- 52 //local 53 val if1_npc = WireInit(0.U(VAddrBits.W)) 54 val if1_valid = !reset.asBool 55 val if1_pc = RegInit(resetVector.U(VAddrBits.W)) 56 //next 57 val if2_ready = WireInit(false.B) 58 val if2_snpc = snpc(if1_pc) //TODO: calculate snpc according to mask of current fetch packet 59 val needflush = WireInit(false.B) 60 // when an RVI instruction is predicted as taken and it crosses over two fetch packets, 61 // IFU should not take this branch but fetch the latter half of the instruction sequentially, 62 // and take the jump target in the next fetch cycle 63 val if2_lateJumpLatch = WireInit(false.B) 64 val if2_lateJumpTarget = RegInit(0.U(VAddrBits.W)) 65 val if4_lateJumpLatch = WireInit(false.B) 66 val if4_lateJumpTarget = RegInit(0.U(VAddrBits.W)) 67 68 //pipe fire 69 val if1_fire = if1_valid && if2_ready || needflush 70 val if1_pcUpdate = if1_fire || needflush 71 72 when(if1_pcUpdate) 73 { 74 if1_pc := if1_npc 75 } 76 77 bpu.io.in.pc.valid := if1_fire 78 bpu.io.in.pc.bits := if1_npc 79 bpu.io.redirectInfo := io.redirectInfo 80 81 XSDebug("[IF1]if1_valid:%d || if1_npc:0x%x || if1_pcUpdate:%d if1_pc:0x%x || if2_ready:%d",if1_valid,if1_npc,if1_pcUpdate,if1_pc,if2_ready) 82 XSDebug(false,if1_fire,"------IF1->fire!!!") 83 XSDebug(false,true.B,"\n") 84 //------------------------- 85 // IF2 btb response 86 // icache visit 87 //------------------------- 88 //local 89 val if2_valid = RegEnable(next=if1_valid,init=false.B,enable=if1_fire) 90 val if2_pc = if1_pc 91 val if2_btb_taken = bpu.io.btbOut.valid && bpu.io.btbOut.bits.redirect 92 val if2_btb_lateJump = WireInit(false.B) 93 val if2_btb_insMask = Mux(if2_btb_taken, bpu.io.btbOut.bits.instrValid.asUInt, Fill(FetchWidth*2, 1.U(1.W))) // TODO: FIX THIS 94 val if2_btb_target = Mux(if2_btb_lateJump, if2_snpc, bpu.io.btbOut.bits.target) 95 96 if2_lateJumpLatch := BoolStopWatch(if2_btb_lateJump, if1_fire, startHighPriority = true) 97 // since late jump target should be taken after the latter half of late jump instr is fetched, we need to latch this target 98 when (if2_btb_lateJump) { 99 if2_lateJumpTarget := bpu.io.btbOut.bits.target 100 } 101 102 //next 103 val if3_ready = WireInit(false.B) 104 105 106 //pipe fire 107 val if2_fire = if2_valid && if3_ready && io.icacheReq.fire() 108 if2_ready := (if2_fire) || !if2_valid 109 110 io.icacheReq.valid := if2_valid 111 io.icacheReq.bits.addr := if2_pc 112 113 when(RegNext(reset.asBool) && !reset.asBool){ 114 XSDebug("RESET....\n") 115 if1_npc := resetVector.U(VAddrBits.W) 116 }.elsewhen (if2_fire) { 117 if1_npc := Mux(if4_lateJumpLatch, if4_lateJumpTarget, Mux(if2_lateJumpLatch, if2_lateJumpTarget, if2_snpc)) 118 }.otherwise { 119 if1_npc := if1_pc 120 } 121 122 //redirect: when if2 fire and if2 redirects, update npc 123 when(if2_fire && if2_btb_taken) 124 { 125 if1_npc := if2_btb_target 126 } 127 128 bpu.io.in.pc.valid := if1_fire && !if2_btb_lateJump 129 130 XSDebug("[IF2]if2_valid:%d || if2_pc:0x%x || if3_ready:%d ",if2_valid,if2_pc,if3_ready) 131 XSDebug(false,if2_fire,"------IF2->fire!!!") 132 XSDebug(false,true.B,"\n") 133 XSDebug("[IF2-Icache-Req] icache_in_valid:%d icache_in_ready:%d\n",io.icacheReq.valid,io.icacheReq.ready) 134 XSDebug("[IF2-BPU-out]if2_btbTaken:%d || if2_btb_insMask:%b || if2_btb_target:0x%x \n",if2_btb_taken,if2_btb_insMask.asUInt,if2_btb_target) 135 //------------------------- 136 // IF3 icache hit check 137 //------------------------- 138 //local 139 val if3_valid = RegEnable(next=if2_valid,init=false.B,enable=if2_fire) 140 val if3_pc = RegEnable(if2_pc,if2_fire) 141 val if3_npc = RegEnable(if1_npc, if2_fire) 142 val if3_btb_target = RegEnable(Mux(if2_lateJumpLatch, if2_lateJumpTarget, Mux(if2_btb_lateJump, bpu.io.btbOut.bits.target, if2_btb_target)), if2_fire) 143 val if3_btb_taken = RegEnable(Mux(if2_lateJumpLatch, true.B, if2_btb_taken), if2_fire) 144 val if3_btb_insMask = RegEnable(Mux(if2_lateJumpLatch, 1.U((FetchWidth*2).W), if2_btb_insMask), if2_fire) 145 val if3_btb_lateJump = RegEnable(if2_btb_lateJump, if2_fire) 146 147 //next 148 val if4_ready = WireInit(false.B) 149 150 //pipe fire 151 val if3_fire = if3_valid && if4_ready 152 if3_ready := if3_fire || !if3_valid 153 154 155 XSDebug("[IF3]if3_valid:%d || if3_pc:0x%x if3_npc:0x%x || if4_ready:%d ",if3_valid,if3_pc,if3_npc,if4_ready) 156 XSDebug(false,if3_fire,"------IF3->fire!!!") 157 XSDebug(false,true.B,"\n") 158 XSDebug("[IF3]if3_btb_taken:%d if3_btb_insMask:%b if3_btb_lateJump:%d if3_btb_target:0x%x\n",if3_btb_taken, if3_btb_insMask, if3_btb_lateJump, if3_btb_target) 159 160 //------------------------- 161 // IF4 icache response 162 // RAS result 163 // taget result 164 //------------------------- 165 val if4_valid = RegEnable(next=if3_valid,init=false.B,enable=if3_fire) 166 val if4_pc = RegEnable(if3_pc,if3_fire) 167 val if4_btb_target = RegEnable(if3_btb_target,if3_fire) 168 val if4_btb_taken = RegEnable(if3_btb_taken,if3_fire) 169 val if4_btb_insMask = RegEnable(if3_btb_insMask, if3_fire) 170 val if4_btb_lateJump = RegEnable(if3_btb_lateJump, if3_fire) 171 val if4_start_ready = io.fetchPacket.ready && (GTimer() > 500.U) 172 //from BPU Stage3 173 val if4_tage_redirect = bpu.io.tageOut.valid && bpu.io.tageOut.bits.redirect 174 val if4_tage_lateJump = if4_tage_redirect && bpu.io.tageOut.bits.lateJump && !io.redirectInfo.flush() 175 val if4_tage_insMask = bpu.io.tageOut.bits.instrValid 176 val if4_snpc = if4_pc + (PopCount(if4_tage_insMask) << 1.U) 177 val if4_tage_target = Mux(if4_tage_lateJump, if4_snpc, bpu.io.tageOut.bits.target) 178 //frome predecode 179 val if4_predec_mask = io.icacheResp.bits.predecode.mask 180 val if4_predec_isRVC = io.icacheResp.bits.predecode.isRVC 181 182 if4_ready := (io.fetchPacket.fire() || !if4_valid) && if4_start_ready 183 184 185 if2_btb_lateJump := if2_btb_taken && bpu.io.btbOut.bits.lateJump && !io.redirectInfo.flush() && !if4_tage_redirect 186 187 if4_lateJumpLatch := BoolStopWatch(if4_tage_lateJump, if1_fire, startHighPriority = true) 188 when (if4_tage_lateJump) { 189 if4_lateJumpTarget := bpu.io.tageOut.bits.target 190 } 191 192 bpu.io.in.pc.valid := if1_fire && !if2_btb_lateJump && !if4_tage_lateJump 193 194 XSDebug("[IF4]if4_valid:%d || if4_pc:0x%x \n",if4_valid,if4_pc) 195 XSDebug("[IF4] if4_btb_taken:%d if4_btb_lateJump:%d if4_btb_insMask:%b if4_btb_target:0x%x\n",if4_btb_taken, if4_btb_lateJump, if4_btb_insMask.asUInt, if4_btb_target) 196 XSDebug("[IF4-TAGE-out]if4_tage_redirect:%d if4_tage_lateJump:%d if4_tage_insMask:%b if4_tage_target:0x%x\n",if4_tage_redirect,if4_tage_lateJump,if4_tage_insMask.asUInt,if4_tage_target) 197 XSDebug("[IF4-ICACHE-RESP]icacheResp.valid:%d icacheResp.ready:%d\n",io.icacheResp.valid,io.icacheResp.ready) 198 199 //redirect: when tage result differ from btb 200 when(if4_tage_redirect) 201 { 202 if1_npc := if4_tage_target 203 } 204 205 //redirect: miss predict 206 when(io.redirectInfo.flush()) 207 { 208 if1_npc := io.redirectInfo.redirect.target 209 } 210 XSDebug(io.redirectInfo.flush(),"[IFU-REDIRECT] target:0x%x \n",io.redirectInfo.redirect.target.asUInt) 211 212 213 //flush pipline 214 needflush := if4_tage_redirect || io.redirectInfo.flush() 215 when(needflush){ 216 if3_valid := false.B 217 if4_valid := false.B 218 } 219 220 //flush ICache register 221 io.icacheReq.bits.flush := needflush 222 223 //to BPU 224 bpu.io.predecode.valid := io.icacheResp.fire() && if4_valid 225 bpu.io.predecode.bits <> io.icacheResp.bits.predecode 226 //TODO: consider RVC && consider cross cacheline fetch 227 bpu.io.predecode.bits.mask := if4_predec_mask 228 bpu.io.predecode.bits.isRVC := if4_predec_isRVC 229 bpu.io.redirectInfo := io.redirectInfo 230 io.icacheResp.ready := if4_start_ready 231 232 //------------------------- 233 // Output fetch packet 234 // -> Ibuffer 235 //------------------------- 236 io.fetchPacket.valid := if4_valid && io.icacheResp.valid && !io.redirectInfo.flush() 237 io.fetchPacket.bits.instrs := io.icacheResp.bits.icacheOut 238 io.fetchPacket.bits.mask := Mux(if4_lateJumpLatch, 1.U((FetchWidth*2).W), 239 Mux(if4_tage_redirect, if4_predec_mask.asUInt & if4_tage_insMask.asUInt, 240 if4_predec_mask.asUInt & if4_btb_insMask.asUInt)) 241 io.fetchPacket.bits.pc := if4_pc 242 243 XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] starPC:0x%x GroupPC:0x%xn\n",if4_pc.asUInt,groupPC(if4_pc).asUInt) 244 XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] instrmask %b\n",io.fetchPacket.bits.mask.asUInt) 245 for(i <- 0 until (FetchWidth*2)) { 246 when (if4_btb_taken && !if4_tage_redirect && i.U === OHToUInt(HighestBit(if4_btb_insMask.asUInt, FetchWidth*2))) { 247 io.fetchPacket.bits.pnpc(i) := if4_btb_target 248 if (i != 0) { 249 when (!io.icacheResp.bits.predecode.isRVC(i) && !if4_btb_lateJump) { 250 io.fetchPacket.bits.pnpc(i-1) := if4_btb_target 251 } 252 } 253 }.elsewhen (if4_tage_redirect && i.U === OHToUInt(HighestBit(if4_tage_insMask.asUInt, FetchWidth*2))) { 254 io.fetchPacket.bits.pnpc(i) := Mux(if4_tage_lateJump, bpu.io.tageOut.bits.target, if4_tage_target) 255 if (i != 0) { 256 when (!io.icacheResp.bits.predecode.isRVC(i) && !if4_tage_lateJump) { 257 io.fetchPacket.bits.pnpc(i-1) := if4_tage_target 258 } 259 } 260 }.otherwise { 261 io.fetchPacket.bits.pnpc(i) := if4_pc + (i.U << 1.U) + Mux(io.icacheResp.bits.predecode.isRVC(i), 2.U, 4.U) 262 } 263 XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] instruction %x pnpc:0x%x\n", 264 Mux((i.U)(0), io.fetchPacket.bits.instrs(i>>1)(31,16), io.fetchPacket.bits.instrs(i>>1)(15,0)), 265 io.fetchPacket.bits.pnpc(i)) 266 } 267 io.fetchPacket.bits.hist := bpu.io.tageOut.bits.hist 268 io.fetchPacket.bits.predCtr := bpu.io.tageOut.bits.predCtr 269 io.fetchPacket.bits.btbHit := bpu.io.tageOut.bits.btbHit 270 io.fetchPacket.bits.tageMeta := bpu.io.tageOut.bits.tageMeta 271 io.fetchPacket.bits.rasSp := bpu.io.tageOut.bits.rasSp 272 io.fetchPacket.bits.rasTopCtr := bpu.io.tageOut.bits.rasTopCtr 273 bpu.io.tageOut.ready := if4_start_ready 274 275}