xref: /XiangShan/src/main/scala/xiangshan/frontend/PreDecode.scala (revision 09c6f1dd83448ac60a0bb7980c3e4e524df66de0)
1*09c6f1ddSLingrui98/***************************************************************************************
2*09c6f1ddSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*09c6f1ddSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*09c6f1ddSLingrui98*
5*09c6f1ddSLingrui98* XiangShan is licensed under Mulan PSL v2.
6*09c6f1ddSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*09c6f1ddSLingrui98* You may obtain a copy of Mulan PSL v2 at:
8*09c6f1ddSLingrui98*          http://license.coscl.org.cn/MulanPSL2
9*09c6f1ddSLingrui98*
10*09c6f1ddSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*09c6f1ddSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*09c6f1ddSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*09c6f1ddSLingrui98*
14*09c6f1ddSLingrui98* See the Mulan PSL v2 for more details.
15*09c6f1ddSLingrui98***************************************************************************************/
16*09c6f1ddSLingrui98
17*09c6f1ddSLingrui98package xiangshan.frontend
18*09c6f1ddSLingrui98
19*09c6f1ddSLingrui98import chipsalliance.rocketchip.config.Parameters
20*09c6f1ddSLingrui98import freechips.rocketchip.rocket.{RVCDecoder, ExpandedInstruction}
21*09c6f1ddSLingrui98import chisel3.{util, _}
22*09c6f1ddSLingrui98import chisel3.util._
23*09c6f1ddSLingrui98import utils._
24*09c6f1ddSLingrui98import xiangshan._
25*09c6f1ddSLingrui98import xiangshan.backend.decode.isa.predecode.PreDecodeInst
26*09c6f1ddSLingrui98import xiangshan.cache._
27*09c6f1ddSLingrui98
28*09c6f1ddSLingrui98trait HasPdConst extends HasXSParameter with HasICacheParameters with HasIFUConst{
29*09c6f1ddSLingrui98  def isRVC(inst: UInt) = (inst(1,0) =/= 3.U)
30*09c6f1ddSLingrui98  def isLink(reg:UInt) = reg === 1.U || reg === 5.U
31*09c6f1ddSLingrui98  def brInfo(instr: UInt) = {
32*09c6f1ddSLingrui98    val brType::Nil = ListLookup(instr, List(BrType.notCFI), PreDecodeInst.brTable)
33*09c6f1ddSLingrui98    val rd = Mux(isRVC(instr), instr(12), instr(11,7))
34*09c6f1ddSLingrui98    val rs = Mux(isRVC(instr), Mux(brType === BrType.jal, 0.U, instr(11, 7)), instr(19, 15))
35*09c6f1ddSLingrui98    val isCall = (brType === BrType.jal && !isRVC(instr) || brType === BrType.jalr) && isLink(rd) // Only for RV64
36*09c6f1ddSLingrui98    val isRet = brType === BrType.jalr && isLink(rs) && !isCall
37*09c6f1ddSLingrui98    List(brType, isCall, isRet)
38*09c6f1ddSLingrui98  }
39*09c6f1ddSLingrui98  def jal_offset(inst: UInt, rvc: Bool): UInt = {
40*09c6f1ddSLingrui98    val rvc_offset = Cat(inst(12), inst(8), inst(10, 9), inst(6), inst(7), inst(2), inst(11), inst(5, 3), 0.U(1.W))
41*09c6f1ddSLingrui98    val rvi_offset = Cat(inst(31), inst(19, 12), inst(20), inst(30, 21), 0.U(1.W))
42*09c6f1ddSLingrui98    val max_width = rvi_offset.getWidth
43*09c6f1ddSLingrui98    SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
44*09c6f1ddSLingrui98  }
45*09c6f1ddSLingrui98  def br_offset(inst: UInt, rvc: Bool): UInt = {
46*09c6f1ddSLingrui98    val rvc_offset = Cat(inst(12), inst(6, 5), inst(2), inst(11, 10), inst(4, 3), 0.U(1.W))
47*09c6f1ddSLingrui98    val rvi_offset = Cat(inst(31), inst(7), inst(30, 25), inst(11, 8), 0.U(1.W))
48*09c6f1ddSLingrui98    val max_width = rvi_offset.getWidth
49*09c6f1ddSLingrui98    SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
50*09c6f1ddSLingrui98  }
51*09c6f1ddSLingrui98  def getBasicBlockIdx( pc: UInt, start:  UInt ): UInt = {
52*09c6f1ddSLingrui98    val byteOffset = pc - start
53*09c6f1ddSLingrui98    (byteOffset - instBytes.U)(log2Ceil(PredictWidth),instOffsetBits)
54*09c6f1ddSLingrui98  }
55*09c6f1ddSLingrui98
56*09c6f1ddSLingrui98  def NOP = "h4501".U(16.W)
57*09c6f1ddSLingrui98}
58*09c6f1ddSLingrui98
59*09c6f1ddSLingrui98object BrType {
60*09c6f1ddSLingrui98  def notCFI   = "b00".U
61*09c6f1ddSLingrui98  def branch  = "b01".U
62*09c6f1ddSLingrui98  def jal     = "b10".U
63*09c6f1ddSLingrui98  def jalr    = "b11".U
64*09c6f1ddSLingrui98  def apply() = UInt(2.W)
65*09c6f1ddSLingrui98}
66*09c6f1ddSLingrui98
67*09c6f1ddSLingrui98object ExcType {  //TODO:add exctype
68*09c6f1ddSLingrui98  def notExc = "b000".U
69*09c6f1ddSLingrui98  def apply() = UInt(3.W)
70*09c6f1ddSLingrui98}
71*09c6f1ddSLingrui98
72*09c6f1ddSLingrui98class PreDecodeInfo extends Bundle {  // 8 bit
73*09c6f1ddSLingrui98  val valid   = Bool()
74*09c6f1ddSLingrui98  val isRVC   = Bool()
75*09c6f1ddSLingrui98  val brType  = UInt(2.W)
76*09c6f1ddSLingrui98  val isCall  = Bool()
77*09c6f1ddSLingrui98  val isRet   = Bool()
78*09c6f1ddSLingrui98  //val excType = UInt(3.W)
79*09c6f1ddSLingrui98  def isBr    = brType === BrType.branch
80*09c6f1ddSLingrui98  def isJal   = brType === BrType.jal
81*09c6f1ddSLingrui98  def isJalr  = brType === BrType.jalr
82*09c6f1ddSLingrui98  def notCFI  = brType === BrType.notCFI
83*09c6f1ddSLingrui98}
84*09c6f1ddSLingrui98
85*09c6f1ddSLingrui98class PreDecodeResp(implicit p: Parameters) extends XSBundle with HasPdConst {
86*09c6f1ddSLingrui98  val pc          = Vec(PredictWidth, UInt(VAddrBits.W))
87*09c6f1ddSLingrui98  val instrs      = Vec(PredictWidth, UInt(32.W))
88*09c6f1ddSLingrui98  val pd          = Vec(PredictWidth, (new PreDecodeInfo))
89*09c6f1ddSLingrui98  val takens      = Vec(PredictWidth, Bool())
90*09c6f1ddSLingrui98  val misOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
91*09c6f1ddSLingrui98  val cfiOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
92*09c6f1ddSLingrui98  val target       = UInt(VAddrBits.W)
93*09c6f1ddSLingrui98  val jalTarget    = UInt(VAddrBits.W)
94*09c6f1ddSLingrui98  val hasLastHalf  = Bool()
95*09c6f1ddSLingrui98  val realEndPC    = UInt(VAddrBits.W)
96*09c6f1ddSLingrui98  val instrRange   = Vec(PredictWidth, Bool())
97*09c6f1ddSLingrui98  val pageFault    = Vec(PredictWidth, Bool())
98*09c6f1ddSLingrui98  val accessFault  = Vec(PredictWidth, Bool())
99*09c6f1ddSLingrui98  val crossPageIPF = Vec(PredictWidth, Bool())
100*09c6f1ddSLingrui98}
101*09c6f1ddSLingrui98
102*09c6f1ddSLingrui98class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
103*09c6f1ddSLingrui98  val io = IO(new Bundle() {
104*09c6f1ddSLingrui98    val in = Input(new IfuToPreDecode)
105*09c6f1ddSLingrui98    val out = Output(new PreDecodeResp)
106*09c6f1ddSLingrui98  })
107*09c6f1ddSLingrui98
108*09c6f1ddSLingrui98  val instValid     = io.in.instValid
109*09c6f1ddSLingrui98  val data          = io.in.data
110*09c6f1ddSLingrui98  val pcStart       = io.in.startAddr
111*09c6f1ddSLingrui98  val pcEnd         = io.in.fallThruAddr
112*09c6f1ddSLingrui98  val pcEndError    = io.in.fallThruError
113*09c6f1ddSLingrui98  val isDoubleLine  = io.in.isDoubleLine
114*09c6f1ddSLingrui98  val bbOffset      = io.in.ftqOffset.bits
115*09c6f1ddSLingrui98  val bbTaken       = io.in.ftqOffset.valid
116*09c6f1ddSLingrui98  val bbTarget      = io.in.target
117*09c6f1ddSLingrui98  val oversize      = io.in.oversize
118*09c6f1ddSLingrui98  val pageFault     = io.in.pageFault
119*09c6f1ddSLingrui98  val accessFault   = io.in.accessFault
120*09c6f1ddSLingrui98
121*09c6f1ddSLingrui98
122*09c6f1ddSLingrui98  val validStart        = Wire(Vec(PredictWidth, Bool()))
123*09c6f1ddSLingrui98  dontTouch(validStart)
124*09c6f1ddSLingrui98  val validEnd          = Wire(Vec(PredictWidth, Bool()))
125*09c6f1ddSLingrui98  val targets           = Wire(Vec(PredictWidth, UInt(VAddrBits.W)))
126*09c6f1ddSLingrui98  val misPred           = Wire(Vec(PredictWidth, Bool()))
127*09c6f1ddSLingrui98  val takens            = Wire(Vec(PredictWidth, Bool()))
128*09c6f1ddSLingrui98  val falseHit          = Wire(Vec(PredictWidth, Bool()))
129*09c6f1ddSLingrui98  val instRange         = Wire(Vec(PredictWidth, Bool()))
130*09c6f1ddSLingrui98  //"real" means signals that are genrated by repaired end pc of this basic block using predecode information
131*09c6f1ddSLingrui98  val realEndPC         = Wire(UInt(VAddrBits.W))
132*09c6f1ddSLingrui98  val realHasLastHalf   = Wire(Vec(PredictWidth, Bool()))
133*09c6f1ddSLingrui98  val realMissPred      = Wire(Vec(PredictWidth, Bool()))
134*09c6f1ddSLingrui98  val realTakens        = Wire(Vec(PredictWidth, Bool()))
135*09c6f1ddSLingrui98
136*09c6f1ddSLingrui98  val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i+1), data(i))))
137*09c6f1ddSLingrui98                       else         VecInit((0 until PredictWidth).map(i => data(i)))
138*09c6f1ddSLingrui98
139*09c6f1ddSLingrui98  val nextLinePC =  align(pcStart, 64) + 64.U
140*09c6f1ddSLingrui98
141*09c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
142*09c6f1ddSLingrui98    //TODO: Terrible timing for pc comparing
143*09c6f1ddSLingrui98    val isNextLine      = (io.out.pc(i) > nextLinePC)
144*09c6f1ddSLingrui98    val nullInstruction = isNextLine && !isDoubleLine
145*09c6f1ddSLingrui98
146*09c6f1ddSLingrui98    val hasPageFault   = validStart(i) && ((io.out.pc(i) < nextLinePC && pageFault(0))   || (io.out.pc(i) > nextLinePC && pageFault(1)))
147*09c6f1ddSLingrui98    val hasAccessFault = validStart(i) && ((io.out.pc(i) < nextLinePC && accessFault(0)) || (io.out.pc(i) > nextLinePC && accessFault(1)))
148*09c6f1ddSLingrui98    val exception      = hasPageFault || hasAccessFault
149*09c6f1ddSLingrui98    val inst           = Mux(exception || nullInstruction , NOP, WireInit(rawInsts(i)))
150*09c6f1ddSLingrui98    val expander       = Module(new RVCExpander)
151*09c6f1ddSLingrui98
152*09c6f1ddSLingrui98    val isFirstInBlock = i.U === 0.U
153*09c6f1ddSLingrui98    val isLastInBlock  = (i == PredictWidth - 1).B
154*09c6f1ddSLingrui98    val currentPC      = pcStart + (i << 1).U((log2Ceil(PredictWidth)+1).W)
155*09c6f1ddSLingrui98    val currentIsRVC   = isRVC(inst) && HasCExtension.B
156*09c6f1ddSLingrui98
157*09c6f1ddSLingrui98    val lastIsValidEnd =  if (i == 0) { !io.in.lastHalfMatch } else { validEnd(i-1) || isFirstInBlock || !HasCExtension.B }
158*09c6f1ddSLingrui98
159*09c6f1ddSLingrui98    validStart(i)   := (lastIsValidEnd || !HasCExtension.B)
160*09c6f1ddSLingrui98    validEnd(i)     := validStart(i) && currentIsRVC || !validStart(i) || !HasCExtension.B
161*09c6f1ddSLingrui98
162*09c6f1ddSLingrui98    val brType::isCall::isRet::Nil = brInfo(inst)
163*09c6f1ddSLingrui98    val jalOffset = jal_offset(inst, currentIsRVC)
164*09c6f1ddSLingrui98    val brOffset  = br_offset(inst, currentIsRVC)
165*09c6f1ddSLingrui98
166*09c6f1ddSLingrui98    io.out.pd(i).valid         := (lastIsValidEnd || !HasCExtension.B)
167*09c6f1ddSLingrui98    io.out.pd(i).isRVC         := currentIsRVC
168*09c6f1ddSLingrui98    io.out.pd(i).brType        := brType
169*09c6f1ddSLingrui98    io.out.pd(i).isCall        := isCall
170*09c6f1ddSLingrui98    io.out.pd(i).isRet         := isRet
171*09c6f1ddSLingrui98    io.out.pc(i)               := currentPC
172*09c6f1ddSLingrui98    io.out.pageFault(i)        := hasPageFault
173*09c6f1ddSLingrui98    io.out.accessFault(i)      := hasAccessFault
174*09c6f1ddSLingrui98    io.out.crossPageIPF(i)     := (io.out.pc(i) === align(realEndPC, 64) - 2.U) && !pageFault(0) && pageFault(1) && !currentIsRVC
175*09c6f1ddSLingrui98
176*09c6f1ddSLingrui98    expander.io.in             := inst
177*09c6f1ddSLingrui98    io.out.instrs(i)           := expander.io.out.bits
178*09c6f1ddSLingrui98
179*09c6f1ddSLingrui98    takens(i)    := (validStart(i)  && (bbTaken && bbOffset === i.U && !io.out.pd(i).notCFI || io.out.pd(i).isJal || io.out.pd(i).isRet))
180*09c6f1ddSLingrui98
181*09c6f1ddSLingrui98    val jumpTarget      = io.out.pc(i) + Mux(io.out.pd(i).isBr, brOffset, jalOffset)
182*09c6f1ddSLingrui98    targets(i) := Mux(takens(i), jumpTarget, pcEnd)
183*09c6f1ddSLingrui98                       //Banch and jal have wrong targets
184*09c6f1ddSLingrui98    val targetFault    = (validStart(i)  && i.U === bbOffset && bbTaken && (io.out.pd(i).isBr || io.out.pd(i).isJal) && bbTarget =/= targets(i))
185*09c6f1ddSLingrui98                       //An not-CFI instruction is predicted taken
186*09c6f1ddSLingrui98    val notCFIFault    = (validStart(i)  && i.U === bbOffset && io.out.pd(i).notCFI && bbTaken)
187*09c6f1ddSLingrui98                       //A jal instruction is predicted not taken
188*09c6f1ddSLingrui98    val jalFault       = (validStart(i)  && !bbTaken && io.out.pd(i).isJal)
189*09c6f1ddSLingrui98                       //A ret instruction is predicted not taken
190*09c6f1ddSLingrui98    val retFault       = (validStart(i)  && !bbTaken && io.out.pd(i).isRet)
191*09c6f1ddSLingrui98                       //An invalid instruction is predicted taken
192*09c6f1ddSLingrui98    val invalidInsFault  = (!validStart(i)  && i.U === bbOffset && bbTaken)
193*09c6f1ddSLingrui98
194*09c6f1ddSLingrui98    misPred(i)   := targetFault  || notCFIFault || jalFault || retFault || invalidInsFault || pcEndError
195*09c6f1ddSLingrui98    falseHit(i)  := invalidInsFault || notCFIFault
196*09c6f1ddSLingrui98
197*09c6f1ddSLingrui98    realMissPred(i)     := misPred(i) && instRange(i)
198*09c6f1ddSLingrui98    realHasLastHalf(i)  := instValid && currentPC === (realEndPC - 2.U) && validStart(i) && instRange(i) && !currentIsRVC
199*09c6f1ddSLingrui98    realTakens(i)       := takens(i) && instRange(i)
200*09c6f1ddSLingrui98  }
201*09c6f1ddSLingrui98
202*09c6f1ddSLingrui98  val jumpOH                  =  VecInit(io.out.pd.zipWithIndex.map{ case(inst, i) => inst.isJal  && validStart(i) }) //TODO: need jalr?
203*09c6f1ddSLingrui98  val jumpOffset              =  PriorityEncoder(jumpOH)
204*09c6f1ddSLingrui98  val rvcOH                   =  VecInit(io.out.pd.map(inst => inst.isRVC))
205*09c6f1ddSLingrui98  val jumpPC                  =  io.out.pc(jumpOffset)
206*09c6f1ddSLingrui98  val jumpIsRVC               =  rvcOH(jumpOffset)
207*09c6f1ddSLingrui98  val jumpNextPC              =  jumpPC + Mux(jumpIsRVC, 2.U, 4.U)
208*09c6f1ddSLingrui98  val (hasFalseHit, hasJump)  =  (ParallelOR(falseHit), ParallelOR(jumpOH))
209*09c6f1ddSLingrui98  val endRange                =  ((Fill(PredictWidth, 1.U(1.W)) >> (~getBasicBlockIdx(realEndPC, pcStart))) | (Fill(PredictWidth, oversize)))
210*09c6f1ddSLingrui98  val takeRange               =  Fill(PredictWidth, !ParallelOR(takens))   | Fill(PredictWidth, 1.U(1.W)) >> (~PriorityEncoder(takens))
211*09c6f1ddSLingrui98  val fixCross                =  ((pcStart + (FetchWidth * 4).U) > nextLinePC) && !isDoubleLine
212*09c6f1ddSLingrui98  val boundPC                 =  Mux(fixCross, nextLinePC - 2.U  ,pcStart + (FetchWidth * 4).U)
213*09c6f1ddSLingrui98
214*09c6f1ddSLingrui98  instRange               :=  VecInit((0 until PredictWidth).map(i => endRange(i) &&  takeRange(i)))
215*09c6f1ddSLingrui98  realEndPC               :=  Mux(hasFalseHit, Mux(hasJump && ((jumpNextPC < boundPC) || (jumpNextPC === boundPC) ), jumpNextPC, boundPC), pcEnd)
216*09c6f1ddSLingrui98
217*09c6f1ddSLingrui98  val validLastOffset     = Mux(io.out.pd((PredictWidth - 1).U).valid, (PredictWidth - 1).U, (PredictWidth - 2).U)
218*09c6f1ddSLingrui98  io.out.misOffset.valid  := ParallelOR(realMissPred)
219*09c6f1ddSLingrui98  io.out.misOffset.bits   := Mux(pcEndError,validLastOffset,PriorityEncoder(realMissPred))
220*09c6f1ddSLingrui98  io.out.instrRange.zipWithIndex.map{case (bit,i) => bit := instRange(i).asBool()}
221*09c6f1ddSLingrui98
222*09c6f1ddSLingrui98  io.out.cfiOffset.valid  := ParallelOR(realTakens)
223*09c6f1ddSLingrui98  io.out.cfiOffset.bits   := PriorityEncoder(realTakens)
224*09c6f1ddSLingrui98
225*09c6f1ddSLingrui98  io.out.target           := Mux(io.out.cfiOffset.valid, targets(io.out.cfiOffset.bits), realEndPC)
226*09c6f1ddSLingrui98  io.out.takens           := realTakens
227*09c6f1ddSLingrui98
228*09c6f1ddSLingrui98  io.out.jalTarget        :=  targets(jumpOffset)
229*09c6f1ddSLingrui98
230*09c6f1ddSLingrui98  io.out.hasLastHalf      := realHasLastHalf.reduce(_||_)
231*09c6f1ddSLingrui98  io.out.realEndPC        := realEndPC
232*09c6f1ddSLingrui98
233*09c6f1ddSLingrui98  for (i <- 0 until PredictWidth) {
234*09c6f1ddSLingrui98    XSDebug(true.B,
235*09c6f1ddSLingrui98      p"instr ${Hexadecimal(io.out.instrs(i))}, " +
236*09c6f1ddSLingrui98      p"validStart ${Binary(validStart(i))}, " +
237*09c6f1ddSLingrui98      p"validEnd ${Binary(validEnd(i))}, " +
238*09c6f1ddSLingrui98      p"pc ${Hexadecimal(io.out.pc(i))}, " +
239*09c6f1ddSLingrui98      p"isRVC ${Binary(io.out.pd(i).isRVC)}, " +
240*09c6f1ddSLingrui98      p"brType ${Binary(io.out.pd(i).brType)}, " +
241*09c6f1ddSLingrui98      p"isRet ${Binary(io.out.pd(i).isRet)}, " +
242*09c6f1ddSLingrui98      p"isCall ${Binary(io.out.pd(i).isCall)}\n"
243*09c6f1ddSLingrui98    )
244*09c6f1ddSLingrui98  }
245*09c6f1ddSLingrui98}
246*09c6f1ddSLingrui98
247*09c6f1ddSLingrui98class RVCExpander(implicit p: Parameters) extends XSModule {
248*09c6f1ddSLingrui98  val io = IO(new Bundle {
249*09c6f1ddSLingrui98    val in = Input(UInt(32.W))
250*09c6f1ddSLingrui98    val out = Output(new ExpandedInstruction)
251*09c6f1ddSLingrui98  })
252*09c6f1ddSLingrui98
253*09c6f1ddSLingrui98  if (HasCExtension) {
254*09c6f1ddSLingrui98    io.out := new RVCDecoder(io.in, XLEN).decode
255*09c6f1ddSLingrui98  } else {
256*09c6f1ddSLingrui98    io.out := new RVCDecoder(io.in, XLEN).passthrough
257*09c6f1ddSLingrui98  }
258*09c6f1ddSLingrui98}
259