1.
repeat
repeat(10)begin ...//执行10次 end
for
integer i ; initial begin for (i = 0 ; i < 8 ; i = i +1 ) begin $display(“ i = %0d”, i) ; end $finish ; end
initial begin fork begin repeat(10) begin task_A end end begin repeat(10) begin task_B end end join_any break end
2.
生成时钟 initial begin clk=1'b0; forever begin #period clk=~clk; end end
fork join 需要满足他们之间所有的语句执行完,在执行后面的语句;fork join_any 只要满足他们之间有一个语句执行完,就执行后面的语句;fork join_none 后面的语句执行与否不依赖于fork join_none内部的语句,他们可以同步执行
module test(); reg CS; reg SCLK; reg DI; initial begin SCLK=1'b0; CS=1'b1; DI=1'b0; always begin SCLK=1'b0; #tCL; SCLK=1'b1; #tCH; end fork # tCH+tCL-tSLCH CS =1'b0; # tCH+tCL-tDVCH DI=1'b1; # tCH+tCL-tDVCH+2*(tCH+tCL) DI=1'b0; # tCH+tCL-tDVCH+6*(tCH+tCL) DI=1'b1; # tCH+tCL-tDVCH+8*(tCH+tCL) DI=1'b0; # 8*(tCH+tCL)+tCHSH CS =1'b1; join end
endmodule
3.
因为 clk1 与 clk2 的频率比为 2,只需要在 clk2 时钟域延迟 2 拍即可。快时钟域的信号被延迟 2 拍,总会被慢时钟域采集到,
reg [1:0] signal_i_r ; always @(posedge clk1 or negedge rstn) begin if (!rstn) signal11_i_r <= 2'b0 ; else signal11_i_r <= {signal_i_r [0], signal_i } ; end reg signal_o_r ; always @(posedge clk2 or negedge rstn) begin if (!rstn) signal_o_r <= 1'b0 ; else signal_o_r <= |signal_i_r ; end assign signal_o = signal_o_r ;
#展宽信号来替代pulse_a实现垮时钟域的握手。先把脉冲信号在clk_a下展宽,变成足够宽的电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。
module Sync_Pulse ( clk_a, clk_b, rst_n, pulse_a_in, pulse_b_out, b_out ); /****************************************************/ input clk_a; input clk_b; input rst_n; input pulse_a; output pulse_b_out; output b_out; /****************************************************/ reg signal_a; reg signal_b; reg signal_b_r1; reg signal_b_r2; reg signal_b_a1; reg signal_b_a2; /****************************************************/ //在时钟域clk_a下,生成展宽信号signal_a always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0) signal_a <= 1'b0; else if (pulse_a_in) //检测到到输入信号pulse_a_in被拉高,则拉高signal_a signal_a <= 1'b1; else if (signal_b_a2) //检测到signal_b1_a2被拉高,则拉低signal_a signal_a <= 1'b0; else; end //在时钟域clk_b下,采集signal_a,生成signal_b always @ (posedge clk_b or negedge rst_n) begin if (rst_n == 1'b0) signal_b <= 1'b0; else signal_b <= signal_a; end //多级触发器处理 always @ (posedge clk_b or negedge rst_n) begin if (rst_n == 1'b0) begin signal_b_r1 <= 1'b0; signal_b_r2 <= 1'b0; end else begin signal_b_r1 <= signal_b; //对signal_b打两拍 signal_b_r2 <= signal_b_r1; end end //在时钟域clk_a下,采集signal_b_r1,用于反馈来拉低展宽信号signal_a always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0) begin signal_b_a1 <= 1'b0; signal_b_a2 <= 1'b0; end else begin signal_b_a1 <= signal_b_r1; //对signal_b_r1打两拍,因为同样涉及到跨时钟域 signal_b_a2 <= signal_b_a1; end end assign pulse_b_out = signal_b_r1 & (~signal_b_r2); assign b_out = signal_b_r1; endmodule
4.
5.
(1)写出真值表 ,逻辑表达式 Y=A'B'C'+ABC+AC'
6.
占空比50%的任意整数分频 module divider( input clk, input rst_n, input [2:0] divider_num, output out_clk ); //奇数分频 reg sig_r ;//定义一个上升沿翻转的信号 reg sig_f ;//定义一个下降沿翻转的信号 reg [2:0] cnt_r;//上升沿计数器 reg [2:0] cnt_f;//下降沿计数器 wire clk_f ; assign divider_num= N ; assign clk_f = ~clk ;//用来触发下降沿计数器的时钟 //由于同时使用上升沿和下降沿触发器不好,因此我们为同一边沿,都使用上升沿触发 //只不过是将时钟进行反向 always @(posedge clk or negedge rst_n)begin//上升沿计数 if(rst_n == 1'b0)begin sig_r <= 0 ; cnt_r <= 0 ; end else begin cnt_r <= cnt_r + 1 ; if( cnt_r == (N-1)/2 )begin sig_r <= ~sig_r ; end else if ( cnt_r == (N-1) )begin sig_r <= ~sig_r ; cnt_r <= 0 ; end end end always @(posedge clk_f or negedge rst_n)begin//下降沿计数 if(rst_n == 1'b0)begin sig_f <= 0 ; cnt_f <= 0 ; end else begin cnt_f <= cnt_f + 1 ; if( cnt_f == (N-1)/2 )begin sig_f <= ~sig_f ; end else if ( cnt_f == (N-1) )begin sig_f <= ~sig_f ; cnt_f <= 0 ; end end end //偶数分频 reg div_reg ; reg [2:0] div_cnt ;//分频计数器 always @(posedge clk or negedge rst_n)begin if (rst_n == 1'b0 )begin div_cnt <= 0 ; div_reg <= 0 ; end else begin div_cnt <= div_cnt + 1'b1 ; if(div_cnt == (N/2 - 1))begin div_cnt <= 0; div_reg <= ~div_reg ; end end end assign out_clk = (N == 1)?clk : ( N%2 == 1)?(sig_f || sig_r ): div_reg; //这里用来输出分频值。对2的取余操作是综合的 endmodule
7.