[chip dv] Single instance of SW logger interface
The existing code had a unique SW logger interface per SW image running
on the CPU - the boot rom and the test SW.
Both instances are monitoring the same address location in the RAM for
new log messages.
Both are operational from the start of time until the end of the
simulation.
This is problematic because only one SW image can run on the CPU at a
time - CPU first executes the boot rom image and then jumps to the flash
to start executing the SW test image.
Additional logic would have had to be added to ensure that only one of
them is running based on which image the CPU is currently executing.
The easier way to deal with it is to just have a single instance of the
logger instead, which is what this PR does.
Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/dv/sv/sw_logger_if/sw_logger_if.sv b/hw/dv/sv/sw_logger_if/sw_logger_if.sv
index e09c218..f91c783 100644
--- a/hw/dv/sv/sw_logger_if/sw_logger_if.sv
+++ b/hw/dv/sv/sw_logger_if/sw_logger_if.sv
@@ -60,10 +60,9 @@
bit enable = 1'b1;
// types
- // image name and log file for parsing
- string sw_name;
- string sw_log_file;
- string sw_rodata_file;
+ // image name and log file for parsing associated with the sw_name
+ string sw_log_file[string];
+ string sw_rodata_file[string];
// typedef addr / data values
typedef bit [DATA_WIDTH-1:0] addr_data_t;
@@ -100,11 +99,11 @@
// signal indicating all initializations are done (this is set by calling ready() function)
bit _ready;
- // hash of log with addr key
- sw_log_t sw_logs[addr_data_t];
+ // hash of log with sw_name and addr keys
+ sw_log_t sw_logs[string][addr_data_t];
- // hash of rodata with addr key
- string sw_rodata[addr_data_t];
+ // hash of rodata with sw_name and addr keys
+ string sw_rodata[string][addr_data_t];
// q of values obtained from the bus
addr_data_t addr_data_q[$];
@@ -116,11 +115,10 @@
// Set the sw_name, The logger assumes that there are two files placed in the rundir -
// <sw_name>_logs.txt: contains logs split as fields of `sw_log_t`
// <sw_name>_rodata.txt: contains constants from the read-only sections.
- function automatic void set_sw_name(string _sw_name);
+ function automatic void set_sw_name(string sw_name);
if (_ready) log_fatal(.log("this function cannot be called after calling ready()"));
- sw_name = _sw_name;
- sw_log_file = {sw_name, "_logs.txt"};
- sw_rodata_file = {sw_name, "_rodata.txt"};
+ sw_log_file[sw_name] = {sw_name, "_logs.txt"};
+ sw_rodata_file[sw_name] = {sw_name, "_rodata.txt"};
endfunction
// signal to indicate that this monitor is good to go - all initializations are done
@@ -134,7 +132,6 @@
initial begin
wait(_ready);
if (parse_sw_log_file()) begin
- void'(parse_sw_rodata_file());
fork
get_addr_data_from_bus();
construct_log_and_print();
@@ -148,64 +145,73 @@
// function that parses the log data file
// returns 1 if log data is avaiable, else false
function automatic bit parse_sw_log_file();
- int fd;
- fd = $fopen(sw_log_file, "r");
- if (!fd) return 0;
+ bit result;
- while (!$feof(fd)) begin
- string field;
- addr_data_t addr;
- sw_log_t sw_log;
- bit status;
+ // Iterate over the available sw names.
+ foreach (sw_log_file[sw]) begin
+ int fd;
+ fd = $fopen(sw_log_file[sw], "r");
+ if (!fd) continue;
- sw_log.name = sw_name;
- status = get_sw_log_field(fd, "addr", field);
- // We proceed to retrieving other fields only if we get the addr.
- if (!status) break;
- addr = field.atohex();
- void'(get_sw_log_field(fd, "severity", field));
- sw_log.severity = log_severity_e'(field.atoi());
- void'(get_sw_log_field(fd, "file", field));
- sw_log.file = field;
- void'(get_sw_log_field(fd, "line", field));
- sw_log.line = field.atoi();
- void'(get_sw_log_field(fd, "nargs", field));
- sw_log.nargs = field.atoi();
- sw_log.arg = new[sw_log.nargs];
- void'(get_sw_log_field(fd, "format", field));
- sw_log.format = field;
- void'(get_sw_log_field(fd, "str_arg_idx", field));
+ while (!$feof(fd)) begin
+ string field;
+ addr_data_t addr;
+ sw_log_t sw_log;
+ bit status;
- begin
- int indices[$];
- get_str_arg_indices(field, indices);
- foreach (indices[i]) begin
- sw_log.str_arg[indices[i]] = "";
+ sw_log.name = sw;
+ status = get_sw_log_field(fd, "addr", field);
+ // We proceed to retrieving other fields only if we get the addr.
+ if (!status) break;
+ addr = field.atohex();
+ void'(get_sw_log_field(fd, "severity", field));
+ sw_log.severity = log_severity_e'(field.atoi());
+ void'(get_sw_log_field(fd, "file", field));
+ sw_log.file = field;
+ void'(get_sw_log_field(fd, "line", field));
+ sw_log.line = field.atoi();
+ void'(get_sw_log_field(fd, "nargs", field));
+ sw_log.nargs = field.atoi();
+ sw_log.arg = new[sw_log.nargs];
+ void'(get_sw_log_field(fd, "format", field));
+ // Replace CRs in the middle of the string with NLs.
+ sw_log.format = replace_cr_with_nl(field);
+ void'(get_sw_log_field(fd, "str_arg_idx", field));
+
+ begin
+ int indices[$];
+ get_str_arg_indices(field, indices);
+ foreach (indices[i]) begin
+ sw_log.str_arg[indices[i]] = "";
+ end
end
- end
- if (sw_logs.exists(addr)) begin
- log_warning($sformatf("Log entry for addr %0x already exists:\nOld: %p\nNew: %p",
- addr, sw_logs[addr], sw_log));
+ if (sw_logs.exists(sw) && sw_logs[sw].exists(addr)) begin
+ log_warning($sformatf("Log entry for addr %0x already exists:\nOld: %p\nNew: %p",
+ addr, sw_logs[sw][addr], sw_log));
+ end
+ sw_logs[sw][addr] = sw_log;
end
- sw_logs[addr] = sw_log;
+ $fclose(fd);
+
+ if (sw_logs.exists(sw) && sw_logs[sw].size() > 0) begin
+ void'(parse_sw_rodata_file(sw));
+ result = 1'b1;
+ end
end
- $fclose(fd);
// print parsed logs
- foreach (sw_logs[addr]) begin
- // Replace CRs in the middle of the string with NLs.
- sw_logs[addr].format = replace_cr_with_nl(sw_logs[addr].format);
+ foreach (sw_logs[sw, addr]) begin
log_info(.verbosity(LogVerbosityHigh),
- .log($sformatf("sw_logs[%0h] = %p", addr, sw_logs[addr])));
+ .log($sformatf("sw_logs[%0s][%0h] = %p", sw, addr, sw_logs[sw][addr])));
end
- return (sw_logs.size() > 0);
+ return result;
endfunction
- function automatic bit parse_sw_rodata_file();
+ function automatic bit parse_sw_rodata_file(string sw);
int fd;
- fd = $fopen(sw_rodata_file, "r");
+ fd = $fopen(sw_rodata_file[sw], "r");
if (!fd) return 0;
while (!$feof(fd)) begin
@@ -219,23 +225,22 @@
addr = field.atohex();
void'(get_sw_log_field(fd, "string", field));
- if (sw_rodata.exists(addr)) begin
+ if (sw_rodata.exists(sw) && sw_rodata[sw].exists(addr)) begin
log_warning($sformatf("Rodata entry for addr %0x already exists:\nOld: %s\nNew: %s",
- addr, sw_rodata[addr], field));
+ addr, sw_rodata[sw][addr], field));
end
- sw_rodata[addr] = field;
+ // Replace CRs in the middle of the string with NLs.
+ sw_rodata[sw][addr] = replace_cr_with_nl(field);
end
$fclose(fd);
- // print parsed logs
- foreach (sw_rodata[addr]) begin
- // Replace CRs in the middle of the string with NLs.
- sw_rodata[addr] = replace_cr_with_nl(sw_rodata[addr]);
+ // print parsed rodata
+ foreach (sw_rodata[sw, addr]) begin
log_info(.verbosity(LogVerbosityHigh),
- .log($sformatf("sw_rodata[%0h] = %p", addr, sw_rodata[addr])));
+ .log($sformatf("sw_rodata[%0s][%0h] = %p", sw, addr, sw_rodata[sw][addr])));
end
- return (sw_rodata.size() > 0);
+ return (sw_rodata[sw].size() > 0);
endfunction
// Get the sw log fields by parsing line-by-line.
@@ -306,13 +311,13 @@
endfunction
// Retrieve the string at the specified addr.
- function automatic string get_str_at_addr(addr_data_t addr);
- if (sw_rodata.exists(addr)) return sw_rodata[addr];
+ function automatic string get_str_at_addr(string sw, addr_data_t addr);
+ if (sw_rodata[sw].exists(addr)) return sw_rodata[sw][addr];
// The string could start midway from an existing addr entry.
- foreach (sw_rodata[str_addr]) begin
- addr_data_t limit = sw_rodata[str_addr].len() - 1;
+ foreach (sw_rodata[sw][str_addr]) begin
+ addr_data_t limit = sw_rodata[sw][str_addr].len() - 1;
if (addr inside {[str_addr : str_addr + limit]}) begin
- return sw_rodata[str_addr].substr(addr - str_addr, limit);
+ return sw_rodata[sw][str_addr].substr(addr - str_addr, limit);
end
end
// If no string was found at the provided addr, then return the addr converted to string.
@@ -342,36 +347,38 @@
addr = addr_data_q.pop_front();
// lookup addr in sw_logs
- if (sw_logs.exists(addr)) begin
- bit rst_occurred;
- fork
- begin
- fork
- // get args
- for (int i = 0; i < sw_logs[addr].nargs; i++) begin
- wait(addr_data_q.size() > 0);
- sw_logs[addr].arg[i] = addr_data_q.pop_front();
- // Check if this is an str arg
- if (sw_logs[addr].str_arg.exists(i)) begin
- // The arg[i] received is the addr in rodata where the string resides.
- sw_logs[addr].str_arg[i] = get_str_at_addr(sw_logs[addr].arg[i]);
- log_info(.verbosity(LogVerbosityDebug),
- .log($sformatf("String arg at addr %0h: %0s",
- sw_logs[addr].arg[i],
- sw_logs[addr].str_arg[i])));
+ foreach (sw_logs[sw]) begin
+ if (sw_logs[sw].exists(addr)) begin
+ bit rst_occurred;
+ fork
+ begin
+ fork
+ // get args
+ for (int i = 0; i < sw_logs[sw][addr].nargs; i++) begin
+ wait(addr_data_q.size() > 0);
+ sw_logs[sw][addr].arg[i] = addr_data_q.pop_front();
+ // Check if this is an str arg
+ if (sw_logs[sw][addr].str_arg.exists(i)) begin
+ // The arg[i] received is the addr in rodata where the string resides.
+ sw_logs[sw][addr].str_arg[i] = get_str_at_addr(sw, sw_logs[sw][addr].arg[i]);
+ log_info(.verbosity(LogVerbosityDebug),
+ .log($sformatf("String arg at addr %0h: %0s",
+ sw_logs[sw][addr].arg[i],
+ sw_logs[sw][addr].str_arg[i])));
+ end
end
- end
- begin
- // check if rst_n occurred - in that case discard and start over
- wait(rst_n === 1'b0);
- rst_occurred = 1'b1;
- end
- join_any
- disable fork;
- end
- join
- if (rst_occurred) continue;
- print_sw_log(sw_logs[addr]);
+ begin
+ // check if rst_n occurred - in that case discard and start over
+ wait(rst_n === 1'b0);
+ rst_occurred = 1'b1;
+ end
+ join_any
+ disable fork;
+ end
+ join
+ if (rst_occurred) continue;
+ print_sw_log(sw_logs[sw][addr]);
+ end
end
end
endtask
@@ -428,7 +435,7 @@
log_verbosity_e verbosity = LogVerbosityLow,
string log);
sw_log_t self_log;
- self_log.name = $sformatf("sw_logger_if[%0s]", sw_name);
+ self_log.name = "sw_logger_if";
self_log.severity = severity;
self_log.verbosity = verbosity;
self_log.file = "";
diff --git a/hw/top_earlgrey/dv/env/chip_env.sv b/hw/top_earlgrey/dv/env/chip_env.sv
index 5aae5d6..6b5ab3d 100644
--- a/hw/top_earlgrey/dv/env/chip_env.sv
+++ b/hw/top_earlgrey/dv/env/chip_env.sv
@@ -51,13 +51,8 @@
end
// get the handle to the sw log monitor for available sw_types
- foreach (cfg.sw_types[i]) begin
- if (!uvm_config_db#(sw_logger_vif)::get(this, "",
- $sformatf("sw_logger_vif[%0s]", cfg.sw_types[i]),
- cfg.sw_logger_vif[cfg.sw_types[i]])) begin
- `uvm_fatal(`gfn, $sformatf("failed to get sw_logger_vif[%0s] from uvm_config_db",
- cfg.sw_types[i]))
- end
+ if (!uvm_config_db#(sw_logger_vif)::get(this, "", "sw_logger_vif", cfg.sw_logger_vif)) begin
+ `uvm_fatal(`gfn, "failed to get sw_logger_vif from uvm_config_db")
end
if (!uvm_config_db#(virtual sw_test_status_if)::get(this, "", "sw_test_status_vif",
diff --git a/hw/top_earlgrey/dv/env/chip_env_cfg.sv b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
index 3d79a33..26098aa 100644
--- a/hw/top_earlgrey/dv/env/chip_env_cfg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
@@ -19,7 +19,7 @@
// sw logger related
string sw_types[] = '{"rom", "sw"};
- sw_logger_vif sw_logger_vif[string];
+ sw_logger_vif sw_logger_vif;
string sw_images[string];
virtual sw_test_status_if sw_test_status_vif;
uint sw_test_timeout_ns = 5_000_000; // 5ms
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_test_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_test_base_vseq.sv
index d2cff0f..cd067c7 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_test_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_test_base_vseq.sv
@@ -23,12 +23,12 @@
cfg.m_uart_agent_cfg.set_parity(1'b0, 1'b0);
cfg.m_uart_agent_cfg.set_baud_rate(BaudRate2Mbps);
- // initialize the sw msg monitor
+ // initialize the sw logger interface
foreach (cfg.sw_types[i]) begin
- cfg.sw_logger_vif[cfg.sw_types[i]].sw_log_addr = SW_DV_LOG_ADDR;
- cfg.sw_logger_vif[cfg.sw_types[i]].set_sw_name(cfg.sw_types[i]);
- cfg.sw_logger_vif[cfg.sw_types[i]].ready();
+ cfg.sw_logger_vif.set_sw_name(cfg.sw_types[i]);
end
+ cfg.sw_logger_vif.sw_log_addr = SW_DV_LOG_ADDR;
+ cfg.sw_logger_vif.ready();
// initialize the sw test status
cfg.sw_test_status_vif.sw_test_status_addr = SW_DV_TEST_STATUS_ADDR;
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index 8c32271..4e8daff 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -108,30 +108,20 @@
);
// connect sw_logger_if
- parameter string SwTypes[] = '{"rom", "sw"};
- generate
- for (genvar i = 0; i < 2; i++) begin: sw_logger_if_i
- bit sw_log_valid;
- bit [TL_AW-1:0] sw_log_addr;
+ bit sw_log_valid;
+ bit [TL_AW-1:0] sw_log_addr;
- sw_logger_if sw_logger_if (
- .clk (`RAM_MAIN_HIER.clk_i),
- .rst_n (`RAM_MAIN_HIER.rst_ni),
- .valid (sw_log_valid),
- .addr_data (`RAM_MAIN_HIER.wdata_i),
- .sw_log_addr (sw_log_addr)
- );
- // TODO: RAM only looks at addr[15:2] - need to find a better way to capture it.
- assign sw_log_valid = !stub_cpu &&
- `RAM_MAIN_HIER.req_i && `RAM_MAIN_HIER.write_i &&
- (`RAM_MAIN_HIER.addr_i == sw_log_addr[15:2]);
-
- initial begin
- uvm_config_db#(virtual sw_logger_if)::set(
- null, "*.env", $sformatf("sw_logger_vif[%0s]", SwTypes[i]), sw_logger_if);
- end
- end
- endgenerate
+ sw_logger_if sw_logger_if (
+ .clk (`RAM_MAIN_HIER.clk_i),
+ .rst_n (`RAM_MAIN_HIER.rst_ni),
+ .valid (sw_log_valid),
+ .addr_data (`RAM_MAIN_HIER.wdata_i),
+ .sw_log_addr (sw_log_addr)
+ );
+ assign sw_log_valid = !stub_cpu &&
+ `RAM_MAIN_HIER.req_i && `RAM_MAIN_HIER.write_i &&
+ /* RAM only looks at the 14-bit word address 15:2 */
+ (`RAM_MAIN_HIER.addr_i == sw_log_addr[15:2]);
// connect the sw_test_status_if
sw_test_status_if sw_test_status_if();
@@ -204,6 +194,9 @@
null, "*.env", "mem_bkdr_vifs[FlashBank0]", `FLASH0_MEM_HIER.flash0_mem_bkdr_if);
uvm_config_db#(virtual mem_bkdr_if)::set(
null, "*.env", "mem_bkdr_vifs[FlashBank1]", `FLASH1_MEM_HIER.flash1_mem_bkdr_if);
+
+ // SW logger and test status interfaces.
+ uvm_config_db#(virtual sw_logger_if)::set(null, "*.env", "sw_logger_vif", sw_logger_if);
uvm_config_db#(virtual sw_test_status_if)::set(
null, "*.env", "sw_test_status_vif", sw_test_status_if);