VHDL subprocedure call

R

Richard Molgner

Hi all,

I have two nested procedures, where the "main" procedure makes use of
"subproc" to accumulates a result in variables t0 and t1, which is
then returned at the end. This should all be computed in one clock
cycle, and the circuit more or less just consists of simple logic
gates (xor, or, and). When I try to describe the circuit as below I
get the following error:

Acutal (variable t0) for formal "a" is not a signal

That makes sense as the subprocure requires signals as input, but I
wanna pass it a variable during the main procedure. Is there a simple
way to circumvent this problem with casting for example?

Thanks

procedure subproc
(
signal a : in std_logic_vector(31 downto 0);
signal b : in std_logic_vector(31 downto 0);
signal c : in std_logic_vector(31 downto 0);
signal d : in std_logic_vector(31 downto 0);
signal e : out std_logic_vector(31 downto 0);
signal f : out std_logic_vector(31 downto 0)
)
is
variable x : std_logic_vector(31 downto 0);
variable y : std_logic_vector(31 downto 0);
begin

x := (others => '0');
y := (others => '0');

for i in 0 to 31 loop
x(i) := (a(i) xor b(i)) and (c(i) xor d(i));
y(i) := (a(i) xor b(i)) or ((d(i) xor c(i)) xor b(i));
end loop;

e <= x(31 downto 0);
f <= y(31 downto 0);

end;

procedure main
(
signal a : in std_logic_vector(31 downto 0);
signal b : in std_logic_vector(31 downto 0);
signal r : out std_logic_vector(31 downto 0)
)
is
variable res : std_logic_vector(31 downto 0);
variable t0, t1 : std_logic_vector(31 downto 0);
constant c : std_logic_vector(31 downto 0) := X"fedcba90";
constant d : std_logic_vector(31 downto 0) := X"7654321f";
begin

t0 := (others => '0');
t1 := (others => '0');

for i in 0 to 31 loop
if ( (c(i) = '0') && (d(i) = '1') ) then
subproc( t0, t1,
a, b, t0, t1 );
end if;
end loop;

r <= t0;
end;
 
R

Richard Molgner

Hi again,

I updated the routine now, and it looks as follows. Although it
compiles fine, the output
of the computation is ALWAYS ZERO. It seems with this software-like
implementation I wont
be able to describe the hardware circuit I want to. Or does anyone see
a problem with my
VHDL description?

procedure main
(
signal a : in std_logic_vector(31 downto 0);
signal b : in std_logic_vector(31 downto 0);
signal r : out std_logic_vector(31 downto 0)
)
is
variable res : std_logic_vector(31 downto 0);
variable t0, t1 : std_logic_vector(31 downto 0);
constant c : std_logic_vector(31 downto 0) := X"fedcba90";
constant d : std_logic_vector(31 downto 0) :=
X"7654321f";
begin

t0 := (others => '0');
t1 := (others => '0');

for i in 0 to 31 loop
if ( (c(i) = '0') and (d(i) = '1') ) then
for j in 0 to 31 loop
t0(j) := (a(j) xor b(j)) and (t0(j) xor t1(j));
t1(j) := (a(j) xor b(j)) or ((t1(j) xor t0(j)) xor
b(j));
end loop;
end if;
end loop;

r <= t0;
end;

many thanks
 
M

Martin Thompson

Richard Molgner said:
Hi again,

I updated the routine now, and it looks as follows. Although it
compiles fine, the output
of the computation is ALWAYS ZERO.

In simulation or synthesis? I might expect the output to be all Us in
simulation. Zeros seems plausible for synthesis.
It seems with this software-like
implementation I wont
be able to describe the hardware circuit I want to. Or does anyone see
a problem with my
VHDL description?

Have you put a call to that procedure inside an entity? Unless *you*
call the procedure it won't get called - there's no implicit
(well, startup-code defined) call to main like there is in c. The
simulator "runs" a top-level entity that you tell it to. The
synthesiser also works on a top-level entity. Procedures are not the
"top" that you may be thinking they are.

I'll attempt to describes what needs to go on (on the assumption that
you are new to VHDL, not and old hand trying some new tricks :) If
we're lucky, it's possible that Jonathan Bromley will also chip in and
give you a description - his is likely to be much better than mine as
he's (been) a professional trainer!

Anyway....

What you have to do is create an "entity" which describes the
interface (in terms of input and/or output pins) to the logic you
want. (This interface will look like the procedure definition
currently does.)

That entity then has an "architecture" which describes what goes on
inside the block to bring the ins and outs of that interface together.

Your procedure is a description of some logic which can go inside that
architecture... inside a "process".

Processes control when code "runs", and you want to run yours whenever a
or b changes. So you need to give a sensitivity list to the process
which has both a and b in it. Then, whenever a or b changes, the
process will run and that can call your procedure. At the end of the
process, it will stop and wait for the next change on any of the
signals in the sensitivity list.

<snip code>

I hope that helps a little!

Cheers,
Martin
 
R

rickman

Hi again,

I updated the routine now, and it looks as follows. Although it
compiles fine, the output
of the computation is ALWAYS ZERO. It seems with this software-like
implementation I wont
be able to describe the hardware circuit I want to. Or does anyone see
a problem with my
VHDL description?

 procedure main
    (
      signal a : in  std_logic_vector(31 downto 0);
      signal b : in  std_logic_vector(31 downto 0);
      signal r : out std_logic_vector(31 downto 0)
    )
    is
      variable res : std_logic_vector(31 downto 0);
      variable t0, t1 : std_logic_vector(31 downto 0);
      constant c : std_logic_vector(31 downto 0) := X"fedcba90";
      constant d : std_logic_vector(31 downto 0) :=
X"7654321f";
    begin

      t0 := (others => '0');
      t1 := (others => '0');

      for i in 0 to 31 loop
        if ( (c(i) = '0') and (d(i) = '1') ) then
             for j in 0 to 31 loop
               t0(j) := (a(j) xor b(j)) and (t0(j) xor t1(j));
               t1(j) := (a(j) xor b(j)) or ((t1(j) xor t0(j)) xor
b(j));
             end loop;
        end if;
      end loop;

      r <= t0;
    end;

many thanks

If you don't think it is calculating the result correctly, why don't
you simulate it where you can view all the details?

The calculations seem a bit odd. I can't picture what problem this
might be solving. I also don't know why you make it so complicated.
The constants c and d are only used in the "if" condition where they
are bit-wise anded. Why couldn't you replace that with a single
constant that has already been bit-wise anded?

The rest of it is a bit too complex to analyze easily and you don't
provide your test data. It looks to me like it would require a fairly
special set of inputs on a and b to cause bits to be set in t0. First
you have to get past the not c and d filter which only passes the 4
lsbs. If you computed the value of not c and d you would see this.
Then in a bit-wise fashion, to set t0 it has to be different from t1.
Since they are both initialized to all zeros, that means t1 has to be
set. To set t1 either a and b must be different or t1, t0 and b must
have an odd number of bits set.

Are you sure your input vectors provide for anything other than zero
bit values output?

Rick
 
P

Paul Uiterlinden

Richard said:
Hi again,

I updated the routine now, and it looks as follows. Although it
compiles fine, the output
of the computation is ALWAYS ZERO. It seems with this software-like
implementation I wont
be able to describe the hardware circuit I want to. Or does anyone see
a problem with my
VHDL description?

procedure main
(
signal a : in std_logic_vector(31 downto 0);
signal b : in std_logic_vector(31 downto 0);
signal r : out std_logic_vector(31 downto 0)
)
is
variable res : std_logic_vector(31 downto 0);
variable t0, t1 : std_logic_vector(31 downto 0);
constant c : std_logic_vector(31 downto 0) := X"fedcba90";
constant d : std_logic_vector(31 downto 0) :=
X"7654321f";
begin

t0 := (others => '0');
t1 := (others => '0');

for i in 0 to 31 loop
if ( (c(i) = '0') and (d(i) = '1') ) then
for j in 0 to 31 loop
t0(j) := (a(j) xor b(j)) and (t0(j) xor t1(j));
t1(j) := (a(j) xor b(j)) or ((t1(j) xor t0(j)) xor
b(j));
end loop;
end if;
end loop;

r <= t0;
end;


With the given values of constants c and d, the only bits for which the 'if'
holds true are 0 to 3. Is that what you intended?

As you have rewritten your code, you now modify t0 and then use it in the
computation of t1. That is not what was intended in the original code, as
far as I can see.

It seems you messed up in an attempt to transform the original code.

Let me try to modify that code so it will compile. No guarantees on
functionality, I'll probably mess up as well!

procedure subproc
(
a : inout std_logic_vector(31 downto 0);
b : inout std_logic_vector(31 downto 0);
c : in std_logic_vector(31 downto 0);
d : in std_logic_vector(31 downto 0)
)
is
variable x : std_logic_vector(31 downto 0);
variable y : std_logic_vector(31 downto 0);
begin
x := (a xor b) and (c xor d);
y := (a xor b) or ((d xor c) xor b);

a := x;
b := y;
end;

procedure main
(
constant a : in std_logic_vector(31 downto 0);
constant b : in std_logic_vector(31 downto 0);
signal r : out std_logic_vector(31 downto 0)
)
is
variable t0, t1 : std_logic_vector(31 downto 0);
constant c : std_logic_vector(31 downto 0) := X"fedcba90";
constant d : std_logic_vector(31 downto 0) := X"7654321f";
begin
t0 := (others => '0');
t1 := (others => '0');

for i in c'range loop
if (c(i) = '0') and (d(i) = '1') then
subproc(t0, t1, a, b);
end if;
end loop;

r <= t0;
end;


Remarks:

1) No need to always use separate bits. Operators like and, or,
xor also work on vectors. No loop needed.

2) If you want to use the complete vector, there is no need to
specify the range. So these are all equivalent:
a := x;
a := x(31 downto 0);
a(31 downto 0) := x;
a(31 downto 0) := x(31 downto 0);

3) Parameters of procedures need not always be of class signal.
Depends on where they are used.

4) Parenthesis around the condition in an 'if' statement are not
needed (style issue). VHDL is not C.

5) There is no operator &&: it is 'and'. VHDL is not C.

6) Variable res in procedure main was never used.

7) If you want to loop over all bits in a vector, use the 'range
attribute. In my opinion it is clearer and it is more robust
against code changes (like changing the vector length).

8) The class of parameters c and d of procedure subproc and
parameters a and b of main all are constant. For input parameters
that is the default. I have the habit to only actually specify
the class of subprogram parameters if one of the parameters has
a non-default class, such as parameter r of main in this case.

9) Simulate before synthesize. That also means: make a testbench.
 

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,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top