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