View difference between Paste ID: 4Yp7Asyr and X4bReQX7
SHOW: | | - or go back to the newest paste.
1
//INSTRUCTIONS
2
//Extend the vending machine model from Section 16.3 to allow 
3
//U.S.A. currencies from a nickel to twenty dollar bill (0.05, 0.10, 0.25, 0.50, 1.00, 2.00, 5.00, 10.00, and 20.00). 
4
//Add a cancel button which  will return the currency inserted. 
5
//Add a two character selection criteria with first character being from A-H and second character from 1-9. 
6
//Read a price file for each of the 72 items. 
7
//Add a current monies held for each type of currency (also read from a file) 
8
//and after dispensing return the residual using the minimum number of currency unit.
9
//Write a testbench which validates each of these functions.
10
11
12
13
14
//d flip flop for state control
15
module DFF(clk, in, out);
16
    parameter n = 1;    //width
17
    input clk;
18
    input [n-1:0] in;
19
    output [n-1:0] out;
20
    reg [n-1:0] out;
21
22
    //posedge triggers on rising edge  of clock signal
23
    always @(posedge clk)
24
        out = in;
25
endmodule
26
27
28
//mux3   - pg 157
29
//three input mux with one-hot select (arbitrary width)
30
module Mux3(a2, a1, a0, s, b);
31
    parameter k = 1;
32
    input [k-1:0] a2, a1, a0;   //inputs
33
    input [2:0] s;              //one-hot selet
34
    output [k-1:0] b;
35
    assign b = ({k{s[2]}} & a2) |
36
                    ({k{s[1]}} & a1) |
37
                    ({k{s[0]}} & a0);
38
endmodule
39
40
41
//addsub - pg 221
42
// add a+b or subtract a - b, check for overflow
43
module AddSub(a, b, sub, s, ovf);
44
    parameter n = 8;
45
    input [n-1:0] a, b;
46
    input sub;              //subtract if sub=1, otherwise add
47
    output [n-1:0] s;
48
    output ovf;             //1 if overflow
49
    wire c1, c2;            //carry out of last two bits
50
    assign ovf = c1 ^ c2;   //overflow if signs don't match
51
52
    //add non sign bits
53
    assign {c1, s[n-2:0]} = a[n-2:0] + (b[n-2:0] ^ {n-1{sub}}) + sub;
54
    //add sign bits
55
    assign {c2, s[n-1]} = a[n-1] + (b[n-1] ^ sub) + c1;
56
endmodule
57
58
59
60
module VendingMachine(clk, rst, nickel, dime, quarter, dispense, done, price, serve, change);
61
    parameter n = `DWIDTH;
62
    input clk, rst, nickel, dime, quarter, dispense, done;
63
    input [n-1:0] price;
64
    output serve, change;
65
66
    wire enough, zero, sub;
67
    wire [3:0] selval;
68
    wire [2:0] selnext;
69
70
    VendingMachineControl vmc(clk, rst, nickel, dime, quarter, dispense, done, enough, zero, serve, change, selval, selnext, sub);
71
72
    VendingMachineData #(n) vmd(clk, selval, selnext, sub, price, enough, zero);
73
endmodule
74
75
76
77
78
module VendingMachineControl(clk, rst, nickel, dime, quarter, dispense, done, enough, zero, serve, change, selval, selnext, sub);
79
    input clk, rst, nickel, dime, quarter, dispense, done, enough, zero;
80
    output serve, change, sub;
81
    output [3:0] selval;
82
    output [2:0] selnext;
83
    wire [`SWIDTH-1:0] state, next;     //current and next state
84
    reg [`SWIDTH-1:0] next1;            //next state w/o reset
85
86
    //outputs
87
    wire first;     //true during first cycle of serve1 or change1
88
    wire serve1 = (state == `SERVE1);
89
    wire change1 = (state == `CHANGE1);
90
    assign serve = serve1 & first;
91
    assign change = chang1 & first;
92
93
    //datapath controls
94
    wire dep = (state == `DEPOSIT);
95
    // price, 1, 2, 5
96
    wire [3:0] selval = {(dep & dispense),
97
                         ((dep & nickel) | change),
98
                         (dep & dime),
99
                         (dep & quarter)};
100
    // amount, sum, 0
101
    wire selv = (dep & (nickel | dime | quarter | (dispense & enough))) |
102
                (change & first);
103
    wire [2:0] selnext = {~(selv | rst), ~rst & selv,rst};
104
105
    //subtract
106
    wire sub = (dep & dispense) | change;
107
108
    //only do actions on first cycle of serve1 or change1
109
    wire nfirst = !(serve1 | change1);
110
    DFF #(1) first_reg(clk, nfirst, first);
111
112
    //state register
113
    DFF #(`SWIDTH) state_reg(clk, next, state);
114
115
    //next state logic
116
    always @(*) begin
117
        casex({dispense, enough, done, zero, state})
118
            {4'b11xx, `DEPOSIT}: next1 = `SERVE1;   //dispense & enough
119
            {4'b0xxx, `DEPOSIT}: next1 = `DEPOSIT;   
120
            {4'bx0xx, `DEPOSIT}: next1 = `DEPOSIT;   
121
            {4'bxx1x, `SERVE1}:  next1 = `SERVE2;   //done
122
            {4'bxx0x, `SERVE1}:  next1 = `SERVE1;
123
            {4'bxx01, `SERVE2}:  next1 = `DEPOSIT;  //~done & zero
124
            {4'bxx00, `SERVE2}:  next1 = `CHANGE1;  //~done & ~zero
125
            {4'bxx1x, `SERVE2}:  next1 = `SERVE2;   //done
126
            {4'bxx1x, `CHANGE1}: next1 = `CHANGE2;  //done
127
            {4'bxx0x, `CHANGE1}: next1 = `CHANGE1;  //done
128
            {4'bxx00, `CHANGE2}: next1 = `CHANGE1;  //~done & ~zero
129
            {4'bxx01, `CHANGE2}: next1 = `DEPOSIT;  //~done & zero
130
            {4'bxx1x, `CHANGE2}: next1 = `CHANGE2;  //~done & ~zero
131
        endcase
132
    end
133
134
    //reset next state
135
    assign next = rst ? `DEPOSIT : next1;
136
endmodule
137
138
139
140
141
142
143
module VendingMachineData(clk, selval, selnext, sub, price, enough, zero);
144
    parameter n = 6;
145
    input clk, sub;
146
    input [3:0] selval;     //price, 1, 2, 5
147
    input [2:0] selnext;    //amount, sum, 0
148
    input [n-1:0] price;    //price of soft drink - in nickels
149
    output enough;          //amount > price
150
    output zero;            //amount = zero
151
    
152
    wire [n-1:0] sum;       //output of add/subtract unit
153
    wire [n-1:0] amount;    //current amount
154
    wire [n-1:0] next;      //next amount
155
    wire [n-1:0] value;     //value to add or subtract from amount
156
    wire ovf;               //overflow - ignore for now
157
158
    //state register holds current amount
159
    DFF #(n) amt(clk, next, amount);
160
161
    //select next state from 0, sum, or hold
162
    Mux3 #(n) nsmux(amount, sum, {n{1'b0}}, selnext, next);
163
164
    //add or subtract a value from current amount
165
    AddSub #(n) add(amount, value, sub, sum, ovf);
166
167
    //select the value to add or subtract
168
    //p 
169
    Mux4 #(n) vmux(price, `NICKEL, `DIME, `QUARTER, selval, value);
170
171
    //comparators
172
    wire enough = (amount >= price);
173
    wire zero = (amount == 0);
174
endmodule
175
176
177
178
179
180
module testVend;
181
    reg clk, rst, nickel, dime, quarter, dispense, done;
182
    reg [3:0] price;
183
    wire serve, change;
184
185
    VendingMachine #(4) vm(clk, rst, nickel, dime, quarter, dispense, done, price,
186
                            serve, change);
187
    
188
    //clock with period of 10 units
189
    initial begin
190
        clk = 1; #5 clk = 0;
191
        forever begin
192
            $display("%b %h %h %b %b",
193
            {nickel, dime, quarter, dispense}, vm.vmc.state, vm.vmd.amount, serve, change);
194
            #5 clk = 1; #5 clk = 0; 
195
        end
196
    end
197
198
    //give prompt feedback
199
    always @(posedge clk) begin
200
        done = (serve | change);
201
    end
202
203
    initial begin
204
        rst = 1; {nickel, dime, quarter, dispense} = 4'b0;
205
        price = `PRICE;
206
        #25 rst = 0;
207
        #10 {nickel, dime, quarter, dispense} = 4'b1000; //nickel 1
208
        #10 {nickel, dime, quarter, dispense} = 4'b0100; //dime 3
209
        #10 {nickel, dime, quarter, dispense} = 4'b0000; //nothing
210
        #10 {nickel, dime, quarter, dispense} = 4'b0001; //try to dispense early
211
        #10 {nickel, dime, quarter, dispense} = 4'b0010; //quarter 8
212
        #10 {nickel, dime, quarter, dispense} = 4'b0010; //quarter 13
213
        #10 {nickel, dime, quarter, dispense} = 4'b0000; //nothing
214
        #10 {nickel, dime, quarter, dispense} = 4'b0001; //dispense 2
215
        #10 dispense = 0;
216
        #100 $stop;
217
    end
218
endmodule