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