/******************************************************************************* * PSHDL is a library and (trans-)compiler for PSHDL input. It generates * output suitable for implementation or simulation of it. * * Copyright (C) 2013 Karsten Becker (feedback (at) pshdl (dot) org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * This License does not grant permission to use the trade names, trademarks, * service marks, or product names of the Licensor, except as required for * reasonable and customary use in describing the origin of the Work. * * Contributors: * Karsten Becker - initial API and implementation ******************************************************************************/ package org.pshdl.model.utils; import static org.pshdl.model.extensions.FullNameExtension.fullNameOf; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.pshdl.model.HDLAnnotation; import org.pshdl.model.HDLArgument; import org.pshdl.model.HDLArithOp; import org.pshdl.model.HDLArithOp.HDLArithOpType; import org.pshdl.model.HDLArrayInit; import org.pshdl.model.HDLAssignment; import org.pshdl.model.HDLAssignment.HDLAssignmentType; import org.pshdl.model.HDLBitOp; import org.pshdl.model.HDLBitOp.HDLBitOpType; import org.pshdl.model.HDLBlock; import org.pshdl.model.HDLClass; import org.pshdl.model.HDLConcat; import org.pshdl.model.HDLDirectGeneration; import org.pshdl.model.HDLEnum; import org.pshdl.model.HDLEnumRef; import org.pshdl.model.HDLEqualityOp; import org.pshdl.model.HDLEqualityOp.HDLEqualityOpType; import org.pshdl.model.HDLExport; import org.pshdl.model.HDLExpression; import org.pshdl.model.HDLForLoop; import org.pshdl.model.HDLFunction; import org.pshdl.model.HDLFunctionCall; import org.pshdl.model.HDLFunctionParameter; import org.pshdl.model.HDLFunctionParameter.Type; import org.pshdl.model.HDLIfStatement; import org.pshdl.model.HDLInterface; import org.pshdl.model.HDLInterfaceInstantiation; import org.pshdl.model.HDLInterfaceRef; import org.pshdl.model.HDLLiteral; import org.pshdl.model.HDLManip; import org.pshdl.model.HDLManip.HDLManipType; import org.pshdl.model.HDLObject; import org.pshdl.model.HDLObject.GenericMeta; import org.pshdl.model.HDLOpExpression; import org.pshdl.model.HDLPackage; import org.pshdl.model.HDLPrimitive; import org.pshdl.model.HDLPrimitive.AnyPrimitive; import org.pshdl.model.HDLPrimitive.HDLPrimitiveType; import org.pshdl.model.HDLRange; import org.pshdl.model.HDLReference; import org.pshdl.model.HDLRegisterConfig; import org.pshdl.model.HDLResolvedRef; import org.pshdl.model.HDLShiftOp; import org.pshdl.model.HDLShiftOp.HDLShiftOpType; import org.pshdl.model.HDLStatement; import org.pshdl.model.HDLSwitchCaseStatement; import org.pshdl.model.HDLSwitchStatement; import org.pshdl.model.HDLTernary; import org.pshdl.model.HDLType; import org.pshdl.model.HDLUnit; import org.pshdl.model.HDLUnresolvedFragment; import org.pshdl.model.HDLUnresolvedFragmentFunction; import org.pshdl.model.HDLVariable; import org.pshdl.model.HDLVariableDeclaration; import org.pshdl.model.HDLVariableDeclaration.HDLDirection; import org.pshdl.model.HDLVariableRef; import org.pshdl.model.IHDLObject; import org.pshdl.model.evaluation.ConstantEvaluate; import org.pshdl.model.evaluation.HDLEvaluationContext; import org.pshdl.model.extensions.FullNameExtension; import org.pshdl.model.extensions.RangeExtension; import org.pshdl.model.extensions.ScopingExtension; import org.pshdl.model.extensions.TypeExtension; import org.pshdl.model.types.builtIn.HDLBuiltInAnnotationProvider.HDLBuiltInAnnotations; import org.pshdl.model.types.builtIn.HDLFunctions; import org.pshdl.model.types.builtIn.HDLGenerators; import org.pshdl.model.types.builtIn.HDLPrimitives; import org.pshdl.model.utils.HDLQuery.Result; import org.pshdl.model.utils.services.CompilerInformation; import org.pshdl.model.utils.services.HDLTypeInferenceInfo; import org.pshdl.model.utils.services.IHDLGenerator.HDLGenerationInfo; import org.pshdl.model.utils.services.IInsulinParticitant; import org.pshdl.model.utils.services.IServiceProvider; import org.pshdl.model.validation.RWValidation; import org.pshdl.model.validation.RWValidation.Init; import org.pshdl.model.validation.builtin.BuiltInValidator; import org.pshdl.model.validation.builtin.BuiltInValidator.IntegerMeta; import com.google.common.base.Optional; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Range; import com.google.common.collect.Sets; public class Insulin { public static final GenericMeta<Boolean> insulated = new GenericMeta<Boolean>("insulated", true); public static final GenericMeta<Boolean> IS_EXPORT = new GenericMeta<Boolean>("isExport", true); public static <T extends IHDLObject> T transform(T orig, String src) { if (orig.hasMeta(insulated)) return orig; T apply = resolveFragments(orig); RWValidation.annotateReadCount(apply); RWValidation.annotateWriteCount(apply); for (final IInsulinParticitant part : participants.values()) { apply = part.preInsulin(apply, src); } apply = inlineConstants(apply); apply = convertIncRecRanges(apply); apply = handlePostfixOp(apply); apply = handleDelayedSignals(apply); apply = handleOutPortRead(apply); apply = handleExports(apply); apply = includeGenerators(apply, src); apply = inlineFunctions(apply); apply = setParameterOnInstance(apply); apply = pushSignIntoLiteral(apply); apply = generateClkAndReset(apply); apply = handleMultiBitAccess(apply, null); apply = handleMultiForLoop(apply); apply = hoistBlockLocalVariables(apply); apply = generateInitializations(apply); apply = fixMultiDimAssignments(apply); apply = fixDoubleNegate(apply); apply = fortifyType(apply); apply = resolveFragments(apply); for (final IInsulinParticitant part : participants.values()) { apply = part.postInsulin(apply, src); } apply.validateAllFields(orig.getContainer(), false); apply.setMeta(insulated); return apply; } public static <T extends IHDLObject> T handleExports(T pkg) { final ModificationSet ms = new ModificationSet(); final HDLExport[] exports = pkg.getAllObjectsOf(HDLExport.class, true); for (final HDLExport hdlExport : exports) { final HDLExpression ref = hdlExport.getExportRef(); if (ref instanceof HDLResolvedRef) { final HDLResolvedRef rr = (HDLResolvedRef) ref; final Optional<HDLVariable> resolveVar = rr.resolveVar(); if (resolveVar.isPresent()) { final HDLVariable hdlVariable = resolveVar.get(); hdlVariable.setMeta(IS_EXPORT); final IHDLObject container = hdlVariable.getContainer(); if (container instanceof HDLVariableDeclaration) { final HDLVariableDeclaration hvd = (HDLVariableDeclaration) container; final HDLVariable newVar = hdlVariable.setDefaultValue(null).addAnnotations(HDLBuiltInAnnotations.VHDLLatchable.create(null)) .addAnnotations(HDLBuiltInAnnotations.genSignal.create("export")); switch (hvd.getDirection()) { case IN: break; case INOUT: case OUT: case CONSTANT: case PARAMETER: ms.replace(hdlExport, hvd.setVariables(HDLObject.asList(newVar.setDefaultValue(rr)))); break; case HIDDEN: case INTERNAL: throw new IllegalArgumentException("Can not export for loop iterator and internal variables"); } } } } } return ms.apply(pkg); } public static <T extends IHDLObject> T convertIncRecRanges(T pkg) { final ModificationSet ms = new ModificationSet(); final HDLRange[] ranges = pkg.getAllObjectsOf(HDLRange.class, true); for (final HDLRange hdlRange : ranges) { if (hdlRange.getInc() != null) { final HDLArithOp incD = new HDLArithOp().setLeft(hdlRange.getTo()).setType(HDLArithOpType.PLUS).setRight(hdlRange.getInc()); ms.replace(hdlRange, new HDLRange().setFrom(incD).setTo(hdlRange.getTo())); } if (hdlRange.getDec() != null) { final HDLArithOp decD = new HDLArithOp().setLeft(hdlRange.getTo()).setType(HDLArithOpType.MINUS).setRight(hdlRange.getDec()); ms.replace(hdlRange, new HDLRange().setFrom(hdlRange.getTo()).setTo(decD)); } } return ms.apply(pkg); } public static <T extends IHDLObject> T hoistBlockLocalVariables(T pkg) { final ModificationSet ms = new ModificationSet(); final HDLUnit[] units = pkg.getAllObjectsOf(HDLUnit.class, true); for (final HDLUnit hdlUnit : units) { final Collection<HDLVariableDeclaration> allHVDs = HDLQuery.select(HDLVariableDeclaration.class).from(hdlUnit).where(HDLObject.fContainer).isNotEqualTo(hdlUnit) .getAll(); for (final HDLVariableDeclaration hvd : allHVDs) { final ArrayList<HDLVariable> newVars = Lists.newArrayList(); for (final HDLVariable var : hvd.getVariables()) { final HDLQualifiedName fqn = FullNameExtension.fullNameOf(var); final String newName = '$' + fqn.getLocalPart().toString('_').replace("@", ""); Refactoring.renameVariable(var, new HDLQualifiedName(newName), hdlUnit, ms); newVars.add(var.setName(newName)); } ms.remove(hvd); ms.addTo(hdlUnit, HDLUnit.fInits, hvd.setVariables(newVars)); } } return ms.apply(pkg); } public static <T extends IHDLObject> T fixMultiDimAssignments(T pkg) { final ModificationSet ms = new ModificationSet(); final HDLAssignment[] asses = pkg.getAllObjectsOf(HDLAssignment.class, true); for (final HDLAssignment ass : asses) { if (BuiltInValidator.skipExp(ass)) { continue; } final HDLReference left = ass.getLeft(); if (left.getClassType() == HDLClass.HDLVariableRef) { final HDLExpression right = ass.getRight(); final HDLVariableRef lRef = (HDLVariableRef) left; final HDLType lRefType = TypeExtension.typeOf(lRef).get(); // Generate loop for each assigned dimension if (right.getClassType() == HDLClass.HDLVariableRef) { final HDLVariableRef rRef = (HDLVariableRef) right; final HDLType rRefType = TypeExtension.typeOf(rRef).get(); if (!lRefType.getDim().isEmpty() || !rRefType.getDim().isEmpty()) { final HDLStatement initLoop = createArrayForLoop(Collections.<HDLExpression> emptyList(), lRef.resolveVar().get().getDimensions(), lRef.getArray().size(), rRef, lRef, true); ms.replace(ass, initLoop); } } // Generate 0 fill then assign each value in a single assigment if (right.getClassType() == HDLClass.HDLArrayInit) { final HDLStatement initLoop = createArrayForLoop(Collections.<HDLExpression> emptyList(), lRef.resolveVar().get().getDimensions(), lRef.getArray().size(), HDLLiteral.get(0), lRef, false); final HDLArrayInit arr = (HDLArrayInit) right; final List<HDLStatement> assignments = Lists.newLinkedList(); assignments.add(initLoop); final LinkedList<HDLLiteral> depth = Lists.newLinkedList(); generateStaticAssignments(lRef, arr, depth, assignments); ms.replace(ass, assignments.toArray(new HDLStatement[assignments.size()])); } } } return ms.apply(pkg); } private static void generateStaticAssignments(HDLVariableRef lRef, HDLArrayInit arr, LinkedList<HDLLiteral> depth, List<HDLStatement> assignments) { final ArrayList<HDLExpression> exp = arr.getExp(); for (int i = 0; i < exp.size(); i++) { final HDLExpression expression = exp.get(i); if (expression.getClassType() == HDLClass.HDLArrayInit) { @SuppressWarnings("unchecked") final LinkedList<HDLLiteral> clone = (LinkedList<HDLLiteral>) depth.clone(); clone.add(HDLLiteral.get(i)); generateStaticAssignments(lRef, (HDLArrayInit) expression, clone, assignments); } else { final ArrayList<HDLExpression> array = lRef.getArray(); @SuppressWarnings("unchecked") final LinkedList<HDLLiteral> clone = (LinkedList<HDLLiteral>) depth.clone(); clone.add(HDLLiteral.get(i)); array.addAll(clone); assignments.add(new HDLAssignment().setLeft(lRef.setArray(array)).setRight(expression)); } } } /** * Find all constants and inline them */ public static <T extends IHDLObject> T inlineConstants(T pkg) { final ModificationSet ms = new ModificationSet(); final Collection<HDLVariableDeclaration> constants = HDLQuery.select(HDLVariableDeclaration.class).from(pkg).where(HDLVariableDeclaration.fDirection) .isEqualTo(HDLDirection.CONSTANT).getAll(); for (final HDLVariableDeclaration hvd : constants) { final Set<HDLVariable> remove = Sets.newHashSet(); final ArrayList<HDLVariable> variables = hvd.getVariables(); for (final HDLVariable var : variables) { final Optional<BigInteger> constVal = ConstantEvaluate.valueOf(var.getDefaultValue()); if (constVal.isPresent()) { final Collection<HDLVariableRef> refs = HDLQuery.getVarRefs(pkg, var); boolean allRefUsed = true; for (final HDLVariableRef ref : refs) { final Optional<BigInteger> refVal = ConstantEvaluate.valueOf(ref); if (refVal.isPresent()) { final Optional<? extends HDLType> typeOf = TypeExtension.typeOf(ref); if (typeOf.isPresent()) { final HDLManip castedType = new HDLManip().setType(HDLManipType.CAST).setCastTo(typeOf.get()).setTarget(HDLLiteral.get(refVal.get())); ms.replace(ref, castedType); } } else { allRefUsed = false; } } if (allRefUsed) { remove.add(var); } } } // Don't remove global constants if (hvd.getContainer(HDLUnit.class) == null) { continue; } variables.removeAll(remove); if (variables.isEmpty()) { ms.remove(hvd); } else { ms.replace(hvd, hvd.setVariables(variables)); } } return ms.apply(pkg); } /** * Finds all register config with delays in them and replaces them with a * non delay version and a fifo */ public static <T extends IHDLObject> T handleDelayedSignals(T pkg) { final ModificationSet ms = new ModificationSet(); final Collection<HDLRegisterConfig> delayRegs = HDLQuery.select(HDLRegisterConfig.class).from(pkg).where(HDLRegisterConfig.fDelay).isNotEqualTo(null).getAll(); for (final HDLRegisterConfig delayedReg : delayRegs) { final HDLExpression delay = delayedReg.getDelay(); final Optional<BigInteger> delayValue = ConstantEvaluate.valueOf(delay); if (delayValue.isPresent()) { if (delayValue.get().signum() == 0) { continue; } } final HDLRegisterConfig undelayedReg = delayedReg.setDelay(null); ms.replace(delayedReg, undelayedReg); HDLForLoop loop = HDLForLoop.tempLoop(HDLLiteral.get(1), delay); final HDLArithOp delayPlusOne = new HDLArithOp().setLeft(delay).setType(HDLArithOpType.PLUS).setRight(HDLLiteral.get(1)); final HDLVariableDeclaration hvd = delayedReg.getContainer(HDLVariableDeclaration.class); for (final HDLVariable var : hvd.getVariables()) { ms.replace(var, var.setDefaultValue(null)); final String dlyName = Insulin.getTempName(var.getName(), "dlyd"); final HDLQualifiedName fqnDelay = HDLQualifiedName.create(dlyName); final HDLVariable dlyVar = var.setName(dlyName).setDefaultValue(null); // Insert dimension as first dimension. Rewrite all existing // references to the new delayed signal. final ArrayList<HDLExpression> dimensions = dlyVar.getDimensions(); dimensions.add(0, delayPlusOne); ms.insertAfter(hvd, hvd.setDirection(HDLDirection.INTERNAL).setRegister(undelayedReg).setVariables(HDLObject.asList(dlyVar.setDimensions(dimensions)))); final Collection<HDLVariableRef> varRefs = HDLQuery.getVarRefs(var.getContainer(HDLUnit.class), var); for (final HDLVariableRef ref : varRefs) { if (ref.getContainer().getClassType() == HDLClass.HDLAssignment) { final HDLAssignment ass = (HDLAssignment) ref.getContainer(); if (ass.getLeft() == ref) { final ArrayList<HDLExpression> array = ref.getArray(); array.add(0, delay); ms.replace(ass, ass.setLeft(ref.setVar(fqnDelay).setArray(array))); } else { final ArrayList<HDLExpression> array = ref.getArray(); array.add(0, HDLLiteral.get(0)); ms.replace(ref, ref.setVar(fqnDelay).setArray(array)); } } else { final ArrayList<HDLExpression> array = ref.getArray(); array.add(0, HDLLiteral.get(0)); ms.replace(ref, ref.setVar(fqnDelay).setArray(array)); } } final HDLExpression defaultValue = var.getDefaultValue(); final HDLVariableRef dlyRef = dlyVar.asHDLRef(); if (defaultValue != null) { final ArrayList<HDLExpression> array = dlyRef.getArray(); array.add(0, delay); ms.insertAfter(hvd, new HDLAssignment().setLeft(dlyRef.setArray(array)).setRight(defaultValue)); } final ArrayList<HDLExpression> arrayZero = dlyRef.getArray(); arrayZero.add(0, HDLLiteral.get(0)); ms.insertAfter(hvd, new HDLAssignment().setLeft(var.asHDLRef()).setRight(dlyRef.setArray(arrayZero))); final HDLVariableRef dim = loop.getParam().asHDLRef(); final HDLArithOp dimMinusOne = new HDLArithOp().setLeft(dim).setType(HDLArithOpType.MINUS).setRight(HDLLiteral.get(1)); final ArrayList<HDLExpression> arrayDimMinOne = dlyRef.getArray(); arrayDimMinOne.add(0, dimMinusOne); final ArrayList<HDLExpression> arrayDim = dlyRef.getArray(); arrayDim.add(0, dim); loop = loop.addDos(new HDLAssignment().setLeft(dlyRef.setArray(arrayDimMinOne)).setRight(dlyRef.setArray(arrayDim))); // Replace original hvd without registers } ms.replace(hvd, hvd.setRegister(null)); if (delayValue.isPresent()) { ms.insertAfter(hvd, loop); } else { final HDLIfStatement hIf = new HDLIfStatement().setIfExp(new HDLEqualityOp().setLeft(delay).setType(HDLEqualityOpType.GREATER).setRight(HDLLiteral.get(0))) .addThenDo(loop); ms.insertAfter(hvd, hIf); } } return ms.apply(pkg); } public static <T extends IHDLObject> T resolveFragments(T pkg) { HDLUnresolvedFragment[] fragments; int count = 0; HDLLibrary.resolveFragments.set(false); try { do { if (count > 50) throw new IllegalArgumentException("Failed to resolve fragments within 50 iterations"); count++; final ModificationSet ms = new ModificationSet(); fragments = pkg.getAllObjectsOf(HDLUnresolvedFragment.class, true); for (final HDLUnresolvedFragment uFrag : fragments) { final IHDLObject container = uFrag.getContainer(); if ((container instanceof HDLUnresolvedFragment)) { final HDLUnresolvedFragment fragment = (HDLUnresolvedFragment) container; // Skip fragments that are sub fragments such as b in // a.b if (fragment.getSub() == uFrag) { continue; } } final Optional<ResolvedPart> resolved = resolveFragment(uFrag); if (resolved.isPresent()) { final ResolvedPart resolvedPart = resolved.get(); // If the remainder is not null, then we attempted to // access // something illegal if (resolvedPart.remainder == null) { if ((resolvedPart.obj instanceof HDLStatement) && uFrag.getIsStatement()) { ms.replace(uFrag, resolvedPart.obj); } if ((resolvedPart.obj instanceof HDLExpression) && !uFrag.getIsStatement()) { ms.replace(uFrag, resolvedPart.obj); } } } } final T newPkg = ms.apply(pkg); if ((newPkg == pkg) && (fragments.length != 0)) return pkg; pkg = newPkg; } while (fragments.length > 0); } finally { HDLLibrary.resolveFragments.set(true); } final HDLRegisterConfig[] regs = pkg.getAllObjectsOf(HDLRegisterConfig.class, true); final ModificationSet ms = new ModificationSet(); for (HDLRegisterConfig reg : regs) { final HDLRegisterConfig orig = reg; reg = reg.setResetTypeFromUnresolved(); reg = reg.setSyncTypeFromUnresolved(); reg = reg.setClockTypeFromUnresolved(); if (reg != orig) { ms.replace(orig, reg); } } return ms.apply(pkg); } public static Optional<ResolvedPart> resolveFragment(HDLUnresolvedFragment uFrag) { // Single fragment (no function) resolves to variable -> Variable // Single fragment (function) resolved to function -> FunctionCall // Fragment (no bits, no function) resolves to variable, // -> fragment (no function) -> Interface Ref // -> fragment (function) -> FunctionCall (first fragment as arg) // Fragment (no bits, no function, no array) resolves to Enum // -> fragment (no bits, no function, no array) -> EnumRef // Fragment (no bits, no array, no function) does not resolve // -> append until we get a Type // -> resolves to enum -> HDLQualifiedName fqn = HDLQualifiedName.EMPTY; HDLUnresolvedFragment cFrag = uFrag; while (cFrag != null) { fqn = fqn.append(cFrag.getFrag()); final Optional<ResolvedPart> attemptResolve = attemptResolve(cFrag, fqn); if (attemptResolve.isPresent()) { final Optional<ResolvedPart> methodChaining = tryMethodChaining(cFrag, Optional.of(attemptResolve.get().obj)); if (methodChaining.isPresent()) return methodChaining; return attemptResolve; } cFrag = cFrag.getSub(); } IHDLObject container = uFrag.getContainer(); while (container instanceof HDLArrayInit) { container = container.getContainer(); } if (container instanceof HDLSwitchCaseStatement) { final HDLSwitchCaseStatement caseStatement = (HDLSwitchCaseStatement) container; final IHDLObject caseContainer = caseStatement.getContainer(); if (caseContainer instanceof HDLSwitchStatement) { final HDLSwitchStatement switchStatement = (HDLSwitchStatement) caseContainer; final Optional<? extends HDLType> switchType = TypeExtension.typeOf(switchStatement.getCaseExp()); if (switchType.isPresent()) return createFullEnum(uFrag, switchType.get()); } } if (container instanceof HDLEqualityOp) { final HDLEqualityOp equalityOp = (HDLEqualityOp) container; if (equalityOp.getLeft() == uFrag) { final Optional<? extends HDLType> type = TypeExtension.typeOf(equalityOp.getRight()); if (type.isPresent()) return createFullEnum(uFrag, type.get()); } if (equalityOp.getRight() == uFrag) { final Optional<? extends HDLType> type = TypeExtension.typeOf(equalityOp.getLeft()); if (type.isPresent()) return createFullEnum(uFrag, type.get()); } } if (container instanceof HDLAssignment) { final HDLAssignment assignment = (HDLAssignment) container; final Optional<? extends HDLType> typeOf = TypeExtension.typeOf(assignment.getLeft()); if (typeOf.isPresent()) return createFullEnum(uFrag, typeOf.get()); } if (container instanceof HDLVariable) { final Optional<? extends HDLType> typeOf = TypeExtension.typeOf(container); if (typeOf.isPresent()) return createFullEnum(uFrag, typeOf.get()); } return Optional.absent(); } private static Optional<ResolvedPart> tryMethodChaining(HDLUnresolvedFragment cFrag, Optional<? extends IHDLObject> attemptResolve) { final HDLUnresolvedFragment sub = cFrag.getSub(); if (sub instanceof HDLUnresolvedFragmentFunction) { final HDLUnresolvedFragmentFunction huf = (HDLUnresolvedFragmentFunction) sub; final HDLQualifiedName funcName = HDLQualifiedName.create(huf.getFrag()); final Optional<Iterable<HDLFunction>> function = ScopingExtension.INST.resolveFunctionName(cFrag, funcName); if (function.isPresent()) { final ArrayList<HDLExpression> params = huf.getParams(); params.add(0, (HDLExpression) attemptResolve.get()); final HDLFunctionCall funcCall = new HDLFunctionCall().setFunction(funcName).setParams(params); final Optional<HDLFunctionCall> funcOp = Optional.of(funcCall); final Optional<ResolvedPart> methodChaining = tryMethodChaining(sub, funcOp); if (methodChaining.isPresent()) return methodChaining; if (funcOp.isPresent()) return Optional.of(new ResolvedPart(funcOp.get(), sub.getSub())); return Optional.absent(); } } return Optional.absent(); } public static class ResolvedPart { public final IHDLObject obj; public final HDLUnresolvedFragment remainder; public ResolvedPart(IHDLObject obj, HDLUnresolvedFragment remainder) { super(); this.obj = obj; this.remainder = remainder; } } protected static Optional<ResolvedPart> attemptResolve(HDLUnresolvedFragment uFrag, HDLQualifiedName hVar) { final HDLUnresolvedFragment sub = uFrag.getSub(); if (uFrag.getClassType() != HDLClass.HDLUnresolvedFragmentFunction) { final Optional<HDLVariable> variableRaw = ScopingExtension.INST.resolveVariable(uFrag, hVar); final HDLUnresolvedFragment ssub = sub != null ? sub.getSub() : null; if (variableRaw.isPresent()) { final HDLVariable variable = variableRaw.get(); if (sub == null) return Optional.of(new ResolvedPart(variable.asHDLRef().setArray(uFrag.getArray()).setBits(uFrag.getBits()), sub)); final HDLFunctionParameter funcPar = variable.getContainer(HDLFunctionParameter.class); if (funcPar != null) { if (funcPar.getType() == Type.PARAM_IF) { final Optional<HDLInterface> resolveInterface = ScopingExtension.INST.resolveInterface(funcPar, funcPar.getIfSpecRefName()); if (resolveInterface.isPresent()) { final HDLQualifiedName typeName = fullNameOf(resolveInterface.get()); final HDLInterfaceRef hir = new HDLInterfaceRef().setHIf(variable.asRef()).setIfArray(uFrag.getArray()).setVar(typeName.append(sub.getFrag())) .setArray(sub.getArray()).setBits(sub.getBits()); return Optional.of(new ResolvedPart(hir, ssub)); } } if (funcPar.getType() == Type.PARAM_ENUM) { final Optional<HDLEnum> resolveEnum = ScopingExtension.INST.resolveEnum(funcPar, funcPar.getEnumSpecRefName()); if (resolveEnum.isPresent()) { final HDLQualifiedName typeName = fullNameOf(resolveEnum.get()); final HDLEnumRef enumRef = new HDLEnumRef().setHEnum(typeName).setVar(typeName.append(sub.getFrag())); return Optional.of(new ResolvedPart(enumRef, ssub)); } } } final Optional<? extends HDLType> type = TypeExtension.typeOf(variable); if ((type.isPresent()) && (type.get().getClassType() == HDLClass.HDLInterface)) { final HDLQualifiedName typeName = fullNameOf(type.get()); final HDLInterfaceRef hir = new HDLInterfaceRef().setHIf(variable.asRef()).setIfArray(uFrag.getArray()).setVar(typeName.append(sub.getFrag())) .setArray(sub.getArray()).setBits(sub.getBits()); return Optional.of(new ResolvedPart(hir, ssub)); } return Optional.of(new ResolvedPart(variable.asHDLRef().setArray(uFrag.getArray()).setBits(uFrag.getBits()), sub)); } final Optional<HDLEnum> enumRaw = ScopingExtension.INST.resolveEnum(uFrag, hVar); if (enumRaw.isPresent()) if (sub != null) { final HDLQualifiedName typeName = fullNameOf(enumRaw.get()); final HDLEnumRef enumRef = new HDLEnumRef().setHEnum(typeName).setVar(typeName.append(sub.getFrag())); return Optional.of(new ResolvedPart(enumRef, ssub)); } final Optional<? extends HDLType> typeRaw = ScopingExtension.INST.resolveType(uFrag, hVar); if (typeRaw.isPresent()) if (sub != null) { final HDLQualifiedName typeName = fullNameOf(typeRaw.get()); if (typeRaw.get() instanceof HDLEnum) { final HDLEnumRef enumRef = new HDLEnumRef().setHEnum(typeName).setVar(typeName.append(sub.getFrag())); return Optional.of(new ResolvedPart(enumRef, ssub)); } } } else { final HDLUnresolvedFragmentFunction uff = (HDLUnresolvedFragmentFunction) uFrag; final HDLFunctionCall call = new HDLFunctionCall().setFunction(hVar).setParams(uff.getParams()); return Optional.of(new ResolvedPart(call, sub)); } return Optional.absent(); } /** * Attempt to create an enum if the type provided is an actual enum * * @param uFrag * the fragment * @param type * the type * @return may return null if not successful */ private static Optional<ResolvedPart> createFullEnum(HDLUnresolvedFragment uFrag, HDLType type) { if (type instanceof HDLEnum) { final HDLEnum enumType = (HDLEnum) type; final Optional<HDLVariable> variable = ScopingExtension.getVariable(enumType, uFrag.getFrag()); if (variable.isPresent()) { final HDLQualifiedName typeName = fullNameOf(enumType); final HDLEnumRef enumRef = new HDLEnumRef().setHEnum(typeName).setVar(typeName.append(uFrag.getFrag())); return Optional.of(new ResolvedPart(enumRef, uFrag.getSub())); } } return Optional.absent(); } private static <T extends IHDLObject> T pushSignIntoLiteral(T pkg) { final HDLLiteral[] literals = pkg.getAllObjectsOf(HDLLiteral.class, true); final ModificationSet ms = new ModificationSet(); for (final HDLLiteral hdlLiteral : literals) if (hdlLiteral.getContainer() instanceof HDLManip) { final HDLManip manip = (HDLManip) hdlLiteral.getContainer(); if (manip.getType() == HDLManipType.ARITH_NEG) if (hdlLiteral.getVal().charAt(0) == '-') { ms.replace(manip, hdlLiteral.setVal(hdlLiteral.getVal().substring(1))); } else { ms.replace(manip, hdlLiteral.setVal("-" + hdlLiteral.getVal())); } } return ms.apply(pkg); } /** * Finds cases where a either a ARITH_NEG contains another ARITH_NEG, or * where an ARITH_NEG contains a negative literal * */ public static <T extends IHDLObject> T fixDoubleNegate(T pkg) { final ModificationSet ms = new ModificationSet(); final Collection<HDLManip> manips = HDLQuery.select(HDLManip.class).from(pkg) // .where(HDLManip.fType).isEqualTo(HDLManipType.ARITH_NEG).getAll(); for (final HDLManip manip : manips) { final HDLExpression target = manip.getTarget(); if (target instanceof HDLManip) { final HDLManip innerManip = (HDLManip) target; if (innerManip.getType() == HDLManipType.ARITH_NEG) { ms.replace(manip, innerManip.getTarget()); } } if (target instanceof HDLLiteral) { final HDLLiteral lit = (HDLLiteral) target; final BigInteger valueAsBigInt = lit.getValueAsBigInt(); if (valueAsBigInt.signum() <= 0) { ms.replace(manip, HDLLiteral.get(valueAsBigInt.negate())); } } } return ms.apply(pkg); } public static <T extends IHDLObject> T inlineFunctions(T pkg) { final ModificationSet ms = new ModificationSet(); boolean doRepeat = false; do { doRepeat = false; final HDLFunctionCall[] functions = pkg.getAllObjectsOf(HDLFunctionCall.class, true); outer: for (final HDLFunctionCall hdi : functions) { final Optional<HDLFunction> function = hdi.resolveFunction(); if (function.isPresent()) { final HDLFunctionCall[] subFunctions = hdi.getAllObjectsOf(HDLFunctionCall.class, true); for (final HDLFunctionCall sub : subFunctions) { if (sub != hdi) { final Optional<HDLFunction> func = sub.resolveFunction(); if (func.isPresent() && (func.get().getClassType() == HDLClass.HDLInlineFunction)) { doRepeat = true; continue outer; } } } HDLFunctions.transform(hdi, null, ms); } } pkg = ms.apply(pkg); } while (doRepeat); return pkg; } public static <T extends IHDLObject> T setParameterOnInstance(T apply) { final ModificationSet ms = new ModificationSet(); final HDLInterfaceInstantiation[] hiis = apply.getAllObjectsOf(HDLInterfaceInstantiation.class, true); for (final HDLInterfaceInstantiation hdi : hiis) { final Map<String, HDLExpression> argMap = Maps.newLinkedHashMap(); final ArrayList<HDLArgument> arguments = hdi.getArguments(); for (final HDLArgument hdlArgument : arguments) { argMap.put(hdlArgument.getName(), hdlArgument.getExpression()); } final Optional<HDLInterface> hIf = hdi.resolveHIf(); if (!hIf.isPresent()) { continue; } for (final HDLVariableDeclaration hvd : hIf.get().getPorts()) if (hvd.getDirection() == HDLDirection.PARAMETER) { HDLVariableDeclaration newHVD = new HDLVariableDeclaration().setType(hvd.resolveType().get()).setDirection(HDLDirection.CONSTANT); for (HDLVariable var : hvd.getVariables()) if (!ScopingExtension.INST.resolveVariable(hdi, HDLQualifiedName.create(var.getName())).isPresent()) { String argName = var.getMeta(HDLInterfaceInstantiation.ORIG_NAME); if (argName == null) { argName = var.getName(); } if (argMap.get(argName) != null) { var = var.setDefaultValue(argMap.get(argName)); } newHVD = newHVD.addVariables(var); } if (!newHVD.getVariables().isEmpty()) { ms.insertBefore(hdi, newHVD); } } } return ms.apply(apply); } /** * Checks for HDLDirectGenerations and calls the generators. If they are * includes, it will be included and the references resolved * */ private static <T extends IHDLObject> T includeGenerators(T apply, String src) { final ModificationSet ms = new ModificationSet(); final HDLDirectGeneration[] gens = apply.getAllObjectsOf(HDLDirectGeneration.class, true); for (final HDLDirectGeneration generation : gens) { final Optional<HDLGenerationInfo> optional = HDLGenerators.getImplementation(generation); if (optional.isPresent()) { final HDLGenerationInfo generationInfo = optional.get(); if (generation.getInclude()) { final HDLQualifiedName ifRef = generation.getHIf().asRef(); final HDLQualifiedName fullName = fullNameOf(generation); final HDLUnit unit = generationInfo.unit; final HDLStatement[] stmnts = unit.getStatements().toArray(new HDLStatement[0]); final HDLStatement[] inits = unit.getInits().toArray(new HDLStatement[0]); final ArrayList<HDLStatement> allStmnt = new ArrayList<HDLStatement>(); allStmnt.addAll(Arrays.asList(stmnts)); allStmnt.addAll(Arrays.asList(inits)); ms.replace(generation, allStmnt.toArray(new HDLStatement[allStmnt.size()])); final HDLInterfaceRef[] ifRefs = apply.getAllObjectsOf(HDLInterfaceRef.class, true); for (final HDLInterfaceRef hdI : ifRefs) if (TypeExtension.typeOf(hdI.resolveHIf().get()).get().asRef().equals(ifRef)) { final HDLQualifiedName newName = fullName.append(hdI.getVarRefName().getLastSegment()); ms.replace(hdI, new HDLVariableRef().setVar(newName).setArray(hdI.getArray()).setBits(hdI.getBits())); } final HDLUnit container = generation.getContainer(HDLUnit.class); if (!unit.getExtendRefName().isEmpty()) { ms.addTo(container, HDLUnit.fExtend, unit.getExtendRefName().toArray(new HDLQualifiedName[0])); } if (!unit.getAnnotations().isEmpty()) { ms.addTo(container, HDLUnit.fAnnotations, unit.getAnnotations().toArray(new HDLAnnotation[0])); } } String libURI = null; switch (apply.getClassType()) { case HDLPackage: libURI = ((HDLPackage) apply).getLibURI(); break; case HDLUnit: libURI = ((HDLUnit) apply).getLibURI(); break; default: libURI = apply.getContainer(HDLUnit.class).getLibURI(); break; } final HDLLibrary library = HDLLibrary.getLibrary(libURI); library.addSideFiles(generationInfo.files, src); } } return ms.apply(apply); } private static EnumSet<HDLDirection> doNotInit = EnumSet.of(HDLDirection.HIDDEN, HDLDirection.CONSTANT, HDLDirection.PARAMETER, HDLDirection.IN); /** * Generate the default initialization code for Arrays, Enums and Non * registers */ private static <T extends IHDLObject> T generateInitializations(T apply) { final ModificationSet ms = new ModificationSet(); final HDLVariableDeclaration[] allVarDecls = apply.getAllObjectsOf(HDLVariableDeclaration.class, true); for (final HDLVariableDeclaration hvd : allVarDecls) { final HDLUnit unit = hvd.getContainer(HDLUnit.class); if ((unit != null) && unit.getSimulation()) { continue; } if (!doNotInit.contains(hvd.getDirection())) { final HDLRegisterConfig register = hvd.getRegister(); for (final HDLVariable var : hvd.getVariables()) { final Set<String> meta = var.getMeta(Init.full); if ((meta != null) && (hvd.getRegister() == null) && (var.getDimensions().size() == 0)) { continue; } final HDLExpression defaultValue = getDefaultValue(hvd, register, var); if ((defaultValue != null) && (hvd.getContainer(HDLInterface.class) == null)) { final HDLVariableRef setVar = new HDLVariableRef().setVar(var.asRef()); generateInit(Collections.<HDLExpression> emptyList(), var.getDimensions(), ms, var, var, defaultValue, setVar); } } } } // Initialize all Interface instantiations by assigning the default // value to each Port final HDLInterfaceInstantiation[] hii = apply.getAllObjectsOf(HDLInterfaceInstantiation.class, true); for (final HDLInterfaceInstantiation hi : hii) { final HDLUnit unit = hi.getContainer(HDLUnit.class); if (unit.getSimulation()) { continue; } Set<String> meta = hi.getVar().getMeta(Init.full); final ArrayList<HDLExpression> ifDim = hi.getVar().getDimensions(); // Either no port is fully initialized, or we do have multiple // dimensions. // In the case that we do have multiple dimensions we ensure that // each dimensions is initialized. Because it might be possible that // we don't write each dimension if ((meta == null) || !ifDim.isEmpty()) { meta = Sets.newLinkedHashSet(); } final Optional<HDLInterface> hIf = hi.resolveHIf(); if (!hIf.isPresent()) { continue; } for (final HDLVariableDeclaration hvd : hIf.get().getPorts()) { final HDLDirection direction = hvd.getDirection(); // Only ports of direction IN need to be initialized if ((direction == HDLDirection.IN) || (direction == HDLDirection.INOUT)) { for (final HDLVariable var : hvd.getVariables()) { // If this port has a full assignment, we don't need to // initialize it. if (meta.contains(var.getName()) || var.hasMeta(IS_EXPORT)) { continue; } final ArrayList<HDLExpression> varDim = var.getDimensions(); final HDLExpression defaultValue = getDefaultValue(hvd, null, var); if (defaultValue != null) { final HDLVariableRef setVar = new HDLInterfaceRef().setHIf(hi.getVar().asRef()).setVar(var.asRef()); generateInit(ifDim, varDim, ms, var, hi.getContainer(HDLUnit.class), defaultValue, setVar); } } } } } return ms.apply(apply); } private static void generateInit(List<HDLExpression> ifDim, List<HDLExpression> varDim, ModificationSet ms, HDLVariable var, IHDLObject container, HDLExpression defaultValue, HDLVariableRef setVar) { boolean synchedArray = false; if (defaultValue instanceof HDLVariableRef) { final HDLVariableRef ref = (HDLVariableRef) defaultValue; synchedArray = ref.resolveVar().get().getDimensions().size() != 0; } HDLStatement init; if (defaultValue instanceof HDLArrayInit) { final HDLArrayInit hai = (HDLArrayInit) defaultValue; init = new HDLAssignment().setLeft(setVar).setRight(hai); } else { init = createArrayForLoop(ifDim, varDim, 0, defaultValue, setVar, synchedArray); } final HDLBlock obj = var.getMeta(RWValidation.BLOCK_META); if ((obj != null) && (obj != RWValidation.UNIT_BLOCK)) { insertFirstStatement(ms, obj, init); } else { insertFirstStatement(ms, container, init); } if (!(setVar instanceof HDLInterfaceRef)) { ms.replace(var, var.setDefaultValue(null)); } } /** * Returns the defaultvalue for the given Variable, taken the Type into * consideration. For Enums the first enum is returned. */ private static HDLExpression getDefaultValue(HDLVariableDeclaration hvd, HDLRegisterConfig register, HDLVariable var) { final HDLExpression defaultValue = var.getDefaultValue(); if ((defaultValue == null) && (register == null)) if ((hvd.getPrimitive() != null)) { if (var.getAnnotation(HDLBuiltInAnnotations.VHDLLatchable) == null) { switch (hvd.getPrimitive().getType()) { case STRING: return HDLLiteral.getString(""); case BOOL: return HDLLiteral.getFalse(); case BIT: case BITVECTOR: case INT: case INTEGER: case NATURAL: case UINT: case ANY_BIT: case ANY_INT: case ANY_UINT: return HDLLiteral.get(0); } } } else { final HDLType resolveType = hvd.resolveType().get(); if (resolveType instanceof HDLEnum) { final HDLEnum hEnum = (HDLEnum) resolveType; return (HDLExpression) new HDLEnumRef().setHEnum(FullNameExtension.fullNameOf(hEnum)).setVar(hEnum.getEnums().get(0).asRef()).freeze(hEnum); } } return defaultValue; } /** * Generate the code to initialize an array with the given default value. * * @param varDim * all dimensions that need to be filled * @param i * the current depth * @param defaultValue * the defaultValue to assign to each dimension * @param ref * the reference which will be used for writing * @param synchedArray * if <code>true</code> the defaultValue will become the same * dimension accesses as the variable * @param interfaceDim * if <code>true</code> the ref parameter will be treated as * HDLIinterfaceRef and gets the interface array filled * @return */ public static HDLStatement createArrayForLoop(List<HDLExpression> ifDim, List<HDLExpression> varDim, int i, HDLExpression defaultValue, HDLVariableRef ref, boolean synchedArray) { final boolean interfaceDim = i < ifDim.size(); if (i == (varDim.size() + ifDim.size())) return new HDLAssignment().setLeft(ref).setRight(defaultValue); final HDLExpression dim = interfaceDim ? ifDim.get(i) : varDim.get(i - ifDim.size()); final HDLRange range = new HDLRange().setFrom(HDLLiteral.get(0)).setTo(new HDLArithOp().setLeft(dim).setType(HDLArithOpType.MINUS).setRight(HDLLiteral.get(1))); final HDLVariable param = new HDLVariable().setName(getTempName("init", null)); final HDLForLoop loop = new HDLForLoop().setRange(HDLObject.asList(range)).setParam(param); final HDLVariableRef paramRef = new HDLVariableRef().setVar(param.asRef()); if (synchedArray) { final HDLVariableRef defRef = (HDLVariableRef) defaultValue; if (interfaceDim) { if (defRef instanceof HDLInterfaceRef) { defaultValue = ((HDLInterfaceRef) defRef).addIfArray(paramRef); } } else { defaultValue = defRef.addArray(paramRef); } } HDLVariableRef subRef; if (interfaceDim) { subRef = ((HDLInterfaceRef) ref).addIfArray(paramRef); } else { subRef = ref.addArray(paramRef); } return loop.addDos(createArrayForLoop(ifDim, varDim, i + 1, defaultValue, subRef, synchedArray)); } private static void insertFirstStatement(ModificationSet ms, IHDLObject container, HDLStatement stmnt) { if (container == null) // This can happen if the container is HDLPackage for example for // global constants return; if ((container.getClassType() != HDLClass.HDLUnit) && (container.getClassType() != HDLClass.HDLBlock)) { insertFirstStatement(ms, container.getContainer(), stmnt); return; } if (container instanceof HDLInterface) return; if (container instanceof HDLUnit) { final HDLUnit unit = (HDLUnit) container; ms.addTo(unit, HDLUnit.fInits, stmnt); } if (container instanceof HDLBlock) { final HDLBlock block = (HDLBlock) container; final HDLStatement statement = block.getStatements().get(0); ms.insertBefore(statement, stmnt); } } /** * Checks for the clock and reset annotation and replaces all $clk and $rst * references with it. It also inserts the clk and rst signals into the * HDLUnit if needed. * * @param unit * @return */ public static <T extends IHDLObject> T generateClkAndReset(T apply) { final ModificationSet ms = new ModificationSet(); final HDLUnit[] units = apply.getAllObjectsOf(HDLUnit.class, true); for (final HDLUnit unit : units) { HDLVariable defClkVar = HDLRegisterConfig.defaultClk(false).addAnnotations(HDLBuiltInAnnotations.clock.create(null)); HDLVariable defRstVar = HDLRegisterConfig.defaultRst(false).addAnnotations(HDLBuiltInAnnotations.reset.create(null)); boolean customClk = false, customRst = false; // Find all clock annotated Signals HDLVariable newVar = extractVar(unit, HDLBuiltInAnnotations.clock); if (newVar != null) { defClkVar = newVar; customClk = true; } newVar = extractVar(unit, HDLBuiltInAnnotations.reset); if (newVar != null) { defRstVar = newVar; customRst = true; } boolean hasClkRegister = false, hasRstRegister = false; // Replace all $clk and $rst with the clock in HDLRegisters final Collection<HDLRegisterConfig> clkRefs = HDLQuery.select(HDLRegisterConfig.class).from(unit).where(HDLRegisterConfig.fClk) .lastSegmentIs(HDLRegisterConfig.DEF_CLK).getAll(); for (final HDLRegisterConfig reg : clkRefs) { hasClkRegister = true; ms.replace(reg, reg.setClk(defClkVar.asHDLRef())); if (!customClk) { insertSig(ms, reg.getContainer(), defClkVar, SignalInserted.ClkInserted); } } final Collection<HDLRegisterConfig> rstRefs = HDLQuery.select(HDLRegisterConfig.class).from(unit).where(HDLRegisterConfig.fRst) .lastSegmentIs(HDLRegisterConfig.DEF_RST).getAll(); for (HDLRegisterConfig reg : rstRefs) { hasRstRegister = true; final HDLRegisterConfig orig = reg; reg = ms.getReplacement(reg); ms.replacePrune(orig, reg.setRst(defRstVar.asHDLRef())); if (!customRst) { insertSig(ms, orig.getContainer(), defRstVar, SignalInserted.RstInserted); } } boolean hasClkRef = false, hasRstRef = false; // Replace all $clk, $rst VariableRefs final Collection<HDLVariableRef> clkVarRefs = HDLQuery.select(HDLVariableRef.class).from(unit).where(HDLResolvedRef.fVar).lastSegmentIs(HDLRegisterConfig.DEF_CLK) .getAll(); for (final HDLVariableRef clkRef : clkVarRefs) { ms.replace(clkRef, defClkVar.asHDLRef()); hasClkRef = true; } final Collection<HDLVariableRef> rstVarRefs = HDLQuery.select(HDLVariableRef.class).from(unit).where(HDLResolvedRef.fVar).lastSegmentIs(HDLRegisterConfig.DEF_RST) .getAll(); for (final HDLVariableRef rstRef : rstVarRefs) { ms.replace(rstRef, defRstVar.asHDLRef()); hasRstRef = true; } if (hasClkRef && !hasClkRegister) { insertSig(ms, unit, defClkVar, SignalInserted.ClkInserted); } if (hasRstRef && !hasRstRegister) { insertSig(ms, unit, defRstVar, SignalInserted.RstInserted); } // Remove the insertion meta to allow the re-use of the same model unit.resetMeta(SignalInserted.RstInserted); unit.resetMeta(SignalInserted.ClkInserted); final HDLRegisterConfig[] regs = unit.getAllObjectsOf(HDLRegisterConfig.class, true); for (final HDLRegisterConfig reg : regs) { final HDLExpression clk = reg.getClk(); // If the signal is an expression or so if (clk instanceof HDLVariableRef) { final HDLVariableRef clkRef = (HDLVariableRef) clk; // If the signal has bit or array references (which are not // allowed in VHDL) if (!clkRef.getBits().isEmpty() || !clkRef.getArray().isEmpty()) { createTempBit(ms, reg, clk, "clock"); } } else { createTempBit(ms, reg, clk, "clock"); } final HDLExpression rst = reg.getRst(); // If the signal is an expression or so if (rst instanceof HDLVariableRef) { final HDLVariableRef rstRef = (HDLVariableRef) rst; // If the signal has bit or array references (which are not // allowed in VHDL) if (!rstRef.getBits().isEmpty() || !rstRef.getArray().isEmpty()) { createTempBit(ms, reg, rst, "reset"); } } else { createTempBit(ms, reg, rst, "reset"); } } } return ms.apply(apply); } protected static void createTempBit(final ModificationSet ms, final HDLRegisterConfig reg, final HDLExpression signalExpression, String prefix) { final HDLVariable tempClock = new HDLVariable().setName(getTempName(prefix, "buf")).setDefaultValue(signalExpression.copyFiltered(CopyFilter.DEEP_META)); ms.insertBefore(reg.getContainer(HDLStatement.class), new HDLVariableDeclaration().setType(HDLPrimitive.getBit()).addVariables(tempClock)); ms.replacePrune(signalExpression, tempClock.asHDLRef()); } private static HDLVariable extractVar(HDLObject apply, HDLBuiltInAnnotations annotation) { final HDLAnnotation clock = HDLQuery.select(HDLAnnotation.class).from(apply).where(HDLAnnotation.fName).isEqualTo(annotation.toString()).getFirst(); if (clock != null) { if (clock.getContainer() instanceof HDLVariableDeclaration) { final HDLVariableDeclaration hvd = (HDLVariableDeclaration) clock.getContainer(); return hvd.getVariables().get(0); } if (clock.getContainer() instanceof HDLVariable) return (HDLVariable) clock.getContainer(); } return null; } public static enum SignalInserted implements MetaAccess<Boolean> { ClkInserted, RstInserted; @Override public boolean inherit() { return false; } } private static void insertSig(ModificationSet ms, IHDLObject container, HDLVariable defVar, SignalInserted signalInserted) { if (container.getClassType() != HDLClass.HDLUnit) { insertSig(ms, container.getContainer(), defVar, signalInserted); return; } final boolean hasMeta = container.hasMeta(signalInserted); if (!hasMeta) { final HDLUnit unit = (HDLUnit) container; container.setMeta(signalInserted); final Result<HDLVariable, String> declarations = HDLQuery.select(HDLVariable.class).from(unit).where(HDLVariable.fName).isEqualTo(defVar.getName()); boolean insertDeclaration = true; for (final HDLVariable hvar : declarations.getAll()) { if (hvar.getContainer().getClassType() == HDLClass.HDLEnum) { continue; } insertDeclaration = false; break; } if (insertDeclaration) { final HDLStatement statement = unit.getStatements().get(0); final HDLPrimitive bit = HDLPrimitive.getBit(); ms.insertBefore(statement, new HDLVariableDeclaration().setDirection(HDLDirection.IN).setType(bit).addVariables(defVar)); } } } private static <T extends IHDLObject> T fortifyType(T apply) { final ModificationSet ms = new ModificationSet(); fortifyOpExpressions(apply, ms); fortifyAssignments(apply, ms); fortifyIfExpressions(apply, ms); fortifyRanges(apply, ms); fortifyWidthExpressions(apply, ms); fortifyDefaultAndResetExpressions(apply, ms); foritfyArrays(apply, ms); foritfyFunctions(apply, ms); foritfyConcats(apply, ms); fortifyTernaryOp(apply, ms); rewriteBoolCasts(apply, ms); return ms.apply(apply); } private static void rewriteBoolCasts(IHDLObject apply, ModificationSet ms) { final Collection<HDLManip> casts = HDLQuery.select(HDLManip.class).from(apply).where(HDLManip.fType).isEqualTo(HDLManipType.CAST).getAll(); for (final HDLManip manip : casts) { final HDLExpression target = manip.getTarget(); final Optional<? extends HDLType> tt = TypeExtension.typeOf(target); if (tt.isPresent()) { if ((tt.get().getType() == HDLPrimitiveType.BOOL) && (manip.getCastTo().getType() != HDLPrimitiveType.BOOL)) { final HDLTernary tern = new HDLTernary().setIfExpr(manip.getTarget()).setThenExpr(HDLLiteral.get(1)).setElseExpr(HDLLiteral.get(0)); ms.replace(manip, manip.setTarget(tern)); } } } } private static void fortifyTernaryOp(IHDLObject apply, ModificationSet ms) { final HDLTernary[] ternaries = apply.getAllObjectsOf(HDLTernary.class, true); for (final HDLTernary hdlTernary : ternaries) { final Optional<? extends HDLType> typeOf = TypeExtension.typeOf(hdlTernary.getThenExpr()); if (typeOf.isPresent()) { final HDLType type = typeOf.get(); if (type instanceof HDLPrimitive) { final HDLPrimitive pt = (HDLPrimitive) type; fortify(ms, hdlTernary.getElseExpr(), pt); } } } } private static void foritfyConcats(IHDLObject apply, ModificationSet ms) { final HDLConcat cats[] = apply.getAllObjectsOf(HDLConcat.class, true); for (final HDLConcat hdlConcat : cats) { final ArrayList<HDLExpression> catExp = hdlConcat.getCats(); for (final HDLExpression hdlExpression : catExp) { final HDLPrimitive typeOf = (HDLPrimitive) TypeExtension.typeOf(hdlExpression).get(); switch (typeOf.getType()) { case BIT: case BITVECTOR: continue; case INT: case UINT: cast(ms, typeOf.setType(HDLPrimitiveType.BITVECTOR), hdlExpression); break; default: throw new IllegalArgumentException("Type:" + typeOf + " not supported in concatenations"); } } } } private static void foritfyFunctions(IHDLObject apply, ModificationSet ms) { final HDLFunctionCall[] calls = apply.getAllObjectsOf(HDLFunctionCall.class, true); for (final HDLFunctionCall call : calls) { final Optional<HDLFunction> func = HDLFunctions.resolve(call); if (func.isPresent()) { final ArrayList<HDLExpression> params = call.getParams(); final ArrayList<HDLFunctionParameter> args = func.get().getArgs(); for (int j = 0; j < params.size(); j++) { final HDLExpression exp = params.get(j); fortify(ms, exp, TypeExtension.typeOf(args.get(j)).get()); } // TODO Re-implement! } } } private static void foritfyArrays(IHDLObject apply, ModificationSet ms) { final HDLVariableRef[] varRefs = apply.getAllObjectsOf(HDLVariableRef.class, true); for (final HDLVariableRef ref : varRefs) { for (final HDLExpression exp : ref.getArray()) { fortify(ms, exp, HDLPrimitive.getNatural()); } if (ref.getClassType() == HDLClass.HDLInterfaceRef) { final HDLInterfaceRef hir = (HDLInterfaceRef) ref; for (final HDLExpression exp : hir.getIfArray()) { fortify(ms, exp, HDLPrimitive.getNatural()); } } } } private static void fortifyWidthExpressions(IHDLObject apply, ModificationSet ms) { final HDLPrimitive[] primitives = apply.getAllObjectsOf(HDLPrimitive.class, true); for (final HDLPrimitive hdlPrimitive : primitives) { final HDLExpression width = hdlPrimitive.getWidth(); if (width != null) { fortify(ms, width, HDLPrimitive.getNatural()); } } } private static void fortifyDefaultAndResetExpressions(IHDLObject apply, ModificationSet ms) { final HDLVariableDeclaration[] primitives = apply.getAllObjectsOf(HDLVariableDeclaration.class, true); for (final HDLVariableDeclaration hvd : primitives) { final HDLRegisterConfig reg = hvd.getRegister(); final HDLType determineType = TypeExtension.typeOf(hvd).get(); if (reg != null) { final HDLExpression resetValue = reg.getResetValue(); if (!(resetValue instanceof HDLArrayInit)) { if (resetValue != null) { fortify(ms, resetValue, determineType); } } else { final HDLArrayInit hai = (HDLArrayInit) resetValue; fortifyArrayInitExp(ms, determineType, hai); } } for (final HDLVariable var : hvd.getVariables()) { final HDLExpression defaultValue = var.getDefaultValue(); if (!(defaultValue instanceof HDLArrayInit)) { if (defaultValue != null) { fortify(ms, defaultValue, determineType); } } else { final HDLArrayInit hai = (HDLArrayInit) defaultValue; fortifyArrayInitExp(ms, determineType, hai); } } } } private static void fortifyArrayInitExp(ModificationSet ms, HDLType determineType, HDLArrayInit hai) { for (final HDLExpression exp : hai.getExp()) { if (exp instanceof HDLArrayInit) { final HDLArrayInit subHai = (HDLArrayInit) exp; fortifyArrayInitExp(ms, determineType, subHai); } else { fortify(ms, exp, determineType); } } } private static void fortifyRanges(IHDLObject apply, ModificationSet ms) { final HDLRange[] ranges = apply.getAllObjectsOf(HDLRange.class, true); for (final HDLRange range : ranges) { if (BuiltInValidator.skipExp(range)) { continue; } final HDLExpression exp = range.getFrom(); if (exp != null) { fortify(ms, exp, HDLPrimitive.getNatural()); } fortify(ms, range.getTo(), HDLPrimitive.getNatural()); } } private static void fortifyIfExpressions(IHDLObject apply, ModificationSet ms) { final HDLIfStatement[] ifs = apply.getAllObjectsOf(HDLIfStatement.class, true); for (final HDLIfStatement assignment : ifs) { fortify(ms, assignment.getIfExp(), HDLPrimitive.getBool()); } final HDLTernary[] ternaries = apply.getAllObjectsOf(HDLTernary.class, true); for (final HDLTernary hdlTernary : ternaries) { fortify(ms, hdlTernary.getIfExpr(), HDLPrimitive.getBool()); } } /** * Ensures that the right hand-side can be assigned to the left hand-side. * This includes converting booleans to ternary operators. */ private static void fortifyAssignments(IHDLObject apply, ModificationSet ms) { final HDLAssignment[] assignments = apply.getAllObjectsOf(HDLAssignment.class, true); for (final HDLAssignment assignment : assignments) { if (BuiltInValidator.skipExp(assignment)) { continue; } final Optional<? extends HDLType> opLeft = TypeExtension.typeOf(assignment.getLeft()); final HDLType leftType = opLeft.get(); final HDLExpression exp = assignment.getRight(); final Optional<? extends HDLType> rightTypeOpt = TypeExtension.typeOf(exp); final HDLType rightType = rightTypeOpt.get(); if (exp.getClassType() == HDLClass.HDLArrayInit) { fortifyArrayInitExp(ms, leftType, (HDLArrayInit) exp); } else if ((rightType.getType() == HDLPrimitiveType.BOOL) && (leftType.getType() != HDLPrimitiveType.BOOL)) { final HDLTernary newIf = new HDLTernary().setIfExpr(exp).setThenExpr(HDLLiteral.get(1)).setElseExpr(HDLLiteral.get(0)); ms.replace(assignment, assignment.setRight(new HDLManip().setType(HDLManipType.CAST).setCastTo(leftType).setTarget(newIf))); } else if (leftType instanceof HDLPrimitive) { final HDLPrimitive pt = (HDLPrimitive) leftType; fortify(ms, exp, pt); } } } private static void fortifyOpExpressions(IHDLObject apply, ModificationSet ms) { final HDLExpression[] opEx = apply.getAllObjectsOf(HDLExpression.class, true); final HDLPrimitives instance = HDLPrimitives.getInstance(); for (final HDLExpression opExpression : opEx) { if (BuiltInValidator.skipExp(opExpression)) { continue; } HDLTypeInferenceInfo inferenceInfo = null; HDLExpression left = null; HDLExpression right = null; switch (opExpression.getClassType()) { case HDLArithOp: final HDLArithOp aop = (HDLArithOp) opExpression; left = aop.getLeft(); right = aop.getRight(); inferenceInfo = instance.getArithOpType(aop); break; case HDLShiftOp: final HDLShiftOp sop = (HDLShiftOp) opExpression; left = sop.getLeft(); right = sop.getRight(); inferenceInfo = instance.getShiftOpType(sop); break; case HDLBitOp: final HDLBitOp bop = (HDLBitOp) opExpression; left = bop.getLeft(); right = bop.getRight(); inferenceInfo = instance.getBitOpType(bop); break; case HDLEqualityOp: final HDLEqualityOp eop = (HDLEqualityOp) opExpression; left = eop.getLeft(); right = eop.getRight(); inferenceInfo = instance.getEqualityOpType(eop); break; case HDLManip: final HDLManip manip = (HDLManip) opExpression; left = manip.getTarget(); inferenceInfo = instance.getManipOpType(manip); break; default: } if (inferenceInfo != null) { if (inferenceInfo.error != null) throw new IllegalArgumentException("The expression " + opExpression + " has an error:" + inferenceInfo.error); fortify(ms, left, inferenceInfo.args[0]); if (right != null) { fortify(ms, right, inferenceInfo.args[1]); } } } } private static void cast(ModificationSet ms, HDLPrimitive targetType, HDLExpression exp) { ms.replace(exp, new HDLManip().setType(HDLManipType.CAST).setCastTo(targetType).setTarget(exp)); } private static void makeBool(ModificationSet ms, HDLExpression exp) { final HDLManip zero = new HDLManip().setType(HDLManipType.CAST).setCastTo(TypeExtension.typeOf(exp).get()).setTarget(HDLLiteral.get(0)); ms.replace(exp, new HDLEqualityOp().setLeft(exp).setType(HDLEqualityOpType.NOT_EQ).setRight(zero)); } private static void fortify(ModificationSet ms, HDLExpression exp, HDLType targetType) { if (targetType instanceof HDLPrimitive) { final HDLPrimitive pt = (HDLPrimitive) targetType; if (BuiltInValidator.skipExp(exp)) return; final Optional<? extends HDLType> lt = TypeExtension.typeOf(exp); if (lt.isPresent()) { final HDLType currentType = lt.get(); if (!targetType.equals(currentType)) { if (targetType instanceof AnyPrimitive) { final AnyPrimitive anyTarget = (AnyPrimitive) targetType; if (currentType instanceof AnyPrimitive) { final AnyPrimitive anyCurrent = (AnyPrimitive) currentType; System.out.println("Cast any " + anyCurrent + " to any " + anyTarget); } else { System.out.println("Cast " + currentType + " to any " + anyTarget); } } else { if (pt.getType() == HDLPrimitiveType.BOOL) { makeBool(ms, exp); } else { cast(ms, pt, exp); } } } } } } private static <T extends IHDLObject> T handlePostfixOp(T apply) { final ModificationSet ms = new ModificationSet(); final HDLAssignment[] loops = apply.getAllObjectsOf(HDLAssignment.class, true); for (final HDLAssignment hdlAssignment : loops) { final HDLOpExpression op = toOpExpression(hdlAssignment); if (op == null) { continue; } final HDLAssignment newAss = new HDLAssignment().setLeft(hdlAssignment.getLeft()).setType(HDLAssignmentType.ASSGN).setRight(op); ms.replace(hdlAssignment, newAss); } return ms.apply(apply); } public static HDLOpExpression toOpExpression(HDLAssignment hdlAssignment) { final HDLAssignmentType type = hdlAssignment.getType(); HDLOpExpression op = null; switch (type) { case DIV_ASSGN: op = new HDLArithOp().setType(HDLArithOpType.DIV); break; case MOD_ASSGN: op = new HDLArithOp().setType(HDLArithOpType.MOD); break; case MUL_ASSGN: op = new HDLArithOp().setType(HDLArithOpType.MUL); break; case ADD_ASSGN: op = new HDLArithOp().setType(HDLArithOpType.PLUS); break; case SUB_ASSGN: op = new HDLArithOp().setType(HDLArithOpType.MINUS); break; case AND_ASSGN: op = new HDLBitOp().setType(HDLBitOpType.AND); break; case OR_ASSGN: op = new HDLBitOp().setType(HDLBitOpType.OR); break; case XOR_ASSGN: op = new HDLBitOp().setType(HDLBitOpType.XOR); break; case SLL_ASSGN: op = new HDLShiftOp().setType(HDLShiftOpType.SLL); break; case SRA_ASSGN: op = new HDLShiftOp().setType(HDLShiftOpType.SRA); break; case SRL_ASSGN: op = new HDLShiftOp().setType(HDLShiftOpType.SRL); break; case ASSGN: return op; } if (op == null) return null; return op.setLeft(hdlAssignment.getLeft()).setRight(hdlAssignment.getRight()); } private static <T extends IHDLObject> T handleMultiForLoop(T apply) { final ModificationSet ms = new ModificationSet(); final HDLForLoop[] loops = apply.getAllObjectsOf(HDLForLoop.class, true); for (final HDLForLoop loop : loops) if (loop.getRange().size() > 1) { final HDLForLoop[] newLoops = new HDLForLoop[loop.getRange().size()]; int i = 0; for (final HDLRange r : loop.getRange()) { newLoops[i++] = loop.setRange(HDLObject.asList(r)); } ms.replace(loop, newLoops); } return ms.apply(apply); } private static AtomicInteger objectID = new AtomicInteger(); private static HashMap<String, IInsulinParticitant> participants; public static void resetID() { objectID.set(0); } public static String getTempName(String prefix, String suffix) { if ((prefix == null) && (suffix == null)) return "$tmp_" + objectID.incrementAndGet(); if (prefix == null) return "$tmp_" + objectID.incrementAndGet() + "_" + suffix; if (suffix == null) return "$tmp_" + prefix + "_" + objectID.incrementAndGet(); return "$tmp_" + prefix + "_" + objectID.incrementAndGet() + "_" + suffix; } public static <T extends IHDLObject> T handleMultiBitAccess(T apply, HDLEvaluationContext context) { final ModificationSet ms = new ModificationSet(); final HDLVariableRef[] refs = apply.getAllObjectsOf(HDLVariableRef.class, true); for (final HDLVariableRef ref : refs) { final ArrayList<HDLRange> bits = ref.getBits(); if (bits.size() > 1) { if (ref.getContainer() instanceof HDLAssignment) { final HDLAssignment ass = (HDLAssignment) ref.getContainer(); if (ass.getLeft() == ref) { // Multi Bit write access i.e b{1,2:3}=8; // variant 1 // b{1}=8>>((3-2)+1) // b{2:3}=8 // variant 2 // bit<widthOfResult> b_bitAcces=8; // b{1}=b_bitAcces{sumOfWidthRightToIdx}; // b{2:3}=b_bitAccess{from-min(from,to)+sumOfWidthRightToIdx:to-min(from,to)+sumOfWidthRightToIdx}; final List<HDLStatement> replacements = new LinkedList<HDLStatement>(); final Optional<BigInteger> constant = ConstantEvaluate.valueOf(ass.getRight(), context); if (constant.isPresent()) { BigInteger shift = BigInteger.ZERO; for (int j = bits.size() - 1; j >= 0; j--) { final HDLRange r = bits.get(j); final Optional<Range<BigInteger>> vr = RangeExtension.rangeOf(r, context); if (vr.isPresent()) { final BigInteger add = vr.get().upperEndpoint().subtract(vr.get().lowerEndpoint()).abs(); final BigInteger mask = BigInteger.ONE.shiftLeft(add.intValue() + 1).subtract(BigInteger.ONE); final BigInteger shifted = constant.get().shiftRight(shift.intValue()); final BigInteger res = shifted.and(mask); final HDLVariableRef newRef = ref.setBits(HDLObject.asList(r)); final HDLAssignment newAss = new HDLAssignment().setLeft(newRef).setType(ass.getType()).setRight(HDLLiteral.get(res)); replacements.add(newAss); shift = add.add(BigInteger.ONE); } else throw new IllegalArgumentException("Can not determine range of " + r + " for multi bit access"); } } else { final HDLQualifiedName varRefName = ref.getVarRefName(); final String varName = getTempName(varRefName.getLastSegment(), "bitAccess"); final HDLQualifiedName hVarName = new HDLQualifiedName(varName); replacements.add(new HDLVariableDeclaration().setType(TypeExtension.typeOf(ref).get()).addVariables(new HDLVariable().setName(varName))); replacements.add(new HDLAssignment().setLeft(new HDLVariableRef().setVar(hVarName)).setRight(ass.getRight())); BigInteger shift = BigInteger.ZERO; for (int j = bits.size() - 1; j >= 0; j--) { final HDLRange r = bits.get(j); final Optional<Range<BigInteger>> vr = RangeExtension.rangeOf(r, context); if (vr.isPresent()) { final BigInteger add = shift.add(vr.get().upperEndpoint().subtract(vr.get().lowerEndpoint()).abs()); final HDLRange newRange = new HDLRange().setTo(HDLLiteral.get(shift)).setFrom(HDLLiteral.get(add)).normalize(); final HDLExpression bitOp = new HDLVariableRef().setVar(hVarName).setBits(HDLObject.asList(newRange)); final HDLVariableRef newRef = ref.setBits(HDLObject.asList(r)); final HDLAssignment newAss = new HDLAssignment().setLeft(newRef).setType(ass.getType()).setRight(bitOp); replacements.add(newAss); shift = add.add(BigInteger.ONE); } else throw new IllegalArgumentException("Can not determine range of " + r + " for multi bit access"); } } ms.replace(ass, replacements.toArray(new HDLStatement[0])); } } // Multi bit read access // b{1,4:5} == b{1}#b{4:5} HDLConcat concat = new HDLConcat(); for (final HDLRange r : bits) { concat = concat.addCats(ref.setBits(HDLObject.asList(r))); } final HDLManip cast = new HDLManip().setType(HDLManipType.CAST).setCastTo(TypeExtension.typeOf(ref).get()).setTarget(concat); if (ref.getContainer() instanceof HDLManip) { final HDLManip manip = (HDLManip) ref.getContainer(); if (manip.getType() == HDLManipType.CAST) { ms.replace(ref, concat); } else { ms.replace(ref, cast); } } else { ms.replace(ref, cast); } } } T tmp = ms.apply(apply); if (tmp != apply) { tmp = handleMultiBitAccess(tmp, context); } return tmp; } private static <T extends IHDLObject> T handleOutPortRead(T orig) { final ModificationSet ms = new ModificationSet(); final Collection<HDLVariableDeclaration> list = HDLQuery.select(HDLVariableDeclaration.class).from(orig).where(HDLVariableDeclaration.fDirection) .isEqualTo(HDLDirection.OUT).getAll(); for (HDLVariableDeclaration hdv : list) { if (hdv.getContainer(HDLInterface.class) != null) { continue; } final HDLVariableDeclaration origHdv = hdv; for (final HDLVariable var : hdv.getVariables()) { final Integer readCount = var.getMeta(IntegerMeta.READ_COUNT); if (readCount != null) { // Create new Declaration out uint<W> bar=bar_OutRead; // Extract bar from declaration out uint<W> x,y,bar=5; // Create a new Declaration uint<W> bar_outRead=5; // Change all reference to bar_OutRead final HDLVariable outVar = var.setName(getTempName(var.getName(), "OutRead")); ms.insertAfter(origHdv, hdv.setRegister(null).setVariables(HDLObject.asList(var.setDefaultValue(outVar.asHDLRef())))); if (hdv.getVariables().size() == 1) { hdv = hdv.setDirection(HDLDirection.INTERNAL).setVariables(HDLObject.asList(outVar)); } else { HDLRegisterConfig register = null; if (hdv.getRegister() != null) { register = hdv.getRegister(); } ms.insertAfter(origHdv, new HDLVariableDeclaration().setRegister(register).setType(origHdv.resolveType().get()).addVariables(outVar)); hdv = hdv.removeVariables(var); } // Replace all read occourances with the new bar_outRead final HDLQualifiedName originalFQN = var.asRef(); final HDLQualifiedName newFQN = outVar.asRef(); final HDLVariableRef[] reads = hdv.getContainer().getAllObjectsOf(HDLVariableRef.class, true); for (final HDLVariableRef varRef : reads) if (varRef.getVarRefName().equals(originalFQN)) { ms.replace(varRef, varRef.setVar(newFQN)); } } } if (origHdv != hdv) { ms.replace(origHdv, hdv); } } return ms.apply(orig); } public static void init(CompilerInformation info, IServiceProvider sp) { participants = Maps.newLinkedHashMap(); for (final IInsulinParticitant iip : sp.getAllInsulinParticipants()) { final String name = iip.getName(); participants.put(name, iip); info.registeredInsulinParticipant.put(name, iip); } } }