Insert row function for matrix (2D array) in vhdl? - matrix

Is there a shorthand way to set a row of values in a matrix? I'm looking for a function/procedure type of solution.
Just to clarify, by matrix I don't mean an array of array but rather a 2D array.
I've managed to read a specific row using:
function extract_row(matrix : matrix_type; row_index : natural) return row_type is
variable res : row_type (matrix'range(2));
begin
for i in res'range loop
res(i) := matrix(row, i);
end loop;
return res;
end function;
And now I need a way to set a row in a fashion similar to how one can set a subarray in the array of arrays:
signal x : array_of_rows_type(range_a)(range_b);
signal y : row_type(range_b);
x(0) <= y;
I realise the shorthand isn't necessary and that one can work around it using loops and generates, but I have many places where I need to do this, and it's becoming increasingly difficult to keep legible code (and my sanity).
For those wondering, the reason why I'm using the matrix approach and not the array of arrays is because I need to reuse the type in multiple entities with different ranges.
Bonus points if the solution somehow allows me to use it in port mapping (although I realise this is impossible, unless I've misunderstood VHDL completely). i.e.:
port map (
row_type_outport => row_insert_solution(matrix, row)
)

I seem to recognize the code for the extract_row function. Perhaps you could adapt the function replace_matrix_column that is given in the same package?
function replace_matrix_column(
input_matrix: bit_matrix;
new_column: bit_vector;
column_index: integer
) return bit_matrix is
variable output: bit_matrix(input_matrix'range(1), input_matrix'range(2));
begin
for i in input_matrix'range(1) loop
for j in input_matrix'range(2) loop
if j = column_index then
output(i, j) := new_column(i);
else
output(i, j) := input_matrix(i, j);
end if;
end loop;
end loop;
return output;
end;
Then you could call it like this:
x <= replace_matrix_row(x, y, 0);
Or, for better clarity:
x <= replace_matrix_row(input_matrix => x, new_row => y, row_index => 0);

I don't have your types, so I can't compile this to make sure it works, but this might help get you close.
function row_insert_solution(matrix : matrix_type;
row_insert : row_type;
row_index : natural
) return matrix_type is
variable res : matrix_type := matrix;
begin
for i in row_insert'range loop
res(row_index, i) := row_insert(i);
end loop;
return res;
end function;

Related

VHDL pass range to procedure

I'm writing my own package to deal with generic matrix-like objects due to unavailability of VHDL-2008 (I'm only concerned with compilation and simulation for the time being).
My aim is getting a matrix M_out from a matrix M_in such that:
M_out(i downto 0, j downto 0) <= M_in(k+i downto k, l+j downto l);
using a subroutine of sort. For, let's say, semantic convenience and analogy with software programming languages my subroutine prototype should ideally look something like this:
type matrix is array(natural range <>, natural range <>) of std_logic;
...
procedure slice_matrix(signal m_out: out matrix;
constant rows: natural range<>;
constant cols: natural range<>;
signal m_in: in matrix);
The compiler does however regard this as an error:
** Error: custom_types.vhd(9): near "<>": syntax error
** Error: custom_types.vhd(9): near "<>": syntax error
Is it possible to pass a range as an argument in some way or shall I surrender and pass 4 separate indexes to calculate it locally?
An unconstrained index range natural range <> is not a VHDL object of class signal, variable, constant, or file. Thus it can not be passed into a subprogram. I wouldn't implement a slice operations as a procedure, because it's a function like behavior.
An implementation for working with matrices and slices thereof is provided by the PoC-Library. The implementation is provided in the vectors package.
function slm_slice(slm : T_SLM; RowIndex : natural; ColIndex : natural; Height : natural; Width : natural) return T_SLM is
variable Result : T_SLM(Height - 1 downto 0, Width - 1 downto 0) := (others => (others => '0'));
begin
for i in 0 to Height - 1 loop
for j in 0 to Width - 1 loop
Result(i, j) := slm(RowIndex + i, ColIndex + j);
end loop;
end loop;
return Result;
end function;
More specialized functions to slice off a row or column can be found in that file too. It also provides procedures to assign parts of a matrix.
This package works in simulation and synthesis.
Unfortunately, slicing multi dimensional arrays will not be part of VHDL-2017. I'll make sure it's discuss for VHDL-202x again.
Passing ranges into a subprogram will be allowed in VHDL-2017. The language change LCS 2016-099 adds this capability.

Transpose matrix ada

How can I transpose matrix in ADA?. I´ve tried:
procedure transpose(A: in out matrix) is
B : matrix(1..A'Last(2),1..A'Last(1));
begin
for i in A'Range(1) loop
for j in A'Range(2) loop
B(j,i):= A(i,j);
end loop;
end loop;
A := B;
end transpose;
but it doesn´t work when A isn´t a square Matrix.
Any help would be appreciated.
As a procedure this can never work for non-square matrices because the output is a different constrained type from the input. However you can return B from a suitable function.
function transpose(A: in matrix) return matrix is
B : matrix(A'Range(2),A'Range(1));
begin
for i in A'Range(1) loop
for j in A'Range(2) loop
B(j,i):= A(i,j);
end loop;
end loop;
return B;
end transpose;
The easiest way to create a matrix of the right constrained type for the result is a declare block:
declare
Transposed : Matrix := Transpose(A);
begin
-- operations on the transposed matrix
end;
You can transpose a matrix by creating a record like:
type Matrix_Type is record
Data : array (1..MAX_SIZE, 1..MAX_SIZE) of Float;
Last_Row : Positive range 1 .. MAX_SIZE;
Last_Column : Positive range 1 .. MAX_SIZE;
end record;
This record can support matrices of any m by n size up to n,m <= MAX_SIZE
Your procedure becomes:
procedure transpose(A: in out Matrix_Type) is
B : Matrix_Type;
begin
for i in 1..A.Last_Row loop
for j in 1..A.Last_Column loop
B(j,i):= A(i,j);
end loop;
end loop;
B.Last_Column := A.Last_Row;
B.Last_Row := A.Last_Column;
A := B;
end transpose;
The easiest way I know of is to use the Fortran convention on an intermediate array-type. (This is because Fortran convention is column-major while in Ada, it is row-major.)
Function Transpose(M : Matrix) return Matrix is
subtype Constrained is Matrix(M'Range(2), M'Range(1));
Type Xposed is new Matrix with Convention => Fortran;
Temp : Xposed := Xposed(M);
Result : Constrained with Import, Address => Temp'Address; --'
begin
Return Result;
end Transpose;

Package vhdl inclusion error

Hi guys i have the following package, defined by myself
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package util_pkg is
function log2c(n : natural) return natural;
end package util_pkg;
package body util_pkg is
function log2c(n : natural) return natural is
variable temp : natural := n;
variable ret_val : natural := 0;
begin
while temp > 1 loop
ret_val := ret_val + 1;
temp = temp/2;
end loop;
return ret_val;
end function log2c;
end package body util_pkg;
while my design is
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use work.util_pkg.all;
entity ldz is
generic(n : natural); --i can assume n > 1
port(x : in std_logic_vector(n - 1 downto 0);
y : out std_logic_vector(log2c(n) - 1 downto 0));
end entity ldz;
-- Example
architecture ldz_arch of ldz is
function ldz_count(x : unsigned) return natural is
n_ldz : natural := 0;
begin
for i in x'high to 0 loop
if(x(i) = '1') then
return x'length - i - 1;
end if;
end loop;
return x'length - 1;
end function ldz_count;
begin
y <= std_logic_vector(to_unsigned(ldz_count(to_unsigned(x)));
end architecture ldz_arch;
When i try to verify the syntax with ncvhdl this is the error i get
unit (UTIL_PKG) not found in library (WORKLIB)
however such unit (package) is in the same library of the design.
the file is util_pkg.vhd while the design is ldz.vhd
What is wrong?
The tool complains because the package has not been analysed (compiled) before ldz. Compile it first and ldz next.
As mentioned in the comments, your code suffers several problems. The following code computes the log2 of a positive, rounded towards 0 or infinity:
function log2_down(n: positive) is
variable res: natural := 0;
begin
if n /= 1 then
res := 1 + log2_down(n / 2);
end if;
return res;
end function log2_down;
function log2_up(n: positive) is
variable res: natural := 0;
begin
if n /= 1 then
res := 1 + log2_up((n + 1) / 2);
end if;
return res;
end function log2_up;
Yes, VHDL supports recursion and most synthesisers too, at least when the number of iterations is statically computable.
The res variable could be avoided but it helps avoiding the warnings of some tools that warn you if the return statements of a function are all under control of a control structure. They do this because they cannot prove that the function will always return while a function shall always return. I always try to suppress the warnings such that any remaining warning is meaningful and cannot be ignored.
Declaring the parameter as positive is a simple way to deal with the log2(0) error. I always try to use the built-in features of the language to deal with errors.
With the same two principles (no warnings, let the built-in features of the language deal with errors), your leading zero counter ldz_count function could be written:
function ldz_count(x: unsigned) return natural is
constant n: positive := x'length;
constant v: unsigned(0 to n - 1) := x;
variable res: natural := n;
begin
for i in 0 to n - 1 loop
if v(i) = '1' then
res := i;
end if;
end if;
return res;
end function ldz_count;
Copying the x parameter with a chosen bit indexing will make your function usable with any x parameter whatever its declaration (7 to 35 or 9 downto 4) as long as it is at least one bit long. This is the third principle I like: if you make something generic, make it really generic.

Target (variable "") is not a signal error in VHDL

I have this piece of code
function func (k1, k2 : in bit_vector) return bit_vector is
variable result : bit_vector(1 to 32);
begin
for i in 0 to 31 loop
result(i) <= k1(i);
end loop;
return result;
end func;
I get this error :
target (variable "result") is not a signal
I know I need to change the type of result but I don't know what it should be.
Thanks.
When assigning to a variable use := as:
result(i) := k1(i);
Assign with <= is for assign to signal.
The range of result (1 to 32) does not match the range in the loop (0 to 31), so first assign in the loop (result(0) := k1(0)) will cause in a range error. Fix this by changing either result or loop range.

Short VHDL for loop code i dont understand

I do understand how to convert a binary number into a decimal number but the following code thats supposed to do that doesnt make sense. I mean lets sat we have a binary number 10, then v(i) would be 0, so result stays 0. Upon the next iteration v(i) will be 1 so result will be 0 + 1 . The loop stops and the function will return the value of result which is 1 and not 2 which is the value of the binary number put into the function. Could someone tell me why I am wrong? This code comes with a university assignment so it should be correct. Thanks. :)
-------------------------------------------------------------------------------
-- convert std_logic vector v to natural
-------------------------------------------------------------------------------
FUNCTION s2n(v: std_logic_vector)
RETURN natural IS
VARIABLE result: natural := 0;
BEGIN
FOR i IN v'range LOOP
result := result * 2;
IF v(i) = '1' THEN
result := result + 1;
END IF;
END LOOP;
RETURN result;
END s2n;
The 'range loop works from left to right. The convention is for the most-significant bit to be on the left
By decoding that first, the *2 operation gets run most times on the MSB as you'd expect.
(BTW, if you want the range to go the other way for some reason, you can use the 'reverse_range attribute)

Resources