Jump to content

markeduda

Members
  • Content Count

    1
  • Joined

  • Last visited

About markeduda

  • Rank
    Member

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. I recently came upon an issue where attempting to write a memory via a backdoor yields a warning similar to the following: "reporter [RegModel] Memory 'tst_reg_blk.test_mem' is not contained within map 'Backdoor' (called from get_access())" In addition to the warning, it appears that due rw.map being overwritten (as explained in the second link), Read-Only memories can be written to via the backdoor, since get_access end up returning the default value of "RW". This appears to be in conflict with the Spec: Researching this warning turned up a couple prior forum posts from 2014: http://forums.accellera.org/topic/2104-question-about-backdoor-map/ http://forums.accellera.org/topic/2107-problem-with-backdoor-access-to-uvm_mem/ Neither of which had an associated answer. I came up with a test case to reproduce the warning: //####################################################################### // Backdoor accesses to a UVM_MEM that is a member of more than 1 map // causes a UVM_WARNING that that the memory is not contained within // the 'Backdoor' register map. // // This appears to happen due to the uvm_mem::Xcheck_accessX call in // uvm_mem::do_write, which replaces rw.map with the pseudo-map 'Backdoor'. // This replacement precedes the get_access(rw.map) call later in do_write. // The warning is generated when map membership is checked in get_local_map // which is called from get_access in the case that there is > 1 maps to // which the memory belongs. // // Below is a test case that reproduces the warning, as well as a workaround // that replaces the overwritten map (if WORKAROUND is defined). //####################################################################### package test_pkg; import uvm_pkg::*; `include "uvm_macros.svh" typedef class basic_test; typedef class test_env; typedef class test_reg_block; typedef class test_mem_class; //######################################### // Test //######################################### class basic_test extends uvm_test; test_env env; `uvm_component_utils(basic_test) //---- New Function ---- function new(string name = "basic_test", uvm_component parent); super.new(name, parent); endfunction : new //---- Build Phase ---- function void build_phase(uvm_phase phase); super.build_phase(phase); env = test_env::type_id::create("env", this); endfunction //---- Run Phase ---- virtual task run_phase(uvm_phase phase); uvm_reg_data_t data = 'hA5; uvm_reg_addr_t offset = 'h0000; uvm_status_e status; phase.raise_objection(this, "Starting Test"); `uvm_info(get_type_name(), "Got into Test Run_Phase.", UVM_LOW) `uvm_info(get_type_name(), $sformatf("Writing 0x%h.", data), UVM_LOW) //This causes a warning if WORKAROUND is not defined env.tst_reg_blk.test_mem.write(.status(status), .offset(offset), .value(data), .path(UVM_BACKDOOR), .map(env.tst_reg_blk.test_reg_map), .parent(null), .prior(-1), .extension(null), .fname(""), .lineno(0)); data = 'h0; //Warning does not occur on read env.tst_reg_blk.test_mem.read( .status(status), .offset(offset), .value(data), .path(UVM_BACKDOOR), .map(env.tst_reg_blk.test_reg_map), .parent(null), .prior(-1), .extension(null), .fname(""), .lineno(0)); `uvm_info(get_type_name(), $sformatf("Read 0x%h.", data), UVM_LOW) phase.drop_objection(this, "Test Is Done"); endtask : run_phase endclass //######################################### // Basic Environment //######################################### class test_env extends uvm_env; test_reg_block tst_reg_blk; `uvm_component_utils(test_env) //---- New Function ---- function new(input string name, input uvm_component parent=null); super.new(name,parent); endfunction //---- Build Phase ---- function void build_phase(uvm_phase phase); super.build_phase(phase); tst_reg_blk = test_reg_block::type_id::create("tst_reg_blk"); tst_reg_blk.configure(); tst_reg_blk.setup(); tst_reg_blk.set_hdl_path_root("test_tb"); endfunction : build_phase endclass //######################################### // Register Block Class //######################################### class test_reg_block extends uvm_reg_block; uvm_reg_map test_reg_map; uvm_reg_map test_reg_map_2; test_mem_class test_mem; `uvm_object_utils(test_reg_block) //---- New Function ---- function new(input string name="test_reg_block"); super.new(name); endfunction // new //Create Map, Add/Configure Memory, Lock Model function void setup(); test_reg_map = create_map("test_reg_map", 'h00000000, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0)); test_reg_map_2 = create_map("test_reg_map", 'h00000000, 4, UVM_LITTLE_ENDIAN, .byte_addressing(0)); test_mem = test_mem_class::type_id::create("test_mem", , get_full_name()); test_mem.configure(this, "rtl_mem"); test_reg_map.add_mem( .mem(test_mem), .offset (32'h00000000), .rights ("RO"), .unmapped (0)); test_reg_map_2.add_mem( .mem(test_mem), .offset (32'h00000000), .rights ("RO"), .unmapped (0)); this.lock_model(); endfunction // setup endclass //######################################### // Register Block Class //######################################### class test_mem_class extends uvm_mem; `uvm_object_utils(test_mem_class) //---- New Function ---- function new(input string name="test_mem_class"); super.new(.name(name), .size(16), .n_bits(8), .access("RW"), .has_coverage(UVM_NO_COVERAGE)); endfunction // new //---- Bug Workaround ---- // Override the do_write task grab a local copy of the map. // Then override pre_write (which occurs after Xcheck_accessX) // to reassign the map with the local copy in the case of a // backdoor access. // // An actual fix would involve changing the behaviour of // Xcheck_accessX, which is non-virtual. `ifdef WORKAROUND protected uvm_reg_map backup_map; virtual task do_write (uvm_reg_item rw); backup_map = rw.map; super.do_write(rw); endtask virtual task pre_write (uvm_reg_item rw); super.pre_write(rw); if(rw.path == UVM_BACKDOOR) begin if(backup_map == null) rw.map = rw.local_map; else rw.map = backup_map; end endtask `endif endclass endpackage : test_pkg //######################################### // Basic TB //######################################### module test_tb(); import uvm_pkg::*; import test_pkg::*; `include "uvm_macros.svh" reg [7:0] rtl_mem [16]; initial run_test("basic_test"); endmodule I was able to come up with a work-around, but I feel that I am missing something. What is the actual purpose of uvm_reg_map::backdoor()? What is it's intended use case? Given that it has no parent block (thus not allowing memories or registers to be added), I do not know how it could be used. Thank you in advance for considering my question. //----------------- Edit ------------------------ I realized after the fact that this is a pre-IEEE issue. I Don't know if the topic can be moved to the correct forum. However, the question still stands; what is the intended purpose of the Backdoor pseudo-map?
×