[dv/common] add csr field access
Update csr_rd to support partial read (sub-word)
Update csr read/write to include field read
Update all IPs scbs to read csr registers address
diff --git a/hw/dv/sv/csr_utils/csr_seq_lib.sv b/hw/dv/sv/csr_utils/csr_seq_lib.sv
index 0160b6d..92764f1 100644
--- a/hw/dv/sv/csr_utils/csr_seq_lib.sv
+++ b/hw/dv/sv/csr_utils/csr_seq_lib.sv
@@ -205,10 +205,19 @@
`uvm_object_new
+ rand bit do_csr_rd_check;
+ rand bit do_csr_field_rd_check;
+
+ constraint csr_or_field_rd_check_c {
+ // at least one of them should be set
+ do_csr_rd_check || do_csr_field_rd_check;
+ }
+
virtual task body();
foreach (test_csrs[i]) begin
uvm_reg_data_t wdata;
uvm_reg_data_t compare_mask;
+ uvm_reg_field test_fields[$];
// check if parent block or register is excluded from write
if (m_csr_excl_item.is_excl(test_csrs[i], CsrExclWrite)) begin
@@ -220,6 +229,7 @@
`uvm_info(`gtn, $sformatf("Verifying register read/write for %0s",
test_csrs[i].get_full_name()), UVM_MEDIUM)
+ `DV_CHECK_FATAL(randomize(do_csr_rd_check, do_csr_field_rd_check))
`DV_CHECK_STD_RANDOMIZE_FATAL(wdata)
wdata &= get_mask_excl_fields(test_csrs[i], CsrExclWrite);
csr_wr(.csr(test_csrs[i]), .value(wdata), .blocking(0));
@@ -239,11 +249,24 @@
end
compare_mask = get_mask_excl_fields(test_csrs[i], CsrExclWriteCheck);
- csr_rd_check(.ptr (test_csrs[i]),
- .blocking (0),
- .compare (!external_checker),
- .compare_vs_ral(1'b1),
- .compare_mask (compare_mask));
+ if (do_csr_rd_check) begin
+ csr_rd_check(.ptr (test_csrs[i]),
+ .blocking (0),
+ .compare (!external_checker),
+ .compare_vs_ral(1'b1),
+ .compare_mask (compare_mask));
+ end
+ if (do_csr_field_rd_check) begin
+ test_csrs[i].get_fields(test_fields);
+ test_fields.shuffle();
+ foreach (test_fields[j]) begin
+ csr_rd_check(.ptr (test_fields[j]),
+ .blocking (0),
+ .compare (!external_checker),
+ .compare_vs_ral(1'b1),
+ .compare_mask (compare_mask));
+ end
+ end
end
endtask
diff --git a/hw/dv/sv/csr_utils/csr_utils_pkg.sv b/hw/dv/sv/csr_utils/csr_utils_pkg.sv
index 4c9021a..b5cb56e 100644
--- a/hw/dv/sv/csr_utils/csr_utils_pkg.sv
+++ b/hw/dv/sv/csr_utils/csr_utils_pkg.sv
@@ -256,9 +256,10 @@
begin
outstanding_csr_accesses++;
csr_or_fld = decode_csr_or_field(ptr);
- csr_or_fld.csr.read(.status(status), .value(value), .path(path), .map(map));
if (csr_or_fld.field != null) begin
- value = get_field_val(csr_or_fld.field, value);
+ csr_or_fld.field.read(.status(status), .value(value), .path(path), .map(map));
+ end else begin
+ csr_or_fld.csr.read(.status(status), .value(value), .path(path), .map(map));
end
if (check == UVM_CHECK) begin
`DV_CHECK_EQ(status, UVM_IS_OK, "", error, msg_id)
diff --git a/hw/dv/sv/tl_agent/tl_reg_adapter.sv b/hw/dv/sv/tl_agent/tl_reg_adapter.sv
index 0bc0439..5712f86 100644
--- a/hw/dv/sv/tl_agent/tl_reg_adapter.sv
+++ b/hw/dv/sv/tl_agent/tl_reg_adapter.sv
@@ -19,13 +19,43 @@
ITEM_T reg_item;
reg_item = ITEM_T::type_id::create("reg_item");
`DV_CHECK_RANDOMIZE_FATAL(reg_item)
- reg_item.a_addr = rw.addr;
- reg_item.a_size = 2; // 4 bytes
reg_item.a_opcode = (rw.kind == UVM_WRITE) ? tlul_pkg::PutFullData : tlul_pkg::Get;
- reg_item.a_mask = rw.byte_en;
- reg_item.a_data = rw.data;
- `uvm_info(`gtn, $sformatf("tl reg req item: addr=0x%0h, op=%0s data=0x%0h",
- reg_item.a_addr, reg_item.a_opcode.name, reg_item.a_data), UVM_HIGH)
+
+ // tlul support partial rd but follow protocol standards
+ // TODO: this code assumes TLUL data is always 32 bits wide, can explore more generic solution
+ if (reg_item.a_opcode == tlul_pkg::Get) begin
+ case ($countones(rw.byte_en))
+ 3, 4: begin // no partial rd
+ reg_item.a_mask = 'hf;
+ reg_item.a_addr = rw.addr;
+ end
+ 1: begin // partial rd 1 byte
+ reg_item.a_mask = rw.byte_en;
+ reg_item.a_addr = rw.addr + $clog2(rw.byte_en);
+ end
+ 2: begin
+ if (rw.byte_en == 'b0110) begin // no partial rd
+ reg_item.a_mask = 'hf;
+ reg_item.a_addr = rw.addr;
+ end else begin // partial rd 2 bytes
+ reg_item.a_mask = rw.byte_en;
+ reg_item.a_addr = (rw.byte_en == 'b0011) ? rw.addr : rw.addr + 2;
+ end
+ end
+ default: begin
+ `uvm_fatal(`gtn, $sformatf("invalid byte_en value = 0x%0h", rw.byte_en));
+ end
+ endcase
+ end
+ else begin
+ reg_item.a_mask = rw.byte_en;
+ reg_item.a_addr = rw.addr;
+ end
+ reg_item.a_size = $clog2($countones(reg_item.a_mask));
+ reg_item.a_data = rw.data;
+ `uvm_info(`gtn, $sformatf("tl reg req item: addr=0x%0h, op=%0s data=0x%0h, mask = %0h",
+ reg_item.a_addr, reg_item.a_opcode.name, reg_item.a_data,
+ reg_item.a_mask), UVM_HIGH)
return reg_item;
endfunction : reg2bus
diff --git a/hw/ip/gpio/dv/env/gpio_scoreboard.sv b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
index 0a505d0..3d98739 100644
--- a/hw/ip/gpio/dv/env/gpio_scoreboard.sv
+++ b/hw/ip/gpio/dv/env/gpio_scoreboard.sv
@@ -43,12 +43,13 @@
// process monitored tl transaction
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
- bit do_read_check = 1'b1;
- bit write = item.is_write();
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
end
if (csr == null) begin
diff --git a/hw/ip/hmac/dv/env/hmac_scoreboard.sv b/hw/ip/hmac/dv/env/hmac_scoreboard.sv
index ca6c5fe..a95d8d0 100644
--- a/hw/ip/hmac/dv/env/hmac_scoreboard.sv
+++ b/hw/ip/hmac/dv/env/hmac_scoreboard.sv
@@ -25,20 +25,19 @@
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
- bit do_read_check = 1'b1;
- bit write = item.is_write();
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
- end
- if (csr == null) begin
- if (!(item.a_addr inside {[HMAC_MSG_FIFO_BASE : HMAC_MSG_FIFO_LAST_ADDR]})) begin
- // we hit an oob addr - expect error response and return
- `DV_CHECK_EQ(item.d_error, 1'b1)
- return;
- end
+ // if addr inside msg fifo, no ral model
+ end else if (!(item.a_addr inside {[HMAC_MSG_FIFO_BASE : HMAC_MSG_FIFO_LAST_ADDR]})) begin
+ // we hit an oob addr - expect error response and return
+ `DV_CHECK_EQ(item.d_error, 1'b1)
+ return;
end
// if incoming access is a write to a valid csr or mem, then update right away on addr channel
diff --git a/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv b/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
index da44ed3..966b28a 100644
--- a/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
+++ b/hw/ip/rv_timer/dv/env/rv_timer_scoreboard.sv
@@ -35,12 +35,13 @@
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
string csr_name;
- bit do_read_check = 1'b1;
- bit write = item.is_write();
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
csr_name = csr.get_name();
end
diff --git a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
index 666b5c0..21b943e 100644
--- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -67,13 +67,13 @@
// this is already called in cip_base_scoreboard::process_tl_a/d_chan_fifo tasks
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
- bit do_read_check = 1'b0; // TODO: fixme
- bit write = item.is_write();
-
+ bit do_read_check = 1'b0; // TODO: fixme
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
end
else if (item.a_addr inside {[cfg.sram_start_addr:cfg.sram_end_addr]}) begin
diff --git a/hw/ip/uart/dv/env/uart_scoreboard.sv b/hw/ip/uart/dv/env/uart_scoreboard.sv
index 2917521..d656429 100644
--- a/hw/ip/uart/dv/env/uart_scoreboard.sv
+++ b/hw/ip/uart/dv/env/uart_scoreboard.sv
@@ -128,12 +128,13 @@
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
- bit do_read_check = 1'b1;
- bit write = item.is_write();
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
end
if (csr == null) begin
diff --git a/util/uvmdvgen/scoreboard.sv.tpl b/util/uvmdvgen/scoreboard.sv.tpl
index 3a2f9ab..68727c4 100644
--- a/util/uvmdvgen/scoreboard.sv.tpl
+++ b/util/uvmdvgen/scoreboard.sv.tpl
@@ -60,12 +60,13 @@
virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
uvm_reg csr;
- bit do_read_check = 1'b1;
- bit write = item.is_write();
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = {item.a_addr[TL_AW-1:2], 2'b00};
// if access was to a valid csr, get the csr handle
- if (item.a_addr inside {cfg.csr_addrs}) begin
- csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ if (csr_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(csr_addr);
`DV_CHECK_NE_FATAL(csr, null)
end
if (csr == null) begin