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)beginif(!rstn)din_dly <= 1'b0;elsedin_dly <= din;
endpulse = 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)beginif (!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 beginclk = 0;rstn = 1;en = 0;#20;#1;rstn = 0;#30;rstn = 1;en = 1;#500;en = 0;#200;$finish();
endcounter 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)beginsf <= {sf[2:0],din};
end
shift to lower bit
reg [3:0] sf;
always @(posedge clk)beginsf <= {din,sf[3:1]};
end
双向shift:
reg [3:0] sf;
wire dir;
always @(posedge clk)beginif (dir == 0)sf <= {sf[2:0],din};elsesf <= {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)beginif (!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)begincase(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 beginclk = 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数endrepeat(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)beginif(!rstn)shift_reg <= 3'b0;elseshift_reg <= {shift_reg[1:0],din};
end
always @(posedge clk or negedge rstn)beginif(!rstn)match <= 1'b0;else if (en&&(shift_reg == 3'b101)&&din)match <= 1'b1;elsematch <= 1'b0;
end//second way
/*
reg [3:0] shift_reg;
always @(posedge clk or negedge rstn)beginif(!rstn)shift_reg <= 4'b0;elseshift_reg <= {shift_reg[2:0],din};
end
always @(posedge clk or negedge rstn)beginif(!rstn)match <= 1'b0;else if (en&&(shift_reg == 4'b1011))match <= 1'b1;elsematch <= 1'b0;
endendmodule