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