I am designing a nanoprocessor and below is my instruction decoder code. As you can see I have used case statements for specific operations based on the input signal.

Because of this, as you can see, many outputs are shown as U (undefined) in the simulation. My question is: is it OK to leave it like this when run on the board, or should I initialize the output variables?

entity Instruction_Decoder is
Port ( Ins : in STD_LOGIC_VECTOR (11 downto 0);
       RegCh : in STD_LOGIC_VECTOR (3 downto 0);
       RegEN : out STD_LOGIC_VECTOR (2 downto 0);
       LSel : out STD_LOGIC;
       ImVal : out STD_LOGIC_VECTOR (3 downto 0);
       RegSel1 : out STD_LOGIC_VECTOR (2 downto 0);
       AdSel : out STD_LOGIC;
       JMPF : out STD_LOGIC;
       Jmadd : out STD_LOGIC_VECTOR (2 downto 0);
       RegSel2 : out STD_LOGIC_VECTOR (2 downto 0));
   end Instruction_Decoder;

   architecture Behavioral of Instruction_Decoder is
   signal I:std_logic_vector(1 downto 0);
        case Ins(11 downto 10) is
            when "10"=>
                RegEN<=Ins( 9 downto 7);
                ImVal<=Ins( 3 downto 0);
            when "00"=>
                RegSel1<=Ins(9 downto 7);
                RegSel2<=Ins(6 downto 4);
                RegEN<=Ins(9 downto 7);
            when "01"=>
                RegSel1<=Ins(9 downto 7);
                RegEN<=Ins(9 downto 7);
             when "11"=>
                RegSel1<=Ins(9 downto 7);
                if (RegCh="0000") then
                    Jmadd<=Ins(2 downto 0);
                end if;
             when others=>
        end case;
    end process case1;

end Behavioral;

enter image description here

  • \$\begingroup\$ Please show the code of the testbench that you're using to simulate your instruction decoder. \$\endgroup\$
    – nanofarad
    Jul 25 at 12:36
  • \$\begingroup\$ On Stackoverflow the term would be minimal,complete, and verifiable example. Here Ins(11 downto 10) is "11" with no assignment to AdSel while there is an assignment to JMPF which suggests a driver external to the process with a value of 'U'. There's not enough information present to determine what's going on without the ability to replicate the problem. \$\endgroup\$ Jul 26 at 1:10

2 Answers 2


It is fine (and in my opinion better) to have 'U' outputs from a component if the output is not to be used, because

  1. it makes it easier to debug downstream components
  2. it gives more freedom to the optimizer

For example, I'd begin the process with

    RegEN <= (others => 'U');
    RegSel <= (others => 'U');

etc, then overwrite in the specific cases.

Without these defaults, synthesis is required to keep the values that aren't reassigned, so it will generate a latch.

If you feed the instruction decoder as it is the values "00010101UUUU" and "10111UUU1111" consecutively, you still see RegSel1 = "010" and RegSel2 = "101" from the first instruction on the outputs, and in the absence of a clock, synthesis cannot reliably use a flip-flop for this behavior, so it needs to generate a lookup table that has its output fed back to itself to implement this, which is brittle.

If you explicitly default the outputs to 'U', the optimizer will likely reduce the entire component down to

RegEN <= Ins(9 downto 7);
RegSel1 <= Ins(9 downto 7);
RegSel2 <= Ins(6 downto 4);
ImVal <= Ins(3 downto 0);
LSel <= Ins(11);
AdSel <= not Ins(10);
JMPF <= '1';
Jmadd <= Ins(2 downto 0);

This way, the entire component uses exactly 0 resources because it consists only of direct connections and one negation, which can be merged into the tables the signal goes to.

You will also notice that this is unlikely to be correct, because JMPF gets a fixed value. From the optimizer's point of view, that is a valid optimization, because there are only two possible values: '1' and 'U', so this can be simplified to a static '1' during synthesis.

The JMPF behavior already exists in the current implementation: the output starts out 'U', and there is only a single assignment, which is '1', so this will be reduced to a static '1'. If you initialize that signal to '0' before the case statement, you will likely get closer to the behavior you want.

  • \$\begingroup\$ IEEE Std 1076-2008 Metalogical values used in assignment references "A synthesis tool shall accept a static metalogical value used as all of, or as one element of, a value expression in an assignment statement, but is not required to provide any particular interpretation of that metalogical value." 'U' is a metalogical value and it's effect is neither universal nor guaranteed. 2. it gives more freedom to the optimizer is no more valid than not having the assignment statements. \$\endgroup\$ Jul 26 at 0:44
  • \$\begingroup\$ See Vivado UG 901 table 5.2 std_logic Allowed Values U is not accepted by Vivado synthesis (it's ignored). \$\endgroup\$ Jul 26 at 0:52

What do the unused bits do?

If they write registers, or drive buses, or change things in your processor, you must put them in an inactive state while performing other instructions.

For example, if JMPF causes a JUMP when '1' and normality when '0', you certainly don't want unscheduled JUMPs to happen during an arithmetic or load or store operation.

So add the appropriate default assignments (like JMPF <= '0';) to the process for EVERY output before the CASE statement. The CASE then overrides the ones you need to perform the specific operation, leaving the rest of the machine in whatever state is safest.

Leaving them 'U' will simplify debugging; but it's debugging you don't need to do in the first place.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.