Verilog经典题

编程入门 行业动态 更新时间:2024-10-09 07:25:40

Verilog<a href=https://www.elefans.com/category/jswz/34/1769979.html style=经典题"/>

Verilog经典题


目录

    • 1.快时钟到慢时钟 检测单时钟脉冲信号
      • 1.2 带有握手信号的脉冲同步
    • 2. 异步复位同步释放
    • 3.握手信号跨时钟域
    • 4.小数分频
    • 5 状态机
      • 5.1 售货机


1.快时钟到慢时钟 检测单时钟脉冲信号

sig_a 是 clka(300M)时钟域的一个单时钟脉冲信号(高电平持续一个时钟clka周期),请设计脉冲同步电路,将sig_a信号同步到时钟域 clkb(100M)中,产生sig_b单时钟脉冲信号(高电平持续一个时钟clkb周期)输出。请用 Verilog 代码描述。
clka时钟域脉冲之间的间隔很大,无需考虑脉冲间隔太小的问题

不考虑间隔的问题,将源时钟域的脉冲信号转换成电平信号。对同步的信号判断,上升沿。

  1 //2 module pulse_detect(3   output sig_b,4   input  clka, //fast 300M5   input  clkb, //slow 100M6   input  rst_n,7   input  sig_a);8 9 reg [2:0] sig_b_reg;10 reg sig_a_reg;11 12 always@(posedge clka or negedge rst_n) begin13   if(!rst_n)14     sig_a_reg <= 0;15   else if(sig_a)16     sig_a_reg <= ~sig_a_reg;17 end18 19 always@(posedge clkb or negedge rst_n) begin20   if(!rst_n)21     sig_b_reg <= 3'b000;22   else23     sig_b_reg <= {sig_b_reg[1:0],sig_a_reg};24 end25 26 assign sig_b = ^sig_b_reg[2:1];27 endmodule

tb:

  1 //`timescale 100ps/100ps2 module tb;3 4 reg clka,clkb,rst_n,sig_a;5 wire sig_b;6 7 pulse_detect dut(.clka(clka),8                  .clkb(clkb),9                  .rst_n(rst_n),10                  .sig_a(sig_a),11                  .sig_b(sig_b));12 13 initial begin14   clka = 0;15   forever begin16     #1.6ns clka = ~clka;17   end18 end19 initial begin20   clkb = 0;21   forever begin22     #5ns clkb = ~clkb;23   end24 end25 26 initial begin27   rst_n = 0;28   sig_a = 0;29 30   #10ns31   rst_n = 1;32   sig_a = 1;33   #3.2ns34   sig_a = 0;35   #200ns36   $stop();37 end38 39 initial begin40  // $fsdbDumpfile("pulse_detect.fsdb");41  // $fsdbDumpvars;42  $vcdpluson;43 end44 45 46 47 48 endmodule : tb
~                                                                                                                                                                                                                                                             
~                             

波形

1.2 带有握手信号的脉冲同步

如果两个脉冲的间隔短,会丢失信号。需要使用握手信号确保。[refer]

module HANDSHAKE_PULSE_SYNC(src_clk , //source clock src_rst_n , //source clock reset (0: reset)src_pulse , //source clock pulse insrc_sync_fail , //source clock sync state: 1 clock pulse if sync fail.dst_clk , //destination clock dst_rst_n , //destination clock reset (0:reset)dst_pulse //destination pulse out);
//PARA DECLARATION
//INPUT DECLARATION
input src_clk ; //source clock 
input src_rst_n ; //source clock reset (0: reset)
input src_pulse ; //source clock pulse in
input dst_clk ; //destination clock 
input dst_rst_n ; //destination clock reset (0:reset)
//OUTPUT DECLARATION
output src_sync_fail ; //source clock sync state: 1 clock pulse if sync fail.
output dst_pulse ; //destination pulse out
//INTER DECLARATION
wire dst_pulse ;
wire src_sync_idle ;
reg src_sync_fail ;
reg src_sync_req ;
reg src_sync_ack ;
reg ack_state_dly1 ;
reg ack_state_dly2 ;
reg req_state_dly1 ;
reg req_state_dly2 ;
reg dst_req_state ;
reg dst_sync_ack ;
//--========================MODULE SOURCE CODE==========================--
//--=========================================--
// DST Clock :
// 1. generate src_sync_fail; 
// 2. generate sync req 
// 3. sync dst_sync_ack
//--=========================================--
assign src_sync_idle = ~(src_sync_req | src_sync_ack );
//report an error if src_pulse when sync busy ;
always @(posedge src_clk or negedge src_rst_n)
beginif(src_rst_n == 1'b0)src_sync_fail <= 1'b0 ;else if (src_pulse & (~src_sync_idle)) src_sync_fail <= 1'b1 ;elsesrc_sync_fail <= 1'b0 ;
end
//set sync req if src_pulse when sync idle ;
always @(posedge src_clk or negedge src_rst_n)
beginif(src_rst_n == 1'b0)src_sync_req <= 1'b0 ;else if (src_pulse & src_sync_idle) src_sync_req <= 1'b1 ;else if (src_sync_ack)src_sync_req <= 1'b0 ;
end
always @(posedge src_clk or negedge src_rst_n)
beginif(src_rst_n == 1'b0)beginack_state_dly1 <= 1'b0 ;ack_state_dly2 <= 1'b0 ;src_sync_ack <= 1'b0 ; endelsebeginack_state_dly1 <= dst_sync_ack ;ack_state_dly2 <= ack_state_dly1 ;src_sync_ack <= ack_state_dly2 ; end 
end
//--=========================================--
// DST Clock :
// 1. sync src sync req 
// 2. generate dst pulse
// 3. generate sync ack
//--=========================================--
always @(posedge dst_clk or negedge dst_rst_n)
beginif(dst_rst_n == 1'b0)beginreq_state_dly1 <= 1'b0 ;req_state_dly2 <= 1'b0 ;dst_req_state <= 1'b0 ;endelsebeginreq_state_dly1 <= src_sync_req ;req_state_dly2 <= req_state_dly1 ;dst_req_state <= req_state_dly2 ;end
end
//Rising Edge of dst_state generate a dst_pulse;
assign dst_pulse = (~dst_req_state) & req_state_dly2 ; 
//set sync ack when src_req = 1 , clear it when src_req = 0 ;
always @(posedge dst_clk or negedge dst_rst_n)
beginif(dst_rst_n == 1'b0)dst_sync_ack <= 1'b0;else if (req_state_dly2) dst_sync_ack <= 1'b1;else dst_sync_ack <= 1'b0;
end
endmodule

2. 异步复位同步释放

使用异步复位同步释放来将输入数据a存储到寄存器中

module reset_release(
input clk,
input rst_n,
input d,
output reg dout);reg [1:0] rst_reg;//two level reg to syn rst_n=1always@(posedge clk or negedge rst_n) beginif(!rst_n)rst_reg <= 2'b0;elserst_reg <= {rst_reg[0],1'b1};endalways@(posedge clk or negedge rst_reg[1]) beginif(!rst_reg[1])dout <= 1'b0;elsedout <= d;endendmodule
module tb;
reg  clk,rst_n,d;
wire dout;reset_release dut(.clk(clk),.rst_n(rst_n),.d(d),.dout(dout));initial beginclk = 0;forever begin#5clk = ~clk;endendinitial beginrst_n = 0;#8rst_n = 1;#200$stop();endinitial begind = 0;#10 d = 1;#10 d = 0;#15 d = 1;endendmodule : tb

3.握手信号跨时钟域

module data_driver(input clk_a,input rst_n,input data_ack,output reg [3:0]data,output reg data_req);reg [2:0] ack_reg;reg [2:0] count;//跨时钟域,此处打三拍避免亚稳态always@(posedge clk_a or negedge rst_n) beginif(!rst_n)ack_reg <= 3'b0;elseack_reg <= {ack_reg[1:0],data_ack};end//ack上升沿assign ack_posedge = !ack_reg[2] && ack_reg[1];always@(posedge clk_a or negedge rst_n) beginif(!rst_n)count <= 3'b0;else if(ack_posedge)count <= 3'b0;elsecount <= count + 1'b1;endalways@(posedge clk_a or negedge rst_n) beginif(!rst_n) begindata <= 3'b000;data_req <= 1'b0;endelse if(count == 3'b100)data_req <= 1'b1;else if(ack_posedge) begindata_req <= 1'b0;data <= data + 1'b1;endend
endmodulemodule data_receiver(input clk_b,input rst_n,input data_req,input [3:0] data,output reg data_ack);reg [3:0] data_reg;reg [2:0] req_reg;always@(posedge clk_b or negedge rst_n) beginif(!rst_n)req_reg <= 3'b0;elsereq_reg <= {req_reg[1:0],data_req};end//req上升沿assign req_posedge = !req_reg[2] && req_reg[1];always@(posedge clk_b or negedge rst_n) beginif(!rst_n) begindata_ack <= 1'b0;endelse if(req_reg[1]) begindata_ack <= 1'b1;elsedata_ack <= 1'b0;endendalways@(posedge clk_b or negedge rst_n) beginif(!rst_n) begindata_reg <= 4'b0;endelse if(req_posedge) begindata_reg <= data;endend  
endmodule

tb:

reg clk_a,clk_b;
reg rst_n;data_driver dut_drv(.clk_a(clk_a),.rst_n(rst_n),.data_ack(data_ack),.data(data),.data_req(data_req));
data_receiver dut_rec(.clk_b(clk_b),.rst_n(rst_n),.data_ack(data_ack),.data(data),.data_req(data_req));initial beginclk_a = 0;forever begin#5ns clk_a = ~clk_a;end
endinitial beginclk_b = 0;forever begin#10ns clk_b = ~clk_b;end
endinitial beginrst_n = 0;#20nsrst_n = 1;#1us$stop();
end
endmodule : tb

4.小数分频

牛客
描述

请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号

注意rst为低电平复位

提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
信号示意图:

8.7分频,即周期扩大8.7倍。原来87个周期,现在10个周期。
则 x+y = 10
Mx+Ny = 87
题目所给M = 8 N = 9 ,所以可以由三个8分频的时钟和七个9分频的时钟组合而成。
设置一个div_flag,在计数27 87翻转,完成时钟的切换。


module div_M_N(input  wire clk_in,input  wire rst,output wire clk_out
);
parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
reg div_flag;
reg [6:0] clk_cnt;
reg [3:0] cnt;
reg clk_out_r;
always@(posedge clk_in or negedge rst) beginif(!rst) div_flag <= 'b0;else div_flag <= (clk_cnt== c89-1 || clk_cnt==M_N-1)? ~div_flag : div_flag;
end
always@(posedge clk_in or negedge rst) beginif(!rst)cnt <= 'b0;else if(!div_flag)cnt <= (cnt == div_e - 1?  0 : cnt + 1);else cnt <= (cnt == div_o - 1?  0 : cnt + 1);
endalways@(posedge clk_in or negedge rst) beginif(!rst)clk_cnt <= 'b0;else clk_cnt <= (clk_cnt == M_N-1) ? 'b0 : clk_cnt+1;
end
always@(posedge clk_in or negedge rst) beginif(!rst)clk_out_r <= 'b0;else if(!div_flag)clk_out_r <= cnt<=(div_e>>1-1);else clk_out_r <= cnt<=(div_o>>1-1);
end
assign clk_out = clk_out_r;
//*************code***********//
endmodule

5 状态机

5.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元,输出有效仅保持一个时钟周期。
接口电路图如下:

使用Mealy型描述,所需要的状态数目会少很多,相对本题来说。

`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   
);
parameter IDLE = 'd0;
parameter S0   = 'd1;
reg n_state,c_state;
wire [2:0] inp;
assign inp = {sel,din};
always@(posedge clk or negedge rst_n) beginif(!rst_n)c_state <= IDLE;else c_state <= n_state;
end
always@(*)
case (c_state)IDLE : n_state = (inp=='b101) ? S0 : IDLE;S0   : n_state = (din=='b0) ? S0 : IDLE;default:n_state = IDLE;
endcase always@(posedge clk or negedge rst_n) beginif(!rst_n){drinks_out,change_out} <= 'b00;else beginif(c_state== S0) beginif(inp=='b101){drinks_out,change_out} <= 'b100;else if(inp == 'b110) {drinks_out,change_out} <= 'b101;else {drinks_out,change_out} <= 'b0;end else beginif(inp=='b001){drinks_out,change_out} <= 'b010;else if(inp == 'b010){drinks_out,change_out} <= 'b011;else if(inp == 'b110){drinks_out,change_out} <= 'b100;else {drinks_out,change_out} <= 'b0;endendendendmodule

更多推荐

Verilog经典题

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

发布评论

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

>www.elefans.com

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