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