// // ------------------------------------------------------------- // Copyright 2004-2009 Synopsys, Inc. // Copyright 2010-2011 Mentor Graphics Corporation // Copyright 2010-2011 Cadence Design Systems, Inc. // All Rights Reserved Worldwide // // Licensed under the Apache License, Version 2.0 (the // "License"); you may not use this file except in // compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in // writing, software distributed under the License is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. // ------------------------------------------------------------- // typedef class uvm_reg_cbs; //----------------------------------------------------------------- // CLASS: uvm_reg_field // Field abstraction class // // A field represents a set of bits that behave consistently // as a single entity. // // A field is contained within a single register, but may // have different access policies depending on the adddress map // use the access the register (thus the field). //----------------------------------------------------------------- class uvm_reg_field extends uvm_object; // Variable: value // Mirrored field value. // This value can be sampled in a functional coverage model // or constrained when randomized. rand uvm_reg_data_t value; // Mirrored after randomize() local uvm_reg_data_t m_mirrored; // What we think is in the HW local uvm_reg_data_t m_desired; // Mirrored after set() local string m_access; local uvm_reg m_parent; local int unsigned m_lsb; local int unsigned m_size; local bit m_volatile; local uvm_reg_data_t m_reset[string]; local bit m_written; local bit m_read_in_progress; local bit m_write_in_progress; local string m_fname; local int m_lineno; local int m_cover_on; local bit m_individually_accessible; local uvm_check_e m_check; local static int m_max_size; local static bit m_policy_names[string]; constraint uvm_reg_field_valid { if (`UVM_REG_DATA_WIDTH > m_size) { value < (`UVM_REG_DATA_WIDTH'h1 << m_size); } } `uvm_object_utils(uvm_reg_field) //---------------------- // Group: Initialization //---------------------- // Function: new // // Create a new field instance // // This method should not be used directly. // The uvm_reg_field::type_id::create() factory method // should be used instead. // extern function new(string name = "uvm_reg_field"); // Function: configure // // Instance-specific configuration // // Specify the ~parent~ register of this field, its // ~size~ in bits, the position of its least-significant bit // within the register relative to the least-significant bit // of the register, its ~access~ policy, volatility, // "HARD" ~reset~ value, // whether the field value is actually reset // (the ~reset~ value is ignored if ~FALSE~), // whether the field value may be randomized and // whether the field is the only one to occupy a byte lane in the register. // // See for a specification of the pre-defined // field access policies. // // If the field access policy is a pre-defined policy and NOT one of // "RW", "WRC", "WRS", "WO", "W1", or "WO1", // the value of ~is_rand~ is ignored and the rand_mode() for the // field instance is turned off since it cannot be written. // extern function void configure(uvm_reg parent, int unsigned size, int unsigned lsb_pos, string access, bit volatile, uvm_reg_data_t reset, bit has_reset, bit is_rand, bit individually_accessible); //--------------------- // Group: Introspection //--------------------- // Function: get_name // // Get the simple name // // Return the simple object name of this field // // Function: get_full_name // // Get the hierarchical name // // Return the hierarchal name of this field // The base of the hierarchical name is the root block. // extern virtual function string get_full_name(); // Function: get_parent // // Get the parent register // extern virtual function uvm_reg get_parent(); extern virtual function uvm_reg get_register(); // Function: get_lsb_pos // // Return the position of the field // // Returns the index of the least significant bit of the field // in the register that instantiates it. // An offset of 0 indicates a field that is aligned with the // least-significant bit of the register. // extern virtual function int unsigned get_lsb_pos(); // Function: get_n_bits // // Returns the width, in number of bits, of the field. // extern virtual function int unsigned get_n_bits(); // // FUNCTION: get_max_size // Returns the width, in number of bits, of the largest field. // extern static function int unsigned get_max_size(); // Function: set_access // // Modify the access policy of the field // // Modify the access policy of the field to the specified one and // return the previous access policy. // // The pre-defined access policies are as follows. // The effect of a read operation are applied after the current // value of the field is sampled. // The read operation will return the current value, // not the value affected by the read operation (if any). // // "RO" - W: no effect, R: no effect // "RW" - W: as-is, R: no effect // "RC" - W: no effect, R: clears all bits // "RS" - W: no effect, R: sets all bits // "WRC" - W: as-is, R: clears all bits // "WRS" - W: as-is, R: sets all bits // "WC" - W: clears all bits, R: no effect // "WS" - W: sets all bits, R: no effect // "WSRC" - W: sets all bits, R: clears all bits // "WCRS" - W: clears all bits, R: sets all bits // "W1C" - W: 1/0 clears/no effect on matching bit, R: no effect // "W1S" - W: 1/0 sets/no effect on matching bit, R: no effect // "W1T" - W: 1/0 toggles/no effect on matching bit, R: no effect // "W0C" - W: 1/0 no effect on/clears matching bit, R: no effect // "W0S" - W: 1/0 no effect on/sets matching bit, R: no effect // "W0T" - W: 1/0 no effect on/toggles matching bit, R: no effect // "W1SRC" - W: 1/0 sets/no effect on matching bit, R: clears all bits // "W1CRS" - W: 1/0 clears/no effect on matching bit, R: sets all bits // "W0SRC" - W: 1/0 no effect on/sets matching bit, R: clears all bits // "W0CRS" - W: 1/0 no effect on/clears matching bit, R: sets all bits // "WO" - W: as-is, R: error // "WOC" - W: clears all bits, R: error // "WOS" - W: sets all bits, R: error // "W1" - W: first one after ~HARD~ reset is as-is, other W have no effects, R: no effect // "WO1" - W: first one after ~HARD~ reset is as-is, other W have no effects, R: error // // It is important to remember that modifying the access of a field // will make the register model diverge from the specification // that was used to create it. // extern virtual function string set_access(string mode); // Function: define_access // // Define a new access policy value // // Because field access policies are specified using string values, // there is no way for SystemVerilog to verify if a spceific access // value is valid or not. // To help catch typing errors, user-defined access values // must be defined using this method to avoid beign reported as an // invalid access policy. // // The name of field access policies are always converted to all uppercase. // // Returns TRUE if the new access policy was not previously // defined. // Returns FALSE otherwise but does not issue an error message. // extern static function bit define_access(string name); local static bit m_predefined = m_predefine_policies(); extern local static function bit m_predefine_policies(); // Function: get_access // // Get the access policy of the field // // Returns the current access policy of the field // when written and read through the specified address ~map~. // If the register containing the field is mapped in multiple // address map, an address map must be specified. // The access policy of a field from a specific // address map may be restricted by the register's access policy in that // address map. // For example, a RW field may only be writable through one of // the address maps and read-only through all of the other maps. // extern virtual function string get_access(uvm_reg_map map = null); // Function: is_known_access // // Check if access policy is a built-in one. // // Returns TRUE if the current access policy of the field, // when written and read through the specified address ~map~, // is a built-in access policy. // extern virtual function bit is_known_access(uvm_reg_map map = null); // // Function: set_volatility // Modify the volatility of the field to the specified one. // // It is important to remember that modifying the volatility of a field // will make the register model diverge from the specification // that was used to create it. // extern virtual function void set_volatility(bit volatile); // // Function: is_volatile // Indicates if the field value is volatile // // UVM uses the IEEE 1685-2009 IP-XACT definition of "volatility". // If TRUE, the value of the register is not predictable because it // may change between consecutive accesses. // This typically indicates a field whose value is updated by the DUT. // The nature or cause of the change is not specified. // If FALSE, the value of the register is not modified between // consecutive accesses. // extern virtual function bit is_volatile(); //-------------- // Group: Access //-------------- // Function: set // // Set the desired value for this field // // It sets the desired value of the field to the specified ~value~ // modified by the field access policy. // It does not actually set the value of the field in the design, // only the desired value in the abstraction class. // Use the method to update the actual register // with the desired value or the method // to actually write the field and update its mirrored value. // // The final desired value in the mirror is a function of the field access // policy and the set value, just like a normal physical write operation // to the corresponding bits in the hardware. // As such, this method (when eventually followed by a call to // ) // is a zero-time functional replacement for the // method. // For example, the desired value of a read-only field is not modified // by this method and the desired value of a write-once field can only // be set if the field has not yet been // written to using a physical (for example, front-door) write operation. // // Use the to modify the mirrored value of // the field. // extern virtual function void set(uvm_reg_data_t value, string fname = "", int lineno = 0); // Function: get // // Return the desired value of the field // // It does not actually read the value // of the field in the design, only the desired value // in the abstraction class. Unless set to a different value // using the , the desired value // and the mirrored value are identical. // // Use the or // method to get the actual field value. // // If the field is write-only, the desired/mirrored // value is the value last written and assumed // to reside in the bits implementing it. // Although a physical read operation would something different, // the returned value is the actual content. // extern virtual function uvm_reg_data_t get(string fname = "", int lineno = 0); // Function: get_mirrored_value // // Return the mirrored value of the field // // It does not actually read the value of the field in the design, only the mirrored value // in the abstraction class. // // If the field is write-only, the desired/mirrored // value is the value last written and assumed // to reside in the bits implementing it. // Although a physical read operation would something different, // the returned value is the actual content. // extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "", int lineno = 0); // Function: reset // // Reset the desired/mirrored value for this field. // // It sets the desired and mirror value of the field // to the reset event specified by ~kind~. // If the field does not have a reset value specified for the // specified reset ~kind~ the field is unchanged. // // It does not actually reset the value of the field in the design, // only the value mirrored in the field abstraction class. // // Write-once fields can be modified after // a "HARD" reset operation. // extern virtual function void reset(string kind = "HARD"); // Function: get_reset // // Get the specified reset value for this field // // Return the reset value for this field // for the specified reset ~kind~. // Returns the current field value is no reset value has been // specified for the specified reset event. // extern virtual function uvm_reg_data_t get_reset(string kind = "HARD"); // Function: has_reset // // Check if the field has a reset value specified // // Return TRUE if this field has a reset value specified // for the specified reset ~kind~. // If ~delete~ is TRUE, removes the reset value, if any. // extern virtual function bit has_reset(string kind = "HARD", bit delete = 0); // Function: set_reset // // Specify or modify the reset value for this field // // Specify or modify the reset value for this field corresponding // to the cause specified by ~kind~. // extern virtual function void set_reset(uvm_reg_data_t value, string kind = "HARD"); // Function: needs_update // // Check if the abstract model contains different desired and mirrored values. // // If a desired field value has been modified in the abstraction class // without actually updating the field in the DUT, // the state of the DUT (more specifically what the abstraction class // ~thinks~ the state of the DUT is) is outdated. // This method returns TRUE // if the state of the field in the DUT needs to be updated // to match the desired value. // The mirror values or actual content of DUT field are not modified. // Use the to actually update the DUT field. // extern virtual function bit needs_update(); // Task: write // // Write the specified value in this field // // Write ~value~ in the DUT field that corresponds to this // abstraction class instance using the specified access // ~path~. // If the register containing this field is mapped in more // than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // If a back-door access path is used, the effect of writing // the field through a physical access is mimicked. For // example, read-only bits in the field will not be written. // // The mirrored value will be updated using the // method. // // If a front-door access is used, and // if the field is the only field in a byte lane and // if the physical interface corresponding to the address map used // to access the field support byte-enabling, // then only the field is written. // Otherwise, the entire register containing the field is written, // and the mirrored values of the other fields in the same register // are used in a best-effort not to modify their value. // // If a backdoor access is used, a peek-modify-poke process is used. // in a best-effort not to modify the value of the other fields in the // register. // extern virtual task write (output uvm_status_e status, input uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Task: read // // Read the current value from this field // // Read and return ~value~ from the DUT field that corresponds to this // abstraction class instance using the specified access // ~path~. // If the register containing this field is mapped in more // than one address map, an address ~map~ must be // specified if a physical access is used (front-door access). // If a back-door access path is used, the effect of reading // the field through a physical access is mimicked. For // example, clear-on-read bits in the filed will be set to zero. // // The mirrored value will be updated using the // method. // // If a front-door access is used, and // if the field is the only field in a byte lane and // if the physical interface corresponding to the address map used // to access the field support byte-enabling, // then only the field is read. // Otherwise, the entire register containing the field is read, // and the mirrored values of the other fields in the same register // are updated. // // If a backdoor access is used, the entire containing register is peeked // and the mirrored value of the other fields in the register is updated. // extern virtual task read (output uvm_status_e status, output uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Task: poke // // Deposit the specified value in this field // // Deposit the value in the DUT field corresponding to this // abstraction class instance, as-is, using a back-door access. // A peek-modify-poke process is used // in a best-effort not to modify the value of the other fields in the // register. // // The mirrored value will be updated using the // method. // extern virtual task poke (output uvm_status_e status, input uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Task: peek // // Read the current value from this field // // Sample the value in the DUT field corresponding to this // absraction class instance using a back-door access. // The field value is sampled, not modified. // // Uses the HDL path for the design abstraction specified by ~kind~. // // The entire containing register is peeked // and the mirrored value of the other fields in the register // are updated using the method. // // extern virtual task peek (output uvm_status_e status, output uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Task: mirror // // Read the field and update/check its mirror value // // Read the field and optionally compared the readback value // with the current mirrored value if ~check~ is . // The mirrored value will be updated using the // method based on the readback value. // // The ~path~ argument specifies whether to mirror using // the () or // or (). // // If ~check~ is specified as , // an error message is issued if the current mirrored value // does not match the readback value, unless was used // disable the check. // // If the containing register is mapped in multiple address maps and physical // access is used (front-door access), an address ~map~ must be specified. // For write-only fields, their content is mirrored and optionally // checked only if a UVM_BACKDOOR // access path is used to read the field. // extern virtual task mirror(output uvm_status_e status, input uvm_check_e check = UVM_NO_CHECK, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Function: set_compare // // Sets the compare policy during a mirror update. // The field value is checked against its mirror only when both the // ~check~ argument in , , // or and the compare policy for the // field is . // extern function void set_compare(uvm_check_e check=UVM_CHECK); // Function: get_compare // // Returns the compare policy for this field. // extern function uvm_check_e get_compare(); // Function: is_indv_accessible // // Check if this field can be written individually, i.e. without // affecting other fields in the containing register. // extern function bit is_indv_accessible (uvm_path_e path, uvm_reg_map local_map); // Function: predict // // Update the mirrored value for this field. // // Predict the mirror value of the field based on the specified // observed ~value~ on a bus using the specified address ~map~. // // If ~kind~ is specified as , the value // was observed in a read transaction on the specified address ~map~ or // backdoor (if ~path~ is ). // If ~kind~ is specified as , the value // was observed in a write transaction on the specified address ~map~ or // backdoor (if ~path~ is ). // If ~kind~ is specified as , the value // was computed and is updated as-is, without regard to any access policy. // For example, the mirrored value of a read-only field is modified // by this method if ~kind~ is specified as . // // This method does not allow an update of the mirror // when the register containing this field is busy executing // a transaction because the results are unpredictable and // indicative of a race condition in the testbench. // // Returns TRUE if the prediction was succesful. // extern function bit predict (uvm_reg_data_t value, uvm_reg_byte_en_t be = -1, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_path_e path = UVM_FRONTDOOR, uvm_reg_map map = null, string fname = "", int lineno = 0); /*local*/ extern virtual function uvm_reg_data_t XpredictX (uvm_reg_data_t cur_val, uvm_reg_data_t wr_val, uvm_reg_map map); /*local*/ extern virtual function uvm_reg_data_t XupdateX(); /*local*/ extern function bit Xcheck_accessX (input uvm_reg_item rw, output uvm_reg_map_info map_info, input string caller); extern virtual task do_write(uvm_reg_item rw); extern virtual task do_read(uvm_reg_item rw); extern virtual function void do_predict (uvm_reg_item rw, uvm_predict_e kind=UVM_PREDICT_DIRECT, uvm_reg_byte_en_t be = -1); extern function void pre_randomize(); extern function void post_randomize(); //----------------- // Group: Callbacks //----------------- `uvm_register_cb(uvm_reg_field, uvm_reg_cbs) // Task: pre_write // // Called before field write. // // If the specified data value, access ~path~ or address ~map~ are modified, // the updated data value, access path or address map will be used // to perform the register operation. // If the ~status~ is modified to anything other than , // the operation is aborted. // // The field callback methods are invoked after the callback methods // on the containing register. // The registered callback methods are invoked after the invocation // of this method. // virtual task pre_write (uvm_reg_item rw); endtask // Task: post_write // // Called after field write. // // If the specified ~status~ is modified, // the updated status will be // returned by the register operation. // // The field callback methods are invoked after the callback methods // on the containing register. // The registered callback methods are invoked before the invocation // of this method. // virtual task post_write (uvm_reg_item rw); endtask // Task: pre_read // // Called before field read. // // If the access ~path~ or address ~map~ in the ~rw~ argument are modified, // the updated access path or address map will be used to perform // the register operation. // If the ~status~ is modified to anything other than , // the operation is aborted. // // The field callback methods are invoked after the callback methods // on the containing register. // The registered callback methods are invoked after the invocation // of this method. // virtual task pre_read (uvm_reg_item rw); endtask // Task: post_read // // Called after field read. // // If the specified readback data or~status~ in the ~rw~ argument is // modified, the updated readback data or status will be // returned by the register operation. // // The field callback methods are invoked after the callback methods // on the containing register. // The registered callback methods are invoked before the invocation // of this method. // virtual task post_read (uvm_reg_item rw); endtask extern virtual function void do_print (uvm_printer printer); extern virtual function string convert2string; extern virtual function uvm_object clone(); extern virtual function void do_copy (uvm_object rhs); extern virtual function bit do_compare (uvm_object rhs, uvm_comparer comparer); extern virtual function void do_pack (uvm_packer packer); extern virtual function void do_unpack (uvm_packer packer); endclass: uvm_reg_field //------------------------------------------------------------------------------ // IMPLEMENTATION //------------------------------------------------------------------------------ // new function uvm_reg_field::new(string name = "uvm_reg_field"); super.new(name); endfunction: new // configure function void uvm_reg_field::configure(uvm_reg parent, int unsigned size, int unsigned lsb_pos, string access, bit volatile, uvm_reg_data_t reset, bit has_reset, bit is_rand, bit individually_accessible); m_parent = parent; if (size == 0) begin `uvm_error("RegModel", $sformatf("Field \"%s\" cannot have 0 bits", get_full_name())); size = 1; end m_size = size; m_volatile = volatile; m_access = access.toupper(); m_lsb = lsb_pos; m_cover_on = UVM_NO_COVERAGE; m_written = 0; m_check = volatile ? UVM_NO_CHECK : UVM_CHECK; m_individually_accessible = individually_accessible; if (has_reset) set_reset(reset); else uvm_resource_db#(bit)::set({"REG::", get_full_name()}, "NO_REG_HW_RESET_TEST", 1); m_parent.add_field(this); if (!m_policy_names.exists(m_access)) begin `uvm_error("RegModel", {"Access policy '",access, "' for field '",get_full_name(),"' is not defined. Setting to RW"}) m_access = "RW"; end if (size > m_max_size) m_max_size = size; // Ignore is_rand if the field is known not to be writeable // i.e. not "RW", "WRC", "WRS", "WO", "W1", "WO1" case (access) "RO", "RC", "RS", "WC", "WS", "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", "WOC", "WOS": is_rand = 0; endcase if (!is_rand) value.rand_mode(0); endfunction: configure // get_parent function uvm_reg uvm_reg_field::get_parent(); return m_parent; endfunction: get_parent // get_full_name function string uvm_reg_field::get_full_name(); return {m_parent.get_full_name(), ".", get_name()}; endfunction: get_full_name // get_register function uvm_reg uvm_reg_field::get_register(); return m_parent; endfunction: get_register // get_lsb_pos function int unsigned uvm_reg_field::get_lsb_pos(); return m_lsb; endfunction: get_lsb_pos // get_n_bits function int unsigned uvm_reg_field::get_n_bits(); return m_size; endfunction: get_n_bits // get_max_size function int unsigned uvm_reg_field::get_max_size(); return m_max_size; endfunction: get_max_size // is_known_access function bit uvm_reg_field::is_known_access(uvm_reg_map map = null); string acc = get_access(map); case (acc) "RO", "RW", "RC", "RS", "WC", "WS", "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", "WRC", "WRS", "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", "WO", "WOC", "WOS", "W1", "WO1" : return 1; endcase return 0; endfunction // get_access function string uvm_reg_field::get_access(uvm_reg_map map = null); get_access = m_access; if (map == uvm_reg_map::backdoor()) return get_access; // Is the register restricted in this map? case (m_parent.get_rights(map)) "RW": // No restrictions return get_access; "RO": case (get_access) "RW", "RO", "WC", "WS", "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", "W1" : get_access = "RO"; "RC", "WRC", "W1SRC", "W0SRC", "WSRC" : get_access = "RC"; "RS", "WRS", "W1CRS", "W0CRS", "WCRS" : get_access = "RS"; "WO", "WOC", "WOS", "WO1": begin `uvm_error("RegModel", $sformatf("%s field \"%s\" restricted to RO in map \"%s\"", get_access(), get_name(), map.get_full_name())) end // No change for the other modes endcase "WO": case (get_access) "RW", "WO": get_access = "WO"; default: begin `uvm_error("RegModel", {get_access," field '",get_full_name(), "' restricted to WO in map '",map.get_full_name(),"'"}) end // No change for the other modes endcase default: `uvm_error("RegModel", {"Register '",m_parent.get_full_name(), "' containing field '",get_name(),"' is mapped in map '", map.get_full_name(),"' with unknown access right '", m_parent.get_rights(map), "'"}) endcase endfunction: get_access // set_access function string uvm_reg_field::set_access(string mode); set_access = m_access; m_access = mode.toupper(); if (!m_policy_names.exists(m_access)) begin `uvm_error("RegModel", {"Access policy '",m_access, "' is not a defined field access policy"}) m_access = set_access; end endfunction: set_access // define_access function bit uvm_reg_field::define_access(string name); if (!m_predefined) m_predefined = m_predefine_policies(); name = name.toupper(); if (m_policy_names.exists(name)) return 0; m_policy_names[name] = 1; return 1; endfunction // m_predefined_policies function bit uvm_reg_field::m_predefine_policies(); if (m_predefined) return 1; m_predefined = 1; void'(define_access("RO")); void'(define_access("RW")); void'(define_access("RC")); void'(define_access("RS")); void'(define_access("WRC")); void'(define_access("WRS")); void'(define_access("WC")); void'(define_access("WS")); void'(define_access("WSRC")); void'(define_access("WCRS")); void'(define_access("W1C")); void'(define_access("W1S")); void'(define_access("W1T")); void'(define_access("W0C")); void'(define_access("W0S")); void'(define_access("W0T")); void'(define_access("W1SRC")); void'(define_access("W1CRS")); void'(define_access("W0SRC")); void'(define_access("W0CRS")); void'(define_access("WO")); void'(define_access("WOC")); void'(define_access("WOS")); void'(define_access("W1")); void'(define_access("WO1")); return 1; endfunction // set_volatility function void uvm_reg_field::set_volatility(bit volatile); m_volatile = volatile; endfunction // is_volatile function bit uvm_reg_field::is_volatile(); return m_volatile; endfunction // XpredictX function uvm_reg_data_t uvm_reg_field::XpredictX (uvm_reg_data_t cur_val, uvm_reg_data_t wr_val, uvm_reg_map map); uvm_reg_data_t mask = ('b1 << m_size)-1; case (get_access(map)) "RO": return cur_val; "RW": return wr_val; "RC": return cur_val; "RS": return cur_val; "WC": return '0; "WS": return mask; "WRC": return wr_val; "WRS": return wr_val; "WSRC": return mask; "WCRS": return '0; "W1C": return cur_val & (~wr_val); "W1S": return cur_val | wr_val; "W1T": return cur_val ^ wr_val; "W0C": return cur_val & wr_val; "W0S": return cur_val | (~wr_val & mask); "W0T": return cur_val ^ (~wr_val & mask); "W1SRC": return cur_val | wr_val; "W1CRS": return cur_val & (~wr_val); "W0SRC": return cur_val | (~wr_val & mask); "W0CRS": return cur_val & wr_val; "WO": return wr_val; "WOC": return '0; "WOS": return mask; "W1": return (m_written) ? cur_val : wr_val; "WO1": return (m_written) ? cur_val : wr_val; default: return wr_val; endcase `uvm_fatal("RegModel", "uvm_reg_field::XpredictX(): Internal error"); return 0; endfunction: XpredictX // predict function bit uvm_reg_field::predict (uvm_reg_data_t value, uvm_reg_byte_en_t be = -1, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_path_e path = UVM_FRONTDOOR, uvm_reg_map map = null, string fname = "", int lineno = 0); uvm_reg_item rw = new; rw.value[0] = value; rw.path = path; rw.map = map; rw.fname = fname; rw.lineno = lineno; do_predict(rw, kind, be); predict = (rw.status == UVM_NOT_OK) ? 0 : 1; endfunction: predict // do_predict function void uvm_reg_field::do_predict(uvm_reg_item rw, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_reg_byte_en_t be = -1); uvm_reg_data_t field_val = rw.value[0] & ((1 << m_size)-1); if (rw.status != UVM_NOT_OK) rw.status = UVM_IS_OK; // Assume that the entire field is enabled if (!be[0]) return; m_fname = rw.fname; m_lineno = rw.lineno; case (kind) UVM_PREDICT_WRITE: begin uvm_reg_field_cb_iter cbs = new(this); if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) field_val = XpredictX(m_mirrored, field_val, rw.map); m_written = 1; for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) cb.post_predict(this, m_mirrored, field_val, UVM_PREDICT_WRITE, rw.path, rw.map); field_val &= ('b1 << m_size)-1; end UVM_PREDICT_READ: begin uvm_reg_field_cb_iter cbs = new(this); if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) begin string acc = get_access(rw.map); if (acc == "RC" || acc == "WRC" || acc == "WSRC" || acc == "W1SRC" || acc == "W0SRC") field_val = 0; // (clear) else if (acc == "RS" || acc == "WRS" || acc == "WCRS" || acc == "W1CRS" || acc == "W0CRS") field_val = ('b1 << m_size)-1; // all 1's (set) else if (acc == "WO" || acc == "WOC" || acc == "WOS" || acc == "WO1") return; end for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) cb.post_predict(this, m_mirrored, field_val, UVM_PREDICT_READ, rw.path, rw.map); field_val &= ('b1 << m_size)-1; end UVM_PREDICT_DIRECT: begin if (m_parent.is_busy()) begin `uvm_warning("RegModel", {"Trying to predict value of field '", get_name(),"' while register '",m_parent.get_full_name(), "' is being accessed"}) rw.status = UVM_NOT_OK; end end endcase // update the mirror with predicted value m_mirrored = field_val; m_desired = field_val; this.value = field_val; endfunction: do_predict // XupdateX function uvm_reg_data_t uvm_reg_field::XupdateX(); // Figure out which value must be written to get the desired value // given what we think is the current value in the hardware XupdateX = 0; case (m_access) "RO": XupdateX = m_desired; "RW": XupdateX = m_desired; "RC": XupdateX = m_desired; "RS": XupdateX = m_desired; "WRC": XupdateX = m_desired; "WRS": XupdateX = m_desired; "WC": XupdateX = m_desired; // Warn if != 0 "WS": XupdateX = m_desired; // Warn if != 1 "WSRC": XupdateX = m_desired; // Warn if != 1 "WCRS": XupdateX = m_desired; // Warn if != 0 "W1C": XupdateX = ~m_desired; "W1S": XupdateX = m_desired; "W1T": XupdateX = m_desired ^ m_mirrored; "W0C": XupdateX = m_desired; "W0S": XupdateX = ~m_desired; "W0T": XupdateX = ~(m_desired ^ m_mirrored); "W1SRC": XupdateX = m_desired; "W1CRS": XupdateX = ~m_desired; "W0SRC": XupdateX = ~m_desired; "W0CRS": XupdateX = m_desired; "WO": XupdateX = m_desired; "WOC": XupdateX = m_desired; // Warn if != 0 "WOS": XupdateX = m_desired; // Warn if != 1 "W1": XupdateX = m_desired; "WO1": XupdateX = m_desired; default: XupdateX = m_desired; endcase XupdateX &= (1 << m_size) - 1; endfunction: XupdateX // set function void uvm_reg_field::set(uvm_reg_data_t value, string fname = "", int lineno = 0); uvm_reg_data_t mask = ('b1 << m_size)-1; m_fname = fname; m_lineno = lineno; if (value >> m_size) begin `uvm_warning("RegModel", $sformatf("Specified value (0x%h) greater than field \"%s\" size (%0d bits)", value, get_name(), m_size)); value &= mask; end if (m_parent.is_busy()) begin `uvm_warning("UVM/FLD/SET/BSY", $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.", get_name(), m_parent.get_full_name())) end case (m_access) "RO": m_desired = m_desired; "RW": m_desired = value; "RC": m_desired = m_desired; "RS": m_desired = m_desired; "WC": m_desired = '0; "WS": m_desired = mask; "WRC": m_desired = value; "WRS": m_desired = value; "WSRC": m_desired = mask; "WCRS": m_desired = '0; "W1C": m_desired = m_desired & (~value); "W1S": m_desired = m_desired | value; "W1T": m_desired = m_desired ^ value; "W0C": m_desired = m_desired & value; "W0S": m_desired = m_desired | (~value & mask); "W0T": m_desired = m_desired ^ (~value & mask); "W1SRC": m_desired = m_desired | value; "W1CRS": m_desired = m_desired & (~value); "W0SRC": m_desired = m_desired | (~value & mask); "W0CRS": m_desired = m_desired & value; "WO": m_desired = value; "WOC": m_desired = '0; "WOS": m_desired = mask; "W1": m_desired = (m_written) ? m_desired : value; "WO1": m_desired = (m_written) ? m_desired : value; default: m_desired = value; endcase this.value = m_desired; endfunction: set // get function uvm_reg_data_t uvm_reg_field::get(string fname = "", int lineno = 0); m_fname = fname; m_lineno = lineno; get = m_desired; endfunction: get // get_mirrored_value function uvm_reg_data_t uvm_reg_field::get_mirrored_value(string fname = "", int lineno = 0); m_fname = fname; m_lineno = lineno; get_mirrored_value = m_mirrored; endfunction: get_mirrored_value // reset function void uvm_reg_field::reset(string kind = "HARD"); if (!m_reset.exists(kind)) return; m_mirrored = m_reset[kind]; m_desired = m_mirrored; value = m_mirrored; if (kind == "HARD") m_written = 0; endfunction: reset // has_reset function bit uvm_reg_field::has_reset(string kind = "HARD", bit delete = 0); if (!m_reset.exists(kind)) return 0; if (delete) m_reset.delete(kind); return 1; endfunction: has_reset // get_reset function uvm_reg_data_t uvm_reg_field::get_reset(string kind = "HARD"); if (!m_reset.exists(kind)) return m_desired; return m_reset[kind]; endfunction: get_reset // set_reset function void uvm_reg_field::set_reset(uvm_reg_data_t value, string kind = "HARD"); m_reset[kind] = value & ((1<> m_size) begin `uvm_warning("RegModel", {"uvm_reg_field::write(): Value greater than field '", get_full_name(),"'"}) rw.value[0] &= ((1<> m_lsb) & ((1<> m_lsb) & ((1<0) begin prev_lsb = fields[fld_idx-1].get_lsb_pos(); prev_sz = fields[fld_idx-1].get_n_bits(); end if (fld_idx < fields.size()-1) begin next_lsb = fields[fld_idx+1].get_lsb_pos(); next_sz = fields[fld_idx+1].get_n_bits(); end // if first field in register if (fld_idx == 0 && ((next_lsb % bus_sz) == 0 || (next_lsb - this_sz) > (next_lsb % bus_sz))) return 1; // if last field in register else if (fld_idx == (fields.size()-1) && ((this_lsb % bus_sz) == 0 || (this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz))) return 1; // if somewhere in between else begin if ((this_lsb % bus_sz) == 0) begin if ((next_lsb % bus_sz) == 0 || (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz)) return 1; end else begin if ( (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz) && ((this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz)) ) return 1; end end end end `uvm_warning("RegModel", {"Target bus does not support byte enabling, and the field '", get_full_name(),"' is not the only field within the entire bus width. ", "Individual field access will not be available. ", "Accessing complete register instead."}) return 0; endfunction // poke task uvm_reg_field::poke(output uvm_status_e status, input uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_data_t tmp; m_fname = fname; m_lineno = lineno; if (value >> m_size) begin `uvm_warning("RegModel", {"uvm_reg_field::poke(): Value exceeds size of field '", get_name(),"'"}) value &= value & ((1<> m_lsb) & ((1<