Hdl path to memory instance

Hello,

I’m trying to use the memory model for access via FRONTDOOR and BACKDOOR. I’ve added the memory’s hdl path to the model (via configure() or add_hdl_path_slice(), both works) and all is fine, except that the (logical) memory block is made up of two (physical) memory instances such that both instances have the same width but half the depth of the logical memory.

So the locigal memory is 32 bit wide and 256 locations deep, made up of two memories, each 32 bit wide and 128 deep.

How can a 2nd hdl path be added to the memory model?

I have tried using add_hdl_path_slice(, 128, 128), but that does not work. Upon reading more about add_hdl_path*(), it seems they are only meant for registers, not memories.

Regards
Gunther

In reply to Gunther Clasen:

Unfortunately, uvm_mem does not support multiple physical memories making up a single logical memory of greater depth. The solution is to add a user defined backdoor.

This is an example of a 24 bit wide memory made up of 64 2048x12 memories. In our case HW accesses all these memories in parallel, but for CPU access they are treated as a single logical memory. Code like this can be generalized, but there’s always a variation that breaks the general case, so it’s not too much difficulty to have a few custom backdoors for the few special cases.


class dmem_backdoor extends uvm_reg_backdoor;
    string m_sBank[32][2];
    uint32 m_nBankSize = 2048;

    function new(string name = "dmem_backdoor", string sRootPath);
       super.new(name);

       for (int i=0; i<32; i++) begin
           for (int j=0; j<2; j++) begin
               string ss = $sformatf("%s.u_ax_e_core.u_ax_bf.idmem.gen_agl_bram_switch[%0d].iram.ga11d12.iram.uut.mem_core_array", sRootPath, 2*i+j);

               m_sBank[i][j] = ss;
           end 
       end 
    endfunction

    virtual task write(uvm_reg_item rw);
        bit ok=1;

        foreach (rw.value[i]) begin
            int nAddr = rw.offset + i;
            int nBank = nAddr / m_nBankSize;
            int nOffset = nAddr % m_nBankSize;

            string sSlice0 = $sformatf("%s[%0d]", m_sBank[nBank][0], nOffset);
            string sSlice1 = $sformatf("%s[%0d]", m_sBank[nBank][1], nOffset);

            `uvm_info("RegModel", {"backdoor_write to ", sSlice0, " ", sSlice1}, UVM_DEBUG);

            ok &= uvm_hdl_deposit(sSlice0, rw.value[i][11:0]);
            ok &= uvm_hdl_deposit(sSlice1, rw.value[i][27:16]);
        end

        rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK);
    endtask

    virtual task read(uvm_reg_item rw);
        bit ok=1;

        foreach (rw.value[i]) begin
            int nAddr = rw.offset + i;
            int nBank = nAddr / m_nBankSize;
            int nOffset = nAddr % m_nBankSize;
            int nData;

            string sSlice0 = $sformatf("%s[%0d]", m_sBank[nBank][0], nOffset);
            string sSlice1 = $sformatf("%s[%0d]", m_sBank[nBank][1], nOffset);

            `uvm_info("RegModel", {"backdoor_read to ", sSlice0, " ", sSlice1}, UVM_DEBUG);

            ok &= uvm_hdl_read(sSlice0, nData);

            rw.value[i][15:0] = 16'(signed'(nData[11:0])); // sign extend on read

            ok &= uvm_hdl_read(sSlice1, nData);

            rw.value[i][31:16] = 16'(signed'(nData[11:0])); // sign extend on read
        end

        rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK);
    endtask
endclass

To use a custom backdoor simply add it to the reg model instance.

your_reg_model.your_mem.set_backdoor(your_back_door_object);

After adding the custom backdoor the uvm_mem instance will use it instead of the built-in backdoor.