Diseño verilog de mostrador de doble filo (detalles)

Un contador de doble filo es un contador que cuenta tanto con los flancos ascendentes como descendentes del reloj. Por lo tanto, se necesitan dos conteos, es decir, el contador de flanco ascendente y el contador de flanco descendente son auxiliares, como se muestra en la siguiente figura:
Insertar descripción de la imagen aquí
Se puede observar que se puede obtener un contador de doble flanco sumando los contadores de flanco ascendente y descendente . Un caso más complicado es el estado establecido de los dos contadores. Ahora supongamos que hacemos un contador de doble filo con un valor máximo de 17, como se muestra en la siguiente figura: Insertar descripción de la imagen aquí
Podemos ver que cuando los dos aceleradores se suman al valor máximo, un contador debe establecerse en 0 y el otro. El contador se establece en 1. Si está en el flanco ascendente. Cuando se detecta que la suma es el valor máximo, el contador del flanco ascendente se establece en 0. De lo contrario, el contador de flanco descendente se establece en 0. Por lo tanto, es necesario declarar dos señales de configuración 1 para estos dos contadores. Si la señal de configuración 1 es alta, el contador correspondiente se establece en 1 en el siguiente ciclo de reloj. Además, es necesario explicar que los respectivos recuentos máximos de los dos contadores son sólo la mitad de los recuentos máximos de los dos bordes. El código específico es el siguiente, con comentarios detallados:

//function:实现双边沿的计数器
//date:2022/08/31

module double_edge_cnt #(
    parameter   MAX         =   100    //计数的最大值   
)

(
    input   wire                clk     ,
    input   wire                rst_n   ,

    output  wire    [31:0]      d_cnt 
);

wire                even_flag       ;       //偶数标志
wire    [31:0]      HALF_MAX        ;

reg     [31:0]      cnt_posedge     ;       //上升沿计数器
reg     [31:0]      cnt_negedge     ;       //下降沿计数器
reg                 set_one_flag_pos;       //上升沿计数器置1信号
reg                 set_one_flas_neg;       //下降沿计数器置1信号

assign even_flag = (MAX[0] == 1'b0) ? 1'b1 : 1'b0;          //判断MAX是不是偶数
assign HALF_MAX = even_flag ? MAX >> 1 : (MAX >> 1) + 1'b1; //MAX一半

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_posedge <= 32'd0;
        set_one_flag_pos <= 1'b0;
    end
    else if((cnt_negedge + cnt_posedge == MAX)) begin       //上升沿检测到加和最大值,
        cnt_posedge <= 32'd0;
    end
    else if(cnt_negedge + cnt_posedge == MAX - 1'b1) begin  //上升沿检测到加和最大值减1,说明会在下降沿检测到最大值
        set_one_flag_pos <= 1'b1;                           //因此拉高置1信号
        cnt_posedge <= cnt_posedge + 1'b1;
    end
    else if(set_one_flag_pos) begin                         //置1信号为高,置位
        set_one_flag_pos <= 1'b0;
        cnt_posedge <= 32'd1;
    end
    else begin
        cnt_posedge <= cnt_posedge + 1'b1;
    end
end

always @(negedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_negedge <= 32'd0;
        set_one_flas_neg <= 1'b0;
    end
    else if(cnt_negedge + cnt_posedge == MAX) begin         //下降沿检测到最大值
        cnt_negedge <= 32'd0;
    end
    else if(cnt_negedge + cnt_posedge == MAX - 1'b1) begin  //下降沿检测到最大值减1,说明会在上升沿检测到最大值
        set_one_flas_neg <= 1'b1;                           //因此拉高下降沿计数器置1信号
        cnt_negedge <= cnt_negedge + 1'b1;
    end
    else if(set_one_flas_neg) begin                         //置1信号为高
        set_one_flas_neg <= 1'b0;
        cnt_negedge <= 32'd1;
    end
    else begin
        cnt_negedge <= cnt_negedge + 1'b1;
    end
end

//为双边沿计数器赋值
assign d_cnt = (((cnt_posedge == HALF_MAX) && (cnt_negedge == 'd0)) || ((cnt_posedge == 'd0) && (cnt_negedge == HALF_MAX))) ? 32'd0 : cnt_negedge + cnt_posedge; 

endmodule

El banco de pruebas es el siguiente:

`timescale 1ns/1ns
`define CLK_CYCLE 20
module tb_double_edge_cnt;

    reg                 clk     ;
    reg                 rst_n   ;

    wire    [31:0]      d_cnt   ;

double_edge_cnt #
(
    99
)u_double_edge_cnt(
    .clk    (clk)   ,
    .rst_n  (rst_n) ,

    .d_cnt  (d_cnt)
);


initial begin
     clk = 1'b0;
     rst_n = 1'b0;
     #200
     rst_n = 1'b1;
     #40000;
     //$finish;
end

always # (`CLK_CYCLE/2) clk = ~clk;


endmodule

Diagrama de forma de onda de simulación:
Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_45614076/article/details/126630588
Recomendado
Clasificación