xref: /XiangShan/src/main/scala/xiangshan/mem/pipeline/AtomicsUnit.scala (revision 2225d46ebbe2fd16b9b29963c27a7d0385a42709)
1package xiangshan.mem
2
3import chipsalliance.rocketchip.config.Parameters
4import chisel3._
5import chisel3.util._
6import utils._
7import xiangshan._
8import xiangshan.cache.{DCacheWordIO, TlbRequestIO, TlbCmd, MemoryOpConstants}
9import difftest._
10
11class AtomicsUnit(implicit p: Parameters) extends XSModule with MemoryOpConstants{
12  val io = IO(new Bundle() {
13    val in            = Flipped(Decoupled(new ExuInput))
14    val out           = Decoupled(new ExuOutput)
15    val dcache        = new DCacheWordIO
16    val dtlb          = new TlbRequestIO
17    val rsIdx         = Input(UInt(log2Up(IssQueSize).W))
18    val flush_sbuffer = new SbufferFlushBundle
19    val tlbFeedback   = ValidIO(new TlbFeedback)
20    val redirect      = Flipped(ValidIO(new Redirect))
21    val flush      = Input(Bool())
22    val exceptionAddr = ValidIO(UInt(VAddrBits.W))
23  })
24
25  //-------------------------------------------------------
26  // Atomics Memory Accsess FSM
27  //-------------------------------------------------------
28  val s_invalid :: s_tlb  :: s_flush_sbuffer_req :: s_flush_sbuffer_resp :: s_cache_req :: s_cache_resp :: s_finish :: Nil = Enum(7)
29  val state = RegInit(s_invalid)
30  val in = Reg(new ExuInput())
31  val exceptionVec = RegInit(0.U.asTypeOf(ExceptionVec()))
32  val atom_override_xtval = RegInit(false.B)
33  // paddr after translation
34  val paddr = Reg(UInt())
35  val is_mmio = Reg(Bool())
36  // dcache response data
37  val resp_data = Reg(UInt())
38  val resp_data_wire = WireInit(0.U)
39  val is_lrsc_valid = Reg(Bool())
40
41  // Difftest signals
42  val paddr_reg = Reg(UInt(64.W))
43  val data_reg = Reg(UInt(64.W))
44  val mask_reg = Reg(UInt(8.W))
45  val fuop_reg = Reg(UInt(8.W))
46
47  io.exceptionAddr.valid := atom_override_xtval
48  io.exceptionAddr.bits  := in.src1
49
50  // assign default value to output signals
51  io.in.ready          := false.B
52  io.out.valid         := false.B
53  io.out.bits          := DontCare
54
55  io.dcache.req.valid  := false.B
56  io.dcache.req.bits   := DontCare
57  io.dcache.resp.ready := false.B
58
59  io.dtlb.req.valid    := false.B
60  io.dtlb.req.bits     := DontCare
61  io.dtlb.resp.ready   := false.B
62
63  io.flush_sbuffer.valid := false.B
64
65  XSDebug("state: %d\n", state)
66
67  when (state === s_invalid) {
68    io.in.ready := true.B
69    when (io.in.fire()) {
70      in := io.in.bits
71      state := s_tlb
72    }
73  }
74
75  // Send TLB feedback to store issue queue
76  // we send feedback right after we receives request
77  // also, we always treat amo as tlb hit
78  // since we will continue polling tlb all by ourself
79  io.tlbFeedback.valid       := RegNext(RegNext(io.in.valid))
80  io.tlbFeedback.bits.hit    := true.B
81  io.tlbFeedback.bits.rsIdx  := RegEnable(io.rsIdx, io.in.valid)
82  io.tlbFeedback.bits.flushState := DontCare
83
84  // tlb translation, manipulating signals && deal with exception
85  when (state === s_tlb) {
86    // send req to dtlb
87    // keep firing until tlb hit
88    io.dtlb.req.valid       := true.B
89    io.dtlb.req.bits.vaddr  := in.src1
90    io.dtlb.req.bits.roqIdx := in.uop.roqIdx
91    io.dtlb.resp.ready      := true.B
92    val is_lr = in.uop.ctrl.fuOpType === LSUOpType.lr_w || in.uop.ctrl.fuOpType === LSUOpType.lr_d
93    io.dtlb.req.bits.cmd    := Mux(is_lr, TlbCmd.atom_read, TlbCmd.atom_write)
94    io.dtlb.req.bits.debug.pc := in.uop.cf.pc
95    io.dtlb.req.bits.debug.isFirstIssue := false.B
96
97    when(io.dtlb.resp.fire && !io.dtlb.resp.bits.miss){
98      // exception handling
99      val addrAligned = LookupTree(in.uop.ctrl.fuOpType(1,0), List(
100        "b00".U   -> true.B,              //b
101        "b01".U   -> (in.src1(0) === 0.U),   //h
102        "b10".U   -> (in.src1(1,0) === 0.U), //w
103        "b11".U   -> (in.src1(2,0) === 0.U)  //d
104      ))
105      exceptionVec(storeAddrMisaligned) := !addrAligned
106      exceptionVec(storePageFault)      := io.dtlb.resp.bits.excp.pf.st
107      exceptionVec(loadPageFault)       := io.dtlb.resp.bits.excp.pf.ld
108      exceptionVec(storeAccessFault)    := io.dtlb.resp.bits.excp.af.st
109      exceptionVec(loadAccessFault)     := io.dtlb.resp.bits.excp.af.ld
110      val exception = !addrAligned ||
111        io.dtlb.resp.bits.excp.pf.st ||
112        io.dtlb.resp.bits.excp.pf.ld ||
113        io.dtlb.resp.bits.excp.af.st ||
114        io.dtlb.resp.bits.excp.af.ld
115      is_mmio := io.dtlb.resp.bits.mmio
116      when (exception) {
117        // check for exceptions
118        // if there are exceptions, no need to execute it
119        state := s_finish
120        atom_override_xtval := true.B
121      } .otherwise {
122        paddr := io.dtlb.resp.bits.paddr
123        state := s_flush_sbuffer_req
124      }
125    }
126  }
127
128
129  when (state === s_flush_sbuffer_req) {
130    io.flush_sbuffer.valid := true.B
131    state := s_flush_sbuffer_resp
132  }
133
134  when (state === s_flush_sbuffer_resp) {
135    when (io.flush_sbuffer.empty) {
136      state := s_cache_req
137    }
138  }
139
140  when (state === s_cache_req) {
141    io.dcache.req.valid := true.B
142    io.dcache.req.bits.cmd := LookupTree(in.uop.ctrl.fuOpType, List(
143      LSUOpType.lr_w      -> M_XLR,
144      LSUOpType.sc_w      -> M_XSC,
145      LSUOpType.amoswap_w -> M_XA_SWAP,
146      LSUOpType.amoadd_w  -> M_XA_ADD,
147      LSUOpType.amoxor_w  -> M_XA_XOR,
148      LSUOpType.amoand_w  -> M_XA_AND,
149      LSUOpType.amoor_w   -> M_XA_OR,
150      LSUOpType.amomin_w  -> M_XA_MIN,
151      LSUOpType.amomax_w  -> M_XA_MAX,
152      LSUOpType.amominu_w -> M_XA_MINU,
153      LSUOpType.amomaxu_w -> M_XA_MAXU,
154
155      LSUOpType.lr_d      -> M_XLR,
156      LSUOpType.sc_d      -> M_XSC,
157      LSUOpType.amoswap_d -> M_XA_SWAP,
158      LSUOpType.amoadd_d  -> M_XA_ADD,
159      LSUOpType.amoxor_d  -> M_XA_XOR,
160      LSUOpType.amoand_d  -> M_XA_AND,
161      LSUOpType.amoor_d   -> M_XA_OR,
162      LSUOpType.amomin_d  -> M_XA_MIN,
163      LSUOpType.amomax_d  -> M_XA_MAX,
164      LSUOpType.amominu_d -> M_XA_MINU,
165      LSUOpType.amomaxu_d -> M_XA_MAXU
166    ))
167
168    io.dcache.req.bits.addr := paddr
169    io.dcache.req.bits.data := genWdata(in.src2, in.uop.ctrl.fuOpType(1,0))
170    // TODO: atomics do need mask: fix mask
171    io.dcache.req.bits.mask := genWmask(paddr, in.uop.ctrl.fuOpType(1,0))
172    io.dcache.req.bits.id   := DontCare
173
174    when(io.dcache.req.fire()){
175      state := s_cache_resp
176      paddr_reg := io.dcache.req.bits.addr
177      data_reg := io.dcache.req.bits.data
178      mask_reg := io.dcache.req.bits.mask
179      fuop_reg := in.uop.ctrl.fuOpType
180    }
181  }
182
183  when (state === s_cache_resp) {
184    io.dcache.resp.ready := true.B
185    when(io.dcache.resp.fire()) {
186      is_lrsc_valid := io.dcache.resp.bits.id
187      val rdata = io.dcache.resp.bits.data
188      val rdataSel = LookupTree(paddr(2, 0), List(
189        "b000".U -> rdata(63, 0),
190        "b001".U -> rdata(63, 8),
191        "b010".U -> rdata(63, 16),
192        "b011".U -> rdata(63, 24),
193        "b100".U -> rdata(63, 32),
194        "b101".U -> rdata(63, 40),
195        "b110".U -> rdata(63, 48),
196        "b111".U -> rdata(63, 56)
197      ))
198
199      resp_data_wire := LookupTree(in.uop.ctrl.fuOpType, List(
200        LSUOpType.lr_w      -> SignExt(rdataSel(31, 0), XLEN),
201        LSUOpType.sc_w      -> rdata,
202        LSUOpType.amoswap_w -> SignExt(rdataSel(31, 0), XLEN),
203        LSUOpType.amoadd_w  -> SignExt(rdataSel(31, 0), XLEN),
204        LSUOpType.amoxor_w  -> SignExt(rdataSel(31, 0), XLEN),
205        LSUOpType.amoand_w  -> SignExt(rdataSel(31, 0), XLEN),
206        LSUOpType.amoor_w   -> SignExt(rdataSel(31, 0), XLEN),
207        LSUOpType.amomin_w  -> SignExt(rdataSel(31, 0), XLEN),
208        LSUOpType.amomax_w  -> SignExt(rdataSel(31, 0), XLEN),
209        LSUOpType.amominu_w -> SignExt(rdataSel(31, 0), XLEN),
210        LSUOpType.amomaxu_w -> SignExt(rdataSel(31, 0), XLEN),
211
212        LSUOpType.lr_d      -> SignExt(rdataSel(63, 0), XLEN),
213        LSUOpType.sc_d      -> rdata,
214        LSUOpType.amoswap_d -> SignExt(rdataSel(63, 0), XLEN),
215        LSUOpType.amoadd_d  -> SignExt(rdataSel(63, 0), XLEN),
216        LSUOpType.amoxor_d  -> SignExt(rdataSel(63, 0), XLEN),
217        LSUOpType.amoand_d  -> SignExt(rdataSel(63, 0), XLEN),
218        LSUOpType.amoor_d   -> SignExt(rdataSel(63, 0), XLEN),
219        LSUOpType.amomin_d  -> SignExt(rdataSel(63, 0), XLEN),
220        LSUOpType.amomax_d  -> SignExt(rdataSel(63, 0), XLEN),
221        LSUOpType.amominu_d -> SignExt(rdataSel(63, 0), XLEN),
222        LSUOpType.amomaxu_d -> SignExt(rdataSel(63, 0), XLEN)
223      ))
224
225      resp_data := resp_data_wire
226      state := s_finish
227    }
228  }
229
230  when (state === s_finish) {
231    io.out.valid := true.B
232    io.out.bits.uop := in.uop
233    io.out.bits.uop.cf.exceptionVec := exceptionVec
234    io.out.bits.uop.diffTestDebugLrScValid := is_lrsc_valid
235    io.out.bits.data := resp_data
236    io.out.bits.redirectValid := false.B
237    io.out.bits.redirect := DontCare
238    io.out.bits.debug.isMMIO := is_mmio
239    io.out.bits.debug.paddr := paddr
240    when (io.out.fire()) {
241      XSDebug("atomics writeback: pc %x data %x\n", io.out.bits.uop.cf.pc, io.dcache.resp.bits.data)
242      state := s_invalid
243    }
244  }
245
246  when(io.redirect.valid || io.flush){
247    atom_override_xtval := false.B
248  }
249
250  if (!env.FPGAPlatform) {
251    val difftest = Module(new DifftestAtomicEvent)
252    difftest.io.clock      := clock
253    difftest.io.coreid     := 0.U
254    difftest.io.atomicResp := io.dcache.resp.fire()
255    difftest.io.atomicAddr := paddr_reg
256    difftest.io.atomicData := data_reg
257    difftest.io.atomicMask := mask_reg
258    difftest.io.atomicFuop := fuop_reg
259    difftest.io.atomicOut  := resp_data_wire
260  }
261}
262