/* * Copyright (c) 2012, IRISA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of IRISA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.backends.llvm.tta.architecture.util; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import net.sf.orcc.OrccRuntimeException; import net.sf.orcc.backends.llvm.tta.architecture.ArchitectureFactory; import net.sf.orcc.backends.llvm.tta.architecture.Bus; import net.sf.orcc.backends.llvm.tta.architecture.ExprBinary; import net.sf.orcc.backends.llvm.tta.architecture.ExprUnary; import net.sf.orcc.backends.llvm.tta.architecture.Extension; import net.sf.orcc.backends.llvm.tta.architecture.FuPort; import net.sf.orcc.backends.llvm.tta.architecture.FunctionUnit; import net.sf.orcc.backends.llvm.tta.architecture.GlobalControlUnit; import net.sf.orcc.backends.llvm.tta.architecture.Guard; import net.sf.orcc.backends.llvm.tta.architecture.Memory; import net.sf.orcc.backends.llvm.tta.architecture.OpBinary; import net.sf.orcc.backends.llvm.tta.architecture.OpUnary; import net.sf.orcc.backends.llvm.tta.architecture.Operation; import net.sf.orcc.backends.llvm.tta.architecture.Processor; import net.sf.orcc.backends.llvm.tta.architecture.Reads; import net.sf.orcc.backends.llvm.tta.architecture.RegisterFile; import net.sf.orcc.backends.llvm.tta.architecture.Resource; import net.sf.orcc.backends.llvm.tta.architecture.Segment; import net.sf.orcc.backends.llvm.tta.architecture.ShortImmediate; import net.sf.orcc.backends.llvm.tta.architecture.Socket; import net.sf.orcc.backends.llvm.tta.architecture.Term; import net.sf.orcc.backends.llvm.tta.architecture.TermBool; import net.sf.orcc.backends.llvm.tta.architecture.TermUnit; import net.sf.orcc.backends.llvm.tta.architecture.Writes; import net.sf.orcc.util.DomUtil; import net.sf.orcc.util.OrccLogger; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * @author Herve Yviquel * */ public class AdfParser { private ArchitectureFactory factory = ArchitectureFactory.eINSTANCE; private Processor processor; private Map<String, Memory> memoryMap; private Map<FunctionUnit, String> fuToMemoryMap; private String romName; private Map<TermBool, String> termToRfMap; private Operation getOperation(Element element, EList<FuPort> ports) { Operation op = factory.createOperation(); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("name")) { op.setName(DomUtil.getNodeValue(child)); } else if (name.equals("bind")) { int index = DomUtil.getNodeIntAttr("name", child); FuPort port = getPort(ports, DomUtil.getNodeValue(child)); op.getPortToIndexMap().put(port, index); } else if (name.equals("pipeline")) { op.getPipeline().addAll(getPipeline(child)); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } return op; } private FuPort getPort(Element element) { FuPort port = factory.createFuPort(); port.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("width")) { int width = DomUtil.getNodeIntValue(child); port.setWidth(width); } else if (name.equals("triggers")) { port.setTrigger(true); } else if (name.equals("sets-opcode")) { port.setOpcodeSelector(true); } else if (name.equals("connects-to")) { // TODO } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } return port; } private ShortImmediate getShortImmediate(Element element) { ShortImmediate shortImmediate = factory.createShortImmediate(); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("width")) { int width = DomUtil.getNodeIntValue(child); shortImmediate.setWidth(width); } else if (name.equals("extension")) { Extension extension = Extension .get(DomUtil.getNodeValue(child)); shortImmediate.setExtension(extension); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } return shortImmediate; } private Segment getSegment(Element element) { Segment segment = factory.createSegment(); return segment; } private Guard getGuard(Element element) { Element child = DomUtil.getFirstElementChild(element); String name = child.getNodeName(); if (name.equals("simple-expr") || name.equals("inverted-expr")) { return getExprUnary(child); } else if (name.equals("and-expr") || name.equals("or-expr")) { return getExprBinary(child); } else if (name.equals("always-true")) { return factory.createExprTrue(); } else if (name.equals("always-false")) { return factory.createExprFalse(); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } } private Term getTerm(Element element) { String name = element.getNodeName(); if (name.equals("bool")) { TermBool term = factory.createTermBool(); Element child = DomUtil.getFirstElementChild(element); String rfName = DomUtil.getNodeValue(child); termToRfMap.put(term, rfName); child = DomUtil.getNextElementSibling(child); int index = DomUtil.getNodeIntValue(child); term.setIndex(index); return term; } else if (name.equals("unit")) { TermUnit term = factory.createTermUnit(); // TODO return term; } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } } private EList<net.sf.orcc.backends.llvm.tta.architecture.Element> getPipeline( Element element) { EList<net.sf.orcc.backends.llvm.tta.architecture.Element> pipeline = new BasicEList<net.sf.orcc.backends.llvm.tta.architecture.Element>(); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("reads")) { Reads reads = factory.createReads(); reads.setStartCycle(DomUtil.getChildIntValue("start-cycle", child)); reads.setCycles(DomUtil.getChildIntValue("cycles", child)); pipeline.add(reads); } else if (name.equals("writes")) { Writes writes = factory.createWrites(); writes.setStartCycle(DomUtil.getChildIntValue("start-cycle", child)); writes.setCycles(DomUtil.getChildIntValue("cycles", child)); pipeline.add(writes); } else if (name.equals("resource")) { Resource resource = factory.createResource(); pipeline.add(resource); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } return pipeline; } private ExprUnary getExprUnary(Element element) { ExprUnary expr = factory.createExprUnary(); String name = element.getNodeName(); if (name.equals("simple-expr")) { expr.setOperator(OpUnary.SIMPLE); } else if (name.equals("inverted-expr")) { expr.setOperator(OpUnary.INVERTED); } Term term = getTerm(DomUtil.getFirstElementChild(element)); expr.setTerm(term); return expr; } private ExprBinary getExprBinary(Element element) { ExprBinary expr = factory.createExprBinary(); String name = element.getNodeName(); if (name.equals("and-expr")) { expr.setOperator(OpBinary.AND); } else if (name.equals("or-expr")) { expr.setOperator(OpBinary.OR); } Element child = DomUtil.getFirstElementChild(element); ExprUnary e1 = getExprUnary(child); child = DomUtil.getNextElementSibling(child); ExprUnary e2 = getExprUnary(child); expr.setE1(e1); expr.setE2(e2); return expr; } private void parseAddressSpace(Element element) { Memory memory = factory.createMemory(); String memName = DomUtil.getNodeAttr("name", element); memory.setName(memName); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("width")) { int width = DomUtil.getNodeIntValue(child); memory.setWordWidth(width); } else if (name.equals("min-address")) { int min = DomUtil.getNodeIntValue(child); memory.setMinAddress(min); } else if (name.equals("max-address")) { int max = DomUtil.getNodeIntValue(child); memory.setMinAddress(max); } else if (name.equals("numerical-id")) { // FIXME: Something to do ? } else if (name.equals("shared-memory")) { throw new OrccRuntimeException( "Parsing ADF with shared memory is not supported"); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } memoryMap.put(memName, memory); } /** * Parses the given document as an architecture description file (ADF). * * @param doc * a DOM document that supposedly represent an XDF network */ private void parseADF(Document doc) throws OrccRuntimeException { Element adfElement = doc.getDocumentElement(); if (!adfElement.getNodeName().equals("adf")) { throw new OrccRuntimeException("Expected \"adf\" start element"); } processor = ArchitectureFactory.eINSTANCE.createProcessor(); memoryMap = new HashMap<String, Memory>(); fuToMemoryMap = new HashMap<FunctionUnit, String>(); termToRfMap = new HashMap<TermBool, String>(); parseBody(adfElement); } /** * Parses the body of the ADF document. The body can contain any element * among the supported elements. Supported elements are: Bus, Socket, * Function-unit, Global-control-unit, Address-space and Register-file. * * @param root */ private void parseBody(Element root) { Element element = DomUtil.getFirstElementChild(root); while (element != null) { String name = element.getNodeName(); if (name.equals("bus")) { parseBus(element); } else if (name.equals("socket")) { parseSocket(element); } else if (name.equals("function-unit")) { parseFU(element); } else if (name.equals("global-control-unit")) { parseGCU(element); } else if (name.equals("address-space")) { parseAddressSpace(element); } else if (name.equals("register-file")) { parseRF(element); } else if (name.equals("immediate-unit")) { // TODO } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } element = DomUtil.getNextElementSibling(element); } // Connect local memories for (FunctionUnit fu : fuToMemoryMap.keySet()) { String name = fuToMemoryMap.get(fu); Memory memory = memoryMap.get(name); if (memory == null) { OrccLogger.severeln("Unknow address space \"" + name + "\"."); } processor.getLocalRAMs().add(memory); fu.setAddressSpace(memory); } // Connect rom Memory memory = memoryMap.get(romName); if (memory == null) { OrccLogger.severeln("Unknow address space \"" + romName + "\"."); } processor.setROM(memory); processor.getGcu().setAddressSpace(memory); for (TermBool term : termToRfMap.keySet()) { term.setRegister(processor.getRegisterFile(termToRfMap.get(term))); } } private void parseBus(Element element) { Bus bus = factory.createBus(); bus.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("width")) { int width = DomUtil.getNodeIntValue(child); bus.setWidth(width); } else if (name.equals("guard")) { bus.getGuards().add(getGuard(child)); } else if (name.equals("segment")) { bus.getSegments().add(getSegment(child)); } else if (name.equals("short-immediate")) { bus.setShortImmediate(getShortImmediate(child)); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } processor.getBuses().add(bus); } private void parseFU(Element element) { FunctionUnit fu = factory.createFunctionUnit(); fu.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("port")) { fu.getPorts().add(getPort(child)); } else if (name.equals("operation")) { fu.getOperations().add(getOperation(child, fu.getPorts())); } else if (name.equals("address-space")) { String asName = DomUtil.getNodeValue(child); if (!asName.isEmpty()) { fuToMemoryMap.put(fu, DomUtil.getNodeValue(child)); } } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } processor.getFunctionUnits().add(fu); } private void parseGCU(Element element) { GlobalControlUnit gcu = factory.createGlobalControlUnit(); gcu.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("port")) { gcu.getPorts().add(getPort(child)); } else if (name.equals("special-port")) { gcu.getPorts().add(getPort(child)); } else if (name.equals("ctrl-operation")) { gcu.getOperations().add(getOperation(child, gcu.getPorts())); } else if (name.equals("address-space")) { romName = DomUtil.getNodeValue(child); } else if (name.equals("delay-slots")) { int delay = DomUtil.getNodeIntValue(child); gcu.setDelaySlots(delay); } else if (name.equals("guard-latency")) { int latency = DomUtil.getNodeIntValue(child); gcu.setDelaySlots(latency); } else if (name.equals("return-address")) { FuPort port = gcu.getPort(DomUtil.getNodeValue(child)); gcu.setReturnAddress(port); } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } processor.setGcu(gcu); } /** * Parses the file given to the constructor of this class. * * @return a processor */ public Processor parseProcessor(InputStream inputStream) { try { // input Document document = DomUtil.parseDocument(inputStream); // parse the input, return the network parseADF(document); return processor; } finally { try { inputStream.close(); } catch (IOException e) { throw new OrccRuntimeException( "I/O error when parsing processor", e); } } } private void parseRF(Element element) { RegisterFile rf = factory.createRegisterFile(); rf.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("width")) { int width = DomUtil.getNodeIntValue(child); rf.setWidth(width); } else if (name.equals("size")) { int size = DomUtil.getNodeIntValue(child); rf.setSize(size); } else if (name.equals("max-reads")) { int maxReads = DomUtil.getNodeIntValue(child); rf.setMaxReads(maxReads); } else if (name.equals("max-writes")) { int maxWrites = DomUtil.getNodeIntValue(child); rf.setMaxWrites(maxWrites); } else if (name.equals("port")) { rf.getPorts().add(getPort(child)); } else if (name.equals("type")) { // FIXME: Something to do... } else if (name.equals("guard-latency")) { // FIXME: Something to do... } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } processor.getRegisterFiles().add(rf); } private void parseSocket(Element element) { Socket socket = factory.createSocket(); socket.setName(DomUtil.getNodeAttr("name", element)); Element child = DomUtil.getFirstElementChild(element); while (child != null) { String name = child.getNodeName(); if (name.equals("writes-to")) { // TODO } else if (name.equals("reads-from")) { // TODO } else { throw new OrccRuntimeException("invalid node \"" + name + "\""); } child = DomUtil.getNextElementSibling(child); } processor.getSockets().add(socket); } private FuPort getPort(EList<FuPort> ports, String name) { for (FuPort port : ports) { if (port.getName().equals(name)) { return port; } } return null; } }