【问题标题】:Why doesn't the up/down counter count down?为什么向上/向下计数器不倒计时?
【发布时间】:2021-09-30 16:33:09
【问题描述】:

我正在做逻辑设计作业,我发现了一些我无法解决的问题。 我需要设计一个6位的计数器,这个计数器需要有两个功能,分别向上和向下计数。 我已经完成了向上部分和向下部分,但是当我运行模拟时,倒计时部分无法正常工作。 倒计时函数:下一个 a = a - 2^n,其中 n = 0, 1, 2, 3... 例如。 a1 = 63, a2 = 63 - 1 = 62, a3 = 62 - 2 = 60, a4 = 56...

但是用我的程序模拟,变成了63、62、61(63 - 2)、59(63 - 4)...

顺便说一句,这个作业有一个重置功能。 但是,我的程序在重置后不会继续计数。 理论上应该归零并继续计数。

以下是我的代码:

`timescale 1ns/100ps
module lab2_1(
    input clk,
    input rst,
    output reg [5:0] out
);
    reg [5:0] cnt;
    wire [5:0] cnt_next;
    reg updown;
    wire [5:0] out_next;
    initial begin
        out = 0;
        cnt = 1;
        updown = 1;
    end
    assign cnt_next = (out == 6'b111111) ? 0 : cnt + 1;
    assign out_next = out - (2**cnt);
    always @(*) begin
        if(out == 6'b111111)begin
            updown = 0;
        end
        if(out == 6'b000000)begin
            updown = 1;
        end
        if(rst == 1) begin
            out = 0;
            updown = 1;
            cnt = 0;
        end
    end
    always @(posedge clk, posedge rst) begin
        if(updown == 1)begin
            if(out > cnt)begin
                out <= out - cnt;
            end
            else
                out <= out + cnt;
        end
        else begin
            out <= out_next;
        end
        cnt <= cnt_next;
    end

endmodule

测试台只监控输出并驱动输入。

`timescale 1ns/100ps
module lab2_1_t;

    wire [5:0] out;
    reg clk;
    reg rst;

    lab2_1 v(clk, rst, out);

    initial begin
        clk = 0;
        rst = 0;
        $monitor($time,":clk = %b, rst = %b, out = %d", clk, rst, out);
    end
    always #10 clk = ~clk;
    always #10000 rst = ~rst;

endmodule

【问题讨论】:

标签: verilog counter


【解决方案1】:

您不应该对来自多个块的同一个信号(例如cnt)进行分配。您可以从单个 always 块分配给 cnt。我认为你不需要outcnt

这是一个自动上下切换的简化版:

module lab2_1(
    input clk,
    input rst,
    output reg [5:0] cnt
);
    reg updown;

    always @(posedge clk, posedge rst) begin
        if (rst) begin
            updown <= 1;
        end else if (cnt == 6'b111110) begin
            updown <= 0;
        end else if (cnt == 6'b000001) begin
            updown <= 1;
        end
    end

    always @(posedge clk, posedge rst) begin
        if (rst) begin
            cnt <= 0;
        end else if (updown) begin
            cnt <= cnt + 1;
        end else begin
            cnt <= cnt - 1;
        end
    end
endmodule

代码显示了在顺序always 块中复位信号的更典型用法。另见for more examples

这是一个修改后的测试平台,其中复位在时间 0 被断言,然后在几个时钟周期后释放。最后,它再次置位重置,因此您可以看到计数器变为 0。

module lab2_1_t;
    wire [5:0] out;
    reg clk;
    reg rst;

    lab2_1 v(clk, rst, out);

    initial begin
        $monitor($time,":clk = %b, rst = %b, out = %d", clk, rst, out);
        clk = 0;
        rst = 1;
        #40 rst = 0;
        #10000 rst = 1;
        #1000 $finish;
    end

    always #10 clk = ~clk;
endmodule

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多