diff --git a/hw/ip/dma/dv/env/dma_env_cfg.sv b/hw/ip/dma/dv/env/dma_env_cfg.sv index 7f940401165f8..0ecc0de97a7c4 100644 --- a/hw/ip/dma/dv/env/dma_env_cfg.sv +++ b/hw/ip/dma/dv/env/dma_env_cfg.sv @@ -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; diff --git a/hw/ip/dma/dv/env/dma_pull_seq.sv b/hw/ip/dma/dv/env/dma_pull_seq.sv index e20b116710e14..d219de253b08f 100644 --- a/hw/ip/dma/dv/env/dma_pull_seq.sv +++ b/hw/ip/dma/dv/env/dma_pull_seq.sv @@ -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. @@ -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 @@ -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; diff --git a/hw/ip/dma/dv/env/dma_scoreboard.sv b/hw/ip/dma/dv/env/dma_scoreboard.sv index a6200e7eeb1b7..8f3faa4948a76 100644 --- a/hw/ip/dma/dv/env/dma_scoreboard.sv +++ b/hw/ip/dma/dv/env/dma_scoreboard.sv @@ -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 @@ -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); diff --git a/hw/ip/dma/dv/env/dma_seq_item.sv b/hw/ip/dma/dv/env/dma_seq_item.sv index 5c002072c4183..39dfc9ce4ac7f 100644 --- a/hw/ip/dma/dv/env/dma_seq_item.sv +++ b/hw/ip/dma/dv/env/dma_seq_item.sv @@ -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 diff --git a/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv b/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv index a1baf341ebdc4..97e1745849b65 100644 --- a/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv +++ b/hw/ip/dma/dv/env/seq_lib/dma_base_vseq.sv @@ -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. @@ -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 @@ -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)) @@ -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)) @@ -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; @@ -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 @@ -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 @@ -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.