Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > VHDL > Problem with ASSERT ... REPORT and NUL

Reply
Thread Tools

Problem with ASSERT ... REPORT and NUL

 
 
Analog_Guy
Guest
Posts: n/a
 
      06-26-2007
I have written a function to pad an input string with NUL to the
chosen string width (set by a constant):

SUBTYPE NAMETYPE IS STRING(1 TO STRING_WIDTH);

FUNCTION pad_string (name : STRING) RETURN NAMETYPE IS
VARIABLE name_pad : NAMETYPE;
BEGIN
name_pad(1 TO name'LENGTH) := name;
name_pad((name'LENGTH + 1) TO name_pad'LENGTH) := (OTHERS => NUL);
RETURN name_pad;
END FUNCTION pad_string;

The FUNCTION works fine, and I can now pass the string to and from
modules through records. However, when I try to use an ASSERT ...
REPORT to print out some NOTES, nothing prints out after the
concatenated record element.

ASSERT (FALSE)
REPORT "*** Signal of Interest: " & reset_cmd.name & " end of
line!"
SEVERITY NOTE;

The final "end of line!" text does not print??? If I substitute
whitespace into the FUNCTION instead of the NUL, then the full REPORT
line prints to the screen. Is the NUL in the reset_cmd.name killing
the rest of the line, and why?

 
Reply With Quote
 
 
 
 
KJ
Guest
Posts: n/a
 
      06-26-2007
On Jun 26, 12:10 pm, Analog_Guy <(E-Mail Removed)> wrote:
>
> The final "end of line!" text does not print??? If I substitute
> whitespace into the FUNCTION instead of the NUL, then the full REPORT
> line prints to the screen. Is the NUL in the reset_cmd.name killing
> the rest of the line

Yes

and why?

Because the 'report' statement uses the NUL character to determine
where to stop 'reporting' but the concatenate operator '&' does not.
To get what you want you'll need to use (or reinvent) the 'strcat'
function or create a different function (say 'trim()') that returns a
string up to but not including the NUL character. Then you would
report this like...
ASSERT (FALSE)
REPORT "*** Signal of Interest: " & trim(reset_cmd.name) & "
end of
line!"
SEVERITY NOTE;

KJ

 
Reply With Quote
 
 
 
 
HT-Lab
Guest
Posts: n/a
 
      06-26-2007

"KJ" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
> On Jun 26, 12:10 pm, Analog_Guy <(E-Mail Removed)> wrote:
>>
>> The final "end of line!" text does not print??? If I substitute
>> whitespace into the FUNCTION instead of the NUL, then the full REPORT
>> line prints to the screen. Is the NUL in the reset_cmd.name killing
>> the rest of the line

> Yes
>
> and why?
>
> Because the 'report' statement uses the NUL character to determine
> where to stop 'reporting' but the concatenate operator '&' does not.
> To get what you want you'll need to use (or reinvent) the 'strcat'
> function or create a different function (say 'trim()') that returns a
> string up to but not including the NUL character. Then you would
> report this like...
> ASSERT (FALSE)
> REPORT "*** Signal of Interest: " & trim(reset_cmd.name) & "
> end of
> line!"
> SEVERITY NOTE;
>
> KJ
>


NULL, not NUL

Hans
www.ht-lab.com



 
Reply With Quote
 
Jonathan Bromley
Guest
Posts: n/a
 
      06-26-2007
On Tue, 26 Jun 2007 09:10:36 -0700, Analog_Guy
<(E-Mail Removed)> wrote:

>I have written a function to pad an input string with NUL to the
>chosen string width (set by a constant):
>
>SUBTYPE NAMETYPE IS STRING(1 TO STRING_WIDTH);
>
>FUNCTION pad_string (name : STRING) RETURN NAMETYPE IS
> VARIABLE name_pad : NAMETYPE;
> BEGIN
> name_pad(1 TO name'LENGTH) := name;
> name_pad((name'LENGTH + 1) TO name_pad'LENGTH) := (OTHERS => NUL);
> RETURN name_pad;
> END FUNCTION pad_string;
>
>The FUNCTION works fine, and I can now pass the string to and from
>modules through records. However, when I try to use an ASSERT ...
>REPORT to print out some NOTES, nothing prints out after the
>concatenated record element.
>
> ASSERT (FALSE)
> REPORT "*** Signal of Interest: " & reset_cmd.name & " end of
>line!"
> SEVERITY NOTE;
>
>The final "end of line!" text does not print??? If I substitute
>whitespace into the FUNCTION instead of the NUL, then the full REPORT
>line prints to the screen. Is the NUL in the reset_cmd.name killing
>the rest of the line, and why?


Clearly it is; I'm not sure what the LRM says about this, but if
you imagine that tools are probably using C strings internally
then it's not too surprising - the NUL character will terminate
the string, if it's copied to a C string internally.

The solution is for you to write a complementary function to your
pad_string(), and then invoke it in the string concatenation:

function unpad(s: in string) return string is
-- Normalise the string to (1 to N), just in case
-- someone's messing you around
constant ns: string(1 to s'length) := s;
-- Variable to store position of last non-null char
variable p: integer := s'length;
begin
-- 1. find where the first NUL happens
for i in ns'range loop
if ns(i) = NUL then
p := i-1;
exit;
end if;
end loop;
-- 2. return the non-NUL part of the string
return ns(1 to p);
end;
....
report "Prefix " & unpad(reset_cmd.name) & " Suffix";

Alternatively, since you are putting your string into a record,
it may be easier to add a "name length" integer to the record.
Then you don't even need to bother with the pad() function;
you can simply copy the name string to the appropriate part
of the record field...

type cmd_record is record
...
name: string (1 to STRING_WIDTH);
name_len: integer;
...
end record;
procedure set_name(cmd: inout cmd_record; name: string) is
begin
cmd.name_len = name'length;
cmd.name(1 to name'length) := name;
end;
function get_name(cmd: cmd_record) return string is
begin
return cmd.name(1 to cmd.name_len);
end;
....
set_name(reset_cmd, "reset");
....
report "Prefix " & get_name(reset_cmd) & " Suffix";

Executive summary: VHDL strings are poo, but you can make them
bearable by a suitable combination of cunning subprograms and
record types. VHDL functions with dynamically-elaborated
return subtypes are brilliant.

Thought for the day: You can build "object-oriented programming"
in VHDL by creating a package with a record definition for your
data, and a bunch of procedures each of which takes a variable
of the record type as its first parameter, and operates on that
variable. The package then works a bit like a class definition.
OK, instead of saying "my_object.method(params);" you must say
"method(my_object, params);" but it's a small price to pay.
And yes, I know there's a pile of important OOP stuff you *can't*
do (inheritance, polymorphism) but hey, it's better than nothing.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Reply With Quote
 
Jonathan Bromley
Guest
Posts: n/a
 
      06-26-2007
On Tue, 26 Jun 2007 16:40:02 GMT,
"HT-Lab" <(E-Mail Removed)> wrote:


>NULL, not NUL


Really? I thought the constant STD.CHARACTER'VAL(0)
was named NUL. NULL is a VHDL keyword.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Reply With Quote
 
HT-Lab
Guest
Posts: n/a
 
      06-26-2007

"Jonathan Bromley" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On Tue, 26 Jun 2007 16:40:02 GMT,
> "HT-Lab" <(E-Mail Removed)> wrote:
>
>
>>NULL, not NUL

>
> Really? I thought the constant STD.CHARACTER'VAL(0)
> was named NUL. NULL is a VHDL keyword.
> --

Oops, my mistake...

Hans
www.ht-lab.com


 
Reply With Quote
 
Analog_Guy
Guest
Posts: n/a
 
      06-26-2007
On Jun 26, 12:41 pm, Jonathan Bromley <(E-Mail Removed)>
wrote:
> On Tue, 26 Jun 2007 09:10:36 -0700, Analog_Guy
>
>
>
>
>
> <(E-Mail Removed)> wrote:
> >I have written a function to pad an input string with NUL to the
> >chosen string width (set by a constant):

>
> >SUBTYPE NAMETYPE IS STRING(1 TO STRING_WIDTH);

>
> >FUNCTION pad_string (name : STRING) RETURN NAMETYPE IS
> > VARIABLE name_pad : NAMETYPE;
> > BEGIN
> > name_pad(1 TO name'LENGTH) := name;
> > name_pad((name'LENGTH + 1) TO name_pad'LENGTH) := (OTHERS => NUL);
> > RETURN name_pad;
> > END FUNCTION pad_string;

>
> >The FUNCTION works fine, and I can now pass the string to and from
> >modules through records. However, when I try to use an ASSERT ...
> >REPORT to print out some NOTES, nothing prints out after the
> >concatenated record element.

>
> > ASSERT (FALSE)
> > REPORT "*** Signal of Interest: " & reset_cmd.name & " end of
> >line!"
> > SEVERITY NOTE;

>
> >The final "end of line!" text does not print??? If I substitute
> >whitespace into the FUNCTION instead of the NUL, then the full REPORT
> >line prints to the screen. Is the NUL in the reset_cmd.name killing
> >the rest of the line, and why?

>
> Clearly it is; I'm not sure what the LRM says about this, but if
> you imagine that tools are probably using C strings internally
> then it's not too surprising - the NUL character will terminate
> the string, if it's copied to a C string internally.
>
> The solution is for you to write a complementary function to your
> pad_string(), and then invoke it in the string concatenation:
>
> function unpad(s: in string) return string is
> -- Normalise the string to (1 to N), just in case
> -- someone's messing you around
> constant ns: string(1 to s'length) := s;
> -- Variable to store position of last non-null char
> variable p: integer := s'length;
> begin
> -- 1. find where the first NUL happens
> for i in ns'range loop
> if ns(i) = NUL then
> p := i-1;
> exit;
> end if;
> end loop;
> -- 2. return the non-NUL part of the string
> return ns(1 to p);
> end;
> ....
> report "Prefix " & unpad(reset_cmd.name) & " Suffix";
>
> Alternatively, since you are putting your string into a record,
> it may be easier to add a "name length" integer to the record.
> Then you don't even need to bother with the pad() function;
> you can simply copy the name string to the appropriate part
> of the record field...
>
> type cmd_record is record
> ...
> name: string (1 to STRING_WIDTH);
> name_len: integer;
> ...
> end record;
> procedure set_name(cmd: inout cmd_record; name: string) is
> begin
> cmd.name_len = name'length;
> cmd.name(1 to name'length) := name;
> end;
> function get_name(cmd: cmd_record) return string is
> begin
> return cmd.name(1 to cmd.name_len);
> end;
> ....
> set_name(reset_cmd, "reset");
> ....
> report "Prefix " & get_name(reset_cmd) & " Suffix";
>
> Executive summary: VHDL strings are poo, but you can make them
> bearable by a suitable combination of cunning subprograms and
> record types. VHDL functions with dynamically-elaborated
> return subtypes are brilliant.
>
> Thought for the day: You can build "object-oriented programming"
> in VHDL by creating a package with a record definition for your
> data, and a bunch of procedures each of which takes a variable
> of the record type as its first parameter, and operates on that
> variable. The package then works a bit like a class definition.
> OK, instead of saying "my_object.method(params);" you must say
> "method(my_object, params);" but it's a small price to pay.
> And yes, I know there's a pile of important OOP stuff you *can't*
> do (inheritance, polymorphism) but hey, it's better than nothing.
> --
> Jonathan Bromley, Consultant
>
> DOULOS - Developing Design Know-how
> VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
>
> Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
> (E-Mail Removed)://www.MYCOMPANY.com
>
> The contents of this message may contain personal views which
> are not the views of Doulos Ltd., unless specifically stated.- Hide quoted text -
>
> - Show quoted text -


Thank you very much for your advice and tips. I don't have any
experience with C or OOP and couldn't find what I was looking for in
the various texts I have.

I will play around with both methods you suggested.

With your second suggestion, what happens to the rest of the string?
Say string length is 10 and your first assignment is 5 characters, and
then your second assignment is 3 characters. I assume that the
defined string will have artifacts from previous assignments, but I
guess it doesn't really matter because you are not looking at the
whole string anyway.

 
Reply With Quote
 
KJ
Guest
Posts: n/a
 
      06-27-2007

"Jonathan Bromley" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Thought for the day: You can build "object-oriented programming"
> in VHDL by creating a package with a record definition for your
> data, and a bunch of procedures each of which takes a variable
> of the record type as its first parameter, and operates on that
> variable. The package then works a bit like a class definition.
> OK, instead of saying "my_object.method(params);" you must say
> "method(my_object, params);" but it's a small price to pay.
> And yes, I know there's a pile of important OOP stuff you *can't*
> do (inheritance, polymorphism) but hey, it's better than nothing.
> --
> Jonathan Bromley, Consultant


My fav OOP-ish thing to do in VHDL in function overloading. All of the
read/write ports with their various bit fields gets defined in a record.
Each one will then get a 'To_Std_Logic_Vector' and 'From_Std_Logic_Vector'
function defined that handles the obligatory conversions to/from
std_logic_vector types. On the testbench side override some 'Read_Port' and
'Write_Port' functions so that the processor model becomes a straightforward
listing of reads and writes to ports without being cluttered up with
conversion functions and other nonsense.

Now, if someone can tell me how to override the 'deallocate' function I'd be
happy. The basic idea is that I have some record type, one element of which
is a pointer to something. I'd like to override 'deallocate' so that I can
first deallocate the record element and then call the deallocate procedure
that would normally have been called, had I not overridden it. Sort of
like...

type t_My_Type is record
....
pSomething: t_Pointer_Type_To_Something;
end record;
type ptr_My_Type is access My_Type;

procedure deallocate(p: ptr_My_Type) is
begin
if p.pSomething /= NUL then
deallocate(p.pSomething; -- Free up the memory if it has been
allocated.
end if;
deallocate(p); --**** Don't think this will work ***
end procedure deallocate;

The line "deallocate(p)" seems problematic since it is not calling the
'base' deallocate procedure but would end up calling itself. Once that
little problem is worked out one can basically have the equivalent of a
'class destructor'....the next thing would be to override 'new' to create
constructors at some point also. Seems like it should be possible, just not
quite sure how one goes about calling the 'base deallocate' procedure (or
even really if 'new' and 'deallocate' can even be overridden for that
matter).

Any thoughts?

KJ


 
Reply With Quote
 
Jonathan Bromley
Guest
Posts: n/a
 
      06-27-2007
On Tue, 26 Jun 2007 21:05:02 -0400,
"KJ" <(E-Mail Removed)> wrote:

>My fav OOP-ish thing to do in VHDL in function overloading. All of the
>read/write ports with their various bit fields gets defined in a record.
>Each one will then get a 'To_Std_Logic_Vector' and 'From_Std_Logic_Vector'
>function defined that handles the obligatory conversions to/from
>std_logic_vector types. On the testbench side override some 'Read_Port' and
>'Write_Port' functions so that the processor model becomes a straightforward
>listing of reads and writes to ports without being cluttered up with
>conversion functions and other nonsense.


Yes. Nice.

>Now, if someone can tell me how to override the 'deallocate' function


I don't believe you can, but I confess I've never bothered to
investigate. It's a "built-in" and such things are often strange.
When I have the same problem I tend to create "dispose" procedures
for any interesting access types. Those can of course be
overloaded by argument type, and each object's "dispose" then
starts by calling "dispose" on any appropriate child objects,
before finally calling "deallocate" on the original pointer
argument once you're sure there is nothing left dangling.
It's obviously harder if your data structure has cycles...

>Any thoughts?


Only rarely
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Reply With Quote
 
Jonathan Bromley
Guest
Posts: n/a
 
      06-27-2007
On Tue, 26 Jun 2007 14:16:13 -0700,
Analog_Guy <(E-Mail Removed)> wrote:

>With your second suggestion, what happens to the rest of the string?
>Say string length is 10 and your first assignment is 5 characters, and
>then your second assignment is 3 characters. I assume that the
>defined string will have artifacts from previous assignments, but I
>guess it doesn't really matter because you are not looking at the
>whole string anyway.


Exactly so. When you do this kind of thing, it's best to make a
contract with yourself so that you *never* access the fields of
the record directly, but instead make use of the set/get
functions/procedures that you have thoughtfully provided.
VHDL can't enforce that contract, unfortunately, but it's a
good discipline and it is likely to make your code much more
robust against future changes to the details of the data structure.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
To assert or not to assert... ImpalerCore C Programming 79 05-17-2010 12:47 PM
assert 0, "foo" vs. assert(0, "foo") Thomas Guettler Python 3 02-23-2005 07:53 PM
assert(x) and '#define ASSERT(x) assert(x)' Alex Vinokur C Programming 5 11-25-2004 08:48 PM
RE: remove assert statement (Was: Re: PEP new assert idiom) Robert Brewer Python 1 11-07-2004 06:53 PM
newb ques: c++ input files always end with NUL? Really?? Pete Wilson C++ 3 04-03-2004 06:21 PM



Advertisments