좀 빡셌다.
// See LICENSE.txt for license details.
package problems
import chisel3._
import chisel3.util.log2Ceil
// Problem:
//
// This module should be able to write 'data' to
// internal memory at 'wrAddr' if 'isWr' is asserted.
//
// This module should perform sequential search of 'data'
// in internal memory if 'en' was asserted at least 1 clock cycle
//
// While searching 'done' should remain 0,
// 'done' should be asserted when search is complete
//
// If 'data' has been found 'target' should be updated to the
// address of the first occurrence
//
class DynamicMemorySearch(val n: Int, val w: Int) extends Module {
val io = IO(new Bundle {
val isWr = Input(Bool())
val wrAddr = Input(UInt(log2Ceil(n).W))
val data = Input(UInt(w.W))
val en = Input(Bool())
val target = Output(UInt(log2Ceil(n).W))
val done = Output(Bool())
})
// Implement below ----------
val list = Mem(n, UInt(w.W)) // length w 짜리 line이 n개 row
val index = RegInit(0.U(log2Ceil(n).W))
val memVal = list(index)
// Implement above ----------
val done = !io.en && ((memVal === io.data) || (index === (n-1).asUInt))
// Implement below ----------
// Implement above ----------
when(io.isWr){
list(io.wrAddr) := io.data
} .elsewhen (io.en) {
index := 0.U
} .elsewhen (done === false.B) {
index := index + 1.U
} .otherwise{
// do nothing
}
io.done := done
io.target := index
}
// See LICENSE.txt for license details.
package problems
import chisel3.iotesters.PeekPokeTester
class DynamicMemorySearchTests(c: DynamicMemorySearch) extends PeekPokeTester(c) {
val list = Array.fill(c.n){ 0 }
// Initialize the memory.
for (k <- 0 until c.n) {
poke(c.io.en, 0)
poke(c.io.isWr, 1)
poke(c.io.wrAddr, k)
poke(c.io.data, 0)
step(1)
}
for (k <- 0 until 16) {
println(k+"th TEST")
// WRITE A WORD
poke(c.io.en, 0)
poke(c.io.isWr, 1)
val wrAddr = rnd.nextInt(c.n-1)
val data = rnd.nextInt((1 << c.w) - 1) + 1 // can't be 0
poke(c.io.wrAddr, wrAddr)
poke(c.io.data, data)
step(1)
list(wrAddr) = data
println(list.mkString(" "))
println(c.io.wrAddr+" <= "+c.io.data)
// SETUP SEARCH
val target = if (k > 12) rnd.nextInt(1 << c.w) else data
poke(c.io.isWr, 0)
poke(c.io.data, target)
poke(c.io.en, 1)
step(1)
// println(list.mkString(" "))
do {
println(peek(c.io.target).toString)
poke(c.io.en, 0)
step(1)
} while (peek(c.io.done) == BigInt(0))
val addr = peek(c.io.target).toInt
if (list contains target)
assert(list(addr) == target, "LOOKING FOR " + target + " FOUND " + addr)
else
assert(addr==(list.length-1), "LOOKING FOR " + target + " FOUND " + addr)
}
}
Register가 HW적으로 구현되어야겠다는 생각이 들면, RegInit으로 Register를 명시적으로 만들어야 한다.
RegInit과 Mem은 다르다.
Mem은 packed Array로 선언되고,
RegInit은 Array로 선언된다.
실제로, list변수는 packed array로, index변수는 reg로 구현되었음을 확인할 수 있다.
testbench 만들 때, test sequence는 Scala에서 지원하는 Array를 활용하여 저장할 수 있다.
val list = Array.fill(c.n){ 0 }
위처럼 사용가능하다.
println(k+"th TEST")
println(list.mkString(" ")) // Array 내의 요소를 빈칸 간격으로 출력
println(peek(c.io.wrAddr)+" <= "+peek(c.io.data))
println(peek(c.io.target).toString)
println(peek(c.io.target).toInt)
안녕하세요, chisel 관련 포스트 잘 보고 있습니다.
혹시 test 과정에서 터미널에 출력되는 매 test 로그는 따로 설정하신건가요?