Долото3: хотите использовать Vec, но нужно использовать IndexedSeq

При генерации сдвинутого регистра сдвига с использованием "scanLeft" мне нужно было использовать IndexedSeq регистров и явное копирование результата scanLeft на выходной провод. Вот четыре примера (с testbench). Только первый работает. Мне больше нравится второй, и я удивляюсь, почему это не правильно.

package tsr

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 rs = IndexedSeq.tabulate( n){ (i) => Reg( d.cloneType)}
    val rs0 = rs.scanLeft( d){ case (x, r) => r := x; r}
    val ys = Wire( Vec( n+1, d.cloneType))
    (ys zip rs0).foreach{ case (y,r) => y := r}
    ys
  }

  def apply1[ T <: Data]( d : T, n : Int) : Vec[T] = { // ChiselException
    val rs = Vec.tabulate( n){ (i) => Reg( d.cloneType)}
    Vec( rs.scanLeft( d){ case (x, r) => r := x; r})
  }

  def apply2[ T <: Data]( d : T, n : Int) : Vec[T] = { // ChiselException
    val rs = IndexedSeq.tabulate( n){ (i) => Reg( d.cloneType)}
    Vec( rs.scanLeft( d){ case (x, r) => r := x; r})
  }

  def apply3[ T <: Data]( d : T, n : Int) : Vec[T] = { // Wrong values
    val rs = Vec.tabulate( n){ (i) => Reg( d.cloneType)}
    val rs0 = rs.scanLeft( d){ case (x, r) => r := x; r}
    val ys = Wire( Vec( n+1, d.cloneType))
    (ys zip rs0).foreach{ case (y,r) => y := r}
    ys
  }

}

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) })
class TSRTest1 extends GenericTSRTest( () => new TappedShiftRegisterIfc { io.out := TappedShiftRegister.apply1( io.inp, 4)})
class TSRTest2 extends GenericTSRTest( () => new TappedShiftRegisterIfc { io.out := TappedShiftRegister.apply2( io.inp, 4)})
class TSRTest3 extends GenericTSRTest( () => new TappedShiftRegisterIfc { io.out := TappedShiftRegister.apply3( io.inp, 4)})

1 ответ

Решение

Первый. Следующее, наиболее близкое к тому, что вам нравится, работает. Я добавил в ваш набор тестов.

def apply4[ T <: Data]( d : T, n : Int) : Vec[T] = { // No ChiselException!
  val rs = Seq.fill(n){ Reg(d.cloneType)}
  VecInit(rs.scanLeft(d){ case (x, r) => r := x; r})
}
class TSRTest4 extends GenericTSRTest( () => new TappedShiftRegisterIfc { io.out := TappedShiftRegister.apply4( io.inp, 4)})

Подробности:

  • Vec.tabulate устарел, вместо него используйте VecInit.
  • Использование VecInit вместо Seq привело к дополнительной задержке. Я все еще пытаюсь понять это, но практическое правило не должно создавать Vec, если они вам действительно не нужны. И в этом случае вам нужен только один Vec, чтобы вы могли назначить его непосредственно на выходной IO.
  • Довольно легко увидеть проблему в файле Firrtl.
Другие вопросы по тегам