Using Constrained Integer instead of SLV

R

rickman

Guest
Moved from "stumped on syntax yet again!"
On May 10, 11:56 am, Mike Treseler <mtrese...@gmail.com> wrote:
Mike Treseler wrote:
rickman wrote:

function sllint (x, sh : natural) return natural is
begin
return x*(2**sh);
end sllint;

I am not clear on what happens when I shift the value of Addr left by
2 and significant bits extend beyond the defined range.

The function, as written, will return x*(2**sh)
up to the natural range. It knows nothing about
any other range unless you add a parameter
to to function.

I would use numeric_std.unsigned and the shift_left
function, and to_integer(my_uns, my_len) as needed.

function, and to_integer(my_uns) as needed.
One of the bad things of being a "jack of all trades" is that I tend
to forget a lot of details between jacking any given trade. I think
it has been at least two years since I have written any VHDL and I
have forgotten a lot of my style.

I get a bit tired of all the typing that is needed to do things in
VHDL and I thought that using integers might be a bit simpler than
using slv. So instead of typing...

DataWr <= DataWr(DataWr'high-Scfg_Din'width downto 0) &
AddrReg(AddrReg'high downto AddrReg'high-Scfg_Din'width);

I was thinking about

DataWr <= sllbar(DataWr, CTPDATAWDTH) + srlbar(AddrReg, AddrRegWidth-
CTPDATAWDTH);

where sllbar is a function that returns an unconstrained integer.

I guess the missing information the width of the data field which is
one of the things that makes the slv version so long. I assume that
if DataWr is a constrained integer, it would be an error in simulation
if the value of sllbar was outside the range of DataWr. How might
this synthesize? Or would it also be a synthesis error because of the
mismatch in range of DataWr and the sllbar result?

If I create a separate sllbar for each data width, sllnib, sllbyte,...
and used the mod operator to restrict the range of the result, that
should cure things, no?

I was hoping to use an overloaded operator so that each one would have
the same name and the correct one would be picked based on the subtype
of the operands. But I believe that this won't work. Is that
correct?

Rick
 
rickman wrote:

I get a bit tired of all the typing that is needed to do things in
VHDL and I thought that using integers might be a bit simpler than
using slv.
It would be easier to use unsigned for vectors
to get the numeric and shift functions.

to_integer(my_unsigned) for integers,

unsigned(my_in_port) for in ports
std_logic_vector(my_unsigned) for out ports)

What's the problem with that?

I was hoping to use an overloaded operator so that each one would have
the same name and the correct one would be picked based on the subtype
of the operands. But I believe that this won't work. Is that
correct?
It could work, but you would be duplicating a standard
library that already works fine.

-- Mike Treseler
 
On May 11, 3:46 pm, "KJ" <kkjenni...@sbcglobal.net> wrote:
"rickman" <gnu...@gmail.com> wrote in message news:f0283d1c-aeab-4651-ad45-

I was thinking about

DataWr <= sllbar(DataWr, CTPDATAWDTH) + srlbar(AddrReg, AddrRegWidth-
CTPDATAWDTH);

where sllbar is a function that returns an unconstrained integer.

Another approach would be a function that takes in DataWr and AddrReg and
Scfg_Din and computes a new DataWr output if that particular type of
function is something you would reuse in several places. That way the mess
is in one place (the function) but the usage (where the function is called)
is easier to follow.
I'm not sure I follow this. I guess the "mess" as I call it is just
the verbosity of VHDL. Hiding it in a function does not really solve
the problem unless the function is general enough to work with other
signals as well. That is what I am trying to do with the integer
shift function. Obviously it is not working well.


I guess the missing information the width of the data field which is
one of the things that makes the slv version so long. I assume that
if DataWr is a constrained integer, it would be an error in simulation
if the value of sllbar was outside the range of DataWr.

Yes, if the actual value returned from the function is outside of the
defined range for DataWr then the simulator would give you an error.
I got that, unfortunately. I was hoping that there was a clean way to
convert the value to something that will fit within the range of
DataWr. But again, obviously there isn't.


How might
this synthesize?

Just fine, synthesis doesn't 'check' for overflow that's a problem that the
design is supposed to catch in simulation. If you had
signal DataWr: integer range 0 to 1023;
then DataWr would get synthesized as a 10 bit number. If there is some
condition under which your design would attempt to assign the value of 1024
to DataWr due to some design error on your part, then DataWr in the actual
design would be set to 0 due to your lack of providing sufficient precision.

This also works for entities as well. If you have an entity that receives
or returns an unconstrained type, you would instantiate that entity and in
doing so would connect it to some signal which *does* have a constrained
type. One possible silent 'gotcha' here though is that integers don't have
to be constrained in which case they will end up being synthesized as full
32 bit things, which might not be what you want. Vectors don't have this
problem since if the vector is not constrained somewhere, it won't compile
so you'll find and fix the problem right away.
That is what I am wondering. If the function is using integers, does
the constrained integer get widened to 32 bits for the calculation in
the function and then truncated when assigned back to the constrained
integer?


Or would it also be a synthesis error because of the
mismatch in range of DataWr and the sllbar result?

Synthesis does not check that you've defined sufficient precision for your
calculations. That is your job as the designer and synthesis expects you to
do that so no errors or warnings would likely be reported (one exception
though can be the assignment of an out of range constant such as DataWr <=
1024; when DataWr has the 0 to 1023 range).
I think you are missing why (or how) I am using the constrained
integer signals. I *want* to lose the overflow. I would explicitly
use the mod operator, but that requires passing in the width of the
data path and we are back to being messy in the function call.


If I create a separate sllbar for each data width, sllnib, sllbyte,...
and used the mod operator to restrict the range of the result, that
should cure things, no?

That would temporarily 'cover up' your design error and push off the
ultimate resolution of this problem until sometime later when it will most
likely be much harder to diagnose. Instead of trying to sweep the
assignment of something that equals '1024' under the rug you should be using
the simulator to catch those problems so you can fix them.
I don't get why you call it a design error. I intend to limit the
range of the signal. A shift left operation is going to shift data
off the end and lose it by design. Or are you just referring to how
the tools view this usage?


Having the simulator report the assignment of something that evaluates to
1024 to something that is 'supposed' to be in the range from 0 to 1023 is a
good thing (a very good thing actually).
The issue is how to simply and easily implement the shifter. I just
get tired of all the long lines that wrap around so that they are hard
to read. VHDL is a very verbose language.

I was hoping to use an overloaded operator so that each one would have
the same name and the correct one would be picked based on the subtype
of the operands. But I believe that this won't work. Is that
correct?

Not quite sure what you're getting at here.
If I defined a shift operator for every subtype of integer, I would
expect the tool to pick the correct one to match the operands. Then
there would be no out of range assignment. But I believe I originally
posted about this when someone said that you can't select overloaded
operators based on subtype. Overloading is always based on the base
types.

Rick
 
On May 11, 11:48 pm, rickman <gnu...@gmail.com> wrote:
On May 11, 3:46 pm, "KJ" <kkjenni...@sbcglobal.net> wrote:

"rickman" <gnu...@gmail.com> wrote in message news:f0283d1c-aeab-4651-ad45-

I was thinking about

DataWr <= sllbar(DataWr, CTPDATAWDTH) + srlbar(AddrReg, AddrRegWidth-
CTPDATAWDTH);

where sllbar is a function that returns an unconstrained integer.

Another approach would be a function that takes in DataWr and AddrReg and
Scfg_Din and computes a new DataWr output if that particular type of
function is something you would reuse in several places.  That way the mess
is in one place (the function) but the usage (where the function is called)
is easier to follow.

I'm not sure I follow this.  I guess the "mess" as I call it is just
the verbosity of VHDL.  Hiding it in a function does not really solve
the problem unless the function is general enough to work with other
signals as well.  That is what I am trying to do with the integer
shift function.  Obviously it is not working well.
To tell you the truth, I'm not quite sure how the two ways you were
proposing were even equivalent. In the verbose wordy version that you
listed, you're taking a certain number of the most significant bits of
DataWr and assigning them back to DataWr (i.e. keep those bits the
same) and then tacking on a certain number of bits from AddrReg to
become the new lower bits of DataWr. In the second approach with
sllbar (assuming this to be a shift left that works with integers)
you're taking DataWr and shifting it up by some number of bits and
assigning it to DataWr...how that will maintain the upper bits of
DataWr unchanged escaped me then and it still does...so I thought that
maybe one time wordiness (i.e. a function) would be preferable, but
apparently not.

Yes, if the actual value returned from the function is outside of the
defined range for DataWr then the simulator would give you an error.

I got that, unfortunately.  I was hoping that there was a clean way to
convert the value to something that will fit within the range of
DataWr.  But again, obviously there isn't.
Not without passing in an argument to the sllbar/srlbar functions to
tell it what range you're interested in. This is directly analogous
to how in numeric_std, you can't just pass in an integer and convert
it to a signed/unsigned, you have to also pass in an argument that
tells it the width of that signed/unsigned output.

How might
this synthesize?

Just fine, synthesis doesn't 'check' for overflow that's a problem that the
design is supposed to catch in simulation.  If you had
signal DataWr: integer range 0 to 1023;
then DataWr would get synthesized as a 10 bit number.  If there is some
condition under which your design would attempt to assign the value of 1024
to DataWr due to some design error on your part, then DataWr in the actual
design would be set to 0 due to your lack of providing sufficient precision.


That is what I am wondering.  If the function is using integers, does
the constrained integer get widened to 32 bits for the calculation in
the function and then truncated when assigned back to the constrained
integer?

The calculation within the functions will be based on the ranges of
the arguments that you supplied when you call the function. That fact
that the function works with unconstrained types is not relevant to
synthesis.

Example:
function AddEm(a, b: integer) return integer is
begin
return(a+b);
end function AddEm;
...
signal A_sig, B_sig, C_sig: integer range 0 to 1023;
...
C_sig <= AddEm(A_sig, B_sig);

This would all be done with 10 bit precision when synthesizing because
that is the range of the arguments (A_sig, B_sig) and where the result
is stored (C_sig). No expanding to 32 bits, no truncating back down
to 10.

The case where A_sig and B_sig add up to something greater than 1023
and therefore wouldn't fit back into C_sig is something that the
simulator would flag if it occurs (i.e. AddEm(512,512)) but synthesis
wouldn't do anything about since not handling overflow properly is the
designer's issue.

Synthesis does not check that you've defined sufficient precision for your
calculations.  That is your job as the designer and synthesis expects you to
do that so no errors or warnings would likely be reported (one exception
though can be the assignment of an out of range constant such as DataWr <> > 1024; when DataWr has the 0 to 1023 range).

I think you are missing why (or how) I am using the constrained
integer signals.  I *want* to lose the overflow.  I would explicitly
use the mod operator, but that requires passing in the width of the
data path and we are back to being messy in the function call.
Well, I do admit I'm not clear on the equivalence of the two
approaches shifting vs. masking) they don't look equivalent to me.

So based on that lack of understanding, all I can add is that I also
don't understand why you think adding a third argument to your shift
functions that defines the range in some fashion suddenly makes what
you see as a good solution turn back to 'messy'.

I'll also add that this is where using numeric_std and signed/unsigned
types has a leg up on integers. When you have a function that
receives signed/unsigned types as arguments, the function itself can
determine the precision if necessary since it can get the length of
argument 'a' with a'length and go from there.

The issue is how to simply and easily implement the shifter.  I just
get tired of all the long lines that wrap around so that they are hard
to read.  VHDL is a very verbose language.
You made an assumption that working with integers might be easier than
working with std_logic_vectors for this particular type of operation
and it seems that that assumption is wrong. Working with unsigned in
this case might be easier where the inherent precision of the signal/
variable is readily available via the length attribute.

If your interface signals tend to always be std_logic_vector then the
wordiness of VHDL will hit you with things like...

blah <= std_logic_vector(shift_left(unsigned(blah), 3));

but this can be overcome by simply creating a simple (and reusable)
shift_left function of your own that takes in and outputs
std_logic_vectors. Then the wordy type conversions are buried down in
your custom shift_left function and you would be left with

blah <= shift_left(blah, 3);

which clearly expresses your design intent without being verbose. The
new shift_left function you can keep in your toolkit and reuse ad
nauseum.

If I defined a shift operator for every subtype of integer, I would
expect the tool to pick the correct one to match the operands.  Then
there would be no out of range assignment.  But I believe I originally
posted about this when someone said that you can't select overloaded
operators based on subtype.  Overloading is always based on the base
types.
That's correct...possibly unfortunate from your perspective but that's
the way it is.

Again, I don't quite understand how the two methods you proposed are
supposed to be equivalent so I may be missing the mark again, but
hopefully there is something useful here for you to work with.

Kevin Jennings
 
rickman wrote:

Yes, but my point is that this information is already contained in the
range of the subtype. Without having looked at it hard, I was hoping
that VHDL would be able to use the constrained range to determine how
many bits are used. I believe this is what happens in synthesis.
Integers don't produce 32 bit data paths if they are constrained to a
smaller range.
Your function expects and returns any natural range.

function sllint (x, sh : natural) return natural

It has no knowledge of the actual range as is.
To add that knowledge, I would have to add
a function of the same name for each subtype
that I want to cover intelligently.

This is a lot of work.
This work has already been done for you
in the numeric_std package.

I'm trying to make integers do the same
work as slv or unsigned.
This is built into verilog.
It might be easer to use verilog
than to make vhdl act like verilog.

-- Mike Treseler
 
On May 12, 8:49 am, KJ <kkjenni...@sbcglobal.net> wrote:
On May 11, 11:48 pm, rickman <gnu...@gmail.com> wrote:



On May 11, 3:46 pm, "KJ" <kkjenni...@sbcglobal.net> wrote:

"rickman" <gnu...@gmail.com> wrote in message news:f0283d1c-aeab-4651-ad45-

I was thinking about

DataWr <= sllbar(DataWr, CTPDATAWDTH) + srlbar(AddrReg, AddrRegWidth-
CTPDATAWDTH);

where sllbar is a function that returns an unconstrained integer.

Another approach would be a function that takes in DataWr and AddrReg and
Scfg_Din and computes a new DataWr output if that particular type of
function is something you would reuse in several places. That way the mess
is in one place (the function) but the usage (where the function is called)
is easier to follow.

I'm not sure I follow this. I guess the "mess" as I call it is just
the verbosity of VHDL. Hiding it in a function does not really solve
the problem unless the function is general enough to work with other
signals as well. That is what I am trying to do with the integer
shift function. Obviously it is not working well.

To tell you the truth, I'm not quite sure how the two ways you were
proposing were even equivalent. In the verbose wordy version that you
listed, you're taking a certain number of the most significant bits of
DataWr and assigning them back to DataWr (i.e. keep those bits the
same) and then tacking on a certain number of bits from AddrReg to
become the new lower bits of DataWr. In the second approach with
sllbar (assuming this to be a shift left that works with integers)
you're taking DataWr and shifting it up by some number of bits and
assigning it to DataWr...how that will maintain the upper bits of
DataWr unchanged escaped me then and it still does...so I thought that
maybe one time wordiness (i.e. a function) would be preferable, but
apparently not.
I think you missed something. In both cases DataWr is being shifted
left by N bits and the N msbs of AddrReg is shifted into the low order
N bits of DataWr.

DataWr <= DataWr(DataWr'high-Scfg_Din'width downto 0) &
AddrReg(AddrReg'high downto AddrReg'high-Scfg_Din'width);

This is the code you seem to be confused about. The index when
reading DataWr is high-N downto 0. This says select the rightmost
bits of DataWr which get assigned to to the msbs of DataWr.


Yes, if the actual value returned from the function is outside of the
defined range for DataWr then the simulator would give you an error.

I got that, unfortunately. I was hoping that there was a clean way to
convert the value to something that will fit within the range of
DataWr. But again, obviously there isn't.

Not without passing in an argument to the sllbar/srlbar functions to
tell it what range you're interested in. This is directly analogous
to how in numeric_std, you can't just pass in an integer and convert
it to a signed/unsigned, you have to also pass in an argument that
tells it the width of that signed/unsigned output.
Yes, but my point is that this information is already contained in the
range of the subtype. Without having looked at it hard, I was hoping
that VHDL would be able to use the constrained range to determine how
many bits are used. I believe this is what happens in synthesis.
Integers don't produce 32 bit data paths if they are constrained to a
smaller range.


How might
this synthesize?

Just fine, synthesis doesn't 'check' for overflow that's a problem that the
design is supposed to catch in simulation. If you had
signal DataWr: integer range 0 to 1023;
then DataWr would get synthesized as a 10 bit number. If there is some
condition under which your design would attempt to assign the value of 1024
to DataWr due to some design error on your part, then DataWr in the actual
design would be set to 0 due to your lack of providing sufficient precision.

That is what I am wondering. If the function is using integers, does
the constrained integer get widened to 32 bits for the calculation in
the function and then truncated when assigned back to the constrained
integer?

The calculation within the functions will be based on the ranges of
the arguments that you supplied when you call the function. That fact
that the function works with unconstrained types is not relevant to
synthesis.

Example:
function AddEm(a, b: integer) return integer is
begin
return(a+b);
end function AddEm;
...
signal A_sig, B_sig, C_sig: integer range 0 to 1023;
...
C_sig <= AddEm(A_sig, B_sig);

This would all be done with 10 bit precision when synthesizing because
that is the range of the arguments (A_sig, B_sig) and where the result
is stored (C_sig). No expanding to 32 bits, no truncating back down
to 10.

The case where A_sig and B_sig add up to something greater than 1023
and therefore wouldn't fit back into C_sig is something that the
simulator would flag if it occurs (i.e. AddEm(512,512)) but synthesis
wouldn't do anything about since not handling overflow properly is the
designer's issue.
I wouldn't expect synthesis to be concerned with overflow, actually I
don't see how it possibly could since this is a run time issue. If
unsigned signals are added and an overflow occurs, the simulation does
not flag this as an error, right? I was expecting the function to
understand that it was being passed constrained integers and to know
to ignore overflow. If the calculation is being done in 10 bit
arithmetic, then the overflow is not an error, it is what I asked
for.


Synthesis does not check that you've defined sufficient precision for your
calculations. That is your job as the designer and synthesis expects you to
do that so no errors or warnings would likely be reported (one exception
though can be the assignment of an out of range constant such as DataWr <=
1024; when DataWr has the 0 to 1023 range).

I think you are missing why (or how) I am using the constrained
integer signals. I *want* to lose the overflow. I would explicitly
use the mod operator, but that requires passing in the width of the
data path and we are back to being messy in the function call.

Well, I do admit I'm not clear on the equivalence of the two
approaches shifting vs. masking) they don't look equivalent to me.
You don't seem to be following my thinking at all. I am not saying
that masking is the same as shifting. I am saying that to implement a
shift using integers to represent a fixed width bus requires that the
value be shifted by multiplying or dividing. When multiplying the
result has to then be masked to represent the overflow bits that are
no longer part of the signal. I'm trying to make integers do the same
work as slv or unsigned.

Maybe I am missing major something here. If I want to implement a
shifter using integers, how would I write a statement to left shift by
N with dropping the bits shifted out? Couldn't it be this?

constant FooWidth : natural 4;
subtype FooRange is natural range 15 downto 0;

function ShiftIntLeft (Foo, N, Width : natural FooRange) begin
Foo <= (Foo*2**N) mod (2**Width);
return (Foo);
end ShiftIntLeft;

If Foo is constrained to the range of 15 downto 0, would it still
simulate without error if Foo is 8 and N is 2?


So based on that lack of understanding, all I can add is that I also
don't understand why you think adding a third argument to your shift
functions that defines the range in some fashion suddenly makes what
you see as a good solution turn back to 'messy'.
More typing and more clutter. By the time you add all this
information it is not really any less cluttered than using slv.


I'll also add that this is where using numeric_std and signed/unsigned
types has a leg up on integers. When you have a function that
receives signed/unsigned types as arguments, the function itself can
determine the precision if necessary since it can get the length of
argument 'a' with a'length and go from there.

The issue is how to simply and easily implement the shifter. I just
get tired of all the long lines that wrap around so that they are hard
to read. VHDL is a very verbose language.

You made an assumption that working with integers might be easier than
working with std_logic_vectors for this particular type of operation
and it seems that that assumption is wrong. Working with unsigned in
this case might be easier where the inherent precision of the signal/
variable is readily available via the length attribute.
Yes, I explored the possibility of using integers for this and I have
not found a way to make it simpler.


If your interface signals tend to always be std_logic_vector then the
wordiness of VHDL will hit you with things like...

blah <= std_logic_vector(shift_left(unsigned(blah), 3));

but this can be overcome by simply creating a simple (and reusable)
shift_left function of your own that takes in and outputs
std_logic_vectors. Then the wordy type conversions are buried down in
your custom shift_left function and you would be left with

blah <= shift_left(blah, 3);

which clearly expresses your design intent without being verbose. The
new shift_left function you can keep in your toolkit and reuse ad
nauseum.
The only trouble is that this is not what I am trying to do. Your
example just shifted an entire bus. Maybe my problem is that I am
simply not using shifting in the best way. With slv I am addressing
each sub bus which is a messy expression, especially when using
constants for the various values. Allowing the shifted busses to be
zero filled would allow the results to be combined with an OR...
except that the two busses are not the same width, so more verbosity
has to be added to compensate for that.


If I defined a shift operator for every subtype of integer, I would
expect the tool to pick the correct one to match the operands. Then
there would be no out of range assignment. But I believe I originally
posted about this when someone said that you can't select overloaded
operators based on subtype. Overloading is always based on the base
types.

That's correct...possibly unfortunate from your perspective but that's
the way it is.

Again, I don't quite understand how the two methods you proposed are
supposed to be equivalent so I may be missing the mark again, but
hopefully there is something useful here for you to work with.
Other than missing the function of the slv version, what do you not
understand? Both approaches take the rightmost M bits of DataWr and
combines it with the N leftmost bits of AddrReg. In essence, I am
shifting N bits left from AddrReg to DataWr with the data shifted out
of DataWr dropping on the floor.


Rick
 
On May 12, 7:49 am, KJ <kkjenni...@sbcglobal.net> wrote:
The calculation within the functions will be based on the ranges of
the arguments that you supplied when you call the function. That fact
that the function works with unconstrained types is not relevant to
synthesis.

Example:
function AddEm(a, b: integer) return integer is
begin
return(a+b);
end function AddEm;
...
signal A_sig, B_sig, C_sig: integer range 0 to 1023;
...
C_sig <= AddEm(A_sig, B_sig);

This would all be done with 10 bit precision when synthesizing because
that is the range of the arguments (A_sig, B_sig) and where the result
is stored (C_sig). No expanding to 32 bits, no truncating back down
to 10.

The case where A_sig and B_sig add up to something greater than 1023
and therefore wouldn't fit back into C_sig is something that the
simulator would flag if it occurs (i.e. AddEm(512,512)) but synthesis
wouldn't do anything about since not handling overflow properly is the
designer's issue.
Not necessarily. The precision of the addition is 32 bit signed,
regardless of the precision of the operands. So both arguments are
promoted to 32 bit signed, added, and then when the assignment is
stored, demoted to 10 bits unsigned. However, the synthesis tool will
optimize out unused bits (all those promoted zeroes, and all the
truncated bits from the assignment), so the final result is a 10 bit
adder with 10 bit addends and sum.

As an example, (a_sig - b_sig) < 0 has meaning for integers, since the
result of the subtraction is 32 bit signed. It does not have meaning
for unsigned vectors, because the result of subtraction with two
unsigned operands is defined as unsigned.

It should be noted that technically, the synthesis tool can do
anything it wants to for an integer storage overflow, since the result
is not defined by the language (there is no result). It turns out that
simple truncation is the least expensive option that meets all the
defined behaviors, so that is what is usually done.

Andy
 
On May 12, 11:19 am, rickman <gnu...@gmail.com> wrote:
Maybe I am missing major something here. If I want to implement a
shifter using integers, how would I write a statement to left shift by
N with dropping the bits shifted out? Couldn't it be this?

constant FooWidth : natural 4;
subtype FooRange is natural range 15 downto 0;

function ShiftIntLeft (Foo, N, Width : natural FooRange) begin
Foo <= (Foo*2**N) mod (2**Width);
return (Foo);
end ShiftIntLeft;

If Foo is constrained to the range of 15 downto 0, would it still
simulate without error if Foo is 8 and N is 2?

Yes, it would work, so long as Foo*2**N still fits in integer'range.
You'd be safer to limit (subtype) N and to truncate Foo beforehand to
make sure the intermediate result does not overflow integer'range.

Andy
 
On May 12, 12:38 pm, Mike Treseler <mike_trese...@comcast.net> wrote:
rickman wrote:
Yes, but my point is that this information is already contained in the
range of the subtype. Without having looked at it hard, I was hoping
that VHDL would be able to use the constrained range to determine how
many bits are used. I believe this is what happens in synthesis.
Integers don't produce 32 bit data paths if they are constrained to a
smaller range.

Your function expects and returns any natural range.

function sllint (x, sh : natural) return natural

It has no knowledge of the actual range as is.
To add that knowledge, I would have to add
a function of the same name for each subtype
that I want to cover intelligently.
That is the issue. I initially posted this discussion in a thread
where it was stated that VHDL does not provide for overloading based
on subtypes. So there seems to be *no* way to provide separate
functions for each subtype I would like this to work with.


This is a lot of work.
This work has already been done for you
in the numeric_std package.

I'm trying to make integers do the same
work as slv or unsigned.

This is built into verilog.
It might be easer to use verilog
than to make vhdl act like verilog.
I just find it funny that a language that has had so much work poured
into it to provide for hardware description is so complex and
difficult to use. I have never gotten conversant with Verilog
although I have used it a bit. Sometimes I wonder if I wouldn't code
more effectively in Verilog if I just took the effort to learn it
better. I would also have to buy new books...
 
On May 12, 1:11 pm, Andy <jonesa...@comcast.net> wrote:
On May 12, 11:19 am, rickman <gnu...@gmail.com> wrote:

Maybe I am missing major something here. If I want to implement a
shifter using integers, how would I write a statement to left shift by
N with dropping the bits shifted out? Couldn't it be this?

constant FooWidth : natural 4;
subtype FooRange is natural range 15 downto 0;

function ShiftIntLeft (Foo, N, Width : natural FooRange) begin
Foo <= (Foo*2**N) mod (2**Width);
return (Foo);
end ShiftIntLeft;

If Foo is constrained to the range of 15 downto 0, would it still
simulate without error if Foo is 8 and N is 2?

Yes, it would work, so long as Foo*2**N still fits in integer'range.
You'd be safer to limit (subtype) N and to truncate Foo beforehand to
make sure the intermediate result does not overflow integer'range.

Andy
I think you are missing the point. I am not trying to perform a
specific calculation, I am trying to find a simpler way of describing
shift operations. If the result (or worse the operands) need to be
truncated with an explicit value, this loses a lot of the appeal.

So it looks like integer is not a good fit here.
 
On May 12, 1:01 pm, Andy <jonesa...@comcast.net> wrote:
On May 12, 7:49 am, KJ <kkjenni...@sbcglobal.net> wrote:



The calculation within the functions will be based on the ranges of
the arguments that you supplied when you call the function. That fact
that the function works with unconstrained types is not relevant to
synthesis.

Example:
function AddEm(a, b: integer) return integer is
begin
return(a+b);
end function AddEm;
...
signal A_sig, B_sig, C_sig: integer range 0 to 1023;
...
C_sig <= AddEm(A_sig, B_sig);

This would all be done with 10 bit precision when synthesizing because
that is the range of the arguments (A_sig, B_sig) and where the result
is stored (C_sig). No expanding to 32 bits, no truncating back down
to 10.

The case where A_sig and B_sig add up to something greater than 1023
and therefore wouldn't fit back into C_sig is something that the
simulator would flag if it occurs (i.e. AddEm(512,512)) but synthesis
wouldn't do anything about since not handling overflow properly is the
designer's issue.

Not necessarily. The precision of the addition is 32 bit signed,
regardless of the precision of the operands. So both arguments are
promoted to 32 bit signed, added, and then when the assignment is
stored, demoted to 10 bits unsigned. However, the synthesis tool will
optimize out unused bits (all those promoted zeroes, and all the
truncated bits from the assignment), so the final result is a 10 bit
adder with 10 bit addends and sum.

As an example, (a_sig - b_sig) < 0 has meaning for integers, since the
result of the subtraction is 32 bit signed. It does not have meaning
for unsigned vectors, because the result of subtraction with two
unsigned operands is defined as unsigned.

It should be noted that technically, the synthesis tool can do
anything it wants to for an integer storage overflow, since the result
is not defined by the language (there is no result). It turns out that
simple truncation is the least expensive option that meets all the
defined behaviors, so that is what is usually done.

Andy
Wouldn't this create a mismatch between simulation and
implementation?
 
On May 12, 4:22 pm, rickman <gnu...@gmail.com> wrote:
I think you are missing the point. I am not trying to perform a
specific calculation, I am trying to find a simpler way of describing
shift operations. If the result (or worse the operands) need to be
truncated with an explicit value, this loses a lot of the appeal.

So it looks like integer is not a good fit here.
Nor is unsigned. Unsigned-overloaded operators truncate results to the
size of the largest vector operand. The new fixed point package would
work though (just use zero fractional bits), but it usually requires
explicit resizing to fit storage, which integer types do automatically
(with an assertion if information is lost).

Andy
 
On May 12, 4:26 pm, rickman <gnu...@gmail.com> wrote:
Wouldn't this create a mismatch between simulation and
implementation?
No, since the simulation does not "do anything" (it stops, which
hardware really can't do very well) in those cases where synthesis
could do whatever it wants.

Andy
 
On May 13, 1:40 pm, Andy <jonesa...@comcast.net> wrote:
On May 12, 4:22 pm, rickman <gnu...@gmail.com> wrote:



I think you are missing the point. I am not trying to perform a
specific calculation, I am trying to find a simpler way of describing
shift operations. If the result (or worse the operands) need to be
truncated with an explicit value, this loses a lot of the appeal.

So it looks like integer is not a good fit here.

Nor is unsigned. Unsigned-overloaded operators truncate results to the
size of the largest vector operand. The new fixed point package would
work though (just use zero fractional bits), but it usually requires
explicit resizing to fit storage, which integer types do automatically
(with an assertion if information is lost).
I can't say I understand what is wrong with truncating? That is
exactly what I want! If I didn't want to truncate the bits shifted
out of the register size I am using, integer would do just fine.

Rick
 

Welcome to EDABoard.com

Sponsor

Back
Top