Related to this: Scaling an input in VHDL, but different enough that I feel it warrants a new question.
I feel this should be simpler that I'm making it.
I have a stream of signed 16 bit samples which I want to attenuate by about 0.5 dB, but let's just use nicer numbers for the sake of illustration. I need:
-32000 (almost -1.0) -> -25600 +32000 (almost +1.0) -> +25600
Simple right? I'm stuck because the multiplication operator must take either signed or unsigned operands, not a mixture of both (that makes sense).
Here is what I initially tried:
variable scale_factor : std_logic_vector(15 downto 0) := x"EFFF"; attenuated_sample <= std_logic_vector(unsigned(sample) * unsigned(scale_factor));
This doesn't work; it makes positive samples smaller but negative samples more negative.
The only way I've managed to achieve what I want is by multiplying the signed sample by a signed scale factor, but I've had to make the scale factor have an extra few zeros at the front so that it is always positive. I.e.,
variable temp : std_logic_vector(39 downto 0); variable scale_factor : std_logic_vector(19 downto 0) := x"0EFFF"; temp := std_logic_vector(resize(signed(sample), 20) * signed(scale_factor); attenuated_sample <= temp(31 downto 16);
This appears to work, but I don't like it because it's ugly. What is the correct way to go about this?