From 563f348ca3e4a984ad23caba9e980dab8fa808bb Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 16 Feb 2017 11:02:21 -0800 Subject: Add support for clock and reset scoping (#509) withClockAndReset, withReset, and withClock allow changing the implicit clock and reset. Module.clock and Module.reset provide access to the current implicit clock and reset. --- .../src/main/scala/chisel3/core/Assert.scala | 8 ++-- .../src/main/scala/chisel3/core/Mem.scala | 6 +-- .../src/main/scala/chisel3/core/Module.scala | 11 +++++ .../src/main/scala/chisel3/core/MultiClock.scala | 54 ++++++++++++++++++++++ .../src/main/scala/chisel3/core/Printf.scala | 9 ++-- .../src/main/scala/chisel3/core/Reg.scala | 5 +- 6 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 chiselFrontend/src/main/scala/chisel3/core/MultiClock.scala (limited to 'chiselFrontend/src/main/scala/chisel3/core') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala index 4782a845..5673e298 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -51,12 +51,12 @@ object assert { // scalastyle:ignore object.name } def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo) { - when (!(cond || Builder.forcedModule.reset)) { + when (!(cond || Builder.forcedReset)) { message match { case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n", data:_*) case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n", data:_*) } - pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), 1)) + pushCommand(Stop(sourceInfo, Node(Builder.forcedClock), 1)) } } @@ -76,8 +76,8 @@ object assert { // scalastyle:ignore object.name object stop { // scalastyle:ignore object.name /** Terminate execution with a failure code. */ def apply(code: Int)(implicit sourceInfo: SourceInfo): Unit = { - when (!Builder.forcedModule.reset) { - pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), code)) + when (!Builder.forcedReset) { + pushCommand(Stop(sourceInfo, Node(Builder.forcedClock), code)) } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala index ca416b1e..a48af15a 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala @@ -27,7 +27,7 @@ object Mem { // TODO(twigg): Remove need for this Binding val mem = new Mem(mt, size) - pushCommand(DefMemory(sourceInfo, mem, mt, size)) // TODO multi-clock + pushCommand(DefMemory(sourceInfo, mem, mt, size)) mem } } @@ -92,7 +92,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId wi val port = pushCommand( DefMemPort(sourceInfo, - t.chiselCloneType, Node(this), dir, i.ref, Node(i._parent.get.clock)) + t.chiselCloneType, Node(this), dir, i.ref, Node(Builder.forcedClock)) ).id // Bind each element of port to being a MemoryPort Binding.bind(port, MemoryPortBinder(Builder.forcedModule), "Error: Fresh t") @@ -128,7 +128,7 @@ object SyncReadMem { // TODO(twigg): Remove need for this Binding val mem = new SyncReadMem(mt, size) - pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) // TODO multi-clock + pushCommand(DefSeqMemory(sourceInfo, mem, mt, size)) mem } } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 3ff68772..1388fb80 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -32,11 +32,13 @@ object Module { Builder.readyForModuleConstr = true val parent: Option[Module] = Builder.currentModule val whenDepth: Int = Builder.whenDepth + val clockAndReset: Option[ClockAndReset] = Builder.currentClockAndReset // Execute the module, this has the following side effects: // - set currentModule // - unset readyForModuleConstr // - reset whenDepth to 0 + // - set currentClockAndReset val m = bc.setRefs() m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs @@ -50,6 +52,7 @@ object Module { } Builder.currentModule = parent // Back to parent! Builder.whenDepth = whenDepth + Builder.currentClockAndReset = clockAndReset // Back to clock and reset scope val ports = m.computePorts // Blackbox inherits from Module so we have to match on it first TODO fix @@ -69,6 +72,11 @@ object Module { } m } + + /** Returns the implicit Clock */ + def clock: Clock = Builder.forcedClock + /** Returns the implicit Reset */ + def reset: Bool = Builder.forcedReset } /** Abstract base class for Modules, which behave much like Verilog modules. @@ -156,6 +164,9 @@ extends HasId { val clock = Port(Input(Clock())) val reset = Port(Input(Bool())) + // Setup ClockAndReset + Builder.currentClockAndReset = Some(ClockAndReset(clock, reset)) + private[chisel3] def addId(d: HasId) { _ids += d } private[core] def ports: Seq[(String,Data)] = Vector( diff --git a/chiselFrontend/src/main/scala/chisel3/core/MultiClock.scala b/chiselFrontend/src/main/scala/chisel3/core/MultiClock.scala new file mode 100644 index 00000000..62163318 --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/core/MultiClock.scala @@ -0,0 +1,54 @@ +// See LICENSE for license details. + +package chisel3.core + +import scala.language.experimental.macros + +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo} + +private[chisel3] final case class ClockAndReset(clock: Clock, reset: Bool) + +object withClockAndReset { // scalastyle:ignore object.name + /** Creates a new Clock and Reset scope + * + * @param clock the new implicit Clock + * @param reset the new implicit Reset + * @param block the block of code to run with new implicit Clock and Reset + * @return the result of the block + */ + def apply[T](clock: Clock, reset: Bool)(block: => T): T = { + // Save parentScope + val parentScope = Builder.currentClockAndReset + Builder.currentClockAndReset = Some(ClockAndReset(clock, reset)) + val res = block // execute block + // Return to old scope + Builder.currentClockAndReset = parentScope + res + } +} + +object withClock { // scalastyle:ignore object.name + /** Creates a new Clock scope + * + * @param clock the new implicit Clock + * @param block the block of code to run with new implicit Clock + * @return the result of the block + */ + def apply[T](clock: Clock)(block: => T): T = + withClockAndReset(clock, Module.reset)(block) +} + +object withReset { // scalastyle:ignore object.name + /** Creates a new Reset scope + * + * @param reset the new implicit Reset + * @param block the block of code to run with new implicit Reset + * @return the result of the block + */ + def apply[T](reset: Bool)(block: => T): T = + withClockAndReset(Module.clock, reset)(block) +} + diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index 4ec13751..81210f45 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -34,9 +34,8 @@ object printf { // scalastyle:ignore object.name * reset). If your definition of reset is not the encapsulating Module's * reset, you will need to gate this externally. * - * May be called outside of a Module (like defined in a function), so - * functions using printf make the standard Module assumptions (single clock - * and single reset). + * May be called outside of a Module (like defined in a function), uses + * whatever clock and reset are in scope. * * @param fmt printf format string * @param data format string varargs containing data to print @@ -56,13 +55,13 @@ object printf { // scalastyle:ignore object.name * @param pable [[Printable]] to print */ def apply(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { - when (!Builder.forcedModule.reset) { + when (!Builder.forcedReset) { printfWithoutReset(pable) } } private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { - val clock = Builder.forcedModule.clock + val clock = Builder.forcedClock pushCommand(Printf(sourceInfo, Node(clock), pable)) } private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala index 30abe5e5..1287ac2f 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala @@ -68,7 +68,8 @@ object Reg { // to resolve all use cases. If the type inferencer / implicit resolution // system improves, this may be changed. val x = makeType(compileOptions, t, next, init) - val clock = Node(x._parent.get.clock) // TODO multi-clock + val clock = Node(Builder.forcedClock) + val reset = Node(Builder.forcedReset) // Bind each element of x to being a Reg Binding.bind(x, RegBinder(Builder.forcedModule), "Error: t") @@ -77,7 +78,7 @@ object Reg { pushCommand(DefReg(sourceInfo, x, clock)) } else { Binding.checkSynthesizable(init, s"'init' ($init)") - pushCommand(DefRegInit(sourceInfo, x, clock, Node(x._parent.get.reset), init.ref)) + pushCommand(DefRegInit(sourceInfo, x, clock, reset, init.ref)) } if (next != null) { Binding.checkSynthesizable(next, s"'next' ($next)") -- cgit v1.2.3