module counter( input clk, input rst_n, output reg[7:0] data_out ); //reg define reg [3:0] cnt; //假设计数器每计数十次,溢满一次 reg [2:0] lsm_cnt; //计数器每溢满一次,lsm_cnt寄存器自加1 //parameter [7:0] num = 8'b10110101;此句和下面两句功能等效 wire [7:0] num; //定义一个八位数据 assign num = 8'b10110101; initial data_out <= 8'b0000_0000; //如果此处没有给初值,那么在仿真中不知道每一位是0还是1,data_out的值将呈现高阻态为8‘dX, //只有后面case语句执行8次将寄存器的每一位都写入值后,仿真中data_out才有值显示出来 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 4'd0; else if(cnt < 9) //如果是发送数据则需要一个标志位去启动计数器开始计数 cnt <= cnt + 1'b1; else cnt <= 4'd0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) lsm_cnt <= 3'd0; else if(cnt == 9) lsm_cnt <= lsm_cnt + 1'b1; else lsm_cnt <= lsm_cnt; end always@(posedge clk )begin if(cnt == 1) //注意此处的作用是为了防止系统在空闲状态下还继续进行发送数据 case(lsm_cnt) 0: data_out[0] <= num[0]; 1: data_out[1] <= num[1]; 2: data_out[2] <= num[2]; 3: data_out[3] <= num[3]; 4: data_out[4] <= num[4]; 5: data_out[5] <= num[5]; 6: data_out[6] <= num[6]; 7: data_out[7] <= num[7]; default : data_out <= 8'd0; endcase // else // data_out <= data_out; end endmodule
仿真代码:
`timescale 1ns/1ps module counter_tb; reg sys_clk; reg sys_rst_n; wire [7:0] data_out; //例化 counter u_counter( .clk(sys_clk), .rst_n(sys_rst_n), .data_out(data_out) ); initial begin sys_clk = 1'b1; sys_rst_n = 1'b0; #100; sys_rst_n = 1'b1; #900 $stop; end always #10 sys_clk = ~sys_clk; endmodule
非阻塞(non-blocking)赋值方式 ( b<= a): b的值被赋成新值a的操作, 并不是立刻完成的,而是在单个块结束时才完成; 块内的多条赋值语句在单个块结束时同时赋值; 硬件有对应的电路。
阻塞(blocking)赋值方式 ( b = a): b的值立刻被赋成新值a; 完成该赋值语句后才能执行下一句的操作; 硬件没有对应的电路,因而综合结果未知。
这里还要特别注意是‘“块内的多条赋值语句在块结束时同时赋值”不能考虑成这个时钟周期末尾到下个时钟上升沿完成赋值,因为always块语句的执行时间很短,要不了一个时钟周期的时间,即真是的赋值是在当前的时钟上升沿延迟一点点时间就完成了新的赋值操作(即时序仿真)。结合程序这就解释了,lsm_cnt和data_out寄存器中的值更新为什么延迟了cnt寄存器一个时钟周期;而cnt寄存器的并未延时一个时钟周期才改变(实际上cnt的值在上升沿到来后,延迟了一点时间就更新了,所以门级仿真就等效在当前上升沿变化了)。
在不同always块里对同一个寄存器进行赋值是不被允许的,会发生数据竞争。
如果在一个always块中调用另一个always块中的寄存器的某个值作为该always块的判断条件时,则该always块的仿真时序图会延迟一个时钟周期才发生变化。代码如下:
always@(posedge clk or negedge rst_n)begin if(!rst_n) lsm_cnt <= 3'd0; else if(cnt == 9) lsm_cnt <= lsm_cnt + 1'b1; else lsm_cnt <= lsm_cnt; end
lsm_寄存器既可以用于数据发送时,发送到第几位的依据标志;也可以用于序列机产生时钟分频时,分频时钟的高低电平变化的依据标志。
来源:https://www.cnblogs.com/liujiahong/p/12538538.html