- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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 ;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page