从一个记忆游戏来说明Verilog——5、顶层模块的书写

编程入门 行业动态 更新时间:2024-10-08 08:25:22

从一个记忆游戏来说明Verilog——5、顶层<a href=https://www.elefans.com/category/jswz/34/1771428.html style=模块的书写"/>

从一个记忆游戏来说明Verilog——5、顶层模块的书写

内容回顾

到这里我们已经实现了所有的子模块,这篇博客简单的对我们的小游戏进行了分析,现在我们按照自顶向下的方式,搭出来主模块的内容。

主模块

首先是输入输出:
输入:5个按键开关、8个拨码开关,一个时钟信号
输出:两组led灯的内容&使能端

因为是拨码开关,我们需要对输入的信号进行消抖处理,消抖模块在这里

主要内容

  1. 在生成随机数的模块中,我们需要有一个种子的输入(可以考虑成C的伪随机数种子),他需要在程序开始就不断自增,在我们需要使用的时候传入随机数模块;
  2. 我们生成的随机数需要输出,读入的地址需要输出,读入的数据需要输出,那么我们就有三个模块对输出显示模块进行控制,但是还不能是一组变量,所以我采用的方式是创建了三组中间变量,通过按键开关的使能信号决定哪一组数据应当被传入显示模块;
  3. 我们需要在最后显示地址-正确的随机数,所以我们需要存储用户输入的地址和每一组随机数;在判定数据正确与否的模块中,我们传出了两个使能信号,这些都需要在主模块中利用中间变量进行传输。
  4. 在整个的程序中,我们采用了一个类似于状态机的东西(因为本身就是通过不断的改变状态来实现指定的功能),我们给出了一些使能端,每一个使能端对应着一个状态(没有给出具体的状态编码而已),
    而输入信号是一闪而过的,我们需要的是一个长时间的信号来保证能在指定的时间内调用这个模块。

代码

`timescale 1ns / 1ps
module ex6_top(input s0_in,//开始生成input s1_in,//输入地址input s2_in,//开始匹配内容input s3_in,//读入一位八进制数input s4_in,//复位input [7:0]sw,input clk,output [7:0]leda,output [7:0]ledb,output [3:0]dn0,output [3:0]dn1,//8个led灯,当匹配成功有流水灯效果output [7:0]cele,		//8个led灯,3-7是匹配模块中判断有多少个数匹配成功,0-2是译码模块判断计数器的,//debug时采用的,没什么具体用处output [7:0]how_many	);//线网型除颤过了的信号wire s0;wire s1;wire s2;wire s3;wire s4;//种子reg [14:0]seed = 15'b010_0110_0011_1100;//输出显示模块的信号源*3wire [3:0]number1_t;wire [3:0]number2_t;wire [3:0]number3_t;wire [3:0]number4_t;wire [3:0]number5_t;wire [3:0]number6_t;wire [3:0]number7_t;wire [3:0]number8_t;wire [3:0]number1_p;wire [3:0]number2_p;wire [3:0]number3_p;wire [3:0]number4_p;wire [3:0]number5_p;wire [3:0]number6_p;wire [3:0]number7_p;wire [3:0]number8_p;wire [3:0]number1_n;wire [3:0]number2_n;wire [3:0]number3_n;wire [3:0]number4_n;wire [3:0]number5_n;wire [3:0]number6_n;wire [3:0]number7_n;wire [3:0]number8_n;//最终送入输出显示模块的信号reg [3:0]number1_r;reg [3:0]number2_r;reg [3:0]number3_r;reg [3:0]number4_r;reg [3:0]number5_r;reg [3:0]number6_r;reg [3:0]number7_r;reg [3:0]number8_r;//中间变量wire [14:0]random_number1;	//5个随机数wire [14:0]random_number2;wire [14:0]random_number3;wire [14:0]random_number4;wire [14:0]random_number5;wire [3:0]place;    		//输入的地址wire if_finish;     		//五个随机数是否生成完成wire flash;         		//控制输入错误的闪烁wire if_right;      		//判断数字对不对//状态机部分的使能信号reg s_zero= 1'b0;reg s_one = 1'b0;reg s_two = 1'b0;reg finish = 1'b0;  		//随机数产生是否完成的使能端,状态机部分reg judge  = 1'b1;			//辅助finish使能信号部分,保证状态正常转换reg [14:0]right_input= 15'b111_111_111_111_111;//地址对应的内容 chuchan cc_0(s0_in,clk,s0);chuchan cc_1(s1_in,clk,s1);chuchan cc_2(s2_in,clk,s2);chuchan cc_3(s3_in,clk,s3);chuchan cc_4(s4_in,clk,s4);always@(posedge clk)    //种子处理seed <= seed + 1;//将各种信号统一修改成类似状态机的状态的使能,以支持模块always@(posedge clk)beginif(s0)			//开始生成随机数begins_zero <= 1'b1;endelse if(if_finish && judge)beginfinish <= 1'b1;judge <= 1'b0;endelse if(s1)		//开始输入地址begins_zero <= 1'b0;finish <= 1'b0;s_one <= 1'b1;case(place)4'b0000: right_input <= random_number1;4'b0001: right_input <= random_number2;4'b0010: right_input <= random_number3;4'b0011: right_input <= random_number4;4'b0100: right_input <= random_number5;endcaseendelse if(s2)		//开始匹配begins_one <= 1'b0;s_two <= 1'b1;endelse if(s4)		//重置begins_zero<= 1'b0;s_one <= 1'b0;s_two <= 1'b0;finish<= 1'b0;judge <= 1'b1;endelse;end//给输出显示模块传入状态对应的数据always@(*)beginif(finish)					//输出随机数的时间beginnumber1_r = number1_t;number2_r = number2_t;number3_r = number3_t;number4_r = number4_t;number5_r = number5_t;number6_r = number6_t;number7_r = number7_t;number8_r = number8_t;endelse if(s_one)				//输出地址的时间beginnumber1_r = number1_p;number2_r = number2_p;number3_r = number3_p;number4_r = number4_p;number5_r = number5_p;number6_r = number6_p;number7_r = number7_p;number8_r = number8_p;endelse if(s_two)				//输出匹配情况的时间beginnumber1_r = number1_n;number2_r = number2_n;number3_r = number3_n;number4_r = number4_n;number5_r = number5_n;number6_r = number6_n;number7_r = number7_n;number8_r = number8_n;endelse;end//功能调用celebrate cel(if_right,clk,cele);light li_all(clk,s_one,s_two,flash,if_right,finish,number1_r,number2_r,number3_r,number4_r,number5_r,number6_r,number7_r,number8_r,leda,ledb,dn0,dn1);random rand(s0,clk,seed,s4,random_number1,random_number2,random_number3,random_number4,random_number5,if_finish);translate translation(random_number1,random_number2,random_number3,random_number4,random_number5,clk,s4,finish,number4_t,number5_t,number6_t,number7_t,number8_t,how_many[2:0]);in_place ip(s1,sw,place,number1_p,number2_p,number3_p,number4_p,number5_p,number6_p,number7_p,number8_p);in_number in(sw[2:0],s3,s_two,s4,clk,right_input,place[2:0],how_many[7:3],number1_n,number2_n,number3_n,number4_n,number5_n,number6_n,number7_n,number8_n,flash,if_right);
endmodule

细节

首先是除颤模块调用,还是之前的博客代码,直接拿过来了就是,这部分不做阐述。

cele模块是我们在匹配成功给出的一个流水灯效果,之前的流水灯博客在这里,这个基本上是相同的。
不过这次的效果是从两侧开始向中间逐渐变亮。

`timescale 1ns / 1psmodule celebrate(input right,input clk,output [7:0]cele_o);wire clk_o;reg [2:0]counter = 3'b111;cele_divider cele_div(clk,clk_o);//4HZ的分频模块reg [7:0]cele = 8'b0000_0000;assign cele_o = cele;always@(posedge clk_o)beginif(right)begincase(counter)3'b000:begincele[0] <= 1'b1;cele[7] <= 1'b1;end3'b001:begincele[1] <= 1'b1;cele[6] <= 1'b1;end3'b010:begincele[2] <= 1'b1;cele[5] <= 1'b1;end3'b011:begincele[3] <= 1'b1;cele[4] <= 1'b1;endendcaseif(counter != 3'b011)counter <= counter+1'b1;else;endelsebegincele = 8'b0000_0000;counter = 3'b111;endendendmodule

分频在流水灯的博客中,都是之前的东西了。

结语

到这里我们的整个记忆游戏项目就结束了,虽然不是很大,但是我们也从中学到了很多。
首先是对于一个项目,如何自顶向下的分析,如何处理好不同模块之间的关系,需要传递什么,需要接受什么;模块之间的并行关系如何形成一个个状态(类似状态机)
还有我们确实很难做到一次将整体的架构搭好,所以我们需要对照着我们的要求,不断将顶层模块和子模块进行修改,这些不可避免,但是如果开始想的比较好,还是会剩下来很多时间的。

项目不大,但是还算有趣,学到了很多东西,尽管Verilog结束了一段时间,但是还是留下了很深的印象。

更多推荐

从一个记忆游戏来说明Verilog——5、顶层模块的书写

本文发布于:2024-03-07 21:44:34,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1718983.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模块   记忆   游戏   Verilog

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!