| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/lib/runtime/log.h" |
| |
| #include <assert.h> |
| |
| #include "sw/device/lib/arch/device.h" |
| #include "sw/device/lib/base/memory.h" |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/runtime/print.h" |
| |
| /** |
| * Ensure that log_fields_t is always 20 bytes. |
| * |
| * The assertion below helps prevent inadvertant changes to the struct. |
| * Please see the description of log_fields_t in log.h for more details. |
| */ |
| static_assert(sizeof(log_fields_t) == 20, |
| "log_fields_t must always be 20 bytes."); |
| |
| /** |
| * Converts a severity to a static string. |
| */ |
| static const char *stringify_severity(log_severity_t severity) { |
| switch (severity) { |
| case kLogSeverityInfo: |
| return "I"; |
| case kLogSeverityWarn: |
| return "W"; |
| case kLogSeverityError: |
| return "E"; |
| case kLogSeverityFatal: |
| return "F"; |
| default: |
| return "?"; |
| } |
| } |
| |
| /** |
| * Logs `log` and the values that follow to stdout. |
| * |
| * @param log the log data to log. |
| * @param ... format parameters matching the format string. |
| */ |
| void base_log_internal_core(log_fields_t log, ...) { |
| size_t file_name_len = |
| ((char *)memchr(log.file_name, '\0', PTRDIFF_MAX)) - log.file_name; |
| const char *base_name = memrchr(log.file_name, '/', file_name_len); |
| if (base_name == NULL) { |
| base_name = log.file_name; |
| } else { |
| ++base_name; // Remove the final '/'. |
| } |
| |
| // A small global counter that increments with each log line. This can be |
| // useful for seeing how many times this function has been called, even if |
| // nothing was printed for some time. |
| static uint16_t global_log_counter = 0; |
| |
| base_printf("%s%05d %s:%d] ", stringify_severity(log.severity), |
| global_log_counter, base_name, log.line); |
| ++global_log_counter; |
| |
| va_list args; |
| va_start(args, log); |
| base_vprintf(log.format, args); |
| va_end(args); |
| |
| base_printf("\r\n"); |
| } |
| |
| /** |
| * Logs `log` and the values that follow in an efficient, DV-testbench |
| * specific way, which bypasses the UART. |
| * |
| * @param log a pointer to log data to log. Note that this pointer is likely to |
| * be invalid at runtime, since the pointed-to data will have been |
| * stripped from the binary. |
| * @param nargs the number of arguments passed to the format string. |
| * @param ... format parameters matching the format string. |
| */ |
| void base_log_internal_dv(const log_fields_t *log, uint32_t nargs, ...) { |
| mmio_region_t log_device = mmio_region_from_addr(kDeviceLogBypassUartAddress); |
| mmio_region_write32(log_device, 0x0, (uintptr_t)log); |
| |
| va_list args; |
| va_start(args, nargs); |
| for (int i = 0; i < nargs; ++i) { |
| mmio_region_write32(log_device, 0x0, va_arg(args, uint32_t)); |
| } |
| va_end(args); |
| } |