xref: /XiangShan/src/main/scala/xiangshan/backend/decode/FusionDecoder.scala (revision bbb5025804d15e99c33b7cdb625687af6aed8720)
188825c5cSYinan Xu/***************************************************************************************
288825c5cSYinan Xu* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
388825c5cSYinan Xu* Copyright (c) 2020-2021 Peng Cheng Laboratory
488825c5cSYinan Xu*
588825c5cSYinan Xu* XiangShan is licensed under Mulan PSL v2.
688825c5cSYinan Xu* You can use this software according to the terms and conditions of the Mulan PSL v2.
788825c5cSYinan Xu* You may obtain a copy of Mulan PSL v2 at:
888825c5cSYinan Xu*          http://license.coscl.org.cn/MulanPSL2
988825c5cSYinan Xu*
1088825c5cSYinan Xu* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1188825c5cSYinan Xu* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1288825c5cSYinan Xu* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1388825c5cSYinan Xu*
1488825c5cSYinan Xu* See the Mulan PSL v2 for more details.
1588825c5cSYinan Xu***************************************************************************************/
1688825c5cSYinan Xu
1788825c5cSYinan Xupackage xiangshan.backend.decode
1888825c5cSYinan Xu
198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
2088825c5cSYinan Xuimport chisel3._
2188825c5cSYinan Xuimport chisel3.util._
22361e6d51SJiuyang Liuimport freechips.rocketchip.rocket.Instructions
233c02ee8fSwakafaimport utility._
243b739f49SXuan Huimport utils._
25361e6d51SJiuyang Liuimport xiangshan._
26730cfbc0SXuan Huimport xiangshan.backend.fu.FuType
27730cfbc0SXuan Huimport xiangshan.backend.Bundles.DecodedInst
2898cfe81bSxgkiriimport xiangshan.backend.decode.isa.bitfield.XSInstBitFields
2988825c5cSYinan Xu
306535afbbSYinan Xuabstract class BaseFusionCase(pair: Seq[Valid[UInt]])(implicit p: Parameters)
3188825c5cSYinan Xu  extends DecodeUnitConstants {
3288825c5cSYinan Xu  require(pair.length == 2)
3388825c5cSYinan Xu
3498cfe81bSxgkiri  protected val inst1: XSInstBitFields = instr(0).asTypeOf(new XSInstBitFields)
3598cfe81bSxgkiri  protected val inst2: XSInstBitFields = instr(1).asTypeOf(new XSInstBitFields)
3698cfe81bSxgkiri
3788825c5cSYinan Xu  protected def instr: Seq[UInt] = pair.map(_.bits)
38a0db5a4bSYinan Xu  protected def pairValid: Bool = VecInit(pair.map(_.valid)).asUInt.andR
3998cfe81bSxgkiri  protected def instr1Rs1: UInt = inst1.RS1
4098cfe81bSxgkiri  protected def instr1Rs2: UInt = inst1.RS2
4198cfe81bSxgkiri  protected def instr1Rd: UInt = inst1.RD
4298cfe81bSxgkiri  def instr2Rs1: UInt = inst2.RS1
4398cfe81bSxgkiri  def instr2Rs2: UInt = inst2.RS2
4498cfe81bSxgkiri  protected def instr2Rd: UInt = inst2.RD
4588825c5cSYinan Xu  protected def withSameDest: Bool = instr1Rd === instr2Rd
46a0db5a4bSYinan Xu  def destToRs1: Bool = instr1Rd === instr2Rs1
4788825c5cSYinan Xu  protected def destToRs2: Bool = instr1Rd === instr2Rs2
480de3199cSsinsanction  protected def instr2Rs1ToRs2: Bool = instr2Rs1 === instr2Rs2
4988825c5cSYinan Xu
50a0db5a4bSYinan Xu  protected def getInstrTable(pat: BitPat): List[BitPat] = {
51a0db5a4bSYinan Xu    // Only these instructions can be fused now
52768f5f91SYangyu Chen    val allDecodeTable = XDecode.table ++ BitmanipDecode.table ++ ScalarCryptoDecode.table
53a0db5a4bSYinan Xu    allDecodeTable.filter(_._1 == pat).map(_._2).head
5488825c5cSYinan Xu  }
55a0db5a4bSYinan Xu  // Must sync these indices with MicroOp.decode
56a0db5a4bSYinan Xu  protected def getInstrFuType(pat: BitPat): BitPat = getInstrTable(pat)(3)
57a0db5a4bSYinan Xu  protected def getInstrFuOpType(pat: BitPat): BitPat = getInstrTable(pat)(4)
58a0db5a4bSYinan Xu  protected def getInstrSrc1Type(pat: BitPat): BitPat = getInstrTable(pat)(0)
59a0db5a4bSYinan Xu  protected def getInstrSrc2Type(pat: BitPat): BitPat = getInstrTable(pat)(1)
6088825c5cSYinan Xu
6188825c5cSYinan Xu  def isValid: Bool
62a0db5a4bSYinan Xu  // To optimize the timing, only these control signals can be affected by instruction fusion.
63a0db5a4bSYinan Xu  def thisInstr: Option[BitPat] = None
64a0db5a4bSYinan Xu  def fusedInstr: Option[BitPat] = None
65a0db5a4bSYinan Xu  // By default, None means unchanged.
66a0db5a4bSYinan Xu  private def compareAndGet(func: BitPat => BitPat): Option[Int] = {
67a0db5a4bSYinan Xu    if (fusedInstr.isDefined) {
68a0db5a4bSYinan Xu      require(thisInstr.isDefined, "thisInstr must be defined to infer the ctrl signals")
69a0db5a4bSYinan Xu      val fused = func(fusedInstr.get)
70a0db5a4bSYinan Xu      // Only when the two instructions have different control field, we make it not None.
71a0db5a4bSYinan Xu      if (fused != func(thisInstr.get)) Some(fused.value.toInt) else None
72a0db5a4bSYinan Xu    } else None
73a0db5a4bSYinan Xu  }
74a0db5a4bSYinan Xu  // We assume only fuType, fuOpType, lsrc2 may be changed now.
75a0db5a4bSYinan Xu  def fuType: Option[Int] = compareAndGet(getInstrFuType)
76a0db5a4bSYinan Xu  def fuOpType: Option[UInt => UInt] = {
77a0db5a4bSYinan Xu    val t = compareAndGet(getInstrFuOpType)
78a0db5a4bSYinan Xu    if (t.isDefined) Some((_: UInt) => t.get.U) else None
79a0db5a4bSYinan Xu  }
80a0db5a4bSYinan Xu  def src2Type: Option[Int] = compareAndGet(getInstrSrc2Type)
81fe528fd6Ssinsanction  def selImm: Option[UInt] = None
82a0db5a4bSYinan Xu  def lsrc2NeedZero: Boolean = false
83a0db5a4bSYinan Xu  def lsrc2NeedMux: Boolean = false
840febc381SYinan Xu  def lsrc2MuxResult: UInt = Mux(destToRs1, instr2Rs2, instr2Rs1)
85a0db5a4bSYinan Xu
8688825c5cSYinan Xu  def fusionName: String
8788825c5cSYinan Xu}
8888825c5cSYinan Xu
89a0db5a4bSYinan Xu// There are 2 types of instruction fusion.
90a0db5a4bSYinan Xu// (1) fused into a fixed new instruction with new control signals.
91a0db5a4bSYinan Xu// (2) the first instruction's op is replaced with another one.
92a0db5a4bSYinan Xu
9388825c5cSYinan Xu// Case: clear upper 32 bits / get lower 32 bits
9488825c5cSYinan Xu// Source: `slli r1, r0, 32` + `srli r1, r1, 32`
9588825c5cSYinan Xu// Target: `add.uw r1, r0, zero` (pseudo instruction: `zext.w r1, r0`)
9688825c5cSYinan Xuclass FusedAdduw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
9798cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
9898cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 32.U
9988825c5cSYinan Xu
10088825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
101a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
102a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD_UW)
103a0db5a4bSYinan Xu  override def lsrc2NeedZero: Boolean = true
10488825c5cSYinan Xu
10588825c5cSYinan Xu  def fusionName: String = "slli32_srli32"
10688825c5cSYinan Xu}
10788825c5cSYinan Xu
10888825c5cSYinan Xu// Case: clear upper 48 bits / get lower 16 bits
10988825c5cSYinan Xu// Source: `slli r1, r0, 48` + `srli r1, r1, 48`
11088825c5cSYinan Xu// Target: `zext.h r1, r0`
11188825c5cSYinan Xuclass FusedZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
11298cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 48.U
11398cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 48.U
11488825c5cSYinan Xu
11588825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
116a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
117a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.PACKW)
118a0db5a4bSYinan Xu  override def lsrc2NeedZero: Boolean = true
11988825c5cSYinan Xu
12088825c5cSYinan Xu  def fusionName: String = "slli48_srli48"
12188825c5cSYinan Xu}
12288825c5cSYinan Xu
12388825c5cSYinan Xu// Another case of Zext.h
12488825c5cSYinan Xu// Source: `slliw r1, r0, 16` + `srliw r1, r1, 16`
12588825c5cSYinan Xu// Target: `zext.h r1, r0`
12688825c5cSYinan Xuclass FusedZexth1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends FusedZexth(pair) {
12798cfe81bSxgkiri  override def inst1Cond: Bool = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U
12898cfe81bSxgkiri  override def inst2Cond: Bool = instr(1) === Instructions.SRLIW && inst2.SHAMT5 === 16.U
12988825c5cSYinan Xu
130a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW)
131a0db5a4bSYinan Xu
13288825c5cSYinan Xu  override def fusionName: String = "slliw16_srliw16"
13388825c5cSYinan Xu}
13488825c5cSYinan Xu
13588825c5cSYinan Xu// Case: sign-extend a 16-bit number
13688825c5cSYinan Xu// Source: `slliw r1, r0, 16` + `sraiw r1, r1, 16`
13788825c5cSYinan Xu// Target: `sext.h r1, r0`
13888825c5cSYinan Xuclass FusedSexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
13998cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U
14098cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRAIW && inst2.SHAMT5 === 16.U
14188825c5cSYinan Xu
14288825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
143a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW)
144a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.SEXT_H)
145a0db5a4bSYinan Xu  override def lsrc2NeedZero: Boolean = true
14688825c5cSYinan Xu
14788825c5cSYinan Xu  def fusionName: String = "slliw16_sraiw16"
14888825c5cSYinan Xu}
14988825c5cSYinan Xu
15088825c5cSYinan Xu// Case: shift left by one and add
15188825c5cSYinan Xu// Source: `slli r1, r0, 1` + `add r1, r1, r2`
15288825c5cSYinan Xu// Target: `sh1add r1, r0, r2`
15388825c5cSYinan Xuclass FusedSh1add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
15498cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 1.U
1550de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
15688825c5cSYinan Xu
15788825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
158a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
159a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.SH1ADD)
160a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
16188825c5cSYinan Xu
16288825c5cSYinan Xu  def fusionName: String = "slli1_add"
16388825c5cSYinan Xu}
16488825c5cSYinan Xu
16588825c5cSYinan Xu// Case: shift left by two and add
16688825c5cSYinan Xu// Source: `slli r1, r0, 2` + `add r1, r1, r2`
16788825c5cSYinan Xu// Target: `sh2add r1, r0, r2`
16888825c5cSYinan Xuclass FusedSh2add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
16998cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 2.U
1700de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
17188825c5cSYinan Xu
17288825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
173a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
174a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.SH2ADD)
175a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
17688825c5cSYinan Xu
17788825c5cSYinan Xu  def fusionName: String = "slli2_add"
17888825c5cSYinan Xu}
17988825c5cSYinan Xu
18088825c5cSYinan Xu// Case: shift left by three and add
18188825c5cSYinan Xu// Source: `slli r1, r0, 3` + `add r1, r1, r2`
18288825c5cSYinan Xu// Target: `sh3add r1, r0, r2`
18388825c5cSYinan Xuclass FusedSh3add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
18498cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 3.U
1850de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
18688825c5cSYinan Xu
18788825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
188a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
189a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.SH3ADD)
190a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
19188825c5cSYinan Xu
19288825c5cSYinan Xu  def fusionName: String = "slli3_add"
19388825c5cSYinan Xu}
19488825c5cSYinan Xu
19588825c5cSYinan Xu// Case: shift zero-extended word left by one
196a0db5a4bSYinan Xu// Source: `slli r1, r0, 32` + `srli r1, r1, 31`
19788825c5cSYinan Xu// Target: `szewl1 r1, r0` (customized internal opcode)
19888825c5cSYinan Xuclass FusedSzewl1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
19998cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
20098cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 31.U
20188825c5cSYinan Xu
20288825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
203a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl1)
20488825c5cSYinan Xu
20588825c5cSYinan Xu  def fusionName: String = "slli32_srli31"
20688825c5cSYinan Xu}
20788825c5cSYinan Xu
20888825c5cSYinan Xu// Case: shift zero-extended word left by two
209a0db5a4bSYinan Xu// Source: `slli r1, r0, 32` + `srli r1, r1, 30`
21088825c5cSYinan Xu// Target: `szewl2 r1, r0` (customized internal opcode)
21188825c5cSYinan Xuclass FusedSzewl2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
21298cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
21398cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 30.U
21488825c5cSYinan Xu
21588825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
216a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl2)
21788825c5cSYinan Xu
21888825c5cSYinan Xu  def fusionName: String = "slli32_srli30"
21988825c5cSYinan Xu}
22088825c5cSYinan Xu
221a792bcf1SYinan Xu// Case: shift zero-extended word left by three
222a0db5a4bSYinan Xu// Source: `slli r1, r0, 32` + `srli r1, r1, 29`
223a792bcf1SYinan Xu// Target: `szewl3 r1, r0` (customized internal opcode)
224a792bcf1SYinan Xuclass FusedSzewl3(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
22598cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
22698cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 29.U
227a792bcf1SYinan Xu
228a792bcf1SYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
229a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl3)
230a792bcf1SYinan Xu
231a792bcf1SYinan Xu  def fusionName: String = "slli32_srli29"
232a792bcf1SYinan Xu}
233a792bcf1SYinan Xu
23488825c5cSYinan Xu// Case: get the second byte
23588825c5cSYinan Xu// Source: `srli r1, r0, 8` + `andi r1, r1, 255`
23688825c5cSYinan Xu// Target: `byte2 r1, r0` (customized internal opcode)
23788825c5cSYinan Xuclass FusedByte2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
23898cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 8.U
23998cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 255.U
24088825c5cSYinan Xu
24188825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
242a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.byte2)
24388825c5cSYinan Xu
24488825c5cSYinan Xu  def fusionName: String = "srli8_andi255"
24588825c5cSYinan Xu}
24688825c5cSYinan Xu
24788825c5cSYinan Xu// Case: shift left by four and add
24888825c5cSYinan Xu// Source: `slli r1, r0, 4` + `add r1, r1, r2`
24988825c5cSYinan Xu// Target: `sh4add r1, r0, r2` (customized internal opcode)
25088825c5cSYinan Xuclass FusedSh4add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
25198cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 4.U
2520de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
25388825c5cSYinan Xu
25488825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
255a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
256a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
257a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sh4add)
258a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
25988825c5cSYinan Xu
26088825c5cSYinan Xu  def fusionName: String = "slli4_add"
26188825c5cSYinan Xu}
26288825c5cSYinan Xu
263a792bcf1SYinan Xu// Case: shift right by 29 and add
264a792bcf1SYinan Xu// Source: `srli r1, r0, 29` + `add r1, r1, r2`
265a792bcf1SYinan Xu// Target: `sr29add r1, r0, r2` (customized internal opcode)
266a792bcf1SYinan Xuclass FusedSr29add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
26798cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 29.U
2680de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
269a792bcf1SYinan Xu
270a792bcf1SYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
271a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
272a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
273a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr29add)
274a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
275a792bcf1SYinan Xu
276a792bcf1SYinan Xu  def fusionName: String = "srli29_add"
277a792bcf1SYinan Xu}
278a792bcf1SYinan Xu
27988825c5cSYinan Xu// Case: shift right by 30 and add
28088825c5cSYinan Xu// Source: `srli r1, r0, 30` + `add r1, r1, r2`
28188825c5cSYinan Xu// Target: `sr30add r1, r0, r2` (customized internal opcode)
28288825c5cSYinan Xuclass FusedSr30add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
28398cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 30.U
2840de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
28588825c5cSYinan Xu
28688825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
287a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
288a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
289a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr30add)
290a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
29188825c5cSYinan Xu
29288825c5cSYinan Xu  def fusionName: String = "srli30_add"
29388825c5cSYinan Xu}
29488825c5cSYinan Xu
29588825c5cSYinan Xu// Case: shift right by 31 and add
29688825c5cSYinan Xu// Source: `srli r1, r0, 31` + `add r1, r1, r2`
29788825c5cSYinan Xu// Target: `sr31add r1, r0, r2` (customized internal opcode)
29888825c5cSYinan Xuclass FusedSr31add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
29998cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 31.U
3000de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
30188825c5cSYinan Xu
30288825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
303a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
304a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
305a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr31add)
306a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
30788825c5cSYinan Xu
30888825c5cSYinan Xu  def fusionName: String = "srli31_add"
30988825c5cSYinan Xu}
31088825c5cSYinan Xu
31188825c5cSYinan Xu// Case: shift right by 32 and add
31288825c5cSYinan Xu// Source: `srli r1, r0, 32` + `add r1, r1, r2`
31388825c5cSYinan Xu// Target: `sr32add r1, r0, r2` (customized internal opcode)
31488825c5cSYinan Xuclass FusedSr32add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
31598cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 32.U
3160de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
31788825c5cSYinan Xu
31888825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
319a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
320a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
321a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr32add)
322a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
32388825c5cSYinan Xu
32488825c5cSYinan Xu  def fusionName: String = "srli32_add"
32588825c5cSYinan Xu}
32688825c5cSYinan Xu
32788825c5cSYinan Xu// Case: add one if odd, otherwise unchanged
32888825c5cSYinan Xu// Source: `andi r1, r0, 1`` + `add r1, r1, r2`
32988825c5cSYinan Xu// Target: `oddadd r1, r0, r2` (customized internal opcode)
33088825c5cSYinan Xuclass FusedOddadd(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
33198cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U
3320de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
33388825c5cSYinan Xu
33488825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
335a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
336a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
337a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddadd)
338a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
33988825c5cSYinan Xu
34088825c5cSYinan Xu  def fusionName: String = "andi1_add"
34188825c5cSYinan Xu}
34288825c5cSYinan Xu
34388825c5cSYinan Xu// Case: add one if odd (in word format), otherwise unchanged
34488825c5cSYinan Xu// Source: `andi r1, r0, 1`` + `addw r1, r1, r2`
34588825c5cSYinan Xu// Target: `oddaddw r1, r0, r2` (customized internal opcode)
34688825c5cSYinan Xuclass FusedOddaddw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
34798cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U
3480de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.ADDW && !instr2Rs1ToRs2
34988825c5cSYinan Xu
35088825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
351a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
352a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
353a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddaddw)
354a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
35588825c5cSYinan Xu
35688825c5cSYinan Xu  def fusionName: String = "andi1_addw"
35788825c5cSYinan Xu}
35888825c5cSYinan Xu
35988825c5cSYinan Xu// Case: addw and extract its lower 8 bits (fused into addwbyte)
360a0db5a4bSYinan Xuclass FusedAddwbyte(pair: Seq[Valid[UInt]])(implicit p: Parameters)
3616535afbbSYinan Xu  extends BaseFusionCase(pair) {
3626535afbbSYinan Xu  // the first instruction is a ALUOpType.addw
3636535afbbSYinan Xu  // According to DecodeUnit.scala, only ADDIW and ADDW are ALUOpType.addw, which are used for inst1Cond.
3648a009b1dSLi Qianruo  def inst1Cond = instr(0) === Instructions.ADDIW || instr(0) === Instructions.ADDW
36598cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0xff.U
36688825c5cSYinan Xu
36788825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
368a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbyte)
36988825c5cSYinan Xu
370675acc68SYinan Xu  def fusionName: String = "addw_andi255"
37188825c5cSYinan Xu}
37288825c5cSYinan Xu
37388825c5cSYinan Xu// Case: addw and extract its lower 1 bit (fused into addwbit)
374a0db5a4bSYinan Xuclass FusedAddwbit(pair: Seq[Valid[UInt]])(implicit p: Parameters)
375a0db5a4bSYinan Xu  extends FusedAddwbyte(pair) {
376675acc68SYinan Xu
37798cfe81bSxgkiri  override def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0x1.U
378a0db5a4bSYinan Xu
379a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbit)
380675acc68SYinan Xu
381675acc68SYinan Xu  override def fusionName: String = "addw_andi1"
382675acc68SYinan Xu}
383675acc68SYinan Xu
384675acc68SYinan Xu// Case: addw and zext.h (fused into addwzexth)
385a0db5a4bSYinan Xuclass FusedAddwzexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
386a0db5a4bSYinan Xu  extends FusedAddwbyte(pair) {
387675acc68SYinan Xu
388675acc68SYinan Xu  override def inst2Cond = instr(1) === Instructions.ZEXT_H
389a0db5a4bSYinan Xu
390a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwzexth)
391675acc68SYinan Xu
392675acc68SYinan Xu  override def fusionName: String = "addw_zexth"
393675acc68SYinan Xu}
394675acc68SYinan Xu
395675acc68SYinan Xu// Case: addw and sext.h (fused into addwsexth)
396a0db5a4bSYinan Xuclass FusedAddwsexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
397a0db5a4bSYinan Xu  extends FusedAddwbyte(pair) {
398675acc68SYinan Xu
399675acc68SYinan Xu  override def inst2Cond = instr(1) === Instructions.SEXT_H
400a0db5a4bSYinan Xu
401a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwsexth)
402675acc68SYinan Xu
403675acc68SYinan Xu  override def fusionName: String = "addw_sexth"
40488825c5cSYinan Xu}
40588825c5cSYinan Xu
40688825c5cSYinan Xu// Case: logic operation and extract its LSB
4076535afbbSYinan Xu
408a0db5a4bSYinan Xuclass FusedLogiclsb(pair: Seq[Valid[UInt]])(implicit p: Parameters)
4096535afbbSYinan Xu  extends BaseFusionCase(pair) {
4106535afbbSYinan Xu  // the first instruction is a logic (and, or, xor, orcb)
4116535afbbSYinan Xu  // (1) def ANDI               = BitPat("b?????????????????111?????0010011")
4126535afbbSYinan Xu  // (2) def AND                = BitPat("b0000000??????????111?????0110011")
4136535afbbSYinan Xu  // (3) def ORI                = BitPat("b?????????????????110?????0010011")
4146535afbbSYinan Xu  // (4) def OR                 = BitPat("b0000000??????????110?????0110011")
4156535afbbSYinan Xu  // (5) def XORI               = BitPat("b?????????????????100?????0010011")
4166535afbbSYinan Xu  // (6) def XOR                = BitPat("b0000000??????????100?????0110011")
4176535afbbSYinan Xu  // (7) def ORC_B              = BitPat("b001010000111?????101?????0010011")
4186535afbbSYinan Xu  val logicInstrList = Seq(Instructions.ANDI, Instructions.AND, Instructions.ORI, Instructions.OR,
4196535afbbSYinan Xu    Instructions.XORI, Instructions.XOR, Instructions.ORC_B)
4206535afbbSYinan Xu  def inst1Cond = VecInit(logicInstrList.map(_ === instr(0))).asUInt.orR
42198cfe81bSxgkiri  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 1.U
42288825c5cSYinan Xu
42388825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
424a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToLsb)
42588825c5cSYinan Xu
42688825c5cSYinan Xu  def fusionName: String = "logic_andi1"
42788825c5cSYinan Xu}
42888825c5cSYinan Xu
429a0db5a4bSYinan Xuclass FusedLogicZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
430a0db5a4bSYinan Xu  extends FusedLogiclsb(pair) {
431675acc68SYinan Xu
432675acc68SYinan Xu  override def inst2Cond = instr(1) === Instructions.ZEXT_H
433a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToZexth)
434675acc68SYinan Xu
435675acc68SYinan Xu  override def fusionName: String = "logic_zexth"
436675acc68SYinan Xu}
437675acc68SYinan Xu
43888825c5cSYinan Xu// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2)
43988825c5cSYinan Xu// Source: `andi r1, r0, -256`` + `or r1, r1, r2`
44088825c5cSYinan Xuclass FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
44198cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 0xf00.U
4420de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.OR && !instr2Rs1ToRs2
44388825c5cSYinan Xu
44488825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
445a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
446a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.OR)
447a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.orh48)
448a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
44988825c5cSYinan Xu
45088825c5cSYinan Xu  def fusionName: String = "andi_f00_or"
45188825c5cSYinan Xu}
45288825c5cSYinan Xu
45388825c5cSYinan Xu// Case: mul 7bit data with 32-bit data
45488825c5cSYinan Xu// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2`
45588825c5cSYinan Xu// Target: `mulw7 r1, r0, r2`
4566535afbbSYinan Xuclass FusedMulw7(pair: Seq[Valid[UInt]])(implicit p: Parameters)
4576535afbbSYinan Xu  extends BaseFusionCase(pair) {
45898cfe81bSxgkiri  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 127.U
4590de3199cSsinsanction  def inst2Cond = instr(1) === Instructions.MULW && !instr2Rs1ToRs2
46088825c5cSYinan Xu
46188825c5cSYinan Xu  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
462a0db5a4bSYinan Xu  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
463a0db5a4bSYinan Xu  override def fusedInstr: Option[BitPat] = Some(Instructions.MULW)
464a0db5a4bSYinan Xu  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => MDUOpType.mulw7)
465a0db5a4bSYinan Xu  override def lsrc2NeedMux: Boolean = true
46688825c5cSYinan Xu
46788825c5cSYinan Xu  def fusionName: String = "andi127_mulw"
46888825c5cSYinan Xu}
46988825c5cSYinan Xu
470fe528fd6Ssinsanction// Case: get 32 bits imm
471fe528fd6Ssinsanction// Source: `lui r1, 0xffffa`` + `addi r1, r1, 1`
472fe528fd6Ssinsanction// Target: `lui32 r1, 0xffffa001` (customized internal opcode)
473fe528fd6Ssinsanctionclass FusedLui32(pair: Seq[Valid[UInt]])(implicit p: Parameters)
474fe528fd6Ssinsanction  extends BaseFusionCase(pair) {
475fe528fd6Ssinsanction  def inst1Cond = instr(0) === Instructions.LUI
476fe528fd6Ssinsanction  def inst2Cond = instr(1) === Instructions.ADDI
477fe528fd6Ssinsanction
478fe528fd6Ssinsanction  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
479fe528fd6Ssinsanction
480fe528fd6Ssinsanction  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32add)
481fe528fd6Ssinsanction  override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32)
482fe528fd6Ssinsanction
483fe528fd6Ssinsanction  def fusionName: String = "lui_addi"
484fe528fd6Ssinsanction
485765e58c6Ssinsanction  XSDebug(isValid, p"[fusedLui32] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n")
486fe528fd6Ssinsanction}
487fe528fd6Ssinsanction
48854711376Ssinsanction// Case: get 32 bits imm (in word format)
48954711376Ssinsanction// Source: `lui r1, 0xffffa`` + `addiw r1, r1, 1`
49054711376Ssinsanction// Target: `lui32 r1, 0xffffa001` (customized internal opcode)
49154711376Ssinsanctionclass FusedLui32w(pair: Seq[Valid[UInt]])(implicit p: Parameters)
49254711376Ssinsanction  extends BaseFusionCase(pair) {
49354711376Ssinsanction  def inst1Cond = instr(0) === Instructions.LUI
49454711376Ssinsanction  def inst2Cond = instr(1) === Instructions.ADDIW
49554711376Ssinsanction
49654711376Ssinsanction  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
49754711376Ssinsanction
49854711376Ssinsanction  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32addw)
49954711376Ssinsanction  override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32)
50054711376Ssinsanction
50154711376Ssinsanction  def fusionName: String = "lui_addiw"
50254711376Ssinsanction
503765e58c6Ssinsanction  XSDebug(isValid, p"[fusedLui32w] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n")
50454711376Ssinsanction}
50554711376Ssinsanction
506a0db5a4bSYinan Xuclass FusionDecodeInfo extends Bundle {
507a0db5a4bSYinan Xu  val rs2FromRs1 = Output(Bool())
508a0db5a4bSYinan Xu  val rs2FromRs2 = Output(Bool())
509a0db5a4bSYinan Xu  val rs2FromZero = Output(Bool())
510a0db5a4bSYinan Xu}
511a0db5a4bSYinan Xu
512ad5c9e6eSJunxiong Jiclass FusionDecodeReplace(implicit p: Parameters) extends XSBundle {
5130febc381SYinan Xu  val fuType = Valid(FuType())
5140febc381SYinan Xu  val fuOpType = Valid(FuOpType())
515ad5c9e6eSJunxiong Ji  val lsrc2 = Valid(UInt(LogicRegsWidth.W))
5160febc381SYinan Xu  val src2Type = Valid(SrcType())
517fe528fd6Ssinsanction  val selImm = Valid(SelImm())
5180febc381SYinan Xu
5193b739f49SXuan Hu  def update(cs: DecodedInst): Unit = {
5200febc381SYinan Xu    when (fuType.valid) {
5210febc381SYinan Xu      cs.fuType := fuType.bits
5220febc381SYinan Xu    }
5230febc381SYinan Xu    when (fuOpType.valid) {
5240febc381SYinan Xu      cs.fuOpType := fuOpType.bits
5250febc381SYinan Xu    }
5260febc381SYinan Xu    when (lsrc2.valid) {
5270febc381SYinan Xu      cs.lsrc(1) := lsrc2.bits
5280febc381SYinan Xu    }
5290febc381SYinan Xu    when (src2Type.valid) {
5300febc381SYinan Xu      cs.srcType(1) := src2Type.bits
5310febc381SYinan Xu    }
532fe528fd6Ssinsanction    when (selImm.valid) {
533fe528fd6Ssinsanction      cs.selImm := selImm.bits
534fe528fd6Ssinsanction    }
5350febc381SYinan Xu  }
5360febc381SYinan Xu}
5370febc381SYinan Xu
53888825c5cSYinan Xuclass FusionDecoder(implicit p: Parameters) extends XSModule {
53988825c5cSYinan Xu  val io = IO(new Bundle {
540*bbb50258STang Haojin    val disableFusion = Input(Bool())
5410febc381SYinan Xu    // T0: detect instruction fusions in these instructions
54288825c5cSYinan Xu    val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W))))
5430febc381SYinan Xu    val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1)
5440febc381SYinan Xu    // T1: decode result
5453b739f49SXuan Hu    val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1)
5460febc381SYinan Xu    // T1: whether an instruction fusion is found
5470febc381SYinan Xu    val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1)
5480febc381SYinan Xu    val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1)
5490febc381SYinan Xu    // T1: fused instruction needs to be cleared
55088825c5cSYinan Xu    val clear = Vec(DecodeWidth, Output(Bool()))
55188825c5cSYinan Xu  })
55288825c5cSYinan Xu
55388825c5cSYinan Xu  io.clear.head := false.B
55488825c5cSYinan Xu
55588825c5cSYinan Xu  val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2))
5560febc381SYinan Xu  instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) =>
55788825c5cSYinan Xu    val fusionList = Seq(
55888825c5cSYinan Xu      new FusedAdduw(pair),
55988825c5cSYinan Xu      new FusedZexth(pair),
56088825c5cSYinan Xu      new FusedZexth1(pair),
56188825c5cSYinan Xu      new FusedSexth(pair),
56288825c5cSYinan Xu      new FusedSh1add(pair),
56388825c5cSYinan Xu      new FusedSh2add(pair),
56488825c5cSYinan Xu      new FusedSh3add(pair),
56588825c5cSYinan Xu      new FusedSzewl1(pair),
56688825c5cSYinan Xu      new FusedSzewl2(pair),
567a792bcf1SYinan Xu      new FusedSzewl3(pair),
56888825c5cSYinan Xu      new FusedByte2(pair),
56988825c5cSYinan Xu      new FusedSh4add(pair),
570a792bcf1SYinan Xu      new FusedSr29add(pair),
57188825c5cSYinan Xu      new FusedSr30add(pair),
57288825c5cSYinan Xu      new FusedSr31add(pair),
57388825c5cSYinan Xu      new FusedSr32add(pair),
57488825c5cSYinan Xu      new FusedOddadd(pair),
57588825c5cSYinan Xu      new FusedOddaddw(pair),
5766535afbbSYinan Xu      new FusedOrh48(pair),
5776535afbbSYinan Xu      new FusedMulw7(pair),
578a0db5a4bSYinan Xu      new FusedAddwbyte(pair),
579a0db5a4bSYinan Xu      new FusedAddwbit(pair),
580a0db5a4bSYinan Xu      new FusedAddwzexth(pair),
581a0db5a4bSYinan Xu      new FusedAddwsexth(pair),
582a0db5a4bSYinan Xu      new FusedLogiclsb(pair),
583fe528fd6Ssinsanction      new FusedLogicZexth(pair),
58454711376Ssinsanction      new FusedLui32(pair),
58554711376Ssinsanction      new FusedLui32w(pair)
58688825c5cSYinan Xu    )
5870febc381SYinan Xu    val fire = io.in(i).valid && io.inReady(i)
5885827388eSYinan Xu    val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i))
5890febc381SYinan Xu    val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire)
5907d62bb17STang Haojin    // HINT instructions are not considered for fusion.
5917d62bb17STang Haojin    // NOTE: The RD of some FENCE instructions are not 0, but they are also HINT instructions.
5927d62bb17STang Haojin    //       However, as FENCE instructions can never be fused, we do not need to consider them.
5937d62bb17STang Haojin    val notHint = RegEnable(VecInit(pair.map(_.bits(11, 7) =/= 0.U)).asUInt.andR, fire)
594*bbb50258STang Haojin    val enabled = RegEnable(!io.disableFusion, fire)
59588825c5cSYinan Xu    val thisCleared = io.clear(i)
596*bbb50258STang Haojin    out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR && notHint && enabled
5970febc381SYinan Xu    XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n")
5980febc381SYinan Xu    def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = {
5990febc381SYinan Xu      field(out.bits).valid := false.B
6000febc381SYinan Xu      field(out.bits).bits := DontCare
601a0db5a4bSYinan Xu      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined)
602a0db5a4bSYinan Xu      if (replaceVec.nonEmpty) {
603a0db5a4bSYinan Xu        // constant values are grouped together for better timing.
6040febc381SYinan Xu        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
605a0db5a4bSYinan Xu        val replTypes = replaceVec.map(_._2.get).distinct
6060febc381SYinan Xu        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR)
6070febc381SYinan Xu        field(out.bits).valid := replEnable
6080febc381SYinan Xu        field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U))
609a0db5a4bSYinan Xu      }
610a0db5a4bSYinan Xu    }
611fe528fd6Ssinsanction    def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = {
612fe528fd6Ssinsanction      field(out.bits).valid := false.B
613fe528fd6Ssinsanction      field(out.bits).bits := DontCare
614fe528fd6Ssinsanction      val replaceVec = if (needReg) fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, RegEnable(x._2.get, fire))) else fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get))
615fe528fd6Ssinsanction      if (replaceVec.nonEmpty) {
616fe528fd6Ssinsanction        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
617fe528fd6Ssinsanction        val replTypes = replaceVec.map(_._2).distinct
618fe528fd6Ssinsanction        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR)
619fe528fd6Ssinsanction        field(out.bits).valid := replEnable
620fe528fd6Ssinsanction        field(out.bits).bits := Mux1H(replSel, replTypes)
621fe528fd6Ssinsanction      }
622fe528fd6Ssinsanction    }
6230febc381SYinan Xu    def connectByUIntFunc(
6240febc381SYinan Xu      field: FusionDecodeReplace => Valid[UInt],
6253b739f49SXuan Hu      csField: DecodedInst => UInt,
6260febc381SYinan Xu      replace: Seq[Option[UInt => UInt]]
6270febc381SYinan Xu    ): Unit = {
6280febc381SYinan Xu      field(out.bits).valid := false.B
6290febc381SYinan Xu      field(out.bits).bits := DontCare
6300febc381SYinan Xu      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec))))
631a0db5a4bSYinan Xu      if (replaceVec.nonEmpty) {
6320febc381SYinan Xu        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
633a0db5a4bSYinan Xu        // constant values are grouped together for better timing.
634a0db5a4bSYinan Xu        val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue))
635a0db5a4bSYinan Xu        val constReplTypes = constReplVec.map(_._2).distinct
636a0db5a4bSYinan Xu        val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR)
637a0db5a4bSYinan Xu        val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U))
638a0db5a4bSYinan Xu        // non-constant values have to be processed naively.
639a0db5a4bSYinan Xu        val noLitRepl = replaceVec.filterNot(_._2.isLit)
6400febc381SYinan Xu        field(out.bits).valid := replEnable
6410febc381SYinan Xu        field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult)
642a0db5a4bSYinan Xu      }
643a0db5a4bSYinan Xu    }
6440febc381SYinan Xu    connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType))
6453b739f49SXuan Hu    connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType))
6460febc381SYinan Xu    connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type))
647fe528fd6Ssinsanction    connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false)
648765e58c6Ssinsanction
649a0db5a4bSYinan Xu    val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR
650a0db5a4bSYinan Xu    val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR
651*bbb50258STang Haojin    io.info(i).rs2FromZero := enabled && src2WithZero
652*bbb50258STang Haojin    io.info(i).rs2FromRs1 := enabled && src2WithMux && !RegEnable(fusionList.head.destToRs1, fire)
653*bbb50258STang Haojin    io.info(i).rs2FromRs2 := enabled && src2WithMux && RegEnable(fusionList.head.destToRs1, fire)
654*bbb50258STang Haojin    out.bits.lsrc2.valid := enabled && (src2WithMux || src2WithZero)
655a0db5a4bSYinan Xu    when (src2WithMux) {
6560febc381SYinan Xu      out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire)
6570febc381SYinan Xu    }.otherwise {//elsewhen (src2WithZero) {
6580febc381SYinan Xu      out.bits.lsrc2.bits := 0.U
659a0db5a4bSYinan Xu    }
66088825c5cSYinan Xu    // TODO: assume every instruction fusion clears the second instruction now
66188825c5cSYinan Xu    io.clear(i + 1) := out.valid
6620febc381SYinan Xu    val lastFire = RegNext(fire)
66388825c5cSYinan Xu    fusionList.zip(fusionVec).foreach { case (f, v) =>
6640febc381SYinan Xu      XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire)
66588825c5cSYinan Xu    }
6660febc381SYinan Xu    XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire)
66788825c5cSYinan Xu  }
66888825c5cSYinan Xu
669765e58c6Ssinsanction  XSPerfAccumulate("fused_instr", PopCount(io.out.zipWithIndex.map{ case (x, i) => x.valid && RegNext(io.in(i).valid && io.inReady(i)) }))
67088825c5cSYinan Xu}
671