chisel3: When to use cloneType? - chisel

I seem to need to use cloneType when creating Reg but don't need to use it when creating a Wire. Can someone explain the difference between the two cases?
Seems that Wire and Reg should have a similar interface.
Here is a complete example with testbench:
package ct
import chisel3._
import chisel3.util._
import chisel3.iotesters._
import org.scalatest.{Matchers, FlatSpec}
object TappedShiftRegister {
def apply[ T <: Data]( d : T, n : Int) : Vec[T] = {
val result = Wire( Vec( n+1, d /* why is "d.cloneType" not needed? */))
result(0) := d
for( i<-0 until n) {
val r = Reg( d.cloneType /* Why doesn't just "d" work? */)
r := result(i)
result(i+1) := r
}
result
}
}
class TappedShiftRegisterIfc extends Module {
val io = IO( new Bundle {
val inp = Input( UInt(8.W))
val out = Output( Vec( 5, UInt(8.W)))
})
}
class GenericTSRTest( factory : () => TappedShiftRegisterIfc) extends FlatSpec with Matchers {
it should "meet all PeekPokeTester expectations" in {
chisel3.iotesters.Driver( factory, "firrtl") { c => new PeekPokeTester(c) {
val N = 4
val off = 47
for { i <- 0 until 100} {
poke( c.io.inp, off+i)
expect( c.io.out(0), off+i) // mealy output
step(1)
for { j <- 0 until N if i > j} {
expect( c.io.out(j+1), off+i-j) // moore outputs
}
}
}} should be (true)
}
}
class TSRTest extends GenericTSRTest( () => new TappedShiftRegisterIfc { io.out := TappedShiftRegister( io.inp, 4) })

Seems that is has been fixed recently.
Now you need to do cloneType on the Wire as well as the Reg.
This is as of:
firrtl: commit f3c0e9e4b268c69d49ef8c18e41c7f75398bb8cf
chisel3: commit 1be90a1e04383675f5b6d967872904ee3dd55faf
firrtl-interpreter: commit 145b9ee89b167c109b732655447b89660908cf87
chisel-testers: commit a6214ffffe761dba9f2eff77463ea58c80d4768a

Related

Generate dynamic bundle

In my project, I have many different custom Bundle.
They can be completely different.
For example these ones:
class MyBundle extends Bundle {
val v1 = UInt(8.W)
val v2 = Bool()
val v3 = UInt(4.W)
}
class MyBundle2 extends Bundle {
val v4 = UInt(18.W)
val v5 = UInt(2.W)
}
...
Instead of manually creating new Bundle to perform each operation, I want to be able to generate for all of them the corresponding Bundle.
So for MyBundle, I want to do:
// Must be generated for each Bundle
class MyGenBundle extends Bundle {
val v1 = UInt(log2Ceil(8 + 1).W) // width = MyBundle.v1 width + 1
val v2 = UInt(log2Ceil(1 + 1).W) // width = MyBundle.v2 width + 1
val v3 = UInt(log2Ceil(4 + 1).W) // width = MyBundle.v3 width + 1
}
class MyModule extends Module {
...
...
val w_b = Wire(new MyBundle())
val w_gb = Wire(new MyGenBundle())
// Must be automated for each Bundle
w_gb.v1 := PopCount(w_b.v1)
w_gb.v2 := PopCount(w_b.v2)
w_gb.v3 := PopCount(w_b.v3)
}
My goal is to automatically generate MyGenBundle (or similar directly in MyModule) from MyBundle, and perform in MyModule the same operation to all signals.
It also means that I need to dynamically address all signals in each Bundle.
Finally, I think the solution can have the following form:
val w_b = Wire(new MyBundle())
val w_gb = Wire(new AutoGenBundle(new MyBundle())) // AutoGenBundle generates a Bundle from parameter
val v_sig = Seq(v1, v1, v3) // Can be recovered automatically
// from w_b.elements I think
foreach (s <- v_sig) {
w_gb."s" := PopCount(w_b."s") // Here "s" the dynamic name of the signal
} // But how in the real case ?
Is this working technically possible in Chisel/Scala?
If so, do you have any ideas for implementing it?
Basic solution is to use the MixedVec chisel type for GenericBundle
class MyBundle extends Bundle {
val v1 = UInt(8.W)
val v2 = Bool()
val v3 = UInt(4.W)
}
class GenericBundle[T <: Bundle](data: T) extends Bundle {
val v = MixedVec(data.elements.values.map(x => UInt(log2Ceil(x.getWidth + 1).W)).toList)
def popCount(data: T): Unit = {
data.elements.values.zip(v).foreach { case (left, right) =>
right := PopCount(left.asUInt())
}
}
}
class MyModule extends MultiIOModule {
val w_b = IO(Input(new MyBundle))
val w_gb = IO(Output(new GenericBundle(w_b)))
w_gb.popCount(w_b)
}

Chisel 3.4.2 syncmem and a black box. No memory replacement with --repl-seq-mem option

I run MemtestInst code with --repl-seq-mem option. It has a black box and a SyncReadMem. No memory replacement happens and config file is empty.
If I comment MyBBox line or use older Chisel, replacement works.
Chisel that works:
val defaultVersions = Map(
"chisel3" -> "3.2.5",
"chisel-iotesters" -> "1.3.5"
)
This one fails (so far the latest one):
val defaultVersions = Map(
"chisel3" -> "3.4.2",
"chisel-iotesters" -> "1.5.2"
)
Scala code:
package explore
import chisel3._
import chisel3.util._
class MemoryInst extends Module {
val bitsDatNb = 64
val bitsAddrNb = 9
val io = IO(new Bundle {
val wAddr = Input(UInt(bitsAddrNb.W))
val wData = Input(UInt(bitsDatNb.W))
val wEn = Input(Bool())
val rAddr = Input(UInt(bitsAddrNb.W))
val rEn = Input(Bool())
val rData = Output(UInt(bitsDatNb.W))
})
val myBbox = Module( new MyBBox())
val memFile = SyncReadMem(1<<bitsAddrNb, UInt(bitsDatNb.W))
when(io.wEn) {
memFile.write(io.wAddr, io.wData)
}
io.rData := memFile.read(io.rAddr, io.rEn)
}
class MyBBox() extends BlackBox(
Map(
"LEN_BITS" -> 8,
"ADDR_BITS" -> 10,
"DATA_BITS" -> 64)) with HasBlackBoxResource {
val io = IO(new Bundle {
val clock = Input(Clock())
val reset = Input(Bool())
})
setResource("/verilog/someverilog.v")
}
object MemtestInst extends App {
chisel3.Driver.execute(args, () => new MemoryInst)
}
Am I missing something?
Thanks in advance!
I had the same problem with Chisel version 3.4.0
I can confirm that the code similar you have works with memory mapping without blackbox and not with it. I suggest the following adding
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
and changing
object MemtestInst extends App {
chisel3.Driver.execute(args, () => new MemoryInst)
}
to
object MemtestInst extends App {
val annos = Seq(ChiselGeneratorAnnotation(() =>
new MemoryInst()
))
(new ChiselStage).execute(args, annos)
}
I think chisel3.Driver.execute is with 3.4 and later.

test rocket chip util 'Arbiters.scala', got error 'bits operated ... must be hardware ..."

I copied a rocket-chip util module 'Arbiters.scala' to a separate work directory, test with the following code:
object try_arbiter extends App {
chisel3.Driver.execute(args, () => new HellaCountingArbiter(UInt(4.W), 3, 5))
}
There's no problem when compiling. However, in the step 'Elaborating design...', it reported [error] chisel3.core.Binding$ExpectedHardwareException: mux condition 'chisel3.core.Bool#46' must be hardware, not a bare Chisel type"
The related code is
PriorityEncoder(io.in.map(_.valid))
when I change this line to the following one, the error's gone (the scala code still has this kind of errs, but not in this line).
PriorityEncoder(io.in.map(x => Wire(x.valid)))
The rocket chip codes should have been evaluated for many times, right? I think there must have sth I have missed... Some configurations?
Thank you for any hints!
Appendix(the Arbiters.scala):
package rocket_examples
import chisel3._
import chisel3.util._
/** A generalized locking RR arbiter that addresses the limitations of the
* version in the Chisel standard library */
abstract class HellaLockingArbiter[T <: Data](typ: T, arbN: Int, rr: Boolean = false)
extends Module {
val io = new Bundle {
val in = Vec(arbN, Decoupled(typ.cloneType)).flip
val out = Decoupled(typ.cloneType)
}
def rotateLeft[T <: Data](norm: Vec[T], rot: UInt): Vec[T] = {
val n = norm.size
Vec.tabulate(n) { i =>
Mux(rot < UInt(n - i), norm(UInt(i) + rot), norm(rot - UInt(n - i)))
}
}
val lockIdx = Reg(init = UInt(0, log2Up(arbN)))
val locked = Reg(init = Bool(false))
val choice = if (rr) {
PriorityMux(
rotateLeft(Vec(io.in.map(_.valid)), lockIdx + UInt(1)),
rotateLeft(Vec((0 until arbN).map(UInt(_))), lockIdx + UInt(1)))
} else {
PriorityEncoder(io.in.map(_.valid))
}
val chosen = Mux(locked, lockIdx, choice)
for (i <- 0 until arbN) {
io.in(i).ready := io.out.ready && chosen === UInt(i)
}
io.out.valid := io.in(chosen).valid
io.out.bits := io.in(chosen).bits
}
/** This locking arbiter determines when it is safe to unlock
* by peeking at the data */
class HellaPeekingArbiter[T <: Data](
typ: T, arbN: Int,
canUnlock: T => Bool,
needsLock: Option[T => Bool] = None,
rr: Boolean = false)
extends HellaLockingArbiter(typ, arbN, rr) {
def realNeedsLock(data: T): Bool =
needsLock.map(_(data)).getOrElse(Bool(true))
when (io.out.fire()) {
when (!locked && realNeedsLock(io.out.bits)) {
lockIdx := choice
locked := Bool(true)
}
// the unlock statement takes precedent
when (canUnlock(io.out.bits)) {
locked := Bool(false)
}
}
}
/** This arbiter determines when it is safe to unlock by counting transactions */
class HellaCountingArbiter[T <: Data](
typ: T, arbN: Int, count: Int,
val needsLock: Option[T => Bool] = None,
rr: Boolean = false)
extends HellaLockingArbiter(typ, arbN, rr) {
def realNeedsLock(data: T): Bool =
needsLock.map(_(data)).getOrElse(Bool(true))
// if count is 1, you should use a non-locking arbiter
require(count > 1, "CountingArbiter cannot have count <= 1")
val lock_ctr = Counter(count)
when (io.out.fire()) {
when (!locked && realNeedsLock(io.out.bits)) {
lockIdx := choice
locked := Bool(true)
lock_ctr.inc()
}
when (locked) {
when (lock_ctr.inc()) { locked := Bool(false) }
}
}
}
The issue is that almost all of the code in rocket-chip has been written against older Chisel2-style APIs and should be compiled with the compatibility wrapper import Chisel._. I see you used import chisel3._ which has somewhat stricter semantics.
For this specific case, the difference between Chisel2 and Chisel3 is that ports (val io) must be wrapped in IO(...), ie.
val io = IO(new Bundle {
val in = Flipped(Vec(arbN, Decoupled(typ)))
val out = Decoupled(typ)
})
Note that I also changed Vec(arbN, Decoupled(typ.cloneType)).flip to Flipped(Vec(arbN, Decoupled(typ))) and removed the .cloneType on val out. The latter two changes are not required for this to compile but they will be flagged as deprecation warnings as of Chisel 3.1.2.

Using ScalaCheck with PeekPokeTester

Here is chisel3 test that uses ScalaCheck to perform property checking on a simple combinational circuit.
package stackoverflow
import org.scalatest.{ Matchers, FlatSpec, GivenWhenThen}
import org.scalacheck.{ Properties, Gen, Arbitrary}
import org.scalacheck.Prop.{ forAll, AnyOperators, collect}
import chisel3._
import firrtl_interpreter.InterpretiveTester
object G {
val width = 8
}
class Add extends Module {
val io = IO(new Bundle {
val a = Input(UInt(G.width.W))
val b = Input(UInt(G.width.W))
val o = Output(UInt(G.width.W))
})
io.o := io.a + io.b
}
class AddTester {
val s = chisel3.Driver.emit( () => new Add)
val tester = new InterpretiveTester( s)
def run( a : Int, b : Int) = {
val result = (a + b) & ((1 << G.width)-1)
tester.poke( s"io_a", a)
tester.poke( s"io_b", b)
tester.peek( s"io_o") ?= result
}
}
object AddTest extends Properties("Add") {
val t = new AddTester
val gen = Gen.choose(0,(1 << G.width)-1)
property("Add") = forAll( gen, gen) {
case (a:Int,b:Int) => t.run( a, b)
}
}
This uses the firrtl interpreter directly. Does anyone know how to do something similar using the PeekPokeTester so I can use the verilator and vcs backends as well?
Is this close to what you have in mind? It's a lot more scalatesty in form. I haven't been able to get the gen stuff working here (there is some kind of weird interaction with chisel), and I'm more familiar with FreeSpec so I started with it. I also threw a printf and a println in so you could believe it was working. This works with the interpreter backend as well.
import org.scalatest.FreeSpec
import org.scalacheck.Prop.AnyOperators
import chisel3._
import chisel3.iotesters.PeekPokeTester
class Add2 extends Module {
val io = IO(new Bundle {
val a = Input(UInt(G.width.W))
val b = Input(UInt(G.width.W))
val o = Output(UInt(G.width.W))
})
io.o := io.a + io.b
printf("%d = %d + %d\n", io.o, io.a, io.b)
}
class ScalaTestyTester extends FreeSpec {
"scalatest verilator test" in {
iotesters.Driver.execute(Array("--backend-name", "verilator"), () => new Add2) { c =>
new PeekPokeTester(c) {
for(_ <- 0 until 10) {
val a = BigInt(G.width, scala.util.Random)
val b = BigInt(G.width, scala.util.Random)
println(s"testing a = $a b = $b")
val result = (a + b) & ((1 << G.width) - 1)
poke(c.io.a, a)
poke(c.io.b, b)
step(1)
peek(c.io.o) ?= result
}
}
}
}
}

restart iterator on exceptions in Scala

I have an iterator (actually a Source.getLines) that's reading an infinite stream of data from a URL. Occasionally the iterator throws a java.io.IOException when there is a connection problem. In such situations, I need to re-connect and re-start the iterator. I want this to be seamless so that the iterator just looks like a normal iterator to the consumer, but underneath is restarting itself as necessary.
For example, I'd like to see the following behavior:
scala> val iter = restartingIterator(() => new Iterator[Int]{
var i = -1
def hasNext = {
if (this.i < 3) {
true
} else {
throw new IOException
}
}
def next = {
this.i += 1
i
}
})
res0: ...
scala> iter.take(6).toList
res1: List[Int] = List(0, 1, 2, 3, 0, 1)
I have a partial solution to this problem, but it will fail on some corner cases (e.g. an IOException on the first item after a restart) and it's pretty ugly:
def restartingIterator[T](getIter: () => Iterator[T]) = new Iterator[T] {
var iter = getIter()
def hasNext = {
try {
iter.hasNext
} catch {
case e: IOException => {
this.iter = getIter()
iter.hasNext
}
}
}
def next = {
try {
iter.next
} catch {
case e: IOException => {
this.iter = getIter()
iter.next
}
}
}
}
I keep feeling like there's a better solution to this, maybe some combination of Iterator.continually and util.control.Exception or something like that, but I couldn't figure one out. Any ideas?
This is fairly close to your version and using scala.util.control.Exception:
def restartingIterator[T](getIter: () => Iterator[T]) = new Iterator[T] {
import util.control.Exception.allCatch
private[this] var i = getIter()
private[this] def replace() = i = getIter()
def hasNext: Boolean = allCatch.opt(i.hasNext).getOrElse{replace(); hasNext}
def next(): T = allCatch.opt(i.next).getOrElse{replace(); next}
}
For some reason this is not tail recursive but it that can be fixed by using a slightly more verbose version:
def restartingIterator2[T](getIter: () => Iterator[T]) = new Iterator[T] {
import util.control.Exception.allCatch
private[this] var i = getIter()
private[this] def replace() = i = getIter()
#annotation.tailrec def hasNext: Boolean = {
val v = allCatch.opt(i.hasNext)
if (v.isDefined) v.get else {replace(); hasNext}
}
#annotation.tailrec def next(): T = {
val v = allCatch.opt(i.next)
if (v.isDefined) v.get else {replace(); next}
}
}
Edit: There is a solution with util.control.Exception and Iterator.continually:
def restartingIterator[T](getIter: () => Iterator[T]) = {
import util.control.Exception.allCatch
var iter = getIter()
def f: T = allCatch.opt(iter.next).getOrElse{iter = getIter(); f}
Iterator.continually { f }
}
There is a better solution, the Iteratee:
http://apocalisp.wordpress.com/2010/10/17/scalaz-tutorial-enumeration-based-io-with-iteratees/
Here is for example an enumerator that restarts on encountering an exception.
def enumReader[A](r: => BufferedReader, it: IterV[String, A]): IO[IterV[String, A]] = {
val tmpReader = r
def loop: IterV[String, A] => IO[IterV[String, A]] = {
case i#Done(_, _) => IO { i }
case Cont(k) => for {
s <- IO { try { val x = tmpReader.readLine; IO(x) }
catch { case e => enumReader(r, it) }}.join
a <- if (s == null) k(EOF) else loop(k(El(s)))
} yield a
}
loop(it)
}
The inner loop advances the Iteratee, but the outer function still holds on to the original. Since Iteratee is a persistent data structure, to restart you just have to call the function again.
I'm passing the Reader by name here so that r is essentially a function that gives you a fresh (restarted) reader. In practise you will want to bracket this more effectively (close the existing reader on exception).
Here's an answer that doesn't work, but feels like it should:
def restartingIterator[T](getIter: () => Iterator[T]): Iterator[T] = {
new Traversable[T] {
def foreach[U](f: T => U): Unit = {
try {
for (item <- getIter()) {
f(item)
}
} catch {
case e: IOException => this.foreach(f)
}
}
}.toIterator
}
I think this very clearly describes the control flow, which is great.
This code will throw a StackOverflowError in Scala 2.8.0 because of a bug in Traversable.toStream, but even after the fix for that bug, this code still won't work for my use case because toIterator calls toStream, which means that it will store all items in memory.
I'd love to be able to define an Iterator by just writing a foreach method, but there doesn't seem to be any easy way to do that.