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 chipsalliance.rocketchip.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 49 protected def getInstrTable(pat: BitPat): List[BitPat] = { 50 // Only these instructions can be fused now 51 val allDecodeTable = XDecode.table ++ X64Decode.table ++ BDecode.table 52 allDecodeTable.filter(_._1 == pat).map(_._2).head 53 } 54 // Must sync these indices with MicroOp.decode 55 protected def getInstrFuType(pat: BitPat): BitPat = getInstrTable(pat)(3) 56 protected def getInstrFuOpType(pat: BitPat): BitPat = getInstrTable(pat)(4) 57 protected def getInstrSrc1Type(pat: BitPat): BitPat = getInstrTable(pat)(0) 58 protected def getInstrSrc2Type(pat: BitPat): BitPat = getInstrTable(pat)(1) 59 60 def isValid: Bool 61 // To optimize the timing, only these control signals can be affected by instruction fusion. 62 def thisInstr: Option[BitPat] = None 63 def fusedInstr: Option[BitPat] = None 64 // By default, None means unchanged. 65 private def compareAndGet(func: BitPat => BitPat): Option[Int] = { 66 if (fusedInstr.isDefined) { 67 require(thisInstr.isDefined, "thisInstr must be defined to infer the ctrl signals") 68 val fused = func(fusedInstr.get) 69 // Only when the two instructions have different control field, we make it not None. 70 if (fused != func(thisInstr.get)) Some(fused.value.toInt) else None 71 } else None 72 } 73 // We assume only fuType, fuOpType, lsrc2 may be changed now. 74 def fuType: Option[Int] = compareAndGet(getInstrFuType) 75 def fuOpType: Option[UInt => UInt] = { 76 val t = compareAndGet(getInstrFuOpType) 77 if (t.isDefined) Some((_: UInt) => t.get.U) else None 78 } 79 def src2Type: Option[Int] = compareAndGet(getInstrSrc2Type) 80 def selImm: Option[UInt] = None 81 def imm: 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 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 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 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 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 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 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 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 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 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 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 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 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 override def imm: Option[UInt] = Some(Cat(instr(0)(31, 12), instr(1)(31, 20))) 483 484 def fusionName: String = "lui_addi" 485 486 XSDebug(isValid, p"[fusedLui32] ${Hexadecimal(imm.get)} instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n") 487} 488 489class FusionDecodeInfo extends Bundle { 490 val rs2FromRs1 = Output(Bool()) 491 val rs2FromRs2 = Output(Bool()) 492 val rs2FromZero = Output(Bool()) 493} 494 495class FusionDecodeReplace extends Bundle { 496 val fuType = Valid(FuType()) 497 val fuOpType = Valid(FuOpType()) 498 val lsrc2 = Valid(UInt(6.W)) 499 val src2Type = Valid(SrcType()) 500 val selImm = Valid(SelImm()) 501 val imm = Valid(UInt(ImmUnion.maxLen.W)) 502 503 def update(cs: DecodedInst): Unit = { 504 when (fuType.valid) { 505 cs.fuType := fuType.bits 506 } 507 when (fuOpType.valid) { 508 cs.fuOpType := fuOpType.bits 509 } 510 when (lsrc2.valid) { 511 cs.lsrc(1) := lsrc2.bits 512 } 513 when (src2Type.valid) { 514 cs.srcType(1) := src2Type.bits 515 } 516 when (selImm.valid) { 517 cs.selImm := selImm.bits 518 } 519 when (imm.valid) { 520 cs.imm := imm.bits 521 } 522 } 523} 524 525class FusionDecoder(implicit p: Parameters) extends XSModule { 526 val io = IO(new Bundle { 527 // T0: detect instruction fusions in these instructions 528 val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W)))) 529 val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1) 530 // T1: decode result 531 val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1) 532 // T1: whether an instruction fusion is found 533 val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1) 534 val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1) 535 // T1: fused instruction needs to be cleared 536 val clear = Vec(DecodeWidth, Output(Bool())) 537 }) 538 539 io.clear.head := false.B 540 541 val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2)) 542 instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) => 543 val fusionList = Seq( 544 new FusedAdduw(pair), 545 new FusedZexth(pair), 546 new FusedZexth1(pair), 547 new FusedSexth(pair), 548 new FusedSh1add(pair), 549 new FusedSh2add(pair), 550 new FusedSh3add(pair), 551 new FusedSzewl1(pair), 552 new FusedSzewl2(pair), 553 new FusedSzewl3(pair), 554 new FusedByte2(pair), 555 new FusedSh4add(pair), 556 new FusedSr29add(pair), 557 new FusedSr30add(pair), 558 new FusedSr31add(pair), 559 new FusedSr32add(pair), 560 new FusedOddadd(pair), 561 new FusedOddaddw(pair), 562 new FusedOrh48(pair), 563 new FusedMulw7(pair), 564 new FusedAddwbyte(pair), 565 new FusedAddwbit(pair), 566 new FusedAddwzexth(pair), 567 new FusedAddwsexth(pair), 568 new FusedLogiclsb(pair), 569 new FusedLogicZexth(pair), 570 new FusedLui32(pair) 571 ) 572 val fire = io.in(i).valid && io.inReady(i) 573 val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i)) 574 val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire) 575 val thisCleared = io.clear(i) 576 out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR 577 XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n") 578 def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = { 579 field(out.bits).valid := false.B 580 field(out.bits).bits := DontCare 581 val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined) 582 if (replaceVec.nonEmpty) { 583 // constant values are grouped together for better timing. 584 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 585 val replTypes = replaceVec.map(_._2.get).distinct 586 val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR) 587 field(out.bits).valid := replEnable 588 field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U)) 589 } 590 } 591 def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = { 592 field(out.bits).valid := false.B 593 field(out.bits).bits := DontCare 594 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)) 595 if (replaceVec.nonEmpty) { 596 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 597 val replTypes = replaceVec.map(_._2).distinct 598 val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR) 599 field(out.bits).valid := replEnable 600 field(out.bits).bits := Mux1H(replSel, replTypes) 601 } 602 } 603 def connectByUIntFunc( 604 field: FusionDecodeReplace => Valid[UInt], 605 csField: DecodedInst => UInt, 606 replace: Seq[Option[UInt => UInt]] 607 ): Unit = { 608 field(out.bits).valid := false.B 609 field(out.bits).bits := DontCare 610 val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec)))) 611 if (replaceVec.nonEmpty) { 612 val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR 613 // constant values are grouped together for better timing. 614 val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue)) 615 val constReplTypes = constReplVec.map(_._2).distinct 616 val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR) 617 val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U)) 618 // non-constant values have to be processed naively. 619 val noLitRepl = replaceVec.filterNot(_._2.isLit) 620 field(out.bits).valid := replEnable 621 field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult) 622 } 623 } 624 connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType)) 625 connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType)) 626 connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type)) 627 connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false) 628 connectByUInt((x: FusionDecodeReplace) => x.imm, fusionList.map(_.imm), true) 629 val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR 630 val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR 631 io.info(i).rs2FromZero := src2WithZero 632 io.info(i).rs2FromRs1 := src2WithMux && !RegEnable(fusionList.head.destToRs1, fire) 633 io.info(i).rs2FromRs2 := src2WithMux && RegEnable(fusionList.head.destToRs1, fire) 634 out.bits.lsrc2.valid := src2WithMux || src2WithZero 635 when (src2WithMux) { 636 out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire) 637 }.otherwise {//elsewhen (src2WithZero) { 638 out.bits.lsrc2.bits := 0.U 639 } 640 // TODO: assume every instruction fusion clears the second instruction now 641 io.clear(i + 1) := out.valid 642 val lastFire = RegNext(fire) 643 fusionList.zip(fusionVec).foreach { case (f, v) => 644 XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire) 645 } 646 XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire) 647 648 XSDebug(out.valid, p"[fusion] valid ${i}, outvalid: ${out.bits.fuType.valid} ${out.bits.fuOpType.valid} ${out.bits.src2Type.valid} ${out.bits.lsrc2.valid} ${out.bits.selImm.valid} ${out.bits.imm.valid}\n") 649 XSDebug(out.valid, p"[fusion] valid ${i}, outbits: ${out.bits.fuType.bits} ${out.bits.fuOpType.bits} ${out.bits.src2Type.bits} ${out.bits.lsrc2.bits} ${out.bits.selImm.bits} ${Hexadecimal(out.bits.imm.bits)}\n") 650 } 651 652 XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire))) 653} 654