xref: /XiangShan/src/main/scala/xiangshan/frontend/IFU.scala (revision 66314a3840e5ebe6cc81ca4725bde95942f67489)
1 package 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
15}
16
17class IFUIO extends XSBundle
18{
19    val fetchPacket = DecoupledIO(new FetchPacket)
20    val redirectInfo = Input(new RedirectInfo)
21    val icacheReq = DecoupledIO(new FakeIcacheReq)
22    val icacheResp = Flipped(DecoupledIO(new FakeIcacheResp))
23}
24
25class FakeBPU extends XSModule{
26  val io = IO(new Bundle() {
27    val redirectInfo = Input(new RedirectInfo)
28    val in = new Bundle { val pc = Flipped(Valid(UInt(VAddrBits.W))) }
29    val btbOut = ValidIO(new BranchPrediction)
30    val tageOut = ValidIO(new BranchPrediction)
31    val predecode = Flipped(ValidIO(new Predecode))
32  })
33
34  io.btbOut.valid := true.B
35  io.btbOut.bits <> DontCare
36  io.btbOut.bits.redirect := GTimer() === 1.U
37  io.btbOut.bits.target := "h080001234".U
38  io.tageOut.valid := false.B
39  io.tageOut.bits <> DontCare
40}
41
42
43class IFU extends XSModule with HasIFUConst
44{
45    val io = IO(new IFUIO)
46    val bpu = if(EnableBPU) Module(new BPU) else Module(new FakeBPU)
47
48    //-------------------------
49    //      IF1  PC update
50    //-------------------------
51    //local
52    val if1_npc = WireInit(0.U(VAddrBits.W))
53    val if1_valid = !reset.asBool
54    val if1_pc = RegInit(resetVector.U(VAddrBits.W))
55    //next
56    val if2_ready = WireInit(false.B)
57    val if2_snpc = snpc(if1_pc) //TODO: this is ugly
58    val needflush = WireInit(false.B)
59
60    //pipe fire
61    val if1_fire = if1_valid && if2_ready
62    val if1_pcUpdate = if1_fire || needflush
63
64    when(RegNext(reset.asBool) && !reset.asBool){
65    //when((GTimer() === 501.U)){ //TODO:this is ugly
66      XSDebug("RESET....\n")
67      if1_npc := resetVector.U(VAddrBits.W)
68    } .otherwise{
69      if1_npc := if2_snpc
70    }
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    //-------------------------
86    //      IF2  btb response
87    //           icache visit
88    //-------------------------
89    //local
90    val if2_valid = RegEnable(next=if1_valid,init=false.B,enable=if1_fire)
91    val if2_pc = if1_pc
92    val if2_btb_taken = bpu.io.btbOut.valid && bpu.io.btbOut.bits.redirect
93    val if2_btb_insMask = bpu.io.btbOut.bits.instrValid
94    val if2_btb_target = bpu.io.btbOut.bits.target
95
96    //next
97    val if3_ready = WireInit(false.B)
98
99    //pipe fire
100    val if2_fire = if2_valid && if3_ready && io.icacheReq.fire()
101    if2_ready := (if2_fire) || !if2_valid
102
103    io.icacheReq.valid := if2_valid
104    io.icacheReq.bits.addr := if2_pc
105
106    when(if2_valid && if2_btb_taken)
107    {
108      if1_npc := if2_btb_target
109    }
110
111    XSDebug("[IF2]if2_valid:%d  ||  if2_pc:0x%x   || if3_ready:%d                                        ",if2_valid,if2_pc,if3_ready)
112    XSDebug(false,if2_fire,"------IF2->fire!!!")
113    XSDebug(false,true.B,"\n")
114    XSDebug("[IF2-Icache-Req] icache_in_valid:%d  icache_in_ready:%d\n",io.icacheReq.valid,io.icacheReq.ready)
115    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)
116    //-------------------------
117    //      IF3  icache hit check
118    //-------------------------
119    //local
120    val if3_valid = RegEnable(next=if2_valid,init=false.B,enable=if2_fire)
121    val if3_pc = RegEnable(if2_pc,if2_fire)
122    val if3_npc = RegEnable(if1_npc,if2_fire)
123    val if3_btb_target = RegEnable(if2_btb_target,if2_fire)
124    val if3_btb_taken = RegEnable(if2_btb_taken,if2_fire)
125    val if3_btb_insMask = RegEnable(if2_btb_insMask, if2_fire)
126
127    //next
128    val if4_ready = WireInit(false.B)
129
130    //pipe fire
131    val if3_fire = if3_valid && if4_ready
132    if3_ready := if3_fire  || !if3_valid
133
134
135    XSDebug("[IF3]if3_valid:%d  ||  if3_pc:0x%x   if3_npc:0x%x || if4_ready:%d                    ",if3_valid,if3_pc,if3_npc,if4_ready)
136    XSDebug(false,if3_fire,"------IF3->fire!!!")
137    XSDebug(false,true.B,"\n")
138
139    //-------------------------
140    //      IF4  icache response
141    //           RAS result
142    //           taget generate
143    //-------------------------
144    val if4_valid = RegEnable(next=if3_valid,init=false.B,enable=if3_fire)
145    val if4_pc = RegEnable(if3_pc,if3_fire)
146    val if4_npc = RegEnable(if3_npc,if3_fire)
147    val if4_btb_target = RegEnable(if3_btb_target,if3_fire)
148    val if4_btb_taken = RegEnable(if3_btb_taken,if3_fire)
149    val if4_btb_insMask = RegEnable(if3_btb_insMask, if3_fire)
150    val if4_tage_target = bpu.io.tageOut.bits.target
151    val if4_tage_taken = bpu.io.tageOut.valid && bpu.io.tageOut.bits.redirect
152    val if4_tage_insMask = bpu.io.tageOut.bits.instrValid
153    val if4_btb_missPre = WireInit(false.B)
154
155    XSDebug("[IF4]if4_valid:%d  ||  if4_pc:0x%x   if4_npc:0x%x\n",if4_valid,if4_pc,if4_npc)
156    XSDebug("[IF4-TAGE-out]if4_tage_taken:%d || if4_btb_insMask:%b || if4_tage_target:0x%x \n",if4_tage_taken,if4_tage_insMask.asUInt,if4_tage_target)
157    XSDebug("[IF4-ICACHE-RESP]icacheResp.valid:%d   icacheResp.ready:%d\n",io.icacheResp.valid,io.icacheResp.ready)
158
159    when(io.icacheResp.fire() && if4_tage_taken &&if4_valid)
160    {
161      if1_npc := if4_tage_target
162    }
163    //redirect: tage result differ btb
164    if4_btb_missPre := (if4_tage_taken ^ if4_btb_taken) || (if4_tage_taken && if4_btb_taken && (if4_tage_target =/=  if4_btb_target))
165
166    if(EnableBPD){
167      when(!if4_tage_taken && if4_btb_taken && if4_valid){
168        if1_npc := if4_pc + (PopCount(io.fetchPacket.bits.mask) >> 2.U)
169      }
170    }
171
172    //redirect: miss predict
173    when(io.redirectInfo.flush()){
174      if1_npc := io.redirectInfo.redirect.target
175    }
176    XSDebug(io.redirectInfo.flush(),"[IFU-REDIRECT] target:0x%x  \n",io.redirectInfo.redirect.target.asUInt)
177
178
179    //flush pipline
180    if(EnableBPD){needflush := (if4_valid && if4_btb_missPre) || io.redirectInfo.flush() }
181    else {needflush := io.redirectInfo.flush()}
182    when(needflush){
183      if3_valid := false.B
184      if4_valid := false.B
185    }
186    //flush ICache
187    io.icacheReq.bits.flush := needflush
188
189    //Output -> iBuffer
190    //io.fetchPacket <> DontCare
191    if4_ready := io.fetchPacket.ready && (io.icacheResp.valid || !if4_valid) && (GTimer() > 500.U)
192    io.fetchPacket.valid := if4_valid && !io.redirectInfo.flush()
193    io.fetchPacket.bits.instrs := io.icacheResp.bits.icacheOut
194    if(EnableBPU){
195      io.fetchPacket.bits.mask := Mux(if4_tage_taken,(Fill(FetchWidth*2, 1.U(1.W)) & Reverse(Cat(if4_tage_insMask.map(i => Fill(2, i.asUInt))).asUInt)),
196        Mux(if4_btb_taken, Fill(FetchWidth*2, 1.U(1.W)) & Reverse(Cat(if4_btb_insMask.map(i => Fill(2, i.asUInt))).asUInt),
197        Fill(FetchWidth*2, 1.U(1.W)))
198      )
199    }
200    else{
201      io.fetchPacket.bits.mask := Fill(FetchWidth*2, 1.U(1.W)) //TODO : consider cross cacheline fetch
202    }
203    io.fetchPacket.bits.pc := if4_pc
204
205    XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] starPC:0x%x   GroupPC:0x%xn\n",if4_pc.asUInt,groupPC(if4_pc).asUInt)
206    XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] instrmask %b\n",io.fetchPacket.bits.mask.asUInt)
207    for(i <- 0 until FetchWidth){
208      //io.fetchPacket.bits.pnpc(i) := if1_npc
209      when (if4_btb_taken && !if4_tage_taken && i.U === OHToUInt(HighestBit(if4_btb_insMask.asUInt, FetchWidth))) {
210        if(EnableBPD){io.fetchPacket.bits.pnpc(i) := if4_pc + ((i + 1).U << 2.U) }     //tage not taken use snpc
211        else{io.fetchPacket.bits.pnpc(i) := if4_btb_target}//use fetch PC
212      }.elsewhen (if4_tage_taken && i.U === OHToUInt(HighestBit(if4_tage_insMask.asUInt, FetchWidth))) {
213        io.fetchPacket.bits.pnpc(i) := if1_npc
214      }.otherwise {
215        io.fetchPacket.bits.pnpc(i) := if4_pc + ((i + 1).U << 2.U) //use fetch PC
216      }
217      XSDebug(io.fetchPacket.fire,"[IFU-Out-FetchPacket] instruction %x    pnpc:0x%x\n",io.fetchPacket.bits.instrs(i).asUInt,io.fetchPacket.bits.pnpc(i).asUInt)
218    }
219    io.fetchPacket.bits.hist := bpu.io.tageOut.bits.hist
220    // io.fetchPacket.bits.btbVictimWay := bpu.io.tageOut.bits.btbVictimWay
221    io.fetchPacket.bits.predCtr := bpu.io.tageOut.bits.predCtr
222    io.fetchPacket.bits.btbHitWay := bpu.io.tageOut.bits.btbHitWay
223    io.fetchPacket.bits.tageMeta := bpu.io.tageOut.bits.tageMeta
224    io.fetchPacket.bits.rasSp := bpu.io.tageOut.bits.rasSp
225    io.fetchPacket.bits.rasTopCtr := bpu.io.tageOut.bits.rasTopCtr
226
227    //to BPU
228    bpu.io.predecode.valid := io.icacheResp.fire() && if4_valid
229    bpu.io.predecode.bits <> io.icacheResp.bits.predecode
230    bpu.io.predecode.bits.mask := Fill(FetchWidth, 1.U(1.W)) //TODO: consider RVC && consider cross cacheline fetch
231    bpu.io.redirectInfo := io.redirectInfo
232    io.icacheResp.ready := io.fetchPacket.ready && (GTimer() > 500.U)
233
234}
235
236