Top Up Prev Next Bottom Contents Index Search

17.1 Class CGTarget


Class CGTarget is derived from class Target. It has a four-argument constructor.

CGTarget(const char* name, const char* starclass, 
	const char* desc, char sep); 
The first argument is the name of the target and the second argument is the star class that this target can support. The third argument is the description of this target. The last one is a separator character for unique symbol generation.

There are two protected states in the CGTarget:

StringState destDirectory; 
IntState loopingLevel;
The first state indicates where to put the code file. The second state determines which scheduler is used in case this target is a single processor target. By default, loopingLevel = 0 and we do not try looping. If loopingLevel = 1, we select Joe's loop scheduler. Otherwise, we use the most complicated loop scheduler.

At the top level, three methods of the Target class are called in sequence: setup, run, and wrapup.

void setup(); 
In this method, we do the following tasks:

(1) Initialize myCode and procedure code stream.

(2) Select a scheduler if no scheduler is selected yet.

At this stage, we check whether the galaxy is assigned or not. In multiprocessor targets, a child target is not assigned a galaxy until a sub-univers is created. If the galaxy is not assigned, return.

(3) Reset the symbol lists.

(4) If we are the top-level target, initialize the galaxy (which performs preinitialization and initialization of the member blocks, including HOF star expansion and porthole type resolution). Then modify the galaxy if necessary by calling modifyGalaxy. The base class implementation of modifyGalaxy splices in type conversion stars where needed, if the domain has supplied a table of type conversion stars. (If there is no table, type conversion is presumed not needed. If there is a table, and a type mismatch is found that the table has no entry to fix, then an error is reported.) Some derived domains redefine modifyGalaxy to perform additional transformations. For example, in AsmTarget we insert some stars (CircToLin, LinToCirc) at loop boundaries to change the type of buffer addressing in case a loop scheduling is performed.

virtual int modifyGalaxy(); 
Is a protected method.

(5) If it is a child target, the schedule was already made at this stage from a parallel scheduler of the parent multiprocessor target. Otherwise, we initialize and schedule the graph.

(6) If it is a child target or it is not inside a wormhole, return. Otherwise, we first adjust the sample rate of the wormhole portholes (adjustSampleRates). Then, we generate and download code: generateCode and wormLoadCode.

void adjustSampleRates(); 
This method is a protected method to be called when this target is inside a wormhole. After scheduling is performed, we need to multiply the sample rate of wormhole portholes by the repetition count of the stars inside the wormhole connected to the porthole.

virtual void generateCode(); 
This method guides the overall procedure to generate code for single processor targets. The procedure is as follows:

(1) If this target is a child target, call setup to initialize the variables. Copy the symbol counter (symbolCounter) of the parent target to the symbol counter of this target to achieve a unique symbol in the system scope.

(2) We compute buffer sizes, allocate memory, etc: allocateMemory.

virtual int allocateMemory(); 
This method is protected. It does nothing and returns TRUE in this base class.

(3) Call the method generateCodeStreams(). This method will be described later.

(4) Organize the CodeStreams into a single code stream and save the result to the myCode stream: frameCode.

virtual void frameCode(); 
This method is a protected method. It does nothing in this base class.

(5) If this target is not a child target, write the generated code to a file: writeCode.

virtual void writeCode(const char* name = NULL); 
This is a public method to write the myCode stream to the argument file. If no argument is given, use "code.output" as the default file name.

(6) If it is a child target, copy the symbol counter to that of the parent target.

The methods described above for code generation are all virtual methods. They will be redefined in the derived targets.

The method

void CGTarget::generateCodeStreams(); 
does the following things:

(1) Write initial code.

virtual void headerCode(); 
In this base class, this protected method writes the header comment to the myCode CodeStream.

virtual StringList headerComment(const char* begin = NULL,
const char* end = "", const char* cont = NULL);
This method is a public virtual method to generate the header comment in the code. In this base class, the head comments include the user id, code creation date, target name, and the galaxy name. The arguments are passed to the comment method.

virtual StringList comment(const char* cmt, const char* begin = 
NULL, const char* end = "", const char* cont = NULL);
This public method generates a comment from a specified string cmt. We prepend begin and append end to the string. If begin is NULL, we prepend '#' as a shell-stype comment. If cont is specified, multi-line comments are supported.

(2) We do initialization for code generation: for example, compute offsets of portholes and call initCode methods of stars: codeGenInit.

virtual int codeGenInit(); 
is a protected method. It does nothing and returns TRUE in this base class.

(3) Generate the code for the main loop: mainLoopCode.

virtual void mainLoopCode(); 
In this method we first compute the number of iterations. If this target is inside a wormhole, the number is -1 indicating an infinite loop. Otherwise, the stopTime of the scheduler determines the number of iterations. In this base class, we call the following five methods sequentially: beginIteration, wormInputCode if inside a wormhole, compileRun, wormOutputCode if inside a wormhole, and endIteration. In the derived class, this sequence may be changed .

void beginIteration(int numiter, int depth); 
void endIteration(int numiter, int depth);
These public methods form the head or ending of the main loop. The arguments of both methods are the number of iteration and the depth of the loop. In the main loop, the depth is set 0.

virtual void wormInputCode();
virtual void wormOutputCode();
virtual void wormInputCode(PortHole& p);
virtual void wormOutputCode(PortHole& p);
The above methods are all public. They generate code at the wormhole boundary if the target resides in a wormhole. The last two methods generate code for the argument porthole that is at the wormhole boundary. In this base class, put comments in myCode CodeStream indicating that the methods are successfully executed. They should be redefined in the derived classes to be useful. The first two methods traverse all portholes at the wormhole boundary to use the last two methods.

virtual void compileRun(SDFScheduler* sched); 
This protected method calls compileRun of the argument scheduler. By default, this method calls go methods of all stars in the scheduled order to generate code in myCode CodeStream.

(4) Call wrapup methods of stars to generate code after the main loop, but still inside the main function.

(5) Add more code if necessary: trailerCode

virtual void trailerCode(); 
This protected method does nothing in this base class.

The method

virtual int wormLoadCode(); 
is protected. It downloads code to the target machine and starts executing it if the target resides in a wormhole. In this base class, we just display the code.

Now, we discuss the run method.

int run(); 
If the target is not inside a wormhole, it generates code by calling generateCode as explained above. Otherwise, we do the transfer of data to and from the target since this method will be called when the wormhole is executed: sendWormData and receiveWormData in sequence.

virtual int sendWormData(); 
virtual int receiveWormData();
virtual int sendWormData(PortHole& p);
virtual int receiveWormData(PortHole& p);
The above methods are all protected. They send and receive samples to this target when run inside a wormhole. The argument is the porthole of the interior star at the wormhole boundary. If no argument is given, send and receive for all the appropriate portholes. In this base class, we generate comments to indicate that these methods are successfully called.

void wrapup(); 
In derived classes, wrapup will generate code to finalize, download, and run the code. This CGTarget class just displays the code.

So far, we have explained the three top level methods of the CGTarget class. Methods related to the CodeStream and unique symbol generations can be found in the previous chapter. We will describe the remaining members.

17.1.1 Other CGTarget protected members

char* schedFileName; 
The name of the log file in case a loop scheduling is taken. By default, the name is set to "schedule.log".

int noSchedule; 
This is a flag to be set to TRUE if scheduling is not needed in the setup stage. This flag will be set when the schedule is copied from copySchedule method in parallel code generation. By default, this flag is set FALSE.

StringList indent(int depth); 
This method returns a list of spaces for indenting. The number of spaces is 4 per each depth.

void switchCodeStream(Block* b, CodeStream* s); 
This method is set to the current myCode pointer of the argument block b to s CodeStream. If b is a galaxy, perform this for all component stars.

17.1.2 Other CGTarget public members

static int haltRequested(); 
Returns TRUE if error is signaled while Ptolemy is running.

int inWormhole(); 
int isA(const char* class);
Is a standard isA method for type identification.

Returns TRUE or FALSE, based on whether the target is inside a wormhole or not.

Block* makeNew() const; 
Create a new, identical CGTarget. Internal variables are not copied.

virtual int incrementalAdd(CGStar* s, int flag = 1); 
This method is called when we add code for the argument star s incrementally. If flag is 1 (default), we allocate memory for the star, and call setup, initCode, go, and wrapup of the star. If flag is 0, we just call go method of that star. In this base class, generate an error message.

virtual int insertGalaxyCode(galaxy* g, SDFScheduler* sched); 
This method inserts the code for the argument galaxy g incrementally. We have to allocate resources and generate initialization, main loop, and wrapup code. It is used to generate code for the galaxy inside a dynamic construct. A dynamic construct is a wormhole in the code generation domain. When we call the go method of the wormhole, we generate code for the inside galaxy.

virtual int compileCode(); 
virtual int loadCode();
virtual int runCode();
These methods compile and load the code, and run the target. The base class, generates error messages.

void writeFiring(Star& s, int depth); 
This method generates code for a firing of the argument star. The base class simply executes run of the star.

void genLoopInit(Star& s, int reps);
void genLoopEnd(Star& s);
In case loop scheduling is taken, we may want to perform loop initialization routines for stars inside each loop. These methods call beginLoop and endLoop methods of the argument star.

void copySchedule(SDFSchedule& sched); 
If this is a child target, the schedule is inherited from the parallel scheduling of the parent target. This method copies the argument schedule to the schedule of this target and set noSchedule flag.

virtual int systemCall(const char* cmd, const char* error = NULL, const char* host ="localhost"); 
This method makes a system call using rshSystem utility function. If error is specified and the system call is unsuccessful, display the error message.

void amInherited(); 
This method declares that this target is inherited from other targets.

virtual int support(Star* s); 
Returns TRUE if this target allows the argument star; returns FALSE otherwise.

virtual int execTime(DataFlowStar* s, CGTarget* t = 0); 
We return the execution time of the argument star s in the argument target t. In a heterogeneous system, execution time of a given star may vary depending on which target executes the star. In this base class, we just call myExecTime method of the star.

17.1.3 Class HLLTarget

Class HLLTarget, derived from CGTarget class, is a base class of all high level language code generation targets. There is AsmTarget class for the base target of all assembly code generation targets. Since we will illustrate the C code generation target, we will explain the HLLTarget class only in this subsection.

HLLTarget class has a constructor with three arguments as CGTarget class. In this base class, we provide some methods to generate C++ code. The following three protected methods are defined to create a C++ identifier, derived from the actual name.

StringList sanitize(const char* s) const; 
StringList sanitizedName(const NamedObj& b) const;
virtual StringList sanitizedFullName(const NamedObj& b) const;
The first method takes a string argument and modifies it with a valid C++ identifier. If the string contains a non-alphanumeric character, it will replace it with '_'. If the string starts with a number, it prepends 'x' at the beginning. The second method calls the first method with the name of the argument object. The third method generates an identifier for the argument object that will be placed in struct data structure. Therefore, we put '.' between the object name and its parent name.

Some public methods are defined.

void beginIteration(int repetitions, int depth); 
void endIteration(int repetitions, int depth);
If the repetitions is negative, we print a while loop with infinite repetition. Otherwise, we generate a for loop. The second argument depth determines the amount of indent we put in front of the code.

void wrapup(); 
Saves the generated code to "code.output" file name.

Since this target is not an actual target, it has a pure virtual method: makeNew.



Top Up Prev Next Bottom Contents Index Search

Copyright © 1990-1997, University of California. All rights reserved.