UVM Reg Frontdoor and Backdoor accesses

Morning all

I am still battling with an oddity between front and backdoor access to the same register block. I have previously detailed my initial simulation in this post here.
To ensure there is not something in that build, i have used another testbench and coded a similar setup to discount anything specific.

I have sequence which reads and writes to two registers RegA and RegB. It will read, modify then write to RegA via the front door, then do the same with RegB. Next i read, modify and write via the back door to RegA again.


 bit[15:0] temp_data;  //, ref_data;
repeat (num_repetions) begin

      // Front door Accesses
      //Read RegA and then add 0x10 to it.
      bus_agent_rm.RegA_h.read(status, temp_data, .parent(this));
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf("Reading  via front door RegA: 0x%04x", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegA return is not OK")            
        
      //Now add 0x10 to RegA and Write it Back via front door.
      temp_data += 'h10;
      bus_agent_rm.RegA_h.write(status, temp_data, .parent(this));;  
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf("Writing via front door to RegA: 0x%04x", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegA return is not OK")                      
 
      //Read RegB and then add 0x1000 to it.
      bus_agent_rm.RegB_h.read(status, temp_data, .parent(this));
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf("Reading via front door RegB: 0x%04x", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegB return is not OK")            
                                   
      //Now add 0x1000 to RegB and Write it Back.
      temp_data += 'h1000;
      bus_agent_rm.RegB_h.write(status, temp_data, .parent(this));
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf("Writing  via front door to RegB: 0x%04x\n", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegB return is not OK")

       // Back door Accesses
      //Read RegA and then add 0x20 to it.
      bus_agent_rm.RegA_h.read(status, temp_data, .parent(this), .path(UVM_BACKDOOR));
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf( "Reading  via back door RegA: 0x%04x", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegA return is not OK")            
        
      //Now add 0x20 to RegA and Write it Back via back door.
      temp_data += 'h20;
      bus_agent_rm.RegA_h.write(status, temp_data, .parent(this), .path(UVM_BACKDOOR));  
      if (status == UVM_IS_OK) 
        `uvm_info({get_type_name(),":body"}, $sformatf("Writing via back door to RegA: 0x%04x \n", temp_data), UVM_NONE)    
      else
        `uvm_fatal({get_type_name(),":body"}, "RegA return is not OK")                              
    End

At the end of this simulation the transcript window should reveal RegA incrementing by h10 with the front door access and h20 on the back door accesses. RegB will increment by `h1000 on the front door access alone.

Unfortunately the transcript reveals…

*** Iterating 10 times through status_reg, RegA and Regb.

UVM_INFO @ 0 ns: reporter [reg2bus:] Instruction: READ. raddr: 2, rdata: 0

UVM_INFO @ 200 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 0, wdata: 0

UVM_INFO @ 220 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO @ 240 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 0, wdata: 0

UVM_INFO @ 250 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(68) @ 250 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegA: 0x0000

UVM_INFO @ 250 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 2, wdata: 10

UVM_INFO @ 260 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 0, wdata: 0

UVM_INFO @ 280 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 300 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 310 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(76) @ 310 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegA: 0x0010

UVM_INFO @ 310 ns: reporter [reg2bus:] Instruction: READ. raddr: 4, rdata: 0

UVM_INFO @ 320 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 340 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 0

UVM_INFO @ 360 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 370 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(83) @ 370 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegB: 0x0000

UVM_INFO @ 370 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 380 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 400 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 420 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 430 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(91) @ 430 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegB: 0x1000

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(106) @ 430 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via back door RegA: 0x0010

Setting vhdl path top.dut.data_RegA_h_localUVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(114) @ 430 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via back door to RegA: 0x0030

UVM_INFO @ 430 ns: reporter [reg2bus:] Instruction: READ. raddr: 2, rdata: 0

UVM_INFO @ 440 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 460 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO @ 480 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 490 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(68) @ 490 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegA: 0x0000

UVM_INFO @ 490 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 2, wdata: 10

UVM_INFO @ 500 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 1000

UVM_INFO @ 520 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 540 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 550 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(76) @ 550 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegA: 0x0010

UVM_INFO @ 550 ns: reporter [reg2bus:] Instruction: READ. raddr: 4, rdata: 0

UVM_INFO @ 560 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 580 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 1000

UVM_INFO @ 600 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 610 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 1000

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(83) @ 610 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegB: 0x1000

UVM_INFO @ 610 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 620 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 640 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 660 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 670 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(91) @ 670 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegB: 0x2000

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(106) @ 670 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via back door RegA: 0x0010

Setting vhdl path top.dut.data_RegA_h_localUVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(114) @ 670 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via back door to RegA: 0x0030

UVM_INFO @ 670 ns: reporter [reg2bus:] Instruction: READ. raddr: 2, rdata: 0

UVM_INFO @ 680 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 700 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO @ 720 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 730 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 2, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(68) @ 730 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegA: 0x0000

UVM_INFO @ 730 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 2, wdata: 10

UVM_INFO @ 740 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 2000

UVM_INFO @ 760 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 780 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 790 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(76) @ 790 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegA: 0x0010

UVM_INFO @ 790 ns: reporter [reg2bus:] Instruction: READ. raddr: 4, rdata: 0

UVM_INFO @ 800 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 820 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 2000

UVM_INFO @ 840 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 850 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 4, rdata: 2000

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(83) @ 850 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via front door RegB: 0x2000

UVM_INFO @ 850 ns: reporter [reg2bus:] Instruction: WRITE. waddr: 4, wdata: 3000

UVM_INFO @ 860 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 2, wdata: 10

UVM_INFO @ 880 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 3000

UVM_INFO @ 900 ns: reporter [bus2reg:] Instruction: UVM_WRITE. waddr: 4, wdata: 3000

UVM_INFO @ 910 ns: reporter [bus2reg:] Instruction: UVM_READ. raddr: 0, rdata: 0

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(91) @ 910 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via front door to RegB: 0x3000

UVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(106) @ 910 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Reading via back door RegA: 0x0010

Setting vhdl path top.dut.data_RegA_h_localUVM_INFO …/uvm_rsp_react/test_uvm/svassistant/my_sva_proj2/tb/sequences/reg_model_seq.svh(114) @ 910 ns: uvm_test_top.m_env.m_bus_agent.m_sequencer@@t_seq [reg_model_seq:body] Writing via back door to RegA: 0x0030

So I am just as uncertain as before. The front door accesses appear fine from RegB, but the minute I introduce a back door access write the contents of RegA are back to the start again.
Even if I did not use a predictor this would only make the front door access out of sync with the register model, so the subsequent front door would read a 0x0010 instead of 0x0000.

I am indeed confused – I appear to be missing something, I just cant determine if it is a simulator config, uvm setting, or sequence method order.
Can anyone offer advice?

Just to report on this bug and close off this ticket.

I have spent at least a week and a half trying to track this down, and with the help of a Mentor FAE we have came to the conclusion that there is a proper clanger in the way Register Generator creates verilog registers from VHDL registers.

The main focus is what you specify in the “Field Backdoor” column of the source spread sheet.

In the regs worksheet if we specify the Field Backdoor = FIELDA_status_reg_h.

In the Verilog RTL the register name matches the Field Backdoor path specified in the spreadsheet. e.g.


always @ (posedge clk or posedge rst)
 begin : reg_status_reg_fielda_status_reg_h
 //Reset
 if (rst)
  FIELDA_status_reg_h <= 1'b0;
  //SW: read-write
 else if (wen_status_reg_h)
  FIELDA_status_reg_h <= wdata[0];
 end

There is subtle difference in the VHDL RTL that is generated from the same register map.
The register name is : FIELDA_status_reg_h_buf. The signal FIELDA_status_reg_h is connected to the register output.


reg_status_reg_fielda_status_reg_h : PROCESS (clk, rst)
 BEGIN
 --Reset
 IF (rst ='1') THEN
  FIELDA_status_reg_h_buf <= '0';
 ELSIF (clk'EVENT) AND (clk ='1') THEN
  --SW: read-write
  IF (wen_status_reg_h = '1') THEN
   FIELDA_status_reg_h_buf <=wdata[0];
  END IF;
 END IF;
END PROCESS reg_status_reg_fielda_status_reg_h;

--Asign internal buffer value to output
FIELDA_status_reg_h <= FIELDA_status_reg_h_buf;

The result of this is that if you are creating registers with Register Generator you need to ensure that the field column of the source spread sheet has “_buf” appended to the name specified in the “Field Backdoor” column.

I am massively disappointed in the Mentor for this. With the Register Assistant now in version 4.5 these sort of details should be crystal clear in the documentation. It feels like the register generator has not been tested correctly for VHDL duts.

The comment in this other post still applies about leaving a delay between frontdoor writes and backdoor reads.