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