diff --git a/hw/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv b/hw/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv index 6c253b97f552c..1d82d9dd19ff5 100644 --- a/hw/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv +++ b/hw/dv/sv/jtag_dmi_agent/jtag_dmi_reg_frontdoor.sv @@ -22,8 +22,9 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; virtual task body(); csr_field_t csr_or_fld; - uvm_reg_data_t wdata = 0; + uvm_reg_data_t wdata = 0, rdata; jtag_dtm_reg_block jtag_dtm_ral = jtag_agent_cfg_h.jtag_dtm_ral; + jtag_dmi_op_rsp_e op_rsp; // If the JTAG agent is sitting in reset, print a debug message and exit early if (jtag_agent_cfg_h.in_reset) begin @@ -74,9 +75,26 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; // soon, it may end up setting the in progress sticky bit, causing more time wasted. jtag_agent_cfg_h.vif.wait_tck(10); - // Poll for completion. + // Poll for completion. Reset DMI if the sticky bit 'InProgress' is set. `DV_SPINWAIT_EXIT( - read_dmi_over_jtag(jtag_dtm_ral, csr_or_fld);, + do begin + csr_rd(.ptr(jtag_dtm_ral.dmi), .value(rdata), .blocking(1)); + op_rsp = jtag_dmi_op_rsp_e'(get_field_val(jtag_dtm_ral.dmi.op, rdata)); + `uvm_info(`gfn, $sformatf("DMI CSR req status: %0s", op_rsp.name()), UVM_HIGH) + if (op_rsp == DmiOpInProgress) begin + csr_wr(.ptr(jtag_dtm_ral.dtmcs.dmireset), .value(1), .blocking(1), .predict(1)); + end else begin + rw_info.status = op_rsp == DmiOpOk ? UVM_IS_OK : UVM_NOT_OK; + if (rw_info.kind == UVM_READ) begin + rdata = get_field_val(jtag_dtm_ral.dmi.data, rdata); + if (csr_or_fld.field != null) begin + rdata = get_field_val(csr_or_fld.field, rdata); + end + rw_info.value = new[1]; + rw_info.value[0] = rdata; + end + end + end while (op_rsp == DmiOpInProgress);, begin fork wait(jtag_agent_cfg_h.in_reset); @@ -90,56 +108,4 @@ class jtag_dmi_reg_frontdoor extends uvm_reg_frontdoor; jtag_dtm_ral_sem_h.put(); endtask - // Use JTAG to read the contents of the DMI register - // - // If the underlying operation in rw_info is UVM_READ, this also updates rw_info.value to contain - // the requested register contents. - // - // For either direction (read or write), it waits until the DMI is running an operation. - task read_dmi_over_jtag(jtag_dtm_reg_block jtag_dtm_ral, csr_field_t csr_or_fld); - uvm_reg_data_t dmi_data_rdata; - jtag_dmi_op_rsp_e op_rsp; - int num_dones_seen = 0; - - // This loop works around a confusing situation where TCK is running much faster than the main - // clock and the first JTAG read responds with DmiOpOk just as it discovers (too late) that - // there was actually an operation in progress. The next JTAG read correctly responds with - // DmiOpInProgress and the operation is done next time we see DmiOpOk (or DmiOpFailed). - // - // If we see two results other than DmiOpInProgress, we know that the operation is genuinely - // finished. - while (num_dones_seen < 2) begin - uvm_reg_data_t rdata; - - csr_rd(.ptr(jtag_dtm_ral.dmi), .value(rdata), .blocking(1)); - op_rsp = jtag_dmi_op_rsp_e'(get_field_val(jtag_dtm_ral.dmi.op, rdata)); - - // If DMI responds with DmiOpInProgress, it is telling us that an operation was running. That - // flag is sticky, so we need to follow up by writing 1 to "dmireset" over JTAG to clear the - // flag. - if (op_rsp == DmiOpInProgress) begin - csr_wr(.ptr(jtag_dtm_ral.dtmcs.dmireset), .value(1), .blocking(1), .predict(1)); - end else begin - if (num_dones_seen == 0) begin - dmi_data_rdata = get_field_val(jtag_dtm_ral.dmi.data, rdata); - end - - num_dones_seen++; - end - end - - // At this point, we've seen two reads where op_rsp is not DmiOpInProgress. Use the results of - // the second read to populate rw_info. If we are doing a UVM_READ, this includes extracting the - // CSR or field from rdata. - rw_info.status = op_rsp == DmiOpOk ? UVM_IS_OK : UVM_NOT_OK; - if (rw_info.kind == UVM_READ) begin - if (csr_or_fld.field != null) begin - dmi_data_rdata = get_field_val(csr_or_fld.field, dmi_data_rdata); - end - - rw_info.value = new[1]; - rw_info.value[0] = dmi_data_rdata; - end - endtask - endclass