Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Commit

Permalink
Add --target:fpga flag to prioritize FPGA-friendly compilation
Browse files Browse the repository at this point in the history
* Update name of FPGA flag based on Jack's comment
* Add Scaladoc to describe what each constituent transform does
* Add SeparateWriteClocks to --target:fpga
  • Loading branch information
albert-magyar committed Mar 24, 2021
1 parent c30de19 commit 31c94d6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/main/scala/firrtl/stage/FirrtlCli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ trait FirrtlCli { this: Shell =>
NoCircuitDedupAnnotation,
WarnNoScalaVersionDeprecation,
PrettyNoExprInlining,
DisableFold
DisableFold,
OptimizeForFPGA
)
.map(_.addOptions(parser))

Expand Down
52 changes: 52 additions & 0 deletions src/main/scala/firrtl/stage/FirrtlCompilerTargets.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0

package firrtl.stage

import firrtl.transforms._
import firrtl.passes.memlib._
import firrtl.options.{HasShellOptions, ShellOption}

/**
* This flag enables a set of options that guide the FIRRTL compilation flow to ultimately generate Verilog that is
* more amenable to using for synthesized FPGA designs. Currently, this flag affects only memories, as the need to emit
* memories that support downstream inference of hardened RAM macros. These options are not intended to be specialized
* to any particular vendor; instead, they aim to emit simple Verilog that more closely reflects traditional
* human-written definitions of synchronous-read memories.
*
* 1) Add a [[firrtl.passes.memlib.PassthroughSimpleSyncReadMemsAnnotation]] to allow some synchronous-read memories
* and readwrite ports to pass through [[firrtl.passes.memlib.VerilogMemDelays]] without introducing explicit
* pipeline registers or splitting ports.
*
* 2) Use the [[firrtl.transforms.SimplifyMems]] transform to Lower aggregate-typed memories with always-high masks to
* packed memories without splitting them into multiple independent ground-typed memories.
*
* 3) Use the [[firrtl.passes.memlib.SeparateWriteClocks]] transform to ensure that each write port of a
* multiple-write, synchronous-read memory with 'undefined' collision behavior ultimately maps to a separate clocked
* process in the emitted Verilog. This avoids the issue of implicitly constraining cross-port collision and write
* ordering behavior and helps simplify inference of true dual-port RAM macros.
*
* 4) Use the [[firrtl.passes.memlib.SetDefaultReadUnderWrite]] to specify that memories with undefined
* read-under-write behavior should map to emitted microarchitectures characteristic of "read-first" ports by
* default. This eliminates the difficulty of inferring a RAM macro that matches the strict semantics of
* "write-first" ports.
*
* 5) Enable the [[firrtl.passes.memlib.InferReadWrite]] transform to reduce port count, where applicable.
*/
object OptimizeForFPGA extends HasShellOptions {
private val fpgaAnnos = Seq(
InferReadWriteAnnotation,
RunFirrtlTransformAnnotation(new InferReadWrite),
RunFirrtlTransformAnnotation(new SeparateWriteClocks),
DefaultReadFirstAnnotation,
RunFirrtlTransformAnnotation(new SetDefaultReadUnderWrite),
RunFirrtlTransformAnnotation(new SimplifyMems),
PassthroughSimpleSyncReadMemsAnnotation
)
val options = Seq(
new ShellOption[Unit](
longOption = "target:fpga",
toAnnotationSeq = a => fpgaAnnos,
helpText = "Choose compilation strategies that generally favor FPGA targets"
)
)
}

0 comments on commit 31c94d6

Please sign in to comment.