diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 690b2d62e8c5bc..7e72b97c2df686 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -541,7 +541,6 @@ resval: 0x0 hwaccess: "hrw" swaccess: "ro" - hwaccess: "hrw" desc: ''' DMA operation is active if this bit is set. DMA engine clears this bit when operation is complete. @@ -558,11 +557,21 @@ ''' } { bits: "2" + name: "chunk_done" + resval: 0x0 + hwaccess: "hrw" + desc: ''' + Transfer of a single chunk is complete. + Only raised for multi-chunk memory-to-memory transfers. + Cleared automatically by the hardware when starting the transfer of a new chunk. + ''' + } + { bits: "3" name: "aborted" resval: 0x0 desc: "Set once aborted operation drains." } - { bits: "3" + { bits: "4" name: "error" resval: 0x0 hwaccess: "hrw" @@ -572,7 +581,7 @@ ERROR_CODE register denotes the source of the error. ''' } - { bits: "4" + { bits: "5" name: "sha2_digest_valid" swaccess: "ro" resval: 0x0 diff --git a/hw/ip/dma/doc/registers.md b/hw/ip/dma/doc/registers.md index 41ba14f7915516..ead852daa9ed28 100644 --- a/hw/ip/dma/doc/registers.md +++ b/hw/ip/dma/doc/registers.md @@ -532,20 +532,21 @@ Other values are reserved. Status indication for DMA data movement. - Offset: `0x48` - Reset default: `0x0` -- Reset mask: `0x1f` +- Reset mask: `0x3f` ### Fields ```wavejson -{"reg": [{"name": "busy", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "aborted", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "sha2_digest_valid", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 27}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +{"reg": [{"name": "busy", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "chunk_done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "aborted", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "sha2_digest_valid", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 26}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} ``` | Bits | Type | Reset | Name | Description | |:------:|:------:|:-------:|:------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 31:5 | | | | Reserved | -| 4 | ro | 0x0 | sha2_digest_valid | Indicates whether the SHA2_DIGEST register contains a valid digest. This value is cleared on the initial transfer and set when the digest is written. | -| 3 | rw1c | 0x0 | error | Error occurred during the operation. ERROR_CODE register denotes the source of the error. | -| 2 | rw1c | 0x0 | aborted | Set once aborted operation drains. | +| 31:6 | | | | Reserved | +| 5 | ro | 0x0 | sha2_digest_valid | Indicates whether the SHA2_DIGEST register contains a valid digest. This value is cleared on the initial transfer and set when the digest is written. | +| 4 | rw1c | 0x0 | error | Error occurred during the operation. ERROR_CODE register denotes the source of the error. | +| 3 | rw1c | 0x0 | aborted | Set once aborted operation drains. | +| 2 | rw1c | 0x0 | chunk_done | Transfer of a single chunk is complete. Only raised for multi-chunk memory-to-memory transfers. Cleared automatically by the hardware when starting the transfer of a new chunk. | | 1 | rw1c | 0x0 | done | Configured DMA operation is complete. Cleared automatically by the hardware when starting a new transfer. | | 0 | ro | 0x0 | busy | DMA operation is active if this bit is set. DMA engine clears this bit when operation is complete. This bit may be set as long as hardware handshake mode is active and triggered. | diff --git a/hw/ip/dma/dv/env/dma_env_cov.sv b/hw/ip/dma/dv/env/dma_env_cov.sv index 9be5e5f3dff902..b7eeba42106ed1 100644 --- a/hw/ip/dma/dv/env/dma_env_cov.sv +++ b/hw/ip/dma/dv/env/dma_env_cov.sv @@ -192,6 +192,7 @@ endgroup covergroup dma_status_cg with function sample( bit busy, bit done, + bit chunk_done, bit aborted, bit error, bit sha2_digest_valid @@ -200,6 +201,7 @@ covergroup dma_status_cg with function sample( option.name = "dma_status_cg"; cp_status_busy: coverpoint busy; cp_status_done: coverpoint done; + cp_status_chunk_done: coverpoint chunk_done; cp_status_aborted: coverpoint aborted; cp_status_error: coverpoint error; cp_sha2_digest_valid: coverpoint sha2_digest_valid; diff --git a/hw/ip/dma/dv/env/dma_scoreboard.sv b/hw/ip/dma/dv/env/dma_scoreboard.sv index 6aa99e3f2bcd37..f7c4d24c90e81e 100644 --- a/hw/ip/dma/dv/env/dma_scoreboard.sv +++ b/hw/ip/dma/dv/env/dma_scoreboard.sv @@ -1066,21 +1066,23 @@ class dma_scoreboard extends cip_base_scoreboard #( do_read_check = 1; end "status": begin - bit busy, done, aborted, error, sha2_digest_valid; + bit busy, done, chunk_done, aborted, error, sha2_digest_valid; bit exp_aborted = abort_via_reg_write; do_read_check = 1'b0; busy = get_field_val(ral.status.busy, item.d_data); done = get_field_val(ral.status.done, item.d_data); + chunk_done = get_field_val(ral.status.chunk_done, item.d_data); aborted = get_field_val(ral.status.aborted, item.d_data); error = get_field_val(ral.status.error, item.d_data); sha2_digest_valid = get_field_val(ral.status.sha2_digest_valid, item.d_data); - if (done || aborted || error) begin + if (done || chunk_done || aborted || error) begin string reasons; - if (done) reasons = "Done "; - if (aborted) reasons = {reasons, "Aborted "}; - if (error) reasons = {reasons, "Error" }; + if (done) reasons = "Done "; + if (chunk_done) reasons = {reasons, "ChunkDone "}; + if (aborted) reasons = {reasons, "Aborted "}; + if (error) reasons = {reasons, "Error" }; operation_in_progress = 1'b0; `uvm_info(`gfn, $sformatf("Detected end of DMA operation (%s)", reasons), UVM_MEDIUM) // Clear variables @@ -1109,13 +1111,14 @@ class dma_scoreboard extends cip_base_scoreboard #( // Sample dma status and error code cov.status_cg.sample(.busy (busy), .done (done), + .chunk_done (chunk_done), .aborted (aborted), .error (error), .sha2_digest_valid (sha2_digest_valid)); end // Check results after each chunk of the transfer (memory-to-memory) or after the complete // transfer (handshaking mode). - if (dma_config.is_valid_config && done) begin + if (dma_config.is_valid_config && (done || chunk_done)) begin if (num_bytes_transferred >= dma_config.total_data_size) begin // SHA digest (expecting zeros if unused) // When using inline hashing, sha2_digest_valid must be raised at the end diff --git a/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv b/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv index 54ad02362a8937..8a1710f9183fe8 100644 --- a/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv +++ b/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv @@ -741,12 +741,12 @@ class dma_base_vseq extends cip_base_vseq #( csr_rd(ral.status, v); // Collect some STATUS bit that do not generate interrupts, and inform parallel threads // if (v[0]) ->e_busy; - if (v[2]) status[StatusAborted] = 1'b1; + if (v[3]) status[StatusAborted] = 1'b1; // Respond to the STATUS.done and STATUS.error bits only if we're not insisting upon // interrupt-driven completion. if (!intr_driven) begin if (v[1]) status[StatusDone] = 1'b1; - if (v[3]) status[StatusError] = 1'b1; + if (v[4]) status[StatusError] = 1'b1; end // Note: sha2_digest_valid is not a completion event // v[12] diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index b3428c2136a89f..f75864127ac174 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -75,7 +75,7 @@ module dma logic dma_state_error; dma_ctrl_state_e ctrl_state_q, ctrl_state_d; - logic set_error_code, clear_go, clear_status, clear_sha_status; + logic set_error_code, clear_go, clear_status, clear_sha_status, chunk_done; logic [INTR_CLEAR_SOURCES_WIDTH-1:0] clear_index_d, clear_index_q; logic clear_index_en, intr_clear_tlul_rsp_valid; @@ -606,6 +606,7 @@ module dma clear_index_en = '0; clear_go = 1'b0; + chunk_done = 1'b0; // Mux the TLUL grant and response signals depending on the selected bus interface intr_clear_tlul_gnt = reg2hw.clear_intr_bus.q[clear_index_q]? dma_host_tlul_gnt : @@ -965,8 +966,9 @@ module dma end else if (chunk_byte_d >= reg2hw.chunk_data_size.q) begin // Conditionally clear the go bit when not being in hardware handshake mode. // In non-hardware handshake mode, finishing one chunk should raise the done IRQ - // and done bit, and release the go bit for the next FW-controlled chunk. + // and chunk done bit, and release the go bit for the next FW-controlled chunk. clear_go = !control_q.cfg_handshake_en; + chunk_done = !control_q.cfg_handshake_en; ctrl_state_d = DmaIdle; end else begin ctrl_state_d = DmaAddrSetup; @@ -1178,11 +1180,15 @@ module dma clear_sha_status = (ctrl_state_q == DmaIdle) && (ctrl_state_d != DmaIdle) && reg2hw.control.initial_transfer.q; - // Set done bit and raise interrupt when we either finished a single transfer or all transfers - // in hardware handshake mode. Automatically clear the done bit when starting a new transfer - hw2reg.status.done.de = ((!cfg_abort_en) && data_move_state && clear_go) | clear_status; + // Set the done bit only when finishing all chunks. Automatically clear the done bit when + // starting a new transfer + hw2reg.status.done.de = ((!cfg_abort_en) && data_move_state && clear_go && ~chunk_done) | + clear_status; hw2reg.status.done.d = clear_status? 1'b0 : 1'b1; + hw2reg.status.chunk_done.de = ((!cfg_abort_en) && chunk_done) | clear_status; + hw2reg.status.chunk_done.d = clear_status? 1'b0 : 1'b1; + hw2reg.status.error.de = (ctrl_state_d == DmaError) | clear_status; hw2reg.status.error.d = clear_status? 1'b0 : 1'b1; @@ -1252,8 +1258,10 @@ module dma hw2reg.control.abort.de = hw2reg.status.aborted.de; hw2reg.control.abort.d = 1'b0; - // interrupt management - hw2reg.intr_state.dma_done.de = reg2hw.status.done.q | test_done_interrupt; + // Interrupt management + // Raise the done interrupt either when finishing finishing a single chunk or the whole + // transfer. + hw2reg.intr_state.dma_done.de = reg2hw.status.done.q | chunk_done | test_done_interrupt; hw2reg.intr_state.dma_done.d = 1'b1; hw2reg.intr_state.dma_error.de = reg2hw.status.error.q | test_error_interrupt; diff --git a/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/ip/dma/rtl/dma_reg_pkg.sv index 0dca94a3d60f55..d2ee80778a26a7 100644 --- a/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -141,6 +141,9 @@ package dma_reg_pkg; struct packed { logic q; } done; + struct packed { + logic q; + } chunk_done; struct packed { logic q; logic qe; @@ -230,6 +233,10 @@ package dma_reg_pkg; logic d; logic de; } done; + struct packed { + logic d; + logic de; + } chunk_done; struct packed { logic d; logic de; @@ -286,24 +293,24 @@ package dma_reg_pkg; // Register -> HW type typedef struct packed { - dma_reg2hw_intr_state_reg_t intr_state; // [1037:1036] - dma_reg2hw_intr_enable_reg_t intr_enable; // [1035:1034] - dma_reg2hw_intr_test_reg_t intr_test; // [1033:1030] - dma_reg2hw_alert_test_reg_t alert_test; // [1029:1028] - dma_reg2hw_src_addr_lo_reg_t src_addr_lo; // [1027:996] - dma_reg2hw_src_addr_hi_reg_t src_addr_hi; // [995:964] - dma_reg2hw_dst_addr_lo_reg_t dst_addr_lo; // [963:932] - dma_reg2hw_dst_addr_hi_reg_t dst_addr_hi; // [931:900] - dma_reg2hw_addr_space_id_reg_t addr_space_id; // [899:892] - dma_reg2hw_enabled_memory_range_base_reg_t enabled_memory_range_base; // [891:859] - dma_reg2hw_enabled_memory_range_limit_reg_t enabled_memory_range_limit; // [858:826] - dma_reg2hw_range_valid_reg_t range_valid; // [825:825] - dma_reg2hw_range_regwen_reg_t range_regwen; // [824:821] - dma_reg2hw_total_data_size_reg_t total_data_size; // [820:789] - dma_reg2hw_chunk_data_size_reg_t chunk_data_size; // [788:757] - dma_reg2hw_transfer_width_reg_t transfer_width; // [756:755] - dma_reg2hw_control_reg_t control; // [754:743] - dma_reg2hw_status_reg_t status; // [742:737] + dma_reg2hw_intr_state_reg_t intr_state; // [1038:1037] + dma_reg2hw_intr_enable_reg_t intr_enable; // [1036:1035] + dma_reg2hw_intr_test_reg_t intr_test; // [1034:1031] + dma_reg2hw_alert_test_reg_t alert_test; // [1030:1029] + dma_reg2hw_src_addr_lo_reg_t src_addr_lo; // [1028:997] + dma_reg2hw_src_addr_hi_reg_t src_addr_hi; // [996:965] + dma_reg2hw_dst_addr_lo_reg_t dst_addr_lo; // [964:933] + dma_reg2hw_dst_addr_hi_reg_t dst_addr_hi; // [932:901] + dma_reg2hw_addr_space_id_reg_t addr_space_id; // [900:893] + dma_reg2hw_enabled_memory_range_base_reg_t enabled_memory_range_base; // [892:860] + dma_reg2hw_enabled_memory_range_limit_reg_t enabled_memory_range_limit; // [859:827] + dma_reg2hw_range_valid_reg_t range_valid; // [826:826] + dma_reg2hw_range_regwen_reg_t range_regwen; // [825:822] + dma_reg2hw_total_data_size_reg_t total_data_size; // [821:790] + dma_reg2hw_chunk_data_size_reg_t chunk_data_size; // [789:758] + dma_reg2hw_transfer_width_reg_t transfer_width; // [757:756] + dma_reg2hw_control_reg_t control; // [755:744] + dma_reg2hw_status_reg_t status; // [743:737] dma_reg2hw_handshake_intr_enable_reg_t handshake_intr_enable; // [736:726] dma_reg2hw_clear_intr_src_reg_t clear_intr_src; // [725:715] dma_reg2hw_clear_intr_bus_reg_t clear_intr_bus; // [714:704] @@ -313,14 +320,14 @@ package dma_reg_pkg; // HW -> register type typedef struct packed { - dma_hw2reg_intr_state_reg_t intr_state; // [699:696] - dma_hw2reg_src_addr_lo_reg_t src_addr_lo; // [695:663] - dma_hw2reg_src_addr_hi_reg_t src_addr_hi; // [662:630] - dma_hw2reg_dst_addr_lo_reg_t dst_addr_lo; // [629:597] - dma_hw2reg_dst_addr_hi_reg_t dst_addr_hi; // [596:564] - dma_hw2reg_cfg_regwen_reg_t cfg_regwen; // [563:560] - dma_hw2reg_control_reg_t control; // [559:554] - dma_hw2reg_status_reg_t status; // [553:544] + dma_hw2reg_intr_state_reg_t intr_state; // [701:698] + dma_hw2reg_src_addr_lo_reg_t src_addr_lo; // [697:665] + dma_hw2reg_src_addr_hi_reg_t src_addr_hi; // [664:632] + dma_hw2reg_dst_addr_lo_reg_t dst_addr_lo; // [631:599] + dma_hw2reg_dst_addr_hi_reg_t dst_addr_hi; // [598:566] + dma_hw2reg_cfg_regwen_reg_t cfg_regwen; // [565:562] + dma_hw2reg_control_reg_t control; // [561:556] + dma_hw2reg_status_reg_t status; // [555:544] dma_hw2reg_error_code_reg_t error_code; // [543:528] dma_hw2reg_sha2_digest_mreg_t [15:0] sha2_digest; // [527:0] } dma_hw2reg_t; diff --git a/hw/ip/dma/rtl/dma_reg_top.sv b/hw/ip/dma/rtl/dma_reg_top.sv index 561aef1d4ab9c7..a22bd62792e43d 100644 --- a/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/ip/dma/rtl/dma_reg_top.sv @@ -199,6 +199,8 @@ module dma_reg_top ( logic status_busy_qs; logic status_done_qs; logic status_done_wd; + logic status_chunk_done_qs; + logic status_chunk_done_wd; logic status_aborted_qs; logic status_aborted_wd; logic status_error_qs; @@ -1165,14 +1167,14 @@ module dma_reg_top ( // R[status]: V(False) logic status_qe; - logic [4:0] status_flds_we; + logic [5:0] status_flds_we; prim_flop #( .Width(1), .ResetValue(0) ) u_status0_qe ( .clk_i(clk_i), .rst_ni(rst_ni), - .d_i(&(status_flds_we | 5'h11)), + .d_i(&(status_flds_we | 6'h21)), .q_o(status_qe) ); // F[busy]: 0:0 @@ -1229,7 +1231,34 @@ module dma_reg_top ( .qs (status_done_qs) ); - // F[aborted]: 2:2 + // F[chunk_done]: 2:2 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_status_chunk_done ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (status_we), + .wd (status_chunk_done_wd), + + // from internal hardware + .de (hw2reg.status.chunk_done.de), + .d (hw2reg.status.chunk_done.d), + + // to internal hardware + .qe (status_flds_we[2]), + .q (reg2hw.status.chunk_done.q), + .ds (), + + // to register interface (read) + .qs (status_chunk_done_qs) + ); + + // F[aborted]: 3:3 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessW1C), @@ -1248,7 +1277,7 @@ module dma_reg_top ( .d (hw2reg.status.aborted.d), // to internal hardware - .qe (status_flds_we[2]), + .qe (status_flds_we[3]), .q (), .ds (), @@ -1256,7 +1285,7 @@ module dma_reg_top ( .qs (status_aborted_qs) ); - // F[error]: 3:3 + // F[error]: 4:4 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessW1C), @@ -1275,7 +1304,7 @@ module dma_reg_top ( .d (hw2reg.status.error.d), // to internal hardware - .qe (status_flds_we[3]), + .qe (status_flds_we[4]), .q (reg2hw.status.error.q), .ds (), @@ -1284,7 +1313,7 @@ module dma_reg_top ( ); assign reg2hw.status.error.qe = status_qe; - // F[sha2_digest_valid]: 4:4 + // F[sha2_digest_valid]: 5:5 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessRO), @@ -1303,7 +1332,7 @@ module dma_reg_top ( .d (hw2reg.status.sha2_digest_valid.d), // to internal hardware - .qe (status_flds_we[4]), + .qe (status_flds_we[5]), .q (reg2hw.status.sha2_digest_valid.q), .ds (), @@ -3056,9 +3085,11 @@ module dma_reg_top ( assign status_done_wd = reg_wdata[1]; - assign status_aborted_wd = reg_wdata[2]; + assign status_chunk_done_wd = reg_wdata[2]; + + assign status_aborted_wd = reg_wdata[3]; - assign status_error_wd = reg_wdata[3]; + assign status_error_wd = reg_wdata[4]; assign handshake_intr_enable_we = addr_hit[36] & reg_we & !reg_error; assign handshake_intr_enable_wd = reg_wdata[10:0]; @@ -3291,9 +3322,10 @@ module dma_reg_top ( addr_hit[18]: begin reg_rdata_next[0] = status_busy_qs; reg_rdata_next[1] = status_done_qs; - reg_rdata_next[2] = status_aborted_qs; - reg_rdata_next[3] = status_error_qs; - reg_rdata_next[4] = status_sha2_digest_valid_qs; + reg_rdata_next[2] = status_chunk_done_qs; + reg_rdata_next[3] = status_aborted_qs; + reg_rdata_next[4] = status_error_qs; + reg_rdata_next[5] = status_sha2_digest_valid_qs; end addr_hit[19]: begin diff --git a/sw/ip/dma/dif/dif_dma.h b/sw/ip/dma/dif/dif_dma.h index bf58bad4096ab4..7de8fba59a4e8f 100644 --- a/sw/ip/dma/dif/dif_dma.h +++ b/sw/ip/dma/dif/dif_dma.h @@ -218,6 +218,8 @@ typedef enum dif_dma_status_code { kDifDmaStatusBusy = 0x01 << DMA_STATUS_BUSY_BIT, // Configured DMA operation is complete. kDifDmaStatusDone = 0x01 << DMA_STATUS_DONE_BIT, + // Transfer of a single chunk is complete. + kDifDmaStatusChunkDone = 0x01 << DMA_STATUS_CHUNK_DONE_BIT, // Set once aborted operation drains. kDifDmaStatusAborted = 0x01 << DMA_STATUS_ABORTED_BIT, // Error occurred during the operation. diff --git a/sw/ip/dma/dif/dif_dma_unittest.cc b/sw/ip/dma/dif/dif_dma_unittest.cc index 84535fe021d6d5..c54a67495afad9 100644 --- a/sw/ip/dma/dif/dif_dma_unittest.cc +++ b/sw/ip/dma/dif/dif_dma_unittest.cc @@ -321,6 +321,7 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(std::vector{{ {1 << DMA_STATUS_BUSY_BIT, kDifDmaStatusBusy}, {1 << DMA_STATUS_DONE_BIT, kDifDmaStatusDone}, + {1 << DMA_STATUS_CHUNK_DONE_BIT, kDifDmaStatusChunkDone}, {1 << DMA_STATUS_ABORTED_BIT, kDifDmaStatusAborted}, {1 << DMA_STATUS_ERROR_BIT, kDifDmaStatusError}, {1 << DMA_STATUS_SHA2_DIGEST_VALID_BIT, kDifDmaStatusSha2DigestValid}, @@ -347,6 +348,7 @@ INSTANTIATE_TEST_SUITE_P( StatusWriteTest, StatusWriteTest, testing::ValuesIn(std::vector{{ {1 << DMA_STATUS_DONE_BIT, kDifDmaStatusDone}, + {1 << DMA_STATUS_CHUNK_DONE_BIT, kDifDmaStatusChunkDone}, {1 << DMA_STATUS_ABORTED_BIT, kDifDmaStatusAborted}, {1 << DMA_STATUS_ERROR_BIT, kDifDmaStatusError}, {1 << DMA_STATUS_SHA2_DIGEST_VALID_BIT, kDifDmaStatusSha2DigestValid},