xref: /XiangShan/src/main/scala/xiangshan/backend/decode/FusionDecoder.scala (revision fe528fd64820115f11edd2eb9d2ea08665ef7ba7)
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._
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
49  protected def getInstrTable(pat: BitPat): List[BitPat] = {
50    // Only these instructions can be fused now
51    val allDecodeTable = XDecode.table ++ X64Decode.table ++ BDecode.table
52    allDecodeTable.filter(_._1 == pat).map(_._2).head
53  }
54  // Must sync these indices with MicroOp.decode
55  protected def getInstrFuType(pat: BitPat): BitPat = getInstrTable(pat)(3)
56  protected def getInstrFuOpType(pat: BitPat): BitPat = getInstrTable(pat)(4)
57  protected def getInstrSrc1Type(pat: BitPat): BitPat = getInstrTable(pat)(0)
58  protected def getInstrSrc2Type(pat: BitPat): BitPat = getInstrTable(pat)(1)
59
60  def isValid: Bool
61  // To optimize the timing, only these control signals can be affected by instruction fusion.
62  def thisInstr: Option[BitPat] = None
63  def fusedInstr: Option[BitPat] = None
64  // By default, None means unchanged.
65  private def compareAndGet(func: BitPat => BitPat): Option[Int] = {
66    if (fusedInstr.isDefined) {
67      require(thisInstr.isDefined, "thisInstr must be defined to infer the ctrl signals")
68      val fused = func(fusedInstr.get)
69      // Only when the two instructions have different control field, we make it not None.
70      if (fused != func(thisInstr.get)) Some(fused.value.toInt) else None
71    } else None
72  }
73  // We assume only fuType, fuOpType, lsrc2 may be changed now.
74  def fuType: Option[Int] = compareAndGet(getInstrFuType)
75  def fuOpType: Option[UInt => UInt] = {
76    val t = compareAndGet(getInstrFuOpType)
77    if (t.isDefined) Some((_: UInt) => t.get.U) else None
78  }
79  def src2Type: Option[Int] = compareAndGet(getInstrSrc2Type)
80  def selImm: Option[UInt] = None
81  def imm: 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
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
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
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
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
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
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
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
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
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
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
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
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  override def imm: Option[UInt] = Some(Cat(instr(0)(31, 12), instr(1)(31, 20)))
483
484  def fusionName: String = "lui_addi"
485
486  XSDebug(isValid, p"[fusedLui32] ${Hexadecimal(imm.get)} instr0=${Hexadecimal(instr(0))} instr1=${Hexadecimal(instr(1))}\n")
487}
488
489class FusionDecodeInfo extends Bundle {
490  val rs2FromRs1 = Output(Bool())
491  val rs2FromRs2 = Output(Bool())
492  val rs2FromZero = Output(Bool())
493}
494
495class FusionDecodeReplace extends Bundle {
496  val fuType = Valid(FuType())
497  val fuOpType = Valid(FuOpType())
498  val lsrc2 = Valid(UInt(6.W))
499  val src2Type = Valid(SrcType())
500  val selImm = Valid(SelImm())
501  val imm = Valid(UInt(ImmUnion.maxLen.W))
502
503  def update(cs: DecodedInst): Unit = {
504    when (fuType.valid) {
505      cs.fuType := fuType.bits
506    }
507    when (fuOpType.valid) {
508      cs.fuOpType := fuOpType.bits
509    }
510    when (lsrc2.valid) {
511      cs.lsrc(1) := lsrc2.bits
512    }
513    when (src2Type.valid) {
514      cs.srcType(1) := src2Type.bits
515    }
516    when (selImm.valid) {
517      cs.selImm := selImm.bits
518    }
519    when (imm.valid) {
520      cs.imm := imm.bits
521    }
522  }
523}
524
525class FusionDecoder(implicit p: Parameters) extends XSModule {
526  val io = IO(new Bundle {
527    // T0: detect instruction fusions in these instructions
528    val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W))))
529    val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1)
530    // T1: decode result
531    val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1)
532    // T1: whether an instruction fusion is found
533    val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1)
534    val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1)
535    // T1: fused instruction needs to be cleared
536    val clear = Vec(DecodeWidth, Output(Bool()))
537  })
538
539  io.clear.head := false.B
540
541  val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2))
542  instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) =>
543    val fusionList = Seq(
544      new FusedAdduw(pair),
545      new FusedZexth(pair),
546      new FusedZexth1(pair),
547      new FusedSexth(pair),
548      new FusedSh1add(pair),
549      new FusedSh2add(pair),
550      new FusedSh3add(pair),
551      new FusedSzewl1(pair),
552      new FusedSzewl2(pair),
553      new FusedSzewl3(pair),
554      new FusedByte2(pair),
555      new FusedSh4add(pair),
556      new FusedSr29add(pair),
557      new FusedSr30add(pair),
558      new FusedSr31add(pair),
559      new FusedSr32add(pair),
560      new FusedOddadd(pair),
561      new FusedOddaddw(pair),
562      new FusedOrh48(pair),
563      new FusedMulw7(pair),
564      new FusedAddwbyte(pair),
565      new FusedAddwbit(pair),
566      new FusedAddwzexth(pair),
567      new FusedAddwsexth(pair),
568      new FusedLogiclsb(pair),
569      new FusedLogicZexth(pair),
570      new FusedLui32(pair)
571    )
572    val fire = io.in(i).valid && io.inReady(i)
573    val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i))
574    val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire)
575    val thisCleared = io.clear(i)
576    out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR
577    XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n")
578    def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = {
579      field(out.bits).valid := false.B
580      field(out.bits).bits := DontCare
581      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined)
582      if (replaceVec.nonEmpty) {
583        // constant values are grouped together for better timing.
584        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
585        val replTypes = replaceVec.map(_._2.get).distinct
586        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR)
587        field(out.bits).valid := replEnable
588        field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U))
589      }
590    }
591    def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = {
592      field(out.bits).valid := false.B
593      field(out.bits).bits := DontCare
594      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))
595      if (replaceVec.nonEmpty) {
596        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
597        val replTypes = replaceVec.map(_._2).distinct
598        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR)
599        field(out.bits).valid := replEnable
600        field(out.bits).bits := Mux1H(replSel, replTypes)
601      }
602    }
603    def connectByUIntFunc(
604      field: FusionDecodeReplace => Valid[UInt],
605      csField: DecodedInst => UInt,
606      replace: Seq[Option[UInt => UInt]]
607    ): Unit = {
608      field(out.bits).valid := false.B
609      field(out.bits).bits := DontCare
610      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec))))
611      if (replaceVec.nonEmpty) {
612        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
613        // constant values are grouped together for better timing.
614        val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue))
615        val constReplTypes = constReplVec.map(_._2).distinct
616        val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR)
617        val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U))
618        // non-constant values have to be processed naively.
619        val noLitRepl = replaceVec.filterNot(_._2.isLit)
620        field(out.bits).valid := replEnable
621        field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult)
622      }
623    }
624    connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType))
625    connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType))
626    connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type))
627    connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false)
628    connectByUInt((x: FusionDecodeReplace) => x.imm, fusionList.map(_.imm), true)
629    val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR
630    val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR
631    io.info(i).rs2FromZero := src2WithZero
632    io.info(i).rs2FromRs1 := src2WithMux && !RegEnable(fusionList.head.destToRs1, fire)
633    io.info(i).rs2FromRs2 := src2WithMux && RegEnable(fusionList.head.destToRs1, fire)
634    out.bits.lsrc2.valid := src2WithMux || src2WithZero
635    when (src2WithMux) {
636      out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire)
637    }.otherwise {//elsewhen (src2WithZero) {
638      out.bits.lsrc2.bits := 0.U
639    }
640    // TODO: assume every instruction fusion clears the second instruction now
641    io.clear(i + 1) := out.valid
642    val lastFire = RegNext(fire)
643    fusionList.zip(fusionVec).foreach { case (f, v) =>
644      XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire)
645    }
646    XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire)
647
648    XSDebug(out.valid, p"[fusion] valid ${i}, outvalid: ${out.bits.fuType.valid} ${out.bits.fuOpType.valid} ${out.bits.src2Type.valid} ${out.bits.lsrc2.valid} ${out.bits.selImm.valid} ${out.bits.imm.valid}\n")
649    XSDebug(out.valid, p"[fusion] valid ${i}, outbits: ${out.bits.fuType.bits} ${out.bits.fuOpType.bits} ${out.bits.src2Type.bits} ${out.bits.lsrc2.bits} ${out.bits.selImm.bits} ${Hexadecimal(out.bits.imm.bits)}\n")
650  }
651
652  XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire)))
653}
654