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