Directly Instansiating a DSP Slice Without IP Core - vhdl

The Problem
I want:
p <= (d-a) * b
Trying to directly instantiate a DSP block by using a DSP48E1 instead of simply writing p <= (d-a) * b plus it helps me understand how this block works for the future. So far I've had little luck with it though.
Referencing this article:
http://www.xilinx.com/support/documentation/user_guides/ug479_7Series_DSP48E1.pdf
Attempt
These are my current settings:
a <= std_logic_vector(to_unsigned(5, 30));
b <= std_logic_vector(to_unsigned(1, 18));
d <= std_logic_vector(to_unsigned(20, 25));
dsp : DSP48E1
generic map (
USE_DPORT => True,
ALUMODEREG => 0,
CARRYINREG => 0,
CARRYINSELREG => 0,
CREG => 0
)
port map(
clk => clk,
acin => std_logic_vector(to_unsigned(1, 30)), -- cascaded data input
alumode => "0000", -- control bits to select logic unit inputs
bcin => std_logic_vector(to_unsigned(1, 18)), -- cascaded data input
carrycascin => '0', -- cascaded data input
carryin => '0', -- carry input
carryinsel => "000", -- selects carry source
cea1 => '1', -- clock enable if AREG = 2 or INMODE0 = 1
cea2 => '1', -- clock enable if AREG = 1 or 2
cead => '1', -- clock enable for AD pipeline register
cealumode => '0', -- clock enable for ALUMODE --0
ceb1 => '1', -- clock enable if BREG = 1 or INMODE4 = 1
ceb2 => '1', -- clock enable if BREG = 1 or 2
cec => '0', -- clock enable for C
cecarryin => '0', -- clock enable
cectrl => '0', -- clock enable for OPMODE and CARRYINSEL ctrl registers
ced => '1', -- clock enable for D
ceinmode => '0',-- **** clock enable input registers
cem => '0', -- clock enable for the post multiply M register and the internal multiply round CARRYIN register
cep => '1', -- clock enable
inmode => "01101", -- *selects functionality of preadder [3] = sign, [4] = B multiplier sel
multsignin => '0', -- MACC extension sign
opmode => "0000101", -- *** Control input to A, Y and Z multiplexers
pcin => std_logic_vector(to_unsigned(1, 48)), -- cascade input
rsta => rst,
rstallcarryin => '0',
rstalumode => '0',
rstb => rst,
rstc => '0',
rstctrl => rst,
rstd => rst,
rstinmode => rst,
rstm => rst,
rstp => rst,
a => a,--_dsp, -- bits 29:25 used in second stage preadder
b => b,--_dsp,
c => c_dsp,
d => d,--_dsp,
p => p_dsp
);
I always get p = 0 even if I force d = 20, a = 5, b = 1.
I figured I should keep ALUMODE and OPMODE at 0 since I'm skipping the final stage and just want a straight subtraction and multiplication.
Photos

Look at table 2-7 from the DSP48E1 user guide page 34.
Your current configuration performs, at the post-adder, P = Z + X + Y + CIN, with Z = 0, X = 0 and Y = 0. You see the problem here?
The OPMODE signals control the value of the multiplexers. You want OPMODE(6 downto 4) = "000", so that Z keeps its null value. However, you want OPMODE(3 downto 0) = "0101" to set X/Y to the multiplier output M. ALUMODE should keep it's current value, it's fine.

Related

HowTo & multidimensional matrix in Ada

I was wondering about how to create a multidimensional matrix using Ada language, I mean, stacking i number of matrix of j x k dimension:
One way I have found is using multidimensional arrays, quite easy.
Are there other ways to accomplish it? Maybe using Ada.Containers.Vectors or mixing it within the array declaration? Any formal library?
Thanks
Here are two examples that might be of use.
The first example shows the use of an array of multi-dimensional arrays. When using this method you need, at some point, to fix the size of the stack of matrices (here: during the declaration of S, the size is fixed to 4). Memory is preallocated to hold all four matrices.
The second example shows the use of an Ada vector container to which matrices can be added. Vectors are "dynamic arrays". Memory is allocated when matrices added.
The Ada standard library that ships with (recent versions of) the GNAT compiler contains formal containers packages (see also here).
example_1.adb
with Ada.Text_IO; use Ada.Text_IO;
procedure Example_1 is
type Rows is new Natural range 0 .. 2;
type Cols is new Natural range 0 .. 2;
type Matrix is array (Rows, Cols) of Integer;
-- A 2D matrix.
type Stack is array (Natural range <>) of Matrix;
-- Stack of 2D matrices.
S : constant Stack (1 .. 4) :=
(1 => (others => (others => 1)),
2 => (others => (others => 2)),
3 => (others => (others => 3)),
4 => (others => (others => 4)));
begin
for Mtx of S loop -- using "of", not "in", such to iterate over the elements.
for R in Rows loop
Put ("[");
for C in Cols loop
Put (Mtx (R, C)'Image);
end loop;
Put_Line (" ]");
end loop;
New_Line;
end loop;
end Example_1;
example_2.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Example_2 is
type Rows is new Natural range 0 .. 2;
type Cols is new Natural range 0 .. 2;
type Matrix is array (Rows, Cols) of Integer;
-- A 2D matrix.
package Stacks is new Ada.Containers.Vectors (Natural, Matrix);
use Stacks;
subtype Stack is Stacks.Vector;
-- Stack of 2D matrices.
Empty_Stack : constant Stack := Stacks.Empty_Vector;
-- An empty stack.
S : Stack;
-- Instead of using Append (..) shown below, you can also
-- initialize the stack using:
--
-- S : Stack := Empty_Stack
-- & (others => (others => 1))
-- & (others => (others => 2))
-- & (others => (others => 3))
-- & (others => (others => 4));
begin
S.Append ((others => (others => 1)));
S.Append ((others => (others => 2)));
S.Append ((others => (others => 3)));
S.Append ((others => (others => 4)));
-- ...
for Mtx of S loop -- using "of", not "in", such to iterate over the elements.
for R in Rows loop
Put ("[");
for C in Cols loop
Put (Mtx (R, C)'Image);
end loop;
Put_Line (" ]");
end loop;
New_Line;
end loop;
end Example_2;
output (same for both examples)
[ 1 1 1 ]
[ 1 1 1 ]
[ 1 1 1 ]
[ 2 2 2 ]
[ 2 2 2 ]
[ 2 2 2 ]
[ 3 3 3 ]
[ 3 3 3 ]
[ 3 3 3 ]
[ 4 4 4 ]
[ 4 4 4 ]
[ 4 4 4 ]
You could also try standard Ada packages Real Vectors and Matrices or Complex Vectors and Matrices which also provide some operations on matrices. It can be the easiest way to accomplish it.

Scilab symbolic matrix multiplication

I have 3 matrix:
T_01 = ['cosd*t1', '-sind*t1', '0', 'd1*cosd*t1'; 'sind*t1', 'cosd*t1', '0', 'd1*sind*t1'; '0', '1', '1', '0'; '0', '0', '0', '1']
T_12 = ['cosd*t2', '-sind*t2', '0', 'd2*cosd*t2'; 'sind*t2', 'cosd*t2', '0', 'd2*sind*t2'; '0', '1', '1', '0'; '0', '0', '0', '1']
T_23 = ['cosd*t3', '-sind*t3', '0', 'd3*cosd*t3'; 'sind*t3', 'cosd*t3', '0', 'd3*sind*t3'; '0', '1', '1', '0'; '0', '0', '0', '1']
I need to make a symbolic multiplication, so I'm trying:
mulf(T_01,T_12,T_23)
But I get this error:
!--error 39
mulf: Quantidade incorreta de argumentos de entrada: esperava-se 2.
What is happening?
Obs.: Sorry for my english.
If what you want is to get the symbolic multiplication of two matrix, you'll have to implement such function. Here I've implemented three functions that together can perform what you want:
function s = scaProd(a,b)
//escalar product of two vectors
//using recursion
if (a == [] | b == []) then
s = ""
elseif (max(size(a)) ~= max(size(b))) | ...
(min(size(a)) ~= min(size(b))) | ...
(min(size(a)) ~= 1) then
error("vectorMulf: Wrong dimensions")
else
s = addf( mulf(a(1), b(1)) , scaProd(a(2:$), b(2:$)) )
end
endfunction
function s = matrixMulf(a,b)
//matrix multiplication
acols = size(a,'c');
brows = size(b,'r');
if acols ~= brows then
error("matrixMulf: Wrong dimensions")
end
arows = size(a,'r');
bcols = size(b,'c');
s = string(zeros(arows,bcols));
for i = 1 : arows
for j = 1 : bcols
s(i,j) = scaProd(a(i,:),b(:,j)');
end
end
endfunction
function s = addP(a)
//encolses each element of a in a pair of parenthesis
s = string(zeros(a));
for i = 1 : size(a,'r')
for j = 1 : size(a,'c')
s(i,j) = "(" + a(i,j) + ")"
end
end
endfunction
Here is an example of it's output. Test code:
A = [1 2; 3 4];
B = [5 6; 7 8];
C = [9 0; 1 2];
disp(A*B*C)
As = string(A);
Bs = string(B);
Cs = string(C);
disp(matrixMulf(As,addP(matrixMulf(Bs, Cs))))
Console output:
193. 44.
437. 100.
!1*(5*9+6*1)+2*(7*9+8*1) 1*(5*0+6*2)+2*(7*0+8*2) !
! !
!3*(5*9+6*1)+4*(7*9+8*1) 3*(5*0+6*2)+4*(7*0+8*2) !
For the result you want, you should do:
Enclose every term of each of your matrices with parenthesis using addP()
Perform the symbolic multiplication like matrixMulf(t1,addP(matrixMulf(t2,t3))), where t1, t2, t3 are the enclosed versions of your matrices.
And two final notes:
It is important to use addP at each multiplication step to get the correct result. You can check that by removing the ( and ) in the example I gave: the result won't be correct.
The functions mulf and addf are not available on Scilab 6.0.0. So remember you won't be able to use them if you upgrade your Scilab to the current stable version.

Function clogb2() generated by vivado can't synthesize with loop limit error

I'm trying to design an AXI_master peripheral with vivado. I used the axi peripheral generator in vivado menu and modified the vhdl code generated.
In vhdl code there is a function clogb2 declared with following code:
function clogb2 (bit_depth : integer) return integer is
variable depth : integer := bit_depth;
variable count : integer := 1;
begin
for clogb2 in 1 to bit_depth loop -- Works for up to 32 bit integers
if (bit_depth <= 2) then
count := 1;
else
if(depth <= 1) then
count := count;
else
depth := depth / 2;
count := count + 1;
end if;
end if;
end loop;
return(count);
end;
This works in simulation (GHDL) but fail in synthesis with error :
[Synth 8-403] loop limit (65538) exceeded
I tried to increase loop limit in vivado with following tcl command :
set_param synth.elaboration.rodinMoreOptions "rt::set_parameter max_loop_limit <X>"
As explained here, but vivado synthesize with an infinite time and never finish.
Do you know how to solve this problem ?
You could also try a different path. Although floating point is not supported in logic (although support is increasing), it is allowed for internal calculations and such. (By at least Xilinx and Altera/Intel).
Try this:
use ieee.math_real.all;
function ceillog2(input : positive) return natural is
begin
return integer(ceil(log2(real(input))));
end function;
Try constraining the range of the input, for example:
function clogb2 (bit_depth : integer range 1 to 32) return integer is
Also, if Vivado is generating code that it cannot compile, this is a bug that you should report on the Xilinx forums.
Finally I found a solution that work by rewriting the function with a big case :
function clogb2 (bit_depth : integer) return integer is
begin
case bit_depth is
when 0 to 2 => return( 1);
when (2** 1)+1 to 2** 2 => return( 2);
when (2** 2)+1 to 2** 3 => return( 3);
when (2** 3)+1 to 2** 4 => return( 4);
when (2** 4)+1 to 2** 5 => return( 5);
when (2** 5)+1 to 2** 6 => return( 6);
when (2** 6)+1 to 2** 7 => return( 7);
when (2** 7)+1 to 2** 8 => return( 8);
when (2** 8)+1 to 2** 9 => return( 9);
when (2** 9)+1 to 2**10 => return(10);
when (2**10)+1 to 2**11 => return(11);
when (2**11)+1 to 2**12 => return(12);
when (2**12)+1 to 2**13 => return(13);
when (2**13)+1 to 2**14 => return(14);
when (2**14)+1 to 2**15 => return(15);
when (2**15)+1 to 2**16 => return(16);
when (2**16)+1 to 2**17 => return(17);
when (2**17)+1 to 2**18 => return(18);
when (2**18)+1 to 2**19 => return(19);
when (2**19)+1 to 2**20 => return(20);
when (2**20)+1 to 2**21 => return(21);
when (2**21)+1 to 2**22 => return(22);
when (2**22)+1 to 2**23 => return(23);
when (2**23)+1 to 2**24 => return(24);
when (2**24)+1 to 2**25 => return(25);
when (2**25)+1 to 2**26 => return(26);
when (2**26)+1 to 2**27 => return(27);
when (2**27)+1 to 2**28 => return(28);
when (2**28)+1 to 2**29 => return(29);
when (2**29)+1 to 2**30 => return(30);
when (2**30)+1 to (2**31)-1 => return(31);
when others => return(0);
end case;
end;
With this weird code structure, that works in synthesis and simulation.
This recursive version synthesises:
function clogb2 (bit_depth : integer) return integer is
begin
if bit_depth <= 1 then
return 0;
else
return clogb2(bit_depth / 2) + 1;
end if;
end function clogb2;
You can use it to dimension other things, eg
entity counter is
generic (max_count : POSITIVE);
port (clock, reset : in std_logic;
Q : out std_logic_vector(clogb2(max_count) downto 0)
);
end;
or you can use it as combinational logic:
process (I)
begin
O <= clogb2(I);
end process;
BTW: you would be better using an integer subtype for your input:
function clogb2 (bit_depth : positive) return integer is
-- ^
-- |

Controlling an LCD in VHDL on spartan 6

I found this code which controls an LCD display of an FPGA but it can't seen to understand some of the code, in particular this part
type LCD_CMDS_T is array(integer range <>) of std_logic_vector(9 downto 0);
constant LCD_CMDS : LCD_CMDS_T := ( 0 => "00"&X"3C", --Function Set
1 => "00"&X"0C", --Display ON, Cursor OFF, Blink OFF
2 => "00"&X"01", --Clear Display
3 => "00"&X"02", --return home
4 => "10"&X"48", --H
5 => "10"&X"65", --e
6 => "10"&X"6C", --l
7 => "10"&X"6C", --l
8 => "10"&X"6F", --o
9 => "10"&X"20", --blank
10 => "10"&X"46", --F
11 => "10"&X"72", --r
12 => "10"&X"6F", --o
13 => "10"&X"6D", --m
14 => "10"&X"20", --blank
15 => "10"&X"44", --D
16 => "10"&X"69", --i
17 => "10"&X"67", --g
18 => "10"&X"69", --i
19 => "10"&X"6C", --l
20 => "10"&X"65", --e
21 => "10"&X"6E", --n
22 => "10"&X"74", --t
23 => "00"&X"18"); --Shift left
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
I understand that an array has been made to hold values of character to be displayed on the display. but i don't understand this line.
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
Can anyone help me to understand whats done here
This signal is being created to index into the string that was created. The constant LCD_CMDS is an array that needs to be indexed. The signal lcd_cmd_ptr is indexing into that constant to drive the display. It is an integer than can be from 0 to 23 in this case.
I bet somewhere there's a line that has:
LCD_CMDS(lcd_cmd_ptr)
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
This code defines a signal which can range from 0 to 'whatever the highest index in the LCD_CMDS array is + 1'.
The 'tick' attributes in VHDL are very useful for writing generic code. To be completely generic, the line above ought to be:
signal lcd_cmd_ptr : integer range LCD_CMDS'low to LCD_CMDS'HIGH + 1;
then if someone removed the entry for item 0 in the array, the signal would have a more limited range. Note that explicitly initialising to '0' in the original case and to LCD_CMDS'LOW in the most generic case is not necessary. The VHDL spec guarantees that integers are always initialised to the lowest value they are allowed to have.
If the signal above only needed to go up to the highest value in the array, you could write more concisely:
signal lcd_cmd_ptr : integer range LCD_CMDS'range;
Again, no explicit initialisation required.

I want to order two signals to one input in vhdl

I want to have two signals (overflow1 and set1) for one input(tick).
counter2 : counter
generic map (border => 5, width => 4)
port map (RST => RST,
tick => overflow1 [...] set1, -- overflow1 and set1 are these signals
enable => SW0,
x => count2,
overflow => overflow2);
so i want to fill the gap there. i hope u can understand my Problem.
thanks
Assuming that tick is an input port, and overflow1 and set1 are std_logic, then in VHDL-2008 you can do overflow1 or set1.
In previous VHDL versions, like VHDL-2002 and before, you must make an internal temporary signal like temp <= overflow1 or set1, and use that to drive the port.

Resources