Skip to content

Commit

Permalink
[hw,dma,rtl] Add support for a memset operation
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Schilling <[email protected]>
  • Loading branch information
Razer6 committed Sep 20, 2024
1 parent 9d58bef commit 4290ed9
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 127 deletions.
8 changes: 7 additions & 1 deletion hw/ip/dma/data/dma.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -448,6 +450,10 @@
name: "SHA512"
desc: "Perform inline hashing using SHA512."
}
{ value: "4",
name: "MEMSET"
desc: "Perform a memset operation."
}
]
}
{ bits: "4"
Expand Down Expand Up @@ -721,7 +727,7 @@
]
}
}
{ skipto: "0x11C" }
{ skipto: "0x120" }
{ multireg: {
name: "INTR_SRC_WR_VAL"
desc: "Write value for interrupt clearing write."
Expand Down
47 changes: 25 additions & 22 deletions hw/ip/dma/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`
Expand All @@ -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`
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
38 changes: 26 additions & 12 deletions hw/ip/dma/dv/env/dma_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -169,19 +169,25 @@ 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)

// 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;
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -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
Expand Down
71 changes: 40 additions & 31 deletions hw/ip/dma/dv/env/dma_seq_item.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down
Loading

0 comments on commit 4290ed9

Please sign in to comment.