Problem with ASSERT ... REPORT and NUL

Discussion in 'VHDL' started by Analog_Guy, Jun 26, 2007.

  1. Analog_Guy

    Analog_Guy Guest

    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?
    Analog_Guy, Jun 26, 2007
    #1
    1. Advertising

  2. Analog_Guy

    KJ Guest

    On Jun 26, 12:10 pm, Analog_Guy <> 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
    KJ, Jun 26, 2007
    #2
    1. Advertising

  3. Analog_Guy

    HT-Lab Guest

    "KJ" <> wrote in message
    news:...
    > On Jun 26, 12:10 pm, Analog_Guy <> 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
    HT-Lab, Jun 26, 2007
    #3
  4. On Tue, 26 Jun 2007 09:10:36 -0700, Analog_Guy
    <> 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.MYCOMPANY.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
    Jonathan Bromley, Jun 26, 2007
    #4
  5. On Tue, 26 Jun 2007 16:40:02 GMT,
    "HT-Lab" <> 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

    http://www.MYCOMPANY.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
    Jonathan Bromley, Jun 26, 2007
    #5
  6. Analog_Guy

    HT-Lab Guest

    "Jonathan Bromley" <> wrote in message
    news:...
    > On Tue, 26 Jun 2007 16:40:02 GMT,
    > "HT-Lab" <> 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
    HT-Lab, Jun 26, 2007
    #6
  7. Analog_Guy

    Analog_Guy Guest

    On Jun 26, 12:41 pm, Jonathan Bromley <>
    wrote:
    > On Tue, 26 Jun 2007 09:10:36 -0700, Analog_Guy
    >
    >
    >
    >
    >
    > <> 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
    > ://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.
    Analog_Guy, Jun 26, 2007
    #7
  8. Analog_Guy

    KJ Guest

    "Jonathan Bromley" <> wrote in message
    news:...
    > 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
    KJ, Jun 27, 2007
    #8
  9. On Tue, 26 Jun 2007 21:05:02 -0400,
    "KJ" <> 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

    http://www.MYCOMPANY.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
    Jonathan Bromley, Jun 27, 2007
    #9
  10. On Tue, 26 Jun 2007 14:16:13 -0700,
    Analog_Guy <> 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

    http://www.MYCOMPANY.com

    The contents of this message may contain personal views which
    are not the views of Doulos Ltd., unless specifically stated.
    Jonathan Bromley, Jun 27, 2007
    #10
  11. Jonathan Bromley wrote:

    > VHDL functions with dynamically-elaborated
    > return subtypes are brilliant.


    .... and woefully underused.
    I can fill in just about anything
    that I think vhdl is "missing"
    by writing a function.
    Some examples:
    http://home.comcast.net/~mike_treseler/min_vec_len.vhd

    > 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.


    Yes this works well for me.
    Once I am comfortable using
    variables, the next step is
    complex data structures and
    the procedures to update them.
    Yes, this code looks
    nothing like a netlist for new
    users, but an RTL viewer can
    solve even that problem.

    -- Mike Treseler
    Mike Treseler, Jun 27, 2007
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Pete Wilson
    Replies:
    3
    Views:
    411
    David Harmon
    Apr 3, 2004
  2. Robert Brewer
    Replies:
    1
    Views:
    484
    bsmith
    Nov 7, 2004
  3. Thomas Guettler

    assert 0, "foo" vs. assert(0, "foo")

    Thomas Guettler, Feb 23, 2005, in forum: Python
    Replies:
    3
    Views:
    2,516
    Carl Banks
    Feb 23, 2005
  4. Alex Vinokur

    assert(x) and '#define ASSERT(x) assert(x)'

    Alex Vinokur, Nov 25, 2004, in forum: C Programming
    Replies:
    5
    Views:
    909
    Keith Thompson
    Nov 25, 2004
  5. ImpalerCore

    To assert or not to assert...

    ImpalerCore, Apr 27, 2010, in forum: C Programming
    Replies:
    79
    Views:
    1,653
    Richard Bos
    May 17, 2010
Loading...

Share This Page