1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.backend.decode 18 19import org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import freechips.rocketchip.rocket.Instructions 23import utility._ 24import utils._ 25import xiangshan._ 26import xiangshan.backend.fu.FuType 27import xiangshan.backend.Bundles.DecodedInst 28import xiangshan.backend.decode.isa.bitfield.XSInstBitFields 29 30abstract class BaseFusionCase(pair: Seq[Valid[UInt]])(implicit p: Parameters) 31 extends DecodeUnitConstants { 32 require(pair.length == 2) 33 34 protected val inst1: XSInstBitFields = instr(0).asTypeOf(new XSInstBitFields) 35 protected val inst2: XSInstBitFields = instr(1).asTypeOf(new XSInstBitFields) 36 37 protected def instr: Seq[UInt] = pair.map(_.bits) 38 protected def pairValid: Bool = VecInit(pair.map(_.valid)).asUInt.andR 39 protected def instr1Rs1: UInt = inst1.RS1 40 protected def instr1Rs2: UInt = inst1.RS2 41 protected def instr1Rd: UInt = inst1.RD 42 def instr2Rs1: UInt = inst2.RS1 43 def instr2Rs2: UInt = inst2.RS2 44 protected def instr2Rd: UInt = inst2.RD 45 protected def withSameDest: Bool = instr1Rd === instr2Rd 46 def destToRs1: Bool = instr1Rd === instr2Rs1 47 protected def destToRs2: Bool = instr1Rd === instr2Rs2 48 protected def instr2Rs1ToRs2: Bool = instr2Rs1 === instr2Rs2 49 50 protected def getInstrTable(pat: BitPat): List[BitPat] = { 51 // Only these instructions can be fused now 52 val allDecodeTable = XDecode.table ++ BitmanipDecode.table ++ ScalarCryptoDecode.table 53 allDecodeTable.filter(_._1 == pat).map(_._2).head 54 } 55 // Must sync these indices with MicroOp.decode 56 protected def getInstrFuType(pat: BitPat): BitPat = getInstrTable(pat)(3) 57 protected def getInstrFuOpType(pat: BitPat): BitPat = getInstrTable(pat)(4) 58 protected def getInstrSrc1Type(pat: BitPat): BitPat = getInstrTable(pat)(0) 59 protected def getInstrSrc2Type(pat: BitPat): BitPat = getInstrTable(pat)(1) 60 61 def isValid: Bool 62 // To optimize the timing, only these control signals can be affected by instruction fusion. 63 def thisInstr: Option[BitPat] = None 64 def fusedInstr: Option[BitPat] = None 65 // By default, None means unchanged. 66 private def compareAndGet(func: BitPat => BitPat): Option[Int] = { 67 if (fusedInstr.isDefined) { 68 require(thisInstr.isDefined, "thisInstr must be defined to infer the ctrl signals") 69 val fused = func(fusedInstr.get) 70 // Only when the two instructions have different control field, we make it not None. 71 if (fused != func(thisInstr.get)) Some(fused.value.toInt) else None 72 } else None 73 } 74 // We assume only fuType, fuOpType, lsrc2 may be changed now. 75 def fuType: Option[Int] = compareAndGet(getInstrFuType) 76 def fuOpType: Option[UInt => UInt] = { 77 val t = compareAndGet(getInstrFuOpType) 78 if (t.isDefined) Some((_: UInt) => t.get.U) else None 79 } 80 def src2Type: Option[Int] = compareAndGet(getInstrSrc2Type) 81 def selImm: Option[UInt] = None 82 def lsrc2NeedZero: Boolean = false 83 def lsrc2NeedMux: Boolean = false 84 def lsrc2MuxResult: UInt = Mux(destToRs1, instr2Rs2, instr2Rs1) 85 86 def fusionName: String 87} 88 89// There are 2 types of instruction fusion. 90// (1) fused into a fixed new instruction with new control signals. 91// (2) the first instruction's op is replaced with another one. 92 93// Case: clear upper 32 bits / get lower 32 bits 94// Source: `slli r1, r0, 32` + `srli r1, r1, 32` 95// Target: `add.uw r1, r0, zero` (pseudo instruction: `zext.w r1, r0`) 96class FusedAdduw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 97 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U 98 def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 32.U 99 100 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 101 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 102 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD_UW) 103 override def lsrc2NeedZero: Boolean = true 104 105 def fusionName: String = "slli32_srli32" 106} 107 108// Case: clear upper 48 bits / get lower 16 bits 109// Source: `slli r1, r0, 48` + `srli r1, r1, 48` 110// Target: `zext.h r1, r0` 111class FusedZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 112 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 48.U 113 def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 48.U 114 115 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 116 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 117 override def fusedInstr: Option[BitPat] = Some(Instructions.PACKW) 118 override def lsrc2NeedZero: Boolean = true 119 120 def fusionName: String = "slli48_srli48" 121} 122 123// Another case of Zext.h 124// Source: `slliw r1, r0, 16` + `srliw r1, r1, 16` 125// Target: `zext.h r1, r0` 126class FusedZexth1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends FusedZexth(pair) { 127 override def inst1Cond: Bool = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U 128 override def inst2Cond: Bool = instr(1) === Instructions.SRLIW && inst2.SHAMT5 === 16.U 129 130 override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW) 131 132 override def fusionName: String = "slliw16_srliw16" 133} 134 135// Case: sign-extend a 16-bit number 136// Source: `slliw r1, r0, 16` + `sraiw r1, r1, 16` 137// Target: `sext.h r1, r0` 138class FusedSexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 139 def inst1Cond = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U 140 def inst2Cond = instr(1) === Instructions.SRAIW && inst2.SHAMT5 === 16.U 141 142 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 143 override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW) 144 override def fusedInstr: Option[BitPat] = Some(Instructions.SEXT_H) 145 override def lsrc2NeedZero: Boolean = true 146 147 def fusionName: String = "slliw16_sraiw16" 148} 149 150// Case: shift left by one and add 151// Source: `slli r1, r0, 1` + `add r1, r1, r2` 152// Target: `sh1add r1, r0, r2` 153class FusedSh1add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 154 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 1.U 155 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 156 157 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 158 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 159 override def fusedInstr: Option[BitPat] = Some(Instructions.SH1ADD) 160 override def lsrc2NeedMux: Boolean = true 161 162 def fusionName: String = "slli1_add" 163} 164 165// Case: shift left by two and add 166// Source: `slli r1, r0, 2` + `add r1, r1, r2` 167// Target: `sh2add r1, r0, r2` 168class FusedSh2add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 169 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 2.U 170 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 171 172 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 173 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 174 override def fusedInstr: Option[BitPat] = Some(Instructions.SH2ADD) 175 override def lsrc2NeedMux: Boolean = true 176 177 def fusionName: String = "slli2_add" 178} 179 180// Case: shift left by three and add 181// Source: `slli r1, r0, 3` + `add r1, r1, r2` 182// Target: `sh3add r1, r0, r2` 183class FusedSh3add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 184 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 3.U 185 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 186 187 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 188 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 189 override def fusedInstr: Option[BitPat] = Some(Instructions.SH3ADD) 190 override def lsrc2NeedMux: Boolean = true 191 192 def fusionName: String = "slli3_add" 193} 194 195// Case: shift zero-extended word left by one 196// Source: `slli r1, r0, 32` + `srli r1, r1, 31` 197// Target: `szewl1 r1, r0` (customized internal opcode) 198class FusedSzewl1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 199 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U 200 def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 31.U 201 202 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 203 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl1) 204 205 def fusionName: String = "slli32_srli31" 206} 207 208// Case: shift zero-extended word left by two 209// Source: `slli r1, r0, 32` + `srli r1, r1, 30` 210// Target: `szewl2 r1, r0` (customized internal opcode) 211class FusedSzewl2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 212 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U 213 def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 30.U 214 215 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 216 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl2) 217 218 def fusionName: String = "slli32_srli30" 219} 220 221// Case: shift zero-extended word left by three 222// Source: `slli r1, r0, 32` + `srli r1, r1, 29` 223// Target: `szewl3 r1, r0` (customized internal opcode) 224class FusedSzewl3(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 225 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U 226 def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 29.U 227 228 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 229 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl3) 230 231 def fusionName: String = "slli32_srli29" 232} 233 234// Case: get the second byte 235// Source: `srli r1, r0, 8` + `andi r1, r1, 255` 236// Target: `byte2 r1, r0` (customized internal opcode) 237class FusedByte2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 238 def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 8.U 239 def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 255.U 240 241 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 242 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.byte2) 243 244 def fusionName: String = "srli8_andi255" 245} 246 247// Case: shift left by four and add 248// Source: `slli r1, r0, 4` + `add r1, r1, r2` 249// Target: `sh4add r1, r0, r2` (customized internal opcode) 250class FusedSh4add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 251 def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 4.U 252 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 253 254 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 255 override def thisInstr: Option[BitPat] = Some(Instructions.SLLI) 256 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 257 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sh4add) 258 override def lsrc2NeedMux: Boolean = true 259 260 def fusionName: String = "slli4_add" 261} 262 263// Case: shift right by 29 and add 264// Source: `srli r1, r0, 29` + `add r1, r1, r2` 265// Target: `sr29add r1, r0, r2` (customized internal opcode) 266class FusedSr29add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 267 def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 29.U 268 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 269 270 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 271 override def thisInstr: Option[BitPat] = Some(Instructions.SRLI) 272 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 273 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr29add) 274 override def lsrc2NeedMux: Boolean = true 275 276 def fusionName: String = "srli29_add" 277} 278 279// Case: shift right by 30 and add 280// Source: `srli r1, r0, 30` + `add r1, r1, r2` 281// Target: `sr30add r1, r0, r2` (customized internal opcode) 282class FusedSr30add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 283 def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 30.U 284 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 285 286 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 287 override def thisInstr: Option[BitPat] = Some(Instructions.SRLI) 288 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 289 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr30add) 290 override def lsrc2NeedMux: Boolean = true 291 292 def fusionName: String = "srli30_add" 293} 294 295// Case: shift right by 31 and add 296// Source: `srli r1, r0, 31` + `add r1, r1, r2` 297// Target: `sr31add r1, r0, r2` (customized internal opcode) 298class FusedSr31add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 299 def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 31.U 300 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 301 302 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 303 override def thisInstr: Option[BitPat] = Some(Instructions.SRLI) 304 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 305 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr31add) 306 override def lsrc2NeedMux: Boolean = true 307 308 def fusionName: String = "srli31_add" 309} 310 311// Case: shift right by 32 and add 312// Source: `srli r1, r0, 32` + `add r1, r1, r2` 313// Target: `sr32add r1, r0, r2` (customized internal opcode) 314class FusedSr32add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 315 def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 32.U 316 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 317 318 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 319 override def thisInstr: Option[BitPat] = Some(Instructions.SRLI) 320 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 321 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr32add) 322 override def lsrc2NeedMux: Boolean = true 323 324 def fusionName: String = "srli32_add" 325} 326 327// Case: add one if odd, otherwise unchanged 328// Source: `andi r1, r0, 1`` + `add r1, r1, r2` 329// Target: `oddadd r1, r0, r2` (customized internal opcode) 330class FusedOddadd(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 331 def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U 332 def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2 333 334 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 335 override def thisInstr: Option[BitPat] = Some(Instructions.ANDI) 336 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 337 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddadd) 338 override def lsrc2NeedMux: Boolean = true 339 340 def fusionName: String = "andi1_add" 341} 342 343// Case: add one if odd (in word format), otherwise unchanged 344// Source: `andi r1, r0, 1`` + `addw r1, r1, r2` 345// Target: `oddaddw r1, r0, r2` (customized internal opcode) 346class FusedOddaddw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 347 def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U 348 def inst2Cond = instr(1) === Instructions.ADDW && !instr2Rs1ToRs2 349 350 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 351 override def thisInstr: Option[BitPat] = Some(Instructions.ANDI) 352 override def fusedInstr: Option[BitPat] = Some(Instructions.ADD) 353 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddaddw) 354 override def lsrc2NeedMux: Boolean = true 355 356 def fusionName: String = "andi1_addw" 357} 358 359// Case: addw and extract its lower 8 bits (fused into addwbyte) 360class FusedAddwbyte(pair: Seq[Valid[UInt]])(implicit p: Parameters) 361 extends BaseFusionCase(pair) { 362 // the first instruction is a ALUOpType.addw 363 // According to DecodeUnit.scala, only ADDIW and ADDW are ALUOpType.addw, which are used for inst1Cond. 364 def inst1Cond = instr(0) === Instructions.ADDIW || instr(0) === Instructions.ADDW 365 def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0xff.U 366 367 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 368 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbyte) 369 370 def fusionName: String = "addw_andi255" 371} 372 373// Case: addw and extract its lower 1 bit (fused into addwbit) 374class FusedAddwbit(pair: Seq[Valid[UInt]])(implicit p: Parameters) 375 extends FusedAddwbyte(pair) { 376 377 override def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0x1.U 378 379 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbit) 380 381 override def fusionName: String = "addw_andi1" 382} 383 384// Case: addw and zext.h (fused into addwzexth) 385class FusedAddwzexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) 386 extends FusedAddwbyte(pair) { 387 388 override def inst2Cond = instr(1) === Instructions.ZEXT_H 389 390 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwzexth) 391 392 override def fusionName: String = "addw_zexth" 393} 394 395// Case: addw and sext.h (fused into addwsexth) 396class FusedAddwsexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) 397 extends FusedAddwbyte(pair) { 398 399 override def inst2Cond = instr(1) === Instructions.SEXT_H 400 401 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwsexth) 402 403 override def fusionName: String = "addw_sexth" 404} 405 406// Case: logic operation and extract its LSB 407 408class FusedLogiclsb(pair: Seq[Valid[UInt]])(implicit p: Parameters) 409 extends BaseFusionCase(pair) { 410 // the first instruction is a logic (and, or, xor, orcb) 411 // (1) def ANDI = BitPat("b?????????????????111?????0010011") 412 // (2) def AND = BitPat("b0000000??????????111?????0110011") 413 // (3) def ORI = BitPat("b?????????????????110?????0010011") 414 // (4) def OR = BitPat("b0000000??????????110?????0110011") 415 // (5) def XORI = BitPat("b?????????????????100?????0010011") 416 // (6) def XOR = BitPat("b0000000??????????100?????0110011") 417 // (7) def ORC_B = BitPat("b001010000111?????101?????0010011") 418 val logicInstrList = Seq(Instructions.ANDI, Instructions.AND, Instructions.ORI, Instructions.OR, 419 Instructions.XORI, Instructions.XOR, Instructions.ORC_B) 420 def inst1Cond = VecInit(logicInstrList.map(_ === instr(0))).asUInt.orR 421 def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 1.U 422 423 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 424 override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToLsb) 425 426 def fusionName: String = "logic_andi1" 427} 428 429class FusedLogicZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) 430 extends FusedLogiclsb(pair) { 431 432 override def inst2Cond = instr(1) === Instructions.ZEXT_H 433 override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToZexth) 434 435 override def fusionName: String = "logic_zexth" 436} 437 438// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2) 439// Source: `andi r1, r0, -256`` + `or r1, r1, r2` 440class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 441 def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 0xf00.U 442 def inst2Cond = instr(1) === Instructions.OR && !instr2Rs1ToRs2 443 444 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 445 override def thisInstr: Option[BitPat] = Some(Instructions.ANDI) 446 override def fusedInstr: Option[BitPat] = Some(Instructions.OR) 447 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.orh48) 448 override def lsrc2NeedMux: Boolean = true 449 450 def fusionName: String = "andi_f00_or" 451} 452 453// Case: mul 7bit data with 32-bit data 454// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2` 455// Target: `mulw7 r1, r0, r2` 456class FusedMulw7(pair: Seq[Valid[UInt]])(implicit p: Parameters) 457 extends BaseFusionCase(pair) { 458 def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 127.U 459 def inst2Cond = instr(1) === Instructions.MULW && !instr2Rs1ToRs2 460 461 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 462 override def thisInstr: Option[BitPat] = Some(Instructions.ANDI) 463 override def fusedInstr: Option[BitPat] = Some(Instructions.MULW) 464 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => MDUOpType.mulw7) 465 override def lsrc2NeedMux: Boolean = true 466 467 def fusionName: String = "andi127_mulw" 468} 469 470// Case: get 32 bits imm 471// Source: `lui r1, 0xffffa`` + `addi r1, r1, 1` 472// Target: `lui32 r1, 0xffffa001` (customized internal opcode) 473class FusedLui32(pair: Seq[Valid[UInt]])(implicit p: Parameters) 474 extends BaseFusionCase(pair) { 475 def inst1Cond = instr(0) === Instructions.LUI 476 def inst2Cond = instr(1) === Instructions.ADDI 477 478 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 479 480 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32add) 481 override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32) 482 483 def fusionName: String = "lui_addi" 484 485 XSDebug(isValid, p"[fusedLui32] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n") 486} 487 488// Case: get 32 bits imm (in word format) 489// Source: `lui r1, 0xffffa`` + `addiw r1, r1, 1` 490// Target: `lui32 r1, 0xffffa001` (customized internal opcode) 491class FusedLui32w(pair: Seq[Valid[UInt]])(implicit p: Parameters) 492 extends BaseFusionCase(pair) { 493 def inst1Cond = instr(0) === Instructions.LUI 494 def inst2Cond = instr(1) === Instructions.ADDIW 495 496 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 497 498 override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32addw) 499 override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32) 500 501 def fusionName: String = "lui_addiw" 502 503 XSDebug(isValid, p"[fusedLui32w] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n") 504} 505 506class FusionDecodeInfo extends Bundle { 507 val rs2FromRs1 = Output(Bool()) 508 val rs2FromRs2 = Output(Bool()) 509 val rs2FromZero = Output(Bool()) 510} 511 512class FusionDecodeReplace(implicit p: Parameters) extends XSBundle { 513 val fuType = Valid(FuType()) 514 val fuOpType = Valid(FuOpType()) 515 val lsrc2 = Valid(UInt(LogicRegsWidth.W)) 516 val src2Type = Valid(SrcType()) 517 val selImm = Valid(SelImm()) 518 519 def update(cs: DecodedInst): Unit = { 520 when (fuType.valid) { 521 cs.fuType := fuType.bits 522 } 523 when (fuOpType.valid) { 524 cs.fuOpType := fuOpType.bits 525 } 526 when (lsrc2.valid) { 527 cs.lsrc(1) := lsrc2.bits 528 } 529 when (src2Type.valid) { 530 cs.srcType(1) := src2Type.bits 531 } 532 when (selImm.valid) { 533 cs.selImm := selImm.bits 534 } 535 } 536} 537 538class FusionDecoder(implicit p: Parameters) extends XSModule { 539 val io = IO(new Bundle { 540 val disableFusion = Input(Bool()) 541 // T0: detect instruction fusions in these instructions 542 val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W)))) 543 val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1) 544 // T1: decode result 545 val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1) 546 // T1: whether an instruction fusion is found 547 val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1) 548 val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1) 549 // T1: fused instruction needs to be cleared 550 val clear = Vec(DecodeWidth, Output(Bool())) 551 }) 552 553 io.clear.head := false.B 554 555 val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2)) 556 instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) => 557 val fusionList = Seq( 558 new FusedAdduw(pair), 559 new FusedZexth(pair), 560 new FusedZexth1(pair), 561 new FusedSexth(pair), 562 new FusedSh1add(pair), 563 new FusedSh2add(pair), 564 new FusedSh3add(pair), 565 new FusedSzewl1(pair), 566 new FusedSzewl2(pair), 567 new FusedSzewl3(pair), 568 new FusedByte2(pair), 569 new FusedSh4add(pair), 570 new FusedSr29add(pair), 571 new FusedSr30add(pair), 572 new FusedSr31add(pair), 573 new FusedSr32add(pair), 574 new FusedOddadd(pair), 575 new FusedOddaddw(pair), 576 new FusedOrh48(pair), 577 new FusedMulw7(pair), 578 new FusedAddwbyte(pair), 579 new FusedAddwbit(pair), 580 new FusedAddwzexth(pair), 581 new FusedAddwsexth(pair), 582 new FusedLogiclsb(pair), 583 new FusedLogicZexth(pair), 584 new FusedLui32(pair), 585 new FusedLui32w(pair) 586 ) 587 val fire = io.in(i).valid && io.inReady(i) 588 val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i)) 589 val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire) 590 // HINT instructions are not considered for fusion. 591 // NOTE: The RD of some FENCE instructions are not 0, but they are also HINT instructions. 592 // However, as FENCE instructions can never be fused, we do not need to consider them. 593 val notHint = RegEnable(VecInit(pair.map(_.bits(11, 7) =/= 0.U)).asUInt.andR, fire) 594 val enabled = RegEnable(!io.disableFusion, fire) 595 val thisCleared = io.clear(i) 596 out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR && notHint && enabled 597 XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n") 598 def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = { 599 field(out.bits).valid := false.B 600 field(out.bits).bits := DontCare 601 val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined) 602 if (replaceVec.nonEmpty) { 603 // constant values are grouped together for better timing. 604 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 605 val replTypes = replaceVec.map(_._2.get).distinct 606 val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR) 607 field(out.bits).valid := replEnable 608 field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U)) 609 } 610 } 611 def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = { 612 field(out.bits).valid := false.B 613 field(out.bits).bits := DontCare 614 val replaceVec = if (needReg) fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, RegEnable(x._2.get, fire))) else fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get)) 615 if (replaceVec.nonEmpty) { 616 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 617 val replTypes = replaceVec.map(_._2).distinct 618 val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR) 619 field(out.bits).valid := replEnable 620 field(out.bits).bits := Mux1H(replSel, replTypes) 621 } 622 } 623 def connectByUIntFunc( 624 field: FusionDecodeReplace => Valid[UInt], 625 csField: DecodedInst => UInt, 626 replace: Seq[Option[UInt => UInt]] 627 ): Unit = { 628 field(out.bits).valid := false.B 629 field(out.bits).bits := DontCare 630 val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec)))) 631 if (replaceVec.nonEmpty) { 632 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 633 // constant values are grouped together for better timing. 634 val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue)) 635 val constReplTypes = constReplVec.map(_._2).distinct 636 val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR) 637 val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U)) 638 // non-constant values have to be processed naively. 639 val noLitRepl = replaceVec.filterNot(_._2.isLit) 640 field(out.bits).valid := replEnable 641 field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult) 642 } 643 } 644 connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType)) 645 connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType)) 646 connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type)) 647 connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false) 648 649 val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR 650 val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR 651 io.info(i).rs2FromZero := enabled && src2WithZero 652 io.info(i).rs2FromRs1 := enabled && src2WithMux && !RegEnable(fusionList.head.destToRs1, fire) 653 io.info(i).rs2FromRs2 := enabled && src2WithMux && RegEnable(fusionList.head.destToRs1, fire) 654 out.bits.lsrc2.valid := enabled && (src2WithMux || src2WithZero) 655 when (src2WithMux) { 656 out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire) 657 }.otherwise {//elsewhen (src2WithZero) { 658 out.bits.lsrc2.bits := 0.U 659 } 660 // TODO: assume every instruction fusion clears the second instruction now 661 io.clear(i + 1) := out.valid 662 val lastFire = RegNext(fire) 663 fusionList.zip(fusionVec).foreach { case (f, v) => 664 XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire) 665 } 666 XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire) 667 } 668 669 XSPerfAccumulate("fused_instr", PopCount(io.out.zipWithIndex.map{ case (x, i) => x.valid && RegNext(io.in(i).valid && io.inReady(i)) })) 670} 671