00001 // $Id: a00245.html,v 1.1 2009/01/07 19:30:01 alex.marin Exp $ 00002 //---------------------------------------------------------------------- 00003 // Copyright 2007-2008 Mentor Graphics Corporation 00004 // Copyright 2007-2008 Cadence Design Systems, Inc. 00005 // All Rights Reserved Worldwide 00006 // 00007 // Licensed under the Apache License, Version 2.0 (the 00008 // "License"); you may not use this file except in 00009 // compliance with the License. You may obtain a copy of 00010 // the License at 00011 // 00012 // http://www.apache.org/licenses/LICENSE-2.0 00013 // 00014 // Unless required by applicable law or agreed to in 00015 // writing, software distributed under the License is 00016 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00017 // CONDITIONS OF ANY KIND, either express or implied. See 00018 // the License for the specific language governing 00019 // permissions and limitations under the License. 00020 //---------------------------------------------------------------------- 00021 00022 `include "base/ovm_misc.svh" 00023 `include "base/ovm_object.svh" 00024 `include "base/ovm_object_globals.svh" 00025 `include "base/ovm_printer.svh" 00026 `include "base/ovm_packer.svh" 00027 typedef class ovm_component; 00028 00029 //---------------------------------------------------------------------------- 00030 // 00031 // CLASS: ovm_object 00032 // 00033 //---------------------------------------------------------------------------- 00034 00035 00036 // new 00037 // --- 00038 00039 function ovm_object::new (string name=""); 00040 00041 m_inst_id = m_inst_count++; 00042 m_leaf_name = name; 00043 m_field_automation (null, OVM_CHECK_FIELDS, ""); 00044 endfunction 00045 00046 00047 // reseed 00048 // ------ 00049 00050 function void ovm_object::reseed (); 00051 if(use_ovm_seeding) 00052 this.srandom(ovm_create_random_seed(get_type_name(), get_full_name())); 00053 endfunction 00054 00055 00056 // get type 00057 // -------- 00058 00059 function ovm_object_wrapper ovm_object::get_type(); 00060 ovm_report_error("NOTYPID", "get_type not implemented in derived class."); 00061 return null; 00062 endfunction 00063 00064 00065 // get inst_id 00066 // ----------- 00067 00068 function int ovm_object::get_inst_id(); 00069 return m_inst_id; 00070 endfunction 00071 00072 00073 // get inst_count 00074 // -------------- 00075 00076 function int ovm_object::get_inst_count(); 00077 return m_inst_count; 00078 endfunction 00079 00080 00081 // get_name 00082 // -------- 00083 00084 function string ovm_object::get_name (); 00085 return m_leaf_name; 00086 endfunction 00087 00088 00089 // get_full_name 00090 // ------------- 00091 00092 function string ovm_object::get_full_name (); 00093 return get_name(); 00094 endfunction 00095 00096 00097 // set_name 00098 // -------- 00099 00100 function void ovm_object::set_name (string name); 00101 m_leaf_name = name; 00102 endfunction 00103 00104 00105 // print 00106 // ----- 00107 00108 function void ovm_object::print(ovm_printer printer=null); 00109 if(printer==null) 00110 printer = ovm_default_printer; 00111 00112 if(printer.istop()) begin 00113 printer.print_object(get_name(), this); 00114 end 00115 else begin 00116 //do m_field_automation here so user doesn't need to call anything to get 00117 //automation. 00118 ovm_auto_options_object.printer = printer; 00119 m_field_automation(null, OVM_PRINT, ""); 00120 //call user override 00121 do_print(printer); 00122 end 00123 endfunction 00124 00125 00126 // sprint 00127 // ------ 00128 00129 function string ovm_object::sprint(ovm_printer printer=null); 00130 bit p; 00131 00132 if(printer==null) 00133 printer = ovm_default_printer; 00134 00135 p = printer.knobs.sprint; 00136 printer.knobs.sprint = 1; 00137 00138 print(printer); 00139 00140 printer.knobs.sprint = p; //revert back to regular printing 00141 return printer.m_string; 00142 endfunction 00143 00144 00145 // do_sprint (virtual) 00146 // --------- 00147 00148 function string ovm_object::do_sprint(ovm_printer printer); 00149 if(!printer.knobs.sprint) begin 00150 ovm_report_error("SPNSTR", "do_sprint called without string option set for printer"); 00151 return ""; 00152 end 00153 do_print(printer); 00154 return printer.m_string; 00155 endfunction 00156 00157 // print_field_match (static) 00158 // ----------------- 00159 00160 function void ovm_object::print_field_match(string fnc, string match); 00161 string scratch; 00162 00163 if(m_sc.save_last_field) 00164 m_sc.last_field = m_sc.get_full_scope_arg(); 00165 00166 if(print_matches) begin 00167 int style; 00168 scratch = { 00169 fnc, ": Matched string ", match, " to field ", m_sc.get_full_scope_arg() 00170 }; 00171 ovm_report_info("STRMTC", scratch, OVM_LOW); 00172 end 00173 endfunction 00174 00175 // set 00176 // --- 00177 00178 function void ovm_object::set_int_local (string field_name, 00179 ovm_bitstream_t value, 00180 bit recurse=1); 00181 if(m_sc.scope.in_hierarchy(this)) return; 00182 00183 this.m_sc.status = 0; 00184 this.m_sc.bitstream = value; 00185 00186 m_field_automation(null, OVM_SETINT, field_name); 00187 00188 if(m_sc.warning && !this.m_sc.status) begin 00189 ovm_report_error("NOMTC", $psprintf("did not find a match for field %s", field_name)); 00190 end 00191 00192 endfunction 00193 00194 00195 // set_object_local 00196 // ---------------- 00197 00198 function void ovm_object::set_object_local (string field_name, 00199 ovm_object value, 00200 bit clone=1, 00201 bit recurse=1); 00202 ovm_object cc; 00203 if(m_sc.scope.in_hierarchy(this)) return; 00204 00205 if(clone && (value!=null)) begin 00206 cc = value.clone(); 00207 if(cc != null) cc.set_name(field_name); 00208 value = cc; 00209 end 00210 00211 this.m_sc.status = 0; 00212 this.m_sc.object = value; 00213 ovm_auto_options_object.clone = clone; 00214 00215 m_field_automation(null, OVM_SETOBJ, field_name); 00216 00217 if(m_sc.warning && !this.m_sc.status) begin 00218 ovm_report_error("NOMTC", $psprintf("did not find a match for field %s", field_name)); 00219 end 00220 00221 endfunction 00222 00223 00224 // set_string_local 00225 // ---------------- 00226 function void ovm_object::set_string_local (string field_name, 00227 string value, 00228 bit recurse=1); 00229 if(m_sc.scope.in_hierarchy(this)) return; 00230 this.m_sc.status = 0; 00231 this.m_sc.stringv = value; 00232 00233 m_field_automation(null, OVM_SETSTR, field_name); 00234 00235 if(m_sc.warning && !this.m_sc.status) begin 00236 `ifdef INCA 00237 ovm_report_error("NOMTC", $psprintf("did not find a match for field %s (@%0d)", field_name, this)); 00238 `else 00239 ovm_report_error("NOMTC", $psprintf("did not find a match for field %s", field_name)); 00240 `endif 00241 end 00242 endfunction 00243 00244 00245 // m_do_set (static) 00246 // ------------ 00247 00248 // function m_do_set (match, arg, lhs, what, flag) 00249 // Precondition: 00250 // match -- a match string to test against arg to do the set 00251 // arg -- the name of the short name of the lhs object 00252 // lhs -- the lhs to do on (left hand side) 00253 // what -- integer, what to do 00254 // flag -- object flags 00255 // 00256 // ovm_object::m_sc.bitstream -- rhs object used for set/get 00257 // ovm_object::m_sc.status -- return status for set/get calls 00258 // 00259 00260 00261 function int ovm_object::m_do_set (string match, 00262 string arg, 00263 inout ovm_bitstream_t lhs, 00264 input int what, 00265 int flag); 00266 00267 bit matched; 00268 00269 if (what < OVM_START_FUNCS || what > OVM_END_FUNCS) 00270 return 0; 00271 00272 matched = ovm_is_match(match, m_sc.scope.get_arg()); 00273 00274 case (what) 00275 OVM_SETINT: 00276 begin 00277 if(matched) begin 00278 if(flag &OVM_READONLY) begin 00279 ovm_report_warning("RDONLY", $psprintf("Readonly argument match %s is ignored", 00280 m_sc.get_full_scope_arg())); 00281 return 0; 00282 end 00283 print_field_match("set_int()", match); 00284 lhs = ovm_object::m_sc.bitstream; 00285 ovm_object::m_sc.status = 1; 00286 return 1; 00287 end 00288 end 00289 default: 00290 begin 00291 if(matched) begin 00292 ovm_report_warning("MTCTYP", $psprintf("matched integral field %s, ", 00293 m_sc.get_full_scope_arg(), 00294 "but expected a non-integral type")); 00295 end 00296 end 00297 endcase 00298 return 0; 00299 endfunction 00300 00301 00302 // m_do_set_string (static) 00303 // ------------------- 00304 00305 // function m_do_set_string (match, arg, lhs, what, flag) 00306 // Precondition: 00307 // match -- a match string to test against arg to do the set 00308 // arg -- the name of the short name of the lhs object 00309 // lhs -- the lhs to do get or set on (left hand side) 00310 // what -- integer, what to do 00311 // flag -- object flags 00312 // 00313 // ovm_object::m_sc.stringv -- rhs object used for set/get 00314 // ovm_object::m_sc.status -- return status for set/get calls 00315 // 00316 00317 function int ovm_object::m_do_set_string(string match, 00318 string arg, 00319 inout string lhs, 00320 input int what, 00321 int flag); 00322 00323 bit matched; 00324 string s; 00325 00326 if (what < OVM_START_FUNCS || what > OVM_END_FUNCS) 00327 return 0; 00328 00329 matched = ovm_is_match(match, m_sc.scope.get_arg()); 00330 00331 case (what) 00332 OVM_SETSTR: 00333 begin 00334 if(matched) begin 00335 if(flag &OVM_READONLY) begin 00336 ovm_report_warning("RDONLY", $psprintf("Readonly argument match %s is ignored", 00337 m_sc.get_full_scope_arg())); 00338 return 0; 00339 end 00340 print_field_match("set_string()", match); 00341 lhs = ovm_object::m_sc.stringv; 00342 ovm_object::m_sc.status = 1; 00343 return 1; 00344 end 00345 end 00346 default: 00347 begin 00348 if(matched) begin 00349 ovm_report_warning("MTCTYP", $psprintf("matched string field %s, ", 00350 m_sc.get_full_scope_arg(), 00351 "but expected a non-string type")); 00352 end 00353 end 00354 endcase 00355 return 0; 00356 endfunction 00357 00358 00359 // m_do_set_object (static) 00360 // ----------------- 00361 00362 // function m_do_set_object (match, arg, lhsobj, what, flag) 00363 // Precondition: 00364 // match -- a match string to test against arg to do the set 00365 // arg -- the name of the short name of the lhs object 00366 // lhsobj -- the object to do set_object on (left hand side) 00367 // what -- integer, what to do 00368 // flag -- object flags 00369 // 00370 // ovm_object::m_sc.object -- rhs object used for set 00371 // ovm_object::m_sc.status -- return status for set/get calls. set 00372 // always returns 0. 00373 // 00374 // Postcondition: 00375 // Performs the set or get operation on an object. If the object doesn't 00376 // match then the object is recursed. The get* operations return true if 00377 // an index was returned. The set* always return 0. 00378 00379 function int ovm_object::m_do_set_object (string match, 00380 string arg, 00381 inout ovm_object lhsobj, 00382 input int what, 00383 int flag); 00384 00385 bit matched; 00386 bit prev; 00387 00388 if (what < OVM_START_FUNCS || what > OVM_END_FUNCS) 00389 return 0; 00390 00391 matched = ovm_is_match(match, m_sc.scope.get_arg()); 00392 00393 case (what) 00394 OVM_SETOBJ: 00395 begin 00396 if(matched) begin 00397 if(flag &OVM_READONLY) begin 00398 ovm_report_warning("RDONLY", $psprintf("Readonly argument match %s is ignored", 00399 m_sc.get_full_scope_arg())); 00400 return 0; 00401 end 00402 print_field_match("set_object()", match); 00403 lhsobj = ovm_object::m_sc.object; 00404 ovm_object::m_sc.status = 1; 00405 end 00406 else if(lhsobj==null) return 0; 00407 if(flag &OVM_READONLY) 00408 return 0; 00409 lhsobj.m_field_automation(null, OVM_SETOBJ, match); 00410 return ovm_object::m_sc.status; 00411 end 00412 endcase 00413 00414 if(matched) begin 00415 ovm_report_warning("MTCTYP", $psprintf("matched object field %s, ", 00416 m_sc.get_full_scope_arg(), 00417 "but expected a non-object type")); 00418 end 00419 if(lhsobj==null) return 0; 00420 lhsobj.m_field_automation(null, what, match); 00421 00422 return ovm_object::m_sc.status; 00423 00424 endfunction 00425 00426 // clone 00427 // ----- 00428 00429 function ovm_object ovm_object::clone(); 00430 ovm_object tmp; 00431 tmp = this.create(get_name()); 00432 if(tmp == null) begin 00433 // ovm_report_warning("CRFLD", $psprintf("The create method failed for %s, object will be copied using shallow copy", get_name())); 00434 // tmp = new this; 00435 ovm_report_warning("CRFLD", $psprintf("The create method failed for %s, object cannot be cloned", get_name())); 00436 end 00437 else begin 00438 tmp.copy(this); 00439 end 00440 00441 return(tmp); 00442 endfunction 00443 00444 00445 // copy 00446 // ---- 00447 00448 ovm_copy_map ovm_global_copy_map = new; 00449 function void ovm_object::copy (ovm_object rhs); 00450 //For cycle checking 00451 static int depth; 00452 if((rhs !=null) && (ovm_global_copy_map.get(rhs) != null)) begin 00453 return; 00454 end 00455 00456 if(rhs==null) begin 00457 ovm_report_warning("NULLCP", "A null object was supplied to copy; copy is ignored"); 00458 return; 00459 end 00460 00461 ovm_global_copy_map.set(rhs, this); 00462 ++depth; 00463 00464 do_copy(rhs); 00465 m_field_automation(rhs, OVM_COPY, ""); 00466 00467 --depth; 00468 if(depth==0) begin 00469 ovm_global_copy_map.clear(); 00470 end 00471 endfunction 00472 00473 00474 // do_copy 00475 // ------- 00476 00477 function void ovm_object::do_copy (ovm_object rhs); 00478 return; 00479 endfunction 00480 00481 00482 // compare 00483 // ------- 00484 00485 function void ovm_comparer::print_msg(string msg); 00486 result++; 00487 if(result <= show_max) begin 00488 msg = {"Miscompare for ", scope.get_arg(), ": ", msg}; 00489 ovm_report_info("MISCMP", msg, OVM_LOW); 00490 end 00491 miscompares = { miscompares, scope.get_arg(), ": ", msg, "\n" }; 00492 endfunction 00493 00494 //Need this funciton because sformat doesn't support objects 00495 function void ovm_comparer::print_rollup(ovm_object rhs, ovm_object lhs); 00496 string msg; 00497 if(scope.depth() == 0) begin 00498 if(result && (show_max || (sev != OVM_INFO))) begin 00499 if(show_max < result) 00500 $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ", 00501 result, show_max); 00502 else 00503 $swrite(msg, "%0d Miscompare(s) for object ", result); 00504 00505 case (sev) 00506 `ifdef INCA 00507 OVM_WARNING: begin 00508 ovm_report_warning("MISCMP", $psprintf("%s%s@%0d vs. %s@%0d", msg, 00509 lhs.get_name(), lhs, rhs.get_name(), rhs)); 00510 end 00511 OVM_ERROR: begin 00512 ovm_report_error("MISCMP", $psprintf("%s%s@%0d vs. %s@%0d", msg, 00513 lhs.get_name(), lhs, rhs.get_name(), rhs)); 00514 end 00515 default: begin 00516 ovm_report_info("MISCMP", $psprintf("%s%s@%0d vs. %s@%0d", msg, 00517 lhs.get_name(), lhs, rhs.get_name(), rhs), OVM_LOW); 00518 end 00519 `else 00520 OVM_WARNING: begin 00521 ovm_report_warning("MISCMP", $psprintf("%s%s vs. %s", msg, 00522 lhs.get_name(), rhs.get_name())); 00523 end 00524 OVM_ERROR: begin 00525 ovm_report_error("MISCMP", $psprintf("%s%s vs. %s", msg, 00526 lhs.get_name(), rhs.get_name())); 00527 end 00528 default: begin 00529 ovm_report_info("MISCMP", $psprintf("%s%s vs. %s", msg, 00530 lhs.get_name(), rhs.get_name()), OVM_LOW); 00531 end 00532 `endif 00533 endcase 00534 end 00535 end 00536 endfunction 00537 00538 function void ovm_comparer::print_msg_object(ovm_object lhs, ovm_object rhs); 00539 result++; 00540 `ifdef INCA 00541 if(result <= show_max) begin 00542 ovm_report_info("MISCMP", 00543 $psprintf("Miscompare for %0s: lhs = @%0d : rhs = @%0d", 00544 scope.get_arg(), lhs, rhs), verbosity); 00545 end 00546 $swrite(miscompares, "%s%s: lhs = @%0d : rhs = @%0d", 00547 miscompares, scope.get_arg(), lhs, rhs); 00548 `else 00549 if(result <= show_max) begin 00550 ovm_report_info("MISCMP", 00551 $psprintf("Miscompare for %0s", 00552 scope.get_arg()), verbosity); 00553 end 00554 $swrite(miscompares, "%s%s:", 00555 miscompares, scope.get_arg()); 00556 `endif 00557 endfunction 00558 00559 function ovm_status_container ovm_object::init_status(); 00560 if(m_sc==null) m_sc=new; 00561 return m_sc; 00562 endfunction 00563 00564 function bit ovm_object::compare (ovm_object rhs, 00565 ovm_comparer comparer=null); 00566 bit t, dc; 00567 static int style; 00568 bit done; 00569 done = 0; 00570 if(comparer != null) 00571 ovm_auto_options_object.comparer = comparer; 00572 else 00573 ovm_auto_options_object.comparer = ovm_default_comparer; 00574 comparer = ovm_auto_options_object.comparer; 00575 00576 if(!m_sc.scope.depth()) begin 00577 comparer.compare_map.clear(); 00578 comparer.result = 0; 00579 comparer.miscompares = ""; 00580 comparer.scope = m_sc.scope; 00581 if(get_name() == "") begin 00582 m_sc.scope.down("<object>", this); 00583 end 00584 else 00585 m_sc.scope.down(this.get_name(), this); 00586 end 00587 if(!done && (rhs == null)) begin 00588 if(m_sc.scope.depth()) begin 00589 comparer.print_msg_object(this, rhs); 00590 end 00591 else begin 00592 comparer.print_msg_object(this, rhs); 00593 `ifdef INCA 00594 ovm_report_info("MISCMP", 00595 $psprintf("%0d Miscompare(s) for object %s@%0d vs. @%0d", 00596 comparer.result, get_name(), this, rhs), ovm_auto_options_object.comparer.verbosity); 00597 `else 00598 ovm_report_info("MISCMP", 00599 $psprintf("%0d Miscompare(s) for object %s", 00600 comparer.result, get_name()), ovm_auto_options_object.comparer.verbosity); 00601 `endif 00602 done = 1; 00603 end 00604 end 00605 00606 if(!done && (comparer.compare_map.get(rhs) != null)) begin 00607 if(comparer.compare_map.get(rhs) != this) begin 00608 comparer.print_msg_object(this, comparer.compare_map.get(rhs)); 00609 end 00610 done = 1; //don't do any more work after this case, but do cleanup 00611 end 00612 00613 if(!done && comparer.check_type && get_type_name() != rhs.get_type_name()) begin 00614 m_sc.stringv = { "lhs type = \"", get_type_name(), 00615 "\" : rhs type = \"", rhs.get_type_name(), "\""}; 00616 comparer.print_msg(m_sc.stringv); 00617 end 00618 00619 if(!done) begin 00620 comparer.compare_map.set(rhs, this); 00621 m_field_automation(rhs, OVM_COMPARE, ""); 00622 dc = do_compare(rhs, comparer); 00623 end 00624 00625 if(m_sc.scope.depth() == 1) begin 00626 m_sc.scope.up(this); 00627 end 00628 00629 comparer.print_rollup(this, rhs); 00630 return (comparer.result == 0 && dc == 1); 00631 endfunction 00632 00633 00634 // do_compare 00635 // ---------- 00636 00637 function bit ovm_object::do_compare (ovm_object rhs, 00638 ovm_comparer comparer); 00639 return 1; 00640 endfunction 00641 00642 00643 // m_field_automation 00644 // -------------- 00645 00646 function void ovm_object::m_field_automation ( ovm_object tmp_data__, 00647 int what__, 00648 string str__ ); 00649 return; 00650 endfunction 00651 00652 00653 // check_fields 00654 // ------------ 00655 00656 function void ovm_object::m_do_field_check(string field); 00657 if(m_field_array.exists(field) && (m_field_array[field] == 1)) begin 00658 ovm_report_error("MLTFLD", $psprintf("Field %s is defined multiple times in type %s", 00659 field, get_type_name())); 00660 end 00661 m_field_array[field]++; 00662 endfunction 00663 00664 00665 // do_print (virtual override) 00666 // ------------ 00667 00668 function void ovm_object::do_print(ovm_printer printer); 00669 return; 00670 endfunction 00671 00672 00673 // m_pack 00674 // ------ 00675 00676 function void ovm_object::m_pack (inout ovm_packer packer); 00677 00678 if(packer!=null) 00679 ovm_auto_options_object.packer = packer; 00680 else 00681 ovm_auto_options_object.packer = ovm_default_packer; 00682 packer = ovm_auto_options_object.packer; 00683 00684 packer.reset(); 00685 packer.scope.down(get_name(), this); 00686 00687 m_field_automation(null, OVM_PACK, ""); 00688 do_pack(packer); 00689 00690 packer.set_packed_size(); 00691 00692 packer.scope.up(this); 00693 00694 endfunction 00695 00696 00697 // pack 00698 // ---- 00699 00700 function int ovm_object::pack (ref bit bitstream [], 00701 input ovm_packer packer =null ); 00702 m_pack(packer); 00703 packer.get_bits(bitstream); 00704 return packer.get_packed_size(); 00705 endfunction 00706 00707 // pack_bytes 00708 // ---------- 00709 00710 function int ovm_object::pack_bytes (ref byte unsigned bytestream [], 00711 input ovm_packer packer=null ); 00712 m_pack(packer); 00713 packer.get_bytes(bytestream); 00714 return packer.get_packed_size(); 00715 endfunction 00716 00717 00718 // pack_ints 00719 // --------- 00720 00721 function int ovm_object::pack_ints (ref int unsigned intstream [], 00722 input ovm_packer packer=null ); 00723 m_pack(packer); 00724 packer.get_ints(intstream); 00725 return packer.get_packed_size(); 00726 endfunction 00727 00728 00729 // do_pack 00730 // ------- 00731 00732 function void ovm_object::do_pack (ovm_packer packer ); 00733 return; 00734 endfunction 00735 00736 00737 // m_unpack_pre 00738 // ------------ 00739 00740 function void ovm_object::m_unpack_pre (inout ovm_packer packer); 00741 if(packer!=null) 00742 ovm_auto_options_object.packer = packer; 00743 else 00744 ovm_auto_options_object.packer = ovm_default_packer; 00745 packer = ovm_auto_options_object.packer; 00746 packer.reset(); 00747 endfunction 00748 00749 00750 // m_unpack_post 00751 // ------------- 00752 00753 function void ovm_object::m_unpack_post (ovm_packer packer); 00754 00755 int provided_size; 00756 00757 provided_size = packer.get_packed_size(); 00758 00759 //Put this object into the hierarchy 00760 packer.scope.down(get_name(), this); 00761 00762 m_field_automation(null, OVM_UNPACK, ""); 00763 00764 do_unpack(packer); 00765 00766 //Scope back up before leaving 00767 packer.scope.up(this); 00768 00769 if(packer.get_packed_size() != provided_size) begin 00770 ovm_report_warning("BDUNPK", $psprintf("Unpack operation unsuccessful: unpacked %0d bits from a total of %0d bits", packer.get_packed_size(), provided_size)); 00771 end 00772 00773 endfunction 00774 00775 00776 // unpack 00777 // ------ 00778 00779 function int ovm_object::unpack (ref bit bitstream [], 00780 input ovm_packer packer=null); 00781 m_unpack_pre(packer); 00782 packer.put_bits(bitstream); 00783 m_unpack_post(packer); 00784 return packer.get_packed_size(); 00785 endfunction 00786 00787 // unpack_bytes 00788 // ------------ 00789 00790 function int ovm_object::unpack_bytes (ref byte unsigned bytestream [], 00791 input ovm_packer packer=null); 00792 m_unpack_pre(packer); 00793 packer.put_bytes(bytestream); 00794 m_unpack_post(packer); 00795 return packer.get_packed_size(); 00796 endfunction 00797 00798 00799 // unpack_ints 00800 // ----------- 00801 00802 function int ovm_object::unpack_ints (ref int unsigned intstream [], 00803 input ovm_packer packer=null); 00804 m_unpack_pre(packer); 00805 packer.put_ints(intstream); 00806 m_unpack_post(packer); 00807 return packer.get_packed_size(); 00808 endfunction 00809 00810 00811 // do_unpack 00812 // --------- 00813 00814 function void ovm_object::do_unpack (ovm_packer packer); 00815 return; 00816 endfunction 00817 00818 00819 // record 00820 // ------ 00821 00822 function void ovm_object::record (ovm_recorder recorder=null); 00823 //mxg if(!recorder) 00824 if(recorder == null) 00825 recorder = ovm_default_recorder; 00826 00827 if(!recorder.tr_handle) return; 00828 00829 ovm_auto_options_object.recorder = recorder; 00830 recorder.recording_depth++; 00831 00832 m_field_automation(null, OVM_RECORD, ""); 00833 do_record(recorder); 00834 00835 recorder.recording_depth--; 00836 00837 if(recorder.recording_depth==0) begin 00838 recorder.tr_handle = 0; 00839 end 00840 endfunction 00841 00842 00843 // do_record (virtual) 00844 // --------- 00845 00846 function void ovm_object::do_record (ovm_recorder recorder); 00847 return; 00848 endfunction 00849 00850 00851 // m_get_function_type (static) 00852 // ------------------- 00853 00854 function string ovm_object::m_get_function_type (int what); 00855 case (what) 00856 OVM_COPY: return "copy"; 00857 OVM_COMPARE: return "compare"; 00858 OVM_PRINT: return "print"; 00859 OVM_RECORD: return "record"; 00860 OVM_PACK: return "pack"; 00861 OVM_UNPACK: return "unpack"; 00862 OVM_FLAGS: return "get_flags"; 00863 OVM_SETINT: return "set"; 00864 OVM_SETOBJ: return "set_object"; 00865 OVM_SETSTR: return "set_string"; 00866 default: return "unknown"; 00867 endcase 00868 endfunction 00869 00870 00871 // m_get_report_object 00872 // ------------------- 00873 00874 function ovm_report_object ovm_object::m_get_report_object(); 00875 return null; 00876 endfunction 00877 00878 00879 // m_record_field_object (static) 00880 // --------------------- 00881 00882 function void ovm_object::m_record_field_object (string arg, 00883 ovm_object value, 00884 ovm_recorder recorder =null, 00885 int flag = OVM_DEFAULT); 00886 begin 00887 if(!recorder) 00888 recorder=ovm_auto_options_object.recorder; 00889 00890 if((flag&OVM_NORECORD) != 0) return; 00891 00892 recorder.record_object(arg, value); 00893 00894 end 00895 endfunction 00896 00897 00898 // m_do_data (static) 00899 // --------- 00900 00901 // function m_do_data (arg, lhs, rhs, what, flag) 00902 // Precondition: 00903 // arg -- the name of the short name of the lhs object 00904 // lhs -- the lhs to do work on (left hand side) 00905 // lhs -- the rhs to do work from (right hand side) 00906 // what -- integer, what to do 00907 // flag -- object flags 00908 00909 function int ovm_object::m_do_data (string arg, 00910 inout ovm_bitstream_t lhs, 00911 input ovm_bitstream_t rhs, 00912 int what, 00913 int bits, 00914 int flag); 00915 00916 00917 if (what > OVM_END_DATA_EXTRA) 00918 return 0; 00919 00920 if(bits > OVM_STREAMBITS) begin 00921 ovm_report_warning("FLDTNC",$psprintf("%s is %0d bits; maximum field size is %0d, truncating", 00922 arg, bits, OVM_STREAMBITS)); 00923 end 00924 case (what) 00925 OVM_COPY: 00926 begin 00927 if(((flag)&OVM_NOCOPY) == 0) begin 00928 ovm_bitstream_t mask; 00929 mask = -1; 00930 mask >>= (OVM_STREAMBITS-bits); 00931 lhs = rhs & mask; 00932 end 00933 return 0; 00934 end 00935 OVM_COMPARE: 00936 begin 00937 if(((flag)&OVM_NOCOMPARE) == 0) begin 00938 bit r; 00939 if(bits <= 64) 00940 r = ovm_auto_options_object.comparer.compare_field_int(arg, lhs, rhs, bits, ovm_radix_enum'(flag&OVM_RADIX)); 00941 else 00942 r = ovm_auto_options_object.comparer.compare_field(arg, lhs, rhs, bits, ovm_radix_enum'(flag&OVM_RADIX)); 00943 end 00944 return 0; 00945 end 00946 OVM_PACK: 00947 begin 00948 if(((flag)&OVM_NOPACK) == 0) begin 00949 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 00950 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 00951 if(bits<=64) 00952 ovm_auto_options_object.packer.pack_field_int(lhs, bits); 00953 else 00954 ovm_auto_options_object.packer.pack_field(lhs, bits); 00955 end 00956 end 00957 return 0; 00958 end 00959 OVM_UNPACK: 00960 begin 00961 if(((flag)&OVM_NOPACK) == 0) begin 00962 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 00963 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 00964 if(bits<=64) 00965 lhs=ovm_auto_options_object.packer.unpack_field_int(bits); 00966 else 00967 lhs=ovm_auto_options_object.packer.unpack_field(bits); 00968 end 00969 end 00970 return 0; 00971 end 00972 OVM_PRINT: 00973 begin 00974 if(((flag)&OVM_NOPRINT) == 0) 00975 begin 00976 ovm_printer printer; 00977 ovm_radix_enum radix; 00978 radix = ovm_radix_enum'(flag&OVM_RADIX); 00979 printer = ovm_auto_options_object.printer; 00980 printer.print_field(arg, lhs, bits, radix); 00981 end 00982 end 00983 OVM_RECORD: 00984 begin 00985 if(((flag)&OVM_NORECORD) == 0) 00986 begin 00987 integer h; 00988 ovm_radix_enum radix; 00989 00990 if(m_sc.scope.depth()) arg = m_sc.scope.get_arg(); 00991 radix = ovm_radix_enum'(flag&OVM_RADIX); 00992 ovm_auto_options_object.recorder.record_field(arg, lhs, bits, radix); 00993 end 00994 end 00995 endcase 00996 return 0; 00997 endfunction 00998 00999 01000 // m_do_data_object (static) 01001 // ---------------- 01002 01003 // function m_do_data_object (arg, lhs, rhs, what, flag) 01004 // Precondition: 01005 // arg -- the name of the short name of the lhs object 01006 // lhs -- the lhs to do work on (left hand side) 01007 // lhs -- the rhs to do work from (right hand side) 01008 // what -- integer, what to do 01009 // flag -- object flags 01010 01011 function int ovm_object::m_do_data_object (string arg, 01012 inout ovm_object lhs, 01013 input ovm_object rhs, 01014 int what, 01015 int flag); 01016 01017 ovm_object lhs_obj; 01018 01019 if (what > OVM_END_DATA_EXTRA) 01020 return 0; 01021 01022 case (what) 01023 OVM_COPY: 01024 begin 01025 int rval; 01026 if(((flag)&OVM_NOCOPY) != 0) begin 01027 return 0; 01028 end 01029 if(rhs == null) begin 01030 lhs = null; 01031 return OVM_REFERENCE; 01032 end 01033 01034 if(flag & OVM_SHALLOW) begin 01035 rval = OVM_SHALLOW; 01036 end 01037 else if(flag & OVM_REFERENCE) begin 01038 lhs = rhs; 01039 rval = OVM_REFERENCE; 01040 end 01041 else //deepcopy 01042 begin 01043 ovm_object v; 01044 v = ovm_global_copy_map.get(rhs); 01045 if(v) begin 01046 lhs = v; 01047 rval = OVM_REFERENCE; 01048 end 01049 else if(lhs==null) begin 01050 lhs = rhs.clone(); 01051 lhs.set_name(arg); 01052 rval = OVM_REFERENCE; 01053 end 01054 else if(rhs == null) begin 01055 rval = OVM_REFERENCE; 01056 end 01057 else begin 01058 //lhs doesn't change for this case, so don't need to copy back 01059 lhs.copy(rhs); 01060 rval = 0; 01061 end 01062 end 01063 return rval; 01064 end 01065 OVM_COMPARE: 01066 begin 01067 bit refcmp; 01068 01069 if(((flag)&OVM_NOCOMPARE) != 0) begin 01070 return 0; 01071 end 01072 01073 //if the object are the same then don't need to do a deep compare 01074 if(rhs == lhs) return 0; 01075 01076 refcmp = (flag & OVM_SHALLOW) && !(ovm_auto_options_object.comparer.policy == OVM_DEEP); 01077 01078 //do a deep compare here 01079 if(!refcmp && !(ovm_auto_options_object.comparer.policy == OVM_REFERENCE)) 01080 begin 01081 if(((rhs == null) && (lhs != null)) || ((lhs==null) && (rhs!=null))) begin 01082 ovm_auto_options_object.comparer.print_msg_object(lhs, rhs); 01083 return 1; //miscompare 01084 end 01085 if((rhs == null) && (lhs==null)) 01086 return 0; 01087 else begin 01088 bit r; 01089 r = lhs.compare(rhs, ovm_auto_options_object.comparer); 01090 if(r == 0) begin 01091 return 1; 01092 end 01093 else begin 01094 return 0; 01095 end 01096 end 01097 end 01098 else begin //reference compare 01099 if(lhs != rhs) begin 01100 ovm_auto_options_object.comparer.print_msg_object(lhs, rhs); 01101 return 1; 01102 end 01103 end 01104 end 01105 OVM_PACK: 01106 begin 01107 if(((flag&OVM_NOPACK) == 0) && ((flag&OVM_REFERENCE)==0)) begin 01108 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 01109 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 01110 ovm_auto_options_object.packer.pack_object(lhs); 01111 end 01112 end 01113 return 0; 01114 end 01115 OVM_UNPACK: 01116 begin 01117 if(((flag&OVM_NOPACK) == 0) && ((flag&OVM_REFERENCE)==0)) begin 01118 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 01119 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 01120 ovm_auto_options_object.packer.unpack_object_ext(lhs); 01121 end 01122 end 01123 return 0; 01124 end 01125 OVM_PRINT: 01126 begin 01127 if(((flag)&OVM_NOPRINT) == 0) 01128 begin 01129 if(((flag)&OVM_REFERENCE) || (lhs == null)) begin 01130 int d; 01131 d = ovm_auto_options_object.printer.knobs.depth; 01132 ovm_auto_options_object.printer.knobs.depth = 0; 01133 ovm_auto_options_object.printer.print_object(arg, lhs); 01134 ovm_auto_options_object.printer.knobs.depth = d; 01135 end 01136 else begin 01137 ovm_component obj; 01138 if(lhs != null) begin 01139 if($cast(obj,lhs)) begin 01140 if(ovm_auto_options_object.printer.m_scope.current() == obj.get_parent() ) 01141 ovm_auto_options_object.printer.print_object(arg, lhs); 01142 else 01143 ovm_auto_options_object.printer.print_object_header(arg, lhs); 01144 end 01145 else begin 01146 ovm_auto_options_object.printer.print_object(arg, lhs); 01147 end 01148 end 01149 end 01150 end 01151 end 01152 OVM_RECORD: 01153 begin 01154 if(((flag)&OVM_NORECORD) == 0) 01155 begin 01156 //If refernce is on then don't want to do cycle check since only 01157 //recording the reference. 01158 if((flag)&OVM_REFERENCE != 0) 01159 m_record_field_object(arg, lhs, ovm_auto_options_object.recorder,flag); 01160 else begin 01161 if(m_sc.scope.in_hierarchy(lhs)) return 0; 01162 m_record_field_object(arg, lhs, ovm_auto_options_object.recorder,flag); 01163 end 01164 end 01165 end 01166 endcase 01167 return 0; 01168 endfunction 01169 01170 01171 // m_do_data_string (static) 01172 // ---------------- 01173 01174 // function m_do_data_string (arg, lhs, rhs, what, flag) 01175 // Precondition: 01176 // arg -- the name of the short name of the lhs object 01177 // lhs -- the lhs to do work on (left hand side) 01178 // lhs -- the rhs to do work from (right hand side) 01179 // what -- integer, what to do 01180 // flag -- object flags 01181 // 01182 01183 function int ovm_object::m_do_data_string(string arg, 01184 inout string lhs, 01185 input string rhs, 01186 int what, 01187 int flag); 01188 01189 01190 if (what > OVM_END_DATA_EXTRA) 01191 return 0; 01192 01193 case (what) 01194 OVM_COPY: 01195 begin 01196 if(((flag)&OVM_NOCOPY) == 0) begin 01197 lhs = rhs; 01198 end 01199 return 0; 01200 end 01201 OVM_COMPARE: 01202 begin 01203 if(((flag)&OVM_NOCOMPARE) == 0) begin 01204 if(lhs != rhs) begin 01205 m_sc.stringv = { "lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; 01206 ovm_auto_options_object.comparer.print_msg(m_sc.stringv); 01207 return 1; 01208 end 01209 end 01210 return 0; 01211 end 01212 OVM_PACK: 01213 begin 01214 if(((flag)&OVM_NOPACK) == 0) begin 01215 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 01216 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 01217 ovm_auto_options_object.packer.pack_string(lhs); 01218 end 01219 end 01220 return 0; 01221 end 01222 OVM_UNPACK: 01223 begin 01224 if(((flag)&OVM_NOPACK) == 0) begin 01225 if(((flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.abstract) || 01226 (!(flag&OVM_ABSTRACT) && ovm_auto_options_object.packer.physical)) begin 01227 lhs = ovm_auto_options_object.packer.unpack_string(); 01228 end 01229 end 01230 return 0; 01231 end 01232 OVM_PRINT: 01233 begin 01234 if(((flag)&OVM_NOPRINT) == 0) 01235 begin 01236 ovm_auto_options_object.printer.print_string(arg, lhs); 01237 end 01238 end 01239 OVM_RECORD: 01240 begin 01241 if(((flag)&OVM_NORECORD) == 0) 01242 begin 01243 ovm_auto_options_object.recorder.record_string(arg, lhs); 01244 end 01245 end 01246 endcase 01247 return 0; 01248 01249 endfunction 01250 01251 01252 //----------------------------------------------------------------------------- 01253 // 01254 // ovm_status_container 01255 // 01256 //----------------------------------------------------------------------------- 01257 01258 function string ovm_status_container::get_full_scope_arg (); 01259 get_full_scope_arg = scope.get_arg(); 01260 endfunction 01261 01262 function ovm_scope_stack ovm_status_container::init_scope(); 01263 if(scope==null) scope=new; 01264 return scope; 01265 endfunction 01266 01267 //----------------------------------------------------------------------------- 01268 // 01269 // ovm_options_container 01270 // 01271 //----------------------------------------------------------------------------- 01272 01273 ovm_options_container ovm_auto_options_object = ovm_options_container::init(); 01274 01275 function ovm_options_container::new(); 01276 comparer = ovm_default_comparer; 01277 packer = ovm_default_packer; 01278 recorder = ovm_default_recorder; 01279 printer = ovm_default_printer; 01280 endfunction 01281 01282 function ovm_options_container ovm_options_container::init(); 01283 if(ovm_auto_options_object==null) ovm_auto_options_object=new; 01284 return ovm_auto_options_object; 01285 endfunction 01286 01287 //----------------------------------------------------------------------------- 01288 // 01289 // ovm_recorder 01290 // 01291 //----------------------------------------------------------------------------- 01292 01293 function void ovm_recorder::record_field (string name, 01294 ovm_bitstream_t value, 01295 int size, 01296 ovm_radix_enum radix=OVM_NORADIX); 01297 if(tr_handle==0) return; 01298 scope.set_arg(name); 01299 01300 if(!radix) 01301 radix = default_radix; 01302 01303 case(radix) 01304 OVM_BIN: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'b",size); 01305 OVM_OCT: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'o",size); 01306 OVM_DEC: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'s",size); 01307 OVM_TIME: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'u",size); 01308 OVM_STRING: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'a",size); 01309 default: ovm_set_attribute_by_name(tr_handle, scope.get_arg(), value, "'x",size); 01310 endcase 01311 endfunction 01312 01313 function void ovm_recorder::record_object (string name, 01314 ovm_object value); 01315 int v; 01316 string str; 01317 01318 if(scope.in_hierarchy(value)) return; 01319 01320 if(identifier) begin 01321 `ifdef INCA 01322 $swrite(str, "%0d", value); 01323 `else 01324 str = ""; 01325 `endif 01326 v = str.atoi(); 01327 scope.set_arg(name); 01328 ovm_set_attribute_by_name(tr_handle, scope.get_arg(), v, "'s"); 01329 end 01330 01331 if(policy != OVM_REFERENCE) begin 01332 if(value!=null) begin 01333 scope.down(name, value); 01334 value.record(this); 01335 scope.up(value); 01336 end 01337 end 01338 endfunction 01339 01340 function void ovm_recorder::record_string (string name, 01341 string value); 01342 scope.set_arg(name); 01343 ovm_set_attribute_by_name(tr_handle, scope.get_arg(), ovm_string_to_bits(value), "'a"); 01344 endfunction 01345 01346 function void ovm_recorder::record_time (string name, 01347 time value); 01348 record_field(name, value, 64, OVM_TIME); 01349 endfunction 01350 01351 function void ovm_recorder::record_generic (string name, 01352 string value); 01353 record_string(name, value); 01354 endfunction 01355 01356 01357 //----------------------------------------------------------------------------- 01358 // 01359 // ovm_comparer 01360 // 01361 //----------------------------------------------------------------------------- 01362 01363 function bit ovm_comparer::compare_field (string name, 01364 ovm_bitstream_t lhs, 01365 ovm_bitstream_t rhs, 01366 int size, 01367 ovm_radix_enum radix=OVM_NORADIX); 01368 ovm_bitstream_t mask; 01369 string msg; 01370 01371 if(size <= 64) 01372 return compare_field_int(name, lhs, rhs, size, radix); 01373 01374 mask = -1; 01375 mask >>= (OVM_STREAMBITS-size); 01376 if((lhs & mask) !== (rhs & mask)) begin 01377 scope.set_arg(name); 01378 case (radix) 01379 OVM_BIN: begin 01380 $swrite(msg, "lhs = 'b%0b : rhs = 'b%0b", 01381 lhs&mask, rhs&mask); 01382 end 01383 OVM_OCT: begin 01384 $swrite(msg, "lhs = 'o%0o : rhs = 'o%0o", 01385 lhs&mask, rhs&mask); 01386 end 01387 OVM_DEC: begin 01388 $swrite(msg, "lhs = %0d : rhs = %0d", 01389 lhs&mask, rhs&mask); 01390 end 01391 OVM_TIME: begin 01392 $swrite(msg, "lhs = %0t : rhs = %0t", 01393 lhs&mask, rhs&mask); 01394 end 01395 OVM_STRING: begin 01396 $swrite(msg, "lhs = %0s : rhs = %0s", 01397 lhs&mask, rhs&mask); 01398 end 01399 OVM_ENUM: begin 01400 //Printed as decimal, user should cuse compare string for enum val 01401 $swrite(msg, "lhs = %0d : rhs = %0d", 01402 lhs&mask, rhs&mask); 01403 end 01404 default: begin 01405 $swrite(msg, "lhs = 'h%0x : rhs = 'h%0x", 01406 lhs&mask, rhs&mask); 01407 end 01408 endcase 01409 print_msg(msg); 01410 return 0; 01411 end 01412 return 1; 01413 endfunction 01414 01415 function bit ovm_comparer::compare_field_int (string name, 01416 logic [63:0] lhs, 01417 logic [63:0] rhs, 01418 int size, 01419 ovm_radix_enum radix=OVM_NORADIX); 01420 logic [63:0] mask; 01421 string msg; 01422 01423 mask = -1; 01424 mask >>= (64-size); 01425 if((lhs & mask) !== (rhs & mask)) begin 01426 scope.set_arg(name); 01427 case (radix) 01428 OVM_BIN: begin 01429 $swrite(msg, "lhs = 'b%0b : rhs = 'b%0b", 01430 lhs&mask, rhs&mask); 01431 end 01432 OVM_OCT: begin 01433 $swrite(msg, "lhs = 'o%0o : rhs = 'o%0o", 01434 lhs&mask, rhs&mask); 01435 end 01436 OVM_DEC: begin 01437 $swrite(msg, "lhs = %0d : rhs = %0d", 01438 lhs&mask, rhs&mask); 01439 end 01440 OVM_TIME: begin 01441 $swrite(msg, "lhs = %0t : rhs = %0t", 01442 lhs&mask, rhs&mask); 01443 end 01444 OVM_STRING: begin 01445 $swrite(msg, "lhs = %0s : rhs = %0s", 01446 lhs&mask, rhs&mask); 01447 end 01448 OVM_ENUM: begin 01449 //Printed as decimal, user should cuse compare string for enum val 01450 $swrite(msg, "lhs = %0d : rhs = %0d", 01451 lhs&mask, rhs&mask); 01452 end 01453 default: begin 01454 $swrite(msg, "lhs = 'h%0x : rhs = 'h%0x", 01455 lhs&mask, rhs&mask); 01456 end 01457 endcase 01458 print_msg(msg); 01459 return 0; 01460 end 01461 return 1; 01462 endfunction 01463 01464 01465 function bit ovm_comparer::compare_object (string name, 01466 ovm_object lhs, 01467 ovm_object rhs); 01468 01469 if (rhs == lhs) 01470 return 1; 01471 01472 if (policy == OVM_REFERENCE && lhs != rhs) begin 01473 scope.set_arg(name); 01474 print_msg_object(lhs, rhs); 01475 return 0; 01476 end 01477 01478 if (rhs == null || lhs == null) begin 01479 scope.set_arg(name); 01480 print_msg_object(lhs, rhs); 01481 return 0; //miscompare 01482 end 01483 01484 scope.down(name, null); 01485 compare_object = lhs.compare(rhs, this); 01486 scope.up(null); 01487 01488 endfunction 01489 01490 function bit ovm_comparer::compare_string (string name, 01491 string lhs, 01492 string rhs); 01493 string msg; 01494 if(lhs != rhs) begin 01495 scope.set_arg(name); 01496 msg = { "lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; 01497 print_msg(msg); 01498 return 0; 01499 end 01500 return 1; 01501 endfunction 01502 01503 function ovm_comparer ovm_comparer::init(); 01504 if(ovm_default_comparer==null) ovm_default_comparer=new; 01505 return ovm_default_comparer; 01506 endfunction
![]() Intelligent Design Verification Project: OVM, Revision: 2.0.1 |
Copyright (c) 2008 Intelligent Design Verification. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included here: http://www.intelligentdv.com/licenses/fdl.txt |
![]() Doxygen Version: 1.5.5 Wed Jan 7 19:27:18 2009 |