//*************************************************************************
// DESCRIPTION: Verilator: main()
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-2009 by Wilson Snyder.  This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
//*************************************************************************

#include "V3Global.h"
#include "V3Ast.h"
#include <time.h>
#include <sys/stat.h>

#include "V3Active.h"
#include "V3ActiveTop.h"
#include "V3Assert.h"
#include "V3AssertPre.h"
#include "V3Begin.h"
#include "V3Branch.h"
#include "V3Case.h"
#include "V3Cast.h"
#include "V3Changed.h"
#include "V3Clean.h"
#include "V3ClkGater.h"
#include "V3Clock.h"
#include "V3Combine.h"
#include "V3Const.h"
#include "V3Coverage.h"
#include "V3CoverageJoin.h"
#include "V3Dead.h"
#include "V3Delayed.h"
#include "V3Depth.h"
#include "V3DepthBlock.h"
#include "V3Descope.h"
#include "V3EmitC.h"
#include "V3EmitMk.h"
#include "V3EmitV.h"
#include "V3Expand.h"
#include "V3File.h"
#include "V3Gate.h"
#include "V3Graph.h"
#include "V3GenClk.h"
#include "V3Inline.h"
#include "V3Inst.h"
#include "V3Life.h"
#include "V3LifePost.h"
#include "V3Link.h"
#include "V3LinkCells.h"
#include "V3LinkDot.h"
#include "V3LinkLevel.h"
#include "V3LinkParse.h"
#include "V3LinkLValue.h"
#include "V3LinkResolve.h"
#include "V3Localize.h"
#include "V3Name.h"
#include "V3Order.h"
#include "V3Param.h"
#include "V3PreShell.h"
#include "V3Premit.h"
#include "V3Read.h"
#include "V3Scope.h"
#include "V3Signed.h"
#include "V3Split.h"
#include "V3SplitAs.h"
#include "V3Stats.h"
#include "V3Subst.h"
#include "V3Table.h"
#include "V3Task.h"
#include "V3Trace.h"
#include "V3TraceDecl.h"
#include "V3Tristate.h"
#include "V3Unknown.h"
#include "V3Unroll.h"
#include "V3Width.h"

V3Global v3Global;

//######################################################################
// V3 Class -- top level

void V3Global::readFiles() {
    V3Read reader (m_rootp);
    // Read top module
    for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin();
	 it != v3Global.opt.vFiles().end(); ++it) {
	string filename = *it;
	reader.readFile(new FileLine("CommandLine",0), filename, false);
    }

    // Read libraries
    // To be compatible with other simulators,
    // this needs to be done after the top file is read
    for (V3StringSet::const_iterator it = v3Global.opt.libraryFiles().begin();
	 it != v3Global.opt.libraryFiles().end(); ++it) {
	string filename = *it;
	reader.readFile(new FileLine("CommandLine",0), filename, true);
    }
    V3Error::abortIfErrors();
}

//######################################################################

void process () {
    // Resolve all modules cells refer to
    V3LinkCells::link(v3Global.rootp());
    V3LinkLevel::modSortByLevel();
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree"));
    V3Error::abortIfErrors();

    // Convert parseref's to varrefs, and other directly post parsing fixups
    V3LinkParse::linkParse(v3Global.rootp());
    // Cross-link signal names
    V3Link::link(v3Global.rootp());
    // Cross-link dotted hierarchical references
    V3LinkDot::linkDotPrearrayed(v3Global.rootp());
    // Correct state we couldn't know at parse time, repair SEL's
    V3LinkResolve::linkResolve(v3Global.rootp());
    // Set Lvalue's in variable refs
    V3LinkLValue::linkLValue(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
    V3Error::abortIfErrors();

    if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link");

    // Remove parameters by cloning modules to de-parameterized versions
    //   This requires some width calculations and constant propagation
    V3Param::param(v3Global.rootp());
    V3LinkDot::linkDotPrearrayed(v3Global.rootp());	// Cleanup as made new modules
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param.tree"));
    V3Error::abortIfErrors();

    // Remove any modules that were parameterized and are no longer referenced.
    V3Dead::deadifyAll(v3Global.rootp(), false);
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
    v3Global.checkTree();

    // Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
    V3Width::width(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("width.tree"));

    // Compute signed/unsigned
    V3Signed::signedAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("signed.tree"));
    V3Error::abortIfErrors();

    // Commit to the widths we've chosen; Make widthMin==width
    V3Width::widthCommit(v3Global.rootp());
    v3Global.assertWidthsSame(true);
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("widthcommit.tree"));

    // Coverage insertion
    //    Before we do dead code elimination and inlining, or we'll loose it.
    if (v3Global.opt.coverage()) {
	V3Coverage::coverage(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("coverage.tree"));
    }

    // Assertion insertion
    //    After we've added block coverage, but before other nasty transforms
    V3AssertPre::assertPreAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assertpre.tree"));
    //
    V3Assert::assertAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("assert.tree"));

    // Add top level wrapper with instance pointing to old top
    // Must do this after we know the width of any parameters
    // We also do it after coverage/assertion insertion so we don't 'cover' the top level.
    V3LinkLevel::wrapTop(v3Global.rootp());

    // Propagate constants into expressions
    V3Const::constifyAllLint(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Expand Inouts
    V3Tristate::inoutAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));

    // Remove cell arrays (must be between V3Width and scoping)
    V3Inst::dearrayAll(v3Global.rootp());
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));

    V3Tristate::tristateAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));

    // Move assignments from X into MODULE temps.
    // (Before flattening, so each new X variable is shared between all scopes of that module.)
    V3Unknown::unknownAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));

    // Task inlining & pushing BEGINs names to variables/cells
    // Begin processing must be after Param, before module inlining
    V3Begin::debeginAll(v3Global.rootp());	// Flatten cell names, before inliner
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));

    // Module inlining
    // Cannot remove dead variables after this, as alias information for final
    // V3Scope's V3LinkDot is in the AstVar.
    if (v3Global.opt.oInline()) {
	V3Inline::inlineAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
	V3LinkDot::linkDotArrayed(v3Global.rootp());	// Cleanup as made new modules
	//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
    }

    //--PRE-FLAT OPTIMIZATIONS------------------

    // Initial const/dead to reduce work for ordering code
    V3Const::constifyAll(v3Global.rootp());
    v3Global.checkTree();
    V3Dead::deadifyAll(v3Global.rootp(), false);
    v3Global.checkTree();
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    V3Error::abortIfErrors();

    //--FLATTENING---------------

    // We're going to flatten the hierarchy, so as many optimizations that
    // can be done as possible should be before this....

    // Convert instantiations to wassigns and always blocks
    V3Inst::instAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inst.tree"));

    // Inst may have made lots of concats; fix them
    V3Const::constifyAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Flatten hierarchy, creating a SCOPE for each module's usage as a cell
    V3Scope::scopeAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("scope.tree"));
    V3LinkDot::linkDotScope(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));

    //--SCOPE BASED OPTIMIZATIONS--------------

    // Cleanup
    V3Const::constifyAll(v3Global.rootp());
    V3Dead::deadifyAll(v3Global.rootp(), false);
    v3Global.checkTree();
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Inline all tasks
    V3Task::taskAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("task.tree"));

    // Add __PVT's
    // After V3Task so task internal variables will get renamed
    V3Name::nameAll(v3Global.rootp());
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("name.tree"));

    // Loop unrolling & convert FORs to WHILEs
    V3Unroll::unrollAll(v3Global.rootp());
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));

    // Convert case statements to if() blocks.  Must be after V3Unknown
    V3Case::caseAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));

    // Push constants across variables and remove redundant assignments
    V3Const::constifyAll(v3Global.rootp());
    if (v3Global.opt.oLife()) {
	V3Life::lifeAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
    }

    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Make large low-fanin logic blocks into lookup tables
    // This should probably be done much later, once we have common logic elimination.
    if (v3Global.opt.oTable()) {
	V3Table::tableAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("table.tree"));
    }

    // Cleanup
    V3Const::constifyAll(v3Global.rootp());
    V3Dead::deadifyAll(v3Global.rootp(), false);
    v3Global.checkTree();
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Detect clock enables and mode into sensitives, and split always based on clocks
    // (so this is a good prelude to splitAlways.)
    if (v3Global.opt.oFlopGater()) {
	V3ClkGater::clkGaterAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clkgater.tree"));
    }

    // Move assignments/sensitives into a SBLOCK for each unique sensitivity list
    // (May convert some ALWAYS to combo blocks, so should be before V3Gate step.)
    V3Active::activeAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("active.tree"));

    // Split single ALWAYS blocks into multiple blocks for better ordering chances
    if (v3Global.opt.oSplit()) {
	V3Split::splitAlwaysAll(v3Global.rootp());
	//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
    }
    V3SplitAs::splitAsAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("splitas.tree"));

    // Create tracing sample points, before we start eliminating signals
    if (v3Global.opt.trace()) {
	V3TraceDecl::traceDeclAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tracedecl.tree"));
    }

    // Gate-based logic elimination; eliminate signals and push constant across cell boundaries
    // Instant propagation makes lots-o-constant reduction possibilities.
    if (v3Global.opt.oGate()) {
	V3Gate::gateAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("gate.tree"));
	// V3Gate calls constant propagation itself.
    } else {
	v3info("Command Line disabled gate optimization with -Og/-O0.  This may cause ordering problems.");
    }

    // Combine COVERINCs with duplicate terms
    if (v3Global.opt.coverage()) {
	V3CoverageJoin::coverageJoin(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("coveragejoin.tree"));
    }

    // Remove unused vars
    V3Const::constifyAll(v3Global.rootp());
    V3Dead::deadifyAll(v3Global.rootp(), true);
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Reorder assignments in pipelined blocks
    if (v3Global.opt.oReorder()) {
	V3Split::splitReorderAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("reorder.tree"));
    }

    // Create delayed assignments
    // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step
    V3Delayed::delayedAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("delayed.tree"));

    // Make Active's on the top level
    // Differs from V3Active, because identical clocks may be pushed down to a module and now be identical
    V3ActiveTop::activeTopAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("activetop.tree"));

    if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");

    // Order the code; form SBLOCKs and BLOCKCALLs
    V3Order::orderAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("order.tree"));

#ifndef NEW_ORDERING
    // Change generated clocks to look at delayed signals
    V3GenClk::genClkAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("genclk.tree"));
#endif

    // Convert sense lists into IF statements.
    V3Clock::clockAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));

    // Cleanup any dly vars or other temps that are simple assignments
    // Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
    if (v3Global.opt.oLife()) {
	V3Const::constifyAll(v3Global.rootp());
	V3Life::lifeAll(v3Global.rootp());
    }
    if (v3Global.opt.oLifePost()) {
	V3LifePost::lifepostAll(v3Global.rootp());
    }
    if (v3Global.opt.oLife() || v3Global.opt.oLifePost()) {
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
    }

    // Remove unused vars
    V3Const::constifyAll(v3Global.rootp());
    V3Dead::deadifyAll(v3Global.rootp(), true);
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

#ifndef NEW_ORDERING
    // Detect change loop
    V3Changed::changedAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("changed.tree"));
#endif

    // Create tracing logic, since we ripped out some signals the user might want to trace
    // Note past this point, we presume traced variables won't move between CFuncs
    // (It's OK if untraced temporaries move around, or vars "effectively" activate the same way.)
    if (v3Global.opt.trace()) {
	V3Trace::traceAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("trace.tree"));
    }

    if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Scoped");

    // Remove scopes; make varrefs/funccalls relative to current module
    V3Descope::descopeAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("descope.tree"));

    //--MODULE OPTIMIZATIONS--------------

    // Split deep blocks to appease MSVC++.  Must be before Localize.
    if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) {
	V3DepthBlock::depthBlockAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("deepblock.tree"));
    }

    // Move BLOCKTEMPS from class to local variables
    if (v3Global.opt.oLocalize()) {
	V3Localize::localizeAll(v3Global.rootp());
    }

    // Icache packing; combine common code in each module's functions into subroutines
    if (v3Global.opt.oCombine()) {
	V3Combine::combineAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("combine.tree"));
    }

    V3Error::abortIfErrors();

    //--GENERATION------------------

    // Remove unused vars
    V3Const::constifyAll(v3Global.rootp());
    V3Dead::deadifyAll(v3Global.rootp(), true);
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));

    // Here down, widthMin() is the Verilog width, and width() is the C++ width
    // Bits between widthMin() and width() are irrelevant, but may be non zero.
    v3Global.assertWidthsSame(false);

    // Make all operations a multiple of 32 bits
    V3Clean::cleanAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clean.tree"));

    // Move wide constants to BLOCK temps.
    V3Premit::premitAll(v3Global.rootp());
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("premit.tree"));

    // Expand macros and wide operators into C++ primitives
    if (v3Global.opt.oExpand()) {
	V3Expand::expandAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("expand.tree"));
    }

    // Propagate constants across WORDSEL arrayed temporaries
    if (v3Global.opt.oSubst()) {
	// Constant folding of expanded stuff
	V3Const::constifyCpp(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
	V3Subst::substituteAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("subst.tree"));
    }
    if (v3Global.opt.oSubstConst()) {
	// Constant folding of substitutions
	V3Const::constifyCpp(v3Global.rootp());

	V3Dead::deadifyAll(v3Global.rootp(), true);
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dead.tree"));
    }

    if (!v3Global.opt.lintOnly()) {
	// Fix very deep expressions
	// Mark evaluation functions as member functions, if needed.
	V3Depth::depthAll(v3Global.rootp());
	//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("depth.tree"));

	// Branch prediction
	V3Branch::branchAll(v3Global.rootp());

	// Add C casts when longs need to become long-long and vice-versa
	// Note depth may insert something needing a cast, so this must be last.
	V3Cast::castAll(v3Global.rootp());
	v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cast.tree"));
    }

    V3Error::abortIfErrors();

    // Output the text
    if (!v3Global.opt.lintOnly()) {
	// emitcInlines is first, as it may set needHInlines which other emitters read
	V3EmitC::emitcInlines();
	V3EmitC::emitcSyms();
	V3EmitC::emitcTrace();
    }
    // Unfortunately we have some lint checks in emitc.
    V3EmitC::emitc();

    // Statistics
    if (v3Global.opt.stats()) {
	V3Stats::statsFinalAll(v3Global.rootp());
	V3Stats::statsReport();
    }

    if (!v3Global.opt.lintOnly()) {
	// Makefile must be after all other emitters
	V3EmitMk::emitmk(v3Global.rootp());
    }
}

//######################################################################

int main(int argc, char** argv, char** env) {
    // General initialization
    ios::sync_with_stdio();

    time_t randseed;
    time(&randseed);
    srand( (int) randseed);

    // Preprocessor
    // Before command parsing so we can handle -Ds on command line.
    V3PreShell::boot(env);

    // Command option parsing
    v3Global.opt.bin(argv[0]);
    string argString = V3Options::argString(argc-1, argv+1);
    v3Global.opt.parseOpts(new FileLine("COMMAND_LINE",0), argc-1, argv+1);
    if (v3Global.opt.coverage() && !v3Global.opt.systemPerl() && !v3Global.opt.lintOnly()) {
	v3fatal("Unsupported: Coverage analysis requires --sp output.");
    }
    if (!v3Global.opt.outFormatOk() && !v3Global.opt.preprocOnly() && !v3Global.opt.lintOnly()) {
	v3fatal("verilator: Need --cc, --sc, --sp, --lint-only or --E option");
    }
    // Check environment
    V3Options::getenvSYSTEMC();
    V3Options::getenvSYSTEMC_ARCH();
    V3Options::getenvSYSTEMPERL();
    V3Options::getenvSYSTEMPERL_INCLUDE();

    V3Error::abortIfErrors();

    // Can we skip doing everything if times are ok?
    V3File::addSrcDepend(v3Global.opt.bin());
    if (v3Global.opt.skipIdentical()
	&& !v3Global.opt.preprocOnly()
	&& !v3Global.opt.lintOnly()
	&& V3File::checkTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__verFiles.dat", argString)) {
	UINFO(1,"--skip-identical: No change to any source files, exiting\n");
	exit(0);
    }

    // Internal tests (after option parsing as need debug() setting)
    V3Graph::test();

    //--FRONTEND------------------

    // Cleanup
    V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.tree");
    V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.dot");
    V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.txt");

    // Read first filename
    v3Global.readFiles();
    //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));

    // Link, etc, if needed
    if (!v3Global.opt.preprocOnly()) {
	process();
    }

    // Final steps
    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",99));
    V3Error::abortIfWarnings();

    if (!v3Global.opt.lintOnly() && v3Global.opt.makeDepend()) {
	V3File::writeDepend(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__ver.d");
    }
    if (!v3Global.opt.lintOnly()
	&& (v3Global.opt.skipIdentical() || v3Global.opt.makeDepend())) {
	V3File::writeTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__verFiles.dat", argString);
    }

#ifdef VL_LEAK_CHECKS
    // Cleanup memory for valgrind leak analysis
    v3Global.clear();
#endif
    FileLine::deleteAllRemaining();

    UINFO(1,"Done, Exiting...\n");
}
