[chisel-tutorial] VendingMachine.scala: FSM 구현

YumeIroVillain·2023년 8월 9일
0

Chisel 독학

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

Enum: Chisel3 cheatsheet 참조

상태머신을 만드는 문제이다.
Enum으로 state를 선언하고,
moore로 짜면 될 것 같다.

풀이

Test Code

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

import chisel3.iotesters.PeekPokeTester

class VendingMachineTests(c: VendingMachine) 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)
  }
}

오답 1 - nextState 사용

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

import chisel3._
import chisel3.util._

// Problem:
//
// Implement a vending machine using 'when' states.
// '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 VendingMachine 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)

  // Implement below ----------

  val state_nxt = WireInit(sIdle)

  val state := state_nxt
  when(state === sIdle){
    when(io.nickel){
      state_nxt := s5
    }.elsewhen(io.dime){
      state_nxt := s10
    }.otherwise{
      state_nxt := state
    }
  }.elsewhen(state === s5){
    when(io.nickel){
      state_nxt := s10
    }.elsewhen(io.dime){
      state_nxt := s15
    }.otherwise{
      state_nxt := state
    }
  }.elsewhen(state === s10){
    when(io.nickel){
      state_nxt := s15
    }.elsewhen(io.dime){
      state_nxt := s0k
    }.otherwise{
      state_nxt := state
    }
  }.elsewhen(state === s15){
    when(io.nickel){
      state_nxt := s0k
    }.elsewhen(io.dime){
      state_nxt := s0k
    }.otherwise{
      state_nxt := state
    }
  }.elsewhen(state === s0k){
    state_nxt := sIdle
  }.otherwise{
    println("ERROR: undefined state")
    state_nxt := sIdle
  }

  // Implement above ----------

  io.valid := (state === sOk)
}

너무나도 당연히, state_nxt를 선언했고
클럭마다 state가 state_nxt로 바뀌는걸 어떻게 해야할지는 모르겠어서,
그냥냅다 val state := state_nxt 해버렸고
돌렸는데, 오류가 나왔다.

정답

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

import chisel3._
import chisel3.util._

// Problem:
//
// Implement a vending machine using 'when' states.
// '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 VendingMachine 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)

  // Implement below ----------

  when(state === sIdle){
    when(io.nickel){
      state := s5
    }.elsewhen(io.dime){
      state := s10
    }.otherwise{
      state := state
    }
  }.elsewhen(state === s5){
    when(io.nickel){
      state := s10
    }.elsewhen(io.dime){
      state := s15
    }.otherwise{
      state := state
    }
  }.elsewhen(state === s10){
    when(io.nickel){
      state := s15
    }.elsewhen(io.dime){
      state := sOk
    }.otherwise{
      state := state
    }
  }.elsewhen(state === s15){
    when(io.nickel){
      state := sOk
    }.elsewhen(io.dime){
      state := sOk
    }.otherwise{
      state := state
    }
  }.elsewhen(state === sOk){
    state := sIdle
  }.otherwise{
    println("ERROR: undefined state")
    state := sIdle
  }

  // Implement above ----------

  io.valid := (state === sOk)
}
  • state_nxt를 지우고, 그냥 state만 선언하여 FSM을 만들었다.
  • 아래는 Chisel book 112Page의 해당 이유에 대한 답글이다.

    Note that we did not introduce a nextState signal for the register input, as it is common practice in Verilog or VHDL.
    Registers in Verilog and VHDL are described in a special syntax and cannot be assigned (and reassigned) within a combinational block.
    Therefore, the additional signal, computed in a combinational block, is introduced and connected to the register input.
    In Chisel a register is a base type and can be freely used and assigned within a combinational block.

  • Enum은 내부적으로 `define 문으로 합성되는게 아니라, 그냥 3'h0같은 숫자로 mapping된다.(독해하기 힘들겠다)


What I learned

  • Chisel에서 Enum 선언할 때, 끝에 Nil은 왜 붙이는거지? 그냥 문법인건가?
  • Enum을 선언해도, 내부적으로는 상수로 mapping된다.
  • Chisel의 Register는 Combination 문과 자유롭게 assign될 수 있으므로, 굳이 nextState를 쓸 필요가 없다.
profile
HW SW 둘다 공부하는 혼종의 넋두리 블로그 / SKKU SSE 17 / SWM 11th
post-custom-banner

0개의 댓글