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 = "andw_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 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 override def fusionName: String = "andw_andi1" 425} 426 427// Case: logic operation and extract its LSB 428class FusedLogiclsb(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 429 extends BaseFusionCase(pair, csPair) { 430 require(csPair.isDefined) 431 432 // the first instruction is a logic 433 def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isLogic(csPair.get(0).fuOpType) 434 def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 1.U 435 436 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 437 def target: CtrlSignals = { 438 val cs = WireInit(csPair.get(0)) 439 // change the opType to lsb format 440 cs.fuOpType := ALUOpType.logicToLSB(csPair.get(0).fuOpType) 441 cs 442 } 443 444 def fusionName: String = "logic_andi1" 445} 446 447// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2) 448// Source: `andi r1, r0, -256`` + `or r1, r1, r2` 449class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 450 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 0xf00.U 451 def inst2Cond = instr(1) === Instructions.OR 452 453 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 454 def target: CtrlSignals = { 455 val cs = getBaseCS(Instructions.OR) 456 // replace the fuOpType with orh48 457 cs.fuOpType := ALUOpType.orh48 458 cs.lsrc(0) := instr1Rs1 459 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 460 cs 461 } 462 463 def fusionName: String = "andi_f00_or" 464} 465 466// Case: mul 7bit data with 32-bit data 467// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2` 468// Target: `mulw7 r1, r0, r2` 469class FusedMulw7(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 470 extends BaseFusionCase(pair, csPair) { 471 require(csPair.isDefined) 472 473 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 127.U 474 def inst2Cond = instr(1) === Instructions.MULW 475 476 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 477 def target: CtrlSignals = { 478 // use MULW as the base 479 val cs = WireInit(csPair.get(1)) 480 // replace the fuOpType with mulw7 481 cs.fuOpType := MDUOpType.mulw7 482 cs.lsrc(0) := instr1Rs1 483 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 484 cs 485 } 486 487 def fusionName: String = "andi127_mulw" 488} 489 490class FusionDecoder(implicit p: Parameters) extends XSModule { 491 val io = IO(new Bundle { 492 // detect instruction fusions in these instructions 493 val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W)))) 494 val dec = Vec(DecodeWidth, Input(new CtrlSignals())) 495 // whether an instruction fusion is found 496 val out = Vec(DecodeWidth - 1, DecoupledIO(new CtrlSignals)) 497 // fused instruction needs to be cleared 498 val clear = Vec(DecodeWidth, Output(Bool())) 499 }) 500 501 io.clear.head := false.B 502 503 val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2)) 504 val csPairs = io.dec.dropRight(1).zip(io.dec.drop(1)).map(x => Seq(x._1, x._2)) 505 instrPairs.zip(csPairs).zip(io.out).zipWithIndex.foreach{ case (((pair, cs), out), i) => 506 val fusionList = Seq( 507 new FusedAdduw(pair), 508 new FusedZexth(pair), 509 new FusedZexth1(pair), 510 new FusedSexth(pair), 511 new FusedSh1add(pair), 512 new FusedSh2add(pair), 513 new FusedSh3add(pair), 514 new FusedSzewl1(pair), 515 new FusedSzewl2(pair), 516 new FusedSzewl3(pair), 517 new FusedByte2(pair), 518 new FusedSh4add(pair), 519 new FusedSr29add(pair), 520 new FusedSr30add(pair), 521 new FusedSr31add(pair), 522 new FusedSr32add(pair), 523 new FusedOddadd(pair), 524 new FusedOddaddw(pair), 525 new FusedAddwbyte(pair, Some(cs)), 526 new FusedAddwbit(pair, Some(cs)), 527 new FusedLogiclsb(pair, Some(cs)), 528 new FusedOrh48(pair), 529 new FusedMulw7(pair, Some(cs)) 530 ) 531 val pairValid = VecInit(pair.map(_.valid)).asUInt().andR 532 val thisCleared = io.clear(i) 533 val fusionVec = VecInit(fusionList.map(_.isValid)) 534 out.valid := pairValid && !thisCleared && fusionVec.asUInt().orR() 535 XSError(PopCount(fusionVec) > 1.U, "more then one fusion matched\n") 536 out.bits := Mux1H(fusionVec, fusionList.map(_.target)) 537 // TODO: assume every instruction fusion clears the second instruction now 538 io.clear(i + 1) := out.valid 539 fusionList.zip(fusionVec).foreach { case (f, v) => 540 XSPerfAccumulate(s"case_${f.fusionName}_$i", pairValid && !thisCleared && v && out.ready) 541 } 542 XSPerfAccumulate(s"conflict_fusion_$i", pairValid && thisCleared && fusionVec.asUInt().orR() && out.ready) 543 } 544 545 XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire))) 546} 547