diff options
| author | jackkoenig | 2016-10-26 16:40:36 -0700 |
|---|---|---|
| committer | Jack Koenig | 2017-02-02 22:53:03 -0800 |
| commit | dd51b917566e6b30c3f123ca22a0393e73c2afe8 (patch) | |
| tree | f81fce104ccc3405c7924c76618483750a4350bb /src/test/scala/examples/SimpleVendingMachine.scala | |
| parent | b0a328492383108509c322189ed2803f671d7a59 (diff) | |
Revamp VendingMachine.scala as cookbook example
* Move to cookbook
* Change FSM implementation to use switch & is
* Add non-FSM implementation
* Add execution-driven test
Diffstat (limited to 'src/test/scala/examples/SimpleVendingMachine.scala')
| -rw-r--r-- | src/test/scala/examples/SimpleVendingMachine.scala | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/test/scala/examples/SimpleVendingMachine.scala b/src/test/scala/examples/SimpleVendingMachine.scala new file mode 100644 index 00000000..d935b611 --- /dev/null +++ b/src/test/scala/examples/SimpleVendingMachine.scala @@ -0,0 +1,95 @@ +// See LICENSE for license details. + +package examples + +import chiselTests.ChiselFlatSpec +import chisel3.testers.BasicTester +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 = Reg(init = 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 explicity add clock and reset + val io = IO(new SimpleVendingMachineIO { + val clock = Input(Clock()) + val reset = Input(Bool()) + }) +} + +// 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 = Vec(true.B, true.B, true.B, true.B, true.B, false.B, false.B, false.B, true.B, false.B) + val dimeInputs = Vec(false.B, false.B, false.B, false.B, false.B, true.B, true.B, false.B, false.B, true.B) + val expected = Vec(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("/VerilogVendingMachine.v")) + } +} |
