xref: /XiangShan/src/main/scala/xiangshan/backend/decode/FusionDecoder.scala (revision 708ceed4afe43fb0ea3a52407e46b2794c573634)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.backend.decode
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util.BitPat.bitPatToUInt
22import chisel3.util._
23import xiangshan._
24import utils._
25
26abstract class BaseFusionCase(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]] = None)(implicit p: Parameters)
27  extends DecodeUnitConstants {
28  require(pair.length == 2)
29
30  protected def instr: Seq[UInt] = pair.map(_.bits)
31  protected def pairValid: Bool = VecInit(pair.map(_.valid)).asUInt().andR()
32  protected def instr1Rs1: UInt = instr(0)(RS1_MSB, RS1_LSB)
33  protected def instr1Rs2: UInt = instr(0)(RS2_MSB, RS2_LSB)
34  protected def instr1Rd: UInt = instr(0)(RD_MSB, RD_LSB)
35  protected def instr2Rs1: UInt = instr(1)(RS1_MSB, RS1_LSB)
36  protected def instr2Rs2: UInt = instr(1)(RS2_MSB, RS2_LSB)
37  protected def instr2Rd: UInt = instr(1)(RD_MSB, RD_LSB)
38  protected def withSameDest: Bool = instr1Rd === instr2Rd
39  protected def destToRs1: Bool = instr1Rd === instr2Rs1
40  protected def destToRs2: Bool = instr1Rd === instr2Rs2
41
42  protected def getBaseCS(pat: BitPat): CtrlSignals = {
43    val allDecodeTable = XDecode.table ++ X64Decode.table ++ BDecode.table
44    val baseTable = allDecodeTable.filter(_._1 == pat).map(_._2).head
45    val cs = Wire(new CtrlSignals)
46    cs := DontCare
47    cs.decode(baseTable)
48    // For simple instruction fusions, we assume their destination registers are the same.
49    cs.ldest := instr1Rd
50    cs
51  }
52
53  def isValid: Bool
54  // TODO: optimize timing
55  def target: CtrlSignals
56  // clear the next instruction
57  // def needClear: Boolean = true
58  def fusionName: String
59}
60
61// Case: clear upper 32 bits / get lower 32 bits
62// Source: `slli r1, r0, 32` + `srli r1, r1, 32`
63// Target: `add.uw r1, r0, zero` (pseudo instruction: `zext.w r1, r0`)
64class FusedAdduw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
65  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U
66  def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 32.U
67
68  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
69  def target: CtrlSignals = {
70    val cs = getBaseCS(Instructions.ADDU_W)
71    cs.lsrc(0) := instr1Rs1
72    cs.lsrc(1) := 0.U
73    cs
74  }
75
76  def fusionName: String = "slli32_srli32"
77}
78
79// Case: clear upper 48 bits / get lower 16 bits
80// Source: `slli r1, r0, 48` + `srli r1, r1, 48`
81// Target: `zext.h r1, r0`
82class FusedZexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
83  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 48.U
84  def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 48.U
85
86  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
87  def target: CtrlSignals = {
88    val cs = getBaseCS(Instructions.PACKW)
89    cs.lsrc(0) := instr1Rs1
90    cs.lsrc(1) := 0.U
91    cs
92  }
93
94  def fusionName: String = "slli48_srli48"
95}
96
97// Another case of Zext.h
98// Source: `slliw r1, r0, 16` + `srliw r1, r1, 16`
99// Target: `zext.h r1, r0`
100class FusedZexth1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends FusedZexth(pair) {
101  override def inst1Cond: Bool = instr(0) === Instructions.SLLIW && instr(0)(24, 20) === 16.U
102  override def inst2Cond: Bool = instr(1) === Instructions.SRLIW && instr(1)(24, 20) === 16.U
103
104  override def fusionName: String = "slliw16_srliw16"
105}
106
107// Case: sign-extend a 16-bit number
108// Source: `slliw r1, r0, 16` + `sraiw r1, r1, 16`
109// Target: `sext.h r1, r0`
110class FusedSexth(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
111  def inst1Cond = instr(0) === Instructions.SLLIW && instr(0)(24, 20) === 16.U
112  def inst2Cond = instr(1) === Instructions.SRAIW && instr(1)(24, 20) === 16.U
113
114  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
115  def target: CtrlSignals = {
116    val cs = getBaseCS(Instructions.SEXT_H)
117    cs.lsrc(0) := instr1Rs1
118    cs
119  }
120
121  def fusionName: String = "slliw16_sraiw16"
122}
123
124// Case: shift left by one and add
125// Source: `slli r1, r0, 1` + `add r1, r1, r2`
126// Target: `sh1add r1, r0, r2`
127class FusedSh1add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
128  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 1.U
129  def inst2Cond = instr(1) === Instructions.ADD
130
131  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
132  def target: CtrlSignals = {
133    val cs = getBaseCS(Instructions.SH1ADD)
134    cs.lsrc(0) := instr1Rs1
135    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
136    cs
137  }
138
139  def fusionName: String = "slli1_add"
140}
141
142// Case: shift left by two and add
143// Source: `slli r1, r0, 2` + `add r1, r1, r2`
144// Target: `sh2add r1, r0, r2`
145class FusedSh2add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
146  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 2.U
147  def inst2Cond = instr(1) === Instructions.ADD
148
149  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
150  def target: CtrlSignals = {
151    val cs = getBaseCS(Instructions.SH2ADD)
152    cs.lsrc(0) := instr1Rs1
153    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
154    cs
155  }
156
157  def fusionName: String = "slli2_add"
158}
159
160// Case: shift left by three and add
161// Source: `slli r1, r0, 3` + `add r1, r1, r2`
162// Target: `sh3add r1, r0, r2`
163class FusedSh3add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
164  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 3.U
165  def inst2Cond = instr(1) === Instructions.ADD
166
167  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
168  def target: CtrlSignals = {
169    val cs = getBaseCS(Instructions.SH3ADD)
170    cs.lsrc(0) := instr1Rs1
171    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
172    cs
173  }
174
175  def fusionName: String = "slli3_add"
176}
177
178// Case: shift zero-extended word left by one
179// Source: `slli r1, r0, 32` + `srli r1, r0, 31`
180// Target: `szewl1 r1, r0` (customized internal opcode)
181class FusedSzewl1(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
182  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U
183  def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 31.U
184
185  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
186  def target: CtrlSignals = {
187    val cs = getBaseCS(Instructions.SEXT_H)
188    // replace the fuOpType with szewl1
189    cs.fuOpType := ALUOpType.szewl1
190    cs.lsrc(0) := instr1Rs1
191    cs
192  }
193
194  def fusionName: String = "slli32_srli31"
195}
196
197// Case: shift zero-extended word left by two
198// Source: `slli r1, r0, 32` + `srli r1, r0, 30`
199// Target: `szewl2 r1, r0` (customized internal opcode)
200class FusedSzewl2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
201  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U
202  def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 30.U
203
204  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
205  def target: CtrlSignals = {
206    val cs = getBaseCS(Instructions.SEXT_H)
207    // replace the fuOpType with szewl2
208    cs.fuOpType := ALUOpType.szewl2
209    cs.lsrc(0) := instr1Rs1
210    cs
211  }
212
213  def fusionName: String = "slli32_srli30"
214}
215
216// Case: shift zero-extended word left by three
217// Source: `slli r1, r0, 32` + `srli r1, r0, 29`
218// Target: `szewl3 r1, r0` (customized internal opcode)
219class FusedSzewl3(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
220  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 32.U
221  def inst2Cond = instr(1) === Instructions.SRLI && instr(1)(25, 20) === 29.U
222
223  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
224  def target: CtrlSignals = {
225    val cs = getBaseCS(Instructions.SEXT_H)
226    // replace the fuOpType with szewl3
227    cs.fuOpType := ALUOpType.szewl3
228    cs.lsrc(0) := instr1Rs1
229    cs
230  }
231
232  def fusionName: String = "slli32_srli29"
233}
234
235// Case: get the second byte
236// Source: `srli r1, r0, 8` + `andi r1, r1, 255`
237// Target: `byte2 r1, r0` (customized internal opcode)
238class FusedByte2(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
239  def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 8.U
240  def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 255.U
241
242  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
243  def target: CtrlSignals = {
244    val cs = getBaseCS(Instructions.SEXT_H)
245    // replace the fuOpType with byte2
246    cs.fuOpType := ALUOpType.byte2
247    cs.lsrc(0) := instr1Rs1
248    cs
249  }
250
251  def fusionName: String = "srli8_andi255"
252}
253
254// Case: shift left by four and add
255// Source: `slli r1, r0, 4` + `add r1, r1, r2`
256// Target: `sh4add r1, r0, r2` (customized internal opcode)
257class FusedSh4add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
258  def inst1Cond = instr(0) === Instructions.SLLI && instr(0)(25, 20) === 4.U
259  def inst2Cond = instr(1) === Instructions.ADD
260
261  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
262  def target: CtrlSignals = {
263    val cs = getBaseCS(Instructions.SH3ADD)
264    // replace the fuOpType with sh4add
265    cs.fuOpType := ALUOpType.sh4add
266    cs.lsrc(0) := instr1Rs1
267    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
268    cs
269  }
270
271  def fusionName: String = "slli4_add"
272}
273
274// Case: shift right by 29 and add
275// Source: `srli r1, r0, 29` + `add r1, r1, r2`
276// Target: `sr29add r1, r0, r2` (customized internal opcode)
277class FusedSr29add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
278  def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 29.U
279  def inst2Cond = instr(1) === Instructions.ADD
280
281  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
282  def target: CtrlSignals = {
283    val cs = getBaseCS(Instructions.SH3ADD)
284    // replace the fuOpType with sr29add
285    cs.fuOpType := ALUOpType.sr29add
286    cs.lsrc(0) := instr1Rs1
287    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
288    cs
289  }
290
291  def fusionName: String = "srli29_add"
292}
293
294// Case: shift right by 30 and add
295// Source: `srli r1, r0, 30` + `add r1, r1, r2`
296// Target: `sr30add r1, r0, r2` (customized internal opcode)
297class FusedSr30add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
298  def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 30.U
299  def inst2Cond = instr(1) === Instructions.ADD
300
301  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
302  def target: CtrlSignals = {
303    val cs = getBaseCS(Instructions.SH3ADD)
304    // replace the fuOpType with sr30add
305    cs.fuOpType := ALUOpType.sr30add
306    cs.lsrc(0) := instr1Rs1
307    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
308    cs
309  }
310
311  def fusionName: String = "srli30_add"
312}
313
314// Case: shift right by 31 and add
315// Source: `srli r1, r0, 31` + `add r1, r1, r2`
316// Target: `sr31add r1, r0, r2` (customized internal opcode)
317class FusedSr31add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
318  def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 31.U
319  def inst2Cond = instr(1) === Instructions.ADD
320
321  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
322  def target: CtrlSignals = {
323    val cs = getBaseCS(Instructions.SH3ADD)
324    // replace the fuOpType with sr31add
325    cs.fuOpType := ALUOpType.sr31add
326    cs.lsrc(0) := instr1Rs1
327    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
328    cs
329  }
330
331  def fusionName: String = "srli31_add"
332}
333
334// Case: shift right by 32 and add
335// Source: `srli r1, r0, 32` + `add r1, r1, r2`
336// Target: `sr32add r1, r0, r2` (customized internal opcode)
337class FusedSr32add(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
338  def inst1Cond = instr(0) === Instructions.SRLI && instr(0)(25, 20) === 32.U
339  def inst2Cond = instr(1) === Instructions.ADD
340
341  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
342  def target: CtrlSignals = {
343    val cs = getBaseCS(Instructions.SH3ADD)
344    // replace the fuOpType with sr32add
345    cs.fuOpType := ALUOpType.sr32add
346    cs.lsrc(0) := instr1Rs1
347    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
348    cs
349  }
350
351  def fusionName: String = "srli32_add"
352}
353
354// Case: add one if odd, otherwise unchanged
355// Source: `andi r1, r0, 1`` + `add r1, r1, r2`
356// Target: `oddadd r1, r0, r2` (customized internal opcode)
357class FusedOddadd(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
358  def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 1.U
359  def inst2Cond = instr(1) === Instructions.ADD
360
361  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
362  def target: CtrlSignals = {
363    val cs = getBaseCS(Instructions.SH3ADD)
364    // replace the fuOpType with oddadd
365    cs.fuOpType := ALUOpType.oddadd
366    cs.lsrc(0) := instr1Rs1
367    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
368    cs
369  }
370
371  def fusionName: String = "andi1_add"
372}
373
374// Case: add one if odd (in word format), otherwise unchanged
375// Source: `andi r1, r0, 1`` + `addw r1, r1, r2`
376// Target: `oddaddw r1, r0, r2` (customized internal opcode)
377class FusedOddaddw(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
378  def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 1.U
379  def inst2Cond = instr(1) === Instructions.ADDW
380
381  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
382  def target: CtrlSignals = {
383    val cs = getBaseCS(Instructions.SH3ADD)
384    // replace the fuOpType with oddaddw
385    cs.fuOpType := ALUOpType.oddaddw
386    cs.lsrc(0) := instr1Rs1
387    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
388    cs
389  }
390
391  def fusionName: String = "andi1_addw"
392}
393
394// Case: addw and extract its lower 8 bits (fused into addwbyte)
395class FusedAddwbyte(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
396  extends BaseFusionCase(pair, csPair) {
397  require(csPair.isDefined)
398
399  // the first instruction is a addw
400  def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isAddw(csPair.get(0).fuOpType)
401  def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 0xff.U
402
403  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
404  def target: CtrlSignals = {
405    val cs = WireInit(csPair.get(0))
406    // replace the fuOpType with addwbyte
407    cs.fuOpType := ALUOpType.addwbyte
408    cs
409  }
410
411  def fusionName: String = "addw_andi255"
412}
413
414// Case: addw and extract its lower 1 bit (fused into addwbit)
415class FusedAddwbit(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
416  extends FusedAddwbyte(pair, csPair) {
417
418  override def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 0x1.U
419  override def target: CtrlSignals = {
420    val cs = WireInit(csPair.get(0))
421    // replace the fuOpType with addwbit
422    cs.fuOpType := ALUOpType.addwbit
423    cs
424  }
425
426  override def fusionName: String = "addw_andi1"
427}
428
429// Case: addw and zext.h (fused into addwzexth)
430class FusedAddwzexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
431  extends FusedAddwbyte(pair, csPair) {
432
433  override def inst2Cond = instr(1) === Instructions.ZEXT_H
434  override def target: CtrlSignals = {
435    val cs = WireInit(csPair.get(0))
436    // replace the fuOpType with addwzexth
437    cs.fuOpType := ALUOpType.addwzexth
438    cs
439  }
440
441  override def fusionName: String = "addw_zexth"
442}
443
444// Case: addw and sext.h (fused into addwsexth)
445class FusedAddwsexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
446  extends FusedAddwbyte(pair, csPair) {
447
448  override def inst2Cond = instr(1) === Instructions.SEXT_H
449  override def target: CtrlSignals = {
450    val cs = WireInit(csPair.get(0))
451    // replace the fuOpType with addwsexth
452    cs.fuOpType := ALUOpType.addwsexth
453    cs
454  }
455
456  override def fusionName: String = "addw_sexth"
457}
458
459// Case: logic operation and extract its LSB
460class FusedLogiclsb(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
461  extends BaseFusionCase(pair, csPair) {
462  require(csPair.isDefined)
463
464  // the first instruction is a logic
465  def inst1Cond = csPair.get(0).fuType === FuType.alu && ALUOpType.isSimpleLogic(csPair.get(0).fuOpType)
466  def inst2Cond = instr(1) === Instructions.ANDI && instr(1)(31, 20) === 1.U
467
468  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && destToRs1
469  def target: CtrlSignals = {
470    val cs = WireInit(csPair.get(0))
471    // change the opType to lsb format
472    cs.fuOpType := ALUOpType.logicToLsb(csPair.get(0).fuOpType)
473    cs
474  }
475
476  def fusionName: String = "logic_andi1"
477}
478
479class FusedLogicZexth(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
480  extends FusedLogiclsb(pair, csPair) {
481
482  override def inst2Cond = instr(1) === Instructions.ZEXT_H
483  override def target: CtrlSignals = {
484    val cs = WireInit(csPair.get(0))
485    // change the opType to lzext format
486    cs.fuOpType := ALUOpType.logicToZexth(csPair.get(0).fuOpType)
487    cs
488  }
489
490  override def fusionName: String = "logic_zexth"
491}
492
493// Case: OR(Cat(src1(63, 8), 0.U(8.W)), src2)
494// Source: `andi r1, r0, -256`` + `or r1, r1, r2`
495class FusedOrh48(pair: Seq[Valid[UInt]])(implicit p: Parameters) extends BaseFusionCase(pair) {
496  def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 0xf00.U
497  def inst2Cond = instr(1) === Instructions.OR
498
499  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
500  def target: CtrlSignals = {
501    val cs = getBaseCS(Instructions.OR)
502    // replace the fuOpType with orh48
503    cs.fuOpType := ALUOpType.orh48
504    cs.lsrc(0) := instr1Rs1
505    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
506    cs
507  }
508
509  def fusionName: String = "andi_f00_or"
510}
511
512// Case: mul 7bit data with 32-bit data
513// Source: `andi r1, r0, 127`` + `mulw r1, r1, r2`
514// Target: `mulw7 r1, r0, r2`
515class FusedMulw7(pair: Seq[Valid[UInt]], csPair: Option[Seq[CtrlSignals]])(implicit p: Parameters)
516  extends BaseFusionCase(pair, csPair) {
517  require(csPair.isDefined)
518
519  def inst1Cond = instr(0) === Instructions.ANDI && instr(0)(31, 20) === 127.U
520  def inst2Cond = instr(1) === Instructions.MULW
521
522  def isValid: Bool = inst1Cond && inst2Cond && withSameDest && (destToRs1 || destToRs2)
523  def target: CtrlSignals = {
524    // use MULW as the base
525    val cs = WireInit(csPair.get(1))
526    // replace the fuOpType with mulw7
527    cs.fuOpType := MDUOpType.mulw7
528    cs.lsrc(0) := instr1Rs1
529    cs.lsrc(1) := Mux(destToRs1, instr2Rs2, instr2Rs1)
530    cs
531  }
532
533  def fusionName: String = "andi127_mulw"
534}
535
536class FusionDecoder(implicit p: Parameters) extends XSModule {
537  val io = IO(new Bundle {
538    // detect instruction fusions in these instructions
539    val in = Vec(DecodeWidth, Flipped(ValidIO(UInt(32.W))))
540    val dec = Vec(DecodeWidth, Input(new CtrlSignals()))
541    // whether an instruction fusion is found
542    val out = Vec(DecodeWidth - 1, DecoupledIO(new CtrlSignals))
543    // fused instruction needs to be cleared
544    val clear = Vec(DecodeWidth, Output(Bool()))
545  })
546
547  io.clear.head := false.B
548
549  val instrPairs = io.in.dropRight(1).zip(io.in.drop(1)).map(x => Seq(x._1, x._2))
550  val csPairs = io.dec.dropRight(1).zip(io.dec.drop(1)).map(x => Seq(x._1, x._2))
551  instrPairs.zip(csPairs).zip(io.out).zipWithIndex.foreach{ case (((pair, cs), out), i) =>
552    val fusionList = Seq(
553      new FusedAdduw(pair),
554      new FusedZexth(pair),
555      new FusedZexth1(pair),
556      new FusedSexth(pair),
557      new FusedSh1add(pair),
558      new FusedSh2add(pair),
559      new FusedSh3add(pair),
560      new FusedSzewl1(pair),
561      new FusedSzewl2(pair),
562      new FusedSzewl3(pair),
563      new FusedByte2(pair),
564      new FusedSh4add(pair),
565      new FusedSr29add(pair),
566      new FusedSr30add(pair),
567      new FusedSr31add(pair),
568      new FusedSr32add(pair),
569      new FusedOddadd(pair),
570      new FusedOddaddw(pair),
571      new FusedAddwbyte(pair, Some(cs)),
572      new FusedAddwbit(pair, Some(cs)),
573      new FusedAddwzexth(pair, Some(cs)),
574      new FusedAddwsexth(pair, Some(cs)),
575      new FusedLogiclsb(pair, Some(cs)),
576      new FusedLogicZexth(pair, Some(cs)),
577      new FusedOrh48(pair),
578      new FusedMulw7(pair, Some(cs))
579    )
580    val pairValid = VecInit(pair.map(_.valid)).asUInt().andR
581    val thisCleared = io.clear(i)
582    val fusionVec = VecInit(fusionList.map(_.isValid))
583    out.valid := pairValid && !thisCleared && fusionVec.asUInt().orR()
584    XSError(PopCount(fusionVec) > 1.U, "more then one fusion matched\n")
585    out.bits := Mux1H(fusionVec, fusionList.map(_.target))
586    // TODO: assume every instruction fusion clears the second instruction now
587    io.clear(i + 1) := out.valid
588    fusionList.zip(fusionVec).foreach { case (f, v) =>
589      XSPerfAccumulate(s"case_${f.fusionName}_$i", pairValid && !thisCleared && v && out.ready)
590    }
591    XSPerfAccumulate(s"conflict_fusion_$i", pairValid && thisCleared && fusionVec.asUInt().orR() && out.ready)
592  }
593
594  XSPerfAccumulate("fused_instr", PopCount(io.out.map(_.fire)))
595}
596