2017-08-30 191 views
0

在使用「scanLeft」生成分接移位寄存器時,我需要使用IndexedSeq寄存器並將scanLeft的結果顯式複製到輸出線。以下是四個示例(使用測試臺)。只有第一個工作。 我最喜歡第二個,並想知道爲什麼它不正確。chisel3:想要使用Vec,但需要使用IndexedSeq

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,以便您可以將其直接分配給輸出IO。
  • 在Firrtl文件中查看問題相當容易。
+0

'val rs = Reg(Vec(n,d.cloneType))'也適用。舊的「使用註冊Vecs而不是註冊Vec」規則 –

+0

謝謝。如果我們不應該使用功能,我們是否應該有棄用消息(或編譯器錯誤)? –

+0

這很好,但理查德說這很難。我的目標是暫時改善文檔。 –