Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diplomatic Clock Primitives #1795

Merged
merged 39 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5feb2f6
clocks: copy clocks package from sifive.fpgashells; update imports
hcook Jan 19, 2019
62b2895
clocks: bundles can use chisel3 bundle to get cloneType for free
hcook Jan 19, 2019
8a7d395
clocks: use chisel3 in all files
hcook Jan 19, 2019
0730c7c
clocks: add ClockSinkDomain and ClockSourceDomain
hcook Jan 19, 2019
5bc8d11
clocks: allow for unspecified clock freqs
hcook Jan 21, 2019
2e94384
clocks: add TestClockSource test harness clock generators
hcook Jan 21, 2019
b073306
clocks: domain nodes are named clockNode
hcook Nov 19, 2019
ce44d0a
clocks: source and sink nodes offer fixedClockResources
hcook Nov 19, 2019
e708663
rename package from clocks to prci
hcook Nov 19, 2019
7752f6d
clocks: ClockGroup.pickGroupFromCrossingType
hcook Dec 10, 2019
21215a2
prci: make abstract base ClockDomain class
hcook Dec 16, 2019
03a15e6
prci: add FixedClockBroadcastNode
hcook Dec 16, 2019
6c4c290
tilelink: add fixedClockOpt to HasTLBusParams
hcook Dec 16, 2019
ef8c95c
tilelink: add clock nodes to TLBusWrapper
hcook Dec 16, 2019
b15d801
subsystem: add clockGroupNode to BaseSubsystem
hcook Dec 16, 2019
e79632e
devices: add example device that can gate clock from TL register-mapp…
hcook Dec 16, 2019
4b2cb7d
prci: add draft of ClockDivider adapter
hcook Dec 17, 2019
3ba1196
buswrapper: derive dtsClk from clockNode.fixedClockResources
hcook Dec 18, 2019
9649cdb
util: update ClockDivider to chisel3
hcook Dec 18, 2019
e5e6191
prci: add package object to hold asyncMux helper func
hcook Jan 7, 2020
9ea75be
prci: add ClockGroupSourceNode and ClockGroupSinkNode
hcook Jan 7, 2020
d5d78d9
prci: ClockGroup and ClockGroupBroadcast are LazyRawModuleImps
hcook Jan 7, 2020
b9bb79a
prci: domain creates clock and reset output IOs
hcook Jan 7, 2020
8688e9e
prci: rename ClockGroupBroadcastNode to ClockGroupAggregateNode
hcook Jan 7, 2020
66e6adb
subsystem: BaseSubsystem has ClockGroupIdentityNode
hcook Jan 7, 2020
face05e
tilelink: TLBusWrapper includes ClockGroupAggregator
hcook Jan 7, 2020
d700e6c
tilelink: TLBusWrapper crossTo/FromBus take implicit ClockGroupIdent…
hcook Jan 7, 2020
c6da16f
system: ExampleRocketSystem supplies default simple clock source
hcook Jan 7, 2020
180a4cc
prci: SimpleClockGroupSource can have a variable number of sources
hcook Jan 9, 2020
1f4d4d4
groundtest: subsystem needs dummyClockGroupSourceNode
hcook Jan 13, 2020
cfa719d
prci: add FixedClockBroadcast helper module and use in TLBusWrapper
hcook Jan 13, 2020
aa93003
prci: ClockEphemeralNode and ClockGroupEphemeralNode
hcook Jan 14, 2020
8317b2b
prci: TLBusWrapper uses ClockGroupEphemeralNode
hcook Jan 14, 2020
51f57c1
subsystem: add traits HasAsyncClockGroupsNode and Attachable
hcook Jan 14, 2020
5d81c8d
subsystem: clean up Attachable and add SubsystemDriveAsyncClockGroupsKey
hcook Jan 20, 2020
9782490
prci: add PRCIClockGroupNode: NexusNode(ClockGroupImp)
hcook Jan 20, 2020
5eb3723
tilelink: better name for BuwWrapper clock aggration nodes
hcook Jan 20, 2020
926abd9
groundtest: delete import that was actually unused
hcook Jan 22, 2020
1449344
prci: move ClockGroupDriverParameters to prci
hcook Jan 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/main/scala/devices/tilelink/ClockBlocker.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// See LICENSE.SiFive for license details.

package freechips.rocketchip.devices.tilelink

import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._

/** This device extends a basic bus blocker by allowing it to gate the clocks of the device
* whose tilelink port is being blocked. For now it is only possible to block
* a single TL port and all the clocks simultaneously.
*/

class TLClockBlocker(params: BasicBusBlockerParams)(implicit p: Parameters)
extends TLBusBypassBase(params.deviceBeatBytes, params.deadlock)
{
val device = new SimpleDevice("clock-blocker", Seq("sifive,clock-blocker0"))

val controlNode = TLRegisterNode(
address = Seq(AddressSet(params.controlAddress, 0xFFF)),
device = device,
beatBytes = params.controlBeatBytes)

val clockNode = ClockAdapterNode()

lazy val module = new LazyModuleImp(this) {
val allow = RegInit(true.B)
val pending = RegNext(bar.module.io.pending)

controlNode.regmap(
0 -> Seq(RegField (32, allow,
RegFieldDesc("allow",
"Used to enable/disable bus transactions", reset=Some(1)))),
4 -> Seq(RegField.r(32, pending, RegFieldDesc("pending",
"Indicates if bus transactions are in-flight", volatile=true)))
)

bar.module.io.bypass := !allow

val (clock_in, _) = clockNode.in.unzip
val (clock_out, _) = clockNode.out.unzip

(clock_in zip clock_out) foreach { case (i, o) =>
o.clock := ClockGate(i.clock, allow || pending)
o.reset := i.reset
}
}
}
16 changes: 16 additions & 0 deletions src/main/scala/prci/ClockBundles.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.prci

import chisel3._
import freechips.rocketchip.util.HeterogeneousBag

class ClockBundle(val params: ClockBundleParameters) extends Bundle
{
val clock = Clock()
val reset = Bool()
hcook marked this conversation as resolved.
Show resolved Hide resolved
}

class ClockGroupBundle(val params: ClockGroupBundleParameters) extends Bundle
{
val member = HeterogeneousBag(params.members.map(p => new ClockBundle(p)))
}
35 changes: 35 additions & 0 deletions src/main/scala/prci/ClockDivider.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.prci

import chisel3._
import chisel3.util.isPow2
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util.{ClockDivider3, Pow2ClockDivider}

/* An example clock adapter that divides all clocks passed through this node by an integer factor
*/
class ClockDivider(div: Int)(implicit p: Parameters) extends LazyModule {
val node = ClockAdapterNode(
sourceFn = { case src => src.copy(give = src.give.map(x => x.copy(freqMHz = x.freqMHz / 2))) },
sinkFn = { case snk => snk.copy(take = snk.take.map(x => x.copy(freqMHz = x.freqMHz * 2))) })

lazy val module = new LazyModuleImp(this) {
(node.in zip node.out).foreach { case ((in, _), (out, _)) =>
val div_clock: Clock = div match {
case x if isPow2(x) => Pow2ClockDivider(in.clock, x)
case 3 => {
val div3 = Module(new ClockDivider3)
div3.io.clk_in := in.clock
div3.io.clk_out
}
case x => throw new IllegalArgumentException(s"rocketchip.util only supports clock division by powers of 2, or exactly 3, but got $x")
}
out.clock := div_clock
out.reset := withClock(out.clock) { RegNext(in.reset) }
}
}
}

// TODO make a version of this that output a clock group with two members,
// one of which is the original clock and the other of which is some number of divided clocks
36 changes: 36 additions & 0 deletions src/main/scala/prci/ClockDomain.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package freechips.rocketchip.prci

import chisel3._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._

abstract class ClockDomain(implicit p: Parameters) extends LazyModule
with LazyScope
with HasClockDomainCrossing
{
def clockBundle: ClockBundle

lazy val module = new LazyRawModuleImp(this) {
childClock := clockBundle.clock
childReset := clockBundle.reset

// these are just for backwards compatibility with external devices
// that were manually wiring themselves to the domain's clock/reset input:
val clock = IO(Output(chiselTypeOf(clockBundle.clock)))
val reset = IO(Output(chiselTypeOf(clockBundle.reset)))
clock := clockBundle.clock
reset := clockBundle.reset
}
}

class ClockSinkDomain(take: Option[ClockParameters] = None)(implicit p: Parameters) extends ClockDomain
{
val clockNode = ClockSinkNode(Seq(ClockSinkParameters(take = take)))
def clockBundle = clockNode.in.head._1
}

class ClockSourceDomain(give: Option[ClockParameters] = None)(implicit p: Parameters) extends ClockDomain
{
val clockNode = ClockSourceNode(Seq(ClockSourceParameters(give = give)))
def clockBundle = clockNode.out.head._1
}
104 changes: 104 additions & 0 deletions src/main/scala/prci/ClockGroup.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.prci

import chisel3._
import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._

case class ClockGroupNode(groupName: String)(implicit valName: ValName)
extends MixedNexusNode(ClockGroupImp, ClockImp)(
dFn = { _ => ClockSourceParameters() },
uFn = { seq => ClockGroupSinkParameters(name = groupName, members = seq) })

class ClockGroup(groupName: String)(implicit p: Parameters) extends LazyModule
{
val node = ClockGroupNode(groupName)

lazy val module = new LazyRawModuleImp(this) {
val (in, _) = node.in(0)
val (out, _) = node.out.unzip

require (node.in.size == 1)
require (in.member.size == out.size)

(in.member zip out) foreach { case (i, o) => o := i }
}
}

object ClockGroup
{
def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new ClockGroup(valName.name)).node
}

case class ClockGroupAggregateNode(groupName: String)(implicit valName: ValName)
extends NexusNode(ClockGroupImp)(
dFn = { _ => ClockGroupSourceParameters() },
uFn = { seq => ClockGroupSinkParameters(name = groupName, members = seq.flatMap(_.members))})

class ClockGroupAggregator(groupName: String)(implicit p: Parameters) extends LazyModule
{
val node = ClockGroupAggregateNode(groupName)

lazy val module = new LazyRawModuleImp(this) {
val (in, _) = node.in.unzip
val (out, _) = node.out.unzip
val outputs = out.flatMap(_.member)

require (node.in.size == 1)
require (in.head.member.size == outputs.size)
in.head.member.zip(outputs).foreach { case (i, o) => o := i }
}
}

object ClockGroupAggregator
{
def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new ClockGroupAggregator(valName.name)).node
}

class SimpleClockGroupSource(numSources: Int = 1)(implicit p: Parameters) extends LazyModule
{
val node = ClockGroupSourceNode(List.fill(numSources) { ClockGroupSourceParameters() })

lazy val module = new LazyModuleImp(this) {
val (out, _) = node.out.unzip
val outputs = out.flatMap(_.member)
outputs.foreach { o => o.clock := clock; o.reset := reset }
}
}

object SimpleClockGroupSource
{
def apply(num: Int = 1)(implicit p: Parameters, valName: ValName) = LazyModule(new SimpleClockGroupSource(num)).node
}

case class FixedClockBroadcastNode(fixedClockOpt: Option[ClockParameters])(implicit valName: ValName)
extends NexusNode(ClockImp)(
dFn = { seq => fixedClockOpt.map(_ => ClockSourceParameters(give = fixedClockOpt)).orElse(seq.headOption).getOrElse(ClockSourceParameters()) },
uFn = { seq => fixedClockOpt.map(_ => ClockSinkParameters(take = fixedClockOpt)).orElse(seq.headOption).getOrElse(ClockSinkParameters()) },
inputRequiresOutput = false) {
def fixedClockResources(name: String, prefix: String = "soc/"): Seq[Option[FixedClockResource]] = Seq(fixedClockOpt.map(t => new FixedClockResource(name, t.freqMHz, prefix)))
}

class FixedClockBroadcast(fixedClockOpt: Option[ClockParameters])(implicit p: Parameters) extends LazyModule
{
val node = FixedClockBroadcastNode(fixedClockOpt)

lazy val module = new LazyRawModuleImp(this) {
val (in, _) = node.in(0)
val (out, _) = node.out.unzip
require (node.in.size == 1)
out.foreach { _ := in }
}
}

object FixedClockBroadcast
{
def apply(fixedClockOpt: Option[ClockParameters])(implicit p: Parameters, valName: ValName) = LazyModule(new FixedClockBroadcast(fixedClockOpt)).node
}

case class PRCIClockGroupNode()(implicit valName: ValName)
extends NexusNode(ClockGroupImp)(
dFn = { _ => ClockGroupSourceParameters() },
uFn = { _ => ClockGroupSinkParameters("prci", Nil) },
outputRequiresInput = false)
91 changes: 91 additions & 0 deletions src/main/scala/prci/ClockNodes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.prci

import chisel3._
import chisel3.internal.sourceinfo.SourceInfo
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._

object ClockImp extends SimpleNodeImp[ClockSourceParameters, ClockSinkParameters, ClockEdgeParameters, ClockBundle]
{
def edge(pd: ClockSourceParameters, pu: ClockSinkParameters, p: Parameters, sourceInfo: SourceInfo) = ClockEdgeParameters(pd, pu, p, sourceInfo)
def bundle(e: ClockEdgeParameters) = new ClockBundle(e.bundle)
def render(e: ClockEdgeParameters) = RenderedEdge(colour = "#00cc00" /* green */)
}

case class ClockSourceNode(val portParams: Seq[ClockSourceParameters])(implicit valName: ValName) extends SourceNode(ClockImp)(portParams)
{
def fixedClockResources(name: String, prefix: String = "soc/"): Seq[Option[FixedClockResource]] = portParams.map { p =>
p.give.map(g => new FixedClockResource(name, g.freqMHz, prefix))
}
}

case class ClockSinkNode(val portParams: Seq[ClockSinkParameters])(implicit valName: ValName) extends SinkNode(ClockImp)(portParams)
{
def fixedClockResources(name: String, prefix: String = "soc/"): Seq[Option[FixedClockResource]] = portParams.map { p =>
p.take.map(t => new FixedClockResource(name, t.freqMHz, prefix))
}
}

case class ClockAdapterNode(
sourceFn: ClockSourceParameters => ClockSourceParameters = { m => m },
sinkFn: ClockSinkParameters => ClockSinkParameters = { s => s })(
implicit valName: ValName)
extends AdapterNode(ClockImp)(sourceFn, sinkFn)

case class ClockIdentityNode()(implicit valName: ValName) extends IdentityNode(ClockImp)()

case class ClockEphemeralNode()(implicit valName: ValName) extends EphemeralNode(ClockImp)()

object ClockSinkNode
{
def apply(
freqMHz: Double,
dutyCycle: Double = 50,
phaseDeg: Double = 0,
// Create SDC/TCL constraints that the clock matches these requirements:
phaseErrorDeg: Double = 5,
freqErrorPPM: Double = 10000,
jitterPS: Double = 300)(implicit valName: ValName): ClockSinkNode =
ClockSinkNode(Seq(ClockSinkParameters(
phaseDeg = phaseDeg,
phaseErrorDeg = phaseErrorDeg,
freqErrorPPM = freqErrorPPM,
jitterPS = jitterPS,
take = Some(ClockParameters(
freqMHz = freqMHz,
dutyCycle = dutyCycle)))))
}

object ClockSourceNode
{
def apply(
freqMHz: Double,
dutyCycle: Double = 50,
jitterPS: Double = 300)(implicit valName: ValName): ClockSourceNode =
ClockSourceNode(Seq(ClockSourceParameters(
jitterPS = Some(jitterPS),
give = Some(ClockParameters(
freqMHz = freqMHz,
dutyCycle = dutyCycle)))))
}

object ClockGroupImp extends SimpleNodeImp[ClockGroupSourceParameters, ClockGroupSinkParameters, ClockGroupEdgeParameters, ClockGroupBundle]
{
def edge(pd: ClockGroupSourceParameters, pu: ClockGroupSinkParameters, p: Parameters, sourceInfo: SourceInfo) = ClockGroupEdgeParameters(pd, pu, p, sourceInfo)
def bundle(e: ClockGroupEdgeParameters) = new ClockGroupBundle(e.bundle)
def render(e: ClockGroupEdgeParameters) = RenderedEdge(colour = "#00cc00" /* green */)
}

case class ClockGroupSourceNode(params: Seq[ClockGroupSourceParameters])(implicit valName: ValName) extends SourceNode(ClockGroupImp)(params)
case class ClockGroupSinkNode(params: Seq[ClockGroupSinkParameters])(implicit valName: ValName) extends SinkNode(ClockGroupImp)(params)

case class ClockGroupAdapterNode(
sourceFn: ClockGroupSourceParameters => ClockGroupSourceParameters = { m => m },
sinkFn: ClockGroupSinkParameters => ClockGroupSinkParameters = { s => s })(
implicit valName: ValName)
extends AdapterNode(ClockGroupImp)(sourceFn, sinkFn)

case class ClockGroupIdentityNode()(implicit valName: ValName) extends IdentityNode(ClockGroupImp)()

case class ClockGroupEphemeralNode()(implicit valName: ValName) extends EphemeralNode(ClockGroupImp)()
Loading