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