-
Notifications
You must be signed in to change notification settings - Fork 660
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
Simple Divider-Only PLL for Multiclock RTL Simulation #676
Changes from all commits
895bace
8e4dedc
b8d3e4a
cfa7e30
6a26a35
0f33ea3
ad147ec
f36183d
84195d2
96bf702
f6989a1
cc949aa
7b8a954
1b3514f
67145c6
b76972d
a6ce850
5b414f5
ebfe310
7d7f7ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// See LICENSE for license details. | ||
|
||
/** | ||
* An unsynthesizable divide-by-N clock divider. | ||
* Duty cycle is 100 * (ceil(DIV / 2)) / DIV. | ||
*/ | ||
|
||
module ClockDividerN #(parameter DIV)(output logic clk_out = 1'b0, input clk_in); | ||
|
||
localparam CWIDTH = $clog2(DIV); | ||
localparam LOW_CYCLES = DIV / 2; | ||
localparam HIGH_TRANSITION = LOW_CYCLES - 1; | ||
localparam LOW_TRANSITION = DIV - 1; | ||
|
||
generate | ||
if (DIV == 1) begin | ||
// This needs to be procedural because of the assignment on declaration | ||
always @(clk_in) begin | ||
clk_out = clk_in; | ||
end | ||
end else begin | ||
reg [CWIDTH - 1: 0] count = HIGH_TRANSITION[CWIDTH-1:0]; | ||
// The blocking assignment to clock out is used to conform what was done | ||
// in RC's clock dividers. | ||
// It should have the effect of preventing registers in the divided clock | ||
// domain latching register updates launched by the fast clock-domain edge | ||
// that occurs at the same simulated time (as the divided clock edge). | ||
always @(posedge clk_in) begin | ||
if (count == LOW_TRANSITION[CWIDTH-1:0]) begin | ||
clk_out = 1'b0; | ||
count <= '0; | ||
end | ||
else begin | ||
if (count == HIGH_TRANSITION[CWIDTH-1:0]) begin | ||
clk_out = 1'b1; | ||
end | ||
count <= count + 1'b1; | ||
end | ||
end | ||
end | ||
endgenerate | ||
endmodule // ClockDividerN |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// See LICENSE for license details. | ||
|
||
package chipyard.clocking | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
|
||
class ClockDividerN(div: Int) extends BlackBox(Map("DIV" -> div)) with HasBlackBoxResource { | ||
require(div > 0); | ||
val io = IO(new Bundle { | ||
val clk_out = Output(Clock()) | ||
val clk_in = Input(Clock()) | ||
}) | ||
addResource("/vsrc/ClockDividerN.sv") | ||
} | ||
|
||
object ClockDivideByN { | ||
def apply(clockIn: Clock, div: Int): Clock = { | ||
val clockDivider = Module(new ClockDividerN(div)) | ||
clockDivider.io.clk_in := clockIn | ||
clockDivider.io.clk_out | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package chipyard.clocking | ||
|
||
import chisel3._ | ||
|
||
import freechips.rocketchip.config.{Parameters} | ||
import freechips.rocketchip.diplomacy._ | ||
import freechips.rocketchip.prci._ | ||
|
||
/** | ||
* This sort of node can be used when it is a connectivity passthrough, but modifies | ||
* the flow of parameters (which may result in changing the names of the underlying signals). | ||
*/ | ||
class ClockGroupParameterModifier( | ||
sourceFn: ClockGroupSourceParameters => ClockGroupSourceParameters = { m => m }, | ||
sinkFn: ClockGroupSinkParameters => ClockGroupSinkParameters = { s => s })( | ||
implicit p: Parameters, v: ValName) extends LazyModule { | ||
val node = ClockGroupAdapterNode(sourceFn, sinkFn) | ||
lazy val module = new LazyRawModuleImp(this) { | ||
(node.out zip node.in).map { case ((o, _), (i, _)) => | ||
(o.member.data zip i.member.data).foreach { case (oD, iD) => oD := iD } | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Pushes the ClockGroup's name into each member's name field as a prefix. This is | ||
* intended to be used before a ClockGroupAggregator so that sources from | ||
* different aggregated ClockGroups can be disambiguated by their names. | ||
*/ | ||
object ClockGroupNamePrefixer { | ||
def apply()(implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = | ||
LazyModule(new ClockGroupParameterModifier(sinkFn = { s => s.copy(members = s.members.zipWithIndex.map { case (m, idx) => | ||
m.copy(name = m.name match { | ||
// This matches what the chisel would do if the names were not modified | ||
case Some(clockName) => Some(s"${s.name}_${clockName}") | ||
case None => Some(s"${s.name}_${idx}") | ||
}) | ||
})})).node | ||
} | ||
|
||
/** | ||
* [Word from on high is that Strings are in...] | ||
* Overrides the take field of all clocks in a group, by attempting to apply a | ||
* series of assignment functions: | ||
* (name: String) => freq-in-MHz: Option[Double] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assigners shouldn't override any take frequencies already specified by the node, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was meaning to ask about that. It seemed to me that in the short run it made sense to blow away all taken frequencies because it would be less surprising, but it's trivial to not do that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the primary means of controlling frequencies is through various There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that sounds good. I'm still a little concerned about specifying absolute frequencies; i do think it would be preferable to be able to specify constraints on derived frequencies but we can punt on that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re: absolute frequencies. I think the more important part is the relative frequencies but it is easy to calculate the ratio with 100 being the default. |
||
* to each sink. Later functions that return non-empty values take priority. | ||
* The default if all functions return None. | ||
*/ | ||
object ClockGroupFrequencySpecifier { | ||
def apply( | ||
assigners: Seq[(String) => Option[Double]], | ||
defaultFreq: Double)( | ||
implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = { | ||
|
||
def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = { | ||
require(clock.name.nonEmpty, "All clocks in clock group must have an assigned name") | ||
val clockFreq = assigners.foldLeft(defaultFreq)( | ||
(currentFreq, candidateFunc) => candidateFunc(clock.name.get).getOrElse(currentFreq)) | ||
|
||
clock.copy(take = clock.take match { | ||
case Some(cp) => | ||
println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.") | ||
Some(cp) | ||
case None => Some(ClockParameters(clockFreq)) | ||
}) | ||
} | ||
|
||
LazyModule(new ClockGroupParameterModifier(sinkFn = { s => s.copy(members = s.members.map(lookupFrequencyForName)) })).node | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just make this
Map[String, Option[Double]]
Is it to support the partial string matching?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was the original motivation. I thought about making it a regex, but then i just settled on doing a more general thing. If you wanted to use the core idx as an argument you could do that with this very simply.