diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 2807840fbc5543..400c50bb3746eb 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -102,6 +102,9 @@ desc: "DMA operation has been completed." type: "status" } + { name: "dma_chunk_done" + desc: "Indicated the transfer of a single chunk has been completed." + } { name: "dma_error" desc: "DMA error has occurred. DMA_STATUS.error_code register shows the details." type: "status" diff --git a/hw/ip/dma/dv/env/dma_env_pkg.sv b/hw/ip/dma/dv/env/dma_env_pkg.sv index a43bf26b3b18c6..0af5c08e550e1f 100644 --- a/hw/ip/dma/dv/env/dma_env_pkg.sv +++ b/hw/ip/dma/dv/env/dma_env_pkg.sv @@ -34,11 +34,13 @@ package dma_env_pkg; // Index of interrupt in intf_vif parameter uint DMA_DONE = 0; - parameter uint DMA_ERROR = 1; + parameter uint DMA_CHUNK_DONE = 1; + parameter uint DMA_ERROR = 2; // Completion status bits (DV-internal) typedef enum { StatusDone, + StatusChunkDone, StatusError, StatusAborted, StatusTimeout diff --git a/hw/ip/dma/dv/env/dma_scoreboard.sv b/hw/ip/dma/dv/env/dma_scoreboard.sv index a6615c4535e91a..f9e68cc974a4a8 100644 --- a/hw/ip/dma/dv/env/dma_scoreboard.sv +++ b/hw/ip/dma/dv/env/dma_scoreboard.sv @@ -605,9 +605,10 @@ class dma_scoreboard extends cip_base_scoreboard #( if (curr_intr[i] !== exp_intr[i]) begin // Collect a list of the mismatched interrupts unique case (i) - DMA_DONE: rsn = {rsn, "Done "}; - DMA_ERROR: rsn = {rsn, "Error "}; - default: rsn = {rsn, "Unknown intr"}; + DMA_DONE: rsn = {rsn, "Done "}; + DMA_CHUNK_DONE: rsn = {rsn, "Done "}; + DMA_ERROR: rsn = {rsn, "Error "}; + default: rsn = {rsn, "Unknown intr"}; endcase end 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 6b586770793adb..fff435775a4645 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 @@ -646,6 +646,13 @@ class dma_base_vseq extends cip_base_vseq #( csr_update(.csr(ral.status)); endtask : clear_done + // Clear 'STATUS.chunk_done' field after a chunk transfer has completed. + task clear_chunk_done(); + `uvm_info(`gfn, "DMA: Clear STATUS.chunk_done", UVM_HIGH) + ral.status.chunk_done.set(1'b1); + csr_update(.csr(ral.status)); + endtask : clear_chunk_done + // Task: Abort the current transaction task abort(); uvm_reg_data_t data = 0; @@ -717,8 +724,9 @@ class dma_base_vseq extends cip_base_vseq #( if (intr_driven) begin forever begin delay(1); - if (cfg.intr_vif.pins[DMA_DONE]) status[StatusDone] = 1'b1; - if (cfg.intr_vif.pins[DMA_ERROR]) status[StatusError] = 1'b1; + if (cfg.intr_vif.pins[DMA_DONE]) status[StatusDone] = 1'b1; + if (cfg.intr_vif.pins[DMA_CHUNK_DONE]) status[StatusChunkDone] = 1'b1; + if (cfg.intr_vif.pins[DMA_ERROR]) status[StatusError] = 1'b1; end end else begin // Rely upon the CSR reading in `poll_status` to detect completion. @@ -739,8 +747,9 @@ class dma_base_vseq extends cip_base_vseq #( // 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[1]) status[StatusDone] = 1'b1; + if (v[3]) status[StatusError] = 1'b1; + if (v[5]) status[StatusChunkDone] = 1'b1; end // Note: sha2_digest_valid is not a completion event // v[12] diff --git a/hw/ip/dma/dv/env/seq_lib/dma_generic_vseq.sv b/hw/ip/dma/dv/env/seq_lib/dma_generic_vseq.sv index bd7345f0d1844c..140f5d3161b4b2 100644 --- a/hw/ip/dma/dv/env/seq_lib/dma_generic_vseq.sv +++ b/hw/ip/dma/dv/env/seq_lib/dma_generic_vseq.sv @@ -276,6 +276,12 @@ class dma_generic_vseq extends dma_base_vseq; clear_done(); status[StatusDone] = 1'b0; end + if (status[StatusChunkDone]) begin + // Clear STATUS.chunk_done bit and then clear the interrupt, if enabled. + clear_chunk_done(); + clear_interrupts(1 << DMA_CHUNK_DONE); + status[StatusChunkDone] = 1'b0; + end if (status[StatusError]) begin // Clear STATUS.error condition and associcated interrupt. clear_errors(dma_config); diff --git a/hw/ip/dma/dv/tb/tb.sv b/hw/ip/dma/dv/tb/tb.sv index a954003eb7aff8..20623040e7a538 100644 --- a/hw/ip/dma/dv/tb/tb.sv +++ b/hw/ip/dma/dv/tb/tb.sv @@ -55,6 +55,7 @@ module tb; .scanmode_i (prim_mubi_pkg::MuBi4False), .lsio_trigger_i (handshake_i), .intr_dma_done_o (interrupts[DMA_DONE]), + .intr_dma_chunk_done_o (interrupts[DMA_CHUNK_DONE]), .intr_dma_error_o (interrupts[DMA_ERROR]), .alert_rx_i (alert_rx), .alert_tx_o (alert_tx), diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index a0077fe4486cd1..01a8aac9e90ce5 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -21,6 +21,7 @@ module dma input prim_mubi_pkg::mubi4_t scanmode_i, // DMA interrupts and incoming LSIO triggers output logic intr_dma_done_o, + output logic intr_dma_chunk_done_o, output logic intr_dma_error_o, input lsio_trigger_t lsio_trigger_i, // Alerts @@ -1094,6 +1095,21 @@ module dma .intr_o ( intr_dma_done_o ) ); + prim_intr_hw #( + .IntrT ( "Status" ) + ) u_intr_chunk_dma_done ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .event_intr_i ( reg2hw.intr_state.dma_chunk_done.q ), + .reg2hw_intr_enable_q_i ( reg2hw.intr_enable.dma_chunk_done.q ), + .reg2hw_intr_test_q_i ( reg2hw.intr_test.dma_chunk_done.q ), + .reg2hw_intr_test_qe_i ( reg2hw.intr_test.dma_chunk_done.qe ), + .reg2hw_intr_state_q_i ( reg2hw.intr_state.dma_chunk_done.q ), + .hw2reg_intr_state_de_o ( hw2reg.intr_state.dma_chunk_done.de ), + .hw2reg_intr_state_d_o ( hw2reg.intr_state.dma_chunk_done.d ), + .intr_o ( intr_dma_chunk_done_o ) + ); + prim_intr_hw #( .IntrT ( "Status" ) ) u_intr_error ( @@ -1112,7 +1128,6 @@ module dma logic data_move_state; logic update_dst_addr_reg, update_src_addr_reg; - assign data_move_state = (ctrl_state_q == DmaSendWrite) || (ctrl_state_q == DmaWaitWriteResponse) || (ctrl_state_q == DmaShaWait) || diff --git a/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/ip/dma/rtl/dma_reg_pkg.sv index f0565bdd5a292d..e8a4c115ddb7f9 100644 --- a/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -21,6 +21,9 @@ package dma_reg_pkg; struct packed { logic q; } dma_error; + struct packed { + logic q; + } dma_chunk_done; struct packed { logic q; } dma_done; @@ -30,6 +33,9 @@ package dma_reg_pkg; struct packed { logic q; } dma_error; + struct packed { + logic q; + } dma_chunk_done; struct packed { logic q; } dma_done; @@ -40,6 +46,10 @@ package dma_reg_pkg; logic q; logic qe; } dma_error; + struct packed { + logic q; + logic qe; + } dma_chunk_done; struct packed { logic q; logic qe; @@ -179,6 +189,10 @@ package dma_reg_pkg; logic d; logic de; } dma_done; + struct packed { + logic d; + logic de; + } dma_chunk_done; struct packed { logic d; logic de; @@ -293,9 +307,9 @@ package dma_reg_pkg; // Register -> HW type typedef struct packed { - 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_intr_state_reg_t intr_state; // [1042:1040] + dma_reg2hw_intr_enable_reg_t intr_enable; // [1039:1037] + dma_reg2hw_intr_test_reg_t intr_test; // [1036: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] @@ -320,7 +334,7 @@ package dma_reg_pkg; // HW -> register type typedef struct packed { - dma_hw2reg_intr_state_reg_t intr_state; // [701:698] + dma_hw2reg_intr_state_reg_t intr_state; // [703: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] @@ -396,8 +410,9 @@ package dma_reg_pkg; parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_10_OFFSET = 9'h 144; // Reset values for hwext registers and their fields - parameter logic [1:0] DMA_INTR_TEST_RESVAL = 2'h 0; + parameter logic [2:0] DMA_INTR_TEST_RESVAL = 3'h 0; parameter logic [0:0] DMA_INTR_TEST_DMA_DONE_RESVAL = 1'h 0; + parameter logic [0:0] DMA_INTR_TEST_DMA_CHUNK_DONE_RESVAL = 1'h 0; parameter logic [0:0] DMA_INTR_TEST_DMA_ERROR_RESVAL = 1'h 0; parameter logic [0:0] DMA_ALERT_TEST_RESVAL = 1'h 0; parameter logic [0:0] DMA_ALERT_TEST_FATAL_FAULT_RESVAL = 1'h 0; diff --git a/hw/ip/dma/rtl/dma_reg_top.sv b/hw/ip/dma/rtl/dma_reg_top.sv index 6940688c60497a..f154728c73dd9c 100644 --- a/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/ip/dma/rtl/dma_reg_top.sv @@ -121,15 +121,21 @@ module dma_reg_top ( // Define SW related signals // Format: __{wd|we|qs} // or _{wd|we|qs} if field == 1 or 0 + logic intr_state_we; logic intr_state_dma_done_qs; + logic intr_state_dma_chunk_done_qs; + logic intr_state_dma_chunk_done_wd; logic intr_state_dma_error_qs; logic intr_enable_we; logic intr_enable_dma_done_qs; logic intr_enable_dma_done_wd; + logic intr_enable_dma_chunk_done_qs; + logic intr_enable_dma_chunk_done_wd; logic intr_enable_dma_error_qs; logic intr_enable_dma_error_wd; logic intr_test_we; logic intr_test_dma_done_wd; + logic intr_test_dma_chunk_done_wd; logic intr_test_dma_error_wd; logic alert_test_we; logic alert_test_wd; @@ -329,7 +335,34 @@ module dma_reg_top ( .qs (intr_state_dma_done_qs) ); - // F[dma_error]: 1:1 + // F[dma_chunk_done]: 1:1 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW1C), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_intr_state_dma_chunk_done ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (intr_state_we), + .wd (intr_state_dma_chunk_done_wd), + + // from internal hardware + .de (hw2reg.intr_state.dma_chunk_done.de), + .d (hw2reg.intr_state.dma_chunk_done.d), + + // to internal hardware + .qe (), + .q (reg2hw.intr_state.dma_chunk_done.q), + .ds (), + + // to register interface (read) + .qs (intr_state_dma_chunk_done_qs) + ); + + // F[dma_error]: 2:2 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessRO), @@ -385,7 +418,34 @@ module dma_reg_top ( .qs (intr_enable_dma_done_qs) ); - // F[dma_error]: 1:1 + // F[dma_chunk_done]: 1:1 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_intr_enable_dma_chunk_done ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (intr_enable_we), + .wd (intr_enable_dma_chunk_done_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.intr_enable.dma_chunk_done.q), + .ds (), + + // to register interface (read) + .qs (intr_enable_dma_chunk_done_qs) + ); + + // F[dma_error]: 2:2 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessRW), @@ -415,7 +475,7 @@ module dma_reg_top ( // R[intr_test]: V(True) logic intr_test_qe; - logic [1:0] intr_test_flds_we; + logic [2:0] intr_test_flds_we; assign intr_test_qe = &intr_test_flds_we; // F[dma_done]: 0:0 prim_subreg_ext #( @@ -433,7 +493,23 @@ module dma_reg_top ( ); assign reg2hw.intr_test.dma_done.qe = intr_test_qe; - // F[dma_error]: 1:1 + // F[dma_chunk_done]: 1:1 + prim_subreg_ext #( + .DW (1) + ) u_intr_test_dma_chunk_done ( + .re (1'b0), + .we (intr_test_we), + .wd (intr_test_dma_chunk_done_wd), + .d ('0), + .qre (), + .qe (intr_test_flds_we[1]), + .q (reg2hw.intr_test.dma_chunk_done.q), + .ds (), + .qs () + ); + assign reg2hw.intr_test.dma_chunk_done.qe = intr_test_qe; + + // F[dma_error]: 2:2 prim_subreg_ext #( .DW (1) ) u_intr_test_dma_error ( @@ -442,7 +518,7 @@ module dma_reg_top ( .wd (intr_test_dma_error_wd), .d ('0), .qre (), - .qe (intr_test_flds_we[1]), + .qe (intr_test_flds_we[2]), .q (reg2hw.intr_test.dma_error.q), .ds (), .qs () @@ -3001,16 +3077,23 @@ module dma_reg_top ( end // Generate write-enables + assign intr_state_we = addr_hit[0] & reg_we & !reg_error; + + assign intr_state_dma_chunk_done_wd = reg_wdata[1]; assign intr_enable_we = addr_hit[1] & reg_we & !reg_error; assign intr_enable_dma_done_wd = reg_wdata[0]; - assign intr_enable_dma_error_wd = reg_wdata[1]; + assign intr_enable_dma_chunk_done_wd = reg_wdata[1]; + + assign intr_enable_dma_error_wd = reg_wdata[2]; assign intr_test_we = addr_hit[2] & reg_we & !reg_error; assign intr_test_dma_done_wd = reg_wdata[0]; - assign intr_test_dma_error_wd = reg_wdata[1]; + assign intr_test_dma_chunk_done_wd = reg_wdata[1]; + + assign intr_test_dma_error_wd = reg_wdata[2]; assign alert_test_we = addr_hit[3] & reg_we & !reg_error; assign alert_test_wd = reg_wdata[0]; @@ -3158,7 +3241,7 @@ module dma_reg_top ( // Assign write-enables to checker logic vector. always_comb begin reg_we_check = '0; - reg_we_check[0] = 1'b0; + reg_we_check[0] = intr_state_we; reg_we_check[1] = intr_enable_we; reg_we_check[2] = intr_test_we; reg_we_check[3] = alert_test_we; @@ -3227,17 +3310,20 @@ module dma_reg_top ( unique case (1'b1) addr_hit[0]: begin reg_rdata_next[0] = intr_state_dma_done_qs; - reg_rdata_next[1] = intr_state_dma_error_qs; + reg_rdata_next[1] = intr_state_dma_chunk_done_qs; + reg_rdata_next[2] = intr_state_dma_error_qs; end addr_hit[1]: begin reg_rdata_next[0] = intr_enable_dma_done_qs; - reg_rdata_next[1] = intr_enable_dma_error_qs; + reg_rdata_next[1] = intr_enable_dma_chunk_done_qs; + reg_rdata_next[2] = intr_enable_dma_error_qs; end addr_hit[2]: begin reg_rdata_next[0] = '0; reg_rdata_next[1] = '0; + reg_rdata_next[2] = '0; end addr_hit[3]: begin