1.边沿检测
检测输入信号din的上升沿,并输出pulse
module edge_check (
clk,
rstn,
din,
pulse
);
input wire clk,rstn;
input wire din;
output reg pulse;
wire din_dly;
always @(posedge clk or negedge rstn)begin
if(!rstn)
din_dly <= 1'b0;
else
din_dly <= din;
end
pulse = din & (!din_dly);
endmodule
2.计数器
module counter(
clk,
rstn,
en,
cnt
);
input wire clk,rstn,en;
output reg [3:0] cnt;
always @(posedge clk or negedge rstn)begin
if (!rstn)
cnt <= 4'b0;
else if (en)
cnt <= cnt + 1;
else
cnt <= cnt;
end
endmodule
testbench:
module tb_counter();
reg clk,rstn,en;
always #5 clk = ~clk;
initial begin
clk = 0;
rstn = 1;
en = 0;
#20;
#1;
rstn = 0;
#30;
rstn = 1;
en = 1;
#500;
en = 0;
#200;
$finish();
end
counter u_counter(
.clk (clk),
.rstn (rstn),
.en (en),
.cnt ( )
);
endmodule
sim:
3.时序逻辑电路有rstn端,为什么组合电路没有?
电路由一堆时序逻辑和组合逻辑组成,如果时序逻辑全都复位到固定值,组合逻辑的输入也是固定值,那么组合逻辑的输出也是固定值。
4.移位寄存器shift-register
shift to higher bit
reg [3:0] sf;
always @(posedge clk)begin
sf <= {sf[2:0],din};
end
shift to lower bit
reg [3:0] sf;
always @(posedge clk)begin
sf <= {din,sf[3:1]};
end
双向shift:
reg [3:0] sf;
wire dir;
always @(posedge clk)begin
if (dir == 0)
sf <= {sf[2:0],din};
else
sf <= {din,sf[3:1]};
end
5.状态机类型
Mearly型:输出由当前状态和输入共同决定;
Moore型:输出只与当前状态有关。
实际工程设计中,主要关心逻辑功能,不太关心类型。因为在PPA上,没有明显优劣。
6.用FSM实现“1011”序列检测,每周期输入1bit,检测到1011后,在下一周期输出一个周期的高电平。
module detect(
clk,
rstn,
din,
en,
dout
);
input wire clk,rstn,din,en;
output reg dout;
reg [1:0] state,nstate;
parameter [1:0] s_idle = 00;
parameter [1:0] s_1 = 01;
parameter [1:0] s_10 = 10;
parameter [1:0] s_101 = 11;
//简洁写法parameter [1:0] s_idle = 'd0, s_1 = 'd1, s_10 = 'd2, s_101 = 'd3;
//时序逻辑
always @(posedge clk or negedge rstn)begin
if (!rstn)
state <= s_idle;
else if (en)
state <= nstate;
end
always @(posedge clk or negedge rstn)
if (!rstn)
dout <= 1'b0;
else if(en &&(state == s_101)&&din)
dout <= 1'b1;
else
dout <= 1'b0;
//组合逻辑
always @(*)begin
if(en)begin
case(state)
s_idle:if (din == 1) nstate = s_1; else nstate = s_idle;
s_1: if (din == 1) nstate = s_1; else nstate = s_10;
s_10: if (din == 1) nstate = s_101; else nstate = s_idle;
s_101: if (din == 1) nstate = s_1; else nstate = s_10;
default:nstate = s_idle;
endcase
end
else
nstate = state;//en无效的话,次态等于现态。
endmodule
if ,else if 要配全,否则会综合出latch。
testbench:
module tb_detect();
reg clk,rstn,din,en;
wire dout;
always #5 clk = ~clk;
initial begin
clk = 0;
rstn = 1;
din = 0;
en =0;
#20;
#1;
rstn = 0;
#20;
rstn = 1;
en = 1;
repeat(20)begin
@(posedge clk) din <= {$random}%2; //产生20个随机1bit数
end
repeat(5) @(posedge clk);
$finish();
end
detect u_detect(
.clk (clk),
.rstn (rstn),
.din (din),
.en (en),
.dout (dout)
);
endmodule
也可以s_idle,s_1,s_10,s_101,s_1011五种状态来写,但是state和nstate就需要3bit位宽来储存,会消耗更多的资源。
7.较长的序列检测,比如0110101,且中间有重叠部分。
用shift_register,以1011为例:
module detect_shift(
clk,
rstn,
en,
din,
match
);
input wire clk,rstn,en,din;
output reg match;
reg [2:0] shift_reg;
always @(posedge clk or negedge rstn)begin
if(!rstn)
shift_reg <= 3'b0;
else
shift_reg <= {shift_reg[1:0],din};
end
always @(posedge clk or negedge rstn)begin
if(!rstn)
match <= 1'b0;
else if (en&&(shift_reg == 3'b101)&&din)
match <= 1'b1;
else
match <= 1'b0;
end
//second way
/*
reg [3:0] shift_reg;
always @(posedge clk or negedge rstn)begin
if(!rstn)
shift_reg <= 4'b0;
else
shift_reg <= {shift_reg[2:0],din};
end
always @(posedge clk or negedge rstn)begin
if(!rstn)
match <= 1'b0;
else if (en&&(shift_reg == 4'b1011))
match <= 1'b1;
else
match <= 1'b0;
end
endmodule