我的Verilog学习历程(三) 时序电路的一个例子:实现连加

学艺不精的我又来记录了(doge
有何错误以及需要改进的地方希望大家不吝指出!
先看题目:
实验内容:
实验一个可以实现连续加法功能的计算器
具体要求如下:
1) 输入100MHz时钟,由EGO1板通过FPGA管脚直接输入;
2) 电路可实现连续加法功能,例如 A+B+C+……=S。其中A、B、C均为一位十进制数,采用8421码方式输入。加数的个数不超过10个,即S不超过100。但超过两位数时,显示后两位,舍弃百位。
3) 加数输入通过拨4开关SW3-SW0输入,SW3为MSB,通过按键开关确定输入。加号和等号及清零等由按键开关输入,输入数据及加法结果显示在最右侧两个数码管上。如下图所示。

在这里插入图片描述
(出题:北京理工大学 张延军老师)
实验思路:
①状态机的设计
解决本题的关键是如何设计状态机。为此可以从加法的过程入手,按下确认键后,电路读入数;按下加法,显示读入的数据;按下确认,读入加数;按下等号,显示结果…其实,可以将整个过程视为电路在“等待”哪个按键的过程。确认键之后,加数输入完毕,就在等待加号或等号;加号之后,下一步一定是输入另一个加数,因此在等待确认键;等号之后,等待确认键或者加号:如果是确认键,那么要清空计算结果,进行新一轮加法;如果是加号,则在这个基础上继续计算。当然,在任何时候按下清零键,都会清空所有结果,进入“清零”状态。
所以,状态机共有四个状态:
i.清零状态(clear),所有数据都是0;
ii.等待加号键或等号键状态(w_f_p_e,wait for plus or equal),在按下确认键之后会进入此状态;
iii.等待确认键状态(w_f_c,wait for confirm),在按下加号键之后会进入此状态;
iv.等待加号键或确认键状态(w_f_p_c,wait for plus or confirm),在按下等号键之后会进入该状态。

状态转换图如下:
在这里插入图片描述
这样设计状态机的优点是:过程容易考虑,规定了某一步之后的下一步是什么,其他按键不会影响当前状态的变化,因此避免了混乱。
这样设计的缺点是:状态发生变化后的下一个时钟上升沿才执行计算,这样造成的问题是:由于输出是由状态决定的(设计为摩尔型),那么就有一个时钟周期的时间(也就是10ns),输出是错误的。但是由于时间很短,实际上并不会影响最终的显示效果。
状态机部分代码如下:

1.	//状态寄存器  
2.	always @(posedge clk) begin  
3.	    if (clear_button)  
4.	        current_state <= clear;  
5.	    else   
6.	        current_state <= next_state;  
7.	end  
8.	  
9.	  
10.	//次态的组合逻辑  
11.	always @* begin  
12.	    case (current_state)  
13.	        clear: begin  
14.	            if (confirm_button) next_state = w_f_p_e;  
15.	            else next_state = clear;  
16.	            end  
17.	        w_f_p_e: begin  
18.	            if (plus_button) next_state = w_f_c;  
19.	            else if (equal_button) next_state = w_f_p_c;  
20.	            else next_state = w_f_p_e;  
21.	            end  
22.	        w_f_c: begin  
23.	            if (confirm_button) next_state = w_f_p_e;  
24.	            else next_state = w_f_c;  
25.	            end  
26.	        w_f_p_c:begin  
27.	            if (plus_button) next_state = w_f_c;  
28.	            else if (confirm_button) next_state = w_f_p_e;  
29.	            else next_state = w_f_p_c;  
30.	            end  
31.	        default: next_state = 2'bxx;   
32.	    endcase  
33.	end  

②加法的设计
这也是本题的另一个关键之处。
加法的基本公式是:当前结果=输入+上次运算的结果。假设暂存结果的变量为result_temp,在本题中不能用result_temp <= result_temp + …的形式,因为result_temp是时序逻辑,写成自加会时钟的每一个上升沿都进行计算。
**试着用另一个变量去储存“上次运算的结果”,**因为输入是比较简单的。
因为按下确认键之后,进入wfpe状态,即下一个有效的键一定是加号或者等号,所以下一步一定是计算操作(除去清零,清零的优先级最高),因此在wfpe状态就将下一步的结果计算出来,在wfpe的第一个周期input_temp(暂存输入值的变量)还没变,但input_temp早晚会成为正确值,因此plus_result_temp
也是早晚会成为有效值。而plus_result_temp = result_temp +input_temp,即上次的结果和当前输入之和。
在摁下加号或者等号之后,进入的wfc或wfpc状态后把plus_result_temp赋给result_temp,这时的result_temp就是我们希望的值,并且在此后,result_temp又成为了“上次运算的结果”,供下次plus计算所用。当然,plus在wfc和wfpc的状态中是不能变更的。
此外,还有一个重要的问题:那便是当结果超过三位数之后,只显示后两位。因此加法的判断过程应当是:首先判断当前输入和result_temp中低4位加法的结果是否大于9,如果大于9那么高四位一定会发生进位,因此还要判断高四位加1后是否大于9,如果二者都大于9,说明加完的结果大于100,应该加0110_0110。
此外,在按下等号后如果按下确认键,则要进行新一轮加法。按照此前状态机的设计,这一点无法达到,必须利用另一个变量来满足要求,若检测到在wfpc(也就是按完等号的状态)的状态中按下了确认键,那么暂存结果的result_temp和plus_result_temp都要清零。
计算模块完整代码如下:

1.	module calculate(  
2.	    input clk,  
3.	    //input rst_n,  
4.	    //四个按键  
5.	    input clear_button,  
6.	    input confirm_button,  
7.	    input plus_button,  
8.	    input equal_button,  
9.	    //输入加数  
10.	    input [3:0] number,  
11.	    //输出结果 8842112.	    output reg [7:0] result  
13.	);  
14.	  
15.	//暂存结果  
16.	reg [7:0] result_temp;  
17.	reg [3:0] input_temp;  
18.	reg [7:0] plus_result_temp;  
19.	  
20.	//此变量仅用于在摁下等号之后,再摁确认键将暂存结果清零,进行新一轮加法  
21.	reg if_clear_result;   
22.	  
23.	  
24.	initial begin  
25.	    result_temp = 8'b0;  
26.	    plus_result_temp = 8'b0;  
27.	    input_temp = 4'b0;  
28.	end  
29.	  
30.	//定义状态  
31.	parameter w_f_p_e = 2'b00; //处于等待加号或等号状态 wait for plus or equal  
32.	parameter w_f_c = 2'b01;  //处于等待确认键状态 wait for confirm  
33.	parameter w_f_p_c = 2'b10;    //处于等待加号或确认键状态 wait for plus or confirm  
34.	parameter clear = 2'b11;    //清零状态  clear  
35.	  
36.	reg [1:0] current_state;  
37.	reg [1:0] next_state;  
38.	  
39.	//状态寄存器  
40.	always @(posedge clk) begin  
41.	    if (clear_button)  
42.	        current_state <= clear;  
43.	    else   
44.	        current_state <= next_state;  
45.	end  
46.	  
47.	  
48.	//次态的组合逻辑  
49.	always @* begin  
50.	    case (current_state)  
51.	        clear: begin  
52.	            if (confirm_button) next_state = w_f_p_e;  
53.	            else next_state = clear;  
54.	            end  
55.	        w_f_p_e: begin  
56.	            if (plus_button) next_state = w_f_c;  
57.	            else if (equal_button) next_state = w_f_p_c;  
58.	            else next_state = w_f_p_e;  
59.	            end  
60.	        w_f_c: begin  
61.	            if (confirm_button) next_state = w_f_p_e;  
62.	            else next_state = w_f_c;  
63.	            end  
64.	        w_f_p_c:begin  
65.	            if (plus_button) next_state = w_f_c;  
66.	            else if (confirm_button) next_state = w_f_p_e;  
67.	            else next_state = w_f_p_c;  
68.	            end  
69.	        default: next_state = 2'bxx;   
70.	    endcase  
71.	end  
72.	  
73.	//input_temp  
74.	always @(posedge clk) begin  
75.	    if (current_state == clear)  
76.	        input_temp <= 4'b0;  
77.	    else if (current_state == w_f_p_e && confirm_button)  //只有在wfpe状态时更新的input_temp才有效  
78.	        input_temp <= number;  
79.	    else if (current_state == w_f_p_c && equal_button)  //按下等号后input_temp要清零  
80.	        input_temp <= 4'b0;  
81.	end  
82.	  
83.	//if_clear_result  
84.	always @ * begin  
85.	    if (current_state == w_f_p_c && confirm_button)  //在等号之后摁下确认键,且状态切换前  
86.	        if_clear_result = 1'b1;  
87.	    else  
88.	        if_clear_result = 1'b0;  
89.	end  
90.	  
91.	/* 
92.	关于plus_result_temp和result_temp: 
93.	    加法的基本公式是:当前结果=输入+上次运算的结果 
94.	    在本题中不能用result_temp <= result_temp + ...的形式,因为result_temp是时序逻辑,写成自加会每一个上升沿都进行计算。 
95.	    试着用另一个变量去储存“上次运算的结果”,因为输入是比较简单的。plus_result_temp就是这个功能。 
96.	    因为按下确认键之后,进入wfpe状态,即下一个有效的键一定是加号或者等号,所以下一步一定是计算操作(除去清零,清零的优先级最高), 
97.	因此在wfpe状态就将下一步的结果计算出来,在wfpe的第一个周期input_temp还没变,但input_temp早晚会成为正确值,因此plus_result_temp 
98.	也是早晚会成为有效值。而plus_result_temp = result_temp +input_temp,即上次的结果和当前输入之和。 
99.	    在摁下加号或者等号之后,进入的wfc或wfpc状态后把plus_result_temp赋给result_temp,这时的result_temp就是我们希望的值,并且在 
100.	此后,result_temp又成为了“上次运算的结果”,供下次plus计算所用。当然,plus在wfc和wfpc的状态中是不能变更的。 
101.	*/  
102.	//plus_result_temp  
103.	always @(posedge clk) begin  
104.	    if (current_state == clear)  
105.	        plus_result_temp <= 8'b0;  
106.	    else if (if_clear_result == 1'b1)  
107.	        plus_result_temp <= 8'b0;  
108.	    else if (current_state == w_f_p_e) begin  
109.	        if (({4'b0000,input_temp} + {4'b0000,result_temp[3:0]} > 8'd9) && (result_temp[7:4] + 1'b1 > 4'b1001))  //这是加数达到三位数的情况,例如99+9  
110.	            plus_result_temp <= result_temp + {4'b0000,input_temp} + 8'b0110_0110;  
111.	        else if (({4'b0000,input_temp} + {4'b0000,result_temp[3:0]} > 8'd9) && (result_temp[7:4] + 1'b1 <= 4'b1001))   //这是需要进位但加数不到三位数的情况  
112.	            plus_result_temp <= result_temp + {4'b0000,input_temp} + 8'b0000_0110;  
113.	        else   
114.	            plus_result_temp <= result_temp + {4'b0000,input_temp};  
115.	    end  
116.	  
117.	end  
118.	  
119.	//result_temp  
120.	always @(posedge clk) begin  
121.	    if (current_state == clear)  
122.	        result_temp <= 8'b0;  
123.	    else if (if_clear_result == 1'b1)  
124.	        result_temp <= 8'b0;  
125.	    //在输入加号或者等号的时候才进行计算,但加号只在wfc状态有效,等号只在wfpc状态有效  
126.	    else if (current_state == w_f_c && plus_button)   
127.	        result_temp <= plus_result_temp;  
128.	    else if (current_state == w_f_p_c && equal_button)  
129.	        result_temp <= plus_result_temp;  
130.	end  
131.	  
132.	//输出result  
133.	always @ * begin  
134.	    if (current_state == clear)  
135.	        result = 8'b0;  
136.	    else if (current_state == w_f_p_e)  
137.	        result = {4'b0000,input_temp};  
138.	    else if (current_state == w_f_c || current_state == w_f_p_c)  
139.	        result = result_temp;  
140.	    else  
141.	        result = 8'b0;  
142.	end  
143.	endmodule // calculate   

控制数码管段选和顶层模块就略去啦!

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值