Skip to content

Commit 2ef376c

Browse files
committed
feat(CustomL1Hint): recover l2hint design in master
1 parent 1dde297 commit 2ef376c

File tree

6 files changed

+50
-32
lines changed

6 files changed

+50
-32
lines changed

src/main/scala/coupledL2/Common.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ class PrefetchRecv extends Bundle {
353353
class L2ToL1Hint(implicit p: Parameters) extends Bundle {
354354
val sourceId = UInt(32.W) // tilelink sourceID
355355
val isKeyword = Bool() // miss entry keyword
356+
val isGrantData = Bool()
356357
}
357358

358359
// custom l2 - l1 tlb

src/main/scala/coupledL2/CoupledL2.scala

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -383,17 +383,12 @@ abstract class CoupledL2Base(implicit p: Parameters) extends LazyModule with Has
383383

384384
// ** WARNING:TODO: this depends on where the latch is
385385
// ** if Hint latched in slice, while D-Channel latched in XSTile
386-
// ** we need only [hintCycleAhead - 1] later
387-
val sliceAhead = hintCycleAhead - 1
386+
// ** we need only [hintCycleAhead - 2] later
387+
val sliceAhead = hintCycleAhead - 2
388388

389389
val hintChosen = Wire(UInt(banks.W))
390390
val hintFire = Wire(Bool())
391-
392-
// if Hint indicates that this slice should fireD, yet no D resp comes out of this slice
393-
// then we releaseSourceD, enabling io.d.ready for other slices
394-
// TODO: if Hint for single slice is 100% accurate, may consider remove this
395-
val releaseSourceD = Wire(Vec(banks, Bool()))
396-
val allCanFire = (RegNextN(!hintFire, sliceAhead) && RegNextN(!hintFire, sliceAhead + 1)) || Cat(releaseSourceD).orR
391+
val hintWithData = Wire(Bool())
397392

398393
val slices = node.in.zip(node.out).zipWithIndex.map {
399394
case (((in, edgeIn), (out, edgeOut)), i) =>
@@ -423,12 +418,14 @@ abstract class CoupledL2Base(implicit p: Parameters) extends LazyModule with Has
423418
// If slice X has no grant then, it means that the hint at cycle T is wrong,
424419
// so we relax the restriction on grant selection.
425420
val sliceCanFire = RegNextN(hintFire && i.U === hintChosen, sliceAhead) ||
426-
RegNextN(hintFire && i.U === hintChosen, sliceAhead + 1)
421+
RegNextN(hintFire && i.U === hintChosen && hintWithData, sliceAhead + 1)
427422

428-
releaseSourceD(i) := sliceCanFire && !slice.io.in.d.valid
423+
when(sliceCanFire) {
424+
assert(slice.io.in.d.valid)
425+
}
429426

430-
in.d.valid := slice.io.in.d.valid && (sliceCanFire || allCanFire)
431-
slice.io.in.d.ready := in.d.ready && (sliceCanFire || allCanFire)
427+
in.d.valid := slice.io.in.d.valid && sliceCanFire
428+
slice.io.in.d.ready := in.d.ready && sliceCanFire
432429
}
433430
in.b.bits.address := restoreAddress(slice.io.in.b.bits.address, i)
434431
slice.io.sliceId := i.U
@@ -512,11 +509,13 @@ abstract class CoupledL2Base(implicit p: Parameters) extends LazyModule with Has
512509
io.l2_hint.valid := l1HintArb.io.out.fire && sourceIsDcache
513510
io.l2_hint.bits.sourceId := l1HintArb.io.out.bits.sourceId - dcacheSourceIdStart
514511
io.l2_hint.bits.isKeyword := l1HintArb.io.out.bits.isKeyword
515-
// continuous hints can only be sent every two cycle, since GrantData takes two cycles
516-
l1HintArb.io.out.ready := !RegNext(io.l2_hint.valid, false.B)
512+
io.l2_hint.bits.isGrantData := l1HintArb.io.out.bits.isGrantData
517513

518514
hintChosen := l1HintArb.io.chosen // ! THIS IS NOT ONE-HOT !
519-
hintFire := io.l2_hint.valid
515+
hintFire := l1HintArb.io.out.fire
516+
hintWithData := l1HintArb.io.out.bits.isGrantData
517+
// continuous hints can only be sent every two cycle, since GrantData takes two cycles
518+
l1HintArb.io.out.ready := !RegNext(hintFire && hintWithData, false.B)
520519
}
521520

522521
// Outer interface connection

src/main/scala/coupledL2/CustomL1Hint.scala

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class CustomL1HintIOBundle(implicit p: Parameters) extends L2Bundle {
3636
val s3 = new L2Bundle {
3737
val task = Flipped(ValidIO(new TaskBundle()))
3838
val need_mshr = Input(Bool())
39+
val retry = Input(Bool())
3940
}
4041

4142
// output hint
@@ -58,16 +59,22 @@ class CustomL1Hint(implicit p: Parameters) extends L2Module {
5859
def isGrant(t: TaskBundle): Bool = t.fromA && t.opcode === Grant
5960
def isHintAck(t: TaskBundle): Bool = t.fromA && t.opcode === HintAck // HintAck has no effect on Hint
6061
def isRelease(t: TaskBundle): Bool = t.fromC && (t.opcode === Release || t.opcode === ReleaseData)
62+
def isReleaseAck(t: TaskBundle): Bool = t.fromC && t.opcode === ReleaseAck
63+
def isCBOAck(t: TaskBundle): Bool = t.fromA && t.opcode === CBOAck
6164
def isMergeGrantData(t: TaskBundle): Bool = t.fromA && t.mergeA && t.aMergeTask.opcode === GrantData
6265
def isMergeGrant(t: TaskBundle): Bool = t.fromA && t.mergeA && t.aMergeTask.opcode === Grant
66+
def isAccessAckData(t: TaskBundle): Bool = t.fromA && t.opcode === AccessAckData
6367

6468
// ==================== Hint Generation ====================
6569
// Hint for "MSHRTask and ReleaseAck" will fire@s1
66-
val mshr_GrantData_s1 = task_s1.valid && mshrReq_s1 && (isGrantData(task_s1.bits) || isMergeGrantData(task_s1.bits))
67-
val mshr_Grant_s1 = task_s1.valid && mshrReq_s1 && (isGrant(task_s1.bits) || isMergeGrant(task_s1.bits))
68-
val chn_Release_s1 = task_s1.valid && !mshrReq_s1 && isRelease(task_s1.bits)
70+
val mshr_GrantData_s1 = task_s1.valid && mshrReq_s1 && (isGrantData(task_s1.bits) || isMergeGrantData(task_s1.bits))
71+
val mshr_Grant_s1 = task_s1.valid && mshrReq_s1 && (isGrant(task_s1.bits) || isMergeGrant(task_s1.bits))
72+
val chn_CBOAck_s1 = task_s1.valid && mshrReq_s1 && isCBOAck(task_s1.bits)
73+
val chn_Release_s1 = task_s1.valid && !mshrReq_s1 && isRelease(task_s1.bits)
74+
val chn_ReleaseAck_s1 = task_s1.valid && !mshrReq_s1 && isReleaseAck(task_s1.bits)
75+
val chn_AccessAckData_s1 = task_s1.valid && mshrReq_s1 && isAccessAckData(task_s1.bits)
6976

70-
val enqValid_s1 = mshr_GrantData_s1 || mshr_Grant_s1 || chn_Release_s1
77+
val enqValid_s1 = mshr_GrantData_s1 || mshr_Grant_s1 || chn_Release_s1 || chn_AccessAckData_s1 || chn_CBOAck_s1
7178
val enqSource_s1 = Mux(task_s1.bits.mergeA, task_s1.bits.aMergeTask.sourceId, task_s1.bits.sourceId)
7279
val enqKeyWord_s1 = Mux(task_s1.bits.mergeA,
7380
task_s1.bits.aMergeTask.isKeyword.getOrElse(false.B),
@@ -77,20 +84,25 @@ class CustomL1Hint(implicit p: Parameters) extends L2Module {
7784
Seq(
7885
mshr_Grant_s1 -> Grant,
7986
mshr_GrantData_s1 -> GrantData,
80-
chn_Release_s1 -> ReleaseAck
87+
chn_Release_s1 -> ReleaseAck,
88+
chn_AccessAckData_s1 -> AccessAckData,
89+
chn_CBOAck_s1 -> CBOAck
8190
)
8291
)
8392

8493
// Hint for "chnTask Hit" will fire@s3
8594
val chn_Grant_s3 = task_s3.valid && !mshrReq_s3 && !need_mshr_s3 && isGrant(task_s3.bits)
8695
val chn_GrantData_s3 = task_s3.valid && !mshrReq_s3 && !need_mshr_s3 && isGrantData(task_s3.bits)
87-
val enqValid_s3 = chn_Grant_s3 || chn_GrantData_s3
96+
val chn_AccessAckData_s3 = task_s3.valid && !mshrReq_s3 && !need_mshr_s3 && isAccessAckData(task_s3.bits)
97+
98+
val enqValid_s3 = chn_Grant_s3 || chn_GrantData_s3 || chn_AccessAckData_s3
8899
val enqSource_s3 = task_s3.bits.sourceId
89100
val enqKeyWord_s3 = task_s3.bits.isKeyword.getOrElse(false.B)
90101
val enqOpcode_s3 = ParallelPriorityMux(
91102
Seq(
92103
chn_Grant_s3 -> Grant,
93-
chn_GrantData_s3 -> GrantData
104+
chn_GrantData_s3 -> GrantData,
105+
chn_AccessAckData_s3 -> AccessAckData
94106
)
95107
)
96108

@@ -108,15 +120,21 @@ class CustomL1Hint(implicit p: Parameters) extends L2Module {
108120
hint_s1Queue.io.deq.ready := hintQueue.io.enq.ready && !enqValid_s3
109121
// WARNING:TODO: ensure queue will never overflow
110122
assert(hint_s1Queue.io.enq.ready, "hint_s1Queue should never be full")
111-
assert(hintQueue.io.enq.ready, "hintQueue should never be full")
123+
// *NOTICE: 'hintQueue' is now possible to be full and backpressing 'hint_s1Queue'.
124+
// Hence, this assertion here was currently unnecessary and overkilled.
125+
//assert(hintQueue.io.enq.ready, "hintQueue should never be full")
126+
127+
val deqLatency = RegNext(io.l1Hint.fire && io.l1Hint.bits.isGrantData)
128+
val hintEnqValid = enqValid_s3 || hint_s1Queue.io.deq.valid
112129

113-
hintQueue.io.enq.valid := enqValid_s3 || hint_s1Queue.io.deq.valid
114-
hintQueue.io.enq.bits.opcode := Mux(enqValid_s3, enqOpcode_s3, hint_s1Queue.io.deq.bits.opcode)
115-
hintQueue.io.enq.bits.source := Mux(enqValid_s3, enqSource_s3, hint_s1Queue.io.deq.bits.source)
116-
hintQueue.io.enq.bits.isKeyword := Mux(enqValid_s3, enqKeyWord_s3, hint_s1Queue.io.deq.bits.isKeyword)
117-
hintQueue.io.deq.ready := io.l1Hint.ready
130+
hintQueue.io.enq.valid := RegNext(hintEnqValid)
131+
hintQueue.io.enq.bits.opcode := RegEnable(Mux(enqValid_s3, enqOpcode_s3, hint_s1Queue.io.deq.bits.opcode), hintEnqValid)
132+
hintQueue.io.enq.bits.source := RegEnable(Mux(enqValid_s3, enqSource_s3, hint_s1Queue.io.deq.bits.source), hintEnqValid)
133+
hintQueue.io.enq.bits.isKeyword := RegEnable(Mux(enqValid_s3, enqKeyWord_s3, hint_s1Queue.io.deq.bits.isKeyword), hintEnqValid)
134+
hintQueue.io.deq.ready := io.l1Hint.ready && !deqLatency
118135

119-
io.l1Hint.valid := hintQueue.io.deq.valid && hintQueue.io.deq.bits.opcode === GrantData
136+
io.l1Hint.valid := hintQueue.io.deq.valid && !deqLatency && !io.s3.retry
120137
io.l1Hint.bits.sourceId := hintQueue.io.deq.bits.source
121138
io.l1Hint.bits.isKeyword := hintQueue.io.deq.bits.isKeyword
139+
io.l1Hint.bits.isGrantData := hintQueue.io.deq.bits.opcode === GrantData || hintQueue.io.deq.bits.opcode === AccessAckData
122140
}

src/main/scala/coupledL2/tl2chi/MainPipe.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ class MainPipe(implicit p: Parameters) extends TL2CHIL2Module with HasCHIOpcodes
757757
customL1Hint.io.s3.task.bits.opcode := Mux(sink_resp_s3.valid, sink_resp_s3.bits.opcode, task_s3.bits.opcode)
758758
// customL1Hint.io.s3.d := d_s3.valid
759759
customL1Hint.io.s3.need_mshr := need_mshr_s3
760+
customL1Hint.io.s3.retry := task_s3.valid && mshr_refill_s3 && retry
760761

761762
// customL1Hint.io.s4.task := task_s4
762763
// customL1Hint.io.s4.d := d_s4.valid

src/main/scala/coupledL2/tl2tl/MainPipe.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ class MainPipe(implicit p: Parameters) extends L2Module with HasPerfEvents {
550550
// overwrite opcode: if sinkReq can respond, use sink_resp_s3.bits.opcode = Grant/GrantData
551551
customL1Hint.io.s3.task.bits.opcode := Mux(sink_resp_s3.valid, sink_resp_s3.bits.opcode, task_s3.bits.opcode)
552552
customL1Hint.io.s3.need_mshr := need_mshr_s3
553+
customL1Hint.io.s3.retry := task_s3.valid && mshr_refill_s3 && retry
553554

554555
customL1Hint.io.l1Hint <> io.l1Hint
555556

src/main/scala/coupledL2/tl2tl/Slice.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ class Slice()(implicit p: Parameters) extends BaseSlice[OuterBundle] {
127127
sourceC.io.in <> mainPipe.io.toSourceC
128128
sourceC.io.pipeStatusVec := reqArb.io.status_vec ++ mainPipe.io.status_vec_toC
129129

130-
io.l1Hint.valid := mainPipe.io.l1Hint.valid
131-
io.l1Hint.bits.sourceId := mainPipe.io.l1Hint.bits.sourceId
132-
io.l1Hint.bits.isKeyword := mainPipe.io.l1Hint.bits.isKeyword
130+
io.l1Hint <> mainPipe.io.l1Hint
133131
mainPipe.io.l1Hint.ready := io.l1Hint.ready
134132
mshrCtl.io.grantStatus := grantBuf.io.grantStatus
135133

0 commit comments

Comments
 (0)