PreDecode.scala 11.7 KB
Newer Older
L
Lingrui98 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/***************************************************************************************
* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
* Copyright (c) 2020-2021 Peng Cheng Laboratory
*
* XiangShan is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

17 18
package xiangshan.frontend

19 20
import chipsalliance.rocketchip.config.Parameters
import freechips.rocketchip.rocket.{RVCDecoder, ExpandedInstruction}
21
import chisel3.{util, _}
22 23 24 25 26 27
import chisel3.util._
import utils._
import xiangshan._
import xiangshan.backend.decode.isa.predecode.PreDecodeInst
import xiangshan.cache._

J
JinYue 已提交
28
trait HasPdConst extends HasXSParameter with HasICacheParameters with HasIFUConst{
29 30 31
  def isRVC(inst: UInt) = (inst(1,0) =/= 3.U)
  def isLink(reg:UInt) = reg === 1.U || reg === 5.U
  def brInfo(instr: UInt) = {
32
    val brType::Nil = ListLookup(instr, List(BrType.notCFI), PreDecodeInst.brTable)
33 34 35 36 37 38
    val rd = Mux(isRVC(instr), instr(12), instr(11,7))
    val rs = Mux(isRVC(instr), Mux(brType === BrType.jal, 0.U, instr(11, 7)), instr(19, 15))
    val isCall = (brType === BrType.jal && !isRVC(instr) || brType === BrType.jalr) && isLink(rd) // Only for RV64
    val isRet = brType === BrType.jalr && isLink(rs) && !isCall
    List(brType, isCall, isRet)
  }
39
  def jal_offset(inst: UInt, rvc: Bool): UInt = {
40 41 42 43
    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))
    val rvi_offset = Cat(inst(31), inst(19, 12), inst(20), inst(30, 21), 0.U(1.W))
    val max_width = rvi_offset.getWidth
    SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
44
  }
45
  def br_offset(inst: UInt, rvc: Bool): UInt = {
46 47 48 49
    val rvc_offset = Cat(inst(12), inst(6, 5), inst(2), inst(11, 10), inst(4, 3), 0.U(1.W))
    val rvi_offset = Cat(inst(31), inst(7), inst(30, 25), inst(11, 8), 0.U(1.W))
    val max_width = rvi_offset.getWidth
    SignExt(Mux(rvc, SignExt(rvc_offset, max_width), SignExt(rvi_offset, max_width)), XLEN)
50
  }
51
  def getBasicBlockIdx( pc: UInt, start:  UInt ): UInt = {
52 53
    val byteOffset = pc - start
    (byteOffset - instBytes.U)(log2Ceil(PredictWidth),instOffsetBits)
54
  }
J
JinYue 已提交
55 56

  def NOP = "h4501".U(16.W)
57 58 59
}

object BrType {
60
  def notCFI   = "b00".U
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
  def branch  = "b01".U
  def jal     = "b10".U
  def jalr    = "b11".U
  def apply() = UInt(2.W)
}

object ExcType {  //TODO:add exctype
  def notExc = "b000".U
  def apply() = UInt(3.W)
}

class PreDecodeInfo extends Bundle {  // 8 bit
  val valid   = Bool()
  val isRVC   = Bool()
  val brType  = UInt(2.W)
  val isCall  = Bool()
  val isRet   = Bool()
  //val excType = UInt(3.W)
79 80 81 82
  def isBr    = brType === BrType.branch
  def isJal   = brType === BrType.jal
  def isJalr  = brType === BrType.jalr
  def notCFI  = brType === BrType.notCFI
83 84
}

85 86 87 88 89
class PreDecodeResp(implicit p: Parameters) extends XSBundle with HasPdConst {
  val pc          = Vec(PredictWidth, UInt(VAddrBits.W))
  val instrs      = Vec(PredictWidth, UInt(32.W))
  val pd          = Vec(PredictWidth, (new PreDecodeInfo))
  val takens      = Vec(PredictWidth, Bool())
90 91
  val misOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
  val cfiOffset    = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))
92
  val target       = UInt(VAddrBits.W)
93
  val jalTarget    = UInt(VAddrBits.W)
J
JinYue 已提交
94
  val hasLastHalf  = Bool()
J
JinYue 已提交
95
  val realEndPC    = UInt(VAddrBits.W)
96
  val instrRange   = Vec(PredictWidth, Bool())
J
JinYue 已提交
97 98 99
  val pageFault    = Vec(PredictWidth, Bool())
  val accessFault  = Vec(PredictWidth, Bool())
  val crossPageIPF = Vec(PredictWidth, Bool())
100 101
}

102
class PreDecode(implicit p: Parameters) extends XSModule with HasPdConst{
103
  val io = IO(new Bundle() {
104
    val in = Input(new IfuToPreDecode)
105 106 107
    val out = Output(new PreDecodeResp)
  })

Y
Yinan Xu 已提交
108
  val instValid     = io.in.instValid
J
JinYue 已提交
109 110 111
  val data          = io.in.data
  val pcStart       = io.in.startAddr
  val pcEnd         = io.in.fallThruAddr
J
JinYue 已提交
112
  val pcEndError    = io.in.fallThruError
J
JinYue 已提交
113 114 115 116 117 118 119
  val isDoubleLine  = io.in.isDoubleLine
  val bbOffset      = io.in.ftqOffset.bits
  val bbTaken       = io.in.ftqOffset.valid
  val bbTarget      = io.in.target
  val oversize      = io.in.oversize
  val pageFault     = io.in.pageFault
  val accessFault   = io.in.accessFault
J
JinYue 已提交
120 121

  val validStart        = Wire(Vec(PredictWidth, Bool()))
J
JinYue 已提交
122
  dontTouch(validStart)
J
JinYue 已提交
123 124 125 126 127 128
  val validEnd          = Wire(Vec(PredictWidth, Bool()))
  val targets           = Wire(Vec(PredictWidth, UInt(VAddrBits.W)))
  val misPred           = Wire(Vec(PredictWidth, Bool()))
  val takens            = Wire(Vec(PredictWidth, Bool()))
  val falseHit          = Wire(Vec(PredictWidth, Bool()))
  val instRange         = Wire(Vec(PredictWidth, Bool()))
J
JinYue 已提交
129
  //"real" means signals that are genrated by repaired end pc of this basic block using predecode information
J
JinYue 已提交
130 131
  val realEndPC         = Wire(UInt(VAddrBits.W))
  val realHasLastHalf   = Wire(Vec(PredictWidth, Bool()))
132 133
  val realMissPred      = Wire(Vec(PredictWidth, Bool()))
  val realTakens        = Wire(Vec(PredictWidth, Bool()))
134

Y
Yinan Xu 已提交
135
  val rawInsts = if (HasCExtension) VecInit((0 until PredictWidth).map(i => Cat(data(i+1), data(i))))
136
                       else         VecInit((0 until PredictWidth).map(i => data(i)))
Y
Yinan Xu 已提交
137

138
  val nextLinePC =  align(pcStart, 64) + 64.U
139

140
  for (i <- 0 until PredictWidth) {
J
JinYue 已提交
141
    //TODO: Terrible timing for pc comparing
J
JinYue 已提交
142 143 144
    val isNextLine      = (io.out.pc(i) > nextLinePC)
    val nullInstruction = isNextLine && !isDoubleLine

145 146
    val hasPageFault   = ((io.out.pc(i) < nextLinePC && pageFault(0))   || ((io.out.pc(i) > nextLinePC || io.out.pc(i) === nextLinePC) && pageFault(1)))
    val hasAccessFault = ((io.out.pc(i) < nextLinePC && accessFault(0)) || ((io.out.pc(i) > nextLinePC || io.out.pc(i) === nextLinePC) && accessFault(1)))
J
JinYue 已提交
147
    val exception      = hasPageFault || hasAccessFault
J
JinYue 已提交
148
    val inst           = Mux(exception || nullInstruction , NOP, WireInit(rawInsts(i)))
J
JinYue 已提交
149 150
    val expander       = Module(new RVCExpander)

151
    val isFirstInBlock = i.U === 0.U
152 153
    val isLastInBlock  = (i == PredictWidth - 1).B
    val currentPC      = pcStart + (i << 1).U((log2Ceil(PredictWidth)+1).W)
154
    val currentIsRVC   = isRVC(inst) && HasCExtension.B
155

156
    val lastIsValidEnd =  if (i == 0) { !io.in.lastHalfMatch } else { validEnd(i-1) || isFirstInBlock || !HasCExtension.B }
Y
Yinan Xu 已提交
157

158
    validStart(i)   := (lastIsValidEnd || !HasCExtension.B)
159
    validEnd(i)     := validStart(i) && currentIsRVC || !validStart(i) || !HasCExtension.B
160 161

    val brType::isCall::isRet::Nil = brInfo(inst)
162 163
    val jalOffset = jal_offset(inst, currentIsRVC)
    val brOffset  = br_offset(inst, currentIsRVC)
164

J
JinYue 已提交
165 166 167
    io.out.pd(i).valid         := (lastIsValidEnd || !HasCExtension.B)
    io.out.pd(i).isRVC         := currentIsRVC
    io.out.pd(i).brType        := brType
Y
Yinan Xu 已提交
168
    io.out.pd(i).isCall        := isCall
J
JinYue 已提交
169 170 171
    io.out.pd(i).isRet         := isRet
    io.out.pc(i)               := currentPC
    io.out.crossPageIPF(i)     := (io.out.pc(i) === align(realEndPC, 64) - 2.U) && !pageFault(0) && pageFault(1) && !currentIsRVC
172 173 174
    io.out.pageFault(i)        := hasPageFault    ||  io.out.crossPageIPF(i) 
    io.out.accessFault(i)      := hasAccessFault

J
JinYue 已提交
175 176 177

    expander.io.in             := inst
    io.out.instrs(i)           := expander.io.out.bits
178

J
JinYue 已提交
179
    takens(i)    := (validStart(i)  && (bbTaken && bbOffset === i.U && !io.out.pd(i).notCFI || io.out.pd(i).isJal || io.out.pd(i).isRet))
180

J
JinYue 已提交
181 182
    val jumpTarget      = io.out.pc(i) + Mux(io.out.pd(i).isBr, brOffset, jalOffset)
    targets(i) := Mux(takens(i), jumpTarget, pcEnd)
183
                       //Banch and jal have wrong targets
Y
Yinan Xu 已提交
184
    val targetFault    = (validStart(i)  && i.U === bbOffset && bbTaken && (io.out.pd(i).isBr || io.out.pd(i).isJal) && bbTarget =/= targets(i))
185
                       //An not-CFI instruction is predicted taken
Y
Yinan Xu 已提交
186
    val notCFIFault    = (validStart(i)  && i.U === bbOffset && io.out.pd(i).notCFI && bbTaken)
187
                       //A jal instruction is predicted not taken
188 189
    val jalFault       = (validStart(i)  && !bbTaken && io.out.pd(i).isJal)
                       //A ret instruction is predicted not taken
Y
Yinan Xu 已提交
190
    val retFault       = (validStart(i)  && !bbTaken && io.out.pd(i).isRet)
191
                       //An invalid instruction is predicted taken
J
JinYue 已提交
192
    val invalidInsFault  = (!validStart(i)  && i.U === bbOffset && bbTaken)
193

J
JinYue 已提交
194
    misPred(i)   := targetFault  || notCFIFault || jalFault || retFault || invalidInsFault || pcEndError
J
JinYue 已提交
195 196 197 198
    falseHit(i)  := invalidInsFault || notCFIFault

    realMissPred(i)     := misPred(i) && instRange(i)
    realHasLastHalf(i)  := instValid && currentPC === (realEndPC - 2.U) && validStart(i) && instRange(i) && !currentIsRVC
Y
Yinan Xu 已提交
199
    realTakens(i)       := takens(i) && instRange(i)
200
  }
201

J
JinYue 已提交
202
  val jumpOH                  =  VecInit(io.out.pd.zipWithIndex.map{ case(inst, i) => inst.isJal  && validStart(i) }) //TODO: need jalr?
J
JinYue 已提交
203 204 205 206
  val jumpOffset              =  PriorityEncoder(jumpOH)
  val rvcOH                   =  VecInit(io.out.pd.map(inst => inst.isRVC))
  val jumpPC                  =  io.out.pc(jumpOffset)
  val jumpIsRVC               =  rvcOH(jumpOffset)
207
  val jumpNextPC              =  jumpPC + Mux(jumpIsRVC, 2.U, 4.U)
J
JinYue 已提交
208
  val (hasFalseHit, hasJump)  =  (ParallelOR(falseHit), ParallelOR(jumpOH))
209 210
  val endRange                =  ((Fill(PredictWidth, 1.U(1.W)) >> (~getBasicBlockIdx(realEndPC, pcStart))) | (Fill(PredictWidth, oversize)))
  val takeRange               =  Fill(PredictWidth, !ParallelOR(takens))   | Fill(PredictWidth, 1.U(1.W)) >> (~PriorityEncoder(takens))
211
  val fixCross                =  ((pcStart + (FetchWidth * 4).U) > nextLinePC || (pcStart + (FetchWidth * 4).U) === nextLinePC) && !isDoubleLine
J
JinYue 已提交
212
  val boundPC                 =  Mux(fixCross, nextLinePC - 2.U  ,pcStart + (FetchWidth * 4).U)
J
JinYue 已提交
213

214
  instRange               :=  VecInit((0 until PredictWidth).map(i => endRange(i) &&  takeRange(i)))
J
JinYue 已提交
215
  realEndPC               :=  Mux(hasFalseHit, Mux(hasJump && ((jumpNextPC < boundPC) || (jumpNextPC === boundPC) ), jumpNextPC, boundPC), pcEnd)
J
JinYue 已提交
216

J
JinYue 已提交
217
  val validLastOffset     = Mux(io.out.pd((PredictWidth - 1).U).valid, (PredictWidth - 1).U, (PredictWidth - 2).U)
J
JinYue 已提交
218
  io.out.misOffset.valid  := ParallelOR(realMissPred)
J
JinYue 已提交
219
  io.out.misOffset.bits   := Mux(pcEndError,validLastOffset,PriorityEncoder(realMissPred))
220
  io.out.instrRange.zipWithIndex.map{case (bit,i) => bit := instRange(i).asBool()}
221

J
JinYue 已提交
222 223
  io.out.cfiOffset.valid  := ParallelOR(realTakens)
  io.out.cfiOffset.bits   := PriorityEncoder(realTakens)
224

J
JinYue 已提交
225
  io.out.target           := Mux(io.out.cfiOffset.valid, targets(io.out.cfiOffset.bits), realEndPC)
J
JinYue 已提交
226
  io.out.takens           := realTakens
227

J
JinYue 已提交
228
  io.out.jalTarget        :=  targets(jumpOffset)
229

J
JinYue 已提交
230
  io.out.hasLastHalf      := realHasLastHalf.reduce(_||_)
J
JinYue 已提交
231
  io.out.realEndPC        := realEndPC
232

L
Lingrui98 已提交
233 234 235 236 237 238 239 240 241 242 243
  for (i <- 0 until PredictWidth) {
    XSDebug(true.B,
      p"instr ${Hexadecimal(io.out.instrs(i))}, " +
      p"validStart ${Binary(validStart(i))}, " +
      p"validEnd ${Binary(validEnd(i))}, " +
      p"pc ${Hexadecimal(io.out.pc(i))}, " +
      p"isRVC ${Binary(io.out.pd(i).isRVC)}, " +
      p"brType ${Binary(io.out.pd(i).brType)}, " +
      p"isRet ${Binary(io.out.pd(i).isRet)}, " +
      p"isCall ${Binary(io.out.pd(i).isCall)}\n"
    )
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  }
}

class RVCExpander(implicit p: Parameters) extends XSModule {
  val io = IO(new Bundle {
    val in = Input(UInt(32.W))
    val out = Output(new ExpandedInstruction)
  })

  if (HasCExtension) {
    io.out := new RVCDecoder(io.in, XLEN).decode
  } else {
    io.out := new RVCDecoder(io.in, XLEN).passthrough
  }
}