xref: /XiangShan/src/main/scala/xiangshan/backend/decode/FusionDecoder.scala (revision 7d62bb17e8791455fc1ef15407d427dbeab8af4c)
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    // T0: detect instruction fusions in these instructions
541    val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W))))
542    val inReady = Vec(DecodeWidth - 1, Input(Bool())) // dropRight(1)
543    // T1: decode result
544    val dec = Vec(DecodeWidth - 1, Input(new DecodedInst)) // dropRight(1)
545    // T1: whether an instruction fusion is found
546    val out = Vec(DecodeWidth - 1, ValidIO(new FusionDecodeReplace)) // dropRight(1)
547    val info = Vec(DecodeWidth - 1, new FusionDecodeInfo) // dropRight(1)
548    // T1: fused instruction needs to be cleared
549    val clear = Vec(DecodeWidth, Output(Bool()))
550  })
551
552  io.clear.head := false.B
553
554  val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2))
555  instrPairs.zip(io.dec).zip(io.out).zipWithIndex.foreach{ case (((pair, dec), out), i) =>
556    val fusionList = Seq(
557      new FusedAdduw(pair),
558      new FusedZexth(pair),
559      new FusedZexth1(pair),
560      new FusedSexth(pair),
561      new FusedSh1add(pair),
562      new FusedSh2add(pair),
563      new FusedSh3add(pair),
564      new FusedSzewl1(pair),
565      new FusedSzewl2(pair),
566      new FusedSzewl3(pair),
567      new FusedByte2(pair),
568      new FusedSh4add(pair),
569      new FusedSr29add(pair),
570      new FusedSr30add(pair),
571      new FusedSr31add(pair),
572      new FusedSr32add(pair),
573      new FusedOddadd(pair),
574      new FusedOddaddw(pair),
575      new FusedOrh48(pair),
576      new FusedMulw7(pair),
577      new FusedAddwbyte(pair),
578      new FusedAddwbit(pair),
579      new FusedAddwzexth(pair),
580      new FusedAddwsexth(pair),
581      new FusedLogiclsb(pair),
582      new FusedLogicZexth(pair),
583      new FusedLui32(pair),
584      new FusedLui32w(pair)
585    )
586    val fire = io.in(i).valid && io.inReady(i)
587    val instrPairValid = RegEnable(VecInit(pair.map(_.valid)).asUInt.andR, false.B, io.inReady(i))
588    val fusionVec = RegEnable(VecInit(fusionList.map(_.isValid)), fire)
589    // HINT instructions are not considered for fusion.
590    // NOTE: The RD of some FENCE instructions are not 0, but they are also HINT instructions.
591    //       However, as FENCE instructions can never be fused, we do not need to consider them.
592    val notHint = RegEnable(VecInit(pair.map(_.bits(11, 7) =/= 0.U)).asUInt.andR, fire)
593    val thisCleared = io.clear(i)
594    out.valid := instrPairValid && !thisCleared && fusionVec.asUInt.orR && notHint
595    XSError(instrPairValid && PopCount(fusionVec) > 1.U, "more then one fusion matched\n")
596    def connectByInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[Int]]): Unit = {
597      field(out.bits).valid := false.B
598      field(out.bits).bits := DontCare
599      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined)
600      if (replaceVec.nonEmpty) {
601        // constant values are grouped together for better timing.
602        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
603        val replTypes = replaceVec.map(_._2.get).distinct
604        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2.get == t).map(_._1)).asUInt.orR)
605        field(out.bits).valid := replEnable
606        field(out.bits).bits := Mux1H(replSel, replTypes.map(_.U))
607      }
608    }
609    def connectByUInt(field: FusionDecodeReplace => Valid[UInt], replace: Seq[Option[UInt]], needReg: Boolean): Unit = {
610      field(out.bits).valid := false.B
611      field(out.bits).bits := DontCare
612      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))
613      if (replaceVec.nonEmpty) {
614        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
615        val replTypes = replaceVec.map(_._2).distinct
616        val replSel = replTypes.map(t => VecInit(replaceVec.filter(_._2 == t).map(_._1)).asUInt.orR)
617        field(out.bits).valid := replEnable
618        field(out.bits).bits := Mux1H(replSel, replTypes)
619      }
620    }
621    def connectByUIntFunc(
622      field: FusionDecodeReplace => Valid[UInt],
623      csField: DecodedInst => UInt,
624      replace: Seq[Option[UInt => UInt]]
625    ): Unit = {
626      field(out.bits).valid := false.B
627      field(out.bits).bits := DontCare
628      val replaceVec = fusionVec.zip(replace).filter(_._2.isDefined).map(x => (x._1, x._2.get(csField(dec))))
629      if (replaceVec.nonEmpty) {
630        val replEnable = VecInit(replaceVec.map(_._1)).asUInt.orR
631        // constant values are grouped together for better timing.
632        val constReplVec = replaceVec.filter(_._2.isLit).map(x => (x._1, x._2.litValue))
633        val constReplTypes = constReplVec.map(_._2).distinct
634        val constReplEnable = constReplTypes.map(t => VecInit(constReplVec.filter(_._2 == t).map(_._1)).asUInt.orR)
635        val constReplResult = Mux1H(constReplEnable, constReplTypes.map(_.U))
636        // non-constant values have to be processed naively.
637        val noLitRepl = replaceVec.filterNot(_._2.isLit)
638        field(out.bits).valid := replEnable
639        field(out.bits).bits := Mux(VecInit(noLitRepl.map(_._1)).asUInt.orR, Mux1H(noLitRepl), constReplResult)
640      }
641    }
642    connectByInt((x: FusionDecodeReplace) => x.fuType, fusionList.map(_.fuType))
643    connectByUIntFunc((x: FusionDecodeReplace) => x.fuOpType, (x: DecodedInst) => x.fuOpType, fusionList.map(_.fuOpType))
644    connectByInt((x: FusionDecodeReplace) => x.src2Type, fusionList.map(_.src2Type))
645    connectByUInt((x: FusionDecodeReplace) => x.selImm, fusionList.map(_.selImm), false)
646
647    val src2WithZero = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedZero)).filter(_._2).map(_._1)).asUInt.orR
648    val src2WithMux = VecInit(fusionVec.zip(fusionList.map(_.lsrc2NeedMux)).filter(_._2).map(_._1)).asUInt.orR
649    io.info(i).rs2FromZero := src2WithZero
650    io.info(i).rs2FromRs1 := src2WithMux && !RegEnable(fusionList.head.destToRs1, fire)
651    io.info(i).rs2FromRs2 := src2WithMux && RegEnable(fusionList.head.destToRs1, fire)
652    out.bits.lsrc2.valid := src2WithMux || src2WithZero
653    when (src2WithMux) {
654      out.bits.lsrc2.bits := RegEnable(fusionList.head.lsrc2MuxResult, fire)
655    }.otherwise {//elsewhen (src2WithZero) {
656      out.bits.lsrc2.bits := 0.U
657    }
658    // TODO: assume every instruction fusion clears the second instruction now
659    io.clear(i + 1) := out.valid
660    val lastFire = RegNext(fire)
661    fusionList.zip(fusionVec).foreach { case (f, v) =>
662      XSPerfAccumulate(s"case_${f.fusionName}_$i", instrPairValid && !thisCleared && v && lastFire)
663    }
664    XSPerfAccumulate(s"conflict_fusion_$i", instrPairValid && thisCleared && fusionVec.asUInt.orR && lastFire)
665  }
666
667  XSPerfAccumulate("fused_instr", PopCount(io.out.zipWithIndex.map{ case (x, i) => x.valid && RegNext(io.in(i).valid && io.inReady(i)) }))
668}
669