Skip to content

Commit

Permalink
Merge branch 'lowRISC:master' into manual-cdi
Browse files Browse the repository at this point in the history
  • Loading branch information
tommychiu-github authored Nov 12, 2024
2 parents a2acec5 + a430c0b commit 2aeb636
Show file tree
Hide file tree
Showing 27 changed files with 306 additions and 107 deletions.
2 changes: 2 additions & 0 deletions hw/dv/tools/vcs/cover.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
-moduletree prim_prince
-moduletree prim_secded_inv_64_57_dec
-moduletree prim_secded_inv_39_32_dec
-moduletree prim_secded_inv_64_57_enc
-moduletree prim_secded_inv_39_32_enc

// The DV environment binds in some modules to add CSR and TileLink
// assertions. Disable all coverage for these modules here. We'll
Expand Down
2 changes: 2 additions & 0 deletions hw/dv/tools/vcs/cover_reg_top.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
-module prim_onehot_check // FPV verified
-moduletree prim_secded_inv_64_57_dec // FPV verified
-moduletree prim_secded_inv_39_32_dec // FPV verified
-moduletree prim_secded_inv_64_57_enc // FPV verified
-moduletree prim_secded_inv_39_32_enc // FPV verified
// The DV environment binds in some modules to add CSR and Tilelink assertions. Make sure that we
// collect assertion coverage for these modules (since that's the whole point!) but don't collect
Expand Down
2 changes: 2 additions & 0 deletions hw/dv/tools/xcelium/cover.ccf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ deselect_coverage -betfs -module prim_prince...
deselect_coverage -betfs -module prim_lfsr...
deselect_coverage -betfs -module prim_secded_inv_64_57_dec...
deselect_coverage -betfs -module prim_secded_inv_39_32_dec...
deselect_coverage -betfs -module prim_secded_inv_64_57_enc...
deselect_coverage -betfs -module prim_secded_inv_39_32_enc...

// Black-box DV CDC module.
deselect_coverage -betfs -module prim_cdc_rand_delay
Expand Down
2 changes: 2 additions & 0 deletions hw/dv/tools/xcelium/cover_reg_top.ccf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ select_coverage -befs -module *_reg_top...
deselect_coverage -betfs -module prim_onehot_check...
deselect_coverage -betfs -module prim_secded_inv_64_57_dec...
deselect_coverage -betfs -module prim_secded_inv_39_32_dec...
deselect_coverage -betfs -module prim_secded_inv_64_57_enc...
deselect_coverage -betfs -module prim_secded_inv_39_32_enc...

// Black-box DV CDC module.
deselect_coverage -betfs -module prim_cdc_rand_delay
Expand Down
13 changes: 12 additions & 1 deletion hw/ip/dma/data/dma.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down Expand Up @@ -541,7 +543,6 @@
resval: 0x0
hwaccess: "hrw"
swaccess: "ro"
hwaccess: "hrw"
desc: '''
DMA operation is active if this bit is set.
DMA engine clears this bit when operation is complete.
Expand Down Expand Up @@ -583,6 +584,16 @@
This value is cleared on the initial transfer and set when the digest is written.
'''
}
{ bits: "5"
name: "chunk_done"
resval: 0x0
hwaccess: "hrw"
desc: '''
Transfer of a single chunk is complete.
Only raised for multi-chunk memory-to-memory transfers.
Cleared automatically by the hardware when starting the transfer of a new chunk.
'''
}
]
}
{ name: "ERROR_CODE"
Expand Down
13 changes: 7 additions & 6 deletions hw/ip/dma/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -532,17 +532,18 @@ Other values are reserved.
Status indication for DMA data movement.
- Offset: `0x48`
- Reset default: `0x0`
- Reset mask: `0x1f`
- Reset mask: `0x3f`

### Fields

```wavejson
{"reg": [{"name": "busy", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "aborted", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "sha2_digest_valid", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 27}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}}
{"reg": [{"name": "busy", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "aborted", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "error", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "sha2_digest_valid", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "chunk_done", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"bits": 26}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}}
```

| Bits | Type | Reset | Name | Description |
|:------:|:------:|:-------:|:------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 31:5 | | | | Reserved |
| 31:6 | | | | Reserved |
| 5 | rw1c | 0x0 | chunk_done | Transfer of a single chunk is complete. Only raised for multi-chunk memory-to-memory transfers. Cleared automatically by the hardware when starting the transfer of a new chunk. |
| 4 | ro | 0x0 | sha2_digest_valid | Indicates whether the SHA2_DIGEST register contains a valid digest. This value is cleared on the initial transfer and set when the digest is written. |
| 3 | rw1c | 0x0 | error | Error occurred during the operation. ERROR_CODE register denotes the source of the error. |
| 2 | rw1c | 0x0 | aborted | Set once aborted operation drains. |
Expand Down
2 changes: 2 additions & 0 deletions hw/ip/dma/dv/env/dma_env_cov.sv
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ endgroup
covergroup dma_status_cg with function sample(
bit busy,
bit done,
bit chunk_done,
bit aborted,
bit error,
bit sha2_digest_valid
Expand All @@ -200,6 +201,7 @@ covergroup dma_status_cg with function sample(
option.name = "dma_status_cg";
cp_status_busy: coverpoint busy;
cp_status_done: coverpoint done;
cp_status_chunk_done: coverpoint chunk_done;
cp_status_aborted: coverpoint aborted;
cp_status_error: coverpoint error;
cp_sha2_digest_valid: coverpoint sha2_digest_valid;
Expand Down
2 changes: 2 additions & 0 deletions hw/ip/dma/dv/env/dma_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ package dma_env_pkg;
parameter uint SYS_ADDR_WIDTH = 64;

// Index of interrupt in intf_vif
// TODO: rename `DMA_x` to indicate that they are interrupt numbers.
parameter uint DMA_DONE = 0;
parameter uint DMA_ERROR = 1;
parameter uint NumDmaInterrupts = 2;

// Completion status bits (DV-internal)
typedef enum {
Expand Down
87 changes: 68 additions & 19 deletions hw/ip/dma/dv/env/dma_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class dma_scoreboard extends cip_base_scoreboard #(

// Interrupt enable state
bit [NUM_MAX_INTERRUPTS-1:0] intr_enable;
// Interrupt test state (contributes to `intr_state`).
bit [NUM_MAX_INTERRUPTS-1:0] intr_test;
// Hardware interrupt state (contributes to `intr_state`).
bit [NUM_MAX_INTERRUPTS-1:0] intr_state_hw;

// Prediction of the state of an interrupt signal from the DUT.
typedef struct packed {
Expand All @@ -60,7 +64,7 @@ class dma_scoreboard extends cip_base_scoreboard #(
uint num_fifo_reg_write;
// Variable to store clear_intr_src register intended for use in monitor_lsio_trigger task
// since ref argument can not be used in fork-join_none
bit[31:0] clear_intr_src;
bit [31:0] clear_intr_src;
bit [TL_DW-1:0] exp_digest[16];

// Allow up to this number of clock cycles from CSR modification until interrupt signal change.
Expand Down Expand Up @@ -474,6 +478,7 @@ class dma_scoreboard extends cip_base_scoreboard #(
if (item.d_error && !tl_error_suppressed) begin
`uvm_info(`gfn, "Bus error detected", UVM_MEDIUM)
predict_interrupts(BusErrorToIntrLatency, 1 << DMA_ERROR, intr_enable);
intr_state_hw[DMA_ERROR] = 1'b1;
end else if (got_dest_item) begin
// Is this the final destination write?
//
Expand All @@ -483,6 +488,7 @@ class dma_scoreboard extends cip_base_scoreboard #(
// Whether a 'DONE' interrupt is expected depends upon whether it is enabled.
`uvm_info(`gfn, "Final write completed", UVM_MEDIUM)
predict_interrupts(WriteToDoneLatency, 1 << DMA_DONE, intr_enable);
intr_state_hw[DMA_DONE] = 1'b1;
end
end
endtask
Expand Down Expand Up @@ -570,6 +576,8 @@ class dma_scoreboard extends cip_base_scoreboard #(
abort_via_reg_write = 0;
fifo_intr_cleared = 0;
intr_enable = 0;
intr_test = 0;
intr_state_hw = 0;
endfunction

// Method to check if DMA interrupt is expected
Expand All @@ -593,8 +601,7 @@ class dma_scoreboard extends cip_base_scoreboard #(
// by the function `predict_interrupts` above.
if (cfg.under_reset) begin
// Interrupts shall be deasserted by DUT reset, and any predictions no longer apply.
`uvm_info(`gfn, "Clearing interrupt predictions", UVM_MEDIUM)
for (uint i = 0; i < NUM_MAX_INTERRUPTS; i++) exp_intr_queue[i].delete();
clear_intr_predictions();
prev_intr = 'b0;
end else if (cfg.en_scb) begin
bit [NUM_MAX_INTERRUPTS-1:0] exp_intr;
Expand Down Expand Up @@ -658,10 +665,14 @@ class dma_scoreboard extends cip_base_scoreboard #(
// Note: this explicitly does NOT mean that they must CHANGE to achieve that state; only that
// they must be in that state by then.
function void predict_interrupts(uint max_delay, bit [31:0] intr_affected, bit [31:0] exp_state);
// Clear all bits that do not map to defined interrupts, to avoid confusion in the log messages.
intr_affected &= {NumDmaInterrupts{1'b1}};
exp_state &= {NumDmaInterrupts{1'b1}};

`uvm_info(`gfn, $sformatf("Predicting interrupt [0,%0x) -> intr_affected 0x%x == 0x%0x",
max_delay, intr_affected, exp_state), UVM_HIGH)

for (uint i = 0; i < NUM_MAX_INTERRUPTS && |intr_affected; i++) begin
for (uint i = 0; i < NumDmaInterrupts && |intr_affected; i++) begin
if (intr_affected[i]) begin
dma_intr_pred_t predict;
predict.delay = max_delay;
Expand All @@ -672,6 +683,12 @@ class dma_scoreboard extends cip_base_scoreboard #(
end
endfunction

// Clear all pending interrupt predictions; these are no longer expected to occur.
function void clear_intr_predictions();
`uvm_info(`gfn, "Clearing interrupt predictions", UVM_MEDIUM)
for (uint i = 0; i < NUM_MAX_INTERRUPTS; i++) exp_intr_queue[i].delete();
endfunction

// Task to monitor LSIO trigger and update scoreboard internal variables
task monitor_lsio_trigger();
fork
Expand Down Expand Up @@ -748,6 +765,9 @@ class dma_scoreboard extends cip_base_scoreboard #(
endcase
endfunction

// Returns the bitmap of Status-type interrupts that are set because of bits in the `status`
// register being asserted.

// Utility function to check the contents of the destination memory/FIFO against the
// corresponding reference source data.
function void check_data(ref dma_seq_item dma_config, bit [63:0] src_addr, bit [63:0] dst_addr,
Expand Down Expand Up @@ -810,17 +830,27 @@ class dma_scoreboard extends cip_base_scoreboard #(
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);
// Writing 1 to an INTR_STATE bit clears the corresponding asserted 'Event' interrupt;
// Status type interrupts are unaffected.
uvm_reg_data_t intr = item.a_data & `gmv(ral.intr_enable) & ~ral.intr_state.get_ro_mask();
predict_interrupts(CSRtoIntrLatency, intr, 0);
end
"intr_test": begin
// The 'Read Only' fields tell us which are Status-type interrupts.
uvm_reg_data_t ro_mask = ral.intr_state.get_ro_mask();
uvm_reg_data_t now_set;

`uvm_info(`gfn, $sformatf("intr_test write 0x%x with enables 0x%0x",
item.a_data, intr_enable), UVM_HIGH)

// Should raise all tested interrupts that are enabled at the time of the test;
// the intr_state bit and the interrupt line then remain high until cleared.
// Test bits are fire-and-forget; they are not retained anywhere.
predict_interrupts(CSRtoIntrLatency, item.a_data, `gmv(ral.intr_enable));
//
// For Status-type interrupts we must retain the fact that they are asserted because of
// the `intr_test` register.
intr_test = item.a_data & ro_mask;
now_set = item.a_data | intr_state_hw;
predict_interrupts(CSRtoIntrLatency, item.a_data | ro_mask, now_set & intr_enable);
end
"src_addr_lo": begin
dma_config.src_addr[31:0] = item.a_data;
Expand Down Expand Up @@ -953,6 +983,16 @@ 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
uvm_reg_data_t clearing = 0;
clearing[DMA_DONE] = get_field_val(ral.status.done, item.a_data);
clearing[DMA_ERROR] = get_field_val(ral.status.error, item.a_data);
// Clearing the hardware contribution to the `intr_state` fields.
intr_state_hw &= ~clearing;
// Clearing the status bits also clears the corresponding Status-type interrupt(s) unless
// the `intr_test` register is forcing them.
predict_interrupts(CSRtoIntrLatency, clearing, intr_test & intr_enable);
end
"control": begin
bit go, initial_transfer, start_transfer;
// Update the 'Aborted' prediction in response to setting the CONTROL.abort bit
Expand Down Expand Up @@ -1063,24 +1103,28 @@ class dma_scoreboard extends cip_base_scoreboard #(
case (csr.get_name())
"intr_state": begin
`uvm_info(`gfn, $sformatf("intr_state = %0x", item.d_data), UVM_MEDIUM)
do_read_check = 1;
// RAL is unaware of the combined contributions of `intr_test` and the `status` register.
`DV_CHECK_EQ(item.d_data, intr_test | intr_state_hw, "Mismatched interrupt state")
do_read_check = 1'b0;
end
"status": begin
bit busy, done, aborted, error, sha2_digest_valid;
bit busy, done, chunk_done, aborted, error, sha2_digest_valid;
bit exp_aborted = abort_via_reg_write;

do_read_check = 1'b0;
busy = get_field_val(ral.status.busy, item.d_data);
done = get_field_val(ral.status.done, item.d_data);
aborted = get_field_val(ral.status.aborted, item.d_data);
error = get_field_val(ral.status.error, item.d_data);
chunk_done = get_field_val(ral.status.chunk_done, item.d_data);
sha2_digest_valid = get_field_val(ral.status.sha2_digest_valid, item.d_data);

if (done || aborted || error) begin
if (done || aborted || error || chunk_done ) begin
string reasons;
if (done) reasons = "Done ";
if (aborted) reasons = {reasons, "Aborted "};
if (error) reasons = {reasons, "Error" };
if (done) reasons = "Done ";
if (aborted) reasons = {reasons, "Aborted "};
if (error) reasons = {reasons, "Error" };
if (chunk_done) reasons = {reasons, "ChunkDone "};
operation_in_progress = 1'b0;
`uvm_info(`gfn, $sformatf("Detected end of DMA operation (%s)", reasons), UVM_MEDIUM)
// Clear variables
Expand All @@ -1091,31 +1135,36 @@ class dma_scoreboard extends cip_base_scoreboard #(
!(aborted || error) && // no abort or error detected
!(src_tl_error_detected || dst_tl_error_detected))
begin // no TL error
// Check if number of bytes transferred is as expected at this point in the transfer
`DV_CHECK_EQ(num_bytes_transferred, exp_bytes_transferred,
$sformatf("act_data_size: %0d exp_data_size: %0d",
num_bytes_transferred, exp_bytes_transferred))
// Check if number of bytes transferred is as expected at this point in the transfer
`DV_CHECK_EQ(num_bytes_transferred, exp_bytes_transferred,
$sformatf("act_data_size: %0d exp_data_size: %0d",
num_bytes_transferred, exp_bytes_transferred))
end
// STATUS.aborted should only be true if we requested an Abort.
// However, the transfer may just have completed successfully even if we did request an
// Abort and it may even have terminated in response to a TL-UL error for some sequences.
if (abort_via_reg_write) begin
bit bus_error = src_tl_error_detected | dst_tl_error_detected;
`DV_CHECK_EQ(|{aborted, bus_error, done}, 1'b1, "Transfer neither Aborted nor completed.")
// Invalidate any still-pending interrupt changes; the abort may have occurred after
// the final write has completed but before the DMA controller actually completes the
// transfer because e.g. the SHA digest calculation is still completing.
clear_intr_predictions();
end else begin
`DV_CHECK_EQ(aborted, 1'b0, "STATUS.aborted bit set when not expected")
end
if (cfg.en_cov) begin
// Sample dma status and error code
cov.status_cg.sample(.busy (busy),
.done (done),
.chunk_done (chunk_done),
.aborted (aborted),
.error (error),
.sha2_digest_valid (sha2_digest_valid));
end
// Check results after each chunk of the transfer (memory-to-memory) or after the complete
// transfer (handshaking mode).
if (dma_config.is_valid_config && done) begin
if (dma_config.is_valid_config && (done || chunk_done)) begin
if (num_bytes_transferred >= dma_config.total_data_size) begin
// SHA digest (expecting zeros if unused)
// When using inline hashing, sha2_digest_valid must be raised at the end
Expand Down
6 changes: 0 additions & 6 deletions hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,6 @@ class dma_base_vseq extends cip_base_vseq #(
cfg_interrupts(interrupts, enable);
endtask : enable_interrupts

// Clear one or more interrupts
task clear_interrupts(bit [31:0] clear);
`uvm_info(`gfn, $sformatf("DMA: Clear Interrupt(s) 0x%0x", clear), UVM_HIGH)
csr_wr(ral.intr_state, clear);
endtask : clear_interrupts

// Task: Enable Handshake Interrupt Enable
task enable_handshake_interrupt();
`uvm_info(`gfn, "DMA: Assert Interrupt Enable", UVM_HIGH)
Expand Down
Loading

0 comments on commit 2aeb636

Please sign in to comment.