首页 > 解决方案 > 使用 UInt 在 Seq 中获取项目

问题描述

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

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

然后我想有如下索引:

   metaMem(way).write(set, MD)

但是,因为 wayUInt在我的代码中,并且 seq 只接受Int索引,所以会导致编译错误。有没有人对如何解决这个问题有任何建议?非常感谢

标签: scalachisel

解决方案


通常,要使用 a 中的动态值访问硬件元素,UInt您必须使用Vec. 在这种情况下,最简单的方法是Vec使用VecInit它创建一个,给定一个 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
        }
    }
  }
}

这是一个可以演示使用此模块的 UnitTest

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")
        }
      }
    }
  }
}

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


推荐阅读