Search code examples
verilogquartusseven-segment-display

Write a Verilog code that only has an output when enabled


I am creating a register file that has 4 empty 4 bit registers, and with each clock cycle, a register gets a value pushed onto it, and then this value is displayed using a 7 segment decoder. If the register is empty, there should not be a display, but once a value is loaded to the register, then there should be a display. I tried writing the verilog code for the 7 segment decoder where there should only be an output if En = 1. My problem is that instead of not displaying anything, the 7 segment decoder will display zero until a value is added to the register, in which case then the decoder will display the loaded value. Here is the verilog code.

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

When the register is loaded with a value, I have an output come from the register saying that it is loaded, and that is used as the input for the enable on this decoder


Solution

  • Look at the possible encodings of {Z, Y, X, W, En} that you've enumerated:

    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
    

    All of the values of En are 1! You never told the module what to do if En is 0. It doesn't know to blank out the display. You need to give it something to do in that case.

    You have a few options:

    Simple Solution
    You can add a default clause that blanks the display in all cases that haven't been enumerated:

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

    Needlessly Complex Solution
    You could get more precise by using 5'bxxxx0 as a clause and the casex statement:

    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"
    

    But know that there are some potential pitfalls to casex that can make it difficult to use correctly and lead to surprising behavior. Also note that this ends up being the same as the first, simple solution. I'd avoid it for now.

    (My) Preferred Solution

    This is effectively the same as the first two, but I think the intention is much more clear:

    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
    

    The advantage of this solution is that the goal of your code is much more clear: if En is not true, then the rest of the signals don't matter. We clear the display. This happens with the other solutions as well, but this structure makes it more obvious what is going on.

    The default case here technically isn't necessary. There shouldn't be any cases where En is true that aren't enumerated. But that's a lot of digits to type out. If you made a typo, in those cases, having a default that forces an error display (perhaps just the center line of the 7seg display?) will help you identify a bug.

    A few other notes:

    1. You should avoid using X and Z as variable names. They may be confused for "don't care" and "high impedance". It makes the code harder to follow than it needs to be.

    2. I've changed your sensitivity list. Greg correctly pointed out that if you want your output to be correctly updated when the inputs W, X, Y and Z change, you need the always block to be triggered when they change. The * operator will tell the Verilog compiler to infer the correct sensitivity list based on the contents of the always block. (Note that this won't look into the tasks or functions to decide the sensitivity list.)

    3. I strongly suggest you put all of your bit patterns in parameters to make your code more readable.