diff --git a/hw/ip/dma/data/dma.hjson b/hw/ip/dma/data/dma.hjson index 690b2d62e8c5b..b19f91c4d8394 100644 --- a/hw/ip/dma/data/dma.hjson +++ b/hw/ip/dma/data/dma.hjson @@ -129,6 +129,7 @@ Data is read from this location in a copy operation. The address may be an IO virtual address. Must be aligned to the transfer width. + When using the memset operation, this register is used as a memset value. ''' swaccess: "rw" hwaccess: "hrw" @@ -147,6 +148,7 @@ desc: '''Upper 32 bits of the source address. Must be aligned to the transfer width. Source and destination address must have the same alignment. + When using the memset operation, this register is used as a memset value. ''' swaccess: "rw" hwaccess: "hrw" @@ -448,6 +450,10 @@ name: "SHA512" desc: "Perform inline hashing using SHA512." } + { value: "4", + name: "MEMSET" + desc: "Perform a memset operation." + } ] } { bits: "4" @@ -721,7 +727,7 @@ ] } } - { skipto: "0x11C" } + { skipto: "0x120" } { multireg: { name: "INTR_SRC_WR_VAL" desc: "Write value for interrupt clearing write." diff --git a/hw/ip/dma/doc/registers.md b/hw/ip/dma/doc/registers.md index 41ba14f791551..a1dd01d0a8c53 100644 --- a/hw/ip/dma/doc/registers.md +++ b/hw/ip/dma/doc/registers.md @@ -55,17 +55,17 @@ | dma.[`INTR_SRC_ADDR_8`](#intr_src_addr) | 0xbc | 4 | Destination address for interrupt source clearing write. | | dma.[`INTR_SRC_ADDR_9`](#intr_src_addr) | 0xc0 | 4 | Destination address for interrupt source clearing write. | | dma.[`INTR_SRC_ADDR_10`](#intr_src_addr) | 0xc4 | 4 | Destination address for interrupt source clearing write. | -| dma.[`INTR_SRC_WR_VAL_0`](#intr_src_wr_val) | 0x11c | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_1`](#intr_src_wr_val) | 0x120 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_2`](#intr_src_wr_val) | 0x124 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_3`](#intr_src_wr_val) | 0x128 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_4`](#intr_src_wr_val) | 0x12c | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_5`](#intr_src_wr_val) | 0x130 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_6`](#intr_src_wr_val) | 0x134 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_7`](#intr_src_wr_val) | 0x138 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_8`](#intr_src_wr_val) | 0x13c | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_9`](#intr_src_wr_val) | 0x140 | 4 | Write value for interrupt clearing write. | -| dma.[`INTR_SRC_WR_VAL_10`](#intr_src_wr_val) | 0x144 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_0`](#intr_src_wr_val) | 0x120 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_1`](#intr_src_wr_val) | 0x124 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_2`](#intr_src_wr_val) | 0x128 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_3`](#intr_src_wr_val) | 0x12c | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_4`](#intr_src_wr_val) | 0x130 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_5`](#intr_src_wr_val) | 0x134 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_6`](#intr_src_wr_val) | 0x138 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_7`](#intr_src_wr_val) | 0x13c | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_8`](#intr_src_wr_val) | 0x140 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_9`](#intr_src_wr_val) | 0x144 | 4 | Write value for interrupt clearing write. | +| dma.[`INTR_SRC_WR_VAL_10`](#intr_src_wr_val) | 0x148 | 4 | Write value for interrupt clearing write. | ## INTR_STATE Interrupt State Register @@ -143,6 +143,7 @@ Lower 32 bits of the physical or virtual address of memory location within SoC m Data is read from this location in a copy operation. The address may be an IO virtual address. Must be aligned to the transfer width. +When using the memset operation, this register is used as a memset value. - Offset: `0x10` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -162,6 +163,7 @@ Must be aligned to the transfer width. Upper 32 bits of the source address. Must be aligned to the transfer width. Source and destination address must have the same alignment. +When using the memset operation, this register is used as a memset value. - Offset: `0x14` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -525,6 +527,7 @@ Defines the type of DMA operations. | 0x1 | SHA256 | Perform inline hashing using SHA256. | | 0x2 | SHA384 | Perform inline hashing using SHA384. | | 0x3 | SHA512 | Perform inline hashing using SHA512. | +| 0x4 | MEMSET | Perform a memset operation. | Other values are reserved. @@ -715,17 +718,17 @@ Write value for interrupt clearing write. | Name | Offset | |:-------------------|:---------| -| INTR_SRC_WR_VAL_0 | 0x11c | -| INTR_SRC_WR_VAL_1 | 0x120 | -| INTR_SRC_WR_VAL_2 | 0x124 | -| INTR_SRC_WR_VAL_3 | 0x128 | -| INTR_SRC_WR_VAL_4 | 0x12c | -| INTR_SRC_WR_VAL_5 | 0x130 | -| INTR_SRC_WR_VAL_6 | 0x134 | -| INTR_SRC_WR_VAL_7 | 0x138 | -| INTR_SRC_WR_VAL_8 | 0x13c | -| INTR_SRC_WR_VAL_9 | 0x140 | -| INTR_SRC_WR_VAL_10 | 0x144 | +| INTR_SRC_WR_VAL_0 | 0x120 | +| INTR_SRC_WR_VAL_1 | 0x124 | +| INTR_SRC_WR_VAL_2 | 0x128 | +| INTR_SRC_WR_VAL_3 | 0x12c | +| INTR_SRC_WR_VAL_4 | 0x130 | +| INTR_SRC_WR_VAL_5 | 0x134 | +| INTR_SRC_WR_VAL_6 | 0x138 | +| INTR_SRC_WR_VAL_7 | 0x13c | +| INTR_SRC_WR_VAL_8 | 0x140 | +| INTR_SRC_WR_VAL_9 | 0x144 | +| INTR_SRC_WR_VAL_10 | 0x148 | ### Fields diff --git a/hw/ip/dma/dv/env/dma_scoreboard.sv b/hw/ip/dma/dv/env/dma_scoreboard.sv index 6aa99e3f2bcd3..e6fc5e8957f0a 100644 --- a/hw/ip/dma/dv/env/dma_scoreboard.sv +++ b/hw/ip/dma/dv/env/dma_scoreboard.sv @@ -169,9 +169,12 @@ class dma_scoreboard extends cip_base_scoreboard #( endfunction // On-the-fly checking of write data against the pre-randomized source data - function void check_write_data(string if_name, bit [63:0] a_addr, ref tl_seq_item item); + function void check_write_data(string if_name, bit [63:0] a_addr, ref tl_seq_item item, + ref dma_seq_item dma_config); bit [tl_agent_pkg::DataWidth-1:0] wdata = item.a_data; bit [31:0] offset = num_bytes_transferred; + bit [31:0] memset_value; + bit [7:0] src_data; `uvm_info(`gfn, $sformatf("if_name %s: write addr 0x%0x mask 0x%0x data 0x%0x", if_name, a_addr, item.a_mask, item.a_data), UVM_HIGH) @@ -179,9 +182,12 @@ class dma_scoreboard extends cip_base_scoreboard #( // Check each of the bytes being written, Little Endian byte ordering for (int i = 0; i < $bits(item.a_mask); i++) begin if (item.a_mask[i]) begin - `uvm_info(`gfn, $sformatf("src_data %0x write data 0x%0x", - cfg.src_data[offset], wdata[7:0]), UVM_DEBUG) - `DV_CHECK_EQ(cfg.src_data[offset], wdata[7:0]) + memset_value = a_addr[3]? dma_config.src_addr[63:32] : dma_config.src_addr[31:0]; + src_data = dma_config.opcode == OpcMemset? memset_value[a_addr[1:0]*8:+8] : + cfg.src_data[offset]; + + `uvm_info(`gfn, $sformatf("src_data %0x write data 0x%0x", src_data, wdata[7:0]), UVM_DEBUG) + `DV_CHECK_EQ(src_data, wdata[7:0]) offset++; end wdata = wdata >> 8; @@ -344,7 +350,7 @@ class dma_scoreboard extends cip_base_scoreboard #( num_bytes_this_txn, intr_source), UVM_HIGH); // On-the-fly checking of writing data - check_write_data(if_name, a_addr, item); + check_write_data(if_name, a_addr, item, dma_config); // Check if opcode is as expected if ((dma_config.per_transfer_width != DmaXfer4BperTxn) || @@ -763,20 +769,28 @@ class dma_scoreboard extends cip_base_scoreboard #( for (int i = 0; i < size; i++) begin // For the source data we access the original randomized data that we chose bit [7:0] src_data = cfg.src_data[src_offset + i]; + bit [31:0] memset_value; bit [7:0] dst_data; - if (dst_fifo) begin - dst_data = get_fifo_data(dma_config.dst_asid, dst_addr); + if (dma_config.opcode != OpcMemset) begin + if (dst_fifo) begin + dst_data = get_fifo_data(dma_config.dst_asid, dst_addr); + end else begin + dst_data = get_model_data(dma_config.dst_asid, dst_addr); + end + src_addr++; end else begin dst_data = get_model_data(dma_config.dst_asid, dst_addr); + // Get the memset depending on the address alignment and the sub-byte index + memset_value = dst_addr[3]? dma_config.src_addr[63:32] : dma_config.src_addr[31:0]; + src_data = memset_value[dst_addr[1:0]*8:+8]; end `uvm_info(`gfn, - $sformatf("checking src_addr = %0x data = %0x : dst_addr = %0x data = %0x", - src_addr, src_data, dst_addr, dst_data), UVM_DEBUG) + $sformatf("checking src_addr = %0x data = %0x : dst_addr = %0x data = %0x", + src_addr, src_data, dst_addr, dst_data), UVM_DEBUG) `DV_CHECK_EQ(src_data, dst_data, - $sformatf("src_addr = %0x data = %0x : dst_addr = %0x data = %0x", - src_addr, src_data, dst_addr, dst_data)) - src_addr++; + $sformatf("src_addr = %0x data = %0x : dst_addr = %0x data = %0x", + src_addr, src_data, dst_addr, dst_data)) if (!dst_fifo) begin dst_addr++; end diff --git a/hw/ip/dma/dv/env/dma_seq_item.sv b/hw/ip/dma/dv/env/dma_seq_item.sv index 9335a83ba6abb..7fffd94dec913 100644 --- a/hw/ip/dma/dv/env/dma_seq_item.sv +++ b/hw/ip/dma/dv/env/dma_seq_item.sv @@ -436,7 +436,7 @@ class dma_seq_item extends uvm_sequence_item; $sformatf("\n\topcode : %0d", opcode), $sformatf("\n\tper_transfer_width : %0d", per_transfer_width), $sformatf("\n\tchunk_data_size : 0x%x", chunk_data_size), - $sformatf("\n\ttotal_data_size : 0x%x", total_data_size) + $sformatf("\n\ttotal_data_size : 0x%x", total_data_size), }; // Verdict on whether this is a valid DMA configuration, eg. post-randomization @@ -493,11 +493,14 @@ class dma_seq_item extends uvm_sequence_item; // have had to be introduced to permit testing in block level DV (see `soc_system_hi_addr` // above); if the upper bits do not match then reads or writes will be faulted, and 32-bit // address wraparound is not permitted. - if (src_asid == SocSystemAddr) begin - if (src_addr[63:32] != soc_system_hi_addr || src_addr[31:0] >= ~memory_range) begin - `uvm_info(`gfn, " - Limitations of 32-bit TL-UL for testing System bus Reads not met", - UVM_MEDIUM) - valid_config = 0; + // No surce checks needed when doing a memset operation + if (opcode != OpcMemset) begin + if (src_asid == SocSystemAddr) begin + if (src_addr[63:32] != soc_system_hi_addr || src_addr[31:0] >= ~memory_range) begin + `uvm_info(`gfn, " - Limitations of 32-bit TL-UL for testing System bus Reads not met", + UVM_MEDIUM) + valid_config = 0; + end end end if (dst_asid == SocSystemAddr) begin @@ -517,9 +520,12 @@ class dma_seq_item extends uvm_sequence_item; `uvm_info(`gfn, " - Destination ASID invalid", UVM_MEDIUM) valid_config = 0; end - if (!(src_asid inside {OtInternalAddr, SocControlAddr, SocSystemAddr})) begin - `uvm_info(`gfn, " - Source ASID invalid", UVM_MEDIUM) - valid_config = 0; + // Source ASID check not needed in memset operation + if (opcode != OpcMemset) begin + if (!(src_asid inside {OtInternalAddr, SocControlAddr, SocSystemAddr})) begin + `uvm_info(`gfn, " - Source ASID invalid", UVM_MEDIUM) + valid_config = 0; + end end // Check if operation is valid @@ -528,7 +534,7 @@ class dma_seq_item extends uvm_sequence_item; `uvm_info(`gfn, $sformatf(" - SHA hashing operates only on 4B/txn"), UVM_MEDIUM) valid_config = 0; end - end else if (opcode != OpcCopy) begin + end else if (!(opcode inside {OpcCopy, OpcMemset})) begin `uvm_info(`gfn, $sformatf(" - Unsupported DMA operation: %s", opcode.name()), UVM_MEDIUM) valid_config = 0; end @@ -549,27 +555,30 @@ class dma_seq_item extends uvm_sequence_item; // For all valid configurations, either source or destination address space Id must point // to OT internal address space, but the memory range restriction does not apply if _both_ // are within the OT internal address space. - if (src_asid == OtInternalAddr && dst_asid != OtInternalAddr) begin - if (mem_range_valid && !is_buffer_in_dma_memory_region(src_addr[31:0], memory_range)) begin - // If source address space ID points to OT internal address space, - // it must be within DMA enabled address range. - `uvm_info(`gfn, - $sformatf( - " - Invalid src addr range found lo: %08x hi: %08x with base: %08x limit: %0x", - src_addr[31:0], src_addr[63:32], mem_range_base, mem_range_limit), - UVM_MEDIUM) - valid_config = 0; - end - end else if (dst_asid == OtInternalAddr && src_asid != OtInternalAddr) begin - // If destination address space ID points to OT internal address space - // it must be within DMA enabled address range. - if (mem_range_valid && !is_buffer_in_dma_memory_region(dst_addr[31:0], memory_range)) begin - `uvm_info(`gfn, + if (opcode != OpcMemset) begin + if (src_asid == OtInternalAddr && dst_asid != OtInternalAddr) begin + if (mem_range_valid && !is_buffer_in_dma_memory_region(src_addr[31:0], memory_range)) begin + // If source address space ID points to OT internal address space, + // it must be within DMA enabled address range. + `uvm_info(`gfn, $sformatf( - " - Invalid dst addr range found lo: %08x hi: %08x with base: %08x limit: %0x", - dst_addr[31:0], dst_addr[63:32], mem_range_base, mem_range_limit), + " - Invalid src addr range found lo: %08x hi: %08x with base: %08x limit: %0x", + src_addr[31:0], src_addr[63:32], mem_range_base, mem_range_limit), UVM_MEDIUM) - valid_config = 0; + valid_config = 0; + end + end else if (dst_asid == OtInternalAddr && src_asid != OtInternalAddr) begin + // If destination address space ID points to OT internal address space + // it must be within DMA enabled address range. + if (mem_range_valid && !is_buffer_in_dma_memory_region(dst_addr[31:0], memory_range)) begin + `uvm_info(`gfn, + $sformatf( + " - Invalid dst addr range found lo: %08x hi: %08x with base: %08x", + " limit: %0x", + dst_addr[31:0], dst_addr[63:32], mem_range_base, mem_range_limit), + UVM_MEDIUM) + valid_config = 0; + end end end @@ -579,7 +588,7 @@ class dma_seq_item extends uvm_sequence_item; `uvm_info(`gfn, " - Destination address out of range for destination ASID", UVM_MEDIUM) valid_config = 0; end - if (src_asid != SocSystemAddr && |src_addr[63:32]) begin + if (opcode != OpcMemset && src_asid != SocSystemAddr && |src_addr[63:32]) begin `uvm_info(`gfn, " - Source addess out of range for source ASID", UVM_MEDIUM) valid_config = 0; end @@ -596,7 +605,7 @@ class dma_seq_item extends uvm_sequence_item; end endcase - if (|(src_addr & align_mask)) begin + if (opcode != OpcMemset && |(src_addr & align_mask)) begin `uvm_info(`gfn, " - Source address does not meet alignment requirements", UVM_MEDIUM) valid_config = 0; end diff --git a/hw/ip/dma/rtl/dma.sv b/hw/ip/dma/rtl/dma.sv index b3428c2136a89..de707cf6d9dbc 100644 --- a/hw/ip/dma/rtl/dma.sv +++ b/hw/ip/dma/rtl/dma.sv @@ -465,6 +465,12 @@ module dma assign src_asid = reg2hw.addr_space_id.src_asid.q; assign dst_asid = reg2hw.addr_space_id.dst_asid.q; + // Memset allows to replicate a 64-bit pattern via src_addr_lo and src_addr_hi + // src_addr_lo is used for 64-bit aligned addresses, src_addr_hi used for non 64-bit aligned + // addresses + logic [top_pkg::TL_AW-1:0] memset_value; + assign memset_value = dst_addr_q[2]? reg2hw.src_addr_hi.q : reg2hw.src_addr_lo.q; + // Note: bus signals shall be asserted only when configured and active, to ensure // that address and - especially - data are not leaked to other buses. @@ -479,7 +485,8 @@ module dma (dma_host_read ? {src_addr_q[top_pkg::TL_AW-1:2], 2'b0} : (dma_host_clear_intr ? reg2hw.intr_src_addr[clear_index_q].q : 'b0)); dma_host_tlul_req_we = dma_host_write | dma_host_clear_intr; - dma_host_tlul_req_wdata = dma_host_write ? read_return_data_q : + dma_host_tlul_req_wdata = dma_host_write ? + (control_q.opcode == OpcMemset? memset_value : read_return_data_q) : (dma_host_clear_intr ? reg2hw.intr_src_wr_val[clear_index_q].q : 'b0); dma_host_tlul_req_be = dma_host_write ? req_dst_be_q : (dma_host_read ? req_src_be_q @@ -497,7 +504,8 @@ module dma (dma_ctn_read ? {src_addr_q[top_pkg::TL_AW-1:2], 2'b0} : (dma_ctn_clear_intr ? reg2hw.intr_src_addr[clear_index_q].q : 'b0)); dma_ctn_tlul_req_we = dma_ctn_write | dma_ctn_clear_intr; - dma_ctn_tlul_req_wdata = dma_ctn_write ? read_return_data_q : + dma_ctn_tlul_req_wdata = dma_ctn_write ? + (control_q.opcode == OpcMemset? memset_value : read_return_data_q) : (dma_ctn_clear_intr ? reg2hw.intr_src_wr_val[clear_index_q].q : 'b0); dma_ctn_tlul_req_be = dma_ctn_write ? req_dst_be_q : (dma_ctn_read ? req_src_be_q : {top_pkg::TL_DBW{dma_ctn_clear_intr}}); @@ -515,7 +523,8 @@ module dma {dst_addr_q[(SYS_ADDR_WIDTH-1):2], 2'b0} : 'b0; sys_req_d.racl_vec [SysCmdWrite] = SysRacl[SysOpcWrite-1:0]; - sys_req_d.write_data = {SYS_DATA_WIDTH{dma_sys_write}} & read_return_data_q; + sys_req_d.write_data = dma_sys_write? + (control_q.opcode == OpcMemset? memset_value : read_return_data_q) : b0; sys_req_d.write_be = {SYS_DATA_BYTEWIDTH{dma_sys_write}} & req_dst_be_q; sys_req_d.vld_vec [SysCmdRead] = dma_sys_read; @@ -810,7 +819,8 @@ module dma next_error[DmaSizeErr] = 1'b1; end - if (!(control_q.opcode inside {OpcCopy, OpcSha256, OpcSha384, OpcSha512})) begin + if (!(control_q.opcode inside {OpcCopy, OpcSha256, OpcSha384, OpcSha512, + OpcMemset})) begin next_error[DmaOpcodeErr] = 1'b1; end @@ -823,9 +833,6 @@ module dma // Ensure that ASIDs have valid values // SEC_CM: ASID.INTERSIG.MUBI - if (!(src_asid inside {OtInternalAddr, SocControlAddr, SocSystemAddr})) begin - next_error[DmaAsidErr] = 1'b1; - end if (!(dst_asid inside {OtInternalAddr, SocControlAddr, SocSystemAddr})) begin next_error[DmaAsidErr] = 1'b1; end @@ -836,56 +843,66 @@ module dma next_error[DmaBaseLimitErr] = 1'b1; end - // In 4-byte transfers, source and destination address must be 4-byte aligned - if (reg2hw.transfer_width.q == DmaXfer4BperTxn && - (|reg2hw.src_addr_lo.q[1:0])) begin - next_error[DmaSrcAddrErr] = 1'b1; - end - if (reg2hw.transfer_width.q == DmaXfer4BperTxn && - (|reg2hw.dst_addr_lo.q[1:0])) begin + // In 2-byte transfers, destination address must be 2-byte aligned + if (reg2hw.transfer_width.q == DmaXfer2BperTxn && reg2hw.dst_addr_lo.q[0]) begin next_error[DmaDstAddrErr] = 1'b1; end - // In 2-byte transfers, source and destination address must be 2-byte aligned - if (reg2hw.transfer_width.q == DmaXfer2BperTxn && reg2hw.src_addr_lo.q[0]) begin - next_error[DmaSrcAddrErr] = 1'b1; - end - if (reg2hw.transfer_width.q == DmaXfer2BperTxn && - reg2hw.dst_addr_lo.q[0]) begin + // In 4-byte transfers, destination address must be 4-byte aligned + if (reg2hw.transfer_width.q == DmaXfer4BperTxn && (|reg2hw.dst_addr_lo.q[1:0])) begin next_error[DmaDstAddrErr] = 1'b1; end - // If data from the SOC system bus or the control bus is transferred - // to the OT internal memory, we must check if the destination address range falls into - // the DMA enabled memory region. - if ((src_asid inside {SocControlAddr, SocSystemAddr}) && (dst_asid == OtInternalAddr) && - // Out-of-bound check - ((reg2hw.dst_addr_lo.q > control_q.enabled_memory_range_limit) || - (reg2hw.dst_addr_lo.q < control_q.enabled_memory_range_base) || - ((SYS_ADDR_WIDTH'(reg2hw.dst_addr_lo.q) + - SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)) > - SYS_ADDR_WIDTH'(control_q.enabled_memory_range_limit)))) begin - next_error[DmaDstAddrErr] = 1'b1; - end + // Source checks are only needed when reading from source and not in memset + if (control_q.opcode != OpcMemset) begin + // Ensure that ASIDs have valid values + // SEC_CM: ASID.INTERSIG.MUBI + if (!(src_asid inside {OtInternalAddr, SocControlAddr, SocSystemAddr})) begin + next_error[DmaAsidErr] = 1'b1; + end - // If data from the OT internal memory is transferred to the SOC system bus or the - // control bus, we must check if the source address range falls into the - // DMA enabled memory region. - if ((dst_asid inside {SocControlAddr, SocSystemAddr}) && (src_asid == OtInternalAddr) && + // In 2-byte transfers, source address must be 2-byte aligned + if (reg2hw.transfer_width.q == DmaXfer2BperTxn && reg2hw.src_addr_lo.q[0]) begin + next_error[DmaSrcAddrErr] = 1'b1; + end + + // In 4-byte transfers, source address must be 4-byte aligned + if (reg2hw.transfer_width.q == DmaXfer4BperTxn && (|reg2hw.src_addr_lo.q[1:0])) begin + next_error[DmaSrcAddrErr] = 1'b1; + end + + // If data from the SOC system bus or the control bus is transferred + // to the OT internal memory, we must check if the destination address range falls into + // the DMA enabled memory region. + if ((src_asid inside {SocControlAddr, SocSystemAddr}) && (dst_asid == OtInternalAddr) && // Out-of-bound check - ((reg2hw.src_addr_lo.q > control_q.enabled_memory_range_limit) || - (reg2hw.src_addr_lo.q < control_q.enabled_memory_range_base) || - ((SYS_ADDR_WIDTH'(reg2hw.src_addr_lo.q) + - SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)) > - SYS_ADDR_WIDTH'(control_q.enabled_memory_range_limit)))) begin - next_error[DmaSrcAddrErr] = 1'b1; - end + ((reg2hw.dst_addr_lo.q > control_q.enabled_memory_range_limit) || + (reg2hw.dst_addr_lo.q < control_q.enabled_memory_range_base) || + ((SYS_ADDR_WIDTH'(reg2hw.dst_addr_lo.q) + + SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)) > + SYS_ADDR_WIDTH'(control_q.enabled_memory_range_limit)))) begin + next_error[DmaDstAddrErr] = 1'b1; + end + + // If data from the OT internal memory is transferred to the SOC system bus or the + // control bus, we must check if the source address range falls into the + // DMA enabled memory region. + if ((dst_asid inside {SocControlAddr, SocSystemAddr}) && (src_asid == OtInternalAddr) && + // Out-of-bound check + ((reg2hw.src_addr_lo.q > control_q.enabled_memory_range_limit) || + (reg2hw.src_addr_lo.q < control_q.enabled_memory_range_base) || + ((SYS_ADDR_WIDTH'(reg2hw.src_addr_lo.q) + + SYS_ADDR_WIDTH'(reg2hw.chunk_data_size.q)) > + SYS_ADDR_WIDTH'(control_q.enabled_memory_range_limit)))) begin + next_error[DmaSrcAddrErr] = 1'b1; + end - // If the source ASID is the SOC control port or the OT internal port, we are accessing a - // 32-bit address space. Thus the upper bits of the source address must be zero - if ((src_asid inside {SocControlAddr, OtInternalAddr}) && - (|reg2hw.src_addr_hi.q)) begin - next_error[DmaSrcAddrErr] = 1'b1; + // If the source ASID is the SOC control port or the OT internal port, we are accessing + // a 32-bit address space. Thus the upper bits of the source address must be zero + if ((src_asid inside {SocControlAddr, OtInternalAddr}) && + (|reg2hw.src_addr_hi.q)) begin + next_error[DmaSrcAddrErr] = 1'b1; + end end // If the destination ASID is the SOC control por or the OT internal port we are accessing @@ -910,7 +927,13 @@ module dma sha2_hash_start = 1'b1; end end - ctrl_state_d = DmaSendRead; + + // In Memset, we can directly go the write operation, no read required + if (control_q.opcode == OpcMemset) begin + ctrl_state_d = DmaSendWrite; + end else begin + ctrl_state_d = DmaSendRead; + end end end diff --git a/hw/ip/dma/rtl/dma_pkg.sv b/hw/ip/dma/rtl/dma_pkg.sv index f88cd577bd21a..7dadd73e96868 100644 --- a/hw/ip/dma/rtl/dma_pkg.sv +++ b/hw/ip/dma/rtl/dma_pkg.sv @@ -41,7 +41,8 @@ package dma_pkg; OpcCopy = 4'h0, OpcSha256 = 4'h1, OpcSha384 = 4'h2, - OpcSha512 = 4'h3 + OpcSha512 = 4'h3, + OpcMemset = 4'h4 } opcode_e; // Control state captured during the operation diff --git a/hw/ip/dma/rtl/dma_reg_pkg.sv b/hw/ip/dma/rtl/dma_reg_pkg.sv index 0dca94a3d60f5..bd777d7fb303e 100644 --- a/hw/ip/dma/rtl/dma_reg_pkg.sv +++ b/hw/ip/dma/rtl/dma_reg_pkg.sv @@ -376,17 +376,17 @@ package dma_reg_pkg; parameter logic [BlockAw-1:0] DMA_INTR_SRC_ADDR_8_OFFSET = 9'h bc; parameter logic [BlockAw-1:0] DMA_INTR_SRC_ADDR_9_OFFSET = 9'h c0; parameter logic [BlockAw-1:0] DMA_INTR_SRC_ADDR_10_OFFSET = 9'h c4; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_0_OFFSET = 9'h 11c; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_1_OFFSET = 9'h 120; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_2_OFFSET = 9'h 124; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_3_OFFSET = 9'h 128; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_4_OFFSET = 9'h 12c; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_5_OFFSET = 9'h 130; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_6_OFFSET = 9'h 134; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_7_OFFSET = 9'h 138; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_8_OFFSET = 9'h 13c; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_9_OFFSET = 9'h 140; - parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_10_OFFSET = 9'h 144; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_0_OFFSET = 9'h 120; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_1_OFFSET = 9'h 124; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_2_OFFSET = 9'h 128; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_3_OFFSET = 9'h 12c; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_4_OFFSET = 9'h 130; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_5_OFFSET = 9'h 134; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_6_OFFSET = 9'h 138; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_7_OFFSET = 9'h 13c; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_8_OFFSET = 9'h 140; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_9_OFFSET = 9'h 144; + parameter logic [BlockAw-1:0] DMA_INTR_SRC_WR_VAL_10_OFFSET = 9'h 148; // Reset values for hwext registers and their fields parameter logic [1:0] DMA_INTR_TEST_RESVAL = 2'h 0;