diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/chisel3/compatibility.scala | 36 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/LFSR.scala | 46 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/LFSR16.scala | 104 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/util/random/LFSRSpec.scala | 59 |
4 files changed, 92 insertions, 153 deletions
diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index 9584fad6..0c4c18a9 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -4,6 +4,8 @@ * while moving to the more standard package naming convention `chisel3` (lowercase c). */ import chisel3._ // required for implicit conversions. +import chisel3.experimental.chiselName +import chisel3.util.random.FibonacciLFSR package object Chisel { // scalastyle:ignore package.object.name number.of.types number.of.methods import chisel3.internal.firrtl.Width @@ -561,7 +563,39 @@ package object Chisel { // scalastyle:ignore package.object.name number.of.t } } - val LFSR16 = chisel3.util.LFSR16 + /** LFSR16 generates a 16-bit linear feedback shift register, returning the register contents. + * This is useful for generating a pseudo-random sequence. + * + * The example below, taken from the unit tests, creates two 4-sided dice using `LFSR16` primitives: + * @example {{{ + * val bins = Reg(Vec(8, UInt(32.W))) + * + * // Create two 4 sided dice and roll them each cycle. + * // Use tap points on each LFSR so values are more independent + * val die0 = Cat(Seq.tabulate(2) { i => LFSR16()(i) }) + * val die1 = Cat(Seq.tabulate(2) { i => LFSR16()(i + 2) }) + * + * val rollValue = die0 +& die1 // Note +& is critical because sum will need an extra bit. + * + * bins(rollValue) := bins(rollValue) + 1.U + * + * }}} + */ + // scalastyle:off magic.number + object LFSR16 { + /** Generates a 16-bit linear feedback shift register, returning the register contents. + * @param increment optional control to gate when the LFSR updates. + */ + @chiselName + def apply(increment: Bool = true.B): UInt = + VecInit( FibonacciLFSR + .maxPeriod(16, increment, seed = Some(BigInt(1) << 15)) + .asBools + .reverse ) + .asUInt + + } + // scalastyle:on magic.number val ListLookup = chisel3.util.ListLookup val Lookup = chisel3.util.Lookup diff --git a/src/main/scala/chisel3/util/LFSR.scala b/src/main/scala/chisel3/util/LFSR.scala deleted file mode 100644 index 5fc778fb..00000000 --- a/src/main/scala/chisel3/util/LFSR.scala +++ /dev/null @@ -1,46 +0,0 @@ -// See LICENSE for license details. - -/** LFSRs in all shapes and sizes. - */ - -package chisel3.util - -import chisel3._ -import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order -import chisel3.util.random.FibonacciLFSR - -/** LFSR16 generates a 16-bit linear feedback shift register, returning the register contents. - * This is useful for generating a pseudo-random sequence. - * - * The example below, taken from the unit tests, creates two 4-sided dice using `LFSR16` primitives: - * @example {{{ - * val bins = Reg(Vec(8, UInt(32.W))) - * - * // Create two 4 sided dice and roll them each cycle. - * // Use tap points on each LFSR so values are more independent - * val die0 = Cat(Seq.tabulate(2) { i => LFSR16()(i) }) - * val die1 = Cat(Seq.tabulate(2) { i => LFSR16()(i + 2) }) - * - * val rollValue = die0 +& die1 // Note +& is critical because sum will need an extra bit. - * - * bins(rollValue) := bins(rollValue) + 1.U - * - * }}} - */ -// scalastyle:off magic.number -@deprecated("LFSR16 is deprecated in favor of the parameterized chisel3.util.random.LFSR", "3.2") -object LFSR16 { - /** Generates a 16-bit linear feedback shift register, returning the register contents. - * @param increment optional control to gate when the LFSR updates. - */ - @deprecated("Use chisel3.util.random.LFSR(16) for a 16-bit LFSR", "3.2") - @chiselName - def apply(increment: Bool = true.B): UInt = - VecInit( FibonacciLFSR - .maxPeriod(16, increment, seed = Some(BigInt(1) << 15)) - .asBools - .reverse ) - .asUInt - -} -// scalastyle:on magic.number diff --git a/src/test/scala/chiselTests/LFSR16.scala b/src/test/scala/chiselTests/LFSR16.scala deleted file mode 100644 index a49d9722..00000000 --- a/src/test/scala/chiselTests/LFSR16.scala +++ /dev/null @@ -1,104 +0,0 @@ -// See LICENSE for license details. - -package chiselTests - -import chisel3._ -import chisel3.testers.BasicTester -import chisel3.util._ -import chisel3.util.random.{PRNG, LFSR} - -/** - * This test creates two 4 sided dice. - * Each cycle it adds them together and adds a count to the bin corresponding to that value - * The asserts check that the bins show the correct distribution. - */ -//scalastyle:off magic.number -class LFSRDistribution(gen: => UInt, cycles: Int = 10000) extends BasicTester { - - val rv = gen - val bins = Reg(Vec(8, UInt(32.W))) - - // Use tap points on each LFSR so values are more independent - val die0 = Cat(Seq.tabulate(2) { i => rv(i) }) - val die1 = Cat(Seq.tabulate(2) { i => rv(i + 2) }) - - val (trial, done) = Counter(true.B, cycles) - - val rollValue = die0 +& die1 // Note +& is critical because sum will need an extra bit. - - bins(rollValue) := bins(rollValue) + 1.U - - when(done) { - printf(p"bins: $bins\n") // Note using the printable interpolator p"" to print out a Vec - - // test that the distribution feels right. - assert(bins(1) > bins(0)) - assert(bins(2) > bins(1)) - assert(bins(3) > bins(2)) - assert(bins(4) < bins(3)) - assert(bins(5) < bins(4)) - assert(bins(6) < bins(5)) - assert(bins(7) === 0.U) - - stop() - } -} - -class LFSRMaxPeriod(gen: => UInt) extends BasicTester { - - val rv = gen - val started = RegNext(true.B, false.B) - val seed = withReset(!started) { RegInit(rv) } - - val (_, wrap) = Counter(started, math.pow(2.0, rv.getWidth).toInt - 1) - - when (rv === seed && started) { - chisel3.assert(wrap) - stop() - } - - val last = RegNext(rv) - chisel3.assert(rv =/= last, "LFSR last value (0b%b) was equal to current value (0b%b)", rv, last) - -} - -/** Check that the output of the new LFSR is the same as the old LFSR */ -class MeetTheNewLFSR16SameAsTheOldLFSR16 extends BasicTester { - val en = Counter(2).value.asBool - - /** This is the exact implementation of the old LFSR16 algorithm */ - val oldLfsr = { - val width = 16 - val lfsr = RegInit(1.U(width.W)) - when (en) { - lfsr := Cat(lfsr(0)^lfsr(2)^lfsr(3)^lfsr(5), lfsr(width-1,1)) - } - lfsr - } - - /** The new LFSR16 uses equivalent taps and a reverse so that it can use LFSR(16) under the hood. */ - val newLfsr = LFSR16(en) - - val (_, done) = Counter(true.B, 16) - - assert(oldLfsr === newLfsr) - - when (done) { - stop() - } - -} - -class LFSRSpec extends ChiselPropSpec { - property("LFSR16 can be used to produce pseudo-random numbers, this tests the distribution") { - assertTesterPasses{ new LFSRDistribution(LFSR16()) } - } - - property("LFSR16 period tester, Period should 2^16 - 1") { - assertTesterPasses{ new LFSRMaxPeriod(LFSR16()) } - } - - property("New LFSR16 is the same as the old LFSR16") { - assertTesterPasses{ new MeetTheNewLFSR16SameAsTheOldLFSR16 } - } -} diff --git a/src/test/scala/chiselTests/util/random/LFSRSpec.scala b/src/test/scala/chiselTests/util/random/LFSRSpec.scala index ce0abf69..9afe7670 100644 --- a/src/test/scala/chiselTests/util/random/LFSRSpec.scala +++ b/src/test/scala/chiselTests/util/random/LFSRSpec.scala @@ -3,11 +3,11 @@ package chiselTests.util.random import chisel3._ -import chisel3.util.{Counter, Enum} +import chisel3.util.{Cat, Counter, Enum} import chisel3.util.random._ import chisel3.testers.BasicTester -import chiselTests.{ChiselFlatSpec, LFSRDistribution, LFSRMaxPeriod} +import chiselTests.{ChiselFlatSpec, Utils} import math.pow @@ -15,6 +15,61 @@ class FooLFSR(val reduction: LFSRReduce, seed: Option[BigInt]) extends PRNG(4, s def delta(s: Seq[Bool]): Seq[Bool] = s } +class LFSRMaxPeriod(gen: => UInt) extends BasicTester { + + val rv = gen + val started = RegNext(true.B, false.B) + val seed = withReset(!started) { RegInit(rv) } + + val (_, wrap) = Counter(started, math.pow(2.0, rv.getWidth).toInt - 1) + + when (rv === seed && started) { + chisel3.assert(wrap) + stop() + } + + val last = RegNext(rv) + chisel3.assert(rv =/= last, "LFSR last value (0b%b) was equal to current value (0b%b)", rv, last) + +} + +/** + * This test creates two 4 sided dice. + * Each cycle it adds them together and adds a count to the bin corresponding to that value + * The asserts check that the bins show the correct distribution. + */ +//scalastyle:off magic.number +class LFSRDistribution(gen: => UInt, cycles: Int = 10000) extends BasicTester { + + val rv = gen + val bins = Reg(Vec(8, UInt(32.W))) + + // Use tap points on each LFSR so values are more independent + val die0 = Cat(Seq.tabulate(2) { i => rv(i) }) + val die1 = Cat(Seq.tabulate(2) { i => rv(i + 2) }) + + val (trial, done) = Counter(true.B, cycles) + + val rollValue = die0 +& die1 // Note +& is critical because sum will need an extra bit. + + bins(rollValue) := bins(rollValue) + 1.U + + when(done) { + printf(p"bins: $bins\n") // Note using the printable interpolator p"" to print out a Vec + + // test that the distribution feels right. + assert(bins(1) > bins(0)) + assert(bins(2) > bins(1)) + assert(bins(3) > bins(2)) + assert(bins(4) < bins(3)) + assert(bins(5) < bins(4)) + assert(bins(6) < bins(5)) + assert(bins(7) === 0.U) + + stop() + } +} + /** This tests that after reset an LFSR is not locked up. This manually sets the seed of the LFSR at run-time to the * value that would cause it to lock up. It then asserts reset. The next cycle it checks that the value is NOT the * locked up value. |
