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