VMM - RAL/vmm_ral_vfield.sv

RAL/vmm_ral_vfield.sv expanded source

00001 // 
00002 // -------------------------------------------------------------
00003 //    Copyright 2004-2008 Synopsys, Inc.
00004 //    All Rights Reserved Worldwide
00005 // 
00006 //    Licensed under the Apache License, Version 2.0 (the
00007 //    "License"); you may not use this file except in
00008 //    compliance with the License.  You may obtain a copy of
00009 //    the License at
00010 // 
00011 //        http://www.apache.org/licenses/LICENSE-2.0
00012 // 
00013 //    Unless required by applicable law or agreed to in
00014 //    writing, software distributed under the License is
00015 //    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00016 //    CONDITIONS OF ANY KIND, either express or implied.  See
00017 //    the License for the specific language governing
00018 //    permissions and limitations under the License.
00019 // -------------------------------------------------------------
00020 // 
00021 
00022 
00023 typedef class vmm_ral_vfield;
00024 class vmm_ral_vfield_callbacks extends vmm_ral_callbacks;
00025 
00026    virtual task pre_write(vmm_ral_vfield                    field,
00027                           longint unsigned                  idx,
00028                           ref bit [`VMM_RAL_DATA_WIDTH-1:0] wdat,
00029                           ref vmm_ral::path_e               path,
00030                           ref string                        domain);
00031    endtask: pre_write
00032 
00033    virtual task post_write(vmm_ral_vfield                field,
00034                            longint unsigned              idx,
00035                            bit [`VMM_RAL_DATA_WIDTH-1:0] wdat,
00036                            vmm_ral::path_e               path,
00037                            string                        domain,
00038                            ref vmm_rw::status_e          status);
00039    endtask: post_write
00040 
00041    virtual task pre_read(vmm_ral_vfield        field,
00042                          longint unsigned      idx,
00043                          ref vmm_ral::path_e   path,
00044                          ref string            domain);
00045    endtask: pre_read
00046 
00047    virtual task post_read(vmm_ral_vfield                    field,
00048                           longint unsigned                  idx,
00049                           ref bit [`VMM_RAL_DATA_WIDTH-1:0] rdat,
00050                           vmm_ral::path_e                   path,
00051                           string                            domain,
00052                           ref vmm_rw::status_e              status);
00053    endtask: post_read
00054 endclass: vmm_ral_vfield_callbacks
00055 
00056 
00057 class vmm_ral_vfield;
00058    static vmm_log log = new("RAL", "virtual field");
00059 
00060    local string name;
00061    local vmm_ral_vreg parent;
00062    local int unsigned lsb;
00063    local int unsigned size;
00064 
00065    vmm_ral_vfield_callbacks XcbsX[$];
00066 
00067    extern /*local*/ function new(vmm_ral_vreg     parent,
00068                                  string           name,
00069                                  int unsigned     size,
00070                                  int unsigned     lsb_pos);
00071 
00072    extern virtual function string get_name();
00073    extern virtual function string get_fullname();
00074    extern virtual function vmm_ral_vreg get_register();
00075    extern virtual function int unsigned get_lsb_pos_in_register();
00076    extern virtual function int unsigned get_n_bits();
00077 
00078    extern virtual function vmm_ral::access_e get_access(string domain = "");
00079 
00080    extern virtual function void display(string prefix = "");
00081    extern virtual function string psdisplay(string prefix = "");
00082 
00083    extern virtual task write(input  longint unsigned              idx,
00084                              output vmm_rw::status_e              status,
00085                              input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00086                              input  vmm_ral::path_e               path = vmm_ral::DEFAULT,
00087                              input  string                        domain = "",
00088                              input  int                           data_id = -1,
00089                              input  int                           scenario_id =- 1,
00090                              input  int                           stream_id = -1);
00091    extern virtual task read(input  longint unsigned             idx,
00092                             output vmm_rw::status_e             status,
00093                             output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00094                             input  vmm_ral::path_e              path = vmm_ral::DEFAULT,
00095                             input  string                       domain = "",
00096                             input  int                          data_id = -1,
00097                             input  int                          scenario_id = -1,
00098                             input  int                          stream_id = -1);
00099                
00100    extern virtual task poke(input  longint unsigned              idx,
00101                             output vmm_rw::status_e              status,
00102                             input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00103                             input  int                           data_id = -1,
00104                             input  int                           scenario_id =- 1,
00105                             input  int                           stream_id = -1);
00106    extern virtual task peek(input  longint unsigned             idx,
00107                             output vmm_rw::status_e             status,
00108                             output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00109                             input  int                          data_id = -1,
00110                             input  int                          scenario_id = -1,
00111                             input  int                          stream_id = -1);
00112                
00113    extern function void prepend_callback(vmm_ral_vfield_callbacks cb);
00114    extern function void append_callback(vmm_ral_vfield_callbacks cb);
00115    extern function void unregister_callback(vmm_ral_vfield_callbacks cb);
00116 endclass: vmm_ral_vfield
00117 
00118 
00119 function vmm_ral_vfield::new(vmm_ral_vreg      parent,
00120                              string            name,
00121                              int unsigned      size,
00122                              int unsigned      lsb_pos);
00123    this.parent = parent;
00124    this.name   = name;
00125 
00126    if (size == 0) begin
00127       `vmm_error(this.log, $psprintf("Virtual field \"%s\" cannot have 0 bits", this.get_fullname()));
00128       size = 1;
00129    end
00130    if (size > `VMM_RAL_DATA_WIDTH) begin
00131       `vmm_error(this.log, $psprintf("Virtual field \"%s\" cannot have more than %0d bits",
00132                                      this.get_fullname(),
00133                                      `VMM_RAL_DATA_WIDTH));
00134       size = `VMM_RAL_DATA_WIDTH;
00135    end
00136 
00137    this.size   = size;
00138    this.lsb    = lsb_pos;
00139 
00140    this.parent.register_field(this);
00141 endfunction: new
00142 
00143 
00144 function string vmm_ral_vfield::get_name();
00145    get_name = this.name;
00146 endfunction: get_name
00147 
00148 
00149 function string vmm_ral_vfield::get_fullname();
00150    get_fullname = {this.parent.get_fullname(), ".", this.name};
00151 endfunction: get_fullname
00152 
00153 
00154 function vmm_ral_vreg vmm_ral_vfield::get_register();
00155    get_register = this.parent;
00156 endfunction: get_register
00157 
00158 
00159 function int unsigned vmm_ral_vfield::get_lsb_pos_in_register();
00160    get_lsb_pos_in_register = this.lsb;
00161 endfunction: get_lsb_pos_in_register
00162 
00163 
00164 function int unsigned vmm_ral_vfield::get_n_bits();
00165    get_n_bits = this.size;
00166 endfunction: get_n_bits
00167 
00168 
00169 function vmm_ral::access_e vmm_ral_vfield::get_access(string domain);
00170    if (this.parent.get_memory() == null) begin
00171       `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::get_rights() on unimplemented virtual field \"%s\"",
00172                                      this.get_fullname()));
00173       return vmm_ral::RW;
00174    end
00175 
00176    get_access = this.parent.get_access(domain);
00177 endfunction: get_access
00178 
00179 
00180 function void vmm_ral_vfield::display(string prefix);
00181    $write("%s\n", this.psdisplay(prefix));
00182 endfunction: display
00183 
00184 
00185 function string vmm_ral_vfield::psdisplay(string prefix);
00186    $sformat(psdisplay, {"%s%s[%0d-%0d]"}, prefix,
00187             this.get_name(),
00188             this.get_lsb_pos_in_register() + this.get_n_bits() - 1,
00189             this.get_lsb_pos_in_register());
00190 endfunction: psdisplay
00191 
00192 
00193 task vmm_ral_vfield::write(input  longint unsigned              idx,
00194                            output vmm_rw::status_e              status,
00195                            input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00196                            input  vmm_ral::path_e               path,
00197                            input  string                        domain,
00198                            input  int                           data_id,
00199                            input  int                           scenario_id,
00200                            input  int                           stream_id);
00201    bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00202    bit [`VMM_RAL_DATA_WIDTH-1:0] segval;
00203    bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff;
00204    vmm_rw::status_e st;
00205 
00206    int flsb, fmsb, rmwbits;
00207    int segsiz, segn;
00208    vmm_ral_mem    mem;
00209    vmm_ral::path_e rm_path;
00210 
00211    mem = this.parent.get_memory();
00212    if (mem == null) begin
00213       `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::write() on unimplemented virtual register \"%s\"",
00214                                      this.get_fullname()));
00215       status = vmm_rw::ERROR;
00216       return;
00217    end
00218 
00219    if (path == vmm_ral::DEFAULT) begin
00220       vmm_ral_block blk = this.parent.get_block();
00221       path = blk.get_default_access();
00222    end
00223 
00224    status = vmm_rw::IS_OK;
00225 
00226    this.parent.XatomicX(1);
00227 
00228    if (value >> this.size) begin
00229       `vmm_warning(log, $psprintf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_fullname(), this.get_n_bits()));
00230       value &= value & ((1<<this.size)-1);
00231    end
00232    tmp = 0;
00233 
00234    foreach (this.XcbsX[j]) begin
00235       vmm_ral_vfield_callbacks cb;
00236       if (!$cast(cb, this.XcbsX[j])) continue;
00237       cb.pre_write(this, idx, value, path, domain);
00238    end
00239 
00240    segsiz = mem.get_n_bytes() * 8;
00241    flsb    = this.get_lsb_pos_in_register();
00242    segoff  = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
00243 
00244    // Favor backdoor read to frontdoor read for the RMW operation
00245    rm_path = vmm_ral::DEFAULT;
00246    if (mem.get_backdoor() != null) rm_path = vmm_ral::BACKDOOR;
00247 
00248    // Any bits on the LSB side we need to RMW?
00249    rmwbits = flsb % segsiz;
00250 
00251    // Total number of memory segment in this field
00252    segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1;
00253 
00254    if (rmwbits > 0) begin
00255       bit [`VMM_RAL_ADDR_WIDTH-1:0] segn;
00256 
00257       mem.read(st, segoff, tmp, rm_path, domain,
00258                data_id, scenario_id, stream_id);
00259       if (st != vmm_rw::IS_OK) begin
00260          `vmm_error(this.log,
00261                     $psprintf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
00262                               mem.get_fullname(), segoff, this.get_fullname()));
00263          status = vmm_rw::ERROR;
00264          this.parent.XatomicX(0);
00265          return;
00266       end
00267 
00268       value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1));
00269    end
00270 
00271    // Any bits on the MSB side we need to RMW?
00272    fmsb = rmwbits + this.get_n_bits() - 1;
00273    rmwbits = (fmsb+1) % segsiz;
00274    if (rmwbits > 0) begin
00275       if (segn > 0) begin
00276          mem.read(st, segoff + segn - 1, tmp, rm_path, domain,
00277                   data_id, scenario_id, stream_id);
00278          if (st != vmm_rw::IS_OK) begin
00279             `vmm_error(this.log,
00280                        $psprintf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
00281                                  mem.get_fullname(), segoff+segn-1,
00282                                  this.get_fullname()));
00283             status = vmm_rw::ERROR;
00284             this.parent.XatomicX(0);
00285             return;
00286          end
00287       end
00288       value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz);
00289    end
00290 
00291    // Now write each of the segments
00292    tmp = value;
00293    repeat (segn) begin
00294       mem.write(st, segoff, tmp, path, domain,
00295                data_id, scenario_id, stream_id);
00296       if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR;
00297 
00298       segoff++;
00299       tmp = tmp >> segsiz;
00300    end
00301 
00302    foreach (this.XcbsX[j]) begin
00303       vmm_ral_vfield_callbacks cb;
00304       if (!$cast(cb, this.XcbsX[j])) continue;
00305       cb.post_write(this, idx, value, path, domain, status);
00306    end
00307 
00308    this.parent.XatomicX(0);
00309 
00310    `vmm_trace(this.log, $psprintf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h",
00311                                   this.get_fullname(), idx,
00312                                   (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00313                                   value));
00314 
00315 endtask: write
00316 
00317 
00318 task vmm_ral_vfield::read(input longint unsigned              idx,
00319                           output vmm_rw::status_e             status,
00320                           output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00321                           input  vmm_ral::path_e              path,
00322                           input  string                       domain,
00323                           input  int                          data_id,
00324                           input  int                          scenario_id,
00325                           input  int                          stream_id);
00326    bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00327    bit [`VMM_RAL_DATA_WIDTH-1:0] segval;
00328    bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff;
00329    vmm_rw::status_e st;
00330 
00331    int flsb, lsb;
00332    int segsiz, segn;
00333    vmm_ral_mem    mem;
00334 
00335    mem = this.parent.get_memory();
00336    if (mem == null) begin
00337       `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::read() on unimplemented virtual register \"%s\"",
00338                                      this.get_fullname()));
00339       status = vmm_rw::ERROR;
00340       return;
00341    end
00342 
00343    if (path == vmm_ral::DEFAULT) begin
00344       vmm_ral_block blk = this.parent.get_block();
00345       path = blk.get_default_access();
00346    end
00347 
00348    status = vmm_rw::IS_OK;
00349 
00350    this.parent.XatomicX(1);
00351 
00352    value = 0;
00353 
00354    foreach (this.XcbsX[j]) begin
00355       vmm_ral_vfield_callbacks cb;
00356       if (!$cast(cb, this.XcbsX[j])) continue;
00357       cb.pre_read(this, idx, path, domain);
00358    end
00359 
00360    segsiz = mem.get_n_bytes() * 8;
00361    flsb    = this.get_lsb_pos_in_register();
00362    segoff  = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
00363    lsb = flsb % segsiz;
00364 
00365    // Total number of memory segment in this field
00366    segn = (lsb + this.get_n_bits() - 1) / segsiz + 1;
00367 
00368    // Read each of the segments, MSB first
00369    segoff += segn - 1;
00370    repeat (segn) begin
00371       value = value << segsiz;
00372 
00373       mem.read(st, segoff, tmp, path, domain,
00374                data_id, scenario_id, stream_id);
00375       if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR;
00376 
00377       segoff--;
00378       value |= tmp;
00379    end
00380 
00381    // Any bits on the LSB side we need to get rid of?
00382    value = value >> lsb;
00383 
00384    // Any bits on the MSB side we need to get rid of?
00385    value &= (1<<this.get_n_bits()) - 1;
00386 
00387    foreach (this.XcbsX[j]) begin
00388       vmm_ral_vfield_callbacks cb;
00389       if (!$cast(cb, this.XcbsX[j])) continue;
00390       cb.post_read(this, idx, value, path, domain, status);
00391    end
00392 
00393    this.parent.XatomicX(0);
00394 
00395    `vmm_trace(this.log, $psprintf("Read virtual field \"%s\"[%0d] via %s: 'h%h",
00396                                   this.get_fullname(), idx,
00397                                   (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00398                                   value));
00399 
00400 endtask: read
00401                
00402 
00403 task vmm_ral_vfield::poke(input  longint unsigned              idx,
00404                           output vmm_rw::status_e              status,
00405                           input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00406                           input  int                           data_id,
00407                           input  int                           scenario_id,
00408                           input  int                           stream_id);
00409    bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00410    bit [`VMM_RAL_DATA_WIDTH-1:0] segval;
00411    bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff;
00412    vmm_rw::status_e st;
00413 
00414    int flsb, fmsb, rmwbits;
00415    int segsiz, segn;
00416    vmm_ral_mem    mem;
00417    vmm_ral::path_e rm_path;
00418 
00419    mem = this.parent.get_memory();
00420    if (mem == null) begin
00421       `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::poke() on unimplemented virtual register \"%s\"",
00422                                      this.get_fullname()));
00423       status = vmm_rw::ERROR;
00424       return;
00425    end
00426 
00427    status = vmm_rw::IS_OK;
00428 
00429    this.parent.XatomicX(1);
00430 
00431    if (value >> this.size) begin
00432       `vmm_warning(log, $psprintf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_fullname(), this.get_n_bits()));
00433       value &= value & ((1<<this.size)-1);
00434    end
00435    tmp = 0;
00436 
00437    segsiz = mem.get_n_bytes() * 8;
00438    flsb    = this.get_lsb_pos_in_register();
00439    segoff  = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
00440 
00441    // Any bits on the LSB side we need to RMW?
00442    rmwbits = flsb % segsiz;
00443 
00444    // Total number of memory segment in this field
00445    segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1;
00446 
00447    if (rmwbits > 0) begin
00448       bit [`VMM_RAL_ADDR_WIDTH-1:0] segn;
00449 
00450       mem.peek(st, segoff, tmp,
00451                data_id, scenario_id, stream_id);
00452       if (st != vmm_rw::IS_OK) begin
00453          `vmm_error(this.log,
00454                     $psprintf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
00455                               mem.get_fullname(), segoff, this.get_fullname()));
00456          status = vmm_rw::ERROR;
00457          this.parent.XatomicX(0);
00458          return;
00459       end
00460 
00461       value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1));
00462    end
00463 
00464    // Any bits on the MSB side we need to RMW?
00465    fmsb = rmwbits + this.get_n_bits() - 1;
00466    rmwbits = (fmsb+1) % segsiz;
00467    if (rmwbits > 0) begin
00468       if (segn > 0) begin
00469          mem.peek(st, segoff + segn - 1, tmp,
00470                   data_id, scenario_id, stream_id);
00471          if (st != vmm_rw::IS_OK) begin
00472             `vmm_error(this.log,
00473                        $psprintf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
00474                                  mem.get_fullname(), segoff+segn-1,
00475                                  this.get_fullname()));
00476             status = vmm_rw::ERROR;
00477             this.parent.XatomicX(0);
00478             return;
00479          end
00480       end
00481       value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz);
00482    end
00483 
00484    // Now write each of the segments
00485    tmp = value;
00486    repeat (segn) begin
00487       mem.poke(st, segoff, tmp,
00488                data_id, scenario_id, stream_id);
00489       if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR;
00490 
00491       segoff++;
00492       tmp = tmp >> segsiz;
00493    end
00494 
00495    this.parent.XatomicX(0);
00496 
00497    `vmm_trace(this.log, $psprintf("Wrote virtual field \"%s\"[%0d] with: 'h%h",
00498                                   this.get_fullname(), idx, value));
00499 
00500 endtask: poke
00501 
00502 
00503 task vmm_ral_vfield::peek(input  longint unsigned             idx,
00504                           output vmm_rw::status_e             status,
00505                           output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00506                           input  int                          data_id,
00507                           input  int                          scenario_id,
00508                           input  int                          stream_id);
00509    bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00510    bit [`VMM_RAL_DATA_WIDTH-1:0] segval;
00511    bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff;
00512    vmm_rw::status_e st;
00513 
00514    int flsb, lsb;
00515    int segsiz, segn;
00516    vmm_ral_mem    mem;
00517 
00518    mem = this.parent.get_memory();
00519    if (mem == null) begin
00520       `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::peek() on unimplemented virtual register \"%s\"",
00521                                      this.get_fullname()));
00522       status = vmm_rw::ERROR;
00523       return;
00524    end
00525 
00526    status = vmm_rw::IS_OK;
00527 
00528    this.parent.XatomicX(1);
00529 
00530    value = 0;
00531 
00532    segsiz = mem.get_n_bytes() * 8;
00533    flsb    = this.get_lsb_pos_in_register();
00534    segoff  = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
00535    lsb = flsb % segsiz;
00536 
00537    // Total number of memory segment in this field
00538    segn = (lsb + this.get_n_bits() - 1) / segsiz + 1;
00539 
00540    // Read each of the segments, MSB first
00541    segoff += segn - 1;
00542    repeat (segn) begin
00543       value = value << segsiz;
00544 
00545       mem.peek(st, segoff, tmp,
00546                data_id, scenario_id, stream_id);
00547       if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR;
00548 
00549       segoff--;
00550       value |= tmp;
00551    end
00552 
00553    // Any bits on the LSB side we need to get rid of?
00554    value = value >> lsb;
00555 
00556    // Any bits on the MSB side we need to get rid of?
00557    value &= (1<<this.get_n_bits()) - 1;
00558 
00559    this.parent.XatomicX(0);
00560 
00561    `vmm_trace(this.log, $psprintf("Peeked virtual field \"%s\"[%0d]: 'h%h",
00562                                   this.get_fullname(), idx, value));
00563 
00564 endtask: peek
00565                
00566 
00567 function void vmm_ral_vfield::prepend_callback(vmm_ral_vfield_callbacks cb);
00568    foreach (this.XcbsX[i]) begin
00569       if (this.XcbsX[i] == cb) begin
00570          `vmm_warning(this.log, $psprintf("Callback has already been registered with field \"%s\"", this.get_fullname()));
00571          return;
00572       end
00573    end
00574    
00575    // Prepend new callback
00576    this.XcbsX.push_front(cb);
00577 endfunction: prepend_callback
00578 
00579 
00580 function void vmm_ral_vfield::append_callback(vmm_ral_vfield_callbacks cb);
00581    foreach (this.XcbsX[i]) begin
00582       if (this.XcbsX[i] == cb) begin
00583          `vmm_warning(this.log, $psprintf("Callback has already been registered with field \"%s\"", this.get_fullname()));
00584          return;
00585       end
00586    end
00587    
00588    // Append new callback
00589    this.XcbsX.push_back(cb);
00590 endfunction: append_callback
00591 
00592 
00593 function void vmm_ral_vfield::unregister_callback(vmm_ral_vfield_callbacks cb);
00594    foreach (this.XcbsX[i]) begin
00595       if (this.XcbsX[i] == cb) begin
00596          int j = i;
00597          // Unregister it
00598          this.XcbsX.delete(j);
00599          return;
00600       end
00601    end
00602 
00603    `vmm_warning(this.log, $psprintf("Callback was not registered with field \"%s\"", this.get_fullname()));
00604 endfunction: unregister_callback