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.
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));