xref: /XiangShan/src/main/scala/xiangshan/backend/decode/FusionDecoder.scala (revision bbb5025804d15e99c33b7cdb625687af6aed8720)
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 org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import freechips.rocketchip.rocket.Instructions
23import utility._
24import utils._
25import xiangshan._
26import xiangshan.backend.fu.FuType
27import xiangshan.backend.Bundles.DecodedInst
28import xiangshan.backend.decode.isa.bitfield.XSInstBitFields
29
30abstract class BaseFusionCase(pair: Seq[Valid[UInt]])(implicit p: Parameters)
31  extends DecodeUnitConstants {
32  require(pair.length == 2)
33
34  protected val inst1: XSInstBitFields = instr(0).asTypeOf(new XSInstBitFields)
35  protected val inst2: XSInstBitFields = instr(1).asTypeOf(new XSInstBitFields)
36
37  protected def instr: Seq[UInt] = pair.map(_.bits)
38  protected def pairValid: Bool = VecInit(pair.map(_.valid)).asUInt.andR
39  protected def instr1Rs1: UInt = inst1.RS1
40  protected def instr1Rs2: UInt = inst1.RS2
41  protected def instr1Rd: UInt = inst1.RD
42  def instr2Rs1: UInt = inst2.RS1
43  def instr2Rs2: UInt = inst2.RS2
44  protected def instr2Rd: UInt = inst2.RD
45  protected def withSameDest: Bool = instr1Rd === instr2Rd
46  def destToRs1: Bool = instr1Rd === instr2Rs1
47  protected def destToRs2: Bool = instr1Rd === instr2Rs2
48  protected def instr2Rs1ToRs2: Bool = instr2Rs1 === instr2Rs2
49
50  protected def getInstrTable(pat: BitPat): List[BitPat] = {
51    // Only these instructions can be fused now
52    val allDecodeTable = XDecode.table ++ BitmanipDecode.table ++ ScalarCryptoDecode.table
53    allDecodeTable.filter(_._1 == pat).map(_._2).head
54  }
55  // Must sync these indices with MicroOp.decode
56  protected def getInstrFuType(pat: BitPat): BitPat = getInstrTable(pat)(3)
57  protected def getInstrFuOpType(pat: BitPat): BitPat = getInstrTable(pat)(4)
58  protected def getInstrSrc1Type(pat: BitPat): BitPat = getInstrTable(pat)(0)
59  protected def getInstrSrc2Type(pat: BitPat): BitPat = getInstrTable(pat)(1)
60
61  def isValid: Bool
62  // To optimize the timing, only these control signals can be affected by instruction fusion.
63  def thisInstr: Option[BitPat] = None
64  def fusedInstr: Option[BitPat] = None
65  // By default, None means unchanged.
66  private def compareAndGet(func: BitPat => BitPat): Option[Int] = {
67    if (fusedInstr.isDefined) {
68      require(thisInstr.isDefined, "thisInstr must be defined to infer the ctrl signals")
69      val fused = func(fusedInstr.get)
70      // Only when the two instructions have different control field, we make it not None.
71      if (fused != func(thisInstr.get)) Some(fused.value.toInt) else None
72    } else None
73  }
74  // We assume only fuType, fuOpType, lsrc2 may be changed now.
75  def fuType: Option[Int] = compareAndGet(getInstrFuType)
76  def fuOpType: Option[UInt => UInt] = {
77    val t = compareAndGet(getInstrFuOpType)
78    if (t.isDefined) Some((_: UInt) => t.get.U) else None
79  }
80  def src2Type: Option[Int] = compareAndGet(getInstrSrc2Type)
81  def selImm: Option[UInt] = None
82  def lsrc2NeedZero: Boolean = false
83  def lsrc2NeedMux: Boolean = false
84  def lsrc2MuxResult: UInt = Mux(destToRs1, instr2Rs2, instr2Rs1)
85
86  def fusionName: String
87}
88
89// There are 2 types of instruction fusion.
90// (1) fused into a fixed new instruction with new control signals.
91// (2) the first instruction's op is replaced with another one.
92
93// Case: clear upper 32 bits / get lower 32 bits
94// Source: `slli r1, r0, 32` + `srli r1, r1, 32`
95// Target: `add.uw r1, r0, zero` (pseudo instruction: `zext.w r1, r0`)
96class FusedAdduw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
97  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
98  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 32.U
99
100  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
101  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
102  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD_UW)
103  override def lsrc2NeedZero: Boolean = true
104
105  def fusionName: String = "slli32_srli32"
106}
107
108// Case: clear upper 48 bits / get lower 16 bits
109// Source: `slli r1, r0, 48` + `srli r1, r1, 48`
110// Target: `zext.h r1, r0`
111class FusedZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
112  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 48.U
113  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 48.U
114
115  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
116  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
117  override def fusedInstr: Option[BitPat] = Some(Instructions.PACKW)
118  override def lsrc2NeedZero: Boolean = true
119
120  def fusionName: String = "slli48_srli48"
121}
122
123// Another case of Zext.h
124// Source: `slliw r1, r0, 16` + `srliw r1, r1, 16`
125// Target: `zext.h r1, r0`
126class FusedZexth1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends FusedZexth(pair) {
127  override def inst1Cond: Bool = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U
128  override def inst2Cond: Bool = instr(1) === Instructions.SRLIW && inst2.SHAMT5 === 16.U
129
130  override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW)
131
132  override def fusionName: String = "slliw16_srliw16"
133}
134
135// Case: sign-extend a 16-bit number
136// Source: `slliw r1, r0, 16` + `sraiw r1, r1, 16`
137// Target: `sext.h r1, r0`
138class FusedSexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
139  def inst1Cond = instr(0) === Instructions.SLLIW && inst1.SHAMT5 === 16.U
140  def inst2Cond = instr(1) === Instructions.SRAIW && inst2.SHAMT5 === 16.U
141
142  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
143  override def thisInstr: Option[BitPat] = Some(Instructions.SLLIW)
144  override def fusedInstr: Option[BitPat] = Some(Instructions.SEXT_H)
145  override def lsrc2NeedZero: Boolean = true
146
147  def fusionName: String = "slliw16_sraiw16"
148}
149
150// Case: shift left by one and add
151// Source: `slli r1, r0, 1` + `add r1, r1, r2`
152// Target: `sh1add r1, r0, r2`
153class FusedSh1add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
154  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 1.U
155  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
156
157  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
158  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
159  override def fusedInstr: Option[BitPat] = Some(Instructions.SH1ADD)
160  override def lsrc2NeedMux: Boolean = true
161
162  def fusionName: String = "slli1_add"
163}
164
165// Case: shift left by two and add
166// Source: `slli r1, r0, 2` + `add r1, r1, r2`
167// Target: `sh2add r1, r0, r2`
168class FusedSh2add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
169  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 2.U
170  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
171
172  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
173  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
174  override def fusedInstr: Option[BitPat] = Some(Instructions.SH2ADD)
175  override def lsrc2NeedMux: Boolean = true
176
177  def fusionName: String = "slli2_add"
178}
179
180// Case: shift left by three and add
181// Source: `slli r1, r0, 3` + `add r1, r1, r2`
182// Target: `sh3add r1, r0, r2`
183class FusedSh3add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
184  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 3.U
185  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
186
187  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
188  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
189  override def fusedInstr: Option[BitPat] = Some(Instructions.SH3ADD)
190  override def lsrc2NeedMux: Boolean = true
191
192  def fusionName: String = "slli3_add"
193}
194
195// Case: shift zero-extended word left by one
196// Source: `slli r1, r0, 32` + `srli r1, r1, 31`
197// Target: `szewl1 r1, r0` (customized internal opcode)
198class FusedSzewl1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
199  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
200  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 31.U
201
202  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
203  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl1)
204
205  def fusionName: String = "slli32_srli31"
206}
207
208// Case: shift zero-extended word left by two
209// Source: `slli r1, r0, 32` + `srli r1, r1, 30`
210// Target: `szewl2 r1, r0` (customized internal opcode)
211class FusedSzewl2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
212  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
213  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 30.U
214
215  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
216  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl2)
217
218  def fusionName: String = "slli32_srli30"
219}
220
221// Case: shift zero-extended word left by three
222// Source: `slli r1, r0, 32` + `srli r1, r1, 29`
223// Target: `szewl3 r1, r0` (customized internal opcode)
224class FusedSzewl3(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
225  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 32.U
226  def inst2Cond = instr(1) === Instructions.SRLI && inst2.SHAMT6 === 29.U
227
228  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
229  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.szewl3)
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 && inst1.SHAMT6 === 8.U
239  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 255.U
240
241  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
242  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.byte2)
243
244  def fusionName: String = "srli8_andi255"
245}
246
247// Case: shift left by four and add
248// Source: `slli r1, r0, 4` + `add r1, r1, r2`
249// Target: `sh4add r1, r0, r2` (customized internal opcode)
250class FusedSh4add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
251  def inst1Cond = instr(0) === Instructions.SLLI && inst1.SHAMT6 === 4.U
252  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
253
254  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
255  override def thisInstr: Option[BitPat] = Some(Instructions.SLLI)
256  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
257  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sh4add)
258  override def lsrc2NeedMux: Boolean = true
259
260  def fusionName: String = "slli4_add"
261}
262
263// Case: shift right by 29 and add
264// Source: `srli r1, r0, 29` + `add r1, r1, r2`
265// Target: `sr29add r1, r0, r2` (customized internal opcode)
266class FusedSr29add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
267  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 29.U
268  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
269
270  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
271  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
272  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
273  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr29add)
274  override def lsrc2NeedMux: Boolean = true
275
276  def fusionName: String = "srli29_add"
277}
278
279// Case: shift right by 30 and add
280// Source: `srli r1, r0, 30` + `add r1, r1, r2`
281// Target: `sr30add r1, r0, r2` (customized internal opcode)
282class FusedSr30add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
283  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 30.U
284  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
285
286  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
287  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
288  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
289  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr30add)
290  override def lsrc2NeedMux: Boolean = true
291
292  def fusionName: String = "srli30_add"
293}
294
295// Case: shift right by 31 and add
296// Source: `srli r1, r0, 31` + `add r1, r1, r2`
297// Target: `sr31add r1, r0, r2` (customized internal opcode)
298class FusedSr31add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
299  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 31.U
300  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
301
302  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
303  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
304  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
305  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr31add)
306  override def lsrc2NeedMux: Boolean = true
307
308  def fusionName: String = "srli31_add"
309}
310
311// Case: shift right by 32 and add
312// Source: `srli r1, r0, 32` + `add r1, r1, r2`
313// Target: `sr32add r1, r0, r2` (customized internal opcode)
314class FusedSr32add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
315  def inst1Cond = instr(0) === Instructions.SRLI && inst1.SHAMT6 === 32.U
316  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
317
318  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
319  override def thisInstr: Option[BitPat] = Some(Instructions.SRLI)
320  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
321  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.sr32add)
322  override def lsrc2NeedMux: Boolean = true
323
324  def fusionName: String = "srli32_add"
325}
326
327// Case: add one if odd, otherwise unchanged
328// Source: `andi r1, r0, 1`` + `add r1, r1, r2`
329// Target: `oddadd r1, r0, r2` (customized internal opcode)
330class FusedOddadd(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
331  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U
332  def inst2Cond = instr(1) === Instructions.ADD && !instr2Rs1ToRs2
333
334  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
335  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
336  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
337  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddadd)
338  override def lsrc2NeedMux: Boolean = true
339
340  def fusionName: String = "andi1_add"
341}
342
343// Case: add one if odd (in word format), otherwise unchanged
344// Source: `andi r1, r0, 1`` + `addw r1, r1, r2`
345// Target: `oddaddw r1, r0, r2` (customized internal opcode)
346class FusedOddaddw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
347  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 1.U
348  def inst2Cond = instr(1) === Instructions.ADDW && !instr2Rs1ToRs2
349
350  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
351  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
352  override def fusedInstr: Option[BitPat] = Some(Instructions.ADD)
353  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.oddaddw)
354  override def lsrc2NeedMux: Boolean = true
355
356  def fusionName: String = "andi1_addw"
357}
358
359// Case: addw and extract its lower 8 bits (fused into addwbyte)
360class FusedAddwbyte(pair: Seq[Valid[UInt]])(implicit p: Parameters)
361  extends BaseFusionCase(pair) {
362  // the first instruction is a ALUOpType.addw
363  // According to DecodeUnit.scala, only ADDIW and ADDW are ALUOpType.addw, which are used for inst1Cond.
364  def inst1Cond = instr(0) === Instructions.ADDIW || instr(0) === Instructions.ADDW
365  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0xff.U
366
367  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
368  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbyte)
369
370  def fusionName: String = "addw_andi255"
371}
372
373// Case: addw and extract its lower 1 bit (fused into addwbit)
374class FusedAddwbit(pair: Seq[Valid[UInt]])(implicit p: Parameters)
375  extends FusedAddwbyte(pair) {
376
377  override def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 0x1.U
378
379  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwbit)
380
381  override def fusionName: String = "addw_andi1"
382}
383
384// Case: addw and zext.h (fused into addwzexth)
385class FusedAddwzexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
386  extends FusedAddwbyte(pair) {
387
388  override def inst2Cond = instr(1) === Instructions.ZEXT_H
389
390  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwzexth)
391
392  override def fusionName: String = "addw_zexth"
393}
394
395// Case: addw and sext.h (fused into addwsexth)
396class FusedAddwsexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
397  extends FusedAddwbyte(pair) {
398
399  override def inst2Cond = instr(1) === Instructions.SEXT_H
400
401  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.addwsexth)
402
403  override def fusionName: String = "addw_sexth"
404}
405
406// Case: logic operation and extract its LSB
407
408class FusedLogiclsb(pair: Seq[Valid[UInt]])(implicit p: Parameters)
409  extends BaseFusionCase(pair) {
410  // the first instruction is a logic (and, or, xor, orcb)
411  // (1) def ANDI               = BitPat("b?????????????????111?????0010011")
412  // (2) def AND                = BitPat("b0000000??????????111?????0110011")
413  // (3) def ORI                = BitPat("b?????????????????110?????0010011")
414  // (4) def OR                 = BitPat("b0000000??????????110?????0110011")
415  // (5) def XORI               = BitPat("b?????????????????100?????0010011")
416  // (6) def XOR                = BitPat("b0000000??????????100?????0110011")
417  // (7) def ORC_B              = BitPat("b001010000111?????101?????0010011")
418  val logicInstrList = Seq(Instructions.ANDI, Instructions.AND, Instructions.ORI, Instructions.OR,
419    Instructions.XORI, Instructions.XOR, Instructions.ORC_B)
420  def inst1Cond = VecInit(logicInstrList.map(_ === instr(0))).asUInt.orR
421  def inst2Cond = instr(1) === Instructions.ANDI && inst2.IMM12 === 1.U
422
423  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
424  override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToLsb)
425
426  def fusionName: String = "logic_andi1"
427}
428
429class FusedLogicZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters)
430  extends FusedLogiclsb(pair) {
431
432  override def inst2Cond = instr(1) === Instructions.ZEXT_H
433  override def fuOpType: Option[UInt => UInt] = Some(ALUOpType.logicToZexth)
434
435  override def fusionName: String = "logic_zexth"
436}
437
438// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2)
439// Source: `andi r1, r0, -256`` + `or r1, r1, r2`
440class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
441  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 0xf00.U
442  def inst2Cond = instr(1) === Instructions.OR && !instr2Rs1ToRs2
443
444  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
445  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
446  override def fusedInstr: Option[BitPat] = Some(Instructions.OR)
447  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.orh48)
448  override def lsrc2NeedMux: Boolean = true
449
450  def fusionName: String = "andi_f00_or"
451}
452
453// Case: mul 7bit data with 32-bit data
454// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2`
455// Target: `mulw7 r1, r0, r2`
456class FusedMulw7(pair: Seq[Valid[UInt]])(implicit p: Parameters)
457  extends BaseFusionCase(pair) {
458  def inst1Cond = instr(0) === Instructions.ANDI && inst1.IMM12 === 127.U
459  def inst2Cond = instr(1) === Instructions.MULW && !instr2Rs1ToRs2
460
461  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
462  override def thisInstr: Option[BitPat] = Some(Instructions.ANDI)
463  override def fusedInstr: Option[BitPat] = Some(Instructions.MULW)
464  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => MDUOpType.mulw7)
465  override def lsrc2NeedMux: Boolean = true
466
467  def fusionName: String = "andi127_mulw"
468}
469
470// Case: get 32 bits imm
471// Source: `lui r1, 0xffffa`` + `addi r1, r1, 1`
472// Target: `lui32 r1, 0xffffa001` (customized internal opcode)
473class FusedLui32(pair: Seq[Valid[UInt]])(implicit p: Parameters)
474  extends BaseFusionCase(pair) {
475  def inst1Cond = instr(0) === Instructions.LUI
476  def inst2Cond = instr(1) === Instructions.ADDI
477
478  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
479
480  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32add)
481  override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32)
482
483  def fusionName: String = "lui_addi"
484
485  XSDebug(isValid, p"[fusedLui32] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n")
486}
487
488// Case: get 32 bits imm (in word format)
489// Source: `lui r1, 0xffffa`` + `addiw r1, r1, 1`
490// Target: `lui32 r1, 0xffffa001` (customized internal opcode)
491class FusedLui32w(pair: Seq[Valid[UInt]])(implicit p: Parameters)
492  extends BaseFusionCase(pair) {
493  def inst1Cond = instr(0) === Instructions.LUI
494  def inst2Cond = instr(1) === Instructions.ADDIW
495
496  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
497
498  override def fuOpType: Option[UInt => UInt] = Some((_: UInt) => ALUOpType.lui32addw)
499  override def selImm: Option[UInt] = Some(SelImm.IMM_LUI32)
500
501  def fusionName: String = "lui_addiw"
502
503  XSDebug(isValid, p"[fusedLui32w] instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n")
504}
505
506class FusionDecodeInfo extends Bundle {
507  val rs2FromRs1 = Output(Bool())
508  val rs2FromRs2 = Output(Bool())
509  val rs2FromZero = Output(Bool())
510}
511
512class FusionDecodeReplace(implicit p: Parameters) extends XSBundle {
513  val fuType = Valid(FuType())
514  val fuOpType = Valid(FuOpType())
515  val lsrc2 = Valid(UInt(LogicRegsWidth.W))
516  val src2Type = Valid(SrcType())
517  val selImm = Valid(SelImm())
518
519  def update(cs: DecodedInst): Unit = {
520    when (fuType.valid) {
521      cs.fuType := fuType.bits
522    }
523    when (fuOpType.valid) {
524      cs.fuOpType := fuOpType.bits
525    }
526    when (lsrc2.valid) {
527      cs.lsrc(1) := lsrc2.bits
528    }
529    when (src2Type.valid) {
530      cs.srcType(1) := src2Type.bits
531    }
532    when (selImm.valid) {
533      cs.selImm := selImm.bits
534    }
535  }
536}
537
538class FusionDecoder(implicit p: Parameters) extends XSModule {
539  val io = IO(new Bundle {
540    val disableFusion = Input(Bool())
541    // T0: detect instruction fusions in these instructions
542    val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W))))
543    val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1)
544    // T1: decode result
545    val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1)
546    // T1: whether an instruction fusion is found
547    val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1)
548    val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1)
549    // T1: fused instruction needs to be cleared
550    val clear = Vec(DecodeWidth, Output(Bool()))
551  })
552
553  io.clear.head := false.B
554
555  val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2))
556  instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) =>
557    val fusionList = Seq(
558      new FusedAdduw(pair),
559      new FusedZexth(pair),
560      new FusedZexth1(pair),
561      new FusedSexth(pair),
562      new FusedSh1add(pair),
563      new FusedSh2add(pair),
564      new FusedSh3add(pair),
565      new FusedSzewl1(pair),
566      new FusedSzewl2(pair),
567      new FusedSzewl3(pair),
568      new FusedByte2(pair),
569      new FusedSh4add(pair),
570      new FusedSr29add(pair),
571      new FusedSr30add(pair),
572      new FusedSr31add(pair),
573      new FusedSr32add(pair),
574      new FusedOddadd(pair),
575      new FusedOddaddw(pair),
576      new FusedOrh48(pair),
577      new FusedMulw7(pair),
578      new FusedAddwbyte(pair),
579      new FusedAddwbit(pair),
580      new FusedAddwzexth(pair),
581      new FusedAddwsexth(pair),
582      new FusedLogiclsb(pair),
583      new FusedLogicZexth(pair),
584      new FusedLui32(pair),
585      new FusedLui32w(pair)
586    )
587    val fire = io.in(i).valid && io.inReady(i)
588    val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i))
589    val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire)
590    // HINT instructions are not considered for fusion.
591    // NOTE: The RD of some FENCE instructions are not 0, but they are also HINT instructions.
592    //       However, as FENCE instructions can never be fused, we do not need to consider them.
593    val notHint = RegEnable(VecInit(pair.map(_.bits(11, 7) =/= 0.U)).asUInt.andR, fire)
594    val enabled = RegEnable(!io.disableFusion, fire)
595    val thisCleared = io.clear(i)
596    out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR && notHint && enabled
597    XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n")
598    def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = {
599      field(out.bits).valid := false.B
600      field(out.bits).bits := DontCare
601      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined)
602      if (replaceVec.nonEmpty) {
603        // constant values are grouped together for better timing.
604        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
605        val replTypes = replaceVec.map(_._2.get).distinct
606        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR)
607        field(out.bits).valid := replEnable
608        field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U))
609      }
610    }
611    def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = {
612      field(out.bits).valid := false.B
613      field(out.bits).bits := DontCare
614      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))
615      if (replaceVec.nonEmpty) {
616        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
617        val replTypes = replaceVec.map(_._2).distinct
618        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR)
619        field(out.bits).valid := replEnable
620        field(out.bits).bits := Mux1H(replSel, replTypes)
621      }
622    }
623    def connectByUIntFunc(
624      field: FusionDecodeReplace => Valid[UInt],
625      csField: DecodedInst => UInt,
626      replace: Seq[Option[UInt => UInt]]
627    ): Unit = {
628      field(out.bits).valid := false.B
629      field(out.bits).bits := DontCare
630      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec))))
631      if (replaceVec.nonEmpty) {
632        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
633        // constant values are grouped together for better timing.
634        val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue))
635        val constReplTypes = constReplVec.map(_._2).distinct
636        val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR)
637        val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U))
638        // non-constant values have to be processed naively.
639        val noLitRepl = replaceVec.filterNot(_._2.isLit)
640        field(out.bits).valid := replEnable
641        field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult)
642      }
643    }
644    connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType))
645    connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType))
646    connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type))
647    connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false)
648
649    val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR
650    val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR
651    io.info(i).rs2FromZero := enabled && src2WithZero
652    io.info(i).rs2FromRs1 := enabled && src2WithMux && !RegEnable(fusionList.head.destToRs1, fire)
653    io.info(i).rs2FromRs2 := enabled && src2WithMux && RegEnable(fusionList.head.destToRs1, fire)
654    out.bits.lsrc2.valid := enabled && (src2WithMux || src2WithZero)
655    when (src2WithMux) {
656      out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire)
657    }.otherwise {//elsewhen (src2WithZero) {
658      out.bits.lsrc2.bits := 0.U
659    }
660    // TODO: assume every instruction fusion clears the second instruction now
661    io.clear(i + 1) := out.valid
662    val lastFire = RegNext(fire)
663    fusionList.zip(fusionVec).foreach { case (f, v) =>
664      XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire)
665    }
666    XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire)
667  }
668
669  XSPerfAccumulate("fused_instr", PopCount(io.out.zipWithIndex.map{ case (x, i) => x.valid && RegNext(io.in(i).valid && io.inReady(i)) }))
670}
671