# VHDL how to make a redundant case statement simpler?

I'm using case statements to check the bits of a word. Is there any way to write this more compact since it uses a lot of space (I have other signals on which I want to do this aswell).

...
case a(1 downto 0) is
when "00" =>
r(3 downto 0) <= "0000";
when "01" =>
r(3 downto 0) <= "0001";
when "10" =>
r(3 downto 0) <= "1100";
when "11" =>
r(3 downto 0) <= "1101";
when others =>
null;
case a(3 downto 2) is
when "00" =>
r(7 downto 4) <= "0000";
when "01" =>
r(7 downto 4) <= "0001";
when "10" =>
r(7 downto 4) <= "1100";
when "11" =>
r(7 downto 4) <= "1101";
when others =>
null;
case a(5 downto 4) is
when "00" =>
r(11 downto 8) <= "0000";
when "01" =>
r(11 downto 8) <= "0001";
when "10" =>
r(11 downto 8) <= "1100";
when "11" =>
r(11 downto 8) <= "1101";
when others =>
null;
case a(7 downto 6) is
when "00" =>
r(15 downto 12) <= "0000";
when "01" =>
r(15 downto 12) <= "0001";
when "10" =>
r(15 downto 12) <= "1100";
when "11" =>
r(15 downto 12) <= "1101";
when others =>
null;
...

• Multiple possibilities. Either use a function or put the lookup/s-box/whatever it is into a separate entity. – svens Aug 28 '15 at 22:01
• There's also a selected signal assignment statement which is a short(er) representation of a case statement. It may not be supported as a sequential statement by your particular synthesis vendor. – user8352 Aug 29 '15 at 3:07

## 2 Answers

You're basically coding a whole bunch of 4-input multiplexers, so you could either write a function or create a submodule that you instantiate for each one.

function map4 (sel: in std_logic_vector (1 downto 0);
constant v0, v1, v2, v3 : in std_logic_vector (3 downto 0))
return std_logic_vector is
begin
case sel is
when "00" => return v0;
when "01" => return v1;
when "10" => return v2;
when "11" => return v3;
when others => return "XXXX";
end case;
end map4;

...

r( 3 downto 0) <= map4 (a(1 downto 0), "0000", "0001", "1100", "1101");
r( 7 downto 4) <= map4 (a(3 downto 2), "0000", "0001", "1100", "1101");
r(11 downto 8) <= map4 (a(5 downto 4), "0000", "0001", "1100", "1101");


If the map values are all the same, then you don't need to pass them as parameters.

Of course, with the specific mapping you give as an example, the logic is trivial: bit 0 of the output is simply bit 0 of the input, bit 1 is always 0, and bits 2 and 3 of the output are bit 1 of the input.

• An alternative to the map function is a constant array, indexed by to_integer(unsigned(relevant bits)) but this is good too. – user16324 Aug 29 '15 at 12:16

You can make loops :

   FOR i IN 0 TO 3 LOOP
CASE a(i*2+1 DOWNTO i*2) IS
when "00" =>
r(i*4+3 downto i*4) <= "0000";
when "01" =>
r(i*4+3 downto i*4) <= "0001";
when "10" =>
r(i*4+3 downto i*4) <= "1100";
when "11" =>
r(i*4+3 downto i*4) <= "1101";
when others =>
r(i*4+3 downto i*4) <= "XXXX";
END CASE;
END LOOP;


(Loops are usually synthesisable, particularly when the number of iterations is fixed)

If you don't need the "others" clause :

   FOR i IN 0 TO 3 LOOP
CASE a(i*2+1 DOWNTO i*2) IS
when "00" =>
r(i*4+3 downto i*4) <= "0000";
when "01" =>
r(i*4+3 downto i*4) <= "0001";
when "10" =>
r(i*4+3 downto i*4) <= "1100";
when others =>
r(i*4+3 downto i*4) <= "1101";
END CASE;
END LOOP;


(If you don't care about the behaviour when inputs are in the 'X', 'Z', 'U'... state)

You can also create a temporary variable to make the code even shorter and easier to read:

  VARIABLE t : unsigned(3 DOWNTO 0);
...
FOR i IN 0 TO 3 LOOP
CASE a(i*2+1 DOWNTO i*2) IS
when "00"   => t := "0000";
when "01"   => t := "0001";
when "10"   => t := "1100";
when others => t := "1101";
END CASE;
r(i*4+3 downto i*4) <= t;
END LOOP;


You can directly write boolean equations, here it is quite simple :

  FOR i IN 0 TO 3 LOOP
r(i*4+3 downto i*4) <= a(i*2+1) & a(i*2+1) & '0' & a(i*2);
END LOOP;