/******************************************************************************* * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package hr.fer.zemris.vhdllab.applets.editor.schema2.model; import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EComponentType; import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.NotImplementedException; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponent; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponentCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWireCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IVHDLSegmentProvider; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.PlacedComponent; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaPort; import hr.fer.zemris.vhdllab.service.ci.CircuitInterface; import hr.fer.zemris.vhdllab.service.ci.Port; import hr.fer.zemris.vhdllab.service.result.Result; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * Na temelju info objekta ISchemaCorea generira * VHDL kod. * Koristi se unutar SchemaVHDLGeneratora. * * @author Axel * */ public class SchemaInfo2VHDL { private static class WireMapping { public ISchemaWire wire; public Caseless inSingleName, outSingleName; public int ioins, ioouts, normins, normouts; public WireMapping(ISchemaWire w) { wire = w; inSingleName = outSingleName = null; ioins = ioouts = normins = normouts = 0; } } /* private fields */ private StringBuilder sb; private ISchemaInfo info; private CircuitInterface circint; private Map<Caseless, Caseless> renamedsignals; /** * Generira VHDL kod. */ public Result generateVHDL(ISchemaInfo schemaInfo) { info = schemaInfo; Result validres = isValid(); if (validres != null) return validres; sb = new StringBuilder(); circint = info.getEntity().getCircuitInterface(schemaInfo); renamedsignals = new HashMap<Caseless, Caseless>(); findRedundantSignals(); appendHeader(); appendEntityBlock(); appendArchitecturalBlock("structural"); return new Result(sb.toString()); } private void findRedundantSignals() { /* * redundant signals are: * -signals mapped to one INOUT component that has a Direction.IN port, * and mapped to Direction.IN ports of other components, but not * mapped to Direction.OUT ports of other components, with the * exception of INOUT components with a Direction.OUT port * (these are replaced with the name of the INOUT component's Direction.IN port) * -signals mapped to one INOUT component that has a Direction.OUT port, * and mapped only to normal components with Direction.OUT ports * (these are replaced with the name of the INOUT component's Direction.OUT port) */ Map<Caseless, WireMapping> wiremap = new HashMap<Caseless, WireMapping>(); ISchemaWireCollection wires = info.getWires(); ISchemaComponentCollection components = info.getComponents(); /* add all wires to wiremap */ for (ISchemaWire w : wires) { wiremap.put(w.getName(), new WireMapping(w)); } /* build wire mappings */ for (PlacedComponent plc : components) { if (plc.comp.getComponentType().equals(EComponentType.IN_OUT)) { for (SchemaPort p : plc.comp.getSchemaPorts()) { Caseless mappedto = p.getMapping(); if (Caseless.isNullOrEmpty(mappedto)) continue; Port origin = plc.comp.getPort(p.getPortindex()); WireMapping wm = wiremap.get(mappedto); if (wm != null) { if (origin.isIN()) { wm.ioins++; if (wm.ioins == 1) wm.inSingleName = getPortWithIndexName(plc, origin, p); } else if (origin.isOUT()) { wm.ioouts++; if (wm.ioouts == 1) wm.outSingleName = getPortWithIndexName(plc, origin, p); } else { throw new NotImplementedException("Only IN and OUT directions implemented."); } } } } else { for (SchemaPort p : plc.comp.getSchemaPorts()) { Caseless mappedto = p.getMapping(); if (Caseless.isNullOrEmpty(mappedto)) continue; Port origin = plc.comp.getPort(p.getPortindex()); WireMapping wm = wiremap.get(mappedto); if (wm != null) { if (origin.isIN()) { wm.normins++; } else if (origin.isOUT()) { wm.normouts++; } else { throw new NotImplementedException("Only IN and OUT directions implemented."); } } } } } /* build renamedsignals map */ for (Entry<Caseless, WireMapping> entry : wiremap.entrySet()) { WireMapping wm = entry.getValue(); if (wm.ioins == 1 && wm.normouts == 0) { renamedsignals.put(entry.getKey(), wm.inSingleName); continue; } if (wm.ioouts == 1 && wm.ioins == 0 && wm.normins == 0) { renamedsignals.put(entry.getKey(), wm.outSingleName); continue; } } } private Caseless getPortWithIndexName(PlacedComponent plc, Port origin, SchemaPort schport) { if (origin.isScalar()) { return new Caseless(origin.getName()); } List<SchemaPort> schemaports = plc.comp.getRelatedTo(schport .getPortindex()); int schindex = 0; for (SchemaPort sp : schemaports) { if (sp.equals(schport)) break; schindex++; } if (origin.isTO()) { schindex += origin.getFrom(); } else { schindex = origin.getTo() - schindex; } return new Caseless(origin.getName() + "(" + schindex + ")"); } private Result isValid() { for (PlacedComponent plc : info.getComponents()) { // find invalidated components if (plc.comp.isInvalidated()) { List<String> errors = new ArrayList<String>(); errors.add("Component '" + plc.comp.getName() + "' is invalidated and must be replaced."); return new Result(errors); } // check if inout if (plc.comp.getComponentType().equals(EComponentType.IN_OUT)) continue; // find empty ports with IN direction List<String> errors = new ArrayList<String>(); for (int i = 0, sz = plc.comp.schemaPortCount(); i < sz; i++) { SchemaPort sp = plc.comp.getSchemaPort(i); Caseless mapping = sp.getMapping(); if (Caseless.isNullOrEmpty(mapping)) { Port p = plc.comp.getPort(sp.getPortindex()); if (p.isIN()) { errors.add("Component '" + plc.comp.getName() + "' has a port '" + p.getName() + "' with direction IN that is not connected to a signal."); } } } if (!errors.isEmpty()) { return new Result(errors); } } return null; } private void appendHeader() { sb.append("library ieee;\nuse ieee.std_logic_1164.all;\n\n"); } private void appendEntityBlock() { sb.append(circint.toString()).append("\n\n\n"); } private void appendArchitecturalBlock(String archName) { sb.append("ARCHITECTURE ").append(archName).append(" OF ").append(circint.getName()); sb.append(" IS\n"); IVHDLSegmentProvider provider = null; // prepare signals for (ISchemaWire wire : info.getWires()) { /* if signal is redundant do not declare it */ if (renamedsignals.containsKey(wire.getName())) continue; /* declare signal */ sb.append("SIGNAL ").append(wire.getName()).append(": std_logic;\n"); } // prepare components for (Caseless name : info.getComponents().getComponentNames()) { ISchemaComponent comp = info.getComponents().fetchComponent(name); provider = comp.getVHDLSegmentProvider(); sb.append(provider.getSignalDefinitions(info)); sb.append('\n'); } sb.append("BEGIN\n"); // map everything for (Caseless name : info.getComponents().getComponentNames()) { ISchemaComponent comp = info.getComponents().fetchComponent(name); provider = comp.getVHDLSegmentProvider(); sb.append(provider.getInstantiation(info, renamedsignals)); sb.append('\n'); } sb.append("END ARCHITECTURE ").append(archName).append(";\n"); } }