-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbus_logger.py
165 lines (149 loc) · 6.92 KB
/
bus_logger.py
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
from uvm.base.uvm_component import UVMComponent
from uvm.macros import uvm_component_utils
from uvm.tlm1.uvm_analysis_port import UVMAnalysisImp
from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info
from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW
from uvm.base.uvm_config_db import UVMConfigDb
from uvm.macros.uvm_tlm_defines import uvm_analysis_imp_decl
import os
import cocotb
from tabulate import tabulate
from EF_UVM.bus_env.bus_item import bus_item
uvm_analysis_imp_bus = uvm_analysis_imp_decl("_bus")
uvm_analysis_imp_irq = uvm_analysis_imp_decl("_irq")
class bus_logger(UVMComponent):
def __init__(self, name="bus_logger", parent=None):
super().__init__(name, parent)
self.analysis_imp_bus = uvm_analysis_imp_bus("analysis_imp_bus", self)
self.analysis_imp_irq = uvm_analysis_imp_irq("analysis_imp_irq", self)
self.tag = name
def build_phase(self, phase):
super().build_phase(phase)
arr = []
if not UVMConfigDb.get(self, "", "bus_regs", arr):
uvm_fatal(self.tag, "No json file wrapper regs")
else:
self.regs = arr[0]
self.configure_logger()
def write_bus(self, tr):
uvm_info(self.tag, "get bus logging for " + tr.convert2string(), UVM_HIGH)
self.bus_log(tr)
self.regs_log(tr)
pass
def write_irq(self, tr):
uvm_info(self.tag, "get irq logg for " + tr.convert2string(), UVM_HIGH)
self.irq_log(tr)
# self.cov_groups.irq_cov(tr)
pass
def configure_logger(self, logger_file="log.txt"):
if not os.path.exists("loggers"):
os.makedirs("loggers")
self.logger_file = f"{os.getcwd()}/loggers/logger_bus.log"
self.logger_file_regs_w = f"{os.getcwd()}/loggers/regs_write.log"
self.logger_irq = f"{os.getcwd()}/loggers/logger_irq.log"
self.col_widths = [10, 10, 10, 10, 10]
# # log the header
self.bus_log(None, header_logged=True)
self.regs_log(None, header_logged=True)
self.irq_log(None, header_logged=True)
def bus_log(self, transaction, header_logged=False):
# Define a max width for each column
if header_logged:
headers = [f"{'Time (ns)'}", f"{'Kind'}", f"{'Address'}", f"{'Data'}", f"{'Size'}"]
header = self.format_row(headers)
with open(self.logger_file, "w") as f:
f.write(f"{header}\n")
else:
sim_time = f"{cocotb.utils.get_sim_time(units='ns')} ns"
if transaction.kind == bus_item.RESET:
table_data = [f"{sim_time}", "Reset", "--", "--", "--"]
else:
# Ensure each piece of data fits within the specified width
operation = (
f"{'Write' if transaction.kind == bus_item.WRITE else 'Read'}"
)
address = f"{hex(transaction.addr)}"
data = (
transaction.data
if type(transaction.data) is not int
else f"{hex(transaction.data)}"
)
size = f"{'word' if transaction.size == bus_item.WORD_ACCESS else 'half word' if transaction.size == bus_item.HALF_WORD_ACCESS else 'byte'}"
# Now, assemble your table_data with the pre-formatted fields
table_data = [f"{sim_time}", f"{operation}", f"{address}", f"{data}", f"{size}"]
table = self.format_row(table_data)
with open(self.logger_file, "a") as f:
f.write(f"{table}\n")
def irq_log(self, transaction, header_logged=False):
if header_logged:
headers = [f"{'Time (ns)'}", f"IRQ"]
header = self.format_row(headers)
with open(self.logger_irq, "w") as f:
f.write(f"{header}\n")
else:
sim_time = f"{cocotb.utils.get_sim_time(units='ns')} ns"
irq = f"{'clear' if transaction.trg_irq == 0 else 'trigger'}"
table_data = [f"{sim_time}", f"{irq}"]
table = self.format_row(table_data)
with open(self.logger_irq, "a") as f:
f.write(f"{table}\n")
def regs_log(self, transaction, header_logged=False):
# Define a max width for each column
if header_logged:
headers = [f"{'Time (ns)'}", f"{'Type'}", f"{'Name'}", f"{'Data'}"]
header = self.format_row(headers)
with open(self.logger_file_regs_w, "w") as f:
f.write(f"{header}\n")
else:
# Ensure each piece of data fits within the specified width
sim_time = f"{cocotb.utils.get_sim_time(units='ns')} ns"
# first write the register write then if it has fields
the_type = "REG"
try:
Name = f"{self.regs.regs[transaction.addr]['name']}"
except KeyError:
Name = f"{hex(transaction.addr)}"
data = (
f"{transaction.data}"
if type(transaction.data) is not int
else f"{hex(transaction.data)}({bin(transaction.data)})"
)
# Now, assemble your table_data with the pre-formatted fields
table_data = [f"{sim_time}", f"{the_type}", f"{Name}", f"{data}"]
table = self.format_row(table_data)
with open(self.logger_file_regs_w, "a") as f:
f.write(f"{table}\n")
try:
if "fields" in self.regs.regs[transaction.addr]:
for field in self.regs.regs[transaction.addr]["fields"]:
the_type = "FIELD"
Name = f"{field['name']}"
field_data = (transaction.data >> int(field["bit_offset"])) & (
(1 << int(field["bit_width"])) - 1
)
data = f"{hex(field_data)}({bin(field_data)})"
# Now, assemble your table_data with the pre-formatted fields
table_data = [
f"{sim_time}",
f"{the_type}",
f"{Name}",
f"{data}"
]
table = self.format_row(table_data)
with open(self.logger_file_regs_w, "a") as f:
f.write(f"{table}\n")
except KeyError:
pass
def format_row(self, row_data):
# Define a max width for each column
trimmed_col_width = self.col_widths[: len(row_data)]
for i in range(len(row_data)):
trimmed_col_width[i] = max(trimmed_col_width[i], len(row_data[i]) + 1)
row_header = "+" + "+".join("-" * (w) for w in trimmed_col_width) + "+"
row = (
"|"
+ "|".join(f"{item:{w}}" for item, w in zip(row_data, trimmed_col_width))
+ "|"
)
return row_header + "\n" + row
uvm_component_utils(bus_logger)