[dv,sw] C messaging flow: part 2 (SV side)
- added sw_msg_monitor_if interface that detects writes to special address
in RAM
- interface is written in pure SV code and is likely to work with Verilator efforts as
well
- interface allows passage of handle to the dynamic side for runtime
manipulation
diff --git a/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.core b/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.core
new file mode 100644
index 0000000..462ef46
--- /dev/null
+++ b/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.core
@@ -0,0 +1,17 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:sw_msg_monitor_if"
+description: "SW msg monitor interface (convert SW msg prints into SV)"
+
+filesets:
+ files_dv:
+ files:
+ - sw_msg_monitor_if.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.sv b/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.sv
new file mode 100644
index 0000000..23de18f
--- /dev/null
+++ b/hw/dv/sv/sw_msg_monitor_if/sw_msg_monitor_if.sv
@@ -0,0 +1,508 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// shortcuts for use in switching # of args to insert in formatted string
+`define _0_ARGS(a)
+`define _1_ARGS(a) , a[0]
+`define _2_ARGS(a) `_1_ARGS(a), a[1]
+`define _3_ARGS(a) `_2_ARGS(a), a[2]
+`define _4_ARGS(a) `_3_ARGS(a), a[3]
+`define _5_ARGS(a) `_4_ARGS(a), a[4]
+`define _6_ARGS(a) `_5_ARGS(a), a[5]
+`define _7_ARGS(a) `_6_ARGS(a), a[6]
+`define _8_ARGS(a) `_7_ARGS(a), a[7]
+`define _9_ARGS(a) `_8_ARGS(a), a[8]
+`define _10_ARGS(a) `_9_ARGS(a), a[9]
+`define _11_ARGS(a) `_10_ARGS(a), a[10]
+`define _12_ARGS(a) `_11_ARGS(a), a[11]
+`define _13_ARGS(a) `_12_ARGS(a), a[12]
+`define _14_ARGS(a) `_13_ARGS(a), a[13]
+`define _15_ARGS(a) `_14_ARGS(a), a[14]
+`define _16_ARGS(a) `_15_ARGS(a), a[15]
+`define _17_ARGS(a) `_16_ARGS(a), a[16]
+`define _18_ARGS(a) `_17_ARGS(a), a[17]
+`define _19_ARGS(a) `_18_ARGS(a), a[18]
+`define _20_ARGS(a) `_19_ARGS(a), a[19]
+`define _21_ARGS(a) `_20_ARGS(a), a[20]
+`define _22_ARGS(a) `_21_ARGS(a), a[21]
+`define _23_ARGS(a) `_22_ARGS(a), a[22]
+`define _24_ARGS(a) `_23_ARGS(a), a[23]
+`define _25_ARGS(a) `_24_ARGS(a), a[24]
+`define _26_ARGS(a) `_25_ARGS(a), a[25]
+`define _27_ARGS(a) `_26_ARGS(a), a[26]
+`define _28_ARGS(a) `_27_ARGS(a), a[27]
+`define _29_ARGS(a) `_28_ARGS(a), a[28]
+`define _30_ARGS(a) `_29_ARGS(a), a[29]
+`define _31_ARGS(a) `_30_ARGS(a), a[30]
+`define _32_ARGS(a) `_31_ARGS(a), a[31]
+`define _ADD_ARGS(a, n) `_``n``_ARGS(a)
+`define NARGS_CASE(n) n: msg = $sformatf(msg `_ADD_ARGS(sw_msg.arg, n));
+
+interface sw_msg_monitor_if #(
+ // width of the data bus
+ parameter int unsigned DATA_WIDTH = 32
+) (
+ input logic clk, // clock
+ input logic rst_n, // active low reset
+ input logic valid, // qualification for addr_data
+ input logic [DATA_WIDTH-1:0] addr_data, // addr/data written to sw_msg_addr
+ output logic [DATA_WIDTH-1:0] sw_msg_addr // used by external logic to qualify valid
+);
+
+ // types
+ // struct to hold sw msg data file and name
+ typedef struct {
+ string name;
+ string file;
+ } sw_msg_data_file_t;
+
+ // typedef addr / data values
+ typedef bit [DATA_WIDTH-1:0] addr_data_t;
+
+ // struct to hold the complete msg data
+ typedef struct {
+ string msg_type; // info, warning, error or fatal
+ string verbosity; // none, low, medium, high, full, debug
+ string name; // sw name
+ string file; // name of C file
+ int line; // line no
+ string header; // custom header (else its [name](file:line))
+ int nargs; // no of args
+ addr_data_t arg[]; // actual arg values
+ string format; // formatted string
+ } sw_msg_t;
+
+ // index of elements parsed from each line of msg data file
+ typedef enum {
+ AddrIndex,
+ MsgTypeIndex,
+ VerbosityIndex,
+ FileIndex,
+ LineIndex,
+ NArgsIndex,
+ FormatIndex,
+ ArgsIndex
+ } sw_msg_fields_index_e;
+
+ // msg scheme
+ typedef enum {
+ MsgSchemeNone, // addr\msg (msg might contain additional metadata)
+ MsgSchmeCustomHeader, // addr\header\nargs\format
+ MsgSchemeDv // addr\msg_type\verbosity\file\line\nargs\format
+ } msg_scheme_e;
+
+ // signal indicating all initializations are done (this is set by calling ready() function)
+ bit _ready;
+
+ // single char string delimiter used to segregate the msg data fields
+ // by default, this is set to '\' which is 5c in hex
+ byte delimiter = 8'h5c;
+ string delimiter_str = "";
+
+ // q of input file sources
+ sw_msg_data_file_t sw_msg_data_files[$];
+
+ // hash of msg with addr key
+ sw_msg_t sw_msgs[addr_data_t];
+
+ // q of values obtained from the bus
+ addr_data_t addr_data_q[$];
+
+ /****************************/
+ /* Initialization functions */
+ /****************************/
+ // function to set the delimiter value
+ function automatic void set_delimiter(byte value);
+ if (_ready) msg_fatal(.msg("this function cannot be called after calling ready()"));
+ delimiter = value;
+ // update the string version
+ // if delimiter is '\' (8'h5c) then the string version
+ // needs to be empty since SV treats '\' as null
+ delimiter_str.putc(0, delimiter);
+ delimiter_str = (delimiter == 8'h5c) ? "" : delimiter_str;
+ endfunction
+
+ // function to add the msg dat files
+ function automatic void add_sw_msg_data_files(string img_name, string img_file);
+ if (_ready) msg_fatal(.msg("this function cannot be called after calling ready()"));
+ sw_msg_data_files.push_back({name:img_name, file:img_file});
+ endfunction
+
+ // signal to indicate all monitor is good to go - all initializations are done
+ function automatic void ready();
+ _ready = 1'b1;
+ endfunction
+
+ /********************/
+ /* Monitoring logic */
+ /********************/
+ initial begin
+ wait(_ready);
+ if (parse_sw_msg_data_files()) begin
+ fork
+ get_addr_data_from_bus();
+ construct_msg_and_print();
+ join_none
+ end
+ end
+
+ /******************/
+ /* helper methods */
+ /******************/
+ // function that parses the msg data file
+ // returns 1 if msg data is avaiable, else false
+ function automatic bit parse_sw_msg_data_files();
+ foreach (sw_msg_data_files[i]) begin
+ int fd;
+ fd = $fopen(sw_msg_data_files[i].file, "r");
+ if (!fd) continue;
+ else begin
+ addr_data_t addr;
+
+ while (!$feof(fd)) begin
+ string line;
+ string fields[$];
+ int merge_fields_idx_start = 0;
+ int merge_fields_idx_end = 0;
+ msg_scheme_e scheme;
+
+ // read line and split into fields based on delimiter
+ void'($fgets(line, fd));
+ if (line inside {"", "\n", "\r"}) continue;
+ split_msg_data_line_to_fields(line, fields);
+
+ // print fields for debug
+ foreach (fields[i]) begin
+ msg_info(.verbosity("d"), .msg($sformatf("fields[%0d] = %0s", i, fields[i])));
+ end
+
+ // get addr (first field)
+ addr = fields[AddrIndex].atohex();
+ if (sw_msgs.exists(addr)) begin
+ msg_warning(.msg($sformatf("msg entry for addr %0x already exists:\n%p",
+ addr, sw_msgs[addr])));
+ end
+
+ // detect msg scheme based on fields size and values
+ // if > 7 fields AND fields[MsgTypeIndex] is either "i", "w", "e" or "f"
+ // then its DV scheme, otherwise it is something else
+ if (fields.size() >= 7) scheme = MsgSchemeDv;
+ // Note: If user adds null termination in the msg that is not supported
+ if (fields[MsgTypeIndex].tolower() inside {"i", "info"}) begin
+ sw_msgs[addr].msg_type = "i";
+ end else if (fields[MsgTypeIndex].tolower() inside {"w", "warn", "warning"}) begin
+ sw_msgs[addr].msg_type = "w";
+ end else if (fields[MsgTypeIndex].tolower() inside {"e", "err", "error"}) begin
+ sw_msgs[addr].msg_type = "e";
+ end else if (fields[MsgTypeIndex].tolower() inside {"f", "fatal"}) begin
+ sw_msgs[addr].msg_type = "f";
+ end else begin
+ // if fields size >= 4, its a msg with custom header
+ // if fields size < 4, there no scheme detected
+ if (fields.size() >= 4) scheme = MsgSchmeCustomHeader;
+ else scheme = MsgSchemeNone;
+ end
+
+ case (scheme)
+ MsgSchemeNone: begin
+ sw_msgs[addr].msg_type = "i";
+ sw_msgs[addr].verbosity = "n";
+ sw_msgs[addr].file = "";
+ sw_msgs[addr].line = 0;
+ sw_msgs[addr].nargs = 0;
+ sw_msgs[addr].format = fields[1];
+ sw_msgs[addr].name = sw_msg_data_files[i].name;
+ merge_fields_idx_start = 2;
+ end
+ MsgSchmeCustomHeader: begin
+ sw_msgs[addr].verbosity = "n";
+ sw_msgs[addr].file = "";
+ sw_msgs[addr].line = 0;
+ sw_msgs[addr].header = fields[1];
+ sw_msgs[addr].nargs = fields[2].atoi();
+ sw_msgs[addr].arg = new[sw_msgs[addr].nargs];
+ sw_msgs[addr].format = fields[3];
+ sw_msgs[addr].name = sw_msg_data_files[i].name;
+ merge_fields_idx_start = 4;
+ end
+ MsgSchemeDv: begin
+ // 7 entries: addr, type, verbosity, file, line, nargs, format
+ sw_msgs[addr].verbosity = fields[VerbosityIndex];
+ sw_msgs[addr].file = fields[FileIndex];
+ sw_msgs[addr].line = fields[LineIndex].atoi();
+ sw_msgs[addr].nargs = fields[NArgsIndex].atoi();
+ sw_msgs[addr].arg = new[sw_msgs[addr].nargs];
+ sw_msgs[addr].format = fields[FormatIndex];
+ sw_msgs[addr].name = sw_msg_data_files[i].name;
+ merge_fields_idx_start = 7;
+ end
+ endcase
+ // its possible that user might have added the delimiter in the msg itself
+ // in that case append the remaining ones back into formatted string
+ for (int i = merge_fields_idx_start; i < fields.size(); i++) begin
+ sw_msgs[addr].format = {sw_msgs[addr].format, delimiter_str, fields[i]};
+ end
+ end
+
+ // cleanup the format of all msgs
+ cleanup_format();
+
+ // print parsed msgs
+ foreach (sw_msgs[addr]) begin
+ msg_info(.verbosity("h"), .msg($sformatf("sw_msgs[%0h] = %p", addr, sw_msgs[addr])));
+ end
+ end
+ $fclose(fd);
+ end
+ return (sw_msgs.size() > 0);
+ endfunction
+
+ // split string using single character delimiter (as byte)
+ function automatic void split_msg_data_line_to_fields(input string str,
+ output string split[$]);
+ int start = 0;
+ for (int i = 0; i < str.len(); i++) begin
+ if (str.getc(i) == delimiter) begin
+ split.push_back(str.substr(start, i - 1));
+ start = i + 1;
+ end
+ end
+ // last one
+ split.push_back(str.substr(start, str.len() - 1));
+ endfunction
+
+ // function to cleanup the string formatting
+ function automatic void cleanup_format();
+ foreach (sw_msgs[addr]) begin
+ string str = sw_msgs[addr].format;
+ if (str.len() >= 2) begin
+ // replace ^M with \n and ^J also with \n (CR is not supported in SV)
+ for (int i = 0; i < str.len() - 1; i++) begin
+ if (str.getc(i) == "^" && str.getc(i + 1) inside {"M", "J"}) begin
+ str = {str.substr(0, i - 1), "\n", str.substr(i + 2, str.len() - 1)};
+ i++;
+ end
+ // replace %x, %d, %h with %0x, %0d and %0h
+ if (str.getc(i) == "%" && str.getc(i + 1) inside {"x", "h", "d"}) begin
+ str = {str.substr(0, i), "0", str.substr(i + 1, str.len() - 1)};
+ i += 2;
+ end
+ end
+ end
+ // remove the last \n added by $fgets
+ if (str.getc(str.len() - 1) == "\n") begin
+ str = str.substr(0, str.len() - 2);
+ end
+ // remove the last \n added in the print msg
+ if (str.getc(str.len() - 1) == "\n") begin
+ str = str.substr(0, str.len() - 2);
+ end
+ sw_msgs[addr].format = str;
+ end
+ endfunction
+
+ // retrieve addr or data from the bus
+ task automatic get_addr_data_from_bus();
+ forever begin
+ @(posedge clk);
+ if (valid === 1'b1 && rst_n !== 0) begin
+ addr_data_q.push_back(addr_data);
+ end
+ end
+ endtask
+
+ //construct msg and print when complete data is available
+ task automatic construct_msg_and_print();
+ forever begin
+ addr_data_t addr;
+ // get addr
+ wait(addr_data_q.size() > 0);
+ addr = addr_data_q.pop_front();
+
+ // lookup addr in sw_msgs
+ if (sw_msgs.exists(addr)) begin
+ bit rst_occurred;
+ fork
+ begin
+ fork
+ // get args
+ for (int i = 0; i < sw_msgs[addr].nargs; i++) begin
+ wait(addr_data_q.size() > 0);
+ sw_msgs[addr].arg[i] = addr_data_q.pop_front();
+ 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;
+ sw_msg_print(sw_msgs[addr]);
+ end
+ end
+ endtask
+
+ // print the msg
+ function automatic void sw_msg_print(sw_msg_t sw_msg);
+ string msg_header = sw_msg.header;
+ string msg = sw_msg.format;
+
+ // if header not available, then construct from other fields: name(file:line)
+ if (msg_header == "") begin
+ msg_header = sw_msg.name;
+ if (sw_msg.file != "") begin
+ msg_header = {msg_header, "(", sw_msg.file, ":", $sformatf("%0d", sw_msg.line), ")"};
+ end
+ end
+
+ // construct formatted string based on args
+ case (sw_msg.nargs)
+ `NARGS_CASE(0)
+ `NARGS_CASE(1)
+ `NARGS_CASE(2)
+ `NARGS_CASE(3)
+ `NARGS_CASE(4)
+ `NARGS_CASE(5)
+ `NARGS_CASE(6)
+ `NARGS_CASE(7)
+ `NARGS_CASE(8)
+ `NARGS_CASE(9)
+ `NARGS_CASE(10)
+ `NARGS_CASE(11)
+ `NARGS_CASE(12)
+ `NARGS_CASE(13)
+ `NARGS_CASE(14)
+ `NARGS_CASE(15)
+ `NARGS_CASE(16)
+ `NARGS_CASE(17)
+ `NARGS_CASE(18)
+ `NARGS_CASE(19)
+ `NARGS_CASE(20)
+ `NARGS_CASE(21)
+ `NARGS_CASE(22)
+ `NARGS_CASE(23)
+ `NARGS_CASE(24)
+ `NARGS_CASE(25)
+ `NARGS_CASE(26)
+ `NARGS_CASE(27)
+ `NARGS_CASE(28)
+ `NARGS_CASE(29)
+ `NARGS_CASE(30)
+ `NARGS_CASE(31)
+ `NARGS_CASE(32)
+ default: msg_fatal("UNSUPPORTED", $sformatf("nargs = %0d (only 0:32 allowed)", sw_msg.nargs));
+ endcase
+
+ // print the msg
+ msg_print(sw_msg.msg_type, sw_msg.verbosity, msg_header, msg);
+ endfunction
+
+ // methods
+ // msg_print api that switches between system call and UVM call
+ function automatic void msg_print(string msg_type = "i",
+ string verbosity = "n",
+ string msg_header = "",
+ string msg);
+`ifdef UVM_PKG_SV
+ import uvm_pkg::*;
+ `include "uvm_macros.svh"
+
+ uvm_verbosity level;
+ case (verbosity)
+ "n", "none": level = UVM_NONE;
+ "l", "lo", "low": level = UVM_LOW;
+ "m", "med", "medium": level = UVM_MEDIUM;
+ "h", "hi", "high": level = UVM_HIGH;
+ "f", "full": level = UVM_FULL;
+ "d", "dbg", "debug": level = UVM_DEBUG;
+ default: level = UVM_NONE;
+ endcase
+
+ // additional cleanup: if msg_header is already enclosed in [],
+ // then remove it, since uvm macros also add them
+ if (msg_header.len() >= 2) begin
+ if (msg_header[0] == "[" && msg_header[msg_header.len() - 1] == "]") begin
+ msg_header = msg_header.substr(1, msg_header.len() - 2);
+ end
+ end
+
+ case (msg_type.tolower())
+ "i", "info": `uvm_info(msg_header, msg, level)
+ "w", "warn", "warning": `uvm_warning(msg_header, msg)
+ "e", "err", "error": `uvm_error(msg_header, msg)
+ "f", "fatal": `uvm_fatal(msg_header, msg)
+ default: `uvm_info(msg_header, msg, level)
+ endcase
+`else
+ case (msg_type.tolower())
+ "i", "info": $info("%0t: %0s %0s", $time, msg_header, msg);
+ "w", "warn", "warning": $warning("%0t: %0s %0s", $time, msg_header, msg);
+ "e", "err", "error": $error("%0t: %0s %0s", $time, msg_header, msg);
+ "f", "fatal": $fatal("%0t: %0s %0s", $time, msg_header, msg);
+ default: $info("%0t: %0s %0s", $time, msg_header, msg);
+ endcase
+`endif
+ endfunction
+
+ // print info msg
+ function automatic void msg_info(string verbosity = "l", string msg_header = "", string msg);
+ msg_print(.verbosity(verbosity), .msg_header(msg_header), .msg(msg));
+ endfunction
+
+ // print warning msg
+ function automatic void msg_warning(string msg_header = "", string msg);
+ msg_print(.msg_type("w"), .msg_header(msg_header), .msg(msg));
+ endfunction
+
+ // print error msg
+ function automatic void msg_error(string msg_header = "", string msg);
+ msg_print(.msg_type("e"), .msg_header(msg_header), .msg(msg));
+ endfunction
+
+ // print fatal msg
+ function automatic void msg_fatal(string msg_header = "", string msg);
+ msg_print(.msg_type("f"), .msg_header(msg_header), .msg(msg));
+ endfunction
+
+endinterface
+
+// undefine previously defined macros
+`undef _0_ARGS
+`undef _1_ARGS
+`undef _2_ARGS
+`undef _3_ARGS
+`undef _4_ARGS
+`undef _5_ARGS
+`undef _6_ARGS
+`undef _7_ARGS
+`undef _8_ARGS
+`undef _9_ARGS
+`undef _10_ARGS
+`undef _11_ARGS
+`undef _12_ARGS
+`undef _13_ARGS
+`undef _14_ARGS
+`undef _15_ARGS
+`undef _16_ARGS
+`undef _17_ARGS
+`undef _18_ARGS
+`undef _19_ARGS
+`undef _20_ARGS
+`undef _21_ARGS
+`undef _22_ARGS
+`undef _23_ARGS
+`undef _24_ARGS
+`undef _25_ARGS
+`undef _26_ARGS
+`undef _27_ARGS
+`undef _28_ARGS
+`undef _29_ARGS
+`undef _30_ARGS
+`undef _31_ARGS
+`undef _32_ARGS
+`undef _ADD_ARGS
+`undef NARGS_CASE
diff --git a/hw/top_earlgrey/dv/env/chip_env.core b/hw/top_earlgrey/dv/env/chip_env.core
index 6c3eb2a..2c8f3b4 100644
--- a/hw/top_earlgrey/dv/env/chip_env.core
+++ b/hw/top_earlgrey/dv/env/chip_env.core
@@ -16,6 +16,7 @@
- lowrisc:dv:hmac_env
- lowrisc:dv:rv_timer_env
- lowrisc:dv:spi_device_env
+ - lowrisc:dv:sw_msg_monitor_if
files:
- chip_env_pkg.sv
- chip_env_cfg.sv: {is_include_file: true}
diff --git a/hw/top_earlgrey/dv/env/chip_env.sv b/hw/top_earlgrey/dv/env/chip_env.sv
index cd4f090..683b647 100644
--- a/hw/top_earlgrey/dv/env/chip_env.sv
+++ b/hw/top_earlgrey/dv/env/chip_env.sv
@@ -43,6 +43,11 @@
end
end
+ if (!uvm_config_db#(sw_msg_monitor_vif)::get(this, "", "sw_msg_monitor_vif",
+ cfg.sw_msg_monitor_vif)) begin
+ `uvm_fatal(`gfn, "failed to get sw_msg_monitor_vif from uvm_config_db")
+ end
+
// create components
m_uart_agent = uart_agent::type_id::create("m_uart_agent", this);
uvm_config_db#(uart_agent_cfg)::set(this, "m_uart_agent*", "cfg", cfg.m_uart_agent_cfg);
diff --git a/hw/top_earlgrey/dv/env/chip_env_cfg.sv b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
index 2fffac5..4f35632 100644
--- a/hw/top_earlgrey/dv/env/chip_env_cfg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_cfg.sv
@@ -8,7 +8,16 @@
// chip top interfaces
gpio_vif gpio_vif;
- virtual mem_bkdr_if mem_bkdr_vifs[chip_mem_e];
+ mem_bkdr_vif mem_bkdr_vifs[chip_mem_e];
+
+ // sw msg monitor related
+ sw_msg_monitor_vif sw_msg_monitor_vif;
+ // below values are constants, but made variables in case some test has different requirements
+ string rom_image = "sw_build/rom/rom.vmem";
+ string rom_msg_data_file = "sw_build/rom/msg_data.txt";
+ string sw_image = "sw_build/sw/sw.vmem";
+ string sw_msg_data_file = "sw_build/sw/msg_data.txt";
+ bit [TL_AW-1:0] sw_msg_addr = 32'h1000fff4;
// ext component cfgs
rand uart_agent_cfg m_uart_agent_cfg;
diff --git a/hw/top_earlgrey/dv/env/chip_env_pkg.sv b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
index 17b532c..47f8e7b 100644
--- a/hw/top_earlgrey/dv/env/chip_env_pkg.sv
+++ b/hw/top_earlgrey/dv/env/chip_env_pkg.sv
@@ -27,11 +27,10 @@
// local parameters and types
parameter NUM_GPIOS = 16;
- parameter string ROM_MEM_IMG = "sw_build/rom/rom.vmem";
- parameter string SW_MEM_IMG = "sw_build/sw/sw.vmem";
typedef virtual pins_if #(NUM_GPIOS) gpio_vif;
typedef virtual mem_bkdr_if mem_bkdr_vif;
+ typedef virtual sw_msg_monitor_if sw_msg_monitor_vif;
// enum to indicate cpu test pass / fail status
typedef enum bit [15:0] {
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
index ab06770..76c411f 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_base_vseq.sv
@@ -46,13 +46,19 @@
// routine to backdoor load cpu test hex image and bring the cpu out of reset (if required)
// TODO(sriyerg): for future implementation
virtual task cpu_init();
- cfg.mem_bkdr_vifs[Rom].load_mem_from_file(ROM_MEM_IMG);
+ cfg.mem_bkdr_vifs[Rom].load_mem_from_file(cfg.rom_image);
cfg.mem_bkdr_vifs[FlashBank0].set_mem();
cfg.mem_bkdr_vifs[FlashBank1].set_mem();
// TODO: the location of the main execution image should be randomized for either bank in future
- cfg.mem_bkdr_vifs[FlashBank0].load_mem_from_file(SW_MEM_IMG);
+ cfg.mem_bkdr_vifs[FlashBank0].load_mem_from_file(cfg.sw_image);
cpu_test_state = CpuTestRunning;
+
+ // initialize the sw msg monitor
+ cfg.sw_msg_monitor_vif.sw_msg_addr = cfg.sw_msg_addr;
+ cfg.sw_msg_monitor_vif.add_sw_msg_data_files("rom", cfg.rom_msg_data_file);
+ cfg.sw_msg_monitor_vif.add_sw_msg_data_files("sw", cfg.sw_msg_data_file);
+ cfg.sw_msg_monitor_vif.ready();
endtask
virtual task dut_shutdown();
@@ -76,7 +82,7 @@
`uvm_info(`gfn, $sformatf("cpu_test_state = %0s", cpu_test_state), UVM_LOW)
case (cpu_test_state)
CpuUnderReset: begin
- wait (cpu_test_state == CpuTestRunning);
+ wait(cpu_test_state == CpuTestRunning);
end
CpuTestRunning: begin
@@ -92,8 +98,8 @@
end
end
- {CpuTestPass, CpuTestFail}: begin
- wait (cpu_test_state == CpuUnderReset);
+ CpuTestPass, CpuTestFail: begin
+ wait(cpu_test_state == CpuUnderReset);
end
endcase
end
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index d358d4c..3aed42e 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -8,6 +8,7 @@
import dv_utils_pkg::*;
import tl_agent_pkg::*;
import chip_env_pkg::*;
+ import top_pkg::*;
// macro includes
`include "uvm_macros.svh"
@@ -68,6 +69,20 @@
.IO_GP15 (gpio_pins[15])
);
+ // connect sw_msg_monitor
+ bit sw_msg_monitor_valid;
+ bit [TL_AW-1:0] sw_msg_monitor_sw_msg_addr;
+
+ sw_msg_monitor_if sw_msg_monitor_if (
+ .clk (`RAM_MAIN_HIER.clk_i),
+ .rst_n (`RAM_MAIN_HIER.rst_ni),
+ .valid (sw_msg_monitor_valid),
+ .addr_data (`RAM_MAIN_HIER.wdata_i),
+ .sw_msg_addr (sw_msg_monitor_sw_msg_addr)
+ );
+ assign sw_msg_monitor_valid = `RAM_MAIN_HIER.req_i && `RAM_MAIN_HIER.write_i &&
+ (`RAM_MAIN_HIER.addr_i == sw_msg_monitor_sw_msg_addr);
+
// connect signals
assign jtag_tck = jtag_if.tck;
assign jtag_tms = jtag_if.tms;
@@ -90,6 +105,8 @@
`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);
+ uvm_config_db#(virtual sw_msg_monitor_if)::set(null, "*.env", "sw_msg_monitor_vif",
+ sw_msg_monitor_if);
$timeformat(-12, 0, " ps", 12);
run_test();
end