-
Notifications
You must be signed in to change notification settings - Fork 2
/
logging.vhd
204 lines (172 loc) · 7.06 KB
/
logging.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
-------------------------------------------------------------------------------
--
-- Logging Package.
--
-- This file is part of the noasic library.
--
-- Dependencies:
-- * txtutils package
--
-- See also:
-- * http://noasic.com/blog/adding-logging-to-a-vhdl-simulation/
--
-- Author(s):
-- Guy Eschemann, Guy.Eschemann@gmail.com
--
-------------------------------------------------------------------------------
-- Copyright (c) 2012-2022 Guy Eschemann
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use work.txtutils.all;
package logging is
-- Initialize the logging framework, i.e. declare the loggers and their
-- associated logging levels
procedure init(config_filename : string);
-- The actual logging procedures:
procedure debug(logger : string; message : string);
procedure info(logger : string; message : string);
procedure warning(logger : string; message : string);
procedure error(logger : string; message : string);
procedure failure(logger : string; message : string);
-- Maximum number of allowed loggers (increase if needed)
constant MAX_LOGGERS : natural := 50;
-- Maximum string length (for a logger's name)
constant MAX_STRING_LENGTH : natural := 256;
end package logging;
package body logging is
-- pragma translate_off
-- The allowed logging levels
type t_logging_level is (DEBUG, INFO, WARNING, ERROR, FAILURE);
-- A configuration entry for a single logger
type t_logging_config_entry is record
logger : string(1 to MAX_STRING_LENGTH);
level : t_logging_level;
end record;
-- A collection of configuration entries for up to MAX_LOGGERS loggers
type t_logging_config_array is array (0 to MAX_LOGGERS - 1) of t_logging_config_entry;
-- The logging type. Using a protected type for thread safety, as the logging
-- procedures may be called from within different processes.
type t_logging is protected
-- Initialize the logging package using a configuration file
procedure init(config_filename : string);
-- Get the current logging level of a given logger
impure function get_level(logger : string) return t_logging_level;
-- Output a logging message to the simulator's standard output, provided
-- the given level is greater than or equal to the logger's current
-- logging level
procedure trace(level : string; logger : string; message : string);
end protected;
type t_logging is protected body
variable v_num_config_entries : natural;
variable v_config_entries : t_logging_config_array := (others => ((others => ' '), DEBUG));
procedure init(config_filename : string) is
file config_file : TEXT;
variable v_line : line;
variable v_status : FILE_OPEN_STATUS;
begin
v_num_config_entries := 0;
file_open(v_status, config_file, config_filename, READ_MODE);
assert v_status = OPEN_OK report "ERROR: could not open file " & config_filename severity failure;
while not endfile(config_file) loop
if v_num_config_entries >= MAX_LOGGERS then
report "too many loggers" severity warning;
exit;
end if;
readline(config_file, v_line);
assert v_line'length > 0 report "ERROR: file contains an empty line" severity failure;
v_config_entries(v_num_config_entries).logger(strip(v_line.all)'range) := strip(v_line.all);
readline(config_file, v_line);
if strip(v_line.all) = string'("debug") then
v_config_entries(v_num_config_entries).level := DEBUG;
elsif strip(v_line.all) = string'("info") then
v_config_entries(v_num_config_entries).level := INFO;
elsif strip(v_line.all) = string'("warning") then
v_config_entries(v_num_config_entries).level := WARNING;
elsif strip(v_line.all) = string'("error") then
v_config_entries(v_num_config_entries).level := ERROR;
elsif strip(v_line.all) = string'("failure") then
v_config_entries(v_num_config_entries).level := FAILURE;
else
report "ERROR: unsupported logging level" severity failure;
end if;
v_num_config_entries := v_num_config_entries + 1;
end loop;
file_close(config_file);
end procedure;
impure function get_level(logger : string) return t_logging_level is
begin
for i in 0 to v_num_config_entries loop
if strip(v_config_entries(i).logger) = strip(logger) then
return v_config_entries(i).level;
end if;
end loop;
return DEBUG; -- unknown logger -> use lowest-possible logging level
end function;
procedure trace(level : string; logger : string; message : string) is
begin
print(time'image(now) & ": " & level & ": " & strip(logger) & ": " & message);
end procedure;
end protected body;
shared variable sv_config : t_logging;
-- pragma translate_on
procedure init(config_filename : string) is
begin
-- pragma translate_off
sv_config.init(config_filename);
-- pragma translate_on
end procedure;
procedure debug(logger : string; message : string) is
begin
-- pragma translate_off
if sv_config.get_level(logger) <= DEBUG then
sv_config.trace("DEBUG", logger, message);
end if;
-- pragma translate_on
end procedure;
procedure info(logger : string; message : string) is
begin
-- pragma translate_off
if sv_config.get_level(logger) <= INFO then
sv_config.trace("INFO", logger, message);
end if;
-- pragma translate_on
end procedure;
procedure warning(logger : string; message : string) is
begin
-- pragma translate_off
if sv_config.get_level(logger) <= WARNING then
sv_config.trace("WARNING", logger, message);
end if;
-- pragma translate_on
end procedure;
procedure error(logger : string; message : string) is
begin
-- pragma translate_off
if sv_config.get_level(logger) <= ERROR then
sv_config.trace("ERROR", logger, message);
end if;
-- pragma translate_on
end procedure;
procedure failure(logger : string; message : string) is
begin
-- pragma translate_off
if sv_config.get_level(logger) <= FAILURE then
sv_config.trace("FAILURE", logger, message);
end if;
-- pragma translate_on
end procedure;
end package body logging;