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]], csPair: Option[Seq[CtrlSignals]] = None)(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, csPair) { 397 require(csPair.isDefined) 398 399 // the first instruction is a addw 400 def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isAddw(csPair.get(0).fuOpType) 401 def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 0xff.U 402 403 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 404 def target: CtrlSignals = { 405 val cs = WireInit(csPair.get(0)) 406 // replace the fuOpType with addwbyte 407 cs.fuOpType := ALUOpType.addwbyte 408 cs 409 } 410 411 def fusionName: String = "addw_andi255" 412} 413 414// Case: addw and extract its lower 1 bit (fused into addwbit) 415class FusedAddwbit(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 416 extends FusedAddwbyte(pair, csPair) { 417 418 override def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 0x1.U 419 override def target: CtrlSignals = { 420 val cs = WireInit(csPair.get(0)) 421 // replace the fuOpType with addwbit 422 cs.fuOpType := ALUOpType.addwbit 423 cs 424 } 425 426 override def fusionName: String = "addw_andi1" 427} 428 429// Case: addw and zext.h (fused into addwzexth) 430class FusedAddwzexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 431 extends FusedAddwbyte(pair, csPair) { 432 433 override def inst2Cond = instr(1) === Instructions.ZEXT_H 434 override def target: CtrlSignals = { 435 val cs = WireInit(csPair.get(0)) 436 // replace the fuOpType with addwzexth 437 cs.fuOpType := ALUOpType.addwzexth 438 cs 439 } 440 441 override def fusionName: String = "addw_zexth" 442} 443 444// Case: addw and sext.h (fused into addwsexth) 445class FusedAddwsexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 446 extends FusedAddwbyte(pair, csPair) { 447 448 override def inst2Cond = instr(1) === Instructions.SEXT_H 449 override def target: CtrlSignals = { 450 val cs = WireInit(csPair.get(0)) 451 // replace the fuOpType with addwsexth 452 cs.fuOpType := ALUOpType.addwsexth 453 cs 454 } 455 456 override def fusionName: String = "addw_sexth" 457} 458 459// Case: logic operation and extract its LSB 460class FusedLogiclsb(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 461 extends BaseFusionCase(pair, csPair) { 462 require(csPair.isDefined) 463 464 // the first instruction is a logic 465 def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isSimpleLogic(csPair.get(0).fuOpType) 466 def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 1.U 467 468 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 469 def target: CtrlSignals = { 470 val cs = WireInit(csPair.get(0)) 471 // change the opType to lsb format 472 cs.fuOpType := ALUOpType.logicToLsb(csPair.get(0).fuOpType) 473 cs 474 } 475 476 def fusionName: String = "logic_andi1" 477} 478 479class FusedLogicZexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 480 extends FusedLogiclsb(pair, csPair) { 481 482 override def inst2Cond = instr(1) === Instructions.ZEXT_H 483 override def target: CtrlSignals = { 484 val cs = WireInit(csPair.get(0)) 485 // change the opType to lzext format 486 cs.fuOpType := ALUOpType.logicToZexth(csPair.get(0).fuOpType) 487 cs 488 } 489 490 override def fusionName: String = "logic_zexth" 491} 492 493// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2) 494// Source: `andi r1, r0, -256`` + `or r1, r1, r2` 495class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 496 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 0xf00.U 497 def inst2Cond = instr(1) === Instructions.OR 498 499 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 500 def target: CtrlSignals = { 501 val cs = getBaseCS(Instructions.OR) 502 // replace the fuOpType with orh48 503 cs.fuOpType := ALUOpType.orh48 504 cs.lsrc(0) := instr1Rs1 505 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 506 cs 507 } 508 509 def fusionName: String = "andi_f00_or" 510} 511 512// Case: mul 7bit data with 32-bit data 513// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2` 514// Target: `mulw7 r1, r0, r2` 515class FusedMulw7(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 516 extends BaseFusionCase(pair, csPair) { 517 require(csPair.isDefined) 518 519 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 127.U 520 def inst2Cond = instr(1) === Instructions.MULW 521 522 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 523 def target: CtrlSignals = { 524 // use MULW as the base 525 val cs = WireInit(csPair.get(1)) 526 // replace the fuOpType with mulw7 527 cs.fuOpType := MDUOpType.mulw7 528 cs.lsrc(0) := instr1Rs1 529 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 530 cs 531 } 532 533 def fusionName: String = "andi127_mulw" 534} 535 536class FusionDecoder(implicit p: Parameters) extends XSModule { 537 val io = IO(new Bundle { 538 // detect instruction fusions in these instructions 539 val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W)))) 540 val dec = Vec(DecodeWidth, Input(new CtrlSignals())) 541 // whether an instruction fusion is found 542 val out = Vec(DecodeWidth - 1, DecoupledIO(new CtrlSignals)) 543 // fused instruction needs to be cleared 544 val clear = Vec(DecodeWidth, Output(Bool())) 545 }) 546 547 io.clear.head := false.B 548 549 val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2)) 550 val csPairs = io.dec.dropRight(1).zip(io.dec.drop(1)).map(x => Seq(x._1, x._2)) 551 instrPairs.zip(csPairs).zip(io.out).zipWithIndex.foreach{ case (((pair, cs), out), i) => 552 val fusionList = Seq( 553 new FusedAdduw(pair), 554 new FusedZexth(pair), 555 new FusedZexth1(pair), 556 new FusedSexth(pair), 557 new FusedSh1add(pair), 558 new FusedSh2add(pair), 559 new FusedSh3add(pair), 560 new FusedSzewl1(pair), 561 new FusedSzewl2(pair), 562 new FusedSzewl3(pair), 563 new FusedByte2(pair), 564 new FusedSh4add(pair), 565 new FusedSr29add(pair), 566 new FusedSr30add(pair), 567 new FusedSr31add(pair), 568 new FusedSr32add(pair), 569 new FusedOddadd(pair), 570 new FusedOddaddw(pair), 571 new FusedAddwbyte(pair, Some(cs)), 572 new FusedAddwbit(pair, Some(cs)), 573 new FusedAddwzexth(pair, Some(cs)), 574 new FusedAddwsexth(pair, Some(cs)), 575 new FusedLogiclsb(pair, Some(cs)), 576 new FusedLogicZexth(pair, Some(cs)), 577 new FusedOrh48(pair), 578 new FusedMulw7(pair, Some(cs)) 579 ) 580 val pairValid = VecInit(pair.map(_.valid)).asUInt().andR 581 val thisCleared = io.clear(i) 582 val fusionVec = VecInit(fusionList.map(_.isValid)) 583 out.valid := pairValid && !thisCleared && fusionVec.asUInt().orR() 584 XSError(PopCount(fusionVec) > 1.U, "more then one fusion matched\n") 585 out.bits := Mux1H(fusionVec, fusionList.map(_.target)) 586 // TODO: assume every instruction fusion clears the second instruction now 587 io.clear(i + 1) := out.valid 588 fusionList.zip(fusionVec).foreach { case (f, v) => 589 XSPerfAccumulate(s"case_${f.fusionName}_$i", pairValid && !thisCleared && v && out.ready) 590 } 591 XSPerfAccumulate(s"conflict_fusion_$i", pairValid && thisCleared && fusionVec.asUInt().orR() && out.ready) 592 } 593 594 XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire))) 595} 596