硬件语言Verilog HDL牛客刷题 day09 哲K部分
1.VL59 根据RTL图编写Verilog程序
1.题目:
根据以下RTL图,使用 Verilog HDL语言编写代码,实现相同的功能,并编写testbench验证功能
2.解题思路
2.1 了解D触发器的知识 (在时钟是上升沿的时候, 输入是什么输出什么)
2.2 注意经过D触发器的器件需要 延时一个周期。
链接:时序约束系列之D触发器原理和FPGA时序结构 - 知乎 (zhihu.com)
3.解题代码
`timescale 1ns/1nsmodule RTL(input clk,input rst_n,input data_in,output reg data_out);
reg flag;
always@(posedge clk or negedge rst_n)beginif(~rst_n)beginflag<=0;endelsebeginflag <=data_in ;endendalways@(posedge clk or negedge rst_n)beginif(~rst_n)begindata_out<=0;endelsebegindata_out <= ~flag && data_in ;endendendmodule
2.VL60 使用握手信号实现跨时钟域数据传输
1.题目:
分别编写一个数据发送模块和一个数据接收模块,模块的时钟信号分别为clk_a,clk_b。两个时钟的频率不相同。数据发送模块循环发送0-7,在每个数据传输完成之后,间隔5个时钟,发送下一个数据。请在两个模块之间添加必要的握手信号,保证数据传输不丢失。
模块的接口信号图如下:
data_req和data_ack的作用说明:
data_req表示数据请求接受信号。当data_out发出时,该信号拉高,在确认数据被成功接收之前,保持为高,期间data应该保持不变,等待接收端接收数据。
当数据接收端检测到data_req为高,表示该时刻的信号data有效,保存数据,并拉高data_ack。
当数据发送端检测到data_ack,表示上一个发送的数据已经被接收。撤销data_req,然后可以改变数据data。等到下次发送时,再一次拉高data_req。
2.解题思路
2.1 两个部分一个接收端, 一个发送端。
2.2 两个部分的需求分析
2.3 开始 使用计时器 启动 发送部分的 data_req 信号。
2.4 信号需要延时两个周期。
3.解题代码
`timescale 1ns/1ns
module data_driver(input clk_a,input rst_n,input data_ack,output reg [3:0]data,output reg data_req);reg data_ack_r1, data_ack_r2;reg [2:0] cnt;always @ (posedge clk_a or negedge rst_n)if (!rst_n) begindata_ack_r1 <= 1'b0;data_ack_r2 <= 1'b0;endelsebegindata_ack_r1 <= data_ack;data_ack_r2 <= data_ack_r1;endalways @ (posedge clk_a or negedge rst_n)if (!rst_n) data <= 4'b0;else if(data_ack_r1 && !data_ack_r2)data <= data + 1'b1;elsedata <= data;always @ (posedge clk_a or negedge rst_n)if (!rst_n) cnt <= 1'b0;else if (data_ack_r1 && !data_ack_r2)cnt <= 1'b0;else if (data_req) //正在请求时不计数cnt <= cnt;else cnt <= cnt + 1'b1;always @ (posedge clk_a or negedge rst_n)if (!rst_n) data_req <= 1'b0;else if (cnt == 3'd4) data_req <= 1'b1;else if (data_ack_r1 && !data_ack_r2)data_req <= 1'b0;else data_req <= data_req;endmodulemodule data_receiver(input clk_b,input rst_n,output reg data_ack,input [3:0]data,input data_req);reg [3:0]data_in_reg;reg data_req_1, data_req_2;always @ (posedge clk_b or negedge rst_n)if (!rst_n) begindata_req_1 <= 1'b0;data_req_2 <= 1'b0;endelse begindata_req_1 <= data_req;data_req_2 <= data_req_1;endalways @ (posedge clk_b or negedge rst_n)if (!rst_n) begindata_ack <= 1'b0;data_in_reg <= 4'b0;endelse if (data_req_1 && !data_req_2) begindata_ack <= 1'b1;data_in_reg <= data;endelse begin data_ack <= 1'b0;data_in_reg <= data_in_reg; endendmodule
3. VL61 自动售卖机
1. 题目
请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。
电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时值不变。
- sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料;
- din表示投币输入,din=0表示未投币,din=1表示投币5元,din=2表示投币10元,不会出现din=3的情况;
- drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;
- change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。
接口电路图如下:
2.解题思路
2.1 首先 注意这个题有一点细节, 在买 B 饮料的时候, 可以存钱。(我去他的)。
2.1.1 在第一次 5 元 存入 , 第二次 5元 输出饮料。零钱清零。
2.1.2 在第一次 5元 存入 , 第二次 10元 输出饮料。 零钱输出 5 元。
2.1 信号延时 1 个周期输出。 (这是这个周期是 符合条件, 下一个 周期输出信号)。
3.解题代码
`timescale 1ns/1nsmodule sale(input clk ,input rst_n ,input sel ,//sel=0,5$dranks,sel=1,10&=$drinksinput [1:0] din ,//din=1,input 5$,din=2,input 10$output reg [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinksoutput reg change_out
);
reg money;always@(posedge clk or negedge rst_n)beginif(~rst_n)begindrinks_out <=0;change_out <=0;money <=0;endelsebeginif(sel == 1'b1)beginif(din == 2'd1)//题目没有说可以存钱啊!1begindrinks_out <=0;change_out <=1'd0; //连续输入两次5 元也可以money <=1;if(money)begindrinks_out <=2'd2;change_out <=1'd0;money <=0;endendelse if(din == 2'd2)begindrinks_out <=2'd2;change_out <=0;if(money)begindrinks_out <=2'd2;change_out <=1'd1;money <=0;endendelsebegindrinks_out <=0;change_out <=0;endendelse if(sel == 1'b0)beginif(din == 2'd1)begindrinks_out <=2'd1;change_out <=1'd0;endelse if(din == 2'd2)begindrinks_out <=2'd1;change_out <=1'd1;endelsebegindrinks_out <=0;change_out <=0;endendendendendmodule
4.VL62 序列发生器
1.题目:
编写一个模块,实现循环输出序列001011。
模块的接口信号图如下:
2. 解题思路
2.1 第一种设置 参数 flag 001011 直接左移 输出 flag[5 ].
2.2 设置标志位 对应输出。
2.3 注意信号延时一个 周期。
3.解题代码
`timescale 1ns/1nsmodule sequence_generator(input clk,input rst_n,output reg data);parameter s0 = 3'd0;
parameter s1 = 3'd1;
parameter s2 = 3'd2;
parameter s3 = 3'd3;
parameter s4 = 3'd4;
parameter s5 = 3'd5;
reg[2:0] flag;
//需要延后一个周期 与
always@(posedge clk or negedge rst_n)beginif(~rst_n)beginflag <= s0; endelsebegincase(flag)s0 : flag <=s1;s1 : flag <=s2;s2 : flag <=s3;s3 : flag <=s4;s4 : flag <=s5;s5 : flag <=s0;default:flag <=s0;endcaseendendalways@(posedge clk or negedge rst_n)beginif(~rst_n)begindata <=0;endelsebegincase (flag)s0: data <= 0;s1: data <= 0;s2: data <= 1;s3: data <= 0;s4: data <= 1;s5: data <= 1;endcaseendendendmodule