04-26-2012 04:39 PM
Hello, everybody. This is my first question on this forum, so please correct me if I make some mistake.
I'm trying to create a multiplexer, but my wish is to make it as generic as possible. This is, with a generic input width and an arbitrary number of signals, to avoid to individually create all options for a large instance. I don't know how to "dynamically create" port inputs, so what I do is to combine all signals in a large input vector.
What I try to do is using the MUXF7 primitive, a 2-input 1-output multiplexer, and replicate it for the number of inputs and the data bit width. To replicate for more than two inputs, the outputs of each multiplexer connect to a new stage of half the size (in number of util signals) until only 1 signal remains.
I guess it is better understood looking at the code.
-- Entity declaration.
entity gmuxer is
WIDTH: integer := 8;
NINPT: integer := 64
chnsel: in std_logic_vector((integer(ceil(LOG2(real(NINPT))))-1) downto 0);
datain: in std_logic_vector((NINPT*WIDTH-1) downto 0);
dataout: out std_logic_vector((WIDTH-1) downto 0);
tst: out std_logic
-- Architecture declaration.
architecture behavioral of gmuxer is
constant LOG2_NINPT: integer := integer(ceil(LOG2(real(NINPT))));
subtype datawrd is std_logic_vector((WIDTH-1) downto 0);
type mux_dat is array (0 to LOG2_NINPT, 0 to (NINPT-1)) of datawrd;
signal mux_flow: mux_dat;
for i in 1 to NINPT generate
mux_flow(0,i-1) <= datain((i*WIDTH-1) downto ((i-1)*WIDTH));
for i in 1 to LOG2_NINPT generate
for j in 0 to ((NINPT/(2**i))-1) generate
for k in 0 to (WIDTH-1) generate
O => mux_flow(i,j)(k),
I0 => mux_flow(i-1,2*j)(k),
I1 => mux_flow(i-1,2*j+1)(k),
S => chnsel(i-1)
-- variable selector: std_logic;
-- for i in 1 to LOG2_NINPT loop
-- selector := chnsel(i-1);
-- for j in 0 to ((NINPT/(2**i))-1) loop
-- for k in 0 to (WIDTH-1) loop
-- case selector is
-- when '1' =>
-- mux_flow(i,j)(k) <= mux_flow(i-1,2*j)(k);
-- when '0' =>
-- mux_flow(i,j)(k) <= mux_flow(i-1,2*j+1)(k);
-- when others =>
-- --mux_flow(i,j)(k) <= mux_flow(i,j)(k);
-- end case;
-- end loop;
-- end loop;
-- end loop;
-- end process;
dataout <= std_logic_vector(mux_flow(LOG2_NINPT,0));
tst <= AND_REDUCE(datain);
--tst <= datain(0);
I'm working in a project for Virtex 5 FPGA. However, when I synthesize the project and try to view the RTL it is empty. I repeated the design using a process but the problem occurs again.
Do anyone know what my error is or if there is a better way to implement my idea?
04-26-2012 05:15 PM
Simple code is good.
Readable (understandable) code is good.
Code with a predictable translation into hardware is good.
'Generic' code which is not simple and not readable... not so good. Even if it synthesises correctly.
To what end are you torturing yourself in this way?
-- Bob Elkind
04-27-2012 02:17 AM - edited 04-27-2012 02:19 AM
"To what end are you torturing yourself in this way?"
Just write code that infers the multiplexing functionality, and let the tools take care of the low-level details. They are actually quite good at that sort of thing now!
05-01-2012 10:02 AM
There is zero point in making a generic multiplexor. Absolutely none. The tools are pretty good at sorting out what you need without resorting to bizarre stuff.
Here are a couple of pro tips, though.
a) The width of each input vector can be arbitrary, and you don't even need a WIDTH generic to set it. Something like this (a two-input mux for clarity) solves the width problem neatly using unconstrained vectors on the port list. Note that it doesn't have to be its own entity (I rarely, if ever, create separate entities just for muxes):
entity Mux2To1 is
InA : in std_logic_vector;
InB : in std_logic_vector;
Select : in std_logic;
OutData : out std_logic_vector);
end entity Mux2To1;
architecture mux of Mux2To1 is
TheMux : process (InA, InB, Select) is
MuxSelect : if Select = '0' then
OutData <= InA;
OutData <= InB;
end if MuxSelect;
end process TheMux;
end architecture mux;
The size of the InA, InB and OutData vectors is set when the entity is instantiated. The port map's actuals (the signals on the right-hand side of each => in the port map) have to have known widths, and those known widths set the size of those vectors in that instance. You can have several instances of the same entity, each with different width ports.
(And if you do need to know the size of the vectors in the mux entity, you can use the 'length attribute.)
b) The mux select doesn't have to be a std_logic_vector. It can be a natural (with a range), for clarity. Here's some fun with attributes and subtypes.
architecture multiplex of foo is
constant WIDTH : natural := 32;
subtype muxdata_t is std_logic_vector(WIDTH-1 downto 0);
constant NUMINPUTS : natural := 10;
subtype select_t is natural range 0 to NUMINPUTS-1;
signal MuxSelect : select_t;
type muxinputs_t is array (select_t'range) of muxdata_t;
signal MuxInputs : muxinputs_t;
signal MuxOutput : muxdata_t;
-- ... assign to various MuxInputs as necessary
-- the mux:
MuxOutput <= MuxInputs(MuxSelect);
end architecture multiplex;
So there are lots of ways to do this. But let the tools do the work.