1 /*
2  * Copyright (c) 2016 Helmut Neemann
3  * Use of this source code is governed by the GPL v3 license
4  * that can be found in the LICENSE file.
5  */
6 package de.neemann.digital.builder.circuit;
7 
8 import de.neemann.digital.analyse.DetermineJKStateMachine;
9 import de.neemann.digital.analyse.ModelAnalyserInfo;
10 import de.neemann.digital.analyse.expression.*;
11 import de.neemann.digital.analyse.expression.Not;
12 import de.neemann.digital.builder.BuilderException;
13 import de.neemann.digital.builder.BuilderInterface;
14 import de.neemann.digital.core.basic.*;
15 import de.neemann.digital.core.element.Keys;
16 import de.neemann.digital.core.element.Rotation;
17 import de.neemann.digital.core.flipflops.FlipflopD;
18 import de.neemann.digital.core.flipflops.FlipflopJK;
19 import de.neemann.digital.core.io.Const;
20 import de.neemann.digital.core.io.In;
21 import de.neemann.digital.core.io.Out;
22 import de.neemann.digital.core.io.Probe;
23 import de.neemann.digital.core.memory.DataField;
24 import de.neemann.digital.core.memory.LookUpTable;
25 import de.neemann.digital.core.wiring.Clock;
26 import de.neemann.digital.core.wiring.Splitter;
27 import de.neemann.digital.draw.elements.Circuit;
28 import de.neemann.digital.draw.elements.Tunnel;
29 import de.neemann.digital.draw.elements.VisualElement;
30 import de.neemann.digital.draw.elements.Wire;
31 import de.neemann.digital.draw.graphics.Vector;
32 import de.neemann.digital.draw.shapes.ShapeFactory;
33 import de.neemann.digital.gui.Settings;
34 import de.neemann.digital.lang.Lang;
35 
36 import java.util.*;
37 
38 import static de.neemann.digital.analyse.expression.Variable.isVar;
39 import static de.neemann.digital.analyse.expression.Variable.isVarOrNotVar;
40 import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
41 
42 /**
43  * Builder to create a circuit from a set of expressions.
44  * Is also able to create a finite state machine.
45  */
46 public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
47 
48     private final VariableVisitor variableVisitor;
49     private final ShapeFactory shapeFactory;
50     private final ArrayList<FragmentVariable> fragmentVariables;
51     private final ArrayList<Fragment> fragments;
52     private final HashMap<String, FragmentVisualElement> combinatorialOutputs;
53     private final ArrayList<Variable> sequentialVars;
54     private final ArrayList<FragmentVisualElement> flipflops;
55     private final ArrayList<Variable> desiredVarOrdering;
56     private final HashSet<String> varsToNet;
57     private final HashSet<String> localVarsUsed;
58     private int pos;
59     private boolean useLUT;
60     private boolean useJKff;
61     private ModelAnalyserInfo mai;
62     private int lutNumber;
63     private boolean resolveLocalVars;
64     private boolean wideShapes;
65 
66 
67     /**
68      * Creates a new builder.
69      *
70      * @param shapeFactory ShapeFactory which is set to the created VisualElements
71      */
CircuitBuilder(ShapeFactory shapeFactory)72     public CircuitBuilder(ShapeFactory shapeFactory) {
73         this(shapeFactory, null);
74     }
75 
76     /**
77      * Creates a new builder.
78      *
79      * @param shapeFactory ShapeFactory which is set to the created VisualElements
80      * @param varOrdering  the desired ordering of the variables, There may be more variables than required. Maybe null.
81      */
CircuitBuilder(ShapeFactory shapeFactory, ArrayList<Variable> varOrdering)82     public CircuitBuilder(ShapeFactory shapeFactory, ArrayList<Variable> varOrdering) {
83         this.shapeFactory = shapeFactory;
84         this.useJKff = false;
85         this.useLUT = false;
86         desiredVarOrdering = varOrdering;
87         variableVisitor = new VariableVisitor();
88         fragmentVariables = new ArrayList<>();
89         fragments = new ArrayList<>();
90         flipflops = new ArrayList<>();
91         combinatorialOutputs = new HashMap<>();
92         sequentialVars = new ArrayList<>();
93         varsToNet = new HashSet<>();
94         localVarsUsed = new HashSet<>();
95         wideShapes = Settings.getInstance().get(Keys.SETTINGS_IEEE_SHAPES);
96     }
97 
98     /**
99      * Allows the usage of local variables
100      *
101      * @param resolveLocalVars true if local variables should be resolved
102      * @return this for chained calls
103      */
setResolveLocalVars(boolean resolveLocalVars)104     public CircuitBuilder setResolveLocalVars(boolean resolveLocalVars) {
105         this.resolveLocalVars = resolveLocalVars;
106         return this;
107     }
108 
109     /**
110      * Enables the usage of JK flip flops
111      *
112      * @param useJKff true if JK ff should be used
113      * @return this for chained calls
114      */
setUseJK(boolean useJKff)115     public CircuitBuilder setUseJK(boolean useJKff) {
116         this.useJKff = useJKff;
117         return this;
118     }
119 
120     /**
121      * Enables the usage of LUTs
122      *
123      * @param useLUT true if LUTs should be used
124      * @return this for chained calls
125      */
setUseLUTs(boolean useLUT)126     public CircuitBuilder setUseLUTs(boolean useLUT) {
127         this.useLUT = useLUT;
128         return this;
129     }
130 
131     /**
132      * Enables wide shapes
133      *
134      * @param wideShapes true if wide shapes should be used
135      * @return this for chained calls
136      */
setWideShapes(boolean wideShapes)137     public CircuitBuilder setWideShapes(boolean wideShapes) {
138         this.wideShapes = wideShapes;
139         return this;
140     }
141 
142     /**
143      * Adds an expression to the circuit
144      *
145      * @param name       the output name
146      * @param expression the expression
147      * @return this for chained calls
148      * @throws BuilderException BuilderException
149      */
150     @Override
addCombinatorial(String name, Expression expression)151     public CircuitBuilder addCombinatorial(String name, Expression expression) throws BuilderException {
152         if (expression instanceof NamedExpression) {
153             name = ((NamedExpression) expression).getName();
154             expression = ((NamedExpression) expression).getExpression();
155         }
156 
157         Fragment fr = createFragment(expression);
158 
159         final FragmentVisualElement frag = new FragmentVisualElement(Out.DESCRIPTION, shapeFactory).setAttr(Keys.LABEL, name);
160         checkPinNumber(frag.getVisualElement());
161 
162         checkForLocalVars(expression);
163 
164         combinatorialOutputs.put(name, frag);
165 
166         fragments.add(new FragmentExpression(fr, frag));
167         expression.traverse(variableVisitor);
168         return this;
169     }
170 
checkForLocalVars(Expression expression)171     void checkForLocalVars(Expression expression) {
172         VariableVisitor vv = new VariableVisitor();
173         expression.traverse(vv);
174         for (Variable usedVar : vv.getVariables())
175             for (String createdVar : combinatorialOutputs.keySet())
176                 if (usedVar.getIdentifier().equals(createdVar))
177                     localVarsUsed.add(createdVar);
178     }
179 
180     /**
181      * Add a transition function of a state machine
182      *
183      * @param name       name of the state
184      * @param expression the expression describing next state
185      * @return this for chained calls
186      * @throws BuilderException BuilderException
187      */
188     @Override
addSequential(String name, Expression expression)189     public CircuitBuilder addSequential(String name, Expression expression) throws BuilderException {
190         boolean useDff = true;
191         long initValue = 0;
192         if (mai != null)
193             initValue = mai.getSequentialInitValue(name);
194 
195         if (useJKff) {
196             try {
197                 DetermineJKStateMachine jk = new DetermineJKStateMachine(name, expression);
198                 useDff = jk.isDFF();
199                 if (!useDff) {
200                     boolean isJequalK = new Equals(jk.getSimplifiedJ(), jk.getSimplifiedK()).isEqual();
201                     Fragment frJ = createFragment(jk.getSimplifiedJ());
202                     if (isJequalK) {
203                         FragmentVisualElement ff = new FragmentVisualElement(FlipflopJK.DESCRIPTION, shapeFactory)
204                                 .ignoreInput(1)
205                                 .setAttr(Keys.LABEL, name)
206                                 .setAttr(Keys.DEFAULT, initValue);
207                         flipflops.add(ff);
208                         FragmentSameInValue fsv = new FragmentSameInValue(ff);
209                         FragmentExpression fe = new FragmentExpression(fsv, new FragmentVisualElement(Tunnel.DESCRIPTION, shapeFactory).setAttr(Keys.NETNAME, name));
210                         fragments.add(new FragmentExpression(frJ, fe));
211                     } else {
212                         Fragment frK = createFragment(jk.getSimplifiedK());
213                         FragmentVisualElement ff = new FragmentVisualElement(FlipflopJK.DESCRIPTION, shapeFactory)
214                                 .ignoreInput(1)
215                                 .setAttr(Keys.LABEL, name)
216                                 .setAttr(Keys.DEFAULT, initValue);
217                         flipflops.add(ff);
218                         FragmentExpression fe = new FragmentExpression(ff, new FragmentVisualElement(Tunnel.DESCRIPTION, shapeFactory).setAttr(Keys.NETNAME, name));
219                         fragments.add(new FragmentExpression(Arrays.asList(frJ, frK), fe));
220                     }
221                 }
222             } catch (ExpressionException e) {
223                 throw new BuilderException(e.getMessage());
224             }
225         }
226         if (useDff) {
227             Fragment fr = createFragment(expression);
228             Fragment fe;
229             if (expression instanceof Constant)
230                 fe = new FragmentVisualElement(Tunnel.DESCRIPTION, shapeFactory).setAttr(Keys.NETNAME, name);
231             else {
232                 FragmentVisualElement ff = new FragmentVisualElement(FlipflopD.DESCRIPTION, shapeFactory)
233                         .setAttr(Keys.LABEL, name)
234                         .setAttr(Keys.DEFAULT, initValue);
235                 flipflops.add(ff);
236                 fe = new FragmentExpression(ff, new FragmentVisualElement(Tunnel.DESCRIPTION, shapeFactory).setAttr(Keys.NETNAME, name));
237             }
238             fragments.add(new FragmentExpression(fr, fe));
239         }
240 
241         checkForLocalVars(expression);
242 
243         expression.traverse(variableVisitor);
244         sequentialVars.add(new Variable(name));
245         return this;
246     }
247 
createFragment(Expression expression)248     private Fragment createFragment(Expression expression) throws BuilderException {
249         if (useLUT) {
250             if (isVarOrNotVar(expression) || expression instanceof Constant)
251                 return createBasicFragment(expression);
252 
253             if (expression instanceof Operation) {
254                 boolean allVars = true;
255                 for (Expression ex : ((Operation) expression).getExpressions()) {
256                     if (!isVarOrNotVar(ex))
257                         allVars = false;
258                 }
259                 if (allVars)
260                     return createBasicFragment(expression);
261             }
262 
263             return createLutFragment(expression);
264         } else
265             return createBasicFragment(expression);
266     }
267 
createLutFragment(Expression expression)268     private Fragment createLutFragment(Expression expression) throws BuilderException {
269         ArrayList<Variable> vars = new ArrayList<>(expression.traverse(new VariableVisitor()).getVariables());
270 
271         ArrayList<Fragment> frags = new ArrayList<>();
272         for (Variable v : vars) {
273             FragmentVariable fragmentVariable = new FragmentVariable(v, false);
274             fragmentVariables.add(fragmentVariable);
275             frags.add(0, fragmentVariable);
276         }
277 
278         final int size = 1 << vars.size();
279         DataField data = new DataField(size);
280         ContextFiller context = new ContextFiller(vars);
281         for (int i = 0; i < size; i++) {
282             context.setContextTo(i);
283             try {
284                 boolean r = expression.calculate(context);
285                 data.setData(i, r ? 1 : 0);
286             } catch (ExpressionException e) {
287                 throw new BuilderException(Lang.get("err_builder_couldNotFillLUT"), e);
288             }
289         }
290 
291         if (isXor(data.getData()))
292             return new FragmentExpression(frags, new FragmentVisualElement(XOr.DESCRIPTION, frags.size(), shapeFactory));
293         else if (isXNor(data.getData()))
294             return new FragmentExpression(frags, new FragmentVisualElement(XNOr.DESCRIPTION, frags.size(), shapeFactory));
295         else {
296             lutNumber++;
297             return new FragmentExpression(frags, new FragmentVisualElement(LookUpTable.DESCRIPTION, frags.size(), shapeFactory)
298                     .setAttr(Keys.LABEL, "L" + lutNumber)
299                     .setAttr(Keys.INPUT_COUNT, frags.size())
300                     .setAttr(Keys.DATA, data)
301                     .setAttr(Keys.BITS, 1));
302         }
303     }
304 
isXNor(long[] data)305     static boolean isXNor(long[] data) {
306         for (int i = 0; i < data.length; i++)
307             if ((Integer.bitCount(i) & 1) == data[i])
308                 return false;
309         return true;
310     }
311 
isXor(long[] data)312     static boolean isXor(long[] data) {
313         for (int i = 0; i < data.length; i++)
314             if (!((Integer.bitCount(i) & 1) == data[i]))
315                 return false;
316         return true;
317     }
318 
createBasicFragment(Expression expression)319     private Fragment createBasicFragment(Expression expression) throws BuilderException {
320         if (expression instanceof Operation) {
321             Operation op = (Operation) expression;
322             ArrayList<Fragment> frags = getOperationFragments(op);
323             if (op instanceof Operation.And)
324                 return new FragmentExpression(frags,
325                         new FragmentVisualElement(And.DESCRIPTION, frags.size(), shapeFactory)
326                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
327             else if (op instanceof Operation.Or)
328                 return new FragmentExpression(frags,
329                         new FragmentVisualElement(Or.DESCRIPTION, frags.size(), shapeFactory)
330                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
331             else if (op instanceof Operation.XOr)
332                 return new FragmentExpression(frags,
333                         new FragmentVisualElement(XOr.DESCRIPTION, frags.size(), shapeFactory)
334                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
335             else
336                 throw new BuilderException(Lang.get("err_builder_operationNotSupported", op.getClass().getSimpleName()));
337         } else if (expression instanceof Not) {
338             Not n = (Not) expression;
339             if (isVar(n.getExpression())) {
340                 FragmentVariable fragmentVariable = new FragmentVariable((Variable) n.getExpression(), true);
341                 fragmentVariables.add(fragmentVariable);
342                 return fragmentVariable;
343             } else if (n.getExpression() instanceof Operation.And) {
344                 ArrayList<Fragment> frags = getOperationFragments((Operation) n.getExpression());
345                 return new FragmentExpression(frags,
346                         new FragmentVisualElement(NAnd.DESCRIPTION, frags.size(), shapeFactory)
347                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
348             } else if (n.getExpression() instanceof Operation.Or) {
349                 ArrayList<Fragment> frags = getOperationFragments((Operation) n.getExpression());
350                 return new FragmentExpression(frags,
351                         new FragmentVisualElement(NOr.DESCRIPTION, frags.size(), shapeFactory)
352                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
353             } else if (n.getExpression() instanceof Operation.XOr) {
354                 ArrayList<Fragment> frags = getOperationFragments((Operation) n.getExpression());
355                 return new FragmentExpression(frags,
356                         new FragmentVisualElement(XNOr.DESCRIPTION, frags.size(), shapeFactory)
357                                 .setAttr(Keys.WIDE_SHAPE, wideShapes));
358             }
359             return new FragmentExpression(createBasicFragment(n.getExpression()), new FragmentVisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION, shapeFactory));
360         } else if (isVar(expression)) {
361             FragmentVariable fragmentVariable = new FragmentVariable((Variable) expression, false);
362             fragmentVariables.add(fragmentVariable);
363             return fragmentVariable;
364         } else if (expression instanceof Constant) {
365             long val = 0;
366             if (((Constant) expression).getValue())
367                 val = 1;
368             return new FragmentVisualElement(Const.DESCRIPTION, shapeFactory).setAttr(Keys.VALUE, val);
369         } else
370             throw new BuilderException(Lang.get("err_builder_exprNotSupported", expression.getClass().getSimpleName()));
371     }
372 
getOperationFragments(Operation op)373     private ArrayList<Fragment> getOperationFragments(Operation op) throws BuilderException {
374         ArrayList<Fragment> frags = new ArrayList<>();
375         for (Expression exp : op.getExpressions())
376             frags.add(createBasicFragment(exp));
377         return frags;
378     }
379 
createInputBus(Collection<Variable> inputs, Circuit circuit)380     private void createInputBus(Collection<Variable> inputs, Circuit circuit) {
381         HashMap<String, Integer> varPos = new HashMap<>();
382         int dx = -(inputs.size() * 3 - 1) * SIZE;
383         pos -= SIZE;
384         for (Variable v : inputs) {
385             VisualElement visualElement;
386             if (sequentialVars.contains(v) || varsToNet.contains(v.getIdentifier())) {
387                 visualElement = new VisualElement(Tunnel.DESCRIPTION.getName()).setShapeFactory(shapeFactory);
388                 visualElement.getElementAttributes()
389                         .set(Keys.ROTATE, new Rotation(1))
390                         .set(Keys.NETNAME, v.getIdentifier());
391             } else {
392                 visualElement = new VisualElement(In.DESCRIPTION.getName()).setShapeFactory(shapeFactory);
393                 visualElement.getElementAttributes()
394                         .set(Keys.ROTATE, new Rotation(3))
395                         .set(Keys.LABEL, v.getIdentifier());
396                 checkPinNumber(visualElement);
397             }
398             visualElement.setPos(new Vector(dx, -SIZE * 5));
399             circuit.add(visualElement);
400 
401             circuit.add(new Wire(new Vector(dx, -SIZE * 5), new Vector(dx, pos)));
402 
403             if (isNotNeeded(v.getIdentifier())) {
404                 visualElement = new VisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION.getName()).setShapeFactory(shapeFactory);
405                 visualElement.getElementAttributes()
406                         .set(Keys.ROTATE, new Rotation(3));
407                 visualElement.setPos(new Vector(dx + SIZE, -SIZE * 3));
408                 circuit.add(visualElement);
409 
410                 circuit.add(new Wire(new Vector(dx, -SIZE * 4), new Vector(dx + SIZE, -SIZE * 4)));
411                 circuit.add(new Wire(new Vector(dx + SIZE, -SIZE * 3), new Vector(dx + SIZE, -SIZE * 4)));
412                 circuit.add(new Wire(new Vector(dx + SIZE, -SIZE), new Vector(dx + SIZE, pos)));
413             }
414 
415             varPos.put(v.getIdentifier(), dx);
416             dx += SIZE * 3;
417         }
418 
419         for (FragmentVariable f : fragmentVariables) {
420             Vector p = f.getCircuitPos();
421             int in = varPos.get(f.getVariable().getIdentifier());
422             if (f.isInvert()) in += SIZE;
423             circuit.add(new Wire(p, new Vector(in, p.y)));
424         }
425     }
426 
isNotNeeded(String identifier)427     private boolean isNotNeeded(String identifier) {
428         for (FragmentVariable fv : fragmentVariables)
429             if (fv.isInvert() && fv.getVariable().getIdentifier().equals(identifier))
430                 return true;
431 
432         return false;
433     }
434 
addFragmentToCircuit(Fragment fr, Circuit circuit)435     private void addFragmentToCircuit(Fragment fr, Circuit circuit) {
436         fr.setPos(new Vector(0, 0));
437         Box b = fr.doLayout();
438 
439         if (fr.traverse(new FindLUTVisitor()).containsLUT())
440             pos += SIZE * 2;
441 
442         fr.addToCircuit(new Vector(0, pos), circuit);
443         pos += b.getHeight() + SIZE * 2;
444     }
445 
446     /**
447      * Creates the circuit
448      *
449      * @return the circuit
450      */
createCircuit()451     public Circuit createCircuit() {
452         if (resolveLocalVars)
453             resolveLocalVars();
454 
455         // determine maximum width
456         int maxWidth = 0;
457         for (Fragment f : fragments) {
458             Box b = f.doLayout();
459             if (maxWidth < b.getWidth()) maxWidth = b.getWidth();
460         }
461         // add space for clock wire!
462         if (!sequentialVars.isEmpty())
463             maxWidth += SIZE * 2;
464 
465         // set width to fragments
466         for (Fragment f : fragments) {
467             if (f instanceof FragmentExpression)
468                 ((FragmentExpression) f).setWidth(maxWidth);
469         }
470 
471         Circuit circuit = new Circuit();
472 
473         int outSplitterY = 0;
474         if (mai != null)
475             outSplitterY = checkForOutputBus(maxWidth + SIZE * 15, circuit);
476 
477         // add fragments to circuit
478         for (Fragment f : fragments)
479             addFragmentToCircuit(f, circuit);
480 
481         // order bus variables
482         Collection<Variable> variables = variableVisitor.getVariables();
483         if (desiredVarOrdering != null)
484             variables = order(variables, desiredVarOrdering);
485         if (!sequentialVars.isEmpty())
486             variables = order(variables, sequentialVars);
487 
488         if (mai != null)
489             checkForInputBus(variables, -SIZE * 5 - variables.size() * SIZE * 3, circuit);
490 
491         createInputBus(variables, circuit);
492 
493         // add clock
494         if (!flipflops.isEmpty())
495             addClockToFlipFlops(circuit);
496 
497         if (combinatorialOutputs.isEmpty())
498             outSplitterY = addNetConnections(circuit, maxWidth + SIZE * 17, outSplitterY);
499 
500         if (mai != null) {
501             final String stateVariableName = mai.getStateSignalName();
502             if (stateVariableName != null)
503                 outSplitterY = createStateVar(maxWidth + SIZE * 15, outSplitterY, circuit, stateVariableName);
504         }
505 
506         return circuit;
507     }
508 
resolveLocalVars()509     private void resolveLocalVars() {
510         for (String lv : localVarsUsed) {
511             varsToNet.add(lv);
512             FragmentVisualElement frag = combinatorialOutputs.get(lv);
513             frag.traverse(new ReplaceOutputByTunnel(lv, shapeFactory));
514         }
515     }
516 
checkForInputBus(Collection<Variable> variables, int splitterXPos, Circuit circuit)517     private void checkForInputBus(Collection<Variable> variables, int splitterXPos, Circuit circuit) {
518         StringBuilder pinString = new StringBuilder();
519         int y = 0;
520         for (Map.Entry<String, ArrayList<String>> e : mai.getInputBusMap().entrySet()) {
521             pinString.setLength(0);
522             int found = 0;
523             final ArrayList<String> inputs = e.getValue();
524             for (String n : inputs) {
525                 if (variables.contains(new Variable(n))) {
526                     found++;
527                     String p = mai.getPins().get(n);
528                     if (p != null) {
529                         if (pinString.length() != 0)
530                             pinString.append(",");
531                         pinString.append(p);
532                     }
533                 }
534             }
535             if (found == inputs.size()) {
536                 varsToNet.addAll(inputs);
537 
538                 circuit.add(new VisualElement(Splitter.DESCRIPTION.getName())
539                         .setAttribute(Keys.INPUT_SPLIT, "" + inputs.size())
540                         .setAttribute(Keys.OUTPUT_SPLIT, "1*" + inputs.size())
541                         .setPos(new Vector(splitterXPos, y))
542                         .setShapeFactory(shapeFactory));
543                 circuit.add(new VisualElement(In.DESCRIPTION.getName())
544                         .setAttribute(Keys.LABEL, e.getKey())
545                         .setAttribute(Keys.BITS, inputs.size())
546                         .setAttribute(Keys.PINNUMBER, pinString.toString())
547                         .setPos(new Vector(splitterXPos - 2 * SIZE, y))
548                         .setShapeFactory(shapeFactory));
549                 circuit.add(new Wire(
550                         new Vector(splitterXPos - 2 * SIZE, y),
551                         new Vector(splitterXPos, y)
552                 ));
553 
554                 for (int i = 0; i < inputs.size(); i++) {
555                     circuit.add(new VisualElement(Tunnel.DESCRIPTION.getName())
556                             .setAttribute(Keys.NETNAME, inputs.get(i))
557                             .setPos(new Vector(splitterXPos + 2 * SIZE, y + i * SIZE))
558                             .setShapeFactory(shapeFactory));
559                     circuit.add(new Wire(
560                             new Vector(splitterXPos + SIZE, y + i * SIZE),
561                             new Vector(splitterXPos + 2 * SIZE, y + i * SIZE)
562                     ));
563                 }
564 
565                 y += (inputs.size() + 2) * SIZE;
566             }
567         }
568     }
569 
checkForOutputBus(int splitterXPos, Circuit circuit)570     private int checkForOutputBus(int splitterXPos, Circuit circuit) {
571         StringBuilder pinString = new StringBuilder();
572         int y = 0;
573         for (Map.Entry<String, ArrayList<String>> e : mai.getOutputBusMap().entrySet()) {
574             pinString.setLength(0);
575             int found = 0;
576             final ArrayList<String> outputs = e.getValue();
577             for (String n : outputs) {
578                 if (combinatorialOutputs.containsKey(n)) {
579                     found++;
580                     String p = mai.getPins().get(n);
581                     if (p != null) {
582                         if (pinString.length() != 0)
583                             pinString.append(",");
584                         pinString.append(p);
585                     }
586                 }
587             }
588             if (found == outputs.size()) {
589 
590                 circuit.add(new VisualElement(Splitter.DESCRIPTION.getName())
591                         .setAttribute(Keys.OUTPUT_SPLIT, "" + outputs.size())
592                         .setAttribute(Keys.INPUT_SPLIT, "1*" + outputs.size())
593                         .setPos(new Vector(splitterXPos, y))
594                         .setShapeFactory(shapeFactory));
595                 circuit.add(new VisualElement(Out.DESCRIPTION.getName())
596                         .setAttribute(Keys.LABEL, e.getKey())
597                         .setAttribute(Keys.BITS, outputs.size())
598                         .setAttribute(Keys.PINNUMBER, pinString.toString())
599                         .setPos(new Vector(splitterXPos + 3 * SIZE, y))
600                         .setShapeFactory(shapeFactory));
601                 circuit.add(new Wire(
602                         new Vector(splitterXPos + 3 * SIZE, y),
603                         new Vector(splitterXPos + SIZE, y)
604                 ));
605 
606                 for (int i = 0; i < outputs.size(); i++) {
607                     circuit.add(new VisualElement(Tunnel.DESCRIPTION.getName())
608                             .setAttribute(Keys.NETNAME, outputs.get(i))
609                             .setRotation(2)
610                             .setPos(new Vector(splitterXPos - SIZE, y + i * SIZE))
611                             .setShapeFactory(shapeFactory));
612                     circuit.add(new Wire(
613                             new Vector(splitterXPos - SIZE, y + i * SIZE),
614                             new Vector(splitterXPos, y + i * SIZE)
615                     ));
616 
617                     FragmentVisualElement frag = combinatorialOutputs.get(outputs.get(i));
618                     frag.setVisualElement(new VisualElement(Tunnel.DESCRIPTION.getName())
619                             .setShapeFactory(shapeFactory)
620                             .setAttribute(Keys.NETNAME, outputs.get(i)));
621                 }
622 
623                 y += (outputs.size() + 2) * SIZE;
624             }
625         }
626         return y;
627     }
628 
createStateVar(int splitterXPos, int y, Circuit circuit, String name)629     private int createStateVar(int splitterXPos, int y, Circuit circuit, String name) {
630         ArrayList<Variable> outputs = sequentialVars;
631         outputs.sort(Comparator.comparing(Variable::getIdentifier));
632 
633         circuit.add(new VisualElement(Splitter.DESCRIPTION.getName())
634                 .setAttribute(Keys.OUTPUT_SPLIT, "" + outputs.size())
635                 .setAttribute(Keys.INPUT_SPLIT, "1*" + outputs.size())
636                 .setPos(new Vector(splitterXPos, y))
637                 .setShapeFactory(shapeFactory));
638         circuit.add(new VisualElement(Probe.DESCRIPTION.getName())
639                 .setAttribute(Keys.LABEL, name)
640                 .setAttribute(Keys.BITS, outputs.size())
641                 .setPos(new Vector(splitterXPos + 3 * SIZE, y))
642                 .setShapeFactory(shapeFactory));
643         circuit.add(new Wire(
644                 new Vector(splitterXPos + 3 * SIZE, y),
645                 new Vector(splitterXPos + SIZE, y)
646         ));
647 
648         for (int i = 0; i < outputs.size(); i++) {
649             circuit.add(new VisualElement(Tunnel.DESCRIPTION.getName())
650                     .setAttribute(Keys.NETNAME, outputs.get(i).getIdentifier())
651                     .setRotation(2)
652                     .setPos(new Vector(splitterXPos - SIZE, y + i * SIZE))
653                     .setShapeFactory(shapeFactory));
654             circuit.add(new Wire(
655                     new Vector(splitterXPos - SIZE, y + i * SIZE),
656                     new Vector(splitterXPos, y + i * SIZE)
657             ));
658         }
659 
660         y += (outputs.size() + 2) * SIZE;
661 
662         return y;
663     }
664 
665 
666     /**
667      * Move the lastItems to the end of the variables list.
668      * Items which are not in lastItems are placed at the beginning of the result list
669      *
670      * @param variables the variables to order
671      * @param lastItems the items to be placed at the end of the list
672      * @return the ordered list
673      */
order(Collection<T> variables, ArrayList<T> lastItems)674     private static <T> ArrayList<T> order(Collection<T> variables, ArrayList<T> lastItems) {
675         ArrayList<T> vars = new ArrayList<>(variables);
676         for (T seq : lastItems)
677             if (vars.contains(seq)) {
678                 vars.remove(seq); // move to end
679                 vars.add(seq);
680             }
681         return vars;
682     }
683 
addClockToFlipFlops(Circuit circuit)684     private void addClockToFlipFlops(Circuit circuit) {
685         int x = Integer.MAX_VALUE;
686         int yMin = Integer.MAX_VALUE;
687         int yMax = Integer.MIN_VALUE;
688         for (FragmentVisualElement ff : flipflops) {
689             Vector p = ff.getVisualElement().getPos();
690             if (p.x < x) x = p.x;
691             if (p.y < yMin) yMin = p.y;
692             if (p.y > yMax) yMax = p.y;
693         }
694         x -= SIZE;
695         if (useJKff) x -= SIZE;
696 
697         int yPos = yMin - SIZE * 3;
698         if (useJKff) yPos = -SIZE;
699 
700         circuit.add(new Wire(new Vector(x, yPos), new Vector(x, yMax + SIZE)));
701 
702         for (FragmentVisualElement ff : flipflops) {
703             Vector p = ff.getVisualElement().getPos();
704             circuit.add(new Wire(new Vector(x, p.y + SIZE), new Vector(p.x, p.y + SIZE)));
705         }
706 
707         VisualElement clock = new VisualElement(Clock.DESCRIPTION.getName())
708                 .setShapeFactory(shapeFactory)
709                 .setPos(new Vector(x, yPos));
710         clock.getElementAttributes()
711                 .set(Keys.LABEL, "C")
712                 .set(Keys.ROTATE, new Rotation(3))
713                 .set(Keys.FREQUENCY, 2)
714                 .set(Keys.RUN_AT_REAL_TIME, true);
715         circuit.add(clock);
716     }
717 
addNetConnections(Circuit circuit, int xPos, int y)718     private int addNetConnections(Circuit circuit, int xPos, int y) {
719         for (Variable name : sequentialVars) {
720             String oName = name.getIdentifier();
721             if (oName.endsWith("n")) {
722                 oName = oName.substring(0, oName.length() - 1);
723                 if (oName.endsWith("_") || oName.endsWith("^")) oName = oName.substring(0, oName.length() - 1);
724             }
725             if (!combinatorialOutputs.containsKey(oName)) {
726                 VisualElement t = new VisualElement(Tunnel.DESCRIPTION.getName()).setShapeFactory(shapeFactory);
727                 t.getElementAttributes().set(Keys.NETNAME, name.getIdentifier());
728                 t.setPos(new Vector(xPos, y));
729                 t.setRotation(2);
730                 circuit.add(t);
731                 VisualElement o = new VisualElement(Out.DESCRIPTION.getName()).setShapeFactory(shapeFactory);
732                 o.getElementAttributes().set(Keys.LABEL, oName);
733                 o.setPos(new Vector(xPos + SIZE, y));
734                 checkPinNumber(o);
735                 circuit.add(o);
736                 circuit.add(new Wire(new Vector(xPos, y), new Vector(xPos + SIZE, y)));
737                 y += SIZE * 2;
738             }
739         }
740         return y;
741     }
742 
checkPinNumber(VisualElement pin)743     private void checkPinNumber(VisualElement pin) {
744         if (mai != null) {
745             String name = pin.getElementAttributes().getLabel();
746             String num = mai.getPins().get(name);
747             if (num != null && num.length() > 0) {
748                 pin.getElementAttributes().set(Keys.PINNUMBER, num);
749             }
750         }
751     }
752 
753     /**
754      * Sets the infos obtained from the model
755      *
756      * @param modelAnalyserInfo the model analyzer infos
757      * @return this for chained calls
758      */
setModelAnalyzerInfo(ModelAnalyserInfo modelAnalyserInfo)759     public CircuitBuilder setModelAnalyzerInfo(ModelAnalyserInfo modelAnalyserInfo) {
760         mai = modelAnalyserInfo;
761         return this;
762     }
763 
764     private static final class FindLUTVisitor implements FragmentVisitor {
765         private boolean hasLUT = false;
766 
767         @Override
visit(Fragment fr)768         public void visit(Fragment fr) {
769             if (fr instanceof FragmentVisualElement) {
770                 if (((FragmentVisualElement) fr).getVisualElement().equalsDescription(LookUpTable.DESCRIPTION))
771                     hasLUT = true;
772             }
773         }
774 
containsLUT()775         private boolean containsLUT() {
776             return hasLUT;
777         }
778     }
779 
780     private static final class ReplaceOutputByTunnel implements FragmentVisitor {
781         private final String outName;
782         private final ShapeFactory shapeFactory;
783 
ReplaceOutputByTunnel(String outName, ShapeFactory shapeFactory)784         private ReplaceOutputByTunnel(String outName, ShapeFactory shapeFactory) {
785             this.outName = outName;
786             this.shapeFactory = shapeFactory;
787         }
788 
789         @Override
visit(Fragment fr)790         public void visit(Fragment fr) {
791             if (fr instanceof FragmentVisualElement) {
792                 FragmentVisualElement fve = (FragmentVisualElement) fr;
793                 VisualElement ve = fve.getVisualElement();
794                 if (ve.equalsDescription(Out.DESCRIPTION) && ve.getElementAttributes().getLabel().equals(outName)) {
795                     fve.setVisualElement(
796                             new VisualElement(Tunnel.DESCRIPTION.getName())
797                                     .setAttribute(Keys.NETNAME, outName)
798                                     .setShapeFactory(shapeFactory));
799                 }
800             }
801         }
802     }
803 }
804