目录
一、单bit信号
慢时钟域→快时钟域
电平同步器
适用于单比特位的控制信号或者进行格雷码编码的连续变化的数据信号。
跨时钟域处理(打两拍)
接收的信号若与所设计模块处于不同时钟域下,即该是异步信号。为防止数据不稳定,需要在本模块clk下打 2 拍,从而同步时钟域。
module data_dff(
input clk ,
input rst_n ,
input data_in ,
output data_out );
//reg define
reg data_in1;
reg data_in2;
//*********main code**********
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
data_in1 <= 1'b0;
data_in2 <= 1'b0;
end else begin
data_in1 <= data_in;
data_in2 <= data_in1;
end
end
assign data_out = data_in2;
endmodule
快时钟域→慢时钟域
脉冲同步,脉冲展宽(单bit,快→慢)
校招Verilog——单bit跨时钟域(脉冲展宽法-握手法)
从某个时钟域取出一个脉冲,然后在新的时钟域中建立另一个单时钟宽度的脉冲。
二、多bit信号
异步 FIFO
数据信号不存在依次变化的特性,格雷码对此类数据无效,因此采用异步FIFO、握手协议或者用使能信号控制这样的方式来进行数据的传输。
三、复位和时钟切换
复位信号同步器
通常在对时序电路进行复位时建议使用异步复位,但是异步复位会带来亚稳态的问题,通过异步复位同步释放模块可以改善这个问题
时钟切换
时钟切换要防止出现毛刺。
Testbench
数据生成模块
数据生成模块常用于测试,写一个输出:写使能、0~254写数据的数据生成模块
module data_gen(
input clk ,
input rst_n ,
output reg wr_en ,
output reg [7:0] wr_data );
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
wr_en <= 1'b0;
end else begin
wr_en <= 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
wr_data <= 8'd0;
end else if(wr_en==1'b1 && (wr_data <= 8'd254))begin
wr_data <= wr_data + 8'd1;
end else begin
wr_data <= 8'd0; //wr_data <= wr_data;
end
end
endmodule
边沿检测
- 脉冲边沿检测原理
脉冲边沿的特性:两侧电平发生了变化。
若检测的是下降沿,那就是高电平变低电平。
若检测的是上升沿,那就是低电平变高电平。
若检测脉冲边沿,只需将前后进来的信号做异或运算,即两个电平不相同则是发生边沿。
- 思路:
设计寄存器用来接收被检测的信号;若{先进reg,后进reg}=2’b10,则是下降沿;
若{先进reg,后进reg}=2’b01,则为上升沿。
注:使用多个寄存器可以更好的检测边沿,防止干扰脉冲。具体看下例:
posedge、negedge、anyedge
`timescale 1ns/10ps
module edge_detect(
input clk,
input rst_n,
input data_in,
output posedge_det,
output negedge_det,
output anyedge_det
);
reg [1:0] data_in_r;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_in_r <= 2'b0;
end else begin
data_in_r <= {data_in_r[0], data_in};
end
end
assign posedge_det = data_in_r[0] & ~data_in_r[1];
assign negedge_det = ~data_in_r[0] & data_in_r[1];
assign anyedge_det = posedge_det ^ negedge_det;
endmodule
- testbench
`timescale 1ns/10ps
module edge_detect_tb();
reg clk;
reg rst_n;
reg data_in;
wire posedge_det;
wire negedge_det;
wire anyedge_det;
initial begin
clk = 0;
rst_n = 0;
data_in = 0;
#15
rst_n = 1;
#15
data_in <= 1'b1;
#20
data_in <= 1'b1;
#20
data_in <= 1'b0;
#20
data_in <= 1'b0;
#20
data_in <= 1'b1;
#20
data_in <= 1'b1;
#100
$stop();
end
always #10 clk= ~clk;
edge_detect u_edge_detect(
.clk (clk ),
.rst_n (rst_n ),
.data_in (data_in ),
.posedge_det (posedge_det),
.negedge_det (negedge_det),
.anyedge_det (anyedge_det)
);
endmodule
- 结果