1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// SPDX-License-Identifier: Apache-2.0
package examples
import chiselTests.ChiselFlatSpec
import chisel3.testers.{BasicTester, TesterDriver}
import chisel3._
import chisel3.util._
class SimpleVendingMachineIO extends Bundle {
val nickel = Input(Bool())
val dime = Input(Bool())
val dispense = Output(Bool())
}
// Superclass for vending machines with very simple IO
abstract class SimpleVendingMachine extends Module {
val io = IO(new SimpleVendingMachineIO)
assert(!(io.nickel && io.dime), "Only one of nickel or dime can be input at a time!")
}
// Vending machine implemented with a Finite State Machine
class FSMVendingMachine extends SimpleVendingMachine {
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 }
}
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
}
}
io.dispense := (state === sOk)
}
class VerilogVendingMachine extends BlackBox {
// Because this is a blackbox, we must explicitly add clock and reset
val io = IO(new SimpleVendingMachineIO {
val clock = Input(Clock())
val reset = Input(Reset())
})
}
// Shim because Blackbox io is slightly different than normal Chisel Modules
class VerilogVendingMachineWrapper extends SimpleVendingMachine {
val impl = Module(new VerilogVendingMachine)
impl.io.clock := clock
impl.io.reset := reset
impl.io.nickel := io.nickel
impl.io.dime := io.dime
io.dispense := impl.io.dispense
}
// Accept a reference to a SimpleVendingMachine so it can be constructed inside
// the tester (in a call to Module.apply as required by Chisel
class SimpleVendingMachineTester(mod: => SimpleVendingMachine) extends BasicTester {
val dut = Module(mod)
val (cycle, done) = Counter(true.B, 10)
when(done) { stop(); stop() } // Stop twice because of Verilator
val nickelInputs = VecInit(true.B, true.B, true.B, true.B, true.B, false.B, false.B, false.B, true.B, false.B)
val dimeInputs = VecInit(false.B, false.B, false.B, false.B, false.B, true.B, true.B, false.B, false.B, true.B)
val expected = VecInit(false.B, false.B, false.B, false.B, true.B, false.B, false.B, true.B, false.B, false.B)
dut.io.nickel := nickelInputs(cycle)
dut.io.dime := dimeInputs(cycle)
assert(dut.io.dispense === expected(cycle))
}
class SimpleVendingMachineSpec extends ChiselFlatSpec {
"An FSM implementation of a vending machine" should "work" in {
assertTesterPasses { new SimpleVendingMachineTester(new FSMVendingMachine) }
}
"An Verilog implementation of a vending machine" should "work" in {
assertTesterPasses(
new SimpleVendingMachineTester(new VerilogVendingMachineWrapper),
List("/chisel3/VerilogVendingMachine.v"),
annotations = TesterDriver.verilatorOnly
)
}
}
|