--- /dev/null
+package dol.visitor.cell;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import dol.datamodel.pn.Channel;
+import dol.datamodel.pn.Port;
+import dol.datamodel.pn.Process;
+import dol.datamodel.pn.ProcessNetwork;
+import dol.visitor.PNVisitor;
+import dol.util.CodePrintStream;
+
+/**
+ * This class is a class for a visitor that is used to generate the the OS for
+ * the SPEs.
+ *
+ * @author lschor, 2009-03-24 * Revision: 2009-03-24: Created
+ */
+public class CellSPEVisitor extends PNVisitor {
+
+ /**
+ * Constructor.
+ *
+ * @param dir
+ * path of this file
+ */
+ public CellSPEVisitor(String dir, CellMapping mapping) {
+ _dir = dir;
+ _mapping = mapping;
+ }
+
+ /**
+ * Visit process network.
+ *
+ * @param x
+ * process network that needs to be rendered
+ */
+ public void visitComponent(ProcessNetwork x) {
+ try {
+ // Create a directory where all SPU's are stored:
+ _spuDir = _dir + _delimiter + "spu";
+ File dir = new File(_spuDir);
+ dir.mkdirs();
+
+ // Copy the header file to this directory
+ // Some library files must be copied to the main directory
+ (new File(_dir + _delimiter + "lib" + _delimiter + "spu_os.h"))
+ .renameTo(new File(dir.getPath() + _delimiter
+ + "spu_os.h"));
+
+ ArrayList<Vector<Process>> spuList = _mapping.getSPUList();
+
+ int i = 0;
+ for (Vector<Process> spu : spuList) {
+ createOSLayer(x, spu, i++);
+ }
+
+ createMakefileSPU();
+
+ } catch (Exception e) {
+ System.out.println("CellSPEVisitor: exception occured: "
+ + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Create the makefile for a SPU (so for the layer). Each SPU gets its own
+ * Makefile
+ *
+ * @param spu
+ * SPU for which the Makefile should be used
+ */
+ protected void createMakefileSPU() {
+ try {
+ // Directory of the process
+ String spuDir = _dir + _delimiter + "spu";
+
+ // Create the filename for the new wrapper
+ String filename = spuDir + _delimiter + "Makefile";
+
+ OutputStream file = new FileOutputStream(filename);
+
+ PrintStream _makefilePS = new CodePrintStream(file);
+
+ _makefilePS.println("# Makefile for SPU OS");
+ _makefilePS.println("");
+ _makefilePS.println("src := $(wildcard ../lib/spu/*.cpp)");
+ _makefilePS.println("obj = $(src:.cpp=.o)");
+ _makefilePS.println("");
+
+ // The Makefile must include all o-Files of the processes needed
+ String dependency = "";
+
+ // Go through all possible processes
+ for (Process p : _mapping.getAllSpuBaseProcess()) {
+ dependency += " .." + _delimiter + "spu_"
+ + p.getBasename() + _delimiter + p.getBasename()
+ + "Wrapper.o";
+ }
+
+ _makefilePS.println("all: ${obj}" + dependency);
+ for (int i = 0; i < _mapping.getNrSPE(); i++) {
+ _makefilePS.println("\tspu-g++ -Wall -I .. -I ../lib -o "
+ + "spu_os_" + i + " spu_os_" + i + ".cpp "
+ + "../lib/spu/Fifo.o ../lib/spu/WindowedFifo.o "
+ + "../lib/spu/dolSupport.o "
+ + "../lib/spu/proc_wrapper.o ../lib/spu/common.o "
+ + "../lib/spu/FastCommunication.o" + dependency
+ + " -ftree-vectorize -lm -mtune=cell -O3"
+ + " -fmodulo-sched -funroll-loops "
+ + " -ffast-math -fno-rtti -ffunction-sections"
+ + " -fdata-sections -Wl,--gc-sections");
+ }
+ _makefilePS.println();
+ _makefilePS.println("clean: ");
+ for (int i = 0; i < _mapping.getNrSPE(); i++) {
+ _makefilePS.println("\trm spu_os_" + i);
+ }
+ _makefilePS.println();
+ _makefilePS.println("%.o : ");
+ _makefilePS.println("\tspu-g++ -c -o $(*D)/$(*F).o "
+ + "$(*D)/$(*F).cpp -I .. -I"
+ + " ../lib -ftree-vectorize -mtune=cell -O3"
+ + " -fmodulo-sched -funroll-loops -ffast-math"
+ + " -fno-rtti -ffunction-sections -fdata-sections");
+ _makefilePS.println();
+ } catch (FileNotFoundException e) {
+ System.out.println("CbeProcessVisitor - Makefile: exception "
+ + "occured: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Creates the OS layer for one SPU
+ *
+ * @param spu
+ * List of all processes a SPU gets
+ * @param index
+ * index of the SPU in the SPU list
+ */
+ protected void createOSLayer(ProcessNetwork x, Vector<Process> spu,
+ int index) {
+ try {
+ // Create the filename for the new layer
+ String filename = _spuDir + _delimiter + "spu_os_" + index
+ + ".cpp";
+
+ // PrintStream for writing to the file
+ OutputStream file = new FileOutputStream(filename);
+ CodePrintStream _code = new CodePrintStream(file);
+
+ _code.println("/****************************************************************");
+ _code.println(" * SPU OS file");
+ _code.println(" * Description: OS for one SPU");
+ _code.println(" */");
+ _code.println();
+ _code.println("#include \"spu_os.h\"");
+
+ // Must include all possible wrappers
+ Vector<String> pList = new Vector<String>();
+ // Go through all possible processes
+ for (Process p : spu) {
+ String basename = p.getBasename();
+ if (!pList.contains(basename)) {
+ pList.add(basename);
+ _code.println("#include \".." + _delimiter + "spu_"
+ + p.getBasename() + _delimiter
+ + p.getBasename() + "Wrapper.h\"");
+ }
+ }
+
+ _code.println("");
+ _code.println("// Main application");
+ _code.println("int main(int speid , uint64_t argp)");
+ _code.println("{");
+ _code.println(" // reserve DMA tag ID");
+ _code.println(" uint32_t tag_id;");
+ _code.println(" if((tag_id=mfc_tag_reserve())==MFC_TAG_INVALID){");
+ _code.println(" printf(\"SPE: ERROR - can't reserve a tag ID\"); return 1;");
+ _code.println(" }");
+ _code.println(" ");
+ _code.println(" // Get the context information for the whole system");
+ _code.println(" mfc_get((void*) &ctx_spu, argp, sizeof(ctx_spu), tag_id, 0, 0);");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println(" ");
+ _code.println(" // This is the number of processes of this SPE");
+ _code.println(" uint64_t nr_proc = ctx_spu.procContentsLen;");
+ _code.println(" ");
+ _code.println(" // Get the addresses of the contexts for the Processes");
+ _code.println(" uint64_t context_addr[nr_proc];");
+ _code.println(" mfc_get((void*)context_addr, ctx_spu.procContents, sizeof(uint64_t) * roundDMA(nr_proc), tag_id,0,0);");
+ _code.println(" ");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println(" ");
+ _code.println(" int32_t queueFromSPU[roundDMA(NUM_FIFO)] __attribute__ ((aligned(16)));");
+ _code.println(" int32_t queueOnSPU[roundDMA(NUM_FIFO)] __attribute__ ((aligned(16)));");
+ _code.println(" uint64_t tailAddresses[roundDMA(NUM_FIFO)] __attribute__ ((aligned(16)));");
+ _code.println(" ");
+ _code.println(" mfc_get((void*)queueFromSPU, ctx_spu.queueFromSPU, sizeof(int32_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println(" ");
+ _code.println(" mfc_get((void*)queueOnSPU, ctx_spu.queueOnSPU, sizeof(int32_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println("");
+ _code.println(" // Get the base addresses");
+ _code.println(" uint64_t procContentsAll[roundDMA(NUM_SPES)] __attribute__ ((aligned(16)));");
+ _code.println(" ");
+ _code.println(" mfc_get((void*)procContentsAll, ctx_spu.procContentsAll, sizeof(uint64_t) * roundDMA(NUM_SPES), tag_id,0,0);");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println(" ");
+ _code.println(" // Read the base address");
+ _code.println(" uint64_t ea_base = ctx_spu.ea_base;");
+ _code.println(" ");
+
+ Vector<Channel> channelList = new Vector<Channel>();
+ int indx = 0;
+ // instantiate channels
+ for (Channel c : x.getChannelList()) {
+ if (spu.contains(c.getOrigin())
+ || spu.contains(c.getTarget())) {
+ channelList.add(c);
+ if (c.getType().equals("fifo")) {
+ _code.printPrefixln(" Fifo " + c.getName() + "("
+ + "FIFO_SIZE[" + indx + "]);");
+ } else if (c.getType().equals("wfifo")) {
+ _code.printPrefixln(" WindowedFifo "
+ + c.getName() + "(" + "FIFO_SIZE[" + indx
+ + "]);");
+ }
+ }
+ indx++;
+ }
+
+ _code.println();
+
+ // Go through all processes
+ for (Process p : spu) {
+ // Create the process wrapper
+ _code.println(" " + p.getBasename() + "Wrapper *" + p.getName() +";");
+ _code.println(" try { "
+ + p.getName() + " = new " + p.getBasename()
+ + "Wrapper (context_addr[" + spu.indexOf(p)
+ + "]); }");
+ _code.println(" catch(std::bad_alloc &e) {");
+ _code.println(" fprintf(stderr, \"[" + p.getBasename() +"Wrapper] Memory allocation failure\\n\");");
+ _code.println(" exit(1);");
+ _code.println(" }");
+
+ // Create the port-mapping
+ for (Port port : p.getPortList()) {
+ if (port.getName().equals(port.getBasename())) {
+ _code.printPrefixln(" " + p.getName() + "->_port"
+ + port.getName() + "Fifo = &"
+ + port.getPeerResource().getName() + ";");
+ } else {
+ _code.printPrefix(" " + p.getName() + "->_port"
+ + port.getBasename() + "Fifo");
+ StringTokenizer tokenizer = new StringTokenizer(
+ port.getName().replaceFirst(
+ port.getBasename(), ""), "_");
+ while (tokenizer.hasMoreTokens()) {
+ _code.print("[" + tokenizer.nextToken() + "]");
+ }
+ _code.println(" = &"
+ + port.getPeerResource().getName() + ";");
+ }
+ }
+ _code.println();
+ }
+
+ // Count the effected channels
+ int countChannels = 0;
+ for (Channel c : channelList) {
+ if (spu.contains(c.getOrigin())
+ && spu.contains(c.getTarget())) {
+ continue;
+ } else if (spu.contains(c.getOrigin()))
+ countChannels++;
+ else if (spu.contains(c.getTarget()))
+ countChannels++;
+ else
+ System.out.println("ERROR! Channel Mapping is wrong.");
+ }
+
+ _code.println(" // inited all queues, now one has to know:");
+ _code.println(" // sends out the start addresses to the SPU (of all out channels)");
+
+ // Check all out queues on the SPU
+ _code.println(" uint32_t queuemessage;");
+ for (Channel c : channelList) {
+ if (spu.contains(c.getOrigin()) && !spu.contains(c.getTarget())) {
+ _code.println(" queuemessage = CREATEQUEUEMESSAGE(" + x.getChannelList().indexOf(c) + ", (uint32_t)" + c.getName() + ".getQueuePointer());");
+ _code.println(" spu_write_out_mbox(queuemessage);");
+ }
+ }
+
+ _code.println(" ");
+ _code.println(" // Wait until we get the okey to read the tail pointers");
+ _code.println(" uint32_t messageIn = spu_read_in_mbox();");
+ _code.println("");
+ _code.println(" mfc_get((void*)tailAddresses, ctx_spu.fifoTails, sizeof(uint64_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
+ _code.println(" mfc_write_tag_mask(1<<tag_id);");
+ _code.println(" mfc_read_tag_status_all();");
+ _code.println(" FastCommunication * com;");
+ _code.println(" try { com = new FastCommunication("
+ + countChannels + ", ea_base, procContentsAll, queueFromSPU, queueOnSPU, tailAddresses); }");
+ _code.println(" catch(std::bad_alloc &e) {");
+ _code.println(" fprintf(stderr, \"[FastCommunication] Memory allocation failure\\n\");");
+ _code.println(" exit(1);");
+ _code.println(" }");
+
+ String channelTyp = "";
+ int i = 0;
+ for (Channel c : channelList) {
+ if (spu.contains(c.getOrigin())
+ && spu.contains(c.getTarget())) {
+ // Local channels have no influence on external
+ // communication (should be Windowed Fifos...)
+ channelTyp = "local";
+ continue;
+ } else if (spu.contains(c.getOrigin()))
+ channelTyp = "out";
+ else if (spu.contains(c.getTarget()))
+ channelTyp = "in";
+ else
+ System.out.println("ERROR! Channel Mapping is wrong.");
+
+ if (c.getType().equals("fifo")) {
+ _code.println(" com->addFifo(" + (i) + ", &"
+ + c.getName() + ", com->" + channelTyp + ", "
+ + x.getChannelList().indexOf(c) + ");");
+ }
+ else if (c.getType().equals("wfifo")) {
+ _code.println(" com->addWFifo(" + (i) + ", &"
+ + c.getName() + ", com->" + channelTyp + ", "
+ + x.getChannelList().indexOf(c) + ");");
+ }
+ i++;
+ }
+
+ // The scheduler (yes, this could be optimized...)
+ _code.println("");
+ _code.println(" printf(\"SPU " + index + ": start to execute\\n\"); ");
+ _code.println("");
+ _code.println(" bool allBlocked = false;");
+ _code.println(" while (!allBlocked)");
+ _code.println(" {");
+ _code.println(" allBlocked = true;");
+ for (Process p : spu) {
+ _code.println(" if (!" + p.getName()
+ + "->isDetached())");
+ _code.println(" {");
+ _code.println(" " + p.getName() + "->fire();");
+ _code.println(" allBlocked = false;");
+ _code.println(" }");
+
+ // communication only if this process needs some communication
+ for (Channel c : channelList) {
+ // the channel may go away
+ if (!spu.contains(c.getOrigin()) || !spu.contains(c.getTarget())) {
+ if (c.getOrigin().equals(p) || c.getTarget().equals(p)) {
+ _code.println(" com->update();");
+ break;
+ }
+ }
+ }
+ _code.println();
+ }
+ _code.println(" }");
+ _code.println();
+
+ // End --> wait until all communications are finished
+ _code
+ .println(" // Are there any open communication requests?");
+ _code.println(" while (!com->empty())");
+ _code.println(" {");
+ _code.println(" com->update();");
+ _code.println(" }");
+
+ for (Process p : spu) {
+ _code.println(" delete " + p.getName() + ";");
+ }
+
+ _code.println(" delete com;");
+ _code.println(" ");
+ _code.println(" // release tag ID before exiting");
+ _code.println(" mfc_tag_release(tag_id);");
+ _code.println(" ");
+ _code.println(" uint32_t message = CREATEFASTMESSAGE(SPE_COMPLETE, 0, 0);");
+ _code.println(" spu_write_out_mbox(message);");
+ _code.println(" ");
+ _code.println(" messageIn = spu_read_in_mbox();");
+ _code.println("}");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected String _spuDir = null;
+ protected CodePrintStream _mainPS = null;
+ protected String _dir = null;
+ protected CellMapping _mapping = null;
+}