Function has Sim vs. Syth Non-Equivalence

J

Jeremy Ralph

Guest
The two incarnations of the is_address_word() function (below)
simulate the same but FPGA prototype differently (on an unnamed FPGA
synthesis tool). The purpose of this function is for decoding a
specific index of a register array in a register-map.

So my question for the VHDL gurus out there... should Version 1 of
is_addressed_word() FPGA prototype the same as it simulates?

SUBTYPE addr_type IS std_logic_vector (ADDR_WIDTH-1 DOWNTO 0);

-- Version 1: works differently in sim vs. synth

FUNCTION is_addressed_word (
CONSTANT specific_addr : addr_type;
CONSTANT index : INTEGER := 0;
SIGNAL current_addr : addr_type
) RETURN BOOLEAN IS
CONSTANT specific_indexed_addr : procreg_addr_type :=
std_logic_vector(UNSIGNED( specific_addr) + index *
PROCREG_ADDR_INC);
BEGIN
RETURN (
current_addr(current_addr'left DOWNTO 2) =
specific_indexed_addr(current_addr'left DOWNTO 2)
);
END FUNCTION is_addressed_word;

-- Version 2: works same for sim vs. synth

FUNCTION is_addressed_word (
CONSTANT specific_addr : addr_type;
CONSTANT index : NATURAL;
SIGNAL current_addr : addr_type
) RETURN BOOLEAN IS
-- Ignore the last two bits... don't worry about byte addresssing
-- stick to 32 bit aligned words.
CONSTANT saddr_const : std_logic_vector(specific_addr'LENGTH-3
DOWNTO 0)
:= specific_addr(current_addr'LENGTH-1 DOWNTO 2);
CONSTANT indexed_saddr_const :
std_logic_vector(specific_addr'LENGTH-3 DOWNTO 0)
:= std_logic_vector(UNSIGNED( saddr_const ) + index);
VARIABLE caddr_const : std_logic_vector(specific_addr'LENGTH-3
DOWNTO 0)
:= current_addr(current_addr'LENGTH-1 DOWNTO 2);
BEGIN
RETURN ( caddr_const = indexed_saddr_const );
END FUNCTION is_addressed_word;

Thanks,
Jeremy

-------------
SpectaReg automates slave memory-map deliverables targeting standard
protocols. Learn more at http://www.productive-eda.com.
 
Jeremy Ralph wrote:
The two incarnations of the is_address_word() function (below)
simulate the same
Make sure the full range of all the parameters is tested.
Note that "index" covers a 32 bit range in the description.
This might not be what you want.

SUBTYPE addr_type IS std_logic_vector (ADDR_WIDTH-1 DOWNTO 0);
subtype procreg_addr_type is ?

-- Version 1: works differently in sim vs. synth

FUNCTION is_addressed_word (
CONSTANT specific_addr : addr_type;
I would leave out CONSTANT as this is the default.

CONSTANT index : INTEGER := 0;
Having a default value for index is of little use
if it isn't the last parameter..

SIGNAL current_addr : addr_type
I would leave out SIGNAL since only the
value is being used anyway, and the default
is easier to test.

-- Mike Treseler
 
Thanks Mike for the useful tips. Any comments on the synthesis
observations? Version 1 caused a lot of grief. After switching to
Version 2 everything worked as expected.

Make sure the full range of all the parameters is tested.
Note that "index" covers a 32 bit range in the description.
This might not be what you want.
The full range was covered i) in simulation, and ii) from embedded
software on the FPGA. This is how the non-equivalence of Version 1
was identified.

For "index" I was thinking the synthesis tool would be smart enough to
only use as many bits as needed based on the calling context.
Different contexts use different ranges of index, thus I did not
narrow the the range.

SUBTYPE addr_type IS std_logic_vector (ADDR_WIDTH-1 DOWNTO 0);

subtype procreg_addr_type is ?
Oops. Typo, I meant to remove all the "procreg_" prefixes to shorten
things up...

FUNCTION is_addressed_word (
CONSTANT specific_addr : addr_type;

I would leave out CONSTANT as this is the default.
Guess that would make things more readable.

CONSTANT index : INTEGER := 0;

Having a default value for index is of little use
if it isn't the last parameter..
Version 2 (the more mature one) abandoned this for that very reason.

SIGNAL current_addr : addr_type

I would leave out SIGNAL since only the
value is being used anyway, and the default
is easier to test.
Hmmm, I thought it needed to be SIGNAL since current_addr is a runtime
varying signal and not really a constant at build-time. When I get a
chance I'll try out your recommendations.


Thanks,
Jeremy

http://www.productive-eda.com
 
Jeremy Ralph wrote:
Thanks Mike for the useful tips. Any comments on the synthesis
observations? Version 1 caused a lot of grief. After switching to
Version 2 everything worked as expected.
I hesitate to guess without knowing all the subtypes,
libraries and actual parameters. I expect there is
some functional difference that could be
found in simulation.

For "index" I was thinking the synthesis tool would be smart enough to
only use as many bits as needed based on the calling context.
Different contexts use different ranges of index, thus I did not
narrow the the range.
True, but knowing the range you are actually using
would simplify the problem.

Oops. Typo, I meant to remove all the "procreg_" prefixes to shorten
things up...
OK. I'll have another look.

FUNCTION is_addressed_word (
CONSTANT specific_addr : addr_type;
I would leave out CONSTANT as this is the default.

Guess that would make things more readable.
I agree. This a confusion factor for me.
CONSTANT only covers the formal parameter,
not the actual.

SIGNAL current_addr : addr_type
I would leave out SIGNAL since only the
value is being used anyway, and the default
is easier to test.

Hmmm, I thought it needed to be SIGNAL since current_addr is a runtime
varying signal and not really a constant at build-time.
No. The function really doesn't care where the
actual value comes from. Unless I am using signal attributes
or creating "impure" side effects, the default is fine.

Thanks,
Jeremy
Thanks for the interesting question.

-- Mike Treselr
 
Mike Treseler wrote:

OK. I'll have another look.
assuming
constant ADDR_WIDTH : natural := 16;
constant procreg_addr_inc : natural := 2;

I get a mismatch between functions for
is_addressed_word(x"0001", 1, x"0001")

0,2,3,4, ... work ok.

-- Mike Treseler
 
Thought I already posted a response to this... guess it didn't go
through.

assuming
constant ADDR_WIDTH : natural := 16;
constant procreg_addr_inc : natural := 2;
These assumptions would lead to a mismatch since Version 2 assumes
ADDR_WIDTH = 32 and ADDR_INC = 4 . Version two ignores the last two
bits and increments by index rather than ADDR_INC * index, this change
was made in an attempt to get things working and makes things less
generic.

I get a mismatch between functions for
is_addressed_word(x"0001", 1, x"0001")
I think this is due to the (16,2) vs. (32,4).

I was seeing some other mismatches with the 32,4 combo for Version 2
(see prev. posting) and Version 3 (below). In the synthesis logs for
version Version 2 were warnings about "Size of operands are
different : result is <false>." These seemed to occur when the most
significant bit of addr_type was one. Version 3 works as expected and
seems synthesizable in XST.

-----------------------------------------------------------------
-- Checks if the specified 32 bit word is being addressed...
-- This function is not concerned about the byte offset from word
-- aligned boundaries.
-----------------------------------------------------------------
FUNCTION is_addressed_word (
specific_addr : addr_type;
index : NATURAL;
current_addr : addr_type
) RETURN BOOLEAN IS
-- Ignore the last two bits... don't worry about byte addressing
-- stick to 32 bit aligned words.
CONSTANT saddr_const : std_logic_vector(specific_addr'LENGTH-3
DOWNTO 0)
:= specific_addr(specific_addr'LENGTH-1 DOWNTO 2);
CONSTANT unsigned_index : unsigned(specific_addr'LENGTH-3 DOWNTO
0)
:= to_unsigned(index,specific_addr'LENGTH-2);
CONSTANT indexed_saddr_const :
std_logic_vector(specific_addr'LENGTH-3 DOWNTO 0)
:= std_logic_vector(UNSIGNED( saddr_const ) + unsigned_index);
VARIABLE caddr : std_logic_vector(specific_addr'LENGTH-3 DOWNTO
0);
BEGIN
caddr := current_addr(current_addr'LENGTH-1 DOWNTO 2);
RETURN ( caddr = indexed_saddr_const );
END FUNCTION is_addressed_word;




-------------
-- SpectaReg automates slave memory-map deliverables targeting
standard
-- protocols. Learn more at http://www.productive-eda.com.
 
Jeremy Ralph wrote:

assuming
constant ADDR_WIDTH : natural := 16;
constant procreg_addr_inc : natural := 2;

These assumptions would lead to a mismatch since Version 2 assumes
ADDR_WIDTH = 32 and ADDR_INC = 4 . Version two ignores the last two
bits and increments by index rather than ADDR_INC * index, this change
was made in an attempt to get things working and makes things less
generic.
I would work all of the dependencies into the function
or use subtypes so that all possible parameter ranges are legal.
Otherwise I am better off without a function.

I expect that the synthesis bugs are
a result of allowing illegal parameters.
I would work on debugging my best version
rather than analyze the differences.
Good luck.

-- Mike Treseler
 

Welcome to EDABoard.com

Sponsor

Back
Top