Error: "expression is not constant" with shift unit - vhdl

I wrote the code below in order the do shift the binary number, I tried to compile it for the device cyclonII - EP2C20F484C7, but got this error:
Error (10779): VHDL error at shiftNbits.vhd(30): expression is not constant
Error (10658): VHDL Operator error at shiftNbits.vhd(30): failed to evaluate call to operator ""&""
vhd(30) is the line:
resultTemp <= A( N-1-numberOfShifts downto 0) & (numberOfShifts-1 downto 0 => '0');
I saw the some people asked about it, and they got the answer that the compiler don't like the idea of N-1-numberOfShifts or numberOfShifts-1 being negative. The thing is that I ensure that numberOfShifts
if numberOfShifts>=N then
resultTemp <= (N-1 downto 0 => '0');
And I even tried to add range to numberOfShifts definitions:
variable numberOfShifts: integer range 1 to N-1;
In order to ensure that numberOfShifts-1 is not negative.
By the way when I doning A(0 downto 0) I get actually one bit vector, How I define NULL vector if A( -1 downto 0) is not legal?
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
entity shiftNbits is
generic(N: integer := 8);
port (
typeOfShift : in std_logic_vector (1 downto 0);
enable : in std_logic;
A : in std_logic_vector(N-1 downto 0);
B : in std_logic_vector (N-1 downto 0);
result : out std_logic_vector(N-1 downto 0)
);
end shiftNbits;
architecture shiftNbitsGate of shiftNbits is
signal resultTemp: std_logic_vector(N-1 downto 0);
begin
process (typeOfShift, enable, A, B)
variable numberOfShifts: integer;
begin
numberOfShifts:= to_integer(unsigned(B));
if enable= '1' then
case typeOfShift is
when "00" => --RLA
if numberOfShifts>=N then
resultTemp <= (N-1 downto 0 => '0');
else
resultTemp <= A( N-1-numberOfShifts downto 0) & (numberOfShifts-1 downto 0 => '0');
end if;
when "01" => --RLC
numberOfShifts := numberOfShifts mod N;
resultTemp <= A( N-1-numberOfShifts downto 0) & A( N-1 downto N-numberOfShifts);
when "10" => --RRA
if numberOfShifts>=N then
resultTemp <= (N-1 downto 0 => A(N-1));
else
resultTemp <= (N-1 downto N-numberOfShifts => A(N-1)) & A( N-1 downto numberOfShifts);
end if;
when "11" => --RRC
numberOfShifts := numberOfShifts mod N;
resultTemp <= A( numberOfShifts-1 downto 0) & A( N-1 downto numberOfShifts);
when others => null;
end case;
else
resultTemp <= A; --what we should insert here?
end if;
end process;
result <= resultTemp;
end shiftNbitsGate;

resultTemp <= A( N-1-numberOfShifts downto 0) & (numberOfShifts-1 downto 0 => '0');
can't be implemented in one "line" (one set of gates / one logic equation) in hardware, as it may correspond to many different cases (one per number of shifts).
In VHDL, you're required to expand all these possibilities with if then else or a case select.
If the shift value had been constant, the code could indeed be synthesized, hence the error message!

Related

Carry/Borrow in VHDL ALU

I am making a generic N-bit ALU in VHDL. I am having trouble assigning the value for the carry for addition, or borrow for subtraction. I have tried the following:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity alu is
generic(n: integer :=1); --Default to 1
port (
a : in std_logic_vector(n-1 downto 0);
b : in std_logic_vector(n-1 downto 0);
op : in std_logic_vector(1 downto 0);
output : out std_logic_vector(n-1 downto 0);
carryborrow: out std_logic
);
end alu;
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "01" =>
result(n) <= '0';
result(n-1 downto 0) <= a or b; --or gate
output <= result(n-1 downto 0);
carryborrow <= '0';
when "10" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) + signed(b)); --addition
output <= result(n-1 downto 0);
carryborrow <= result(n);
when "11" =>
result(n) <= '0';
result(n-1 downto 0) <= std_logic_vector(signed(a) - signed(b)); --subtraction
output <= result(n-1 downto 0);
carryborrow <= result(n);
when others =>
NULL;
end case;
end process;
end Behavioral;
This seems to set the carryborrow bit to always be 0. How can I assign it to what it should be without type errors?
There are bugs in your code:
i) You have not taken into account the fact that signals are not updated immediately. Consequently, the following lines will not do as I think you are expecting:
result(n) <= '0';
result(n-1 downto 0) <= a and b; --and gate
output <= result(n-1 downto 0);
Instead, you need to take the lines driving output and carryborrow outside the combinational process, as you can see below.
ii) Assuming you wish this code to be synthesisable, simply putting NULL in your always branch will result in latches being inferred. You need to drive result in the others branch, too.
So, making an assumption about how your carry output is to behave with the and and or operations, this is how I would have written your code:
architecture Behavioral of alu is
signal result: std_logic_vector(n downto 0);
begin
process( a, b, op )
begin
case op is
when "00" =>
result <= '0' & (a and b); --and gate
when "01" =>
result <= '0' & (a or b); --or gate
when "10" =>
result <= std_logic_vector(resize(signed(a), n+1) + resize(signed(b), n+1)); --addition
when "11" =>
result <= std_logic_vector(resize(signed(a), n+1) - resize(signed(b), n+1)); --subtraction
when others =>
result <= (others => 'X');
end case;
end process;
output <= result(n-1 downto 0);
carryborrow <= result(n);
end Behavioral;
I normally do this:
result <= std_logic_vector(signed(a(n-1) & a) + signed(b(n-1) & b));
result <= std_logic_vector(signed(a(n-1) & a) - signed(b(n-1) & b));
Sign extend and then do the operation to take care of overflow, when the result is one extra bit long.
Hmm, consider this in a 4 bit environment, say a="0101" and b="1001". Adding them shall give the output="1110", with NO carry.
However, sign extending with resize(signed(a), n+1) and resize(signed(b), n+1) will set a="00101" and b="11001" and hence result="11110" and carryborrow='1', which is wrong!
By sign extending vectors a and b, the numeral range has increased to 5 bits, and thus result needs to be 6 bits to be able to hold carry, and we're back to square one.
Vectors a and b should only be zero extended, that is '0' & a and '0' & b before adding them to result, and then carryborrow, as MSB(Most Significant Bit) of result, will get the correct value.

Issue with using component and forloop in VHDL

I am trying to create a component for division in VHDL, below is my code. I dont know where i am going wrong. My logic is:
At every step,
• shift divisor right and compare it with current dividend
• if divisor is larger, shift 0 as the next bit of the quotient
• if divisor is smaller, subtract to get new dividend and shift 1
as the next bit of the quotient.
I have used '-' sign here but in actual i have to use gates so either i have to use my subtraction component or just create a subtractor here.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
ENTITY divprog IS
PORT(
a: IN std_logic_vector(3 downto 0);
b: IN std_logic_vector(3 downto 0);
err: OUT std_logic;
reslow: OUT std_logic_vector(3 downto 0);
reshigh: OUT std_logic_vector(3 downto 0));
END divprog;
architecture behaviour of divprog is
signal ax,bx,bsub,res :std_logic_vector(7 downto 0) := (others => '0');
signal quo: std_logic_vector(3 downto 0) := (others => '0');
signal intcarry: std_logic_vector(8 downto 0):= (others => '0');
BEGIN
--sub1: subtractor PORT MAP(aa,bb,x,ss);
Process is
variable i : POSITIVE := 1;
BEGIN
ax <= "0000" & a;
bx <= b & "0000";
if(b > "0000") then
while (i <=3) loop
bx <= '0'&bx(7 downto 1);
IF (ax < bx) then
quo <= quo(2 downto 0)& '0';
--bx <= '0'&bx(7 downto 1);
res <=ax;
elsif(ax >= bx) then
res <= ax - bx;
quo <=quo(2 downto 0)& '1';
end if;
i := i + 1;
ax <= res;
end loop;
reshigh <= quo;
reslow <= res(3 downto 0);
end IF;
wait for 100 ns;
END PROCESS;
end behaviour;
Can please someone help me with this?
Thanks
The functional problem is related to variable i. It gets stuck at 4 after the first 100ns. It should be set to 1 between BEGIN and END PROCESS.

Bundle statements in VHDL

How can I combine/bundle statements for further use and better handling? For example some assignments like this which would be used many times more in future calls of the routine.
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
Into something like this.
NOP = {ADDR_PC <= "00000000", ADDR_OP_A <= "00000", ...}
I don't know if there are any possibilities to do that in VHDL. Any tip would be helpful.
Records and/or aggregates:
library ieee;
use ieee.std_logic_1164.all;
entity op_decoded is
end entity;
architecture foo of op_decoded is
-- These declarations probably want to be in a package
constant IMMED_NULL: std_logic_vector (8 downto 0) := (others => '0');
constant OP_NOP: std_logic_vector (5 downto 0) := (others => '0');
type decode_op is
record
PC: std_logic_vector (7 downto 0);
OP_A: std_logic_vector (4 downto 0);
OP_B: std_logic_vector (4 downto 0);
OP_CODE: std_logic_vector (5 downto 0);
OP_IMMED: std_logic_vector (8 downto 0);
WE_SREG: std_logic_vector (4 downto 0); -- S V N C Z
end record;
constant NOP: decode_op := (
PC => "00000000",
OP_A => "00000",
OP_B => "00000",
OP_CODE => OP_NOP,
OP_IMMED => IMMED_NULL,
WE_SREG => "00000"
);
-- actual signals
signal ADDR_PC: std_logic_vector (7 downto 0);
signal ADDR_OP_A: std_logic_vector (4 downto 0);
signal ADDR_OP_B: std_logic_vector (4 downto 0);
signal OP_CODE: std_logic_vector (5 downto 0);
signal OP_IMMED: std_logic_vector (8 downto 0);
signal WE_SREG: std_logic_vector (4 downto 0);
signal pipe1: decode_op;
signal pipe_disc: decode_op;
begin
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <= NOP;
pipe1 <= NOP;
pipe_disc <= (pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
end architecture;
This analyzes, elaborates and simulates (showing it's syntactically and semantically correct).
There's also an aggregate target with an aggregate right hand side (with the type provided):
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <=
decode_op'(pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
VHDL has records (C calls it struct).
Declaration example:
type T_MY_RECORD is record
Member1 : STD_LOGIC;
Member2 : STD_LOGIC_VECTOR(15 downto 0);
end record;
signal mySignal1 : T_MY_RECORD;
signal mySignal2 : T_MY_RECORD;
Usage examples:
mySignal1 <= (
Member1 => '1',
Member2 => x"12FC"
);
mySignal2.Member1 <= '0';
Records can be nested, e.g. for the flags.
Records and/or aggregates are one possibility, but and alternative is to declare a procedure in the process where the signals are driven, and then call the procedure, like:
process (clk_i) is
procedure NOP is
begin
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
end procedure;
begin
if rising_edge(clk_i) then
...
NOP;
...
end if;
end process;
This work both for simulation and synthesizable code.

padding out std_logic_vector with leading zeros

ok, what I would like to do is assign a smaller std_vector to a large one, padding out the upper bits with zeros. But, I want something generic and simple that doesn't involve knowing the size of each first.
for instance if I have:
signal smaller_vec: std_logic_vector(15 downto 0);
signal larger_vec: std_logic_vector(31 downto 0);
I could do:
larger_vec <= X"0000" & smaller_vec;
But what if I don't know the size of the smaller vector. Is there a was of specifying that all upper bits are zero.
I know about the others clause, but that would get messy as I'd need a couple of lines:
larger_vec(smaller_vec'high downto 0) <= smaller_vec;
larger_vec(31 downto smaller_vec'length) <= (others => '0');
I thought I could use:
larger_vec <= "" & smaller_vec;
but this didn't work. any ideas?
Have you tried:
larger_vec <= (31 downto smaller_vec'length => '0') & smaller_vec;
In the past I have had synthesis tool issues with code like that, so I have used:
constant ZERO : std_logic_vector(larger_vec'range) := (others => '0');
. . .
larger_vec <= ZERO(31 downto smaller_vec'length) & smaller_vec;
James0's 2nd post was close, but the <= is facing the wrong direction, see below for a working example from duolos. I would edit, but at the time of this post I did not have enough reputation.
In https://www.doulos.com/knowhow/vhdl_designers_guide/vhdl_2008/vhdl_200x_ease/ in the Vectors in aggregates section it says:
variable V : std_logic_vector(7 downto 0);
begin
V := (others => '0'); -- "00000000"
V := ('1', '0', others => '0'); -- "10000000"
V := (4 => '1', others => '0'); -- "00010000"
V := (3 downto 0 => '0', others => '1'); -- "11110000"
-- V := ("0000", others => '1'); -- illegal!
larger_vec <= (smaller_vec'high downto 0 => smaller_vec, others => '0');
should work.
in my case I also like the following:
larger_vec <= (smaller_vec'high downto 0 <= smaller_vec, others => '0');
Which does my final answer in one line. This works, yes?
I have encountered similar issues and tried the following:
larger_vec <= (larger_vec'range => '0') + shorter_vec;
You need to use IEEE.std_logic_unsigned.all for this approach.
Zero-Pad or Truncate any std_logic_vector or std_logic to exactly 16 bits:
function pad16(x: std_logic_vector)
return std_logic_vector is
constant ZERO : std_logic_vector(15 downto 0) := (others => '0');
begin
if (x'length < 16) then
return ZERO(15 downto x'length) & x;
else
return x(15 downto 0);
end if;
end function;
--overload function for single bit
function pad16(x: std_logic)
return std_logic_vector is
constant ZERO : std_logic_vector(15 downto 0) := (others => '0');
begin
return ZERO(15 downto 1) & x;
end function;
-- USAGE:
--
-- reg16 <= pad16(X"3");

"Can't determine the definition of operator +" when designing a 16-bit ALU

I am designing a 16-bit ALU which does few operations. I have a syntax error:
"Can't determine the definition of operator "+"".
The following code does Signed & Unsigned addition and subtraction and shift operation. It does a few other operations like OR, XOR etc., which I am not showing, as they doesn't have any problem.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU16 is port
( A: in std_logic_vector (15 downto 0);
B: in std_logic_vector (15 downto 0);
AluOp: in std_logic_vector (4 downto 0);
shamt: in std_logic_vector (2 downto 0);
Zero: out std_logic;
Overflow: out std_logic;
R: out std_logic_vector (15 downto 0)
);
end ALU16;
architecture RTL of ALU16 is
signal temp : std_logic_vector( 16 downto 0);
signal usgnA, usgnB, Reg1 : unsigned(15 downto 0);
signal sgnA, sgnB, Reg2 : signed(15 downto 0);
begin
process(AluOp)
variable p : integer range 0 to 15;
begin
--usgnA <= unsigned(A);
--usgnB <= unsigned(B);
sgnA <= signed(A);
sgnB <= signed(B);
case AluOp is
when "00000" =>
--Reg1 <= usgnA + usgnB;
temp <= ('0' & A) + ('0' & B);
Overflow <= temp(16);
--temp <= A + B;
R<=temp(15 downto 0);
--Overflow <= A(15) and B(15);
-- when "00001" =>
-- --Reg1 <= usgnA - usgnB;
-- R<=A-B;
-- if (A < B) then Overflow<= '1';
-- else Overflow<= '0';
-- end if;
--
-- when "00010" =>
-- Reg2 <= sgnA + sgnB;
-- R<=std_logic(Reg2);
-- Overflow <= A(14) and B(14);
--
-- when "00011" =>
-- R <= sgnA - sgnB;
-- R<=std_logic(Reg2);
-- if (sgnA < sgnB) then Overflow<= '1';
-- else Overflow<= '0';
-- end if;
--
-- when "01011" =>
-- temp <= A;
-- temp <= shift_right(A,to_integer(shamt));
-- p :=to_integer(shamt);
-- for i in 1 to 3 loop
-- temp(i-1) <= '0';
-- end loop;
-- R<= temp;
--
when others =>
NULL;
-- if( R = "0000000000000000" ) then
-- Zero <= '1';
-- else Zero <='0';
-- end if;
end case;
end process;
end RTL;
As you are using numeric_std (which you should be), you will need to either change the type of temp to unsigned or cast the result of the addition to std_logic_vector. For signed addition, you can detect overflow by comparing the input signs with the output sign. If the input signs match and the output sign is different, you have overflow. Otherwise, you don't. I might also recommend using variables instead of signals for all intermediate results (so you don't run into any problems with sequential signal assignment):
process (AluOp)
variable Temp : std_logic_vector(15 downto 0);
begin
...
when "00010" =>
Temp := std_logic_vector(sgnA + sgnB);
R <= Temp;
Overflow <= (sgnA(15) xnor sgnB(15)) and (sgnA(15) xor Temp(15));
You are doing sum of to std_logic_vector.
and you have not used ieee.std_logic_arith.all, So it is showing the error.
but in one hdl file you can not use use IEEE.NUMERIC_STD.ALL and ieee.std_logic_arith.all.
It will make the compiler confused.
so better tryout temp <= std_logic_vector(unsigned(A) + unsigned(B));
It might solve your problem.
try out different combinations like this.

Resources