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.mem 18 19import org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import utility._ 24import xiangshan._ 25import xiangshan.backend.rob.RobPtr 26import xiangshan.backend.Bundles._ 27import xiangshan.mem._ 28import xiangshan.backend.fu.FuType 29import freechips.rocketchip.diplomacy.BufferParams 30import xiangshan.cache.mmu._ 31import xiangshan.cache._ 32import xiangshan.cache.wpu.ReplayCarry 33import xiangshan.backend.fu.util.SdtrigExt 34import xiangshan.ExceptionNO._ 35import xiangshan.backend.fu.vector.Bundles.VConfig 36import xiangshan.backend.datapath.NewPipelineConnect 37import xiangshan.backend.fu.vector.Utils.VecDataToMaskDataVec 38 39class VSegmentBundle(implicit p: Parameters) extends VLSUBundle 40{ 41 val baseVaddr = UInt(VAddrBits.W) 42 val uop = new DynInst 43 val paddr = UInt(PAddrBits.W) 44 val mask = UInt(VLEN.W) 45 val alignedType = UInt(alignTypeBits.W) 46 val vl = UInt(elemIdxBits.W) 47 val uopFlowNum = UInt(elemIdxBits.W) 48 val uopFlowNumMask = UInt(elemIdxBits.W) 49 // for exception 50 val vstart = UInt(elemIdxBits.W) 51 val exceptionVaddr = UInt(VAddrBits.W) 52 val exceptionGpaddr = UInt(GPAddrBits.W) 53 val exception_va = Bool() 54 val exception_gpa = Bool() 55 val exception_pa = Bool() 56 val exceptionVstart = UInt(elemIdxBits.W) 57 val exceptionVl = UInt(elemIdxBits.W) 58 val isFof = Bool() 59} 60 61// latch each uop's VecWen, pdest, v0Wen, uopIdx 62class VSegmentUop(implicit p: Parameters) extends VLSUBundle{ 63 val uop = new DynInst 64} 65 66class VSegmentUnit (implicit p: Parameters) extends VLSUModule 67 with HasDCacheParameters 68 with MemoryOpConstants 69 with SdtrigExt 70 with HasLoadHelper 71{ 72 val io = IO(new VSegmentUnitIO) 73 74 val maxSize = VSegmentBufferSize 75 76 class VSegUPtr(implicit p: Parameters) extends CircularQueuePtr[VSegUPtr](maxSize){ 77 } 78 79 object VSegUPtr { 80 def apply(f: Bool, v: UInt)(implicit p: Parameters): VSegUPtr = { 81 val ptr = Wire(new VSegUPtr) 82 ptr.flag := f 83 ptr.value := v 84 ptr 85 } 86 } 87 88 89 /** 90 ******************************************************************************************************** 91 * Use an example to illustrate the working logic of a segmentunit: * 92 * For: * 93 * lmul=2 sew=32 emul=2 eew=32 vl=16 * 94 * Then: * 95 * Access memory in the order: * 96 * (V2,S0),(V4,S0),(V6,S0),(V8,S0), * 97 * (V2,S1),(V4,S1),(V6,S1),(V8,S1), * 98 * (V2,S2),(V4,S2),(V6,S2),(V8,S2), * 99 * (V2,S3),(V4,S3),(V6,S3),(V8,S3), * 100 * (V3,S4),(V5,S4),(V7,S4),(V9,S4), * 101 * (V3,S5),(V5,S5),(V7,S5),(V9,S5), * 102 * (V3,S6),(V5,S6),(V7,S6),(V9,S6), * 103 * (V3,S7),(V5,S7),(V7,S7),(V9,S7), * 104 * * 105 * * 106 * [[data]] saves the data generated by the access and corresponds to the register. * 107 * [[splitPtr]] controls the destination register written to. * 108 * * 109 * splitptr offset can be seen in [[splitPtrNext]] is assignment logic, * 110 * which is mainly calculated in terms of [[fieldIdx]] and [[segmentIdx]] * 111 * First access different fields of the same segment, and then visit different segments. * 112 * For the case of 'emul' greater than 1, such as the following example, * 113 * although 'v2' and 'v3' are different vd and the same field, they are still different segments, * 114 * so they should be accessed sequentially.Just like the 'Access memory in the order' above. * 115 * * 116 * [[segmentIdx]] * 117 * | * 118 * | * 119 * V * 120 * * 121 * S0 S1 S2 S3 * 122 * ---------------------------------------------------------------------------- * 123 * [[splitPtr]]--> v2 | field0 | field0 | field0 | field0 | * 124 * ---------------------------------------------------------------------------- * 125 * S4 S5 S6 S7 * 126 * ---------------------------------------------------------------------------- * 127 * v3 | field0 | field0 | field0 | field0 | * 128 * ---------------------------------------------------------------------------- * 129 * S0 S1 S2 S3 * 130 * ---------------------------------------------------------------------------- * 131 * v4 | field1 | field1 | field1 | field1 | * 132 * ---------------------------------------------------------------------------- * 133 * S4 S5 S6 S7 * 134 * ---------------------------------------------------------------------------- * 135 * v5 | field1 | field1 | field1 | field1 | * 136 * ---------------------------------------------------------------------------- * 137 * S0 S1 S2 S3 * 138 * ---------------------------------------------------------------------------- * 139 * v6 | field2 | field2 | field2 | field2 | * 140 * ---------------------------------------------------------------------------- * 141 * S4 S5 S6 S7 * 142 * ---------------------------------------------------------------------------- * 143 * v7 | field2 | field2 | field2 | field2 | * 144 * ---------------------------------------------------------------------------- * 145 * S0 S1 S2 S3 * 146 * ---------------------------------------------------------------------------- * 147 * v8 | field3 | field3 | field3 | field3 | * 148 * ---------------------------------------------------------------------------- * 149 * S4 S5 S6 S7 * 150 * ---------------------------------------------------------------------------- * 151 * v9 | field3 | field3 | field3 | field3 | * 152 * ---------------------------------------------------------------------------- * * 153 * * * 154 * * * 155 ******************************************************************************************************** 156 **/ 157 158 159 // buffer uop 160 val instMicroOp = Reg(new VSegmentBundle) 161 val instMicroOpValid = RegInit(false.B) 162 val data = Reg(Vec(maxSize, UInt(VLEN.W))) 163 val uopq = Reg(Vec(maxSize, new VSegmentUop)) 164 val stride = Reg(Vec(maxSize, UInt(VLEN.W))) 165 val allocated = RegInit(VecInit(Seq.fill(maxSize)(false.B))) 166 val enqPtr = RegInit(0.U.asTypeOf(new VSegUPtr)) 167 val deqPtr = RegInit(0.U.asTypeOf(new VSegUPtr)) 168 val stridePtr = WireInit(0.U.asTypeOf(new VSegUPtr)) // for select stride/index 169 170 val segmentIdx = RegInit(0.U(elemIdxBits.W)) 171 val fieldIdx = RegInit(0.U(fieldBits.W)) 172 val segmentOffset = RegInit(0.U(VAddrBits.W)) 173 val splitPtr = RegInit(0.U.asTypeOf(new VSegUPtr)) // for select load/store data 174 val splitPtrNext = WireInit(0.U.asTypeOf(new VSegUPtr)) 175 176 val exception_va = WireInit(false.B) 177 val exception_gpa = WireInit(false.B) 178 val exception_pa = WireInit(false.B) 179 180 val maxSegIdx = instMicroOp.vl - 1.U 181 val maxNfields = instMicroOp.uop.vpu.nf 182 val latchVaddr = RegInit(0.U(VAddrBits.W)) 183 184 XSError((segmentIdx > maxSegIdx) && instMicroOpValid, s"segmentIdx > vl, something error!\n") 185 XSError((fieldIdx > maxNfields) && instMicroOpValid, s"fieldIdx > nfields, something error!\n") 186 187 // MicroOp 188 val baseVaddr = instMicroOp.baseVaddr 189 val alignedType = instMicroOp.alignedType 190 val fuType = instMicroOp.uop.fuType 191 val mask = instMicroOp.mask 192 val exceptionVec = instMicroOp.uop.exceptionVec 193 val issueEew = instMicroOp.uop.vpu.veew 194 val issueLmul = instMicroOp.uop.vpu.vtype.vlmul 195 val issueSew = instMicroOp.uop.vpu.vtype.vsew 196 val issueEmul = EewLog2(issueEew) - issueSew + issueLmul 197 val elemIdxInVd = segmentIdx & instMicroOp.uopFlowNumMask 198 val issueInstType = Cat(true.B, instMicroOp.uop.fuOpType(6, 5)) // always segment instruction 199 val issueUopFlowNumLog2 = GenRealFlowLog2(issueInstType, issueEmul, issueLmul, issueEew, issueSew, true) // max element number log2 in vd 200 val issueVlMax = instMicroOp.uopFlowNum // max elementIdx in vd 201 val issueMaxIdxInIndex = GenVLMAX(Mux(issueEmul.asSInt > 0.S, 0.U, issueEmul), issueEew(1, 0)) // index element index in index register 202 val issueMaxIdxInIndexMask = GenVlMaxMask(issueMaxIdxInIndex, elemIdxBits) 203 val issueMaxIdxInIndexLog2 = GenVLMAXLog2(Mux(issueEmul.asSInt > 0.S, 0.U, issueEmul), issueEew(1, 0)) 204 val issueIndexIdx = segmentIdx & issueMaxIdxInIndexMask 205 val segmentActive = (mask & UIntToOH(segmentIdx)).orR 206 207 // sbuffer write interface 208 val sbufferOut = Wire(Decoupled(new DCacheWordReqWithVaddrAndPfFlag)) 209 210 // Segment instruction's FSM 211 /* 212 * s_idle: wait request 213 * s_flush_sbuffer_req: flush sbuffer 214 * s_wait_flush_sbuffer_resp: wait sbuffer empty 215 * s_tlb_req: request tlb 216 * s_wait_tlb_resp: wait tlb resp 217 * s_pm: check pmp 218 * s_cache_req: request cache 219 * s_cache_resp: wait cache resp 220 * s_latch_and_merge_data: for read data 221 * s_send_data: for send write data 222 * s_finish: 223 * */ 224 val s_idle :: s_flush_sbuffer_req :: s_wait_flush_sbuffer_resp :: s_tlb_req :: s_wait_tlb_resp :: s_pm ::s_cache_req :: s_cache_resp :: s_latch_and_merge_data :: s_send_data :: s_finish :: Nil = Enum(11) 225 val state = RegInit(s_idle) 226 val stateNext = WireInit(s_idle) 227 val sbufferEmpty = io.flush_sbuffer.empty 228 229 /** 230 * state update 231 */ 232 state := stateNext 233 234 /** 235 * state transfer 236 */ 237 when(state === s_idle){ 238 stateNext := Mux(isAfter(enqPtr, deqPtr), s_flush_sbuffer_req, s_idle) 239 }.elsewhen(state === s_flush_sbuffer_req){ 240 stateNext := Mux(sbufferEmpty, s_tlb_req, s_wait_flush_sbuffer_resp) // if sbuffer is empty, go to query tlb 241 242 }.elsewhen(state === s_wait_flush_sbuffer_resp){ 243 stateNext := Mux(sbufferEmpty, s_tlb_req, s_wait_flush_sbuffer_resp) 244 245 }.elsewhen(state === s_tlb_req){ 246 stateNext := Mux(segmentActive, s_wait_tlb_resp, Mux(FuType.isVLoad(instMicroOp.uop.fuType), s_latch_and_merge_data, s_send_data)) 247 248 }.elsewhen(state === s_wait_tlb_resp){ 249 stateNext := Mux(io.dtlb.resp.fire, 250 Mux(!io.dtlb.resp.bits.miss, 251 s_pm, 252 s_tlb_req), 253 s_wait_tlb_resp) 254 255 }.elsewhen(state === s_pm){ 256 /* if is vStore, send data to sbuffer, so don't need query dcache */ 257 stateNext := Mux(exception_pa || exception_va || exception_gpa, 258 s_finish, 259 Mux(FuType.isVLoad(instMicroOp.uop.fuType), s_cache_req, s_send_data)) 260 261 }.elsewhen(state === s_cache_req){ 262 stateNext := Mux(io.rdcache.req.fire, s_cache_resp, s_cache_req) 263 264 }.elsewhen(state === s_cache_resp){ 265 when(io.rdcache.resp.fire) { 266 when(io.rdcache.resp.bits.miss || io.rdcache.s2_bank_conflict) { 267 stateNext := s_cache_req 268 }.otherwise { 269 stateNext := Mux(FuType.isVLoad(instMicroOp.uop.fuType), s_latch_and_merge_data, s_send_data) 270 } 271 }.otherwise{ 272 stateNext := s_cache_resp 273 } 274 /* if segment is inactive, don't need to wait access all of the field */ 275 }.elsewhen(state === s_latch_and_merge_data) { 276 when((segmentIdx === maxSegIdx) && (fieldIdx === maxNfields) || 277 ((segmentIdx === maxSegIdx) && !segmentActive)) { 278 279 stateNext := s_finish // segment instruction finish 280 }.otherwise { 281 stateNext := s_tlb_req // need continue 282 } 283 /* if segment is inactive, don't need to wait access all of the field */ 284 }.elsewhen(state === s_send_data) { // when sbuffer accept data 285 when(!sbufferOut.fire && segmentActive) { 286 stateNext := s_send_data 287 }.elsewhen((segmentIdx === maxSegIdx) && (fieldIdx === maxNfields || !segmentActive)) { 288 stateNext := s_finish // segment instruction finish 289 }.otherwise { 290 stateNext := s_tlb_req // need continue 291 } 292 }.elsewhen(state === s_finish){ // writeback uop 293 stateNext := Mux(distanceBetween(enqPtr, deqPtr) === 0.U, s_idle, s_finish) 294 295 }.otherwise{ 296 stateNext := s_idle 297 XSError(true.B, s"Unknown state!\n") 298 } 299 300 /************************************************************************* 301 * enqueue logic 302 *************************************************************************/ 303 io.in.ready := true.B 304 val fuOpType = io.in.bits.uop.fuOpType 305 val vtype = io.in.bits.uop.vpu.vtype 306 val mop = fuOpType(6, 5) 307 val instType = Cat(true.B, mop) 308 val eew = io.in.bits.uop.vpu.veew 309 val sew = vtype.vsew 310 val lmul = vtype.vlmul 311 val emul = EewLog2(eew) - sew + lmul 312 val vl = instMicroOp.vl 313 val vm = instMicroOp.uop.vpu.vm 314 val vstart = instMicroOp.uop.vpu.vstart 315 val srcMask = GenFlowMask(Mux(vm, Fill(VLEN, 1.U(1.W)), io.in.bits.src_mask), vstart, vl, true) 316 // first uop enqueue, we need to latch microOp of segment instruction 317 when(io.in.fire && !instMicroOpValid){ 318 // element number in a vd 319 // TODO Rewrite it in a more elegant way. 320 val uopFlowNum = ZeroExt(GenRealFlowNum(instType, emul, lmul, eew, sew, true), elemIdxBits) 321 instMicroOp.baseVaddr := io.in.bits.src_rs1(VAddrBits - 1, 0) 322 instMicroOpValid := true.B // if is first uop 323 instMicroOp.alignedType := Mux(isIndexed(instType), sew(1, 0), eew) 324 instMicroOp.uop := io.in.bits.uop 325 instMicroOp.mask := srcMask 326 instMicroOp.vstart := 0.U 327 instMicroOp.uopFlowNum := uopFlowNum 328 instMicroOp.uopFlowNumMask := GenVlMaxMask(uopFlowNum, elemIdxBits) // for merge data 329 instMicroOp.vl := io.in.bits.src_vl.asTypeOf(VConfig()).vl 330 segmentOffset := 0.U 331 instMicroOp.isFof := (fuOpType === VlduType.vleff) && FuType.isVLoad(fuType) 332 } 333 // latch data 334 when(io.in.fire){ 335 data(enqPtr.value) := io.in.bits.src_vs3 336 stride(enqPtr.value) := io.in.bits.src_stride 337 uopq(enqPtr.value).uop := io.in.bits.uop 338 } 339 340 // update enqptr, only 1 port 341 when(io.in.fire){ 342 enqPtr := enqPtr + 1.U 343 } 344 345 /************************************************************************* 346 * output logic 347 *************************************************************************/ 348 349 val indexStride = IndexAddr( // index for indexed instruction 350 index = stride(stridePtr.value), 351 flow_inner_idx = issueIndexIdx, 352 eew = issueEew 353 ) 354 val realSegmentOffset = Mux(isIndexed(issueInstType), 355 indexStride, 356 segmentOffset) 357 val vaddr = baseVaddr + (fieldIdx << alignedType).asUInt + realSegmentOffset 358 359 //latch vaddr 360 when(state === s_tlb_req){ 361 latchVaddr := vaddr 362 } 363 /** 364 * tlb req and tlb resq 365 */ 366 367 // query DTLB IO Assign 368 io.dtlb.req := DontCare 369 io.dtlb.resp.ready := true.B 370 io.dtlb.req.valid := state === s_tlb_req && segmentActive 371 io.dtlb.req.bits.cmd := Mux(FuType.isVLoad(fuType), TlbCmd.read, TlbCmd.write) 372 io.dtlb.req.bits.vaddr := vaddr 373 io.dtlb.req.bits.size := instMicroOp.alignedType(2,0) 374 io.dtlb.req.bits.memidx.is_ld := FuType.isVLoad(fuType) 375 io.dtlb.req.bits.memidx.is_st := FuType.isVStore(fuType) 376 io.dtlb.req.bits.debug.robIdx := instMicroOp.uop.robIdx 377 io.dtlb.req.bits.no_translate := false.B 378 io.dtlb.req.bits.debug.pc := instMicroOp.uop.pc 379 io.dtlb.req.bits.debug.isFirstIssue := DontCare 380 io.dtlb.req_kill := false.B 381 382 val canTriggerException = segmentIdx === 0.U || !instMicroOp.isFof // only elementIdx = 0 or is not fof can trigger 383 // tlb resp 384 when(io.dtlb.resp.fire && state === s_wait_tlb_resp){ 385 exceptionVec(storePageFault) := io.dtlb.resp.bits.excp(0).pf.st && canTriggerException 386 exceptionVec(loadPageFault) := io.dtlb.resp.bits.excp(0).pf.ld && canTriggerException 387 exceptionVec(storeGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.st && canTriggerException 388 exceptionVec(loadGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.ld && canTriggerException 389 exceptionVec(storeAccessFault) := io.dtlb.resp.bits.excp(0).af.st && canTriggerException 390 exceptionVec(loadAccessFault) := io.dtlb.resp.bits.excp(0).af.ld && canTriggerException 391 when(!io.dtlb.resp.bits.miss){ 392 instMicroOp.paddr := io.dtlb.resp.bits.paddr(0) 393 instMicroOp.exceptionGpaddr := io.dtlb.resp.bits.gpaddr(0) 394 } 395 } 396 // pmp 397 // NOTE: only handle load/store exception here, if other exception happens, don't send here 398 val pmp = WireInit(io.pmpResp) 399 when(state === s_pm) { 400 val addr_aligned = LookupTree(Mux(isIndexed(issueInstType), issueSew(1, 0), issueEew(1, 0)), List( 401 "b00".U -> true.B, //b 402 "b01".U -> (vaddr(0) === 0.U), //h 403 "b10".U -> (vaddr(1, 0) === 0.U), //w 404 "b11".U -> (vaddr(2, 0) === 0.U) //d 405 )) 406 val missAligned = !addr_aligned 407 exceptionVec(loadAddrMisaligned) := missAligned && FuType.isVLoad(fuType) && canTriggerException 408 exceptionVec(storeAddrMisaligned) := missAligned && FuType.isVStore(fuType) && canTriggerException 409 410 exception_va := exceptionVec(storePageFault) || exceptionVec(loadPageFault) || 411 exceptionVec(storeAccessFault) || exceptionVec(loadAccessFault) || (missAligned && canTriggerException) 412 exception_gpa := exceptionVec(storeGuestPageFault) || exceptionVec(loadGuestPageFault) 413 exception_pa := (pmp.st || pmp.ld || pmp.mmio) && canTriggerException 414 415 instMicroOp.exception_pa := exception_pa 416 instMicroOp.exception_va := exception_va 417 instMicroOp.exception_gpa := exception_gpa 418 // update storeAccessFault bit. Currently, we don't support vector MMIO 419 exceptionVec(loadAccessFault) := (exceptionVec(loadAccessFault) || pmp.ld || pmp.mmio) && canTriggerException 420 exceptionVec(storeAccessFault) := (exceptionVec(storeAccessFault) || pmp.st || pmp.mmio) && canTriggerException 421 422 when(exception_va || exception_gpa || exception_pa) { 423 when(canTriggerException) { 424 instMicroOp.exceptionVaddr := vaddr 425 instMicroOp.exceptionVl := segmentIdx // for exception 426 instMicroOp.exceptionVstart := segmentIdx // for exception 427 }.otherwise { 428 instMicroOp.exceptionVl := segmentIdx 429 } 430 } 431 } 432 433 /** 434 * flush sbuffer IO Assign 435 */ 436 io.flush_sbuffer.valid := !sbufferEmpty && (state === s_flush_sbuffer_req) 437 438 439 /** 440 * merge data for load 441 */ 442 val cacheData = LookupTree(latchVaddr(3,0), List( 443 "b0000".U -> io.rdcache.resp.bits.data_delayed(63, 0), 444 "b0001".U -> io.rdcache.resp.bits.data_delayed(63, 8), 445 "b0010".U -> io.rdcache.resp.bits.data_delayed(63, 16), 446 "b0011".U -> io.rdcache.resp.bits.data_delayed(63, 24), 447 "b0100".U -> io.rdcache.resp.bits.data_delayed(63, 32), 448 "b0101".U -> io.rdcache.resp.bits.data_delayed(63, 40), 449 "b0110".U -> io.rdcache.resp.bits.data_delayed(63, 48), 450 "b0111".U -> io.rdcache.resp.bits.data_delayed(63, 56), 451 "b1000".U -> io.rdcache.resp.bits.data_delayed(127, 64), 452 "b1001".U -> io.rdcache.resp.bits.data_delayed(127, 72), 453 "b1010".U -> io.rdcache.resp.bits.data_delayed(127, 80), 454 "b1011".U -> io.rdcache.resp.bits.data_delayed(127, 88), 455 "b1100".U -> io.rdcache.resp.bits.data_delayed(127, 96), 456 "b1101".U -> io.rdcache.resp.bits.data_delayed(127, 104), 457 "b1110".U -> io.rdcache.resp.bits.data_delayed(127, 112), 458 "b1111".U -> io.rdcache.resp.bits.data_delayed(127, 120) 459 )) 460 val pickData = rdataVecHelper(alignedType(1,0), cacheData) 461 val mergedData = mergeDataWithElemIdx( 462 oldData = data(splitPtr.value), 463 newData = Seq(pickData), 464 alignedType = alignedType(1,0), 465 elemIdx = Seq(elemIdxInVd), 466 valids = Seq(true.B) 467 ) 468 when(state === s_latch_and_merge_data && segmentActive){ 469 data(splitPtr.value) := mergedData 470 } 471 /** 472 * split data for store 473 * */ 474 val splitData = genVSData( 475 data = data(splitPtr.value), 476 elemIdx = elemIdxInVd, 477 alignedType = alignedType 478 ) 479 val flowData = genVWdata(splitData, alignedType) // TODO: connect vstd, pass vector data 480 val wmask = genVWmask(latchVaddr, alignedType(1, 0)) & Fill(VLENB, segmentActive) 481 482 /** 483 * rdcache req, write request don't need to query dcache, because we write element to sbuffer 484 */ 485 io.rdcache.req := DontCare 486 io.rdcache.req.valid := state === s_cache_req && FuType.isVLoad(fuType) 487 io.rdcache.req.bits.cmd := MemoryOpConstants.M_XRD 488 io.rdcache.req.bits.vaddr := latchVaddr 489 io.rdcache.req.bits.mask := mask 490 io.rdcache.req.bits.data := flowData 491 io.rdcache.pf_source := LOAD_SOURCE.U 492 io.rdcache.req.bits.id := DontCare 493 io.rdcache.resp.ready := true.B 494 io.rdcache.s1_paddr_dup_lsu := instMicroOp.paddr 495 io.rdcache.s1_paddr_dup_dcache := instMicroOp.paddr 496 io.rdcache.s1_kill := false.B 497 io.rdcache.s1_kill_data_read := false.B 498 io.rdcache.s2_kill := false.B 499 if (env.FPGAPlatform){ 500 io.rdcache.s0_pc := DontCare 501 io.rdcache.s1_pc := DontCare 502 io.rdcache.s2_pc := DontCare 503 }else{ 504 io.rdcache.s0_pc := instMicroOp.uop.pc 505 io.rdcache.s1_pc := instMicroOp.uop.pc 506 io.rdcache.s2_pc := instMicroOp.uop.pc 507 } 508 io.rdcache.replacementUpdated := false.B 509 io.rdcache.is128Req := false.B 510 511 512 /** 513 * write data to sbuffer 514 * */ 515 sbufferOut.bits := DontCare 516 sbufferOut.valid := state === s_send_data && segmentActive 517 sbufferOut.bits.vecValid := state === s_send_data && segmentActive 518 sbufferOut.bits.mask := wmask 519 sbufferOut.bits.data := flowData 520 sbufferOut.bits.vaddr := latchVaddr 521 sbufferOut.bits.cmd := MemoryOpConstants.M_XWR 522 sbufferOut.bits.id := DontCare 523 sbufferOut.bits.addr := instMicroOp.paddr 524 525 NewPipelineConnect( 526 sbufferOut, io.sbuffer, io.sbuffer.fire, 527 false.B, 528 Option(s"VSegmentUnitPipelineConnect") 529 ) 530 531 io.vecDifftestInfo.valid := io.sbuffer.valid 532 io.vecDifftestInfo.bits := uopq(deqPtr.value).uop 533 534 /** 535 * update ptr 536 * */ 537 private val fieldActiveWirteFinish = sbufferOut.fire && segmentActive // writedata finish and is a active segment 538 XSError(sbufferOut.fire && !segmentActive, "Attempt write inactive segment to sbuffer, something wrong!\n") 539 540 private val segmentInactiveFinish = ((state === s_latch_and_merge_data) || (state === s_send_data)) && !segmentActive 541 542 val splitPtrOffset = Mux( 543 isIndexed(instType), 544 Mux(lmul.asSInt < 0.S, 1.U, (1.U << lmul).asUInt), 545 Mux(emul.asSInt < 0.S, 1.U, (1.U << emul).asUInt) 546 ) 547 splitPtrNext := 548 Mux(fieldIdx === maxNfields || !segmentActive, // if segment is active, need to complete this segment, otherwise jump to next segment 549 // segment finish, By shifting 'issueUopFlowNumLog2' to the right to ensure that emul != 1 can correctly generate lateral offset. 550 (deqPtr + ((segmentIdx +& 1.U) >> issueUopFlowNumLog2).asUInt), 551 // next field. 552 (splitPtr + splitPtrOffset) 553 ) 554 555 dontTouch(issueUopFlowNumLog2) 556 dontTouch(issueEmul) 557 dontTouch(splitPtrNext) 558 dontTouch(stridePtr) 559 dontTouch(segmentActive) 560 561 // update splitPtr 562 when(state === s_latch_and_merge_data || (state === s_send_data && (fieldActiveWirteFinish || !segmentActive))){ 563 splitPtr := splitPtrNext 564 }.elsewhen(io.in.fire && !instMicroOpValid){ 565 splitPtr := deqPtr // initial splitPtr 566 } 567 568 // update stridePtr, only use in index 569 val strideOffset = Mux(isIndexed(issueInstType), segmentIdx >> issueMaxIdxInIndexLog2, 0.U) 570 stridePtr := deqPtr + strideOffset 571 572 // update fieldIdx 573 when(io.in.fire && !instMicroOpValid){ // init 574 fieldIdx := 0.U 575 }.elsewhen(state === s_latch_and_merge_data && segmentActive || 576 (state === s_send_data && fieldActiveWirteFinish)){ // only if segment is active 577 578 /* next segment, only if segment complete */ 579 fieldIdx := Mux(fieldIdx === maxNfields, 0.U, fieldIdx + 1.U) 580 }.elsewhen(segmentInactiveFinish){ // segment is inactive, go to next segment 581 fieldIdx := 0.U 582 } 583 //update segmentIdx 584 when(io.in.fire && !instMicroOpValid){ 585 segmentIdx := 0.U 586 }.elsewhen(fieldIdx === maxNfields && (state === s_latch_and_merge_data || (state === s_send_data && fieldActiveWirteFinish)) && 587 segmentIdx =/= maxSegIdx){ // next segment, only if segment is active 588 589 segmentIdx := segmentIdx + 1.U 590 }.elsewhen(segmentInactiveFinish && segmentIdx =/= maxSegIdx){ // if segment is inactive, go to next segment 591 segmentIdx := segmentIdx + 1.U 592 } 593 594 //update segmentOffset 595 /* when segment is active or segment is inactive, increase segmentOffset */ 596 when((fieldIdx === maxNfields && (state === s_latch_and_merge_data || (state === s_send_data && fieldActiveWirteFinish))) || 597 segmentInactiveFinish){ 598 599 segmentOffset := segmentOffset + Mux(isUnitStride(issueInstType), (maxNfields +& 1.U) << issueEew(1, 0), stride(stridePtr.value)) 600 } 601 602 //update deqPtr 603 when((state === s_finish) && !isEmpty(enqPtr, deqPtr)){ 604 deqPtr := deqPtr + 1.U 605 } 606 607 /************************************************************************* 608 * dequeue logic 609 *************************************************************************/ 610 val vdIdxInField = GenUopIdxInField(Mux(isIndexed(instType), issueLmul, issueEmul), uopq(deqPtr.value).uop.vpu.vuopIdx) 611 /*select mask of vd, maybe remove in feature*/ 612 val realEw = Mux(isIndexed(issueInstType), issueSew(1, 0), issueEew(1, 0)) 613 val maskDataVec: Vec[UInt] = VecDataToMaskDataVec(instMicroOp.mask, realEw) 614 val maskUsed = maskDataVec(vdIdxInField) 615 616 when(stateNext === s_idle){ 617 instMicroOpValid := false.B 618 } 619 // writeback to backend 620 val writebackOut = WireInit(io.uopwriteback.bits) 621 val writebackValid = (state === s_finish) && !isEmpty(enqPtr, deqPtr) 622 writebackOut.uop := uopq(deqPtr.value).uop 623 writebackOut.uop.vpu := instMicroOp.uop.vpu 624 writebackOut.uop.exceptionVec := instMicroOp.uop.exceptionVec 625 writebackOut.mask.get := instMicroOp.mask 626 writebackOut.data := data(deqPtr.value) 627 writebackOut.vdIdx.get := vdIdxInField 628 writebackOut.uop.vpu.vl := instMicroOp.vl 629 writebackOut.uop.vpu.vstart := instMicroOp.vstart 630 writebackOut.uop.vpu.vmask := maskUsed 631 writebackOut.uop.vpu.vuopIdx := uopq(deqPtr.value).uop.vpu.vuopIdx 632 writebackOut.debug := DontCare 633 writebackOut.vdIdxInField.get := vdIdxInField 634 writebackOut.uop.robIdx := instMicroOp.uop.robIdx 635 writebackOut.uop.fuOpType := instMicroOp.uop.fuOpType 636 637 io.uopwriteback.valid := RegNext(writebackValid) 638 io.uopwriteback.bits := RegEnable(writebackOut, writebackValid) 639 640 dontTouch(writebackValid) 641 642 //to RS 643 val feedbackOut = WireInit(0.U.asTypeOf(io.feedback.bits)) 644 val feedbackValid = state === s_finish && !isEmpty(enqPtr, deqPtr) 645 feedbackOut.hit := true.B 646 feedbackOut.robIdx := instMicroOp.uop.robIdx 647 feedbackOut.sourceType := DontCare 648 feedbackOut.flushState := DontCare 649 feedbackOut.dataInvalidSqIdx := DontCare 650 feedbackOut.sqIdx := uopq(deqPtr.value).uop.sqIdx 651 feedbackOut.lqIdx := uopq(deqPtr.value).uop.lqIdx 652 653 io.feedback.valid := RegNext(feedbackValid) 654 io.feedback.bits := RegEnable(feedbackOut, feedbackValid) 655 656 dontTouch(feedbackValid) 657 658 // exception 659 io.exceptionInfo := DontCare 660 io.exceptionInfo.bits.robidx := instMicroOp.uop.robIdx 661 io.exceptionInfo.bits.uopidx := uopq(deqPtr.value).uop.vpu.vuopIdx 662 io.exceptionInfo.bits.vstart := instMicroOp.exceptionVstart 663 io.exceptionInfo.bits.vaddr := instMicroOp.exceptionVaddr 664 io.exceptionInfo.bits.gpaddr := instMicroOp.exceptionGpaddr 665 io.exceptionInfo.bits.vl := instMicroOp.exceptionVl 666 io.exceptionInfo.valid := (state === s_finish) && instMicroOp.uop.exceptionVec.asUInt.orR && !isEmpty(enqPtr, deqPtr) 667} 668 669