This is a VHDL string formatting package that is based on f-strings found in Python 3.
Working with strings in VHDL is somewhat difficult. They require known sizes, are
concatenated with the &
operator, and can be difficult to align concisely.
A typical string building line might look like:
report "int: " & integer'image(int) & " real: " & real'image(r);
VHDL has operator overloading which includes the return style, so we can emulate the style of f-strings in VHDL.
report f("int: {} real: {}", f(int), f(r));
Here, we have defined the function f()
for all the standard types included with
VHDL as well as a function that uses the formatted string as the first argument.
In fact, we can extend this further and insert formatting information into the
string itself, or when we perform the initial conversion on the type.
report f("int: {:>12d} real: {}", f(int), f(r, "0.12f"));
In this example, we are right justifying a signed decimal number with a width of 12,
and creating a string from the value r
with 12 bits of precision after the decimal
point.
The fmt
package defines the following functions for use.
-- Format string building function using a string_list
procedure f(sfmt : string ; variable args : inout string_list ; variable l : inout line) ;
alias fmt is f[string, string_list, line] ;
-- Format string building function using up to 16 arguments
function f(sfmt : string ; a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 : in string := "") return string ;
alias fmt is f[string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string return string] ;
-- Single argument formatting
function f(sfmt : string ; value : bit) return string ;
function f(sfmt : string ; value : bit_vector) return string ;
function f(sfmt : string ; value : boolean) return string ;
function f(sfmt : string ; value : character) return string ;
function f(sfmt : string ; value : integer) return string ;
function f(sfmt : string ; value : real) return string ;
function f(sfmt : string ; value : time) return string ;
-- Functions to format standard types
-- NOTE: Aliases added for ambiguous types
function f(value : bit ; sfmt : string := "b") return string ;
alias fbit is f[bit, string return string] ;
function f(value : bit_vector ; sfmt : string := "b") return string ;
alias fbv is f[bit_vector, string return string] ;
function f(value : boolean ; sfmt : string := "s") return string ;
function f(value : character ; sfmt : string := "c") return string ;
alias fchar is f[character, string return string] ;
function f(value : integer ; sfmt : string := "d") return string ;
function f(value : real ; sfmt : string := "f") return string ;
function f(value : string ; sfmt : string := "s") return string ;
alias fstr is f[string, string return string] ;
function f(value : time ; sfmt : string := ".9t") return string ;
These are all included in a single file: fmt.vhd
.
The format specification is close to the Python 3 format specification, but not exactly.
[fill][align][sign][width][.precision][class]
fill: Any character
The character to fill any extra space when the string does not fit the requested width.
Example:
fmt("{:~20s}", "string")
Output: string~~~~~~~~~~~~~~
align: <
>
^
=
Left Justification (<
), Right Justification (>
), Centered (^
), and Sign Align
Justification (=
, for d
, e
, f
, u
classes only)
sign: +
Always print the sign of a number (for d
, e
, f
, u
classes only)
width: A number
The minimum number of characters to write.
.precision: A point then a number
For the (e
, f
) classes, defines the number of places to the right of the decimal.
For the t
class, determines which timebase to utilize for the conversion.
Precision | Time Unit |
---|---|
.0 |
1 second |
.3 |
1 millisecond |
.6 |
1 microsecond |
.9 |
1 nanosecond |
.12 |
1 picosecond |
.15 |
1 femtosecond |
class: b
, c
, d
, e
, f
, o
, s
, t
, u
, x
The class of the string represented.
Character | Class |
---|---|
b |
Binary |
c |
Character |
d |
Signed integer |
e |
Floating point (exp notation - i.e. 3.14159e+00) |
f |
Floating point (fixed notation - i.e. 3.14159) |
o |
Octal |
s |
String |
t |
Time value |
u |
Unsigned integer |
x |
Hexadecimal |
Note: Both uppercase and lowercase versions of the class are accepted.
The usage of the package should be straight forward and easy. The main goal is easier string manipulation, so being able to do simple string substitutions is the easiest way to use the package.
report f("{} {}", "hello", "world");
Argument reordering can also be done.
report f("{1} {0}", "world", "hello");
Formatting can be done inline.
report f("{:<20s} {:>20s}", "hello", "world");
Formatting may also be done on the argument.
report f("{} {}", fstr("hello","<20s"), fstr("world",">20s));
Lastly, for convenience, single argument overloads are available, too.
report f("realnum: {:12.8f}", 3.14159));
For more examples, please see the fmt_examples.vhd
file.
- Binary/Octal/Hex Conversions for Integers
- Add
std_logic_vector
f()
- Add
signed
andunsigned
f()
- Add
sfixed
andufixed
f()
- Generic
f()
for easier customization with default'image
orto_string()
conversions - Add the
#
option for printing0b
,0o
, or0x
before the printed number
The package is provided under the Unlicense so feel free to do whatever you like with it. If you like the project, please let me know. If you run into issues, please feel free to file an issue as well.