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;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,
IntState loopingLevel;
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,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
const char* end = "", const char* cont = NULL);
comment
method.
virtual StringList comment(const char* cmt, const char* begin =This public method generates a comment from a specified string
NULL, const char* end = "", const char* cont = NULL);
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);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.
void endIteration(int numiter, int depth);
virtual void wormInputCode();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
virtual void wormOutputCode();
virtual void wormInputCode(PortHole& p);
virtual void wormOutputCode(PortHole& p);
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();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.
virtual int receiveWormData();
virtual int sendWormData(PortHole& p);
virtual int receiveWormData(PortHole& p);
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.
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.
static int haltRequested();Returns TRUE if error is signaled while Ptolemy is running.
int inWormhole();Is a standard
int isA(const char* class);
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();These methods compile and load the code, and run the target. The base class, generates error messages.
virtual int loadCode();
virtual int runCode();
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);In case loop scheduling is taken, we may want to perform loop initialization routines for stars inside each loop. These methods call
void genLoopEnd(Star& s);
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.
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;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
StringList sanitizedName(const NamedObj& b) const;
virtual StringList sanitizedFullName(const NamedObj& b) const;
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);If the
void endIteration(int repetitions, int depth);
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.