0
\$\begingroup\$

I have declared a string in the testbench code. However, I find that it is not simple to assign value to it. Here is the test code:

process  
    variable str : string(1 to 64);
begin
    str := "hello world";
    report str;
    wait;
end process;

Why can't string contain index 0 in it? Also, how can I assign a string of any length to this variable since it won't be easy to make every string I assign to it, equal 64 characters by putting in white spaces.

EDIT:

This is what I came up with at the end, is there a simpler way to do this in VHDL?

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_misc.all;
use IEEE.numeric_std.all;

entity experiment_4 is
end entity;

architecture beh of experiment_4 is
  procedure write_string(strout: out string; constant strin: in string) is
  variable str : string(strout'range);
  variable l,r: integer;
  begin                 
    if strin'length > strout'length then
      assert false report "the specified string cannot fit into the specified variable" severity failure;
    else
      for i in strout'range loop
        strout(i) := ' ';   
      end loop;
      strout(strin'range) := strin;
    end if;    
  end procedure;    
begin
    
    process  
        variable str : string(1 to 64);
    begin       
        write_string(str, "hello world");
        report str;
        wait;
    end process;
    
end architecture;
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

I'm not quite certain to understand what you are trying to do here. Maybe there is a bit of a XY problem in the first place. Nonetheless, I'll try to answer questions we have so far.

Strings are defined by standard as:

  type STRING is array (POSITIVE range <>) of CHARACTER;

and positive is defined as:

  subtype POSITIVE is INTEGER range 1 to INTEGER'HIGH;

That's why you cannot use index 0: by definition, string indices are from 1 onwards. When declaring variables/signals/subtypes, you may only be more restrictive than the original range.

In VHDL, strings are no more than arrays, the very same way std_logic_vectors are arrays. You should think about assign strings the same way you do when assigning (part of) logic arrays.

Here in your example code, you seem to want to assign a variable-length string literal to a (constrained) string variable. You do it with a procedure that pads the input argument. You could as well create a function, which may be clearer:

function padded(s: string; len: positive := 64; p: character := ' ') return string
is
  alias xs: string(1 to s'length) is s;
  variable ret : string(1 to len) := (others => p);
begin
  if xs'length >= len then
    ret := xs(1 to len);
  else
    ret(1 to xs'length) := xs;
  end if;
  return ret;
end function;

Then:

process  
    variable str : string(1 to 64);
begin       
    str := padded("hello world", str'length);
    report str;
    wait;
end process;

Another option is to use access to a string. Access is VHDL equivalent of pointers, with the nice feature that actual array constraints are attached to the targetted instance, so they may change.

It happens standard defines such thing in std.textio, line, which is defined as:

type LINE is access STRING;

Line type definition comes with procedures that are able to append text to it, called write.

procedure WRITE (L: inout LINE; VALUE: in STRING;
                 JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0);

Note write is overloaded for many other value types, but I wont include them here, see standard for more.

Notice write L argument is inout. It is actually modified by the procedure. Behind the scenes, write reallocates the targetted string object to new size.

Typical usage is for constructing variable-length message:

use std.textio.all;

-- ...

function describe_number(v: in integer) return string is
  variable ret: line := new string'("");
begin
  write(ret, string'("Passed argument is: "));
  write(ret, v);
  if v >= 1000 then
    write(ret, string'(", this is a lot !"));
  end if;
  return ret.all;
end function describe_number;

-- ...

process  
begin       
  report describe_number(1);
  report describe_number(1000);
  wait;
end process;
\$\endgroup\$
0
\$\begingroup\$

All right, this is the final solution, I don't think there is a better way but let me know if there is one.

  procedure write_string(strout: out string; constant strin: in string) is
  begin
    assert strin'length <= strout'length
    report "the specified string size " & integer'image(strin'length) & " cannot fit into the specified variable size " & integer'image(strout'length)
    severity failure;
    for i in strout'range loop
      strout(i) := ' ';
    end loop;
    strout(strin'range) := strin;
  end procedure;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.