Multiple frontdoor sequences for same RAL

Hi there,

is it possible to have multiple frontdoor sequnces over the same register layer?
I would require this for a design having more (redundant) interfaces to access the same bus.
I could imagine something like:

ral.jtag_read()
ral.vme_read()

You could use different maps to go through different busses:


ral.read(..., .map(jtag_map);
ral.read(..., .map(vme_map);

In reply to dipling:
If you are using the same bus you need only one map.
I understood you have different adapters/bridges to access your bus, one from jtag and another one from vme. Is this correct?

In reply to chr_sue:

I understood you have different adapters/bridges to access your bus, one from jtag and another one from vme. Is this correct?

That is correct.

In reply to Tudor Timi:

Hi,

I started to do the coding for multiple maps with distinct frontdoor_seq (and physical interfaces), however I ran into the following error:

UVM_ERROR […] @ 0.0000us: reporter [RegModel] Map ‘ral.my_regs.reg_map’ is already a child of map ral.jtag_map

However the documentation of uvm_reg_map says:

An address map may be added to multiple address maps if it is accessible from multiple
physical interfaces

I obviously did something wrong, but I can’t figgure out what. Any hints?

class my_reg_block extends uvm_reg_block;
    `uvm_object_utils(my_reg_block )
    
    rand my_reg1_rc my_reg1;
    rand my_reg2_rc my_reg2;

    uvm_reg_map my_regs_map; // Block map

    function new(string name = "my_reg_block ");
        super.new(name, UVM_NO_COVERAGE);
    endfunction

    virtual function void build();
        my_reg1= my_reg1_rc ::type_id::create("my_reg1");
        my_reg1.configure(this, null, "");
        my_reg1.build();
        ... 

        my_regs_map= create_map("my_regs_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
        my_regs_map.add_reg(my_reg1, 32'h8000 , "RW");
        my_regs_map.add_reg(my_reg2, 32'h8001 , "RW");
endclass

class my_register_model extends uvm_reg_block;
    `uvm_object_utils(my_register_model )

    function new(string name = "my_register_model ");
        super.new(name);
    endfunction

    rand my_reg_block my_regs;

    uvm_reg_map jtag_map;
    uvm_reg_map vme_map;

    function void build();
        // default map : jtag bus sequencer
        jtag_map = new("jtag_map");
        jtag_map = create_map("jtag_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
        // same map again --> attach to VME sequencer
        vme_map = new("vme_map");
        vme_map = create_map("vme_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));

        // register blocks
        my_regs= my_reg_block ::type_id::create("my_regs",  , get_full_name());
        my_regs.configure(this);
        my_regs.build();

        // add all register blocks (identical configuration) to the jtag and vme maps
        jtag_map.add_submap(this.my_regs.default_map, 'h0);
        vme_map.add_submap(this.my_regs.default_map, 'h0);

        // define default submap == JTAG
        default_map = jtag_map;
        this.lock_model();
    endfunction

endclass

class my_env extens uvm_env;

    jtag_reg2cmd_adapter m_jtag_reg2cmd;
    jtag_frontdoor_seq fdsq_jtag;
    vme_reg2cmd_adapter m_vme_reg2cmd;
    vme_frontdoor_seq fdsq_vme;
    my_register_model ral;

    //build phase
    fdsq_jtag = jtag_frontdoor_seq::type_id::create("fdsq_jtag");
    fdsq_vme = vme_frontdoor_seq::type_id::create("fdsq_vme");

    //connect phase
    uvm_reg regs[$];
    uvm_reg_map vme_map, jtag_map;

    vme_map   = ral.get_map_by_name("vme_map");
    jtag_map  = ral.get_map_by_name("jtag_map");


    ral.jtag_map.get_registers(regs);
    foreach(regs[i]) begin
        regs[i].set_frontdoor(.ftdr(fdsq_jtag), .map(jtag_map));
    end
    regs.delete();

    ral.vme_map.get_registers(regs);
    foreach(regs[i]) begin
        regs[i].set_frontdoor(.ftdr(fdsq_vme), .map(vme_map));
    end
    regs.delete();

endclass


Hi,

at least for the “child-grandchild” error I have a solution.
However this is just as good as a complete duplication of the register model.

How can I make the predictor understand that the registers in the two maps refer to the same DUT registers?

class my_reg_block extends uvm_reg_block;
    `uvm_object_utils(my_reg_block )
    
    rand my_reg1_rc my_reg1;
    rand my_reg2_rc my_reg2;

    uvm_reg_map my_regs_map_for_vme; // Block map
    uvm_reg_map my_regs_map_for_jtag; // Block map

    function new(string name = "my_reg_block ");
        super.new(name, UVM_NO_COVERAGE);
    endfunction

    virtual function void build();

        ... 

        my_regs_map_for_vme= create_map("my_regs_map_for_vme", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
        my_regs_map_for_vme.add_reg(my_reg1, 32'h8000 , "RW");
        my_regs_map_for_vme.add_reg(my_reg2, 32'h8001 , "RW");
        my_regs_map_for_jtag= create_map("my_regs_map_for_jtag", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
        my_regs_map_for_jtag.add_reg(my_reg1, 32'h8000 , "RW");
        my_regs_map_for_jtag.add_reg(my_reg2, 32'h8001 , "RW");
endclass

class my_register_model extends uvm_reg_block;
    `uvm_object_utils(my_register_model )

    function new(string name = "my_register_model ");
        super.new(name);
    endfunction

    rand my_reg_block my_regs;

    uvm_reg_map jtag_map;
    uvm_reg_map vme_map;

    function void build();
        // default map : jtag bus sequencer
        jtag_map = new("jtag_map");
        jtag_map = create_map("jtag_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));
        // same map again --> attach to VME sequencer
        vme_map = new("vme_map");
        vme_map = create_map("vme_map", 'h0, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0));

        ...

        // add all register blocks (identical configuration) to the jtag and vme maps
        jtag_map.add_submap(this.my_regs.my_regs_map_for_jtag, 'h0);
        vme_map.add_submap(this.my_regs.my_regs_map_for_vme, 'h0);

        // define default submap == JTAG
        default_map = jtag_map;
        this.lock_model();
    endfunction

endclass


In reply to dipling:

The documentation and the implementation aren’t in sync. The error message you’re getting explicitly prohibits a map from being added to multiple address maps.

What you can do is create two different maps and add the registers to exactly the same offsets as in the default_map. This doesn’t mean that you have to duplicate the code. You can do this programmatically:


// get a list of all regs that are mapped in default_map
uvm_reg regs;
default_map.get_registers(regs);

// start adding all of those registers to the other map
foreach (regs*)
  jtag_map.add_reg(regs[i], regs[i].get_offset(default_map);

// do the same for the 'vme_map'
// ...

This way you only specify the actual offsets of the registers once, when adding them to [i]default_map*.

DISCLAIMER: I didn’t test the code.