Published:

This article shows how to work with strings containing line breaks in VHDL. Read on to learn how to split long lines in your VHDL code, print text containing newline characters, and how VHDL differs from regular programming languages regarding non-printing control characters in strings.

Splitting string literals in the VHDL code

Sometimes you want to define a long line of text as a string constant or variable while keeping your VHDL code lines short, and that’s easy to do. You can split long and unruly text lines by using the ampersand & concatenation operator:

constant quote : string := "VHDLwhiz helps you understand " &
  "advanced concepts within FPGA design without being overly technical.";

When printing the quote constant during simulation, the two string literals appear as one long line:

# VHDLwhiz helps you understand advanced concepts within FPGA design without being overly technical.

Adding a newline character to a string

This section shows how to add a line feed character in your string to produce a line break once you print the string during simulation.

Line breaks are made up of control characters that differ between systems. Fortunately, VHDL makes it easy to do with its dedicated LF line feed character:

constant banner : string :=
  "__      ___    _ _____  _             _     _     " & LF &
  "\ \    / / |  | |  __ \| |           | |   (_)    " & LF &
  " \ \  / /| |__| | |  | | |  __      _| |__  _ ____" & LF &
  "  \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /" & LF &
  "   \  /  | |  | | |__| | |___\ V  V /| | | | |/ / " & LF &
  "    \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|";

When printed to the simulator console, the LF characters translate into line breaks:

# __      ___    _ _____  _             _     _     
# \ \    / / |  | |  __ \| |           | |   (_)    
#  \ \  / /| |__| | |  | | |  __      _| |__  _ ____
#   \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /
#    \  /  | |  | | |__| | |___\ V  V /| | | | |/ / 
#     \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|

According to the VHDL Language Reference Manual, the LF character shall translate into the representation of the end of a line on whatever system you are running. Thus, the LF character may produce slightly different log files between operating systems.

For completeness, let’s see what happens if we use the "\r\n" sequence instead, which means carriage return + line feed (CR+LF) in many programming languages:

constant banner_not_working : string :=
  "__      ___    _ _____  _             _     _     \r\n" &
  "\ \    / / |  | |  __ \| |           | |   (_)    \r\n" &
  " \ \  / /| |__| | |  | | |  __      _| |__  _ ____\r\n" &
  "  \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /\r\n" &
  "   \  /  | |  | | |__| | |___\ V  V /| | | | |/ / \r\n" &
  "    \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|";

It doesn’t work because VHDL doesn’t treat the backslash as an escape sequence. Instead, they are printed literally to the simulator console:

# __      ___    _ _____  _             _     _     \r\n\ \    / / |  | |  __ \| |           | |   (_)    \r\n \ \  / /| |__| | |  | | |  __      _| |__  _ ____\r\n  \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /\r\n   \  /  | |  | | |__| | |___\ V  V /| | | | |/ / \r\n    \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|

Printing a single line in VHDL

And finally, when printing using the report statement or the writeline procedure, a newline always follows the printed text. For example, after importing use std.textio.all; at the top of the VHDL file, we can define this procedure that prints a string to the simulator console:

procedure print(msg : string) is
  variable l : line;
begin
  write(l, msg);
  writeline(output, l);
end procedure;

Then we could call the new print procedure once for each string we want to print on an individual line:

print("__      ___    _ _____  _             _     _     ");
print("\ \    / / |  | |  __ \| |           | |   (_)    ");
print(" \ \  / /| |__| | |  | | |  __      _| |__  _ ____");
print("  \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /");
print("   \  /  | |  | | |__| | |___\ V  V /| | | | |/ / ");
print("    \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|");

That would have the same effect as calling print on the banner constant we defined earlier, containing the LF line breaks:

print(banner);

The output to the simulator console in both cases is:

# __      ___    _ _____  _             _     _     
# \ \    / / |  | |  __ \| |           | |   (_)    
#  \ \  / /| |__| | |  | | |  __      _| |__  _ ____
#   \ \/ / |  __  | |  | | |  \ \ /\ / / '_ \| |_  /
#    \  /  | |  | | |__| | |___\ V  V /| | | | |/ / 
#     \/   |_|  |_|_____/|______\_/\_/ |_| |_|_/___|

Summary

  • Ampersand & is the string concatenation operator in VHDL
  • LF is VHDL’s line feed/newline/end of line/EOL character
  • The backslash “\” character has no special meaning in string literals
  • The report statement and TEXTIO’s writeline procedure produce a newline after the printed text

Author: Jonas Julian Jensen

I’m from Norway, but I live in Bangkok, Thailand. Before I started VHDLwhiz, I worked as an FPGA engineer in the defense industry. I earned my master’s degree in informatics at the University of Oslo.

Leave a Reply

Your email address will not be published. Required fields are marked *

One thought on “How to define and print multiline string literals in VHDL

  1. Thanks for the article! Very useful

    I’ve always seen printing using both write line and report in testbenches also noticed that report gets registered in the msg field in the waveform window view, while writeline doesn’t….

    Sometimes also seen that it is preferred declaring a print procedure with write and writeline instead using the report function which this last I think it would be quicker and will require less coding.
    just wondering, is there any advantage of using one method or the other (report vs writeline)? Or both would be equivalent?

    Posted on October 23, 2022 at 7:52 pm