Skip to content

Commit

Permalink
Separate FIFOs for source and destination
Browse files Browse the repository at this point in the history
If the source and destination are the same interface then it
may be necessary to have separate FIFOs for the read and write
traffic now, given the more flexible addressing available in
the modified design.

Signed-off-by: Adrian Lees <a.lees@lowrisc.org>
  • Loading branch information
alees24 authored and andreaskurth committed Dec 23, 2024
1 parent e484a21 commit fa49bd9
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 45 deletions.
13 changes: 10 additions & 3 deletions hw/ip/dma/dv/env/dma_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,16 @@ class dma_env_cfg extends cip_base_env_cfg #(.RAL_T(dma_reg_block));
// FIFO depending on handshake_mode_en
// These models are used in TL device sequences
// Data comparison is done in scoreboard
dma_handshake_mode_fifo#(.AddrWidth(HOST_ADDR_WIDTH)) fifo_host;
dma_handshake_mode_fifo#(.AddrWidth(CTN_ADDR_WIDTH)) fifo_ctn;
dma_handshake_mode_fifo#(.AddrWidth(SYS_ADDR_WIDTH)) fifo_sys;
dma_handshake_mode_fifo#(.AddrWidth(HOST_ADDR_WIDTH)) fifo_dst_host;
dma_handshake_mode_fifo#(.AddrWidth(CTN_ADDR_WIDTH)) fifo_dst_ctn;
dma_handshake_mode_fifo#(.AddrWidth(SYS_ADDR_WIDTH)) fifo_dst_sys;
// Each interface requires separate source and destination FIFO to handle the case where the
// read traffic and the write traffic both occur on the same interface and neither is using
// incrementing addressing.
dma_handshake_mode_fifo#(.AddrWidth(HOST_ADDR_WIDTH)) fifo_src_host;
dma_handshake_mode_fifo#(.AddrWidth(CTN_ADDR_WIDTH)) fifo_src_ctn;
dma_handshake_mode_fifo#(.AddrWidth(SYS_ADDR_WIDTH)) fifo_src_sys;
// Memory models may be used for typical transfers where addresses are incremented.
mem_model#(.AddrWidth(HOST_ADDR_WIDTH), .DataWidth(HOST_DATA_WIDTH)) mem_host;
mem_model#(.AddrWidth(CTN_ADDR_WIDTH), .DataWidth(CTN_DATA_WIDTH)) mem_ctn;
mem_model#(.AddrWidth(SYS_ADDR_WIDTH), .DataWidth(SYS_DATA_WIDTH)) mem_sys;
Expand Down
9 changes: 5 additions & 4 deletions hw/ip/dma/dv/env/dma_pull_seq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ class dma_pull_seq #(int AddrWidth = 32) extends tl_device_seq#(.AddrWidth(AddrW
// FIFO interrupt clear register address
// with address as key and corresponding write value as value of the associative array
bit [31:0] fifo_intr_clear_reg[bit [31:0]];
// FIFO instance
dma_handshake_mode_fifo #(AddrWidth) fifo;
// FIFO instances for destination and source.
dma_handshake_mode_fifo #(AddrWidth) dst_fifo;
dma_handshake_mode_fifo #(AddrWidth) src_fifo;
// Bytes/transaction; because the `tlul_adapter_host` module always retrieves entire bus words,
// to track the number of bytes read by the DMA controller, this 'useful bytes per transaction'
// must be supplied.
Expand Down Expand Up @@ -93,7 +94,7 @@ class dma_pull_seq #(int AddrWidth = 32) extends tl_device_seq#(.AddrWidth(AddrW
if (rsp.a_mask[i]) begin
bytes_written++;
if (write_fifo_en) begin
fifo.write_byte(a_addr + i, data[7:0]);
dst_fifo.write_byte(a_addr + i, data[7:0]);
end else begin
mem.write_byte(a_addr + i, data[7:0]);
end
Expand All @@ -104,7 +105,7 @@ class dma_pull_seq #(int AddrWidth = 32) extends tl_device_seq#(.AddrWidth(AddrW
end else begin
// Collect data from source model
if (read_fifo_en) begin
rsp.d_data = fifo.read_word_tlul(a_addr, rsp.a_mask);
rsp.d_data = src_fifo.read_word_tlul(a_addr, rsp.a_mask);
end else begin
for (int i = 0; i < $bits(rsp.a_mask); i++) begin
rsp.d_data = rsp.d_data >> 8;
Expand Down
7 changes: 4 additions & 3 deletions hw/ip/dma/dv/env/dma_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,9 @@ class dma_scoreboard extends cip_base_scoreboard #(
// Note: that this is destructive in that it pops the data from the FIFO
function bit [7:0] get_fifo_data(asid_encoding_e asid, bit [63:0] addr);
case (asid)
OtInternalAddr: return cfg.fifo_host.read_byte(addr);
SocControlAddr: return cfg.fifo_ctn.read_byte(addr);
SocSystemAddr : return cfg.fifo_sys.read_byte(addr);
OtInternalAddr: return cfg.fifo_dst_host.read_byte(addr);
SocControlAddr: return cfg.fifo_dst_ctn.read_byte(addr);
SocSystemAddr : return cfg.fifo_dst_sys.read_byte(addr);
default: begin
`uvm_error(`gfn, $sformatf("Unsupported Address space ID %d", asid))
end
Expand Down Expand Up @@ -901,6 +901,7 @@ class dma_scoreboard extends cip_base_scoreboard #(
dma_config.dst_addr[63:32] = item.a_data;
`uvm_info(`gfn, $sformatf("Got dst_addr_hi = %0x", dma_config.dst_addr[63:32]), UVM_HIGH)
end
// TODO: Drop dst_control and src_control
"dst_config", "dst_control": begin
`uvm_info(`gfn, $sformatf("Got dst_config = %0x", item.a_data), UVM_HIGH)
dma_config.dst_chunk_wrap = get_field_val(ral.dst_config.wrap, item.a_data);
Expand Down
10 changes: 10 additions & 0 deletions hw/ip/dma/dv/env/dma_seq_item.sv
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ class dma_seq_item extends uvm_sequence_item;
intr_src_wr_val.size() == dma_reg_pkg::NumIntClearSources;
}

// Constrain the source/destination address configuration; presently the DV cannot handle
// non-wrapping, non-incrementing because this requires a FIFO model that accepts
// data at multiple addresses.
constraint src_config_c {
src_addr_inc | src_chunk_wrap;
};
constraint dst_config_c {
dst_addr_inc | dst_chunk_wrap;
};

constraint src_addr_c {
// Set solve order to make sure source address is randomized correctly in case
// valid_dma_config is set
Expand Down
116 changes: 81 additions & 35 deletions hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,24 @@ class dma_base_vseq extends cip_base_vseq #(
seq_host = dma_pull_seq #(.AddrWidth(HOST_ADDR_WIDTH))::type_id::create("seq_host");
seq_sys = dma_pull_seq #(.AddrWidth(SYS_ADDR_WIDTH))::type_id::create("seq_sys");
// Create memory models
seq_host.fifo = dma_handshake_mode_fifo#(
seq_host.dst_fifo = dma_handshake_mode_fifo#(
.AddrWidth(HOST_ADDR_WIDTH))::type_id::create("fifo_host");
seq_ctn.fifo = dma_handshake_mode_fifo#(
seq_ctn.dst_fifo = dma_handshake_mode_fifo#(
.AddrWidth(CTN_ADDR_WIDTH))::type_id::create("fifo_ctn");
seq_sys.fifo = dma_handshake_mode_fifo#(
seq_sys.dst_fifo = dma_handshake_mode_fifo#(
.AddrWidth(SYS_ADDR_WIDTH))::type_id::create("fifo_sys");
seq_host.src_fifo = dma_handshake_mode_fifo#(
.AddrWidth(HOST_ADDR_WIDTH))::type_id::create("fifo_host");
seq_ctn.src_fifo = dma_handshake_mode_fifo#(
.AddrWidth(CTN_ADDR_WIDTH))::type_id::create("fifo_ctn");
seq_sys.src_fifo = dma_handshake_mode_fifo#(
.AddrWidth(SYS_ADDR_WIDTH))::type_id::create("fifo_sys");
seq_host.mem = mem_model#(.AddrWidth(HOST_ADDR_WIDTH),
.DataWidth(HOST_DATA_WIDTH))::type_id::create("mem_host");
seq_ctn.mem = mem_model#(.AddrWidth(CTN_ADDR_WIDTH),
.DataWidth(CTN_DATA_WIDTH))::type_id::create("mem_ctn");
seq_sys.mem = mem_model#(.AddrWidth(SYS_ADDR_WIDTH),
.DataWidth(SYS_DATA_WIDTH))::type_id::create("mem_sys");
.DataWidth(SYS_DATA_WIDTH))::type_id::create("mem_sys");

// System bus is currently unavailable and untestable withing this DV environment,
// so activate additional constraints to prevent it causing test failures.
Expand All @@ -66,16 +72,24 @@ class dma_base_vseq extends cip_base_vseq #(
cfg.mem_host = seq_host.mem;
cfg.mem_sys = seq_sys.mem;
// Assign dma_handshake_mode_fifo instance handle to config object
cfg.fifo_ctn = seq_ctn.fifo;
cfg.fifo_host = seq_host.fifo;
cfg.fifo_sys = seq_sys.fifo;
cfg.fifo_dst_ctn = seq_ctn.dst_fifo;
cfg.fifo_dst_host = seq_host.dst_fifo;
cfg.fifo_dst_sys = seq_sys.dst_fifo;
cfg.fifo_src_ctn = seq_ctn.src_fifo;
cfg.fifo_src_host = seq_host.src_fifo;
cfg.fifo_src_sys = seq_sys.src_fifo;
// Initialize memory
cfg.mem_host.init();
cfg.mem_ctn.init();
cfg.mem_sys.init();
cfg.fifo_host.init();
cfg.fifo_ctn.init();
cfg.fifo_sys.init();
// Initialize destination FIFOs
cfg.fifo_dst_host.init();
cfg.fifo_dst_ctn.init();
cfg.fifo_dst_sys.init();
// Initialize source FIFOs
cfg.fifo_src_host.init();
cfg.fifo_src_ctn.init();
cfg.fifo_src_sys.init();
endfunction

// When full testing of the Soc System bus has been waived at block level and we have only a
Expand Down Expand Up @@ -164,13 +178,13 @@ class dma_base_vseq extends cip_base_vseq #(
input bit [31:0] offset, input bit [31:0] size);
case (asid)
OtInternalAddr: begin
cfg.fifo_host.populate_fifo(src_data, offset, size);
cfg.fifo_src_host.populate_fifo(src_data, offset, size);
end
SocControlAddr: begin
cfg.fifo_ctn.populate_fifo(src_data, offset, size);
cfg.fifo_src_ctn.populate_fifo(src_data, offset, size);
end
SocSystemAddr: begin
cfg.fifo_sys.populate_fifo(src_data, offset, size);
cfg.fifo_src_sys.populate_fifo(src_data, offset, size);
end
default: begin
`uvm_error(`gfn, $sformatf("Unsupported Address space ID %d", asid))
Expand Down Expand Up @@ -201,24 +215,49 @@ class dma_base_vseq extends cip_base_vseq #(
end
endfunction

// Function to set dma_handshake_mode_fifo mode settings
function void set_model_fifo_mode(asid_encoding_e asid,
bit [63:0] start_addr = '0,
dma_transfer_width_e per_transfer_width,
bit [31:0] max_size);
// Function to set the transfer properties for a source FIFO.
function void set_model_src_fifo_mode(asid_encoding_e asid,
bit [63:0] start_addr = '0,
dma_transfer_width_e per_transfer_width,
bit [31:0] max_size);
start_addr[1:0] = 2'd0; // Address generated by DMA is 4B aligned
case (asid)
OtInternalAddr: begin
cfg.fifo_src_host.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
SocControlAddr: begin
cfg.fifo_src_ctn.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
SocSystemAddr: begin
cfg.fifo_src_sys.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
default: begin
`uvm_error(`gfn, $sformatf("Unsupported Address space ID %d", asid))
end
endcase
endfunction

// Function to set the transfer properties for a destination FIFO.
function void set_model_dst_fifo_mode(asid_encoding_e asid,
bit [63:0] start_addr = '0,
dma_transfer_width_e per_transfer_width,
bit [31:0] max_size);
start_addr[1:0] = 2'd0; // Address generated by DMA is 4B aligned
case (asid)
OtInternalAddr: begin
cfg.fifo_host.enable_fifo(.fifo_base (start_addr), .per_transfer_width(per_transfer_width),
.max_size (max_size));
cfg.fifo_dst_host.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
SocControlAddr: begin
cfg.fifo_ctn.enable_fifo(.fifo_base (start_addr), .per_transfer_width(per_transfer_width),
.max_size (max_size));
cfg.fifo_dst_ctn.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
SocSystemAddr: begin
cfg.fifo_sys.enable_fifo(.fifo_base (start_addr), .per_transfer_width(per_transfer_width),
.max_size (max_size));
cfg.fifo_dst_sys.enable_fifo(.fifo_base(start_addr),
.per_transfer_width(per_transfer_width), .max_size(max_size));
end
default: begin
`uvm_error(`gfn, $sformatf("Unsupported Address space ID %d", asid))
Expand All @@ -243,8 +282,8 @@ class dma_base_vseq extends cip_base_vseq #(
// Configure Source model
if (dma_config.get_read_fifo_en()) begin
// Enable read FIFO mode in models
set_model_fifo_mode(dma_config.src_asid, dma_config.src_addr, dma_config.per_transfer_width,
chunk_size);
set_model_src_fifo_mode(dma_config.src_asid, dma_config.src_addr,
dma_config.per_transfer_width, chunk_size);
end else begin
// The source address depends upon the configuration; chunks may overlap each other.
bit [31:0] src_addr = dma_config.src_addr;
Expand All @@ -266,8 +305,8 @@ class dma_base_vseq extends cip_base_vseq #(
end

// Enable write FIFO mode in models
set_model_fifo_mode(dma_config.dst_asid, dma_config.dst_addr, dma_config.per_transfer_width,
max_size);
set_model_dst_fifo_mode(dma_config.dst_asid, dma_config.dst_addr,
dma_config.per_transfer_width, max_size);
end

// Return the updated byte offset within the transfer
Expand Down Expand Up @@ -565,10 +604,14 @@ class dma_base_vseq extends cip_base_vseq #(
seq_ctn.set_fifo_clear(0);
seq_host.set_fifo_clear(0);
seq_sys.set_fifo_clear(0);
// Disable FIFO
cfg.fifo_host.disable_fifo();
cfg.fifo_ctn.disable_fifo();
cfg.fifo_sys.disable_fifo();
// Disable destination FIFOs
cfg.fifo_dst_host.disable_fifo();
cfg.fifo_dst_ctn.disable_fifo();
cfg.fifo_dst_sys.disable_fifo();
// Disable source FIFOs
cfg.fifo_dst_host.disable_fifo();
cfg.fifo_dst_ctn.disable_fifo();
cfg.fifo_dst_sys.disable_fifo();
endtask

// Method to clear memory models of any content
Expand All @@ -584,9 +627,12 @@ class dma_base_vseq extends cip_base_vseq #(
function void clear_fifo();
// Clear FIFO contents
`uvm_info(`gfn, $sformatf("Clearing FIFO contents"), UVM_MEDIUM)
cfg.fifo_host.init();
cfg.fifo_ctn.init();
cfg.fifo_sys.init();
cfg.fifo_dst_host.init();
cfg.fifo_dst_ctn.init();
cfg.fifo_dst_sys.init();
cfg.fifo_src_host.init();
cfg.fifo_src_ctn.init();
cfg.fifo_src_sys.init();
endfunction

// Task: Set the CONTROL register, optionally commencing a transfer.
Expand Down

0 comments on commit fa49bd9

Please sign in to comment.