【问题标题】:Get an item in Seq using UInt使用 UInt 在 Seq 中获取项目
【发布时间】:2020-10-04 01:13:55
【问题描述】:

我正在尝试编写高速缓存,因此我创建了 Mem 类型的 Seq,因为我试图同时访问一组高速缓存中的所有元素。

val metaMem = Seq.fill(nWays) (Mem((nSets), new MetaData))

然后我想要如下索引:

   metaMem(way).write(set, MD)

但是,因为我的代码中的方式是UInt,而seq 只接受Int 进行索引,所以会导致编译错误。 有人对如何解决这个问题有任何建议吗? 非常感谢

【问题讨论】:

    标签: scala chisel


    【解决方案1】:

    通常要使用UInt 中的动态值访问硬件元素,您必须使用Vec。在这种情况下,最简单的方法是使用VecInit 创建一个Vec,给定一个seq,定义Vec 并连接你的元素。

    但是记忆不是数据的子类(正如Vec/VecInit 所要求的那样)。 这是一个非常简单的示例,它创建了一个内存库并提供对它们的读/写访问权限。

    /** Simulate a VecLike bank of memories
      */
    class MemBank(val banks: Int, val bankDepth: Int) extends MultiIOModule {
      val bank = IO(Input(UInt(16.W)))
      val address = IO(Input(UInt(16.W)))
      val isRead = IO(Input(Bool()))
      val inputValue = IO(Input(UInt(32.W)))
      val outputValue = IO(Output(UInt(32.W)))
    
      val mems = Seq.fill(banks) { Mem(bankDepth, UInt(32.W)) }
    
      outputValue := DontCare
    
      when(isRead) {
        (0 until banks).foldLeft(when(false.B) {}) {
          case (whenContext, bankIndex) =>
            whenContext.elsewhen(bank === bankIndex.U) {
              outputValue := mems(bankIndex)(address)
            }
        }
      }.otherwise {
        (0 until banks).foldLeft(when(false.B) {}) {
          case (whenContext, bankIndex) =>
            whenContext.elsewhen(bank === bankIndex.U) {
              mems(bankIndex)(address) := inputValue
            }
        }
      }
    }
    

    这是一个可以演示使用此模块的单元测试

    class MemBankTest extends FreeSpec with ChiselScalatestTester {
    
      "MemBankSimulation should work" in {
        test(new MemBank(banks = 3, bankDepth = 3)) { dut =>
          // write values into memory
          dut.isRead.poke(false.B)
          for (bank <- 0 until dut.banks) {
            for (address <- 0 until dut.bankDepth) {
              dut.clock.step()
              dut.bank.poke(bank.U)
              dut.address.poke(address.U)
              dut.inputValue.poke((bank * 1000 + address).U)
            }
          }
    
          // read values out of memory banks
          dut.isRead.poke(true.B)
          for (bank <- 0 until dut.banks) {
            for (address <- 0 until dut.bankDepth) {
              dut.clock.step()
              dut.bank.poke(bank.U)
              dut.address.poke(address.U)
              println(f"Bank $bank%3d at address $address%3d contains ${dut.outputValue.peek().litValue()}%6d")
            }
          }
        }
      }
    }
    

    还有很多其他方法可以做到这一点,我鼓励您查看其他凿子项目,如火箭芯片,了解如何处理多个内存。 看看这种方法是如何工作的仍然很好。它创建了MemSeq,但它使用 foldLeft(一个非常有用的方法)创建了一组 Muxes 来选择您感兴趣的银行。它有两个并行用途来控制读取和写入分别地。 我希望这会有所帮助,这是一个很好且棘手的问题。

    【讨论】:

    • 非常感谢您的回复。但是,它给了我错误:重载方法值 apply with alternatives(...) cannot be applied to (Seq[chisel3.Mem[memory.cache.MetaData]])
    • 嗯,看起来错误是因为 Mem 不是 Data 的子类,我会深入挖掘一下,看看在实践中是如何完成的
    • 我已经更新了对记忆有用的答案。我认为访问最后一个内存的最后一个元素有一个小问题,但调试起来应该不难
    • foldLeft 以种子值开头。在这种情况下,我将种子作为when(false.B){} 传递,它返回WhenContextfoldLeft 调用我提供的一个函数,它接受两个参数,第一个参数是该函数计算的最后一个值(在第一次迭代中是种子),另一个参数是您正在迭代的列表中的下一个值, case (a,b) =&gt; ... 正是你表达功能foldLeft 需要的方式
    • 函数的每次调用都会调用前一个WhenContextelsewhen方法,并返回一个新的WhenContext用于下一个值。希望有帮助
    猜你喜欢
    • 2015-02-02
    • 2021-11-13
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多