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