编写仅在启用时有输出的 Verilog 代码

Write a Verilog code that only has an output when enabled

我正在创建一个寄存器文件,它有 4 个空的 4 位寄存器,在每个时钟周期,寄存器都会将一个值推送到它上面,然后使用 7 段解码器显示该值。如果寄存器为空,则不应显示,但一旦将值加载到寄存器,则应显示。我尝试为 7 段解码器编写 verilog 代码,其中只有 En = 1 时才应该有输出。我的问题是,7 段解码器不会不显示任何内容,而是会显示零,直到将一个值添加到寄存器中,在在这种情况下,解码器将显示加载的值。这是verilog代码。

module seven_seg_decoder(S, Z, Y, X, W,En);
input Z,Y,X,W,En; 
output [6:0] S;
reg [6:0] S;

always @(En)
    begin
        case({Z,Y,X,W,En})
            5'b00001: S = 'b0000001;
            5'b00011: S = 'b1001111;
            5'b00101: S = 'b0010010;
            5'b00111: S = 'b0000110;
            5'b01001: S = 'b1001100;
            5'b01011: S = 'b0100100;
            5'b01101: S = 'b0100000;
            5'b01111: S = 'b0001111;
            5'b10001: S = 'b0000000;
            5'b10011: S = 'b0000100;
            5'b10101: S = 'b0001000;
            5'b10111: S = 'b1100000;
            5'b11001: S = 'b0110001;
            5'b11011: S = 'b1000010;
            5'b11101: S = 'b0110000;
            5'b11111: S = 'b0111000;

        endcase
    end
endmodule

当寄存器加载一个值时,我有一个来自寄存器的输出说它已加载,并且用作此解码器上启用的输入

查看您列举的 {Z, Y, X, W, En} 的可能编码:

5'b00001: S = 'b0000001;
5'b00011: S = 'b1001111;
5'b00101: S = 'b0010010;
5'b00111: S = 'b0000110;
5'b01001: S = 'b1001100;
5'b01011: S = 'b0100100;
5'b01101: S = 'b0100000;
5'b01111: S = 'b0001111;
5'b10001: S = 'b0000000;
5'b10011: S = 'b0000100;
5'b10101: S = 'b0001000;
5'b10111: S = 'b1100000;
5'b11001: S = 'b0110001;
5'b11011: S = 'b1000010;
5'b11101: S = 'b0110000;
5'b11111: S = 'b0111000;
//     ^ Look here

En的所有值都是1!如果 En0,您从未告诉模块该做什么。它不知道要清空显示。在这种情况下,你需要给它一些事情做。

您有几个选择:

简单的解决方案
您可以添加一个默认子句,在所有未列举的情况下显示空白:

 default: S = 'b0000000; //change to whatever means "turn everything off"

不必要的复杂解决方案
您可以通过使用 5'bxxxx0 作为子句和 casex 语句来获得更精确的信息:

casex ({Z,Y,X,W,En})
    // all other enumerated cases
    5'bxxxx0: S = 'b0000000; //change to "everything off"
    default:  S = 'b0000000; //change to "everything off"

但要知道 casex 存在一些潜在的陷阱,可能会导致难以正确使用并导致令人惊讶的行为。另请注意,这最终与第一个简单的解决方案相同。我暂时避免使用它。

(我的)首选方案

这实际上与前两个相同,但我认为意图更加明确:

always @(*)
    begin
        if (!En)
            S = 'b0000000; // change to "everything off"

        else
            case({Z,Y,X,W,En})
                5'b00001: S = 'b0000001;
                5'b00011: S = 'b1001111;
                5'b00101: S = 'b0010010;
                5'b00111: S = 'b0000110;
                5'b01001: S = 'b1001100;
                5'b01011: S = 'b0100100;
                5'b01101: S = 'b0100000;
                5'b01111: S = 'b0001111;
                5'b10001: S = 'b0000000;
                5'b10011: S = 'b0000100;
                5'b10101: S = 'b0001000;
                5'b10111: S = 'b1100000;
                5'b11001: S = 'b0110001;
                5'b11011: S = 'b1000010;
                5'b11101: S = 'b0110000;
                5'b11111: S = 'b0111000;
                default: S = 'b0000000; // change to some error code
            endcase       
    end

此解决方案的优点是代码的目标更加清晰:如果 En 不为真,则其余信号无关紧要。我们清除显示。其他解决方案也会发生这种情况,但这种结构使发生的事情更加明显。

这里的 default 案例在技术上是没有必要的。不应该有任何 En 为真但未被枚举的情况。但是要输入很多数字。如果您打错了字,在这些情况下,默认强制显示错误(也许只是 7seg 显示的中心线?)将帮助您识别错误。

其他一些注意事项:

  1. 您应该避免使用 XZ 作为变量名。他们可能会混淆 "don't care" 和 "high impedance"。它使代码更难遵循。

  2. 我已经更改了您的敏感度列表。 如果您希望在输入 WXYZ 发生变化时正确更新输出,则需要 always 块在它们改变时被触发。 * 运算符将告诉 Verilog 编译器根据 always 块的内容推断出正确的敏感度列表。 (请注意,这不会查看决定敏感度列表的任务或函数。)

  3. 我强烈建议您将所有位模式放在 parameters 中,以使您的代码更具可读性。