verilog入門例項一
阿新 • • 發佈:2020-07-31
verilog入門例項一
- 分頻器設計,要求:對輸入時鐘clk,進行分2、5、10分頻。例如輸入時鐘50Mhz,輸出時鐘就是25、10、5Mhz。
主要思路:
偶數分頻:假設偶數為EVEN,對時鐘訊號週期進行計數,則先寫一個模(EVEN)的計數器,只要計數至EVEN-1則使輸出訊號翻轉,便形成了偶數分頻。
奇數分頻:由兩個訊號作或運算而成。假設奇數為ODD。第一個訊號,以時鐘訊號的上跳沿進行計數,形成一個模(ODD)的計數器,令計數至0,1,2...(EVEN-3)/2全部為高電平,其他為低電平,形成一個佔空比不為0.5的訊號。第二個訊號,以時鐘的下跳沿進行計數,形成一個模(ODD)的計數器令計數至0,1,2...(EVEN-1)/2全部為高電平,其他為低電平,形成一個佔空比不為0.5的訊號。這兩個訊號做或運算則可形成奇數分頻。舉例:5分頻。以時鐘上跳沿計數,計數為0,1時為高電平,計數為2,3,4為低電平,如此形成一個訊號1。同理以時鐘下跳沿進行計數,計數為0,1時為高電平,計數為2,3,4為低電平,如此形成一個訊號2。兩個訊號做或運算可以形成奇數分頻訊號。
module divider( input clk; input rst_n; output clk_div2; output clk_div5; output clk_div10 ); reg [3:0]cnt1; reg [3:0]cnt2; reg [3:0]cnt3; reg clk_div51,clk_div52; parameter NUM_DIV_ODD ==5; parameter NUM_DIV_EVEN ==10; //二分頻 always@(posedge clk or negedge rst_n) begin if(!rst_n) clk_div2 <= 1'b0; else clk_div2 <= ~clk_div2; end //奇數五分頻由兩個佔空比為0.4的訊號相和而成 //第一個上跳沿計數的訊號clk_div51 always@(posedge clk or negedge rst_n) begin if(!rst_n) cnt1 <= 1'b0; else if (cnt < NUM_DIV - 1) cnt1 <= cnt1+1'b1; else cnt1 <= 1'b0; end always@(posedge clk or negedge rst_n) begin if(!rst_n) clk_div51 <= 1'b0; else if(cnt1<NUM_DIV/2) clk_div51 <=1'b1; else clk_div51 <= 1'b0; end //第二個下跳沿計數的訊號clk_div52 always@(negedge clk or negedge rst_n) begin if(!rst_n) cnt2 <= 1'b0; else if (cnt < NUM_DIV -1 ) cnt2 <= cnt2 + 1'b1; else cnt <= 1'b0; end always@(negedge clk or negedge rst_n) begin if(!rst_n) clk_div52 <= 1'b0; else if (cnt2 < NUM_DIV/2) clk_div52 <= 1'b1; else clk_div52 <= 1'b0; end assign clk_div5 <= clk_div51 | clk_div52; //十分頻 always@(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_div10 <= 1'b0; cnt3 <=0; end else if (cnt3 < NUM_DIV_EVEN/2) begin cnt3 <= cnt3 + 1'b1; clk_div10 <= clk_div10; end else begin cnt3 <= 1'b0; clk_div10 <= ~clk_div10; end end endmodule
testbench
`timescale 1ns/1ps module tb_divider; reg clk; reg rst_n; wire clk_div2; wire clk_div5; wire clk_div10; parameter TIME = 20; divider uut( .clk(clk), .rst_div(rst_n), .clk_div2(clk_div2), .clk_div5(clk_div5), .clk_div10(clk_div10) ); always@ #(TIME/2) clk = ~clk; initial begin clk = 0; rst_n = 0; #TIME rst_n = 1; #(TiME * 80000) $finish; end endmodule
模擬效果:
其中clk_div51和clk_div52是奇數5分頻的訊號1和訊號2。
- 訊號燈
要求:東西方向和南北方向各有四盞燈,分別為左拐燈、綠燈、黃燈和紅燈
東西方向訊號燈的時間為:紅燈55s,黃燈5s,綠燈40s,左拐燈15s;
南北方向訊號燈的時間為:紅燈65,黃燈5,綠燈30,左拐燈15s;
思路:把訊號燈分為以上7種狀態,由於有時間要求,則以5s記一次數,訊號燈跑完整個過程,需要120s,則形成一個模24計數器,下面流程圖中白色中的數字就是計數值。
真值表:
Light_ns(南北訊號燈) | Light_ew(東西訊號燈) | 狀態 |
---|---|---|
左 綠 黃 紅 | 左 綠 黃 紅 | |
0 0 1 0 | 0 0 1 0 | IDLE |
1 0 0 0 | 0 0 0 1 | S1 |
0 1 0 0 | 0 0 0 1 | S2 |
0 0 1 0 | 0 0 0 1 | S3 |
0 0 0 1 | 1 0 0 0 | S4 |
0 0 0 1 | 0 1 0 0 | S5 |
0 0 0 1 | 0 0 1 0 | S6 |
流程圖:
module signal_light(clk,rst_n,light_ns,light_ew,count);
input clk,rst_n;
output light_ns,light_ew;//ns:north sourth,ew:east west
output count;
//output clk_count;
reg[3:0]light_ns,light_ew;
reg[4:0]count;
reg[2:0]current_state,next_state;
parameter IDLE=3'b000;
parameter S1=3'b001;
parameter S2=3'b010;
parameter S3=3'b011;
parameter S4=3'b100;
parameter S5=3'b101;
parameter S6=3'b110;
// reg clk_count;
//reg count1;
//parameter T=9'd250000000;
/*
always@(posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
clk_count <= 1'b0;
cnt1 <=0;
end
else if (cnt1 < T/2)
begin
cnt1 <= cnt1 + 1'b1;
clk_count <= clk_count;
end
else
begin
cnt1 <= 1'b0;
clk_count <= ~clk_count;
end
end
*/
//counter
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
count<=1'b0;
else if(count==5'b10111)
count<=1'd0;
else
count<=count+1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
current_state<=IDLE;
else
current_state<=next_state;
end
always@(*)
begin
case(current_state)
IDLE:if(!count)next_state=S1;
else next_state=IDLE;
S1:if(count==2)next_state=S2;
else next_state=S3;
S2:if(count==9)next_state=S3;
else next_state=S2;
S3:begin
if(count==3)next_state=S2;
else
begin
if(count==10)next_state=S4;
else next_state=S3;
end
end
S4:if(count==13)next_state=S6;
else next_state=S4;
S5:if(count==22)next_state=S6;
else next_state=S5;
S6:begin
if(count==14)next_state=S5;
else
begin
if(count==23)next_state=S1;
else next_state=S6;
end
end
default:next_state=IDLE;
endcase
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
light_ns<=4'b0010;
light_ew<=4'b0010;
end
else
case(next_state)
IDLE :begin
light_ns<=4'b0010;
light_ew<=4'b0010;
end
S1 :begin
light_ns<=4'b1000;
light_ew<=4'b0001;
end
S2 :begin
light_ns<=4'b0100;
light_ew<=4'b0001;
end
S3 :begin
light_ns<=4'b0010;
light_ew<=4'b0001;
end
S4 :begin
light_ns<=4'b0001;
light_ew<=4'b1000;
end
S5 :begin
light_ns<=4'b0001;
light_ew<=4'b0100;
end
S6 :begin
light_ns<=4'b0001;
light_ew<=4'b0010;
end
default:begin
light_ns<=4'b0010;
light_ew<=4'b0010;
end
endcase
end
endmodule
testbench
`timescale 1ns/1ps
module tb_signal_light;
reg clk;
reg rst_n;
wire [4:0]count;
wire [3:0]light_ew;
wire [3:0]light_ns;
//wire clk_count;
parameter TIME=20;
signal_light uut(
.clk(clk),
.rst_n(rst_n),
.light_ns(light_ns),
.light_ew(light_ew),
.count(count)
//.clk_count(clk_count)
);
always #10 clk = ~clk;
initial
begin
clk = 0;
rst_n = 0;
#TIME rst_n = 1;
//#(TiME * 80000) $finish;
end
endmodule
模擬結果:
結果中還有一個問題就是未分頻,應該是要寫一個週期的5s的時鐘訊號。