Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16593 Discussions

Generic One-Hot Multiplexer

Altera_Forum
Honored Contributor II
3,506 Views

I am looking for a way to dynamic instantiate a multiplexer of N channels which has a one-hot encoded select. My current hard-coded version for a 3 channel system looks like this: 

 

signal ChannelSelect : unsigned(CHAN_SEL_BITS-1 downto 0); signal EventOneHotFlag : std_logic_vector(NUM_CHANNELS-1 downto 0); ..... ChannelSelect <= "00" when EventOneHotFlag(0) = '1' else "01" when EventOneHotFlag(1) = '1' else "10" when EventOneHotFlag(2) = '1' else "00"; MuxOutputData <= MuxInputArray(to_integer(ChannelSelect))  

 

However, I also have up to 32 channels in some systems that result in the following: 

 

 

ChannelSelect <= '0'&x"0" when EventOneHotFlag(0) = '1' else '0'&x"1" when EventOneHotFlag(1) = '1' else '0'&x"2" when EventOneHotFlag(2) = '1' else '0'&x"3" when EventOneHotFlag(3) = '1' else .... Sparing you the whole list...... '1'&x"D" when EventOneHotFlag(29) = '1' else '1'&x"E" when EventOneHotFlag(30) = '1' else '1'&x"F" when EventOneHotFlag(31) = '1' else '0'&x"0"; MuxOutputData <= MuxInputArray(to_integer(ChannelSelect))  

 

Both work correctly, but I have not found a synthesize solution to parameterize the mux to make it generic for use across system builds. I have been unsuccessful trying Generate statements or For Loops to handle the One-Hot select case.  

 

Thanks, 

Aaron
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
1,986 Views

 

--- Quote Start ---  

I am looking for a way to dynamic instantiate a multiplexer of N channels which has a one-hot encoded select. My current hard-coded version for a 3 channel system looks like this: 

 

Both work correctly, but I have not found a synthesize solution to parameterize the mux to make it generic for use across system builds. I have been unsuccessful trying Generate statements or For Loops to handle the One-Hot select case.  

 

Thanks, 

Aaron 

--- Quote End ---  

 

 

Here is a solution with a for loop

entity combmuxs is generic ( WIDTH_D : natural := 4 ; SIZE : natural := 16 ) ; port ( D : in std_logic_2D( SIZE - 1 downto 0 , WIDTH_D - 1 downto 0) ; Sel : in std_logic_vector(SIZE - 1 downto 0) ; Q : out std_logic_vector(WIDTH_D - 1 downto 0) ) ; end combmuxs ; architecture a of combmuxs is function smux3( d : std_logic_2D ; sel : std_logic_vector) return std_logic_vector is variable r : std_logic_vector( d'high(2) downto 0) ; begin r:= (others => '0') ; -- default return if none selected for i in 0 to d'high(1) loop if (sel(i) = '1') then return to_std_logic_vector( d , i ) ; end if ; end loop ; return r ; end function ; begin process( D , Sel ) begin Q <= smux3(D , Sel) ; end process ; end a ;  

It is written for a std_logic_2d from the lpm_components package but it is easy to replace this by a 1Dx1D array. I have written it as a function so I could test other approaches, like a recursive version. 

I add the supporting function: 

function to_std_logic_vector( source : std_logic_2D ; idx : natural ) return std_logic_vector is variable r : std_logic_vector( source'high(2) downto 0) ; begin for i in 0 to source'high(2) loop r(i) := source(idx , i) ; end loop ; return r ; end function ;
0 Kudos
Altera_Forum
Honored Contributor II
1,986 Views

If you're happy to use VHDL 2008, you can avoid the annoying (IMO) std_logic_2d type: 

 

--in a package: type slv_array_t is array(integer range <>) of std_logic_vector; .... entity combmuxs is generic ( WIDTH_D : natural := 4 ; SIZE : natural := 16 ) ; port ( D : in slv_array_t( SIZE - 1 downto 0)(WIDTH_D - 1 downto 0) ; Sel : in std_logic_vector(SIZE - 1 downto 0) ; Q : out std_logic_vector(WIDTH_D - 1 downto 0) ) ; end combmuxs ; architecture a of combmuxs is function smux3( d : slv_array_t ; sel : std_logic_vector) return std_logic_vector is constant r : std_logic_vector( d(0)'range ) := (others=>'0'); begin for i in d'range loop if (sel(i) = '1') then return d(i) ; end if ; end loop ; return r ; end function ; begin process( D , Sel ) begin Q <= smux3(D , Sel) ; end process ; end architecture;
0 Kudos
Altera_Forum
Honored Contributor II
1,986 Views

 

--- Quote Start ---  

If you're happy to use VHDL 2008, you can avoid the annoying (IMO) std_logic_2d type: 

 

--in a package: type slv_array_t is array(integer range <>) of std_logic_vector; .... entity combmuxs is generic ( WIDTH_D : natural := 4 ; SIZE : natural := 16 ) ; port ( D : in slv_array_t( SIZE - 1 downto 0)(WIDTH_D - 1 downto 0) ; Sel : in std_logic_vector(SIZE - 1 downto 0) ; Q : out std_logic_vector(WIDTH_D - 1 downto 0) ) ; end combmuxs ; architecture a of combmuxs is function smux3( d : slv_array_t ; sel : std_logic_vector) return std_logic_vector is constant r : std_logic_vector( d(0)'range ) := (others=>'0'); begin for i in d'range loop if (sel(i) = '1') then return d(i) ; end if ; end loop ; return r ; end function ; begin process( D , Sel ) begin Q <= smux3(D , Sel) ; end process ; end architecture;  

--- Quote End ---  

 

 

I just wanted to show the use of a for loop

This code was originally written before Quartus supported VHDL-2008 and unconstrained arrays of unconstrained std_logic_vector. The std_logic_2D was/is highly underrated (IMO). Mind you, Altera used std_logic_2D to model the array ports of their AHDL-based LPM_COMPONENT blocks. I have written (had to) numerous supporting functions to support the std_logic_2D type and it beat (at the time) writing custom packages for every user array-type ... and allowing very modular code. E.g. in Qsys you can only transport std_logic_vector, so I wrote a general function to convert this into a std_logic_2D and vice-versa. 

 

I also have a recursive approach on the OP's requirement, this involves a few more std_logic_2D (and std_logic_vector) support functions 

-- overloading the "and" operator function "and" ( s : std_logic ; v : std_logic_vector) return std_logic_vector is variable r : std_logic_vector(v'high downto 0) ; begin for i in 0 to v'high loop r(i) := s and v(i) ; end loop ; return r ; end function ; function "and" (v : std_logic_vector ; s : std_logic ) return std_logic_vector is variable r : std_logic_vector(v'high downto 0) ; begin for i in 0 to v'high loop r(i) := s and v(i) ; end loop ; return r ; end function ; function smux( d : std_logic_2D ; sel : std_logic_vector) return std_logic_vector is begin if (d'high(1) = 0) then return ( sel(0) and to_std_logic_vector(d , 0) ) ; elsif (d'high(1) = 1) then return( (sel(0) and to_std_logic_vector(d , 0)) or (sel(1) and to_std_logic_vector(d , 1)) ) ; else return ( smux( split_std_logic_2D(d , UPPER) , split_slv( sel , UPPER) ) or smux( split_std_logic_2D(d , LOWER) , split_slv( sel , LOWER) ) ) ; end if ; end function ;  

The split functions divide a std_logic_2D/std_logic_vector in two parts. 

The nice thing about the recursive version is that iso converting the one-hot bit into an index and then accessing an array, it builds a binary tree of and and or functions. 

 

Anyway, that's behind me now. I now develop with myhdl (http://www.myhdl.org), which is a Python library for HDL development. It beats VHDL for writing (self-checking) test-benches by a mile...
0 Kudos
Altera_Forum
Honored Contributor II
1,986 Views

Thanks everyone. An updated For Loop function for the One-Hot to Integer conversion worked. In my case I am driving multiple Muxes and have some other logic based on channel number. I ended up with a converting to an integer output to drive Mux selects and that I could also cast to unsigned: 

 

-- Convert One-Hot array to integer channel select function ONEHOT_TO_INT( OneHotCode : std_logic_vector ) return integer is constant DefaultReturn: integer := 0; begin for NumChan in OneHotCode'range loop if (OneHotCode(NumChan) = '1') then return NumChan; end if; end loop; return DefaultReturn; end function; ........ ChannelSelect <= ONEHOT_TO_INT(EventOneHotFlag); SomeData_slv <= (others => '0') when (ChannelSelect = LAST_CHANNEL) else std_logic_vector(OtherData_u(ChannelSelect)); PacketOut_slv <= Header_slv & std_logic_vector(to_unsigned(ChannelSelect, 8)) & PacketData_slv;
0 Kudos
Reply