[chisel-tutorial] VendingMachineSwitch.scala: Switch 문으로 FSM 구현

YumeIroVillain·2023년 8월 9일
0

Chisel 독학

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

FSM을 이번에는 when문이 아니라, switch문으로 구현하는 차이점 뿐이다.
즉 간단하다.

풀이

Test Code

// See LICENSE.txt for license details.
package problems

import chisel3.iotesters.PeekPokeTester

class VendingMachineSwitchTests(c: VendingMachineSwitch) extends PeekPokeTester(c) {
  var money = 0
  var isValid = false
  for (t <- 0 until 20) {
    val coin     = rnd.nextInt(3)*5
    val isNickel = coin == 5
    val isDime   = coin == 10

    // Advance circuit
    poke(c.io.nickel, if (isNickel) 1 else 0)
    poke(c.io.dime,   if (isDime) 1 else 0)
    step(1)

    // Advance model
    money = if (isValid) 0 else money + coin
    isValid = money >= 20

    // Compare
    expect(c.io.valid, if (isValid) 1 else 0)
  }
}

내부적으로 money 변수를 유지하고, 20 이상인지의 여부를 정답으로 생성하여
Chisel 모듈의 답과 비교하는 간단한 테스트코드이다.

오답 1

// See LICENSE.txt for license details.
package problems

import chisel3._
import chisel3.util._

// Problem:
//
// Implement a vending machine using a 'switch' statement.
// 'nickel' is a 5 cent coin
// 'dime'   is 10 cent coin
// 'sOk' is reached when there are coins totalling 20 cents or more in the machine.
// The vending machine should return to the 'sIdle' state from the 'sOk' state.
//
class VendingMachineSwitch extends Module {
  val io = IO(new Bundle {
    val nickel = Input(Bool())
    val dime   = Input(Bool())
    val valid  = Output(Bool())
  })
  val sIdle :: s5 :: s10 :: s15 :: sOk :: Nil = Enum(5)
  val state = RegInit(sIdle)

  switch (state) {
    is (sIdle) {
      when (io.nickel) { state := s5 }
      when (io.dime) { state := s10 }
    }
    // Implement below ----------
    is (s5){
      when(io.nickel){ state := s10}
      when(io.dime){ state := s15}
    }
    is (s10){
      when(io.nickel){ state := s15}
      when(io.dime){ state := sOk}
    }
    is (s15){
      when(io.nickel){ state := sOk}
      when(io.dime){ state := sOk}
    }
    is (sOk){
      when(io.nickel){ state := sIdle}
      when(io.dime){ state := sIdle}
    }
    // Implement above ----------
  }
  io.valid := (state === sOk)
}
  • 실수가 있었다.
  • sOk 상태에서는 무지성 state := sIdle해야하는데,
    조건 2개가 아니면 state := state가 암묵적으로 들어가게 되어버렸다.

정답

// See LICENSE.txt for license details.
package problems

import chisel3._
import chisel3.util._

// Problem:
//
// Implement a vending machine using a 'switch' statement.
// 'nickel' is a 5 cent coin
// 'dime'   is 10 cent coin
// 'sOk' is reached when there are coins totalling 20 cents or more in the machine.
// The vending machine should return to the 'sIdle' state from the 'sOk' state.
//
class VendingMachineSwitch extends Module {
  val io = IO(new Bundle {
    val nickel = Input(Bool())
    val dime   = Input(Bool())
    val valid  = Output(Bool())
  })
  val sIdle :: s5 :: s10 :: s15 :: sOk :: Nil = Enum(5)
  val state = RegInit(sIdle)

  switch (state) {
    is (sIdle) {
      when (io.nickel) { state := s5 }
      when (io.dime) { state := s10 }
    }
    // Implement below ----------
    is (s5){
      when(io.nickel){ state := s10}
      when(io.dime){ state := s15}
    }
    is (s10){
      when(io.nickel){ state := s15}
      when(io.dime){ state := sOk}
    }
    is (s15){
      when(io.nickel){ state := sOk}
      when(io.dime){ state := sOk}
    }
    is (sOk){
      state := sIdle
    }
    // Implement above ----------
  }
  io.valid := (state === sOk)
}

고쳤고, 통과했다.

  • 왼쪽은 switch로 구현한 FSM이 만든 .v
    오른쪽은 when-elsewhen-otherwise로 구현한 FSM의 .v이다.
  • 두 경우 모두 차이는 없고, 동일히 elaborate되는 것을 알 수 있다.

What I learned

  • switch(state){ is() ...} 문을 활용해 when문을 대체할 수 있으며, elaborate 결과는 동일하다.
  • 이 때, default값은 .otherwise를 못쓰므로, 위에 선언해야한다.출처
... // default values here
switch ( myState ) {
  is( state1 ) {
    ... // some logic here
  }
  is( state2 ) {
    ... // some logic here
  }
}
profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th
post-custom-banner

0개의 댓글