@@ -12,15 +12,19 @@ import org.chipsalliance.cde.config.{Parameters, Field, Config}
1212import freechips .rocketchip .diplomacy ._
1313import freechips .rocketchip .regmapper .{HasRegMap , RegField }
1414import freechips .rocketchip .tilelink ._
15- import freechips .rocketchip .util .UIntIsOneOf
15+ import freechips .rocketchip .util ._
1616
1717// DOC include start: GCD params
1818case class GCDParams (
1919 address : BigInt = 0x4000 ,
2020 width : Int = 32 ,
2121 useAXI4 : Boolean = false ,
2222 useBlackBox : Boolean = true ,
23- useHLS : Boolean = false )
23+ useHLS : Boolean = false ,
24+ externallyClocked : Boolean = false
25+ ) {
26+ require(! (useAXI4 && useHLS))
27+ }
2428// DOC include end: GCD params
2529
2630// DOC include start: GCD key
@@ -287,48 +291,104 @@ trait CanHavePeripheryGCD { this: BaseSubsystem =>
287291 private val pbus = locateTLBusWrapper(PBUS )
288292
289293 // Only build if we are using the TL (nonAXI4) version
290- val gcd_busy = p(GCDKey ) match {
294+ val ( gcd_busy, gcd_clock) = p(GCDKey ) match {
291295 case Some (params) => {
296+
297+ // If externallyClocked is true, create an input port for the GCD clock.
298+ // This clock is distinct from the pbus clock or other internal clocks.
299+ // It's defined within InModuleBody as it's a hardware port.
300+ val gcd_clock = Option .when(params.externallyClocked) {
301+ InModuleBody { IO (Input (Clock ())).suggestName(" gcd_clock_in" ) }
302+ }
303+ // Define the clock source node for the GCD module.
304+ val gcdClockNode = if (params.externallyClocked) {
305+ // If externally clocked, create a new ClockSourceNode.
306+ // This node acts as the root of the GCD's independent clock domain.
307+ val gcdSourceClockNode = ClockSourceNode (Seq (ClockSourceParameters ()))
308+ InModuleBody {
309+ // Connect the ClockSourceNode's output clock to the external gcd_clock input.
310+ gcdSourceClockNode.out(0 )._1.clock := gcd_clock.get
311+ // The reset signal for the GCD's clock domain must be synchronous to the gcd_clock.
312+ // ResetCatchAndSync synchronizes the asynchronous pbus reset to the gcd_clock domain.
313+ gcdSourceClockNode.out(0 )._1.reset := ResetCatchAndSync (gcd_clock.get, pbus.module.reset.asBool)
314+ }
315+ gcdSourceClockNode
316+ } else {
317+ // If not externally clocked, the GCD runs on the same clock as the pbus.
318+ pbus.fixedClockNode
319+ }
320+ // Define the type of clock crossing required between the pbus and the GCD module.
321+ val gcdCrossing = if (params.externallyClocked) {
322+ // If the GCD has its own clock, an AsynchronousCrossing is necessary
323+ // to safely transfer data between the pbus clock domain and the GCD clock domain.
324+ AsynchronousCrossing ()
325+ } else {
326+ // If the GCD uses the pbus clock, a SynchronousCrossing can be used.
327+ SynchronousCrossing ()
328+ }
329+
330+ // Instantiate the GCD module (either TL, AXI4, or HLS variant)
292331 val gcd = if (params.useAXI4) {
293332 val gcd = LazyModule (new GCDAXI4 (params, pbus.beatBytes)(p))
294- gcd.clockNode := pbus.fixedClockNode
333+ // Connect the GCD's clock input to our determined gcdClockNode.
334+ gcd.clockNode := gcdClockNode
335+ // Couple the GCD to the pbus, inserting the necessary clock crossing logic.
295336 pbus.coupleTo(portName) {
296- gcd.node :=
337+ // AXI4InwardClockCrossingHelper handles crossing details for AXI4.
338+ AXI4InwardClockCrossingHelper (" gcd_crossing" , gcd, gcd.node)(gcdCrossing) :=
297339 AXI4Buffer () :=
298340 TLToAXI4 () :=
299- // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needsx
341+ // toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needs
300342 TLFragmenter (pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true ) := _
301343 }
302344 gcd
303345 } else if (params.useHLS) {
304346 val gcd = LazyModule (new HLSGCDAccel (params, pbus.beatBytes)(p))
305- gcd.clockNode := pbus.fixedClockNode
306- pbus.coupleTo(portName) { gcd.node := TLFragmenter (pbus.beatBytes, pbus.blockBytes) := _ }
347+ // Connect the GCD's clock input to our determined gcdClockNode.
348+ gcd.clockNode := gcdClockNode
349+ // Couple the GCD to the pbus, inserting the necessary clock crossing logic.
350+ pbus.coupleTo(portName) {
351+ // TLInwardClockCrossingHelper handles crossing details for TileLink.
352+ TLInwardClockCrossingHelper (" gcd_crossing" , gcd, gcd.node)(gcdCrossing) :=
353+ TLFragmenter (pbus.beatBytes, pbus.blockBytes) := _
354+ }
307355 gcd
308356 } else {
309357 val gcd = LazyModule (new GCDTL (params, pbus.beatBytes)(p))
310- gcd.clockNode := pbus.fixedClockNode
311- pbus.coupleTo(portName) { gcd.node := TLFragmenter (pbus.beatBytes, pbus.blockBytes) := _ }
358+ // Connect the GCD's clock input to our determined gcdClockNode.
359+ gcd.clockNode := gcdClockNode
360+ // Couple the GCD to the pbus, inserting the necessary clock crossing logic.
361+ pbus.coupleTo(portName) {
362+ // TLInwardClockCrossingHelper handles crossing details for TileLink.
363+ TLInwardClockCrossingHelper (" gcd_crossing" , gcd, gcd.node)(gcdCrossing) :=
364+ TLFragmenter (pbus.beatBytes, pbus.blockBytes) := _
365+ }
312366 gcd
313367 }
368+ // Expose the GCD's busy signal.
314369 val gcd_busy = InModuleBody {
315370 val busy = IO (Output (Bool ())).suggestName(" gcd_busy" )
316371 busy := gcd.module.io.gcd_busy
317372 busy
318373 }
319- Some (gcd_busy)
374+ // Return the busy signal (always needed if GCD exists) and the optional external clock input.
375+ // The Option[Clock] allows the IOBinder (WithGCDIOPunchthrough) to conditionally
376+ // create the top-level clock input only when `externallyClocked` is true.
377+ // The busy signal is Some(busy) because the entire GCD peripheral itself is optional based on GCDKey.
378+ (Some (gcd_busy), gcd_clock)
320379 }
321- case None => None
380+ // If GCDKey is None, the GCD peripheral is not instantiated. Return None for both signals.
381+ case None => (None , None )
322382 }
323383}
324384// DOC include end: GCD lazy trait
325385
326386// DOC include start: GCD config fragment
327- class WithGCD (useAXI4 : Boolean = false , useBlackBox : Boolean = false , useHLS : Boolean = false ) extends Config ((site, here, up) => {
387+ class WithGCD (useAXI4 : Boolean = false , useBlackBox : Boolean = false , useHLS : Boolean = false , externallyClocked : Boolean = false ) extends Config ((site, here, up) => {
328388 case GCDKey => {
329389 // useHLS cannot be used with useAXI4 and useBlackBox
330- assert(! useHLS || (useHLS && ! useAXI4 && ! useBlackBox))
331- Some (GCDParams (useAXI4 = useAXI4, useBlackBox = useBlackBox, useHLS = useHLS))
390+ assert(! useHLS || (useHLS && ! useAXI4 && ! useBlackBox))
391+ Some (GCDParams (useAXI4 = useAXI4, useBlackBox = useBlackBox, useHLS = useHLS, externallyClocked = externallyClocked ))
332392 }
333393})
334394// DOC include end: GCD config fragment
0 commit comments