how to make a fully generic MUX in VHDL 93 - vhdl

I would like to synthesis a generic MUX with two generics :
addressSize (in number of words)
wordSize (in bits)
This seems fairly easy as per these very similar question : 3459057 and 32562488. The catch is : I must use vhdl 93, and both the answer assumes vhdl 2008 and/or only one of the generics to be a given.
entity Mux is
generic (
addressSize : integer := 2;
wordSize : integer := 32
);
port (
…
);
end entity;
architecture RTL of Mux is
begin
…
end architecture;
I'm stuck, Indeed, in vhdl 93, I may not use unconstrained std_logic_vector in array:
package common is
type WORD_ARRAY_type is array (integer range <>) of std_logic_vector;
end package;
Which would have let me use both generics has such :
port(
input : WORD_ARRAY_type(0 to addressSize)(wordSize - 1 downto 0);
…
);
and, of course, I may not define a type in between the generics and ports. The thing is, I must certainly not be the first person who encounters this specific question so I wander : "How would one do this very classic function in VHDL 93 ?"

I understand what you think you want, however, for a small combinational logic block like this, I would use a function instead and then use overloading to define the a Mux function for each Mux size you need:
function Mux (
sel : std_logic ;
A1 : std_logic_vector ;
A2 : std_logic_vector
) return std_logic_vector is
variable Y : std_logic_vector(A1'range) ;
begin
case sel is
when '0' => Y := A1 ;
when '1' => Y := A2 ;
when others => Y := (others => 'X') ;
end case ;
return Y ;
end function Mux ;
Yes it is brute force to develop the package, but once done, it is very simple to use. Reference the package and do the function call. And since it is a function, you can chain the outputs together.
MuxOut <= Mux(Sel, A, B) and Mux(Sel, C, D) ;
If you would like to see something like this in the IEEE standard (which would be a good idea), reach out to me and I can help you get started in participating.
Above, I enforced the sizing to be the same by using the variable. VHDL-2019 gives us better options. In fact, it gives us ways to allow the types of A1, ... to be more flexible than just std_logic_vector.
Adding on the #Tricky method, but applying it to subprograms:
function Mux (
Width : integer ;
sel : integer ;
A : std_logic_vector
) return std_logic_vector is
alias normalizedA : std_logic_vector(0 to A'length-1) is A ;
constant WordStart : integer := width * sel ;
begin
return normalizedA(WordStart to WordStart + Width - 1) ;
end function Mux ;

Related

std_logic_vector to integer conversion vhdl

I faced with conversion problem/I read a lot of similar topics but my code still not working.Could you pls give me some hints. Quartus give me error:
Error (10476): VHDL error at true_dual_port_ram_single_clock.vhd(44): type of identifier "random_num_i" does not agree with its usage as "std_logic_vector" type
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use IEEE.std_logic_signed.all;
use IEEE.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
entity write_ram is
generic(width : integer := 32);
port(clock_i : IN STD_LOGIC;
we_w : IN STD_LOGIC;
wr_addr : IN INTEGER RANGE 0 to 31;
read_add : IN INTEGER RANGE 0 to 31;
q_out : out STD_LOGIC_VECTOR(2 DOWNTO 0)
);
end write_ram;
architecture rtl of write_ram is
--- Component decalarartion
component random is
port(clk : in std_logic;
random_num : out std_logic_vector(width - 1 downto 0) --output vector
);
end component;
component single_clock_ram is
port(clock : IN STD_LOGIC;
data : IN INTEGER RANGE 0 to 31;
write_address : IN INTEGER RANGE 0 to 31;
read_address : IN INTEGER RANGE 0 to 31;
we : IN STD_LOGIC;
q : OUT STD_LOGIC_VECTOR(2 DOWNTO 0)
);
end component;
for all : random use entity work.random(rtl);
for all : single_clock_ram use entity work.single_clock_ram(rtl);
Signal random_num_i : INTEGER RANGE 0 to 31; --interanal signals
begin
-- Component Instantiation
C1 : random Port map(
clk => clock_i,
--random_num <=to_integer(to_signed(random_num_i))
random_num => random_num_i
);
random_num <= to_integer(to_signed(random_num_i)); -- error
C2 : single_clock_ram
Port map(
clock => clock_i,
we => we_w,
read_address => read_add,
write_address => wr_addr,
data => random_num_i,
q => q_out
);
end rtl;
Your question isn't an MCVE with the configuration specifications for random and single_clock_ram present. You didn't supply the entity declarations and architecture bodies (rtl) for them.
With them commented out this analyzes:
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_signed.all; -- NOT USED
-- use ieee.std_logic_unsigned.all; -- NOT USED
use ieee.numeric_std.all;
-- use ieee.std_logic_arith.all; -- NOT USED
entity write_ram is
generic (width: integer := 32);
port (clock_i: in std_logic;
we_w: in std_logic;
wr_addr: in integer range 0 to 31;
read_add: in integer range 0 to 31;
q_out: out std_logic_vector(2 downto 0)
);
end entity write_ram;
architecture rtl of write_ram is
--- component declaration
component random is
port (clk: in std_logic;
random_num: out std_logic_vector(width - 1 downto 0) --output vector
);
end component;
component single_clock_ram is
port (clock: in std_logic;
data: in integer range 0 to 31;
write_address: in integer range 0 to 31;
read_address: in integer range 0 to 31;
we: in std_logic;
q: out std_logic_vector(2 downto 0)
);
end component;
-- for all: random use entity work.random(rtl);
-- for all: single_clock_ram use entity work.single_clock_ram(rtl);
signal random_num_i: integer range 0 to 31; -- internal signals
signal random_num: std_logic_vector(width - 1 downto 0); -- added
begin
-- component instantiation
c1: random port map (
clk => clock_i,
-- random_num <=to_integer(to_signed(random_num_i))
-- random_num => random_num_i -- DELETED
random_num => random_num -- ADDED
);
-- random_num <= to_integer(to_signed(random_num_i)); -- error DELETED
random_num_i <= to_integer(signed(random_num)); -- ADDED
c2: single_clock_ram
port map (
clock => clock_i,
we => we_w,
read_address => read_add,
write_address => wr_addr,
data => random_num_i,
q => q_out
);
end architecture rtl;
Note there's been a random_num std_logic_vector declared to hook up to the output of random, which is converted an integer random_num_i used as an input to single_clock_ram data. The output q from the single_clock_ram looks a bit suspicious, should that be an integer or a wider std_logic_vector?
First, delete the non-standard libraries.
use IEEE.std_logic_signed.all;
use IEEE.std_logic_unsigned.all;
use IEEE.STD_LOGIC_ARITH.ALL;
leaving only std_logic_1164 and numeric_std.
The others introduce a bunch of overlapping declarations which make it difficult to determine what is going on - and if there are several declarations for the same operator with the same argument and result types, the compiler makes them all invisible rather than picking an arbitrary one.
Then, decide what you are trying to do. This is currently ambiguous and contradictory.
(1)You have a generic (width : integer :=32); and a port declaration
random_num : out std_logic_vector (width-1 downto 0)
which suggest you are dealing with 32 bit words.
(2) You have a ranged integer : Signal random_num_i: INTEGER RANGE 0 to 31; which (a) should be a ranged NATURAL to make it even clearer that negative values are errors, and (b) suggests you are dealing with 5 bit words.
Which is it? What exactly are you trying to do?
And here, you are apparently trying to connect them together in a port map...
C1: random Port map (
clk => clock_i,
--random_num <=to_integer(to_signed(random_num_i))
random_num =>random_num_i
);
random_num <=to_integer(to_signed(random_num_i)); -- error
There are a number of things wrong here.
1) A simple port mapping like random_num =>random_num_i requires that both sides have the same type. This would work if both sides actually WERE the same type : for example, if you added a signal declaration
random_num_slv : std_logic_vector (width-1 downto 0);
then the port mapping random_num =>random_num_slv would work. Now you can convert to the required type random_num_i in a signal assignment.
random_num_i <= to_integer (unsigned(random_num_slv));
There are still problems with this : a 32-bit output is likely to overflow a 5-bit integer.
While adding an intermediate signal random_num_slv may look inefficient and redundant, it keeps the design clean and simple, which matters when dealing with tools that don't understand type conversions in ports.
Make sure you know how to use intermediate signals even if there's a cleaner approach. It can save you when all else fails.
(2) The commented out port mapping
random_num <=to_integer(to_signed(random_num_i))
would be the way to do it, except for three things ...
(a) <= is a signal assignment, you need => a n association operator
(b) you're converting an integer to an integer, and driving a std_logic_vector with it. That really won't work...
(c) the component port is an OUTPUT so you shouldn't be driving it in the first place.
What you probably meant was
to_integer(unsigned(random_num)) => random_num_i
and this would be the cleanest way to do it if your tools support conversions in port maps properly.
Notes:
again it has the overflow problem, a 32-bit vector won't fit a 5 bit integer.
You can convert from std_logic_vector to either signed or unsigned by casting unsigned rather than a conversion function to_signed as they are closely related types. Integers are not "closely related" to these, so need a conversion function to_integer.
As negative numbers aren't permitted by the declaration of random_num_i, use unsigned rather than signed.
(3) The existing signal assignment
random_num <=to_integer(to_signed(random_num_i)); -- error
again contains several errors. The biggest is that there is no random_num port visible outside the component declaration. Simply delete this line, you need to use one of the port mappings.
Further considerations:
(1) Some type conversions are inevitable. But if you are doing too many, that generally points to a design error, like the use of std_logic_vector everywhere, even for thengs like addresses which are inevitably unsigned integers so either unsigned ornatural would be a better choice. Keep the design as simple and readable as possible. I think your use of integer here is generally good but natural would be better (unless you need negative addresses!)
(2) If you're adding the flexibility of a generic like width, use it correctly and consistently - OR - check it's valid.
Here, as described above, your design ONLY works correctly without surprises IF this entity is instantiated with width => 5.
So, check the value and abort if this precondition is not met.
assert Width = 5 report "Width of " & natural'image(width) & " not supported!"
severity FAILURE;
OR make the design work for all reasonable values of the generic, for example by making other quantities dependent on it in valid ways. For example:
constant DEPTH : natural := 2**WIDTH - 1;
signal random_num_i : natural range 0 to DEPTH;
and so on...

Generic Multiplexer warning

I created a generic multiplexer( on number of inputs and bits per input) in VHDL. I tested it and it works correctly but I get a width mismatch warning:
Width mismatch. < output > has a width of 8 bits but assigned expression is 64-bit wide.
This is the code of my generic MUX. Can anyone explain me why I get this warning? WHat's wrong with my code? My professor wants me to implement this without the use of process. Thanks
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.package_log.all;
use IEEE.NUMERIC_STD.ALL;
entity mux_generic is
generic(N : natural :=8;
M : natural := 8);
-- N: number of inputs
-- M: bit per input/output
Port ( input : in STD_LOGIC_VECTOR (N*M-1 downto 0);
sel: in STD_LOGIC_VECTOR (log2ceil(N)-1 downto 0);
output : out STD_LOGIC_VECTOR (M-1 downto 0));
end mux_generic;
architecture DataFlow of mux_generic is
begin
output <= input(M*(to_integer(unsigned(sel))+1) - 1 downto M*(to_integer(unsigned(sel))));
end DataFlow;
The function log2ceil is defined in this way:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package package_log is
function log2ceil( n : natural) return natural;
end package_log;
package body package_log is
function log2ceil (N : natural) return natural is
variable i, j : natural;
begin
i := 0;
j := 1;
while (j < N) loop
i := i+1;
j := 2*j;
end loop;
return i;
end function log2ceil;
end package_log;
Please update to the lastest ISE version 14.7, if you haven't done so far. Then enable the new parser for your Spartan-3E FPGA:
Right click on Synthesize -> Process Properties.
Change property display level to "Advanced".
For property "Other XST Command Line Options" enter -use_new_parser yes.
Now the warning goes away. A new warning appears, just noting, that the new parser is not the default one. But, I didn't experienced a problem with this yet.
By the way, your multiplexer description is not yet efficient. Take at look at my other post, for different implementations and their effects on resource usage and timing analysis.

AND all elements of an n-bit array in VHDL

lets say I have an n-bit array. I want to AND all elements in the array. Similar to wiring each element to an n-bit AND gate.
How do I achieve this in VHDL?
Note: I am trying to use re-usable VHDL code so I want to avoid hard coding something like
result <= array(0) and array(1) and array(2)....and array(n);
Thanks
Oshara
Solution 1: With unary operator
VHDL-2008 defines unary operators, like these:
outp <= and "11011";
outp <= xor "11011";
outp <= and inp; --this would be your case
However, they might not be supported yet by your compiler.
Solution 2: With pure combinational (and traditional) code
Because in concurrent code you cannot assign a value to a signal more than once, your can create a temp signal with an "extra" dimension. In your case, the output is one-bit, so the temp signal should be a 1D array, as shown below.
-------------------------------------------
entity unary_AND IS
generic (N: positive := 8); --array size
port (
inp: in bit_vector(N-1 downto 0);
outp: out bit);
end entity;
-------------------------------------------
architecture unary_AND of unary_AND is
signal temp: bit_vector(N-1 downto 0);
begin
temp(0) <= inp(0);
gen: for i in 1 to N-1 generate
temp(i) <= temp(i-1) and inp(i);
end generate;
outp <= temp(N-1);
end architecture;
-------------------------------------------
The inferred circuit is shown in the figure below.
Solution 3: With sequential code
This is simpler than solution 2, though you are now using sequential code to solve a purely combinational problem (but the hardware will be the same). You can either write a code similar to that in solution 2, but with a process and loop (the latter, in place of generate) or using a function. Because in sequential code you are allowed to assign a value to a signal more than once, the temp signal of solution 2 is not needed here.
If you have VHDL-2008 available, then reduction and is build into the
language as David Koontz and Pedroni have explained.
If you only have VHDL-2003 and prior available, then you can use a function
like:
function and_reduct(slv : in std_logic_vector) return std_logic is
variable res_v : std_logic := '1'; -- Null slv vector will also return '1'
begin
for i in slv'range loop
res_v := res_v and slv(i);
end loop;
return res_v;
end function;
You can then use the function both inside and outside functions with:
signal arg : std_logic_vector(7 downto 0);
signal res : std_logic;
...
res <= and_reduct(arg);
My favorite, non-VHDL-2008 solution is:
use ieee.std_logic_unsigned.all ; -- assuming not VHDL-2008
. . .
result <= '1' when not MyArray = 0 else '0' ;
With VHDL-2008, I recommend that you use the "and" reduction built-in (see Pedroni's post) and use the IEEE standard package "ieee.numeric_std_unsigned.all" instead of the shareware package "std_logic_unsigned".

Conversion from numeric_std unsigned to std_logic_vector in vhdl

I have a question related to conversion from numeric_std to std_logic_vector. I am using moving average filter code that I saw online and filtering my ADC values to stable the values.
The filter package code is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package filterpack is
subtype number is unsigned(27 downto 0);
type numbers is array(natural range <>) of number;
function slv_to_num(signal slv: in std_logic_vector) return number;
procedure MAF_filter(
signal x: in number;
signal h: inout numbers;
signal y: out number
);
end filterpack;
package body filterpack is
function slv_to_num(signal slv: in std_logic_vector) return number is
variable x: number := (others => '0');
begin
for i in slv'range loop
if slv(i) = '1' then
x(i+4) := '1';
end if;
end loop;
return x;
end function slv_to_num;
procedure MAF_filter(
signal x: in number;
signal h: inout numbers;
signal y: out number
) is
begin
h(0) <= x + h(1); -- h[n] = x[n] + h[n-1]
y <= h(0) - h(h'high); -- y[n] = h[n] - h[n-M]
end MAF_filter;
end package body filterpack;
In my top level file, I call the MAF_filter procedure.
Asign_x: x <= slv_to_num(adc_dat);
Filter: MAF_filter(x,h,y);
The adc_dat is defined as:
adc_dat : out std_logic_vector (23 downto 0);
I want to convert the output of the MAF_Filter to std_logic_vector (23 downto 0). Can anyone tell how can I convert filter output 'y' to 'std_logic_vector'?
Many Thanks!
What do you want to do with the 4 extra bits? Your type number has 28 bits, but your signal adc_dat has only 24.
If it's ok to discard them, you could use:
adc_dat <= std_logic_vector(y(adc_dat'range));
Also, is there a reason not to write your function slv_to_num as shown below?
function slv_to_num(signal slv: in std_logic_vector) return number is
begin
return number(slv & "0000");
end function slv_to_num;
The conversion has to solve 2 problems : the type difference you noted, and the fact that the two words are different sizes.
The type difference is easy : std_logic_vector (y) will give you the correct type. Because the two types are related types, this is just a cast.
The size difference ... only you have the knowledge to do that.
adc_dat <= std_logic_vector(y(23 downto 0)) will give you the LSBs of Y - i.e. the value of Y itself, but can overflow. Or as Rick says, adc_dat <= std_logic_vector(y(adc_dat'range)); which is usually better, but I wanted to expose the details.
adc_dat <= std_logic_vector(y(27 downto 4)) cannot overflow, but actually gives you y/16.

How to make a simple 4 bit parity checker in VHDL?

I am trying to learn VHDL and I'm trying to make 4-bit parity checker. The idea is that the bits come from one input line (one bit per clock pulse) and the checker should find out if there is odd number of 1s in the 4-bit sequence (i.e 1011 , 0100 , etc.) and send an error output(e.g error flag: error <=´1´) if there is.
Would someone give me an example how it´s done, so that I can study it?
I have tried searching the web, but all the discussions I found were related to something way more complicated and I could not understand them.
VHDL 2008 standard offers a new xor operator to perform this operation. Much more simple than the traditional solution offered by Aaron.
signal Data : std_logic_vector(3 downto 0) ;
signal Parity : std_logic ;
. . .
Parity <= xor Data ;
This assumes "invec" is your input std_logic_vector:
parity <= invec(3) xor invec(2) xor invec(1) xor invec(0);
If it got any larger than 4 inputs, a loop would probably be best:
variable parity_v : std_logic := '0';
for i in invec'range loop
parity_v := parity_v xor invec(i);
end loop;
parity <= parity_v;
That loop would be converted into the proper LUT values at synthesis time.
(I did this from memory; may be slight syntax issues.)
small syntax error in the code. should remove ":" after loop.
library ieee;
use ieee.std_logic_1164.all;
entity bus_parity is
generic(
WPARIN : integer := 8
);
port(
parity_in : in std_logic_vector(WPARIN-1 downto 0);
parity_out : out std_logic
);
end entity;
architecture rtl of bus_parity is
begin
process(parity_in)
variable i : integer;
variable result: std_logic;
begin
result := '0';
for i in parity_in'range loop
result := result xor parity_in(i);
end loop;
parity_out <= result;
end process;
end architecture;
Or in Verilog:
`timescale 1ns/10ps
`default_nettype none
module bus_parity #(
parameter WPARIN = 8
) (
input wire [WPARIN-1:0] parity_in,
output reg parity_out
);
always #* begin : parity
integer i;
reg result;
result = 1'b0;
for(i=0; i < WPARIN-1; i=i+1) begin
result = result ^ parity_in[i];
end
parity_out = result;
end
endmodule
`default_nettype wire

Resources