Uvm_reg_field Individual Byte Access Works in UVM 1.2 but not in UVM IEEE 1800.2-2017

Hi,
I have 32-bit uvm_regs that contains uvm_reg_fields that are the only fields in their byte lane. I configure the uvm_reg_field instances with individually_accessible=1. In my uvm_reg_adapter I set supports_byte_enable=1. My APB bus has byte enable bits and as far as I can tell I have them connected and implemented correctly. I should be able to write these fields/bytes individually using uvm_reg_field::write(). This works fine for me with UVM 1.2, but not with UVM IEEE 1800.2-2017. I have tried the UVM implementations from my vendor and direct from Accellera (uvm-1.2 and 1800.2-2017-1.1).

With IEEE what appears to be happening is the uvm_reg_map::Xget_bus_infoX() and uvm_reg_map::do_bus_access() subroutines don’t calculate the bit and byte shifts and offsets correctly so when I attempt a uvm_reg_field::write(), the write data is shifted into the wrong byte lanes so the wrong data is written to the register.

I have a small test case based on the examples/simple/registers/primer/ code from UVM 1.2.

Here’s my register definition with four sub-byte fields of varying widths, configured with individually_accessible=1:

class reg_slave_USER1 extends uvm_reg;

   uvm_reg_field ALPHA;
   uvm_reg_field BRAVO;
   uvm_reg_field CHARLIE;
   uvm_reg_field DELTA;

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

   virtual function void build();
      this.ALPHA = uvm_reg_field::type_id::create("ALPHA");
      this.BRAVO = uvm_reg_field::type_id::create("BRAVO");
      this.CHARLIE = uvm_reg_field::type_id::create("CHARLIE");
      this.DELTA = uvm_reg_field::type_id::create("DELTA");

      this.ALPHA.configure(this, 1,  0, "RW",   0, 1'h0, 1, 0, 1);
      this.BRAVO.configure(this, 2,  8, "RW",   0, 2'h0, 1, 0, 1);
      this.CHARLIE.configure(this, 4, 16,"RW", 0, 4'h0, 1, 0, 1);
      this.DELTA.configure(this, 8, 24,"RW", 0, 8'h00, 1, 0, 1);
   endfunction
   
   `uvm_object_utils(reg_slave_USER1)

endclass

Here’s my uvm_reg_adapter with byte enables assigned and supports_byte_enable = 1’b1:

class reg2apb_adapter extends uvm_reg_adapter;

  `uvm_object_utils(reg2apb_adapter)

   function new(string name = "reg2apb_adapter");
      super.new(name);
      supports_byte_enable = 1'b1;
   endfunction 

  virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
    apb_rw apb = apb_rw::type_id::create("apb_rw");
    apb.kind = (rw.kind == UVM_READ) ? apb_rw::READ : apb_rw::WRITE;
    apb.addr = rw.addr;
    apb.data = rw.data;
    apb.byte_en = rw.byte_en;
    return apb;
  endfunction

  virtual function void bus2reg(uvm_sequence_item bus_item,
                                ref uvm_reg_bus_op rw);
    apb_rw apb;
    if (!$cast(apb,bus_item)) begin
      `uvm_fatal("NOT_APB_TYPE","Provided bus_item is not of the correct type")
      return;
    end
    rw.kind = apb.kind == apb_rw::READ ? UVM_READ : UVM_WRITE;
    rw.addr = apb.addr;
    rw.data = apb.data;
    rw.status = UVM_IS_OK;
    rw.byte_en = apb.byte_en;
  endfunction

endclass

Here’s an excerpt from my DUT showing register byte writes and reads:

always @ (posedge apb.pclk)
  begin
   if (rst) begin
      INDEX <= 'h00;
      ALPHA <= 'h00;
      BRAVO <= 'h00;
      CHARLIE <= 'h00;
      DELTA <= 'h00;
      pr_data <= 32'h0;
   end
   else begin

      // Wait for a SETUP+READ or ENABLE+WRITE cycle
      if (apb.psel == 1'b1 && apb.penable == apb.pwrite) begin
         pr_data <= 32'h0;
         if (apb.pwrite) begin
            casex (apb.paddr)
              16'h0800: begin
                 if (apb.pstrb[0]) ALPHA <= apb.pwdata[0+:1];
                 if (apb.pstrb[1]) BRAVO <= apb.pwdata[8+:2];
                 if (apb.pstrb[2]) CHARLIE <= apb.pwdata[16+:4];
                 if (apb.pstrb[3]) DELTA <= apb.pwdata[24+:8];
              end
            endcase
         end
         else begin
            casex (apb.paddr)
              16'h0800: pr_data <= {DELTA, {4'h0, CHARLIE}, {6'h00, BRAVO}, {7'h00, ALPHA}};
            endcase
         end
      end
   end
end

My uvm_driver makes the connection between the transaction byte_en signals and the APB pstrb signals.

Has anyone else seen this problem in UVM IEEE?

Thanks very much.

In reply to William Moore:

This is a reported bug: 0004675: uvm_reg_field::is_indv_accessible looks bogus - Accellera Mantis

In reply to dave_59:

Great, thanks Dave!

Indeed this related bug is spot on:
https://accellera.mantishub.io/view.php?id=6956