Search code examples
cvhdl

Converting C Macro to VHDL


I'm fairly new to VHDL and trying to convert two given C macros to be executed as a single instruction on my FPGA. The macros are:

#define m_in_bits(buf, num) (buf) >> (24 - (num)) // buf is uint32_t
#define m_ext_bits(buf, i) ((buf) < (1<<((i)-1)) ? (buf) + (((-1)<<(i)) + 1) : (buf))

And the C code that uses the macros is:

m_ext_bits(m_in_bits(buffer, size), size);

I'm having issues with getting m_ext_bits to properly compile. Here's my VHDL:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity myEntity is
port(
  signal buffer: in std_logic_vector(31 downto 0);
  signal result: out std_logic_vector(31 downto 0)
);
end entity myEntity;

architecture myArch of myEntity  is
  signal size : signed (3 downto 0);
begin

size <= signed(buffer(27 downto 24));

result(15 downto 0) <= std_logic_vector(signed(buffer(23 downto 0)) srl (24 - to_integer(size))
                     + signed((-1 sll to_integer(size)) + 1)); -- the offending line

end architecture myArch ;

The long line beginning with result(15 downto 0) <= actually compiles without error (that implements the m_in_bits macro). However, when I add the following line, beginning with the +, errors occur. I tried playing around with casting the std_logic_vector and signed types and the errors change.

type of expression is ambiguous - "SIGNED" or "UNSIGNED" are two possible matches...
can't determine definition of operator ""sll"" -- found 0 possible definitions...
illegal SIGNED in expression...

I think it's a matter of proper casting and using the correct types to fulfill the required operations.


Solution

  • First, buffer is a reserved VHDL word, so change that; using argbuf below.

    The expression -1 sll to_integer(size) is not defined in VHDL, since the integer value -1 is a numerical expression only with no bit representation specified by VHDL, so shifting is not possible. Neither are operations like bitwise and, or, etc. on integers. A -1 representation in 24-bit signed type can be created as:

    to_signed(-1, 24)
    

    There is a length issue with the assign, since 16-bit signal (result(15 downto 0)) is assigned with 24-bit value (based on right side argbuf(23 downto 0)).

    The srl should then compile when the above is addressed.

    Code as:

    result(15 downto 0) <= std_logic_vector(resize((signed(argbuf(23 downto 0)) srl (24 - to_integer(size)))
                                                   + signed((to_signed(-1, 24) sll to_integer(size)) + 1), 16));
    

    However, the VHDL shift operators, e.g. srl, may give unexpected results, as described in this page "Arithmetic and logical shifts and rotates are done with functions in VHDL, not operators", so you may consider using the shift functions defined in numeric_std instead, e.g. shift_right, as a general coding style. Code with functions as:

    result(15 downto 0) <= std_logic_vector(resize(shift_right(signed(argbuf(23 downto 0)), 24 - to_integer(size))
                                                   + signed(shift_left(to_signed(-1, 24), to_integer(size)) + 1), 16));