blob: 56ee33bb9114f0d6cacf919ce4b2366ad3c143bb [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_PRINT_H_
#define OPENTITAN_SW_DEVICE_LIB_RUNTIME_PRINT_H_
#include <stdarg.h>
#include <stddef.h>
#include "sw/device/lib/dif/dif_uart.h"
/**
* @file
* @brief Libc-like printing facilities.
*
* This header provides libc-like printing facilities, which is agnostic of the
* underlying hardware printing mechanism.
*
* We avoid using libc names here, since we do not support the full suite of
* format specifier syntax, and use a different character sink type instead of
* the traditional `FILE *`.
*
* All functions in this file should be machine word size agnostic, that is, the
* same code should work correctly on both 32-bit and 64-bit machines, though
* formatting, where the exact format style is unspecified, is allowed to vary
* slightly on machine word size.
*/
/**
* A buffer_sink_t represents a place to write bytes to, implemented as a
* C-style "closure".
*
* It consists of a generic data pointer, which can hold instance-specific
* information, and a sink function, which takes the data pointer, a buffer, and
* that buffer's length.
*
* The sink function should return the number of bytes actually written.
*/
typedef struct buffer_sink {
void *data;
size_t (*sink)(void *data, const char *buf, size_t len);
} buffer_sink_t;
/**
* Prints out a message to stdout, formatted according to the format string
* `format`.
*
* The definition of "stdout" is not provided by this library; rather, it must
* be initialized using `base_set_stdout()`.
*
* This function supports a subset of the format specifiers provided by standard
* C `printf`. Those are, namely:
* - %%, which prints a percent sign.
* - %c, which prints the lowest byte of a uint32_t as a character.
* - %s, which prints a NUL-terminated string.
* - %d and %i, which print a signed decimal uint32_t.
* - %u, which prints an unsigned decimal uint32_t.
* - %o, which prints an unsigned octal uint32_t.
* - %x and %X, which print an unsigned hex uint32_t.
* - %p, which prints a pointer in a consistent but unspecified way.
*
* Additionally, three SystemVerilog format specifiers are supported:
* - %h and %H, which are aliases for %x and %X, respectively.
* - %b, which prints an unsigned binary uint32_t.
*
* Finally, additional nonstandard format specifiers is supported:
* - %!s, which takes a size_t followed by a pointer to a buffer, and prints
* out that many characters from the buffer.
* - %!x, %!X, %!y, and %!Y, which are like %!s but print out a hex dump
* instead; casing is as with %x, and %!x will print in big-endian order
* (i.e., last byte printed first) while %!y will print in little-endian
* order (i.e., first byte printed first). This makes sure %!x is consistent
* with %x.
* - %!b, which takes a bool and prints either true or false.
* - %r, which takes a status_t and prints the status, argument and module ID.
* - %!r, which takes a status_t and prints the status, argument and module ID
* as JSON.
*
* When compiled for a DV testbench, this function will not read any pointers,
* and as such the specifiers %s, %!s, %!x, %!X, %!y, and %!Y will behave as if
* they were printing garbage, and are, as such, unsupported.
*
* This function furthermore supports width modifiers for integer specifiers,
* such as `%010d`. It does not support dynamic widths like `%*d`. If the width
* specifier starts with a `0`, it is padded with zeroes; otherwise, it is
* padded with spaces, consistent with the standard C behavior.
*
* Of course, providing arguments for formatting which are incompatible with a
* given format specifier is Undefined Behavior.
*
* Note that for logging in DV, the following script updates the format
* specifiers supported in C above and changes them to match the SystemVerilog
* language semantics: util/device_sw_utils/extract_sw_logs.py
* It also makes fixes as needed for custom speficiers such as %!s.
*
* @param format the format spec.
* @param ... values to interpolate in the format spec.
*/
size_t base_printf(const char *format, ...);
/**
* Prints out a message to stdout, formatted according to the format string
* `format`.
*
* This function is identical to `base_printf`, except in that it takes a
* `va_list` instead of having a vararg parameter. This function plays a role
* analogous to `base_vfprintf`, for functions that wish to use the currently
* set `stdout`.
*
* This function *does not* take ownership of `args`; callers are responsible
* for calling `va_end`.
*
* See `base_printf()` for the semantics of the format specification.
*
* @param format the format spec.
* @param args values to interpolate in the format spec.
*/
size_t base_vprintf(const char *format, va_list args);
/*
* Prints a message to the buffer `buf`, capped at a given length.
*
* It goes without saying that the caller must ensure the given buffer is large
* enough; failure to do so is Undefined Behavior.
*
* See `base_printf()` for the semantics of the format specification.
*
* @param buf a buffer to print to.
* @param format the format spec.
* @param ... values to interpolate in the format spec.
*/
size_t base_snprintf(char *buf, size_t len, const char *format, ...);
/**
* Prints a message to the sink `out`.
*
* If `out.sink` is `NULL`, writes are treated as-if they were written to a
* UNIX-like /dev/null: writes succeed, but the actual bytes are not printed
* anywhere.
*
* See `base_printf()` for the semantics of the format specification.
*
* @param out a sink to print to.
* @param format the format spec.
* @param ... values to interpolate in the format spec.
*/
size_t base_fprintf(buffer_sink_t out, const char *format, ...);
/**
* Prints a message to the sink `out`.
*
* This function is identical to `base_fprintf`, except in that it takes a
* `va_list` instead of having a vararg parameter. This function is provided
* not for calling directly, but rather for being called by functions that
* already take a variable number of arguments, and wish to make use of
* formatting facilities.
*
* This function *does not* take ownership of `args`; callers are responsible
* for calling `va_end`.
*
* If `out.sink` is `NULL`, writes are treated as-if they were written to a
* UNIX-like /dev/null: writes succeed, but the actual bytes are not printed
* anywhere.
*
* See `base_printf()` for the semantics of the format specification.
*
* @param out a sink to print to.
* @param format the format spec.
* @param args values to interpolate in the format spec.
*/
size_t base_vfprintf(buffer_sink_t out, const char *format, va_list args);
/**
* Configuration options for `base_hexdump` and friends.
*/
typedef struct base_hexdump_fmt {
/** How many bytes to print per word of output. */
size_t bytes_per_word;
/** How many words (as defined above) per line of output. */
size_t words_per_line;
/**
* The alphabet to use for char-ifying a byte.
*
* These characters will be written as-is to the sink.
*/
const char (*alphabet)[256];
} base_hexdump_fmt_t;
/**
* The default alphabet used by `base_hexdump()` functions.
*/
extern const char kBaseHexdumpDefaultFmtAlphabet[256];
/**
* Dumps `hex` in an xxd-style hexdump to stdout, using default formatting
* options.
*
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_hexdump(const char *buf, size_t len);
/**
* Dumps `hex` in an xxd-style hexdump to the buffer `buf`, capped at the given
* length, using default formatting options.
*
* @param out a buffer to print to.
* @param out_len the length of the output buffer.
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_snhexdump(char *out, size_t out_len, const char *buf, size_t len);
/**
* Dumps `hex` in an xxd-style hexdump to `out`, using default formatting
* options.
*
* If `out.sink` is `NULL`, writes are treated as-if they were written to a
* UNIX-like /dev/null: writes succeed, but the actual bytes are not printed
* anywhere.
*
* @param out a sink to print to.
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_fhexdump(buffer_sink_t out, const char *buf, size_t len);
/**
* Dumps `hex` in an xxd-style hexdump to stdout.
*
* @param fmt the format for dumping.
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_hexdump_with(base_hexdump_fmt_t fmt, const char *buf, size_t len);
/**
* Dumps `hex` in an xxd-style hexdump to the buffer `buf`, capped at the given
* length.
*
* @param out a buffer to print to.
* @param out_len the length of the output buffer.
* @param fmt the format for dumping.
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_snhexdump_with(char *out, size_t out_len, base_hexdump_fmt_t fmt,
const char *buf, size_t len);
/**
* Dumps `hex` in an xxd-style hexdump to `out`.
*
* If `out.sink` is `NULL`, writes are treated as-if they were written to a
* UNIX-like /dev/null: writes succeed, but the actual bytes are not printed
* anywhere.
*
* @param out a sink to print to.
* @param fmt the format for dumping.
* @param buf the buffer to dump.
* @param len the number of bytes to dump from hex.
*/
size_t base_fhexdump_with(buffer_sink_t out, base_hexdump_fmt_t fmt,
const char *buf, size_t len);
/**
* Sets what the "stdout" sink is, which is used by `base_printf()`.
*
* The default sink behaves like /dev/null on a standard UNIX system: writes
* are treated as successful, but the contents of buffers are ignored.
*
* As such, this function must be called for printed messages to wind up
* somewhere.
*
* Passing in `NULL` instead of a real function pointer will reset stdout to
* the default /dev/null behavior.
*
* @param out the sink to use for "default" printing.
*/
void base_set_stdout(buffer_sink_t out);
/**
* Configures UART stdout for `base_print.h` to use.
*
* Note that this function will save `uart` in a global variable, so the pointer
* must have static storage duration.
*
* @param uart The UART handle to use for stdout.
*/
void base_uart_stdout(const dif_uart_t *uart);
#endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_PRINT_H_