What makes you think that your code is sub-optimal? It looks like a good solution to the problem of building a memory address decoder.... and it will allow you to split the address ranges if you want, which is a good thing as hardware isn't always as clean as software - and after all, a different implementation won't be any more efficient. Your implementation is explicit, can be audited, doesn't rely on hidden, implicit behavior, it just lacks a little bit of flexibility.
Your code might be expressed a little cleaner without the long constants, which can be done like this:
process(in_bus_mm.address)
begin
-- default to zeros
device_sel <= (others => '0');
-- set whichever bit is needed
case in_bus_mm.address(31 downto 28) is
when "0000" => device_sel(0) <= in_bus_mm.enable;
when "0001" => device_sel(1) <= in_bus_mm.enable;
when "0010" => device_sel(2) <= in_bus_mm.enable;
....
end case;
end process;
However, you might be feeling uneasy because you know you are looking at the problem from the wrong perspective, and perhaps your subconscious is struggling to let you know what you really should be doing.
Most likely the solution you are wanting to find is this:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity addr_decode is
Port ( addr_in : in STD_LOGIC_VECTOR;
enable : in STD_LOGIC;
dev_sel : out STD_LOGIC_VECTOR);
end addr_decode;
architecture Behavioral of addr_decode is
begin
g: for i in 0 to dev_sel'high generate
dev_sel(i) <= enable when unsigned(addr_in) = to_unsigned(i, addr_in'length) else '0';
end generate;
end Behavioral;
As addr_in is an unconstrained vector it can be as long or as short as you want. you just need to pass in the bits you want to decode (e.g. "addr_in => address(15 downto 12)" when you create an instance)
As dev_sel is also an unconstrained vector, you can decode as many dev_sel lines as you want, as long as they start at zero and are contiguous. If you don't use them all in your design they will be optimized away.
The only slight worries are if you as for more dev_sel outputs than the addr_in can encode strange things may happen. Hopefully "to_unsigned(i, addr_in'length)" will through an error if 'i' can not be decoded in "addr_in'length" bits - but at least in ISE it doesn't, it only decodes the first 8 dev_sel bits, the rest are just zeros.
It can be used like this - decoding four bits into 12 select lines:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity test_addr_decode is
Port ( addr_in : in STD_LOGIC_VECTOR (3 downto 0);
enable : in STD_LOGIC;
dev_sel : out STD_LOGIC_VECTOR (11 downto 0));
end test_addr_decode;
architecture Behavioral of test_addr_decode is
COMPONENT addr_decode
PORT(
addr_in : IN STD_LOGIC_VECTOR;
enable : IN STD_LOGIC;
dev_sel : OUT STD_LOGIC_VECTOR
);
END COMPONENT;
begin
i_addr_decode: addr_decode PORT MAP(
addr_in => addr_in,
enable => enable,
dev_sel => dev_sel);
end Behavioral;
On the surface it appears to work, but I don't like it, it has lurking bugs like simulation mismatches.
To prove a point I simulated the above code in ISM, and with three bits of address and 12 bits of dev_sel, An input of "011" would give "000000001000" in hardware (as checked in the technology schematic). In Simulation it gives "100000001000", as to_integer(11,3) apparently results in a value of 3.
All these different methods result in the exact same logic, so are much a muchness to me... stick with whichever you like. But being too smart is dumb.
