From 5cfea4863e8ce669e05b0424e7471be129084385 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 9 Aug 2024 11:06:39 -0700 Subject: [PATCH] [hw,dma,rtl] Flexible address increment options This PR adds support for a flexible address increment mode. For the source and destination address, the DMA can be configured to perform: * No address increment (FIXED). The DMA always reads/writes from the same address. * Wrapped increment (WRAP). The DMA increments and when finishing one chunk wraps back to the starting address. * Linear increment (LINEAR). The DMA always increments the address These modes are independent of the hardware handshake mode. Signed-off-by: Robert Schilling --- hw/ip/dma/data/dma.hjson | 61 +++++++++++------- hw/ip/dma/doc/registers.md | 86 +++++++++++++------------ hw/ip/dma/rtl/dma.sv | 102 +++++++++++++++--------------- hw/ip/dma/rtl/dma_pkg.sv | 15 +++-- hw/ip/dma/rtl/dma_reg_pkg.sv | 69 ++++++++++---------- hw/ip/dma/rtl/dma_reg_top.sv | 119 +++++++++++++++++------------------ 6 files changed, 239 insertions(+), 213 deletions(-) diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 2807840fbc5543..18581d035c59fd 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -466,35 +466,49 @@ No explicit clearing necessary. ''' } - { bits: "5" - name: "memory_buffer_auto_increment_enable" + { bits: "6:5" + name: "src_addr_mode" resval: 0x0 desc: ''' - Used in conjunction with the hardware handshake mode of operation. - Auto Increments the memory buffer address register by data size to point to the next memory buffer address. - Generate a warning (assert interrupt) if the auto-incremented address reaches close to the value set in limit address register to prevent destination buffer overflow. - Enables firmware to take appropriate action prior to reaching the limit. + Defines the address increment behavior for the source address. ''' + enum: [ + { value: "0", + name: "FIXED" + desc: "Do not increment the address, always read from the same address." + } + { value: "1", + name: "WRAP" + desc: "Wrap the address to the beginning after transferring one chunk." + } + { value: "2", + name: "LINEAR" + desc: "Always increment the source address." + } + ] } - { bits: "6" - name: "fifo_auto_increment_enable" + { bits: "8:7" + name: "dst_addr_mode" resval: 0x0 desc: ''' - Used in conjunction with the hardware handshake mode of operation. - If set, reads/writes from/to incremental addresses for FIFO data accesses within each chunk, resetting to the initial value at the beginning of each new chunk. - Else uses the same address for all transactions. - ''' - } - { bits: "7" - name: "data_direction" - resval: 0x0 - desc: ''' - Used in conjunction with the hardware handshake enable. - 0: Receive data from LSIO FIFO to memory buffer. - 1: Send data from memory buffer to LSIO FIFO. + Defines the address increment behavior for the destination address. ''' + enum: [ + { value: "0", + name: "FIXED" + desc: "Do not increment the address, always write to the same address." + } + { value: "1", + name: "WRAP" + desc: "Wrap the address to the beginning after transferring one chunk." + } + { value: "2", + name: "LINEAR" + desc: "Always increment the destination address." + } + ] } - { bits: "8" + { bits: "9" name: "initial_transfer" resval: 0x0 hwaccess: "hrw" @@ -644,6 +658,11 @@ resval: 0x0 desc: "The source or destination ASID contains an invalid value." } + { bits: "8" + name: "addr_increment_error" + resval: 0x0 + desc: "The source or destination address increment mode contains an invalid value." + } ] } { multireg: { diff --git a/hw/ip/dma/doc/registers.md b/hw/ip/dma/doc/registers.md index 43ce2c4ccbccd8..4170acb623eae1 100644 --- a/hw/ip/dma/doc/registers.md +++ b/hw/ip/dma/doc/registers.md @@ -453,26 +453,25 @@ Other values are reserved. Control register for DMA data movement. - Offset: `0x44` - Reset default: `0x0` -- Reset mask: `0x880001ff` +- Reset mask: `0x880003ff` ### Fields ```wavejson -{"reg": [{"name": "opcode", "bits": 4, "attr": ["rw"], "rotate": 0}, {"name": "hardware_handshake_enable", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "memory_buffer_auto_increment_enable", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "fifo_auto_increment_enable", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "data_direction", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "initial_transfer", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 18}, {"name": "abort", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 3}, {"name": "go", "bits": 1, "attr": ["rw"], "rotate": -90}], "config": {"lanes": 1, "fontsize": 10, "vspace": 370}} +{"reg": [{"name": "opcode", "bits": 4, "attr": ["rw"], "rotate": 0}, {"name": "hardware_handshake_enable", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "src_addr_mode", "bits": 2, "attr": ["rw"], "rotate": -90}, {"name": "dst_addr_mode", "bits": 2, "attr": ["rw"], "rotate": -90}, {"name": "initial_transfer", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 17}, {"name": "abort", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 3}, {"name": "go", "bits": 1, "attr": ["rw"], "rotate": -90}], "config": {"lanes": 1, "fontsize": 10, "vspace": 270}} ``` -| Bits | Type | Reset | Name | -|:------:|:------:|:-------:|:-------------------------------------------------------------------------------------| -| 31 | rw | 0x0 | [go](#control--go) | -| 30:28 | | | Reserved | -| 27 | wo | 0x0 | [abort](#control--abort) | -| 26:9 | | | Reserved | -| 8 | rw | 0x0 | [initial_transfer](#control--initial_transfer) | -| 7 | rw | 0x0 | [data_direction](#control--data_direction) | -| 6 | rw | 0x0 | [fifo_auto_increment_enable](#control--fifo_auto_increment_enable) | -| 5 | rw | 0x0 | [memory_buffer_auto_increment_enable](#control--memory_buffer_auto_increment_enable) | -| 4 | rw | 0x0 | [hardware_handshake_enable](#control--hardware_handshake_enable) | -| 3:0 | rw | 0x0 | [opcode](#control--opcode) | +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:-----------------------------------------------------------------| +| 31 | rw | 0x0 | [go](#control--go) | +| 30:28 | | | Reserved | +| 27 | wo | 0x0 | [abort](#control--abort) | +| 26:10 | | | Reserved | +| 9 | rw | 0x0 | [initial_transfer](#control--initial_transfer) | +| 8:7 | rw | 0x0 | [dst_addr_mode](#control--dst_addr_mode) | +| 6:5 | rw | 0x0 | [src_addr_mode](#control--src_addr_mode) | +| 4 | rw | 0x0 | [hardware_handshake_enable](#control--hardware_handshake_enable) | +| 3:0 | rw | 0x0 | [opcode](#control--opcode) | ### CONTROL . go Trigger the DMA operation when the Go bit is set. @@ -490,21 +489,27 @@ Marks the initial transfer to initialize the DMA and SHA engine for one transfer Used for hardware handshake and ordinary transfers, in which multiple transfers contribute to a final digest. Note, for non-handshake transfers with inline hashing mode enabled, this bit must be set to also mark the first transfer. -### CONTROL . data_direction -Used in conjunction with the hardware handshake enable. -0: Receive data from LSIO FIFO to memory buffer. -1: Send data from memory buffer to LSIO FIFO. +### CONTROL . dst_addr_mode +Defines the address increment behavior for the destination address. -### CONTROL . fifo_auto_increment_enable -Used in conjunction with the hardware handshake mode of operation. -If set, reads/writes from/to incremental addresses for FIFO data accesses within each chunk, resetting to the initial value at the beginning of each new chunk. -Else uses the same address for all transactions. +| Value | Name | Description | +|:--------|:-------|:----------------------------------------------------------------| +| 0x0 | FIXED | Do not increment the address, always write to the same address. | +| 0x1 | WRAP | Wrap the address to the beginning after transferring one chunk. | +| 0x2 | LINEAR | Always increment the destination address. | -### CONTROL . memory_buffer_auto_increment_enable -Used in conjunction with the hardware handshake mode of operation. -Auto Increments the memory buffer address register by data size to point to the next memory buffer address. -Generate a warning (assert interrupt) if the auto-incremented address reaches close to the value set in limit address register to prevent destination buffer overflow. -Enables firmware to take appropriate action prior to reaching the limit. +Other values are reserved. + +### CONTROL . src_addr_mode +Defines the address increment behavior for the source address. + +| Value | Name | Description | +|:--------|:-------|:-----------------------------------------------------------------| +| 0x0 | FIXED | Do not increment the address, always read from the same address. | +| 0x1 | WRAP | Wrap the address to the beginning after transferring one chunk. | +| 0x2 | LINEAR | Always increment the source address. | + +Other values are reserved. ### CONTROL . hardware_handshake_enable Enable hardware handshake mode. @@ -555,25 +560,26 @@ Denotes the source of the operational error. The error is cleared by writing the RW1C STATUS.error register. - Offset: `0x4c` - Reset default: `0x0` -- Reset mask: `0xff` +- Reset mask: `0x1ff` ### Fields ```wavejson -{"reg": [{"name": "src_addr_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "dst_addr_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "opcode_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "size_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "bus_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "base_limit_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "range_valid_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "asid_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 24}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}} +{"reg": [{"name": "src_addr_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "dst_addr_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "opcode_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "size_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "bus_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "base_limit_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "range_valid_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "asid_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "addr_increment_error", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 23}], "config": {"lanes": 1, "fontsize": 10, "vspace": 220}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:------------------|:--------------------------------------------------------------------------------------------------------------------------------------| -| 31:8 | | | | Reserved | -| 7 | ro | 0x0 | asid_error | The source or destination ASID contains an invalid value. | -| 6 | ro | 0x0 | range_valid_error | The DMA enabled memory range is not configured. | -| 5 | ro | 0x0 | base_limit_error | The base and limit addresses contain an invalid value. | -| 4 | ro | 0x0 | bus_error | The bus transfer returned an error. | -| 3 | ro | 0x0 | size_error | TRANSFER_WIDTH encodes an invalid value, TOTAL_DATA_SIZE or CHUNK_SIZE are zero, or inline hashing is not using 32-bit transfer width | -| 2 | ro | 0x0 | opcode_error | Opcode is invalid. | -| 1 | ro | 0x0 | dst_addr_error | Destination address is invalid. | -| 0 | ro | 0x0 | src_addr_error | Source address is invalid. | +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:---------------------|:--------------------------------------------------------------------------------------------------------------------------------------| +| 31:9 | | | | Reserved | +| 8 | ro | 0x0 | addr_increment_error | The source or destination address increment mode contains an invalid value. | +| 7 | ro | 0x0 | asid_error | The source or destination ASID contains an invalid value. | +| 6 | ro | 0x0 | range_valid_error | The DMA enabled memory range is not configured. | +| 5 | ro | 0x0 | base_limit_error | The base and limit addresses contain an invalid value. | +| 4 | ro | 0x0 | bus_error | The bus transfer returned an error. | +| 3 | ro | 0x0 | size_error | TRANSFER_WIDTH encodes an invalid value, TOTAL_DATA_SIZE or CHUNK_SIZE are zero, or inline hashing is not using 32-bit transfer width | +| 2 | ro | 0x0 | opcode_error | Opcode is invalid. | +| 1 | ro | 0x0 | dst_addr_error | Destination address is invalid. | +| 0 | ro | 0x0 | src_addr_error | Source address is invalid. | ## SHA2_DIGEST Digest register for the inline hashing operation. diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index 1adcfb9ffd757b..3e212f84ccdfd2 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -71,7 +71,6 @@ module dma logic capture_return_data; logic [top_pkg::TL_DW-1:0] read_return_data_q, read_return_data_d, dma_rsp_data; - logic [SYS_ADDR_WIDTH-1:0] new_src_addr, new_dst_addr; logic dma_state_error; dma_ctrl_state_e ctrl_state_q, ctrl_state_d; @@ -267,14 +266,11 @@ module dma always_comb begin control_d.opcode = opcode_e'(reg2hw.control.opcode.q); control_d.cfg_handshake_en = reg2hw.control.hardware_handshake_enable.q; - control_d.cfg_data_direction = reg2hw.control.data_direction.q; - control_d.cfg_fifo_auto_increment_en = reg2hw.control.fifo_auto_increment_enable.q; + control_d.src_addr_mode = addr_incr_e'(reg2hw.control.src_addr_mode.q); + control_d.dst_addr_mode = addr_incr_e'(reg2hw.control.dst_addr_mode.q); control_d.range_valid = reg2hw.range_valid.q; control_d.enabled_memory_range_base = reg2hw.enabled_memory_range_base.q; control_d.enabled_memory_range_limit = reg2hw.enabled_memory_range_limit.q; - - control_d.cfg_memory_buffer_auto_increment_en = - reg2hw.control.memory_buffer_auto_increment_enable.q; end prim_flop_en #( @@ -747,30 +743,28 @@ module dma default: next_error[DmaSizeErr] = 1'b1; // Invalid transfer_width endcase + // Use start address on first byte of transaction if ((transfer_byte_q == '0) || - (control_q.cfg_handshake_en && - // Does the source address need resetting to the configured base address? - ((control_q.cfg_data_direction && chunk_byte_q == '0 && - !control_q.cfg_memory_buffer_auto_increment_en) || - (!control_q.cfg_data_direction && - (chunk_byte_q == '0 || !control_q.cfg_fifo_auto_increment_en))))) begin + // or when being in the fixed address mode + control_q.src_addr_mode == AddrIncrFixed || + // or when transferring the first byte of a chunk and in wrapped increment mode + (chunk_byte_q == '0 && control_q.src_addr_mode == AddrIncrWrap)) begin src_addr_d = {reg2hw.src_addr_hi.q, reg2hw.src_addr_lo.q}; end else begin // Advance from the previous transaction within this chunk src_addr_d = src_addr_q + SYS_ADDR_WIDTH'(transfer_width_d); end + // Use start address on first byte of transaction if ((transfer_byte_q == '0) || - (control_q.cfg_handshake_en && - // Does the destination address need resetting to the configured base address? - ((!control_q.cfg_data_direction && chunk_byte_q == '0 && - !control_q.cfg_memory_buffer_auto_increment_en) || - (control_q.cfg_data_direction && - (chunk_byte_q == '0 || !control_q.cfg_fifo_auto_increment_en))))) begin - dst_addr_d = {reg2hw.dst_addr_hi.q, reg2hw.dst_addr_lo.q}; + // or when being in the fixed address mode + control_q.dst_addr_mode == AddrIncrFixed || + // or when transferring the first byte of a chunk and in wrapped increment mode + (chunk_byte_q == '0 && control_q.dst_addr_mode == AddrIncrWrap)) begin + dst_addr_d = {reg2hw.src_addr_hi.q, reg2hw.src_addr_lo.q}; end else begin // Advance from the previous transaction within this chunk - dst_addr_d = dst_addr_q + SYS_ADDR_WIDTH'(transfer_width_d); + dst_addr_d = src_addr_q + SYS_ADDR_WIDTH'(transfer_width_d); end unique case (transfer_width_d) @@ -818,6 +812,14 @@ module dma next_error[DmaOpcodeErr] = 1'b1; end + if (!(control_q.src_addr_mode inside {AddrIncrFixed, AddrIncrWrap, AddrIncrLinear})) begin + next_error[DmaAddrIncrErr] = 1'b1; + end + + if (!(control_q.dst_addr_mode inside {AddrIncrFixed, AddrIncrWrap, AddrIncrLinear})) begin + next_error[DmaAddrIncrErr] = 1'b1; + end + // Inline hashing is only allowed for 32-bit transfer width if (use_inline_hashing) begin if (reg2hw.transfer_width.q != DmaXfer4BperTxn) begin @@ -1123,14 +1125,6 @@ module dma (ctrl_state_q == DmaShaWait) || (ctrl_state_q == DmaShaFinalize); - assign new_dst_addr = control_q.cfg_data_direction ? - ({reg2hw.dst_addr_hi.q, reg2hw.dst_addr_lo.q} + SYS_ADDR_WIDTH'(transfer_width_q)) : - ({reg2hw.dst_addr_hi.q, reg2hw.dst_addr_lo.q} + SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)); - - assign new_src_addr = control_q.cfg_data_direction ? - ({reg2hw.src_addr_hi.q, reg2hw.src_addr_lo.q} + SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)) : - ({reg2hw.src_addr_hi.q, reg2hw.src_addr_lo.q} + SYS_ADDR_WIDTH'(transfer_width_q)); - // Calculate the number of bytes remaining until the end of the current chunk. // Note that the total transfer size may be a non-integral multiple of the programmed chunk size, // so we must consider the `total_data_size` here too; this is important in determining the @@ -1167,14 +1161,6 @@ 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 - hw2reg.control.initial_transfer.de = 1'b1; - end - hw2reg.dst_addr_hi.de = update_dst_addr_reg; hw2reg.dst_addr_hi.d = new_dst_addr[63:32]; @@ -1187,6 +1173,14 @@ module dma hw2reg.src_addr_lo.de = update_src_addr_reg; hw2reg.src_addr_lo.d = new_src_addr[31:0]; + 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 + hw2reg.control.initial_transfer.de = 1'b1; + end + // Assert busy write enable on // - transitions from IDLE out // - clearing the go bit (going back to idle) @@ -1261,23 +1255,25 @@ module dma set_error_code = (ctrl_state_q != DmaError) && (ctrl_state_d == DmaError); // Fiddle out error signals - hw2reg.error_code.src_addr_error.de = set_error_code | clear_status; - hw2reg.error_code.dst_addr_error.de = set_error_code | clear_status; - hw2reg.error_code.opcode_error.de = set_error_code | clear_status; - hw2reg.error_code.size_error.de = set_error_code | clear_status; - hw2reg.error_code.bus_error.de = set_error_code | clear_status; - hw2reg.error_code.base_limit_error.de = set_error_code | clear_status; - hw2reg.error_code.range_valid_error.de = set_error_code | clear_status; - hw2reg.error_code.asid_error.de = set_error_code | clear_status; - - hw2reg.error_code.src_addr_error.d = clear_status? '0 : next_error[DmaSrcAddrErr]; - hw2reg.error_code.dst_addr_error.d = clear_status? '0 : next_error[DmaDstAddrErr]; - hw2reg.error_code.opcode_error.d = clear_status? '0 : next_error[DmaOpcodeErr]; - hw2reg.error_code.size_error.d = clear_status? '0 : next_error[DmaSizeErr]; - hw2reg.error_code.bus_error.d = clear_status? '0 : next_error[DmaBusErr]; - hw2reg.error_code.base_limit_error.d = clear_status? '0 : next_error[DmaBaseLimitErr]; - hw2reg.error_code.range_valid_error.d = clear_status? '0 : next_error[DmaRangeValidErr]; - hw2reg.error_code.asid_error.d = clear_status? '0 : next_error[DmaAsidErr]; + hw2reg.error_code.src_addr_error.de = set_error_code | clear_status; + hw2reg.error_code.dst_addr_error.de = set_error_code | clear_status; + hw2reg.error_code.opcode_error.de = set_error_code | clear_status; + hw2reg.error_code.size_error.de = set_error_code | clear_status; + hw2reg.error_code.bus_error.de = set_error_code | clear_status; + hw2reg.error_code.base_limit_error.de = set_error_code | clear_status; + hw2reg.error_code.range_valid_error.de = set_error_code | clear_status; + hw2reg.error_code.asid_error.de = set_error_code | clear_status; + hw2reg.error_code.addr_increment_error.de = set_error_code | clear_status; + + hw2reg.error_code.src_addr_error.d = clear_status? '0 : next_error[DmaSrcAddrErr]; + hw2reg.error_code.dst_addr_error.d = clear_status? '0 : next_error[DmaDstAddrErr]; + hw2reg.error_code.opcode_error.d = clear_status? '0 : next_error[DmaOpcodeErr]; + hw2reg.error_code.size_error.d = clear_status? '0 : next_error[DmaSizeErr]; + hw2reg.error_code.bus_error.d = clear_status? '0 : next_error[DmaBusErr]; + hw2reg.error_code.base_limit_error.d = clear_status? '0 : next_error[DmaBaseLimitErr]; + hw2reg.error_code.range_valid_error.d = clear_status? '0 : next_error[DmaRangeValidErr]; + hw2reg.error_code.asid_error.d = clear_status? '0 : next_error[DmaAsidErr]; + hw2reg.error_code.addr_increment_error.d = clear_status? '0 : next_error[DmaAddrIncrErr]; // Clear the control.abort bit once we have handled the abort request hw2reg.control.abort.de = hw2reg.status.aborted.de; diff --git a/hw/ip/dma/rtl/dma_pkg.sv b/hw/ip/dma/rtl/dma_pkg.sv index 0c7a45fdb496d9..02ffe65f06ff27 100644 --- a/hw/ip/dma/rtl/dma_pkg.sv +++ b/hw/ip/dma/rtl/dma_pkg.sv @@ -8,7 +8,7 @@ package dma_pkg; typedef logic [dma_reg_pkg::NumIntClearSources-1:0] lsio_trigger_t; // Possible error bits the DMA can raise - typedef enum logic [3:0] { + typedef enum logic [4:0] { DmaSrcAddrErr, DmaDstAddrErr, DmaOpcodeErr, @@ -17,6 +17,7 @@ package dma_pkg; DmaBaseLimitErr, DmaRangeValidErr, DmaAsidErr, + DmaAddrIncrErr, DmaErrLast } dma_error_e; @@ -44,14 +45,20 @@ package dma_pkg; OpcSha512 = 4'h3 } opcode_e; + // Supported address increment modes by the DMA + typedef enum logic [1:0] { + AddrIncrFixed = 2'h0, + AddrIncrWrap = 2'h1, + AddrIncrLinear = 2'h2 + } addr_incr_e; + // Control state captured during the operation typedef struct packed { // Control register opcode_e opcode; logic cfg_handshake_en; - logic cfg_memory_buffer_auto_increment_en; - logic cfg_fifo_auto_increment_en; - logic cfg_data_direction; + addr_incr_e src_addr_mode; + addr_incr_e dst_addr_mode; logic range_valid; // Enabled memory base register logic [31:0] enabled_memory_range_base; diff --git a/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/ip/dma/rtl/dma_reg_pkg.sv index f0565bdd5a292d..199302c39a549c 100644 --- a/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -118,14 +118,11 @@ package dma_reg_pkg; logic q; } initial_transfer; struct packed { - logic q; - } data_direction; - struct packed { - logic q; - } fifo_auto_increment_enable; + logic [1:0] q; + } dst_addr_mode; struct packed { - logic q; - } memory_buffer_auto_increment_enable; + logic [1:0] q; + } src_addr_mode; struct packed { logic q; } hardware_handshake_enable; @@ -284,6 +281,10 @@ package dma_reg_pkg; logic d; logic de; } asid_error; + struct packed { + logic d; + logic de; + } addr_increment_error; } dma_hw2reg_error_code_reg_t; typedef struct packed { @@ -293,23 +294,23 @@ 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_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_intr_state_reg_t intr_state; // [1039:1038] + dma_reg2hw_intr_enable_reg_t intr_enable; // [1037:1036] + dma_reg2hw_intr_test_reg_t intr_test; // [1035:1032] + dma_reg2hw_alert_test_reg_t alert_test; // [1031:1030] + dma_reg2hw_src_addr_lo_reg_t src_addr_lo; // [1029:998] + dma_reg2hw_src_addr_hi_reg_t src_addr_hi; // [997:966] + dma_reg2hw_dst_addr_lo_reg_t dst_addr_lo; // [965:934] + dma_reg2hw_dst_addr_hi_reg_t dst_addr_hi; // [933:902] + dma_reg2hw_addr_space_id_reg_t addr_space_id; // [901:894] + dma_reg2hw_enabled_memory_range_base_reg_t enabled_memory_range_base; // [893:861] + dma_reg2hw_enabled_memory_range_limit_reg_t enabled_memory_range_limit; // [860:828] + dma_reg2hw_range_valid_reg_t range_valid; // [827:827] + dma_reg2hw_range_regwen_reg_t range_regwen; // [826:823] + dma_reg2hw_total_data_size_reg_t total_data_size; // [822:791] + dma_reg2hw_chunk_data_size_reg_t chunk_data_size; // [790:759] + dma_reg2hw_transfer_width_reg_t transfer_width; // [758:757] + dma_reg2hw_control_reg_t control; // [756: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] @@ -320,15 +321,15 @@ package dma_reg_pkg; // HW -> register type typedef struct packed { - 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_intr_state_reg_t intr_state; // [703:700] + dma_hw2reg_src_addr_lo_reg_t src_addr_lo; // [699:667] + dma_hw2reg_src_addr_hi_reg_t src_addr_hi; // [666:634] + dma_hw2reg_dst_addr_lo_reg_t dst_addr_lo; // [633:601] + dma_hw2reg_dst_addr_hi_reg_t dst_addr_hi; // [600:568] + dma_hw2reg_cfg_regwen_reg_t cfg_regwen; // [567:564] + dma_hw2reg_control_reg_t control; // [563:558] + dma_hw2reg_status_reg_t status; // [557:546] + dma_hw2reg_error_code_reg_t error_code; // [545:528] dma_hw2reg_sha2_digest_mreg_t [15:0] sha2_digest; // [527:0] } dma_hw2reg_t; @@ -490,7 +491,7 @@ package dma_reg_pkg; 4'b 0001, // index[16] DMA_TRANSFER_WIDTH 4'b 1111, // index[17] DMA_CONTROL 4'b 0001, // index[18] DMA_STATUS - 4'b 0001, // index[19] DMA_ERROR_CODE + 4'b 0011, // index[19] DMA_ERROR_CODE 4'b 1111, // index[20] DMA_SHA2_DIGEST_0 4'b 1111, // index[21] DMA_SHA2_DIGEST_1 4'b 1111, // index[22] DMA_SHA2_DIGEST_2 diff --git a/hw/ip/dma/rtl/dma_reg_top.sv b/hw/ip/dma/rtl/dma_reg_top.sv index 6940688c60497a..8bdee60d2bb58d 100644 --- a/hw/ip/dma/rtl/dma_reg_top.sv +++ b/hw/ip/dma/rtl/dma_reg_top.sv @@ -178,12 +178,10 @@ module dma_reg_top ( logic [3:0] control_opcode_wd; logic control_hardware_handshake_enable_qs; logic control_hardware_handshake_enable_wd; - logic control_memory_buffer_auto_increment_enable_qs; - logic control_memory_buffer_auto_increment_enable_wd; - logic control_fifo_auto_increment_enable_qs; - logic control_fifo_auto_increment_enable_wd; - logic control_data_direction_qs; - logic control_data_direction_wd; + logic [1:0] control_src_addr_mode_qs; + logic [1:0] control_src_addr_mode_wd; + logic [1:0] control_dst_addr_mode_qs; + logic [1:0] control_dst_addr_mode_wd; logic control_initial_transfer_qs; logic control_initial_transfer_wd; logic control_abort_wd; @@ -208,6 +206,7 @@ module dma_reg_top ( logic error_code_base_limit_error_qs; logic error_code_range_valid_error_qs; logic error_code_asid_error_qs; + logic error_code_addr_increment_error_qs; logic [31:0] sha2_digest_0_qs; logic [31:0] sha2_digest_1_qs; logic [31:0] sha2_digest_2_qs; @@ -931,7 +930,7 @@ module dma_reg_top ( // R[control]: V(False) logic control_qe; - logic [7:0] control_flds_we; + logic [6:0] control_flds_we; prim_flop #( .Width(1), .ResetValue(0) @@ -995,19 +994,19 @@ module dma_reg_top ( .qs (control_hardware_handshake_enable_qs) ); - // F[memory_buffer_auto_increment_enable]: 5:5 + // F[src_addr_mode]: 6:5 prim_subreg #( - .DW (1), + .DW (2), .SwAccess(prim_subreg_pkg::SwAccessRW), - .RESVAL (1'h0), + .RESVAL (2'h0), .Mubi (1'b0) - ) u_control_memory_buffer_auto_increment_enable ( + ) u_control_src_addr_mode ( .clk_i (clk_i), .rst_ni (rst_ni), // from register interface .we (control_we), - .wd (control_memory_buffer_auto_increment_enable_wd), + .wd (control_src_addr_mode_wd), // from internal hardware .de (1'b0), @@ -1015,26 +1014,26 @@ module dma_reg_top ( // to internal hardware .qe (control_flds_we[2]), - .q (reg2hw.control.memory_buffer_auto_increment_enable.q), + .q (reg2hw.control.src_addr_mode.q), .ds (), // to register interface (read) - .qs (control_memory_buffer_auto_increment_enable_qs) + .qs (control_src_addr_mode_qs) ); - // F[fifo_auto_increment_enable]: 6:6 + // F[dst_addr_mode]: 8:7 prim_subreg #( - .DW (1), + .DW (2), .SwAccess(prim_subreg_pkg::SwAccessRW), - .RESVAL (1'h0), + .RESVAL (2'h0), .Mubi (1'b0) - ) u_control_fifo_auto_increment_enable ( + ) u_control_dst_addr_mode ( .clk_i (clk_i), .rst_ni (rst_ni), // from register interface .we (control_we), - .wd (control_fifo_auto_increment_enable_wd), + .wd (control_dst_addr_mode_wd), // from internal hardware .de (1'b0), @@ -1042,41 +1041,14 @@ module dma_reg_top ( // to internal hardware .qe (control_flds_we[3]), - .q (reg2hw.control.fifo_auto_increment_enable.q), - .ds (), - - // to register interface (read) - .qs (control_fifo_auto_increment_enable_qs) - ); - - // F[data_direction]: 7:7 - prim_subreg #( - .DW (1), - .SwAccess(prim_subreg_pkg::SwAccessRW), - .RESVAL (1'h0), - .Mubi (1'b0) - ) u_control_data_direction ( - .clk_i (clk_i), - .rst_ni (rst_ni), - - // from register interface - .we (control_we), - .wd (control_data_direction_wd), - - // from internal hardware - .de (1'b0), - .d ('0), - - // to internal hardware - .qe (control_flds_we[4]), - .q (reg2hw.control.data_direction.q), + .q (reg2hw.control.dst_addr_mode.q), .ds (), // to register interface (read) - .qs (control_data_direction_qs) + .qs (control_dst_addr_mode_qs) ); - // F[initial_transfer]: 8:8 + // F[initial_transfer]: 9:9 prim_subreg #( .DW (1), .SwAccess(prim_subreg_pkg::SwAccessRW), @@ -1095,7 +1067,7 @@ module dma_reg_top ( .d (hw2reg.control.initial_transfer.d), // to internal hardware - .qe (control_flds_we[5]), + .qe (control_flds_we[4]), .q (reg2hw.control.initial_transfer.q), .ds (), @@ -1122,7 +1094,7 @@ module dma_reg_top ( .d (hw2reg.control.abort.d), // to internal hardware - .qe (control_flds_we[6]), + .qe (control_flds_we[5]), .q (reg2hw.control.abort.q), .ds (), @@ -1149,7 +1121,7 @@ module dma_reg_top ( .d (hw2reg.control.go.d), // to internal hardware - .qe (control_flds_we[7]), + .qe (control_flds_we[6]), .q (reg2hw.control.go.q), .ds (), @@ -1553,6 +1525,33 @@ module dma_reg_top ( .qs (error_code_asid_error_qs) ); + // F[addr_increment_error]: 8:8 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRO), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_error_code_addr_increment_error ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (1'b0), + .wd ('0), + + // from internal hardware + .de (hw2reg.error_code.addr_increment_error.de), + .d (hw2reg.error_code.addr_increment_error.d), + + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (error_code_addr_increment_error_qs) + ); + // Subregister 0 of Multireg sha2_digest // R[sha2_digest_0]: V(False) @@ -3059,13 +3058,11 @@ module dma_reg_top ( assign control_hardware_handshake_enable_wd = reg_wdata[4]; - assign control_memory_buffer_auto_increment_enable_wd = reg_wdata[5]; - - assign control_fifo_auto_increment_enable_wd = reg_wdata[6]; + assign control_src_addr_mode_wd = reg_wdata[6:5]; - assign control_data_direction_wd = reg_wdata[7]; + assign control_dst_addr_mode_wd = reg_wdata[8:7]; - assign control_initial_transfer_wd = reg_wdata[8]; + assign control_initial_transfer_wd = reg_wdata[9]; assign control_abort_wd = reg_wdata[27]; @@ -3300,10 +3297,9 @@ module dma_reg_top ( addr_hit[17]: begin reg_rdata_next[3:0] = control_opcode_qs; reg_rdata_next[4] = control_hardware_handshake_enable_qs; - reg_rdata_next[5] = control_memory_buffer_auto_increment_enable_qs; - reg_rdata_next[6] = control_fifo_auto_increment_enable_qs; - reg_rdata_next[7] = control_data_direction_qs; - reg_rdata_next[8] = control_initial_transfer_qs; + reg_rdata_next[6:5] = control_src_addr_mode_qs; + reg_rdata_next[8:7] = control_dst_addr_mode_qs; + reg_rdata_next[9] = control_initial_transfer_qs; reg_rdata_next[27] = '0; reg_rdata_next[31] = control_go_qs; end @@ -3326,6 +3322,7 @@ module dma_reg_top ( reg_rdata_next[5] = error_code_base_limit_error_qs; reg_rdata_next[6] = error_code_range_valid_error_qs; reg_rdata_next[7] = error_code_asid_error_qs; + reg_rdata_next[8] = error_code_addr_increment_error_qs; end addr_hit[20]: begin