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