dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / CellSPEVisitor.java
diff --git a/dol/src/dol/visitor/cell/CellSPEVisitor.java b/dol/src/dol/visitor/cell/CellSPEVisitor.java
new file mode 100644 (file)
index 0000000..a8061ec
--- /dev/null
@@ -0,0 +1,416 @@
+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;
+}