상태머신을 만드는 문제이다.
Enum으로 state를 선언하고,
moore로 짜면 될 것 같다.
// 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)
}
}
// 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)
}
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.