0
votes

I'm writing a generic multiplier in VHDL, which should be able to be instantiated to handle any combination of signed and unsigned factors.

It's my understanding that, in order to do all 4 combinations of signed and unsigned multiplication from a single generic entity, and because there is no data type/ port that can accept both signed and unsigned values (no polymorphism), I'll need to pass both factors as std_logic_vectors and recast them as signed or unsigned depending on their signedness.

In order to feed my generic_multiplier my factors' signedness, because signedness is static, I have decided to pass in the strings "signed" or "unsigned" as generic arguments. Depending on these statements, generate statements will take care of the necessary typecasting and sign extension from std_logic to multipliable factors.

I'd like my module to throw an error if the user passes in any string other than "signed" or "unsigned" into my signedness argument during generic template instantiation. I can think of an ad-hoc way to do this with if-statements, but is there any way for me to define a set of strings universal to all multiplier modules (namely, {"signed", "unsigned"}), and throw a compiler error if my input string fails to lie within that set?

I know this is possible with SystemVerilog containers or meta-programming libraries, but I don't think I can convince my team to use these kinds of tools, and was wondering if there were any such constructs to assist metaprogramming in base VHDL.

1
Not at compile time, but Assert severity failure will do the job during elaboration. I'd suggest an enumeration (in a package) rather than strings, which would eliminate the possibility of invalid values.user_1818839

1 Answers

0
votes

Might this be easier to declare a signed*unsigned function, as signed * signed and unsigned * unsigned already exists in numeric_std. Then pass in the types and the function as generics to an entity (with VHDL 2008)? This way, it forces the user to define a multiply function. If you have the 4 options already available, you've got all your bases covered. If the user wants to use some other wacky type, they also have to define a "*" function for it.

function "*" (l :   signed; r : unsigned) return signed;
function "*" (l : unsigned; r :   signed) return signed;

entity mult_generic is
  generic (
    type op1_t;
    type op2_t;
    type mult_t;
    function "*" (l : op1_t; r: op2_t) return mult_t is <>;
  );

  port (
    clk : in std_logic;

    op1  : op1_t;
    op2  : op2_t;
    mult : mult_t;
  );
end entity mult_generic;

architecture rtl of mult_generic is
begin

  process(clk)
  begin
    if rising_edge(clk) then
      mult <= op1 * op2;
    end if;
  end process;

end architecture;

....

--example
mult_inst : entity work.mult_generic
generic map (
  op1_t => unsigned;
  op2_t => signed;
  mult_t => signed;
)
port map (
  --etc
);