"Global Variables" for configuration in VHDL

P

pvwa

Hi,

i have the following (maybe strange) problem:

My design is very modular and will be configured by a setup file
(pkg)! This setup file defines wether specific modules are generated
or not.

For a special reason only the generated modules should now become an
individual (increasing) number as an address, e.g. in a generic! This
is only for configuration!!

I am thinking of a kind of a function with a "Global Variable" there,
which is intialized (to 0) at the beginning and increased by one every
time a module is instanciated (the function called)!! This is easy in
a procedural language but i can not find any construction in VHDL,
which could do this.

function NextAddress() return integer is
global variable addr : integer := 0;
begin
addr := addr+1;
return addr;
end;

I know this function does not work, but do you know a solution?
I already thought of shared variables, pointers (are these supported
in synthesis?) and File I/O. But nothing works?

Thanks ahead for any clue
Peter
 
T

Tricky

Hi,

i have the following (maybe strange) problem:

My design is very modular and will be configured by a setup file
(pkg)! This setup file defines wether specific modules are generated
or not.

For a special reason only the generated modules should now become an
individual (increasing) number as an address, e.g. in a generic! This
is only for configuration!!

I am thinking of a kind of a function with a "Global Variable" there,
which is intialized (to 0) at the beginning and increased by one every
time a module is instanciated (the function called)!! This is easy in
a procedural language but i can not find any construction in VHDL,
which could do this.

function NextAddress() return integer is
  global variable addr : integer := 0;
 begin
   addr := addr+1;
   return addr;
 end;

I know this function does not work, but do you know a solution?
I already thought of shared variables, pointers (are these supported
in synthesis?) and File I/O. But nothing works?

Thanks ahead for any clue
Peter

What are you actually trying to do? are you trying to created the
address map at elaboration time?
 
K

KJ

Hi,

i have the following (maybe strange) problem:

My design is very modular and will be configured by a setup file
(pkg)! This setup file defines wether specific modules are generated
or not.

For a special reason only the generated modules should now become an
individual (increasing) number as an address, e.g. in a generic! This
is only for configuration!!

I am thinking of a kind of a function with a "Global Variable" there,
which is intialized (to 0) at the beginning and increased by one every
time a module is instanciated (the function called)!! This is easy in
a procedural language but i can not find any construction in VHDL,
which could do this.

function NextAddress() return integer is
  global variable addr : integer := 0;
 begin
   addr := addr+1;
   return addr;
 end;

I know this function does not work, but do you know a solution?
I already thought of shared variables, pointers (are these supported
in synthesis?) and File I/O. But nothing works?

Thanks ahead for any clue
Peter

I'm not sure I totally understand what you want, but I'm assuming the
following:
- The 'setup file' that defines wether specific modules are generated
or not is also a VHDL file.
- The list of module addresses that come out are supposed to be
constants for a given setup file.

Given those assumptions, one approach would be:
- Have the 'setup file' be a simple list of flags in a vector. For
example, if the universe is a list of five modules that may (or may
not) be included, then you would have a five element vector with '1'
or '0' in a particular location to indicate that the item should be
included.
Ex:
constant List_Of_Modules_Included: std_ulogic_vector(1 to 5) :=
"10110";

- Now create a function that takes an input vector and creates a
vector of addresses.
Ex:
type arr_integer is array(integer range <>) of integer;
...
function Create_Addresses(V: std_ulogic_vector) return arr_integer
is
variable RetVal: arr_integer(V'range);
variable Start_Address: integer := 0; -- Or whatever initial value
begin
for i in V'range loop
if (V(i) = '1') then
RetVal(i) := Start_Address;
Start_Address := Start_Address + 1;
else
RetVal(i) := 0; -- Presuming unused can be any address
end if;
end loop;
return(RetVal);
end function Create_Addresses;

Now you can create your addresses like this...
constant List_Of_Addresses: arr_integer :=
Create_Addresses(List_Of_Modules_Included);

Not sure just how you then want to use these addresses, but at least
this should get you started on a possible approach.

Kevin Jennings
 
P

pvwa

Hi Kevin,

thanks for your elaborated answer!
I think, your proposal is actually what i am doing right now.
I use for every module a specific function which evaluates, by
scanning my setupfile, a unique number, which is used as an address.
Unfortunately this gets very, very complicated and i thought of a much
simpler solution based on when (!) a module is instanciated!?
Is this possible?
 
M

Mike Treseler

I use for every module a specific function which evaluates, by
scanning my setupfile, a unique number, which is used as an address.
Unfortunately this gets very, very complicated and i thought of a much
simpler solution based on when (!) a module is instantiated!?
Is this possible?

A vhdl "setup file" is called a package.
These work fine with any kind of vhdl design unit.

Your package might want to contain a constant array of vectors
to be used directly by your module. Maybe something like the example below.


-- Mike Treseler

_____________________________

library ieee;
use ieee.std_logic_1164.all;

package adr_decode is
constant reg_len_c : positive := 16;
constant array_len_c : positive := 16;
subtype reg_t is std_logic_vector(reg_len_c-1 downto 0);
type regs_t is array (0 to array_len_c-1) of reg_t;
constant mem_size : natural := 2**add_length;
type mem_t is array (mem_size-1 downto 0) of
std_logic_vector (data_length-1 downto 0);
constant mem : mem_t := (0 => x"abcd", 1 => x"beef",
2 => x"5555", 3 => x"1010",
4 => x"5a6b", 5 => x"f0f0",
6 => x"1234", 7 => x"fabc",
8 => x"2345", 9 => x"9876",
10 => x"5432", 11 => x"6666",
12 => x"0101", 13 => x"abab",
others => x"4247");
end package adr_decode;
 
A

Andy

A vhdl "setup file" is called a package.
These work fine with any kind of vhdl design unit.

Your package might want to contain a constant array of vectors
to be used directly by your module. Maybe something like the example below.

    -- Mike Treseler

_____________________________

library ieee;
use ieee.std_logic_1164.all;

package adr_decode is
    constant reg_len_c    : positive := 16;
    constant array_len_c  : positive := 16;
    subtype reg_t is std_logic_vector(reg_len_c-1 downto 0);
    type regs_t is array (0 to array_len_c-1) of reg_t;
    constant mem_size : natural := 2**add_length;
    type     mem_t is array (mem_size-1 downto 0) of
       std_logic_vector (data_length-1 downto 0);
    constant mem : mem_t := (0      => x"abcd", 1  => x"beef",
                             2      => x"5555", 3  => x"1010",
                             4      => x"5a6b", 5  => x"f0f0",
                             6      => x"1234", 7  => x"fabc",
                             8      => x"2345", 9  => x"9876",
                             10     => x"5432", 11 => x"6666",
                             12     => x"0101", 13 => x"abab",
                             others => x"4247");
end package adr_decode;

Apparently the package will contain a set of flags (hopefully an
array) that determine whether the associated module is actually
generated.

Write a function that processes the array of flags, in the correct
order, and returns an array with the appropriate, incrementing
addresses. Initialize a constant address array with that function.
Mind you, the length of this array should be fixed (matching the
length of the array of flags), and only those elements whose modules
are instantiated will have meaningful values. Then pass the
corresponding address array element as a generic to the module when it
is generated.

if flag(this_one) generate
...
generic_map(address => address_array(this_one));

Andy
 
K

KJ

Hi Kevin,

thanks for your elaborated answer!
I think, your proposal is actually what i am doing right now.
I use for every module a specific function which evaluates, by
scanning my setupfile, a unique number, which is used as an address.

What exactly do you mean by "scanning my setupfile"? To me, that
sounds like you're literally reading some file from disk (the setup
file), parsing that file, performing some function on the parsed data
to create an address...if that's what you're doing, you're making
things very difficult on yourself
Unfortunately this gets very, very complicated and i thought of a much
simpler solution

If it's how I interpret what you wrote, then yes, parsing files is not
always a simple thing, it's particularly tedious in VHDL...but it begs
the question of why you would even want to do it that way in the first
place?
based on when (!) a module is instanciated!?
Is this possible?

Going back to my first post where I detailed how to create a vector of
addresses from a vector of flags that defines which modules are
included (or not)...you would use that same vector of flags to control
whether a module is included or not like this

gen_1 : if List_Of_Modules_Included(1) = '1' generate
inst_mod1 : entity work.module1
generic map (List_Of_Addresses(1)...)
port map(...)
end generate gen_1;

gen_2 : if List_Of_Modules_Included(2) = '1' generate
inst_mod2 : entity work.module2
generic map (List_Of_Addresses(2)...)
port map(...)
end generate gen_2;
etc...

So 'module1' is only included if List_Of_Modules_Included(1) = '1'.
Since 'List_Of_Modules_Included' is the simple string that you
configure with what you want included, simply editing this text string
controls which modules get instantiated, what the address for that
module is at and any other things you want to affect.

Kevin Jennings
 
P

pvwa

Hi all,

What exactly do you mean by "scanning my setupfile"?  To me, that
sounds like you're literally reading some file from disk (the setup
file), parsing that file, performing some function on the parsed data
to create an address...if that's what you're doing, you're making
things very difficult on yourself

No, its not a file from disk but simply a VHDL package which contains
constant vectors, which define my modules with versionnumbers!
I think very similar to your proposal!?
See here an excerpt from my code:
------------------------------------------------------

type N_Vers is array ( NATURAL RANGE <> ) of integer;
constant Module_A: N_Vers := (8,0,1,0,2,2,0,0,0);
constant Module_B: N_Vers := (0);
constant Module_C: N_Vers := (2,0,0);
....
-- this is part of my setupfile
-- the first element of the constants are the number of modules of
that type, the other numbers are the according versions of that
type!...


-- Now these special functions "NextAddress.." (also in a pkg) take
care of the address calculation, similar to this:

function NextAddress_A(pos: integer) return integer is
begin
return pos; -- this is easy, because Module_A is the first module
type in the chain
end;

function NextAddress_B(pos: integer) return integer is
begin
return Module_A(0)+pos;
end;

function NextAddress_C(pos: integer) return integer is
begin
return Module_A(0)+Module_B(0)+pos; -- things getting more and more
complicated!
end;

....

-- finally here the mdoules according the setup constants are
generated

gen_Module_A : for i in 1 to Module_A(0) generate
  iModule_A : entity work.ModuleA
    generic map (Address => NextAddressA(i),
(Version => Module_A(i))
    port map(...)
end generate;

gen_Module_B : for i in 1 to Module_B(0) generate
  iModule_B : entity work.ModuleB
    generic map (Address => NextAddressB(i),
(Version => Module_B(i))
    port map(...)
end generate;

gen_Module_C : for i in 1 to Module_C(0) generate
  iModule_C : entity work.ModuleC
    generic map (Address => NextAddressC(i),
(Version => Module_C(i))
    port map(...)
end generate;

...

------------------------------------------------------

I think you get the idea!

The code above is very simplified, because i don't have to generate
not only addresses but also other numbers, which are dependent on the
versionnumbers of the modules!

So i have to write for each module, according functions, which do the
calculations!
Now imagine i want to change my code, e.g. i remove Module_B, then ALL
the dependent functions have to be changed also!!

I simply search for another solution, where the calculation can be
done in the Modules itself and this is not depended on other modules
(or functions) but simply on the fact of beeing instanciated or not!
My thinking was of a kind of "global variable", which is simply
incremented
So there would be only one function "NextAddress" be needed, similar
to this:

function NextAddress() return integer is
global variable pos: integer := 0; this is the initialization of the
variable
begin
pos := pos +1;
return pos;
end;

But nothingh like this seems to be possible in VHDL!?

My thinking was also of writing out the number+1 to a file and read it
back, whenever the function is called, but i learned that file
read&write in VHDL is not possible??

Peter von Walter
 
T

Tricky

Hi all,



No, its not a file from disk but simply a VHDL package which contains
constant vectors, which define my modules with versionnumbers!
I think very similar to your proposal!?
See here an excerpt from my code:
------------------------------------------------------

type N_Vers is array ( NATURAL RANGE <> ) of integer;
constant Module_A: N_Vers := (8,0,1,0,2,2,0,0,0);
constant Module_B: N_Vers := (0);
constant Module_C: N_Vers := (2,0,0);
...
-- this is part of my setupfile
-- the first element of the constants are the number of modules of
that type, the other numbers are the according versions of that
type!...

-- Now these special functions "NextAddress.." (also in a pkg) take
care of the address calculation, similar to this:

function NextAddress_A(pos: integer) return integer is
begin
        return pos; -- this is easy, because Module_A is the first module
type in the chain
end;

function NextAddress_B(pos: integer) return integer is
begin
        return Module_A(0)+pos;
end;

function NextAddress_C(pos: integer) return integer is
begin
        return Module_A(0)+Module_B(0)+pos; -- things getting more and more
complicated!
end;

...

-- finally here the mdoules according the setup constants are
generated

 gen_Module_A : for i in 1 to Module_A(0) generate
   iModule_A : entity work.ModuleA
     generic map (Address => NextAddressA(i),
                 (Version => Module_A(i))
     port map(...)
 end generate;

  gen_Module_B : for i in 1 to Module_B(0) generate
   iModule_B : entity work.ModuleB
     generic map (Address => NextAddressB(i),
                 (Version => Module_B(i))
     port map(...)
 end generate;

  gen_Module_C : for i in 1 to Module_C(0) generate
   iModule_C : entity work.ModuleC
     generic map (Address => NextAddressC(i),
                 (Version => Module_C(i))
     port map(...)
 end generate;

 ...

------------------------------------------------------

I think you get the idea!

The code above is very simplified, because i don't have to generate
not only addresses but also other numbers, which are dependent on the
versionnumbers of the modules!

So i have to write for each module, according functions, which do the
calculations!
Now imagine i want to change my code, e.g. i remove Module_B, then ALL
the dependent functions have to be changed also!!

I simply search for another solution, where the calculation can be
done in the Modules itself and this is not depended on other modules
(or functions) but simply on the fact of beeing instanciated or not!
My thinking was of a kind of "global variable", which is simply
incremented
So there would be only one function "NextAddress" be needed, similar
to this:

function NextAddress() return integer is
        global variable pos: integer := 0; this is the initialization of the
variable
begin
        pos := pos +1;
        return pos;
end;

But nothingh like this seems to be possible in VHDL!?

My thinking was also of writing out the number+1 to a file and read it
back, whenever the function is called, but i learned that file
read&write in VHDL is not possible??

Peter von Walter

You could try using a shared variable in the package and impure
functions to access them.

shared variable pos : integer := 0;

impure function NextAddress() return integer is
begin
pos := pos + 1;
return pos;
end function NextAddress;

The only problem with this is I dont think you can guarantee the order
in which the entities are instantiated, and may even change from
compilation to compilation. I know Quartus does support shared
variables, but dont know whether it will support them in this way. I
know it wont let you use signals in packages and from past experience
it has treated shared variables as signals inside entites.

This is only VHDL 93 standard. From 2000 onwards shared variables are
supposed to be protected. But Quartus doesnt really support alot more
than 93 (and doesnt complain even when you switch 2008 mode on)

Give this a go and let us know what happens.
 
K

KJ

Hi all,



No, its not a file from disk but simply a VHDL package which contains
constant vectors, which define my modules with versionnumbers!
I think very similar to your proposal!?
See here an excerpt from my code:
------------------------------------------------------

type N_Vers is array ( NATURAL RANGE <> ) of integer;
constant Module_A: N_Vers := (8,0,1,0,2,2,0,0,0);
constant Module_B: N_Vers := (0);
constant Module_C: N_Vers := (2,0,0);
...
-- this is part of my setupfile
-- the first element of the constants are the number of modules of
that type, the other numbers are the according versions of that
type!...

-- Now these special functions "NextAddress.." (also in a pkg) take
care of the address calculation, similar to this:

function NextAddress_A(pos: integer) return integer is
begin
        return pos; -- this is easy, because Module_A is the first module
type in the chain
end;

function NextAddress_B(pos: integer) return integer is
begin
        return Module_A(0)+pos;
end;

function NextAddress_C(pos: integer) return integer is
begin
        return Module_A(0)+Module_B(0)+pos; -- things getting more and more
complicated!
end;

Yes, because you didn't take my suggestion which was to create a
single function that loops through the list of all the modules and
return an array of constant addresses. Now that you've posted some
code to get a better idea of what you're trying to accomplish, let me
suggest the following which uses the 'Create_Addresses' function that
I posted earlier, modified slightly to take an extra input parameter
that is a 'start address' which would be used to initialize the first
element in the computed addresses

type arr_integer is array(integer range <>) of integer;
...
function Create_Addresses(V: std_ulogic_vector; Start_Address:
natural) return arr_integer
...
constant Module_A_Address: arr_integer(Module_A'range) :=
Create_Addresses(Module_A, 0);
constant Module_B_Address: arr_integer(Module_B'range) :=
Create_Addresses(Module_A, Module_A_Address(Module_A_Address'right)
+1);
constant Module_C_Address: arr_integer(Module_C'range) :=
Create_Addresses(Module_B, Module_B_Address
(Module_B_Address'right)+1);

Now you have three sets of arrays of integers for each of the three
modules, those would be used when instantiating the modules like
this...
...

-- finally here the mdoules according the setup constants are
generated

 gen_Module_A : for i in 1 to Module_A(0) generate
   iModule_A : entity work.ModuleA
     generic map (Address => Module_A_Address(i),
                 (Version => Module_A(i))
     port map(...)
 end generate;

The only change from your code then is to use the pre-computed
constants as the address generic.
So i have to write for each module, according functions, which do the
calculations!

Not really. As I showed, one 'function' covered nearly all of the
computations. The only other calculation is the part that links
address from the end of the 'Module A' list to the address start of
the 'Module B' list. This is accomplished with the added parameter to
'Create_Addresses' which allows for an arbitrary 'first' address to
use and then invoking that function by passing it the address of the
end of the 'Module A' list and adding 1 (i.e. the
"Module_A_Address(Module_A_Address'right)+1" portion of the call to
define Module_B_Address

constant Module_B_Address: arr_integer(Module_B'range) :=
Create_Addresses(Module_A, Module_A_Address(Module_A_Address'right)
+1);

Module B and C are similarly linked.
Now imagine i want to change my code, e.g. i remove Module_B, then ALL
the dependent functions have to be changed also!!

I would 'remove' a module by having a flag indicating whether the
module is to be generated or not. I'm not quite sure if that's what
you're doing or not.
I simply search for another solution, where the calculation can be
done in the Modules itself and this is not depended on other modules
(or functions) but simply on the fact of beeing instanciated or not!
My thinking was of a kind of "global variable", which is simply
incremented

You can't do it with the way that you're viewing the problem which is
in terms of some *variable*. You can do it though by viewing the
problem in terms of generating a *constant* vector which is what I'm
trying to get across.
So there would be only one function "NextAddress" be needed, similar
to this:

function NextAddress() return integer is
        global variable pos: integer := 0; this is the initialization of the
variable
begin
        pos := pos +1;
        return pos;
end;

That function simply lacks an input to indicate whether something
should be included or not and some base address to start at. Other
than that it is doing essentially the same thing as the
'Create_Addresses' function that I posted, the crucial difference is
that my function returns something that can be used to generate the
vector of constants that you need.
But nothingh like this seems to be possible in VHDL!?

It is...the mental hurdle is to stop viewing this address calculation
as being some variable that needs incrementing but instead see it as
the computation of a set of constants.
My thinking was also of writing out the number+1 to a file and read it
back, whenever the function is called, but i learned that file
read&write in VHDL is not possible??
That approach would not be a good path to go down.

Kevin Jennings
 
P

pvwa

Give this a go and let us know what happens.

Ok, here is the result!
This is now my (complete) test code:
--------------------------------------------------------
-- This is the top entity
-- it is simply a group of 10 Modules which decode input a and give a
'1' signal if it matches with a

entity TestModules is
Port ( a : in std_logic_vector (7 downto 0);
b : out std_logic_vector (1 to 10));
end TestModules;

architecture Behavioral of TestModules is

shared variable pos : integer :=0;

impure function NextAddress return integer is
begin
pos := pos +1;
return pos;
end function NextAddress;

begin

gen: for i in 1 to 10 generate
Module: entity work.myModule
Generic Map(Addr => NextAddress)
Port Map(x => a,
y => b(i));
end generate;

end Behavioral;

-- and now here comes the module itself

entity MyModule is
Generic (Addr : integer);
Port ( x : in std_logic_vector(7 downto 0);
y : out std_logic);
end MyModule;

architecture Behavioral of MyModule is

begin
y <= '1' when Conv_integer(x)=Addr else '0';
end Behavioral;

---
unfortunately the syntax check (XILINX ISE 9.1) brings up the
following error:

ERROR: HDLParsers:3305 - "C:/VHDL/TestSharedVariable/TestModules.vhd"
Line 25. The actual value (result of operator) associated with a
generic must be a globally static expression.

pointing to line 25: Generic Map(Addr => NextAddress)

Can anybody give me a hint how to repair this!

Thanks
Peter
 
P

pvwa

        impure function NextAddress return integer is
        begin
                pos := pos +1;
                return pos;
        end function NextAddress;

If i remove the keyword impure it gives me this warning:

WARNING: HDLParsers:3310 - "C:/VHDL/TestSharedVariable/
TestModules.vhd" Line 25. Function NextAddress is not pure. VHDL 87
allowed this; VHDL 93 requires the keyword IMPURE.

So what's going on?
 
A

Andy

Hi all,



No, its not a file from disk but simply a VHDL package which contains
constant vectors, which define my modules with versionnumbers!
I think very similar to your proposal!?
See here an excerpt from my code:
------------------------------------------------------

type N_Vers is array ( NATURAL RANGE <> ) of integer;
constant Module_A: N_Vers := (8,0,1,0,2,2,0,0,0);
constant Module_B: N_Vers := (0);
constant Module_C: N_Vers := (2,0,0);
...
-- this is part of my setupfile
-- the first element of the constants are the number of modules of
that type, the other numbers are the according versions of that
type!...

-- Now these special functions "NextAddress.." (also in a pkg) take
care of the address calculation, similar to this:

function NextAddress_A(pos: integer) return integer is
begin
        return pos; -- this is easy, because Module_A is the first module
type in the chain
end;

function NextAddress_B(pos: integer) return integer is
begin
        return Module_A(0)+pos;
end;

function NextAddress_C(pos: integer) return integer is
begin
        return Module_A(0)+Module_B(0)+pos; -- things getting more and more
complicated!
end;

...

-- finally here the mdoules according the setup constants are
generated

 gen_Module_A : for i in 1 to Module_A(0) generate
   iModule_A : entity work.ModuleA
     generic map (Address => NextAddressA(i),
                 (Version => Module_A(i))
     port map(...)
 end generate;

  gen_Module_B : for i in 1 to Module_B(0) generate
   iModule_B : entity work.ModuleB
     generic map (Address => NextAddressB(i),
                 (Version => Module_B(i))
     port map(...)
 end generate;

  gen_Module_C : for i in 1 to Module_C(0) generate
   iModule_C : entity work.ModuleC
     generic map (Address => NextAddressC(i),
                 (Version => Module_C(i))
     port map(...)
 end generate;

 ...

------------------------------------------------------

I think you get the idea!

The code above is very simplified, because i don't have to generate
not only addresses but also other numbers, which are dependent on the
versionnumbers of the modules!

So i have to write for each module, according functions, which do the
calculations!
Now imagine i want to change my code, e.g. i remove Module_B, then ALL
the dependent functions have to be changed also!!

I simply search for another solution, where the calculation can be
done in the Modules itself and this is not depended on other modules
(or functions) but simply on the fact of beeing instanciated or not!
My thinking was of a kind of "global variable", which is simply
incremented
So there would be only one function "NextAddress" be needed, similar
to this:

function NextAddress() return integer is
        global variable pos: integer := 0; this is the initialization of the
variable
begin
        pos := pos +1;
        return pos;
end;

But nothingh like this seems to be possible in VHDL!?

My thinking was also of writing out the number+1 to a file and read it
back, whenever the function is called, but i learned that file
read&write in VHDL is not possible??

Peter von Walter

If you built an array of n_vers's (they would have to be fixed length
(i.e. padded with additional unused version numbers for uninstantiated
modules), then you could have one address function that iterated
through the array up to the current module/instance to calculate the
address, without using shared variables.

You could take it a step further by eliminating the number of modules
(1st) element in the array, and use -1 as a version number that
indicates the module is not instantiated.

Andy
 
T

Tricky

If i remove the keyword impure it gives me this warning:

WARNING: HDLParsers:3310 - "C:/VHDL/TestSharedVariable/
TestModules.vhd" Line 25. Function NextAddress is not pure.  VHDL 87
allowed this; VHDL 93 requires the keyword IMPURE.

So what's going on?

So the old globally static chestnut.
The only way round this I can think of is to create an array type and
create a constant, but I doubt this will work either:

type addr_array_t is array (0 to N_ENTITIES-1) of natural;
Constant addr_array : addr_array_t := ( others => NextAddress);

then when you instantiate the entity, you say:

Generic Map(Addr => addr_array(i))

For your second point - impure is needed because you are updating a
variable declared outside of the function. Pure functions can only
output 1 thing (the thing that they return) but impure ones can change
variables outside of the function. Any function can read things
declared outside of it.
 
P

pvwa

Kevin
Yes, because you didn't take my suggestion which was to create a
single function that loops through the list of all the modules and
return an array of constant addresses.  Now that you've posted some
code to get a better idea of what you're trying to accomplish, let me
suggest the following which uses the 'Create_Addresses' function that
I posted earlier, modified slightly to take an extra input parameter
that is a 'start address' which would be used to initialize the first
element in the computed addresses

  type arr_integer is array(integer range <>) of integer;
  ...
  function Create_Addresses(V: std_ulogic_vector; Start_Address:
natural) return arr_integer
  ...
  constant Module_A_Address:  arr_integer(Module_A'range) :=
Create_Addresses(Module_A, 0);
  constant Module_B_Address:  arr_integer(Module_B'range) := Create_Addresses(Module_A,Module_A_Address(Module_A_Address'right)+1);
  constant Module_C_Address:  arr_integer(Module_C'range) :=
Create_Addresses(Module_B, Module_B_Address(Module_B_Address'right)+1);

Now you have three sets of arrays of integers for each of the three
modules, those would be used when instantiating the modules like
this...




The only change from your code then is to use the pre-computed
constants as the address generic.




Not really.  As I showed, one 'function' covered nearly all of the
computations.  The only other calculation is the part that links
address from the end of the 'Module A' list to the address start of
the 'Module B' list.  This is accomplished with the added parameter to
'Create_Addresses' which allows for an arbitrary 'first' address to
use and then invoking that function by passing it the address of the
end of the 'Module A' list and adding 1 (i.e. the
"Module_A_Address(Module_A_Address'right)+1" portion of the call to
define Module_B_Address

  constant Module_B_Address:  arr_integer(Module_B'range) :=
Create_Addresses(Module_A, Module_A_Address(Module_A_Address'right)
+1);

Module B and C are similarly linked.


I would 'remove' a module by having a flag indicating whether the
module is to be generated or not.  I'm not quite sure if that's what
you're doing or not.

This is really the main point!
My code is still in work and constantly changing. This is meant by
"removing"! I really want to be able to remove/substitute/add modules
in the source code without having to change too much in other parts
(functions)!

As far as i understand, you put the task of address generation into
the generation of constant vectors, which are then finally used! These
vectors have to be linked "manually", by using the next proper start
adresses (range.right) as paramter in "Create_Addresses()". The task
of linking the addresses remains (the crucial problem!). And again, if
i have to change my code i have to be very careful to reestablish the
linking!

Again, I thought there is a much simpler solution (something like
"impure functions" see below!)

But your proposal (in contrary to mine) is interesting anyway! Maybe
it simplifies overall editing of my code! Give me some time and i will
give it a try!
You can't do it with the way that you're viewing the problem which is
in terms of some *variable*.  You can do it though by viewing the
problem in terms of generating a *constant* vector which is what I'm
trying to get across.



That function simply lacks an input to indicate whether something
should be included or not and some base address to start at.  Other
than that it is doing essentially the same thing as the
'Create_Addresses' function that I posted, the crucial difference is
that my function returns something that can be used to generate the
vector of constants that you need.


It is...the mental hurdle is to stop viewing this address calculation
as being some variable that needs incrementing but instead see it as
the computation of a set of constants.


That approach would not be a good path to go down.

Why? Would'nt it work?

Greetings, appreciating you patience!
Peter
 
P

pvwa

If you built an array of n_vers's (they would have to be fixed length
(i.e. padded with additional unused version numbers for uninstantiated
modules), then you could have one address function that iterated
through the array up to the current module/instance to calculate the
address, without using shared variables.

You could take it a step further by eliminating the number of modules
(1st) element in the array, and use -1 as a version number that
indicates the module is not instantiated.

Andy

I would have preferred a solution with a kind of "shared variable",
but this seems not to work!?
Thanks
Peter
 
P

pvwa

So the old globally static chestnut.
The only way round this I can think of is to create an array type and
create a constant, but I doubt this will work either:

type addr_array_t is array (0 to N_ENTITIES-1) of natural;
Constant addr_array : addr_array_t := ( others => NextAddress);

then when you instantiate the entity, you say:

Generic Map(Addr => addr_array(i))

No this works, and is what Kevin (above) proposes!
Using the impure function there does not help because then everything
is static and i was looking for a solution which works with
instantiation (calling the function in Generic Map or maybe even in
the module itself!!).

Peter
 
P

pvwa

Hi all,

it seems i have a solution!

This is my code (only for testing!):

I have a pkg File where the impure function NextAddress is defined:
----------------------------------------------------
package Test_pkg is
shared variable pos : integer := 0;
impure function NextAddress return integer;
end Test_pkg;

package body Test_pkg is

impure function NextAddress return integer is
begin
pos := pos+1;
return pos;
end function NextAddress;

end Test_pkg;
----------------------------------------------------

Now i use this function inside (not with Generic) in my Module:

----------------------------------------------------
entity MyModule is
Port ( x : in std_logic_vector(3 downto 0);
y : out std_logic);
end MyModule;

architecture Behavioral of MyModule is
constant ModuleAddress: integer := NextAddress;
begin
y <= '1' when Conv_integer(x)=ModuleAddressA else '0';
end Behavioral;
----------------------------------------------------

It is necessary to use the function for setting up a constant
"ModuleAddress" and use this in the address decoder!
Direct use of the function "NextAddress" in the comparator gives no
syntax error it simply does not work!!??
Has anybody a explanation for that!

No my top entity, where i instantiate 10 Modules.
Whenever a module is instantiated it should have a consecutive
address:

----------------------------------------------------
entity TestModules is
Port ( a : in std_logic_vector (3 downto 0);
b : out std_logic_vector (1 to 10));
end TestModules;

architecture Behavioral of TestModules is
begin

gen: for i in 1 to 10 generate
Module: entity work.myModule
Port Map(x => a,
y => b(i));
end generate;

end Behavioral;
----------------------------------------------------

No syntax error!
Now i test my circuitry with this testbench:

----------------------------------------------------
BEGIN

uut: TestModules PORT MAP(
a => a,
b => b
);

tb : PROCESS
BEGIN
wait for 100 ns;
a <= "0000"; --0
wait for 100 ns;
a <= "0001"; --1
wait for 100 ns;
a <= "0010"; --2
wait for 100 ns;
a <= "0011"; --3
wait for 100 ns;
a <= "0100"; --4
wait;
END PROCESS;

END;
----------------------------------------------------

Unfortunately i cannot give you a picture, but it shows the correct
answers of 4 Modules!
Now i have to synthesize and implement to be really sure everything
works as expected!

This seemes to me a very elegant possibility and simplifies my design
significantly!

One (little) disadvantage with not beeing able to transfer the address
via Generic is the missing of this information in the report!
I am not used to it, but how can i report (Assert?) my generated
addresses?

Thanks Tricky, to show me the way!
Peter
 
T

Tricky

It is necessary to use the function for setting up a constant
"ModuleAddress" and use this in the address decoder!
Direct use of the function "NextAddress" in the comparator gives no
syntax error it simply does not work!!??
Has anybody a explanation for that!

Because every time you call NextAddress, it changes the address. So
You would have to get lucky for the incoming address to match in the
ever changing match. Setting it to a constant means it never changes.

One (little) disadvantage with not beeing able to transfer the address
via Generic is the missing of this information in the report!
I am not used to it, but how can i report (Assert?) my generated
addresses?

Asserts can be placed almost anywhere. for what you want, just put it
inside the architecture.
Try this:
assert false report my_ent'PATH_NAME & ": Address of something = " &
integer'image(ConstantAddress) severity NOTE;

Now, as discussed previously in another thread, asserts get treated
different by different synthesisors. I Know Quartus handles them very
well, but other synthesisors either ignore them or mishandle them and
just print Failures/errors as warnings!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top