summaryrefslogtreecommitdiff
path: root/src/main/scala/chisel3/util/random/FibonacciLFSR.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/chisel3/util/random/FibonacciLFSR.scala')
-rw-r--r--src/main/scala/chisel3/util/random/FibonacciLFSR.scala108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/util/random/FibonacciLFSR.scala b/src/main/scala/chisel3/util/random/FibonacciLFSR.scala
new file mode 100644
index 00000000..53a42320
--- /dev/null
+++ b/src/main/scala/chisel3/util/random/FibonacciLFSR.scala
@@ -0,0 +1,108 @@
+// See LICENSE for license details.
+
+package chisel3.util.random
+
+import chisel3._
+
+/** Fibonacci Linear Feedback Shift Register (LFSR) generator.
+ *
+ * A Fibonacci LFSR can be generated by defining a width and a set of tap points (corresponding to a polynomial). An
+ * optional initial seed and a reduction operation ([[XOR]], the default, or [[XNOR]]) can be used to augment the
+ * generated hardware. The resulting hardware has support for a run-time programmable seed (via [[PRNGIO.seed]]) and
+ * conditional increment (via [[PRNGIO.increment]]).
+ *
+ * $seedExplanation
+ *
+ * In the example below, a 4-bit Fibonacci LFSR is constructed. Tap points are defined as four and three (using LFSR
+ * convention of indexing from one). This results in the hardware configuration shown in the diagram.
+ *
+ * {{{
+ * val lfsr4 = Module(new FibonacciLFSR(4, Set(4, 3))
+ * // +---+
+ * // +-------------->|XOR|-------------------------------------------------------+
+ * // | +---+ |
+ * // | +-------+ ^ +-------+ +-------+ +-------+ |
+ * // | | | | | | | | | | |
+ * // +---+ x^4 |<----+-----| x^3 |<----------| x^2 |<----------| x^1 |<--+
+ * // | | | | | | | |
+ * // +-------+ +-------+ +-------+ +-------+
+ * }}}
+ *
+ * If you require a maximal period Fibonacci LFSR of a specific width, you can use [[MaxPeriodFibonacciLFSR]]. If you
+ * only require a pseudorandom [[UInt]] you can use the [[FibonacciLFSR$ FibonacciLFSR companion
+ * object]].
+ * @see [[https://en.wikipedia.org/wiki/Linear-feedback_shift_register#Fibonacci_LFSRs]]
+ * $paramWidth
+ * $paramTaps
+ * $paramSeed
+ * $paramReduction
+ * $paramStep
+ * $paramUpdateSeed
+ */
+class FibonacciLFSR(
+ width: Int,
+ taps: Set[Int],
+ seed: Option[BigInt] = Some(1),
+ val reduction: LFSRReduce = XOR,
+ step: Int = 1,
+ updateSeed: Boolean = false) extends PRNG(width, seed, step, updateSeed) with LFSR {
+
+ def delta(s: UInt): UInt = s(width-2,0) ## taps.map{ case i => s(i - 1) }.reduce(reduction)
+
+}
+
+/** A maximal period Fibonacci Linear Feedback Shift Register (LFSR) generator. The maximal period taps are sourced from
+ * [[LFSR.tapsMaxPeriod LFSR.tapsMaxPeriod]].
+ * {{{
+ * val lfsr8 = Module(new MaxPeriodFibonacciLFSR(8))
+ * }}}
+ * $paramWidth
+ * $paramSeed
+ * $paramReduction
+ */
+class MaxPeriodFibonacciLFSR(width: Int, seed: Option[BigInt] = Some(1), reduction: LFSRReduce = XOR)
+ extends FibonacciLFSR(width, LFSR.tapsMaxPeriod.getOrElse(width, LFSR.badWidth(width)).head, seed, reduction)
+
+/** Utility for generating a pseudorandom [[UInt]] from a [[FibonacciLFSR]].
+ *
+ * For example, to generate a pseudorandom 8-bit [[UInt]] that changes every cycle, you can use:
+ * {{{
+ * val pseudoRandomNumber = FibonacciLFSR.maxPeriod(8)
+ * }}}
+ *
+ * @define paramWidth @param width of pseudorandom output
+ * @define paramTaps @param taps a set of tap points to use when constructing the LFSR
+ * @define paramIncrement @param increment when asserted, a new random value will be generated
+ * @define paramSeed @param seed an initial value for internal LFSR state
+ * @define paramReduction @param reduction the reduction operation (either [[XOR]] or
+ * [[XNOR]])
+ */
+object FibonacciLFSR {
+
+ /** Return a pseudorandom [[UInt]] generated from a [[FibonacciLFSR]].
+ * $paramWidth
+ * $paramTaps
+ * $paramIncrement
+ * $paramSeed
+ * $paramReduction
+ */
+ def apply(
+ width: Int,
+ taps: Set[Int],
+ increment: Bool = true.B,
+ seed: Option[BigInt] = Some(1),
+ reduction: LFSRReduce = XOR): UInt = PRNG(new FibonacciLFSR(width, taps, seed, reduction), increment)
+
+ /** Return a pseudorandom [[UInt]] generated using a maximal period [[FibonacciLFSR]]
+ * $paramWidth
+ * $paramIncrement
+ * $paramSeed
+ * $paramReduction
+ */
+ def maxPeriod(
+ width: Int,
+ increment: Bool = true.B,
+ seed: Option[BigInt] = Some(1),
+ reduction: LFSRReduce = XOR): UInt = PRNG(new MaxPeriodFibonacciLFSR(width, seed, reduction), increment)
+
+}