written by @hzj
//版本迭代//
# V1.0 2022.7.25
# V1.1 2022.7.27
# V1.2 2022.7.28
# V1.3 2022.8.1
# V1.4 2022.8.3
# V1.5 2022.8.8
前言
针对常用的代码(常用代码/面试常考察/基础代码)进行手撕训练,总共的实现代码总共将近20余个,将在一个月内更新完成,感兴趣的朋友可以及时关注下这篇博客,如果有任何的疑问,可以及时与我进行分享。
所有功能模块为了统一化,都将使用同一个工程名称“test”,包含src源文件以及tb测试文件,以及可能的RTL图
废话不多说,直接进入正题
1、序列检测器
(1)三段式状态机实现方式
功能:若检测序列00110,输出检测有效信号signal_en为1
- SRC:
module test(
input i_fpga_clk ,
input i_fpga_rst_n ,
input data_in ,
output reg signal_enable
);
//define state
localparam IDLE = 3'b000;
localparam S1 = 3'b001;
localparam S2 = 3'b010;
localparam S3 = 3'b011;
localparam S4 = 3'b100;
localparam S5 = 3'b101;
//three state
reg [2:0] current_state;
reg [2:0] next_state ;
reg [7:0] count ;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end
always @(*) begin
case(current_state)
IDLE:
if(data_in == 1'b0)
next_state <= S1;
else
next_state <= IDLE;
S1 :
if(data_in == 1'b0)
next_state <= S2;
else
next_state <= IDLE;
S2 :
if(data_in == 1'b1)
next_state <= S3;
else
next_state <= S2;
S3 :
if(data_in == 1'b1)
next_state <= S4;
else
next_state <= S1;
S4 :
if(data_in == 1'b0)
next_state <= S5;
else
next_state <= IDLE;
S5 :
if(data_in == 1'b0)
next_state <= S2;
else
next_state <= IDLE;
default:
next_state <= IDLE;
endcase
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
signal_enable <= 1'b0;
end
else if(current_state == S5)begin
signal_enable <= 1'b1;
end
else begin
signal_enable <= 1'b0;
end
end
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
reg clk_368 ;
reg rst_n_368 ;
initial
begin
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
reg data_in;
reg [7:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
data_in <= 'd0;
count <= 8'b00110001;
end
else begin
count <= {count[6:0], count[7]};
data_in <= count[7] ;
end
end
test module_test(
.i_fpga_clk (i_fpga_clk ) ,
.i_fpga_rst_n (i_fpga_rst_n ) ,
.data_in (data_in ) ,
.signal_enable(signal_enable)
);
endmodule
- 仿真结果:
- 电路:
(2)移位寄存器实现方式
- SRC:
module test(
input i_fpga_clk ,
input i_fpga_rst_n ,
input data_in ,
output reg signal_enable
);
//00110
reg [4:0] data_state;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
data_state <= 5'b00000;
end
else begin
data_state <= {data_state[3:0], data_in};
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
signal_enable <= 1'b0;
end
else if(data_state == 5'b00110)begin
signal_enable <= 1'b1;
end
else begin
signal_enable <= 1'b0;
end
end
endmodule
-
TB:
同1、序列检测器(三段式状态机实现方式)的TB代码 -
仿真结果:
-
电路:
2、序列生成器
功能:若检测序列00110,输出检测有效信号signal_en为1
(1)移位寄存器方式实现
- SRC:
module test(
input i_fpga_clk ,
input i_fpga_rst_n ,
output reg signal_out
);
reg [4:0] signal_register;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
signal_register <= 5'b11010 ;
end
else begin
signal_register <= {signal_register[3:0], signal_register[4]};
end
end
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
signal_out <= 1'b0 ;
end
else begin
signal_out <= signal_register[4];
end
end
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
reg clk_368 ;
reg rst_n_368 ;
initial
begin
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
wire signal_out;
test module_test(
.i_fpga_clk (i_fpga_clk ),
.i_fpga_rst_n(i_fpga_rst_n),
.signal_out (signal_out )
);
endmodule
-
仿真:
-
电路:
(2)计数器方式实现
- SRC:
module test(
input i_fpga_clk,
input i_fpga_rst_n,
output signal_out
);
//11010
reg [2:0] count;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
count <= 1'b0;
end
else if(count == 'd4)begin
count <= 'd0;
end
else begin
count <= count + 1'b1;
end
end
assign signal_out = ((!count[2])&(!count[1])&(!count[0])) | ((!count[2])&(!count[1])&(count[0])) | ((!count[2])&(count[1])&(count[0]));
endmodule
-
TB:
同2(1) -
仿真:
-
电路:
(3)三段式状态机方式实现
- SRC:
module test(
input i_fpga_clk,
input i_fpga_rst_n,
output reg signal_out
);
localparam IDLE = 3'b000;
localparam S1 = 3'b001;
localparam S2 = 3'b010;
localparam S3 = 3'b011;
localparam S4 = 3'b100;
reg [2:0] current_state;
reg [2:0] next_state ;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
IDLE:
next_state <= S1;
S1 :
next_state <= S2;
S2 :
next_state <= S3;
S3 :
next_state <= S4;
S4 :
next_state <= IDLE;
default:
next_state <= IDLE;
endcase
end
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
signal_out <= 1'b0;
end
else begin
case(current_state)
IDLE:
signal_out <= 1'b1;
S1 :
signal_out <= 1'b1;
S2 :
signal_out <= 1'b0;
S3 :
signal_out <= 1'b1;
S4 :
signal_out <= 1'b0;
default:
signal_out <= 1'b0;
endcase
end
end
endmodule
-
TB:
同2(1) -
仿真:
-
电路:
3、分频
(1)偶数分频
功能:实现4分频电路
- SRC:
module test(
input i_fpga_clk,
input i_fpga_rst_n,
output reg div
);
reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
count <= 2'b00;
end
else begin
count <= count + 2'b01;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
div <= 1'b0;
end
else if(count == 2'd1 || count == 2'd3)begin
div <= ~div;
end
else begin
div <= div;
end
end
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
reg clk_368 ;
reg rst_n_368 ;
initial
begin
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
wire div;
test module_test(
.i_fpga_clk (i_fpga_clk ),
.i_fpga_rst_n(i_fpga_rst_n),
.div (div )
);
endmodule
- 仿真:
- 电路:
(2)奇数分频
功能:实现奇数分频的三分频电路
①相与实现
- SRC:
module counter(
input i_fpga_clk ,
input i_fpga_rst_n ,
output div
);
reg wave_1;
reg wave_2;
reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
count <= 'd0;
end
else if(count == 2'd2)begin
count <= 'd0;
end
else begin
count <= count + 1'b1;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_1 <= 1'b0;
end
else if(count == 2'd2)begin
wave_1 <= 1'b0;
end
else begin
wave_1 <= 1'b1;
end
end
always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_2 <= 'd0;
end
else if(count == 2'd2)begin
wave_2 <= 1'b0;
end
else begin
wave_2 <= 1'b1;
end
end
assign div = wave_1 & wave_2;
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_complex_mult;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
wire div ;
counter module_counter(
.i_fpga_clk (i_fpga_clk ) ,
.i_fpga_rst_n(i_fpga_rst_n) ,
.div (div )
);
endmodule
-
仿真:
-
电路:
②相或实现
- SRC:
module counter(
input i_fpga_clk ,
input i_fpga_rst_n ,
output div
);
reg wave_1;
reg wave_2;
reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
count <= 'd0;
end
else if(count == 2'd2)begin
count <= 'd0;
end
else begin
count <= count + 1'b1;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_1 <= 1'b0;
end
else if(count == 2'd0)begin
wave_1 <= 1'b1;
end
else begin
wave_1 <= 1'b0;
end
end
always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_2 <= 'd0;
end
else if(count == 2'd0)begin
wave_2 <= 1'b1;
end
else begin
wave_2 <= 1'b0;
end
end
assign div = wave_1 | wave_2;
endmodule
-
TB:
同4(1) -
仿真:
-
电路:
③相异或实现
- SRC:
module counter(
input i_fpga_clk ,
input i_fpga_rst_n ,
output div
);
reg wave_1;
reg wave_2;
reg [1:0] count;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
count <= 'd0;
end
else if(count == 2'd2)begin
count <= 'd0;
end
else begin
count <= count + 1'b1;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_1 <= 1'b0;
end
else if(count == 2'd0)begin
wave_1 <= ~wave_1;
end
else begin
wave_1 <= wave_1;
end
end
always @(negedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'd0)begin
wave_2 <= 'd0;
end
else if(count == 2'd2)begin
wave_2 <= ~wave_2;
end
else begin
wave_2 <= wave_2;
end
end
assign div = wave_1 ^ wave_2;
endmodule
-
TB:
同4(1) -
仿真:
-
电路:
4、FIFO
(1)同步FIFO
*功能:实现深度大小为8,位宽大小为32的同步FIFO*
①采用地址技术的方式实现
- SRC:
module test#(
parameter DATA_DEPTH = 16,
parameter DATA_WIDTH = 16
)(
input i_fpga_clk ,
input i_fpga_rst_n ,
input wr_en ,
input [DATA_WIDTH-1:0] wr_data ,
input rd_en ,
output reg [DATA_DEPTH-1:0] rd_data ,
output full_signal ,
output empty_signal
);
reg [DATA_WIDTH-1:0] memory [DATA_DEPTH-1:0];//定义一个数组元素用作存储
function integer c2log(input [DATA_DEPTH-1:0] data_depth);
begin
for(c2log = 0; data_depth > 0 ;c2log = c2log + 1)begin
data_depth = data_depth >> 1;
end
end
endfunction
reg [c2log(DATA_DEPTH - 1)-1 :0] wr_addr;
reg [c2log(DATA_DEPTH - 1)-1 :0] rd_addr;
//wr_addr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
wr_addr <= 'd0;
end
else if(wr_en == 1'b1 && full_signal != 1'b1)begin
wr_addr <= wr_addr + 1'b1;
end
else begin
wr_addr <= wr_addr;
end
end
//rd_addr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
rd_addr <= 'd0;
end
else if(rd_en == 1'b1 && empty_signal != 1'b1)begin
rd_addr <= rd_addr + 1'b1;
end
else begin
rd_addr <= rd_addr;
end
end
//mem_wr
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
memory[wr_addr] <= 'd0;
end
else if(wr_en == 1'b1 && full_signal != 1'b1)begin
memory[wr_addr] <= wr_data;
end
else begin
memory[wr_addr] <= memory[wr_addr];
end
end
//mem_rd
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
rd_data <= 'd0;
end
else if(rd_en == 1'b1 && empty_signal != 1'b1)begin
rd_data <= memory[rd_addr];
end
else begin
rd_data <= rd_data;
end
end
//judege_empty_full
assign empty_signal = (wr_addr == rd_addr )? 1'd1: 1'd0;
assign full_signal = ((wr_addr[2:0]== rd_addr[2:0])&&(wr_addr[3] != rd_addr[3]))? 1'd1: 1'd0;
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
counter <= 'd0;
wr_en <= 'd0;
rd_en <= 'd0;
flag <= 'd0;
end
else if(counter == 'd7 && flag == 'd0)begin
flag <= 'd1;
wr_en <= 'd1;
end
else if(counter == 'd7 && flag == 'd1)begin
counter <= 'd0;
wr_en <= ~wr_en;
rd_en <= ~rd_en;
end
else begin
counter <= counter + 1'b1;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
wr_data <= 'd0;
end
else if(wr_data == 'd20)begin
wr_data <= 'd0;
end
else begin
wr_data <= wr_data + 1;
end
end
wire [15:0]rd_data;
test#(
.DATA_DEPTH(16),
.DATA_WIDTH(16)
)module_test(
.i_fpga_clk (i_fpga_clk ),
.i_fpga_rst_n (i_fpga_rst_n),
.wr_en (wr_en ),
.wr_data (wr_data ),
.rd_en (rd_en ),
.rd_data (rd_data ),
.full_signal (full_signal ),
.empty_signal (empty_signal)
);
endmodule
-
仿真:
-
电路:
②采用计数器计数的方式实现
- SRC:
module test#(
parameter DATA_WIDTH = 16,
parameter DATA_DEPTH = 8
)( //sync_fifo
input i_fpga_clk ,
input i_fpga_rst_n ,
input [DATA_WIDTH - 1 : 0] wr_data ,
input wr_en ,
output reg [DATA_WIDTH -1 : 0] rd_data ,
input rd_en ,
output full_signal ,
output empty_signal
);
//calculate the DEPTH bits
function integer c2log(input [DATA_DEPTH - 1: 0] data_depth);
begin
for(c2log = 0; data_depth >0 ; c2log = c2log + 1)begin
data_depth = data_depth >> 1;
end
end
endfunction
//define the dignal
reg [c2log(DATA_DEPTH-1) - 1 : 0] wr_addr ;
reg [c2log(DATA_DEPTH-1) - 1 : 0] rd_addr ;
reg [DATA_WIDTH - 1 : 0] mem [DATA_DEPTH-1 : 0];
//wr_addr
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
wr_addr <= 16'd0;
end
else if(wr_en == 1'b1 && full_signal == 1'b0)begin
wr_addr <= wr_addr + 1'b1;
end
end
//rd_addr
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
rd_addr <= 16'b0;
end
else if(empty_signal == 1'b0 && rd_en == 1'b1)begin
rd_addr <= rd_addr + 1'b1;
end
end
//wr_data
integer bit_width;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
for(bit_width = 0; bit_width < DATA_DEPTH; bit_width = bit_width + 1)begin
mem[bit_width] <= 32'd0;
end
end
else if(wr_en == 1'b1 && full_signal == 1'b0)begin
mem[wr_addr] <= wr_data;
end
end
//rd_data
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
rd_data <= 'd0;
end
else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
rd_data <= mem[rd_addr];
end
end
//count
reg [3:0] count;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
count <= 'd0;
end
else if(wr_en == 1'b1 && full_signal == 1'b0)begin
count <= count + 1'b1;
end
else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
count <= count - 1'b1;
end
else begin
count <= count;
end
end
assign full_signal = (count == 'd8 ? 1 : 0);
assign empty_signal = (count == 'd0 ? 1 : 0);
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
counter <= 'd0;
wr_en <= 'd0;
rd_en <= 'd0;
flag <= 'd0;
end
else if(counter == 'd7 && flag == 'd0)begin
flag <= 'd1;
wr_en <= 'd1;
end
else if(counter == 'd7 && flag == 'd1)begin
counter <= 'd0;
wr_en <= ~wr_en;
rd_en <= ~rd_en;
end
else begin
counter <= counter + 1'b1;
end
end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
wr_data <= 'd0;
end
else if(wr_data == 'd20)begin
wr_data <= 'd0;
end
else begin
wr_data <= wr_data + 1;
end
end
wire [15:0]rd_data;
test#(
.DATA_WIDTH(16),
.DATA_DEPTH( 8)
)module_test( //sync_fifo
.i_fpga_clk (i_fpga_clk ),
.i_fpga_rst_n (i_fpga_rst_n),
.wr_data (wr_data ),
.wr_en (wr_en ),
.rd_data (rd_data ),
.rd_en (rd_en ),
.full_signal (full_signal ),
.empty_signal (empty_signal)
);
endmodule
- 仿真:
- 电路:
(2)异步FIFO
功能:实现异步FIFO功能,具备gray码
- SRC:
module test#(
parameter DATA_WIDTH = 16,
parameter DATA_DEPTH = 8
)( //sync_fifo
input i_fpga_clk_wr ,
input i_fpga_rst_n_wr ,
input i_fpga_clk_rd ,
input i_fpga_rst_n_rd ,
input [DATA_WIDTH - 1 : 0] wr_data ,
input wr_en ,
output reg [DATA_WIDTH -1 : 0] rd_data ,
input rd_en ,
output full_signal ,
output empty_signal
);
//calculate the DEPTH bits
function integer c2log(input [DATA_DEPTH - 1: 0] data_depth);
begin
for(c2log = 0; data_depth >0 ; c2log = c2log + 1)begin
data_depth = data_depth >> 1;
end
end
endfunction
//define the dignal
reg [c2log(DATA_DEPTH-1) : 0] wr_ptr ;
wire[c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_0 ;
reg [c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_1 ;
reg [c2log(DATA_DEPTH-1) : 0] gray_wr_ptr_2 ;
reg [c2log(DATA_DEPTH-1) : 0] rd_ptr ;
wire[c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_0 ;
reg [c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_1 ;
reg [c2log(DATA_DEPTH-1) : 0] gray_rd_ptr_2 ;
reg [DATA_WIDTH - 1 : 0] mem [DATA_DEPTH-1 : 0];
//wr data
always @(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
if(i_fpga_rst_n_wr == 1'b0)begin
wr_ptr <= {(c2log(DATA_DEPTH)){1'b0}};
end
else if(wr_en == 1'b1 && full_signal == 1'b0)begin
wr_ptr <= wr_ptr + 1'b1;
end
end
//rd c2log
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
if(i_fpga_rst_n_rd == 1'b0)begin
rd_ptr <= {(c2log(DATA_DEPTH-1)){1'b0}};
end
else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
rd_ptr <= rd_ptr + 1'b1;
end
end
//gray generate
assign gray_wr_ptr_0 = wr_ptr ^ (wr_ptr >> 1);
assign gray_rd_ptr_0 = rd_ptr ^ (rd_ptr >> 1);
//CDC sync wr
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
if(i_fpga_rst_n_rd == 1'b0)begin
gray_wr_ptr_1 <= {(c2log(DATA_DEPTH-1)){1'b0}};
gray_wr_ptr_2 <= {(c2log(DATA_DEPTH-1)){1'b0}};
end
else begin
gray_wr_ptr_1 <= gray_wr_ptr_0;
gray_wr_ptr_2 <= gray_wr_ptr_1;
end
end
//CDC sync rd
always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
if(i_fpga_rst_n_wr == 1'b0)begin
gray_rd_ptr_1 <= {(c2log(DATA_DEPTH-1)){1'b0}};
gray_rd_ptr_2 <= {(c2log(DATA_DEPTH-1)){1'b0}};
end
else begin
gray_rd_ptr_1 <= gray_rd_ptr_0;
gray_rd_ptr_2 <= gray_rd_ptr_1;
end
end
//full_signal && empty signal
assign full_signal = (gray_wr_ptr_0 == {~gray_rd_ptr_2[c2log(DATA_DEPTH-1) : c2log(DATA_DEPTH-1) - 1], gray_rd_ptr_2[c2log(DATA_DEPTH-1)-2 : 0]} ? 1 : 0 );
assign empty_signal= (gray_rd_ptr_0 == gray_wr_ptr_2);
//addr generate
wire [c2log(DATA_DEPTH - 1) - 1 : 0]wr_addr;
wire [c2log(DATA_DEPTH - 1) - 1 : 0]rd_addr;
assign wr_addr = wr_ptr [c2log(DATA_DEPTH - 1) - 1 : 0];
assign rd_addr = rd_ptr [c2log(DATA_DEPTH - 1) - 1 : 0];
//wr_data
integer i;
always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
if(i_fpga_rst_n_wr == 1'b0)begin
for(i = 0 ; i < DATA_DEPTH ; i = i + 1)begin
mem[i] <= {DATA_DEPTH{1'b0}};
end
end
else if(wr_en == 1'b1 && full_signal == 1'b0)begin
mem[wr_addr] <= wr_data;
end
end
//rd_data
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
if(i_fpga_rst_n_rd == 1'b0)begin
rd_data <= {DATA_WIDTH{1'b0}};
end
else if(rd_en == 1'b1 && empty_signal == 1'b0)begin
rd_data <= mem[rd_addr];
end
end
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
initial
begin
forever #(PERIOD_245P76/2) clk_245 =~clk_245; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_wr = clk_368 ;
assign i_fpga_rst_n_wr = rst_n_368;
assign i_fpga_clk_rd = clk_245;
assign i_fpga_rst_n_rd = rst_n_245;
reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
counter <= 'd0;
wr_en <= 'd0;
flag <= 'd0;
end
else if(counter == 'd7 && flag == 'd0)begin
flag <= 'd1;
wr_en <= 'd1;
end
else if(counter == 'd7 && flag == 'd1)begin
//counter <= 'd0;
wr_en <= ~wr_en;
end
else if(counter == 'd15)begin
counter <= 'd0;
end
else begin
counter <= counter + 1'b1;
end
end
//reg flag_rd;
//reg [4:0] count_rd;
//always @(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd begin
// if(i_fpga_rst_n_rd == 1'b0)begin
// rd_en <= 'd0;
// flag_rd<= 'd0;
// end
// else if(count_rd == 'd && flag_rd== 'd0)begin
// flag_rd<= 'd1;
// end
// else if(count_rd == 'd7 && flag_rd== 'd1)begin
// rd_en <= ~rd_en;
// end
//end
always @(posedge i_fpga_clk or negedge i_fpga_rst_n) begin
if(i_fpga_rst_n == 1'b0)begin
wr_data <= 'd0;
end
else if(wr_data == 'd20)begin
wr_data <= 'd0;
end
else begin
wr_data <= wr_data + 1;
end
end
wire [15:0]rd_data;
reg [8:0]count_time;
always@(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd)begin
if(i_fpga_rst_n_rd == 1'b0)begin
count_time <= 'd0;
rd_en <= 'd1;
end
else if(count_time == 'd100)begin
rd_en <= 'd0;
end
else begin
count_time <= count_time + 1'b1;
rd_en <= rd_en;
end
end
test#(
.DATA_WIDTH(16),
.DATA_DEPTH( 8)
)test( //sync_fifo
.i_fpga_clk_wr (i_fpga_clk_wr ) ,
.i_fpga_rst_n_wr (i_fpga_rst_n_wr ) ,
.i_fpga_clk_rd (i_fpga_clk_rd ) ,
.i_fpga_rst_n_rd (i_fpga_rst_n_rd ) ,
.wr_data (wr_data ) ,
.wr_en (wr_en ) ,
.rd_data (rd_data) ,
.rd_en (rd_en ) ,
.full_signal (full_signal ) ,
.empty_signal(empty_signal)
);
endmodule
- 仿真:
- 电路:
5、单比特CDC
(1)单比特信号从慢时钟域->快时钟域
功能:单比特信号CDC(采用打两拍实现)
- SRC:
module test(
input i_fpga_clk_src ,//slow
input i_fpga_rst_n_src ,
input i_fpga_clk_des ,//fast
input i_fpga_rst_n_des ,
input i_pulse_in ,
output o_pulse_out
);
reg r_pluse_r1;
reg r_pluse_r2;
always @(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des) begin
if(i_fpga_rst_n_des == 1'b0)begin
r_pluse_r1 <= 1'b0;
r_pluse_r2 <= 1'b0;
end
else begin
r_pluse_r1 <= i_pulse_in;
r_pluse_r2 <= r_pluse_r1;
end
end
assign o_pulse_out = r_pluse_r2;
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
initial
begin
forever #(PERIOD_245P76/2) clk_245 =~clk_245; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_rd = clk_368 ;
assign i_fpga_rst_n_rd = rst_n_368;
assign i_fpga_clk_wr = clk_245;
assign i_fpga_rst_n_wr = rst_n_245;
reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always@(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr)begin
if(i_fpga_rst_n == 1'b0)begin
counter <= 'd0;
wr_en <= 1'b0;
end
else if(counter == 'd7 | counter == 'd8)begin
wr_en <= 1'b1;
counter <= counter + 1'b1;
end
else begin
wr_en <= 1'b0;
counter <= counter + 1'b1;
end
end
wire o_pulse_out;
test module_test(
.i_fpga_clk_src (i_fpga_clk_wr ),
.i_fpga_rst_n_src(i_fpga_rst_n_wr),
.i_fpga_clk_des (i_fpga_clk_rd ),
.i_fpga_rst_n_des(i_fpga_rst_n_rd),
.i_pulse_in (wr_en ),
.o_pulse_out (o_pulse_out)
);
endmodule
-
仿真:
-
电路:
(2)单比特信号从快时钟域->慢时钟域
功能:单位脉冲信号单比特信号从快时钟域->慢时钟域CDC
①一般实现方式
- SRC:
module test(
input i_fpga_clk_src ,
input i_fpga_rst_n_src ,
input i_fpga_clk_des ,
input i_fpga_rst_n_des ,
input i_pulse_in ,
output o_pulse_out
);
//define reg
reg req_signal;
reg req_signal_r1;
reg req_signal_r2;
reg ack_signal;
reg ack_signal_r1;
reg ack_signal_r2;
//req mamaegement
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
if(i_fpga_rst_n_src == 1'b0)begin
req_signal <= 1'b0;
end
else if(i_pulse_in == 1'b1)begin
req_signal <= 1'b1;
end
else if(ack_signal_r2 == 1'b1)begin
req_signal <= 1'b0;
end
else begin
req_signal <= req_signal;
end
end
//CDC req_signal
always@(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des)begin
if(i_fpga_rst_n_des == 1'b0)begin
req_signal_r1 <= 1'b0;
req_signal_r2 <= 1'b0;
end
else begin
req_signal_r1 <= req_signal ;
req_signal_r2 <= req_signal_r1;
ack_signal <= req_signal_r2;
end
end
//CDC ack_signal
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
if(i_fpga_rst_n_src == 1'b0)begin
ack_signal_r1 <= 1'b0;
ack_signal_r2 <= 1'b0;
end
else begin
ack_signal_r1 <= ack_signal ;
ack_signal_r2 <= ack_signal_r1;
end
end
//output signal generate
assign o_pulse_out = req_signal_r2 & ~ack_signal;
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
integer i;
integer j;
initial
begin
i <= 0;
j <= 0;
clk_368 <= 'd0 ;
rst_n_368 <= 'd0 ;
clk_245 <= 'd0 ;
rst_n_245 <= 'd0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
initial
begin
forever #(PERIOD_368P64/2) clk_368 =~clk_368; //clk_368的周期
end
initial
begin
forever #(PERIOD_245P76/2) clk_245 =~clk_245; //clk_368的周期
end
assign i_fpga_clk = clk_368 ;
assign i_fpga_rst_n = rst_n_368;
assign i_fpga_clk_wr = clk_368 ;
assign i_fpga_rst_n_wr = rst_n_368;
assign i_fpga_clk_rd = clk_245;
assign i_fpga_rst_n_rd = rst_n_245;
reg wr_en;
reg rd_en;
reg [15:0] wr_data;
reg [4:0 ] counter;
reg flag;
always@(posedge i_fpga_clk or negedge i_fpga_rst_n)begin
if(i_fpga_rst_n == 1'b0)begin
counter <= 'd0;
wr_en <= 1'b0;
end
else if(counter == 'd7 | counter == 'd8)begin
wr_en <= 1'b1;
counter <= counter + 1'b1;
end
else begin
wr_en <= 1'b0;
counter <= counter + 1'b1;
end
end
test module_test(
.i_fpga_clk_src (i_fpga_clk_wr ),
.i_fpga_rst_n_src(i_fpga_rst_n_wr),
.i_fpga_clk_des (i_fpga_clk_rd ),
.i_fpga_rst_n_des(i_fpga_rst_n_rd),
.i_pulse_in (wr_en) ,
. o_pulse_out ()
);
endmodule
- 仿真:
- 电路:
②脉冲较近校准(输出错误信息模式)
可以校准相邻较近的脉冲信号,若相邻太近输入,那么将会输出error
- SRC:
module test(
input i_fpga_clk_src ,
input i_fpga_rst_n_src ,
input i_fpga_clk_des ,
input i_fpga_rst_n_des ,
input i_pulse_in ,
output o_pulse_out
);
//define reg
reg req_signal;
reg req_signal_r1;
reg req_signal_r2;
reg ack_signal;
reg ack_signal_r1;
reg ack_signal_r2;
wire idle_state;
reg error_state;
//idle_state setting
assign idle_state = ~(req_signal | req_signal_r2);
//error state detect
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
if(i_fpga_rst_n_src == 1'b0)begin
error_state <= 1'b0;
end
else if(idle_state == 1'b1 & i_pulse_in == 1'b1)begin
error_state <= 1'b1;
end
else begin
error_state <= 1'b0;
end
end
//req mamaegement
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
if(i_fpga_rst_n_src == 1'b0)begin
req_signal <= 1'b0;
end
else if(i_pulse_in == 1'b1 && idle_state == 1'b1)begin
req_signal <= 1'b1;
end
else if(ack_signal_r2 == 1'b1)begin
req_signal <= 1'b0;
end
else begin
req_signal <= req_signal;
end
end
//CDC req_signal
always@(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des)begin
if(i_fpga_rst_n_des == 1'b0)begin
req_signal_r1 <= 1'b0;
req_signal_r2 <= 1'b0;
ack_signal <= 1'b0;
end
else begin
req_signal_r1 <= req_signal ;
req_signal_r2 <= req_signal_r1;
ack_signal <= req_signal_r2;
end
end
//CDC ack_signal
always@(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src)begin
if(i_fpga_rst_n_src == 1'b0)begin
ack_signal_r1 <= 1'b0;
ack_signal_r2 <= 1'b0;
end
else begin
ack_signal_r1 <= ack_signal ;
ack_signal_r2 <= ack_signal_r1;
end
end
//output signal generate
assign o_pulse_out = ack_signal_r1 & ~ack_signal_r2;
endmodule
-
TB:
同7(1) -
仿真:
-
电路:
6、时钟切换电路
功能:实现不同时钟的切换
(1)使用组合逻辑实现(不推荐)
有很多毛刺,后级时钟信号不安全,无法直接使用
- SRC:
module test(
input i_fpga_clk_frq1 ,
input i_fpga_clk_frq2 ,
input i_seletion ,
input i_fpga_rst ,
output o_fpga_clk
);
assign o_fpga_clk = i_seletion ? i_fpga_clk_frq1 : i_fpga_clk_frq2;
//no suggest to use
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_368P64 = 1000/368.64;
parameter PERIOD_245P76 = 1000/245.76;
//define
reg clk_368 ;
reg clk_245;
reg rst_n_368 ;
reg rst_n_245 ;
reg selection ;
//initial
initial
begin
clk_245 = 0 ;
clk_368 = 0 ;
rst_n_245 = 0 ;
rst_n_368 = 0 ;
selection = 0 ;
repeat(10) @ (posedge clk_368);
selection = 1 ;
repeat(30) @ (posedge clk_368);
selection = 0 ;
end
initial begin
#(PERIOD_368P64) rst_n_368 = 1'b1;
end
initial begin
#(PERIOD_245P76) rst_n_245 = 1'b1;
end
//clk generate
always #(PERIOD_368P64) clk_368 = ~clk_368;
always #(PERIOD_245P76) clk_245 = ~clk_245;
//module
wire o_fpga_clk;
test tb_test(
.i_fpga_clk_frq1(clk_368 ),
.i_fpga_clk_frq2(clk_245 ),
.i_seletion (selection),
.i_fpga_rst (rst_n_368),
.o_fpga_clk (o_fpga_clk)
);
endmodule
-
仿真:
-
电路:
(2)时钟切换电路(giltch_free同源)
- SRC:
module test(
input i_fpga_clk_frq1 ,
input i_fpga_clk_frq2 ,
input i_seletion ,
input i_fpga_rst ,
output o_fpga_clk
);
//define
reg enable_1;
reg enable_2;
//domain 1
always @(negedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_1 <= 1'b0;
end
else begin
enable_1 <= (~enable_2) & i_seletion;
end
end
//domain 2
always @(negedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_2 <= 1'b0;
end
else begin
enable_2 <= (~enable_1) & (~i_seletion);
end
end
//generate
assign o_fpga_clk = (enable_1 & i_fpga_clk_frq1) | (enable_2 & i_fpga_clk_frq2);
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_400 = 4000/400;
parameter PERIOD_200 = 4000/200;
//define
reg clk_400 ;
reg clk_200;
reg rst_n_400 ;
reg rst_n_200 ;
reg selection ;
//initial
initial
begin
clk_200 = 0 ;
clk_400 = 0 ;
rst_n_200 = 0 ;
rst_n_400 = 0 ;
selection = 0 ;
repeat(10) @ (posedge clk_400);
selection = 1 ;
repeat(30) @ (posedge clk_400);
selection = 0 ;
end
initial begin
#(PERIOD_400) rst_n_400 = 1'b1;
end
initial begin
#(PERIOD_200) rst_n_200 = 1'b1;
end
//clk generate
always #(PERIOD_400) clk_400 = ~clk_400;
always #(PERIOD_200) clk_200 = ~clk_200;
//module
wire o_fpga_clk;
test tb_test(
.i_fpga_clk_frq1(clk_400 ),
.i_fpga_clk_frq2(clk_200 ),
.i_seletion (selection),
.i_fpga_rst (rst_n_400),
.o_fpga_clk (o_fpga_clk)
);
endmodule
-
仿真:
-
电路:
(3)时钟切换电路(giltch_free异步)
- SRC:
module test(
input i_fpga_clk_frq1 ,
input i_fpga_clk_frq2 ,
input i_selection ,
input i_fpga_rst ,
output o_fpga_clk
);
//define
reg enable_1 ;
reg enable_1_r;
reg enable_2 ;
reg enable_2_r;
//domain 1
always @(posedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_1 <= 1'b0;
end
else begin
enable_1 <= (~enable_2_r) & i_selection ;
end
end
always @(negedge i_fpga_clk_frq1 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_1_r <= 1'b0 ;
end
else begin
enable_1_r <= enable_1 ;
end
end
//domain 2
always @(posedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_2 <= 1'b0;
end
else begin
enable_2 <= (~enable_1_r) & (~i_selection);
end
end
always @(negedge i_fpga_clk_frq2 or negedge i_fpga_rst) begin
if(i_fpga_rst == 1'b0)begin
enable_2_r <= 1'b0 ;
end
else begin
enable_2_r <= enable_2 ;
end
end
//generate
assign o_fpga_clk = (enable_1_r & i_fpga_clk_frq1) | (enable_2_r & i_fpga_clk_frq2);
endmodule
- TB:
`timescale 1ns / 1ps //1000M
module tb_test;
parameter PERIOD_400 = 4000/399;
parameter PERIOD_200 = 4000/200;
//define
reg clk_400 ;
reg clk_200;
reg rst_n_400 ;
reg rst_n_200 ;
reg selection ;
//initial
initial
begin
clk_200 = 0 ;
clk_400 = 0 ;
rst_n_200 = 0 ;
rst_n_400 = 0 ;
selection = 0 ;
repeat(10) @ (posedge clk_400);
selection = 1 ;
repeat(30) @ (posedge clk_400);
selection = 0 ;
end
initial begin
#(PERIOD_400) rst_n_400 = 1'b1;
end
initial begin
#(PERIOD_200) rst_n_200 = 1'b1;
end
//clk generate
always #(PERIOD_400) clk_400 = ~clk_400;
always #(PERIOD_200) clk_200 = ~clk_200;
//module
wire o_fpga_clk;
test tb_test(
.i_fpga_clk_frq1(clk_400 ),
.i_fpga_clk_frq2(clk_200 ),
.i_selection (selection),
.i_fpga_rst (rst_n_400),
.o_fpga_clk (o_fpga_clk)
);
endmodule
-
仿真:
-
电路:
7、
功能:
(1)\
- SRC:
- TB:
- 仿真:
- 电路:
8、
功能:
(1)\
- SRC:
- TB:
- 仿真:
- 电路: