From 2411b1dbd58b08e33c0584bd992d35b2144931f6 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 19 Sep 2024 11:24:09 +0200 Subject: [PATCH] [hw,dma,rtl] Use a status interrupt and interrupt prims Signed-off-by: Robert Schilling --- hw/ip/dma/data/dma.hjson | 2 + hw/ip/dma/doc/registers.md | 6 +-- hw/ip/dma/dv/env/dma_scoreboard.sv | 12 +++-- hw/ip/dma/rtl/dma.sv | 52 ++++++++++++------- hw/ip/dma/rtl/dma_reg_top.sv | 22 +++----- sw/device/lib/dif/autogen/dif_dma_autogen.c | 4 +- .../dif/autogen/dif_dma_autogen_unittest.cc | 2 +- sw/device/lib/testing/autogen/isr_testutils.c | 3 ++ sw/device/lib/testing/autogen/isr_testutils.h | 2 + 9 files changed, 61 insertions(+), 44 deletions(-) diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 3fd6605d068142..2807840fbc5543 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -100,9 +100,11 @@ interrupt_list: [ { name: "dma_done" desc: "DMA operation has been completed." + type: "status" } { name: "dma_error" desc: "DMA error has occurred. DMA_STATUS.error_code register shows the details." + type: "status" } ] alert_list: [ diff --git a/hw/ip/dma/doc/registers.md b/hw/ip/dma/doc/registers.md index 58e03fe5f5e65e..43ce2c4ccbccd8 100644 --- a/hw/ip/dma/doc/registers.md +++ b/hw/ip/dma/doc/registers.md @@ -76,14 +76,14 @@ Interrupt State Register ### Fields ```wavejson -{"reg": [{"name": "dma_done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "dma_error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 110}} +{"reg": [{"name": "dma_done", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "dma_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 110}} ``` | Bits | Type | Reset | Name | Description | |:------:|:------:|:-------:|:----------|:--------------------------------------------------------------------------| | 31:2 | | | | Reserved | -| 1 | rw1c | 0x0 | dma_error | DMA error has occurred. DMA_STATUS.error_code register shows the details. | -| 0 | rw1c | 0x0 | dma_done | DMA operation has been completed. | +| 1 | ro | 0x0 | dma_error | DMA error has occurred. DMA_STATUS.error_code register shows the details. | +| 0 | ro | 0x0 | dma_done | DMA operation has been completed. | ## INTR_ENABLE Interrupt Enable Register diff --git a/hw/ip/dma/dv/env/dma_scoreboard.sv b/hw/ip/dma/dv/env/dma_scoreboard.sv index a6615c4535e91a..66f624738b7c31 100644 --- a/hw/ip/dma/dv/env/dma_scoreboard.sv +++ b/hw/ip/dma/dv/env/dma_scoreboard.sv @@ -809,10 +809,6 @@ class dma_scoreboard extends cip_base_scoreboard #( // that may be changed according to the new enable bits. predict_interrupts(CSRtoIntrLatency, `gmv(ral.intr_state), item.a_data); end - "intr_state": begin - // Writing 1 to an INTR_STATE bit clears the corresponding asserted interrupt. - predict_interrupts(CSRtoIntrLatency, item.a_data & `gmv(ral.intr_enable), 0); - end "intr_test": begin `uvm_info(`gfn, $sformatf("intr_test write 0x%x with enables 0x%0x", item.a_data, intr_enable), UVM_HIGH) @@ -953,6 +949,14 @@ class dma_scoreboard extends cip_base_scoreboard #( index = get_index_from_reg_name(csr.get_name()); dma_config.intr_src_wr_val[index] = item.a_data; end + "status": begin + bit done, error; + done = get_field_val(ral.status.done, item.a_data); + error = get_field_val(ral.status.error, item.a_data); + // Clearing the status bits also clears the status interrupt + predict_interrupts(CSRtoIntrLatency, done << DMA_DONE & `gmv(ral.intr_enable), 0); + predict_interrupts(CSRtoIntrLatency, error << DMA_ERROR & `gmv(ral.intr_enable), 0); + end "control": begin bit go, initial_transfer, start_transfer; // Update the 'Aborted' prediction in response to setting the CONTROL.abort bit diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index 1b4c87124c7132..01f49545d049be 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -1079,17 +1079,39 @@ module dma assign sha2_data.mask = {<<1{req_dst_be_q}}; // Interrupt logic - logic test_done_interrupt; - logic test_error_interrupt; + prim_intr_hw #( + .IntrT ( "Status" ) + ) u_intr_dma_done ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .event_intr_i ( reg2hw.status.done.q ), + .reg2hw_intr_enable_q_i ( reg2hw.intr_enable.dma_done.q ), + .reg2hw_intr_test_q_i ( reg2hw.intr_test.dma_done.q ), + .reg2hw_intr_test_qe_i ( reg2hw.intr_test.dma_done.qe ), + .reg2hw_intr_state_q_i ( reg2hw.intr_state.dma_done.q ), + .hw2reg_intr_state_de_o ( hw2reg.intr_state.dma_done.de ), + .hw2reg_intr_state_d_o ( hw2reg.intr_state.dma_done.d ), + .intr_o ( intr_dma_done_o ) + ); + + prim_intr_hw #( + .IntrT ( "Status" ) + ) u_intr_error ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .event_intr_i ( reg2hw.status.error.q ), + .reg2hw_intr_enable_q_i ( reg2hw.intr_enable.dma_error.q ), + .reg2hw_intr_test_q_i ( reg2hw.intr_test.dma_error.q ), + .reg2hw_intr_test_qe_i ( reg2hw.intr_test.dma_error.qe ), + .reg2hw_intr_state_q_i ( reg2hw.intr_state.dma_error.q ), + .hw2reg_intr_state_de_o ( hw2reg.intr_state.dma_error.de ), + .hw2reg_intr_state_d_o ( hw2reg.intr_state.dma_error.d ), + .intr_o ( intr_dma_error_o ) + ); + logic data_move_state; logic update_dst_addr_reg, update_src_addr_reg; - assign test_done_interrupt = reg2hw.intr_test.dma_done.q && reg2hw.intr_test.dma_done.qe; - assign test_error_interrupt = reg2hw.intr_test.dma_error.q && reg2hw.intr_test.dma_error.qe; - - // Signal interrupt controller whenever an enabled interrupt info bit is set - assign intr_dma_done_o = reg2hw.intr_state.dma_done.q && reg2hw.intr_enable.dma_done.q; - assign intr_dma_error_o = reg2hw.intr_state.dma_error.q && reg2hw.intr_enable.dma_error.q; assign data_move_state = (ctrl_state_q == DmaSendWrite) || (ctrl_state_q == DmaWaitWriteResponse) || @@ -1114,8 +1136,6 @@ module dma transfer_remaining_bytes : chunk_remaining_bytes; always_comb begin - hw2reg = '0; - // Clear the go bit if we are in a single transfer and finished the DMA operation, // hardware handshake mode when we finished all transfers, or when aborting the transfer. hw2reg.control.go.de = clear_go || cfg_abort_en; @@ -1138,6 +1158,8 @@ module dma end end + hw2reg.control.initial_transfer.de = 1'b0; + hw2reg.control.initial_transfer.d = 1'b0; // Clear the inline initial transfer flag starting flag when leaving the DmaIdle the first time if ((ctrl_state_q == DmaIdle) && (ctrl_state_d != DmaIdle) && reg2hw.control.initial_transfer.q) begin @@ -1199,6 +1221,7 @@ module dma // SHA2-512: digest[0-7][63:0] store the 512-bit digest. for (int i = 0; i < NR_SHA_DIGEST_ELEMENTS; i++) begin hw2reg.sha2_digest[i].de = sha2_digest_set | clear_sha_status; + hw2reg.sha2_digest[i].d = '0; end // Only mux the digest data when sha2_digest_set is set. Setting the digest happens during the @@ -1251,15 +1274,6 @@ module dma hw2reg.control.abort.de = hw2reg.status.aborted.de; hw2reg.control.abort.d = 1'b0; - // 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; - hw2reg.intr_state.dma_error.d = 1'b1; - // Clear the SHA2 digests if the SHA2 valid flag is cleared (RW1C) if (reg2hw.status.sha2_digest_valid.qe & reg2hw.status.sha2_digest_valid.q) begin for (int i = 0; i < NR_SHA_DIGEST_ELEMENTS; i++) begin diff --git a/hw/ip/dma/rtl/dma_reg_top.sv b/hw/ip/dma/rtl/dma_reg_top.sv index ee01351fdff42a..6940688c60497a 100644 --- a/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/ip/dma/rtl/dma_reg_top.sv @@ -121,11 +121,8 @@ 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_done_wd; logic intr_state_dma_error_qs; - logic intr_state_dma_error_wd; logic intr_enable_we; logic intr_enable_dma_done_qs; logic intr_enable_dma_done_wd; @@ -308,7 +305,7 @@ module dma_reg_top ( // F[dma_done]: 0:0 prim_subreg #( .DW (1), - .SwAccess(prim_subreg_pkg::SwAccessW1C), + .SwAccess(prim_subreg_pkg::SwAccessRO), .RESVAL (1'h0), .Mubi (1'b0) ) u_intr_state_dma_done ( @@ -316,8 +313,8 @@ module dma_reg_top ( .rst_ni (rst_ni), // from register interface - .we (intr_state_we), - .wd (intr_state_dma_done_wd), + .we (1'b0), + .wd ('0), // from internal hardware .de (hw2reg.intr_state.dma_done.de), @@ -335,7 +332,7 @@ module dma_reg_top ( // F[dma_error]: 1:1 prim_subreg #( .DW (1), - .SwAccess(prim_subreg_pkg::SwAccessW1C), + .SwAccess(prim_subreg_pkg::SwAccessRO), .RESVAL (1'h0), .Mubi (1'b0) ) u_intr_state_dma_error ( @@ -343,8 +340,8 @@ module dma_reg_top ( .rst_ni (rst_ni), // from register interface - .we (intr_state_we), - .wd (intr_state_dma_error_wd), + .we (1'b0), + .wd ('0), // from internal hardware .de (hw2reg.intr_state.dma_error.de), @@ -3004,11 +3001,6 @@ module dma_reg_top ( end // Generate write-enables - assign intr_state_we = addr_hit[0] & reg_we & !reg_error; - - assign intr_state_dma_done_wd = reg_wdata[0]; - - assign intr_state_dma_error_wd = reg_wdata[1]; assign intr_enable_we = addr_hit[1] & reg_we & !reg_error; assign intr_enable_dma_done_wd = reg_wdata[0]; @@ -3166,7 +3158,7 @@ module dma_reg_top ( // Assign write-enables to checker logic vector. always_comb begin reg_we_check = '0; - reg_we_check[0] = intr_state_we; + reg_we_check[0] = 1'b0; reg_we_check[1] = intr_enable_we; reg_we_check[2] = intr_test_we; reg_we_check[3] = alert_test_we; diff --git a/sw/device/lib/dif/autogen/dif_dma_autogen.c b/sw/device/lib/dif/autogen/dif_dma_autogen.c index d79f9be8878a23..55f586c408e1f9 100644 --- a/sw/device/lib/dif/autogen/dif_dma_autogen.c +++ b/sw/device/lib/dif/autogen/dif_dma_autogen.c @@ -65,8 +65,8 @@ static bool dma_get_irq_bit_index(dif_dma_irq_t irq, } static dif_irq_type_t irq_types[] = { - kDifIrqTypeEvent, - kDifIrqTypeEvent, + kDifIrqTypeStatus, + kDifIrqTypeStatus, }; OT_WARN_UNUSED_RESULT diff --git a/sw/device/lib/dif/autogen/dif_dma_autogen_unittest.cc b/sw/device/lib/dif/autogen/dif_dma_autogen_unittest.cc index 8bf21514c738ce..31fdc68c3bd636 100644 --- a/sw/device/lib/dif/autogen/dif_dma_autogen_unittest.cc +++ b/sw/device/lib/dif/autogen/dif_dma_autogen_unittest.cc @@ -77,7 +77,7 @@ TEST_F(IrqGetTypeTest, Success) { dif_irq_type_t type; EXPECT_DIF_OK(dif_dma_irq_get_type(&dma_, kDifDmaIrqDmaDone, &type)); - EXPECT_EQ(type, kDifIrqTypeEvent); + EXPECT_EQ(type, kDifIrqTypeStatus); } class IrqGetStateTest : public DmaTest {}; diff --git a/sw/device/lib/testing/autogen/isr_testutils.c b/sw/device/lib/testing/autogen/isr_testutils.c index 08a51444855aff..c6224321ad4e59 100644 --- a/sw/device/lib/testing/autogen/isr_testutils.c +++ b/sw/device/lib/testing/autogen/isr_testutils.c @@ -213,6 +213,7 @@ void isr_testutils_csrng_isr( } void isr_testutils_dma_isr(plic_isr_ctx_t plic_ctx, dma_isr_ctx_t dma_ctx, + bool mute_status_irq, top_earlgrey_plic_peripheral_t *peripheral_serviced, dif_dma_irq_t *irq_serviced) { // Claim the IRQ at the PLIC. @@ -243,6 +244,8 @@ void isr_testutils_dma_isr(plic_isr_ctx_t plic_ctx, dma_isr_ctx_t dma_ctx, CHECK_DIF_OK(dif_dma_irq_get_type(dma_ctx.dma, irq, &type)); if (type == kDifIrqTypeEvent) { CHECK_DIF_OK(dif_dma_irq_acknowledge(dma_ctx.dma, irq)); + } else if (mute_status_irq) { + CHECK_DIF_OK(dif_dma_irq_set_enabled(dma_ctx.dma, irq, kDifToggleDisabled)); } // Complete the IRQ at the PLIC. diff --git a/sw/device/lib/testing/autogen/isr_testutils.h b/sw/device/lib/testing/autogen/isr_testutils.h index 51cef3137eb9ba..544fc4e2e94845 100644 --- a/sw/device/lib/testing/autogen/isr_testutils.h +++ b/sw/device/lib/testing/autogen/isr_testutils.h @@ -691,11 +691,13 @@ void isr_testutils_csrng_isr( * * @param plic_ctx A PLIC ISR context handle. * @param dma_ctx A(n) dma ISR context handle. + * @param mute_status_irq set to true to disable the serviced status type IRQ. * @param[out] peripheral_serviced Out param for the peripheral that was * serviced. * @param[out] irq_serviced Out param for the IRQ that was serviced. */ void isr_testutils_dma_isr(plic_isr_ctx_t plic_ctx, dma_isr_ctx_t dma_ctx, + bool mute_status_irq, top_earlgrey_plic_peripheral_t *peripheral_serviced, dif_dma_irq_t *irq_serviced);