Verilog基础知识(简单的时序逻辑)

寄存器

同步时序电路设计风格下建议所有的输出都是reg型,也就是最后的输出要有一个寄存器(边沿触发)。
常用的寄存器有不带置位和重置的简单DFF,异步置位同步释放的DFF,异步置位重置同步释放的DFF。

module FlipFlops(
    input D, clk, rst, pst,
    output reg Qsimple, Qasyncrst, Qasyncpst
    );

// simple DFF
always @(posedge clk)
    Qsimple <= D;

// asynchronous reset, synchronous release
always @(posedge clk, posedge rst)begin
    if (rst == 1'b1)
        Qasyncrst <= 1'b0;
    else
        Qasyncrst <= D;
end

// asynchronous reset/preset, synchronous release
always @(posedge clk, posedge rst, posedge pst)begin
    if (rst == 1'b1)
        Qasyncpst <= 1'b0;
    else if (pst == 1'b1)
        Qasyncpst <= 1'b1;
    else
        Qasyncpst <= D;
end

endmodule
`timescale 1ns/100ps

module FlipFlops_tb;

reg D, clk, rst, pst;
wire Qsimple, Qasyncrst, Qasyncpst;

FlipFlops FF_U1(
    .D(D),
    .clk(clk),
    .rst(rst),
    .pst(pst),
    .Qsimple(Qsimple),
    .Qasyncrst(Qasyncrst),
    .Qasyncpst(Qasyncpst)
    );

always #1 clk = ~clk;

initial begin
    #0
        clk = 1'b1;
        D = 1'b0;
        rst = 1'b0;
        pst = 1'b0;
    #1
        rst = 1'b1;
        pst = 1'b1;
    #2.5
        D = 1'b1;
    #5
        rst = 1'b0;
    #7.5
        pst = 1'b0;
    #10
        $finish;
end


endmodule

锁存器

好的设计风格应该尽量避免锁存器的出现,一般在always块的敏感列表是电平敏感,但是没有把所有组合逻辑需要的信号都列出来的情况就会出现锁存器。见下例

input a,b,c;
reg e,d;
always @(a,b,c)begin
// 因为d没有出现在敏感列表,所以d变化时,e不能立刻变化,需要等到abc某个信号变化的时候才能体现,实际上是产生了一个锁存器把d的信号锁存了
    e = d&a&b;
end

常用的Dlatch的代码如下

module DLatch(
    input D, ena, rst, pst,
    output reg Qsimple, Qasyncrst, Qasyncpst
    );

always @(D, ena)
    if (ena == 1'b1)
        Qsimple <= D;

always @(D, ena, rst)begin
    if (rst == 1'b1)
        Qasyncrst <= 1'b0;
    else if (ena == 1'b1)
        Qasyncrst <= D;
end

always @(D, ena, rst, pst)begin
    if (rst == 1'b1)
        Qasyncpst <= 1'b0;
    else if (pst == 1'b1)
        Qasyncpst <= 1'b1;
    else if (ena == 1'b1)
        Qasyncpst <= D;
end

endmodule
`timescale 1ns/100ps

module Dlatch_tb;

reg D, ena, rst, pst;
wire Qsimple, Qasyncrst, Qasyncpst;

DLatch Latch_U1(
    .D(D),
    .ena(ena),
    .rst(rst),
    .pst(pst),
    .Qsimple(Qsimple),
    .Qasyncrst(Qasyncrst),
    .Qasyncpst(Qasyncpst)
    );

always #1 ena = ~ena;

initial begin
    #0
        ena = 1'b1;
        D = 1'b0;
        rst = 1'b0;
        pst = 1'b0;
    #1
        rst = 1'b1;
        pst = 1'b1;
    #2.5
        D = 1'b1;
    #5
        rst = 1'b0;
    #7.5
        pst = 1'b0;
    #10
        $finish;
end

endmodule


可以看到输出并不是在时钟边沿变化。

移位寄存器

module ShiftReg(
    input Din, shift_ena, clk, rst,
    output Qout
    );

reg [4:0] Qreg;

always @(posedge clk or posedge rst) begin
    if (rst) begin
        Qreg <= 5'b0;   // reset
    end
    else begin
        Qreg[0] <= (shift_ena == 1'b1)? Din     : Qreg[0];
        Qreg[1] <= (shift_ena == 1'b1)? Qreg[0] : Qreg[1];
        Qreg[2] <= (shift_ena == 1'b1)? Qreg[1] : Qreg[2];
        Qreg[3] <= (shift_ena == 1'b1)? Qreg[2] : Qreg[3];
        Qreg[4] <= (shift_ena == 1'b1)? Qreg[3] : Qreg[4];      
    end
end

assign Qout = Qreg[4];

endmodule
`timescale 1ns/100ps

module ShiftReg_tb;

reg Din, shift_ena, clk, rst;
wire Qout;

ShiftReg shift_U1(
    .Din(Din),
    .shift_ena(shift_ena),
    .clk(clk),
    .rst(rst),
    .Qout(Qout)
    );

always #1 clk = ~clk;
always begin
    #3.2 Din = ~Din;
    #1.8 Din = 0;
end

initial begin
    Din = 1'b0;
    shift_ena = 1'b0;
    clk = 1'b1;
    rst = 1'b1;

    #5 shift_ena = 1'b1;
    #180 rst = 1'b0;
    #200 $finish;
end

endmodule

计数器

计数器主要用于分频,任务控制等,计数器有门级模型,状态机,行为级三种verilog写法,推荐使用行为级写法。以下是使用计数器实现一个分频器。

module fdiv
    #(parameter Ndiv = 2)(
    input fin, rst,
    output reg fout 
    );

reg [7:0] cnt;

always @(posedge fin or posedge rst) begin
    if (rst) begin
//      fout <= 1'b0;
        cnt <= 8'b0;
    end
    else if (cnt == Ndiv) begin
        cnt <= 8'b0;
//      fout <= ~fout;
    end
    else cnt <= cnt+1;
end

always @(posedge fin or posedge rst) begin
    if (rst) begin
        fout <= 1'b0;
    end
    else if (cnt == Ndiv) begin
        fout <= ~fout;
    end
end

endmodule
`timescale 1ns/100ps

module fdiv_tb;

reg fin, rst;
wire fout;

fdiv #(
    .Ndiv(4)
    )
U1 (
    .fin(fin),
    .rst(rst),
    .fout(fout)
    );

initial begin
    rst = 1'b1;
    fin = 1'b0;
    #20 rst = 1'b0;
    #500 $finish; 
end

always #5 fin = ~fin;

endmodule

猜你喜欢

转载自blog.csdn.net/maxwell2ic/article/details/81014100