目錄
- 前言
- 1、序列檢測器
- (1)三段式狀態機實現方式
- (2)移位寄存器實現方式
- 2、序列生成器
- (1)移位寄存器方式實現
- (2)計數器方式實現
- (3)三段式狀態機方式實現
- 3、分頻
- 4、FIFO
- (1)同步FIFO
- ①采用地址技術的方式實現
- ②采用計數器計數的方式實現
- (2)異步FIFO
- 5、單比特CDC
- (1)單比特信號從慢時鐘域->快時鐘域
- (2)單比特信號從快時鐘域->慢時鐘域
- 6、時鐘切換電路
- (1)使用組合邏輯實現(不推薦)
- (2)時鐘切換電路(giltch_free同源)
- (3)時鐘切換電路(giltch_free異步)
- 7、
- 8、
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
module
test(input i_fpga_clk
,input i_fpga_rst_n
,input data_in
,output reg signal_enable
);
localparam
IDLE = 3'b000
;
localparam
S1 = 3'b001
;
localparam
S2 = 3'b010
;
localparam
S3 = 3'b011
;
localparam
S4 = 3'b100
;
localparam
S5 = 3'b101
;
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
)begincurrent_state
<= IDLE;end
else begincurrent_state
<= next_state
;end
endalways @
(*) 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;elsenext_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
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginsignal_enable
<= 1'b0
;end
else if(current_state
== S5)beginsignal_enable
<= 1'b1
;end
else beginsignal_enable
<= 1'b0
;end
endendmodule
`timescale 1ns
/ 1ps module tb_test
;parameter
PERIOD_368P64 = 1000/368.64;reg clk_368
;
reg rst_n_368
;initial
beginclk_368
<= 'd0
;rst_n_368
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endassign 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
)begindata_in
<= 'd0
;count
<= 8'b00110001
;end
else begincount
<= {count
[6:0], count
[7]};data_in
<= count
[7] ;end
endtest
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)移位寄存器實現方式
module
test(input i_fpga_clk
,input i_fpga_rst_n
,input data_in
,output reg signal_enable
);reg
[4:0] data_state
;always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)begindata_state
<= 5'b00000
;end
else begindata_state
<= {data_state
[3:0], data_in
};end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginsignal_enable
<= 1'b0
;end
else if(data_state
== 5'b00110
)beginsignal_enable
<= 1'b1
;end
else beginsignal_enable
<= 1'b0
;end
endendmodule
2、序列生成器
功能:若檢測序列00110,輸出檢測有效信號signal_en為1
(1)移位寄存器方式實現
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
)beginsignal_register
<= 5'b11010
; end
else beginsignal_register
<= {signal_register
[3:0], signal_register
[4]};endendalways@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)beginsignal_out
<= 1'b0
;end
else beginsignal_out
<= signal_register
[4];end
endendmodule
`timescale 1ns
/ 1ps module tb_test
;parameter
PERIOD_368P64 = 1000/368.64;reg clk_368
;
reg rst_n_368
;initial
beginclk_368
<= 'd0
;rst_n_368
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endassign 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)計數器方式實現
module
test(input i_fpga_clk
,input i_fpga_rst_n
,output signal_out
);
reg
[2:0] count
;
always@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)begincount
<= 1'b0
;end
else if(count
== 'd4
)begincount
<= 'd0
;end
else begincount
<= count
+ 1'b1
;end
endassign signal_out
= ((!count
[2])&(!count
[1])&(!count
[0])) | ((!count
[2])&(!count
[1])&(count
[0])) | ((!count
[2])&(count
[1])&(count
[0]));endmodule
(3)三段式狀態機方式實現
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
)begincurrent_state
<= IDLE;end
else begincurrent_state
<= next_state
;end
endalways@
(*)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
endalways@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)beginsignal_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
; endcaseend
endendmodule
3、分頻
(1)偶數分頻
功能:實現4分頻電路
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
)begincount
<= 2'b00
;end
else begincount
<= count
+ 2'b01
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)begindiv
<= 1'b0
;end
else if(count
== 2'd1 || count == 2'd3
)begindiv
<= ~div
;end
else begindiv
<= div
;end
endendmodule
`timescale 1ns
/ 1ps module tb_test
;parameter
PERIOD_368P64 = 1000/368.64;reg clk_368
;
reg rst_n_368
;initial
beginclk_368
<= 'd0
;rst_n_368
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endassign 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)奇數分頻
功能:實現奇數分頻的三分頻電路
①相與實現
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
)begincount
<= 'd0
;end
else if(count
== 2'd2
)begincount
<= 'd0
;end
else begincount
<= count
+ 1'b1
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_1
<= 1'b0
;end
else if(count
== 2'd2
)beginwave_1
<= 1'b0
;end
else beginwave_1
<= 1'b1
;end
endalways @
(negedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_2
<= 'd0
;end
else if(count
== 2'd2
)beginwave_2
<= 1'b0
;end
else beginwave_2
<= 1'b1
;end
endassign div
= wave_1
& wave_2
;endmodule
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) 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
②相或實現
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
)begincount
<= 'd0
;end
else if(count
== 2'd2
)begincount
<= 'd0
;end
else begincount
<= count
+ 1'b1
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_1
<= 1'b0
;end
else if(count
== 2'd0
)beginwave_1
<= 1'b1
;end
else beginwave_1
<= 1'b0
;end
endalways @
(negedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_2
<= 'd0
;end
else if(count
== 2'd0
)beginwave_2
<= 1'b1
;end
else beginwave_2
<= 1'b0
;end
endassign div
= wave_1
| wave_2
;endmodule
③相異或實現
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
)begincount
<= 'd0
;end
else if(count
== 2'd2
)begincount
<= 'd0
;end
else begincount
<= count
+ 1'b1
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_1
<= 1'b0
;end
else if(count
== 2'd0
)beginwave_1
<= ~wave_1
;end
else beginwave_1
<= wave_1
;end
endalways @
(negedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'd0
)beginwave_2
<= 'd0
;end
else if(count
== 2'd2
)beginwave_2
<= ~wave_2
;end
else beginwave_2
<= wave_2
;end
endassign div
= wave_1
^ wave_2
;endmodule
4、FIFO
(1)同步FIFO
*功能:實現深度大小為8,位寬大小為32的同步FIFO*
①采用地址技術的方式實現
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)begindata_depth
= data_depth
>> 1;end
end
endfunctionreg
[c2log(DATA_DEPTH - 1)-1 :0] wr_addr
;
reg
[c2log(DATA_DEPTH - 1)-1 :0] rd_addr
;
always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginwr_addr
<= 'd0
;end
else if(wr_en
== 1'b1 && full_signal != 1'b1
)beginwr_addr
<= wr_addr
+ 1'b1
;end
else beginwr_addr
<= wr_addr
;end
end
always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginrd_addr
<= 'd0
;end
else if(rd_en
== 1'b1 && empty_signal != 1'b1
)beginrd_addr
<= rd_addr
+ 1'b1
;end
else beginrd_addr
<= rd_addr
;end
end
always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginmemory
[wr_addr
] <= 'd0
;end
else if(wr_en
== 1'b1 && full_signal != 1'b1
)beginmemory
[wr_addr
] <= wr_data
;end
else beginmemory
[wr_addr
] <= memory
[wr_addr
];end
end
always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginrd_data
<= 'd0
;end
else if(rd_en
== 1'b1 && empty_signal != 1'b1
)beginrd_data
<= memory
[rd_addr
];end
else beginrd_data
<= rd_data
;end
end
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
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endassign 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
)begincounter
<= 'd0
;wr_en
<= 'd0
;rd_en
<= 'd0
;flag
<= 'd0
;end
else if(counter
== 'd7 && flag == 'd0
)beginflag
<= 'd1
;wr_en
<= 'd1
;end
else if(counter
== 'd7 && flag == 'd1
)begincounter
<= 'd0
;wr_en
<= ~wr_en
;rd_en
<= ~rd_en
;end
else begincounter
<= counter
+ 1'b1
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginwr_data
<= 'd0
;end
else if(wr_data
== 'd20
)beginwr_data
<= 'd0
;end
else beginwr_data
<= wr_data
+ 1;end
endwire
[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
②采用計數器計數的方式實現
module test#
(parameter
DATA_WIDTH = 16,parameter
DATA_DEPTH = 8
)( 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
);function integer
c2log(input
[DATA_DEPTH - 1: 0] data_depth
);begin
for(c2log
= 0; data_depth
>0 ; c2log
= c2log
+ 1)begindata_depth
= data_depth
>> 1; endendendfunctionreg
[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];always@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)beginwr_addr
<= 16'd0
;end
else if(wr_en
== 1'b1 && full_signal == 1'b0
)beginwr_addr
<= wr_addr
+ 1'b1
;endendalways@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)beginrd_addr
<= 16'b0
;end
else if(empty_signal
== 1'b0 && rd_en == 1'b1
)beginrd_addr
<= rd_addr
+ 1'b1
;endendinteger 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)beginmem
[bit_width
] <= 32'd0
;endend
else if(wr_en
== 1'b1 && full_signal == 1'b0
)beginmem
[wr_addr
] <= wr_data
;endendalways@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)beginrd_data
<= 'd0
;end
else if(rd_en
== 1'b1 && empty_signal == 1'b0
)beginrd_data
<= mem
[rd_addr
];endendreg
[3:0] count
;always@
(posedge i_fpga_clk or negedge i_fpga_rst_n
)begin
if(i_fpga_rst_n
== 1'b0
)begincount
<= 'd0
; end
else if(wr_en
== 1'b1 && full_signal == 1'b0
)begincount
<= count
+ 1'b1
;end
else if(rd_en
== 1'b1 && empty_signal == 1'b0
)begincount
<= count
- 1'b1
;end
else begincount
<= count
;endendassign full_signal
= (count
== 'd8
? 1 : 0);assign empty_signal
= (count
== 'd0
? 1 : 0); endmodule
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endassign 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
)begincounter
<= 'd0
;wr_en
<= 'd0
;rd_en
<= 'd0
;flag
<= 'd0
;end
else if(counter
== 'd7 && flag == 'd0
)beginflag
<= 'd1
;wr_en
<= 'd1
;end
else if(counter
== 'd7 && flag == 'd1
)begincounter
<= 'd0
;wr_en
<= ~wr_en
;rd_en
<= ~rd_en
;end
else begincounter
<= counter
+ 1'b1
;end
endalways @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginwr_data
<= 'd0
;end
else if(wr_data
== 'd20
)beginwr_data
<= 'd0
;end
else beginwr_data
<= wr_data
+ 1;end
endwire
[15:0]rd_data
;test#
(.DATA_WIDTH(16),.DATA_DEPTH( 8)
)module_test( .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碼
module test#
(parameter
DATA_WIDTH = 16,parameter
DATA_DEPTH = 8
)( 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
);function integer
c2log(input
[DATA_DEPTH - 1: 0] data_depth
);begin
for(c2log
= 0; data_depth
>0 ; c2log
= c2log
+ 1)begindata_depth
= data_depth
>> 1; endendendfunctionreg
[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];always @
(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr
)begin
if(i_fpga_rst_n_wr
== 1'b0
)beginwr_ptr
<= {(c2log(DATA_DEPTH)){1'b0
}};end
else if(wr_en
== 1'b1 && full_signal == 1'b0
)beginwr_ptr
<= wr_ptr
+ 1'b1
;endend
always@
(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd
)begin
if(i_fpga_rst_n_rd
== 1'b0
)beginrd_ptr
<= {(c2log(DATA_DEPTH-1)){1'b0
}};end
else if(rd_en
== 1'b1 && empty_signal == 1'b0
)beginrd_ptr
<= rd_ptr
+ 1'b1
;end
end
assign gray_wr_ptr_0
= wr_ptr
^ (wr_ptr
>> 1);
assign gray_rd_ptr_0
= rd_ptr
^ (rd_ptr
>> 1);
always@
(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd
)begin
if(i_fpga_rst_n_rd
== 1'b0
)begingray_wr_ptr_1
<= {(c2log(DATA_DEPTH-1)){1'b0
}};gray_wr_ptr_2
<= {(c2log(DATA_DEPTH-1)){1'b0
}};end
else begingray_wr_ptr_1
<= gray_wr_ptr_0
;gray_wr_ptr_2
<= gray_wr_ptr_1
;end
end
always@
(posedge i_fpga_clk_wr or negedge i_fpga_rst_n_wr
)begin
if(i_fpga_rst_n_wr
== 1'b0
)begingray_rd_ptr_1
<= {(c2log(DATA_DEPTH-1)){1'b0
}};gray_rd_ptr_2
<= {(c2log(DATA_DEPTH-1)){1'b0
}};end
else begingray_rd_ptr_1
<= gray_rd_ptr_0
;gray_rd_ptr_2
<= gray_rd_ptr_1
;end
end
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
);
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];
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)beginmem
[i
] <= {DATA_DEPTH{1'b0
}};endend
else if(wr_en
== 1'b1 && full_signal == 1'b0
)beginmem
[wr_addr
] <= wr_data
;end
end
always@
(posedge i_fpga_clk_rd or negedge i_fpga_rst_n_rd
)begin
if(i_fpga_rst_n_rd
== 1'b0
)beginrd_data
<= {DATA_WIDTH{1'b0
}};end
else if(rd_en
== 1'b1 && empty_signal == 1'b0
)beginrd_data
<= mem
[rd_addr
];end
endendmodule
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endinitial
beginforever #
(PERIOD_245P76/2) clk_245
=~clk_245
;
endassign 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
)begincounter
<= 'd0
;wr_en
<= 'd0
;flag
<= 'd0
;end
else if(counter
== 'd7 && flag == 'd0
)beginflag
<= 'd1
;wr_en
<= 'd1
;end
else if(counter
== 'd7 && flag == 'd1
)beginwr_en
<= ~wr_en
;end
else if(counter
== 'd15
)begincounter
<= 'd0
;end
else begincounter
<= counter
+ 1'b1
;end
end
always @
(posedge i_fpga_clk or negedge i_fpga_rst_n
) begin
if(i_fpga_rst_n
== 1'b0
)beginwr_data
<= 'd0
;end
else if(wr_data
== 'd20
)beginwr_data
<= 'd0
;end
else beginwr_data
<= wr_data
+ 1;end
endwire
[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
)begincount_time
<= 'd0
;rd_en
<= 'd1
;end
else if(count_time
== 'd100
)beginrd_en
<= 'd0
;end
else begin count_time
<= count_time
+ 1'b1
;rd_en
<= rd_en
;end
endtest#
(.DATA_WIDTH(16),.DATA_DEPTH( 8)
)test( .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(采用打兩拍實現)
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
);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
)beginr_pluse_r1
<= 1'b0
;r_pluse_r2
<= 1'b0
;end
else beginr_pluse_r1
<= i_pulse_in
;r_pluse_r2
<= r_pluse_r1
;end
endassign o_pulse_out
= r_pluse_r2
;endmodule
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endinitial
beginforever #
(PERIOD_245P76/2) clk_245
=~clk_245
;
endassign 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
)begincounter
<= 'd0
;wr_en
<= 1'b0
;end
else if(counter
== 'd7 | counter == 'd8
)beginwr_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
①一般實現方式
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
);
reg req_signal
;
reg req_signal_r1
;
reg req_signal_r2
;reg ack_signal
;
reg ack_signal_r1
;
reg ack_signal_r2
;always@
(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src
)begin
if(i_fpga_rst_n_src
== 1'b0
)beginreq_signal
<= 1'b0
;end
else if(i_pulse_in
== 1'b1
)beginreq_signal
<= 1'b1
;end
else if(ack_signal_r2
== 1'b1
)beginreq_signal
<= 1'b0
;end
else beginreq_signal
<= req_signal
;end
end
always@
(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des
)begin
if(i_fpga_rst_n_des
== 1'b0
)beginreq_signal_r1
<= 1'b0
;req_signal_r2
<= 1'b0
;end
else beginreq_signal_r1
<= req_signal
;req_signal_r2
<= req_signal_r1
;ack_signal
<= req_signal_r2
;end
end
always@
(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src
)begin
if(i_fpga_rst_n_src
== 1'b0
)beginack_signal_r1
<= 1'b0
;ack_signal_r2
<= 1'b0
;end
else beginack_signal_r1
<= ack_signal
;ack_signal_r2
<= ack_signal_r1
;end
end
assign o_pulse_out
= req_signal_r2
& ~ack_signal
;endmodule
`timescale 1ns
/ 1ps 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
begini
<= 0;j
<= 0;clk_368
<= 'd0
;rst_n_368
<= 'd0
;clk_245
<= 'd0
;rst_n_245
<= 'd0
;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endinitial
beginforever #
(PERIOD_368P64/2) clk_368
=~clk_368
;
endinitial
beginforever #
(PERIOD_245P76/2) clk_245
=~clk_245
;
endassign 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
)begincounter
<= 'd0
;wr_en
<= 1'b0
;end
else if(counter
== 'd7 | counter == 'd8
)beginwr_en
<= 1'b1
;counter
<= counter
+ 1'b1
;end
else begin wr_en
<= 1'b0
;counter
<= counter
+ 1'b1
;end
endtest
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
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
);
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
;
assign idle_state
= ~(req_signal
| req_signal_r2
);
always@
(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src
)begin
if(i_fpga_rst_n_src
== 1'b0
)beginerror_state
<= 1'b0
;end
else if(idle_state
== 1'b1 & i_pulse_in == 1'b1
)beginerror_state
<= 1'b1
;end
else beginerror_state
<= 1'b0
;end
endalways@
(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src
)begin
if(i_fpga_rst_n_src
== 1'b0
)beginreq_signal
<= 1'b0
;end
else if(i_pulse_in
== 1'b1 && idle_state == 1'b1
)beginreq_signal
<= 1'b1
;end
else if(ack_signal_r2
== 1'b1
)beginreq_signal
<= 1'b0
;end
else beginreq_signal
<= req_signal
;end
end
always@
(posedge i_fpga_clk_des or negedge i_fpga_rst_n_des
)begin
if(i_fpga_rst_n_des
== 1'b0
)beginreq_signal_r1
<= 1'b0
;req_signal_r2
<= 1'b0
;ack_signal
<= 1'b0
;end
else beginreq_signal_r1
<= req_signal
;req_signal_r2
<= req_signal_r1
;ack_signal
<= req_signal_r2
;end
end
always@
(posedge i_fpga_clk_src or negedge i_fpga_rst_n_src
)begin
if(i_fpga_rst_n_src
== 1'b0
)beginack_signal_r1
<= 1'b0
;ack_signal_r2
<= 1'b0
;end
else beginack_signal_r1
<= ack_signal
;ack_signal_r2
<= ack_signal_r1
;end
end
assign o_pulse_out
= ack_signal_r1
& ~ack_signal_r2
;endmodule
6、時鐘切換電路
功能:實現不同時鐘的切換
(1)使用組合邏輯實現(不推薦)
有很多毛刺,后級時鐘信號不安全,無法直接使用
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
;endmodule
`timescale 1ns
/ 1ps 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
;
reg selection
;
initial
beginclk_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 ;
endinitial begin#
(PERIOD_368P64) rst_n_368
= 1'b1
;
endinitial begin#
(PERIOD_245P76) rst_n_245
= 1'b1
;
endalways #
(PERIOD_368P64) clk_368
= ~clk_368
;always #
(PERIOD_245P76) clk_245
= ~clk_245
;
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同源)
module
test(input i_fpga_clk_frq1
,input i_fpga_clk_frq2
,input i_seletion
,input i_fpga_rst
,output o_fpga_clk
);reg enable_1
;reg enable_2
;always @
(negedge i_fpga_clk_frq1 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_1
<= 1'b0
;end
else beginenable_1
<= (~enable_2
) & i_seletion
;endendalways @
(negedge i_fpga_clk_frq2 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_2
<= 1'b0
;end
else beginenable_2
<= (~enable_1
) & (~i_seletion
);endendassign o_fpga_clk
= (enable_1
& i_fpga_clk_frq1
) | (enable_2
& i_fpga_clk_frq2
);endmodule
`timescale 1ns
/ 1ps module tb_test
;parameter
PERIOD_400 = 4000/400;
parameter
PERIOD_200 = 4000/200;
reg clk_400
;
reg clk_200
;
reg rst_n_400
;
reg rst_n_200
;
reg selection
;
initial
beginclk_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 ;
endinitial begin#
(PERIOD_400) rst_n_400
= 1'b1
;
endinitial begin#
(PERIOD_200) rst_n_200
= 1'b1
;
endalways #
(PERIOD_400) clk_400
= ~clk_400
;always #
(PERIOD_200) clk_200
= ~clk_200
;
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異步)
module
test(input i_fpga_clk_frq1
,input i_fpga_clk_frq2
,input i_selection
,input i_fpga_rst
,output o_fpga_clk
);reg enable_1
;reg enable_1_r
;reg enable_2
;reg enable_2_r
;always @
(posedge i_fpga_clk_frq1 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_1
<= 1'b0
;end
else beginenable_1
<= (~enable_2_r
) & i_selection
;endendalways @
(negedge i_fpga_clk_frq1 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_1_r
<= 1'b0
;end
else beginenable_1_r
<= enable_1
;endendalways @
(posedge i_fpga_clk_frq2 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_2
<= 1'b0
;end
else beginenable_2
<= (~enable_1_r
) & (~i_selection
);endendalways @
(negedge i_fpga_clk_frq2 or negedge i_fpga_rst
) begin
if(i_fpga_rst
== 1'b0
)beginenable_2_r
<= 1'b0
;end
else beginenable_2_r
<= enable_2
;endendassign o_fpga_clk
= (enable_1_r
& i_fpga_clk_frq1
) | (enable_2_r
& i_fpga_clk_frq2
);endmodule
`timescale 1ns
/ 1ps module tb_test
;parameter
PERIOD_400 = 4000/399;
parameter
PERIOD_200 = 4000/200;
reg clk_400
;
reg clk_200
;
reg rst_n_400
;
reg rst_n_200
;
reg selection
;
initial
beginclk_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 ;
endinitial begin#
(PERIOD_400) rst_n_400
= 1'b1
;
endinitial begin#
(PERIOD_200) rst_n_200
= 1'b1
;
endalways #
(PERIOD_400) clk_400
= ~clk_400
;always #
(PERIOD_200) clk_200
= ~clk_200
;
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)\
8、
功能:
(1)\
總結
以上是生活随笔為你收集整理的FPGA秋招面试手撕代码20+的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。