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+ */
17+
18+ package coupledL2 .tl2chi
19+
20+ import chisel3 ._
21+ import chisel3 .util ._
22+ import org .chipsalliance .cde .config .Parameters
23+ import coupledL2 .L2Module
24+
25+ class ChannelIO [+ T <: Data ](gen : T ) extends Bundle {
26+ // Flit Pending. Early indication that a flit might be transmitted in the following cycle
27+ val flitpend = Output (Bool ()) // To be confirmed: can this be ignored?
28+ // Flit Valid. The transmitter sets the signal HIGH to indicate when FLIT[(W-1):0] is valid.
29+ val flitv = Output (Bool ())
30+ // Flit.
31+ val flit = Output (UInt (gen.getWidth.W ))
32+ // L-Credit Valid. The receiver sets this signal HIGH to return a channel L-Credit to a transmitter.
33+ val lcrdv = Input (Bool ())
34+ }
35+
36+ object ChannelIO {
37+ def apply [T <: Data ](gen : T ): ChannelIO [T ] = new ChannelIO (gen)
38+
39+ private final class EmptyBundle extends Bundle
40+ def apply (): ChannelIO [Data ] = apply(new EmptyBundle )
41+ }
42+
43+ trait HasLinkSwitch { this : Bundle =>
44+ val linkactivereq = Output (Bool ())
45+ val linkactiveack = Input (Bool ())
46+ }
47+
48+ trait HasPortSwitch { this : Bundle =>
49+ val txsactive = Output (Bool ())
50+ val rxsactive = Input (Bool ())
51+ }
52+
53+ class DownwardsLinkIO extends Bundle with HasLinkSwitch {
54+ val req = ChannelIO (new CHIREQ )
55+ val rsp = ChannelIO (new CHIRSP )
56+ val dat = ChannelIO (new CHIDAT )
57+ }
58+
59+ class UpwardsLinkIO extends Bundle with HasLinkSwitch {
60+ val rsp = ChannelIO (new CHIRSP )
61+ val dat = ChannelIO (new CHIDAT )
62+ val snp = ChannelIO (new CHISNP )
63+ }
64+
65+ class DecoupledDownwardsLinkIO extends Bundle {
66+ val req = DecoupledIO (new CHIREQ )
67+ val rsp = DecoupledIO (new CHIRSP )
68+ val dat = DecoupledIO (new CHIDAT )
69+ }
70+
71+ class DecoupledUpwardsLinkIO extends Bundle {
72+ val rsp = DecoupledIO (new CHIRSP )
73+ val dat = DecoupledIO (new CHIDAT )
74+ val snp = DecoupledIO (new CHISNP )
75+ }
76+
77+ class DecoupledDownwardsNoSnpLinkIO extends Bundle {
78+ val req = DecoupledIO (new CHIREQ )
79+ val dat = DecoupledIO (new CHIDAT )
80+ }
81+
82+ class DecoupledUpwardsNoSnpLinkIO extends Bundle {
83+ val rsp = DecoupledIO (new CHIRSP )
84+ val dat = DecoupledIO (new CHIDAT )
85+ }
86+
87+ class PortIO extends Bundle with HasPortSwitch {
88+ val tx = new DownwardsLinkIO
89+ val rx = Flipped (new UpwardsLinkIO )
90+ }
91+
92+ class DecoupledPortIO extends Bundle {
93+ val tx = new DecoupledDownwardsLinkIO
94+ val rx = Flipped (new DecoupledUpwardsLinkIO )
95+ }
96+
97+ class DecoupledNoSnpPortIO extends Bundle {
98+ val tx = new DecoupledDownwardsNoSnpLinkIO
99+ val rx = Flipped (new DecoupledUpwardsNoSnpLinkIO )
100+ }
101+
102+ object LinkStates {
103+ val width = 2
104+
105+ def STOP = 0 .U (width.W )
106+ def ACTIVATE = 1 .U (width.W )
107+ def RUN = 2 .U (width.W )
108+ def DEACTIVATE = 3 .U (width.W )
109+ }
110+
111+ class LinkState extends Bundle {
112+ val state = UInt (LinkStates .width.W )
113+ }
114+
115+ object LinkState {
116+ def apply (s : UInt ) = {
117+ val ls = Wire (new LinkState )
118+ ls.state := s
119+ ls
120+ }
121+ def onReset = LinkState (LinkStates .STOP )
122+ }
123+
124+ class LCredit2Decoupled [T <: Bundle ](
125+ gen : T ,
126+ lcreditNum : Int = 4 // the number of L-Credits that a receiver can provide
127+ ) extends Module {
128+ val io = IO (new Bundle () {
129+ val in = Flipped (ChannelIO (gen.cloneType))
130+ val out = DecoupledIO (gen.cloneType)
131+ val state = Input (new LinkState ())
132+ val reclaimLCredit = Output (Bool ())
133+ })
134+
135+ require(lcreditNum <= 15 )
136+
137+ val queue = Module (new Queue (gen.cloneType, entries = lcreditNum, pipe = true , flow = false ))
138+
139+ val state = io.state.state
140+ val enableLCredit = state === LinkStates .RUN
141+
142+ val lcreditsWidth = log2Up(lcreditNum) + 1
143+ val lcreditInflight = RegInit (0 .U (lcreditsWidth.W ))
144+ val lcreditPool = RegInit (lcreditNum.U (lcreditsWidth.W ))
145+ assert(lcreditInflight + lcreditPool === lcreditNum.U )
146+ val lcreditOut = (lcreditPool > queue.io.count) && enableLCredit
147+
148+ val ready = lcreditInflight =/= 0 .U
149+ val accept = ready && io.in.flitv && RegNext (io.in.flitpend)
150+
151+ when (lcreditOut) {
152+ when (! accept) {
153+ lcreditInflight := lcreditInflight + 1 .U
154+ lcreditPool := lcreditPool - 1 .U
155+ }
156+ }.otherwise {
157+ when (accept) {
158+ lcreditInflight := lcreditInflight - 1 .U
159+ lcreditPool := lcreditPool + 1 .U
160+ }
161+ }
162+
163+ queue.io.enq.valid := accept
164+ // queue.io.enq.bits := io.in.bits
165+ var lsb = 0
166+ queue.io.enq.bits.getElements.reverse.foreach { case e =>
167+ e := io.in.flit(lsb + e.asUInt.getWidth - 1 , lsb).asTypeOf(e.cloneType)
168+ lsb += e.asUInt.getWidth
169+ }
170+
171+ assert(! accept || queue.io.enq.ready)
172+
173+ io.in.lcrdv := lcreditOut
174+
175+ io.out <> queue.io.deq
176+ val opcodeElements = queue.io.deq.bits.elements.filter(_._1 == " opcode" )
177+ require (opcodeElements.size == 1 )
178+ for ((_, opcode) <- opcodeElements) {
179+ when (queue.io.deq.valid && opcode === 0 .U ) {
180+ // This is a *LCrdReturn flit
181+ queue.io.deq.ready := true .B
182+ io.out.valid := false .B
183+ }
184+ }
185+ io.reclaimLCredit := lcreditInflight === 0 .U
186+ }
187+
188+ object LCredit2Decoupled {
189+ val defaultLCreditNum = 4
190+
191+ def apply [T <: Bundle ](
192+ left : ChannelIO [T ],
193+ right : DecoupledIO [T ],
194+ state : LinkState ,
195+ reclaimLCredit : Bool ,
196+ suggestName : Option [String ] = None ,
197+ lcreditNum : Int = defaultLCreditNum
198+ ): Unit = {
199+ val mod = Module (new LCredit2Decoupled (right.bits.cloneType, lcreditNum))
200+ suggestName.foreach(name => mod.suggestName(s " LCredit2Decoupled_ ${name}" ))
201+
202+ mod.io.in <> left
203+ right <> mod.io.out
204+ mod.io.state := state
205+ reclaimLCredit := mod.io.reclaimLCredit
206+ }
207+ }
208+
209+ class Decoupled2LCredit [T <: Bundle ](gen : T ) extends Module {
210+ val io = IO (new Bundle () {
211+ val in = Flipped (DecoupledIO (gen.cloneType))
212+ val out = ChannelIO (gen.cloneType)
213+ val state = Input (new LinkState ())
214+ })
215+
216+ val state = io.state.state
217+ val disableFlit = state === LinkStates .STOP || state === LinkStates .ACTIVATE
218+ val disableLCredit = state === LinkStates .STOP
219+ val acceptLCredit = io.out.lcrdv && ! disableLCredit
220+
221+ // The maximum number of L-Credits that a receiver can provide is 15.
222+ val lcreditsMax = 15
223+ val lcreditPool = RegInit (0 .U (log2Up(lcreditsMax).W ))
224+
225+ val returnLCreditValid = ! io.in.valid && state === LinkStates .DEACTIVATE && lcreditPool =/= 0 .U
226+
227+ when (acceptLCredit) {
228+ when (! io.out.flitv) {
229+ lcreditPool := lcreditPool + 1 .U
230+ assert(lcreditPool + 1 .U =/= 0 .U , " L-Credit pool overflow" )
231+ }
232+ }.otherwise {
233+ when (io.out.flitv) {
234+ lcreditPool := lcreditPool - 1 .U
235+ }
236+ }
237+
238+ io.in.ready := lcreditPool =/= 0 .U && ! disableFlit
239+ io.out.flitpend := true .B
240+ io.out.flitv := io.in.fire || returnLCreditValid
241+ io.out.flit := Mux (
242+ io.in.valid,
243+ Cat (io.in.bits.getElements.map(_.asUInt)),
244+ 0 .U // LCrdReturn
245+ )
246+ }
247+
248+ object Decoupled2LCredit {
249+ def apply [T <: Bundle ](
250+ left : DecoupledIO [T ],
251+ right : ChannelIO [T ],
252+ state : LinkState ,
253+ suggestName : Option [String ] = None
254+ ): Unit = {
255+ val mod = Module (new Decoupled2LCredit (left.bits.cloneType))
256+ suggestName.foreach(name => mod.suggestName(s " Decoupled2LCredit_ ${name}" ))
257+
258+ mod.io.in <> left
259+ right <> mod.io.out
260+ mod.io.state := state
261+ }
262+ }
263+
264+ class LinkMonitor (implicit p : Parameters ) extends L2Module with HasCHIMsgParameters {
265+ val io = IO (new Bundle () {
266+ val in = Flipped (new DecoupledPortIO ())
267+ val out = new PortIO
268+ val nodeID = Input (UInt (NODEID_WIDTH .W ))
269+ })
270+ // val s_stop :: s_activate :: s_run :: s_deactivate :: Nil = Enum(4)
271+
272+ val txState = RegInit (LinkStates .STOP )
273+ val rxState = RegInit (LinkStates .STOP )
274+
275+ Seq (txState, rxState).zip(MixedVecInit (Seq (io.out.tx, io.out.rx))).foreach { case (state, link) =>
276+ state := MuxLookup (Cat (link.linkactivereq, link.linkactiveack), LinkStates .STOP )(Seq (
277+ Cat (true .B , false .B ) -> LinkStates .ACTIVATE ,
278+ Cat (true .B , true .B ) -> LinkStates .RUN ,
279+ Cat (false .B , true .B ) -> LinkStates .DEACTIVATE ,
280+ Cat (false .B , false .B ) -> LinkStates .STOP
281+ ))
282+ }
283+
284+ /* IO assignment */
285+ val rxsnpDeact, rxrspDeact, rxdatDeact = Wire (Bool ())
286+ val rxDeact = rxsnpDeact && rxrspDeact && rxdatDeact
287+ Decoupled2LCredit (setSrcID(io.in.tx.req, io.nodeID), io.out.tx.req, LinkState (txState), Some (" txreq" ))
288+ Decoupled2LCredit (setSrcID(io.in.tx.rsp, io.nodeID), io.out.tx.rsp, LinkState (txState), Some (" txrsp" ))
289+ Decoupled2LCredit (setSrcID(io.in.tx.dat, io.nodeID), io.out.tx.dat, LinkState (txState), Some (" txdat" ))
290+ LCredit2Decoupled (io.out.rx.snp, io.in.rx.snp, LinkState (rxState), rxsnpDeact, Some (" rxsnp" ))
291+ LCredit2Decoupled (io.out.rx.rsp, io.in.rx.rsp, LinkState (rxState), rxrspDeact, Some (" rxrsp" ))
292+ LCredit2Decoupled (io.out.rx.dat, io.in.rx.dat, LinkState (rxState), rxdatDeact, Some (" rxdat" ))
293+
294+ io.out.txsactive := true .B
295+ io.out.tx.linkactivereq := ! reset.asBool
296+ io.out.rx.linkactiveack := RegNext (io.out.rx.linkactivereq) || ! rxDeact
297+
298+ dontTouch(io.out)
299+
300+ def setSrcID [T <: Bundle ](in : DecoupledIO [T ], srcID : UInt = 0 .U ): DecoupledIO [T ] = {
301+ val out = Wire (in.cloneType)
302+ out <> in
303+ out.bits.elements.filter(_._1 == " srcID" ).head._2 := srcID
304+ out
305+ }
306+ }
0 commit comments