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.ZEXT_H) 89 cs.lsrc(0) := instr1Rs1 90 cs 91 } 92 93 def fusionName: String = "slli48_srli48" 94} 95 96// Another case of Zext.h 97// Source: `slliw r1, r0, 16` + `srliw r1, r1, 16` 98// Target: `zext.h r1, r0` 99class FusedZexth1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends FusedZexth(pair) { 100 override def inst1Cond: Bool = instr(0) === Instructions.SLLIW && instr(0)(24, 20) === 16.U 101 override def inst2Cond: Bool = instr(1) === Instructions.SRLIW && instr(1)(24, 20) === 16.U 102 103 override def fusionName: String = "slliw16_srliw16" 104} 105 106// Case: sign-extend a 16-bit number 107// Source: `slliw r1, r0, 16` + `sraiw r1, r1, 16` 108// Target: `sext.h r1, r0` 109class FusedSexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 110 def inst1Cond = instr(0) === Instructions.SLLIW && instr(0)(24, 20) === 16.U 111 def inst2Cond = instr(1) === Instructions.SRAIW && instr(1)(24, 20) === 16.U 112 113 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 114 def target: CtrlSignals = { 115 val cs = getBaseCS(Instructions.SEXT_H) 116 cs.lsrc(0) := instr1Rs1 117 cs 118 } 119 120 def fusionName: String = "slliw16_sraiw16" 121} 122 123// Case: shift left by one and add 124// Source: `slli r1, r0, 1` + `add r1, r1, r2` 125// Target: `sh1add r1, r0, r2` 126class FusedSh1add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 127 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 1.U 128 def inst2Cond = instr(1) === Instructions.ADD 129 130 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 131 def target: CtrlSignals = { 132 val cs = getBaseCS(Instructions.SH1ADD) 133 cs.lsrc(0) := instr1Rs1 134 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 135 cs 136 } 137 138 def fusionName: String = "slli1_add" 139} 140 141// Case: shift left by two and add 142// Source: `slli r1, r0, 2` + `add r1, r1, r2` 143// Target: `sh2add r1, r0, r2` 144class FusedSh2add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 145 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 2.U 146 def inst2Cond = instr(1) === Instructions.ADD 147 148 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 149 def target: CtrlSignals = { 150 val cs = getBaseCS(Instructions.SH2ADD) 151 cs.lsrc(0) := instr1Rs1 152 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 153 cs 154 } 155 156 def fusionName: String = "slli2_add" 157} 158 159// Case: shift left by three and add 160// Source: `slli r1, r0, 3` + `add r1, r1, r2` 161// Target: `sh3add r1, r0, r2` 162class FusedSh3add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 163 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 3.U 164 def inst2Cond = instr(1) === Instructions.ADD 165 166 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 167 def target: CtrlSignals = { 168 val cs = getBaseCS(Instructions.SH3ADD) 169 cs.lsrc(0) := instr1Rs1 170 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 171 cs 172 } 173 174 def fusionName: String = "slli3_add" 175} 176 177// Case: shift zero-extended word left by one 178// Source: `slli r1, r0, 32` + `srli r1, r0, 31` 179// Target: `szewl1 r1, r0` (customized internal opcode) 180class FusedSzewl1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 181 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U 182 def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 31.U 183 184 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 185 def target: CtrlSignals = { 186 val cs = getBaseCS(Instructions.ZEXT_H) 187 // replace the fuOpType with szewl1 188 cs.fuOpType := ALUOpType.szewl1 189 cs.lsrc(0) := instr1Rs1 190 cs 191 } 192 193 def fusionName: String = "slli32_srli31" 194} 195 196// Case: shift zero-extended word left by two 197// Source: `slli r1, r0, 32` + `srli r1, r0, 30` 198// Target: `szewl2 r1, r0` (customized internal opcode) 199class FusedSzewl2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 200 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U 201 def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 30.U 202 203 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 204 def target: CtrlSignals = { 205 val cs = getBaseCS(Instructions.ZEXT_H) 206 // replace the fuOpType with szewl2 207 cs.fuOpType := ALUOpType.szewl2 208 cs.lsrc(0) := instr1Rs1 209 cs 210 } 211 212 def fusionName: String = "slli32_srli30" 213} 214 215// Case: shift zero-extended word left by three 216// Source: `slli r1, r0, 32` + `srli r1, r0, 29` 217// Target: `szewl3 r1, r0` (customized internal opcode) 218class FusedSzewl3(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 219 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U 220 def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 29.U 221 222 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 223 def target: CtrlSignals = { 224 val cs = getBaseCS(Instructions.ZEXT_H) 225 // replace the fuOpType with szewl3 226 cs.fuOpType := ALUOpType.szewl3 227 cs.lsrc(0) := instr1Rs1 228 cs 229 } 230 231 def fusionName: String = "slli32_srli29" 232} 233 234// Case: get the second byte 235// Source: `srli r1, r0, 8` + `andi r1, r1, 255` 236// Target: `byte2 r1, r0` (customized internal opcode) 237class FusedByte2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 238 def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 8.U 239 def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 255.U 240 241 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 242 def target: CtrlSignals = { 243 val cs = getBaseCS(Instructions.ZEXT_H) 244 // replace the fuOpType with byte2 245 cs.fuOpType := ALUOpType.byte2 246 cs.lsrc(0) := instr1Rs1 247 cs 248 } 249 250 def fusionName: String = "srli8_andi255" 251} 252 253// Case: shift left by four and add 254// Source: `slli r1, r0, 4` + `add r1, r1, r2` 255// Target: `sh4add r1, r0, r2` (customized internal opcode) 256class FusedSh4add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 257 def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 4.U 258 def inst2Cond = instr(1) === Instructions.ADD 259 260 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 261 def target: CtrlSignals = { 262 val cs = getBaseCS(Instructions.SH3ADD) 263 // replace the fuOpType with sh4add 264 cs.fuOpType := ALUOpType.sh4add 265 cs.lsrc(0) := instr1Rs1 266 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 267 cs 268 } 269 270 def fusionName: String = "slli4_add" 271} 272 273// Case: shift right by 29 and add 274// Source: `srli r1, r0, 29` + `add r1, r1, r2` 275// Target: `sr29add r1, r0, r2` (customized internal opcode) 276class FusedSr29add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 277 def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 29.U 278 def inst2Cond = instr(1) === Instructions.ADD 279 280 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 281 def target: CtrlSignals = { 282 val cs = getBaseCS(Instructions.SH3ADD) 283 // replace the fuOpType with sr29add 284 cs.fuOpType := ALUOpType.sr29add 285 cs.lsrc(0) := instr1Rs1 286 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 287 cs 288 } 289 290 def fusionName: String = "srli29_add" 291} 292 293// Case: shift right by 30 and add 294// Source: `srli r1, r0, 30` + `add r1, r1, r2` 295// Target: `sr30add r1, r0, r2` (customized internal opcode) 296class FusedSr30add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 297 def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 30.U 298 def inst2Cond = instr(1) === Instructions.ADD 299 300 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 301 def target: CtrlSignals = { 302 val cs = getBaseCS(Instructions.SH3ADD) 303 // replace the fuOpType with sr30add 304 cs.fuOpType := ALUOpType.sr30add 305 cs.lsrc(0) := instr1Rs1 306 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 307 cs 308 } 309 310 def fusionName: String = "srli30_add" 311} 312 313// Case: shift right by 31 and add 314// Source: `srli r1, r0, 31` + `add r1, r1, r2` 315// Target: `sr31add r1, r0, r2` (customized internal opcode) 316class FusedSr31add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 317 def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 31.U 318 def inst2Cond = instr(1) === Instructions.ADD 319 320 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 321 def target: CtrlSignals = { 322 val cs = getBaseCS(Instructions.SH3ADD) 323 // replace the fuOpType with sr31add 324 cs.fuOpType := ALUOpType.sr31add 325 cs.lsrc(0) := instr1Rs1 326 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 327 cs 328 } 329 330 def fusionName: String = "srli31_add" 331} 332 333// Case: shift right by 32 and add 334// Source: `srli r1, r0, 32` + `add r1, r1, r2` 335// Target: `sr32add r1, r0, r2` (customized internal opcode) 336class FusedSr32add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 337 def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 32.U 338 def inst2Cond = instr(1) === Instructions.ADD 339 340 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 341 def target: CtrlSignals = { 342 val cs = getBaseCS(Instructions.SH3ADD) 343 // replace the fuOpType with sr32add 344 cs.fuOpType := ALUOpType.sr32add 345 cs.lsrc(0) := instr1Rs1 346 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 347 cs 348 } 349 350 def fusionName: String = "srli32_add" 351} 352 353// Case: add one if odd, otherwise unchanged 354// Source: `andi r1, r0, 1`` + `add r1, r1, r2` 355// Target: `oddadd r1, r0, r2` (customized internal opcode) 356class FusedOddadd(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 357 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 1.U 358 def inst2Cond = instr(1) === Instructions.ADD 359 360 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 361 def target: CtrlSignals = { 362 val cs = getBaseCS(Instructions.SH3ADD) 363 // replace the fuOpType with oddadd 364 cs.fuOpType := ALUOpType.oddadd 365 cs.lsrc(0) := instr1Rs1 366 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 367 cs 368 } 369 370 def fusionName: String = "andi1_add" 371} 372 373// Case: add one if odd (in word format), otherwise unchanged 374// Source: `andi r1, r0, 1`` + `addw r1, r1, r2` 375// Target: `oddaddw r1, r0, r2` (customized internal opcode) 376class FusedOddaddw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 377 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 1.U 378 def inst2Cond = instr(1) === Instructions.ADDW 379 380 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 381 def target: CtrlSignals = { 382 val cs = getBaseCS(Instructions.SH3ADD) 383 // replace the fuOpType with oddaddw 384 cs.fuOpType := ALUOpType.oddaddw 385 cs.lsrc(0) := instr1Rs1 386 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 387 cs 388 } 389 390 def fusionName: String = "andi1_addw" 391} 392 393// Case: addw and extract its lower 8 bits (fused into addwbyte) 394class FusedAddwbyte(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 395 extends BaseFusionCase(pair, csPair) { 396 require(csPair.isDefined) 397 398 // the first instruction is a addw 399 def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isAddw(csPair.get(0).fuOpType) 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 = "andw_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 override def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 0x1.U 417 override def target: CtrlSignals = { 418 val cs = WireInit(csPair.get(0)) 419 // replace the fuOpType with addwbit 420 cs.fuOpType := ALUOpType.addwbit 421 cs 422 } 423 override def fusionName: String = "andw_andi1" 424} 425 426// Case: logic operation and extract its LSB 427class FusedLogiclsb(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 428 extends BaseFusionCase(pair, csPair) { 429 require(csPair.isDefined) 430 431 // the first instruction is a logic 432 def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isLogic(csPair.get(0).fuOpType) 433 def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 1.U 434 435 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1 436 def target: CtrlSignals = { 437 val cs = WireInit(csPair.get(0)) 438 // change the opType to lsb format 439 cs.fuOpType := ALUOpType.logicToLSB(csPair.get(0).fuOpType) 440 cs 441 } 442 443 def fusionName: String = "logic_andi1" 444} 445 446// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2) 447// Source: `andi r1, r0, -256`` + `or r1, r1, r2` 448class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) { 449 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 0xf00.U 450 def inst2Cond = instr(1) === Instructions.OR 451 452 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 453 def target: CtrlSignals = { 454 val cs = getBaseCS(Instructions.OR) 455 // replace the fuOpType with orh48 456 cs.fuOpType := ALUOpType.orh48 457 cs.lsrc(0) := instr1Rs1 458 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 459 cs 460 } 461 462 def fusionName: String = "andi_f00_or" 463} 464 465// Case: mul 7bit data with 32-bit data 466// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2` 467// Target: `mulw7 r1, r0, r2` 468class FusedMulw7(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters) 469 extends BaseFusionCase(pair, csPair) { 470 require(csPair.isDefined) 471 472 def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 127.U 473 def inst2Cond = instr(1) === Instructions.MULW 474 475 def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2) 476 def target: CtrlSignals = { 477 // use MULW as the base 478 val cs = WireInit(csPair.get(1)) 479 // replace the fuOpType with mulw7 480 cs.fuOpType := MDUOpType.mulw7 481 cs.lsrc(0) := instr1Rs1 482 cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1) 483 cs 484 } 485 486 def fusionName: String = "andi127_mulw" 487} 488 489class FusionDecoder(implicit p: Parameters) extends XSModule { 490 val io = IO(new Bundle { 491 // detect instruction fusions in these instructions 492 val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W)))) 493 val dec = Vec(DecodeWidth, Input(new CtrlSignals())) 494 // whether an instruction fusion is found 495 val out = Vec(DecodeWidth - 1, DecoupledIO(new CtrlSignals)) 496 // fused instruction needs to be cleared 497 val clear = Vec(DecodeWidth, Output(Bool())) 498 }) 499 500 io.clear.head := false.B 501 502 val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2)) 503 val csPairs = io.dec.dropRight(1).zip(io.dec.drop(1)).map(x => Seq(x._1, x._2)) 504 instrPairs.zip(csPairs).zip(io.out).zipWithIndex.foreach{ case (((pair, cs), out), i) => 505 val fusionList = Seq( 506 new FusedAdduw(pair), 507 new FusedZexth(pair), 508 new FusedZexth1(pair), 509 new FusedSexth(pair), 510 new FusedSh1add(pair), 511 new FusedSh2add(pair), 512 new FusedSh3add(pair), 513 new FusedSzewl1(pair), 514 new FusedSzewl2(pair), 515 new FusedSzewl3(pair), 516 new FusedByte2(pair), 517 new FusedSh4add(pair), 518 new FusedSr29add(pair), 519 new FusedSr30add(pair), 520 new FusedSr31add(pair), 521 new FusedSr32add(pair), 522 new FusedOddadd(pair), 523 new FusedOddaddw(pair), 524 new FusedAddwbyte(pair, Some(cs)), 525 new FusedAddwbit(pair, Some(cs)), 526 new FusedLogiclsb(pair, Some(cs)), 527 new FusedOrh48(pair), 528 new FusedMulw7(pair, Some(cs)) 529 ) 530 val pairValid = VecInit(pair.map(_.valid)).asUInt().andR 531 val thisCleared = io.clear(i) 532 val fusionVec = VecInit(fusionList.map(_.isValid)) 533 out.valid := pairValid && !thisCleared && fusionVec.asUInt().orR() 534 XSError(PopCount(fusionVec) > 1.U, "more then one fusion matched\n") 535 out.bits := Mux1H(fusionVec, fusionList.map(_.target)) 536 // TODO: assume every instruction fusion clears the second instruction now 537 io.clear(i + 1) := out.valid 538 fusionList.zip(fusionVec).foreach { case (f, v) => 539 XSPerfAccumulate(s"case_${f.fusionName}_$i", pairValid && !thisCleared && v && out.ready) 540 } 541 XSPerfAccumulate(s"conflict_fusion_$i", pairValid && thisCleared && fusionVec.asUInt().orR() && out.ready) 542 } 543 544 XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire))) 545} 546