xref: /XiangShan/src/main/scala/xiangshan/frontend/IFU.scala (revision 28a7d001afbf5ec277b92034a17851fb5421d25d)
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}