load가 켜져있으면 동시초기화를,
shift가 켜져있으면 0번 인덱스만 push하고 나머지는 밀려나는
left shift register를 구현하면 되는
간단한 문제다.
// See LICENSE.txt for license details.
package problems
import chisel3.iotesters.PeekPokeTester
class VecShiftRegisterTests(c: VecShiftRegister) extends PeekPokeTester(c) {
val reg = Array.fill(4){ 0 }
val ins = Array.fill(4){ 0 }
// Initialize the delays.
for (i <- 0 until 4)
poke(c.io.ins(i), 0)
poke(c.io.load, 1)
step(1)
for (t <- 0 until 16) {
for (i <- 0 until 4)
ins(i) = rnd.nextInt(16)
val shift = rnd.nextInt(2)
val load = rnd.nextInt(2)
for (i <- 0 until 4)
poke(c.io.ins(i), ins(i))
poke(c.io.load, load)
poke(c.io.shift, shift)
step(1)
if (load == 1) {
for (i <- 0 until 4)
reg(i) = ins(i)
} else if (shift == 1) {
for (i <- 3 to 1 by -1)
reg(i) = reg(i-1)
reg(0) = ins(0)
}
expect(c.io.out, reg(3))
}
}
// See LICENSE.txt for license details.
package problems
import chisel3._
// Problem:
//
// Implement a loadable shift register with four 4-bit stages using Vec
// Shift occurs if 'shift' is asserted
// Load occurs if 'load' is asserted
// Whole state should be replaced with 'ins' when loaded
//
class VecShiftRegister extends Module {
val io = IO(new Bundle {
val ins = Input(Vec(4, UInt(4.W)))
val load = Input(Bool())
val shift = Input(Bool())
val out = Output(UInt(4.W))
})
// Implement below ----------
val ROM = Vec(4, UInt(4.W))
when(io.load){
for (i <- 0 until 4){
ROM(i) := io.ins(i)
}
}.elsewhen(io.shift){
for (i <- 0 until 3){
ROM(i+1) := ROM(i)
}
ROM(0) := ROM(3)
}.otherwise{
}
io.out := ROM(3)
// Implement above ----------
}
compile error가 아니라, elaborate 하는 도중 exception이 발생하는, 가장 골때리는 경우가 나왔다.(이러면 sbt도 다시 켜야해서 귀찮고, 어디서 터졌는지도 안알려준다)
Errors: 1: in the following tutorials
Tutorial VecShiftRegister: exception data to be connected 'UInt<4>' must be hardware, not a bare Chisel type. Perhaps you forgot to wrap it in Wire(_) or IO(_)?
val ROM = Vec(4, UInt(4.W))
를
val ROM = Reg(Vec(4, UInt(4.W)))
로 바꾸면 된다.
아니, Scala의 vector는 Vector라서, Vec는 당연히 Chisel3 타입인줄알았는데...
따로 Reg로 또 감싸줘야했구나.
마찬가지로,
Wire(Vec(4,UInt(4,W)))
할때도 있고
Input(Vec(4,UInt(4.W)))
도 가능한 모양이다.
// See LICENSE.txt for license details.
package problems
import chisel3._
// Problem:
//
// Implement a loadable shift register with four 4-bit stages using Vec
// Shift occurs if 'shift' is asserted
// Load occurs if 'load' is asserted
// Whole state should be replaced with 'ins' when loaded
//
class VecShiftRegister extends Module {
val io = IO(new Bundle {
val ins = Input(Vec(4, UInt(4.W)))
val load = Input(Bool())
val shift = Input(Bool())
val out = Output(UInt(4.W))
})
// Implement below ----------
val ROM = Reg(Vec(4, UInt(4.W)))
when(io.load){
for (i <- 0 until 4){
ROM(i) := io.ins(i)
}
}.elsewhen(io.shift){
for (i <- 0 until 3){
ROM(i+1) := ROM(i)
}
ROM(0) := ROM(3)
}.otherwise{
}
io.out := ROM(3)
// Implement above ----------
}
테케는 뚫었지만, 진짜 모범답안은
// See LICENSE.txt for license details.
package problems
import chisel3._
// Problem:
//
// Implement a loadable shift register with four 4-bit stages using Vec
// Shift occurs if 'shift' is asserted
// Load occurs if 'load' is asserted
// Whole state should be replaced with 'ins' when loaded
//
class VecShiftRegister extends Module {
val io = IO(new Bundle {
val ins = Input(Vec(4, UInt(4.W)))
val load = Input(Bool())
val shift = Input(Bool())
val out = Output(UInt(4.W))
})
// Implement below ----------
val shift_reg = Reg(Vec(4, UInt(4.W)))
when(io.load){
for (i <- 0 until 4){
shift_reg(i) := io.ins(i)
}
}.elsewhen(io.shift){
for (i <- 0 until 3){
shift_reg(i+1) := shift_reg(i)
}
shift_reg(0) := io.ins(0)
}
io.out := shift_reg(3)
// Implement above ----------
}
위처럼,
io.shift일때도, 루프도는게 아니라
shift_reg(0) := io.ins(0)
이다.
(추가적으로, ROM도 아니라서 변수명 걍 바꿨다.)
val ROM = Vec(4, UInt(4.W))
는 불가능하고,
val ROM = Reg(Vec(4, UInt(4.W)))
Wire(Vec(4,UInt(4,W)))
Input(Vec(4,UInt(4.W)))
IO(Vec(4,UInt(4.W)))
처럼 구체적으로 어떤 HW인지까지 선언해야 한다.
처럼 simultaneous하게 동시에 shift가 잘 되게 합성된다.