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

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.

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.

Vhdl error 10344 dont know what to do

I am trying to make set&load d-flip flop code(synch) but it keeps giving me count <= '0' & d; it has 2 elements but must have 9 elements error.Thanks in advance
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity syn is
port (
clk : in std_logic;
rst_n : in std_logic;
d : in std_logic;
ld : in std_logic;
q : out std_logic_vector(7 downto 0);
co : out std_logic);
end syn;
architecture rtl of syn is
signal count : std_logic_vector(8 downto 0);
begin
co <= count(8);
q <= count(7 downto 0);
process (clk)
begin
if (clk'event and clk = '1') then
if (rst_n = '0') then
count <= (others => '0'); -- sync reset
elsif (ld = '1') then
count <= '0' & d; -- sync load
else
count <= count + 1; -- sync increment
end if;
end if;
end process;
end rtl;
Input d is std_logic, so '0' & d is 2 bit vector. Count is std_logic_vector of length 9, so you can't make assignment like this.
I'm not entirely sure what you are trying to achieve. If you want to assign '0' & d to some part of a vector, you can write for example
count(1 downto 0) <= '0' & d
If d is supposed to be equal size of counter, then change it's size in entity declaration.

VHDL shift operators

Hi I have the program below that does what I want to do, shift 1 bit left or right depending on inputs s_right or s_enable. The numeric.std library contains shift operators and I want to start using them so I get a better grasp on the language but can find no good examples that show me the right way at using them
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
ENTITY S_REG8 IS
port ( clk, s_enable, s_right, ser_in : in std_logic;
ser_out : out std_logic
);
END ENTITY S_REG8;
ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg : std_logic_vector (7 DOWNTO 0); --7,6,5,4,3,2,1,0
SIGNAL selectors : std_logic_vector (1 DOWNTO 0);
BEGIN
SHIFT_REG:PROCESS (clk, s_enable, s_right)
BEGIN
selectors <= s_enable & s_right;
IF clk'EVENT and clk ='1' THEN
IF selectors <= "00" THEN
reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
ELSIF selectors <= "01" THEN
reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
ELSIF selectors <="10" THEN
reg (0) <= ser_in;
ser_out <= reg(7);
--reg <= std_logic_vector(shift_left(unsigned(reg), 1);
--SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
reg (7 DOWNTO 1) <= reg (6 DOWNTO 0);
ELSIF selectors <= "11" THEN
reg (7) <= ser_in;
ser_out <= reg(0);
--reg <= shift_right(std_logic_vector(reg));
reg (6 DOWNTO 0) <= reg (7 DOWNTO 1);
END IF;
END IF;
END PROCESS;
END ARCHITECTURE dflow;
Any help would be great thanks.
From package numeric_std, the body:
-- Id: S.1
function SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
begin
if (ARG'LENGTH < 1) then return NAU;
end if;
return UNSIGNED(XSLL(STD_LOGIC_VECTOR(ARG), COUNT));
end SHIFT_LEFT;
-- Id: S.2
function SHIFT_RIGHT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
begin
if (ARG'LENGTH < 1) then return NAU;
end if;
return UNSIGNED(XSRL(STD_LOGIC_VECTOR(ARG), COUNT));
end SHIFT_RIGHT;
These call:
-----------------Local Subprograms - shift/rotate ops-------------------------
function XSLL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
is
constant ARG_L: INTEGER := ARG'LENGTH-1;
alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0'); begin
if COUNT <= ARG_L then
RESULT(ARG_L downto COUNT) := XARG(ARG_L-COUNT downto 0);
end if;
return RESULT; end XSLL;
function XSRL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
is
constant ARG_L: INTEGER := ARG'LENGTH-1;
alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0'); begin
if COUNT <= ARG_L then
RESULT(ARG_L-COUNT downto 0) := XARG(ARG_L downto COUNT);
end if;
return RESULT; end XSRL;
Where you find SHIFT_LEFT fills reg(0) with '0' and SHIFT_RIGHT fills reg(7) with '0'.
You had previously assigned ser_in to reg(7) and reg(0) respectively, those assignments would be lost (the last assignment in a sequence of statements wins).
So reverse the order of the assignments:
architecture fie of s_reg8 is
signal reg: std_logic_vector (7 downto 0);
signal selectors: std_logic_vector (1 downto 0);
begin
-- make process purely clock synchrnous
selectors <= s_enable & s_right;
-- ser_out multiplexer instead of flip flop:
ser_out <= reg(7) when s_right = '0' else
reg(0); -- when s_right = '1' else
-- 'X';
shift_reg:
process (clk)
begin
if rising_edge (clk) then -- immunity to metastability transitions
-- if clk'event and clk ='1' then
-- if selectors <= "00" then -- redundant
-- reg (7 downto 0) <= reg (7 downto 0);
-- if selectors <= "01" then -- redundant
-- reg (7 downto 0) <= reg (7 downto 0);
-- elsif selectors <= "10" then
if selectors = "10" then -- was elsif equality not
reg <= std_logic_vector(shift_left(unsigned(reg), 1));
-- also added missing right paren
reg (0) <= ser_in; -- change the order so this occurs
-- ser_out <= reg(7); -- no flip flop
-- reg <= std_logic_vector(shift_left(unsigned(reg), 1);
-- SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
-- reg (7 downto 1) <= reg (6 downto 0);
-- elsif selectors <= "11" then
elsif selectors = "11" then
reg <= std_logic_vector(shift_right(unsigned(reg),1));
-- missing distance, proper type conversion
reg (7) <= ser_in; -- change order so this assignment happens
-- ser_out <= reg(0); -- no flip flop
-- reg <= shift_right(std_logic_vector(reg));
-- reg (6 downto 0) <= reg (7 downto 1);
end if;
end if;
end process;
end architecture;
Notice this also gets rid of the ser_out flip flop using a 2:1 mux instead, get's rid of the superfluous 'hold' assignments to reg(7 downto 0), uses the rising_edge function for immunity to events from a metastability value on clk and moves the selectors assignment to a concurrent signal assignment, allowing the process to be purely clock synchronous.
With a testbench (for shift right only):
library ieee;
use ieee.std_logic_1164.all;
entity s_reg8_tb is
end entity;
architecture foo of s_reg8_tb is
signal clk: std_logic := '0';
signal s_enable: std_logic;
signal s_right: std_logic;
signal ser_in: std_logic;
signal ser_out: std_logic;
constant ser_in_val0: std_logic_vector (1 to 8) := x"B9";
constant ser_in_val1: std_logic_vector (1 to 8) := x"AC";
begin
CLOCK: -- clock period 20 ns
process
begin
wait for 10 ns;
clk <= not clk;
if now > 800 ns then -- automagically stop the clock
wait;
end if;
end process;
DUT:
entity work.s_reg8
port map (
clk => clk,
s_enable => s_enable,
s_right => s_right,
ser_in => ser_in,
ser_out => ser_out
);
STIMULUS:
process
begin
s_enable <= '1';
s_right <= '1';
for i in 1 to 8 loop
ser_in <= ser_in_val0(i);
wait for 20 ns; -- one clock period
end loop;
for i in 1 to 8 loop
ser_in <= ser_in_val1(i);
wait for 20 ns; -- one clock period
end loop;
for i in 1 to 8 loop -- so we get all val0 out
ser_in <= ser_in_val0(i);
wait for 20 ns; -- one clock period
end loop;
s_enable <= '0';
wait for 20 ns; -- one clock
wait;
end process;
end architecture;
We get:
Notice at this point we haven't tested s_enable nor s_right = '0', but SHIFT_RIGHT works. Will SHIFT_LEFT work?
The secret was assigning the serial in to reg(0) or reg(7) after the shift function.
Thanks for the detailed reply user1155120. I have used the description below to simulate the left and right shift of one bit through the register.
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
ENTITY S_REG8 IS
port ( clk, s_enable, s_right, ser_in : in std_logic;
ser_out : out std_logic
);
END ENTITY S_REG8;
ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg: std_logic_vector (7 downto 0);
SIGNAL selectors: std_logic_vector (1 downto 0);
BEGIN
selectors <= s_right & s_enable;
ser_out <= reg(7) when selectors = "01" else
reg(0);
shift_reg:
PROCESS (clk)
BEGIN
IF rising_edge (clk) THEN
IF selectors = "01" THEN
reg <= std_logic_vector(shift_left(unsigned(reg), 1));
reg (0) <= ser_in;
-- ser_out <= reg (7);
ELSIF selectors = "11" THEN
reg <= std_logic_vector(shift_right(unsigned(reg),1));
reg (7) <= ser_in;
-- ser_out <= reg (0);
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
For simulation I have been using Quartus II ModSim which I get the following results from:
The results look great. Adding a single 1 bit state into the register I can see it move to the left or right of the register depending on the toggling of inputs s_right or s_enable.
The use of the multiplexer on the set_out and reg(0) and (7) makes much more sense in comparison to the addition latch that I added to the original description.
MANY THANKS

How Can i eliminate inout signal for my vhdl Adder?

I have written the following VHDL code which is the component of a Fast Adder. The fast adder consists of an 8by8 register hooked up to adder whose code is below. How can i eliminate the use of inout Read_Adress. I want Read_Adress to be out std_logic_vector not inout?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
Entity Adder is
port(
Clock_50_MHZ :in std_logic;
En :in std_logic;
Data_Registerfile : in std_logic_vector(7 downto 0);
Read_Address: inout std_logic_vector(2 downto 0) := "000";
Output : out std_logic_vector(11 downto 0)
);
end Adder;
Architecture arch of Adder is
Signal result : unsigned (11 downto 0):="000000000000";
Signal regData: std_logic_vector(7 downto 0);
Begin
regData <= Data_Registerfile;
Process(Clock_50_MHZ)
Begin
if rising_edge(Clock_50_MHZ) then
if (En = '1') then
if(Read_Address = "000") then
result <= "000000000000" + unsigned(regData);
Read_Address <= Read_Address + 1;
elsif(Read_Address = "111") then
Output <= std_logic_vector( result + unsigned(regData) );
Read_Address <= "000";
else
result <= result + unsigned(regData);
Read_Address <= Read_Address + 1;
end if;
end if;
end if;
End Process;
end arch;
This is a classic inconvenience in VHDL: you can't use your out ports as
signals (if you are used to Verilog, you often find yourself wanting to do
that).
The best way that I know of is to create an extra dummy signal:
signal Read_Address_tmp : std_logic_vector(2 downto 0) := "000";
do the computation with that:
Process(Clock_50_MHZ)
Begin
if rising_edge(Clock_50_MHZ) then
if (En = '1') then
if(Read_Address_tmp = "000") then
result <= "000000000000" + unsigned(regData);
Read_Address_tmp <= Read_Address_tmp + 1;
elsif(Read_Address_tmp = "111") then
Output <= std_logic_vector( result + unsigned(regData) );
Read_Address_tmp <= "000";
else
result <= result + unsigned(regData);
Read_Address_tmp <= Read_Address_tmp + 1;
end if;
end if;
end if;
End Process;
and then link it to your output:
Read_Address <= Read_Address_tmp;
Owen's answer is the usual way, historically.
The "new" VHDL 2008 allows reading of out-mode ports now. If your tools don't support it, log a bug with the vendor. See the bottom of this page from "VHDL 2008 - just the new stuff"
http://books.google.co.uk/books?id=ETxLguPMEY0C&pg=PA163&lpg=PA163#v=onepage&q&f=false

Resources