I am looking at this example and below answer which is a nice solution to produce two's complement:
library ieee;
use ieee.numeric_std.all;
entity twoscomplement is
generic
(
Nbits : positive := 8
);
port
(
A : in unsigned (Nbits-1 downto 0);
Y : out signed (Nbits downto 0)
);
end entity twoscomplement;
architecture a1 of twoscomplement is
begin
Y <= -signed(resize(A, Y'length));
end architecture;
I want to use the said example to have two's complement and then make a "16-bit subtractor". The code will look like the following:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity subtractor_16bit is
Port ( a : in STD_LOGIC_VECTOR(15 downto 0);
b : in STD_LOGIC_VECTOR(15 downto 0);
cin : in STD_LOGIC;
sum : out STD_LOGIC_VECTOR(15 downto 0);
cout : out STD_LOGIC;
over : out STD_LOGIC
);
end subtractor_16bit;
architecture Behavioral of subtractor_16bit is
component fulladder_16bit is
Port (
a : in STD_LOGIC_VECTOR(15 downto 0);
b : in STD_LOGIC_VECTOR(15 downto 0);
cin : in STD_LOGIC;
sum : out STD_LOGIC_VECTOR(15 downto 0);
cout : out STD_LOGIC;
over : out STD_LOGIC
);
end component;
component twoscomplement is
Port (
A : in unsigned (15 downto 0);
C : out signed (15 downto 0)
);
end component;
signal n1 : STD_LOGIC_VECTOR(15 downto 0);
begin
twoscomplement_1: twoscomplement port map (a => a ,c => n1); --ERROR
fulladder_16bit_1: fulladder_16bit port map (a => a, b => n1, sum => sum , cin => cin, cout => cout, over => over);
end Behavioral;
However, I am receiving an error saying:
Error: type error near a; current type std_logic_vector; expected type unsigned.
Kindly help me to solve this problem.
As nobody is answering this and nobody is down voting it, I will answer.
Look at the error
Error: type error near a; current type std_logic_vector; expected type unsigned.
Now look at entity subtractor_16bit.
[...]
entity subtractor_16bit is
Port ( a : in STD_LOGIC_VECTOR(15 downto 0);
[...]
component twoscomplement is
Port (
A : in unsigned (15 downto 0);
[...]
twoscomplement_1: twoscomplement port map (a => a ,c => n1);
[...]
What do you see? twoscomplement expects an unsigned, while a is std_logic_vector! Just like the error says.
std_logic_vector and unsigned are two separate types. As VHDL is a strongly typed language, you cannot just put the data from one type to another. You need to use type conversion.
For unrelated types, you should implement a type conversion function. Or functions, if you want bidirectional conversion. E.g.
function (input : type_a) return type_b;
But in this case, std_logic_vector and unsigned have the same underlying type, std_logic. (std_ulogic actually since VHDL-2008 I believe.)
In that case you can convert from one type to another explicitly. E.g.
signal a_u : unsigned(y downto 0);
signal a_slv : std_logic_vector(y downto 0);
begin
a_u <= unsigned(a_slv);
Next, your not instantiating the twoscomplement component properly. The entity has a generic Nbits. By default you set it to 8. But in your architecture Behavioral of subtractor_16bit, you feed it with 16 bits, without changing the generic value. That doesn't work.
Also: twoscomplement has two ports: A and Y. But in subtractor_16bit you start using A and C. That's bad coding practice.
Finally, you can drop the component declarations. Just instantiate the entities from the library. E.g.
twoscomplement_1: entity work.twoscomplement [...]
So, subtractor_16bit should look something like this:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity subtractor_16bit is
Port (
a : in STD_LOGIC_VECTOR(15 downto 0);
b : in STD_LOGIC_VECTOR(15 downto 0);
cin : in STD_LOGIC;
sum : out STD_LOGIC_VECTOR(15 downto 0);
cout : out STD_LOGIC;
over : out STD_LOGIC
);
end entity;
architecture structural of subtractor_16bit is
use IEEE.NUMERIC_STD.ALL;
signal n1 : signed(a'range);
begin
twoscomplement_1: entity work.twoscomplement
generic map(
NBits => a'length
)
port map (
a => unsigned(a),
y => n1
);
fulladder_16bit_1: entity work.fulladder_16bit
port map (
a => a,
b => std_logic_vector(n1),
sum => sum,
cin => cin,
cout => cout,
over => over
);
end architecture;
...
HOWEVER this will still not work.
As you see on your entity twoscomplement, port A has a size of NBits, and port Y has a size of NBits+1. That is because you seem to want to keep 16-bit value precision. So when converting unsigned to signed, you need to add a 17th bit for the sign. As a result, the rest of you code will need to be modified!
.... But this can be fixed a different way. I will learn you something about two's complement: -a = not(a) + 1.
Proof (Take 4 bits signed precision):
0 = b'0000 => -0 is not(b'0000)+1 = b'1111'+1 = b'0000'
7 = b'0111 => -7 is not(b'0111)+1 = b'1000'+1 = b'1001'
-6 = b'1010' => 6 is not(b'1010)+1 = b'0101'+1 = b'0110'
See?
So now I will solve your puzzle for you:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity subtractor_16bit is
Port (
a : in STD_LOGIC_VECTOR(15 downto 0);
b : in STD_LOGIC_VECTOR(15 downto 0);
sum : out STD_LOGIC_VECTOR(15 downto 0);
cout : out STD_LOGIC;
over : out STD_LOGIC
);
end entity;
architecture structural of subtractor_16bit is
begin
fulladder_16bit_1: entity work.fulladder_16bit
port map (
a => a,
b => not(b),
sum => sum,
cin => '1',
cout => cout,
over => over
);
end architecture;
You will still need to change/fix the cout and over behavior...
I have written a simple VHDL code to add two matrices containing 32 bit floating point numbers. The matrix dimensions have been defined in a package. Currently, I specify the matrix dimensions in the vhdl code and use the corresponding type from the package. However, I would like to use generic in the design to deal with matrices of different dimensions. For this I would have to somehow use the right type defined in the package. How do I go about doing this?
My current VHDL code is as below.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.mat_pak.all;
entity newproj is
Port ( clk : in STD_LOGIC;
clr : in STD_LOGIC;
start : in STD_LOGIC;
A_in : in t2;
B_in : in t2;
AplusB : out t2;
parallel_add_done : out STD_LOGIC);
end newproj;
architecture Behavioral of newproj is
COMPONENT add
PORT (
a : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
b : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
clk : IN STD_LOGIC;
sclr : IN STD_LOGIC;
ce : IN STD_LOGIC;
result : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
rdy: OUT STD_LOGIC
);
END COMPONENT;
signal temp_out: t2 := (others=>(others=>(others=>'0')));
signal add_over: t2bit:=(others=>(others=>'0'));
signal check_all_done,init_val: std_logic:='0';
begin
init_val <= '1';
g0: for k in 0 to 1 generate
g1: for m in 0 to 1 generate
add_instx: add port map(A_in(k)(m), B_in(k)(m), clk, clr, start, temp_out(k)(m), add_over(k)(m));
end generate;
end generate;
g2: for k in 0 to 1 generate
g3: for m in 0 to 1 generate
check_all_done <= add_over(k)(m) and init_val;
end generate;
end generate;
p1_add:process(check_all_done,temp_out)
begin
AplusB <= temp_out;
parallel_add_done <= check_all_done;
end process;
end Behavioral;
My package is as below
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
package mat_pak is
subtype small_int is integer range 0 to 2;
type t22 is array (0 to 1) of std_logic_vector(31 downto 0);
type t2 is array (0 to 1) of t22; --2*2 matrix
type t22bit is array (0 to 1) of std_logic;
type t2bit is array (0 to 1) of t22bit; --2*2 matrix bit
type t33 is array (0 to 2) of std_logic_vector(31 downto 0);
type t3 is array (0 to 2) of t33; --3*3 matrix
end mat_pak;
Any suggestions would be welcome. Thank you.
There are some logical issues with your design.
First, there's some maximum number of ports for a sub-hierarchy a design can tolerate, you have 192 'bits' of matrix inputs and outputs. Do you really believe this number should be configurable?
At some point it will only fit in the very large FPGA devices, and shortly thereafter not fit there either.
Imagining some operation taking a variable number of clocks in add and parallel_add_done signifies when an aplusb datum is available comprised of elements of the matrix array contributed by all instantiated add components, the individual rdy signals are ANDed together. If the adds all take the same amount of time you could take the rdy from anyone of them (If you silicon is not that deterministic it would not be usable, there are registers in add).
The nested generate statements all assign the result of the AND between add_over(k,m) and init_val (which is a synthesis constant of 1). The effect or wire ANDing add_over(k.m) bits together (which doesn't work in VHDL and is likely not achievable in synthesis, either).
Note I also showed the proper indexing method for the two dimensional arrays.
Using Jonathan's method of sizing matrixes:
library ieee;
use ieee.std_logic_1164.all;
package mat_pak is
type matrix is array (natural range <>, natural range <>)
of std_logic_vector(31 downto 0);
type bmatrix is array (natural range <>, natural range <>)
of std_logic;
end package mat_pak;
library ieee;
use ieee.std_logic_1164.all;
use work.mat_pak.all;
entity newproj is
generic ( size: natural := 2 );
port (
clk: in std_logic;
clr: in std_logic;
start: in std_logic;
a_in: in matrix (0 to size - 1, 0 to size - 1);
b_in: in matrix (0 to size - 1, 0 to size - 1);
aplusb: out matrix (0 to size - 1, 0 to size - 1);
parallel_add_done: out std_logic
);
end entity newproj;
architecture behavioral of newproj is
component add
port (
a: in std_logic_vector(31 downto 0);
b: in std_logic_vector(31 downto 0);
clk: in std_logic;
sclr: in std_logic;
ce: in std_logic;
result: out std_logic_vector(31 downto 0);
rdy: out std_logic
);
end component;
signal temp_out: matrix (0 to size - 1, 0 to size - 1)
:= (others => (others => (others => '0')));
signal add_over: bmatrix (0 to size - 1, 0 to size - 1)
:= (others => (others => '0'));
begin
g0:
for k in 0 to size - 1 generate
g0x:
for m in 0 to size - 1 generate
add_instx: add
port map (
a => a_in(k,m),
b => b_in(k,m),
clk => clk,
sclr => clr,
ce => start,
result => temp_out(k,m),
rdy => add_over(k,m)
);
end generate;
end generate;
aplusb <= temp_out;
p1_add:
process (add_over)
variable check_all_done: std_logic;
begin
check_all_done := '1';
for k in 0 to size - 1 loop
for m in 0 to size -1 loop
check_all_done := check_all_done and add_over(k,m);
end loop;
end loop;
parallel_add_done <= check_all_done;
end process;
end architecture behavioral;
We find that we really want to AND the various rdy outputs (add_over array) together. In VHDL -2008 this can be done with the unary AND, otherwise you're counting on a synthesis tool to flatten the AND (and they generally do).
I made the assignment to aplusb a concurrent assignment.
So I dummied up an add entity with an empty architecture, the above then analyzes, elaborates and simulates, which shows that none of the connectivity has length mismatches anywhere.
I'm not quite sure to understand perfectly, but I'll try to answer anyway ;)
You can use unconstrained array like this:
package mat_pak is
type matrix is array(natural range <>, natural range <>) of std_logic_vector(31 downto 0);
end package mat_pack;
entity newproj is
Generic ( size : natural );
Port ( clk : in STD_LOGIC;
clr : in STD_LOGIC;
start : in STD_LOGIC;
A_in : in matrix(0 to size-1, 0 to size-1);
B_in : in matrix(0 to size-1, 0 to size-1);
AplusB : out matrix(0 to size-1, 0 to size-1);
parallel_add_done : out STD_LOGIC);
end newproj;
i'm using the sin/cos lookup table in VHDL known as sincos_lut.vhd and i'm getting an error when used with my code. I'm implementing my datapath and i need to perform sin and cos on an integer value. I do not know where my problem is but here is the code and error:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.MATH_REAL.all;
entity DFT is
port(
clk_en, clk, reset, Clock: std_logic;
t_sel,K_sel,sr_sel,si_sel,ld_t,ld_K,ld_sumreal,ld_sumimag,ld_angle: in std_logic;
N: in integer;
e: in std_logic_vector(3 downto 0);
outreal, outimag: out integer;
sig1, sig2: out std_logic
);
end DFT;
architecture str of DFT is
component Adder
Port( a, b: in integer;
f: out integer
);
end component;
component Reg
Port(
Clk: in std_logic;
ld: in std_logic;
a: in integer;
f: out integer
);
end component;
component Mul
Port(
a, b: in integer;
f: out integer
);
end component;
component LT
Port(
a, b: in integer;
sig: out std_logic
);
end component;
component Div
Port(
a, b: in integer;
f: out integer
);
end component;
component Mux
Port(
sel: in std_logic;
a, b: in integer;
f: out integer
);
end component;
component Mem
port( Clock: in std_logic;
Read: in std_logic;
Write: in std_logic;
Address: in integer;
Data_in: in integer;
Data_out: out integer
);
end component;
component sincos_lut Port
(
reset : in std_logic;
clk : in std_logic;
clk_en : in std_logic;
theta : in integer;
sin_data : out signed(integer);
cos_data : out signed(integer)
);
end component;
signal s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25,s26,s30,s31,s32,s33 : integer;
constant MATH_PI : real := 3.14159_26535_89793_23846;
begin
G1: Mux port map(K_sel,0,s1,s2);
G2: Mux port map(t_sel,0,s3,s4);
G3: Reg port map(Clk,ld_K,s2,s5);
G4: Reg port map(Clk,ld_t,s4,s6);
G5: LT port map(s5,N,sig1);
G6: LT port map(s6,N,sig2);
G7: Adder port map(s5,1,s1);
G8: Adder port map(s6,1,s3);
G9: Div port map(s5,N,s7);
G10: Mul port map(s7,s6,s8);
G11: Mul port map(s8,integer(MATH_PI),s9);
G12: Mul port map(s9,2,s10);
G13: Reg port map(Clk, ld_angle,s10,s11);
G14: Mem port map(Clock,'1','0',s6,0,s12);
G15: Mem port map(Clock,'1','0',s6,0,s13);
G16: Mul port map(s12,s33,s14);
G17: Mul port map(s13,s30,s15);
G18: Adder port map(s14,s15,s16);
G19: Mux port map(sr_sel,0,s17,s18);
G20: Reg port map(Clk, ld_sumreal,s18,s19);
G21: Adder port map(s16,s19,s17);
G22: Mul port map(s12, -1,s20);
G31: sincos_lut port map(reset, clk, clk_en, s11, s30, s31);
G32: sincos_lut port map(reset, clk, clk_en, s11, s32, s33);
G23: Mul port map(s20, s30, s21);
G24: Mul port map(s13, s33, s22);
G25: Adder port map(s21, s22,s23);
G26: Mux port map(si_sel,0,s24,s25);
G27: Reg port map(Clk, ld_sumimag,s25,s26);
G28: Adder port map(s23,s26,s24);
G29: Mem port map(Clock, '0','1',s5,outimag);
G30: Mem port map(Clk, '0','1',s5,outreal);
sincos_lut
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sincos_lut is
port
(
reset : in std_logic;
clk : in std_logic;
clk_en : in std_logic;
theta : in integer;
sin_data : out signed(integer);
cos_data : out signed(integer)
);
end sincos_lut;
architecture rtl of sincos_lut is
signal theta_int : integer range 0 to 4095 := 0;
signal sin_data_int : signed(integer);
signal cos_data_int : signed(integer);
begin
theta_int <= theta;
process(reset,clk)
begin
if(reset = '1')then
sin_data_int <= to_signed(0,12);
cos_data_int <= to_signed(0,12);
elsif(rising_edge(clk)) then
if clk_en = '1' then
sin_data <= sin_data_int;
cos_data <= cos_data_int;
case theta_int is
end str;
Errors:
Error (10476): VHDL error at DFT.vhd(119): type of identifier "s30" does not agree with its usage as "SIGNED" type
Error (10558): VHDL error at DFT.vhd(119): cannot associate formal port "sin_data" of mode "out" with an expression
Error (10476): VHDL error at DFT.vhd(119): type of identifier "s31" does not agree with its usage as "SIGNED" type
Error (10558): VHDL error at DFT.vhd(119): cannot associate formal port "cos_data" of mode "out" with an expression
Line 119 is:
G31: sincos_lut port map(reset, clk, clk_en, s11, s30, s31);
Your errors are because s30 and s31 are integers and you are connecting them to a signed ports.
Kevin.
type of identifier "s30" does not agree with its usage as "SIGNED" type
This error is caused by mixing different types. The type of s30 is integer, but you are trying to map it to a port of type signed.
cannot associate formal port "sin_data" of mode "out" with an expression
This error is normally caused by "reading" an output port in your logic, but I don't see a clear reason for this error. Possibly this is related to your ports of type : signed(integer). Signed() is used for type conversion.
Your code isn't a Minimal, Complete, and Verifiable example. Note your sincos_lut doesn't analyze either.
signal s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25,s26,s30,s31,s32,s33 : integer;
constant MATH_PI : real := 3.14159_26535_89793_23846;
signal signed_s30: signed (11 downto 0);
signal signed_s31: signed (11 downto 0);
signal signed_s32: signed (11 downto 0);
signal signed_s33: signed (11 downto 0);
begin
s30 <= to_integer(signed_s30);
s31 <= to_integer(signed_s31);
s32 <= to_integer(signed_s32);
s33 <= to_integer(signed_s33);
You can create signed versions of s30, s31, s32 and s33 and convert
and assign them to s30, s31, s32, s33.
Also note there were associated errors in the sincos_lut, both in port declarations and signal declarations. A type name doesn't represent a range constraint. These have been fixed by:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sincos_lut is
port
(
reset : in std_logic;
clk : in std_logic;
clk_en : in std_logic;
theta : in integer;
sin_data : out signed(11 downto 0); -- integer);
cos_data : out signed(11 downto 0) -- integer)
);
end sincos_lut;
architecture rtl of sincos_lut is
signal theta_int : integer range 0 to 4095 := 0;
signal sin_data_int : signed(11 downto 0); -- integer);
signal cos_data_int : signed(11 downto 0); -- integer);
The range of the signed values (actually the length) is determined by the to_signed function calls in the process.
Note use package numeric_std function to_integer, and in dft:
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_arith.all;
-- use ieee.std_logic_unsigned.all;
-- use ieee.math_real.all;
use ieee.numeric_std.all; -- never, never mix std_logic_arith/numeric_std
-- (see sincos_lut)
Type declarations in two different packages are unique regardless of whether they have the same name and base type or not. They are not compatible. If your tool let's you it is not compliant to the VHDL standard.
G31: sincos_lut port map(reset, clk, clk_en, s11, signed_s30, signed_s31);
G32: sincos_lut port map(reset, clk, clk_en, s11, signed_s32, signed_s33);
That lops of those errors, but reveals two more:
G29: Mem port map(Clock, '0','1',s5,outimag);
G30: Mem port map(Clk, '0','1',s5,outreal);
If you look at your mem component and the positional association list in the instance port maps you'll find you're missing an integer argument for both of these representing Address.
I don't think you've revealed enough of your 'precious' IP from someone to tell what should be connected here. It's part of the price in seeking help, showing what you got. When someone tells you it isn't a minimum example, in this case it would be throwing out component instantiations and signals not connected to the actual error reports.
Also note the promiscuous use of unconstrained integers which can end up implying 32 bit values in synthesis. You should be careful and constrain everything you can.
For instance defining the range constraint for the integer address going to the Mem component defines how big the memory is.
Dummy-ing up a signal Address, an integer and inserting it in the component allows dft to finish analyzing:
G29: Mem port map(Clock, '0','1',Address,s5,outimag);
G30: Mem port map(Clk, '0','1',Address,s5,outreal);
It's not possible to elaborate your design without dummy-ing up entity and architecture pairs for all your instantiated components or eliminating them (which would lead you to a second question later).
(And you could have produced integers from the sincos_lut entity/architecture pair, but without a range constraint that would have likely been a 32 bit value).