How to set a register to a value thru a hierarchy receiving as string?

I am going to write to the specific registers filed via the task like follow


    task automatic set_register(string block_name, string register_file, string register_name, string field_name, bit [3:0] RegisterValue);
        
        uvm_reg_block   reg_model;
        uvm_reg_block   reg_block;
        uvm_reg         reg_name[$];
        uvm_reg_field   reg_field[$];
        uvm_status_e    status;

        reg_model = m_env.m_ral.lckg_ral;
        reg_block = reg_model.get_block_by_name(block_name);
        if (reg_block == null)
            `uvm_fatal_context("set_register", "lckg_ral block not found", uvm_root::get());

        reg_block.get_registers(reg_name);
        reg_block.get_fields(reg_field);
        foreach (reg_field[i]) begin
            if ((reg_field[i].get_name() == field_name) && (reg_field[i].get_parent().get_name() == register_name) && (reg_field[i].get_parent().get_regfile().get_name() == register_file)) begin
               reg_field[i].set(RegisterValue);
            end
        end
        foreach (reg_name[i]) begin
            if ((reg_name[i].get_name() == register_name) && (reg_name[i].get_regfile().get_name() == register_file)) begin
                reg_name[i].update(status);
            end
        end

    endtask

This task is called when reach to the core of nested foreach loop in main_phase

 foreach (cfg.paths[input_clk]) begin
                foreach (cfg.paths[input_clk][output_clk]) begin
                    foreach (cfg.paths[input_clk][output_clk][string1]) begin
                        foreach (cfg.paths[input_clk][output_clk][string1][string2]) begin
                            foreach (cfg.paths[input_clk][output_clk][string1][string2][string3]) begin
                                foreach (cfg.paths[input_clk][output_clk][string1][string2][string3][string4]) begin
                                        set_register("boston_lckg_lckg_csr", string2, string3, string4, cfg.paths[input_clk][output_clk][string1][string2][string3][string4]);
                                    
                                end
                            end
                        end
                    end
                end
            end

and the paths is the associate array which is defines:

int paths [ace_input_clks_e][ace_output_clks_e][string][string][string][string];

The above task working properly but not sure what I am doing is the good approach in terms of UVM RAL and systemVerilog concept, as well as number of search I am doing, or there is optimized option?

In reply to MahD:

Actually in the other word,
If I had get_regfile_by_name function:

regfile_name = reg_block.get_regfile_by_name(register_file);

I could write to register field with 5 line code:

        reg_block = reg_model.get_block_by_name(block_name);
        regfile_name = reg_block.get_regfile_by_name(register_file);
        reg_name = regfile_name.get_reg_by_name(register_name);
        reg_field = reg_name.get_field_by_name(field_name);

        reg_field.set(RegisterValue);
        reg_name.update(status);

In reply to MahD:

Assuming the implementation of the built-in array locator methods have better performance, set_register task could be like

    // ---------------------------------------------------------------------//
    task automatic set_register(string block_name, string register_file, 
                    string register_name, string field_name, 
                    bit [3:0] RegisterValue);

        uvm_reg_block   reg_model;
        uvm_reg_block   reg_block;
        uvm_reg         regs[$];
        uvm_reg_field   fields[$];
        uvm_status_e    status;

        uvm_reg register[$];
        uvm_reg_field field[$];
        string field_full_name;
        string reg_full_name;

        reg_model = m_env.m_ral.lckg_ral;
        reg_block = reg_model.get_block_by_name(block_name);
        if (reg_block == null)
            `uvm_fatal_context("set_register", "lckg_ral block not found", uvm_root::get());

        reg_block.get_registers(regs);
        reg_block.get_fields(fields);

        field_full_name = {reg_block.get_full_name(), ".", register_name, ".", field_name};
        reg_full_name   = {reg_block.get_full_name(), ".", register_name};

        register = regs.find with(item.get_full_name() == reg_full_name); 
        field    = fields.find with (item.get_full_name() == field_full_name);
        // Check for the size of register and field
        if(register.size != 1) 
            `uvm_fatal_context("REGISTER_NAME", "register name doesn't exist!!!", uvm_root::get());
        if(field.size != 1) 
            `uvm_fatal_context("FIELD_NAME", "field name doesn't exist!!", uvm_root::get());

        field[0].set(RegisterValue);
        register[0].update(status);
    endtask

For the nested foreachs, you could use the following equivalent one, I don’t think you will gain a performance, but it will be more readable.

 foreach (cfg.paths[clk_i, clk_o, s1, s2, s3, s4]) begin
      set_register("boston_lckg_lckg_csr", s2, s3, s4, cfg.paths[clk_i][clk_o][s1][s2][s3][s4]);         
 end

Note: I’ve partially compiled the code, to compile it fully I need the whole environment setup, but I guess you get the idea.

In reply to Ahmed Kelany:

Really appreciate your help.
Just a minor modification needed to access to register filed properly as follow:

reg_full_name   = {reg_block.get_full_name(), ".", register_file_name, ".", register_name};
        field_full_name = {reg_block.get_full_name(), ".", register_file_name, ".", register_name, ".", field_name};