Skip to content

Commit 869b6b3

Browse files
linjuanZyulightenyuIvyfeatherKumonda221-CrO3cyril0124
committed
feat: an initial version of CHIUtils (OpenXiangShan/CoupledL2#145)
--------- Co-authored-by: Zhu Yu <[email protected]> Co-authored-by: Chen Xi <[email protected]> Co-authored-by: Kumonda221 <[email protected]> Co-authored-by: cyril0124 <[email protected]>
1 parent 992ce71 commit 869b6b3

File tree

4 files changed

+842
-0
lines changed

4 files changed

+842
-0
lines changed

LinkLayer.scala

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
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

Comments
 (0)