This is a deepdive into uvm_reg_bit_bash_seq. It’s one of UVM RAL builtin sequences to test registers. uvm_reg_bit_bash_seq can be used as by setting the model and start the sequence and that’s it.

         seq = uvm_reg_bit_bash_seq::type_id::create("seq",this);
         seq.model = env.regmodel;

         seq.start(null);
         seq.wait_for_sequence_state(FINISHED);

Starting with body(), it seems reset_blk is empty in src/reg/sequences/uvm_reg_bit_bash_seq.svh


      reg_seq = uvm_reg_single_bit_bash_seq::type_id::create("reg_single_bit_bash_seq");

      this.reset_blk(model);
      model.reset();

      do_block(model);

The loop works on all registers and calls vm_reg_single_bit_bash_seq on each register

   protected virtual task do_block(uvm_reg_block blk);
      uvm_reg regs[$];
      ...
      ...

      // Iterate over all registers, checking accesses
      blk.get_registers(regs, UVM_NO_HIER);
      foreach (regs[i]) begin
         // Registers with some attributes are not to be tested
         if (uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()},
                                                "NO_REG_TESTS", 0) != null ||
	     uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()},
                                                "NO_REG_BIT_BASH_TEST", 0) != null )
            continue;
         
         reg_seq.rg = regs[i];
         reg_seq.start(null,this);
      end

And then call do_block recursively

      begin
         uvm_reg_block blks[$];
         
         blk.get_blocks(blks);
         foreach (blks[i]) begin
            do_block(blks[i]);
         end
      end
   endtask: do_block

Ok, let’s look at vm_reg_single_bit_bash_seq. Note there are few knobs to disable the checks in case the user wants to. NO_REG_TESTS is set into the uvm_resource_db for registers that we don’t checked.

Surprisingly, body() is well documented with comments (thank you, whoever wrote it!). But to sump, It loops over that fields and bits in each field, Calculate mask based on which bits are writable and then goes these bits and change the value and check the new value.

 virtual task body();

      // Registers with some attributes are not to be tested
      if (uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()},
                                             "NO_REG_TESTS", 0) != null ||
          uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()},
                                             "NO_REG_BIT_BASH_TEST", 0) != null )
            return;
      
      n_bits = rg.get_n_bytes() * 8;
         
      // Let's see what kind of bits we have...
      rg.get_fields(fields);
         
      // Registers may be accessible from multiple physical interfaces (maps)
      rg.get_maps(maps);
         
      // Bash the bits in the register via each map
      foreach (maps[j]) begin
         uvm_status_e status;
         uvm_reg_data_t  val, exp, v;
         int next_lsb;
         
         next_lsb = 0;
         dc_mask  = 0;
         foreach (fields[k]) begin
            int lsb, w, dc;

            dc = (fields[k].get_compare() == UVM_NO_CHECK);
            lsb = fields[k].get_lsb_pos();
            w   = fields[k].get_n_bits();
            // Ignore Write-only fields because
            // you are not supposed to read them
            case (fields[k].get_access(maps[j]))
             "WO", "WOC", "WOS", "WO1": dc = 1;
            endcase
            // Any unused bits on the right side of the LSB?
            while (next_lsb < lsb) mode[next_lsb++] = "RO";
            
            repeat (w) begin
               mode[next_lsb] = fields[k].get_access(maps[j]);
               dc_mask[next_lsb] = dc;
               next_lsb++;
            end
         end
         // Any unused bits on the left side of the MSB?
         while (next_lsb < `UVM_REG_DATA_WIDTH)
            mode[next_lsb++] = "RO";
         
         `uvm_info("uvm_reg_bit_bash_seq", $sformatf("Verifying bits in register %s in map \"%s\"...",
                                    rg.get_full_name(), maps[j].get_full_name()),UVM_LOW);
         
         // Bash the kth bit
         for (int k = 0; k < n_bits; k++) begin
            // Cannot test unpredictable bit behavior
            if (dc_mask[k]) continue;

            bash_kth_bit(rg, k, mode[k], maps[j], dc_mask);
         end
            
      end
   endtask: body

In bash_kth_bit, bit is written then read back and finally, The comparison at the end of task reports is there is a mismatch

   task bash_kth_bit(uvm_reg         rg,
                     int             k,
                     string          mode,
                     uvm_reg_map     map,
                     uvm_reg_data_t  dc_mask);
      uvm_status_e status;
      uvm_reg_data_t  val, exp, v;
      bit bit_val;

      `uvm_info("uvm_reg_bit_bash_seq", $sformatf("...Bashing %s bit #%0d", mode, k),UVM_HIGH);
      
      repeat (2) begin
         val = rg.get();
         v   = val;
         exp = val;
         val[k] = ~val[k];
         bit_val = val[k];
         
         rg.write(status, val, UVM_FRONTDOOR, map, this);
         if (status != UVM_IS_OK) begin
            `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Status was %s when writing to register \"%s\" through map \"%s\".",
                                        status.name(), rg.get_full_name(), map.get_full_name()));
         end
         
         exp = rg.get() & ~dc_mask;
         rg.read(status, val, UVM_FRONTDOOR, map, this);
         if (status != UVM_IS_OK) begin
            `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Status was %s when reading register \"%s\" through map \"%s\".",
                                        status.name(), rg.get_full_name(), map.get_full_name()));
         end

         val &= ~dc_mask;
         if (val !== exp) begin
            `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Writing a %b in bit #%0d of register \"%s\" with initial value 'h%h yielded 'h%h instead of 'h%h",
                                        bit_val, k, rg.get_full_name(), v, val, exp));
         end
      end
   endtask: bash_kth_bit