Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Common log interface #776

Merged
merged 1 commit into from
Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/logging/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,26 @@ and then let the location preprocessor know about the added procedure
ui = VUnit.from_argv()
ui.enable_location_preprocessing(additional_subprograms=['my_convenience_procedure'])

External Logging Framework Integration
--------------------------------------

VUnit provides a package ``common_log_pkg`` providing a single procedure ``write_to_log`` that is used to
output the string produced by a log entry. The implementation of this procedure can be changed to redirect VUnit log
messages to a third party logging framework, thereby aligning the logging styles in a testbench with code using several
logging frameworks. The feature is enabled by passing a reference to the file implementing the package body:

.. code-block:: python

ui.add_vhdl_builtins(use_external_log="path/to/other/common_log_pkg/body")

The procedure interface is designed to be generic and suitable for third party logging frameworks as well. If provided,
third party log messages can also be redirected to VUnit logging:

.. literalinclude:: ../../vunit/vhdl/logging/src/common_log_pkg.vhd
:language: vhdl
:lines: 7-


Deprecated Interfaces
---------------------

Expand Down
1 change: 1 addition & 0 deletions docs/news.d/776.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add common log interface for third-party logging framework integration.
5,841 changes: 5,841 additions & 0 deletions examples/vhdl/osvvm_log_integration/osvvm_integration/AlertLogPkg.vhd

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
-- You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com

library vunit_lib;
context vunit_lib.vunit_context;

package body common_log_pkg is
procedure write_to_log(
file log_destination : text;
msg : string := "";
log_time : time := no_time;
log_level : string := "";
log_source_name : string := "";
str_1, str_2, str_3, str_4, str_5, str_6, str_7, str_8, str_9, str_10 : string := "";
val_1, val_2, val_3, val_4, val_5, val_6, val_7, val_8, val_9, val_10 : integer := no_val
) is
constant stripped_log_level : string := strip(log_level);

alias prefix is str_2;
alias suffix is str_3;

variable logger : logger_t;
variable vunit_log_level : log_level_t;
variable full_msg : line;
begin
logger := get_logger(log_source_name);

if stripped_log_level = "WARNING" then
vunit_log_level := warning;
elsif stripped_log_level = "ERROR" then
vunit_log_level := error;
elsif stripped_log_level = "FAILURE" then
vunit_log_level := failure;
elsif stripped_log_level = "DEBUG" then
vunit_log_level := debug;
elsif stripped_log_level = "PASSED" then
vunit_log_level := pass;
else
vunit_log_level := info;
end if;

if prefix /= "" then
write(full_msg, prefix & " ");
end if;

write(full_msg, msg);

if suffix /= "" then
write(full_msg, " " & suffix);
end if;

log(logger, msg, vunit_log_level, path_offset => 4);
end;

end package body;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
-- You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com

use work.ansi_pkg.all;
use work.log_levels_pkg.all;
use work.string_ops.upper;

library osvvm;
use osvvm.AlertLogPkg.all;

package body common_log_pkg is

procedure write_to_log(
file log_destination : text;
msg : string := "";
log_time : time := no_time;
log_level : string := "";
log_source_name : string := "";
str_1, str_2, str_3, str_4, str_5, str_6, str_7, str_8, str_9, str_10 : string := "";
val_1, val_2, val_3, val_4, val_5, val_6, val_7, val_8, val_9, val_10 : integer := no_val
) is
begin
if (log_level = "warning") or (log_level = "error") or (log_level = "failure") then
Alert(GetAlertLogID(log_source_name), msg, AlertType'value(upper(log_level)));
elsif (log_level = "debug") then
osvvm.AlertLogPkg.Log(GetAlertLogID(log_source_name), msg, DEBUG);
elsif (log_level = "pass") then
osvvm.AlertLogPkg.Log(GetAlertLogID(log_source_name), msg, PASSED);
else
osvvm.AlertLogPkg.Log(GetAlertLogID(log_source_name), msg);
end if;
end;

end package body;
63 changes: 63 additions & 0 deletions examples/vhdl/osvvm_log_integration/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env python3

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com

from pathlib import Path
from itertools import product
from vunit import VUnit, VUnitCLI

cli = VUnitCLI()
cli.parser.add_argument(
"--use-osvvm-log",
action="store_true",
default=False,
help="Re-direct VUnit log output to OSVVM log handling",
)
cli.parser.add_argument(
"--use-vunit-log",
action="store_true",
default=False,
help="Re-direct OSVVM log output to VUnit log handling",
)
args = cli.parse_args()
if args.use_osvvm_log and args.use_vunit_log:
raise RuntimeError("Only one of --use-osvvm-log and --use-vunit-log can be used at any time.")
args.clean = True
prj = VUnit.from_args(args=args)
root = Path(__file__).parent
if args.use_osvvm_log:
prj.add_vhdl_builtins(use_external_log=Path(root / "osvvm_integration" / "vunit_to_osvvm_common_log_pkg-body.vhd"))
else:
prj.add_vhdl_builtins()

lib = prj.add_library("lib")
lib.add_source_files(root / "*.vhd")
lib.test_bench("tb_example").set_generic("use_osvvm_log", args.use_osvvm_log)
lib.test_bench("tb_example").set_generic("use_vunit_log", args.use_vunit_log)

osvvm = prj.add_library("osvvm")
osvvm_files_to_compile = [
"NamePkg.vhd",
"OsvvmGlobalPkg.vhd",
"TranscriptPkg.vhd",
"TextUtilPkg.vhd",
"OsvvmScriptSettingsPkg.vhd",
"OsvvmScriptSettingsPkg_default.vhd",
]
for osvvm_file in osvvm_files_to_compile:
osvvm.add_source_files(root / ".." / ".." / ".." / "vunit" / "vhdl" / "osvvm" / osvvm_file)

if args.use_vunit_log:
osvvm.add_source_files(root / ".." / ".." / ".." / "vunit" / "vhdl" / "logging" / "src" / "common_log_pkg.vhd")
osvvm.add_source_files(root / "osvvm_integration" / "osvvm_to_vunit_common_log_pkg-body.vhd")
osvvm.add_source_files(root / "osvvm_integration" / "AlertLogPkg.vhd")
else:
osvvm.add_source_files(root / ".." / ".." / ".." / "vunit" / "vhdl" / "osvvm" / "AlertLogPkg.vhd")


prj.set_compile_option("rivierapro.vcom_flags", ["-dbg"])
prj.main()
85 changes: 85 additions & 0 deletions examples/vhdl/osvvm_log_integration/tb_example.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
-- You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com

library vunit_lib;
context vunit_lib.vunit_context;

library osvvm;
use osvvm.AlertLogPkg.all;

library ieee;
use ieee.std_logic_1164.all;

entity tb_example is
generic (
runner_cfg : string;
use_osvvm_log : boolean;
use_vunit_log : boolean);
end entity;

architecture tb of tb_example is

begin
main : process
constant logger : logger_t := get_logger("A VUnit logger name");
constant parent_logger : logger_t := get_logger("VUnit parent");
constant child_logger : logger_t := get_logger("VUnit child", parent_logger);
constant checker : checker_t := new_checker(logger);

constant id : AlertLogIDType := GetAlertLogID("An OSVVM ID");
constant parent_id : AlertLogIDType := GetAlertLogID("OSVVM parent");
constant child_id : AlertLogIDType := GetAlertLogID("OSVVM child", parent_id);
begin
test_runner_setup(runner, runner_cfg);
set_stop_level(failure);

if use_osvvm_log then
print(LF & "-------------------------------------------------------------------");
print("This is what VUnit log messages look like when piped through OSVVM:");
print("-------------------------------------------------------------------" & LF);
else
print(LF & "------------------------------------------------------------------------");
print("This is what standard VUnit log messages look like. Call run.py");
print("with --use-osvvm-log to see what is looks like when piped through OSVVM.");
print("------------------------------------------------------------------------" & LF);
end if;

info(logger, "Hello from VUnit");
check(checker, false, "An error from VUnit");
info(child_logger, "Hello from VUnit hierarchy");

if use_vunit_log then
print(LF & "-------------------------------------------------------------------");
print("This is what OSVVM log messages look like when piped through VUnit:");
print("-------------------------------------------------------------------" & LF);
else
print(LF & "------------------------------------------------------------------------");
print("This is what standard OSVVM log messages look like. Call run.py");
print("with --use-vunit-log to see what is looks like when piped through VUnit.");
print("------------------------------------------------------------------------" & LF);
end if;

osvvm.AlertLogPkg.Log(id, "Hello from OSVVM");
Alert(id, "An error from OSVVM");
osvvm.AlertLogPkg.Log(child_id, "Hello from OSVVM hierarchy");

if use_osvvm_log then
print(LF & "------------------------------------------------------------------------");
print("Only log messages are piped through OSVVM. Print messages outside of the");
print("the logging framework are unaffected. For example this FAILURE");
print("message.");
print("------------------------------------------------------------------------" & LF);
else
print(LF & "");
end if;

test_runner_cleanup(runner);
end process;

test_runner_watchdog(runner, 1000 ns);


end architecture;
2 changes: 2 additions & 0 deletions tests/acceptance/artificial/vhdl/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
for file in glob(str(root / "*.vhd")):
if "tb_set_generic" in file:
lib2.add_source_files(file)
elif "other_logging_framework" in file:
continue
else:
lib.add_source_files(file)

Expand Down
7 changes: 7 additions & 0 deletions tests/acceptance/test_external_run_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ def test_vhdl_array_axis_vcs_example_project(self):
def test_vhdl_axi_dma_example_project(self):
self.check(ROOT / "examples/vhdl/axi_dma/run.py")

def test_vhdl_osvvm_log_integration(self):
self.check(ROOT / "examples/vhdl/osvvm_log_integration/run.py", exit_code=1)
check_report(
self.report_file,
[("failed", "lib.tb_example.all")],
)

@mark.skipif(
simulator_check(lambda simclass: not simclass.supports_vhdl_contexts()),
reason="This simulator/backend does not support VHDL contexts",
Expand Down
2 changes: 2 additions & 0 deletions tests/lint/test_license.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ def find_licensed_files():
(Path(root) / file_name).resolve(),
):
continue
if file_name == "AlertLogPkg.vhd":
continue
if is_prefix_of(
(VHDL_PATH / "JSON-for-VHDL").resolve(),
(Path(root) / file_name).resolve(),
Expand Down
11 changes: 10 additions & 1 deletion vunit/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def add_verilog_builtins(self):
"""
self._vunit_lib.add_source_files(VERILOG_PATH / "vunit_pkg.sv")

def add_vhdl_builtins(self, external=None):
def add_vhdl_builtins(self, external=None, use_external_log=None):
"""
Add vunit VHDL builtin libraries

Expand Down Expand Up @@ -273,6 +273,14 @@ def add_vhdl_builtins(self, external=None):
):
self._add_files(VHDL_PATH / path / "src" / "*.vhd")

logging_files = glob(str(VHDL_PATH / "logging" / "src" / "*.vhd"))
for logging_file in logging_files:
if logging_file.endswith("common_log_pkg-body.vhd") and use_external_log:
self._add_files(Path(use_external_log))
continue

self._add_files(Path(logging_file))


def osvvm_is_installed():
"""
Expand Down Expand Up @@ -304,6 +312,7 @@ def add(self, name, args=None):
"""
Add builtin with arguments
"""

args = {} if args is None else args

if not self._add_check(name, args):
Expand Down
6 changes: 4 additions & 2 deletions vunit/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,11 +972,13 @@ def add_verilog_builtins(self):
"""
self._builtins.add_verilog_builtins()

def add_vhdl_builtins(self, external=None):
def add_vhdl_builtins(self, external=None, use_external_log=None):
"""
Add VUnit VHDL builtin libraries.

:param external: struct to provide bridges for the external VHDL API.
:param use_external_log: path to external implementation of common_log_pkg-body to allow
VUnit log messages to be redirected to another logging framework.

:example:

Expand All @@ -992,7 +994,7 @@ def add_vhdl_builtins(self, external=None):
VHDL users need to call this method explicitly in order to preserve the functionality.
See :vunit_issue:`777`.
"""
self._builtins.add_vhdl_builtins(external=external)
self._builtins.add_vhdl_builtins(external=external, use_external_log=use_external_log)

def add_com(self):
"""
Expand Down
4 changes: 1 addition & 3 deletions vunit/vhdl/logging/src/ansi_pkg.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com

use std.textio.all;

library vunit_lib;
use vunit_lib.string_ptr_pkg.all;
use work.string_ptr_pkg.all;

package ansi_pkg is

Expand Down