Electronic – Scaling an input in VHDL


I want to attenuate an incoming signal (16 bit signed number between -1 and 1) by a certain amount (let's say 0.8), i.e.,

incoming = incoming * 0.8

Where incoming is a signal:

signal incoming : std_logic_vector(15 downto 0);

But I'm having trouble getting this to work. Inside a process block:

variable temp : std_logic_vector(31 downto 0);
variable scale_factor : std_logic_vector(15 downto 0) := x"6666";


incoming_raw <= data_in;
temp := incoming_raw * scale_factor;
incoming <= temp(31 downto 16);

end process;

ModelSim doesn't like this and gives me:

# ** Error: /home/blah/blah.vhd(254): No feasible entries for infix operator "*".
# ** Error: /home/blah/blah.vhd(254): Bad right hand side (infix expression) in variable assignment.

Why can't the * operator do this when both operands are 16 bit std_logic_vectors?

Best Answer

You can do this quite elegantly with the new fixed_pkg:

pr_scale : process is    
    constant b : s_fixed(0 downto -15) := to_sfixed(0.8, 0, -15);
    variable x, y : s_fixed(0 downto -15);
    x        := to_sfixed(data_in, x);
    y        := resize( b * x, y);
    incoming <= to_slv(y);
end process;

As a side note I want to comment on the common misuse of types in VHDL: std_logic_vector is an array std_logic, which is a set of variables, signals or constants frequently used to model digital signals. std_logic_vector has no numerical interpretation by default, and therefore has no associated * operator. To do math on std_logic_vector you need to convert it to the correct type in one of the numerical libraries provided by the IEEE: ieee.fixed_pkgand ieee.numeric_std; only you know which one. Since both std_logic_vector and(un)signed are defined as arrays of std_logic they are closely-related types and can be converted with a simple cast. But due to the strong typing nature they are still different types and cannot me mixed.

As a closing remark I want to mention that there seem to be a widespread misunderstanding that you need to convert everything to std_logic_(vector). Most synthesis tools will handle numeric_std types, integers and booleans just fine, so there is no need to discard this valuable tool of abstraction because software twenty years ago didn't support it. To quote Abraham Lincoln:

The dogmas of the quiet past are inadequate to the stormy present.