std_logic minimal example
'U' just means that a signal isn't driven. If you have:

signal sig : std_logic;


and never assign it, then if you look at this signal in a simulator, it will have value 'U'.



'-' is useful if you have a logical function of some kind where you genuinely don't care what the output is in one or more particular conditions. This allows a synthesis tool to optimize the design such that the output in this case is whatever uses the minimum amount of FPGA resource. There are probably other uses for it too.



'L' and 'H' are useful in test benches for modelling external interfaces that rely on pull up/down resistors for part of their operation. A good example of this would be I2C, where to model the bus properly, you would only ever drive the signals from your FPGA low ('0') or High-Z ('Z'), then have the external pull-up modeled as a permanent assignment to 'H' in your test bench. For example:

-- In FPGA:
process (i2c_data)
begin
  if (i2c_data = '0') then
    i2c_sda_pin &lt;= '0';
  else
    i2c_sda_pin &lt;= 'Z';
  end if;
end process;

-- In test bench, `i2c_sda_pin` is connected to signal `i2c_sda`
i2c_sda &lt;= 'H';


The result will be a signal that toggles between 'H' and '0'; this allows it to be connected to multiple I2C devices in the test bench, while avoiding any possibility of contention ('X').

As a side note, this is an example of where the clk'event and clk = '1' style of edge detection doesn't work; the I2C clock would toggle between '0' and 'H'. rising_edge(clk) works much more intuitively.



'X' is usually the result of two processes trying to drive the same signal with different values in a way that cannot be resolved, i.e. when there is contention on a signal. For example:

p1 : process(sig)
begin
  output &lt;= '0';
end process;

p2 : process(sig)
begin
  output &lt;= '1';
end process;


The result will be that output takes the value 'X', because there is no way to resolve the two outputs. Think of this as a signal line with two output pins on it. As long as they both drive the same value, the line will look OK. If they both drive different values, there will be contention, and the state of the line cannot be relied on.

If we change the second process to:

p2 : process(sig)
begin
  output &lt;= 'L';
end process;


output will take the value '1', because a strong '1' overrides a weak 'L'. Think of this as connecting a logic output pin to a line with a weak pull-down resistor; if the pin drives high, the line will go high.

It can also be useful to drive a signal with 'X', for example to simulate the timing of an external interface.



'W' is the resolved result when a signal is driven with both 'L' and 'H'. I don't know if there is a use case for purposefully setting a signal to 'W', but there's bound to be one somewhere.



The result when driving two std_logic values onto the same signal is determined by the 'resolution function' for this type, and the fact that std_logic is a 'resolved type', i.e. a resolution function exists for it, is what makes it special. There is an existing question here that looks at the particular resolution function for std_logic in more detail.