@@ -20,7 +20,9 @@ case class LoadStoreUnitParams(
2020 val storeDataEntries : Int = 8 , // limited to 8 unissued store requests
2121 val addressEntries : Int = 16 , // limited to 16 unissued memory requests
2222
23+ // purely performance optimizations; turn off if bad things are happening
2324 val smemDoesntReorder : Boolean = true , // see comment above LSQMemUpdate
25+ val fastHeadUpdate : Boolean = true , // allow logical head to update on same cycle as memUpdate / memResponse
2426) {
2527 val globalLdqIndexBits = log2Up(numGlobalLdqEntries)
2628 val globalStqIndexBits = log2Up(numGlobalStqEntries)
@@ -380,9 +382,12 @@ class LoadStoreQueue(implicit p: Parameters) extends CoreModule()(p) {
380382 val storeDataIdx = RegInit (VecInit .fill(entries)(0 .U (muonParams.lsu.storeDataIdxBits.W )))
381383 val loadDataIdx = RegInit (VecInit .fill(entries)(0 .U (muonParams.lsu.loadDataIdxBits.W )))
382384 val loadPackets = RegInit (VecInit .fill(entries)(0 .U (lsuDerived.packetBits.W )))
383- val done = RegInit (VecInit .fill(entries)(false .B ))
385+ val doneNext = Wire (Vec (entries, Bool ()))
386+ val done = RegNext (doneNext, VecInit .fill(entries)(false .B ))
384387 val writeback = RegInit (VecInit .fill(entries)(false .B ))
385388
389+ doneNext := done
390+
386391 val debugId = lsuDerived.debugIdBits.map { bits =>
387392 RegInit (VecInit .fill(entries)(0 .U (bits.W )))
388393 }
@@ -400,7 +405,7 @@ class LoadStoreQueue(implicit p: Parameters) extends CoreModule()(p) {
400405 storeDataIdx(idxBits(tail)) := io.storeDataIdx
401406 }
402407 loadPackets(idxBits(tail)) := 0 .U (lsuDerived.packetBits.W )
403- done (idxBits(tail)) := false .B
408+ doneNext (idxBits(tail)) := false .B
404409 if (lsuDerived.debugIdBits.isDefined) {
405410 debugId.get(idxBits(tail)) := io.debugId.get
406411 }
@@ -521,7 +526,7 @@ class LoadStoreQueue(implicit p: Parameters) extends CoreModule()(p) {
521526
522527 // set done when receiving mem update or mem response, allowing logical head to move forward
523528 when (io.receivedMemUpdate.valid) {
524- done (localIndex(io.receivedMemUpdate.bits.token.index)) := true .B
529+ doneNext (localIndex(io.receivedMemUpdate.bits.token.index)) := true .B
525530 }
526531
527532 // Lookup interface: provides loadDataIdx without triggering state updates
@@ -539,7 +544,7 @@ class LoadStoreQueue(implicit p: Parameters) extends CoreModule()(p) {
539544 loadPackets(memResponseIndex) := loadPackets(memResponseIndex) + 1 .U
540545
541546 when (loadPackets(memResponseIndex) === (lsuDerived.numPackets - 1 ).U ) {
542- done (memResponseIndex) := true .B
547+ doneNext (memResponseIndex) := true .B
543548
544549 if (loadQueue) {
545550 // every load needs to write back
@@ -569,8 +574,13 @@ class LoadStoreQueue(implicit p: Parameters) extends CoreModule()(p) {
569574
570575 // update logical head
571576 // update physical head
572- // TODO: optimize this to be faster (multiple entries? probably want at least same cycle updates)
573- when (logicalHead =/= tail && (! valid(idxBits(logicalHead)) || done(idxBits(logicalHead)))) {
577+ val advanceLogicalHead = {
578+ ! valid(idxBits(logicalHead)) ||
579+ done(idxBits(logicalHead)) ||
580+ (muonParams.lsu.fastHeadUpdate.B && doneNext(idxBits(logicalHead))) // same-cycle update
581+ }
582+
583+ when (logicalHead =/= tail && advanceLogicalHead) {
574584 logicalHead := logicalHead + 1 .U
575585 }
576586
@@ -1335,17 +1345,17 @@ class LoadStoreUnit(implicit p: Parameters) extends CoreModule()(p) {
13351345
13361346 // -- Memory Update --
13371347 if (muonParams.lsu.smemDoesntReorder) {
1338- // if io.shmemReq fired last cycle, then send receivedMemUpdate to appropriate queue
1339- // it might be possible to send it on the same cycle that it fires, but this seems safer
1340- // if the response comes back the next cycle anyways, this should still be fine too
1341- val shmemReqFire_d1 = RegNext (io.shmemReq.fire, false . B )
1342- val shmemReqToken_d1 = RegNext (
1343- io.shmemReq.bits.tag.asTypeOf( new LsuMemTag ),
1344- 0 . U .asTypeOf( new LsuMemTag )
1345- )
1346-
1347- loadStoreQueues.io.receivedMemUpdate.valid := shmemReqFire_d1
1348- loadStoreQueues.io.receivedMemUpdate.bits.token := shmemReqToken_d1.token
1348+ // if queueRequest fired this cycle w/ shared mem request , then send receivedMemUpdate to appropriate queue
1349+ // it's critical to get this update back to load/store queues ASAP to ensure full shared memory store throughput
1350+ val queueRequest = loadStoreQueues.io.sendMemRequest.req
1351+ val queueRequestToken = queueRequest.bits.token
1352+ when (queueRequest.fire && queueRequestToken.addressSpace === AddressSpace .sharedMemory) {
1353+ loadStoreQueues. io.receivedMemUpdate.valid := true . B
1354+ loadStoreQueues.io.receivedMemUpdate.bits.token := queueRequestToken
1355+ }.otherwise {
1356+ loadStoreQueues.io.receivedMemUpdate.valid := false . B
1357+ loadStoreQueues.io.receivedMemUpdate.bits.token := DontCare
1358+ }
13491359 }
13501360 else {
13511361 loadStoreQueues.io.receivedMemUpdate.valid := false .B
0 commit comments