xref: /XiangShan/src/main/scala/xiangshan/backend/rob/ExceptionGen.scala (revision 8a020714df826c6ac860308700137855ecd6ba07)
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.rob
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import difftest._
23import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
24import utility._
25import utils._
26import xiangshan._
27import xiangshan.backend.BackendParams
28import xiangshan.backend.Bundles.{DynInst, ExceptionInfo, ExuOutput}
29import xiangshan.backend.fu.{FuConfig, FuType}
30import xiangshan.frontend.FtqPtr
31import xiangshan.mem.{LqPtr, LsqEnqIO, SqPtr}
32import xiangshan.backend.Bundles.{DynInst, ExceptionInfo, ExuOutput}
33import xiangshan.backend.ctrlblock.{DebugLSIO, DebugLsInfo, LsTopdownInfo}
34import xiangshan.backend.fu.vector.Bundles.VType
35import xiangshan.backend.rename.SnapshotGenerator
36
37class ExceptionGen(params: BackendParams)(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
38  val io = IO(new Bundle {
39    val redirect = Input(Valid(new Redirect))
40    val flush = Input(Bool())
41    val enq = Vec(RenameWidth, Flipped(ValidIO(new RobExceptionInfo)))
42    // csr + load + store + varith + vload + vstore
43    val wb = Vec(params.numException, Flipped(ValidIO(new RobExceptionInfo)))
44    val out = ValidIO(new RobExceptionInfo)
45    val state = ValidIO(new RobExceptionInfo)
46  })
47
48  val wbExuParams = params.allExuParams.filter(_.exceptionOut.nonEmpty)
49
50  def getOldest(valid: Seq[Bool], bits: Seq[RobExceptionInfo]): RobExceptionInfo = {
51    def getOldest_recursion(valid: Seq[Bool], bits: Seq[RobExceptionInfo]): (Seq[Bool], Seq[RobExceptionInfo]) = {
52      assert(valid.length == bits.length)
53      if (valid.length == 1) {
54        (valid, bits)
55      } else if (valid.length == 2) {
56        val res = Seq.fill(2)(Wire(ValidIO(chiselTypeOf(bits(0)))))
57        for (i <- res.indices) {
58          res(i).valid := valid(i)
59          res(i).bits := bits(i)
60        }
61        val oldest = Mux(!valid(1) || valid(0) && isAfter(bits(1).robIdx, bits(0).robIdx), res(0), res(1))
62        (Seq(oldest.valid), Seq(oldest.bits))
63      } else {
64        val left = getOldest_recursion(valid.take(valid.length / 2), bits.take(valid.length / 2))
65        val right = getOldest_recursion(valid.drop(valid.length / 2), bits.drop(valid.length / 2))
66        getOldest_recursion(left._1 ++ right._1, left._2 ++ right._2)
67      }
68    }
69    getOldest_recursion(valid, bits)._2.head
70  }
71
72
73  val currentValid = RegInit(false.B)
74  val current = Reg(new RobExceptionInfo)
75
76  // orR the exceptionVec
77  val lastCycleFlush = RegNext(io.flush)
78  val enq_s0_valid = VecInit(io.enq.map(e => e.valid && e.bits.has_exception && !lastCycleFlush))
79  val enq_s0_bits = WireInit(VecInit(io.enq.map(_.bits)))
80  enq_s0_bits zip io.enq foreach { case (sink, source) =>
81    sink.flushPipe := source.bits.flushPipe && !source.bits.hasException
82  }
83
84  // s0: compare wb in 6 groups
85  val csr_wb = io.wb.zip(wbExuParams).filter(_._2.fuConfigs.filter(t => t.isCsr).nonEmpty).map(_._1)
86  val load_wb = io.wb.zip(wbExuParams).filter(_._2.fuConfigs.filter(_.fuType == FuType.ldu).nonEmpty).map(_._1)
87  val store_wb = io.wb.zip(wbExuParams).filter(_._2.fuConfigs.filter(t => t.isSta || t.fuType == FuType.mou).nonEmpty).map(_._1)
88  val varith_wb = io.wb.zip(wbExuParams).filter(_._2.fuConfigs.filter(_.isVecArith).nonEmpty).map(_._1)
89  val vls_wb = io.wb.zip(wbExuParams).filter(_._2.fuConfigs.exists(x => FuType.FuTypeOrR(x.fuType, FuType.vecMem))).map(_._1)
90
91  val writebacks = Seq(csr_wb, load_wb, store_wb, varith_wb, vls_wb)
92  val in_wb_valids = writebacks.map(_.map(w => w.valid && w.bits.has_exception && !lastCycleFlush))
93  val wb_valid = in_wb_valids.zip(writebacks).map { case (valid, wb) =>
94    valid.zip(wb.map(_.bits)).map { case (v, bits) => v && !(bits.robIdx.needFlush(io.redirect) || io.flush) }.reduce(_ || _)
95  }
96  val wb_bits = in_wb_valids.zip(writebacks).map { case (valid, wb) => getOldest(valid, wb.map(_.bits))}
97
98  val s0_out_valid = wb_valid.map(x => RegNext(x))
99  val s0_out_bits = wb_bits.zip(wb_valid).map{ case(b, v) => RegEnable(b, v)}
100
101  // s1: compare last six and current flush
102  val s1_valid = VecInit(s0_out_valid.zip(s0_out_bits).map{ case (v, b) => v && !(b.robIdx.needFlush(io.redirect) || io.flush) })
103  val s1_out_bits = RegEnable(getOldest(s0_out_valid, s0_out_bits), s1_valid.asUInt.orR)
104  val s1_out_valid = RegNext(s1_valid.asUInt.orR)
105
106  val enq_s1_valid = RegNext(enq_s0_valid.asUInt.orR && !io.redirect.valid && !io.flush)
107  val enq_s1_bits: RobExceptionInfo = RegEnable(ParallelPriorityMux(enq_s0_valid, enq_s0_bits), enq_s0_valid.asUInt.orR && !io.redirect.valid && !io.flush)
108
109  // s2: compare the input exception with the current one
110  // priorities:
111  // (1) system reset
112  // (2) current is valid: flush, remain, merge, update
113  // (3) current is not valid: s1 or enq
114  val current_flush = current.robIdx.needFlush(io.redirect) || io.flush
115  val s1_flush = s1_out_bits.robIdx.needFlush(io.redirect) || io.flush
116  when (currentValid) {
117    when (current_flush) {
118      currentValid := Mux(s1_flush, false.B, s1_out_valid)
119    }
120    when (s1_out_valid && !s1_flush) {
121      when (isAfter(current.robIdx, s1_out_bits.robIdx)) {
122        current := s1_out_bits
123      }.elsewhen (current.robIdx === s1_out_bits.robIdx) {
124        current.exceptionVec := (s1_out_bits.exceptionVec.asUInt | current.exceptionVec.asUInt).asTypeOf(ExceptionVec())
125        current.flushPipe := s1_out_bits.flushPipe || current.flushPipe
126        current.replayInst := s1_out_bits.replayInst || current.replayInst
127        current.singleStep := s1_out_bits.singleStep || current.singleStep
128        current.trigger := (s1_out_bits.trigger | current.trigger)
129      }
130    }
131  }.elsewhen (s1_out_valid && !s1_flush) {
132    currentValid := true.B
133    current := s1_out_bits
134  }.elsewhen (enq_s1_valid && !(io.redirect.valid || io.flush)) {
135    currentValid := true.B
136    current := enq_s1_bits
137  }
138
139  io.out.valid   := s1_out_valid || enq_s1_valid && enq_s1_bits.can_writeback
140  io.out.bits    := Mux(s1_out_valid, s1_out_bits, enq_s1_bits)
141  io.state.valid := currentValid
142  io.state.bits  := current
143
144}