[chisel-tutorial] VecShiftRegister.scala: Vec 사용시, 구체적인 HW명을 명시하자

YumeIroVillain·2023년 8월 8일
0

Chisel 독학

목록 보기
24/44
post-custom-banner

load가 켜져있으면 동시초기화를,
shift가 켜져있으면 0번 인덱스만 push하고 나머지는 밀려나는
left shift register를 구현하면 되는
간단한 문제다.

풀이

Test Code

// 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))
  }
}
  • 명령어 우선순위는 load가 shift보다 높다.
  • load 입력시, ins 입력대로 내부 shift register가 전부 초기화된다.
  • shift 입력시, 3<2 2<1 1<0 0<3 형식으로 한칸씩 밀려난다(leftshift).

오답 1

// 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도 아니라서 변수명 걍 바꿨다.)


What I learned

  • UInt<4> 같은 데이터가 connect되는 대상은 반드시 HW여야만 한다. 그것이 IO던지, Wire던지, Reg던지 아무튼 선언을 해야한다는 뜻이다.
    따라서,
  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인지까지 선언해야 한다.

  • for문으로 shift를 정의해도,

처럼 simultaneous하게 동시에 shift가 잘 되게 합성된다.

profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th
post-custom-banner

0개의 댓글