Access (to W/R) 2 Specific fields in a 32-bit register

How to write and read into specific fields in a address mapped register?

I have a register named spu_rst_ctl_register with 2 fields

  1. spu_reset_enable_bit (1 bit wide )
  2. spu_reset_type_and_spu_reset_polarity_bit ( 2 bits wide)
  3. RFU (reserved for future use)

below is my register sequence code for write and read through frontdoor access. But using .write() method (which uses the hierarchy {.<register_instance>.write()}) applies to all fields.

So how to write and read from specific field at a given point of time?

class spu_rst_ctl_reg extends uvm_reg;
  
  `uvm_object_utils(spu_rst_ctl_reg)
  
  rand uvm_reg_field spu_reset_enable_bit;
  rand uvm_reg_field spu_reset_type_bit_spu_reset_polarity_bit;
//  rand uvm_reg_field spu_reset_duration;
  
  function new (string name = "spu_rst_ctl_reg");
    super.new(name,32,UVM_NO_COVERAGE);
  endfunction
  
  function void build();
    
    spu_reset_enable_bit = uvm_reg_field :: type_id :: create ("spu_reset_enable_bit");
    spu_reset_enable_bit.configure(.parent(this),
                                            .size(1),
                                            .lsb_pos(0),
                                            .access("RW"),
                                            .volatile(0),
                                            .reset(32'hF),
                                            .has_reset(1),
                                            .is_rand(1),
                                            .individually_accessible(1)
                                           );
    
     spu_reset_type_bit_spu_reset_polarity_bit = uvm_reg_field :: type_id :: create ("spu_reset_type_bit_spu_reset_polarity_bit");
    spu_reset_type_bit_spu_reset_polarity_bit.configure(.parent(this),
                                            .size(2),
                                            .lsb_pos(1),
                                            .access("RW"),
                                            .volatile(0),
                                            .reset(32'hF),
                                            .has_reset(1),
                                            .is_rand(1),
                                            .individually_accessible(1)
                                           );
    
//      spu_reset_duration = uvm_reg_field :: type_id :: create ("spu_reset_duration");
//     spu_reset_duration.configure(.parent(this),
//                                             .size(15),
//                                             .lsb_pos(3),
//                                             .access("RW"),
//                                             .volatile(0),
//                                             .reset(32'hF),
//                                             .has_reset(1),
//                                             .is_rand(1),
//                                             .individually_accessible(1)
//                                            );
    
    
    
	 /*
	 /*
	 spu_clk_en = spu_clock_enable :: type_id :: create ("spu_clk_en");
	 spu_clk_en.configure(.parent(this),.size(1),.lsb_pos(3),.access("RW"),.volatile(0),.reset(1'b1),.has_reset(1),.is_rand(1),.individually_accessible(1));
	 
	 spu_clk_gat = spu_clock_gat :: type_id :: create ("spu_clk_gat");
	 spu_clk_gat.configure(.parent(this),.size(3),.lsb_pos(4),.access("RW"),.volatile(0),.reset(1'b1),.has_reset(1),.is_rand(1),.individually_accessible(1)); */
	 
  endfunction
  
endclass

There are 2 parts to it - what’s your host protocol minimum width? Assuming it is 32-bits and your register width is also 32, then it is always entire register access. On the REGMODEL itself, this is easy -

  spu_rst_ctl_reg.spu_reset_enable_bit.set(1'b1);
  spu_rst_ctl_reg.update(stat);