一、前言
本系列旨在提供100%准确的数字IC设计/验证手撕代码环节的题目,原理,RTL设计,Testbench和参考仿真波形,每篇文章的内容都经过仿真核对。快速导航链接如下:
1.奇数分频
2.偶数分频
3.半整数分批
4.小数/分数分频
5.序列检测器
6.模三检测器
7.饮料机
8.异步复位,同步释放
9.边沿检测(上升沿,下降沿,双边沿)
10.全加器,半加器
11.格雷码转二进制
12.单bit跨时钟域(打两拍,边沿同步,脉冲同步)
13.奇偶校验
14.伪随机数生成器[线性反馈移位寄存器]
15.同步FIFO
16.无毛刺时钟切换电路
应当说,手撕代码环节是面试流程中既重要又简单的一个环节,跟软件类的岗位相比起来,数字IC的手撕代码题目固定,数量有限,属于整个面试中必得分的一个环节,在这个系列以外,笔者同样推荐数字IC求职者使用“HdlBits”进行代码的训练
链接如下
HDLBits — Verilog Practice
二、自动售卖饮料机题目
1.使用Verilog设计电路,完成以下功能:每瓶饮料1.5元,一次只能投入一个硬币,可投入0.5与1.0两种硬币,具有找零功能。
三、自动售卖饮料机原理
首先,很显而易见的是,这个手撕代码应该用状态机来完成
对于状态的区分,我们可以根据饮料机中剩余的的金额来进行分类,因为硬币只存在两种,0.5/1元,因此状态的划分可以如下
- IDLE:复位状态,表示饮料机中的余额为0元
- s1:饮料机的余额为0.5元
- s2:饮料机中的余额为1元
- s3:饮料机中的余额为1.5元(输出饮料,不找零)
- s4:饮料集中的余额为2元(输出饮料,找零)
那么对于这个状态机的输入和输出来说
输入:两位input代表投入的硬币,input[1]拉高意味着投入一元,input[0]拉高意味着投入0.5元,默认一次只能投入一枚硬币。
输出:drink代表输出饮料,coin代表输出硬币。
四、Veilog设计
module drink_machine( clk ,rst_n, money,drink,coin); input clk; input rst_n; input [1:0] money; output drink; output coin; parameter IDLE = 3'd0, s1=3'd1 ,s2=3'd2, s3=3'd3,s4=3'd4; reg [2:0] state,nstate; always@(posedge clk or negedge rst_n) begin if(!rst_n) state<=IDLE; else state<=nstate; end always@(*) begin case(state) IDLE:nstate = money[1] ? s2 : (money[0] ? s1 :IDLE); s1: nstate = money[1] ? s3 : (money[0] ? s2 : s1); s2: nstate = money[1] ? s4 : (money[0] ? s3 : s2); s3: nstate = money[1] ? s2 : (money[0] ? s1 :IDLE); s4: nstate = money[1] ? s2 : (money[0] ? s1 :IDLE); default nstate = IDLE; endcase end assign drink = (state == s3 || state == s4)? 1:0; assign coin = (state == s4)? 1:0; endmodule
五、Testbench设计
module drink_machine_tb(); reg clk; reg rst_n; reg [1:0] money; wire drink; wire coin; drink_machine u1 (.clk(clk),.rst_n(rst_n),.money(money),.drink(drink),.coin(coin)); always #5 clk = !clk; always #10.001 money = {$random} % 3; initial begin clk = 0; rst_n = 1; #10 rst_n = 0; #20 rst_n = 1; #1000 $stop; end endmodule
六、仿真结果
从20ns到80ns的过程中,投了一个五毛,一个一块,drink输出为1.
紧接着,投了一个一块,又投了一个一块,drink输出为1的同时coin也输出为1
其他的状态跳转也符合预期,设计成立。