VHDL: Combining multiplication and slicing into one line - vhdl

I have a hardware accelerated function that requires two instances of fixed point multiplication. My current solution (example below) requires two clock cycles per multiplication; one step of multiplication, followed by a second step where that value is sliced back to the original input word size. I would like this to take as few cycles as necessary for latency.
Here is my current solution:
signal a : std_logic_vector(7 downto 0);
signal b : std_logic_vector(7 downto 0);
signal y : std_logic_vector(7 downto 0);
signal product : std_logic_vector(15 downto 0);
MULTIPLY_PROCESS : process(clk)
begin
if(rising_edge(clk)) then
product <= std_logic_vector(unsigned(a) * unsigned(b));
y <= product(11 downto 4); --takes one additional clock cycle
end if; --for y to appear
end process;
It makes sense to me that this could be shrunk down to one clock cycle, as normal unsigned multiplication does this automatically by throwing out the top end of the oversized vector.
example:
signal a : std_logic_vector(7 downto 0);
signal b : std_logic_vector(7 downto 0);
signal y : std_logic_vector(7 downto 0);
MULTIPLY_PROCESS : process(clk)
begin
if(rising_edge(clk)) then
y <= std_logic_vector(unsigned(a) * unsigned(b)); --truncates automatically
end if;
end process;
This is code I thought would work, but throws a compiler error:
y <= std_logic_vector(unsigned(x) * unsigned(a))(11 downto 4)
Error: Prefix of slice name cannot be type conversion (STD_LOGIC_VECTOR) expression.
Is there some way to fixed-point multiply and truncate in a single line/step/clock cycle?

Credit to user1155120. Calling the multiplication through a function and then slicing the function before conversion does the trick.
y <= std_logic_vector("*"(unsigned(x), unsigned(a))(11 downto 4));

Related

8 bit serial to parallel shifter in vhdl

I programmed an 8-bit shifter in vhdl:
entity 8b is
port(s, clk : in std_logic; p : out std_logic_vector (7 downto 0));
end entity;
architecture arch of 8b is
Signal iq : std_logic_vector (7 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
end if;
end process;
p <= iq;
end architecture;
The idea is that I'm taking input and giving it to my first D-FF.
Then over the next 7 cycles, the other Flip Flops get the other serial inputs which will be given to the parallel output p.
However, I'm not sure if this logic is flawed because this is the solution we got for this exercise:
architecture behavior of 8b is
signal p_intern : std_logic_vector(7 downto 0);
begin
P <= p_intern;
process(CLK)
begin
if rising_edge(CLK) then
p_intern <= p_intern(6 downto 0) & S;
end if;
end process;
end architecture;
But I don't get the p_intern <= p_inter(6 downto 0) & S; part.
Can someone please explain the logic behind this and if my version is also valid?
The only difference between the two implementations seem to be the lines
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
vs.
p_intern <= p_intern(6 downto 0) & S;
and that iq is named p_intern. Let's assume they are both named iq for the sake of comparison.
Let's see what they are doing:
The first implementation (yours) assigns to the positions of iq:
7 6 5 ... 1 0
s iq(7) iq(6) ... iq(2) iq(1)
The second implementation (the solution) assigns
7 6 5 ... 1 0
iq(6) iq(5) iq(4) ... iq(0) s
Where iq(6 downto 0) & s means "concatenate s to the right of iq(6 downto 0)".
So they are not equivalent. Your implementation shifts in the values from the left, and the solution shifts in the values from the right. Which one is correct depends on the specification (presumably the solution is correct).

Width mismatch in assignment: VHDL

My code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library work;
use work.costanti.all;
entity Multiplier is
generic(nbA:integer:=nbA;
nbB:integer:=nbB);
port (
A: in STD_LOGIC_VECTOR(nbA-1 downto 0);
B: in STD_LOGIC_VECTOR(nbB-1 downto 0);
clk: in STD_LOGIC;
R: out STD_LOGIC_VECTOR(nbA+nbB-1 downto 0));
end Multiplier;
architecture Behavioral of Multiplier is
component AdderTree is
generic(nbit: integer:=nbA+nbB);
port (
IN1: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN2: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN3: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN4: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN5: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN6: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN7: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN8: in STD_LOGIC_VECTOR(nbit-1 downto 0);
IN9: in STD_LOGIC_VECTOR(nbit-1 downto 0);
S: out STD_LOGIC_VECTOR(nbit-1 downto 0)
);
end component;
signal V : STD_LOGIC_VECTOR(nbA-1 downto 0);
signal P : STD_LOGIC_VECTOR((nbA*nbB)-1 downto 0);
signal PP_0to6 : STD_LOGIC_VECTOR( (nbA)+(nbA+1)+(nbA+2)+(nbA+3)+(nbA+4)+(nbA+5)+(nbA+6)-1 downto 0); --(dim(pp0+PP1+PP2+PP3+PP4+PP5+PP6) downto 0 )
signal PP7 : STD_LOGIC_VECTOR(nbA+nbB-1 downto 0);
signal P7 : STD_LOGIC_VECTOR(nbA downto 0);
signal PPP : STD_LOGIC_VECTOR((nbA+nbB)*(nbB+1)-1 downto 0);
begin
for_g: for i in 0 to nbB-1 generate
V <= (others => B(i));
P((nbB)*(i)+(nbB-1) downto (nbB)*(i)) <= V and A;
end generate for_g;
P7 <= '0' & P((nbA*nbB)-1 downto (nbA*nbB)-1-(nbB-1));
PP_0to6(nbB-1 downto 0) <= P(nbB-1 downto 0); --PP0
for_g2: for i in 0 to nbB-3 generate
PP_0to6((nbB+1)*(i+1)+(i*(i+1)/2)+7 downto (nbB+1)*(i+1)+(i*(i+1)/2)) <= P(nbB*(i+1)+(nbB-1) downto nbB*(i+1)); --PP1 to PP6
PP_0to6((nbB+1)*(i+1)+(i*(i+1)/2)-1 downto (nbB+1)*(i)+((i-1)*(i)/2)+7+1) <= (others => '0');
end generate for_g2;
PP7(nbA+nbB-1 downto nbA-1) <= P7;
PP7(nbA-2 downto 0) <= (others => '0');
PPP_0to6: for i in 3 to nbB-2 generate
PPP(((i+1)*(nbA+nbB-1)+i)-(8-i) downto i*(nbA+nbB)) <= PP_0to6( (i+1)*(nbB-1)+((1/2)*((i*i)+(3*i))) downto i*(nbB)+(i-1)*i/2); --PP0 to PP6
PPP(((i+1)*(nbA+nbB-1)+i) downto ((i+1)*(nbA+nbB-1)+i)-(8-i)+1)<= (others => '0');
end generate PPP_0to6;
-- Fill last 32 bits of PPP
--Insert ADDER TREE
end Behavioral;
Portion of the error code: portion of code
PPP_0to6: for i in 0 to nbB-2 generate
PPP(((i+1)*(nbA+nbB-1)+i)-(8-i) downto i*(nbA+nbB)) <= PP_0to6( (i+1)*(nbB-1)+((1/2)*((i*i)+(3*i))) downto i*(nbB)+(i-1)*i/2); --PP0 to PP6
PPP(((i+1)*(nbA+nbB-1)+i) downto ((i+1)*(nbA+nbB-1)+i)-(8-i)+1)<= (others => '0');
end generate PPP_0to6;
Hi, I'm making a multiplier on vhdl, but on line 66 it reports me the following error:
if i=1: [Synth 8-690] width mismatch in assignment; target has 9 bits, source has 7 bits ["...Multiplier.vhd":66]
if i=2: [Synth 8-690] width mismatch in assignment; target has 10 bits, source has 5 bits ["...Multiplier.vhd":66]
if i=3: [Synth 8-690] width mismatch in assignment; target has 11 bits, source has 2 bits ["...Multiplier.vhd":66]
and so on..
I can't understand why, they seem to be the same size ..
my constant are:
nbA=8
nbB=8
and the signal P, PP_0to6 and PPP:
signal P : STD_LOGIC_VECTOR((nbA*nbB)-1 downto 0);
signal PP_0to6 : STD_LOGIC_VECTOR( (nbA)+(nbA+1)+(nbA+2)+(nbA+3)+(nbA+4)+(nbA+5)+(nbA+6)-1 downto 0);
signal PPP : STD_LOGIC_VECTOR((nbA+nbB)*(nbB+1)-1 downto 0);
N.B. I make sure to shift to the rigth by adding zeros as in the figure:
schema
The error is here:
PPP(((i+1)*(nbA+nbB-1)+i)-(8-i) downto i*(nbA+nbB)) <= PP_0to6( (i+1)*(nbB-1)+((1/2)*((i*i)+(3*i))) downto i*(nbB)+(i-1)*i/2);
but if I tried to replace the value of i:
i=0: PPP(7 downto 0) <= PP_0to6(7 downto 0);
i=1: PPP(24 downto 16)<=PP_0to6(16 downto 8)
i=2: PPP(41 downto 32)<=PP_0to6(26 downto 17)
i=3: PPP(58 downto 48)<=PP_0to6(37 downto 27)
...
...
the dimensions look the same.
I guess strictly speaking this answer doesn't really answer your question, since I'm not trying to figure out where your error is. But I'm convinced that if you change your coding style you won't encounter such difficult to debug errors any more.
As mentioned in my comments, your code will become must clearer and easier to debug if you split the signal up properly. I.e. don't create one giant signal for everything.
VHDL has arrays and records, use them, they won't make your circuit any larger, but the code will be much easier to reason about.
It's been a while since I actually wrote VHDL, so the syntax below might contain typo's, but hopefully the idea behind the code is clear:
constant c_AllZeros : std_logic_vector(c_MaxZeros - 1 downto 0) := (others => '0');
...
type t_P is std_logic_vector(c_SomeLength - 1 downto 0);
subtype t_P_Array is array (natural range <>) of t_P;
...
signal P : t_P_Array(0 to c_NumInputs - 1);
...
PPP_0to6: for i in PPP'range generate
PP(i) <= P(i) & c_AllZeros(index downto 0);
PPP(i) <= c_AllZeros(c_MaxZeros - index downto 0) & PP(i);
end generate PPP_0to6;
As you might notice, I also got rid of the explicit indices for the for-loop in the generate. There's still a magic number when indexing the all_zeroes signal to generate PPP. If I was writing this code, I'd replace that with some (calculated) constant with a meaningful name. This will make the code both more readable and trivial to change later on.
Note that there's other ways to do this. E.g. you could first set all bits of all PP signals to 0 and then assign a slice of them the P value.

Can't normally see result in wave (Modesim)

I have code designed for Vivid software. How I can translate this code into ModelSIM? In vivado, I should get the following values, but in modelsim I get completely different ones.
This is noise generator. Successful in adding pseudorandom noise sequence to our sine wave, but now we are trying to add Gaussian noise. The code and the simulation results for ADDITION OF PSEUDORANDOM NOISE SEQUENCE TO SINE WAVE IS GIVEN BELOW:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --try to use this library as much as possible.
entity sine_wave is
generic ( width : integer := 4 );
port (clk :in std_logic;
random_num : out std_logic_vector (width-1 downto 0);
data_out : out STD_LOGIC_VECTOR(7 downto 0)
);
end sine_wave;
architecture Behavioral of sine_wave is
signal data_out1,rand_temp1,noisy_signal : integer;
signal noisy_signal1 : STD_LOGIC_VECTOR(7 downto 0);
signal i : integer range 0 to 29:=0;
--type memory_type is array (0 to 29) of integer;
type memory_type is array (0 to 29) of std_logic_vector(7 downto 0);
--ROM for storing the sine values generated by MATLAB.
signal sine : memory_type := ("01001101","01011101","01101100","01111010","10000111","10010000","10010111","10011010","10011010");
--hi
begin
process(clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=(width-1 => '1',others => '0');
variable temp : std_logic := '0';
begin
--to check the rising edge of the clock signal
if(rising_edge(clk)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
--data_out <= sine(i);
i <= i+ 1;
if(i = 29) then
i <= 0;
end if;
end if;
data_out <= sine(i);
data_out1<=to_integer(unsigned(sine(i)));
random_num <= rand_temp;
rand_temp1<=to_integer(unsigned(rand_temp));
noisy_signal<=data_out1+rand_temp1;
noisy_signal1<= std_logic_vector(to_signed(noisy_signal,8));
end process;
end Behavioral;
Vivado
ModelSIM

Use of conv_integer in VHDL

I am in the process of trying to write some code that will simply just shift a 32 bit vector left or right, with a 5 bit input that will be used for the shift amount (shamt). The issue I am having is trying to convert an std_logic_vector to an integer. My code is this:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x : in std_logic_vector(31 downto 0);
shamt : in std_logic_vector( 4 downto 0);
y : out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
signal shift : integer;
signal temp : std_logic_vector(31 downto 0);
begin
shift <= conv_integer(unsigned(shamt));
temp <= x(shift downto 0);
y <= temp;
end beh;
The code is not complete I know, but to test some ideas I am trying to pass "00010" (2) into shamt, but shift comes out to be -2147483648. But I cannot figure out why it is doing this, nor can I find any resources online that shows anything different than what I am doing. I greatly appreciate any help.
-2147483648 (-2**31) is the default initial value for integers, being the leftmost, most negative value in its range. It suggests that the signal assignment to shift has not executed. Most likely because it is a continuous assignment and there hasn't been an event on shamt to cause it to update.
std_logic_arith is not an IEEE standard library. You should use to_integer() from ieee.numeric_std instead. It is also beneficial to keep numeric ports as unsigned or signed so that your intent is clear and to minimize type conversions. Also, you cannot directly assign the variable length slice of x to temp since their lengths do not match. You should use resize() (from numeric_std) to extend the length back to 32-bits or rethink your approach.
I fixed the obvious typo in the entity name, started the simulation (ModelSim) and forced the signal shamt to "00010". Then just after trying to run for 1 ps, ModelSim complains about:
Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 0 (-2147483648 downto 0 (null array)).
Time: 0 ps Iteration: 0 Process: /shiftlogical/line__16 File: shiftlogical.vhdl
Fatal error in Architecture beh at shiftlogical.vhdl line 16
That is because all your concurrent statements are executed in parallel. The new signal values are scheduled for the next delta cycle within the simulation. Thus, the line
temp <= x(shift downto 0);
is executed with the old value of shift which is the initial value of this signal. The initial value of an integer is -2**31 as also Kevin pointed out.
Of course you can initialize the signal shift, but the only value which will not result in an error will be 31 because in this asignment the signal on the left and the expression on the right must match in array (std_logic_vector) size. The signal shamt must be forced to "11111" as well, so that shift keeps 31.
You cannot easily fix this, because for a left shift you must add zeros at the right (LSB) and for a right shift zeros or the sign at the left (MSB).
#Martin Zabel what I had really tested there was to see if shift would hold an integer value which it did until I tried to pass it in for temp <= x(shift downto 0); What I realized was that the signal needed to really be a variable to work as intended and as follows my code consists of:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x: in std_logic_vector(31 downto 0);
shamt: in std_logic_vector(4 downto 0);
dir: in std_logic;
y: out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
begin
process(dir)
variable shift : integer;
begin
shift := conv_integer(unsigned(shamt));
if(dir = '0') then --Left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
elsif(dir = '1') then --Right shift
y(31-shift downto 0) <= x(31 downto shift);
y(31 downto 31-shift) <= (others => '0');
else --Always left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
end if;
end process;
end beh;

How to convert 8 bits to 16 bits in VHDL?

I have an input signal from ADC convertor that is 8 bits (std_logic_vector(7 downto 0)). I have to convert them to a 16 bits signal (std_logic_vector(15 downto 0)) for 16 bits signal processing to the 16 bits system.
If the 8 bit value is interpreted as signed (2's complement), then the general and standard VHDL conversion method is to use the IEEE numeric_std library:
library ieee;
use ieee.numeric_std.all;
architecture sim of tb is
signal slv_8 : std_logic_vector( 8 - 1 downto 0);
signal slv_16 : std_logic_vector(16 - 1 downto 0);
begin
slv_16 <= std_logic_vector(resize(signed(slv_8), slv_16'length));
end architecture;
So first the std_logic_vector is converted to a signed value, then the resize is applied, which will sign extend the signed value, and the result is finally converted back to std_logic_vector.
The conversion is rather lengthy, but has the advantage that it is general and works even if the target length is changed later on.
The attribute 'length simply returns the length of the slv_16 std_logic_vector, thus 16.
For unsigned representation instead of signed, it can be done using unsigned instead of signed, thus with this code:
slv_16 <= std_logic_vector(resize(unsigned(slv_8), slv_16'length));
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0);
begin
s16 <= X"00" & s8;
end;
This handles the conversion without having to edit the widths of the zeroes if either std_logic_vector changes:
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0) := (others => '0');
begin
s16(s8'range) <= s8;
end;
For completeness, yet another way which is occasionally useful:
-- Clear all the slv_16 bits first and then copy in the bits you need.
process (slv_8)
begin
slv_16 <= (others => '0');
slv_16(7 downto 0) <= slv_8;
end process;
I've not had to do this for vectors that I can recall, but I have had need of this under more complex circumstances: copying just a few relevant signals into a bigger, more complex, record was one time.
With the newly released VHDL-2019 standard you can do
larger_vec <= extend(shorter_vec);
where extend is a function defined as follows
function extend(vec : std_logic_vector) return target_vec of std_logic_vector is
variable result : std_logic_vector(target_vec'length - 1 downto 0) := (others => '0');
begin
assert vec'length <= target_vec'length report "Cannot extend to shorter vector";
result(vec'length - 1 downto 0) := vec;
return result;
end function;
Tool support is still a bit limited but at least one simulator supports this (Riviera-PRO).

Resources