From ab30ade81a2958d9440a7067165d1bbc93ab3dae Mon Sep 17 00:00:00 2001 From: ThatDeparted2061 Date: Sat, 14 Jun 2025 22:41:49 +0530 Subject: [PATCH 1/3] chore: Sync src to v0/src and v1/src --- v0/src/assets/constants/theme.ts | 17 + .../DialogBox/CombinationalAnalysis.vue | 412 +- v0/src/components/DialogBox/ExportProject.vue | 4 +- v0/src/components/DialogBox/ExportVerilog.vue | 6 +- .../components/DialogBox/InsertSubcircuit.vue | 2 +- v0/src/components/DialogBox/OpenOffline.vue | 83 +- .../DialogBox/Themes/ApplyThemes.vue | 101 +- v0/src/components/Extra.vue | 399 +- v0/src/components/Logo/Logo.vue | 4 +- .../Navbar/Hamburger/Hamburger2.vue | 142 + v0/src/components/Navbar/Navbar.css | 2 +- v0/src/components/Navbar/Navbar.vue | 34 +- .../NavbarLinks/NavbarLink/NavbarLink2.vue | 121 + .../Navbar/NavbarLinks/NavbarLinks.vue | 4 +- .../Navbar/QuickButton/QuickButton.ts | 37 + .../Navbar/QuickButton/QuickButton.vue | 104 +- .../Navbar/QuickButton/QuickButtonMobile.vue | 172 + v0/src/components/Navbar/User/UserMenu.vue | 190 + .../Panels/ElementsPanel/ElementsPanel.ts | 25 + .../Panels/ElementsPanel/ElementsPanel.vue | 42 +- .../ElementsPanel/ElementsPanelMobile.vue | 329 + .../LayoutElementsPanel.vue | 94 + .../LayoutProperty/LayoutProperty.vue | 25 +- .../ModuleProperty/ModuleProperty.vue | 4 +- .../ProjectProperty/ProjectProperty.vue | 31 +- .../Panels/PropertiesPanel/PropertiesPanel.ts | 66 + .../PropertiesPanel/PropertiesPanel.vue | 67 +- .../PropertiesPanel/PropertiesPanelMobile.vue | 177 + .../components/Panels/Shared/InputGroups.vue | 14 + .../TestBenchPanel/TestBenchCreator.vue | 592 ++ .../Panels/TestBenchPanel/TestBenchPanel.vue | 134 + .../TestBenchPanel/TestBenchValidator.vue | 106 + .../TimingDiagramButtons.vue | 28 +- .../TimingDiagramMobile.vue | 74 + .../TimingDiagramPanel/TimingDiagramPanel.ts | 42 + .../TimingDiagramPanel/TimingDiagramPanel.vue | 66 +- .../VerilogEditorPanel/VerilogEditorPanel.vue | 2 +- .../VerilogEditorPanelMobile.vue | 100 + .../ReportIssue/ReportIssueButton.vue | 4 + v0/src/components/TabsBar/TabsBar.vue | 27 +- .../helpers/deleteCircuit/DeleteCircuit.vue | 6 +- v0/src/env.d.ts | 6 + v0/src/globalVariables.ts | 4 - v0/src/locales/bn.json | 151 + v0/src/locales/en.json | 5 + v0/src/locales/hi.json | 5 + v0/src/locales/i18n.ts | 14 +- v0/src/main.ts | 1 - v0/src/pages/embed.vue | 30 +- v0/src/pages/simulatorHandler.vue | 11 +- v0/src/router/index.ts | 2 +- v0/src/simulator/spec/bitConvertor.spec.js | 88 + .../Decoders-plexers-circuitdata.json | 2430 ++--- .../spec/circuits/alu-circuitdata.json | 8377 +++++++++++++++++ .../spec/circuits/gates-circuitdata.json | 1565 +-- .../spec/circuits/misc-circuitdata.json | 1572 ++++ .../rippleCarryAdder-circuitdata.json | 3109 ++++++ .../spec/circuits/sequential-circuitdata.json | 1184 +++ .../spec/circuits/subCircuit-circuitdata.json | 814 ++ .../spec/combinationalAnalysis.spec.js | 92 + v0/src/simulator/spec/complexCircuit.spec.js | 96 + v0/src/simulator/spec/data.spec.js | 189 +- .../simulator/spec/decoders-plexers.spec.js | 115 + v0/src/simulator/spec/gates.spec.js | 160 +- v0/src/simulator/spec/misc.spec.js | 130 + v0/src/simulator/spec/sequential.spec.js | 105 + v0/src/simulator/spec/subCircuit.spec.js | 85 + .../simulator/spec/testData/alu-testdata.json | 108 + .../spec/testData/decoders-plexers.json | 401 + .../spec/testData/gates-testdata.json | 492 +- .../spec/testData/misc-testdata.json | 959 ++ .../spec/testData/ripple-carry-adder.json | 92 + .../spec/testData/sequential-testdata.json | 250 + .../spec/testData/subCircuit-testdata.json | 86 + v0/src/simulator/spec/vitestSetup.ts | 11 + v0/src/simulator/src/Verilog2CV.js | 45 +- v0/src/simulator/src/VerilogClasses.js | 40 - v0/src/simulator/src/{app.js => app.ts} | 14 +- v0/src/simulator/src/arrayHelpers.js | 34 - v0/src/simulator/src/backgroundArea.js | 17 - v0/src/simulator/src/backgroundArea.ts | 20 + v0/src/simulator/src/canvas2svg.js | 1433 --- v0/src/simulator/src/canvasApi.js | 21 +- .../simulator/src/{circuit.js => circuit.ts} | 220 +- v0/src/simulator/src/circuitElement.js | 34 +- v0/src/simulator/src/combinationalAnalysis.js | 950 +- v0/src/simulator/src/contention.ts | 123 + v0/src/simulator/src/data.js | 20 +- v0/src/simulator/src/data/backupCircuit.js | 2 + v0/src/simulator/src/data/load.js | 9 +- .../src/data/{project.js => project.ts} | 28 +- v0/src/simulator/src/data/redo.js | 47 - v0/src/simulator/src/data/redo.ts | 76 + v0/src/simulator/src/data/save.js | 57 +- v0/src/simulator/src/data/saveImage.js | 18 - v0/src/simulator/src/data/saveImage.ts | 16 + v0/src/simulator/src/data/undo.js | 51 - v0/src/simulator/src/data/undo.ts | 82 + v0/src/simulator/src/embed.js | 2 +- v0/src/simulator/src/embedListeners.js | 373 +- v0/src/simulator/src/engine.js | 35 +- .../src/simulator/src/eventQueue.ts | 31 +- v0/src/simulator/src/events.js | 25 +- .../src/hotkey_binder/defaultKeys.ts | 5 +- .../src/hotkey_binder/model/actions.js | 205 - .../src/hotkey_binder/model/actions.ts | 340 + .../model/{addShortcut.js => addShortcut.ts} | 61 +- .../src/hotkey_binder/model/model.types.ts | 25 + .../hotkey_binder/model/shortcuts.plugin.js | 250 - .../hotkey_binder/model/shortcuts.plugin.ts | 232 + .../src/hotkey_binder/model/utils.js | 67 - .../src/hotkey_binder/model/utils.ts | 74 + .../simulator/src/interface/backgroundArea.ts | 6 + .../simulator/src/interface/simulationArea.ts | 39 + .../src/simulator/src/layout/layoutBuffer.ts | 17 +- .../src/simulator/src/layout/layoutNode.ts | 29 +- .../src/{layoutMode.js => layoutMode.ts} | 96 +- v0/src/simulator/src/listeners.js | 810 +- v0/src/simulator/src/metadata.json | 179 - v0/src/simulator/src/metadata.ts | 191 + v0/src/simulator/src/minimap.js | 3 +- v0/src/simulator/src/moduleSetup.js | 2 +- v0/src/simulator/src/modules.js | 2 +- v0/src/simulator/src/modules/ALU.js | 4 +- v0/src/simulator/src/modules/Adder.js | 2 +- v0/src/simulator/src/modules/AndGate.js | 6 +- v0/src/simulator/src/modules/Arrow.js | 8 +- v0/src/simulator/src/modules/BitSelector.js | 4 +- v0/src/simulator/src/modules/Buffer.js | 7 +- v0/src/simulator/src/modules/Button.js | 6 +- v0/src/simulator/src/modules/ConstantVal.js | 4 +- .../src/modules/ControlledInverter.js | 17 +- v0/src/simulator/src/modules/Counter.js | 4 +- v0/src/simulator/src/modules/Decoder.js | 40 +- v0/src/simulator/src/modules/Demultiplexer.js | 4 +- v0/src/simulator/src/modules/DigitalLed.js | 15 +- v0/src/simulator/src/modules/Flag.js | 11 +- v0/src/simulator/src/modules/Ground.js | 28 +- v0/src/simulator/src/modules/HexDisplay.js | 12 +- .../simulator/src/modules/ImageAnnotation.js | 7 +- v0/src/simulator/src/modules/Input.js | 5 +- v0/src/simulator/src/modules/LSB.js | 11 +- v0/src/simulator/src/modules/MSB.js | 11 +- v0/src/simulator/src/modules/Multiplexer.js | 8 +- v0/src/simulator/src/modules/NandGate.js | 7 +- v0/src/simulator/src/modules/NorGate.js | 10 +- v0/src/simulator/src/modules/NotGate.js | 11 +- v0/src/simulator/src/modules/OrGate.js | 175 - v0/src/simulator/src/modules/OrGate.ts | 133 + v0/src/simulator/src/modules/Output.js | 21 +- v0/src/simulator/src/modules/Power.js | 10 +- .../simulator/src/modules/PriorityEncoder.js | 10 +- v0/src/simulator/src/modules/RGBLed.js | 12 +- v0/src/simulator/src/modules/RGBLedMatrix.js | 5 +- v0/src/simulator/src/modules/Random.js | 4 +- v0/src/simulator/src/modules/Rectangle.js | 8 +- .../simulator/src/modules/SevenSegDisplay.js | 7 +- .../src/modules/SixteenSegDisplay.js | 8 +- v0/src/simulator/src/modules/Splitter.js | 57 +- v0/src/simulator/src/modules/SquareRGBLed.js | 9 +- v0/src/simulator/src/modules/Stepper.js | 7 +- v0/src/simulator/src/modules/Text.js | 9 +- v0/src/simulator/src/modules/TriState.js | 18 +- v0/src/simulator/src/modules/Tunnel.js | 28 +- v0/src/simulator/src/modules/TwoComplement.js | 10 +- v0/src/simulator/src/modules/VariableLed.js | 17 +- v0/src/simulator/src/modules/XnorGate.js | 8 +- v0/src/simulator/src/modules/XorGate.js | 10 +- .../simulator/src/modules/verilogDivider.js | 5 +- .../src/modules/verilogMultiplier.js | 5 +- v0/src/simulator/src/modules/verilogPower.js | 5 +- .../simulator/src/modules/verilogShiftLeft.js | 5 +- .../src/modules/verilogShiftRight.js | 5 +- v0/src/simulator/src/node.js | 181 +- v0/src/simulator/src/plotArea.js | 88 +- .../src/simulator/src/quinMcCluskey.ts | 41 +- v0/src/simulator/src/sequential.js | 17 +- v0/src/simulator/src/sequential/Clock.js | 5 +- v0/src/simulator/src/sequential/DflipFlop.js | 10 +- v0/src/simulator/src/sequential/Dlatch.js | 16 +- v0/src/simulator/src/sequential/EEPROM.js | 3 - v0/src/simulator/src/sequential/ForceGate.js | 92 + v0/src/simulator/src/sequential/JKflipFlop.js | 11 +- v0/src/simulator/src/sequential/Keyboard.js | 7 +- v0/src/simulator/src/sequential/RAM.js | 9 +- v0/src/simulator/src/sequential/Rom.js | 7 +- v0/src/simulator/src/sequential/SRflipFlop.js | 20 +- v0/src/simulator/src/sequential/TTY.js | 17 +- v0/src/simulator/src/sequential/TflipFlop.js | 9 +- v0/src/simulator/src/sequential/verilogRAM.js | 45 +- v0/src/simulator/src/setup.js | 48 +- v0/src/simulator/src/simulationArea.js | 99 - v0/src/simulator/src/simulationArea.ts | 70 + v0/src/simulator/src/subcircuit.js | 79 +- v0/src/simulator/src/testCreator.js | 780 -- v0/src/simulator/src/testbench.js | 1140 --- v0/src/simulator/src/testbench.ts | 761 ++ v0/src/simulator/src/testbench/ForceGate.js | 2 +- .../simulator/src/testbench/testbenchInput.js | 5 +- .../src/testbench/testbenchOutput.js | 36 +- ...straction.js => customThemeAbstraction.ts} | 19 +- v0/src/simulator/src/themer/customThemer.js | 154 - v0/src/simulator/src/themer/customThemer.vue | 174 + .../{themeCardSvg.js => themeCardSvg.ts} | 7 +- v0/src/simulator/src/themer/themer.js | 223 - v0/src/simulator/src/themer/themer.ts | 218 + v0/src/simulator/src/themer/themer.types.ts | 13 + .../src/simulator/src/themer/themes.ts | 8 +- v0/src/simulator/src/tutorials.js | 29 +- v0/src/simulator/src/types/app.types.ts | 33 + v0/src/simulator/src/{utils.js => utils.ts} | 213 +- v0/src/simulator/src/ux.js | 513 +- v0/src/simulator/src/verilog.js | 76 +- v0/src/simulator/src/verilogHelpers.js | 1 - v0/src/simulator/src/wire.js | 240 - v0/src/simulator/src/wire.ts | 265 + v0/src/simulator/vendor/canvas2svg.js | 1469 --- v0/src/store/SimulatorStore/actions.ts | 18 +- v0/src/store/SimulatorStore/state.ts | 44 +- v0/src/store/authStore.ts | 14 +- v0/src/store/layoutStore.ts | 84 + v0/src/store/propertiesPanelStore.ts | 24 + v0/src/store/simulatorMobileStore.ts | 36 + v0/src/store/testBenchStore.ts | 105 + v0/src/store/timingDiagramPanelStore.ts | 25 + v0/src/styles/color_theme.scss | 6 +- v0/src/styles/css/UX.css | 25 - v0/src/styles/css/embed.css | 15 +- v0/src/styles/css/main.stylesheet.css | 34 +- v0/src/styles/css/testCreator.css | 2 +- v0/src/styles/simulator.scss | 3 +- v1/src/assets/constants/theme.ts | 17 + .../DialogBox/CombinationalAnalysis.vue | 397 +- v1/src/components/DialogBox/ExportProject.vue | 4 +- v1/src/components/DialogBox/ExportVerilog.vue | 6 +- .../components/DialogBox/InsertSubcircuit.vue | 2 +- v1/src/components/DialogBox/OpenOffline.vue | 81 +- .../DialogBox/Themes/ApplyThemes.vue | 101 +- v1/src/components/Extra.vue | 399 +- v1/src/components/Logo/Logo.vue | 4 +- .../Navbar/Hamburger/Hamburger2.vue | 142 + v1/src/components/Navbar/Navbar.css | 2 +- v1/src/components/Navbar/Navbar.vue | 34 +- .../NavbarLinks/NavbarLink/NavbarLink2.vue | 121 + .../Navbar/NavbarLinks/NavbarLinks.vue | 4 +- .../Navbar/QuickButton/QuickButton.ts | 37 + .../Navbar/QuickButton/QuickButton.vue | 104 +- .../Navbar/QuickButton/QuickButtonMobile.vue | 172 + v1/src/components/Navbar/User/UserMenu.vue | 190 + .../Panels/ElementsPanel/ElementsPanel.ts | 25 + .../Panels/ElementsPanel/ElementsPanel.vue | 42 +- .../ElementsPanel/ElementsPanelMobile.vue | 329 + .../LayoutElementsPanel.vue | 94 + .../LayoutProperty/LayoutProperty.vue | 25 +- .../ModuleProperty/ModuleProperty.vue | 4 +- .../ProjectProperty/ProjectProperty.vue | 31 +- .../Panels/PropertiesPanel/PropertiesPanel.ts | 66 + .../PropertiesPanel/PropertiesPanel.vue | 67 +- .../PropertiesPanel/PropertiesPanelMobile.vue | 177 + .../components/Panels/Shared/InputGroups.vue | 14 + .../TestBenchPanel/TestBenchCreator.vue | 592 ++ .../Panels/TestBenchPanel/TestBenchPanel.vue | 134 + .../TestBenchPanel/TestBenchValidator.vue | 106 + .../TimingDiagramButtons.vue | 28 +- .../TimingDiagramMobile.vue | 74 + .../TimingDiagramPanel/TimingDiagramPanel.ts | 42 + .../TimingDiagramPanel/TimingDiagramPanel.vue | 66 +- .../VerilogEditorPanel/VerilogEditorPanel.vue | 2 +- .../VerilogEditorPanelMobile.vue | 100 + .../ReportIssue/ReportIssueButton.vue | 4 + v1/src/components/TabsBar/TabsBar.vue | 27 +- .../helpers/deleteCircuit/DeleteCircuit.vue | 6 +- v1/src/env.d.ts | 6 + v1/src/globalVariables.ts | 4 - v1/src/locales/bn.json | 151 + v1/src/locales/en.json | 5 + v1/src/locales/hi.json | 5 + v1/src/locales/i18n.ts | 14 +- v1/src/main.ts | 1 - v1/src/pages/embed.vue | 30 +- v1/src/pages/simulatorHandler.vue | 11 +- v1/src/router/index.ts | 2 +- v1/src/simulator/spec/bitConvertor.spec.js | 88 + .../Decoders-plexers-circuitdata.json | 2430 ++--- .../spec/circuits/alu-circuitdata.json | 8377 +++++++++++++++++ .../spec/circuits/gates-circuitdata.json | 1565 +-- .../spec/circuits/misc-circuitdata.json | 1572 ++++ .../rippleCarryAdder-circuitdata.json | 3109 ++++++ .../spec/circuits/sequential-circuitdata.json | 1184 +++ .../spec/circuits/subCircuit-circuitdata.json | 814 ++ .../spec/combinationalAnalysis.spec.js | 92 + v1/src/simulator/spec/complexCircuit.spec.js | 96 + v1/src/simulator/spec/data.spec.js | 189 +- .../simulator/spec/decoders-plexers.spec.js | 115 + v1/src/simulator/spec/gates.spec.js | 160 +- v1/src/simulator/spec/misc.spec.js | 130 + v1/src/simulator/spec/sequential.spec.js | 105 + v1/src/simulator/spec/subCircuit.spec.js | 85 + .../simulator/spec/testData/alu-testdata.json | 108 + .../spec/testData/decoders-plexers.json | 401 + .../spec/testData/gates-testdata.json | 492 +- .../spec/testData/misc-testdata.json | 959 ++ .../spec/testData/ripple-carry-adder.json | 92 + .../spec/testData/sequential-testdata.json | 250 + .../spec/testData/subCircuit-testdata.json | 86 + v1/src/simulator/spec/vitestSetup.ts | 11 + v1/src/simulator/src/Verilog2CV.js | 45 +- v1/src/simulator/src/VerilogClasses.js | 40 - v1/src/simulator/src/{app.js => app.ts} | 14 +- v1/src/simulator/src/arrayHelpers.js | 34 - v1/src/simulator/src/backgroundArea.js | 17 - v1/src/simulator/src/backgroundArea.ts | 20 + v1/src/simulator/src/canvas2svg.js | 1433 --- v1/src/simulator/src/canvasApi.js | 21 +- .../simulator/src/{circuit.js => circuit.ts} | 220 +- v1/src/simulator/src/circuitElement.js | 34 +- v1/src/simulator/src/combinationalAnalysis.js | 950 +- v1/src/simulator/src/contention.ts | 123 + v1/src/simulator/src/data.js | 20 +- v1/src/simulator/src/data/backupCircuit.js | 2 + v1/src/simulator/src/data/load.js | 9 +- .../src/data/{project.js => project.ts} | 28 +- v1/src/simulator/src/data/redo.js | 47 - v1/src/simulator/src/data/redo.ts | 76 + v1/src/simulator/src/data/save.js | 57 +- v1/src/simulator/src/data/saveImage.js | 18 - v1/src/simulator/src/data/saveImage.ts | 16 + v1/src/simulator/src/data/undo.js | 51 - v1/src/simulator/src/data/undo.ts | 82 + v1/src/simulator/src/embed.js | 2 +- v1/src/simulator/src/embedListeners.js | 373 +- v1/src/simulator/src/engine.js | 35 +- .../src/simulator/src/eventQueue.ts | 31 +- v1/src/simulator/src/events.js | 25 +- .../src/hotkey_binder/defaultKeys.ts | 5 +- .../src/hotkey_binder/model/actions.js | 205 - .../src/hotkey_binder/model/actions.ts | 340 + .../model/{addShortcut.js => addShortcut.ts} | 61 +- .../src/hotkey_binder/model/model.types.ts | 25 + .../hotkey_binder/model/shortcuts.plugin.js | 250 - .../hotkey_binder/model/shortcuts.plugin.ts | 232 + .../src/hotkey_binder/model/utils.js | 67 - .../src/hotkey_binder/model/utils.ts | 74 + .../simulator/src/interface/backgroundArea.ts | 6 + .../simulator/src/interface/simulationArea.ts | 39 + .../src/simulator/src/layout/layoutBuffer.ts | 17 +- .../src/simulator/src/layout/layoutNode.ts | 29 +- .../src/{layoutMode.js => layoutMode.ts} | 96 +- v1/src/simulator/src/listeners.js | 810 +- v1/src/simulator/src/metadata.json | 179 - v1/src/simulator/src/metadata.ts | 191 + v1/src/simulator/src/minimap.js | 3 +- v1/src/simulator/src/moduleSetup.js | 2 +- v1/src/simulator/src/modules.js | 2 +- v1/src/simulator/src/modules/ALU.js | 4 +- v1/src/simulator/src/modules/Adder.js | 2 +- v1/src/simulator/src/modules/AndGate.js | 6 +- v1/src/simulator/src/modules/Arrow.js | 8 +- v1/src/simulator/src/modules/BitSelector.js | 4 +- v1/src/simulator/src/modules/Buffer.js | 7 +- v1/src/simulator/src/modules/Button.js | 6 +- v1/src/simulator/src/modules/ConstantVal.js | 4 +- .../src/modules/ControlledInverter.js | 17 +- v1/src/simulator/src/modules/Counter.js | 4 +- v1/src/simulator/src/modules/Decoder.js | 40 +- v1/src/simulator/src/modules/Demultiplexer.js | 4 +- v1/src/simulator/src/modules/DigitalLed.js | 15 +- v1/src/simulator/src/modules/Flag.js | 11 +- v1/src/simulator/src/modules/Ground.js | 28 +- v1/src/simulator/src/modules/HexDisplay.js | 12 +- .../simulator/src/modules/ImageAnnotation.js | 7 +- v1/src/simulator/src/modules/Input.js | 5 +- v1/src/simulator/src/modules/LSB.js | 11 +- v1/src/simulator/src/modules/MSB.js | 11 +- v1/src/simulator/src/modules/Multiplexer.js | 8 +- v1/src/simulator/src/modules/NandGate.js | 7 +- v1/src/simulator/src/modules/NorGate.js | 10 +- v1/src/simulator/src/modules/NotGate.js | 11 +- v1/src/simulator/src/modules/OrGate.js | 175 - v1/src/simulator/src/modules/OrGate.ts | 133 + v1/src/simulator/src/modules/Output.js | 21 +- v1/src/simulator/src/modules/Power.js | 10 +- .../simulator/src/modules/PriorityEncoder.js | 10 +- v1/src/simulator/src/modules/RGBLed.js | 12 +- v1/src/simulator/src/modules/RGBLedMatrix.js | 5 +- v1/src/simulator/src/modules/Random.js | 4 +- v1/src/simulator/src/modules/Rectangle.js | 8 +- .../simulator/src/modules/SevenSegDisplay.js | 7 +- .../src/modules/SixteenSegDisplay.js | 8 +- v1/src/simulator/src/modules/Splitter.js | 57 +- v1/src/simulator/src/modules/SquareRGBLed.js | 9 +- v1/src/simulator/src/modules/Stepper.js | 7 +- v1/src/simulator/src/modules/Text.js | 9 +- v1/src/simulator/src/modules/TriState.js | 18 +- v1/src/simulator/src/modules/Tunnel.js | 28 +- v1/src/simulator/src/modules/TwoComplement.js | 10 +- v1/src/simulator/src/modules/VariableLed.js | 17 +- v1/src/simulator/src/modules/XnorGate.js | 8 +- v1/src/simulator/src/modules/XorGate.js | 10 +- .../simulator/src/modules/verilogDivider.js | 5 +- .../src/modules/verilogMultiplier.js | 5 +- v1/src/simulator/src/modules/verilogPower.js | 5 +- .../simulator/src/modules/verilogShiftLeft.js | 5 +- .../src/modules/verilogShiftRight.js | 5 +- v1/src/simulator/src/node.js | 181 +- v1/src/simulator/src/plotArea.js | 88 +- .../src/simulator/src/quinMcCluskey.ts | 41 +- v1/src/simulator/src/sequential.js | 17 +- v1/src/simulator/src/sequential/Clock.js | 5 +- v1/src/simulator/src/sequential/DflipFlop.js | 10 +- v1/src/simulator/src/sequential/Dlatch.js | 16 +- v1/src/simulator/src/sequential/EEPROM.js | 3 - v1/src/simulator/src/sequential/ForceGate.js | 92 + v1/src/simulator/src/sequential/JKflipFlop.js | 11 +- v1/src/simulator/src/sequential/Keyboard.js | 7 +- v1/src/simulator/src/sequential/RAM.js | 9 +- v1/src/simulator/src/sequential/Rom.js | 7 +- v1/src/simulator/src/sequential/SRflipFlop.js | 20 +- v1/src/simulator/src/sequential/TTY.js | 17 +- v1/src/simulator/src/sequential/TflipFlop.js | 9 +- v1/src/simulator/src/sequential/verilogRAM.js | 45 +- v1/src/simulator/src/setup.js | 48 +- v1/src/simulator/src/simulationArea.js | 99 - v1/src/simulator/src/simulationArea.ts | 70 + v1/src/simulator/src/subcircuit.js | 79 +- v1/src/simulator/src/testCreator.js | 780 -- v1/src/simulator/src/testbench.js | 1140 --- v1/src/simulator/src/testbench.ts | 761 ++ v1/src/simulator/src/testbench/ForceGate.js | 2 +- .../simulator/src/testbench/testbenchInput.js | 5 +- .../src/testbench/testbenchOutput.js | 36 +- ...straction.js => customThemeAbstraction.ts} | 19 +- v1/src/simulator/src/themer/customThemer.js | 154 - v1/src/simulator/src/themer/customThemer.vue | 174 + .../{themeCardSvg.js => themeCardSvg.ts} | 7 +- v1/src/simulator/src/themer/themer.js | 223 - v1/src/simulator/src/themer/themer.ts | 218 + v1/src/simulator/src/themer/themer.types.ts | 13 + .../src/simulator/src/themer/themes.ts | 8 +- v1/src/simulator/src/tutorials.js | 29 +- v1/src/simulator/src/types/app.types.ts | 33 + v1/src/simulator/src/{utils.js => utils.ts} | 213 +- v1/src/simulator/src/ux.js | 513 +- v1/src/simulator/src/verilog.js | 76 +- v1/src/simulator/src/verilogHelpers.js | 1 - v1/src/simulator/src/wire.js | 240 - v1/src/simulator/src/wire.ts | 265 + v1/src/simulator/vendor/canvas2svg.js | 1469 --- v1/src/store/SimulatorStore/actions.ts | 18 +- v1/src/store/SimulatorStore/state.ts | 44 +- v1/src/store/authStore.ts | 14 +- v1/src/store/layoutStore.ts | 84 + v1/src/store/propertiesPanelStore.ts | 24 + v1/src/store/simulatorMobileStore.ts | 36 + v1/src/store/testBenchStore.ts | 105 + v1/src/store/timingDiagramPanelStore.ts | 25 + v1/src/styles/color_theme.scss | 6 +- v1/src/styles/css/UX.css | 25 - v1/src/styles/css/embed.css | 15 +- v1/src/styles/css/main.stylesheet.css | 34 +- v1/src/styles/css/testCreator.css | 2 +- v1/src/styles/simulator.scss | 3 +- 462 files changed, 57868 insertions(+), 25325 deletions(-) create mode 100644 v0/src/assets/constants/theme.ts create mode 100644 v0/src/components/Navbar/Hamburger/Hamburger2.vue create mode 100644 v0/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue create mode 100644 v0/src/components/Navbar/QuickButton/QuickButton.ts create mode 100644 v0/src/components/Navbar/QuickButton/QuickButtonMobile.vue create mode 100644 v0/src/components/Navbar/User/UserMenu.vue create mode 100644 v0/src/components/Panels/ElementsPanel/ElementsPanel.ts create mode 100644 v0/src/components/Panels/ElementsPanel/ElementsPanelMobile.vue create mode 100644 v0/src/components/Panels/LayoutElementsPanel/LayoutElementsPanel.vue create mode 100644 v0/src/components/Panels/PropertiesPanel/PropertiesPanel.ts create mode 100644 v0/src/components/Panels/PropertiesPanel/PropertiesPanelMobile.vue create mode 100644 v0/src/components/Panels/TestBenchPanel/TestBenchCreator.vue create mode 100644 v0/src/components/Panels/TestBenchPanel/TestBenchPanel.vue create mode 100644 v0/src/components/Panels/TestBenchPanel/TestBenchValidator.vue create mode 100644 v0/src/components/Panels/TimingDiagramPanel/TimingDiagramMobile.vue create mode 100644 v0/src/components/Panels/TimingDiagramPanel/TimingDiagramPanel.ts create mode 100644 v0/src/components/Panels/VerilogEditorPanel/VerilogEditorPanelMobile.vue create mode 100644 v0/src/locales/bn.json create mode 100644 v0/src/simulator/spec/bitConvertor.spec.js create mode 100644 v0/src/simulator/spec/circuits/alu-circuitdata.json create mode 100644 v0/src/simulator/spec/circuits/misc-circuitdata.json create mode 100644 v0/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json create mode 100644 v0/src/simulator/spec/circuits/sequential-circuitdata.json create mode 100644 v0/src/simulator/spec/circuits/subCircuit-circuitdata.json create mode 100644 v0/src/simulator/spec/combinationalAnalysis.spec.js create mode 100644 v0/src/simulator/spec/complexCircuit.spec.js create mode 100644 v0/src/simulator/spec/decoders-plexers.spec.js create mode 100644 v0/src/simulator/spec/misc.spec.js create mode 100644 v0/src/simulator/spec/sequential.spec.js create mode 100644 v0/src/simulator/spec/subCircuit.spec.js create mode 100644 v0/src/simulator/spec/testData/alu-testdata.json create mode 100644 v0/src/simulator/spec/testData/decoders-plexers.json create mode 100644 v0/src/simulator/spec/testData/misc-testdata.json create mode 100644 v0/src/simulator/spec/testData/ripple-carry-adder.json create mode 100644 v0/src/simulator/spec/testData/sequential-testdata.json create mode 100644 v0/src/simulator/spec/testData/subCircuit-testdata.json create mode 100644 v0/src/simulator/spec/vitestSetup.ts rename v0/src/simulator/src/{app.js => app.ts} (97%) delete mode 100644 v0/src/simulator/src/arrayHelpers.js delete mode 100644 v0/src/simulator/src/backgroundArea.js create mode 100644 v0/src/simulator/src/backgroundArea.ts delete mode 100644 v0/src/simulator/src/canvas2svg.js rename v0/src/simulator/src/{circuit.js => circuit.ts} (69%) create mode 100644 v0/src/simulator/src/contention.ts rename v0/src/simulator/src/data/{project.js => project.ts} (86%) delete mode 100644 v0/src/simulator/src/data/redo.js create mode 100644 v0/src/simulator/src/data/redo.ts delete mode 100644 v0/src/simulator/src/data/saveImage.js create mode 100644 v0/src/simulator/src/data/saveImage.ts delete mode 100644 v0/src/simulator/src/data/undo.js create mode 100644 v0/src/simulator/src/data/undo.ts rename v1/src/simulator/src/eventQueue.js => v0/src/simulator/src/eventQueue.ts (87%) rename v1/src/simulator/src/hotkey_binder/defaultKeys.js => v0/src/simulator/src/hotkey_binder/defaultKeys.ts (89%) delete mode 100644 v0/src/simulator/src/hotkey_binder/model/actions.js create mode 100644 v0/src/simulator/src/hotkey_binder/model/actions.ts rename v0/src/simulator/src/hotkey_binder/model/{addShortcut.js => addShortcut.ts} (69%) create mode 100644 v0/src/simulator/src/hotkey_binder/model/model.types.ts delete mode 100644 v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js create mode 100644 v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts delete mode 100644 v0/src/simulator/src/hotkey_binder/model/utils.js create mode 100644 v0/src/simulator/src/hotkey_binder/model/utils.ts create mode 100644 v0/src/simulator/src/interface/backgroundArea.ts create mode 100644 v0/src/simulator/src/interface/simulationArea.ts rename v1/src/simulator/src/layout/layoutBuffer.js => v0/src/simulator/src/layout/layoutBuffer.ts (87%) rename v1/src/simulator/src/layout/layoutNode.js => v0/src/simulator/src/layout/layoutNode.ts (85%) rename v0/src/simulator/src/{layoutMode.js => layoutMode.ts} (83%) delete mode 100644 v0/src/simulator/src/metadata.json create mode 100644 v0/src/simulator/src/metadata.ts delete mode 100644 v0/src/simulator/src/modules/OrGate.js create mode 100644 v0/src/simulator/src/modules/OrGate.ts rename v1/src/simulator/src/quinMcCluskey.js => v0/src/simulator/src/quinMcCluskey.ts (84%) create mode 100644 v0/src/simulator/src/sequential/ForceGate.js delete mode 100644 v0/src/simulator/src/simulationArea.js create mode 100644 v0/src/simulator/src/simulationArea.ts delete mode 100644 v0/src/simulator/src/testCreator.js delete mode 100644 v0/src/simulator/src/testbench.js create mode 100644 v0/src/simulator/src/testbench.ts rename v0/src/simulator/src/themer/{customThemeAbstraction.js => customThemeAbstraction.ts} (74%) delete mode 100644 v0/src/simulator/src/themer/customThemer.js create mode 100644 v0/src/simulator/src/themer/customThemer.vue rename v0/src/simulator/src/themer/{themeCardSvg.js => themeCardSvg.ts} (98%) delete mode 100644 v0/src/simulator/src/themer/themer.js create mode 100644 v0/src/simulator/src/themer/themer.ts create mode 100644 v0/src/simulator/src/themer/themer.types.ts rename v1/src/simulator/src/themer/themes.js => v0/src/simulator/src/themer/themes.ts (99%) create mode 100644 v0/src/simulator/src/types/app.types.ts rename v0/src/simulator/src/{utils.js => utils.ts} (50%) delete mode 100644 v0/src/simulator/src/wire.js create mode 100644 v0/src/simulator/src/wire.ts delete mode 100644 v0/src/simulator/vendor/canvas2svg.js create mode 100644 v0/src/store/layoutStore.ts create mode 100644 v0/src/store/propertiesPanelStore.ts create mode 100644 v0/src/store/simulatorMobileStore.ts create mode 100644 v0/src/store/testBenchStore.ts create mode 100644 v0/src/store/timingDiagramPanelStore.ts create mode 100644 v1/src/assets/constants/theme.ts create mode 100644 v1/src/components/Navbar/Hamburger/Hamburger2.vue create mode 100644 v1/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue create mode 100644 v1/src/components/Navbar/QuickButton/QuickButton.ts create mode 100644 v1/src/components/Navbar/QuickButton/QuickButtonMobile.vue create mode 100644 v1/src/components/Navbar/User/UserMenu.vue create mode 100644 v1/src/components/Panels/ElementsPanel/ElementsPanel.ts create mode 100644 v1/src/components/Panels/ElementsPanel/ElementsPanelMobile.vue create mode 100644 v1/src/components/Panels/LayoutElementsPanel/LayoutElementsPanel.vue create mode 100644 v1/src/components/Panels/PropertiesPanel/PropertiesPanel.ts create mode 100644 v1/src/components/Panels/PropertiesPanel/PropertiesPanelMobile.vue create mode 100644 v1/src/components/Panels/TestBenchPanel/TestBenchCreator.vue create mode 100644 v1/src/components/Panels/TestBenchPanel/TestBenchPanel.vue create mode 100644 v1/src/components/Panels/TestBenchPanel/TestBenchValidator.vue create mode 100644 v1/src/components/Panels/TimingDiagramPanel/TimingDiagramMobile.vue create mode 100644 v1/src/components/Panels/TimingDiagramPanel/TimingDiagramPanel.ts create mode 100644 v1/src/components/Panels/VerilogEditorPanel/VerilogEditorPanelMobile.vue create mode 100644 v1/src/locales/bn.json create mode 100644 v1/src/simulator/spec/bitConvertor.spec.js create mode 100644 v1/src/simulator/spec/circuits/alu-circuitdata.json create mode 100644 v1/src/simulator/spec/circuits/misc-circuitdata.json create mode 100644 v1/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json create mode 100644 v1/src/simulator/spec/circuits/sequential-circuitdata.json create mode 100644 v1/src/simulator/spec/circuits/subCircuit-circuitdata.json create mode 100644 v1/src/simulator/spec/combinationalAnalysis.spec.js create mode 100644 v1/src/simulator/spec/complexCircuit.spec.js create mode 100644 v1/src/simulator/spec/decoders-plexers.spec.js create mode 100644 v1/src/simulator/spec/misc.spec.js create mode 100644 v1/src/simulator/spec/sequential.spec.js create mode 100644 v1/src/simulator/spec/subCircuit.spec.js create mode 100644 v1/src/simulator/spec/testData/alu-testdata.json create mode 100644 v1/src/simulator/spec/testData/decoders-plexers.json create mode 100644 v1/src/simulator/spec/testData/misc-testdata.json create mode 100644 v1/src/simulator/spec/testData/ripple-carry-adder.json create mode 100644 v1/src/simulator/spec/testData/sequential-testdata.json create mode 100644 v1/src/simulator/spec/testData/subCircuit-testdata.json create mode 100644 v1/src/simulator/spec/vitestSetup.ts rename v1/src/simulator/src/{app.js => app.ts} (97%) delete mode 100644 v1/src/simulator/src/arrayHelpers.js delete mode 100644 v1/src/simulator/src/backgroundArea.js create mode 100644 v1/src/simulator/src/backgroundArea.ts delete mode 100644 v1/src/simulator/src/canvas2svg.js rename v1/src/simulator/src/{circuit.js => circuit.ts} (69%) create mode 100644 v1/src/simulator/src/contention.ts rename v1/src/simulator/src/data/{project.js => project.ts} (86%) delete mode 100644 v1/src/simulator/src/data/redo.js create mode 100644 v1/src/simulator/src/data/redo.ts delete mode 100644 v1/src/simulator/src/data/saveImage.js create mode 100644 v1/src/simulator/src/data/saveImage.ts delete mode 100644 v1/src/simulator/src/data/undo.js create mode 100644 v1/src/simulator/src/data/undo.ts rename v0/src/simulator/src/eventQueue.js => v1/src/simulator/src/eventQueue.ts (87%) rename v0/src/simulator/src/hotkey_binder/defaultKeys.js => v1/src/simulator/src/hotkey_binder/defaultKeys.ts (89%) delete mode 100644 v1/src/simulator/src/hotkey_binder/model/actions.js create mode 100644 v1/src/simulator/src/hotkey_binder/model/actions.ts rename v1/src/simulator/src/hotkey_binder/model/{addShortcut.js => addShortcut.ts} (69%) create mode 100644 v1/src/simulator/src/hotkey_binder/model/model.types.ts delete mode 100644 v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js create mode 100644 v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts delete mode 100644 v1/src/simulator/src/hotkey_binder/model/utils.js create mode 100644 v1/src/simulator/src/hotkey_binder/model/utils.ts create mode 100644 v1/src/simulator/src/interface/backgroundArea.ts create mode 100644 v1/src/simulator/src/interface/simulationArea.ts rename v0/src/simulator/src/layout/layoutBuffer.js => v1/src/simulator/src/layout/layoutBuffer.ts (87%) rename v0/src/simulator/src/layout/layoutNode.js => v1/src/simulator/src/layout/layoutNode.ts (85%) rename v1/src/simulator/src/{layoutMode.js => layoutMode.ts} (83%) delete mode 100644 v1/src/simulator/src/metadata.json create mode 100644 v1/src/simulator/src/metadata.ts delete mode 100644 v1/src/simulator/src/modules/OrGate.js create mode 100644 v1/src/simulator/src/modules/OrGate.ts rename v0/src/simulator/src/quinMcCluskey.js => v1/src/simulator/src/quinMcCluskey.ts (84%) create mode 100644 v1/src/simulator/src/sequential/ForceGate.js delete mode 100644 v1/src/simulator/src/simulationArea.js create mode 100644 v1/src/simulator/src/simulationArea.ts delete mode 100644 v1/src/simulator/src/testCreator.js delete mode 100644 v1/src/simulator/src/testbench.js create mode 100644 v1/src/simulator/src/testbench.ts rename v1/src/simulator/src/themer/{customThemeAbstraction.js => customThemeAbstraction.ts} (74%) delete mode 100644 v1/src/simulator/src/themer/customThemer.js create mode 100644 v1/src/simulator/src/themer/customThemer.vue rename v1/src/simulator/src/themer/{themeCardSvg.js => themeCardSvg.ts} (98%) delete mode 100644 v1/src/simulator/src/themer/themer.js create mode 100644 v1/src/simulator/src/themer/themer.ts create mode 100644 v1/src/simulator/src/themer/themer.types.ts rename v0/src/simulator/src/themer/themes.js => v1/src/simulator/src/themer/themes.ts (99%) create mode 100644 v1/src/simulator/src/types/app.types.ts rename v1/src/simulator/src/{utils.js => utils.ts} (50%) delete mode 100644 v1/src/simulator/src/wire.js create mode 100644 v1/src/simulator/src/wire.ts delete mode 100644 v1/src/simulator/vendor/canvas2svg.js create mode 100644 v1/src/store/layoutStore.ts create mode 100644 v1/src/store/propertiesPanelStore.ts create mode 100644 v1/src/store/simulatorMobileStore.ts create mode 100644 v1/src/store/testBenchStore.ts create mode 100644 v1/src/store/timingDiagramPanelStore.ts diff --git a/v0/src/assets/constants/theme.ts b/v0/src/assets/constants/theme.ts new file mode 100644 index 00000000..d3dddd85 --- /dev/null +++ b/v0/src/assets/constants/theme.ts @@ -0,0 +1,17 @@ +export type ThemeType = { + 'default': string; + 'night-sky': string; + 'lite-born-spring': string; + 'g-and-w': string; + 'high-contrast': string; + 'color-blind': string; +}; + +export const THEME: ThemeType = { + 'default': 'Default Theme', + 'night-sky': 'Night Sky', + 'lite-born-spring': 'Lite-born Spring', + 'g-and-w': 'G&W', + 'high-contrast': 'High Contrast', + 'color-blind': 'Color Blind', +}; \ No newline at end of file diff --git a/v0/src/components/DialogBox/CombinationalAnalysis.vue b/v0/src/components/DialogBox/CombinationalAnalysis.vue index b69accbc..b4826594 100644 --- a/v0/src/components/DialogBox/CombinationalAnalysis.vue +++ b/v0/src/components/DialogBox/CombinationalAnalysis.vue @@ -23,21 +23,11 @@ import { stripTags } from '#/simulator/src/utils' import { useState } from '#/store/SimulatorStore/state' import messageBox from '@/MessageBox/messageBox.vue' -import { ref } from '@vue/reactivity' -import { onMounted, onUpdated } from '@vue/runtime-core' +import { ref } from 'vue' +import { onMounted } from 'vue' /* imports from combinationalAnalysis.js */ -import Node from '#/simulator/src/node' -import BooleanMinimize from '#/simulator/src/quinMcCluskey' -import Input from '#/simulator/src/modules/Input' -import ConstantVal from '#/simulator/src/modules/ConstantVal' -import Output from '#/simulator/src/modules/Output' -import AndGate from '#/simulator/src/modules/AndGate' -import OrGate from '#/simulator/src/modules/OrGate' -import NotGate from '#/simulator/src/modules/NotGate' -import simulationArea from '#/simulator/src/simulationArea' -import { findDimensions } from '#/simulator/src/canvasApi' -import { confirmSingleOption } from '../helpers/confirmComponent/ConfirmComponent.vue' +import { GenerateCircuit, solveBooleanFunction } from '#/simulator/src/combinationalAnalysis' const SimulatorState = useState() onMounted(() => { @@ -148,7 +138,7 @@ function dialogBoxConformation(selectedOption, circuitItem) { } if (selectedOption == 'generateCircuit') { SimulatorState.dialogBox.combinationalanalysis_dialog = false - generateCircuit() + GenerateCircuit() clearData() SimulatorState.dialogBox.combinationalanalysis_dialog = false } @@ -199,7 +189,7 @@ function createLogicTable() { SimulatorState.dialogBox.combinationalanalysis_dialog = false output.value = [] solveBooleanFunction(booleanInputVariables, booleanExpression) - if (output != null) { + if (output.value != null) { createBooleanPrompt(booleanInputVariables, booleanExpression) } } else if ( @@ -295,392 +285,6 @@ function createBooleanPrompt(inputList, outputList, scope = globalScope) { ] } - -const generateBooleanTableData = (outputListNames) => { - const data = {}; - - const table = document.querySelector('.content-table'); - const rows = table?.querySelectorAll('tbody tr') || []; - - const rowData = [...rows].slice(1).map((row, index) => { - const cells = row.cells; - const lastValue = cells[cells.length - 1]?.textContent.trim(); - return { index, value: lastValue }; - }); - - for (const outputName of outputListNames) { - data[outputName] = { x: [], 1: [], 0: [] }; - - rowData.forEach(({ index, value }) => { - if (value === '0') { - data[outputName]['0'].push(String(index)); - } else if (value === '1') { - data[outputName]['1'].push(String(index)); - } else { - data[outputName]['x'].push(String(index)); - } - }); - } - - return data; -}; - - -function drawCombinationalAnalysis( - combinationalData, - inputList, - outputList, - scope = globalScope -) { - findDimensions(scope) - var inputCount = inputList.length - var maxTerms = 0 - for (var i = 0; i < combinationalData.length; i++) { - maxTerms = Math.max(maxTerms, combinationalData[i].length) - } - - var startPosX = 200 - var startPosY = 200 - - var currentPosY = 300 - - if (simulationArea.maxWidth && simulationArea.maxHeight) { - if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { - startPosX += simulationArea.maxWidth - } else { - startPosY += simulationArea.maxHeight - currentPosY += simulationArea.maxHeight - } - } - var andPosX = startPosX + inputCount * 40 + 40 + 40 - var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80 - var outputPosX = orPosX + 60 - var inputObjects = [] - - var logixNodes = [] - - // Appending constant input to the end of inputObjects - for (var i = 0; i <= inputCount; i++) { - if (i < inputCount) { - // Regular Input - inputObjects.push( - new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1) - ) - inputObjects[i].setLabel(inputList[i]) - } else { - // Constant Input - inputObjects.push( - new ConstantVal( - startPosX + i * 40, - startPosY, - scope, - 'DOWN', - 1, - '1' - ) - ) - inputObjects[i].setLabel('_C_') - } - - inputObjects[i].newLabelDirection('UP') - var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root) - inputObjects[i].output1.connect(v1) - var v2 = new Node( - startPosX + i * 40 + 20, - startPosY + 20, - 2, - scope.root - ) - v1.connect(v2) - var notG = new NotGate( - startPosX + i * 40 + 20, - startPosY + 40, - scope, - 'DOWN', - 1 - ) - notG.inp1.connect(v2) - logixNodes.push(v1) - logixNodes.push(notG.output1) - } - - function countTerm(s) { - var c = 0 - for (var i = 0; i < s.length; i++) { - if (s[i] !== '-') c++ - } - return c - } - - for (var i = 0; i < combinationalData.length; i++) { - var andGateNodes = [] - for (var j = 0; j < combinationalData[i].length; j++) { - var c = countTerm(combinationalData[i][j]) - if (c > 1) { - var andGate = new AndGate( - andPosX, - currentPosY, - scope, - 'RIGHT', - c, - 1 - ) - andGateNodes.push(andGate.output1) - var misses = 0 - for (var k = 0; k < combinationalData[i][j].length; k++) { - if (combinationalData[i][j][k] == '-') { - misses++ - continue - } - var index = 2 * k + (combinationalData[i][j][k] == 0) - var v = new Node( - logixNodes[index].absX(), - andGate.inp[k - misses].absY(), - 2, - scope.root - ) - logixNodes[index].connect(v) - logixNodes[index] = v - v.connect(andGate.inp[k - misses]) - } - } else { - for (var k = 0; k < combinationalData[i][j].length; k++) { - if (combinationalData[i][j][k] == '-') continue - var index = 2 * k + (combinationalData[i][j][k] == 0) - var andGateSubstituteNode = new Node( - andPosX, - currentPosY, - 2, - scope.root - ) - var v = new Node( - logixNodes[index].absX(), - andGateSubstituteNode.absY(), - 2, - scope.root - ) - logixNodes[index].connect(v) - logixNodes[index] = v - v.connect(andGateSubstituteNode) - andGateNodes.push(andGateSubstituteNode) - } - } - currentPosY += c * 10 + 30 - } - - var andGateCount = andGateNodes.length - var midWay = Math.floor(andGateCount / 2) - var orGatePosY = - (andGateNodes[midWay].absY() + - andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / - 2 - if (orGatePosY % 10 == 5) { - orGatePosY += 5 - } // To make or gate fall in grid - if (andGateCount > 1) { - var o = new OrGate( - orPosX, - orGatePosY, - scope, - 'RIGHT', - andGateCount, - 1 - ) - if (andGateCount % 2 == 1) - andGateNodes[midWay].connect(o.inp[midWay]) - for (var j = 0; j < midWay; j++) { - var v = new Node( - andPosX + 30 + (midWay - j) * 10, - andGateNodes[j].absY(), - 2, - scope.root - ) - v.connect(andGateNodes[j]) - var v2 = new Node( - andPosX + 30 + (midWay - j) * 10, - o.inp[j].absY(), - 2, - scope.root - ) - v2.connect(v) - o.inp[j].connect(v2) - - var v = new Node( - andPosX + 30 + (midWay - j) * 10, - andGateNodes[andGateCount - j - 1].absY(), - 2, - scope.root - ) - v.connect(andGateNodes[andGateCount - j - 1]) - var v2 = new Node( - andPosX + 30 + (midWay - j) * 10, - o.inp[andGateCount - j - 1].absY(), - 2, - scope.root - ) - v2.connect(v) - o.inp[andGateCount - j - 1].connect(v2) - } - var out = new Output(outputPosX, o.y, scope, 'LEFT', 1) - out.inp1.connect(o.output1) - } else { - var out = new Output( - outputPosX, - andGateNodes[0].absY(), - scope, - 'LEFT', - 1 - ) - out.inp1.connect(andGateNodes[0]) - } - out.setLabel(outputList[i]) - out.newLabelDirection('RIGHT') - } - for (var i = 0; i < logixNodes.length; i++) { - if (logixNodes[i].absY() != currentPosY) { - var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root) - logixNodes[i].connect(v) - } - } - globalScope.centerFocus() -} - -/** - * This function solves passed boolean expression and returns - * output array which contains solution of the truth table - * of given boolean expression - * @param {Array} inputListNames - labels for input nodes - * @param {String} booleanExpression - boolean expression which is to be solved - */ -function solveBooleanFunction(inputListNames, booleanExpression) { - let i - let j - output.value = [] - - if ( - booleanExpression.match( - /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g - ) != null - ) { - // alert('One of the characters is not allowed.') - confirmSingleOption('One of the characters is not allowed.') - return - } - - if (inputListNames.length > 8) { - // alert('You can only have 8 variables at a time.') - confirmSingleOption('You can only have 8 variables at a time.') - return - } - var matrix = [] - for (i = 0; i < inputListNames.length; i++) { - matrix[i] = new Array(inputListNames.length) - } - - for (i = 0; i < inputListNames.length; i++) { - for (j = 0; j < 1 << inputListNames.length; j++) { - matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) - } - } - // generate equivalent expression by replacing input vars with possible combinations of o and 1 - for (i = 0; i < 2 ** inputListNames.length; i++) { - const data = [] - for (j = 0; j < inputListNames.length; j++) { - data[j] = - Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 - } - let equation = booleanExpression - for (j = 0; j < inputListNames.length; j++) { - equation = equation.replace( - new RegExp(inputListNames[j], 'g'), - data[j] - ) - } - - output.value[i] = solve(equation) - } - // generates solution for the truth table of booleanexpression - function solve(equation) { - while (equation.indexOf('(') != -1) { - const start = equation.lastIndexOf('(') - const end = equation.indexOf(')', start) - if (start != -1) { - equation = - equation.substring(0, start) + - solve(equation.substring(start + 1, end)) + - equation.substring(end + 1) - } - } - equation = equation.replace(/''/g, '') - equation = equation.replace(/0'/g, '1') - equation = equation.replace(/1'/g, '0') - for (let i = 0; i < equation.length - 1; i++) { - if ( - (equation[i] == '0' || equation[i] == '1') && - (equation[i + 1] == '0' || equation[i + 1] == '1') - ) { - equation = - equation.substring(0, i + 1) + - '*' + - equation.substring(i + 1, equation.length) - } - } - try { - const safeEval = eval - const answer = safeEval(equation) - if (answer == 0) { - return 0 - } - if (answer > 0) { - return 1 - } - return '' - } catch (e) { - return '' - } - } -} - -function generateCircuit() { - var data = generateBooleanTableData(outputListNamesInteger.value) - var minimizedCircuit = [] - let inputCount = inputListNames.value.length - for (const output in data) { - let oneCount = data[output][1].length // Number of ones - let zeroCount = data[output][0].length // Number of zeroes - if (oneCount == 0) { - // Hardcode to 0 as output - minimizedCircuit.push(['-'.repeat(inputCount) + '0']) - } else if (zeroCount == 0) { - // Hardcode to 1 as output - minimizedCircuit.push(['-'.repeat(inputCount) + '1']) - } else { - // Perform KMap like minimzation - const temp = new BooleanMinimize( - inputListNames.value.length, - data[output][1].map(Number), - data[output].x.map(Number) - ) - minimizedCircuit.push(temp.result) - } - } - if (output.value == null) { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames.value, - outputListNames.value, - globalScope - ) - } else { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames.value, - [`${outputListNames.value}`], - globalScope - ) - } -} - function printBooleanTable() { var sTable = $('.messageBox .v-card-text')[0].innerHTML @@ -688,7 +292,7 @@ function printBooleanTable() { ``.replace(/\n/g, "") var win = window.open('', '', 'height=700,width=700') var htmlBody = ` @@ -717,7 +321,7 @@ function printBooleanTable() { } - diff --git a/v0/src/components/DialogBox/ExportProject.vue b/v0/src/components/DialogBox/ExportProject.vue index 0da58f88..77645495 100644 --- a/v0/src/components/DialogBox/ExportProject.vue +++ b/v0/src/components/DialogBox/ExportProject.vue @@ -41,7 +41,7 @@ import { ref } from 'vue' import { useState } from '#/store/SimulatorStore/state' import { useProjectStore } from '#/store/projectStore' import { generateSaveData } from '#/simulator/src/data/save' -import { download } from '#/simulator/src/utils' +import { downloadFile } from '#/simulator/src/utils' import { escapeHtml } from '#/simulator/src/utils' export function ExportProject() { @@ -73,7 +73,7 @@ const exportAsFile = async () => { false ) fileName = `${fileName.replace(/[^a-z0-9]/gi, '_')}.cv` - download(fileName, circuitData) + downloadFile(fileName, circuitData) SimulatorState.dialogBox.export_project_dialog = false } diff --git a/v0/src/components/DialogBox/ExportVerilog.vue b/v0/src/components/DialogBox/ExportVerilog.vue index d826ad35..8bcaae12 100644 --- a/v0/src/components/DialogBox/ExportVerilog.vue +++ b/v0/src/components/DialogBox/ExportVerilog.vue @@ -43,7 +43,7 @@ \ No newline at end of file +import LayoutElementsPanel from './Panels/LayoutElementsPanel/LayoutElementsPanel.vue' +import TestBenchPanel from './Panels/TestBenchPanel/TestBenchPanel.vue' +import TestBenchCreator from './Panels/TestBenchPanel/TestBenchCreator.vue' +import TestBenchValidator from './Panels/TestBenchPanel/TestBenchValidator.vue' +import QuickButtonMobile from './Navbar/QuickButton/QuickButtonMobile.vue' +import TimingDiagramMobile from './Panels/TimingDiagramPanel/TimingDiagramMobile.vue' +import ElementsPanelMobile from './Panels/ElementsPanel/ElementsPanelMobile.vue' +import PropertiesPanelMobile from './Panels/PropertiesPanel/PropertiesPanelMobile.vue' +import { simulationArea } from '#/simulator/src/simulationArea' +import { paste } from '#/simulator/src/events' +import { panStart, panMove, panStop } from '#/simulator/src/listeners' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { useState } from '#/store/SimulatorStore/state' +import { reactive, ref, watch } from 'vue' + +const simulatorMobileStore = useSimulatorMobileStore() +const selectMultiple = ref(false) +const propertiesPanelPos = reactive({ + up: 22, + down: 14 +}); + +watch(() => simulatorMobileStore.isVerilog, (val) => { + if (val) { + propertiesPanelPos.up = 10 + propertiesPanelPos.down = 2 + } else { + propertiesPanelPos.up = 22 + propertiesPanelPos.down = 14 + } +}) + +const copyBtnClick = () => { + window.document.execCommand('copy') + simulationArea.shiftDown = false + simulatorMobileStore.isCopy = true +} + +const pasteBtnClick = () => { + paste(localStorage.getItem('clipboardData')); + simulatorMobileStore.isCopy = false +} + +const propertiesBtnClick = () => { + simulatorMobileStore.showPropertiesPanel = !simulatorMobileStore.showPropertiesPanel +} + + + diff --git a/v0/src/components/Logo/Logo.vue b/v0/src/components/Logo/Logo.vue index 56130b8c..48ef6c97 100644 --- a/v0/src/components/Logo/Logo.vue +++ b/v0/src/components/Logo/Logo.vue @@ -1,7 +1,7 @@ + + \ No newline at end of file diff --git a/v0/src/components/Navbar/Navbar.css b/v0/src/components/Navbar/Navbar.css index fb969639..acdaef1a 100644 --- a/v0/src/components/Navbar/Navbar.css +++ b/v0/src/components/Navbar/Navbar.css @@ -1,4 +1,4 @@ -@import url('/v0/src/styles/color_theme.scss'); +@import url('/src/styles/color_theme.scss'); .navbar { background-color: var(--white); diff --git a/v0/src/components/Navbar/Navbar.vue b/v0/src/components/Navbar/Navbar.vue index caeec961..a1a4bcb5 100644 --- a/v0/src/components/Navbar/Navbar.vue +++ b/v0/src/components/Navbar/Navbar.vue @@ -1,9 +1,12 @@ diff --git a/v0/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue b/v0/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue new file mode 100644 index 00000000..19455127 --- /dev/null +++ b/v0/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue @@ -0,0 +1,121 @@ + + + + + + + \ No newline at end of file diff --git a/v0/src/components/Navbar/NavbarLinks/NavbarLinks.vue b/v0/src/components/Navbar/NavbarLinks/NavbarLinks.vue index 3c01a4dc..72241d76 100644 --- a/v0/src/components/Navbar/NavbarLinks/NavbarLinks.vue +++ b/v0/src/components/Navbar/NavbarLinks/NavbarLinks.vue @@ -5,12 +5,12 @@ :key="navbarItem.id" class="navbar-nav navbar-menu noSelect pointerCursor" > - + - diff --git a/v0/src/components/Navbar/QuickButton/QuickButtonMobile.vue b/v0/src/components/Navbar/QuickButton/QuickButtonMobile.vue new file mode 100644 index 00000000..6d9791b1 --- /dev/null +++ b/v0/src/components/Navbar/QuickButton/QuickButtonMobile.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/v0/src/components/Navbar/User/UserMenu.vue b/v0/src/components/Navbar/User/UserMenu.vue new file mode 100644 index 00000000..4d5c825f --- /dev/null +++ b/v0/src/components/Navbar/User/UserMenu.vue @@ -0,0 +1,190 @@ + + + + \ No newline at end of file diff --git a/v0/src/components/Panels/ElementsPanel/ElementsPanel.ts b/v0/src/components/Panels/ElementsPanel/ElementsPanel.ts new file mode 100644 index 00000000..66a6462e --- /dev/null +++ b/v0/src/components/Panels/ElementsPanel/ElementsPanel.ts @@ -0,0 +1,25 @@ +import { simulationArea } from "#/simulator/src/simulationArea" +import modules from "#/simulator/src/modules" +import { uxvar } from "#/simulator/src/ux" + +export function createElement(elementName: string) { + if (simulationArea.lastSelected?.newElement) + simulationArea.lastSelected.delete() + var obj = new modules[elementName]() + simulationArea.lastSelected = obj + uxvar.smartDropXX += 70 + if (uxvar.smartDropXX / globalScope.scale > width) { + uxvar.smartDropXX = 50 + uxvar.smartDropYY += 80 + } +} + +export function getImgUrl(elementName: string) { + try { + const elementImg = new URL(`../../../assets/img/${elementName}.svg`, import.meta.url).href; + return elementImg; + } catch (e) { + console.error("Error loading image:", e); + return ''; + } +} diff --git a/v0/src/components/Panels/ElementsPanel/ElementsPanel.vue b/v0/src/components/Panels/ElementsPanel/ElementsPanel.vue index e5c52896..8aac793c 100644 --- a/v0/src/components/Panels/ElementsPanel/ElementsPanel.vue +++ b/v0/src/components/Panels/ElementsPanel/ElementsPanel.vue @@ -1,6 +1,6 @@ diff --git a/v0/src/router/index.ts b/v0/src/router/index.ts index 730aea09..0a604dab 100644 --- a/v0/src/router/index.ts +++ b/v0/src/router/index.ts @@ -2,7 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router' import simulatorHandler from '../pages/simulatorHandler.vue' import Embed from '../pages/embed.vue' -const routes = [ +export const routes = [ { path: '/', redirect: '/simulatorvue', // @TODO: update later back to /simulator diff --git a/v0/src/simulator/spec/bitConvertor.spec.js b/v0/src/simulator/spec/bitConvertor.spec.js new file mode 100644 index 00000000..157db0c5 --- /dev/null +++ b/v0/src/simulator/spec/bitConvertor.spec.js @@ -0,0 +1,88 @@ +import { setup } from '../src/setup'; +import { bitConverterDialog, setBaseValues, setupBitConvertor } from '../src/utils'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('data dir working', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + // Open BitConvertor Dialog + test('bitConvertor Dialog working', () => { + expect(() => bitConverterDialog()).not.toThrow(); + }); + + test('function setupBitConvertor working', () => { + expect(() => setupBitConvertor()).not.toThrow(); + }); + + test('function setBaseValues working', () => { + const randomBaseValue = Math.floor(Math.random() * 100); + console.log('Testing for Base Value --> ', randomBaseValue); + expect(() => setBaseValues(randomBaseValue)).not.toThrow(); + }); +}); diff --git a/v0/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json b/v0/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json index bf601345..90b10612 100644 --- a/v0/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json +++ b/v0/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json @@ -1,1109 +1,1337 @@ { - "name": "Decoders and Plexers", - "timePeriod": 500, - "clockEnabled": true, - "projectId": "RVvp1Qq4hf3eVcfUO7sE", - "focussedCircuit": 11597572508, - "orderedTabs": ["11597572508"], - "scopes": [ - { - "layout": { - "width": 100, - "height": 280, - "title_x": 50, - "title_y": 13, - "titleEnabled": true + "name": "Decoder&Plexers", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "hWmIAEfeaUjXbtHfKS15", + "focussedCircuit": 11597572508, + "orderedTabs": [ + "11597572508" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 540, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Control Signal", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 970, + "y": -60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 9 + ] + }, + { + "x": 560, + "y": -60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 17, + 29 + ] + }, + { + "x": 560, + "y": 590, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": -10, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": -10, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Control Signal", + "connections": [ + 17 + ] + }, + { + "x": 860, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 16, + 20 + ] + }, + { + "x": 860, + "y": 30, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 15 + ] + }, + { + "x": 560, + "y": 50, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 10, + 14 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 820, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 15, + 37 + ] + }, + { + "x": 780, + "y": -130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 6, + 25 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": -10, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": -10, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 780, + "y": 410, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 31 + ] + }, + { + "x": 820, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 37 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 560, + "y": -190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 9 + ] + }, + { + "x": -10, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 30, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 30, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 10, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 820, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 26, + 30 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "Input", + "connections": [ + 60 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Output", + "connections": [ + 47 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "2", + "label": "Bit Selector", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "2", + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 20, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 250, + "y": 290, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 48, + 57, + 60 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 49 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 20, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 250, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 51, + 54 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 56 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 43, + 51 + ] + } + ], + "id": 11597572508, + "name": "Main", + "Input": [ + { + "x": 480, + "y": -190, + "objectType": "Input", + "label": "s", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 4 }, - "verilogMetadata": { - "isVerilogCircuit": false, - "isMainCircuit": false, - "code": "// Write Some Verilog Code Here!", - "subCircuitScopeIds": [] + "values": { + "state": 1 }, - "allNodes": [ - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [14] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [5] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [6] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Control Signal", - "connections": [24] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [14] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [1] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [2] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [15] - }, - { - "x": -10, - "y": -10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [12] - }, - { - "x": -10, - "y": 10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [13] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Control Signal", - "connections": [11] - }, - { - "x": 80, - "y": 510, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [10, 25] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [8] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [9] - }, - { - "x": -30, - "y": 130, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [0, 4, 15] - }, - { - "x": -30, - "y": 340, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [7, 14] - }, - { - "x": -20, - "y": 0, - "type": 0, - "bitWidth": 2, - "label": "Input", - "connections": [20] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "Output", - "connections": [19] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Bit Selector", - "connections": [26] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [17] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 2, - "label": "", - "connections": [16] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [22] - }, - { - "x": -180, - "y": 160, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [21, 23] - }, - { - "x": -180, - "y": 220, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [22, 24, 25] - }, - { - "x": 90, - "y": 220, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [3, 23] - }, - { - "x": -180, - "y": 510, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [11, 23, 27] - }, - { - "x": 70, - "y": 700, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [18, 27] - }, - { - "x": -180, - "y": 700, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [25, 26] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [33] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [32] - }, - { - "x": 20, - "y": 20, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [30] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [28] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [39] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [37] - }, - { - "x": 20, - "y": 20, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [38] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [35] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [36] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [34] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [46] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [47] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [45] - }, - { - "x": 10, - "y": 30, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [44] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [43] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [42] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [40] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [41] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [53] - }, - { - "x": -10, - "y": -10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [51] - }, - { - "x": -10, - "y": 10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [52] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [49] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [50] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [48] - } - ], - "id": 11597572508, - "name": "Main", - "Input": [ - { - "x": -70, - "y": 130, - "objectType": "Input", - "label": "inp1", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 4 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 60, - "id": "cZW4OLLsTA1aBoRSmHxv" - } - ] - } - }, - { - "x": -70, - "y": 150, - "objectType": "Input", - "label": "inp2", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 5 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 20, - "id": "OhBFKFzir02JVzBVOV44" - } - ] - } - }, - { - "x": -30, - "y": 630, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 20 - }, - "values": { - "state": 3 - }, - "constructorParamaters": [ - "RIGHT", - 2, - { - "x": 0, - "y": 120, - "id": "Tci49l79hiLHSfxqSPhk" - } - ] - } - }, - { - "x": -360, - "y": 160, - "objectType": "Input", - "label": "s", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 21 - }, - "values": { - "state": 0 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 40, - "id": "2jYcmNNFpmoq6jcELh8X" - } - ] - } - }, - { - "x": -10, - "y": 840, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 33 - }, - "values": { - "state": 0 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 80, - "id": "wUbTZgbmrEStf17qxgOw" - } - ] - } - }, - { - "x": 0, - "y": 1030, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 39 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 100, - "id": "hiFGtGajuArxucFOfydA" - } - ] - } - }, - { - "x": -550, - "y": 310, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 46 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 140, - "id": "6br60gi40FN03qZRFG9W" - } - ] - } - }, - { - "x": -550, - "y": 330, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 47 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 160, - "id": "EcNRmJVcoyFZdMUmGwQw" - } - ] - } - }, - { - "x": -600, - "y": 680, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 53 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 180, - "id": "eAluIwGbrt2vmFD37xUb" - } - ] - } - } - ], - "Output": [ - { - "x": 250, - "y": 140, - "objectType": "Output", - "label": "out1", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 6 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 40, - "id": "PQtMRkU1V36zoiUZaKnC" - } - ] - } - }, - { - "x": 340, - "y": 330, - "objectType": "Output", - "label": "out3", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 12 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 20, - "id": "rl7YenrdGRoBr9BXA2Ee" - } - ] - } - }, - { - "x": 340, - "y": 350, - "objectType": "Output", - "label": "out4", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 13 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 60, - "id": "gPrg5glyUDxsQmGldTow" - } - ] - } - }, - { - "x": 260, - "y": 630, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 19 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 80, - "id": "qqnDrlsm0T8y1dyyiGlL" - } - ] - } - }, - { - "x": 270, - "y": 860, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 31 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 120, - "id": "2smYfkmptbhEZ2gFBMmf" - } - ] - } - }, - { - "x": 270, - "y": 840, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 32 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 100, - "id": "45NWNA9b3l54VZE5cFYS" - } - ] - } - }, - { - "x": 220, - "y": 1030, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 37 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 140, - "id": "COIaU2CIfnmcZ8h0Nxpq" - } - ] - } - }, - { - "x": 220, - "y": 1050, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 38 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 160, - "id": "bJ7CLsYt9Johbanua2d4" - } - ] - } - }, - { - "x": -460, - "y": 400, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 44 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 180, - "id": "Of7qPmfBvyW9mhiLkfpN" - } - ] - } - }, - { - "x": -290, - "y": 320, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 45 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 200, - "id": "LLwXovDSOe6rplHPIDhv" - } - ] - } - }, - { - "x": -310, - "y": 670, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 51 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 220, - "id": "Yo4Zo5P6gClWQJZWt5DF" - } - ] - } - }, - { - "x": -310, - "y": 690, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 52 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 240, - "id": "T86CxN5DtKbZtDaZXSMx" - } - ] - } - } - ], - "Multiplexer": [ - { - "x": 90, - "y": 140, - "objectType": "Multiplexer", - "label": "multiplexer", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 1, 1], - "nodes": { - "inp": [0, 1], - "output1": 2, - "controlSignalInput": 3 - } - } - } - ], - "BitSelector": [ - { - "x": 70, - "y": 630, - "objectType": "BitSelector", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 16, - "output1": 17, - "bitSelectorInp": 18 - }, - "constructorParamaters": ["RIGHT", 2, 1] - } - } - ], - "Demultiplexer": [ - { - "x": 80, - "y": 340, - "objectType": "Demultiplexer", - "label": "demultiplexer", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["LEFT", 1, 1], - "nodes": { - "output1": [8, 9], - "input": 7, - "controlSignalInput": 10 - } - } - } - ], - "MSB": [ - { - "x": 70, - "y": 840, - "objectType": "MSB", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 28, - "output1": 29, - "enable": 30 - }, - "constructorParamaters": ["RIGHT", 1] - } - } - ], - "LSB": [ - { - "x": 70, - "y": 1030, - "objectType": "LSB", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 34, - "output1": 35, - "enable": 36 - }, - "constructorParamaters": ["RIGHT", 1] - } - } + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "af8X6iUZ1TNVcEuYsobR" + } + ] + } + }, + { + "x": 730, + "y": -150, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 80, + "id": "AHg5Ngs8KrHtKKUUBv5o" + } + ] + } + }, + { + "x": 730, + "y": -130, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "0uCn6zjaOWINyTt3INWL" + } + ] + } + }, + { + "x": 750, + "y": 430, + "objectType": "Input", + "label": "inp3", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 38 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "OjD26bycgCZOCebnr0Ta" + } + ] + } + }, + { + "x": 750, + "y": 450, + "objectType": "Input", + "label": "inp4", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 39 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 100, + "id": "YdXUBNPghcKOcTzkSNxJ" + } + ] + } + }, + { + "x": 300, + "y": 110, + "objectType": "Input", + "label": "CS", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 46 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "UP", + "2", + { + "x": 0, + "y": 120, + "id": "W3XYx9tc8fIFjVMFNfU4" + } + ] + } + }, + { + "x": 210, + "y": 20, + "objectType": "Input", + "label": "inp5", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 60 + }, + "values": { + "state": 8 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 140, + "id": "fKHb7DuWJcS9KM2fSxKT" + } + ] + } + } + ], + "Output": [ + { + "x": 1130, + "y": -140, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 7 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 280, + "id": "qkQ6ZVtFDuQN5LjoFSAx" + } + ] + } + }, + { + "x": 1130, + "y": 20, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 18 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "vRfw4YkouGy4laNyoTHO" + } + ] + } + }, + { + "x": 1130, + "y": 40, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 19 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "m1fSssWAIUVKndqPS8U1" + } + ] + } + }, + { + "x": 1040, + "y": 610, + "objectType": "Output", + "label": "out11", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 27 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 260, + "id": "uN0pAvVNRJQlNB4Vc9o0" + } + ] + } + }, + { + "x": 1040, + "y": 630, + "objectType": "Output", + "label": "out12", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 28 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "5UVbtIsq3uzOx0b1RtVW" + } + ] + } + }, + { + "x": 940, + "y": 540, + "objectType": "Output", + "label": "en", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 40 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 220, + "id": "2xTmvrisBijPkcsbt8lX" + } + ] + } + }, + { + "x": 1090, + "y": 410, + "objectType": "Output", + "label": "out9", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 41 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "Jh30ULWWwan7JgfJXssO" + } + ] + } + }, + { + "x": 1090, + "y": 430, + "objectType": "Output", + "label": "out10", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 42 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "3RzXrQjoiihgZROY8zOw" + } + ] + } + }, + { + "x": 440, + "y": 20, + "objectType": "Output", + "label": "out13", + "direction": "LEFT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 47 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 240, + "id": "i9MpQKKTbqxk9t7uOyol" + } + ] + } + }, + { + "x": 430, + "y": 290, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 52 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 60, + "id": "Nl8jdW1Ovj3hvi0lyLd6" + } + ] + } + }, + { + "x": 400, + "y": 310, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 53 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "lSTBjSRHvf3uvq8AI5FR" + } + ] + } + }, + { + "x": 380, + "y": 410, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 58 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 100, + "id": "xfXE7U7J0IRm1FVEzw3I" + } + ] + } + }, + { + "x": 350, + "y": 430, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "0tRtiePfdUKapjpaz8uy" + } + ] + } + } + ], + "Multiplexer": [ + { + "x": 970, + "y": -140, + "objectType": "Multiplexer", + "label": "Multiplexer", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1, + 1 ], - "PriorityEncoder": [ - { - "x": -480, - "y": 320, - "objectType": "PriorityEncoder", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": [40, 41], - "output1": [42], - "enable": 43 - }, - "constructorParamaters": ["RIGHT", 1] - } - } + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2, + "controlSignalInput": 3 + } + } + } + ], + "BitSelector": [ + { + "x": 300, + "y": 20, + "objectType": "BitSelector", + "label": "bit-selector", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 43, + "output1": 44, + "bitSelectorInp": 45 + }, + "constructorParamaters": [ + "RIGHT", + "4", + "2" + ] + } + } + ], + "Demultiplexer": [ + { + "x": 980, + "y": 30, + "objectType": "Demultiplexer", + "label": "Demultiplexer", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1, + 1 ], - "Decoder": [ - { - "x": -480, - "y": 680, - "objectType": "Decoder", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["LEFT", 1], - "nodes": { - "output1": [49, 50], - "input": 48 - } - } - } + "nodes": { + "output1": [ + 12, + 13 + ], + "input": 11, + "controlSignalInput": 14 + } + } + } + ], + "MSB": [ + { + "x": 320, + "y": 290, + "objectType": "MSB", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 48, + "output1": 49, + "enable": 50 + }, + "constructorParamaters": [ + "RIGHT", + 4 + ] + } + } + ], + "LSB": [ + { + "x": 320, + "y": 410, + "objectType": "LSB", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 54, + "output1": 55, + "enable": 56 + }, + "constructorParamaters": [ + "RIGHT", + 4 + ] + } + } + ], + "PriorityEncoder": [ + { + "x": 920, + "y": 420, + "objectType": "PriorityEncoder", + "label": "priority encoder", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": [ + 30, + 31, + 32, + 33 + ], + "output1": [ + 34, + 35 + ], + "enable": 36 + }, + "constructorParamaters": [ + "RIGHT", + 2 + ] + } + } + ], + "Decoder": [ + { + "x": 950, + "y": 620, + "objectType": "Decoder", + "label": "Decoder", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1 ], - "restrictedCircuitElementsUsed": [], - "nodes": [11, 14, 15, 22, 23, 24, 25, 26, 27] + "nodes": { + "output1": [ + 23, + 24 + ], + "input": 22 + } + } } - ] + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 8, + 9, + 10, + 15, + 16, + 17, + 20, + 21, + 25, + 26, + 29, + 37, + 51, + 57 + ] + } + ] } diff --git a/v0/src/simulator/spec/circuits/alu-circuitdata.json b/v0/src/simulator/spec/circuits/alu-circuitdata.json new file mode 100644 index 00000000..cd350e17 --- /dev/null +++ b/v0/src/simulator/spec/circuits/alu-circuitdata.json @@ -0,0 +1,8377 @@ +{ + "name": "ALU-74LS181", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "eWFjA0GCvFw4aqbmWcc4", + "focussedCircuit": 33755305138, + "orderedTabs": [ + "33755305138", + "35784513673" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 300, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 750, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 6, + 73 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 740, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 22, + 24 + ] + }, + { + "x": 650, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 25, + 39 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 650, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 28, + 29 + ] + }, + { + "x": 620, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 27 + ] + }, + { + "x": 690, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 27 + ] + }, + { + "x": 700, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 9, + 82 + ] + }, + { + "x": 540, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 33 + ] + }, + { + "x": 520, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 33 + ] + }, + { + "x": 530, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 32, + 34 + ] + }, + { + "x": 530, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 35, + 37 + ] + }, + { + "x": 710, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 10, + 34, + 36 + ] + }, + { + "x": 730, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 35 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 580, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 16, + 90 + ] + }, + { + "x": 560, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 24 + ] + }, + { + "x": 600, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 12, + 92 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 366 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 49 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 364 + ] + }, + { + "x": 530, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 49 + ] + }, + { + "x": 560, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 48 + ] + }, + { + "x": 580, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 46, + 51 + ] + }, + { + "x": 610, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 50 + ] + }, + { + "x": 700, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 53 + ] + }, + { + "x": 710, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 52 + ] + }, + { + "x": 740, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 55 + ] + }, + { + "x": 730, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 54 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 88 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 73 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 106 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 81 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 82 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 87 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 104 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 92 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 80 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 103 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 91 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 90 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 97 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 84 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 83 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 100 + ] + }, + { + "x": 450, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 58, + 125 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 440, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 57, + 74, + 76 + ] + }, + { + "x": 350, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 75, + 77, + 91 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 79 + ] + }, + { + "x": 350, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 78, + 80, + 81 + ] + }, + { + "x": 320, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 65, + 79 + ] + }, + { + "x": 390, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 60, + 79 + ] + }, + { + "x": 400, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 61, + 134 + ] + }, + { + "x": 240, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 71, + 85 + ] + }, + { + "x": 220, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 70, + 85 + ] + }, + { + "x": 230, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 83, + 84, + 86 + ] + }, + { + "x": 230, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 85, + 87, + 89 + ] + }, + { + "x": 410, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 62, + 86, + 88 + ] + }, + { + "x": 430, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 87 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 86 + ] + }, + { + "x": 280, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 68, + 142 + ] + }, + { + "x": 260, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 67, + 76 + ] + }, + { + "x": 300, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 40, + 64, + 144 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 105 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 107 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 352 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 101 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 69 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 102 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 353 + ] + }, + { + "x": 230, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 72, + 101 + ] + }, + { + "x": 260, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 96, + 100 + ] + }, + { + "x": 280, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 98, + 103 + ] + }, + { + "x": 310, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 66, + 102 + ] + }, + { + "x": 400, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 63, + 105 + ] + }, + { + "x": 410, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 93, + 104 + ] + }, + { + "x": 440, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 59, + 107 + ] + }, + { + "x": 430, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 94, + 106 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 140 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 127 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 125 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 158 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 133 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 134 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 139 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 156 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 144 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 132 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 155 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 143 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 142 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 149 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 136 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 135 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 152 + ] + }, + { + "x": 150, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 73, + 110, + 177 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 127 + ] + }, + { + "x": 140, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 109, + 126, + 128 + ] + }, + { + "x": 50, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 127, + 129, + 143 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 128 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 131 + ] + }, + { + "x": 50, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 130, + 132, + 133 + ] + }, + { + "x": 20, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 117, + 131 + ] + }, + { + "x": 90, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 112, + 131 + ] + }, + { + "x": 100, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 82, + 113, + 186 + ] + }, + { + "x": -60, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 123, + 137 + ] + }, + { + "x": -80, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 122, + 137 + ] + }, + { + "x": -70, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 135, + 136, + 138 + ] + }, + { + "x": -70, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 137, + 139, + 141 + ] + }, + { + "x": 110, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 114, + 138, + 140 + ] + }, + { + "x": 130, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 108, + 139 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 138 + ] + }, + { + "x": -20, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 90, + 120, + 194 + ] + }, + { + "x": -40, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 119, + 128 + ] + }, + { + "x": 0, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 92, + 116, + 196 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 157 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 159 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 347 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 153 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 121 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 154 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 348 + ] + }, + { + "x": -70, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 124, + 153 + ] + }, + { + "x": -40, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 148, + 152 + ] + }, + { + "x": -20, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 150, + 155 + ] + }, + { + "x": 10, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 118, + 154 + ] + }, + { + "x": 100, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 115, + 157 + ] + }, + { + "x": 110, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 145, + 156 + ] + }, + { + "x": 140, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 111, + 159 + ] + }, + { + "x": 130, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 146, + 158 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 192 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 179 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 177 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 210 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 185 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 186 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 191 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 208 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 196 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 184 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 207 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 195 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 194 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 201 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 188 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 187 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 204 + ] + }, + { + "x": -140, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 125, + 162 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 179 + ] + }, + { + "x": -150, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 161, + 178, + 180 + ] + }, + { + "x": -240, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 179, + 181, + 195 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 180 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 183 + ] + }, + { + "x": -240, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 182, + 184, + 185 + ] + }, + { + "x": -270, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 169, + 183 + ] + }, + { + "x": -200, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 164, + 183 + ] + }, + { + "x": -190, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 134, + 165 + ] + }, + { + "x": -350, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 175, + 189 + ] + }, + { + "x": -370, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 174, + 189 + ] + }, + { + "x": -360, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 187, + 188, + 190 + ] + }, + { + "x": -360, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 189, + 191, + 193 + ] + }, + { + "x": -180, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 166, + 190, + 192 + ] + }, + { + "x": -160, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 160, + 191 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 190 + ] + }, + { + "x": -310, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 142, + 172 + ] + }, + { + "x": -330, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 171, + 180 + ] + }, + { + "x": -290, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 144, + 168 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 209 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 211 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 246 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 205 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 173 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 206 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 253 + ] + }, + { + "x": -360, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 176, + 205 + ] + }, + { + "x": -330, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 200, + 204 + ] + }, + { + "x": -310, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 202, + 207 + ] + }, + { + "x": -280, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 170, + 206 + ] + }, + { + "x": -190, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 167, + 209 + ] + }, + { + "x": -180, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 197, + 208 + ] + }, + { + "x": -150, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 163, + 211 + ] + }, + { + "x": -160, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 198, + 210 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 214 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 235 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 212 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 238 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 238 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 235 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 219 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 218 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 232 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 290 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 236 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 237 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 228 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 229 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 230 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 248 + ] + }, + { + "x": -310, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 224, + 229 + ] + }, + { + "x": -300, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 225, + 228 + ] + }, + { + "x": -280, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 226, + 231 + ] + }, + { + "x": -270, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 230, + 244 + ] + }, + { + "x": -440, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 220, + 233 + ] + }, + { + "x": -370, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 232, + 439 + ] + }, + { + "x": -380, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 253, + 437 + ] + }, + { + "x": -450, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 213, + 217, + 236 + ] + }, + { + "x": -320, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 222, + 235, + 240 + ] + }, + { + "x": -300, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 223, + 253, + 283 + ] + }, + { + "x": -470, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 215, + 216, + 239 + ] + }, + { + "x": -280, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 238, + 241, + 456 + ] + }, + { + "x": -270, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 236, + 242, + 268 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 239 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 240 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 245 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 231 + ] + }, + { + "x": -260, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 243, + 247, + 246 + ] + }, + { + "x": -170, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 199, + 245, + 271 + ] + }, + { + "x": -360, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 245, + 438 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 227 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 257 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 294 + ] + }, + { + "x": -140, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 348, + 440 + ] + }, + { + "x": -120, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 284, + 441 + ] + }, + { + "x": -320, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 203, + 234, + 237 + ] + }, + { + "x": 830, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "3", + "connections": [ + 361, + 397 + ] + }, + { + "x": 880, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "4", + "connections": [ + 387, + 401 + ] + }, + { + "x": 870, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "1", + "connections": [ + 357, + 402 + ] + }, + { + "x": -270, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 249, + 258 + ] + }, + { + "x": -130, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 257, + 442 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 290 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 294 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 269 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 283 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 284 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 276 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 268 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 282 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 279 + ] + }, + { + "x": -40, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 240, + 265, + 269 + ] + }, + { + "x": 0, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 261, + 268, + 270 + ] + }, + { + "x": 30, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 269, + 342, + 452 + ] + }, + { + "x": 60, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 246, + 349, + 453 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 278 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 305 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 298 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 280 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 264 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 281 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 272 + ] + }, + { + "x": -30, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 267, + 280 + ] + }, + { + "x": 0, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 275, + 279 + ] + }, + { + "x": 20, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 277, + 458 + ] + }, + { + "x": -20, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 266, + 348, + 361 + ] + }, + { + "x": 10, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 237, + 262, + 357 + ] + }, + { + "x": 20, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 252, + 263, + 457 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 297 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 293 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 301 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 302 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 307 + ] + }, + { + "x": -450, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 221, + 259, + 291 + ] + }, + { + "x": -180, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 290, + 292 + ] + }, + { + "x": -180, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 291, + 293 + ] + }, + { + "x": -150, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 286, + 292 + ] + }, + { + "x": -280, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 250, + 260, + 295 + ] + }, + { + "x": -190, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 294, + 296 + ] + }, + { + "x": -190, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 295, + 297 + ] + }, + { + "x": -140, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 285, + 296 + ] + }, + { + "x": 20, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 274, + 299, + 427 + ] + }, + { + "x": -90, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 298, + 300 + ] + }, + { + "x": -90, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 299, + 301 + ] + }, + { + "x": -120, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 287, + 300 + ] + }, + { + "x": -110, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 288, + 303 + ] + }, + { + "x": -80, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 302, + 304 + ] + }, + { + "x": -80, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 303, + 358 + ] + }, + { + "x": 30, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 273, + 306 + ] + }, + { + "x": 170, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 305, + 445 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 289 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 342 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 362 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 335 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 346 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 345 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 349 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 350 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 351 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 338 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 357 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 344 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 356 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 355 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 337 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 343 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 361 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 360 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 336 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 332 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 331 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 333 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 334 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 339 + ] + }, + { + "x": 280, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 327, + 335 + ] + }, + { + "x": 290, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 326, + 336 + ] + }, + { + "x": 310, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 328, + 337 + ] + }, + { + "x": 320, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 329, + 338 + ] + }, + { + "x": 230, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 310, + 331 + ] + }, + { + "x": 280, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 325, + 332 + ] + }, + { + "x": 330, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 321, + 333 + ] + }, + { + "x": 380, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 316, + 334 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 330 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 368 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 358 + ] + }, + { + "x": 220, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 270, + 308, + 343 + ] + }, + { + "x": 270, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 322, + 342, + 344 + ] + }, + { + "x": 310, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 318, + 343, + 345 + ] + }, + { + "x": 360, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 312, + 344 + ] + }, + { + "x": 370, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 311, + 385, + 456 + ] + }, + { + "x": 120, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 147, + 356, + 457 + ] + }, + { + "x": -30, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 151, + 251, + 282 + ] + }, + { + "x": 380, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 271, + 313, + 384 + ] + }, + { + "x": 390, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 314, + 356, + 383 + ] + }, + { + "x": 400, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 315, + 352, + 355 + ] + }, + { + "x": 420, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 95, + 351, + 382 + ] + }, + { + "x": 270, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 99, + 354, + 362 + ] + }, + { + "x": 780, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "5", + "connections": [ + 353, + 394 + ] + }, + { + "x": 350, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 320, + 351, + 360 + ] + }, + { + "x": 340, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 319, + 347, + 350 + ] + }, + { + "x": 320, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 256, + 283, + 317 + ] + }, + { + "x": 310, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 304, + 341, + 359 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 358 + ] + }, + { + "x": 290, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 324, + 355, + 447 + ] + }, + { + "x": 280, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 254, + 282, + 323 + ] + }, + { + "x": 240, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 309, + 353, + 446 + ] + }, + { + "x": 470, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 364, + 448 + ] + }, + { + "x": 570, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 363, + 410 + ] + }, + { + "x": 490, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 381, + 449 + ] + }, + { + "x": 720, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 389, + 411 + ] + }, + { + "x": 910, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "8", + "connections": [ + 404, + 412 + ] + }, + { + "x": 320, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 340, + 369 + ] + }, + { + "x": 480, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 368, + 450 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 383 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 384 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 382 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 381 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 390 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 386 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 385 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 387 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 388 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 389 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 428 + ] + }, + { + "x": 610, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 365, + 373, + 389 + ] + }, + { + "x": 600, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 352, + 372, + 388 + ] + }, + { + "x": 580, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 350, + 370, + 387 + ] + }, + { + "x": 570, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 349, + 371, + 386 + ] + }, + { + "x": 620, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 346, + 376 + ] + }, + { + "x": 630, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 375, + 384 + ] + }, + { + "x": 640, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 255, + 377, + 383 + ] + }, + { + "x": 650, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 378, + 382, + 413 + ] + }, + { + "x": 660, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 366, + 379, + 381 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 374 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 407 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 408 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 419 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 354 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 411 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 421 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 254 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 413 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 412 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 423 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 255 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 256 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 406 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 367 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 426 + ] + }, + { + "x": 900, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 403, + 413 + ] + }, + { + "x": 730, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 391, + 409 + ] + }, + { + "x": 750, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 392, + 409 + ] + }, + { + "x": 740, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 407, + 408, + 410 + ] + }, + { + "x": 740, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 364, + 409 + ] + }, + { + "x": 800, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 366, + 395, + 412 + ] + }, + { + "x": 850, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 367, + 399, + 411 + ] + }, + { + "x": 840, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 388, + 398, + 406 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 422 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 420 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 424 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 425 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 431 + ] + }, + { + "x": 740, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 393, + 420 + ] + }, + { + "x": 800, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 415, + 419 + ] + }, + { + "x": 790, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 396, + 422 + ] + }, + { + "x": 810, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 414, + 421 + ] + }, + { + "x": 840, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 400, + 424 + ] + }, + { + "x": 830, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 416, + 423 + ] + }, + { + "x": 840, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 417, + 426 + ] + }, + { + "x": 890, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 405, + 425 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 298 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 380 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 432 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 435 + ] + }, + { + "x": 820, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 418, + 432, + 433 + ] + }, + { + "x": 660, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 429, + 431 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 431 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 436 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 430 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 434 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 234 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 247 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 233 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 251 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 252 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 258 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 446 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 447 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 306 + ] + }, + { + "x": 160, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 362, + 443 + ] + }, + { + "x": 180, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 360, + 444 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 363 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 365 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 369 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 456 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 270 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 271 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 457 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 458 + ] + }, + { + "x": 40, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 239, + 346, + 451 + ] + }, + { + "x": 70, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 284, + 347, + 454 + ] + }, + { + "x": 50, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 281, + 455 + ] + } + ], + "id": 35784513673, + "name": "ALU", + "Input": [ + { + "x": 870, + "y": 120, + "objectType": "Input", + "label": "S0", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 20, + "id": "bgyS7iMmTulYzuhvuJAw" + } + ] + } + }, + { + "x": 870, + "y": 140, + "objectType": "Input", + "label": "S1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 1 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 40, + "id": "WLqXqxdEhvoLWHtBXHjI" + } + ] + } + }, + { + "x": 870, + "y": 160, + "objectType": "Input", + "label": "S2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 2 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 60, + "id": "a8z7DkCwKWXkSw3WfkAz" + } + ] + } + }, + { + "x": 870, + "y": 180, + "objectType": "Input", + "label": "S3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 3 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 80, + "id": "oU212lSCqnaiI2XB6l6k" + } + ] + } + }, + { + "x": 740, + "y": 30, + "objectType": "Input", + "label": "~B3", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 22 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 100, + "id": "1ukWtQYmxOZZ1aandrYs" + } + ] + } + }, + { + "x": 530, + "y": 30, + "objectType": "Input", + "label": "~A3", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 37 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 120, + "id": "dtsyFvTYyoF8pFrQ4gZv" + } + ] + } + }, + { + "x": 440, + "y": 30, + "objectType": "Input", + "label": "~B2", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 74 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 140, + "id": "rMYJA0Nz0IHW6cXFoIMh" + } + ] + } + }, + { + "x": 230, + "y": 30, + "objectType": "Input", + "label": "~A2", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 89 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 160, + "id": "k4Q6Y6aWUXjA9uMOFLA9" + } + ] + } + }, + { + "x": 140, + "y": 30, + "objectType": "Input", + "label": "~B1", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 126 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 180, + "id": "omeNlryzvz7Pz0lFjW6r" + } + ] + } + }, + { + "x": -70, + "y": 30, + "objectType": "Input", + "label": "~A1", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 141 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 200, + "id": "n8heKwweZojnOjBCw7yI" + } + ] + } + }, + { + "x": -150, + "y": 30, + "objectType": "Input", + "label": "~B0", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 178 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 220, + "id": "EZQWSGwtHHM3LMJAiLUX" + } + ] + } + }, + { + "x": -360, + "y": 30, + "objectType": "Input", + "label": "~A0", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 193 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 240, + "id": "DnHv05kyFumssr1vnxvh" + } + ] + } + }, + { + "x": -450, + "y": 30, + "objectType": "Input", + "label": "M", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 214 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 260, + "id": "UrilH2CzjLyUst4aRdT7" + } + ] + } + }, + { + "x": -470, + "y": 30, + "objectType": "Input", + "label": "~Cn", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 215 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 280, + "id": "OCylfDQemyKD1ghkGw99" + } + ] + } + } + ], + "Output": [ + { + "x": -450, + "y": 890, + "objectType": "Output", + "label": "~F0", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 259 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 80, + "id": "O88tnQx6pYWyz8DgCW2w" + } + ] + } + }, + { + "x": -280, + "y": 890, + "objectType": "Output", + "label": "~F1", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 260 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 100, + "id": "Q7u02WLnBPTPrO8hOd0v" + } + ] + } + }, + { + "x": -130, + "y": 890, + "objectType": "Output", + "label": "A=B", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 307 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 120, + "id": "9FyiglYgXYTjs8PjQO9z" + } + ] + } + }, + { + "x": 310, + "y": 890, + "objectType": "Output", + "label": "~F3", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 359 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 140, + "id": "pGwpiM47ZeuqcCx5ecc5" + } + ] + } + }, + { + "x": 590, + "y": 890, + "objectType": "Output", + "label": "~P", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 390 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 160, + "id": "lLu0TkM1mm3IY2JQMoOO" + } + ] + } + }, + { + "x": 20, + "y": 890, + "objectType": "Output", + "label": "~F2", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 427 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 180, + "id": "iPKabWfwVrry6UrorWWC" + } + ] + } + }, + { + "x": 650, + "y": 890, + "objectType": "Output", + "label": "~Cn+4", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 435 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 200, + "id": "wyQYiBXlg5PGYSQBqecL" + } + ] + } + }, + { + "x": 820, + "y": 890, + "objectType": "Output", + "label": "~G", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 436 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 220, + "id": "5UE1sKl4PlJGJHUtfQdh" + } + ] + } + } + ], + "NotGate": [ + { + "x": 650, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 26, + "inp1": 25 + } + } + }, + { + "x": 350, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 78, + "inp1": 77 + } + } + }, + { + "x": 50, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 130, + "inp1": 129 + } + } + }, + { + "x": -240, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 182, + "inp1": 181 + } + } + }, + { + "x": -450, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 213, + "inp1": 212 + } + } + }, + { + "x": 820, + "y": 830, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 434, + "inp1": 433 + } + } + } + ], + "AndGate": [ + { + "x": 740, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 4, + 5, + 6 + ], + "output1": 7 + } + } + }, + { + "x": 700, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 8, + 9, + 10 + ], + "output1": 11 + } + } + }, + { + "x": 610, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 12, + 13 + ], + "output1": 14 + } + } + }, + { + "x": 570, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 15, + 16 + ], + "output1": 17 + } + } + }, + { + "x": 530, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 18, + 19 + ], + "output1": 20 + } + } + }, + { + "x": 440, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 56, + 57, + 58 + ], + "output1": 59 + } + } + }, + { + "x": 400, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 60, + 61, + 62 + ], + "output1": 63 + } + } + }, + { + "x": 310, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 64, + 65 + ], + "output1": 66 + } + } + }, + { + "x": 270, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 67, + 68 + ], + "output1": 69 + } + } + }, + { + "x": 230, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 70, + 71 + ], + "output1": 72 + } + } + }, + { + "x": 140, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 108, + 109, + 110 + ], + "output1": 111 + } + } + }, + { + "x": 100, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 112, + 113, + 114 + ], + "output1": 115 + } + } + }, + { + "x": 10, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 116, + 117 + ], + "output1": 118 + } + } + }, + { + "x": -30, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 119, + 120 + ], + "output1": 121 + } + } + }, + { + "x": -70, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 122, + 123 + ], + "output1": 124 + } + } + }, + { + "x": -150, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 160, + 161, + 162 + ], + "output1": 163 + } + } + }, + { + "x": -190, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 164, + 165, + 166 + ], + "output1": 167 + } + } + }, + { + "x": -280, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 168, + 169 + ], + "output1": 170 + } + } + }, + { + "x": -320, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 171, + 172 + ], + "output1": 173 + } + } + }, + { + "x": -360, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 174, + 175 + ], + "output1": 176 + } + } + }, + { + "x": -310, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 222, + 223 + ], + "output1": 224 + } + } + }, + { + "x": -270, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 241, + 242, + 243 + ], + "output1": 244 + } + } + }, + { + "x": 10, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 261, + 262, + 263 + ], + "output1": 264 + } + } + }, + { + "x": -30, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 265, + 266 + ], + "output1": 267 + } + } + }, + { + "x": -130, + "y": 800, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 285, + 286, + 287, + 288 + ], + "output1": 289 + } + } + }, + { + "x": 230, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 308, + 309 + ], + "output1": 310 + } + } + }, + { + "x": 380, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "5", + 1 + ], + "nodes": { + "inp": [ + 311, + 312, + 313, + 314, + 315 + ], + "output1": 316 + } + } + }, + { + "x": 330, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 317, + 318, + 319, + 320 + ], + "output1": 321 + } + } + }, + { + "x": 280, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 322, + 323, + 324 + ], + "output1": 325 + } + } + }, + { + "x": 740, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 391, + 392 + ], + "output1": 393 + } + } + }, + { + "x": 790, + "y": 590, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 394, + 395 + ], + "output1": 396 + } + } + }, + { + "x": 840, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 397, + 398, + 399 + ], + "output1": 400 + } + } + }, + { + "x": 890, + "y": 590, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 401, + 402, + 403, + 404 + ], + "output1": 405 + } + } + }, + { + "x": 50, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 451, + 452, + 453, + 454 + ], + "output1": 455 + } + } + } + ], + "NorGate": [ + { + "x": 720, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 41, + 42 + ], + "output1": 43 + } + } + }, + { + "x": 570, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 44, + 45, + 46 + ], + "output1": 47 + } + } + }, + { + "x": 420, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 93, + 94 + ], + "output1": 95 + } + } + }, + { + "x": 270, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 96, + 97, + 98 + ], + "output1": 99 + } + } + }, + { + "x": 120, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 145, + 146 + ], + "output1": 147 + } + } + }, + { + "x": -30, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 148, + 149, + 150 + ], + "output1": 151 + } + } + }, + { + "x": -170, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 197, + 198 + ], + "output1": 199 + } + } + }, + { + "x": -320, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 200, + 201, + 202 + ], + "output1": 203 + } + } + }, + { + "x": -290, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 225, + 226 + ], + "output1": 227 + } + } + }, + { + "x": 10, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 275, + 276, + 277 + ], + "output1": 278 + } + } + }, + { + "x": 300, + "y": 660, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 326, + 327, + 328, + 329 + ], + "output1": 330 + } + } + }, + { + "x": 820, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 414, + 415, + 416, + 417 + ], + "output1": 418 + } + } + } + ], + "NandGate": [ + { + "x": -460, + "y": 580, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 216, + 217 + ], + "output1": 218 + } + } + }, + { + "x": 590, + "y": 580, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 370, + 371, + 372, + 373 + ], + "output1": 374 + } + } + }, + { + "x": 640, + "y": 590, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "5", + 1 + ], + "nodes": { + "inp": [ + 375, + 376, + 377, + 378, + 379 + ], + "output1": 380 + } + } + }, + { + "x": 650, + "y": 770, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 428, + 429 + ], + "output1": 430 + } + } + } + ], + "XorGate": [ + { + "x": -450, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 219, + 220 + ], + "output1": 221 + } + } + }, + { + "x": -280, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 248, + 249 + ], + "output1": 250 + } + } + }, + { + "x": 20, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 272, + 273 + ], + "output1": 274 + } + } + }, + { + "x": 310, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 339, + 340 + ], + "output1": 341 + } + } + }, + { + "x": -370, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 437, + 438 + ], + "output1": 439 + } + } + }, + { + "x": -130, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 440, + 441 + ], + "output1": 442 + } + } + }, + { + "x": 170, + "y": 680, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 443, + 444 + ], + "output1": 445 + } + } + }, + { + "x": 480, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 448, + 449 + ], + "output1": 450 + } + } + } + ], + "nodes": [ + 21, + 23, + 24, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 38, + 39, + 40, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 73, + 75, + 76, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 90, + 91, + 92, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 125, + 127, + 128, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 142, + 143, + 144, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 177, + 179, + 180, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 194, + 195, + 196, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 245, + 246, + 247, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 268, + 269, + 270, + 271, + 279, + 280, + 281, + 282, + 283, + 284, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 381, + 382, + 383, + 384, + 385, + 386, + 387, + 388, + 389, + 406, + 407, + 408, + 409, + 410, + 411, + 412, + 413, + 419, + 420, + 421, + 422, + 423, + 424, + 425, + 426, + 431, + 432, + 446, + 447, + 456, + 457, + 458 + ] + }, + { + "layout": { + "width": 100, + "height": 140, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 1 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 9 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 11 + ] + }, + { + "x": 870, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 61 + ] + }, + { + "x": 870, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 6 + ] + }, + { + "x": 890, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 57 + ] + }, + { + "x": 890, + "y": 360, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 8 + ] + }, + { + "x": 840, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 55 + ] + }, + { + "x": 840, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 10 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 910, + "y": 410, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 19 + ] + }, + { + "x": 910, + "y": 360, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 60 + ] + }, + { + "x": 900, + "y": 430, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 21 + ] + }, + { + "x": 900, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 58 + ] + }, + { + "x": 860, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 16, + 23 + ] + }, + { + "x": 860, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 56 + ] + }, + { + "x": 810, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 25 + ] + }, + { + "x": 810, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 24, + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 920, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 28 + ] + }, + { + "x": 920, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 62 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 940, + "y": 600, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 31 + ] + }, + { + "x": 940, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 63 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 65 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 43 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 67 + ] + }, + { + "x": 1120, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 44 + ] + }, + { + "x": 1120, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 69 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 66 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 68 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 71 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 80, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": 0, + "y": 100, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 0, + "y": 120, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": 0, + "y": 140, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 0, + "y": 160, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 0, + "y": 180, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 200, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 3 + ] + }, + { + "x": 0, + "y": 220, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 0, + "y": 240, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 0, + "y": 260, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 0, + "y": 280, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 100, + "y": 80, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 100, + "y": 100, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 100, + "y": 120, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 46 + ] + }, + { + "x": 100, + "y": 140, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 100, + "y": 160, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 100, + "y": 180, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 100, + "y": 200, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 100, + "y": 220, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 49 + ] + } + ], + "id": 33755305138, + "name": "Main", + "Input": [ + { + "x": 710, + "y": 390, + "objectType": "Input", + "label": "~A", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 15 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 100, + "id": "KkUsNwfO4X0x4c04hwMv" + } + ] + } + }, + { + "x": 710, + "y": 480, + "objectType": "Input", + "label": "~B", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 12 + }, + "values": { + "state": 12 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 20, + "id": "P6IeBwGNUu70jnDV7AEM" + } + ] + } + }, + { + "x": 740, + "y": 560, + "objectType": "Input", + "label": "Mode", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 26 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "v6fmRUb6A8NpuXLnnBr2" + } + ] + } + }, + { + "x": 740, + "y": 600, + "objectType": "Input", + "label": "~Cn", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 29 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "xxDizRwLr4gvjxzTAF9Q" + } + ] + } + }, + { + "x": 700, + "y": 230, + "objectType": "Input", + "label": "S", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 32 + }, + "values": { + "state": 4 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 80, + "id": "wjiTCwACtzuNTQPiA7Qd" + } + ] + } + } + ], + "Output": [ + { + "x": 1260, + "y": 290, + "objectType": "Output", + "label": "~F", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 40, + "id": "8EmhK1WYRAieQ1CdZaw8" + } + ] + } + }, + { + "x": 1090, + "y": 260, + "objectType": "Output", + "label": "A=B", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 46 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "HBawk8lC7uuFfL6yoUs4" + } + ] + } + }, + { + "x": 1090, + "y": 300, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 47 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "j9nnntr30X9Y0XSOHFG9" + } + ] + } + }, + { + "x": 1090, + "y": 340, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 48 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "82KrKflpCRdOtyEkALcm" + } + ] + } + }, + { + "x": 1090, + "y": 360, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 49 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "dqfl9XSBF9zphXeBra5W" + } + ] + } + } + ], + "Splitter": [ + { + "x": 770, + "y": 360, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 2, + 3, + 4, + 5 + ], + "inp1": 1 + } + } + }, + { + "x": 770, + "y": 450, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 14, + 15, + 16, + 17 + ], + "inp1": 13 + } + } + }, + { + "x": 780, + "y": 200, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 34, + 35, + 36, + 37 + ], + "inp1": 33 + } + } + }, + { + "x": 1200, + "y": 260, + "objectType": "Splitter", + "label": "", + "direction": "LEFT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 39, + 40, + 41, + 42 + ], + "inp1": 38 + } + } + } + ], + "SubCircuit": [ + { + "x": 960, + "y": 140, + "id": "35784513673", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63 + ], + "outputNodes": [ + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 6, + 7, + 8, + 9, + 10, + 11, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 27, + 28, + 30, + 31, + 43, + 44 + ] + } + ] +} diff --git a/v0/src/simulator/spec/circuits/gates-circuitdata.json b/v0/src/simulator/spec/circuits/gates-circuitdata.json index a5c96609..7361a1d5 100644 --- a/v0/src/simulator/spec/circuits/gates-circuitdata.json +++ b/v0/src/simulator/spec/circuits/gates-circuitdata.json @@ -1,710 +1,879 @@ { - "name": "gates-circuitdata", - "timePeriod": 500, - "clockEnabled": true, - "projectId": "hCqg1Ns4JVckHsnyKQDi", - "focussedCircuit": 11597572508, - "orderedTabs": ["11597572508"], - "scopes": [ - { - "layout": { - "width": 100, - "height": 280, - "title_x": 50, - "title_y": 13, - "titleEnabled": true + "name": "gates-circuitdata", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "hCqg1Ns4JVckHsnyKQDi", + "focussedCircuit": 11597572508, + "orderedTabs": [ + "11597572508" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 280, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 260, + "y": -10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 20, + 30 + ] + }, + { + "x": 260, + "y": 130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 3, + 33 + ] + }, + { + "x": 210, + "y": 10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 21, + 32 + ] + }, + { + "x": 210, + "y": 150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 4, + 34 + ] + }, + { + "x": 260, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 11, + 35 + ] + }, + { + "x": 210, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 32, + 12, + 41 + ] + }, + { + "x": 260, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 6, + 36 + ] + }, + { + "x": 260, + "y": 600, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 17, + 38 + ] + }, + { + "x": 260, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 14 + ] + }, + { + "x": 260, + "y": 740, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 36, + 37, + 8 + ] + }, + { + "x": 210, + "y": 840, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 40 + ] + }, + { + "x": 210, + "y": 760, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 39, + 9, + 41 + ] + }, + { + "x": 210, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 40, + 18 + ] + } + ], + "id": 11597572508, + "name": "Main", + "Input": [ + { + "x": -30, + "y": -10, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 20 }, - "verilogMetadata": { - "isVerilogCircuit": false, - "isMainCircuit": false, - "code": "// Write Some Verilog Code Here!", - "subCircuitScopeIds": [] + "values": { + "state": 1 }, - "allNodes": [ - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [22] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [30] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [32] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [23] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [35] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [25] - }, - { - "x": -20, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [38] - }, - { - "x": -20, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [40] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [27] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [33] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [34] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [24] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [37] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [39] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [28] - }, - { - "x": -20, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [36] - }, - { - "x": -20, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [41] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [26] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [2] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [5] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [13] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [7] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [19] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [10] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [16] - }, - { - "x": 260, - "y": -10, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [0, 20, 30] - }, - { - "x": 260, - "y": 130, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [29, 3, 33] - }, - { - "x": 210, - "y": 10, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [1, 21, 32] - }, - { - "x": 210, - "y": 150, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [31, 4, 34] - }, - { - "x": 260, - "y": 300, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [30, 11, 35] - }, - { - "x": 210, - "y": 320, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [32, 12, 41] - }, - { - "x": 260, - "y": 460, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [33, 6, 36] - }, - { - "x": 260, - "y": 600, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [35, 17, 38] - }, - { - "x": 260, - "y": 820, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [38, 14] - }, - { - "x": 260, - "y": 740, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [36, 37, 8] - }, - { - "x": 210, - "y": 840, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [15, 40] - }, - { - "x": 210, - "y": 760, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [39, 9, 41] - }, - { - "x": 210, - "y": 620, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [34, 40, 18] - } - ], - "id": 11597572508, - "name": "Main", - "Input": [ - { - "x": -30, - "y": -10, - "objectType": "Input", - "label": "inp1", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 20 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 20, - "id": "55mKFwVFnZeU6ucfO8am" - } - ] - } - }, - { - "x": -30, - "y": 10, - "objectType": "Input", - "label": "inp2", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 21 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 40, - "id": "2O2YfZk7yuqLrtiRb429" - } - ] - } - } - ], - "Output": [ - { - "x": 500, - "y": 0, - "objectType": "Output", - "label": "out1", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 22 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 20, - "id": "RarwxCcQgRygZftUFlMr" - } - ] - } - }, - { - "x": 510, - "y": 140, - "objectType": "Output", - "label": "out2", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 23 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 40, - "id": "N0agpzN04aqy9nLexP98" - } - ] - } - }, - { - "x": 520, - "y": 310, - "objectType": "Output", - "label": "out3", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 24 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 60, - "id": "2yO9fxrqrjPk1urH47Fc" - } - ] - } - }, - { - "x": 520, - "y": 460, - "objectType": "Output", - "label": "out4", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 25 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 80, - "id": "IN7sNsKhkByzBHRShVdu" - } - ] - } - }, - { - "x": 520, - "y": 610, - "objectType": "Output", - "label": "out5", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 26 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 100, - "id": "Dfr4VEfv27q3AOwkLqpx" - } - ] - } - }, - { - "x": 520, - "y": 750, - "objectType": "Output", - "label": "out6", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 27 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 120, - "id": "FGeZ7ip5nJo9MUlEyJ35" - } - ] - } - }, - { - "x": 530, - "y": 830, - "objectType": "Output", - "label": "out7", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 28 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 140, - "id": "oYVAxzNmrQgKjC7I3xOg" - } - ] - } - } - ], - "NotGate": [ - { - "x": 340, - "y": 460, - "objectType": "NotGate", - "label": "NOT GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 1], - "nodes": { - "output1": 7, - "inp1": 6 - } - } - } + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "55mKFwVFnZeU6ucfO8am" + } + ] + } + }, + { + "x": -30, + "y": 10, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 21 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "2O2YfZk7yuqLrtiRb429" + } + ] + } + } + ], + "Output": [ + { + "x": 500, + "y": 0, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 22 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "RarwxCcQgRygZftUFlMr" + } + ] + } + }, + { + "x": 510, + "y": 140, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 23 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "N0agpzN04aqy9nLexP98" + } + ] + } + }, + { + "x": 520, + "y": 310, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 24 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "2yO9fxrqrjPk1urH47Fc" + } + ] + } + }, + { + "x": 520, + "y": 460, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 25 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "IN7sNsKhkByzBHRShVdu" + } + ] + } + }, + { + "x": 520, + "y": 610, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 26 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 100, + "id": "Dfr4VEfv27q3AOwkLqpx" + } + ] + } + }, + { + "x": 520, + "y": 750, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 27 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "FGeZ7ip5nJo9MUlEyJ35" + } + ] + } + }, + { + "x": 530, + "y": 830, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 28 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "oYVAxzNmrQgKjC7I3xOg" + } + ] + } + } + ], + "NotGate": [ + { + "x": 340, + "y": 460, + "objectType": "NotGate", + "label": "NOT GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 ], - "OrGate": [ - { - "x": 330, - "y": 140, - "objectType": "OrGate", - "label": "OR GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [3, 4], - "output1": 5 - } - } - } + "nodes": { + "output1": 7, + "inp1": 6 + } + } + } + ], + "OrGate": [ + { + "x": 330, + "y": 140, + "objectType": "OrGate", + "label": "OR GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "AndGate": [ - { - "x": 320, - "y": 0, - "objectType": "AndGate", - "label": "AND GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [0, 1], - "output1": 2 - } - } - } + "nodes": { + "inp": [ + 3, + 4 + ], + "output1": 5 + } + } + } + ], + "AndGate": [ + { + "x": 320, + "y": 0, + "objectType": "AndGate", + "label": "AND GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "NorGate": [ - { - "x": 330, - "y": 830, - "objectType": "NorGate", - "label": "NOR", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [14, 15], - "output1": 16 - } - } - } + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2 + } + } + } + ], + "NorGate": [ + { + "x": 330, + "y": 830, + "objectType": "NorGate", + "label": "NOR", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "NandGate": [ - { - "x": 340, - "y": 310, - "objectType": "NandGate", - "label": "NAND GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [11, 12], - "output1": 13 - } - } - } + "nodes": { + "inp": [ + 14, + 15 + ], + "output1": 16 + } + } + } + ], + "NandGate": [ + { + "x": 340, + "y": 310, + "objectType": "NandGate", + "label": "NAND GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "XorGate": [ - { - "x": 330, - "y": 750, - "objectType": "XorGate", - "label": "XOR", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [8, 9], - "output1": 10 - } - } - } + "nodes": { + "inp": [ + 11, + 12 + ], + "output1": 13 + } + } + } + ], + "XorGate": [ + { + "x": 330, + "y": 750, + "objectType": "XorGate", + "label": "XOR", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "XnorGate": [ - { - "x": 330, - "y": 610, - "objectType": "XnorGate", - "label": "XNOR GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [17, 18], - "output1": 19 - } - } - } + "nodes": { + "inp": [ + 8, + 9 + ], + "output1": 10 + } + } + } + ], + "XnorGate": [ + { + "x": 330, + "y": 610, + "objectType": "XnorGate", + "label": "XNOR GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "restrictedCircuitElementsUsed": [], - "nodes": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41] + "nodes": { + "inp": [ + 17, + 18 + ], + "output1": 19 + } + } } - ] + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41 + ] + } + ] } diff --git a/v0/src/simulator/spec/circuits/misc-circuitdata.json b/v0/src/simulator/spec/circuits/misc-circuitdata.json new file mode 100644 index 00000000..9da89ca2 --- /dev/null +++ b/v0/src/simulator/spec/circuits/misc-circuitdata.json @@ -0,0 +1,1572 @@ +{ + "name": "misc", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "Z66aSelqsnFvwJteATxg", + "focussedCircuit": 60033074305, + "orderedTabs": [ + "60033074305" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 320, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -30, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "A", + "connections": [ + 12 + ] + }, + { + "x": -30, + "y": 30, + "type": 0, + "bitWidth": 1, + "label": "B", + "connections": [ + 22 + ] + }, + { + "x": -10, + "y": -40, + "type": 0, + "bitWidth": 3, + "label": "Ctrl", + "connections": [ + 5 + ] + }, + { + "x": -10, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "Cout", + "connections": [ + 10 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Out", + "connections": [ + 8 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 3, + "label": "", + "connections": [ + 2, + 56 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": -20, + "y": -240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 9 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -110, + "y": -400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 6, + 13 + ] + }, + { + "x": -110, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 12, + 21 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "A", + "connections": [ + 21 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "B", + "connections": [ + 23 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Cin", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Sum", + "connections": [ + 25 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Cout", + "connections": [ + 27 + ] + }, + { + "x": -110, + "y": -20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 16, + 31 + ] + }, + { + "x": -170, + "y": -340, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 7, + 23 + ] + }, + { + "x": -170, + "y": -10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 22, + 72 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 70, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 26 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 3, + "label": "input stream", + "connections": [ + 56 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 3, + "label": "2's complement", + "connections": [ + 30 + ] + }, + { + "x": 30, + "y": 0, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -110, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 32, + 39 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "reset", + "connections": [] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": -110, + "y": 340, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 36, + 44 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [ + 50 + ] + }, + { + "x": -110, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 39, + 41, + 69 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 50, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 48 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": -160, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 46, + 47, + 49 + ] + }, + { + "x": -160, + "y": 570, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 48, + 50 + ] + }, + { + "x": 60, + "y": 570, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 49 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 20, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 40, + "y": -660, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 51, + 56, + 63 + ] + }, + { + "x": 40, + "y": -530, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 5, + 28, + 55 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 63 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 2, + "label": "", + "connections": [ + 65 + ] + }, + { + "x": 40, + "y": -850, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 55, + 60 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 61 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 2, + "label": "", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 71 + ] + }, + { + "x": -110, + "y": 700, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 70 + ] + }, + { + "x": 60, + "y": 700, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 69, + 67 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 68 + ] + }, + { + "x": -170, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 66 + ] + } + ], + "id": 60033074305, + "name": "Main", + "Input": [ + { + "x": -50, + "y": -530, + "objectType": "Input", + "label": "mode", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 7 + }, + "constructorParamaters": [ + "RIGHT", + 3, + { + "x": 0, + "y": 100, + "id": "XLIG7xxHzqiqXN4niWjc" + } + ] + } + }, + { + "x": -260, + "y": -400, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "xnFLotUtTF8dDqzdt63A" + } + ] + } + }, + { + "x": -260, + "y": -340, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 7 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "20RIzYI8HAyZyA6HZkie" + } + ] + } + }, + { + "x": -240, + "y": 0, + "objectType": "Input", + "label": "inp3", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 24 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "4Pt2rPBEr90DVh789QpH" + } + ] + } + }, + { + "x": -230, + "y": 260, + "objectType": "Input", + "label": "enable", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 47 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 80, + "id": "Bvzy3iTJUD5HiGnxpab6" + } + ] + } + } + ], + "Output": [ + { + "x": 250, + "y": -370, + "objectType": "Output", + "label": "ALU-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 8 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "AKbMNYWkZvw4oWCYQ12W" + } + ] + } + }, + { + "x": 260, + "y": -240, + "objectType": "Output", + "label": "ALU-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 9 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "K7hEEwIPmQ17joAgCPXg" + } + ] + } + }, + { + "x": 250, + "y": -150, + "objectType": "Output", + "label": "Tunnel-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 15 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "jgCz5e7jPDpPEbwEaQgh" + } + ] + } + }, + { + "x": 150, + "y": -10, + "objectType": "Output", + "label": "Adder-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 25 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "IaKcxWxYEyFXwog5mmN9" + } + ] + } + }, + { + "x": 200, + "y": 60, + "objectType": "Output", + "label": "Adder-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 26 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "zuWpzdjxikK9URyRNLmT" + } + ] + } + }, + { + "x": 270, + "y": -530, + "objectType": "Output", + "label": "2s-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 30 + }, + "constructorParamaters": [ + "LEFT", + 3, + { + "x": 100, + "y": 100, + "id": "4uEXpHNgO8CNC3NeKPhs" + } + ] + } + }, + { + "x": 160, + "y": 190, + "objectType": "Output", + "label": "T-state-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 35 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "MwFKnzZlWzyDBVGrzz5e" + } + ] + } + }, + { + "x": 160, + "y": 340, + "objectType": "Output", + "label": "buffer-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 40 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "kCRFdkujlb6UZZaBH2Wi" + } + ] + } + }, + { + "x": 180, + "y": 450, + "objectType": "Output", + "label": "CI-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "vh7IJznYSr54Ohz8GC2R" + } + ] + } + }, + { + "x": 240, + "y": -710, + "objectType": "Output", + "label": "s-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 57 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "c4XKu6fhOdVbCK6wqiht" + } + ] + } + }, + { + "x": 240, + "y": -690, + "objectType": "Output", + "label": "s-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 58 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 220, + "id": "IcyojhGiGRYqMM9B87k5" + } + ] + } + }, + { + "x": 240, + "y": -670, + "objectType": "Output", + "label": "s-out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 240, + "id": "ccIvryJkgZqu7qvSQg4l" + } + ] + } + }, + { + "x": 220, + "y": -880, + "objectType": "Output", + "label": "s-un-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 64 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 260, + "id": "9CB5RKzglQEWYo6MvnDa" + } + ] + } + }, + { + "x": 230, + "y": -860, + "objectType": "Output", + "label": "s-un-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 65 + }, + "constructorParamaters": [ + "LEFT", + 2, + { + "x": 100, + "y": 280, + "id": "dujdaDsq5xV6Z9bOchmB" + } + ] + } + }, + { + "x": 170, + "y": 640, + "objectType": "Output", + "label": "Force-out", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 71 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 300, + "id": "iHSRiMZgMM6EXgN1xPfJ" + } + ] + } + } + ], + "Splitter": [ + { + "x": 120, + "y": -680, + "objectType": "Splitter", + "label": "splitter-equal", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3, + [ + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 52, + 53, + 54 + ], + "inp1": 51 + } + } + }, + { + "x": 130, + "y": -860, + "objectType": "Splitter", + "label": "splitter-unequal", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3, + [ + 1, + 2 + ] + ], + "nodes": { + "outputs": [ + 61, + 62 + ], + "inp1": 60 + } + } + } + ], + "ControlledInverter": [ + { + "x": 60, + "y": 450, + "objectType": "ControlledInverter", + "label": "controlled Inverter", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 42, + "inp1": 41, + "state": 43 + } + } + } + ], + "TriState": [ + { + "x": 50, + "y": 190, + "objectType": "TriState", + "label": "T-state buffer", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 33, + "inp1": 32, + "state": 34 + } + } + } + ], + "Adder": [ + { + "x": 50, + "y": -10, + "objectType": "Adder", + "label": "Adder", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "inpA": 16, + "inpB": 17, + "carryIn": 18, + "carryOut": 20, + "sum": 19 + } + } + } + ], + "TwoComplement": [ + { + "x": 120, + "y": -530, + "objectType": "TwoComplement", + "label": "2's compliment", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3 + ], + "nodes": { + "output1": 29, + "inp1": 28 + } + } + } + ], + "Buffer": [ + { + "x": 50, + "y": 340, + "objectType": "Buffer", + "label": "buffer", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 38, + "inp1": 36, + "reset": 37 + } + } + } + ], + "Tunnel": [ + { + "x": -50, + "y": -150, + "objectType": "Tunnel", + "label": "Tunnel-IN", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1, + "T" + ], + "nodes": { + "inp1": 11 + }, + "values": { + "identifier": "T" + } + } + }, + { + "x": 140, + "y": -150, + "objectType": "Tunnel", + "label": "Tunnel-Out", + "direction": "LEFT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1, + "T" + ], + "nodes": { + "inp1": 14 + }, + "values": { + "identifier": "T" + } + } + } + ], + "ALU": [ + { + "x": -10, + "y": -370, + "objectType": "ALU", + "label": "ALU", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "inp1": 0, + "inp2": 1, + "output": 4, + "carryOut": 3, + "controlSignalInput": 2 + } + } + } + ], + "ForceGate": [ + { + "x": 60, + "y": 640, + "objectType": "ForceGate", + "label": "force gate", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 68, + "inp1": 66, + "inp2": 67 + } + } + }, + { + "x": 60, + "y": 640, + "objectType": "ForceGate", + "label": "force gate", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 68, + "inp1": 66, + "inp2": 67 + } + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 10, + 12, + 13, + 21, + 22, + 23, + 27, + 31, + 39, + 44, + 46, + 48, + 49, + 50, + 55, + 56, + 63, + 69, + 70, + 72 + ] + } + ] +} diff --git a/v0/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json b/v0/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json new file mode 100644 index 00000000..3b684246 --- /dev/null +++ b/v0/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json @@ -0,0 +1,3109 @@ +{ + "name": "Ripple-carry-adder", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "4XoG4GWmQZ9NS4om0iHI", + "focussedCircuit": 93663071628, + "orderedTabs": [ + "93663071628", + "71620967501", + "51553545569" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "1", + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "1", + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 200, + "y": 90, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 13, + 27 + ] + }, + { + "x": 200, + "y": 130, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 14, + 28 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 300, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 200, + "y": 100, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 3, + 10 + ] + }, + { + "x": 200, + "y": 120, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 4, + 11 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 300, + "y": 130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 6, + 16 + ] + }, + { + "x": 310, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 12, + 15, + 20 + ] + }, + { + "x": 310, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 19 + ] + }, + { + "x": 260, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 6, + 22 + ] + }, + { + "x": 260, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 26 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 160, + "y": 200, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 23, + 27 + ] + }, + { + "x": 160, + "y": 90, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 0, + 3, + 26 + ] + }, + { + "x": 150, + "y": 130, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 1, + 4, + 29 + ] + }, + { + "x": 150, + "y": 220, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 24, + 28 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 370, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 34 + ] + }, + { + "x": 370, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + } + ], + "id": 71620967501, + "name": "1 Bit Full adder", + "Input": [ + { + "x": 120, + "y": 90, + "objectType": "Input", + "label": "A", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + "1", + { + "x": 0, + "y": 20, + "id": "E2sClOSN6pWrS98RgOYs" + } + ] + } + }, + { + "x": 120, + "y": 130, + "objectType": "Input", + "label": "B", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 1 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + "1", + { + "x": 0, + "y": 40, + "id": "HTbtSbs9eS4J1TQuPXGO" + } + ] + } + }, + { + "x": 120, + "y": 170, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 2 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "VEynnegCN4NTDTf8CiFi" + } + ] + } + } + ], + "Output": [ + { + "x": 470, + "y": 120, + "objectType": "Output", + "label": "Sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 5 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "iaTzfFCd96wCDEqETEJQ" + } + ] + } + }, + { + "x": 470, + "y": 200, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 35 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "dW2kDiC82HpklbBdEwV7" + } + ] + } + } + ], + "OrGate": [ + { + "x": 420, + "y": 200, + "objectType": "OrGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 30, + 31 + ], + "output1": 32 + } + } + } + ], + "AndGate": [ + { + "x": 340, + "y": 180, + "objectType": "AndGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 7, + 8 + ], + "output1": 9 + } + } + }, + { + "x": 180, + "y": 210, + "objectType": "AndGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 23, + 24 + ], + "output1": 25 + } + } + } + ], + "XorGate": [ + { + "x": 260, + "y": 110, + "objectType": "XorGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 10, + 11 + ], + "output1": 12 + } + } + }, + { + "x": 350, + "y": 120, + "objectType": "XorGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 15, + 16 + ], + "output1": 17 + } + } + } + ], + "nodes": [ + 3, + 4, + 6, + 13, + 14, + 18, + 19, + 20, + 21, + 22, + 26, + 27, + 28, + 29, + 33, + 34 + ] + }, + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 1 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 7 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 620, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 61 + ] + }, + { + "x": 620, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 12, + 64 + ] + }, + { + "x": 830, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 66 + ] + }, + { + "x": 830, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 69 + ] + }, + { + "x": 260, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 52 + ] + }, + { + "x": 280, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 18 + ] + }, + { + "x": 440, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 73 + ] + }, + { + "x": 300, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 20 + ] + }, + { + "x": 630, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 21 + ] + }, + { + "x": 630, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 62 + ] + }, + { + "x": 320, + "y": 220, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 23 + ] + }, + { + "x": 840, + "y": 220, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 24 + ] + }, + { + "x": 840, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 67 + ] + }, + { + "x": 650, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 33 + ] + }, + { + "x": 650, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 25, + 63 + ] + }, + { + "x": 430, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 28 + ] + }, + { + "x": 270, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 29 + ] + }, + { + "x": 270, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 28, + 53 + ] + }, + { + "x": 450, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 31 + ] + }, + { + "x": 460, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 32 + ] + }, + { + "x": 460, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 57 + ] + }, + { + "x": 470, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 10, + 25 + ] + }, + { + "x": 490, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 35 + ] + }, + { + "x": 850, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 36 + ] + }, + { + "x": 850, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 68 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 46 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 600, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 45, + 60 + ] + }, + { + "x": 600, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 46 + ] + }, + { + "x": 470, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 45 + ] + }, + { + "x": 490, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 48 + ] + }, + { + "x": 790, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 76 + ] + }, + { + "x": 1000, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 50, + 77 + ] + }, + { + "x": 510, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 49 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 79 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 74 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 73 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 77 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 450, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 40, + 55 + ] + }, + { + "x": 440, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 58 + ] + }, + { + "x": 430, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 75 + ] + }, + { + "x": 430, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 59, + 74 + ] + }, + { + "x": 790, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 48, + 65 + ] + }, + { + "x": 1000, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 49, + 70 + ] + }, + { + "x": 1020, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 71, + 79 + ] + }, + { + "x": 1020, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 51, + 78 + ] + } + ], + "id": 51553545569, + "name": "4 bit Full adder", + "Input": [ + { + "x": 330, + "y": 90, + "objectType": "Input", + "label": "A", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + "4", + { + "x": 0, + "y": 20, + "id": "2bB0Ry57AnIPDOzWSzda" + } + ] + } + }, + { + "x": 500, + "y": 90, + "objectType": "Input", + "label": "B", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 8 + }, + "constructorParamaters": [ + "DOWN", + "4", + { + "x": 0, + "y": 40, + "id": "Iw9xWH2HyRpquRWUnMOe" + } + ] + } + }, + { + "x": 240, + "y": 320, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 37 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "A9dm3htBUx0UtdfjbjKF" + } + ] + } + } + ], + "Output": [ + { + "x": 520, + "y": 500, + "objectType": "Output", + "label": "Sum", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 38 + }, + "constructorParamaters": [ + "UP", + "4", + { + "x": 100, + "y": 30, + "id": "Yawujtkc6mntSdTwrzFi" + } + ] + } + }, + { + "x": 1050, + "y": 310, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 51 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 50, + "id": "NkU1KLcqXFqu75u3vyJJ" + } + ] + } + } + ], + "Splitter": [ + { + "x": 300, + "y": 130, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 2, + 3, + 4, + 5 + ], + "inp1": 1 + } + } + }, + { + "x": 470, + "y": 130, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 8, + 9, + 10, + 11 + ], + "inp1": 7 + } + } + }, + { + "x": 490, + "y": 450, + "objectType": "Splitter", + "label": "", + "direction": "UP", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "UP", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 40, + 41, + 42, + 43 + ], + "inp1": 39 + } + } + } + ], + "SubCircuit": [ + { + "x": 310, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 52, + 53, + 54 + ], + "outputNodes": [ + 55, + 56 + ], + "version": "2.0" + }, + { + "x": 480, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 57, + 58, + 59 + ], + "outputNodes": [ + 60, + 61 + ], + "version": "2.0" + }, + { + "x": 670, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 62, + 63, + 64 + ], + "outputNodes": [ + 65, + 66 + ], + "version": "2.0" + }, + { + "x": 870, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 67, + 68, + 69 + ], + "outputNodes": [ + 70, + 71 + ], + "version": "2.0" + } + ], + "nodes": [ + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79 + ] + }, + { + "layout": { + "width": 100, + "height": 110, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 66 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 16, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 16, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 16, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 16, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 69 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 56 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 71 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 720, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 0, + 8 + ] + }, + { + "x": 740, + "y": 370, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 9, + 34 + ] + }, + { + "x": 890, + "y": 370, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 33, + 35 + ] + }, + { + "x": 890, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 17, + 34 + ] + }, + { + "x": 760, + "y": 360, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 10, + 37 + ] + }, + { + "x": 1040, + "y": 360, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 36, + 38 + ] + }, + { + "x": 1040, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 22, + 37 + ] + }, + { + "x": 780, + "y": 340, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 11, + 40 + ] + }, + { + "x": 1180, + "y": 340, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 39, + 41 + ] + }, + { + "x": 1180, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 27, + 40 + ] + }, + { + "x": 1090, + "y": 320, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 13, + 43 + ] + }, + { + "x": 690, + "y": 320, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 42, + 44 + ] + }, + { + "x": 690, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 1, + 43 + ] + }, + { + "x": 900, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 18, + 46 + ] + }, + { + "x": 900, + "y": 300, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 45, + 47 + ] + }, + { + "x": 1110, + "y": 300, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 14, + 46 + ] + }, + { + "x": 1130, + "y": 330, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 15, + 49 + ] + }, + { + "x": 1060, + "y": 330, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 48, + 50 + ] + }, + { + "x": 1060, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 23, + 49 + ] + }, + { + "x": 1210, + "y": 290, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 16, + 52 + ] + }, + { + "x": 1210, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 28, + 51 + ] + }, + { + "x": 890, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 54 + ] + }, + { + "x": 890, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 53 + ] + }, + { + "x": 1050, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 56 + ] + }, + { + "x": 1050, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 24, + 55 + ] + }, + { + "x": 1200, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 58 + ] + }, + { + "x": 1200, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 57 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "16", + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 67 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 74 + ] + }, + { + "x": 900, + "y": 530, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 60, + 65 + ] + }, + { + "x": 870, + "y": 530, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 64, + 66 + ] + }, + { + "x": 870, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 3, + 65 + ] + }, + { + "x": 920, + "y": 520, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 61, + 68 + ] + }, + { + "x": 1030, + "y": 520, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 67, + 69 + ] + }, + { + "x": 1030, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 20, + 68 + ] + }, + { + "x": 940, + "y": 560, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 62, + 80 + ] + }, + { + "x": 1180, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 25, + 81 + ] + }, + { + "x": 1350, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 30, + 73 + ] + }, + { + "x": 1350, + "y": 600, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 72, + 74 + ] + }, + { + "x": 960, + "y": 600, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 63, + 73 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": "16", + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 1020, + "y": 660, + "type": 2, + "bitWidth": "16", + "label": "", + "connections": [ + 59, + 77 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 81 + ] + }, + { + "x": 1180, + "y": 560, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 70, + 81 + ] + }, + { + "x": 1180, + "y": 540, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 71, + 79, + 80 + ] + } + ], + "id": 93663071628, + "name": "Main", + "Input": [ + { + "x": 790, + "y": 230, + "objectType": "Input", + "label": "A", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 14332 + }, + "constructorParamaters": [ + "DOWN", + 16, + { + "x": 0, + "y": 60, + "id": "RSEDtPWAqfBaZZokKbtT" + } + ] + } + }, + { + "x": 1160, + "y": 230, + "objectType": "Input", + "label": "B", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 24572 + }, + "constructorParamaters": [ + "DOWN", + 16, + { + "x": 0, + "y": 20, + "id": "Txd27FkQfb3c95FRrcnk" + } + ] + } + }, + { + "x": 700, + "y": 450, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 76 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "DemZmzyVBGIMNFmj70kj" + } + ] + } + } + ], + "Output": [ + { + "x": 1380, + "y": 440, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 75 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 90, + "id": "tLrcFmdJBCxYVIMskoQb" + } + ] + } + }, + { + "x": 1020, + "y": 740, + "objectType": "Output", + "label": "Sum", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 77 + }, + "constructorParamaters": [ + "UP", + 16, + { + "x": 100, + "y": 20, + "id": "o31VsUe37gDTsycMMgVW" + } + ] + } + }, + { + "x": 1250, + "y": 540, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 79 + }, + "constructorParamaters": [ + "LEFT", + "4", + { + "x": 100, + "y": 40, + "id": "XOjb1SYysdaUdivdnR9O" + } + ] + } + } + ], + "Splitter": [ + { + "x": 760, + "y": 270, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 8, + 9, + 10, + 11 + ], + "inp1": 7 + } + } + }, + { + "x": 1130, + "y": 270, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 13, + 14, + 15, + 16 + ], + "inp1": 12 + } + } + }, + { + "x": 940, + "y": 650, + "objectType": "Splitter", + "label": "", + "direction": "UP", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "UP", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 60, + 61, + 62, + 63 + ], + "inp1": 59 + } + } + } + ], + "SubCircuit": [ + { + "x": 760, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 0, + 1, + 2 + ], + "outputNodes": [ + 3, + 4 + ], + "version": "2.0" + }, + { + "x": 920, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 17, + 18, + 19 + ], + "outputNodes": [ + 20, + 21 + ], + "version": "2.0" + }, + { + "x": 1070, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 22, + 23, + 24 + ], + "outputNodes": [ + 25, + 26 + ], + "version": "2.0" + }, + { + "x": 1230, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 27, + 28, + 29 + ], + "outputNodes": [ + 30, + 31 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 78, + 80, + 81 + ] + } + ] +} diff --git a/v0/src/simulator/spec/circuits/sequential-circuitdata.json b/v0/src/simulator/spec/circuits/sequential-circuitdata.json new file mode 100644 index 00000000..b97d60ce --- /dev/null +++ b/v0/src/simulator/spec/circuits/sequential-circuitdata.json @@ -0,0 +1,1184 @@ +{ + "name": "sample", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "yDvzoCP6Qa2VDwWDoj5Q", + "focussedCircuit": 81140742990, + "orderedTabs": [ + "81140742990" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 220, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 3 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 19 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "D", + "connections": [ + 17 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 12 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 790, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 34 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 20 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "D", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 21 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 22 + ] + }, + { + "x": 600, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 9, + 18 + ] + }, + { + "x": 600, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 17, + 32 + ] + }, + { + "x": 480, + "y": 330, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 10, + 20 + ] + }, + { + "x": 480, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 19, + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 33 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "T", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 30 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 600, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 24, + 49 + ] + }, + { + "x": 480, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 23, + 50 + ] + }, + { + "x": 400, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 12, + 35 + ] + }, + { + "x": 400, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 36, + 47 + ] + }, + { + "x": 800, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 35 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "J", + "connections": [ + 49 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "K", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 50 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 45 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 48 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 400, + "y": 890, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 48, + 64 + ] + }, + { + "x": 790, + "y": 890, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 47 + ] + }, + { + "x": 600, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 32, + 37, + 61 + ] + }, + { + "x": 480, + "y": 840, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 39 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "R", + "connections": [ + 63 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "S", + "connections": [ + 61 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 59 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 60 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 65 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 600, + "y": 990, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 49, + 53 + ] + }, + { + "x": 570, + "y": 830, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 51, + 63 + ] + }, + { + "x": 570, + "y": 1010, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 52, + 62 + ] + }, + { + "x": 400, + "y": 1060, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 65 + ] + }, + { + "x": 790, + "y": 1060, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 64 + ] + } + ], + "id": 81140742990, + "name": "Main", + "Input": [ + { + "x": 270, + "y": 310, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 9 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "ADKJudOKQoIs54SteC0v" + } + ] + } + }, + { + "x": 270, + "y": 390, + "objectType": "Input", + "label": "RST", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "auACgXFHbJMmKSylcRIS" + } + ] + } + }, + { + "x": 540, + "y": 830, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 51 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "gxYJoZ7q7csS6z5HFjAu" + } + ] + } + } + ], + "Output": [ + { + "x": 920, + "y": 310, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "p812Pea4ZmGV5PkGdpPe" + } + ] + } + }, + { + "x": 920, + "y": 330, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 8 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "bQnnZVmd5kDPIeO22TfP" + } + ] + } + }, + { + "x": 920, + "y": 450, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 21 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "7kEPCd8x0CsWmJDHGtz7" + } + ] + } + }, + { + "x": 920, + "y": 470, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 22 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "umwIPzgaQxhyw3KXeoIe" + } + ] + } + }, + { + "x": 900, + "y": 620, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 30 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 100, + "id": "ACFEeZBErU96lY78ng2n" + } + ] + } + }, + { + "x": 900, + "y": 640, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 31 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "3TD9jZdXa1AX43jOeh4V" + } + ] + } + }, + { + "x": 900, + "y": 820, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "hCbf5heEes1MWbjfBxag" + } + ] + } + }, + { + "x": 900, + "y": 840, + "objectType": "Output", + "label": "out8", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 46 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "U33L7gSGF200Koy8RUpn" + } + ] + } + }, + { + "x": 900, + "y": 990, + "objectType": "Output", + "label": "out9", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "4rIpXftfQyQsEnQT7uXl" + } + ] + } + }, + { + "x": 900, + "y": 1010, + "objectType": "Output", + "label": "out10", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 60 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "CYefIzHlGgRM7OF8Ctdw" + } + ] + } + } + ], + "TflipFlop": [ + { + "x": 790, + "y": 630, + "objectType": "TflipFlop", + "label": "T Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 23, + "dInp": 24, + "qOutput": 25, + "qInvOutput": 26, + "reset": 27, + "preset": 28, + "en": 29 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "JKflipFlop": [ + { + "x": 780, + "y": 830, + "objectType": "JKflipFlop", + "label": "Jk Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "J": 37, + "K": 38, + "clockInp": 39, + "qOutput": 40, + "qInvOutput": 41, + "reset": 42, + "preset": 43, + "en": 44 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "SRflipFlop": [ + { + "x": 780, + "y": 1000, + "objectType": "SRflipFlop", + "label": "SR Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "S": 53, + "R": 52, + "qOutput": 54, + "qInvOutput": 55, + "reset": 56, + "preset": 57, + "en": 58 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "DflipFlop": [ + { + "x": 780, + "y": 320, + "objectType": "DflipFlop", + "label": "D Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 1, + "dInp": 2, + "qOutput": 3, + "qInvOutput": 4, + "reset": 5, + "preset": 6, + "en": 7 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "Clock": [ + { + "x": 270, + "y": 330, + "objectType": "Clock", + "label": "CLOCK", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 10 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "Dlatch": [ + { + "x": 790, + "y": 460, + "objectType": "Dlatch", + "label": "D latch", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 13, + "dInp": 14, + "qOutput": 15, + "qInvOutput": 16 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 12, + 17, + 18, + 19, + 20, + 32, + 33, + 34, + 35, + 36, + 47, + 48, + 49, + 50, + 61, + 62, + 63, + 64, + 65 + ] + } + ] +} diff --git a/v0/src/simulator/spec/circuits/subCircuit-circuitdata.json b/v0/src/simulator/spec/circuits/subCircuit-circuitdata.json new file mode 100644 index 00000000..e1703e76 --- /dev/null +++ b/v0/src/simulator/spec/circuits/subCircuit-circuitdata.json @@ -0,0 +1,814 @@ +{ + "name": "SubCircuit", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "KXmhGDZlwFlzVjPmxY8g", + "focussedCircuit": 69980799589, + "orderedTabs": [ + "69980799589", + "98622262167" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 60, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 9 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 660, + "y": 250, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 7, + 11 + ] + }, + { + "x": 660, + "y": 370, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 6 + ] + }, + { + "x": 620, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 9, + 10 + ] + }, + { + "x": 620, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + } + ], + "id": 98622262167, + "name": "Half-adder", + "Input": [ + { + "x": 580, + "y": 230, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 10 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "yDbVL6dY6nnuOp5jcZ95" + } + ] + } + }, + { + "x": 580, + "y": 250, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "xQoyxdS12E5xJ9dmz35B" + } + ] + } + } + ], + "Output": [ + { + "x": 990, + "y": 240, + "objectType": "Output", + "label": "sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 12 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "dzWcRuJoJdE8Bg2MY1KI" + } + ] + } + }, + { + "x": 1010, + "y": 380, + "objectType": "Output", + "label": "carry", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 13 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "MxBKygipJq4eP2ofPb14" + } + ] + } + } + ], + "AndGate": [ + { + "x": 740, + "y": 380, + "objectType": "AndGate", + "label": "AND", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 3, + 4 + ], + "output1": 5 + } + } + } + ], + "XorGate": [ + { + "x": 750, + "y": 240, + "objectType": "XorGate", + "label": "Xor", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2 + } + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 6, + 7, + 8, + 9 + ] + }, + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": -270, + "y": 0, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 12 + ] + }, + { + "x": -310, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 11 + ] + }, + { + "x": -240, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 19 + ] + }, + { + "x": 40, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 20 + ] + }, + { + "x": 40, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 19 + ] + }, + { + "x": -20, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 22 + ] + }, + { + "x": -20, + "y": 70, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 23 + ] + }, + { + "x": 270, + "y": 70, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 24 + ] + }, + { + "x": 270, + "y": 40, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 23 + ] + } + ], + "id": 69980799589, + "name": "Main", + "Input": [ + { + "x": -320, + "y": -140, + "objectType": "Input", + "label": "x", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "TzPoFqkKRnczSlQMidjq" + } + ] + } + }, + { + "x": -280, + "y": -140, + "objectType": "Input", + "label": "y", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 12 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "XBpwBuRDlldQywdEHsgz" + } + ] + } + }, + { + "x": -250, + "y": -140, + "objectType": "Input", + "label": "cin", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 13 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "HQYLk2tHMKI6uYYikApo" + } + ] + } + } + ], + "Output": [ + { + "x": 420, + "y": 0, + "objectType": "Output", + "label": "sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 14 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "GOiOE9VzXMlMW1txqFEb" + } + ] + } + }, + { + "x": 420, + "y": 30, + "objectType": "Output", + "label": "carry", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 15 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "ASuCOL13vtFBub8uPD7N" + } + ] + } + } + ], + "OrGate": [ + { + "x": 320, + "y": 30, + "objectType": "OrGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 8, + 9 + ], + "output1": 10 + } + } + } + ], + "SubCircuit": [ + { + "x": -180, + "y": -20, + "id": "98622262167", + "label": "half-adder", + "labelDirection": "UP", + "inputNodes": [ + 2, + 3 + ], + "outputNodes": [ + 0, + 1 + ], + "version": "2.0" + }, + { + "x": 110, + "y": -20, + "id": "98622262167", + "label": "half-adder", + "labelDirection": "UP", + "inputNodes": [ + 6, + 7 + ], + "outputNodes": [ + 4, + 5 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24 + ] + } + ] +} diff --git a/v0/src/simulator/spec/combinationalAnalysis.spec.js b/v0/src/simulator/spec/combinationalAnalysis.spec.js new file mode 100644 index 00000000..646187cd --- /dev/null +++ b/v0/src/simulator/spec/combinationalAnalysis.spec.js @@ -0,0 +1,92 @@ +import { setup } from '../src/setup'; +import { runAll } from '../src/testbench'; +import testData from './testData/gates-testdata.json'; +import { GenerateCircuit, performCombinationalAnalysis } from '../src/combinationalAnalysis'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Combinational Analysis Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('performCombinationalAnalysis function working', () => { + expect(() => performCombinationalAnalysis('', '', 'AB')).not.toThrow(); + }); + + test('Generating Circuit', () => { + expect(() => GenerateCircuit([13], ['A', 'B'], [0, 0, 0, 1], 'AB')).not.toThrow(); + }); + + test('testing Combinational circuit', () => { + testData.AndGate.groups[0].inputs[0].label = 'A'; + testData.AndGate.groups[0].inputs[1].label = 'B'; + testData.AndGate.groups[0].outputs[0].label = 'AB'; + + const result = runAll(testData.AndGate); + expect(result.summary.passed).toBe(3); + }); +}); diff --git a/v0/src/simulator/spec/complexCircuit.spec.js b/v0/src/simulator/spec/complexCircuit.spec.js new file mode 100644 index 00000000..32b33083 --- /dev/null +++ b/v0/src/simulator/spec/complexCircuit.spec.js @@ -0,0 +1,96 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import { runAll } from '../src/testbench'; +import aluCircuitData from './circuits/alu-circuitdata.json'; +import rippleCircuitData from './circuits/rippleCarryAdder-circuitdata.json'; +import rippleTestData from './testData/ripple-carry-adder.json'; +import aluTestData from './testData/alu-testdata.json'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('data dir working', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load ripple carry adder circuit-data', () => { + expect(() => load(rippleCircuitData)).not.toThrow(); + }); + + test('ripple carry adder circuit testing', () => { + const result = runAll(rippleTestData.testData); + expect(result.summary.passed).toBe(10); + }); + + test('load ALU circuit-data', () => { + expect(() => load(aluCircuitData)).not.toThrow(); + }); + + test('ALU circuit testing', () => { + const result = runAll(aluTestData.testData); + expect(result.summary.passed).toBe(5); + }); +}); diff --git a/v0/src/simulator/spec/data.spec.js b/v0/src/simulator/spec/data.spec.js index f91a08c8..f1626d66 100644 --- a/v0/src/simulator/spec/data.spec.js +++ b/v0/src/simulator/spec/data.spec.js @@ -1,121 +1,170 @@ -/** - * @jest-environment jsdom - */ - -import CodeMirror from 'codemirror' -import { setup } from '../src/setup' -import load from '../src/data/load' -import gatesCircuitData from './circuits/gates-circuitdata.json' -import decoderCircuitData from './circuits/Decoders-plexers-circuitdata.json' -import { checkIfBackup, scheduleBackup } from '../src/data/backupCircuit' -import undo from '../src/data/undo' -import redo from '../src/data/redo' -import save from '../src/data/save' +import { describe, test, expect, vi, beforeAll } from 'vitest'; +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import gatesCircuitData from './circuits/gates-circuitdata.json'; +import decoderCircuitData from './circuits/Decoders-plexers-circuitdata.json'; +import { checkIfBackup, scheduleBackup } from '../src/data/backupCircuit'; +import undo from '../src/data/undo'; +import redo from '../src/data/redo'; +import save from '../src/data/save'; import { clearProject, newProject, recoverProject, saveOffline, openOffline, -} from '../src/data/project' -import createSaveAsImgPrompt from '../src/data/saveImage' - -jest.mock('codemirror') +} from '../src/data/project'; +import createSaveAsImgPrompt from '../src/data/saveImage'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import simulator from '#/pages/simulatorHandler.vue'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import vuetify from '#/plugins/vuetify'; +import { routes } from '#/router'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => {} })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); describe('data dir working', () => { - CodeMirror.fromTextArea.mockReturnValueOnce({ setValue: () => {} }) - window.confirm = jest.fn(() => true) - setup() + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); test('load gates_circuitData without throwing error', () => { - expect(() => load(gatesCircuitData)).not.toThrow() - }) + expect(() => load(gatesCircuitData)).not.toThrow(); + }); test('should load another circuit data decoder_circuitData', () => { - expect(() => load(decoderCircuitData)).not.toThrow() - }) + expect(() => load(decoderCircuitData)).not.toThrow(); + }); test('schedule backup working', () => { - // toggle states of inputs a dn then run schedule backup globalScope.Input.forEach((input) => { - input.state = input.state === 1 ? 0 : 1 - expect(() => scheduleBackup()).not.toThrow() - }) - }) + input.state = input.state === 1 ? 0 : 1; + expect(() => scheduleBackup()).not.toThrow(); + }); + }); test('check if backup performed', () => { - expect(() => checkIfBackup(globalScope)).toBeTruthy() - }) + expect(checkIfBackup(globalScope)).toBeTruthy(); + }); test('undo working', () => { const beforeUndo = { backups: globalScope.backups.length, history: globalScope.history.length, - } + }; for (let i = 1; i < beforeUndo.backups; i++) { - undo() + undo(); const afterUndo = { backups: globalScope.backups.length + i, history: globalScope.history.length - i, - } - expect(afterUndo).toEqual(beforeUndo) + }; + expect(afterUndo).toEqual(beforeUndo); } - }) + }); test('redo working', () => { const beforeRedo = { backups: globalScope.backups.length, history: globalScope.history.length, - } + }; for (let i = 1; i < beforeRedo.history; i++) { - redo() + redo(); const afterRedo = { backups: globalScope.backups.length - i, history: globalScope.history.length + i, - } - expect(afterRedo).toEqual(beforeRedo) + }; + expect(afterRedo).toEqual(beforeRedo); } - }) + }); test('save updated circuit_data', () => { - // save project - window.logixProjectId = decoderCircuitData.projectId - expect(() => save()).not.toThrow() - }) + window.logixProjectId = decoderCircuitData.projectId; + expect(() => save()).not.toThrow(); + }); test('project working', () => { - // create new project - expect(() => newProject(true)).not.toThrow() - }) + expect(() => newProject(true)).not.toThrow(); + }); test('clear Project working', () => { - // clear project - expect(() => clearProject()).not.toThrow() - }) + expect(() => clearProject()).not.toThrow(); + }); test('recover Project working', () => { - // recover project from localstorage - localStorage.setItem('recover', JSON.stringify(gatesCircuitData)) - expect(() => recoverProject()).not.toThrow() - }) + localStorage.setItem('recover', JSON.stringify(gatesCircuitData)); + expect(() => recoverProject()).not.toThrow(); + }); test('SaveOffline working', () => { - // save offline gate project - expect(() => saveOffline()).not.toThrow() - }) + expect(() => saveOffline()).not.toThrow(); + }); test('OpenOffline working', () => { - // open dialog - openOffline() - // click on first input - $('#openProjectDialog input')[0].click() - // click on open button - $('#Open_offline_btn')[0].click() - // it should load the offline saved project - expect(globalScope.id).toBe(11597572508) - }) + openOffline(); + document.querySelector('#openProjectDialog input')?.click(); + document.querySelector('#Open_offline_btn')?.click(); + expect(globalScope.id).toBe(11597572508); + }); test('saveImage working', () => { - expect(() => createSaveAsImgPrompt()).not.toThrow() - }) -}) + expect(() => createSaveAsImgPrompt()).not.toThrow(); + }); +}); diff --git a/v0/src/simulator/spec/decoders-plexers.spec.js b/v0/src/simulator/spec/decoders-plexers.spec.js new file mode 100644 index 00000000..2c4151b1 --- /dev/null +++ b/v0/src/simulator/spec/decoders-plexers.spec.js @@ -0,0 +1,115 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/Decoders-plexers-circuitdata.json'; +import testData from './testData/decoders-plexers.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Decoders and Plexers Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load decoders-plexers circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('Multiplexer working', () => { + const result = runAll(testData.Multiplexers); + expect(result.summary.passed).toBe(8); + }); + + test('Demultiplexer working', () => { + const result = runAll(testData.Demultiplexer); + expect(result.summary.passed).toBe(4); + }); + + test('BitSelector working', () => { + const result = runAll(testData['bit-selector']); + expect(result.summary.passed).toBe(4); + }); + + test('MSB working', () => { + const result = runAll(testData.msb); + expect(result.summary.passed).toBe(5); + }); + + test('LSB working', () => { + const result = runAll(testData.lsb); + expect(result.summary.passed).toBe(10); + }); + + test('Priority Encoder working', () => { + const result = runAll(testData['priority-encoder']); + expect(result.summary.passed).toBe(4); + }); + + test('Decoder working', () => { + const result = runAll(testData.Decoder); + expect(result.summary.passed).toBe(2); + }); +}); diff --git a/v0/src/simulator/spec/gates.spec.js b/v0/src/simulator/spec/gates.spec.js index 90c7b1bd..1af5a4a7 100644 --- a/v0/src/simulator/spec/gates.spec.js +++ b/v0/src/simulator/spec/gates.spec.js @@ -1,57 +1,115 @@ -/** - * @jest-environment jsdom - */ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/gates-circuitdata.json'; +import testData from './testData/gates-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; -import CodeMirror from 'codemirror' -import { setup } from '../src/setup' +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); -import load from '../src/data/load' -import circuitData from './circuits/gates-circuitdata.json' -import testData from './testData/gates-testdata.json' -import { runAll } from '../src/testbench' +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); -jest.mock('codemirror') +describe('Simulator Gates Working', () => { + let pinia; + let router; -describe('Simulator Gates Testing', () => { - CodeMirror.fromTextArea.mockReturnValueOnce({ setValue: (text) => {} }) - setup() + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); test('load circuitData', () => { - expect(() => load(circuitData)).not.toThrow() - }) - - test('AND gate testing', () => { - const result = runAll(testData.AndGate) - expect(result.summary.passed).toBe(4) - }) - - test('NAND gate testing', () => { - const result = runAll(testData.nandGate) - expect(result.summary.passed).toBe(4) - }) - - test('NOR gate testing', () => { - const result = runAll(testData.norGate) - expect(result.summary.passed).toBe(4) - }) - - test('NOT gate testing', () => { - const result = runAll(testData.notGate) - expect(result.summary.passed).toBe(2) - }) - - test('OR gate testing', () => { - const result = runAll(testData.OrGate) - expect(result.summary.passed).toBe(4) - }) - - test('XNOR gate testing', () => { - const result = runAll(testData.xnorGate) - expect(result.summary.passed).toBe(4) - }) - - test('XOR gate testing', () => { - const result = runAll(testData.xorGate) - expect(result.summary.passed).toBe(4) - }) -}) + expect(() => load(circuitData)).not.toThrow(); + }); + + test('AND gate working', () => { + const result = runAll(testData.AndGate); + expect(result.summary.passed).toBe(4); + }); + + test('NAND gate working', () => { + const result = runAll(testData.nandGate); + expect(result.summary.passed).toBe(4); + }); + + test('NOR gate working', () => { + const result = runAll(testData.norGate); + expect(result.summary.passed).toBe(4); + }); + + test('NOT gate working', () => { + const result = runAll(testData.notGate); + expect(result.summary.passed).toBe(2); + }); + + test('OR gate working', () => { + const result = runAll(testData.OrGate); + expect(result.summary.passed).toBe(4); + }); + + test('XNOR gate working', () => { + const result = runAll(testData.xnorGate); + expect(result.summary.passed).toBe(4); + }); + + test('XOR gate working', () => { + const result = runAll(testData.xorGate); + expect(result.summary.passed).toBe(4); + }); +}); diff --git a/v0/src/simulator/spec/misc.spec.js b/v0/src/simulator/spec/misc.spec.js new file mode 100644 index 00000000..57a217e2 --- /dev/null +++ b/v0/src/simulator/spec/misc.spec.js @@ -0,0 +1,130 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/misc-circuitdata.json'; +import testData from './testData/misc-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Misc-Elements Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('ALU working', () => { + const result = runAll(testData.ALU); + expect(result.summary.passed).toBe(28); + }); + + test('Adder working', () => { + const result = runAll(testData.Adder); + expect(result.summary.passed).toBe(8); + }); + + test('Buffer working', () => { + const result = runAll(testData.buffer); + expect(result.summary.passed).toBe(2); + }); + + test('TriState Buffer working', () => { + const result = runAll(testData.Tristate); + expect(result.summary.passed).toBe(4); + }); + + test('Tunnel working', () => { + const result = runAll(testData.Tunnel); + expect(result.summary.passed).toBe(2); + }); + + test("2's Compliment working", () => { + const result = runAll(testData.comp); + expect(result.summary.passed).toBe(8); + }); + + test('Controlled Inverter working', () => { + const result = runAll(testData.ControlledInverter); + expect(result.summary.passed).toBe(3); + }); + + test('Equal Splitter working', () => { + const result = runAll(testData.SplitterEqual); + expect(result.summary.passed).toBe(8); + }); + + test('UnEqual Splitter working', () => { + const result = runAll(testData.SplitterUnEqual); + expect(result.summary.passed).toBe(8); + }); + + test('Force Gate working', () => { + const result = runAll(testData.ForceGate); + expect(result.summary.passed).toBe(2); + }); +}); diff --git a/v0/src/simulator/spec/sequential.spec.js b/v0/src/simulator/spec/sequential.spec.js new file mode 100644 index 00000000..74cdb75f --- /dev/null +++ b/v0/src/simulator/spec/sequential.spec.js @@ -0,0 +1,105 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/sequential-circuitdata.json'; +import testData from './testData/sequential-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Sequential Element Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('D Flip Flop working', () => { + const result = runAll(testData.DFlipFlop); + expect(result.summary.passed).toBe(2); + }); + + test('D latch working', () => { + const result = runAll(testData.DLatch); + expect(result.summary.passed).toBe(2); + }); + + test('JK Flip Flop working', () => { + const result = runAll(testData.JkFlipFlop); + expect(result.summary.passed).toBe(4); + }); + + test('SR Flip Flop working', () => { + const result = runAll(testData.SRFlipFlop); + expect(result.summary.passed).toBe(4); + }); + + test('T Flip Flop working', () => { + const result = runAll(testData.TFlipFlop); + expect(result.summary.passed).toBe(4); + }); +}); diff --git a/v0/src/simulator/spec/subCircuit.spec.js b/v0/src/simulator/spec/subCircuit.spec.js new file mode 100644 index 00000000..f8bae60b --- /dev/null +++ b/v0/src/simulator/spec/subCircuit.spec.js @@ -0,0 +1,85 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/subCircuit-circuitdata.json'; +import { runAll } from '../src/testbench'; +import testData from './testData/subCircuit-testdata.json'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('SubCircuit Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load subCircuit data without throwing error', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('subCircuit working', () => { + const result = runAll(testData.subCircuit); + expect(result.summary.passed).toBe(8); + }); +}); diff --git a/v0/src/simulator/spec/testData/alu-testdata.json b/v0/src/simulator/spec/testData/alu-testdata.json new file mode 100644 index 00000000..ada54b17 --- /dev/null +++ b/v0/src/simulator/spec/testData/alu-testdata.json @@ -0,0 +1,108 @@ +{ + "testData": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "S", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0010", + "1111", + "0100" + ] + }, + { + "label": "~A", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "1100", + "1100", + "1111" + ] + }, + { + "label": "~B", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "1100", + "1100", + "1100" + ] + }, + { + "label": "Mode", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1" + ] + }, + { + "label": "~Cn", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "~F", + "bitWidth": 4, + "values": [ + "0001", + "0000", + "1111", + "1011", + "0011" + ], + "results": [ + "0001", + "0000", + "1111", + "1011", + "0011" + ] + }, + { + "label": "A=B", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0", + "0" + ], + "results": [ + "0", + "0", + "1", + "0", + "0" + ] + } + ], + "n": 5 + } + ] + } +} + diff --git a/v0/src/simulator/spec/testData/decoders-plexers.json b/v0/src/simulator/spec/testData/decoders-plexers.json new file mode 100644 index 00000000..504919c3 --- /dev/null +++ b/v0/src/simulator/spec/testData/decoders-plexers.json @@ -0,0 +1,401 @@ +{ + "Multiplexers": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Multiplexers", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "Demultiplexer":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Demultiplexer", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "out2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "0" + ] + }, + { + "label": "out3", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "Decoder":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Decoder", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out11", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + }, + { + "label": "out12", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "priority-encoder":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "priority-encoder", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp4", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out9", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "out10", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "en", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "bit-selector": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "bit-selector", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0001", + "0010", + "0100", + "1000" + ] + }, + { + "label": "CS", + "bitWidth": 2, + "values": [ + "00", + "01", + "10", + "11" + ] + } + ], + "outputs": [ + { + "label": "out13", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "msb": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "msb", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0000", + "0001", + "0010", + "0100", + "1000" + ] + } + ], + "outputs": [ + { + "label": "out4", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0001", + "0010", + "0011" + ] + }, + { + "label": "out5", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "n": 5 + } + ] + }, + "lsb": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "lsb", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0000", + "0001", + "0011", + "0111", + "1111", + "1000", + "1100", + "1110", + "0100", + "0010" + ] + } + ], + "outputs": [ + { + "label": "out6", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0000", + "0000", + "0000", + "0011", + "0010", + "0001", + "0010", + "0001" + ] + }, + { + "label": "out7", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "1" + ] + } + ], + "n": 10 + } + ] + } + } diff --git a/v0/src/simulator/spec/testData/gates-testdata.json b/v0/src/simulator/spec/testData/gates-testdata.json index 3152253b..18cdf8fc 100644 --- a/v0/src/simulator/spec/testData/gates-testdata.json +++ b/v0/src/simulator/spec/testData/gates-testdata.json @@ -1,200 +1,296 @@ { - "AndGate": { - "type": "comb", - "title": "AND Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out1", - "bitWidth": 1, - "values": ["0", "0", "0", "1"] - } - ], - "n": 4 - } - ] - }, - "OrGate": { - "type": "comb", - "title": "OR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out2", - "bitWidth": 1, - "values": ["0", "1", "1", "1"] - } - ], - "n": 4 - } - ] - }, - "nandGate": { - "type": "comb", - "title": "NAND Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out3", - "bitWidth": 1, - "values": ["1", "1", "1", "0"] - } - ], - "n": 4 - } - ] - }, - "xorGate": { - "type": "comb", - "title": "XOR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out6", - "bitWidth": 1, - "values": ["0", "1", "1", "0"] - } - ], - "n": 4 - } - ] - }, - "norGate": { - "type": "comb", - "title": "NOR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out7", - "bitWidth": 1, - "values": ["1", "0", "0", "0"] - } - ], - "n": 4 - } - ] - }, - "notGate": { - "type": "comb", - "title": "NOT GAte", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "1"] - } - ], - "outputs": [ - { - "label": "out4", - "bitWidth": 1, - "values": ["1", "0"] - } - ], - "n": 2 - } - ] - }, - "xnorGate": { - "type": "comb", - "title": "XNOR GAte", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out5", - "bitWidth": 1, - "values": ["1", "0", "0", "1"] - } - ], - "n": 4 - } - ] - } + "AndGate": { + "type": "comb", + "title": "AND Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "OrGate": { + "type": "comb", + "title": "OR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "nandGate": { + "type": "comb", + "title": "NAND Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out3", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "xorGate": { + "type": "comb", + "title": "XOR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out6", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "norGate": { + "type": "comb", + "title": "NOR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out7", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "notGate": { + "type": "comb", + "title": "NOT GAte", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out4", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "xnorGate": { + "type": "comb", + "title": "XNOR GAte", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out5", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + } } diff --git a/v0/src/simulator/spec/testData/misc-testdata.json b/v0/src/simulator/spec/testData/misc-testdata.json new file mode 100644 index 00000000..df7e6509 --- /dev/null +++ b/v0/src/simulator/spec/testData/misc-testdata.json @@ -0,0 +1,959 @@ +{ + "ALU": { + "type": "comb", + "title": "ALU", + "groups": [ + { + "label": "000", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "000", + "000", + "000" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0" + ], + "results": [ + "0", + "0", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "001", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "001", + "001", + "001", + "001" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ], + "results": [ + "0", + "1", + "1", + "1" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "010", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "010", + "010", + "010", + "010" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ], + "results": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + }, + { + "label": "100", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "100", + "100", + "100", + "100" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0" + ], + "results": [ + "0", + "0", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "101", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "101", + "101", + "101", + "101" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1", + "1" + ], + "results": [ + "1", + "0", + "1", + "1" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "110", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "110", + "110", + "110", + "110" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "111", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "111", + "111", + "111", + "111" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "0" + ], + "results": [ + "0", + "1", + "0", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "Adder": { + "type": "comb", + "title": "Adder", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Adder-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "Adder-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "buffer": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "buffer-out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "Tristate": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "enable", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "T-state-out1", + "bitWidth": 1, + "values": [ + "X", + "X", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "Tunnel": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Tunnel-out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "comp": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "001", + "010", + "011", + "100", + "101", + "110", + "111" + ] + } + ], + "outputs": [ + { + "label": "2s-out1", + "bitWidth": 3, + "values": [ + "000", + "111", + "110", + "101", + "100", + "011", + "010", + "001" + ] + } + ], + "n": 8 + } + ] + }, + "ControlledInverter": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1" + ] + }, + { + "label": "enable", + "bitWidth": 1, + "values": [ + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "CI-out1", + "bitWidth": 1, + "values": [ + "X", + "1", + "0" + ] + } + ], + "n": 3 + } + ] + }, + "SplitterEqual": { + "type": "comb", + "title": "Splitter", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Adder-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ], + "results": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "Adder-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ], + "results": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "SplitterUnEqual": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "001", + "010", + "011", + "100", + "101", + "110", + "111" + ] + } + ], + "outputs": [ + { + "label": "s-un-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s-un-out2", + "bitWidth": 2, + "values": [ + "00", + "00", + "01", + "01", + "10", + "10", + "11", + "11" + ] + } + ], + "n": 8 + } + ] + }, + "ForceGate": { + "type": "comb", + "title": "Force Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Force-out", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 8 + } + ] + } +} diff --git a/v0/src/simulator/spec/testData/ripple-carry-adder.json b/v0/src/simulator/spec/testData/ripple-carry-adder.json new file mode 100644 index 00000000..1a76b9ce --- /dev/null +++ b/v0/src/simulator/spec/testData/ripple-carry-adder.json @@ -0,0 +1,92 @@ +{ + "testData": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "A", + "bitWidth": 16, + "values": [ + "0", + "1111111111111111", + "1111111111111111", + "1111111111111110", + "1111111111111110", + "1111111111111100", + "1111111111111100", + "0011111111111100", + "0011111111111100", + "0011011111111100" + ] + }, + { + "label": "B", + "bitWidth": 16, + "values": [ + "0", + "1111111111111111", + "1111111111111111", + "1111111111111110", + "1111111111111110", + "1111111111111100", + "1111111111111100", + "1101111111111100", + "1101111111111100", + "0101111111111100" + ] + }, + { + "label": "Cin", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "Sum", + "bitWidth": 16, + "values": [ + "0000000000000000", + "1111111111111110", + "1111111111111111", + "1111111111111100", + "1111111111111101", + "1111111111111000", + "1111111111111001", + "0001111111111000", + "0001111111111001", + "1001011111111001" + ], + "results": [ + "0000000000000000", + "1111111111111110", + "1111111111111111", + "1111111111111100", + "1111111111111101", + "1111111111111000", + "1111111111111001", + "0001111111111000", + "0001111111111001", + "1001011111111001" + ] + } + ], + "n": 10 + } + ] + } +} diff --git a/v0/src/simulator/spec/testData/sequential-testdata.json b/v0/src/simulator/spec/testData/sequential-testdata.json new file mode 100644 index 00000000..545ed223 --- /dev/null +++ b/v0/src/simulator/spec/testData/sequential-testdata.json @@ -0,0 +1,250 @@ +{ + "DFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ], + "results": [ + "0", + "1" + ] + }, + { + "label": "out2", + "bitWidth": 1, + "values": [ + "1", + "0" + ], + "results": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "DLatch": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out3", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + }, + { + "label": "out4", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "JkFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out7", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ], + "results": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "out8", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "SRFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out9", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "0" + ] + }, + { + "label": "out10", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "TFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1", + "0" + ] + } + ], + "outputs": [ + { + "label": "out5", + "bitWidth": 1, + "values": [ + "1", + "1", + "0", + "0" + ] + }, + { + "label": "out6", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + } +} diff --git a/v0/src/simulator/spec/testData/subCircuit-testdata.json b/v0/src/simulator/spec/testData/subCircuit-testdata.json new file mode 100644 index 00000000..2bd50617 --- /dev/null +++ b/v0/src/simulator/spec/testData/subCircuit-testdata.json @@ -0,0 +1,86 @@ +{ + "subCircuit": { + "type": "comb", + "title": "fullAdder", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "x", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "y", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "cin", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "sum", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "carry", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + } + } diff --git a/v0/src/simulator/spec/vitestSetup.ts b/v0/src/simulator/spec/vitestSetup.ts new file mode 100644 index 00000000..1f2780a0 --- /dev/null +++ b/v0/src/simulator/spec/vitestSetup.ts @@ -0,0 +1,11 @@ +global.window = window; +global.jQuery = require('jquery'); +global.DPR = true; +global.width = true; +global.height = true; + +window.Jquery = require('jquery'); +window.$ = require('jquery'); +window.restrictedElements = []; +window.userSignedIn = true; +window.embed = false; diff --git a/v0/src/simulator/src/Verilog2CV.js b/v0/src/simulator/src/Verilog2CV.js index 83e7641e..bc1a755d 100644 --- a/v0/src/simulator/src/Verilog2CV.js +++ b/v0/src/simulator/src/Verilog2CV.js @@ -4,7 +4,7 @@ import { changeCircuitName, } from './circuit' import SubCircuit from './subcircuit' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import CodeMirror from 'codemirror/lib/codemirror.js' import 'codemirror/lib/codemirror.css' @@ -31,6 +31,8 @@ import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/display/autorefresh.js' import { showError, showMessage } from './utils' import { showProperties } from './ux' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' var editor var verilogMode = false @@ -42,7 +44,17 @@ export async function createVerilogCircuit() { true, true ) - if (returned) verilogModeSet(true) + + if (returned) { + verilogModeSet(true) + + try { + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) + simulatorMobileStore.isVerilog.value = true + } catch (error) { + console.error('Failed to update simulatorMobileStore:', error) + } + } } export function saveVerilogCode() { @@ -72,11 +84,26 @@ export function verilogModeSet(mode) { if (mode == verilogMode) return verilogMode = mode if (mode) { + const code_window = document.getElementById('code-window') + if(code_window) document.getElementById('code-window').style.display = 'block' + + const elementPanel = document.querySelector('.elementPanel') + if(elementPanel) document.querySelector('.elementPanel').style.display = 'none' + + const timingDiagramPanel = document.querySelector('.timing-diagram-panel') + if(timingDiagramPanel) document.querySelector('.timing-diagram-panel').style.display = 'none' + + const quickBtn = document.querySelector('.quick-btn') + if(quickBtn) document.querySelector('.quick-btn').style.display = 'none' + + const verilogEditorPanel = document.getElementById('verilogEditorPanel') + if(verilogEditorPanel) document.getElementById('verilogEditorPanel').style.display = 'block' + if (!embed) { simulationArea.lastSelected = globalScope.root showProperties(undefined) @@ -84,10 +111,24 @@ export function verilogModeSet(mode) { } resetVerilogCode() } else { + const code_window = document.getElementById('code-window') + if(code_window) document.getElementById('code-window').style.display = 'none' + + const elementPanel = document.querySelector('.elementPanel') + if(elementPanel) document.querySelector('.elementPanel').style.display = '' + + const timingDiagramPanel = document.querySelector('.timing-diagram-panel') + if(timingDiagramPanel) document.querySelector('.timing-diagram-panel').style.display = '' + + const quickBtn = document.querySelector('.quick-btn') + if(quickBtn) document.querySelector('.quick-btn').style.display = '' + + const verilogEditorPanel = document.getElementById('verilogEditorPanel') + if(verilogEditorPanel) document.getElementById('verilogEditorPanel').style.display = 'none' } } diff --git a/v0/src/simulator/src/VerilogClasses.js b/v0/src/simulator/src/VerilogClasses.js index 253748af..3dfe92ca 100644 --- a/v0/src/simulator/src/VerilogClasses.js +++ b/v0/src/simulator/src/VerilogClasses.js @@ -3,67 +3,27 @@ import NandGate from './modules/NandGate' import Multiplexer from './modules/Multiplexer' import XorGate from './modules/XorGate' import XnorGate from './modules/XnorGate' -import SevenSegDisplay from './modules/SevenSegDisplay' -import SixteenSegDisplay from './modules/SixteenSegDisplay' -import HexDisplay from './modules/HexDisplay' import OrGate from './modules/OrGate' -import Stepper from './modules/Stepper' import NotGate from './modules/NotGate' -import Text from './modules/Text' -import TriState from './modules/TriState' import Buffer from './modules/Buffer' -import ControlledInverter from './modules/ControlledInverter' import Adder from './modules/Adder' import verilogMultiplier from './modules/verilogMultiplier' import verilogDivider from './modules/verilogDivider' import verilogPower from './modules/verilogPower' import verilogShiftLeft from './modules/verilogShiftLeft' import verilogShiftRight from './modules/verilogShiftRight' -import TwoComplement from './modules/TwoComplement' import Splitter from './modules/Splitter' -import Ground from './modules/Ground' -import Power from './modules/Power' import Input from './modules/Input' import Output from './modules/Output' -import BitSelector from './modules/BitSelector' import ConstantVal from './modules/ConstantVal' import NorGate from './modules/NorGate' import DigitalLed from './modules/DigitalLed' -import VariableLed from './modules/VariableLed' import Button from './modules/Button' -import RGBLed from './modules/RGBLed' -import SquareRGBLed from './modules/SquareRGBLed' -import Demultiplexer from './modules/Demultiplexer' -import Decoder from './modules/Decoder' -import Flag from './modules/Flag' -import MSB from './modules/MSB' import LSB from './modules/LSB' -import PriorityEncoder from './modules/PriorityEncoder' -import Tunnel from './modules/Tunnel' import ALU from './modules/ALU' -import Rectangle from './modules/Rectangle' -import Arrow from './modules/Arrow' -import Counter from './modules/Counter' -import Random from './modules/Random' -import RGBLedMatrix from './modules/RGBLedMatrix' -import simulationArea from './simulationArea' -import TflipFlop from './sequential/TflipFlop' import DflipFlop from './sequential/DflipFlop' -import Dlatch from './sequential/Dlatch' -import SRflipFlop from './sequential/SRflipFlop' -import JKflipFlop from './sequential/JKflipFlop' -import TTY from './sequential/TTY' -import Keyboard from './sequential/Keyboard' import Clock from './sequential/Clock' -import RAM from './sequential/RAM' import verilogRAM from './sequential/verilogRAM' -import EEPROM from './sequential/EEPROM' -import Rom from './sequential/Rom' -import TB_Input from './testbench/testbenchInput' -import TB_Output from './testbench/testbenchOutput' -import ForceGate from './testbench/ForceGate' -import { newCircuit, switchCircuit, changeCircuitName } from './circuit' -import SubCircuit from './subcircuit' function getBitWidth(bitsJSON) { if (Number.isInteger(bitsJSON)) { diff --git a/v0/src/simulator/src/app.js b/v0/src/simulator/src/app.ts similarity index 97% rename from v0/src/simulator/src/app.js rename to v0/src/simulator/src/app.ts index 00b64e60..0f4c7940 100644 --- a/v0/src/simulator/src/app.js +++ b/v0/src/simulator/src/app.ts @@ -1,9 +1,9 @@ -import { setup } from './setup' -import Array from './arrayHelpers' +import { setup } from './setup'; +import { JsConfig } from './types/app.types' document.addEventListener('DOMContentLoaded', () => { - setup() - var js = { + setup(); + const js: JsConfig = { devices: { dev0: { type: 'Input', @@ -207,7 +207,5 @@ document.addEventListener('DOMContentLoaded', () => { }, ], subcircuits: {}, - } -}) - -window.Array = Array + }; +}); \ No newline at end of file diff --git a/v0/src/simulator/src/arrayHelpers.js b/v0/src/simulator/src/arrayHelpers.js deleted file mode 100644 index 8d10917e..00000000 --- a/v0/src/simulator/src/arrayHelpers.js +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable func-names */ -/* eslint-disable no-global-assign */ -/* eslint-disable no-extend-native */ -export default Array = window.Array - -Object.defineProperty(Array.prototype, 'clean', { - value: function (deleteValue) { - for (var i = 0; i < this.length; i++) { - if (this[i] === deleteValue) { - this.splice(i, 1) - i-- - } - } - return this - }, - enumerable: false, -}) - -Object.defineProperty(Array.prototype, 'extend', { - value: function (otherArray) { - /* you should include a test to check whether other_array really is an array */ - otherArray.forEach(function (v) { - this.push(v) - }, this) - }, - enumerable: false, -}) - -Object.defineProperty(Array.prototype, 'contains', { - value: function (value) { - return this.indexOf(value) > -1 - }, - enumerable: false, -}) diff --git a/v0/src/simulator/src/backgroundArea.js b/v0/src/simulator/src/backgroundArea.js deleted file mode 100644 index 49da21aa..00000000 --- a/v0/src/simulator/src/backgroundArea.js +++ /dev/null @@ -1,17 +0,0 @@ -import { dots } from './canvasApi' - -var backgroundArea -export default backgroundArea = { - canvas: document.getElementById('backgroundArea'), - setup() { - this.canvas = document.getElementById('backgroundArea') - this.canvas.width = width - this.canvas.height = height - this.context = this.canvas.getContext('2d') - dots(true, false) - }, - clear() { - if (!this.context) return - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) - }, -} diff --git a/v0/src/simulator/src/backgroundArea.ts b/v0/src/simulator/src/backgroundArea.ts new file mode 100644 index 00000000..7556b0f8 --- /dev/null +++ b/v0/src/simulator/src/backgroundArea.ts @@ -0,0 +1,20 @@ +import { BackgroundArea } from './interface/backgroundArea' +import { dots } from './canvasApi'; + +export const backgroundArea: BackgroundArea = { + canvas: null, + context: null, + setup() { + this.canvas = document.getElementById('backgroundArea') as HTMLCanvasElement; + this.canvas.width = width; + this.canvas.height = height; + this.context = this.canvas.getContext('2d'); + dots(true, false); + }, + clear() { + if (!this.context || !this.canvas) { + return; + } + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + }, +}; diff --git a/v0/src/simulator/src/canvas2svg.js b/v0/src/simulator/src/canvas2svg.js deleted file mode 100644 index d6f5dc64..00000000 --- a/v0/src/simulator/src/canvas2svg.js +++ /dev/null @@ -1,1433 +0,0 @@ -/*!! - * Canvas 2 Svg v1.0.19 - * A low level canvas to SVG converter. Uses a mock canvas context to build an SVG document. - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Author: - * Kerry Liu - * - * Copyright (c) 2014 Gliffy Inc. - */ - -/** - * CircuitVerse - Edited - * Latest npm package is 1.0.16 but we need 1.0.19 - */ - -'use strict' - -var STYLES, ctx, CanvasGradient, CanvasPattern, namedEntities - -//helper function to format a string -function format(str, args) { - var keys = Object.keys(args), - i - for (i = 0; i < keys.length; i++) { - str = str.replace( - new RegExp('\\{' + keys[i] + '\\}', 'gi'), - args[keys[i]] - ) - } - return str -} - -//helper function that generates a random string -function randomString(holder) { - var chars, randomstring, i - if (!holder) { - throw new Error( - 'cannot create a random attribute name for an undefined object' - ) - } - chars = 'ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz' - randomstring = '' - do { - randomstring = '' - for (i = 0; i < 12; i++) { - randomstring += chars[Math.floor(Math.random() * chars.length)] - } - } while (holder[randomstring]) - return randomstring -} - -//helper function to map named to numbered entities -function createNamedToNumberedLookup(items, radix) { - var i, - entity, - lookup = {}, - base10, - base16 - items = items.split(',') - radix = radix || 10 - // Map from named to numbered entities. - for (i = 0; i < items.length; i += 2) { - entity = '&' + items[i + 1] + ';' - base10 = parseInt(items[i], radix) - lookup[entity] = '&#' + base10 + ';' - } - //FF and IE need to create a regex from hex values ie   == \xa0 - lookup['\\xa0'] = ' ' - return lookup -} - -//helper function to map canvas-textAlign to svg-textAnchor -function getTextAnchor(textAlign) { - //TODO: support rtl languages - var mapping = { - left: 'start', - right: 'end', - center: 'middle', - start: 'start', - end: 'end', - } - return mapping[textAlign] || mapping.start -} - -//helper function to map canvas-textBaseline to svg-dominantBaseline -function getDominantBaseline(textBaseline) { - //INFO: not supported in all browsers - var mapping = { - alphabetic: 'alphabetic', - hanging: 'hanging', - top: 'text-before-edge', - bottom: 'text-after-edge', - middle: 'central', - } - return mapping[textBaseline] || mapping.alphabetic -} - -// Unpack entities lookup where the numbers are in radix 32 to reduce the size -// entity mapping courtesy of tinymce -namedEntities = createNamedToNumberedLookup( - '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + - '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + - '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + - '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + - '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + - '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + - '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + - '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + - '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + - '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + - 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + - 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + - 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + - 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + - 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + - '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + - '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + - '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + - '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + - '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + - 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + - 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + - 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + - '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + - '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', - 32 -) - -//Some basic mappings for attributes and default values. -STYLES = { - strokeStyle: { - svgAttr: 'stroke', //corresponding svg attribute - canvas: '#000000', //canvas default - svg: 'none', //svg default - apply: 'stroke', //apply on stroke() or fill() - }, - fillStyle: { - svgAttr: 'fill', - canvas: '#000000', - svg: null, //svg default is black, but we need to special case this to handle canvas stroke without fill - apply: 'fill', - }, - lineCap: { - svgAttr: 'stroke-linecap', - canvas: 'butt', - svg: 'butt', - apply: 'stroke', - }, - lineJoin: { - svgAttr: 'stroke-linejoin', - canvas: 'miter', - svg: 'miter', - apply: 'stroke', - }, - miterLimit: { - svgAttr: 'stroke-miterlimit', - canvas: 10, - svg: 4, - apply: 'stroke', - }, - lineWidth: { - svgAttr: 'stroke-width', - canvas: 1, - svg: 1, - apply: 'stroke', - }, - globalAlpha: { - svgAttr: 'opacity', - canvas: 1, - svg: 1, - apply: 'fill stroke', - }, - font: { - //font converts to multiple svg attributes, there is custom logic for this - canvas: '10px sans-serif', - }, - shadowColor: { - canvas: '#000000', - }, - shadowOffsetX: { - canvas: 0, - }, - shadowOffsetY: { - canvas: 0, - }, - shadowBlur: { - canvas: 0, - }, - textAlign: { - canvas: 'start', - }, - textBaseline: { - canvas: 'alphabetic', - }, - lineDash: { - svgAttr: 'stroke-dasharray', - canvas: [], - svg: null, - apply: 'stroke', - }, -} - -/** - * - * @param gradientNode - reference to the gradient - * @constructor - */ -CanvasGradient = function (gradientNode, ctx) { - this.__root = gradientNode - this.__ctx = ctx -} - -/** - * Adds a color stop to the gradient root - */ -CanvasGradient.prototype.addColorStop = function (offset, color) { - var stop = this.__ctx.__createElement('stop'), - regex, - matches - stop.setAttribute('offset', offset) - if (color.indexOf('rgba') !== -1) { - //separate alpha value, since webkit can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(color) - stop.setAttribute( - 'stop-color', - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - stop.setAttribute('stop-opacity', matches[4]) - } else { - stop.setAttribute('stop-color', color) - } - this.__root.appendChild(stop) -} - -CanvasPattern = function (pattern, ctx) { - this.__root = pattern - this.__ctx = ctx -} - -/** - * The mock canvas context - * @param o - options include: - * ctx - existing Context2D to wrap around - * width - width of your canvas (defaults to 500) - * height - height of your canvas (defaults to 500) - * enableMirroring - enables canvas mirroring (get image data) (defaults to false) - * document - the document object (defaults to the current document) - */ -ctx = function (o) { - var defaultOptions = { width: 500, height: 500, enableMirroring: false }, - options - - //keep support for this way of calling C2S: new C2S(width,height) - if (arguments.length > 1) { - options = defaultOptions - options.width = arguments[0] - options.height = arguments[1] - } else if (!o) { - options = defaultOptions - } else { - options = o - } - - if (!(this instanceof ctx)) { - //did someone call this without new? - return new ctx(options) - } - - //setup options - this.width = options.width || defaultOptions.width - this.height = options.height || defaultOptions.height - this.enableMirroring = - options.enableMirroring !== undefined - ? options.enableMirroring - : defaultOptions.enableMirroring - - this.canvas = this ///point back to this instance! - this.__document = options.document || document - - // allow passing in an existing context to wrap around - // if a context is passed in, we know a canvas already exist - if (options.ctx) { - this.__ctx = options.ctx - } else { - this.__canvas = this.__document.createElement('canvas') - this.__ctx = this.__canvas.getContext('2d') - } - - this.__setDefaultStyles() - this.__stack = [this.__getStyleState()] - this.__groupStack = [] - - //the root svg element - this.__root = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg' - ) - this.__root.setAttribute('version', 1.1) - this.__root.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - this.__root.setAttributeNS( - 'http://www.w3.org/2000/xmlns/', - 'xmlns:xlink', - 'http://www.w3.org/1999/xlink' - ) - this.__root.setAttribute('width', this.width) - this.__root.setAttribute('height', this.height) - - //make sure we don't generate the same ids in defs - this.__ids = {} - - //defs tag - this.__defs = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'defs' - ) - this.__root.appendChild(this.__defs) - - //also add a group child. the svg element can't use the transform attribute - this.__currentElement = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'g' - ) - this.__root.appendChild(this.__currentElement) -} - -/** - * Creates the specified svg element - * @private - */ -ctx.prototype.__createElement = function (elementName, properties, resetFill) { - if (typeof properties === 'undefined') { - properties = {} - } - - var element = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - elementName - ), - keys = Object.keys(properties), - i, - key - if (resetFill) { - //if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black. - element.setAttribute('fill', 'none') - element.setAttribute('stroke', 'none') - } - for (i = 0; i < keys.length; i++) { - key = keys[i] - element.setAttribute(key, properties[key]) - } - return element -} - -/** - * Applies default canvas styles to the context - * @private - */ -ctx.prototype.__setDefaultStyles = function () { - //default 2d canvas context properties see:http://www.w3.org/TR/2dcontext/ - var keys = Object.keys(STYLES), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = STYLES[key].canvas - } -} - -/** - * Applies styles on restore - * @param styleState - * @private - */ -ctx.prototype.__applyStyleState = function (styleState) { - var keys = Object.keys(styleState), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = styleState[key] - } -} - -/** - * Gets the current style state - * @return {Object} - * @private - */ -ctx.prototype.__getStyleState = function () { - var i, - styleState = {}, - keys = Object.keys(STYLES), - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - styleState[key] = this[key] - } - return styleState -} - -/** - * Apples the current styles to the current SVG element. On "ctx.fill" or "ctx.stroke" - * @param type - * @private - */ -ctx.prototype.__applyStyleToCurrentElement = function (type) { - var currentElement = this.__currentElement - var currentStyleGroup = this.__currentElementsToStyle - if (currentStyleGroup) { - currentElement.setAttribute(type, '') - currentElement = currentStyleGroup.element - currentStyleGroup.children.forEach(function (node) { - node.setAttribute(type, '') - }) - } - - var keys = Object.keys(STYLES), - i, - style, - value, - id, - regex, - matches - for (i = 0; i < keys.length; i++) { - style = STYLES[keys[i]] - value = this[keys[i]] - if (style.apply) { - //is this a gradient or pattern? - if (value instanceof CanvasPattern) { - //pattern - if (value.__ctx) { - //copy over defs - while (value.__ctx.__defs.childNodes.length) { - id = value.__ctx.__defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild( - value.__ctx.__defs.childNodes[0] - ) - } - } - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if (value instanceof CanvasGradient) { - //gradient - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if ( - style.apply.indexOf(type) !== -1 && - style.svg !== value - ) { - if ( - (style.svgAttr === 'stroke' || style.svgAttr === 'fill') && - value.indexOf('rgba') !== -1 - ) { - //separate alpha value, since illustrator can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(value) - currentElement.setAttribute( - style.svgAttr, - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - //should take globalAlpha here - var opacity = matches[4] - var globalAlpha = this.globalAlpha - if (globalAlpha != null) { - opacity *= globalAlpha - } - currentElement.setAttribute( - style.svgAttr + '-opacity', - opacity - ) - } else { - var attr = style.svgAttr - if (keys[i] === 'globalAlpha') { - attr = type + '-' + style.svgAttr - if (currentElement.getAttribute(attr)) { - //fill-opacity or stroke-opacity has already been set by stroke or fill. - continue - } - } - //otherwise only update attribute if right type, and not svg default - currentElement.setAttribute(attr, value) - } - } - } - } -} - -/** - * Will return the closest group or svg node. May return the current element. - * @private - */ -ctx.prototype.__closestGroupOrSvg = function (node) { - node = node || this.__currentElement - if (node.nodeName === 'g' || node.nodeName === 'svg') { - return node - } else { - return this.__closestGroupOrSvg(node.parentNode) - } -} - -/** - * Returns the serialized value of the svg so far - * @param fixNamedEntities - Standalone SVG doesn't support named entities, which document.createTextNode encodes. - * If true, we attempt to find all named entities and encode it as a numeric entity. - * @return serialized svg - */ -ctx.prototype.getSerializedSvg = function (fixNamedEntities) { - var serialized = new XMLSerializer().serializeToString(this.__root), - keys, - i, - key, - value, - regexp, - xmlns - - //IE search for a duplicate xmnls because they didn't implement setAttributeNS correctly - xmlns = - /xmlns="http:\/\/www\.w3\.org\/2000\/svg".+xmlns="http:\/\/www\.w3\.org\/2000\/svg/gi - if (xmlns.test(serialized)) { - serialized = serialized.replace( - 'xmlns="http://www.w3.org/2000/svg', - 'xmlns:xlink="http://www.w3.org/1999/xlink' - ) - } - - if (fixNamedEntities) { - keys = Object.keys(namedEntities) - //loop over each named entity and replace with the proper equivalent. - for (i = 0; i < keys.length; i++) { - key = keys[i] - value = namedEntities[key] - regexp = new RegExp(key, 'gi') - if (regexp.test(serialized)) { - serialized = serialized.replace(regexp, value) - } - } - } - - return serialized -} - -/** - * Returns the root svg - * @return svg - */ -ctx.prototype.getSvg = function () { - return this.__root -} -/** - * Will generate a group tag. - */ -ctx.prototype.save = function () { - var group = this.__createElement('g') - var parent = this.__closestGroupOrSvg() - this.__groupStack.push(parent) - parent.appendChild(group) - this.__currentElement = group - this.__stack.push(this.__getStyleState()) -} -/** - * Sets current element to parent, or just root if already root - */ -ctx.prototype.restore = function () { - this.__currentElement = this.__groupStack.pop() - this.__currentElementsToStyle = null - //Clearing canvas will make the poped group invalid, currentElement is set to the root group node. - if (!this.__currentElement) { - this.__currentElement = this.__root.childNodes[1] - } - var state = this.__stack.pop() - this.__applyStyleState(state) -} - -/** - * Helper method to add transform - * @private - */ -ctx.prototype.__addTransform = function (t) { - //if the current element has siblings, add another group - var parent = this.__closestGroupOrSvg() - if (parent.childNodes.length > 0) { - if (this.__currentElement.nodeName === 'path') { - if (!this.__currentElementsToStyle) - this.__currentElementsToStyle = { - element: parent, - children: [], - } - this.__currentElementsToStyle.children.push(this.__currentElement) - this.__applyCurrentDefaultPath() - } - - var group = this.__createElement('g') - parent.appendChild(group) - this.__currentElement = group - } - - var transform = this.__currentElement.getAttribute('transform') - if (transform) { - transform += ' ' - } else { - transform = '' - } - transform += t - this.__currentElement.setAttribute('transform', transform) -} - -/** - * scales the current element - */ -ctx.prototype.scale = function (x, y) { - if (y === undefined) { - y = x - } - this.__addTransform(format('scale({x},{y})', { x: x, y: y })) -} - -/** - * rotates the current element - */ -ctx.prototype.rotate = function (angle) { - var degrees = (angle * 180) / Math.PI - this.__addTransform( - format('rotate({angle},{cx},{cy})', { angle: degrees, cx: 0, cy: 0 }) - ) -} - -/** - * translates the current element - */ -ctx.prototype.translate = function (x, y) { - this.__addTransform(format('translate({x},{y})', { x: x, y: y })) -} - -/** - * applies a transform to the current element - */ -ctx.prototype.transform = function (a, b, c, d, e, f) { - this.__addTransform( - format('matrix({a},{b},{c},{d},{e},{f})', { - a: a, - b: b, - c: c, - d: d, - e: e, - f: f, - }) - ) -} - -/** - * Create a new Path Element - */ -ctx.prototype.beginPath = function () { - var path, parent - - // Note that there is only one current default path, it is not part of the drawing state. - // See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path - this.__currentDefaultPath = '' - this.__currentPosition = {} - - path = this.__createElement('path', {}, true) - parent = this.__closestGroupOrSvg() - parent.appendChild(path) - this.__currentElement = path -} - -/** - * Helper function to apply currentDefaultPath to current path element - * @private - */ -ctx.prototype.__applyCurrentDefaultPath = function () { - var currentElement = this.__currentElement - if (currentElement.nodeName === 'path') { - currentElement.setAttribute('d', this.__currentDefaultPath) - } else { - console.error( - 'Attempted to apply path command to node', - currentElement.nodeName - ) - } -} - -/** - * Helper function to add path command - * @private - */ -ctx.prototype.__addPathCommand = function (command) { - this.__currentDefaultPath += ' ' - this.__currentDefaultPath += command -} - -/** - * Adds the move command to the current path element, - * if the currentPathElement is not empty create a new path element - */ -ctx.prototype.moveTo = function (x, y) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - - // creates a new subpath with the given point - this.__currentPosition = { x: x, y: y } - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) -} - -/** - * Closes the current path - */ -ctx.prototype.closePath = function () { - if (this.__currentDefaultPath) { - this.__addPathCommand('Z') - } -} - -/** - * Adds a line to command - */ -ctx.prototype.lineTo = function (x, y) { - this.__currentPosition = { x: x, y: y } - if (this.__currentDefaultPath.indexOf('M') > -1) { - this.__addPathCommand(format('L {x} {y}', { x: x, y: y })) - } else { - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } -} - -/** - * Add a bezier command - */ -ctx.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}', { - cp1x: cp1x, - cp1y: cp1y, - cp2x: cp2x, - cp2y: cp2y, - x: x, - y: y, - }) - ) -} - -/** - * Adds a quadratic curve to command - */ -ctx.prototype.quadraticCurveTo = function (cpx, cpy, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('Q {cpx} {cpy} {x} {y}', { cpx: cpx, cpy: cpy, x: x, y: y }) - ) -} - -/** - * Return a new normalized vector of given vector - */ -var normalize = function (vector) { - var len = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]) - return [vector[0] / len, vector[1] / len] -} - -/** - * Adds the arcTo to the current path - * - * @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto - */ -ctx.prototype.arcTo = function (x1, y1, x2, y2, radius) { - // Let the point (x0, y0) be the last point in the subpath. - var x0 = this.__currentPosition && this.__currentPosition.x - var y0 = this.__currentPosition && this.__currentPosition.y - - // First ensure there is a subpath for (x1, y1). - if (typeof x0 == 'undefined' || typeof y0 == 'undefined') { - return - } - - // Negative values for radius must cause the implementation to throw an IndexSizeError exception. - if (radius < 0) { - throw new Error( - 'IndexSizeError: The radius provided (' + radius + ') is negative.' - ) - } - - // If the point (x0, y0) is equal to the point (x1, y1), - // or if the point (x1, y1) is equal to the point (x2, y2), - // or if the radius radius is zero, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - if ((x0 === x1 && y0 === y1) || (x1 === x2 && y1 === y2) || radius === 0) { - this.lineTo(x1, y1) - return - } - - // Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - var unit_vec_p1_p0 = normalize([x0 - x1, y0 - y1]) - var unit_vec_p1_p2 = normalize([x2 - x1, y2 - y1]) - if ( - unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === - unit_vec_p1_p0[1] * unit_vec_p1_p2[0] - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius, - // and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1), - // and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2). - // The points at which this circle touches these two lines are called the start and end tangent points respectively. - - // note that both vectors are unit vectors, so the length is 1 - var cos = - unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + - unit_vec_p1_p0[1] * unit_vec_p1_p2[1] - var theta = Math.acos(Math.abs(cos)) - - // Calculate origin - var unit_vec_p1_origin = normalize([ - unit_vec_p1_p0[0] + unit_vec_p1_p2[0], - unit_vec_p1_p0[1] + unit_vec_p1_p2[1], - ]) - var len_p1_origin = radius / Math.sin(theta / 2) - var x = x1 + len_p1_origin * unit_vec_p1_origin[0] - var y = y1 + len_p1_origin * unit_vec_p1_origin[1] - - // Calculate start angle and end angle - // rotate 90deg clockwise (note that y axis points to its down) - var unit_vec_origin_start_tangent = [-unit_vec_p1_p0[1], unit_vec_p1_p0[0]] - // rotate 90deg counter clockwise (note that y axis points to its down) - var unit_vec_origin_end_tangent = [unit_vec_p1_p2[1], -unit_vec_p1_p2[0]] - var getAngle = function (vector) { - // get angle (clockwise) between vector and (1, 0) - var x = vector[0] - var y = vector[1] - if (y >= 0) { - // note that y axis points to its down - return Math.acos(x) - } else { - return -Math.acos(x) - } - } - var startAngle = getAngle(unit_vec_origin_start_tangent) - var endAngle = getAngle(unit_vec_origin_end_tangent) - - // Connect the point (x0, y0) to the start tangent point by a straight line - this.lineTo( - x + unit_vec_origin_start_tangent[0] * radius, - y + unit_vec_origin_start_tangent[1] * radius - ) - - // Connect the start tangent point to the end tangent point by arc - // and adding the end tangent point to the subpath. - this.arc(x, y, radius, startAngle, endAngle) -} - -/** - * Sets the stroke property on the current element - */ -ctx.prototype.stroke = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute('paint-order', 'fill stroke markers') - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('stroke') -} - -/** - * Sets fill properties on the current element - */ -ctx.prototype.fill = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute('paint-order', 'stroke fill markers') - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('fill') -} - -/** - * Adds a rectangle to the path. - */ -ctx.prototype.rect = function (x, y, width, height) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - this.moveTo(x, y) - this.lineTo(x + width, y) - this.lineTo(x + width, y + height) - this.lineTo(x, y + height) - this.lineTo(x, y) - this.closePath() -} - -/** - * adds a rectangle element - */ -ctx.prototype.fillRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('fill') -} - -/** - * Draws a rectangle with no fill - * @param x - * @param y - * @param width - * @param height - */ -ctx.prototype.strokeRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('stroke') -} - -/** - * Clear entire canvas: - * 1. save current transforms - * 2. remove all the childNodes of the root g element - */ -ctx.prototype.__clearCanvas = function () { - var current = this.__closestGroupOrSvg(), - transform = current.getAttribute('transform') - var rootGroup = this.__root.childNodes[1] - var childNodes = rootGroup.childNodes - for (var i = childNodes.length - 1; i >= 0; i--) { - if (childNodes[i]) { - rootGroup.removeChild(childNodes[i]) - } - } - this.__currentElement = rootGroup - //reset __groupStack as all the child group nodes are all removed. - this.__groupStack = [] - if (transform) { - this.__addTransform(transform) - } -} - -/** - * "Clears" a canvas by just drawing a white rectangle in the current group. - */ -ctx.prototype.clearRect = function (x, y, width, height) { - //clear entire canvas - if (x === 0 && y === 0 && width === this.width && height === this.height) { - this.__clearCanvas() - return - } - var rect, - parent = this.__closestGroupOrSvg() - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - fill: '#FFFFFF', - }, - true - ) - parent.appendChild(rect) -} - -/** - * Adds a linear gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ -ctx.prototype.createLinearGradient = function (x1, y1, x2, y2) { - var grad = this.__createElement( - 'linearGradient', - { - id: randomString(this.__ids), - x1: x1 + 'px', - x2: x2 + 'px', - y1: y1 + 'px', - y2: y2 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) -} - -/** - * Adds a radial gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ -ctx.prototype.createRadialGradient = function (x0, y0, r0, x1, y1, r1) { - var grad = this.__createElement( - 'radialGradient', - { - id: randomString(this.__ids), - cx: x1 + 'px', - cy: y1 + 'px', - r: r1 + 'px', - fx: x0 + 'px', - fy: y0 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) -} - -/** - * Parses the font string and returns svg mapping - * @private - */ -ctx.prototype.__parseFont = function () { - var regex = - /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\'\"\sa-z0-9]+?)\s*$/i - var fontPart = regex.exec(this.font) - var data = { - style: fontPart[1] || 'normal', - size: fontPart[4] || '10px', - family: fontPart[6] || 'sans-serif', - weight: fontPart[3] || 'normal', - decoration: fontPart[2] || 'normal', - href: null, - } - - //canvas doesn't support underline natively, but we can pass this attribute - if (this.__fontUnderline === 'underline') { - data.decoration = 'underline' - } - - //canvas also doesn't support linking, but we can pass this as well - if (this.__fontHref) { - data.href = this.__fontHref - } - - return data -} - -/** - * Helper to link text fragments - * @param font - * @param element - * @return {*} - * @private - */ -ctx.prototype.__wrapTextLink = function (font, element) { - if (font.href) { - var a = this.__createElement('a') - a.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - font.href - ) - a.appendChild(element) - return a - } - return element -} - -/** - * Fills or strokes text - * @param text - * @param x - * @param y - * @param action - stroke or fill - * @private - */ -ctx.prototype.__applyText = function (text, x, y, action) { - var font = this.__parseFont(), - parent = this.__closestGroupOrSvg(), - textElement = this.__createElement( - 'text', - { - 'font-family': font.family, - 'font-size': font.size, - 'font-style': font.style, - 'font-weight': font.weight, - 'text-decoration': font.decoration, - x: x, - y: y, - 'text-anchor': getTextAnchor(this.textAlign), - 'dominant-baseline': getDominantBaseline(this.textBaseline), - }, - true - ) - - textElement.appendChild(this.__document.createTextNode(text)) - this.__currentElement = textElement - this.__applyStyleToCurrentElement(action) - parent.appendChild(this.__wrapTextLink(font, textElement)) -} - -/** - * Creates a text element - * @param text - * @param x - * @param y - */ -ctx.prototype.fillText = function (text, x, y) { - this.__applyText(text, x, y, 'fill') -} - -/** - * Strokes text - * @param text - * @param x - * @param y - */ -ctx.prototype.strokeText = function (text, x, y) { - this.__applyText(text, x, y, 'stroke') -} - -/** - * No need to implement this for svg. - * @param text - * @return {TextMetrics} - */ -ctx.prototype.measureText = function (text) { - this.__ctx.font = this.font - return this.__ctx.measureText(text) -} - -/** - * Arc command! - */ -ctx.prototype.arc = function ( - x, - y, - radius, - startAngle, - endAngle, - counterClockwise -) { - // in canvas no circle is drawn if no angle is provided. - if (startAngle === endAngle) { - return - } - startAngle = startAngle % (2 * Math.PI) - endAngle = endAngle % (2 * Math.PI) - if (startAngle === endAngle) { - //circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle) - endAngle = - (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % - (2 * Math.PI) - } - var endX = x + radius * Math.cos(endAngle), - endY = y + radius * Math.sin(endAngle), - startX = x + radius * Math.cos(startAngle), - startY = y + radius * Math.sin(startAngle), - sweepFlag = counterClockwise ? 0 : 1, - largeArcFlag = 0, - diff = endAngle - startAngle - - // https://github.com/gliffy/canvas2svg/issues/4 - if (diff < 0) { - diff += 2 * Math.PI - } - - if (counterClockwise) { - largeArcFlag = diff > Math.PI ? 0 : 1 - } else { - largeArcFlag = diff > Math.PI ? 1 : 0 - } - - this.lineTo(startX, startY) - this.__addPathCommand( - format( - 'A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}', - { - rx: radius, - ry: radius, - xAxisRotation: 0, - largeArcFlag: largeArcFlag, - sweepFlag: sweepFlag, - endX: endX, - endY: endY, - } - ) - ) - - this.__currentPosition = { x: endX, y: endY } -} - -/** - * Generates a ClipPath from the clip command. - */ -ctx.prototype.clip = function () { - var group = this.__closestGroupOrSvg(), - clipPath = this.__createElement('clipPath'), - id = randomString(this.__ids), - newGroup = this.__createElement('g') - - this.__applyCurrentDefaultPath() - group.removeChild(this.__currentElement) - clipPath.setAttribute('id', id) - clipPath.appendChild(this.__currentElement) - - this.__defs.appendChild(clipPath) - - //set the clip path to this group - group.setAttribute('clip-path', format('url(#{id})', { id: id })) - - //clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations - // to this path - group.appendChild(newGroup) - - this.__currentElement = newGroup -} - -/** - * Draws a canvas, image or mock context to this canvas. - * Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support. - * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage - */ -ctx.prototype.drawImage = function () { - //convert arguments to a real array - var args = Array.prototype.slice.call(arguments), - image = args[0], - dx, - dy, - dw, - dh, - sx = 0, - sy = 0, - sw, - sh, - parent, - svg, - defs, - group, - currentElement, - svgImage, - canvas, - context, - id - - if (args.length === 3) { - dx = args[1] - dy = args[2] - sw = image.width - sh = image.height - dw = sw - dh = sh - } else if (args.length === 5) { - dx = args[1] - dy = args[2] - dw = args[3] - dh = args[4] - sw = image.width - sh = image.height - } else if (args.length === 9) { - sx = args[1] - sy = args[2] - sw = args[3] - sh = args[4] - dx = args[5] - dy = args[6] - dw = args[7] - dh = args[8] - } else { - throw new Error( - 'Inavlid number of arguments passed to drawImage: ' + - arguments.length - ) - } - - parent = this.__closestGroupOrSvg() - currentElement = this.__currentElement - var translateDirective = 'translate(' + dx + ', ' + dy + ')' - if (image instanceof ctx) { - //canvas2svg mock canvas context. In the future we may want to clone nodes instead. - //also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context. - svg = image.getSvg().cloneNode(true) - if (svg.childNodes && svg.childNodes.length > 1) { - defs = svg.childNodes[0] - while (defs.childNodes.length) { - id = defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild(defs.childNodes[0]) - } - group = svg.childNodes[1] - if (group) { - //save original transform - var originTransform = group.getAttribute('transform') - var transformDirective - if (originTransform) { - transformDirective = - originTransform + ' ' + translateDirective - } else { - transformDirective = translateDirective - } - group.setAttribute('transform', transformDirective) - parent.appendChild(group) - } - } - } else if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - //canvas or image - svgImage = this.__createElement('image') - svgImage.setAttribute('width', dw) - svgImage.setAttribute('height', dh) - svgImage.setAttribute('preserveAspectRatio', 'none') - - if (sx || sy || sw !== image.width || sh !== image.height) { - //crop the image using a temporary canvas - canvas = this.__document.createElement('canvas') - canvas.width = dw - canvas.height = dh - context = canvas.getContext('2d') - context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh) - image = canvas - } - svgImage.setAttribute('transform', translateDirective) - svgImage.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - parent.appendChild(svgImage) - } -} - -/** - * Generates a pattern tag - */ -ctx.prototype.createPattern = function (image, repetition) { - var pattern = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'pattern' - ), - id = randomString(this.__ids), - img - pattern.setAttribute('id', id) - pattern.setAttribute('width', image.width) - pattern.setAttribute('height', image.height) - if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - img = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'image' - ) - img.setAttribute('width', image.width) - img.setAttribute('height', image.height) - img.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - pattern.appendChild(img) - this.__defs.appendChild(pattern) - } else if (image instanceof ctx) { - pattern.appendChild(image.__root.childNodes[1]) - this.__defs.appendChild(pattern) - } - return new CanvasPattern(pattern, this) -} - -ctx.prototype.setLineDash = function (dashArray) { - if (dashArray && dashArray.length > 0) { - this.lineDash = dashArray.join(',') - } else { - this.lineDash = null - } -} - -/** - * Not yet implemented - */ -ctx.prototype.drawFocusRing = function () {} -ctx.prototype.createImageData = function () {} -ctx.prototype.getImageData = function () {} -ctx.prototype.putImageData = function () {} -ctx.prototype.globalCompositeOperation = function () {} -ctx.prototype.setTransform = function () {} - -//add options for alternative namespace -// if (typeof window === "object") { -// window.C2S = ctx; -// } - -// CommonJS/Browserify -// if (typeof module === "object" && typeof module.exports === "object") { -// module.exports = ctx; -// } - -export default ctx diff --git a/v0/src/simulator/src/canvasApi.js b/v0/src/simulator/src/canvasApi.js index 08ee65d3..950bb2b8 100644 --- a/v0/src/simulator/src/canvasApi.js +++ b/v0/src/simulator/src/canvasApi.js @@ -1,8 +1,9 @@ /* eslint-disable no-param-reassign */ -import backgroundArea from './backgroundArea' -import simulationArea from './simulationArea' +import { backgroundArea } from './backgroundArea' +import { simulationArea } from './simulationArea' import miniMapArea, { removeMiniMap, updatelastMinimapShown } from './minimap' import { colors } from './themer/themer' +import { updateOrder } from './metadata' var unit = 10 @@ -107,9 +108,10 @@ export function changeScale(delta, xx, yy, method = 1) { if (!embed && !lightMode) { findDimensions(globalScope) miniMapArea.setup() - $('#miniMap').show() + let miniMap = document.querySelector('#miniMap'); + miniMap.style.display = 'block'; updatelastMinimapShown() - $('#miniMap').show() + miniMap.style.display = 'block'; setTimeout(removeMiniMap, 2000) } } @@ -240,7 +242,10 @@ export function moveTo(ctx, x1, y1, xx, yy, dir, bypass = false) { xx *= globalScope.scale yy *= globalScope.scale if (bypass) { - ctx.moveTo(xx + globalScope.ox + newX, yy + globalScope.oy + newY) + ctx.moveTo( + Math.round(xx + globalScope.ox + newX), + Math.round(yy + globalScope.oy + newY) + ) } else { ctx.moveTo( Math.round(xx + globalScope.ox + newX - correction) + correction, @@ -437,9 +442,9 @@ export function drawLine(ctx, x1, y1, x2, y2, color, width) { // Checks if string color is a valid color using a hack export function validColor(color) { - var $div = $('
') - $div.css('border', `1px solid ${color}`) - return $div.css('border-color') !== '' + let newDiv = document.createElement('div') + newDiv.style.border = `1px solid ${color}` + return newDiv.style.borderColor !== '' } // Helper function to color "RED" to RGBA diff --git a/v0/src/simulator/src/circuit.js b/v0/src/simulator/src/circuit.ts similarity index 69% rename from v0/src/simulator/src/circuit.js rename to v0/src/simulator/src/circuit.ts index f86429e3..cf04fc9e 100644 --- a/v0/src/simulator/src/circuit.js +++ b/v0/src/simulator/src/circuit.ts @@ -11,13 +11,10 @@ /* eslint-disable no-alert */ import CircuitElement from './circuitElement' import plotArea from './plotArea' -import simulationArea, { changeClockTime } from './simulationArea' +import { simulationArea } from './simulationArea' import { stripTags, uniq, - showMessage, - showError, - truncateString, } from './utils' import { findDimensions, dots } from './canvasApi' import { updateRestrictedElementsList } from './restrictedElementDiv' @@ -32,28 +29,33 @@ import { changeLightMode, } from './engine' import { toggleLayoutMode, layoutModeGet } from './layoutMode' -import { setProjectName, getProjectName } from './data/save' +import { setProjectName } from './data/save' import { changeClockEnable } from './sequential' import { changeInputSize } from './modules' import { verilogModeGet, verilogModeSet } from './Verilog2CV' -import { updateTestbenchUI } from './testbench' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' -import { toRef, toRefs } from 'vue' +import { toRefs } from 'vue' import { provideCircuitName } from '#/components/helpers/promptComponent/PromptComponent.vue' import { deleteCurrentCircuit } from '#/components/helpers/deleteCircuit/DeleteCircuit.vue' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { inputList, moduleList } from './metadata' export const circuitProperty = { toggleLayoutMode, setProjectName, changeCircuitName, - // changeClockTime, deleteCurrentCircuit, changeClockEnable, changeInputSize, changeLightMode, + changeClockTime } -export var scopeList = {} +function changeClockTime(t: number) { + simulationArea.changeClockTime(t) +} + +export let scopeList: { [key: string]: Scope } = {} export function resetScopeList() { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) @@ -65,20 +67,20 @@ export function resetScopeList() { * Disables layoutMode if enabled * Changes UI tab etc * Sets flags to make updates, resets most of the things - * @param {string} id - identifier for circuit - * @category circuit */ -export function switchCircuit(id) { +export function switchCircuit(id: string) { // TODO: fix tomorrow const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) const { activeCircuit } = toRefs(simulatorStore) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) if (layoutModeGet()) { toggleLayoutMode() } if (!scopeList[id].verilogMetadata.isVerilogCircuit) { verilogModeSet(false) + simulatorMobileStore.isVerilog.value = false } // globalScope.fixLayout(); @@ -94,6 +96,7 @@ export function switchCircuit(id) { globalScope = scopeList[id] if (globalScope.verilogMetadata.isVerilogCircuit) { verilogModeSet(true) + simulatorMobileStore.isVerilog.value = true } if (globalScope.isVisible()) { // $(`#${id}`).addClass('current') @@ -101,8 +104,10 @@ export function switchCircuit(id) { (circuit) => circuit.id == id ) // TODO: add strict equality after typescript circuit_list.value[index].focussed = true - activeCircuit.value.id = globalScope.id - activeCircuit.value.name = globalScope.name + if (activeCircuit.value) { + activeCircuit.value.id = globalScope.id + activeCircuit.value.name = globalScope.name + } } updateSimulationSet(true) updateSubcircuitSet(true) @@ -111,7 +116,6 @@ export function switchCircuit(id) { simulationArea.lastSelected = globalScope.root if (!embed) { showProperties(simulationArea.lastSelected) - updateTestbenchUI() plotArea.reset() } updateCanvasSet(true) @@ -121,13 +125,18 @@ export function switchCircuit(id) { updateRestrictedElementsList() } -export function getDependenciesList(scopeId) { +export function getDependenciesList(scopeId: string | number) { let scope = scopeList[scopeId] if (scope == undefined) scope = scopeList[globalScope.id] let dependencies = '' - for (id in scopeList) { - if (id != scope.id && scopeList[id].checkDependency(scope.id)) { + for (let id in scopeList) { + let formattedId; + if (typeof scopeId === 'number') + formattedId = scopeId; + else + formattedId = parseInt(scopeId); + if (id != scope.id && scopeList[id].checkDependency(formattedId)) { if (dependencies === '') { dependencies = scopeList[id].name } else { @@ -171,8 +180,8 @@ export function getDependenciesList(scopeId) { * Wrapper function around newCircuit to be called from + button on UI */ export async function createNewCircuitScope( - name, - id = undefined, + name: string | Error | undefined = undefined, + id: string | undefined = undefined, isVerilog = false, isVerilogMain = false ) { @@ -185,28 +194,31 @@ export async function createNewCircuitScope( newCircuit(name, id, isVerilog, isVerilogMain) if (!embed) { showProperties(simulationArea.lastSelected) - updateTestbenchUI() plotArea.reset() } return true } +export function circuitNameClicked() { + simulationArea.lastSelected = globalScope.root +} + /** * Function to create new circuit * Function creates button in tab, creates scope and switches to this circuit - * @param {string} name - name of the new circuit - * @param {string} id - identifier for circuit - * @category circuit */ -export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { +export function newCircuit(name: string | undefined, id: string | undefined, isVerilog = false, isVerilogMain = false) { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) const { activeCircuit } = toRefs(simulatorStore) + const { circuit_name_clickable } = toRefs(simulatorStore) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) if (layoutModeGet()) { toggleLayoutMode() } if (verilogModeGet()) { verilogModeSet(false) + simulatorMobileStore.isVerilog.value = false } name = name || 'Untitled-Circuit' name = stripTags(name) @@ -231,46 +243,26 @@ export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { // $('.circuits').removeClass('current') circuit_list.value.forEach((circuit) => (circuit.focussed = false)) circuit_list.value[circuit_list.value.length - 1].focussed = true - activeCircuit.value.id = scope.id - activeCircuit.value.name = scope.name + if (activeCircuit.value) { + activeCircuit.value.id = scope.id + activeCircuit.value.name = scope.name + } if (!isVerilog || isVerilogMain) { - if (embed) { - // added calss - embed-tab using vue logic - // var html = `
${truncateString( - // name, - // 18 - // )}
` - // $('#tabsBar').append(html) - // $('#tabsBar').addClass('embed-tabs') - } else { - // logic implemented in vue - } - + circuit_name_clickable.value = false; // Remove listeners - //$('.circuits').off('click') - $('.circuitName').off('click') - //$('.tabsCloseButton').off('click') - + // $('.circuitName').off('click') // switch circuit function moved inside vue component - if (!embed) { - $('.circuitName').on('click', () => { - simulationArea.lastSelected = globalScope.root - setTimeout(() => { - // here link with the properties panel - document.getElementById('circname').select() - }, 100) - }) + // $('.circuitName').on('click', () => { + // simulationArea.lastSelected = globalScope.root + // setTimeout(() => { + // // here link with the properties panel + // document.getElementById('circname').select() + // }, 100) + // }) + circuit_name_clickable.value = true; } - // moved inside vue - component - // $('.tabsCloseButton').on('click', function (e) { - // e.stopPropagation() - // deleteCurrentCircuit(this.id) - // }) - if (!embed) { showProperties(scope.root) } @@ -281,20 +273,15 @@ export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { /** * Used to change name of a circuit - * @param {string} name - new name - * @param {string} id - id of the circuit - * @category circuit */ -export function changeCircuitName(name, id = globalScope.id) { +export function changeCircuitName(name: string, id = globalScope.id) { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) - // const { activeCircuit } = toRefs(simulatorStore) name = name || 'Untitled' name = stripTags(name) scopeList[id].name = name const index = circuit_list.value.findIndex((circuit) => circuit.id === id) circuit_list.value[index].name = name - // activeCircuit.value.name = name // add later if necessary at current stage not important handled by projectProperty on switching circuit } /** @@ -305,6 +292,30 @@ export function changeCircuitName(name, id = globalScope.id) { * @category circuit */ export default class Scope { + restrictedCircuitElementsUsed: any[]; + id: number | string; + CircuitElement: any[]; + name: string; + root: CircuitElement; + backups: string[]; + history: string[]; + timeStamp: number; + verilogMetadata: { isVerilogCircuit: boolean; isMainCircuit: boolean; code: string; subCircuitScopeIds: string[]; }; + ox: number; + oy: number; + scale: number; + stack: any[]; + layout: { width: number; height: number; title_x: number; title_y: number; titleEnabled: boolean; }; + tunnelList?: {}; + pending?: any[]; + nodes?: any[]; + allNodes?: any[]; + wires?: any[]; + Input?: any[]; + Output?: any[]; + Splitter?: any[]; + SubCircuit?: any[]; + Clock?: any[]; constructor(name = 'localScope', id = undefined) { this.restrictedCircuitElementsUsed = [] this.id = id || Math.floor(Math.random() * 100000000000 + 1) @@ -364,14 +375,20 @@ export default class Scope { * Resets all nodes recursively */ reset() { - for (let i = 0; i < this.allNodes.length; i++) { - this.allNodes[i].reset() + if (this.allNodes) { + for (let i = 0; i < this.allNodes.length; i++) { + this.allNodes[i].reset() + } } - for (let i = 0; i < this.Splitter.length; i++) { - this.Splitter[i].reset() + if (this.Splitter) { + for (let i = 0; i < this.Splitter.length; i++) { + this.Splitter[i].reset() + } } - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].reset() + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].reset() + } } } @@ -381,12 +398,14 @@ export default class Scope { addInputs() { for (let i = 0; i < inputList.length; i++) { for (var j = 0; j < this[inputList[i]].length; j++) { - simulationArea.simulationQueue.add(this[inputList[i]][j], 0) + simulationArea.simulationQueue?.add(this[inputList[i]][j], 0) } } - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].addInputs() + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].addInputs() + } } } @@ -394,27 +413,34 @@ export default class Scope { * Ticks clocks recursively -- needs to be deprecated and synchronize all clocks with a global clock */ clockTick() { - for (let i = 0; i < this.Clock.length; i++) { - this.Clock[i].toggleState() - } // tick clock! - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].localScope.clockTick() - } // tick clock! + if (this.Clock) { + for (let i = 0; i < this.Clock.length; i++) { + this.Clock[i].toggleState() + } // tick clock! + } + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].localScope.clockTick() + } // tick clock! + } } /** * Checks if this circuit contains directly or indirectly scope with id * Recursive nature */ - checkDependency(id) { + checkDependency(id: number) { if (id === this.id) return true - for (let i = 0; i < this.SubCircuit.length; i++) { - if (this.SubCircuit[i].id === id) return true + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + if (this.SubCircuit[i].id === id) return true + } } - - for (let i = 0; i < this.SubCircuit.length; i++) { - if (scopeList[this.SubCircuit[i].id].checkDependency(id)) - return true + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + if (scopeList[this.SubCircuit[i].id].checkDependency(id)) + return true + } } return false @@ -425,9 +451,11 @@ export default class Scope { */ getDependencies() { var list = [] - for (let i = 0; i < this.SubCircuit.length; i++) { - list.push(this.SubCircuit[i].id) - list.extend(scopeList[this.SubCircuit[i].id].getDependencies()) + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + list.push(this.SubCircuit[i].id) + list.push(...scopeList[this.SubCircuit[i].id].getDependencies()) + } } return uniq(list) } @@ -437,11 +465,15 @@ export default class Scope { */ fixLayout() { var maxY = 20 - for (let i = 0; i < this.Input.length; i++) { - maxY = Math.max(this.Input[i].layoutProperties.y, maxY) + if (this.Input) { + for (let i = 0; i < this.Input.length; i++) { + maxY = Math.max(this.Input[i].layoutProperties.y, maxY) + } } - for (let i = 0; i < this.Output.length; i++) { - maxY = Math.max(this.Output[i].layoutProperties.y, maxY) + if (this.Output) { + for (let i = 0; i < this.Output.length; i++) { + maxY = Math.max(this.Output[i].layoutProperties.y, maxY) + } } if (maxY !== this.layout.height) { this.layout.height = maxY + 10 diff --git a/v0/src/simulator/src/circuitElement.js b/v0/src/simulator/src/circuitElement.js index cd368c4d..a7d5565e 100644 --- a/v0/src/simulator/src/circuitElement.js +++ b/v0/src/simulator/src/circuitElement.js @@ -1,7 +1,8 @@ /* eslint-disable no-multi-assign */ /* eslint-disable no-bitwise */ +/* eslint-disable */ import { scheduleUpdate } from './engine' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { fixDirection, fillText, @@ -154,7 +155,7 @@ export default class CircuitElement { /** * To generate JSON-safe data that can be loaded * @memberof CircuitElement - * @return {JSON} - the data to be saved + * @return {object} - the data to be saved */ saveObject() { var data = { @@ -176,7 +177,7 @@ export default class CircuitElement { /** * Always overriden * @memberof CircuitElement - * @return {JSON} - the data to be saved + * @return {object} - the data to be saved */ // eslint-disable-next-line class-methods-use-this customSave() { @@ -332,7 +333,7 @@ export default class CircuitElement { this.drag() if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( let i = 0; @@ -348,7 +349,7 @@ export default class CircuitElement { this.startDragging() if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( let i = 0; @@ -376,9 +377,9 @@ export default class CircuitElement { if (simulationArea.shiftDown) { simulationArea.lastSelected = undefined if ( - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { - simulationArea.multipleObjectSelections.clean(this) + simulationArea.multipleObjectSelections = simulationArea.multipleObjectSelections.filter(x => x !== this); } else { simulationArea.multipleObjectSelections.push(this) } @@ -479,8 +480,8 @@ export default class CircuitElement { * NOT OVERRIDABLE */ isHover() { - var mX = simulationArea.mouseXf - this.x - var mY = this.y - simulationArea.mouseYf + var mX = simulationArea.touch ? simulationArea.mouseDownX - this.x : simulationArea.mouseXf - this.x; + var mY = simulationArea.touch ? this.y - simulationArea.mouseDownY : this.y - simulationArea.mouseYf; var rX = this.rightDimensionX var lX = this.leftDimensionX @@ -578,7 +579,7 @@ export default class CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -646,7 +647,7 @@ export default class CircuitElement { /** Draws element in layout mode (inside the subcircuit) @param {number} xOffset - x position of the subcircuit - @param {number} yOffset - y position of the subcircuit + @param {number} yOffset - y position of the subcircuit Called by subcirucit.js/customDraw() - for drawing as a part of another circuit and layoutMode.js/renderLayout() - for drawing in layoutMode @@ -734,7 +735,7 @@ export default class CircuitElement { // OVERRIDE WITH CAUTION delete() { simulationArea.lastSelected = undefined - this.scope[this.objectType].clean(this) // CHECK IF THIS IS VALID + this.scope[this.objectType] = this.scope[this.objectType].filter(x => x !== this) if (this.deleteNodesWhenDeleted) { this.deleteNodes() } else { @@ -852,7 +853,8 @@ export default class CircuitElement { resolve() {} /** - * Helper Function to process verilog + * Helper Function to process Verilog + * @return {string} */ processVerilog() { // Output count used to sanitize output @@ -882,7 +884,7 @@ export default class CircuitElement { if ( !this.scope.verilogWireList[ this.nodeList[i].bitWidth - ].contains(this.nodeList[i].verilogLabel) + ].includes(this.nodeList[i].verilogLabel) ) this.scope.verilogWireList[ this.nodeList[i].bitWidth @@ -956,8 +958,8 @@ export default class CircuitElement { } /** - * Helper Function to generate verilog - * @return {JSON} + * Helper Function to generate Verilog. + * @return {string} */ generateVerilog() { // Example: and and_1(_out, _out, _Q[0]); diff --git a/v0/src/simulator/src/combinationalAnalysis.js b/v0/src/simulator/src/combinationalAnalysis.js index e45cb1b8..7577dcc0 100644 --- a/v0/src/simulator/src/combinationalAnalysis.js +++ b/v0/src/simulator/src/combinationalAnalysis.js @@ -1,667 +1,333 @@ /* eslint-disable import/no-cycle */ /* eslint-disable guard-for-in */ /* eslint-disable no-restricted-syntax */ -import Node from './node' -import { scheduleBackup } from './data/backupCircuit' -import BooleanMinimize from './quinMcCluskey' -import Input from './modules/Input' -import ConstantVal from './modules/ConstantVal' -import Output from './modules/Output' -import AndGate from './modules/AndGate' -import OrGate from './modules/OrGate' -import NotGate from './modules/NotGate' -import { stripTags } from './utils' -import simulationArea from './simulationArea' -import { findDimensions } from './canvasApi' +import Node from './node'; +import { scheduleBackup } from './data/backupCircuit'; +import BooleanMinimize from './quinMcCluskey'; +import Input from './modules/Input'; +import ConstantVal from './modules/ConstantVal'; +import Output from './modules/Output'; +import AndGate from './modules/AndGate'; +import OrGate from './modules/OrGate'; +import NotGate from './modules/NotGate'; +import { stripTags } from './utils'; +import { simulationArea } from './simulationArea'; +import { findDimensions } from './canvasApi'; import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' -// var inputSample = 5 -// var dataSample = [ -// ['01---', '11110', '01---', '00000'], -// ['01110', '1-1-1', '----0'], -// ['01---', '11110', '01110', '1-1-1', '0---0'], -// ['----1'], -// ] +export const performCombinationalAnalysis = (inputNameList, outputNameList, booleanNameExpression, scope = globalScope) => { + if(!inputNameList || !outputNameList || !booleanNameExpression) { + return; + } + var flag = 0; + var inputList = stripTags(inputNameList).split(','); + var outputList = stripTags(outputNameList).split(','); + var booleanExpression = booleanNameExpression; + inputList = inputList.map((x) => x.trim()); + inputList = inputList.filter((e) => e); + outputList = outputList.map((x) => x.trim()); + outputList = outputList.filter((e) => e); + booleanExpression = booleanExpression.replace(/ /g, ''); + booleanExpression = booleanExpression.toUpperCase(); -// var sampleInputListNames = ['A', 'B'] -// var sampleOutputListNames = ['X'] + var booleanInputVariables = []; + for (var i = 0; i < booleanExpression.length; i++) { + if ((booleanExpression[i] >= 'A' && booleanExpression[i] <= 'Z')) { + if (booleanExpression.indexOf(booleanExpression[i]) == i) { + booleanInputVariables.push(booleanExpression[i]); + } + } + } + booleanInputVariables.sort(); + if (inputList.length > 0 && outputList.length > 0 && booleanInputVariables.length == 0) { + createBooleanPrompt(inputList, outputList, null, scope); + } + else if (booleanInputVariables.length > 0 && inputList.length == 0 && outputList.length == 0) { + var output = solveBooleanFunction(booleanInputVariables, booleanExpression); + if(output != null) { + createBooleanPrompt(booleanInputVariables, booleanExpression, output, scope); + } + } + else if ((inputList.length == 0 || outputList.length == 0) && booleanInputVariables == 0) { + alert('Enter Input / Output Variable(s) OR Boolean Function!'); + } + else { + alert('Use Either Combinational Analysis Or Boolean Function To Generate Circuit!'); + } +}; -/** - * The prompt for combinational analysis - * @param {Scope=} - the circuit in which we want combinational analysis - * @category combinationalAnalysis - */ -export function createCombinationalAnalysisPrompt(scope = globalScope) { - scheduleBackup() - SimulatorStore().dialogBox.combinationalanalysis_dialog = true - /* - $('#combinationalAnalysis').empty() - $('#combinationalAnalysis').append( - "

Enter Input names separated by commas:

" - ) - $('#combinationalAnalysis').append( - "

Enter Output names separated by commas:

" - ) - $('#combinationalAnalysis').append("

OR

") - $('#combinationalAnalysis').append( - "

Enter Boolean Function:

" - ) - $('#combinationalAnalysis').append( - "" - ) - $('#combinationalAnalysis').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - style: 'padding: 5px', - text: 'Next', - click() { - var inputList = stripTags($('#inputNameList').val()).split( - ',' - ) - var outputList = stripTags( - $('#outputNameList').val() - ).split(',') - var booleanExpression = $('#booleanExpression').val() - inputList = inputList.map((x) => x.trim()) - inputList = inputList.filter((e) => e) - outputList = outputList.map((x) => x.trim()) - outputList = outputList.filter((e) => e) - booleanExpression = booleanExpression.replace(/ /g, '') - booleanExpression = booleanExpression.toUpperCase() - var booleanInputVariables = [] - for (var i = 0; i < booleanExpression.length; i++) { - if ( - booleanExpression[i] >= 'A' && - booleanExpression[i] <= 'Z' - ) { - if ( - booleanExpression.indexOf( - booleanExpression[i] - ) == i - ) { - booleanInputVariables.push(booleanExpression[i]) - } - } - } - booleanInputVariables.sort() - if ( - inputList.length > 0 && - outputList.length > 0 && - booleanInputVariables.length == 0 - ) { - $(this).dialog('close') - createBooleanPrompt(inputList, outputList, null, scope) - } else if ( - booleanInputVariables.length > 0 && - inputList.length == 0 && - outputList.length == 0 - ) { - $(this).dialog('close') - var output = solveBooleanFunction( - booleanInputVariables, - booleanExpression - ) - if (output != null) { - createBooleanPrompt( - booleanInputVariables, - booleanExpression, - output, - scope - ) - } - } else if ( - (inputList.length == 0 || outputList.length == 0) && - booleanInputVariables == 0 - ) { - alert( - 'Enter Input / Output Variable(s) OR Boolean Function!' - ) - } else { - alert( - 'Use Either Combinational Analysis Or Boolean Function To Generate Circuit!' - ) - } - }, - }, - ], - }) - - $('#combinationalAnalysis').checkBo() - */ -} -// /** -// * This funciton hashes the output array and makes required JSON using -// * a BooleanMinimize class defined in Quin_Mcluskey.js var s which will -// * be output table is also initialied here -// * @param {Array} inputListNames - labels of input nodes -// * @param {Array} outputListNames - labels of output nodes -// * @param {Scope=} scope - h circuit -// * @category combinationalAnalysis -// */ -/* - function createBooleanPrompt( - inputListNames, - outputListNames, - output, - scope = globalScope - ) { - var inputListNames = - inputListNames || prompt('Enter inputs separated by commas').split(',') - var outputListNames = - outputListNames || - prompt('Enter outputs separated by commas').split(',') - var outputListNamesInteger = [] - if (output == null) { - for (var i = 0; i < outputListNames.length; i++) { - outputListNamesInteger[i] = 7 * i + 13 - } // assigning an integer to the value, 7*i + 13 is random - } else { - outputListNamesInteger = [13] - } - var s = '' - s += '' - s += '' - if ($('#decimalColumnBox').is(':checked')) { - s += '' - } - for (var i = 0; i < inputListNames.length; i++) { - s += `` - } - if (output == null) { - for (var i = 0; i < outputListNames.length; i++) { - s += `` - } - } else { - s += `` - } - s += '' - - var matrix = [] - for (var i = 0; i < inputListNames.length; i++) { - matrix[i] = new Array(1 << inputListNames.length) - } - - for (var i = 0; i < inputListNames.length; i++) { - for (var j = 0; j < 1 << inputListNames.length; j++) { - matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) - } - } - - for (var j = 0; j < 1 << inputListNames.length; j++) { - s += '' - if ($('#decimalColumnBox').is(':checked')) { - s += `` - } - for (var i = 0; i < inputListNames.length; i++) { - s += `` - } - for (var i = 0; i < outputListNamesInteger.length; i++) { - if (output == null) { - s += - `' - // using hash values as they'll be used in the generateBooleanTableData function - } - } - if (output != null) { - s += - `' - } - s += '' - } - s += '' - s += '
' + 'dec' + '${inputListNames[i]}${outputListNames[i]}${outputListNames}
${j}${matrix[i][j]}` + - 'x' + - '` + - `${output[j]}` + - '
' - $('#combinationalAnalysis').empty() - $('#combinationalAnalysis').append(s) - $('#combinationalAnalysis').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - style: 'padding: 6px', - text: 'Generate Circuit', - click() { - $(this).dialog('close') - var data = generateBooleanTableData(outputListNamesInteger) - // passing the hash values to avoid spaces being passed which is causing a problem - var minimizedCircuit = [] - let inputCount = inputListNames.length - for (const output in data) { - let oneCount = data[output][1].length // Number of ones - let zeroCount = data[output][0].length // Number of zeroes - if (oneCount == 0) { - // Hardcode to 0 as output - minimizedCircuit.push([ - '-'.repeat(inputCount) + '0', - ]) - } else if (zeroCount == 0) { - // Hardcode to 1 as output - minimizedCircuit.push([ - '-'.repeat(inputCount) + '1', - ]) - } else { - // Perform KMap like minimzation - const temp = new BooleanMinimize( - inputListNames.length, - data[output][1].map(Number), - data[output].x.map(Number) - ) - minimizedCircuit.push(temp.result) - } - } - if (output == null) { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames, - outputListNames, - scope - ) - } else { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames, - [`${outputListNames}`], - scope - ) - } - }, - }, - { - style: 'padding: 6px', - text: 'Print Truth Table', - click() { - var sTable = document.getElementById( - 'combinationalAnalysis' - ).innerHTML - var style = - '' - var win = window.open('', '', 'height=700,width=700') - var htmlBody = ` - \ - Boolean Logic Table\ - ${style}\ - \ - \ -
${sTable}
\ - - ` - win.document.write(htmlBody) - win.document.close() - win.print() - }, - }, - ], - }) - - $('.output').on('click', function () { - var v = $(this).html() - if (v == 0) v = $(this).html(1) - else if (v == 1) v = $(this).html('x') - else if (v == 'x') v = $(this).html(0) - }) - } -*/ - -// function generateBooleanTableData(outputListNames) { -// var data = {} -// for (var i = 0; i < outputListNames.length; i++) { -// data[outputListNames[i]] = { -// x: [], -// 1: [], -// 0: [], -// } -// var rows = $(`.${outputListNames[i]}`) -// for (let j = 0; j < rows.length; j++) { -// data[outputListNames[i]][rows[j].innerHTML].push(rows[j].id) -// } -// } -// return data -// } - -// function drawCombinationalAnalysis( -// combinationalData, -// inputList, -// outputListNames, -// scope = globalScope -// ) { -// findDimensions(scope) -// var inputCount = inputList.length -// var maxTerms = 0 -// for (var i = 0; i < combinationalData.length; i++) { -// maxTerms = Math.max(maxTerms, combinationalData[i].length) -// } +export const GenerateCircuit = (outputListNamesInteger, inputListNames, output, outputListNames, scope = globalScope) => { + var data = generateBooleanTableData(outputListNamesInteger); + // passing the hash values to avoid spaces being passed which is causing a problem + var minimizedCircuit = []; + let inputCount = inputListNames.length; + for (const output in data) { + let oneCount = data[output][1].length; // Number of ones + let zeroCount = data[output][0].length; // Number of zeroes + if(oneCount == 0) { + // Hardcode to 0 as output + minimizedCircuit.push(['-'.repeat(inputCount) + '0']); + } + else if(zeroCount == 0) { + // Hardcode to 1 as output + minimizedCircuit.push(['-'.repeat(inputCount) + '1']); + } + else { + // Perform KMap like minimzation + const temp = new BooleanMinimize( + inputListNames.length, + data[output][1].map(Number), + data[output].x.map(Number), + ); + minimizedCircuit.push(temp.result); + } + } + if (output == null) { + drawCombinationalAnalysis(minimizedCircuit, inputListNames, outputListNames, scope); + } + else { + drawCombinationalAnalysis(minimizedCircuit, inputListNames, [`${outputListNames}`], scope); + } +}; -// var startPosX = 200 -// var startPosY = 200 - -// var currentPosY = 300 - -// if (simulationArea.maxWidth && simulationArea.maxHeight) { -// if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { -// startPosX += simulationArea.maxWidth -// } else { -// startPosY += simulationArea.maxHeight -// currentPosY += simulationArea.maxHeight -// } -// } -// var andPosX = startPosX + inputCount * 40 + 40 + 40 -// var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80 -// var outputPosX = orPosX + 60 -// var inputObjects = [] +function generateBooleanTableData(outputListNames) { + var data = {}; + for (var i = 0; i < outputListNames.length; i++) { + data[outputListNames[i]] = { + x: [], + 1: [], + 0: [], + }; + var rows = $(`.${outputListNames[i]}`); + for (let j = 0; j < rows.length; j++) { + data[outputListNames[i]][rows[j].innerHTML].push(rows[j].id); + } + } + return data; +} -// var logixNodes = [] +function drawCombinationalAnalysis(combinationalData, inputList, outputListNames, scope = globalScope) { + findDimensions(scope); + var inputCount = inputList.length; + var maxTerms = 0; + for (var i = 0; i < combinationalData.length; i++) { maxTerms = Math.max(maxTerms, combinationalData[i].length); } -// // Appending constant input to the end of inputObjects -// for (var i = 0; i <= inputCount; i++) { -// if (i < inputCount) { -// // Regular Input -// inputObjects.push( -// new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1) -// ) -// inputObjects[i].setLabel(inputList[i]) -// } else { -// // Constant Input -// inputObjects.push( -// new ConstantVal( -// startPosX + i * 40, -// startPosY, -// scope, -// 'DOWN', -// 1, -// '1' -// ) -// ) -// inputObjects[i].setLabel('_C_') -// } + var startPosX = 200; + var startPosY = 200; -// inputObjects[i].newLabelDirection('UP') -// var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root) -// inputObjects[i].output1.connect(v1) -// var v2 = new Node( -// startPosX + i * 40 + 20, -// startPosY + 20, -// 2, -// scope.root -// ) -// v1.connect(v2) -// var notG = new NotGate( -// startPosX + i * 40 + 20, -// startPosY + 40, -// scope, -// 'DOWN', -// 1 -// ) -// notG.inp1.connect(v2) -// logixNodes.push(v1) -// logixNodes.push(notG.output1) -// } + var currentPosY = 300; -// function countTerm(s) { -// var c = 0 -// for (var i = 0; i < s.length; i++) { -// if (s[i] !== '-') c++ -// } -// return c -// } + if (simulationArea.maxWidth && simulationArea.maxHeight) { + if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { + startPosX += simulationArea.maxWidth; + } else { + startPosY += simulationArea.maxHeight; + currentPosY += simulationArea.maxHeight; + } + } + var andPosX = startPosX + inputCount * 40 + 40 + 40; + var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80; + var outputPosX = orPosX + 60; + var inputObjects = []; -// for (var i = 0; i < combinationalData.length; i++) { -// var andGateNodes = [] -// for (var j = 0; j < combinationalData[i].length; j++) { -// var c = countTerm(combinationalData[i][j]) -// if (c > 1) { -// var andGate = new AndGate( -// andPosX, -// currentPosY, -// scope, -// 'RIGHT', -// c, -// 1 -// ) -// andGateNodes.push(andGate.output1) -// var misses = 0 -// for (var k = 0; k < combinationalData[i][j].length; k++) { -// if (combinationalData[i][j][k] == '-') { -// misses++ -// continue -// } -// var index = 2 * k + (combinationalData[i][j][k] == 0) -// var v = new Node( -// logixNodes[index].absX(), -// andGate.inp[k - misses].absY(), -// 2, -// scope.root -// ) -// logixNodes[index].connect(v) -// logixNodes[index] = v -// v.connect(andGate.inp[k - misses]) -// } -// } else { -// for (var k = 0; k < combinationalData[i][j].length; k++) { -// if (combinationalData[i][j][k] == '-') continue -// var index = 2 * k + (combinationalData[i][j][k] == 0) -// var andGateSubstituteNode = new Node( -// andPosX, -// currentPosY, -// 2, -// scope.root -// ) -// var v = new Node( -// logixNodes[index].absX(), -// andGateSubstituteNode.absY(), -// 2, -// scope.root -// ) -// logixNodes[index].connect(v) -// logixNodes[index] = v -// v.connect(andGateSubstituteNode) -// andGateNodes.push(andGateSubstituteNode) -// } -// } -// currentPosY += c * 10 + 30 -// } + var logixNodes = []; -// var andGateCount = andGateNodes.length -// var midWay = Math.floor(andGateCount / 2) -// var orGatePosY = -// (andGateNodes[midWay].absY() + -// andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / -// 2 -// if (orGatePosY % 10 == 5) { -// orGatePosY += 5 -// } // To make or gate fall in grid -// if (andGateCount > 1) { -// var o = new OrGate( -// orPosX, -// orGatePosY, -// scope, -// 'RIGHT', -// andGateCount, -// 1 -// ) -// if (andGateCount % 2 == 1) -// andGateNodes[midWay].connect(o.inp[midWay]) -// for (var j = 0; j < midWay; j++) { -// var v = new Node( -// andPosX + 30 + (midWay - j) * 10, -// andGateNodes[j].absY(), -// 2, -// scope.root -// ) -// v.connect(andGateNodes[j]) -// var v2 = new Node( -// andPosX + 30 + (midWay - j) * 10, -// o.inp[j].absY(), -// 2, -// scope.root -// ) -// v2.connect(v) -// o.inp[j].connect(v2) + // Appending constant input to the end of inputObjects + for (var i = 0; i <= inputCount; i++) { + if(i < inputCount) { + // Regular Input + inputObjects.push(new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1)); + inputObjects[i].setLabel(inputList[i]); + } + else { + // Constant Input + inputObjects.push(new ConstantVal(startPosX + i * 40, startPosY, scope, 'DOWN', 1, '1')); + inputObjects[i].setLabel('_C_'); + } -// var v = new Node( -// andPosX + 30 + (midWay - j) * 10, -// andGateNodes[andGateCount - j - 1].absY(), -// 2, -// scope.root -// ) -// v.connect(andGateNodes[andGateCount - j - 1]) -// var v2 = new Node( -// andPosX + 30 + (midWay - j) * 10, -// o.inp[andGateCount - j - 1].absY(), -// 2, -// scope.root -// ) -// v2.connect(v) -// o.inp[andGateCount - j - 1].connect(v2) -// } -// var out = new Output(outputPosX, o.y, scope, 'LEFT', 1) -// out.inp1.connect(o.output1) -// } else { -// var out = new Output( -// outputPosX, -// andGateNodes[0].absY(), -// scope, -// 'LEFT', -// 1 -// ) -// out.inp1.connect(andGateNodes[0]) -// } -// out.setLabel(outputListNames[i]) -// out.newLabelDirection('RIGHT') -// } -// for (var i = 0; i < logixNodes.length; i++) { -// if (logixNodes[i].absY() != currentPosY) { -// var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root) -// logixNodes[i].connect(v) -// } -// } -// globalScope.centerFocus() -// } + inputObjects[i].newLabelDirection('UP'); + var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root); + inputObjects[i].output1.connect(v1); + var v2 = new Node(startPosX + i * 40 + 20, startPosY + 20, 2, scope.root); + v1.connect(v2); + var notG = new NotGate(startPosX + i * 40 + 20, startPosY + 40, scope, 'DOWN', 1); + notG.inp1.connect(v2); + logixNodes.push(v1); + logixNodes.push(notG.output1); + } -// /** -// * This function solves passed boolean expression and returns -// * output array which contains solution of the truth table -// * of given boolean expression -// * @param {Array} inputListNames - labels for input nodes -// * @param {String} booleanExpression - boolean expression which is to be solved -// */ -// function solveBooleanFunction(inputListNames, booleanExpression) { -// let i -// let j -// let output = [] + function countTerm(s) { + var c = 0; + for (var i = 0; i < s.length; i++) { if (s[i] !== '-')c++; } + return c; + } -// if ( -// booleanExpression.match( -// /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g -// ) != null -// ) { -// alert('One of the characters is not allowed.') -// return -// } + for (var i = 0; i < combinationalData.length; i++) { + var andGateNodes = []; + for (var j = 0; j < combinationalData[i].length; j++) { + var c = countTerm(combinationalData[i][j]); + if (c > 1) { + var andGate = new AndGate(andPosX, currentPosY, scope, 'RIGHT', c, 1); + andGateNodes.push(andGate.output1); + var misses = 0; + for (var k = 0; k < combinationalData[i][j].length; k++) { + if (combinationalData[i][j][k] == '-') { misses++; continue; } + var index = 2 * k + (combinationalData[i][j][k] == 0); + var v = new Node(logixNodes[index].absX(), andGate.inp[k - misses].absY(), 2, scope.root); + logixNodes[index].connect(v); + logixNodes[index] = v; + v.connect(andGate.inp[k - misses]); + } + } else { + for (var k = 0; k < combinationalData[i][j].length; k++) { + if (combinationalData[i][j][k] == '-') continue; + var index = 2 * k + (combinationalData[i][j][k] == 0); + var andGateSubstituteNode = new Node(andPosX, currentPosY, 2, scope.root); + var v = new Node(logixNodes[index].absX(), andGateSubstituteNode.absY(), 2, scope.root); + logixNodes[index].connect(v); + logixNodes[index] = v; + v.connect(andGateSubstituteNode); + andGateNodes.push(andGateSubstituteNode); + } + } + currentPosY += c * 10 + 30; + } -// if (inputListNames.length > 8) { -// alert('You can only have 8 variables at a time.') -// return -// } + var andGateCount = andGateNodes.length; + var midWay = Math.floor(andGateCount / 2); + var orGatePosY = (andGateNodes[midWay].absY() + andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / 2; + if (orGatePosY % 10 == 5) { orGatePosY += 5; } // To make or gate fall in grid + if (andGateCount > 1) { + var o = new OrGate(orPosX, orGatePosY, scope, 'RIGHT', andGateCount, 1); + if (andGateCount % 2 == 1)andGateNodes[midWay].connect(o.inp[midWay]); + for (var j = 0; j < midWay; j++) { + var v = new Node(andPosX + 30 + (midWay - j) * 10, andGateNodes[j].absY(), 2, scope.root); + v.connect(andGateNodes[j]); + var v2 = new Node(andPosX + 30 + (midWay - j) * 10, o.inp[j].absY(), 2, scope.root); + v2.connect(v); + o.inp[j].connect(v2); -// var s = '' -// s += '' -// s += '' -// if ($('#decimalColumnBox').is(':checked')) { -// s += '' -// } -// for (i = 0; i < inputListNames.length; i++) { -// s += `` -// } -// s += `` -// s += '' -// var matrix = [] -// for (i = 0; i < inputListNames.length; i++) { -// matrix[i] = new Array(inputListNames.length) -// } + var v = new Node(andPosX + 30 + (midWay - j) * 10, andGateNodes[andGateCount - j - 1].absY(), 2, scope.root); + v.connect(andGateNodes[andGateCount - j - 1]); + var v2 = new Node(andPosX + 30 + (midWay - j) * 10, o.inp[andGateCount - j - 1].absY(), 2, scope.root); + v2.connect(v); + o.inp[andGateCount - j - 1].connect(v2); + } + var out = new Output(outputPosX, o.y, scope, 'LEFT', 1); + out.inp1.connect(o.output1); + } else { + var out = new Output(outputPosX, andGateNodes[0].absY(), scope, 'LEFT', 1); + out.inp1.connect(andGateNodes[0]); + } + out.setLabel(outputListNames[i]); + out.newLabelDirection('RIGHT'); + } + for (var i = 0; i < logixNodes.length; i++) { + if (logixNodes[i].absY() != currentPosY) { + var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root); + logixNodes[i].connect(v); + } + } + globalScope.centerFocus(); +} -// for (i = 0; i < inputListNames.length; i++) { -// for (j = 0; j < 1 << inputListNames.length; j++) { -// matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) -// } -// } -// // generate equivalent expression by replacing input vars with possible combinations of o and 1 -// for (i = 0; i < 2 ** inputListNames.length; i++) { -// const data = [] -// for (j = 0; j < inputListNames.length; j++) { -// data[j] = -// Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 -// } -// let equation = booleanExpression -// for (j = 0; j < inputListNames.length; j++) { -// equation = equation.replace( -// new RegExp(inputListNames[j], 'g'), -// data[j] -// ) -// } +/** + * This function solves passed boolean expression and returns + * output array which contains solution of the truth table + * of given boolean expression + * @param {Array} inputListNames - labels for input nodes + * @param {String} booleanExpression - boolean expression which is to be solved + */ +export function solveBooleanFunction(inputListNames, booleanExpression) { + let i + let j + output.value = [] -// output[i] = solve(equation) -// } + if ( + booleanExpression.match( + /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g + ) != null + ) { + // alert('One of the characters is not allowed.') + confirmSingleOption('One of the characters is not allowed.') + return + } -// for (j = 0; j < 1 << inputListNames.length; j++) { -// s += '' -// if ($('#decimalColumnBox').is(':checked')) { -// s += `` -// } -// for (i = 0; i < inputListNames.length; i++) { -// s += `` -// } + if (inputListNames.length > 8) { + // alert('You can only have 8 variables at a time.') + confirmSingleOption('You can only have 8 variables at a time.') + return + } + var matrix = [] + for (i = 0; i < inputListNames.length; i++) { + matrix[i] = new Array(inputListNames.length) + } -// s += `' -// s += '' -// } + for (i = 0; i < inputListNames.length; i++) { + for (j = 0; j < 1 << inputListNames.length; j++) { + matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) + } + } + // generate equivalent expression by replacing input vars with possible combinations of o and 1 + for (i = 0; i < 2 ** inputListNames.length; i++) { + const data = [] + for (j = 0; j < inputListNames.length; j++) { + data[j] = + Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 + } + let equation = booleanExpression + for (j = 0; j < inputListNames.length; j++) { + equation = equation.replace( + new RegExp(inputListNames[j], 'g'), + data[j] + ) + } -// s += '' -// s += '
' + 'dec' + '${inputListNames[i]}${booleanExpression}
${j}${matrix[i][j]}` + `${output[j]}` + '
' -// // generates solution for the truth table of booleanexpression -// function solve(equation) { -// while (equation.indexOf('(') != -1) { -// const start = equation.lastIndexOf('(') -// const end = equation.indexOf(')', start) -// if (start != -1) { -// equation = -// equation.substring(0, start) + -// solve(equation.substring(start + 1, end)) + -// equation.substring(end + 1) -// } -// } -// equation = equation.replace(/''/g, '') -// equation = equation.replace(/0'/g, '1') -// equation = equation.replace(/1'/g, '0') -// for (let i = 0; i < equation.length - 1; i++) { -// if ( -// (equation[i] == '0' || equation[i] == '1') && -// (equation[i + 1] == '0' || equation[i + 1] == '1') -// ) { -// equation = -// equation.substring(0, i + 1) + -// '*' + -// equation.substring(i + 1, equation.length) -// } -// } -// try { -// const safeEval = eval -// const answer = safeEval(equation) -// if (answer == 0) { -// return 0 -// } -// if (answer > 0) { -// return 1 -// } -// return '' -// } catch (e) { -// return '' -// } -// } + output.value[i] = solve(equation) + } + // generates solution for the truth table of booleanexpression + function solve(equation) { + while (equation.indexOf('(') != -1) { + const start = equation.lastIndexOf('(') + const end = equation.indexOf(')', start) + if (start != -1) { + equation = + equation.substring(0, start) + + solve(equation.substring(start + 1, end)) + + equation.substring(end + 1) + } + } + equation = equation.replace(/''/g, '') + equation = equation.replace(/0'/g, '1') + equation = equation.replace(/1'/g, '0') + for (let i = 0; i < equation.length - 1; i++) { + if ( + (equation[i] == '0' || equation[i] == '1') && + (equation[i + 1] == '0' || equation[i + 1] == '1') + ) { + equation = + equation.substring(0, i + 1) + + '*' + + equation.substring(i + 1, equation.length) + } + } + try { + const safeEval = eval + const answer = safeEval(equation) + if (answer == 0) { + return 0 + } + if (answer > 0) { + return 1 + } + return '' + } catch (e) { + return '' + } + } +} -// return output -// } +export function createCombinationalAnalysisPrompt(scope = globalScope) { + scheduleBackup() + SimulatorStore().dialogBox.combinationalanalysis_dialog = true +} diff --git a/v0/src/simulator/src/contention.ts b/v0/src/simulator/src/contention.ts new file mode 100644 index 00000000..23c5ee24 --- /dev/null +++ b/v0/src/simulator/src/contention.ts @@ -0,0 +1,123 @@ +/** + * Represents a node with bitWidth and value properties + */ +interface Node { + bitWidth: number; + value: number | undefined; + } + + /** + * @class ContentionPendingData + * + * Data structure to store pending contentions in the circuit. + */ + export default class ContentionPendingData { + private contentionPendingMap: Map>; + private totalContentions: number; + + constructor() { + this.contentionPendingMap = new Map>(); + this.totalContentions = 0; + } + + /** + * Adds a contention between two nodes + * @param ourNode The source node + * @param theirNode The target node + */ + add(ourNode: Node, theirNode: Node): void { + if (this.contentionPendingMap.has(ourNode)) { + const existingSet = this.contentionPendingMap.get(ourNode)!; + if (!existingSet.has(theirNode)) this.totalContentions++; + existingSet.add(theirNode); + return; + } + + this.totalContentions++; + this.contentionPendingMap.set(ourNode, new Set([theirNode])); + } + + /** + * Checks if a node has any pending contentions + * @param ourNode The node to check + * @returns Whether the node has contentions + */ + has(ourNode: Node): boolean { + return this.contentionPendingMap.has(ourNode); + } + + /** + * Removes a specific contention entry + * @param ourNode The source node + * @param theirNode The target node + */ + remove(ourNode: Node, theirNode: Node): void { + if (!this.contentionPendingMap.has(ourNode) || + !this.contentionPendingMap.get(ourNode)!.has(theirNode)) return; + + this.contentionPendingMap.get(ourNode)!.delete(theirNode); + if (this.contentionPendingMap.get(ourNode)!.size === 0) { + this.contentionPendingMap.delete(ourNode); + } + this.totalContentions--; + } + + /** + * Removes all contentions for a specific node + * @param ourNode The node to remove contentions for + */ + removeAllContentionsForNode(ourNode: Node): void { + if (!this.contentionPendingMap.has(ourNode)) return; + + const contentionsForOurNode = this.contentionPendingMap.get(ourNode)!; + for (const theirNode of contentionsForOurNode) { + this.remove(ourNode, theirNode); + } + } + + /** + * Removes a contention if the nodes are resolved + * @param ourNode The source node + * @param theirNode The target node + */ + removeIfResolved(ourNode: Node, theirNode: Node): void { + if (ourNode.bitWidth === theirNode.bitWidth && + (ourNode.value === theirNode.value || ourNode.value === undefined)) { + this.remove(ourNode, theirNode); + } + } + + /** + * Removes resolved contentions for a specific node + * @param ourNode The node to check for resolved contentions + */ + removeIfResolvedAllContentionsForNode(ourNode: Node): void { + if (!this.contentionPendingMap.has(ourNode)) return; + + const contentionsForOurNode = this.contentionPendingMap.get(ourNode)!; + for (const theirNode of contentionsForOurNode) { + this.removeIfResolved(ourNode, theirNode); + } + } + + /** + * @returns Total number of contentions + */ + size(): number { + return this.totalContentions; + } + + /** + * @returns List of all contention pairs + */ + nodes(): [Node, Node][] { + const items: [Node, Node][] = []; + for (const [ourNode, contentionSet] of this.contentionPendingMap) { + for (const theirNode of contentionSet) { + items.push([ourNode, theirNode]); + } + } + + return items; + } + } \ No newline at end of file diff --git a/v0/src/simulator/src/data.js b/v0/src/simulator/src/data.js index 4e573c21..bb9df0e7 100644 --- a/v0/src/simulator/src/data.js +++ b/v0/src/simulator/src/data.js @@ -10,16 +10,11 @@ import { openOffline, recoverProject, } from './data/project' -import { newCircuit, createNewCircuitScope } from './circuit' +import { createNewCircuitScope } from './circuit' import { createCombinationalAnalysisPrompt } from './combinationalAnalysis' import { colorThemes } from './themer/themer' import { showTourGuide } from './tutorials' -import { - createVerilogCircuit, - // saveVerilogCode, - // resetVerilogCode, - // applyVerilogTheme, -} from './Verilog2CV' +import { createVerilogCircuit } from './Verilog2CV' import { generateVerilog } from './verilog' import { bitConverterDialog } from './utils' import { keyBinder } from '#/components/DialogBox/CustomShortcut.vue' @@ -33,7 +28,6 @@ logixFunction.createSaveAsImgPrompt = createSaveAsImgPrompt logixFunction.clearProject = clearProject logixFunction.newProject = newProject logixFunction.saveOffline = saveOffline -// logixFunction.newCircuit = newCircuit logixFunction.createOpenLocalPrompt = openOffline logixFunction.recoverProject = recoverProject logixFunction.createSubCircuitPrompt = createSubCircuitPrompt @@ -43,12 +37,9 @@ logixFunction.fullViewOption = fullView logixFunction.colorThemes = colorThemes logixFunction.showTourGuide = showTourGuideHelper logixFunction.newVerilogModule = createVerilogCircuit -// logixFunction.saveVerilogCode = saveVerilogCode -// logixFunction.resetVerilogCode = resetVerilogCode logixFunction.generateVerilog = generateVerilog -// logixFunction.applyVerilogTheme = applyVerilogTheme logixFunction.bitconverter = bitConverterDialog -logixFunction.createNewCircuitScope = createNewCircuitScope +logixFunction.createNewCircuitScope = createNewCircuit logixFunction.customShortcut = keyBinder logixFunction.ExportProject = ExportProject logixFunction.ImportProject = ImportProject @@ -60,3 +51,8 @@ function showTourGuideHelper() { showTourGuide() }, 100) } + +// Hack to call createNewCircuitScope with keyboard shortcut +function createNewCircuit() { + createNewCircuitScope() +} diff --git a/v0/src/simulator/src/data/backupCircuit.js b/v0/src/simulator/src/data/backupCircuit.js index c17a93c3..e15f5e44 100644 --- a/v0/src/simulator/src/data/backupCircuit.js +++ b/v0/src/simulator/src/data/backupCircuit.js @@ -1,4 +1,6 @@ import { projectSavedSet } from './project' +import { moduleList, updateOrder } from '../metadata' + /* eslint-disable no-param-reassign */ function extract(obj) { return obj.saveObject() diff --git a/v0/src/simulator/src/data/load.js b/v0/src/simulator/src/data/load.js index f9d7b89b..1bc51e65 100644 --- a/v0/src/simulator/src/data/load.js +++ b/v0/src/simulator/src/data/load.js @@ -8,7 +8,7 @@ import { gridUpdateSet, } from '../engine' import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { loadSubCircuit } from '../subcircuit' import { scheduleBackup } from './backupCircuit' @@ -18,9 +18,11 @@ import { generateId } from '../utils' import modules from '../modules' import { oppositeDirection } from '../canvasApi' import plotArea from '../plotArea' -import { updateTestbenchUI, TestbenchData } from '../testbench' +import { TestbenchData } from '#/simulator/src/testbench' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' import { toRefs } from 'vue' +import { moduleList } from '../metadata' + /** * Backward compatibility - needs to be deprecated * @param {CircuitElement} obj - the object to be rectified @@ -282,9 +284,6 @@ export default function load(data) { // Switch to last focussedCircuit if (data.focussedCircuit) switchCircuit(String(data.focussedCircuit)) - // Update the testbench UI - updateTestbenchUI() - updateSimulationSet(true) updateCanvasSet(true) gridUpdateSet(true) diff --git a/v0/src/simulator/src/data/project.js b/v0/src/simulator/src/data/project.ts similarity index 86% rename from v0/src/simulator/src/data/project.js rename to v0/src/simulator/src/data/project.ts index 5a88fdd5..71d244b7 100644 --- a/v0/src/simulator/src/data/project.js +++ b/v0/src/simulator/src/data/project.ts @@ -17,7 +17,8 @@ import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComp */ export async function recoverProject() { if (localStorage.getItem('recover')) { - var data = JSON.parse(localStorage.getItem('recover')) + const recover = localStorage.getItem('recover') + const data = recover ? JSON.parse(recover) : {} if (await confirmOption(`Would you like to recover: ${data.name}`)) { load(data) } @@ -78,11 +79,10 @@ export function openOffline() { } /** * Flag for project saved or not - * @type {boolean} * @category data */ -var projectSaved = true -export function projectSavedSet(param) { +let projectSaved = true +export function projectSavedSet(param: boolean) { projectSaved = param } @@ -91,10 +91,11 @@ export function projectSavedSet(param) { * @category data */ export async function saveOffline() { - const data = await generateSaveData() + const data = await generateSaveData('') if (data instanceof Error) return localStorage.setItem(projectId, data) - const temp = JSON.parse(localStorage.getItem('projectList')) || {} + const projectList = localStorage.getItem('projectList') + const temp = projectList ? JSON.parse(projectList) : {} temp[projectId] = getProjectName() localStorage.setItem('projectList', JSON.stringify(temp)) showMessage( @@ -109,8 +110,8 @@ export async function saveOffline() { function checkToSave() { let saveFlag = false // eslint-disable-next-line no-restricted-syntax - for (id in scopeList) { - saveFlag |= checkIfBackup(scopeList[id]) + for (const id in scopeList) { + saveFlag = saveFlag || checkIfBackup(scopeList[id]) } return saveFlag } @@ -131,14 +132,14 @@ window.onbeforeunload = async function () { // 'You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?' // ) const data = await generateSaveData('Untitled') - localStorage.setItem('recover', await data) + const stringData = JSON.stringify(data) + localStorage.setItem('recover', stringData) // eslint-disable-next-line consistent-return return 'Are u sure u want to leave? Any unsaved changes may not be recoverable' } /** * Function to clear project - * @category data */ export async function clearProject() { if (await confirmOption('Would you like to clear the project?')) { @@ -152,10 +153,8 @@ export async function clearProject() { /** Function used to start a new project while prompting confirmation from the user - * @param {boolean} verify - flag to verify a new project - * @category data */ -export async function newProject(verify) { +export async function newProject(verify: boolean) { if ( verify || projectSaved || @@ -166,7 +165,8 @@ export async function newProject(verify) { ) { clearProject() localStorage.removeItem('recover') - window.location = '/simulator' + const baseUrl = window.location.origin !== 'null' ? window.location.origin : 'http://localhost:4000'; + window.location.assign(`${baseUrl}/simulatorvue/`); setProjectName(undefined) projectId = generateId() diff --git a/v0/src/simulator/src/data/redo.js b/v0/src/simulator/src/data/redo.js deleted file mode 100644 index bc252a98..00000000 --- a/v0/src/simulator/src/data/redo.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable import/no-cycle */ -/** - * Function to restore copy from backup - * @param {Scope=} scope - The circuit on which redo is called - * @category data - */ -import { layoutModeGet } from '../layoutMode' -import Scope, { scopeList } from '../circuit' -import { loadScope } from './load' -import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import { forceResetNodesSet } from '../engine' -/** - * Function called to generate a prompt to save an image - * @param {Scope=} - the circuit in which we want to call redo - * @category data - * @exports redo - */ -export default function redo(scope = globalScope) { - if (layoutModeGet()) return - if (scope.history.length === 0) return - const backupOx = globalScope.ox - const backupOy = globalScope.oy - const backupScale = globalScope.scale - globalScope.ox = 0 - globalScope.oy = 0 - const tempScope = new Scope(scope.name) - loading = true - const redoData = scope.history.pop() - scope.backups.push(redoData) - loadScope(tempScope, JSON.parse(redoData)) - tempScope.backups = scope.backups - tempScope.history = scope.history - tempScope.id = scope.id - tempScope.name = scope.name - tempScope.testbenchData = scope.testbenchData - scopeList[scope.id] = tempScope - globalScope = tempScope - globalScope.ox = backupOx - globalScope.oy = backupOy - globalScope.scale = backupScale - loading = false - forceResetNodesSet(true) - - // Updated restricted elements - updateRestrictedElementsInScope() -} -// for html file diff --git a/v0/src/simulator/src/data/redo.ts b/v0/src/simulator/src/data/redo.ts new file mode 100644 index 00000000..67753db0 --- /dev/null +++ b/v0/src/simulator/src/data/redo.ts @@ -0,0 +1,76 @@ +/* eslint-disable import/no-cycle */ +import { layoutModeGet } from '../layoutMode'; +import Scope, { scopeList } from '../circuit'; +import { loadScope } from './load'; +import { updateRestrictedElementsInScope } from '../restrictedElementDiv'; +import { forceResetNodesSet } from '../engine'; + +// Extend the Scope type to include missing properties +interface ExtendedScope extends Scope { + testbenchData: any; + ox: number; + oy: number; + scale: number; + history: string[]; + backups: string[]; + name: string; + id: string | number; +} + +// Type declarations for global variables +declare var globalScope: ExtendedScope; +declare var loading: boolean; + +/** + * Function to restore copy from backup + * @param {ExtendedScope=} scope - The circuit on which redo is called + * @category data + */ +export default function redo(scope: ExtendedScope = globalScope): void { + if (layoutModeGet()) return; + if (scope.history.length === 0) return; + + // Store the current view state + const backupOx: number = globalScope.ox; + const backupOy: number = globalScope.oy; + const backupScale: number = globalScope.scale; + + // Reset the view position + globalScope.ox = 0; + globalScope.oy = 0; + + // Create a temporary scope + const tempScope: ExtendedScope = new Scope(scope.name) as ExtendedScope; + loading = true; + + // Get the redo data and update history + const redoData: string = scope.history.pop()!; + scope.backups.push(redoData); + + // Load the scope data + loadScope(tempScope, JSON.parse(redoData)); + + // Transfer persistent properties + tempScope.backups = scope.backups; + tempScope.history = scope.history; + tempScope.id = scope.id; + tempScope.name = scope.name; + tempScope.testbenchData = scope.testbenchData; + + // Update the scope list + scopeList[scope.id] = tempScope; + + // Update global scope + globalScope = tempScope; + + // Restore view state + globalScope.ox = backupOx; + globalScope.oy = backupOy; + globalScope.scale = backupScale; + + loading = false; + forceResetNodesSet(true); + + // Update restricted elements + updateRestrictedElementsInScope(); +} \ No newline at end of file diff --git a/v0/src/simulator/src/data/save.js b/v0/src/simulator/src/data/save.js index e32090a6..ecc38eb4 100644 --- a/v0/src/simulator/src/data/save.js +++ b/v0/src/simulator/src/data/save.js @@ -1,22 +1,23 @@ import { scopeList } from '../circuit' import { resetup } from '../setup' -import { update } from '../engine' +import { update, updateSubcircuitSet } from '../engine' import { stripTags, showMessage } from '../utils' import { backUp } from './backupCircuit' -import simulationArea from '../simulationArea' -import backgroundArea from '../backgroundArea' +import { simulationArea } from '../simulationArea' +import { backgroundArea } from '../backgroundArea' import { findDimensions } from '../canvasApi' import { projectSavedSet } from './project' import { colors } from '../themer/themer' import { layoutModeGet, toggleLayoutMode } from '../layoutMode' import { verilogModeGet } from '../Verilog2CV' import domtoimage from 'dom-to-image' -import '../../vendor/canvas2svg' +import canvasToSvg from "canvas-to-svg" import { useProjectStore } from '#/store/projectStore' import { provideProjectName } from '#/components/helpers/promptComponent/PromptComponent.vue' import { UpdateProjectDetail } from '#/components/helpers/createNewProject/UpdateProjectDetail.vue' import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' import { getToken } from '#/pages/simulatorHandler.vue' +import { renderOrder } from '../metadata' // var projectName = undefined @@ -68,7 +69,7 @@ function downloadAsImg(name, imgType) { export function getTabsOrder() { var tabs = document.getElementById('tabsBar').firstChild.children var order = [] - for (let i = 0; i < tabs.length; i++) { + for (let i = 0; i < tabs?.length; i++) { order.push(tabs[i].id) } return order @@ -98,7 +99,6 @@ export async function generateSaveData(name, setName = true) { data.timePeriod = simulationArea.timePeriod data.clockEnabled = simulationArea.clockEnabled data.projectId = projectId - data.simulatorVersion = "v0" data.focussedCircuit = globalScope.id data.orderedTabs = getTabsOrder() @@ -122,6 +122,13 @@ export async function generateSaveData(name, setName = true) { } completed[id] = true + + // This update is very important. + // if a scope's input/output changes and the user saves without going + // to circuits where this circuit is used as a subcircuit. It will + // break the code since the Subcircuit will have different number of + // in/out nodes compared to the localscope input/output objects. + updateSubcircuitSet(true); update(scopeList[id], true) // For any pending integrity checks on subcircuits data.scopes.push(backUp(scopeList[id])) } @@ -186,7 +193,7 @@ export function generateImage( // If SVG, create SVG context - using canvas2svg here if (imgType === 'svg') { - simulationArea.context = new C2S(width, height) + simulationArea.context = new canvasToSvg(width, height) resolution = 1 } else if (imgType !== 'png') { transparent = false @@ -237,7 +244,7 @@ export function generateImage( simulationArea.context.fill() } - // Draw circuits, why is it updateOrder and not renderOrder? + // Draw circuits for (let i = 0; i < renderOrder.length; i++) { for (let j = 0; j < scope[renderOrder[i]].length; j++) { scope[renderOrder[i]][j].draw() @@ -309,16 +316,16 @@ async function generateImageForOnline() { if (verilogModeGet()) { var node = document.getElementsByClassName('CodeMirror')[0] // var node = document.getElementsByClassName('CodeMirror')[0]; - var prevHeight = $(node).css('height') - var prevWidth = $(node).css('width') + var prevHeight = window.getComputedStyle(node).height + var prevWidth = window.getComputedStyle(node).width var baseWidth = 500 var baseHeight = Math.round(baseWidth / ratio) - $(node).css('height', baseHeight) - $(node).css('width', baseWidth) + node.style.height = baseHeight + 'px' + node.style.width = baseWidth + 'px' var data = await domtoimage.toJpeg(node) - $(node).css('width', prevWidth) - $(node).css('height', prevHeight) + node.style.width = prevWidth + node.style.height = prevHeight data = await crop(data, baseWidth, baseHeight) return data } @@ -359,14 +366,16 @@ export default async function save() { const data = await generateSaveData() if (data instanceof Error) return - $('.loadingIcon').fadeIn() + let loadingIcon = document.querySelector('.loadingIcon'); + loadingIcon.style.transition = 'opacity 0.5s linear'; + loadingIcon.style.opacity = '1'; const projectName = getProjectName() var imageData = await generateImageForOnline() const headers = { 'Content-Type': 'application/json', - 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'), + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'), Authorization: `Token ${getToken('cvt')}`, } @@ -380,7 +389,11 @@ export default async function save() { ) ) window.location.href = '/users/sign_in' - else $('.loadingIcon').fadeOut() + else { + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; + } // eslint-disable-next-line camelcase } else if ([0, undefined, null, '', '0'].includes(window.logixProjectId)) { // Create new project - this part needs to be improved and optimised @@ -433,7 +446,11 @@ export default async function save() { showMessage( `We have Created a new project: ${projectName} in our servers.` ) - $('.loadingIcon').fadeOut() + + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; + localStorage.removeItem('recover') const responseJson = response.json() responseJson.then((data) => { @@ -503,7 +520,9 @@ export default async function save() { "There was an error, we couldn't save to our servers" ) } - $('.loadingIcon').fadeOut() + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; }) .catch((error) => { console.error('Error:', error) diff --git a/v0/src/simulator/src/data/saveImage.js b/v0/src/simulator/src/data/saveImage.js deleted file mode 100644 index 8e2b813d..00000000 --- a/v0/src/simulator/src/data/saveImage.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Helper function to show prompt to save image - * Options - resolution, image type, view - * @param {Scope=} scope - useless though - * @category data - */ -import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' - -/** - * Function called to generate a prompt to save an image - * @category data - * @param {Scope=} - circuit whose image we want - * @exports createSaveAsImgPrompt - */ -export default function createSaveAsImgPrompt(scope = globalScope) { - const simulatorStore = SimulatorStore() - simulatorStore.dialogBox.saveimage_dialog = true -} diff --git a/v0/src/simulator/src/data/saveImage.ts b/v0/src/simulator/src/data/saveImage.ts new file mode 100644 index 00000000..cce91367 --- /dev/null +++ b/v0/src/simulator/src/data/saveImage.ts @@ -0,0 +1,16 @@ +import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore'; +import Scope from '../circuit'; + +// Type declaration for global variable +declare var globalScope: Scope; + +/** + * Function called to generate a prompt to save an image + * @category data + * @param {Scope=} scope - circuit whose image we want + * @exports createSaveAsImgPrompt + */ +export default function createSaveAsImgPrompt(scope: Scope = globalScope): void { + const simulatorStore = SimulatorStore(); + simulatorStore.dialogBox.saveimage_dialog = true; +} \ No newline at end of file diff --git a/v0/src/simulator/src/data/undo.js b/v0/src/simulator/src/data/undo.js deleted file mode 100644 index 67f22005..00000000 --- a/v0/src/simulator/src/data/undo.js +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable import/no-cycle */ -/** - * Function to restore copy from backup - * @param {Scope=} scope - The circuit on which undo is called - * @category data - */ -import { layoutModeGet } from '../layoutMode' -import Scope, { scopeList } from '../circuit' -import { loadScope } from './load' -import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import { forceResetNodesSet } from '../engine' -/** - * Function called to generate a prompt to save an image - * @param {Scope=} - the circuit in which we want to call undo - * @category data - * @exports undo - */ -export default function undo(scope = globalScope) { - if (layoutModeGet()) return - if (scope.backups.length < 2) return - const backupOx = globalScope.ox - const backupOy = globalScope.oy - const backupScale = globalScope.scale - globalScope.ox = 0 - globalScope.oy = 0 - const tempScope = new Scope(scope.name) - loading = true - const undoData = scope.backups.pop() - scope.history.push(undoData) - scope.backups.length !== 0 && - loadScope( - tempScope, - JSON.parse(scope.backups[scope.backups.length - 1]) - ) - tempScope.backups = scope.backups - tempScope.history = scope.history - tempScope.id = scope.id - tempScope.name = scope.name - tempScope.testbenchData = scope.testbenchData - scopeList[scope.id] = tempScope - globalScope = tempScope - globalScope.ox = backupOx - globalScope.oy = backupOy - globalScope.scale = backupScale - loading = false - forceResetNodesSet(true) - - // Updated restricted elements - updateRestrictedElementsInScope() -} -// for html file diff --git a/v0/src/simulator/src/data/undo.ts b/v0/src/simulator/src/data/undo.ts new file mode 100644 index 00000000..c2bf64b2 --- /dev/null +++ b/v0/src/simulator/src/data/undo.ts @@ -0,0 +1,82 @@ +/* eslint-disable import/no-cycle */ +import { layoutModeGet } from '../layoutMode' +import Scope, { scopeList } from '../circuit' +import { loadScope } from './load' +import { updateRestrictedElementsInScope } from '../restrictedElementDiv' +import { forceResetNodesSet } from '../engine' + +// Declare global variables +declare let globalScope: Scope +declare let loading: boolean + +/** + * Function to restore copy from backup + * @param scope - The circuit on which undo is called + * @category data + */ +export default function undo(scope: Scope = globalScope): void { + if (layoutModeGet() || scope.backups.length < 2) return + + const { ox, oy, scale } = saveGlobalScopePosition() + resetGlobalScopePosition() + + loading = true + const undoData = popLastBackup(scope) + if (!undoData) return + + scope.history.push(undoData) + + const tempScope = createTempScope(scope) + if (!tempScope) return + + updateGlobalScope(tempScope, ox, oy, scale) + forceResetNodesSet(true) + updateRestrictedElementsInScope() +} + +function saveGlobalScopePosition() { + return { + ox: globalScope.ox, + oy: globalScope.oy, + scale: globalScope.scale, + } +} + +function resetGlobalScopePosition() { + globalScope.ox = 0 + globalScope.oy = 0 +} + +function popLastBackup(scope: Scope): string | undefined { + return scope.backups.pop() +} + +function createTempScope(scope: Scope): Scope | undefined { + const tempScope = new Scope(scope.name) + if (scope.backups.length === 0) return tempScope + + try { + loadScope(tempScope, JSON.parse(scope.backups[scope.backups.length - 1])) + } catch (error) { + console.error('Failed to parse backup data:', error) + loading = false + return undefined + } + + tempScope.backups = scope.backups + tempScope.history = scope.history + tempScope.id = scope.id + tempScope.name = scope.name + tempScope.testbenchData = scope.testbenchData + + return tempScope +} + +function updateGlobalScope(tempScope: Scope, ox: number, oy: number, scale: number) { + scopeList[tempScope.id] = tempScope + globalScope = tempScope + globalScope.ox = ox + globalScope.oy = oy + globalScope.scale = scale + loading = false +} \ No newline at end of file diff --git a/v0/src/simulator/src/embed.js b/v0/src/simulator/src/embed.js index b17e82ba..f1a103ec 100644 --- a/v0/src/simulator/src/embed.js +++ b/v0/src/simulator/src/embed.js @@ -1,7 +1,7 @@ // /* eslint-disable import/no-cycle */ // // Helper functions for when circuit is embedded // import { scopeList, circuitProperty } from './circuit' -// import simulationArea from './simulationArea' +// import { simulationArea } from './simulationArea' // import { // scheduleUpdate, // wireToBeCheckedSet, diff --git a/v0/src/simulator/src/embedListeners.js b/v0/src/simulator/src/embedListeners.js index e7cb2d0a..6f7acece 100644 --- a/v0/src/simulator/src/embedListeners.js +++ b/v0/src/simulator/src/embedListeners.js @@ -1,7 +1,11 @@ /* eslint-disable import/no-cycle */ // Listeners when circuit is embedded +/* eslint-disable no-plusplus */ +/* eslint-disable func-names */ +/* eslint-disable prefer-const */ +/* eslint-disable max-len */ // Refer listeners.js -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, update, @@ -14,167 +18,191 @@ import { errorDetectedSet, } from './engine' import { changeScale } from './canvasApi' -import { copy, paste } from './events' -import { ZoomIn, ZoomOut } from './listeners' +import { ZoomIn, ZoomOut, pinchZoom, getCoordinate, } from './listeners'; -var unit = 10 +const unit = 10 +let embedCoordinate; +/** *Function embedPanStart + *This function hepls to initialize mouse and touch + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanStart(e) { + embedCoordinate = getCoordinate(e); + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); -export default function startListeners() { - window.addEventListener('keyup', (e) => { - scheduleUpdate(1) - if (e.keyCode == 16) { - simulationArea.shiftDown = false - } - if (e.key == 'Meta' || e.key == 'Control') { - simulationArea.controlDown = false + simulationArea.lastSelected = undefined; + simulationArea.selected = false; + simulationArea.hover = undefined; + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseDownRawX = (embedCoordinate.x - rect.left) * DPR; + simulationArea.mouseDownRawY = (embedCoordinate.y - rect.top) * DPR; + simulationArea.mouseDownX = Math.round(((simulationArea.mouseDownRawX - globalScope.ox) / globalScope.scale) / unit) * unit; + simulationArea.mouseDownY = Math.round(((simulationArea.mouseDownRawY - globalScope.oy) / globalScope.scale) / unit) * unit; + simulationArea.mouseDown = true; + simulationArea.oldx = globalScope.ox; + simulationArea.oldy = globalScope.oy; + e.preventDefault(); + scheduleUpdate(1); +} +/** *Function embedPanMove + *This function hepls to move simulator and its elements using touch and mouse + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanMove(e) { + embedCoordinate = getCoordinate(e); + if (!simulationArea.touch || e.touches.length === 1) { + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseRawX = (embedCoordinate.x - rect.left) * DPR; + simulationArea.mouseRawY = (embedCoordinate.y - rect.top) * DPR; + simulationArea.mouseXf = (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale; + simulationArea.mouseYf = (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale; + simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit; + simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit; + updateCanvasSet(true); + if (simulationArea.lastSelected == globalScope.root) { + updateCanvasSet(true); + let fn; + fn = function () { + updateSelectionsAndPane(); + }; + scheduleUpdate(0, 20, fn); + } else { + scheduleUpdate(0, 200); } - }) - - document - .getElementById('simulationArea') - .addEventListener('mousedown', (e) => { - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - - simulationArea.lastSelected = undefined - simulationArea.selected = false - simulationArea.hover = undefined - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseDownRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseDownRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseDownX = - Math.round( - (simulationArea.mouseDownRawX - globalScope.ox) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDownY = - Math.round( - (simulationArea.mouseDownRawY - globalScope.oy) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDown = true - simulationArea.oldx = globalScope.ox - simulationArea.oldy = globalScope.oy - - e.preventDefault() - scheduleUpdate(1) - }) - - document - .getElementById('simulationArea') - .addEventListener('mousemove', () => { - var ele = document.getElementById('elementName') - if (globalScope && simulationArea && simulationArea.objectList) { - var { objectList } = simulationArea - objectList = objectList.filter((val) => val !== 'wires') + } + if (simulationArea.touch && e.touches.length === 2) { + pinchZoom(e); + } +} +/** *Function embedPanEnd + *This function update simulator after mouse and touch end + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanEnd() { + simulationArea.mouseDown = false; + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + scheduleUpdate(1); +} +/** *Function BlockElementPan + *This function block the pan of elements since in embed simulator you can only view simulator NOT update +*/ - for (var i = 0; i < objectList.length; i++) { - for ( - var j = 0; - j < globalScope[objectList[i]].length; - j++ - ) { - if (globalScope[objectList[i]][j].isHover()) { - ele.style.display = 'block' - if (objectList[i] === 'SubCircuit') { - ele.innerHTML = `Subcircuit: ${globalScope.SubCircuit[j].data.name}` - } else { - ele.innerHTML = `CircuitElement: ${objectList[i]}` - } - return - } +function BlockElementPan() { + const ele = document.getElementById('elementName'); + if (globalScope && simulationArea && simulationArea.objectList) { + let { objectList } = simulationArea; + objectList = objectList.filter((val) => val !== 'wires'); + for (let i = 0; i < objectList.length; i++) { + for (let j = 0; j < globalScope[objectList[i]].length; j++) { + if (globalScope[objectList[i]][j].isHover()) { + ele.style.display = 'block'; + if (objectList[i] === 'SubCircuit') { + ele.innerHTML = `Subcircuit: ${globalScope.SubCircuit[j].data.name}`; + } else { + ele.innerHTML = `CircuitElement: ${objectList[i]}`; } + return; } } + } + } + ele.style.display = 'none'; + document.getElementById('elementName').innerHTML = ''; +} - ele.style.display = 'none' - document.getElementById('elementName').innerHTML = '' - }) - +export default function startListeners() { + window.addEventListener('keyup', (e) => { + scheduleUpdate(1); + if (e.keyCode == 16) { + simulationArea.shiftDown = false; + } + if (e.key == 'Meta' || e.key == 'Control') { + simulationArea.controlDown = false; + } + }); + // All event listeners starts from here + document.getElementById('simulationArea').addEventListener('mousedown', (e) => { + simulationArea.touch = false; + embedPanStart(e); + }); + document.getElementById('simulationArea').addEventListener('mousemove', () => { + simulationArea.touch = false; + BlockElementPan(); + }); + document.getElementById('simulationArea').addEventListener('touchstart', (e) => { + simulationArea.touch = true; + embedPanStart(e); + }); + document.getElementById('simulationArea').addEventListener('touchmove', () => { + simulationArea.touch = true; + BlockElementPan(); + }); window.addEventListener('mousemove', (e) => { - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseXf = - (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale - simulationArea.mouseYf = - (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale - simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit - simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit + embedPanMove(e); + }); + window.addEventListener('touchmove', (e) => { + embedPanMove(e); + }); + window.addEventListener('mouseup', () => { + embedPanEnd(); + }); + window.addEventListener('mousedown', function () { + this.focus(); + }); + window.addEventListener('touchend', () => { + embedPanEnd(); + }); + window.addEventListener('touchstart', function () { + this.focus(); + }); + document.getElementById('simulationArea').addEventListener('mousewheel', MouseScroll); + document.getElementById('simulationArea').addEventListener('DOMMouseScroll', MouseScroll); - updateCanvasSet(true) - if (simulationArea.lastSelected == globalScope.root) { - updateCanvasSet(true) - var fn - fn = function () { - updateSelectionsAndPane() - } - scheduleUpdate(0, 20, fn) - } else { - scheduleUpdate(0, 200) - } - }) window.addEventListener('keydown', (e) => { - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); // zoom in (+) if (e.key == 'Meta' || e.key == 'Control') { - simulationArea.controlDown = true + simulationArea.controlDown = true; } - - if ( - simulationArea.controlDown && - (e.keyCode == 187 || e.KeyCode == 171) - ) { - e.preventDefault() - ZoomIn() + if (simulationArea.controlDown && (e.keyCode == 187 || e.KeyCode == 171)) { + e.preventDefault(); + ZoomIn(); } - // zoom out (-) - if ( - simulationArea.controlDown && - (e.keyCode == 189 || e.Keycode == 173) - ) { - e.preventDefault() - ZoomOut() + if (simulationArea.controlDown && (e.keyCode == 189 || e.Keycode == 173)) { + e.preventDefault(); + ZoomOut(); } - if ( - simulationArea.mouseRawX < 0 || - simulationArea.mouseRawY < 0 || - simulationArea.mouseRawX > width || - simulationArea.mouseRawY > height - ) - return + if (simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height) return; - scheduleUpdate(1) - updateCanvasSet(true) + scheduleUpdate(1); + updateCanvasSet(true); - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.keyDown - ) { - if ( - e.key.toString().length == 1 || - e.key.toString() == 'Backspace' - ) { - simulationArea.lastSelected.keyDown(e.key.toString()) - return + if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown) { + if (e.key.toString().length == 1 || e.key.toString() == 'Backspace') { + simulationArea.lastSelected.keyDown(e.key.toString()); + return; } } - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.keyDown2 - ) { + if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown2) { if (e.key.toString().length == 1) { - simulationArea.lastSelected.keyDown2(e.key.toString()) - return + simulationArea.lastSelected.keyDown2(e.key.toString()); + return; } } @@ -187,73 +215,46 @@ export default function startListeners() { // } if (e.key == 'T' || e.key == 't') { - simulationArea.changeClockTime(prompt('Enter Time:')) + simulationArea.changeClockTime(prompt('Enter Time:')); } - }) - document - .getElementById('simulationArea') - .addEventListener('dblclick', (e) => { - scheduleUpdate(2) - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.dblclick !== undefined - ) { - simulationArea.lastSelected.dblclick() - } - }) - - window.addEventListener('mouseup', (e) => { - simulationArea.mouseDown = false - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - }) - window.addEventListener('mousedown', function (e) { - this.focus() - }) - - document - .getElementById('simulationArea') - .addEventListener('mousewheel', MouseScroll) - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', MouseScroll) - + }); + document.getElementById('simulationArea').addEventListener('dblclick', () => { + scheduleUpdate(2); + if (simulationArea.lastSelected && simulationArea.lastSelected.dblclick !== undefined) { + simulationArea.lastSelected.dblclick(); + } + }); function MouseScroll(event) { - updateCanvasSet(true) + updateCanvasSet(true); - event.preventDefault() - var deltaY = event.wheelDelta ? event.wheelDelta : -event.detail - var scrolledUp = deltaY < 0 - var scrolledDown = deltaY > 0 + event.preventDefault(); + const deltaY = event.wheelDelta ? event.wheelDelta : -event.detail; + const scrolledUp = deltaY < 0; + const scrolledDown = deltaY > 0; if (event.ctrlKey) { if (scrolledUp && globalScope.scale > 0.5 * DPR) { - changeScale(-0.1 * DPR) + changeScale(-0.1 * DPR); } if (scrolledDown && globalScope.scale < 4 * DPR) { - changeScale(0.1 * DPR) + changeScale(0.1 * DPR); } } else { if (scrolledUp && globalScope.scale < 4 * DPR) { - changeScale(0.1 * DPR) + changeScale(0.1 * DPR); } if (scrolledDown && globalScope.scale > 0.5 * DPR) { - changeScale(-0.1 * DPR) + changeScale(-0.1 * DPR); } } - updateCanvasSet(true) - gridUpdateSet(true) - update() // Schedule update not working, this is INEFFICENT + updateCanvasSet(true); + gridUpdateSet(true); + update(); // Schedule update not working, this is INEFFICENT } } +// eslint-disable-next-line no-unused-vars var isIe = navigator.userAgent.toLowerCase().indexOf('msie') != -1 || navigator.userAgent.toLowerCase().indexOf('trident') != -1 diff --git a/v0/src/simulator/src/engine.js b/v0/src/simulator/src/engine.js index 2f74df6e..5227eb76 100644 --- a/v0/src/simulator/src/engine.js +++ b/v0/src/simulator/src/engine.js @@ -5,13 +5,15 @@ /* eslint-disable no-bitwise */ import { layoutModeGet, layoutUpdate } from './layoutMode' import plotArea from './plotArea' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { dots, canvasMessage, findDimensions, rect2 } from './canvasApi' import { showProperties, prevPropertyObjGet } from './ux' import { showError } from './utils' import miniMapArea from './minimap' import { resetup } from './setup' import { verilogModeGet } from './Verilog2CV' +import { renderOrder, updateOrder } from './metadata' +import ContentionPendingData from './contention'; /** * Core of the simulation and rendering algorithm. @@ -368,7 +370,7 @@ export function updateSelectionsAndPane(scope = globalScope) { for (let i = 0; i < updateOrder.length; i++) { for (var j = 0; j < scope[updateOrder[i]].length; j++) { var obj = scope[updateOrder[i]][j] - if (simulationArea.multipleObjectSelections.contains(obj)) + if (simulationArea.multipleObjectSelections.includes(obj)) continue var x var y @@ -404,6 +406,7 @@ export function play(scope = globalScope, resetNodes = false) { simulationArea.simulationQueue.reset() plotArea.setExecutionTime() // Waveform thing + resetNodeHighlights(scope); // Reset Nodes if required if (resetNodes || forceResetNodes) { scope.reset() @@ -411,9 +414,8 @@ export function play(scope = globalScope, resetNodes = false) { forceResetNodesSet(false) } - // To store list of circuitselements that have shown contention but kept temporarily - // Mainly to resolve tristate bus issues - simulationArea.contentionPending = [] + // To store set of Nodes that have shown contention but kept temporarily + simulationArea.contentionPending = new ContentionPendingData(); // add inputs to the simulation queue scope.addInputs() // to check if we have infinite loop in circuit @@ -425,25 +427,34 @@ export function play(scope = globalScope, resetNodes = false) { return } elem = simulationArea.simulationQueue.pop() + elem.resolve() + stepCount++ if (stepCount > 1000000) { // Cyclic or infinite Circuit Detection showError( 'Simulation Stack limit exceeded: maybe due to cyclic paths or contention' ) - errorDetectedSet(true) forceResetNodesSet(true) } } - // Check for TriState Contentions - if (simulationArea.contentionPending.length) { - showError('Contention at TriState') - forceResetNodesSet(true) - errorDetectedSet(true) + // Check for Contentions + if (simulationArea.contentionPending.size() > 0) { + for (const [ourNode, theirNode] of simulationArea.contentionPending.nodes()) { + ourNode.highlighted = true; + theirNode.highlighted = true; + } + + forceResetNodesSet(true); + showError('Contention Error: One or more bus contentions in the circuit (check highlighted nodes)'); } } +export function resetNodeHighlights(scope) { + for (const node of scope.allNodes) node.highlighted = false; +} + /** * Function to check for any UI update, it is throttled by time * @param {number=} count - this is used to force update @@ -451,7 +462,7 @@ export function play(scope = globalScope, resetNodes = false) { * @param {function} fn - function to run before updating UI * @category engine */ -export function scheduleUpdate(count = 0, time = 100, fn) { +export function scheduleUpdate(count = 0, time = 100, fn = undefined) { if (lightMode) time *= 5 var updateFn = layoutModeGet() ? layoutUpdate : update if (count) { diff --git a/v1/src/simulator/src/eventQueue.js b/v0/src/simulator/src/eventQueue.ts similarity index 87% rename from v1/src/simulator/src/eventQueue.js rename to v0/src/simulator/src/eventQueue.ts index f40110e1..349f137c 100644 --- a/v1/src/simulator/src/eventQueue.js +++ b/v0/src/simulator/src/eventQueue.ts @@ -2,19 +2,29 @@ * Event Queue is simply a priority Queue, basic implementation O(n^2). * @category eventQueue */ -export default class EventQueue { - constructor(size) { + +interface QueueObject { + queueProperties: { + inQueue: boolean + time: number + index: number + } + propagationDelay: number +} + +export class EventQueue { + size: number + queue: Array + frontIndex: number + time: number + constructor(size: number) { this.size = size this.queue = new Array(size) this.frontIndex = 0 this.time = 0 } - /** - * @param {CircuitElement} obj - the elemnt to be added - * @param {number} delay - the delay in adding an object to queue - */ - add(obj, delay) { + add(obj: QueueObject, delay: number) { if (obj.queueProperties.inQueue) { obj.queueProperties.time = this.time + (delay || obj.propagationDelay) @@ -41,7 +51,6 @@ export default class EventQueue { if (this.frontIndex == this.size) throw 'EventQueue size exceeded' this.queue[this.frontIndex] = obj - // obj.queueProperties.time=obj.propagationDelay; obj.queueProperties.time = this.time + (delay || obj.propagationDelay) obj.queueProperties.index = this.frontIndex this.frontIndex++ @@ -60,7 +69,7 @@ export default class EventQueue { * To add without any delay. * @param {CircuitElement} obj - the object to be added */ - addImmediate(obj) { + addImmediate(obj: QueueObject) { this.queue[this.frontIndex] = obj obj.queueProperties.time = this.time obj.queueProperties.index = this.frontIndex @@ -70,10 +79,8 @@ export default class EventQueue { /** * Function to swap two objects in queue. - * @param {number} v1 - * @param {number} v2 */ - swap(v1, v2) { + swap(v1: number, v2: number) { const obj1 = this.queue[v1] obj1.queueProperties.index = v2 diff --git a/v0/src/simulator/src/events.js b/v0/src/simulator/src/events.js index c3c0edca..07de4275 100644 --- a/v0/src/simulator/src/events.js +++ b/v0/src/simulator/src/events.js @@ -11,16 +11,16 @@ import { import { backUp } from './data/backupCircuit' import { getNextPosition } from './modules' import { generateId } from './utils' -import simulationArea from './simulationArea' -import { TestbenchData } from './testbench' +import { simulationArea } from './simulationArea' +import { TestbenchData } from '#/simulator/src/testbench' +import { moduleList, updateOrder } from './metadata' /** * Helper function to paste - * @param {JSON} copyData - the data to be pasted * @category events */ export function paste(copyData) { - if (copyData === undefined) return + if (copyData === 'undefined') return var data = JSON.parse(copyData) if (!data.logixClipBoardData) return @@ -104,7 +104,7 @@ export function paste(copyData) { l !== 'objects' && l !== 'CircuitElement' ) { - globalScope[l].extend(tempScope[l]) + globalScope[l].push(...tempScope[l]) } }) for (let i = 0; i < tempScope.Input.length; i++) { @@ -119,7 +119,6 @@ export function paste(copyData) { globalScope ) } - var canvasUpdate = true updateSimulationSet(true) updateSubcircuitSet(true) scheduleUpdate() @@ -165,7 +164,7 @@ export function cut(copyList) { const obj = globalScope[updateOrder[i]][j] if (obj.objectType != 'Wire') { // }&&obj.objectType!='CircuitElement'){//}&&(obj.objectType!='Node'||obj.type==2)){ - if (!copyList.contains(globalScope[updateOrder[i]][j])) { + if (!copyList.includes(globalScope[updateOrder[i]][j])) { globalScope[updateOrder[i]][j].cleanDelete() } } @@ -198,9 +197,8 @@ export function cut(copyList) { data.logixClipBoardData = true data = JSON.stringify(data) - simulationArea.multipleObjectSelections = [] // copyList.slice(); - simulationArea.copyList = [] // copyList.slice(); - var canvasUpdate = true + simulationArea.multipleObjectSelections = [] + simulationArea.copyList = [] updateSimulationSet(true) globalScope = tempScope scheduleUpdate() @@ -252,7 +250,7 @@ export function copy(copyList, cutflag = false) { const obj = globalScope[updateOrder[i]][j] if (obj.objectType != 'Wire') { // }&&obj.objectType!='CircuitElement'){//}&&(obj.objectType!='Node'||obj.type==2)){ - if (!copyList.contains(globalScope[updateOrder[i]][j])) { + if (!copyList.includes(globalScope[updateOrder[i]][j])) { globalScope[updateOrder[i]][j].cleanDelete() } } @@ -297,9 +295,8 @@ export function copy(copyList, cutflag = false) { data.logixClipBoardData = true data.testbenchData = undefined // Don't copy testbench data data = JSON.stringify(data) - simulationArea.multipleObjectSelections = [] // copyList.slice(); - simulationArea.copyList = [] // copyList.slice(); - var canvasUpdate = true + simulationArea.multipleObjectSelections = [] + simulationArea.copyList = [] updateSimulationSet(true) globalScope = tempScope scheduleUpdate() diff --git a/v1/src/simulator/src/hotkey_binder/defaultKeys.js b/v0/src/simulator/src/hotkey_binder/defaultKeys.ts similarity index 89% rename from v1/src/simulator/src/hotkey_binder/defaultKeys.js rename to v0/src/simulator/src/hotkey_binder/defaultKeys.ts index 0529ce5f..42afbbf6 100644 --- a/v1/src/simulator/src/hotkey_binder/defaultKeys.js +++ b/v0/src/simulator/src/hotkey_binder/defaultKeys.ts @@ -1,8 +1,11 @@ /**Add more elements here, along with a valid value for key * Elements keys must have the same name as their ID **/ +export interface DefaultKeysType { + [key: string]: string; +} -export const defaultKeys = { +export const defaultKeys: DefaultKeysType = { 'New Circuit': 'Shift + N', 'Save Online': 'Ctrl + S', 'Save Offline': 'Ctrl + Alt + S', diff --git a/v0/src/simulator/src/hotkey_binder/model/actions.js b/v0/src/simulator/src/hotkey_binder/model/actions.js deleted file mode 100644 index 102209ee..00000000 --- a/v0/src/simulator/src/hotkey_binder/model/actions.js +++ /dev/null @@ -1,205 +0,0 @@ -import { defaultKeys } from '../defaultKeys' -import { addShortcut } from './addShortcut' -import { updateHTML } from '../view/panel.ui' -import simulationArea from '../../simulationArea' -import { - scheduleUpdate, - update, - updateSelectionsAndPane, - wireToBeCheckedSet, - updatePositionSet, - updateSimulationSet, - updateCanvasSet, - gridUpdateSet, - errorDetectedSet, -} from '../../engine' - -import { getOS } from './utils.js' -import { shortcut } from './shortcuts.plugin.js' -/** - * Function used to add or change keys user or default - * grabs the keycombo from localstorage & - * calls the addShortcut function in a loop to bind them - * @param {string} mode - user custom keys or default keys - */ -export const addKeys = (mode) => { - shortcut.removeAll() - if (mode === 'user') { - localStorage.removeItem('defaultKeys') - let userKeys = localStorage.get('userKeys') - for (let pref in userKeys) { - let key = userKeys[pref] - key = key.split(' ').join('') - addShortcut(key, pref) - } - updateHTML('user') - } else if (mode == 'default') { - if (localStorage.userKeys) localStorage.removeItem('userKeys') - let defaultKeys = localStorage.get('defaultKeys') - for (let pref in defaultKeys) { - let key = defaultKeys[pref] - key = key.split(' ').join('') - addShortcut(key, pref) - } - updateHTML('default') - } -} -/** - * Function used to check if new keys are added, adds missing keys if added - */ -export const checkUpdate = () => { - const userK = localStorage.get('userKeys') - if (Object.size(userK) !== Object.size(defaultKeys)) { - for (const [key, value] of Object.entries(defaultKeys)) { - if (!Object.keys(userK).includes(key)) { - userK[key] = value - } - } - localStorage.set('userKeys', userK) - } else { - return - } -} -/** - * Function used to set userKeys, grabs the keycombo from the panel UI - * sets it to the localStorage & cals addKeys - * removes the defaultkeys from localStorage - */ -export const setUserKeys = () => { - if (localStorage.defaultKeys) localStorage.removeItem('defaultKeys') - let userKeys = {} - let x = 0 - while ($('#preference').children()[x]) { - userKeys[ - $('#preference').children()[x].children[1].children[0].innerText - ] = $('#preference').children()[x].children[1].children[1].innerText - x++ - } - localStorage.set('userKeys', userKeys) - addKeys('user') -} -/** - * Function used to set defaultKeys, grabs the keycombo from the defaultkeys metadata - * sets it to the localStorage & cals addKeys - * removes the userkeys from localStorage if present - * also checks for OS type - */ -export const setDefault = () => { - if (localStorage.userKeys) localStorage.removeItem('userKeys') - if (getOS() === 'MacOS') { - const macDefaultKeys = {} - for (let [key, value] of Object.entries(defaultKeys)) { - if (value.split(' + ')[0] == 'Ctrl'); - macDefaultKeys[key] = - value.split(' + ')[0] == 'Ctrl' - ? value.replace('Ctrl', 'Meta') - : value - localStorage.set('defaultKeys', macDefaultKeys) - } - } else { - localStorage.set('defaultKeys', defaultKeys) //TODO add a confirmation alert - } - addKeys('default') -} -/** - * function to check if user entered keys are already assigned to other key - * gives a warning message if keys already assigned - * @param {string} combo the key combo - * @param {string} target the target option of the panel - */ -export const warnOverride = (combo, target, warning) => { - let x = 0 - while ($('#preference').children()[x]) { - if ( - $('#preference').children()[x].children[1].children[1].innerText === - combo && - $('#preference').children()[x].children[1].children[0].innerText !== - target.previousElementSibling.innerText - ) { - const assignee = - $('#preference').children()[x].children[1].children[0].innerText - // $('#warning').text( - // `This key(s) is already assigned to: ${assignee}, press Enter to override.` - // ) - warning.value = `This key(s) is already assigned to: ${assignee}, press Enter to override.` - $('#edit').css('border', '1.5px solid #dc5656') - return - } else { - $('#edit').css('border', 'none') - } - x++ - } -} - -export const elementDirection = (direct) => () => { - if (simulationArea.lastSelected) { - simulationArea.lastSelected.newDirection(direct.toUpperCase()) - $("select[name |= 'newDirection']").val(direct.toUpperCase()) - updateSystem() - } -} - -export const labelDirection = (direct) => () => { - if ( - simulationArea.lastSelected && - !simulationArea.lastSelected.labelDirectionFixed - ) { - simulationArea.lastSelected.labelDirection = direct.toUpperCase() - $("select[name |= 'newLabelDirection']").val(direct.toUpperCase()) - updateSystem() - } -} - -export const insertLabel = () => { - if (simulationArea.lastSelected) { - $("input[name |= 'setLabel']").focus() - $("input[name |= 'setLabel']").val().length - ? null - : $("input[name |= 'setLabel']").val('Untitled') - $("input[name |= 'setLabel']").select() - updateSystem() - } -} - -export const moveElement = (direct) => () => { - if (simulationArea.lastSelected) { - switch (direct) { - case 'up': - simulationArea.lastSelected.y -= 10 - break - case 'down': - simulationArea.lastSelected.y += 10 - break - case 'left': - simulationArea.lastSelected.x -= 10 - break - case 'right': - simulationArea.lastSelected.x += 10 - break - } - updateSystem() - } -} - -export const openHotkey = () => $('#customShortcut').trigger('click') - -export const createNewCircuitScopeCall = () => - $('#createNewCircuitScope').trigger('click') // TODO: remove later - -export const openDocumentation = () => { - if ( - simulationArea.lastSelected == undefined || - simulationArea.lastSelected.helplink == undefined - ) { - // didn't select any element or documentation not found - window.open('https://docs.circuitverse.org/', '_blank') - } else { - window.open(simulationArea.lastSelected.helplink, '_blank') - } -} - -function updateSystem() { - updateCanvasSet(true) - wireToBeCheckedSet(1) - scheduleUpdate(1) -} diff --git a/v0/src/simulator/src/hotkey_binder/model/actions.ts b/v0/src/simulator/src/hotkey_binder/model/actions.ts new file mode 100644 index 00000000..33452764 --- /dev/null +++ b/v0/src/simulator/src/hotkey_binder/model/actions.ts @@ -0,0 +1,340 @@ +/* eslint-disable import/no-cycle */ +import { defaultKeys } from '../defaultKeys' +import { addShortcut } from './addShortcut' +import { updateHTML } from '../view/panel.ui' +import { simulationArea } from '../../simulationArea' +import { + scheduleUpdate, + wireToBeCheckedSet, + updateCanvasSet, +} from '../../engine' + +import { getOS } from './utils' +import { shortcut } from './shortcuts.plugin' + +import { KeyMap } from './model.types' + +type DirectionType = 'up' | 'down' | 'left' | 'right' + +/** + * Function used to add or change keys user or default + * grabs the keycombo from localstorage & + * calls the addShortcut function in a loop to bind them + * @param {string} mode - user custom keys or default keys + */ +export const addKeys = (mode: 'user' | 'default'): void => { + shortcut.removeAll() + const keys = mode === 'user' ? getUserKeys() : getDefaultKeys() + bindKeys(keys, mode) +} + +/** + * Get user keys from localStorage + */ +const getUserKeys = (): KeyMap => { + localStorage.removeItem('defaultKeys') + return JSON.parse(localStorage.getItem('userKeys') || '{}') +} + +/** + * Get default keys from localStorage + */ +const getDefaultKeys = (): KeyMap => { + if (localStorage.userKeys) localStorage.removeItem('userKeys') + return JSON.parse(localStorage.getItem('defaultKeys') || '{}') +} + +/** + * Bind keys to shortcuts + */ +const bindKeys = (keys: KeyMap, mode: 'user' | 'default'): void => { + Object.entries(keys).forEach(([pref, key]) => { + const normalizedKey = key.split(' ').join('') + addShortcut(normalizedKey, pref) + }) + updateHTML(mode) +} + +/** + * Function used to check if new keys are added, adds missing keys if added + */ +export const checkUpdate = (): void => { + const userK: KeyMap = JSON.parse(localStorage.getItem('userKeys') || '{}'); + const defaultK: KeyMap = defaultKeys; + + const hasChanges = syncKeys(userK, defaultK); + + if (hasChanges) { + localStorage.setItem('userKeys', JSON.stringify(userK)); + } +}; + +const syncKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + const hasAddedOrUpdated = addOrUpdateKeys(userK, defaultK); + const hasRemoved = removeObsoleteKeys(userK, defaultK); + + return hasAddedOrUpdated || hasRemoved; +}; + +const addOrUpdateKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + let hasChanges = false; + + for (const key of Object.keys(defaultK)) { + if (!Object.hasOwn(userK, key) || userK[key] !== defaultK[key]) { + userK[key] = defaultK[key]; + hasChanges = true; + } + } + + return hasChanges; +}; + +const removeObsoleteKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + let hasChanges = false; + + for (const key of Object.keys(userK)) { + if (!Object.hasOwn(defaultK, key)) { + delete userK[key]; + hasChanges = true; + } + } + + return hasChanges; +}; + +/** + * Add missing keys to user keys + */ +const addMissingKeys = (userK: KeyMap): void => { + Object.entries(defaultKeys).forEach(([key, value]) => { + if (!userK[key]) { + userK[key] = value + } + }) +} + +/** + * Function used to set userKeys, grabs the keycombo from the panel UI + * sets it to the localStorage & calls addKeys + * removes the defaultkeys from localStorage + */ +export const setUserKeys = (): void => { + if (localStorage.defaultKeys) localStorage.removeItem('defaultKeys') + const userKeys = getUserKeysFromUI() + localStorage.setItem('userKeys', JSON.stringify(userKeys)) + addKeys('user') +} + +/** + * Get user keys from the UI + */ +const getUserKeysFromUI = (): KeyMap => { + const userKeys: KeyMap = {} + const preferenceChildren = document.getElementById('preference')?.children + if (!preferenceChildren) return userKeys + + Array.from(preferenceChildren).forEach((child) => { + const keyChild = child?.children[1]?.children[0] + const valueChild = child?.children[1]?.children[1] + + if (keyChild instanceof HTMLElement && valueChild instanceof HTMLElement) { + userKeys[keyChild.innerText] = valueChild.innerText + } + }) + return userKeys +} + +/** + * Function used to set defaultKeys, grabs the keycombo from the defaultkeys metadata + * sets it to the localStorage & calls addKeys + * removes the userkeys from localStorage if present + * also checks for OS type + */ +export const setDefault = (): void => { + if (localStorage.getItem('userKeys')) localStorage.removeItem('userKeys') + const keys = getOS() === 'MacOS' ? getMacDefaultKeys() : defaultKeys + localStorage.setItem('defaultKeys', JSON.stringify(keys)) + addKeys('default') +} + +/** + * Get default keys for MacOS + */ +const getMacDefaultKeys = (): KeyMap => { + const macDefaultKeys: KeyMap = {} + Object.entries(defaultKeys).forEach(([key, value]) => { + macDefaultKeys[key] = value.split(' + ')[0] === 'Ctrl' ? value.replace('Ctrl', 'Meta') : value + }) + return macDefaultKeys +} + +/** + * Function to check if user entered keys are already assigned to other key + * gives a warning message if keys already assigned + */ +export const warnOverride = ( + combo: string, + target: HTMLElement, + warning: HTMLInputElement +): void => { + const preferenceChildren = document.getElementById('preference')?.children + if (!preferenceChildren) return + + const isComboAssigned = checkIfComboIsAssigned(combo, target, preferenceChildren) + if (isComboAssigned) { + warning.value = `This key(s) is already assigned to: ${isComboAssigned}, press Enter to override.` + setEditElementBorder('#dc5656') + } else { + setEditElementBorder('none') + } +} + +/** + * Check if the key combo is already assigned to another key + */ +const checkIfComboIsAssigned = ( + combo: string, + target: HTMLElement, + preferenceChildren: HTMLCollection +): string | undefined => { + return Array.from(preferenceChildren).reduce((acc, child) => { + if (acc) return acc + return getAssigneeFromPreference(child, combo, target) + }, undefined) +} + +/** + * Get the assignee from a preference element if the combo matches + */ +const getAssigneeFromPreference = ( + preferenceElement: Element | null, + combo: string, + target: HTMLElement +): string | undefined => { + const keyChild = preferenceElement?.children[1]?.children[0] + const valueChild = preferenceElement?.children[1]?.children[1] + + if (keyChild instanceof HTMLElement && valueChild instanceof HTMLElement) { + const assignee = keyChild.innerText + if (valueChild.innerText === combo && + assignee !== (target.previousElementSibling as HTMLElement)?.innerText) { + return assignee + } + } + return undefined +} + +/** + * Set border style for edit element + */ +const setEditElementBorder = (color: string): void => { + const editElement = document.getElementById('edit') + if (editElement) { + editElement.style.border = color === 'none' ? 'none' : `1.5px solid ${color}` + } +} + +/** + * Update element direction + */ +export const elementDirection = (direct: string) => (): void => { + if (simulationArea.lastSelected) { + simulationArea.lastSelected.newDirection(direct.toUpperCase()) + updateSelectElement("select[name^='newDirection']", direct.toUpperCase()) + updateSystem() + } +} + +/** + * Update label direction + */ +export const labelDirection = (direct: string) => (): void => { + if (simulationArea.lastSelected && !simulationArea.lastSelected.labelDirectionFixed) { + simulationArea.lastSelected.labelDirection = direct.toUpperCase() + updateSelectElement("select[name^='newLabelDirection']", direct.toUpperCase()) + updateSystem() + } +} + +/** + * Update select element value + */ +const updateSelectElement = (selector: string, value: string): void => { + const selectElement = document.querySelector(selector) + if (selectElement) { + selectElement.value = value + } +} + +/** + * Insert label into input field + */ +export const insertLabel = (): void => { + if (!simulationArea.lastSelected) return + + const labelInput = document.querySelector("input[name^='setLabel']") + if (!labelInput) return + + focusAndSetLabel(labelInput) + updateSystem() +} + +/** + * Focus on the label input and set a default value if empty + */ +const focusAndSetLabel = (labelInput: HTMLInputElement): void => { + labelInput.focus() + if (!labelInput.value) { + labelInput.value = 'Untitled' + } + labelInput.select() +} + +/** + * Move element in a specific direction + */ +export const moveElement = (direct: DirectionType) => (): void => { + if (simulationArea.lastSelected) { + const { x, y } = simulationArea.lastSelected + const newPosition = calculateNewPosition(direct, x, y) + simulationArea.lastSelected.x = newPosition.x + simulationArea.lastSelected.y = newPosition.y + updateSystem() + } +} + +/** + * Calculate new position based on direction + */ +const calculateNewPosition = (direct: DirectionType, x: number, y: number): { x: number; y: number } => { + switch (direct) { + case 'up': return { x, y: y - 10 } + case 'down': return { x, y: y + 10 } + case 'left': return { x: x - 10, y } + case 'right': return { x: x + 10, y } + } +} + +/** + * Open hotkey settings + */ +export const openHotkey = (): void => { + document.getElementById('customShortcut')?.click() +} + +/** + * Open documentation + */ +export const openDocumentation = (): void => { + const url = simulationArea.lastSelected?.helplink || 'https://docs.circuitverse.org/' + window.open(url, '_blank') +} + +/** + * Update system state + */ +function updateSystem(): void { + updateCanvasSet(true) + wireToBeCheckedSet(1) + scheduleUpdate(1) +} \ No newline at end of file diff --git a/v0/src/simulator/src/hotkey_binder/model/addShortcut.js b/v0/src/simulator/src/hotkey_binder/model/addShortcut.ts similarity index 69% rename from v0/src/simulator/src/hotkey_binder/model/addShortcut.js rename to v0/src/simulator/src/hotkey_binder/model/addShortcut.ts index 27834ab1..c5e0b4dd 100644 --- a/v0/src/simulator/src/hotkey_binder/model/addShortcut.js +++ b/v0/src/simulator/src/hotkey_binder/model/addShortcut.ts @@ -1,8 +1,4 @@ -// import { shortcut } from './Shortcuts.plugin'; -// import createSaveAsImgPrompt from '../../data/saveImage'; -//Assign the callback func for the keymap here import { - createNewCircuitScopeCall, elementDirection, insertLabel, labelDirection, @@ -15,13 +11,44 @@ import { saveOffline, openOffline } from '../../data/project' import createSaveAsImgPrompt from '../../data/saveImage' import { createSubCircuitPrompt } from '../../subcircuit' import { createCombinationalAnalysisPrompt } from '../../combinationalAnalysis' -import { shortcut } from './shortcuts.plugin.js' +import { shortcut } from './shortcuts.plugin' +import logixFunction from '../../data' +import { ShortcutOptions } from './model.types' + +export type ActionType = + | 'New Circuit' + | 'Save Online' + | 'Save Offline' + | 'Download as Image' + | 'Open Offline' + | 'Insert Sub-circuit' + | 'Combinational Analysis' + | 'Direction Up' + | 'Direction Down' + | 'Direction Left' + | 'Direction Right' + | 'Insert Label' + | 'Label Direction Up' + | 'Label Direction Down' + | 'Label Direction Left' + | 'Label Direction Right' + | 'Move Element Up' + | 'Move Element Down' + | 'Move Element Left' + | 'Move Element Right' + | 'Hotkey Preference' + | 'Open Documentation' + +export const addShortcut = ( + keys: string, + action: ActionType, + customOptions?: Partial +): void => { + let callback: (() => void) | (() => Promise) -export const addShortcut = (keys, action) => { - let callback switch (action) { case 'New Circuit': - callback = createNewCircuitScopeCall // TODO: directly call rather than using dom click + callback = logixFunction.createNewCircuitScope break case 'Save Online': callback = save @@ -40,10 +67,7 @@ export const addShortcut = (keys, action) => { break case 'Combinational Analysis': callback = createCombinationalAnalysisPrompt - break //bug - // case "Start Plot": - // callback = startPlot; - // break; + break case 'Direction Up': callback = elementDirection('up') break @@ -90,13 +114,16 @@ export const addShortcut = (keys, action) => { callback = openDocumentation break default: - callback = () => console.log('No shortcut found..') - break + callback = () => console.error('No shortcut found..') } - shortcut.add(keys, callback, { + + const options: ShortcutOptions = { type: 'keydown', propagate: false, target: document, disable_in_input: true, - }) -} + ...customOptions + } + + shortcut.add(keys, callback, options) +} \ No newline at end of file diff --git a/v0/src/simulator/src/hotkey_binder/model/model.types.ts b/v0/src/simulator/src/hotkey_binder/model/model.types.ts new file mode 100644 index 00000000..271cbf01 --- /dev/null +++ b/v0/src/simulator/src/hotkey_binder/model/model.types.ts @@ -0,0 +1,25 @@ +//This file holds the interfaces required for src/simulator/src/hotkey_binder/model +//to be continued for storing interfaces of the parent folder + +export interface ShortcutOptions { + type?: string + propagate?: boolean + disable_in_input?: boolean + target?: Document | string + keycode?: number | false +} + +export interface ShortcutBinding { + callback: EventListener + target: Document | HTMLElement + event: string +} + +export interface ModifierState { + wanted: boolean + pressed: boolean +} + +export interface KeyMap { + [key: string]: string +} diff --git a/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js b/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js deleted file mode 100644 index f80d37bd..00000000 --- a/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * http://www.openjs.com/scripts/events/keyboard_shortcuts/ - * Version : 2.01.B - * By Binny V A - * License : BSD - */ - -/** - * Restrictions: - * The shortcut key combination should be specified in this format ... Modifier[+Modifier..]+Key. - * Can have a single key without Modifier .. Key, not Key + Key - * These restrictions must be be hardcoded to not let users input invalid key combo - * There is no way to override Ctrl+N, Ctrl+T, or Ctrl+W in Google Chrome since version 4 of Chrome (shipped in 2010). - * - **/ - -//*! This plugin has been modified - -export const shortcut = { - all_shortcuts: {}, //All the shortcuts are stored in this array ex. download : keycombo; - add: function (shortcut_combination, callback, opt) { - //Provide a set of default options - var default_options = { - type: 'keydown', - propagate: false, - disable_in_input: true, - target: document, - keycode: false, - } - - if (!opt) opt = default_options - else { - for (var dfo in default_options) { - if (typeof opt[dfo] == 'undefined') - opt[dfo] = default_options[dfo] - } - } - - var ele = opt.target - if (typeof opt.target == 'string') - ele = document.getElementById(opt.target) - var ths = this - shortcut_combination = shortcut_combination.toLowerCase() - - //The function to be called at keypress - var func = function (e) { - e = e || window.event - if (opt['disable_in_input']) { - //Don't enable shortcut keys in Input, Textarea fields - var element - if (e.target) element = e.target - else if (e.srcElement) element = e.srcElement - if (element.nodeType == 3) element = element.parentNode - - if (element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') - return - } - - let code = '' - //Find Which key is pressed - if (e.keyCode) code = e.keyCode - else if (e.which) code = e.which - var character = String.fromCharCode(code).toLowerCase() - // e.preventDefault(); - - if (code == 188) character = ',' //If the user presses , when the type is onkeydown - if (code == 190) character = '.' //If the user presses , when the type is onkeydown - - var keys = shortcut_combination.split('+') - //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked - var kp = 0 - - //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken - var shift_nums = { - '`': '~', - 1: '!', - 2: '@', - 3: '#', - 4: '$', - 5: '%', - 6: '^', - 7: '&', - 8: '*', - 9: '(', - 0: ')', - '-': '_', - '=': '+', - ';': ':', - "'": '"', - ',': '<', - '.': '>', - '/': '?', - '\\': '|', - } - //Special Keys - and their codes - var special_keys = { - esc: 27, - escape: 27, - tab: 9, - space: 32, - return: 13, - enter: 13, - backspace: 8, - - scrolllock: 145, - scroll_lock: 145, - scroll: 145, - capslock: 20, - caps_lock: 20, - caps: 20, - numlock: 144, - num_lock: 144, - num: 144, - - pause: 19, - break: 19, - - insert: 45, - home: 36, - delete: 46, - end: 35, - - pageup: 33, - page_up: 33, - pu: 33, - - pagedown: 34, - page_down: 34, - pd: 34, - - left: 37, - up: 38, - right: 39, - down: 40, - - f1: 112, - f2: 113, - f3: 114, - f4: 115, - f5: 116, - f6: 117, - f7: 118, - f8: 119, - f9: 120, - f10: 121, - f11: 122, - f12: 123, - } - - var modifiers = { - shift: { wanted: false, pressed: false }, - ctrl: { wanted: false, pressed: false }, - alt: { wanted: false, pressed: false }, - meta: { wanted: false, pressed: false }, //Meta is Mac specific - } - - if (e.ctrlKey) modifiers.ctrl.pressed = true - if (e.shiftKey) modifiers.shift.pressed = true - if (e.altKey) modifiers.alt.pressed = true - if (e.metaKey) modifiers.meta.pressed = true - - let k - for (var i = 0; (k = keys[i]), i < keys.length; i++) { - //Modifiers - if (k == 'ctrl' || k == 'control') { - kp++ - modifiers.ctrl.wanted = true - } else if (k == 'shift') { - kp++ - modifiers.shift.wanted = true - } else if (k == 'alt') { - kp++ - modifiers.alt.wanted = true - } else if (k == 'meta') { - kp++ - modifiers.meta.wanted = true - } else if (k.length > 1) { - //If it is a special key - if (special_keys[k] == code) kp++ - } else if (opt['keycode']) { - if (opt['keycode'] == code) kp++ - } else { - //The special keys did not match - if (character == k) kp++ - else { - if (shift_nums[character] && e.shiftKey) { - //Stupid Shift key bug created by using lowercase - character = shift_nums[character] - if (character == k) kp++ - } - } - } - } - - if ( - kp == keys.length && - modifiers.ctrl.pressed == modifiers.ctrl.wanted && - modifiers.shift.pressed == modifiers.shift.wanted && - modifiers.alt.pressed == modifiers.alt.wanted && - modifiers.meta.pressed == modifiers.meta.wanted - ) { - callback(e) - - if (!opt['propagate']) { - //Stop the event - //e.cancelBubble is supported by IE - this will kill the bubbling process. - e.cancelBubble = true - e.returnValue = false - - //e.stopPropagation works in Firefox. - if (e.stopPropagation) { - e.stopPropagation() - e.preventDefault() - } - return false - } - } - } - this.all_shortcuts[shortcut_combination] = { - callback: func, - target: ele, - event: opt['type'], - } - //Attach the function with the event - if (ele.addEventListener) ele.addEventListener(opt['type'], func, false) - else if (ele.attachEvent) ele.attachEvent('on' + opt['type'], func) - else ele['on' + opt['type']] = func - }, - - //Remove the shortcut - just specify the shortcut and I will remove the binding - remove: function (shortcut_combination) { - shortcut_combination = shortcut_combination.toLowerCase() - var binding = this.all_shortcuts[shortcut_combination] - delete this.all_shortcuts[shortcut_combination] - if (!binding) return - var type = binding['event'] - var ele = binding['target'] - var callback = binding['callback'] - - if (ele.detachEvent) ele.detachEvent('on' + type, callback) - else if (ele.removeEventListener) - ele.removeEventListener(type, callback, false) - else ele['on' + type] = false - }, - removeAll: function () { - for (let x in this.all_shortcuts) { - this.remove(x) - } - }, -} diff --git a/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts b/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts new file mode 100644 index 00000000..f34d25b3 --- /dev/null +++ b/v0/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts @@ -0,0 +1,232 @@ +import { ShortcutOptions,ShortcutBinding,ModifierState } from './model.types' + +export const shortcut = { + all_shortcuts: {} as Record, + + add: function (shortcut_combination: string, callback: (e: KeyboardEvent) => void, opt?: ShortcutOptions): void { + if (!shortcut_combination || typeof shortcut_combination !== 'string') { + throw new Error('Shortcut combination must be a non-empty string'); + } + if (!callback || typeof callback !== 'function') { + throw new Error('Callback must be a function'); + } + + const options = this.getOptions(opt); + const ele = this.getTargetElement(options.target); + shortcut_combination = shortcut_combination.toLowerCase(); + + const func = this.createEventListener(shortcut_combination, callback, options); + this.registerShortcut(shortcut_combination, func, ele, options.type || 'keydown'); + }, + + remove: function (shortcut_combination: string): void { + shortcut_combination = shortcut_combination.toLowerCase(); + const binding = this.all_shortcuts[shortcut_combination]; + + if (binding) { + this.unregisterShortcut(binding); + delete this.all_shortcuts[shortcut_combination]; + } else { + console.warn(`No binding found for shortcut: ${shortcut_combination}`); + } + }, + + removeAll: function (): void { + const failures: string[] = []; + Object.keys(this.all_shortcuts).forEach(shortcut => { + try { + this.remove(shortcut); + } catch (error) { + failures.push(shortcut); + console.error(`Failed to remove shortcut ${shortcut}: ${error}`); + } + }); + if (failures.length > 0) { + console.warn(`Failed to remove ${failures.length} shortcuts: ${failures.join(', ')}`); + } + }, + + getOptions: function (opt?: ShortcutOptions): ShortcutOptions { + const default_options: ShortcutOptions = { + type: 'keydown', + propagate: false, + disable_in_input: true, + target: document, + keycode: false, + }; + return opt ? { ...default_options, ...opt } : default_options; + }, + + getTargetElement: function (target: Document | string | undefined): Document | HTMLElement { + if (typeof target === 'string') { + return document.getElementById(target) || document; + } + return target || document; + }, + + createEventListener: function (shortcut_combination: string, callback: (e: KeyboardEvent) => void, options: ShortcutOptions): EventListener { + return (evt: Event): void => { + const e = evt as KeyboardEvent; + + if (this.shouldIgnoreEvent(e, options)) { + return; + } + + if (this.isShortcutMatch(shortcut_combination, e, options)) { + this.handleShortcutMatch(e, callback, options); + } + }; + }, + + shouldIgnoreEvent: function (e: KeyboardEvent, options: ShortcutOptions): boolean { + return (options.disable_in_input ?? true) && this.isInputElement(e.target as HTMLElement); + }, + + handleShortcutMatch: function (e: KeyboardEvent, callback: (e: KeyboardEvent) => void, options: ShortcutOptions): void { + callback(e); + + if (!options.propagate) { + e.stopPropagation(); + e.preventDefault(); + } + }, + + isInputElement: function (element: HTMLElement): boolean { + if (element.nodeType === 3 && element.parentNode) { + element = element.parentNode as HTMLElement; + } else if (element.nodeType === 3) { + return true; + } + return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA'; + }, + + isShortcutMatch: function (shortcut_combination: string, e: KeyboardEvent, options: ShortcutOptions): boolean { + const keys = shortcut_combination.split('+'); + const modifiers = this.getModifiersState(keys, e); + const character = this.getCharacterFromKeyCode(e); + + return this.checkKeysMatch(keys, character, e, options) && + this.checkModifiersMatch(modifiers); + }, + + getModifiersState: function (keys: string[], e: KeyboardEvent): Record { + const modifiers: Record = { + shift: { wanted: false, pressed: e.shiftKey }, + ctrl: { wanted: false, pressed: e.ctrlKey }, + alt: { wanted: false, pressed: e.altKey }, + meta: { wanted: false, pressed: e.metaKey } + }; + + keys.forEach(k => { + if (k === 'ctrl' || k === 'control') modifiers.ctrl.wanted = true; + else if (k === 'shift') modifiers.shift.wanted = true; + else if (k === 'alt') modifiers.alt.wanted = true; + else if (k === 'meta') modifiers.meta.wanted = true; + }); + + return modifiers; + }, + + getCharacterFromKeyCode: function (e: KeyboardEvent): string { + const code = e.keyCode || e.which; + let character = String.fromCharCode(code).toLowerCase(); + + if (code === 188) character = ','; + if (code === 190) character = '.'; + + return character; + }, + + checkKeysMatch: function (keys: string[], character: string, e: KeyboardEvent, options: ShortcutOptions): boolean { + let kp = 0; + + keys.forEach(k => { + if (this.isModifierKey(k)) { + kp++; + } else if (this.isSpecialKeyMatch(k, e)) { + kp++; + } else if (options.keycode && this.isKeyCodeMatch(options.keycode, e)) { + kp++; + } else if (this.isCharacterMatch(k, character, e)) { + kp++; + } + }); + + return kp === keys.length; + }, + + isModifierKey: function (key: string): boolean { + return key === 'ctrl' || key === 'control' || key === 'shift' || key === 'alt' || key === 'meta'; + }, + + isSpecialKeyMatch: function (key: string, e: KeyboardEvent): boolean { + const special_keys: Record = { + esc: 27, escape: 27, tab: 9, space: 32, return: 13, enter: 13, backspace: 8, + scrolllock: 145, scroll_lock: 145, scroll: 145, capslock: 20, caps_lock: 20, caps: 20, + numlock: 144, num_lock: 144, num: 144, pause: 19, break: 19, insert: 45, home: 36, + delete: 46, end: 35, pageup: 33, page_up: 33, pu: 33, pagedown: 34, page_down: 34, pd: 34, + left: 37, up: 38, right: 39, down: 40, f1: 112, f2: 113, f3: 114, f4: 115, f5: 116, + f6: 117, f7: 118, f8: 119, f9: 120, f10: 121, f11: 122, f12: 123 + }; + + return special_keys[key] === (e.keyCode || e.which); + }, + + isKeyCodeMatch: function (keycode: number | false, e: KeyboardEvent): boolean { + return keycode === (e.keyCode || e.which); + }, + + isCharacterMatch: function (key: string, character: string, e: KeyboardEvent): boolean { + const shift_nums: Record = { + '`': '~', 1: '!', 2: '@', 3: '#', 4: '$', 5: '%', 6: '^', 7: '&', 8: '*', 9: '(', 0: ')', + '-': '_', '=': '+', ';': ':', "'": '"', ',': '<', '.': '>', '/': '?', '\\': '|' + }; + + if (character === key) { + return true; + } else if (shift_nums[character] && e.shiftKey) { + return shift_nums[character] === key; + } + + return false; + }, + + checkModifiersMatch: function (modifiers: Record): boolean { + return modifiers.ctrl.pressed === modifiers.ctrl.wanted && + modifiers.shift.pressed === modifiers.shift.wanted && + modifiers.alt.pressed === modifiers.alt.wanted && + modifiers.meta.pressed === modifiers.meta.wanted; + }, + + registerShortcut: function (shortcut_combination: string, func: EventListener, ele: Document | HTMLElement, event: string): void { + this.all_shortcuts[shortcut_combination] = { + callback: func, + target: ele, + event: event + }; + + if (ele.addEventListener) { + ele.addEventListener(event, func, false); + } else if ((ele as any).attachEvent) { + (ele as any).attachEvent('on' + event, func); + } else { + (ele as any)['on' + event] = func; + } + }, + + unregisterShortcut: function (binding: ShortcutBinding): void { + const { target, callback, event } = binding; + + try { + if (target.removeEventListener) { + target.removeEventListener(event, callback); + } else if ((target as any).detachEvent) { + (target as any).detachEvent('on' + event, callback); + } else { + (target as any)['on' + event] = null; + } + } catch (error) { + console.warn(`Failed to remove event Listener: ${error}`); + } + } +}; \ No newline at end of file diff --git a/v0/src/simulator/src/hotkey_binder/model/utils.js b/v0/src/simulator/src/hotkey_binder/model/utils.js deleted file mode 100644 index 8a2a8a8b..00000000 --- a/v0/src/simulator/src/hotkey_binder/model/utils.js +++ /dev/null @@ -1,67 +0,0 @@ -Storage.prototype.set = function (key, obj) { - return this.setItem(key, JSON.stringify(obj)) -} - -Storage.prototype.get = function (key) { - return JSON.parse(this.getItem(key)) -} - -Object.size = function (obj) { - var size = 0, - key - for (key in obj) { - if (obj.hasOwnProperty(key)) size++ - } - return size -} - -export const getKey = (obj, val) => - Object.keys(obj).find((key) => obj[key] === val) - -export const getOS = () => { - let OSName = '' - if (navigator.appVersion.indexOf('Win') != -1) OSName = 'Windows' - if (navigator.appVersion.indexOf('Mac') != -1) OSName = 'MacOS' - if (navigator.appVersion.indexOf('X11') != -1) OSName = 'UNIX' - if (navigator.appVersion.indexOf('Linux') != -1) OSName = 'Linux' - return OSName -} - -export const checkRestricted = (key) => { - const restrictedKeys = [ - 'Ctrl + N', - 'Ctrl + W', - 'Ctrl + T', - 'Ctrl + C', - 'Ctrl + V', - 'Ctrl + Delete', - 'Ctrl + Backspace', - 'Ctrl + /', - 'Ctrl + \\', - 'Ctrl + ]', - "Ctrl + '", - 'Ctrl + `', - 'Ctrl + [', - 'Ctrl + ~', - 'Ctrl + Num1', - 'Ctrl + Num2', - 'Ctrl + Num3', - 'Ctrl + Num4', - 'Ctrl + Num5', - 'Ctrl + Num6', - 'Ctrl + Num*', - 'Ctrl + Num/', - 'Ctrl + Num.', - 'Ctrl + Num0', - ] - if (getOS == 'macOS') { - restrictedKeys.forEach((value, i) => { - if (value.split(' + ')[0] == 'Ctrl'); - restrictedKeys[i] = - value.split(' + ')[0] == 'Ctrl' - ? value.replace('Ctrl', 'Meta') - : value - }) - } - return restrictedKeys.includes(key) -} diff --git a/v0/src/simulator/src/hotkey_binder/model/utils.ts b/v0/src/simulator/src/hotkey_binder/model/utils.ts new file mode 100644 index 00000000..8e51b981 --- /dev/null +++ b/v0/src/simulator/src/hotkey_binder/model/utils.ts @@ -0,0 +1,74 @@ +// Add type-safe set method to Storage Prototype +Storage.prototype.set = function(key: string, obj: T): void { + this.setItem(key, JSON.stringify(obj)); +} + +// Add type-safe get method to Storage prototype +Storage.prototype.get = function(key: string): T | null { + const item = this.getItem(key); + if (!item) return null; + try { + return JSON.parse(item) as T; + } catch (e) { + console.error(`Failed to parse stored item ${key}:`, e); + return null; + } + +} + +// Type-safe object size function +export function objectSize(obj: Record): number { + return Object.keys(obj).length; +} + +// Find key by value in an object +export function getKey>(obj: T, val: any): string | undefined { + return Object.keys(obj).find(key => { + const value = obj[key]; + if (typeof value === 'object' && value !== null) { + return JSON.stringify(value) === JSON.stringify(val); + } + return value === val; + }); +} + +// OS detection patterns +const OS_PATTERNS: Record = { + 'Windows': /windows/i, + 'MacOS': /mac/i, + 'Linux': /linux/i, + 'UNIX': /x11/i +}; +export function getOS(): string { + const userInput = `${navigator.platform} ${navigator.userAgent}`.toLowerCase(); + + for (const [os, pattern] of Object.entries(OS_PATTERNS)) { + if (pattern.test(userInput)) { + return os; + } + } + + return ''; +} +// Check for restricted key combinations +export function checkRestricted(key: string): boolean { + const restrictedKeys: string[] = [ + 'Ctrl + N', 'Ctrl + W', 'Ctrl + T', 'Ctrl + C', 'Ctrl + V', + 'Ctrl + Delete', 'Ctrl + Backspace', 'Ctrl + /', 'Ctrl + \\', + 'Ctrl + ]', "Ctrl + '", 'Ctrl + `', 'Ctrl + [', 'Ctrl + ~', + 'Ctrl + Num1', 'Ctrl + Num2', 'Ctrl + Num3', 'Ctrl + Num4', + 'Ctrl + Num5', 'Ctrl + Num6', 'Ctrl + Num*', 'Ctrl + Num/', + 'Ctrl + Num.', 'Ctrl + Num0' + ]; + + // Adjust for MacOS if needed + const modifiedKeys = getOS() === 'MacOS' + ? restrictedKeys.map(value => + value.startsWith('Ctrl') + ? value.replace('Ctrl', 'Meta') + : value + ) + : restrictedKeys; + + return modifiedKeys.includes(key); +} \ No newline at end of file diff --git a/v0/src/simulator/src/interface/backgroundArea.ts b/v0/src/simulator/src/interface/backgroundArea.ts new file mode 100644 index 00000000..e4d08e13 --- /dev/null +++ b/v0/src/simulator/src/interface/backgroundArea.ts @@ -0,0 +1,6 @@ +export interface BackgroundArea { + canvas: HTMLCanvasElement | null; + context: CanvasRenderingContext2D | null; + setup(): void; + clear(): void; +} \ No newline at end of file diff --git a/v0/src/simulator/src/interface/simulationArea.ts b/v0/src/simulator/src/interface/simulationArea.ts new file mode 100644 index 00000000..de181800 --- /dev/null +++ b/v0/src/simulator/src/interface/simulationArea.ts @@ -0,0 +1,39 @@ +import { EventQueue } from '../eventQueue' +export interface SimulationArea { + canvas: HTMLCanvasElement; + context: CanvasRenderingContext2D|null; + selected: boolean; + hover: boolean; + clockState: number; + clockEnabled: boolean; + // TODO: make this CircuitElement|null once converted to typescript + lastSelected: any|null; + stack: any[]; + prevScale: number; + oldx: number; + oldy: number; + objectList: any[]; + maxHeight: number; + maxWidth: number; + minHeight: number; + minWidth: number; + multipleObjectSelections: any[]; + copyList: any[]; + shiftDown: boolean; + controlDown: boolean; + timePeriod: number; + mouseX: number; + mouseY: number; + mouseDownX: number; + mouseDownY: number; + simulationQueue: EventQueue; + clickCount: number; + lock: string; + mouseDown: boolean; + ClockInterval: NodeJS.Timeout|null; + touch: boolean; + timer: () => void; + setup: () => void; + changeClockTime: (t: number) => void; + clear: () => void; +} \ No newline at end of file diff --git a/v1/src/simulator/src/layout/layoutBuffer.js b/v0/src/simulator/src/layout/layoutBuffer.ts similarity index 87% rename from v1/src/simulator/src/layout/layoutBuffer.js rename to v0/src/simulator/src/layout/layoutBuffer.ts index 1c339d28..c5705b77 100644 --- a/v1/src/simulator/src/layout/layoutBuffer.js +++ b/v0/src/simulator/src/layout/layoutBuffer.ts @@ -1,3 +1,4 @@ +import CircuitElement from '../circuitElement' import LayoutNode from './layoutNode' /** * Buffer object to store changes so that you can reset changes @@ -6,6 +7,18 @@ import LayoutNode from './layoutNode' * @category layout */ export default class LayoutBuffer { + layout: { + width: number + height: number + x: number + y: number + title_x: number + title_y: number + titleEnabled: boolean + } + Input: LayoutNode[] + Output: LayoutNode[] + subElements: CircuitElement[] constructor(scope = globalScope) { var w = 300 * DPR var h = 50 * DPR @@ -53,7 +66,7 @@ export default class LayoutBuffer { * Check if position is on the boundaries of subcircuit * if the desired width and heiht is allowed */ - isAllowed(x, y) { + isAllowed(x: number, y: number) { if (x < 0 || x > this.layout.width || y < 0 || y > this.layout.height) return false if (x > 0 && x < this.layout.width && y > 0 && y < this.layout.height) @@ -76,7 +89,7 @@ export default class LayoutBuffer { * Function is called while decreasing height to * check if it is possible without moving other node */ - isNodeAt(x, y) { + isNodeAt(x: number, y: number) { for (let i = 0; i < this.Input.length; i++) { if (this.Input[i].x === x && this.Input[i].y === y) return true } diff --git a/v1/src/simulator/src/layout/layoutNode.js b/v0/src/simulator/src/layout/layoutNode.ts similarity index 85% rename from v1/src/simulator/src/layout/layoutNode.js rename to v0/src/simulator/src/layout/layoutNode.ts index ddf199b3..33d55d4f 100644 --- a/v1/src/simulator/src/layout/layoutNode.js +++ b/v0/src/simulator/src/layout/layoutNode.ts @@ -1,21 +1,28 @@ import { drawCircle } from '../canvasApi' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { tempBuffer } from '../layoutMode' +import CircuitElement from '../circuitElement' /** - * @class - * @param {number} x - x coord of node - * @param {number} y - y coord of node - * @param {strng} id - id for node - * @param {string=} label - label for the node - * @param {number} xx - parent x - * @param {number} yy - parent y - * @param {number} type - input or output node - * @param {CircuitElement} parent parent of the node * @category layout */ export default class LayoutNode { - constructor(x, y, id, label = '', type, parent) { + x: number + y: number + prevx: number | undefined + prevy: number | undefined + radius: number + clicked: boolean + hover: boolean + wasClicked: boolean + prev: string + count: number + objectType: string + type: number + id: string + label: string + parent: CircuitElement + constructor(x: number, y: number, id: string, label = '', type: number, parent: CircuitElement) { this.type = type this.id = id diff --git a/v0/src/simulator/src/layoutMode.js b/v0/src/simulator/src/layoutMode.ts similarity index 83% rename from v0/src/simulator/src/layoutMode.js rename to v0/src/simulator/src/layoutMode.ts index c400cb71..5c548db6 100644 --- a/v0/src/simulator/src/layoutMode.js +++ b/v0/src/simulator/src/layoutMode.ts @@ -2,9 +2,8 @@ /* eslint-disable no-continue */ import { dots, correctWidth, fillText, rect2 } from './canvasApi' import LayoutBuffer from './layout/layoutBuffer' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { - hideProperties, fillSubcircuitElements, prevPropertyObjGet, prevPropertyObjSet, @@ -19,8 +18,11 @@ import { } from './engine' import miniMapArea from './minimap' import { showMessage } from './utils' -import * as metadata from './metadata.json' -import { verilogModeGet, verilogModeSet } from './Verilog2CV' +import { verilogModeSet } from './Verilog2CV' +import { useLayoutStore } from '#/store/layoutStore' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' +import { circuitElementList } from './metadata' /** * Layout.js - all subcircuit layout related code is here @@ -31,11 +33,11 @@ import { verilogModeGet, verilogModeSet } from './Verilog2CV' var layoutMode = false -export function layoutModeSet(param) { +export function layoutModeSet(param: boolean) { layoutMode = param } -export function layoutModeGet(param) { +export function layoutModeGet() { return layoutMode } @@ -43,15 +45,13 @@ export function layoutModeGet(param) { * @type {LayoutBuffer} - used to temporartily store all changes. * @category layoutMode */ -export var tempBuffer +export var tempBuffer: LayoutBuffer /** * Helper function to determine alignment and position of nodes for rendering - * @param {number} x - width of label - * @param {number} y - height of label * @category layoutMode */ -export function determineLabel(x, y) { +export function determineLabel(x: number, y: number) { if (x === 0) return ['left', 5, 5] if (x === tempBuffer.layout.width) return ['right', -5, 5] if (y === 0) return ['center', 0, 13] @@ -148,8 +148,8 @@ export function renderLayout(scope = globalScope) { fillText( ctx, tempBuffer.Input[i].label, - tempBuffer.Input[i].x + info[1], - tempBuffer.Input[i].y + info[2], + tempBuffer.Input[i].x + typeof info[1] === 'number' ? info[1] : parseInt(info[1] as string), + tempBuffer.Input[i].y + typeof info[2] === 'number' ? info[2] : parseInt(info[2] as string), 12 ) } @@ -164,8 +164,8 @@ export function renderLayout(scope = globalScope) { fillText( ctx, tempBuffer.Output[i].label, - tempBuffer.Output[i].x + info[1], - tempBuffer.Output[i].y + info[2], + tempBuffer.Output[i].x + typeof info[1] === 'number' ? info[1] : parseInt(info[1] as string), + tempBuffer.Output[i].y + typeof info[2] === 'number' ? info[2] : parseInt(info[2] as string), 12 ) } @@ -446,29 +446,25 @@ export function saveLayout() { * @category layoutMode */ export function toggleLayoutMode() { - // hideProperties() - // lines from hideProperty function() <--- + const layoutStore = toRefs(useLayoutStore()) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) prevPropertyObjSet(undefined) $('.objectPropertyAttribute').unbind('change keyup paste click') if (layoutModeGet()) { layoutModeSet(false) - $('#layoutDialog').fadeOut() - $('.layoutElementPanel').fadeOut() - $('.elementPanel').fadeIn() - $('.timing-diagram-panel').fadeIn() - $('.testbench-manual-panel').fadeIn() + layoutStore.layoutMode.value = false globalScope.centerFocus(false) - if (globalScope.verilogMetadata.isVerilogCircuit) verilogModeSet(true) + if (globalScope.verilogMetadata.isVerilogCircuit) { + verilogModeSet(true) + simulatorMobileStore.isVerilog.value = true + } dots() } else { layoutModeSet(true) verilogModeSet(false) - $('#layoutDialog').fadeIn() - $('.layoutElementPanel').fadeIn() - $('.elementPanel').fadeOut() - $('.timing-diagram-panel').fadeOut() - $('.testbench-manual-panel').fadeOut() + layoutStore.layoutMode.value = true + simulatorMobileStore.isVerilog.value = false fillSubcircuitElements() globalScope.ox = 0 @@ -476,7 +472,6 @@ export function toggleLayoutMode() { globalScope.scale = DPR * 1.3 dots() tempBuffer = new LayoutBuffer() - // $('#toggleLayoutTitle')[0].checked = tempBuffer.layout.titleEnabled } update(globalScope, true) scheduleUpdate() @@ -497,48 +492,3 @@ export const layoutFunctions = { saveLayout, toggleLayoutMode, } - -// export function setupLayoutModePanelListeners() { -// $('#decreaseLayoutWidth').on('click', () => { -// decreaseLayoutWidth() -// }) -// $('#increaseLayoutWidth').on('click', () => { -// increaseLayoutWidth() -// }) -// $('#decreaseLayoutHeight').on('click', () => { -// decreaseLayoutHeight() -// }) -// $('#increaseLayoutHeight').on('click', () => { -// increaseLayoutHeight() -// }) -// $('#layoutResetNodes').on('click', () => { -// layoutResetNodes() -// }) -// $('#layoutTitleUp').on('click', () => { -// layoutTitleUp() -// }) -// $('#layoutTitleDown').on('click', () => { -// layoutTitleDown() -// }) -// $('#layoutTitleLeft').on('click', () => { -// layoutTitleLeft() -// }) -// $('#layoutTitleRight').on('click', () => { -// layoutTitleRight() -// }) -// $('#toggleLayoutTitle').on('click', () => { -// toggleLayoutTitle() -// }) -// $('#saveLayout').on('click', () => { -// saveLayout() -// }) -// $('#cancelLayout').on('click', () => { -// cancelLayout() -// }) -// $('#layoutDialog button').on('click', () => { -// scheduleUpdate() -// }) -// $('#layoutDialog input').on('click', () => { -// scheduleUpdate() -// }) -// } diff --git a/v0/src/simulator/src/listeners.js b/v0/src/simulator/src/listeners.js index 460be076..6db5661a 100644 --- a/v0/src/simulator/src/listeners.js +++ b/v0/src/simulator/src/listeners.js @@ -1,11 +1,18 @@ +/* eslint-disable no-shadow */ +/* eslint-disable no-negated-condition */ +/* eslint-disable no-alert */ +/* eslint-disable new-cap */ +/* eslint-disable no-undef */ +/* eslint-disable eqeqeq */ +/* eslint-disable prefer-template */ +/* eslint-disable no-param-reassign */ // Most Listeners are stored here import { layoutModeGet, tempBuffer, layoutUpdate, - // setupLayoutModePanelListeners, } from './layoutMode' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, update, @@ -17,127 +24,298 @@ import { gridUpdateSet, errorDetectedSet, } from './engine' -import { changeScale } from './canvasApi' +import { changeScale, findDimensions } from './canvasApi' import { scheduleBackup } from './data/backupCircuit' -import { - hideProperties, - deleteSelected, - uxvar, - fullView, - exitFullView, -} from './ux' -import { - updateRestrictedElementsList, - updateRestrictedElementsInScope, - hideRestricted, - showRestricted, -} from './restrictedElementDiv' +import { hideProperties, deleteSelected, uxvar, exitFullView } from './ux'; +import { updateRestrictedElementsList, updateRestrictedElementsInScope, hideRestricted, showRestricted } from './restrictedElementDiv'; import { removeMiniMap, updatelastMinimapShown } from './minimap' import undo from './data/undo' import redo from './data/redo' import { copy, paste, selectAll } from './events' -import save from './data/save' import { verilogModeGet } from './Verilog2CV' import { setupTimingListeners } from './plotArea' +import logixFunction from './data' +import { listen } from '@tauri-apps/api/event' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' + +const unit = 10 +let listenToSimulator = true +let coordinate; +const returnCoordinate = { + x: 0, + y: 0 +} -var unit = 10 -var listenToSimulator = true +let currDistance = 0; +let distance = 0; +let pinchZ = 0; +let centreX; +let centreY; +let timeout; +let lastTap = 0; + +/** + * + * @param {event} e + * function for double click or double tap + */ +function onDoubleClickorTap(e) { + updateCanvasSet(true); + if (simulationArea.lastSelected && simulationArea.lastSelected.dblclick !== undefined) { + simulationArea.lastSelected.dblclick(); + } else if (!simulationArea.shiftDown) { + simulationArea.multipleObjectSelections = []; + } + scheduleUpdate(2); + e.preventDefault(); +} -export default function startListeners() { - // added the below functionalities in QuickButton.vue component local script tag part - - // $('#deleteSelected').on('click', () => { - // deleteSelected() - // }) - - // $('#zoomIn').on('click', () => { - // changeScale(0.2, 'zoomButton', 'zoomButton', 2) - // }) - - // $('#zoomOut').on('click', () => { - // changeScale(-0.2, 'zoomButton', 'zoomButton', 2) - // }) - - // $('#undoButton').on('click', () => { - // undo() - // }) - // $('#redoButton').on('click', () => { - // redo() - // }) - // $('#viewButton').on('click', () => { - // fullView() - // }) +/** + * + * @param {event} e + * function to detect tap and double tap + */ +function getTap(e) { + const currentTime = new Date().getTime(); + const tapLength = currentTime - lastTap; + clearTimeout(timeout); + if (tapLength < 500 && tapLength > 0) { + onDoubleClickorTap(e); + } else { + // Single tap + } + lastTap = currentTime; + e.preventDefault(); +} + +const isIe = (navigator.userAgent.toLowerCase().indexOf('msie') != -1 || navigator.userAgent.toLowerCase().indexOf('trident') != -1); + +// Function to getCoordinate +// *If touch is enable then it will return touch coordinate +// *else it will return mouse coordinate +// +export function getCoordinate(e) { + if (simulationArea.touch) { + returnCoordinate.x = e.touches[0].clientX; + returnCoordinate.y = e.touches[0].clientY; + return returnCoordinate; + } + + if (!simulationArea.touch) { + returnCoordinate.x = e.clientX; + returnCoordinate.y = e.clientY; + return returnCoordinate; + } + + return returnCoordinate; +} + +/* Function for Panstop on simulator + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +export function pinchZoom(e, globalScope) { + e.preventDefault(); + gridUpdateSet(true); + scheduleUpdate(); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + // Calculating distance between touch to see if its pinchIN or pinchOut + distance = Math.sqrt((e.touches[1].clientX - e.touches[0].clientX) ** 2, (e.touches[1].clientY - e.touches[0].clientY) ** 2); + if (distance >= currDistance) { + pinchZ += 0.02; + currDistance = distance; + } else if (currDistance >= distance) { + pinchZ -= 0.02; + currDistance = distance; + } + if (pinchZ >= 2) { + pinchZ = 2; + } + else if (pinchZ <= 0.5) { + pinchZ = 0.5; + } + const oldScale = globalScope.scale; + globalScope.scale = Math.max(0.5, Math.min(4 * DPR, pinchZ * 3)); + globalScope.scale = Math.round(globalScope.scale * 10) / 10; + // This is not working as expected + centreX = (e.touches[0].clientX + e.touches[1].clientX) / 2; + centreY = (e.touches[0].clientY + e.touches[1].clientY) / 2; + const rect = simulationArea.canvas.getBoundingClientRect(); + const RawX = (centreX - rect.left) * DPR; + const RawY = (centreY - rect.top) * DPR; + const Xf = Math.round(((RawX - globalScope.ox) / globalScope.scale) / unit); + const Yf = Math.round(((RawY - globalScope.ox) / globalScope.scale) / unit); + const currCentreX = Math.round(Xf / unit) * unit; + const currCentreY = Math.round(Yf / unit) * unit; + globalScope.ox = Math.round(currCentreX * (globalScope.scale - oldScale)); + globalScope.oy = Math.round(currCentreY * (globalScope.scale - oldScale)); + gridUpdateSet(true); + scheduleUpdate(1); +} + +/* + *Function to start the pan in simulator + *Works for both touch and Mouse + *For now variable name starts from mouse like mouseDown are used both + touch and mouse will change in future + */ +export function panStart(e) { + coordinate = getCoordinate(e); + simulationArea.mouseDown = true; + // Deselect Input + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + simulationArea.lastSelected = undefined; + simulationArea.selected = false; + simulationArea.hover = undefined; + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseDownRawX = (coordinate.x - rect.left) * DPR; + simulationArea.mouseDownRawY = (coordinate.y - rect.top) * DPR; + simulationArea.mouseDownX = Math.round(((simulationArea.mouseDownRawX - globalScope.ox) / globalScope.scale) / unit) * unit; + simulationArea.mouseDownY = Math.round(((simulationArea.mouseDownRawY - globalScope.oy) / globalScope.scale) / unit) * unit; + if (simulationArea.touch) { + simulationArea.mouseX = simulationArea.mouseDownX; + simulationArea.mouseY = simulationArea.mouseDownY; + } + + simulationArea.oldx = globalScope.ox; + simulationArea.oldy = globalScope.oy; + e.preventDefault(); + scheduleBackup(); + scheduleUpdate(1); + $('.dropdown.open').removeClass('open'); +} + +/* + * Function to pan in simulator + * Works for both touch and Mouse + * Pinch to zoom also implemented in the same + * For now variable name starts from mouse like mouseDown are used both + touch and mouse will change in future + */ + +export function panMove(e) { + // If only one it touched + // pan left or right + if (!simulationArea.touch || e.touches.length === 1) { + coordinate = getCoordinate(e); + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseRawX = (coordinate.x - rect.left) * DPR; + simulationArea.mouseRawY = (coordinate.y - rect.top) * DPR; + simulationArea.mouseXf = (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale; + simulationArea.mouseYf = (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale; + simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit; + simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit; + updateCanvasSet(true); + if (simulationArea.lastSelected && (simulationArea.mouseDown || simulationArea.lastSelected.newElement)) { + updateCanvasSet(true); + let fn; + + if (simulationArea.lastSelected == globalScope.root) { + fn = function () { + updateSelectionsAndPane(); + }; + } else { + fn = function () { + if (simulationArea.lastSelected) { + simulationArea.lastSelected.update(); + } + }; + } + + scheduleUpdate(0, 20, fn); + } else { + scheduleUpdate(0, 200); + } + } + // If two fingures are touched + // pinchZoom + if (simulationArea.touch && e.touches.length === 2) { + pinchZoom(e, globalScope); + } +} + +export function panStop(e) { + const simulatorMobileStore = useSimulatorMobileStore() + simulationArea.mouseDown = false; + if (!lightMode) { + updatelastMinimapShown(); + setTimeout(removeMiniMap, 2000); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + + scheduleUpdate(1); + simulationArea.mouseDown = false; + + // eslint-disable-next-line no-plusplus + for (let i = 0; i < 2; i++) { + updatePositionSet(true); + wireToBeCheckedSet(1); + update(); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + + scheduleUpdate(1); + // Var rect = simulationArea.canvas.getBoundingClientRect(); + + if (!(simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height)) { + uxvar.smartDropXX = simulationArea.mouseX + 100; // Math.round(((simulationArea.mouseRawX - globalScope.ox+100) / globalScope.scale) / unit) * unit; + uxvar.smartDropYY = simulationArea.mouseY - 50; // Math.round(((simulationArea.mouseRawY - globalScope.oy+100) / globalScope.scale) / unit) * unit; + } + + if (simulationArea.touch) { + const { isCopy } = toRefs(simulatorMobileStore) + // small hack so Current circuit element should not spwan above last circuit element + if (!isCopy.value) { + findDimensions(globalScope); + simulationArea.mouseX = 100 + simulationArea.maxWidth || 0; + simulationArea.mouseY = simulationArea.minHeight || 0; + getTap(e); + } + } +} + +export default function startListeners() { $(document).on('keyup', (e) => { if (e.key === 'Escape') exitFullView() }) $('#projectName').on('click', () => { - simulationArea.lastSelected = globalScope.root - setTimeout(() => { - document.getElementById('projname').select() - }, 100) - }) - /* Makes tabs reordering possible by making them sortable */ - // $("#tabsBar").sortable({ - // containment: 'parent', - // items: '> div', - // revert: false, - // opacity: 0.5, - // tolerance: 'pointer', - // placeholder: 'placeholder', - // forcePlaceholderSize: true, - // }); + simulationArea.lastSelected = globalScope.root; + setTimeout(() => { + document.getElementById("projname").select(); + }, 100); + }); - document - .getElementById('simulationArea') - .addEventListener('mousedown', (e) => { - simulationArea.mouseDown = true - - // Deselect Input - if (document.activeElement instanceof HTMLElement) - document.activeElement.blur() - - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - - simulationArea.lastSelected = undefined - simulationArea.selected = false - simulationArea.hover = undefined - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseDownRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseDownRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseDownX = - Math.round( - (simulationArea.mouseDownRawX - globalScope.ox) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDownY = - Math.round( - (simulationArea.mouseDownRawY - globalScope.oy) / - globalScope.scale / - unit - ) * unit - simulationArea.oldx = globalScope.ox - simulationArea.oldy = globalScope.oy - - e.preventDefault() - scheduleBackup() - scheduleUpdate(1) - $('.dropdown.open').removeClass('open') - }) document .getElementById('simulationArea') .addEventListener('mouseup', (e) => { - if (simulationArea.lastSelected) + if (simulationArea.lastSelected) { simulationArea.lastSelected.newElement = false - /* - handling restricted circuit elements - */ - + } + // handling restricted circuit elements if ( simulationArea.lastSelected && restrictedElements.includes( @@ -153,7 +331,7 @@ export default function startListeners() { updateRestrictedElementsList() } - // deselect multible elements with click + // deselect multible elements with click if ( !simulationArea.shiftDown && simulationArea.multipleObjectSelections.length > 0 @@ -167,9 +345,6 @@ export default function startListeners() { } } }) - document - .getElementById('simulationArea') - .addEventListener('mousemove', onMouseMove) window.addEventListener('keyup', (e) => { scheduleUpdate(1) @@ -220,10 +395,6 @@ export default function startListeners() { if (listenToSimulator) { // If mouse is focusing on input element, then override any action - // if($(':focus').length){ - // return; - // } - if ( document.activeElement.tagName == 'INPUT' || simulationArea.mouseRawX < 0 || @@ -279,18 +450,6 @@ export default function startListeners() { updateCanvasSet(true) wireToBeCheckedSet(1) - // Needs to be deprecated, moved to more recent listeners - if ( - simulationArea.controlDown && - (e.key == 'C' || e.key == 'c') - ) { - // simulationArea.copyList=simulationArea.multipleObjectSelections.slice(); - // if(simulationArea.lastSelected&&simulationArea.lastSelected!==simulationArea.root&&!simulationArea.copyList.contains(simulationArea.lastSelected)){ - // simulationArea.copyList.push(simulationArea.lastSelected); - // } - // copy(simulationArea.copyList); - } - if ( simulationArea.lastSelected && simulationArea.lastSelected.keyDown @@ -344,7 +503,7 @@ export default function startListeners() { simulationArea.lastSelected.objectType != 'Wire' && simulationArea.lastSelected.objectType != 'CircuitElement' && - !simulationArea.multipleObjectSelections.contains( + !simulationArea.multipleObjectSelections.includes( simulationArea.lastSelected ) ) { @@ -407,31 +566,9 @@ export default function startListeners() { true ) - document - .getElementById('simulationArea') - .addEventListener('dblclick', (e) => { - updateCanvasSet(true) - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.dblclick !== undefined - ) { - simulationArea.lastSelected.dblclick() - } else if (!simulationArea.shiftDown) { - simulationArea.multipleObjectSelections = [] - } - scheduleUpdate(2) - }) - - document - .getElementById('simulationArea') - .addEventListener('mouseup', onMouseUp) - - document - .getElementById('simulationArea') - .addEventListener('mousewheel', MouseScroll) - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', MouseScroll) + document.getElementById('simulationArea').addEventListener('dblclick', e => { + onDoubleClickorTap(e); + }); function MouseScroll(event) { updateCanvasSet(true) @@ -448,6 +585,13 @@ export default function startListeners() { else update() // Schedule update not working, this is INEFFICIENT } + document + .getElementById('simulationArea') + .addEventListener('mousewheel', MouseScroll) + document + .getElementById('simulationArea') + .addEventListener('DOMMouseScroll', MouseScroll) + document.addEventListener('cut', (e) => { if (verilogModeGet()) return if (document.activeElement.tagName == 'INPUT') return @@ -459,12 +603,12 @@ export default function startListeners() { if ( simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && - !simulationArea.copyList.contains(simulationArea.lastSelected) + !simulationArea.copyList.includes(simulationArea.lastSelected) ) { simulationArea.copyList.push(simulationArea.lastSelected) } - var textToPutOnClipboard = copy(simulationArea.copyList, true) + const textToPutOnClipboard = copy(simulationArea.copyList, true) // Updated restricted elements updateRestrictedElementsInScope() @@ -490,12 +634,12 @@ export default function startListeners() { if ( simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && - !simulationArea.copyList.contains(simulationArea.lastSelected) + !simulationArea.copyList.includes(simulationArea.lastSelected) ) { simulationArea.copyList.push(simulationArea.lastSelected) } - var textToPutOnClipboard = copy(simulationArea.copyList) + const textToPutOnClipboard = copy(simulationArea.copyList) // Updated restricted elements updateRestrictedElementsInScope() @@ -532,33 +676,25 @@ export default function startListeners() { }) // 'drag and drop' event listener for subcircuit elements in layout mode - $('#subcircuitMenu').on( - 'dragstop', - '.draggableSubcircuitElement', - function (event, ui) { - const sideBarWidth = $('#guide_1')[0].clientWidth - let tempElement - - if (ui.position.top > 10 && ui.position.left > sideBarWidth) { - // make a shallow copy of the element with the new coordinates - tempElement = - globalScope[this.dataset.elementName][ - this.dataset.elementId - ] - - // Changing the coordinate doesn't work yet, nodes get far from element - tempElement.x = ui.position.left - sideBarWidth - tempElement.y = ui.position.top - for (let node of tempElement.nodeList) { - node.x = ui.position.left - sideBarWidth - node.y = ui.position.top - } - - tempBuffer.subElements.push(tempElement) - this.parentElement.removeChild(this) + $('#subcircuitMenu').on('dragstop', '.draggableSubcircuitElement', function (event, ui) { + const sideBarWidth = $('#guide_1')[0].clientWidth; + let tempElement; + + if (ui.position.top > 10 && ui.position.left > sideBarWidth) { + // Make a shallow copy of the element with the new coordinates + tempElement = globalScope[this.dataset.elementName][this.dataset.elementId]; + // Changing the coordinate doesn't work yet, nodes get far from element + tempElement.x = ui.position.left - sideBarWidth; + tempElement.y = ui.position.top; + for (const node of tempElement.nodeList) { + node.x = ui.position.left - sideBarWidth; + node.y = ui.position.top; } + + tempBuffer.subElements.push(tempElement); + this.parentElement.removeChild(this); } - ) + }); restrictedElements.forEach((element) => { $(`#${element}`).mouseover(() => { @@ -571,102 +707,15 @@ export default function startListeners() { }) zoomSliderListeners() - // setupLayoutModePanelListeners() if (!embed) { setupTimingListeners() } } -var isIe = - navigator.userAgent.toLowerCase().indexOf('msie') != -1 || - navigator.userAgent.toLowerCase().indexOf('trident') != -1 - -function onMouseMove(e) { - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseXf = - (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale - simulationArea.mouseYf = - (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale - simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit - simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit - - updateCanvasSet(true) - - if ( - simulationArea.lastSelected && - (simulationArea.mouseDown || simulationArea.lastSelected.newElement) - ) { - updateCanvasSet(true) - var fn - - if (simulationArea.lastSelected == globalScope.root) { - fn = function () { - updateSelectionsAndPane() - } - } else { - fn = function () { - if (simulationArea.lastSelected) { - simulationArea.lastSelected.update() - } - } - } - scheduleUpdate(0, 20, fn) - } else { - scheduleUpdate(0, 200) - } -} - -function onMouseUp(e) { - simulationArea.mouseDown = false - if (!lightMode) { - updatelastMinimapShown() - setTimeout(removeMiniMap, 2000) - } - - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - simulationArea.mouseDown = false - - for (var i = 0; i < 2; i++) { - updatePositionSet(true) - wireToBeCheckedSet(1) - update() - } - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - var rect = simulationArea.canvas.getBoundingClientRect() - - if ( - !( - simulationArea.mouseRawX < 0 || - simulationArea.mouseRawY < 0 || - simulationArea.mouseRawX > width || - simulationArea.mouseRawY > height - ) - ) { - uxvar.smartDropXX = simulationArea.mouseX + 100 // Math.round(((simulationArea.mouseRawX - globalScope.ox+100) / globalScope.scale) / unit) * unit; - uxvar.smartDropYY = simulationArea.mouseY - 50 // Math.round(((simulationArea.mouseRawY - globalScope.oy+100) / globalScope.scale) / unit) * unit; - } -} - function resizeTabs() { - var $windowsize = $('body').width() - var $sideBarsize = $('.side').width() - var $maxwidth = $windowsize - $sideBarsize + const $windowsize = $('body').width() + const $sideBarsize = $('.side').width() + const $maxwidth = $windowsize - $sideBarsize $('#tabsBar div').each(function (e) { $(this).css({ 'max-width': $maxwidth - 30 }) }) @@ -675,87 +724,156 @@ function resizeTabs() { window.addEventListener('resize', resizeTabs) resizeTabs() -// $(() => { -// $('[data-toggle="tooltip"]').tooltip() -// }) - // direction is only 1 or -1 -function handleZoom(direction) { - var zoomSlider = $('#customRange1') - var currentSliderValue = parseInt(zoomSlider.val(), 10) - currentSliderValue += direction - +function handleZoom (direction) { if (globalScope.scale > 0.5 * DPR) { - zoomSlider.val(currentSliderValue).change() + changeScale(direction * 0.1 * DPR); } else if (globalScope.scale < 4 * DPR) { - zoomSlider.val(currentSliderValue).change() + changeScale(direction * 0.1 * DPR); } - - gridUpdateSet(true) - scheduleUpdate() -} - -export function ZoomIn() { - handleZoom(1) -} - -export function ZoomOut() { - handleZoom(-1) -} - -function zoomSliderListeners() { - document.getElementById('customRange1').value = 5 - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', zoomSliderScroll) - document - .getElementById('simulationArea') - .addEventListener('mousewheel', zoomSliderScroll) - let curLevel = document.getElementById('customRange1').value + gridUpdateSet(true); + scheduleUpdate(); + } + export function ZoomIn () { + handleZoom(1); + } + export function ZoomOut () { + handleZoom(-1); + } + function zoomSliderListeners () { + document.getElementById("customRange1").value = 5; + document.getElementById('simulationArea').addEventListener('DOMMouseScroll', zoomSliderScroll); + document.getElementById('simulationArea').addEventListener('mousewheel', zoomSliderScroll); + let curLevel = document.getElementById("customRange1").value; $(document).on('input change', '#customRange1', function (e) { - let newValue = $(this).val() - let changeInScale = newValue - curLevel - updateCanvasSet(true) - changeScale(changeInScale * 0.1, 'zoomButton', 'zoomButton', 3) - gridUpdateSet(true) - curLevel = newValue - }) - function zoomSliderScroll(e) { - let zoomLevel = document.getElementById('customRange1').value - let deltaY = e.wheelDelta ? e.wheelDelta : -e.detail - const directionY = deltaY > 0 ? 1 : -1 - if (directionY > 0) zoomLevel++ - else zoomLevel-- - if (zoomLevel >= 45) { - zoomLevel = 45 - document.getElementById('customRange1').value = 45 - } else if (zoomLevel <= 0) { - zoomLevel = 0 - document.getElementById('customRange1').value = 0 - } else { - document.getElementById('customRange1').value = zoomLevel - curLevel = zoomLevel - } + const newValue = $(this).val(); + const changeInScale = newValue - curLevel; + updateCanvasSet(true); + changeScale(changeInScale * 0.1, 'zoomButton', 'zoomButton', 3) + gridUpdateSet(true); + curLevel = newValue; + }); + function zoomSliderScroll (e) { + let zoomLevel = document.getElementById("customRange1").value; + const deltaY = e.wheelDelta ? e.wheelDelta : -e.detail; + const directionY = deltaY > 0 ? 1 : -1; + if (directionY > 0) zoomLevel++ + else zoomLevel-- + if (zoomLevel >= 45) { + zoomLevel = 45; + document.getElementById("customRange1").value = 45; + } else if (zoomLevel <= 0) { + zoomLevel = 0; + document.getElementById("customRange1").value = 0; + } else { + document.getElementById("customRange1").value = zoomLevel; + curLevel = zoomLevel; + } } - - // previously used for the + and - zoom buttons in quickButtons - - // function sliderZoomButton(direction) { - // var zoomSlider = $('#customRange1') - // var currentSliderValue = parseInt(zoomSlider.val(), 10) - // if (direction === -1) { - // currentSliderValue-- - // } else { - // currentSliderValue++ - // } - // zoomSlider.val(currentSliderValue).change() - // } - - // $('#decrement').click(() => { - // sliderZoomButton(-1) - // }) - - // $('#increment').click(() => { - // sliderZoomButton(1) - // }) -} + function sliderZoomButton (direction) { + const zoomSlider = $('#customRange1'); + let currentSliderValue = parseInt(zoomSlider.val(), 10); + if (direction === -1) { + currentSliderValue--; + } else { + currentSliderValue++; + } + zoomSlider.val(currentSliderValue).change(); + } + $('#decrement').click(() => { + sliderZoomButton(-1); + }); + $('#increment').click(() => { + sliderZoomButton(1); + }); + } + +// Desktop App Listeners + +listen('new-project', () => { + logixFunction.newProject(); +}); + +listen('save-online', () => { + logixFunction.save(); +}); + +listen('save-offline', () => { + logixFunction.saveOffline(); +}); + +listen('open-offline', () => { + logixFunction.createOpenLocalPrompt(); +}); + +listen('export', () => { + logixFunction.ExportProject(); +}); + +listen('import', () => { + logixFunction.ImportProject(); +}); + +listen('recover', () => { + logixFunction.recoverProject(); +}); + +listen('clear', () => { + logixFunction.clearProject(); +}); + +listen('preview-circuit', () => { + logixFunction.fullViewOption(); +}); + +listen('new-circuit', () => { + logixFunction.createNewCircuitScope(); +}); + +listen('new-verilog-module', () => { + logixFunction.newVerilogModule(); +}); + +listen('insert-sub-circuit', () => { + logixFunction.createSubCircuitPrompt(); +}); + +listen('combinational-analysis', () => { + logixFunction.createCombinationalAnalysisPrompt(); +}); + +listen('hex-bin-dec', () => { + logixFunction.bitconverter(); +}); + +listen('download-image', () => { + logixFunction.createSaveAsImgPrompt(); +}); + +listen('themes', () => { + logixFunction.colorThemes(); +}); + +listen('custom-shortcut', () => { + logixFunction.customShortcut(); +}); + +listen('export-verilog', () => { + logixFunction.generateVerilog(); +}); + +listen('tutorial', () => { + logixFunction.showTourGuide(); +}); + +listen('user-manual', () => { + logixFunction.showUserManual(); +}); + +listen('learn-digital-circuit', () => { + logixFunction.showDigitalCircuit(); +}); + +listen('discussion-forum', () => { + logixFunction.showDiscussionForum(); +}); diff --git a/v0/src/simulator/src/metadata.json b/v0/src/simulator/src/metadata.json deleted file mode 100644 index 8ed4f225..00000000 --- a/v0/src/simulator/src/metadata.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "circuitElementList": [ - "Input", - "Output", - "NotGate", - "OrGate", - "AndGate", - "NorGate", - "NandGate", - "XorGate", - "XnorGate", - "SevenSegDisplay", - "SixteenSegDisplay", - "HexDisplay", - "Multiplexer", - "BitSelector", - "Splitter", - "Power", - "Ground", - "ConstantVal", - "ControlledInverter", - "TriState", - "Adder", - "verilogMultiplier", - "verilogDivider", - "verilogPower", - "verilogShiftLeft", - "TwoComplement", - "verilogShiftRight", - "Rom", - "RAM", - "verilogRAM", - "EEPROM", - "TflipFlop", - "JKflipFlop", - "SRflipFlop", - "DflipFlop", - "TTY", - "Keyboard", - "Clock", - "DigitalLed", - "Stepper", - "VariableLed", - "RGBLed", - "SquareRGBLed", - "RGBLedMatrix", - "Button", - "Demultiplexer", - "Buffer", - "SubCircuit", - "Flag", - "MSB", - "LSB", - "PriorityEncoder", - "Tunnel", - "ALU", - "Decoder", - "Random", - "Counter", - "Dlatch", - "TB_Input", - "TB_Output", - "ForceGate" - ], - "annotationList": ["Text", "Rectangle", "Arrow", "ImageAnnotation"], - "inputList": [ - "Random", - "Dlatch", - "JKflipFlop", - "TflipFlop", - "SRflipFlop", - "DflipFlop", - "Buffer", - "Stepper", - "Ground", - "Power", - "ConstantVal", - "Input", - "Clock", - "Button", - "Counter" - ], - "subCircuitInputList": [ - "Random", - "Dlatch", - "JKflipFlop", - "TflipFlop", - "SRflipFlop", - "DflipFlop", - "Buffer", - "Stepper", - "Ground", - "Power", - "ConstantVal", - "Clock", - "Button", - "Counter" - ], - "elementHierarchy": { - "Input": [ - { "name": "Input", "label": "Input" }, - { "name": "Button", "label": "Button" }, - { "name": "Power", "label": "Power" }, - { "name": "Ground", "label": "Ground" }, - { "name": "ConstantVal", "label": "Constant Value" }, - { "name": "Stepper", "label": "Stepper" }, - { "name": "Random", "label": "Random" }, - { "name": "Counter", "label": "Counter" } - ], - "Output": [ - { "name": "Output", "label": "Output" }, - { "name": "RGBLed", "label": "RGB Led" }, - { "name": "DigitalLed", "label": "Digital Led" }, - { "name": "VariableLed", "label": "Variable Led" }, - { "name": "HexDisplay", "label": "Hex Display" }, - { "name": "SevenSegDisplay", "label": "Seven Segment Display" }, - { "name": "SixteenSegDisplay", "label": "Sixteen Segment Display" }, - { "name": "SquareRGBLed", "label": "Square RGB Led" }, - { "name": "RGBLedMatrix", "label": "RGB Led Matrix" } - ], - "Gates": [ - { "name": "AndGate", "label": "And Gate" }, - { "name": "OrGate", "label": "Or Gate" }, - { "name": "NotGate", "label": "Not Gate" }, - { "name": "XorGate", "label": "Xor Gate" }, - { "name": "NandGate", "label": "Nand Gate" }, - { "name": "NorGate", "label": "Nor Gate" }, - { "name": "XnorGate", "label": "Xnor Gate" } - ], - "Decoders & Plexers": [ - { "name": "Multiplexer", "label": "Multiplexer" }, - { "name": "Demultiplexer", "label": "Demultiplexer" }, - { "name": "BitSelector", "label": "Bit Selector" }, - { "name": "MSB", "label": "MSB(Most Significant Bit)" }, - { "name": "LSB", "label": "LSB(Least Significant Bit)" }, - { "name": "PriorityEncoder", "label": "Priority Encoder" }, - { "name": "Decoder", "label": "Decoder" } - ], - "Sequential Elements": [ - { "name": "DflipFlop", "label": "D flip Flop" }, - { "name": "Dlatch", "label": "D latch" }, - { "name": "TflipFlop", "label": "T flip Flop" }, - { "name": "JKflipFlop", "label": "JK flip Flop" }, - { "name": "SRflipFlop", "label": "SR flip Flop" }, - { "name": "TTY", "label": "TTY" }, - { "name": "Keyboard", "label": "Keyboard" }, - { "name": "Clock", "label": "Clock" }, - { "name": "Rom", "label": "ROM" }, - { "name": "RAM", "label": "RAM" }, - { "name": "verilogRAM", "label": "Verilog RAM" }, - { "name": "EEPROM", "label": "EEPROM" } - ], - "Annotation": [ - { "name": "Rectangle", "label": "Rectangle" }, - { "name": "Arrow", "label": "Arrow" }, - { "name": "ImageAnnotation", "label": "Image Annotation" }, - { "name": "Text", "label": "Text" } - ], - "Misc": [ - { "name": "TwoComplement", "label": "Two Complement" }, - { "name": "Flag", "label": "Flag" }, - { "name": "Splitter", "label": "Splitter" }, - { "name": "Adder", "label": "Adder" }, - { "name": "ALU", "label": "ALU(Arithmetic and Logical Unit)" }, - { "name": "TriState", "label": "TriState Flip Flop" }, - { "name": "Tunnel", "label": "Tunnel" }, - { "name": "verilogMultiplier", "label": "Verilog Multiplier" }, - { "name": "verilogDivider", "label": "Verilog Divider" }, - { "name": "verilogPower", "label": "Verilog Power" }, - { "name": "verilogShiftLeft", "label": "Verilog Shift Left" }, - { "name": "verilogShiftRight", "label": "Verilog Shift Right" }, - { "name": "Buffer", "label": "Buffer" }, - { "name": "ControlledInverter", "label": "Controlled Inverter" }, - { "name": "TB_Input", "label": "TB Input" }, - { "name": "TB_Output", "label": "TB Output" }, - { "name": "ForceGate", "label": "Force Gate" } - ] - } -} diff --git a/v0/src/simulator/src/metadata.ts b/v0/src/simulator/src/metadata.ts new file mode 100644 index 00000000..5d99084c --- /dev/null +++ b/v0/src/simulator/src/metadata.ts @@ -0,0 +1,191 @@ + +export const circuitElementList = [ + "Input", + "Output", + "NotGate", + "OrGate", + "AndGate", + "NorGate", + "NandGate", + "XorGate", + "XnorGate", + "SevenSegDisplay", + "SixteenSegDisplay", + "HexDisplay", + "Multiplexer", + "BitSelector", + "Splitter", + "Power", + "Ground", + "ConstantVal", + "ControlledInverter", + "TriState", + "Adder", + "verilogMultiplier", + "verilogDivider", + "verilogPower", + "verilogShiftLeft", + "TwoComplement", + "verilogShiftRight", + "Rom", + "RAM", + "verilogRAM", + "EEPROM", + "TflipFlop", + "JKflipFlop", + "SRflipFlop", + "DflipFlop", + "TTY", + "Keyboard", + "Clock", + "DigitalLed", + "Stepper", + "VariableLed", + "RGBLed", + "SquareRGBLed", + "RGBLedMatrix", + "Button", + "Demultiplexer", + "Buffer", + "SubCircuit", + "Flag", + "MSB", + "LSB", + "PriorityEncoder", + "Tunnel", + "ALU", + "Decoder", + "Random", + "Counter", + "Dlatch", + "TB_Input", + "TB_Output", + "ForceGate" +] +const annotationList = ["Text", "Rectangle", "Arrow", "ImageAnnotation"] +export const moduleList = [...circuitElementList, ...annotationList] +export const updateOrder = [ + 'wires', + ...circuitElementList, + 'nodes', + ...annotationList, +] // Order of update +export const renderOrder = [...moduleList.slice().reverse(), 'wires', 'allNodes'] // Order of render +export const inputList = [ + "Random", + "Dlatch", + "JKflipFlop", + "TflipFlop", + "SRflipFlop", + "DflipFlop", + "Buffer", + "Stepper", + "Ground", + "Power", + "ConstantVal", + "Input", + "Clock", + "Button", + "Counter" +] +export const subCircuitInputList = [ + "Random", + "Dlatch", + "JKflipFlop", + "TflipFlop", + "SRflipFlop", + "DflipFlop", + "Buffer", + "Stepper", + "Ground", + "Power", + "ConstantVal", + "Clock", + "Button", + "Counter" +] +interface NameLabel { + name: string; + label: string; +} + +export const elementHierarchy: Record = { + "Input": [ + { name: "Input", label: "Input" }, + { name: "Button", label: "Button" }, + { name: "Power", label: "Power" }, + { name: "Ground", label: "Ground" }, + { name: "ConstantVal", label: "Constant Value" }, + { name: "Stepper", label: "Stepper" }, + { name: "Random", label: "Random" }, + { name: "Counter", label: "Counter" } + ], + "Output": [ + { name: "Output", label: "Output" }, + { name: "RGBLed", label: "RGB Led" }, + { name: "DigitalLed", label: "Digital Led" }, + { name: "VariableLed", label: "Variable Led" }, + { name: "HexDisplay", label: "Hex Display" }, + { name: "SevenSegDisplay", label: "Seven Segment Display" }, + { name: "SixteenSegDisplay", label: "Sixteen Segment Display" }, + { name: "SquareRGBLed", label: "Square RGB Led" }, + { name: "RGBLedMatrix", label: "RGB Led Matrix" } + ], + "Gates": [ + { name: "AndGate", label: "And Gate" }, + { name: "OrGate", label: "Or Gate" }, + { name: "NotGate", label: "Not Gate" }, + { name: "XorGate", label: "Xor Gate" }, + { name: "NandGate", label: "Nand Gate" }, + { name: "NorGate", label: "Nor Gate" }, + { name: "XnorGate", label: "Xnor Gate" } + ], + "Decoders & Plexers": [ + { name: "Multiplexer", label: "Multiplexer" }, + { name: "Demultiplexer", label: "Demultiplexer" }, + { name: "BitSelector", label: "Bit Selector" }, + { name: "MSB", label: "MSB(Most Significant Bit)" }, + { name: "LSB", label: "LSB(Least Significant Bit)" }, + { name: "PriorityEncoder", label: "Priority Encoder" }, + { name: "Decoder", label: "Decoder" } + ], + "Sequential Elements": [ + { name: "DflipFlop", label: "D flip Flop" }, + { name: "Dlatch", label: "D latch" }, + { name: "TflipFlop", label: "T flip Flop" }, + { name: "JKflipFlop", label: "JK flip Flop" }, + { name: "SRflipFlop", label: "SR flip Flop" }, + { name: "TTY", label: "TTY" }, + { name: "Keyboard", label: "Keyboard" }, + { name: "Clock", label: "Clock" }, + { name: "Rom", label: "ROM" }, + { name: "RAM", label: "RAM" }, + { name: "verilogRAM", label: "Verilog RAM" }, + { name: "EEPROM", label: "EEPROM" } + ], + "Annotation": [ + { name: "Rectangle", label: "Rectangle" }, + { name: "Arrow", label: "Arrow" }, + { name: "ImageAnnotation", label: "Image Annotation" }, + { name: "Text", label: "Text" } + ], + "Misc": [ + { name: "TwoComplement", label: "Two Complement" }, + { name: "Flag", label: "Flag" }, + { name: "Splitter", label: "Splitter" }, + { name: "Adder", label: "Adder" }, + { name: "ALU", label: "ALU(Arithmetic and Logical Unit)" }, + { name: "TriState", label: "TriState Flip Flop" }, + { name: "Tunnel", label: "Tunnel" }, + { name: "verilogMultiplier", label: "Verilog Multiplier" }, + { name: "verilogDivider", label: "Verilog Divider" }, + { name: "verilogPower", label: "Verilog Power" }, + { name: "verilogShiftLeft", label: "Verilog Shift Left" }, + { name: "verilogShiftRight", label: "Verilog Shift Right" }, + { name: "Buffer", label: "Buffer" }, + { name: "ControlledInverter", label: "Controlled Inverter" }, + { name: "TB_Input", label: "TB Input" }, + { name: "TB_Output", label: "TB Output" }, + { name: "ForceGate", label: "Force Gate" } + ] +} \ No newline at end of file diff --git a/v0/src/simulator/src/minimap.js b/v0/src/simulator/src/minimap.js index 6cfcf49d..84286984 100644 --- a/v0/src/simulator/src/minimap.js +++ b/v0/src/simulator/src/minimap.js @@ -1,6 +1,7 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { colors } from './themer/themer' import { layoutModeGet } from './layoutMode' +import { updateOrder } from './metadata' /** * @type {Object} miniMapArea diff --git a/v0/src/simulator/src/moduleSetup.js b/v0/src/simulator/src/moduleSetup.js index 5002bc69..fb75f6a8 100644 --- a/v0/src/simulator/src/moduleSetup.js +++ b/v0/src/simulator/src/moduleSetup.js @@ -54,7 +54,7 @@ import Rom from './sequential/Rom' import SRflipFlop from './sequential/SRflipFlop' import TflipFlop from './sequential/TflipFlop' import TTY from './sequential/TTY' -import ForceGate from './testbench/ForceGate' +import ForceGate from './sequential/ForceGate' import TB_Input from './testbench/testbenchInput' import TB_Output from './testbench/testbenchOutput' import verilogMultiplier from './modules/verilogMultiplier' diff --git a/v0/src/simulator/src/modules.js b/v0/src/simulator/src/modules.js index 41bacb6f..f52adb3b 100644 --- a/v0/src/simulator/src/modules.js +++ b/v0/src/simulator/src/modules.js @@ -1,5 +1,5 @@ /* eslint-disable import/no-cycle */ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' export function getNextPosition(x = 0, scope = globalScope) { let possibleY = 20 diff --git a/v0/src/simulator/src/modules/ALU.js b/v0/src/simulator/src/modules/ALU.js index 19cda667..bd10474e 100644 --- a/v0/src/simulator/src/modules/ALU.js +++ b/v0/src/simulator/src/modules/ALU.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText4 } from '../canvasApi' import { colors } from '../themer/themer' @@ -95,7 +95,7 @@ export default class ALU extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v0/src/simulator/src/modules/Adder.js b/v0/src/simulator/src/modules/Adder.js index 8f369a9f..205455b1 100644 --- a/v0/src/simulator/src/modules/Adder.js +++ b/v0/src/simulator/src/modules/Adder.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class diff --git a/v0/src/simulator/src/modules/AndGate.js b/v0/src/simulator/src/modules/AndGate.js index 43c3fced..4885d8ab 100644 --- a/v0/src/simulator/src/modules/AndGate.js +++ b/v0/src/simulator/src/modules/AndGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' import { changeInputSize } from '../modules' import { colors } from '../themer/themer' @@ -123,7 +123,7 @@ export default class AndGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -142,7 +142,7 @@ export default class AndGate extends CircuitElement { * @category modules */ AndGate.prototype.tooltipText = - 'And Gate Tooltip : Implements logical conjunction' + 'And Gate ToolTip : Implements logical conjunction' /** * @memberof AndGate diff --git a/v0/src/simulator/src/modules/Arrow.js b/v0/src/simulator/src/modules/Arrow.js index 24eeddfd..1956bb70 100644 --- a/v0/src/simulator/src/modules/Arrow.js +++ b/v0/src/simulator/src/modules/Arrow.js @@ -1,8 +1,6 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Arrow @@ -64,7 +62,7 @@ export default class Arrow extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/BitSelector.js b/v0/src/simulator/src/modules/BitSelector.js index 8c91cee4..d730a8d5 100644 --- a/v0/src/simulator/src/modules/BitSelector.js +++ b/v0/src/simulator/src/modules/BitSelector.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, extractBits } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -118,7 +118,7 @@ export default class BitSelector extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/Buffer.js b/v0/src/simulator/src/modules/Buffer.js index f3e9cd69..e1237b83 100644 --- a/v0/src/simulator/src/modules/Buffer.js +++ b/v0/src/simulator/src/modules/Buffer.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Buffer @@ -103,7 +102,7 @@ export default class Buffer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/Button.js b/v0/src/simulator/src/modules/Button.js index b108afaa..e4099ffa 100644 --- a/v0/src/simulator/src/modules/Button.js +++ b/v0/src/simulator/src/modules/Button.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' /** @@ -86,7 +86,7 @@ export default class Button extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(232, 13, 13,0.6)' } @@ -111,7 +111,7 @@ export default class Button extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(232, 13, 13,0.6)' if (this.wasClicked) ctx.fillStyle = 'rgba(232, 13, 13,0.8)' diff --git a/v0/src/simulator/src/modules/ConstantVal.js b/v0/src/simulator/src/modules/ConstantVal.js index d5f9028a..3e58dc64 100644 --- a/v0/src/simulator/src/modules/ConstantVal.js +++ b/v0/src/simulator/src/modules/ConstantVal.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText, oppositeDirection } from '../canvasApi' import { colors } from '../themer/themer' @@ -140,7 +140,7 @@ export default class ConstantVal extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/ControlledInverter.js b/v0/src/simulator/src/modules/ControlledInverter.js index c846abec..4f74d147 100644 --- a/v0/src/simulator/src/modules/ControlledInverter.js +++ b/v0/src/simulator/src/modules/ControlledInverter.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * ControlledInverter @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class ControlledInverter extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['ControlledInverter'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) @@ -72,9 +68,14 @@ export default class ControlledInverter extends CircuitElement { (32 - this.bitWidth) simulationArea.simulationQueue.add(this.output1) } - if (this.state.value === 0) { - this.output1.value = undefined + else if ( + this.output1.value !== undefined && + !simulationArea.contentionPending.has(this.output1) + ) { + this.output1.value = undefined; + simulationArea.simulationQueue.add(this.output1); } + simulationArea.contentionPending.removeAllContentionsForNode(this.output1); } /** @@ -96,7 +97,7 @@ export default class ControlledInverter extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/Counter.js b/v0/src/simulator/src/modules/Counter.js index 7ffb23fc..633baaec 100644 --- a/v0/src/simulator/src/modules/Counter.js +++ b/v0/src/simulator/src/modules/Counter.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { lineTo, moveTo, fillText, correctWidth, rect2 } from '../canvasApi' import { colors } from '../themer/themer' @@ -142,7 +142,7 @@ export default class Counter extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v0/src/simulator/src/modules/Decoder.js b/v0/src/simulator/src/modules/Decoder.js index 6b6d9278..3d4a6955 100644 --- a/v0/src/simulator/src/modules/Decoder.js +++ b/v0/src/simulator/src/modules/Decoder.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, rect, fillText } from '../canvasApi' /** * @class @@ -18,10 +18,6 @@ import { colors } from '../themer/themer' export default class Decoder extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'LEFT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Decoder'].push(this); - */ - // this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10); this.outputsize = 1 << this.bitWidth this.xOff = 0 this.yOff = 1 @@ -31,31 +27,8 @@ export default class Decoder extends CircuitElement { if (this.bitWidth <= 3) { this.yOff = 2 } - - // this.changeControlSignalSize = function(size) { - // if (size === undefined || size < 1 || size > 32) return; - // if (this.controlSignalSize === size) return; - // let obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size); - // this.cleanDelete(); - // simulationArea.lastSelected = obj; - // return obj; - // } - // this.mutableProperties = { - // "controlSignalSize": { - // name: "Control Signal Size", - // type: "number", - // max: "32", - // min: "1", - // func: "changeControlSignalSize", - // }, - // } // eslint-disable-next-line no-shadow this.newBitWidth = function (bitWidth) { - // this.bitWidth = bitWidth; - // for (let i = 0; i < this.inputSize; i++) { - // this.outputs1[i].bitWidth = bitWidth - // } - // this.input.bitWidth = bitWidth; if (bitWidth === undefined || bitWidth < 1 || bitWidth > 32) return if (this.bitWidth === bitWidth) return const obj = new Decoder( @@ -85,8 +58,6 @@ export default class Decoder extends CircuitElement { ) this.output1.push(a) } - - // this.controlSignalInput = new Node(0,this.yOff * 10 * (this.outputsize / 2 - 1) +this.xOff + 10, 0, this, this.controlSignalSize,"Control Signal"); } /** @@ -129,12 +100,6 @@ export default class Decoder extends CircuitElement { const xx = this.x const yy = this.y - - // ctx.beginPath(); - // moveTo(ctx, 0,this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 *this.xOff, xx, yy, this.direction); - // lineTo(ctx, 0,this.yOff * 5 * (this.outputsize - 1) +this.xOff, xx, yy, this.direction); - // ctx.stroke(); - ctx.beginPath() ctx.strokeStyle = colors['stroke'] ctx.lineWidth = correctWidth(4) @@ -176,7 +141,7 @@ export default class Decoder extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } @@ -186,7 +151,6 @@ export default class Decoder extends CircuitElement { ctx.beginPath() ctx.fillStyle = 'black' ctx.textAlign = 'center' - // [xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2); for (let i = 0; i < this.outputsize; i++) { if (this.direction === 'LEFT') fillText( diff --git a/v0/src/simulator/src/modules/Demultiplexer.js b/v0/src/simulator/src/modules/Demultiplexer.js index feb21cfa..1a679539 100644 --- a/v0/src/simulator/src/modules/Demultiplexer.js +++ b/v0/src/simulator/src/modules/Demultiplexer.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -206,7 +206,7 @@ export default class Demultiplexer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v0/src/simulator/src/modules/DigitalLed.js b/v0/src/simulator/src/modules/DigitalLed.js index df17fbfa..da280340 100644 --- a/v0/src/simulator/src/modules/DigitalLed.js +++ b/v0/src/simulator/src/modules/DigitalLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, @@ -10,7 +10,6 @@ import { drawCircle2, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * DigitalLed @@ -26,13 +25,11 @@ import { colors } from '../themer/themer' export default class DigitalLed extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { // Calling base class constructor - super(x, y, scope, 'UP', 1) - /* this is done in this.baseSetup() now - this.scope['DigitalLed'].push(this); - */ this.rectangleObject = false - this.setDimensions(10, 20) + this.setWidth(10); + this.upDimensionY = 20; + this.downDimensionY = 40; this.inp1 = new Node(-40, 0, 0, this, 1) this.directionFixed = true this.fixedBitWidth = true @@ -114,7 +111,7 @@ export default class DigitalLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -140,7 +137,7 @@ export default class DigitalLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v0/src/simulator/src/modules/Flag.js b/v0/src/simulator/src/modules/Flag.js index f332622b..b0cd9bf2 100644 --- a/v0/src/simulator/src/modules/Flag.js +++ b/v0/src/simulator/src/modules/Flag.js @@ -1,9 +1,8 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText } from '../canvasApi' import plotArea from '../plotArea' -import EventQueue from '../eventQueue' /** * @class * Flag @@ -28,9 +27,6 @@ export default class Flag extends CircuitElement { identifier ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Flag'].push(this); - */ this.setWidth(60) this.setHeight(20) this.rectangleObject = false @@ -127,7 +123,7 @@ export default class Flag extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -189,9 +185,6 @@ export default class Flag extends CircuitElement { } else { this.inp1.leftx = 20 } - // if(this.direction=="LEFT" || this.direction=="RIGHT") this.inp1.leftx=50-this.xSize; - // this.inp1.refresh(); - this.inp1.refresh() } } diff --git a/v0/src/simulator/src/modules/Ground.js b/v0/src/simulator/src/modules/Ground.js index f1c88932..e9e801b9 100644 --- a/v0/src/simulator/src/modules/Ground.js +++ b/v0/src/simulator/src/modules/Ground.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Ground @@ -18,33 +17,12 @@ import { colors } from '../themer/themer' export default class Ground extends CircuitElement { constructor(x, y, scope = globalScope, bitWidth = 1) { super(x, y, scope, 'RIGHT', bitWidth) - /* this is done in this.baseSetup() now - this.scope['Ground'].push(this); - */ this.rectangleObject = false this.setDimensions(10, 10) this.directionFixed = true this.output1 = new Node(0, -10, 1, this) } - /** - * @memberof Ground - * fn to create save Json Data of object - * @return {JSON} - */ - customSave() { - const data = { - nodes: { - output1: findNode(this.output1), - }, - values: { - state: this.state, - }, - constructorParamaters: [this.direction, this.bitWidth], - } - return data - } - /** * @memberof Ground * resolve output values based on inputData @@ -80,7 +58,7 @@ export default class Ground extends CircuitElement { ctx.strokeStyle = [colors['stroke'], 'brown'][ ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + 0 + simulationArea.multipleObjectSelections.includes(this)) + 0 ] ctx.lineWidth = correctWidth(3) diff --git a/v0/src/simulator/src/modules/HexDisplay.js b/v0/src/simulator/src/modules/HexDisplay.js index b96cd096..1c58b1b1 100644 --- a/v0/src/simulator/src/modules/HexDisplay.js +++ b/v0/src/simulator/src/modules/HexDisplay.js @@ -1,16 +1,14 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, - arc, rect2, validColor, colorToRGBA, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * HexDisplay @@ -25,9 +23,6 @@ import { colors } from '../themer/themer' export default class HexDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 4) - /* this is done in this.baseSetup() now - this.scope['HexDisplay'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(30, 50) @@ -96,9 +91,6 @@ export default class HexDisplay extends CircuitElement { customDraw() { var ctx = simulationArea.context - const xx = this.x - const yy = this.y - ctx.strokeStyle = colors['stroke'] ctx.lineWidth = correctWidth(3) @@ -366,7 +358,7 @@ export default class HexDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v0/src/simulator/src/modules/ImageAnnotation.js b/v0/src/simulator/src/modules/ImageAnnotation.js index 67ac4d8b..d46eba66 100644 --- a/v0/src/simulator/src/modules/ImageAnnotation.js +++ b/v0/src/simulator/src/modules/ImageAnnotation.js @@ -1,9 +1,8 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText, drawImage } from '../canvasApi' import { colors } from '../themer/themer' -import { promptFile, showMessage, getImageDimensions } from '../utils' +import { promptFile, showMessage } from '../utils' /** * @class * Image @@ -113,7 +112,7 @@ export default class ImageAnnotation extends CircuitElement { if ( simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.1)' ctx.fill() diff --git a/v0/src/simulator/src/modules/Input.js b/v0/src/simulator/src/modules/Input.js index d33c8627..d6ac8dd2 100644 --- a/v0/src/simulator/src/modules/Input.js +++ b/v0/src/simulator/src/modules/Input.js @@ -1,7 +1,7 @@ /* eslint-disable no-unused-expressions */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, oppositeDirection, fillText } from '../canvasApi' import { getNextPosition } from '../modules' import { generateId } from '../utils' @@ -40,9 +40,6 @@ export default class Input extends CircuitElement { layoutProperties ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Input'].push(this); - */ if (layoutProperties) { this.layoutProperties = layoutProperties } else { diff --git a/v0/src/simulator/src/modules/LSB.js b/v0/src/simulator/src/modules/LSB.js index 0f7e4e61..c4b9e487 100644 --- a/v0/src/simulator/src/modules/LSB.js +++ b/v0/src/simulator/src/modules/LSB.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,16 +18,12 @@ import { colors } from '../themer/themer' export default class LSB extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['LSB'].push(this); - */ this.leftDimensionX = 10 this.rightDimensionX = 20 this.setHeight(30) this.directionFixed = true this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.rectangleObject = false - // this.inputSize = 1 << this.bitWidth; this.intputSize = this.bitWidth this.inp1 = new Node(-10, 0, 0, this, this.inputSize) @@ -58,7 +54,6 @@ export default class LSB extends CircuitElement { * @param {number} bitWidth - new bitwidth */ newBitWidth(bitWidth) { - // this.inputSize = 1 << bitWidth this.inputSize = bitWidth this.inp1.bitWidth = this.inputSize this.bitWidth = bitWidth @@ -104,9 +99,9 @@ export default class LSB extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() diff --git a/v0/src/simulator/src/modules/MSB.js b/v0/src/simulator/src/modules/MSB.js index fbe14b2c..dfb587b4 100644 --- a/v0/src/simulator/src/modules/MSB.js +++ b/v0/src/simulator/src/modules/MSB.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,17 +18,12 @@ import { colors } from '../themer/themer' export default class MSB extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['MSB'].push(this); - */ - // this.setDimensions(20, 20); this.leftDimensionX = 10 this.rightDimensionX = 20 this.setHeight(30) this.directionFixed = true this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.rectangleObject = false - // this.inputSize = 1 << this.bitWidth; this.intputSize = this.bitWidth this.inp1 = new Node(-10, 0, 0, this, this.inputSize) @@ -98,9 +93,9 @@ export default class MSB extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() diff --git a/v0/src/simulator/src/modules/Multiplexer.js b/v0/src/simulator/src/modules/Multiplexer.js index 638b9d01..59c92387 100644 --- a/v0/src/simulator/src/modules/Multiplexer.js +++ b/v0/src/simulator/src/modules/Multiplexer.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * Multiplexer @@ -27,9 +26,6 @@ export default class Multiplexer extends CircuitElement { controlSignalSize = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Multiplexer'].push(this); - */ this.controlSignalSize = controlSignalSize || parseInt(prompt('Enter control signal bitWidth'), 10) @@ -215,7 +211,7 @@ export default class Multiplexer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v0/src/simulator/src/modules/NandGate.js b/v0/src/simulator/src/modules/NandGate.js index 1cf25e82..2a57fe14 100644 --- a/v0/src/simulator/src/modules/NandGate.js +++ b/v0/src/simulator/src/modules/NandGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2, arc } from '../canvasApi' import { changeInputSize } from '../modules' import { gateGenerateVerilog } from '../utils' @@ -29,9 +29,6 @@ export default class NandGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NandGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) this.inp = [] @@ -120,7 +117,7 @@ export default class NandGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/NorGate.js b/v0/src/simulator/src/modules/NorGate.js index 38572dd5..e7e370c0 100644 --- a/v0/src/simulator/src/modules/NorGate.js +++ b/v0/src/simulator/src/modules/NorGate.js @@ -1,13 +1,12 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { gateGenerateVerilog } from '../utils' import { correctWidth, bezierCurveTo, moveTo, - arc2, drawCircle2, } from '../canvasApi' import { changeInputSize } from '../modules' @@ -35,9 +34,6 @@ export default class NorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -134,9 +130,9 @@ export default class NorGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() ctx.beginPath() diff --git a/v0/src/simulator/src/modules/NotGate.js b/v0/src/simulator/src/modules/NotGate.js index 38ec3a05..6c1ca9a5 100644 --- a/v0/src/simulator/src/modules/NotGate.js +++ b/v0/src/simulator/src/modules/NotGate.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * NotGate @@ -19,12 +18,8 @@ import { colors } from '../themer/themer' export default class NotGate extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NotGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) - this.inp1 = new Node(-10, 0, 0, this) this.output1 = new Node(20, 0, 1, this) } @@ -79,7 +74,7 @@ export default class NotGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -107,7 +102,7 @@ export default class NotGate extends CircuitElement { * @category modules */ NotGate.prototype.tooltipText = - 'Not Gate Tooltip : Inverts the input digital signal.' + 'Not Gate ToolTip : Inverts the input digital signal.' NotGate.prototype.helplink = 'https://docs.circuitverse.org/#/chapter4/4gates?id=not-gate' NotGate.prototype.objectType = 'NotGate' NotGate.prototype.verilogType = 'not' diff --git a/v0/src/simulator/src/modules/OrGate.js b/v0/src/simulator/src/modules/OrGate.js deleted file mode 100644 index 31b557cd..00000000 --- a/v0/src/simulator/src/modules/OrGate.js +++ /dev/null @@ -1,175 +0,0 @@ -import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, bezierCurveTo, moveTo, arc2 } from '../canvasApi' -import { changeInputSize } from '../modules' -import { gateGenerateVerilog } from '../utils' - -/** - * @class - * OrGate - * @extends CircuitElement - * @param {number} x - x coordinate of element. - * @param {number} y - y coordinate of element. - * @param {Scope=} scope - Cirucit on which element is drawn - * @param {string=} dir - direction of element - * @param {number=} inputs - number of input nodes - * @param {number=} bitWidth - bit width per node. - * @category modules - */ -import { colors } from '../themer/themer' - -export default class OrGate extends CircuitElement { - constructor( - x, - y, - scope = globalScope, - dir = 'RIGHT', - inputs = 2, - bitWidth = 1 - ) { - // Calling base class constructor - super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['OrGate'].push(this); - */ - this.rectangleObject = false - this.setDimensions(15, 20) - // Inherit base class prototype - this.inp = [] - this.inputSize = inputs - if (inputs % 2 === 1) { - for (let i = Math.floor(inputs / 2) - 1; i >= 0; i--) { - const a = new Node(-10, -10 * (i + 1), 0, this) - this.inp.push(a) - } - let a = new Node(-10, 0, 0, this) - this.inp.push(a) - for (let i = 0; i < Math.floor(inputs / 2); i++) { - a = new Node(-10, 10 * (i + 1), 0, this) - this.inp.push(a) - } - } else { - for (let i = inputs / 2 - 1; i >= 0; i--) { - const a = new Node(-10, -10 * (i + 1), 0, this) - this.inp.push(a) - } - for (let i = 0; i < inputs / 2; i++) { - const a = new Node(-10, 10 * (i + 1), 0, this) - this.inp.push(a) - } - } - this.output1 = new Node(20, 0, 1, this) - } - - /** - * @memberof OrGate - * fn to create save Json Data of object - * @return {JSON} - */ - customSave() { - const data = { - constructorParamaters: [ - this.direction, - this.inputSize, - this.bitWidth, - ], - - nodes: { - inp: this.inp.map(findNode), - output1: findNode(this.output1), - }, - } - return data - } - - /** - * @memberof OrGate - * resolve output values based on inputData - */ - resolve() { - let result = this.inp[0].value || 0 - if (this.isResolvable() === false) { - return - } - for (let i = 1; i < this.inputSize; i++) - result |= this.inp[i].value || 0 - this.output1.value = result >>> 0 - simulationArea.simulationQueue.add(this.output1) - } - - /** - * @memberof OrGate - * function to draw element - */ - customDraw() { - var ctx = simulationArea.context - ctx.strokeStyle = colors['stroke'] - ctx.lineWidth = correctWidth(3) - - const xx = this.x - const yy = this.y - ctx.beginPath() - ctx.fillStyle = colors['fill'] - - moveTo(ctx, -10, -20, xx, yy, this.direction, true) - bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction) - bezierCurveTo( - 0 + 15, - 0 + 10, - 0, - 0 + 20, - -10, - +20, - xx, - yy, - this.direction - ) - bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - ctx.closePath() - if ( - (this.hover && !simulationArea.shiftDown) || - simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) - ) - ctx.fillStyle = colors['hover_select'] - ctx.fill() - ctx.stroke() - } - - generateVerilog() { - return gateGenerateVerilog.call(this, '|') - } -} - -/** - * @memberof OrGate - * Help Tip - * @type {string} - * @category modules - */ -OrGate.prototype.tooltipText = - 'Or Gate Tooltip : Implements logical disjunction' - -/** - * @memberof OrGate - * function to change input nodes of the element - * @category modules - */ -OrGate.prototype.changeInputSize = changeInputSize - -/** - * @memberof SevenSegDisplay - * @type {boolean} - * @category modules - */ -OrGate.prototype.alwaysResolve = true - -/** - * @memberof SevenSegDisplay - * @type {string} - * @category modules - */ -OrGate.prototype.verilogType = 'or' -OrGate.prototype.helplink = 'https://docs.circuitverse.org/#/chapter4/4gates?id=or-gate' -OrGate.prototype.objectType = 'OrGate' diff --git a/v0/src/simulator/src/modules/OrGate.ts b/v0/src/simulator/src/modules/OrGate.ts new file mode 100644 index 00000000..897cc229 --- /dev/null +++ b/v0/src/simulator/src/modules/OrGate.ts @@ -0,0 +1,133 @@ +import CircuitElement from '../circuitElement'; +import Node, { findNode } from '../node'; +import { simulationArea } from '../simulationArea'; +import { correctWidth, bezierCurveTo, moveTo } from '../canvasApi'; +import { changeInputSize } from '../modules'; +import { gateGenerateVerilog } from '../utils'; + +import { colors } from '../themer/themer'; + +export default class OrGate extends CircuitElement { + private inp: Node[]; + private inputSize: number; + private output1: Node; + + constructor( + x: number, + y: number, + scope: any = globalScope, + dir: string = 'RIGHT', + inputs: number = 2, + bitWidth: number = 1 + ) { + super(x, y, scope, dir, bitWidth); + this.rectangleObject = false; + this.setDimensions(15, 20); + this.inp = []; + this.inputSize = inputs; + if (inputs % 2 === 1) { + for (let i = Math.floor(inputs / 2) - 1; i >= 0; i--) { + const a = new Node(-10, -10 * (i + 1), 0, this); + this.inp.push(a); + } + let a = new Node(-10, 0, 0, this); + this.inp.push(a); + for (let i = 0; i < Math.floor(inputs / 2); i++) { + a = new Node(-10, 10 * (i + 1), 0, this); + this.inp.push(a); + } + } else { + for (let i = inputs / 2 - 1; i >= 0; i--) { + const a = new Node(-10, -10 * (i + 1), 0, this); + this.inp.push(a); + } + for (let i = 0; i < inputs / 2; i++) { + const a = new Node(-10, 10 * (i + 1), 0, this); + this.inp.push(a); + } + } + this.output1 = new Node(20, 0, 1, this); + } + + // Resolve output values based on inp + resolve() { + let result = this.inp[0].value || 0; + if (this.isResolvable() === false) { + return; + } + for (let i = 1; i < this.inputSize; i++) { + result |= this.inp[i].value || 0; + } + this.output1.value = result >>> 0; + simulationArea.simulationQueue.add(this.output1); + } + + customDraw() { + var ctx = simulationArea.context; + if (ctx) { + ctx.strokeStyle = colors['stroke']; + ctx.lineWidth = correctWidth(3); + + const xx = this.x; + const yy = this.y; + ctx.beginPath(); + ctx.fillStyle = colors['fill']; + + moveTo(ctx, -10, -20, xx, yy, this.direction, true); + bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction); + bezierCurveTo( + 0 + 15, + 0 + 10, + 0, + 0 + 20, + -10, + +20, + xx, + yy, + this.direction + ); + bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction); + ctx.closePath(); + if ( + (this.hover && !simulationArea.shiftDown) || + simulationArea.lastSelected === this || + simulationArea.multipleObjectSelections.includes(this) + ) { + ctx.fillStyle = colors['hover_select']; + } + ctx.fill(); + ctx.stroke(); + } + } + + customSave(): object { + const data = { + constructorParamaters: [ + this.direction, + this.inputSize, + this.bitWidth, + ], + nodes: { + inp: this.inp.map(findNode), + output1: findNode(this.output1), + }, + }; + return data; + } + + generateVerilog(): string { + return gateGenerateVerilog.call(this, '|'); + } +} + +OrGate.prototype.tooltipText = + 'Or Gate ToolTip : Implements logical disjunction'; + +OrGate.prototype.changeInputSize = changeInputSize; + +OrGate.prototype.alwaysResolve = true; + +OrGate.prototype.verilogType = 'or'; +OrGate.prototype.helplink = + 'https://docs.circuitverse.org/#/chapter4/4gates?id=or-gate'; +OrGate.prototype.objectType = 'OrGate'; \ No newline at end of file diff --git a/v0/src/simulator/src/modules/Output.js b/v0/src/simulator/src/modules/Output.js index 23ef3975..b4442664 100644 --- a/v0/src/simulator/src/modules/Output.js +++ b/v0/src/simulator/src/modules/Output.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText, rect2, oppositeDirection } from '../canvasApi' import { getNextPosition } from '../modules' import { generateId } from '../utils' @@ -40,9 +40,6 @@ export default class Output extends CircuitElement { ) { // Calling base class constructor super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Output'].push(this); - */ if (layoutProperties) { this.layoutProperties = layoutProperties } else { @@ -59,15 +56,6 @@ export default class Output extends CircuitElement { this.inp1 = new Node(this.bitWidth * 10, 0, 0, this) } - /** - * @memberof Output - * function to generate verilog for output - * @return {string} - */ - generateVerilog() { - return `assign ${this.label} = ${this.inp1.verilogLabel};` - } - /** * @memberof Output * fn to create save Json Data of object @@ -140,7 +128,7 @@ export default class Output extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } @@ -186,6 +174,11 @@ export default class Output extends CircuitElement { this.labelDirection = oppositeDirection[this.direction] } + /** + * @memberof Output + * function to generate verilog for output + * @return {string} + */ generateVerilog() { return ( 'assign ' + this.verilogLabel + ' = ' + this.inp1.verilogLabel + ';' diff --git a/v0/src/simulator/src/modules/Power.js b/v0/src/simulator/src/modules/Power.js index 87c419a5..f1efe4a0 100644 --- a/v0/src/simulator/src/modules/Power.js +++ b/v0/src/simulator/src/modules/Power.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Power @@ -18,9 +17,6 @@ import { colors } from '../themer/themer' export default class Power extends CircuitElement { constructor(x, y, scope = globalScope, bitWidth = 1) { super(x, y, scope, 'RIGHT', bitWidth) - /* this is done in this.baseSetup() now - this.scope['Power'].push(this); - */ this.directionFixed = true this.rectangleObject = false this.setDimensions(10, 10) @@ -72,7 +68,7 @@ export default class Power extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/PriorityEncoder.js b/v0/src/simulator/src/modules/PriorityEncoder.js index b74d7f90..0eea9e7e 100644 --- a/v0/src/simulator/src/modules/PriorityEncoder.js +++ b/v0/src/simulator/src/modules/PriorityEncoder.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class PriorityEncoder extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['PriorityEncoder'].push(this); - */ this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.inputSize = 1 << this.bitWidth @@ -29,7 +26,8 @@ export default class PriorityEncoder extends CircuitElement { this.yOff = 2 } - this.setDimensions(20, this.yOff * 5 * this.inputSize) + this.setDimensions(20, this.yOff * 5 * this.inputSize + 10); + this.rightDimensionX += 10; this.directionFixed = true this.rectangleObject = false @@ -182,7 +180,7 @@ export default class PriorityEncoder extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/RGBLed.js b/v0/src/simulator/src/modules/RGBLed.js index a1bcc659..799979f2 100644 --- a/v0/src/simulator/src/modules/RGBLed.js +++ b/v0/src/simulator/src/modules/RGBLed.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, arc, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * RGBLed @@ -18,12 +17,10 @@ export default class RGBLed extends CircuitElement { constructor(x, y, scope = globalScope) { // Calling base class constructor super(x, y, scope, 'UP', 8) - /* this is done in this.baseSetup() now - this.scope['RGBLed'].push(this); - */ this.rectangleObject = false this.inp = [] this.setDimensions(10, 10) + this.downDimensionY = 40; this.inp1 = new Node(-40, -10, 0, this, 8) this.inp2 = new Node(-40, 0, 0, this, 8) this.inp3 = new Node(-40, 10, 0, this, 8) @@ -89,7 +86,6 @@ export default class RGBLed extends CircuitElement { `rgba(${a}, ${b}, ${c}, 0.8)`, 'rgba(227, 228, 229, 0.8)', ][(a === undefined || b === undefined || c === undefined) + 0] - // ctx.fillStyle = ["rgba(200, 200, 200, 0.3)","rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined) || (a === 0 && b === 0 && c === 0)) + 0]; ctx.lineWidth = correctWidth(1) ctx.beginPath() @@ -115,7 +111,7 @@ export default class RGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -145,7 +141,7 @@ export default class RGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v0/src/simulator/src/modules/RGBLedMatrix.js b/v0/src/simulator/src/modules/RGBLedMatrix.js index 00fe1757..4825b0f6 100644 --- a/v0/src/simulator/src/modules/RGBLedMatrix.js +++ b/v0/src/simulator/src/modules/RGBLedMatrix.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, rotate, lineTo, moveTo } from '../canvasApi' /** @@ -28,9 +28,6 @@ export default class RGBLedMatrix extends CircuitElement { } = {} ) { super(x, y, scope, 'RIGHT', 8) - /* this is done in this.baseSetup() now - this.scope['RGBLedMatrix'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.rectangleObject = true diff --git a/v0/src/simulator/src/modules/Random.js b/v0/src/simulator/src/modules/Random.js index 01c9427b..fbfa2084 100644 --- a/v0/src/simulator/src/modules/Random.js +++ b/v0/src/simulator/src/modules/Random.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText, lineTo, moveTo, correctWidth, rect2 } from '../canvasApi' /** * @class @@ -131,7 +131,7 @@ export default class Random extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v0/src/simulator/src/modules/Rectangle.js b/v0/src/simulator/src/modules/Rectangle.js index 09bf240f..4fa2c461 100644 --- a/v0/src/simulator/src/modules/Rectangle.js +++ b/v0/src/simulator/src/modules/Rectangle.js @@ -1,6 +1,5 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect } from '../canvasApi' /** * @class @@ -16,9 +15,6 @@ import { correctWidth, rect } from '../canvasApi' export default class Rectangle extends CircuitElement { constructor(x, y, scope = globalScope, rows = 15, cols = 20) { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['Rectangle'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.rectangleObject = false @@ -100,7 +96,7 @@ export default class Rectangle extends CircuitElement { if ( simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.1)' ctx.fill() diff --git a/v0/src/simulator/src/modules/SevenSegDisplay.js b/v0/src/simulator/src/modules/SevenSegDisplay.js index eedd26f0..9c79ace5 100644 --- a/v0/src/simulator/src/modules/SevenSegDisplay.js +++ b/v0/src/simulator/src/modules/SevenSegDisplay.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { colorToRGBA, correctWidth, @@ -23,9 +23,6 @@ import { export default class SevenSegDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['SevenSegDisplay'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.setDimensions(30, 50) @@ -266,7 +263,7 @@ export default class SevenSegDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v0/src/simulator/src/modules/SixteenSegDisplay.js b/v0/src/simulator/src/modules/SixteenSegDisplay.js index 944ba443..9a15575a 100644 --- a/v0/src/simulator/src/modules/SixteenSegDisplay.js +++ b/v0/src/simulator/src/modules/SixteenSegDisplay.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { colorToRGBA, correctWidth, @@ -10,7 +10,6 @@ import { rect2, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * SixteenSegDisplay @@ -23,9 +22,6 @@ import { changeInputSize } from '../modules' export default class SixteenSegDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 16) - /* this is done in this.baseSetup() now - this.scope['SixteenSegDisplay'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.setDimensions(30, 50) @@ -435,7 +431,7 @@ export default class SixteenSegDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v0/src/simulator/src/modules/Splitter.js b/v0/src/simulator/src/modules/Splitter.js index ffcb296c..1cf3f006 100644 --- a/v0/src/simulator/src/modules/Splitter.js +++ b/v0/src/simulator/src/modules/Splitter.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText2 } from '../canvasApi' import { colors } from '../themer/themer' @@ -30,9 +30,6 @@ export default class Splitter extends CircuitElement { bitWidthSplit = undefined ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Splitter'].push(this); - */ this.rectangleObject = false this.bitWidthSplit = @@ -169,8 +166,6 @@ export default class Splitter extends CircuitElement { this.inp1.value = n >>> 0 simulationArea.simulationQueue.add(this.inp1) } - // else if (this.inp1.value !== n) { - // } } this.prevInpValue = this.inp1.value } @@ -183,57 +178,16 @@ export default class Splitter extends CircuitElement { this.prevInpValue = undefined } - /** - * @memberof Splitter - * fn to process verilog of the element - * @return {JSON} - */ - processVerilog() { - if ( - this.inp1.verilogLabel !== '' && - this.outputs[0].verilogLabel === '' - ) { - let bitCount = 0 - for (let i = 0; i < this.splitCount; i++) { - // let bitSplitValue = extractBits(this.inp1.value, bitCount, bitCount + this.bitWidthSplit[i] - 1); - if (this.bitWidthSplit[i] > 1) { - const label = `${this.inp1.verilogLabel}[ ${ - bitCount + this.bitWidthSplit[i] - 1 - }:${bitCount}]` - } else { - const label = `${this.inp1.verilogLabel}[${bitCount}]` - } - if (this.outputs[i].verilogLabel !== label) { - this.outputs[i].verilogLabel = label - this.scope.stack.push(this.outputs[i]) - } - bitCount += this.bitWidthSplit[i] - } - } else if ( - this.inp1.verilogLabel === '' && - this.outputs[0].verilogLabel !== '' - ) { - const label = `{${this.outputs - .map((x) => x.verilogLabel) - .join(',')}}` - if (this.inp1.verilogLabel !== label) { - this.inp1.verilogLabel = label - this.scope.stack.push(this.inp1) - } - } - } - /** * @memberof Splitter * function to draw element */ customDraw() { var ctx = simulationArea.context - // ctx.strokeStyle = [colors['splitter'], 'brown'][ ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + 0 + simulationArea.multipleObjectSelections.includes(this)) + 0 ] ctx.lineWidth = correctWidth(3) const xx = this.x @@ -280,13 +234,18 @@ export default class Splitter extends CircuitElement { ctx.fill() } + /** + * @memberof Splitter + * fn to process verilog of the element + * @return {JSON} + */ processVerilog() { // Combiner if (this.inp1.verilogLabel == '') { this.isSplitter = false this.inp1.verilogLabel = this.verilogLabel + '_cmb' if ( - !this.scope.verilogWireList[this.bitWidth].contains( + !this.scope.verilogWireList[this.bitWidth].includes( this.inp1.verilogLabel ) ) diff --git a/v0/src/simulator/src/modules/SquareRGBLed.js b/v0/src/simulator/src/modules/SquareRGBLed.js index b93e0bb6..c9bb5295 100644 --- a/v0/src/simulator/src/modules/SquareRGBLed.js +++ b/v0/src/simulator/src/modules/SquareRGBLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, rect2 } from '../canvasApi' /** @@ -17,9 +17,6 @@ import { correctWidth, lineTo, moveTo, rect2 } from '../canvasApi' export default class SquareRGBLed extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'UP', pinLength = 1) { super(x, y, scope, dir, 8) - /* this is done in this.baseSetup() now - this.scope['SquareRGBLed'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) this.pinLength = pinLength === undefined ? 1 : pinLength @@ -146,7 +143,7 @@ export default class SquareRGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32)' } @@ -175,7 +172,7 @@ export default class SquareRGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32)' } diff --git a/v0/src/simulator/src/modules/Stepper.js b/v0/src/simulator/src/modules/Stepper.js index c6cfbd3f..7b0b0cb1 100644 --- a/v0/src/simulator/src/modules/Stepper.js +++ b/v0/src/simulator/src/modules/Stepper.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * Stepper @@ -19,11 +18,7 @@ import { colors } from '../themer/themer' export default class Stepper extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 8) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Stepper'].push(this); - */ this.setDimensions(20, 20) - this.output1 = new Node(20, 0, 1, this, bitWidth) this.state = 0 } diff --git a/v0/src/simulator/src/modules/Text.js b/v0/src/simulator/src/modules/Text.js index 7248c575..3713edbc 100644 --- a/v0/src/simulator/src/modules/Text.js +++ b/v0/src/simulator/src/modules/Text.js @@ -1,6 +1,5 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { rect2, fillText } from '../canvasApi' /** * @class @@ -19,10 +18,6 @@ import { copy, paste } from '../events' export default class Text extends CircuitElement { constructor(x, y, scope = globalScope, label = '', fontSize = 14) { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['Text'].push(this); - */ - // this.setDimensions(15, 15); this.fixedBitWidth = true this.directionFixed = true this.labelDirectionFixed = true @@ -130,7 +125,7 @@ export default class Text extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.beginPath() ctx.fillStyle = colors['fill'] diff --git a/v0/src/simulator/src/modules/TriState.js b/v0/src/simulator/src/modules/TriState.js index e4048fc9..b408a0d9 100644 --- a/v0/src/simulator/src/modules/TriState.js +++ b/v0/src/simulator/src/modules/TriState.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * TriState @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class TriState extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['TriState'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) @@ -29,9 +25,6 @@ export default class TriState extends CircuitElement { this.output1 = new Node(20, 0, 1, this) this.state = new Node(0, 0, 0, this, 1, 'Enable') } - - // TriState.prototype.propagationDelay=10000; - /** * @memberof TriState * fn to create save Json Data of object @@ -74,15 +67,14 @@ export default class TriState extends CircuitElement { this.output1.value = this.inp1.value // >>>0)<<(32-this.bitWidth))>>>(32-this.bitWidth); simulationArea.simulationQueue.add(this.output1) } - simulationArea.contentionPending.clean(this) } else if ( this.output1.value !== undefined && - !simulationArea.contentionPending.contains(this) + !simulationArea.contentionPending.has(this.output1) ) { this.output1.value = undefined simulationArea.simulationQueue.add(this.output1) } - simulationArea.contentionPending.clean(this) + simulationArea.contentionPending.removeAllContentionsForNode(this.output1); } /** @@ -104,7 +96,7 @@ export default class TriState extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/Tunnel.js b/v0/src/simulator/src/modules/Tunnel.js index 7e3f96c5..d8acab0a 100644 --- a/v0/src/simulator/src/modules/Tunnel.js +++ b/v0/src/simulator/src/modules/Tunnel.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText } from '../canvasApi' import plotArea from '../plotArea' import { showError } from '../utils' @@ -28,9 +28,6 @@ export default class Tunnel extends CircuitElement { identifier ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Tunnel'].push(this); - */ this.rectangleObject = false this.centerElement = true this.xSize = 10 @@ -77,8 +74,6 @@ export default class Tunnel extends CircuitElement { this.upDimensionY = Math.abs(-20 + yRotate) this.rightDimensionX = Math.abs(xRotate) this.downDimensionY = Math.abs(20 + yRotate) - - // rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT"); } /** @@ -174,13 +169,18 @@ export default class Tunnel extends CircuitElement { * @param {string=} id - id so that every link is unique */ setIdentifier(id = '') { - if (id.length === 0) return - if (this.scope.tunnelList[this.identifier]) - this.scope.tunnelList[this.identifier].clean(this) + if (id.length === 0) { + return + } + if (this.scope.tunnelList[this.identifier]) { + this.scope.tunnelList[this.identifier] = this.scope.tunnelList[this.identifier].filter(x=> x !== this); + } this.identifier = id - if (this.scope.tunnelList[this.identifier]) + if (this.scope.tunnelList[this.identifier]) { this.scope.tunnelList[this.identifier].push(this) - else this.scope.tunnelList[this.identifier] = [this] + } else { + this.scope.tunnelList[this.identifier] = [this] + } // Change the bitwidth to be same as the other elements with this.identifier if ( @@ -203,8 +203,8 @@ export default class Tunnel extends CircuitElement { * delete the tunnel element */ delete() { - this.scope.Tunnel.clean(this) - this.scope.tunnelList[this.identifier].clean(this) + this.scope.Tunnel = this.scope.Tunnel.filter(x => x !== this); + this.scope.tunnelList[this.identifier] = this.scope.tunnelList[this.identifier].filter(x=> x !== this); super.delete() } @@ -250,7 +250,7 @@ export default class Tunnel extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v0/src/simulator/src/modules/TwoComplement.js b/v0/src/simulator/src/modules/TwoComplement.js index ace62ec7..88b35979 100644 --- a/v0/src/simulator/src/modules/TwoComplement.js +++ b/v0/src/simulator/src/modules/TwoComplement.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * TwoComplement @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class TwoComplement extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['TwoComplement'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) this.inp1 = new Node(-10, 0, 0, this, this.bitWidth, 'input stream') @@ -77,7 +73,7 @@ export default class TwoComplement extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -98,5 +94,5 @@ export default class TwoComplement extends CircuitElement { * @category modules */ TwoComplement.prototype.tooltipText = - "Two's Complement Tooltip : Calculates the two's complement" + "Two's Complement ToolTip : Calculates the two's complement" TwoComplement.prototype.objectType = 'TwoComplement' diff --git a/v0/src/simulator/src/modules/VariableLed.js b/v0/src/simulator/src/modules/VariableLed.js index a32cb5aa..bd9c5bef 100644 --- a/v0/src/simulator/src/modules/VariableLed.js +++ b/v0/src/simulator/src/modules/VariableLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, @@ -10,7 +10,6 @@ import { colorToRGBA, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * VariableLed @@ -24,14 +23,10 @@ import { colors } from '../themer/themer' export default class VariableLed extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { - // Calling base class constructor - super(x, y, scope, 'UP', 8) - /* this is done in this.baseSetup() now - this.scope['VariableLed'].push(this); - */ this.rectangleObject = false this.setDimensions(10, 20) + this.downDimensionY = 40; this.inp1 = new Node(-40, 0, 0, this, 8) this.directionFixed = true this.fixedBitWidth = true @@ -120,16 +115,12 @@ export default class VariableLed extends CircuitElement { lineTo(ctx, 0, -9, xx, yy, this.direction) arc(ctx, 0, 0, 9, -Math.PI / 2, Math.PI / 2, xx, yy, this.direction) lineTo(ctx, -20, 9, xx, yy, this.direction) - /* lineTo(ctx,-18,12,xx,yy,this.direction); - arc(ctx,0,0,Math.sqrt(468),((Math.PI/2) + Math.acos(12/Math.sqrt(468))),((-Math.PI/2) - Math.asin(18/Math.sqrt(468))),xx,yy,this.direction); - - */ lineTo(ctx, -20, -9, xx, yy, this.direction) ctx.stroke() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -157,7 +148,7 @@ export default class VariableLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v0/src/simulator/src/modules/XnorGate.js b/v0/src/simulator/src/modules/XnorGate.js index dd93e734..0a95867e 100644 --- a/v0/src/simulator/src/modules/XnorGate.js +++ b/v0/src/simulator/src/modules/XnorGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, bezierCurveTo, @@ -35,9 +35,6 @@ export default class XnorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['XnorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -132,12 +129,11 @@ export default class XnorGate extends CircuitElement { this.direction ) bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction); ctx.closePath() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/modules/XorGate.js b/v0/src/simulator/src/modules/XorGate.js index 74c5b0d8..067afd05 100644 --- a/v0/src/simulator/src/modules/XorGate.js +++ b/v0/src/simulator/src/modules/XorGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, bezierCurveTo, moveTo, arc2 } from '../canvasApi' import { changeInputSize } from '../modules' import { gateGenerateVerilog } from '../utils' @@ -29,9 +29,6 @@ export default class XorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['XorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -125,12 +122,11 @@ export default class XorGate extends CircuitElement { this.direction ) bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction); ctx.closePath() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -161,7 +157,7 @@ export default class XorGate extends CircuitElement { * @type {string} * @category modules */ -XorGate.prototype.tooltipText = 'Xor Gate Tooltip : Implements an exclusive OR.' +XorGate.prototype.tooltipText = 'Xor Gate ToolTip : Implements an exclusive OR.' /** * @memberof XorGate diff --git a/v0/src/simulator/src/modules/verilogDivider.js b/v0/src/simulator/src/modules/verilogDivider.js index cd6acaf5..c3421cc8 100644 --- a/v0/src/simulator/src/modules/verilogDivider.js +++ b/v0/src/simulator/src/modules/verilogDivider.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogDivider extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogDivider'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v0/src/simulator/src/modules/verilogMultiplier.js b/v0/src/simulator/src/modules/verilogMultiplier.js index d428c036..2e3a41db 100644 --- a/v0/src/simulator/src/modules/verilogMultiplier.js +++ b/v0/src/simulator/src/modules/verilogMultiplier.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogMultiplier extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogMultiplier'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v0/src/simulator/src/modules/verilogPower.js b/v0/src/simulator/src/modules/verilogPower.js index ded6fdc1..10f764fa 100644 --- a/v0/src/simulator/src/modules/verilogPower.js +++ b/v0/src/simulator/src/modules/verilogPower.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogPower extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogPower'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v0/src/simulator/src/modules/verilogShiftLeft.js b/v0/src/simulator/src/modules/verilogShiftLeft.js index 65a61a4c..012fa63f 100644 --- a/v0/src/simulator/src/modules/verilogShiftLeft.js +++ b/v0/src/simulator/src/modules/verilogShiftLeft.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogShiftLeft extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogShiftLeft'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input') diff --git a/v0/src/simulator/src/modules/verilogShiftRight.js b/v0/src/simulator/src/modules/verilogShiftRight.js index a37332fb..5aad5c23 100644 --- a/v0/src/simulator/src/modules/verilogShiftRight.js +++ b/v0/src/simulator/src/modules/verilogShiftRight.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogShiftRight extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogShiftRight'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input') diff --git a/v0/src/simulator/src/node.js b/v0/src/simulator/src/node.js index 696a664b..c81f781a 100644 --- a/v0/src/simulator/src/node.js +++ b/v0/src/simulator/src/node.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-cycle */ import { drawCircle, drawLine, arc } from './canvasApi' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { distance, showError } from './utils' import { renderCanvas, @@ -12,8 +12,8 @@ import { canvasMessageData, } from './engine' import Wire from './wire' -// import { colors } from './themer/themer'; import { colors } from './themer/themer' +import ContentionMeta from './contention' /** * Constructs all the connections of Node node @@ -24,7 +24,7 @@ import { colors } from './themer/themer' export function constructNodeConnections(node, data) { for (var i = 0; i < data.connections.length; i++) { if ( - !node.connections.contains(node.scope.allNodes[data.connections[i]]) + !node.connections.includes(node.scope.allNodes[data.connections[i]]) ) node.connect(node.scope.allNodes[data.connections[i]]) } @@ -42,12 +42,13 @@ export function replace(node, index) { } var { scope } = node var { parent } = node - parent.nodeList.clean(node) + parent.nodeList = parent.nodeList.filter(x=> x !== node); node.delete() node = scope.allNodes[index] node.parent = parent parent.nodeList.push(node) node.updateRotation() + node.scope.timeStamp = new Date().getTime() return node } function rotate(x1, y1, dir) { @@ -162,7 +163,7 @@ export default class Node { this.id = `node${uniqueIdCounter}` uniqueIdCounter++ this.parent = parent - if (type != 2 && this.parent.nodeList !== undefined) { + if (type != NODE_INTERMEDIATE && this.parent.nodeList !== undefined) { this.parent.nodeList.push(this) } @@ -187,6 +188,7 @@ export default class Node { this.hover = false this.wasClicked = false this.scope = this.parent.scope + this.scope.timeStamp = new Date().getTime() /** * @type {string} * value of this.prev is @@ -201,7 +203,7 @@ export default class Node { // This fn is called during rotations and setup this.refresh() - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { this.parent.scope.nodes.push(this) } @@ -226,7 +228,7 @@ export default class Node { * function to convert a node to intermediate node */ converToIntermediate() { - this.type = 2 + this.type = NODE_INTERMEDIATE this.x = this.absX() this.y = this.absY() this.parent = this.scope.root @@ -250,10 +252,10 @@ export default class Node { } /** - * Funciton for saving a node + * function for saving a node */ saveObject() { - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { this.leftx = this.x this.lefty = this.y } @@ -288,8 +290,9 @@ export default class Node { refresh() { this.updateRotation() for (var i = 0; i < this.connections.length; i++) { - this.connections[i].connections.clean(this) + this.connections[i].connections = this.connections[i].connections.filter(x => x !== this) } + this.scope.timeStamp = new Date().getTime() this.connections = [] } @@ -312,7 +315,7 @@ export default class Node { */ updateScope(scope) { this.scope = scope - if (this.type == 2) this.parent = scope.root + if (this.type == NODE_INTERMEDIATE) this.parent = scope.root } /** @@ -335,11 +338,15 @@ export default class Node { */ connect(n) { if (n == this) return - if (n.connections.contains(this)) return - var w = new Wire(this, n, this.parent.scope) + if (n.connections.includes(this)) { + return + } + new Wire(this, n, this.parent.scope) this.connections.push(n) n.connections.push(this) + this.scope.timeStamp = new Date().getTime() + updateCanvasSet(true) updateSimulationSet(true) scheduleUpdate() @@ -350,11 +357,13 @@ export default class Node { */ connectWireLess(n) { if (n == this) return - if (n.connections.contains(this)) return + if (n.connections.includes(this)) return this.connections.push(n) n.connections.push(this) - updateCanvasSet(true) + this.scope.timeStamp = new Date().getTime() + + // updateCanvasSet(true) updateSimulationSet(true) scheduleUpdate() } @@ -363,14 +372,22 @@ export default class Node { * disconnecting two nodes connected wirelessly */ disconnectWireLess(n) { - this.connections.clean(n) - n.connections.clean(this) + this.connections = this.connections.filter(x => x !== n) + n.connections = n.connections.filter(x => x !== this) + + this.scope.timeStamp = new Date().getTime() } /** * function to resolve a node */ resolve() { + if (this.type == NODE_OUTPUT) { + // Since output node forces its value on its neighbours, remove its contentions. + // An existing contention will now trickle to the other output node that was causing + // the contention. + simulationArea.contentionPending.removeAllContentionsForNode(this); + } // Remove Propogation of values (TriState) if (this.value == undefined) { for (var i = 0; i < this.connections.length; i++) { @@ -395,7 +412,7 @@ export default class Node { this.parent.isResolvable() && !this.parent.queueProperties.inQueue ) { - if (this.parent.objectType == 'TriState') { + if (this.parent.objectType == 'TriState' || this.parent.objectType == 'ControlledInverter') { if (this.parent.state.value) { simulationArea.simulationQueue.add(this.parent) } @@ -408,52 +425,69 @@ export default class Node { return } - if (this.type == 0) { + // For input nodes, resolve its parents if they are resolvable at this point. + if (this.type == NODE_INPUT) { if (this.parent.isResolvable()) { simulationArea.simulationQueue.add(this.parent) } } + else if (this.type == NODE_OUTPUT) { + // Since output node forces its value on its neighbours, remove its contentions. + // An existing contention will now trickle to the other output node that was causing + // the contention. + simulationArea.contentionPending.removeAllContentionsForNode(this); + } for (var i = 0; i < this.connections.length; i++) { - const node = this.connections[i] - - if (node.value != this.value || node.bitWidth != this.bitWidth) { - if ( - node.type == 1 && - node.value != undefined && - node.parent.objectType != 'TriState' && - !(node.subcircuitOverride && node.scope != this.scope) && // Subcircuit Input Node Output Override - node.parent.objectType != 'SubCircuit' - ) { - // Subcircuit Output Node Override - this.highlighted = true - node.highlighted = true - var circuitName = node.scope.name - var circuitElementName = node.parent.objectType - showError( - `Contention Error: ${this.value} and ${node.value} at ${circuitElementName} in ${circuitName}` - ) - } else if (node.bitWidth == this.bitWidth || node.type == 2) { - if ( - node.parent.objectType == 'TriState' && - node.value != undefined && - node.type == 1 - ) { - if (node.parent.state.value) { - simulationArea.contentionPending.push(node.parent) + const node = this.connections[i]; + + switch (node.type) { + // TODO: For an output node, a downstream value (value given by elements other than the parent) + // should be overwritten in contention check and should not cause contention. + case NODE_OUTPUT: + if (node.value != this.value || node.bitWidth != this.bitWidth) { + // Check contentions + if (node.value != undefined && node.parent.objectType != 'SubCircuit' + && !(node.subcircuitOverride && node.scope != this.scope)) { + // Tristate has always been a pain in the ass. + if ((node.parent.objectType == 'TriState' || node.parent.objectType == 'ControlledInverter') && node.value != undefined) { + if (node.parent.state.value) { + simulationArea.contentionPending.add(node, this); + break; + } + } + else { + simulationArea.contentionPending.add(node, this); + break; } } - - node.bitWidth = this.bitWidth - node.value = this.value - simulationArea.simulationQueue.add(node) } else { - this.highlighted = true - node.highlighted = true - showError( - `BitWidth Error: ${this.bitWidth} and ${node.bitWidth}` - ) + // Output node was given an agreeing value, so remove any contention + // entry between these two nodes if it exists. + simulationArea.contentionPending.remove(node, this); + } + + // Fallthrough. NODE_OUTPUT propagates like a contention checked NODE_INPUT + case NODE_INPUT: + // Check bitwidths + if (this.bitWidth != node.bitWidth) { + this.highlighted = true; + node.highlighted = true; + showError(`BitWidth Error: ${this.bitWidth} and ${node.bitWidth}`); + break; } + + // Fallthrough. NODE_INPUT propagates like a bitwidth checked NODE_INTERMEDIATE + case NODE_INTERMEDIATE: + + if (node.value != this.value || node.bitWidth != this.bitWidth) { + // Propagate + node.bitWidth = this.bitWidth; + node.value = this.value; + simulationArea.simulationQueue.add(node); + } + default: + break; } } } @@ -563,8 +597,8 @@ export default class Node { if (this.bitWidth == 1) colorNode = [colorNodeConnect, colorNodePow][this.value] if (this.value == undefined) colorNode = colorNodeLose - if (this.type == 2) this.checkHover() - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) this.checkHover() + if (this.type == NODE_INTERMEDIATE) { drawCircle(ctx, this.absX(), this.absY(), 3, colorNode) } else { drawCircle(ctx, this.absX(), this.absY(), 3, colorNodeSelected) @@ -576,7 +610,7 @@ export default class Node { (this.isHover() && !simulationArea.selected && !simulationArea.shiftDown) || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.strokeStyle = colorNodeSelected ctx.beginPath() @@ -600,7 +634,7 @@ export default class Node { if (this.showHover || simulationArea.lastSelected == this) { canvasMessageData.x = this.absX() canvasMessageData.y = this.absY() - 15 - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { var v = 'X' if (this.value !== undefined) { v = this.value.toString(16) @@ -629,7 +663,7 @@ export default class Node { */ checkDeleted() { if (this.deleted) this.delete() - if (this.connections.length == 0 && this.type == 2) this.delete() + if (this.connections.length == 0 && this.type == NODE_INTERMEDIATE) this.delete() } /** @@ -670,10 +704,10 @@ export default class Node { if (!this.wasClicked && this.clicked) { this.wasClicked = true this.prev = 'a' - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( var i = 0; @@ -689,9 +723,9 @@ export default class Node { if (simulationArea.shiftDown) { simulationArea.lastSelected = undefined if ( - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { - simulationArea.multipleObjectSelections.clean(this) + simulationArea.multipleObjectSelections = simulationArea.multipleObjectSelections.filter(x=> x !== this); } else { simulationArea.multipleObjectSelections.push(this) } @@ -702,7 +736,7 @@ export default class Node { } else if (this.wasClicked && this.clicked) { if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( var i = 0; @@ -712,7 +746,7 @@ export default class Node { simulationArea.multipleObjectSelections[i].drag() } } - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { if ( this.connections.length == 1 && this.connections[0].absX() == simulationArea.mouseX && @@ -881,7 +915,7 @@ export default class Node { simulationArea.lastSelected = n2 } - if (this.type == 2 && simulationArea.mouseDown == false) { + if (this.type == NODE_INTERMEDIATE && simulationArea.mouseDown == false) { if (this.connections.length == 2) { if ( this.connections[0].absX() == this.connections[1].absX() || @@ -900,17 +934,20 @@ export default class Node { delete() { updateSimulationSet(true) this.deleted = true - this.parent.scope.allNodes.clean(this) - this.parent.scope.nodes.clean(this) + this.parent.scope.allNodes = this.parent.scope.allNodes.filter(x => x !== this) + this.parent.scope.nodes = this.parent.scope.nodes.filter(x => x !== this) - this.parent.scope.root.nodeList.clean(this) // Hope this works! - Can cause bugs + this.parent.scope.root.nodeList = this.parent.scope.root.nodeList.filter(x => x !== this) // Hope this works! - Can cause bugs if (simulationArea.lastSelected == this) simulationArea.lastSelected = undefined for (var i = 0; i < this.connections.length; i++) { - this.connections[i].connections.clean(this) + this.connections[i].connections = this.connections[i].connections.filter(x => x !== this) this.connections[i].checkDeleted() } + + this.scope.timeStamp = new Date().getTime() + wireToBeCheckedSet(1) forceResetNodesSet(true) scheduleUpdate() @@ -947,7 +984,7 @@ export default class Node { y == this.parent.scope.allNodes[i].absY() ) { n = this.parent.scope.allNodes[i] - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { for (var j = 0; j < this.connections.length; j++) { n.connect(this.connections[j]) } @@ -964,7 +1001,7 @@ export default class Node { for (var i = 0; i < this.parent.scope.wires.length; i++) { if (this.parent.scope.wires[i].checkConvergence(this)) { var n = this - if (this.type != 2) { + if (this.type != NODE_INTERMEDIATE) { n = new Node( this.absX(), this.absY(), diff --git a/v0/src/simulator/src/plotArea.js b/v0/src/simulator/src/plotArea.js index 79bf2582..869d27ac 100644 --- a/v0/src/simulator/src/plotArea.js +++ b/v0/src/simulator/src/plotArea.js @@ -1,5 +1,10 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { convertors } from './utils' +import { join, downloadDir } from '@tauri-apps/api/path'; +import { writeFile } from '@tauri-apps/plugin-fs'; +import { isTauri } from '@tauri-apps/api/core' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' var DPR = window.devicePixelRatio || 1 @@ -106,12 +111,43 @@ const plotArea = { }, // download as image download() { + if(isTauri()){ + this.downloadImageDesktop() + return + } + var img = this.canvas.toDataURL(`image/png`) const anchor = document.createElement('a') anchor.href = img anchor.download = `waveform.png` anchor.click() }, + // download as image for desktop + async downloadImageDesktop() { + try { + const img = this.canvas.toDataURL('image/png'); + + const response = await fetch(img); + const blob = await response.blob(); + + const arrayBuffer = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsArrayBuffer(blob); + }); + + const downloadsDirectory = await downloadDir(); + + const random = Math.random().toString(36).substring(7); + + const path = await join(downloadsDirectory, `waveform-${random}.png`); + + await writeFile({ path, contents: new Uint8Array(arrayBuffer) }); + } catch (error) { + console.error('Error during download:', error); + } + }, // update canvas size to use full screen resize() { var oldHeight = this.height @@ -403,12 +439,16 @@ const plotArea = { }, // Driver function to render and update plot() { + const simulatorMobileStore = useSimulatorMobileStore() + const { showCanvas } = toRefs(simulatorMobileStore) if (embed) return if (globalScope.Flag.length === 0) { this.canvas.width = 0 this.canvas.height = 0 + showCanvas.value = false return } + showCanvas.value = true this.update() this.render() @@ -445,52 +485,6 @@ const timingDiagramButtonActions = { export { timingDiagramButtonActions } export function setupTimingListeners() { - // $('.timing-diagram-smaller').on('click', () => { - // $('#plot').width(Math.max($('#plot').width() - 20, 560)) - // plotArea.resize() - // }) - // $('.timing-diagram-larger').on('click', () => { - // $('#plot').width($('#plot').width() + 20) - // plotArea.resize() - // }) - // $('.timing-diagram-small-height').on('click', () => { - // if (plotHeight >= sh(20)) { - // plotHeight -= sh(5) - // waveFormHeight = plotHeight - 2 * waveFormPadding - // } - // }) - // $('.timing-diagram-large-height').on('click', () => { - // if (plotHeight < sh(50)) { - // plotHeight += sh(5) - // waveFormHeight = plotHeight - 2 * waveFormPadding - // } - // }) - // $('.timing-diagram-reset').on('click', () => { - // plotArea.reset() - // }) - // $('.timing-diagram-calibrate').on('click', () => { - // plotArea.calibrate() - // }) - // $('.timing-diagram-resume').on('click', () => { - // plotArea.resume() - // }) - // $('.timing-diagram-pause').on('click', () => { - // plotArea.pause() - // }) - // $('.timing-diagram-download').on('click', () => { - // plotArea.download() - // }) - // $('.timing-diagram-zoom-in').on('click', () => { - // plotArea.zoomIn() - // }) - // $('.timing-diagram-zoom-out').on('click', () => { - // plotArea.zoomOut() - // }) - // $('#timing-diagram-units').on('change paste keyup', function () { - // var timeUnits = parseInt($(this).val(), 10) - // if (isNaN(timeUnits) || timeUnits < 1) return - // plotArea.cycleUnit = timeUnits - // }) document.getElementById('plotArea').addEventListener('mousedown', (e) => { var rect = plotArea.canvas.getBoundingClientRect() var x = sh(e.clientX - rect.left) diff --git a/v1/src/simulator/src/quinMcCluskey.js b/v0/src/simulator/src/quinMcCluskey.ts similarity index 84% rename from v1/src/simulator/src/quinMcCluskey.js rename to v0/src/simulator/src/quinMcCluskey.ts index f15041db..5983fb47 100644 --- a/v1/src/simulator/src/quinMcCluskey.js +++ b/v0/src/simulator/src/quinMcCluskey.ts @@ -1,11 +1,18 @@ // Algorithm used for Combinational Analysis +type BooleanMinimizeType = { + minTerms: number[] + dontCares: number[] + numVars: number + result: string[] +} + export default function BooleanMinimize( - numVarsArg, - minTermsArg, - dontCaresArg = [] + numVarsArg: number, + minTermsArg: number[], + dontCaresArg: number[] = [] ) { - var __result + var __result: string[] Object.defineProperties(this, { minTerms: { @@ -47,7 +54,7 @@ export default function BooleanMinimize( } BooleanMinimize.prototype.solve = function () { - function dec_to_binary_string(n) { + const dec_to_binary_string = (n: number) => { var str = n.toString(2) while (str.length != this.numVars) { @@ -57,14 +64,14 @@ BooleanMinimize.prototype.solve = function () { return str } - function num_set_bits(s) { + const num_set_bits = (s: string) => { var ans = 0 for (let i = 0; i < s.length; ++i) if (s[i] === '1') ans++ return ans } - function get_prime_implicants(allTerms) { - var table = [] + const get_prime_implicants = (allTerms: string[]) => { + var table: Set[] = [] var primeImplicants = new Set() var reduced @@ -115,11 +122,11 @@ BooleanMinimize.prototype.solve = function () { return primeImplicants } - function get_essential_prime_implicants(primeImplicants, minTerms) { + const get_essential_prime_implicants = (primeImplicants: string[], minTerms: string[]) => { var table = [], column - function check_if_similar(minTerm, primeImplicant) { + const check_if_similar = (minTerm: string, primeImplicant: string) => { for (let i = 0; i < primeImplicant.length; ++i) { if ( primeImplicant[i] !== '-' && @@ -131,7 +138,7 @@ BooleanMinimize.prototype.solve = function () { return true } - function get_complexity(terms) { + const get_complexity = (terms: string[]) => { var complexity = terms.length for (let t of terms) { @@ -146,7 +153,7 @@ BooleanMinimize.prototype.solve = function () { return complexity } - function isSubset(sub, sup) { + const isSubset = (sub: Set, sup: Set) => { for (let i of sub) { if (!sup.has(i)) return false } @@ -166,8 +173,8 @@ BooleanMinimize.prototype.solve = function () { table.push(column) } - var possibleSets = [], - tempSets + let possibleSets: Set[] = [], + tempSets: Set[] for (let i of table[0]) { possibleSets.push(new Set([i])) @@ -216,12 +223,12 @@ BooleanMinimize.prototype.solve = function () { return essentialImplicants } - var minTerms = this.minTerms.map(dec_to_binary_string.bind(this)) - var dontCares = this.dontCares.map(dec_to_binary_string.bind(this)) + var minTerms: string[] = this.minTerms.map(dec_to_binary_string.bind(this)) + var dontCares: string[] = this.dontCares.map(dec_to_binary_string.bind(this)) return get_essential_prime_implicants.call( this, - Array.from(get_prime_implicants.call(this, minTerms.concat(dontCares))), + Array.from(get_prime_implicants.call(this, minTerms.concat(dontCares))) as string[], minTerms ) } diff --git a/v0/src/simulator/src/sequential.js b/v0/src/simulator/src/sequential.js index bd1740de..46dcd693 100644 --- a/v0/src/simulator/src/sequential.js +++ b/v0/src/simulator/src/sequential.js @@ -1,5 +1,5 @@ import { scheduleUpdate, play, updateCanvasSet } from './engine' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' /** * a global function as a helper for simulationArea.changeClockEnable @@ -8,18 +8,3 @@ import simulationArea from './simulationArea' export function changeClockEnable(val) { simulationArea.clockEnabled = val } - -/** - * WIP function defined and used - * @param {number} n - * @category sequential - */ -export function runTest(n = 10) { - var t = new Date().getTime() - for (var i = 0; i < n; i++) { - clockTick() - } - updateCanvasSet(true) - play() - scheduleUpdate() -} diff --git a/v0/src/simulator/src/sequential/Clock.js b/v0/src/simulator/src/sequential/Clock.js index 86e24955..fcfac673 100644 --- a/v0/src/simulator/src/sequential/Clock.js +++ b/v0/src/simulator/src/sequential/Clock.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo } from '../canvasApi' import { colors } from '../themer/themer' /** @@ -17,9 +17,6 @@ import { colors } from '../themer/themer' export default class Clock extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['Clock'].push(this); - */ this.fixedBitWidth = true this.output1 = new Node(10, 0, 1, this, 1) this.state = 0 diff --git a/v0/src/simulator/src/sequential/DflipFlop.js b/v0/src/simulator/src/sequential/DflipFlop.js index 4543ba61..f21fe2a1 100644 --- a/v0/src/simulator/src/sequential/DflipFlop.js +++ b/v0/src/simulator/src/sequential/DflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import { colors } from '../themer/themer' /** @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class DflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* - this.scope['DflipFlop'].push(this); - */ this.directionFixed = true this.setDimensions(20, 20) this.rectangleObject = true @@ -43,9 +40,6 @@ export default class DflipFlop extends CircuitElement { */ isResolvable() { return true - // if (this.reset.value == 1) return true; - // if (this.clockInp.value != undefined && this.dInp.value != undefined) return true; - // return false; } newBitWidth(bitWidth) { @@ -116,7 +110,6 @@ export default class DflipFlop extends CircuitElement { customDraw() { var ctx = simulationArea.context - // ctx.strokeStyle = colors['stroke'] ctx.fillStyle = colors['fill'] ctx.beginPath() @@ -127,7 +120,6 @@ export default class DflipFlop extends CircuitElement { moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() diff --git a/v0/src/simulator/src/sequential/Dlatch.js b/v0/src/simulator/src/sequential/Dlatch.js index 7532d3db..cc3b7097 100644 --- a/v0/src/simulator/src/sequential/Dlatch.js +++ b/v0/src/simulator/src/sequential/Dlatch.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -20,9 +20,6 @@ import { colors } from '../themer/themer' export default class Dlatch extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* - this.scope['Dlatch'].push(this); - */ this.directionFixed = true this.setDimensions(20, 20) this.rectangleObject = true @@ -30,16 +27,13 @@ export default class Dlatch extends CircuitElement { this.dInp = new Node(-20, -10, 0, this, this.bitWidth, 'D') this.qOutput = new Node(20, -10, 1, this, this.bitWidth, 'Q') this.qInvOutput = new Node(20, 10, 1, this, this.bitWidth, 'Q Inverse') - // this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset"); - // this.preset = new Node(0, 20, 0, this, this.bitWidth, "Preset"); - // this.en = new Node(-10, 20, 0, this, 1, "Enable"); this.state = 0 this.prevClockState = 0 this.wasClicked = false } /** - * Idea: shoould be D FF? + * Idea: should be D FF? */ isResolvable() { if (this.clockInp.value != undefined && this.dInp.value != undefined) @@ -52,7 +46,6 @@ export default class Dlatch extends CircuitElement { this.dInp.bitWidth = bitWidth this.qOutput.bitWidth = bitWidth this.qInvOutput.bitWidth = bitWidth - // this.preset.bitWidth = bitWidth; } /** @@ -80,9 +73,6 @@ export default class Dlatch extends CircuitElement { dInp: findNode(this.dInp), qOutput: findNode(this.qOutput), qInvOutput: findNode(this.qInvOutput), - // reset: findNode(this.reset), - // preset: findNode(this.preset), - // en: findNode(this.en), }, constructorParamaters: [this.direction, this.bitWidth], } @@ -97,11 +87,9 @@ export default class Dlatch extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' diff --git a/v0/src/simulator/src/sequential/EEPROM.js b/v0/src/simulator/src/sequential/EEPROM.js index 3a3427b8..f2e13636 100644 --- a/v0/src/simulator/src/sequential/EEPROM.js +++ b/v0/src/simulator/src/sequential/EEPROM.js @@ -31,9 +31,6 @@ export default class EEPROM extends RAM { data = null ) { super(x, y, scope, dir, bitWidth, addressWidth) - /* - this.scope['EEPROM'].push(this); - */ this.data = data || this.data } diff --git a/v0/src/simulator/src/sequential/ForceGate.js b/v0/src/simulator/src/sequential/ForceGate.js new file mode 100644 index 00000000..332af06c --- /dev/null +++ b/v0/src/simulator/src/sequential/ForceGate.js @@ -0,0 +1,92 @@ +import CircuitElement from '../circuitElement' +import Node, { findNode } from '../node' +import { simulationArea } from '../simulationArea' +import { fillText4 } from '../canvasApi' +/** + * @class + * ForceGate + * @extends CircuitElement + * @param {number} x - x coordinate of element. + * @param {number} y - y coordinate of element. + * @param {Scope=} scope - Cirucit on which element is drawn + * @param {string=} dir - direction of element + * @param {number=} bitWidth - bit width per node. + * @category testbench + */ +export default class ForceGate extends CircuitElement { + constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { + super(x, y, scope, dir, bitWidth) + this.setDimensions(20, 10) + this.objectType = 'ForceGate' + this.scope.ForceGate.push(this) + this.inp1 = new Node(-20, 0, 0, this) + this.inp2 = new Node(0, 0, 0, this) + this.output1 = new Node(20, 0, 1, this) + } + + /** + * @memberof ForceGate + * Checks if the element is resolvable + * @return {boolean} + */ + isResolvable() { + return this.inp1.value !== undefined || this.inp2.value !== undefined + } + + /** + * @memberof ForceGate + * fn to create save Json Data of object + * @return {JSON} + */ + customSave() { + const data = { + constructorParamaters: [this.direction, this.bitWidth], + nodes: { + output1: findNode(this.output1), + inp1: findNode(this.inp1), + inp2: findNode(this.inp2), + }, + } + return data + } + + /** + * @memberof ForceGate + * resolve output values based on inputData + */ + resolve() { + if (this.inp2.value !== undefined) { + this.output1.value = this.inp2.value + } else { + this.output1.value = this.inp1.value + } + simulationArea.simulationQueue.add(this.output1) + } + + /** + * @memberof ForceGate + * function to draw element + */ + customDraw() { + var ctx = simulationArea.context + const xx = this.x + const yy = this.y + + ctx.beginPath() + ctx.fillStyle = 'Black' + ctx.textAlign = 'center' + + fillText4(ctx, 'I', -10, 0, xx, yy, this.direction, 10) + fillText4(ctx, 'O', 10, 0, xx, yy, this.direction, 10) + ctx.fill() + } +} + +/** + * @memberof ForceGate + * Help Tip + * @type {string} + * @category testbench + */ +ForceGate.prototype.tooltipText = 'Force Gate ToolTip : ForceGate Selected.' +ForceGate.prototype.objectType = 'ForceGate' diff --git a/v0/src/simulator/src/sequential/JKflipFlop.js b/v0/src/simulator/src/sequential/JKflipFlop.js index c02eae3f..4f975c79 100644 --- a/v0/src/simulator/src/sequential/JKflipFlop.js +++ b/v0/src/simulator/src/sequential/JKflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class JKflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['JKflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -37,8 +34,6 @@ export default class JKflipFlop extends CircuitElement { this.slaveState = 0 this.masterState = 0 this.prevClockState = 0 - - // this.wasClicked = false; } /** @@ -139,13 +134,9 @@ export default class JKflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() diff --git a/v0/src/simulator/src/sequential/Keyboard.js b/v0/src/simulator/src/sequential/Keyboard.js index ffeb7a9c..a86a1d04 100644 --- a/v0/src/simulator/src/sequential/Keyboard.js +++ b/v0/src/simulator/src/sequential/Keyboard.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText3 } from '../canvasApi' /** * @class @@ -18,15 +18,12 @@ import { colors } from '../themer/themer' export default class Keyboard extends CircuitElement { constructor(x, y, scope = globalScope, bufferSize = 32) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['Keyboard'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.bufferSize = bufferSize || parseInt(prompt('Enter buffer size:')) this.elementWidth = Math.max(80, Math.ceil(this.bufferSize / 2) * 20) - this.elementHeight = 40 // Math.max(40,Math.ceil(this.rows*15/20)*20); + this.elementHeight = 40 this.setWidth(this.elementWidth / 2) this.setHeight(this.elementHeight / 2) diff --git a/v0/src/simulator/src/sequential/RAM.js b/v0/src/simulator/src/sequential/RAM.js index b406f921..cdaab091 100644 --- a/v0/src/simulator/src/sequential/RAM.js +++ b/v0/src/simulator/src/sequential/RAM.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' import { parseNumber, showMessage } from '../utils' /** @@ -43,7 +43,6 @@ import { parseNumber, showMessage } from '../utils' * by keeping the max addressWidth small. If needed, we can increase the max. * @category sequential */ -import { colors } from '../themer/themer' import { showError } from '../utils' export default class RAM extends CircuitElement { constructor( @@ -55,9 +54,6 @@ export default class RAM extends CircuitElement { addressWidth = 10 ) { super(x, y, scope, dir, Math.min(Math.max(1, bitWidth), 32)) - /* - this.scope['RAM'].push(this); - */ this.setDimensions(60, 40) this.directionFixed = true @@ -270,9 +266,6 @@ export default class RAM extends CircuitElement { } showMessage('Data dumped to developer Console') - - console.log(JSON.stringify(this.data)) - if (logLabel) { console.groupEnd() } diff --git a/v0/src/simulator/src/sequential/Rom.js b/v0/src/simulator/src/sequential/Rom.js index 69bb544b..823208ab 100644 --- a/v0/src/simulator/src/sequential/Rom.js +++ b/v0/src/simulator/src/sequential/Rom.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText3 } from '../canvasApi' /** * @class @@ -21,9 +21,6 @@ export default class Rom extends CircuitElement { data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['Rom'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.rectangleObject = false @@ -133,7 +130,7 @@ export default class Rom extends CircuitElement { hoverIndex === undefined && ((!simulationArea.shiftDown && this.hover) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + simulationArea.multipleObjectSelections.includes(this)) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v0/src/simulator/src/sequential/SRflipFlop.js b/v0/src/simulator/src/sequential/SRflipFlop.js index af1a16ce..f3010fbe 100644 --- a/v0/src/simulator/src/sequential/SRflipFlop.js +++ b/v0/src/simulator/src/sequential/SRflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class SRflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['SRflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -33,9 +30,6 @@ export default class SRflipFlop extends CircuitElement { this.preset = new Node(0, 20, 0, this, 1, 'Preset') this.en = new Node(-10, 20, 0, this, 1, 'Enable') this.state = 0 - // this.slaveState = 0; - // this.prevClockState = 0; - // this.wasClicked = false; } newBitWidth(bitWidth) { @@ -52,9 +46,6 @@ export default class SRflipFlop extends CircuitElement { */ isResolvable() { return true - if (this.reset.value == 1) return true - if (this.S.value != undefined && this.R.value != undefined) return true - return false } /** @@ -105,20 +96,13 @@ export default class SRflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - - // rect(ctx, xx - 20, yy - 20, 40, 40); - // moveTo(ctx, -20, 5, xx, yy, this.direction); - // lineTo(ctx, -15, 10, xx, yy, this.direction); - // lineTo(ctx, -20, 15, xx, yy, this.direction); - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' ctx.fillStyle = colors['input_text'] ctx.textAlign = 'center' - fillText(ctx, this.state.toString(16), xx, yy + 5) + this.state ? fillText(ctx, this.state.toString(16), xx, yy + 5) : fillText(ctx, '0', xx, yy + 5); ctx.fill() } } diff --git a/v0/src/simulator/src/sequential/TTY.js b/v0/src/simulator/src/sequential/TTY.js index d0c89461..e533b99c 100644 --- a/v0/src/simulator/src/sequential/TTY.js +++ b/v0/src/simulator/src/sequential/TTY.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText3 } from '../canvasApi' import { colors } from '../themer/themer' @@ -21,9 +21,6 @@ import { colors } from '../themer/themer' export default class TTY extends CircuitElement { constructor(x, y, scope = globalScope, rows = 3, cols = 32) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['TTY'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.cols = cols || parseInt(prompt('Enter cols:')) @@ -33,7 +30,6 @@ export default class TTY extends CircuitElement { this.elementHeight = Math.max(40, Math.ceil((this.rows * 15) / 20) * 20) this.setWidth(this.elementWidth / 2) this.setHeight(this.elementHeight / 2) - // this.element = new Element(x, y, "TTY",this.elementWidth/2, this,this.elementHeight/2); this.clockInp = new Node( -this.elementWidth / 2, @@ -51,7 +47,6 @@ export default class TTY extends CircuitElement { 7, 'Ascii Input' ) - // this.qOutput = new Node(20, -10, 1, this); this.reset = new Node( 30 - this.elementWidth / 2, this.elementHeight / 2, @@ -68,8 +63,6 @@ export default class TTY extends CircuitElement { 1, 'Enable' ) - // this.masterState = 0; - // this.slaveState = 0; this.prevClockState = 0 this.data = '' @@ -78,7 +71,7 @@ export default class TTY extends CircuitElement { /** * @memberof TTY - * this funciton is used to change the size of the screen + * this function is used to change the size of the screen */ changeRowSize(size) { if (size == undefined || size < 1 || size > 10) return @@ -91,7 +84,7 @@ export default class TTY extends CircuitElement { /** * @memberof TTY - * this funciton is used to change the size of the screen + * this function is used to change the size of the screen */ changeColSize(size) { if (size == undefined || size < 20 || size > 100) return @@ -173,7 +166,6 @@ export default class TTY extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - this.elementWidth/2, yy - this.elementHeight/2, this.elementWidth, this.elementHeight); moveTo( ctx, @@ -199,9 +191,6 @@ export default class TTY extends CircuitElement { yy, this.direction ) - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) - // ctx.fillStyle = "rgba(255, 255, 32,0.8)"; ctx.stroke() ctx.beginPath() diff --git a/v0/src/simulator/src/sequential/TflipFlop.js b/v0/src/simulator/src/sequential/TflipFlop.js index cedb9f6b..ce1f7be9 100644 --- a/v0/src/simulator/src/sequential/TflipFlop.js +++ b/v0/src/simulator/src/sequential/TflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import { colors } from '../themer/themer' @@ -19,9 +19,6 @@ import { colors } from '../themer/themer' export default class TflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['TflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -36,8 +33,6 @@ export default class TflipFlop extends CircuitElement { this.masterState = 0 this.slaveState = 0 this.prevClockState = 0 - - // this.wasClicked = false; } /** @@ -133,12 +128,10 @@ export default class TflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' diff --git a/v0/src/simulator/src/sequential/verilogRAM.js b/v0/src/simulator/src/sequential/verilogRAM.js index d1e9c71d..c3915d47 100644 --- a/v0/src/simulator/src/sequential/verilogRAM.js +++ b/v0/src/simulator/src/sequential/verilogRAM.js @@ -1,7 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' +import { simulationArea } from '../simulationArea' /** * @class * verilogRAM Component. @@ -42,7 +41,6 @@ import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' * by keeping the max addressWidth small. If needed, we can increase the max. * @category sequential */ -import { colors } from '../themer/themer' function customResolve( clockInp, @@ -110,7 +108,6 @@ function customResolve( if (en[i].value == 0) { prevClockState[i] = clockInp[i].value } else if (en[i].value == 1 || en[i].connections.length == 0) { - // if(en.value==1) // Creating Infinite Loop, WHY ?? if (clockInp[i].value == prevClockState[i]) { if (clockInp[i].value == 0 && dInp[i].value != undefined) { masterState[i] = dInp[i].value @@ -152,9 +149,6 @@ export default class verilogRAM extends CircuitElement { wrports ) { super(x, y, scope, dir, Math.min(Math.max(1, bitWidth), 32)) - /* - this.scope['verilogRAM'].push(this); - */ this.setDimensions(60, 40) this.directionFixed = true @@ -413,22 +407,9 @@ export default class verilogRAM extends CircuitElement { } newBitWidth(value) { - // value = parseInt(value); - // if (!isNaN(value) && this.bitWidth != value && value >= 1 && value <= 32) { - // this.bitWidth = value; - // this.dataIn.bitWidth = value; - // this.dataOut.bitWidth = value; - // this.clearData(); - // } } changeAddressWidth(value) { - // value = parseInt(value); - // if (!isNaN(value) && this.addressWidth != value && value >= 1 && value <= this.maxAddressWidth) { - // this.addressWidth = value; - // this.address.bitWidth = value; - // this.clearData(); - // } } clearData() { @@ -498,27 +479,6 @@ export default class verilogRAM extends CircuitElement { } customDraw() { - // var ctx = simulationArea.context; - // // - // var xx = this.x; - // var yy = this.y; - // ctx.beginPath(); - // ctx.strokeStyle = 'gray'; - // ctx.fillStyle = this.write.value ? 'red' : 'lightgreen'; - // ctx.lineWidth = correctWidth(1); - // drawCircle2(ctx, 50, -30, 3, xx, yy, this.direction); - // ctx.fill(); - // ctx.stroke(); - // ctx.beginPath(); - // ctx.textAlign = 'center'; - // ctx.fillStyle = 'black'; - // fillText4(ctx, this.memSizeString(), 0, -10, xx, yy, this.direction, 12); - // fillText4(ctx, this.shortName, 0, 10, xx, yy, this.direction, 12); - // fillText2(ctx, 'A', this.address.x + 12, this.address.y, xx, yy, this.direction); - // fillText2(ctx, 'DI', this.dataIn.x + 12, this.dataIn.y, xx, yy, this.direction); - // fillText2(ctx, 'W', this.write.x + 12, this.write.y, xx, yy, this.direction); - // fillText2(ctx, 'DO', this.dataOut.x - 15, this.dataOut.y, xx, yy, this.direction); - // ctx.fill(); } memSizeString() { @@ -543,9 +503,6 @@ export default class verilogRAM extends CircuitElement { if (logLabel) { console.group(this.label) } - - console.log(this.data) - if (logLabel) { console.groupEnd() } diff --git a/v0/src/simulator/src/setup.js b/v0/src/simulator/src/setup.js index 764a211c..1f04977e 100644 --- a/v0/src/simulator/src/setup.js +++ b/v0/src/simulator/src/setup.js @@ -1,20 +1,15 @@ /* eslint-disable import/no-cycle */ /* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */ - -import { Tooltip } from 'bootstrap' -import metadata from './metadata.json' import { generateId, showMessage } from './utils' -import backgroundArea from './backgroundArea' +import { backgroundArea } from './backgroundArea' import plotArea from './plotArea' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { dots } from './canvasApi' import { update, updateSimulationSet, updateCanvasSet } from './engine' import { setupUI } from './ux' import startMainListeners from './listeners' -// import startEmbedListeners from './embedListeners' -import './embed' -import { newCircuit, scopeList } from './circuit' +import { newCircuit } from './circuit' import load from './data/load' import save from './data/save' import { showTourGuide } from './tutorials' @@ -26,7 +21,6 @@ import 'codemirror/addon/edit/closebrackets' import 'codemirror/addon/hint/anyword-hint' import 'codemirror/addon/hint/show-hint' import { setupCodeMirrorEnvironment } from './Verilog2CV' -// import { keyBinder } from '#/components/DialogBox/CustomShortcut.vue' import '../vendor/jquery-ui.min.css' import '../vendor/jquery-ui.min' import { confirmSingleOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' @@ -47,7 +41,7 @@ export function resetup() { if (!embed) { height = (document.body.clientHeight - - document.getElementById('toolbar').clientHeight) * + document.getElementById('toolbar')?.clientHeight) * DPR } else { height = document.getElementById('simulation').clientHeight * DPR @@ -97,29 +91,6 @@ function setupEnvironment() { setupCodeMirrorEnvironment() } -/** - * It initializes some useful array which are helpful - * while simulating, saving and loading project. - * It also draws icons in the sidebar - * @category setup - */ -function setupElementLists() { - // $('#menu').empty() - - window.circuitElementList = metadata.circuitElementList - window.annotationList = metadata.annotationList - window.inputList = metadata.inputList - window.subCircuitInputList = metadata.subCircuitInputList - window.moduleList = [...circuitElementList, ...annotationList] - window.updateOrder = [ - 'wires', - ...circuitElementList, - 'nodes', - ...annotationList, - ] // Order of update - window.renderOrder = [...moduleList.slice().reverse(), 'wires', 'allNodes'] // Order of render -} - /** * Fetches project data from API and loads it into the simulator. * @param {number} projectId The ID of the project to fetch data for @@ -139,14 +110,6 @@ async function fetchProjectData(projectId) { ) if (response.ok) { const data = await response.json() - const simulatorVersion = data.simulatorVersion - const projectName = data.name - if(!simulatorVersion){ - window.location.href = `/simulator/edit/${projectName}` - } - if(simulatorVersion && simulatorVersion != "v0"){ - window.location.href = `/simulatorvue/edit/${projectName}?simver=${simulatorVersion}` - } await load(data) await simulationArea.changeClockTime(data.timePeriod || 500) $('.loadingIcon').fadeOut() @@ -205,9 +168,6 @@ function showTour() { * @category setup */ export function setup() { - // let embed = false - // const startListeners = embed ? startEmbedListeners : startMainListeners - setupElementLists() setupEnvironment() if (!embed) { setupUI() diff --git a/v0/src/simulator/src/simulationArea.js b/v0/src/simulator/src/simulationArea.js deleted file mode 100644 index 3784988a..00000000 --- a/v0/src/simulator/src/simulationArea.js +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable import/no-cycle */ -import EventQueue from './eventQueue' -import { clockTick } from './utils' - -/** - * simulation environment object - holds simulation canvas - * @type {Object} simulationArea - * @property {HTMLCanvasElement} canvas - * @property {boolean} selected - * @property {boolean} hover - * @property {number} clockState - * @property {boolean} clockEnabled - * @property {undefined} lastSelected - * @property {Array} stack - * @property {number} prevScale - * @property {number} oldx - * @property {number} oldy - * @property {Array} objectList - * @property {number} maxHeight - * @property {number} maxWidth - * @property {number} minHeight - * @property {number} minWidth - * @property {Array} multipleObjectSelections - * @property {Array} copyList - List of selected elements - * @property {boolean} shiftDown - shift down or not - * @property {boolean} controlDown - contol down or not - * @property {number} timePeriod - time period - * @property {number} mouseX - mouse x - * @property {number} mouseY - mouse y - * @property {number} mouseDownX - mouse click x - * @property {number} mouseDownY - mouse click y - * @property {Array} simulationQueue - simulation queue - * @property {number} clickCount - number of clicks - * @property {string} lock - locked or unlocked - * @property {function} timer - timer - * @property {function} setup - to setup the simulaton area - * @property {function} changeClockTime - change clock time - * @property {function} clear - clear the simulation area - * @category simulationArea - */ -const simulationArea = { - canvas: document.getElementById('simulationArea'), - selected: false, - hover: false, - clockState: 0, - clockEnabled: true, - lastSelected: undefined, - stack: [], - prevScale: 0, - oldx: 0, - oldy: 0, - objectList: [], - maxHeight: 0, - maxWidth: 0, - minHeight: 0, - minWidth: 0, - multipleObjectSelections: [], - copyList: [], - shiftDown: false, - controlDown: false, - timePeriod: 500, - mouseX: 0, - mouseY: 0, - mouseDownX: 0, - mouseDownY: 0, - simulationQueue: undefined, - multiAddElement: false, - - clickCount: 0, // double click - lock: 'unlocked', - timer() { - ckickTimer = setTimeout(() => { - simulationArea.clickCount = 0 - }, 600) - }, - - setup() { - this.canvas = document.getElementById('simulationArea') - this.canvas.width = width - this.canvas.height = height - this.simulationQueue = new EventQueue(10000) - this.context = this.canvas.getContext('2d') - simulationArea.changeClockTime(simulationArea.timePeriod) - this.mouseDown = false - }, - changeClockTime(t) { - if (t < 50) return - clearInterval(simulationArea.ClockInterval) - t = t || prompt('Enter Time Period:') - simulationArea.timePeriod = t - simulationArea.ClockInterval = setInterval(clockTick, t) - }, - clear() { - if (!this.context) return - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) - }, -} -export const { changeClockTime } = simulationArea -export default simulationArea diff --git a/v0/src/simulator/src/simulationArea.ts b/v0/src/simulator/src/simulationArea.ts new file mode 100644 index 00000000..bd2f3f9a --- /dev/null +++ b/v0/src/simulator/src/simulationArea.ts @@ -0,0 +1,70 @@ +import { EventQueue } from './eventQueue' +import { SimulationArea } from './interface/simulationArea' +import { clockTick } from './utils' + +const simulationArea: SimulationArea = { + canvas: document.getElementById('simulationArea') as HTMLCanvasElement, + context: null, + selected: false, + hover: false, + clockState: 0, + clockEnabled: true, + lastSelected: null, + stack: [], + prevScale: 0, + oldx: 0, + oldy: 0, + objectList: [], + maxHeight: 0, + maxWidth: 0, + minHeight: 0, + minWidth: 0, + multipleObjectSelections: [], + copyList: [], + shiftDown: false, + controlDown: false, + timePeriod: 500, + mouseX: 0, + mouseY: 0, + mouseDownX: 0, + mouseDownY: 0, + simulationQueue: new EventQueue(10000), + clickCount: 0, + lock: 'unlocked', + mouseDown: false, + ClockInterval: null, + touch: false, + + timer() { + const clickTimer = setTimeout(() => { + simulationArea.clickCount = 0 + }, 600) + }, + setup() { + this.canvas = document.getElementById('simulationArea') as HTMLCanvasElement; + this.canvas.width = width; + this.canvas.height = height; + this.simulationQueue = new EventQueue(10000); + this.context = this.canvas.getContext('2d')!; + simulationArea.changeClockTime(simulationArea.timePeriod); + this.mouseDown = false; + }, + changeClockTime(t: number) { + if (t < 50) { + return; + } + if (simulationArea.ClockInterval != null) { + clearInterval(simulationArea.ClockInterval); + } + simulationArea.timePeriod = t; + simulationArea.ClockInterval = setInterval(clockTick, t); + }, + clear() { + if (!this.context) { + return; + } + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + }, +}; +export { simulationArea } +export const { changeClockTime } = simulationArea \ No newline at end of file diff --git a/v0/src/simulator/src/subcircuit.js b/v0/src/simulator/src/subcircuit.js index 85fdc53e..377ea3b5 100644 --- a/v0/src/simulator/src/subcircuit.js +++ b/v0/src/simulator/src/subcircuit.js @@ -1,7 +1,7 @@ /* eslint-disable import/no-cycle */ import Scope, { scopeList, switchCircuit } from './circuit' import CircuitElement from './circuitElement' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleBackup, checkIfBackup } from './data/backupCircuit' import { scheduleUpdate, @@ -20,6 +20,8 @@ import { layoutModeGet } from './layoutMode' import { verilogModeGet } from './Verilog2CV' import { sanitizeLabel } from './verilogHelpers' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { circuitElementList, subCircuitInputList } from './metadata' + /** * Function to load a subcicuit * @category subcircuit @@ -40,50 +42,6 @@ export function createSubCircuitPrompt(scope = globalScope) { } const simulatorStore = SimulatorStore() simulatorStore.dialogBox.insertsubcircuit_dialog = true - /* - $('#insertSubcircuitDialog').empty() - let flag = true - for (id in scopeList) { - if ( - !scopeList[id].checkDependency(scope.id) && - scopeList[id].isVisible() - ) { - flag = false - $('#insertSubcircuitDialog').append( - `` - ) - } - } - if (flag) - $('#insertSubcircuitDialog').append( - "

Looks like there are no other circuits which doesn't have this circuit as a dependency. Create a new one!

" - ) - $('#insertSubcircuitDialog').dialog({ - resizable: false, - maxHeight: 800, - width: 450, - maxWidth: 800, - minWidth: 250, - buttons: !flag - ? [ - { - text: 'Insert SubCircuit', - click() { - if (!$('input[name=subCircuitId]:checked').val()) - return - simulationArea.lastSelected = new SubCircuit( - undefined, - undefined, - globalScope, - $('input[name=subCircuitId]:checked').val() - ) - $(this).dialog('close') - }, - }, - ] - : [], - }) - */ } /** @@ -207,8 +165,8 @@ export default class SubCircuit extends CircuitElement { this.downDimensionY = subcircuitScope.layout.height } - this.nodeList.extend(this.inputNodes) - this.nodeList.extend(this.outputNodes) + this.nodeList.push(...this.inputNodes) + this.nodeList.push(...this.outputNodes) } else { this.version = '2.0' } @@ -297,14 +255,11 @@ export default class SubCircuit extends CircuitElement { // Needs to be deprecated, removed reBuild() { - // new SubCircuit(x = this.x, y = this.y, scope = this.scope, this.id); - // this.scope.backups = []; // Because all previous states are invalid now - // this.delete(); - // showMessage('Subcircuit: ' + subcircuitScope.name + ' has been reloaded.'); } /** - * rebuilds the subcircuit if any change to localscope is made + * If the circuit referenced by localscope is changed, then the localscope + * needs to be updated. This function does that. */ reBuildCircuit() { this.data = JSON.parse(scheduleBackup(scopeList[this.id])) @@ -365,7 +320,7 @@ export default class SubCircuit extends CircuitElement { } else { this.scope.backups = [] this.inputNodes[i].delete() - this.nodeList.clean(this.inputNodes[i]) + this.nodeList = this.nodeList.filter(x => x !== this.inputNodes[i]) } } @@ -381,7 +336,7 @@ export default class SubCircuit extends CircuitElement { } else { this.scope.backups = [] temp_map_inp[id][1].delete() - this.nodeList.clean(temp_map_inp[id][1]) + this.nodeList = this.nodeList.filter(x => x !== temp_map_inp[id][1]) temp_map_inp[id][1] = new Node( temp_map_inp[id][0].layoutProperties.x, temp_map_inp[id][0].layoutProperties.y, @@ -426,7 +381,7 @@ export default class SubCircuit extends CircuitElement { this.outputNodes[i] } else { this.outputNodes[i].delete() - this.nodeList.clean(this.outputNodes[i]) + this.nodeList = this.nodeList.filter(x => x !== this.outputNodes[i]) } } @@ -441,7 +396,7 @@ export default class SubCircuit extends CircuitElement { temp_map_out[id][1].bitWidth = temp_map_out[id][0].bitWidth } else { temp_map_out[id][1].delete() - this.nodeList.clean(temp_map_out[id][1]) + this.nodeList = this.nodeList.filter(x => x !== temp_map_out[id][1]) temp_map_out[id][1] = new Node( temp_map_out[id][0].layoutProperties.x, temp_map_out[id][0].layoutProperties.y, @@ -479,12 +434,9 @@ export default class SubCircuit extends CircuitElement { this.reBuildCircuit() } - // Should this be done here or only when this.reBuildCircuit() is called? - { - this.localScope.reset() - updateSimulationSet(true) - forceResetNodesSet(true) - } + this.localScope.reset() + updateSimulationSet(true) + forceResetNodesSet(true) this.makeConnections() } @@ -658,7 +610,7 @@ export default class SubCircuit extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] } @@ -688,6 +640,7 @@ export default class SubCircuit extends CircuitElement { ) } } else { + console.error('Unknown Version: ', this.version) } for (var i = 0; i < subcircuitScope.Input.length; i++) { diff --git a/v0/src/simulator/src/testCreator.js b/v0/src/simulator/src/testCreator.js deleted file mode 100644 index 4a1708c2..00000000 --- a/v0/src/simulator/src/testCreator.js +++ /dev/null @@ -1,780 +0,0 @@ -/* - This file contains all javascript related to the test creator UI - at /testbench -*/ - -import _ from '../vendor/table2csv' - -const CREATORMODE = { - NORMAL: 0, - SIMULATOR_POPUP: 1, -} - -var testMode = 'comb' -var groupIndex = 0 -var inputCount = 0 -var nextInputIndex = 0 -var outputCount = 0 -var nextOutputIndex = 0 -var cases = [0] -var creatorMode = CREATORMODE.NORMAL -var circuitScopeID - -function dataReset() { - groupIndex = -1 - cases = [0] -} - -/** - * Onload, check if it is opened in a popup. - * Check if test is being edited, or created - */ -window.onload = () => { - const query = new URLSearchParams(window.location.search) - if (query.has('popUp')) { - if (query.get('popUp') == 'true') { - creatorMode = CREATORMODE.SIMULATOR_POPUP - $('.right-button-group').append( - '' - ) - } - } - if (query.has('data')) { - $('#tb-creator-head').html('Edit Test') - circuitScopeID = query.get('scopeID') - loadData(query.get('data')) - return - } - - if (query.has('result')) { - $('#tb-creator-head').html('Test Result') - loadResult(query.get('result')) - readOnlyUI() - return - } - - circuitScopeID = query.get('scopeID') - addInput() - addOutput() - makeSortable() -} - -/* Change UI testMode between Combinational(comb) and Sequential(seq) */ -function changeTestMode(m) { - if (testMode === m) return false - dataReset() - testMode = m - $('#combSelect').removeClass('tab-selected') - $('#seqSelect').removeClass('tab-selected') - $('#tb-new-group').css('visibility', m === 'seq' ? 'visible' : 'hidden') - $(`#${m}Select`).addClass('tab-selected') - $('#dataGroup').empty() - - return true -} - -/* Adds case to a group */ -function addCase(grp) { - const currentGroupTable = $(`#data-table-${grp + 1}`) - - let s = - '
\n' - for (let i = 0; i < inputCount + outputCount; i++) - s += '0' - s += '' - - // Sortable hack - currentGroupTable.find('tbody').remove() - currentGroupTable.append(s) -} - -/* Deletes case from a group */ -function deleteCase(element) { - const row = element.parent().parent() - const grp = Number(row.parent().attr('id').split('-').pop()) - - row.remove() -} - -/* Adds group with default name 'Group N' or name supplied in @param groupName */ -/* Used without params by UI, used with params by loadData() */ -function addGroup( - groupName = `${testMode === 'comb' ? 'Group' : 'Set'} ${groupIndex + 2}` -) { - $('.plus-button').removeClass('latest-button') - groupIndex++ - - const s = ` -
-

${escapeHtml(groupName)}

-
Click + to add tests to the ${ - testMode === 'comb' ? 'group' : 'set' - }
- - -
- -
- ` - cases[groupIndex] = 0 - $('#dataGroup').append(s) - - makeSortable() -} - -/* Deletes a group */ -function deleteGroup(element) { - const groupDiv = element.parent() - const grp = Number(groupDiv.attr('id').split('-').pop()) - groupDiv.remove() -} - -/* Adds input with default value 0 or values supplied in @param inputData */ -/* Used without params for UI, used with params by loadData() */ -function addInput( - label = `inp${nextInputIndex + 1}`, - bitwidth = 1, - inputData = [] -) { - nextInputIndex++ - inputCount++ - // Change head table contents - const sHead = `${escapeHtml( - label - )} ` - const sData = `${escapeHtml( - bitwidth.toString() - )}` - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .eq(inputCount - 1) - .after(sHead) - $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .eq(inputCount - 1) - .after(sData) - $('#tb-inputs-head').attr('colspan', inputCount) - - // Change data tables' contents - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - const s = `${ - inputData.length - ? escapeHtml(inputData[group_i][case_i]) - : 0 - }` - $(this) - .find('td') - .eq(inputCount - 1) - .after(s) - }) - }) -} - -/* Adds output with default value 0 or values supplied in @param outputData */ -/* Used without params for UI, used with params by loadData() */ -/* Used with resultData and result=true for setting result */ -function addOutput( - label = `out${nextOutputIndex + 1}`, - bitwidth = 1, - outputData = [], - result = false, - resultData = [] -) { - nextOutputIndex++ - outputCount++ - // Change head table contents - let sHead = `${escapeHtml( - label - )} ` - let sData = `${escapeHtml( - bitwidth.toString() - )}` - - // If result then set colspan to 2 - if (result) { - sHead = `${escapeHtml( - label - )} ` - sData = `${escapeHtml( - bitwidth.toString() - )}` - } - - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .eq(inputCount + outputCount - 1) - .after(sHead) - $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .eq(inputCount + outputCount - 1) - .after(sData) - // If not result then colspan is outputCount - $('#tb-outputs-head').attr('colspan', outputCount) - // else it's 2*outputCount - if (result) { - $('#tb-outputs-head').attr('colspan', 2 * outputCount) - } - - // Change data tables' contents - - // If not result just add the outputs - if (!result) { - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - const s = `${ - outputData.length - ? escapeHtml(outputData[group_i][case_i]) - : 0 - }` - $(this) - .find('td') - .eq(inputCount + outputCount - 1) - .after(s) - }) - }) - - // If result then add results besides the outputs - // Hacky - } else { - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - // Add the outputs (expected values) - const outputCellData = `${escapeHtml( - outputData[group_i][case_i] - )}` - $(this) - .find('td') - .eq(inputCount + 2 * (outputCount - 1)) - .after(outputCellData) - - // Add the actual values - const resultColor = - resultData[group_i][case_i] === - outputData[group_i][case_i] - ? 'green' - : 'red' - const resultCellData = `${escapeHtml( - resultData[group_i][case_i] - )}` - $(this) - .find('td') - .eq(inputCount + 2 * outputCount - 1) - .after(resultCellData) - }) - }) - } -} - -/* Deletes input unless there's only one input */ -function deleteInput(element) { - if (inputCount === 1) return - const columnIndex = element.parent().eq(0).index() - - $('#testBenchTable tr, .data-group tr') - .slice(1) - .each(function () { - $(this).find('td, th').eq(columnIndex).remove() - }) - - inputCount-- - $('#tb-inputs-head').attr('colspan', inputCount) -} - -/* Deletes output unless there's only one output */ -function deleteOutput(element) { - if (outputCount === 1) return - const columnIndex = element.parent().eq(0).index() - - $('#testBenchTable tr, .data-group tr') - .slice(1) - .each(function () { - $(this).find('td, th').eq(columnIndex).remove() - }) - - outputCount-- - $('#tb-outputs-head').attr('colspan', outputCount) -} - -/* Returns input/output(keys) and their bitwidths(values) */ -/* Called by getData() */ -function getBitWidths() { - const bitwidths = {} - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .slice(1) - .each(function (index) { - const inp = $(this).text() - const bw = $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .slice(1) - .eq(index) - .html() - bitwidths[inp] = Number(bw) - }) - return bitwidths -} - -/* Returns data for all the groups for all inputs and outputs */ -/* Called by parse() */ -function getData() { - const bitwidths = getBitWidths() - const groups = [] - const groupCount = $('#dataGroup').children().length - for (let group_i = 0; group_i < groupCount; group_i++) { - const group = {} - group.label = getGroupTitle(group_i) - group.inputs = [] - group.outputs = [] - - const group_table = $(`#data-table-${group_i + 1}`) - group.n = group_table.find('tr').length - - // Push all the inputs in the group - for (let inp_i = 0; inp_i < inputCount; inp_i++) { - const label = Object.keys(bitwidths)[inp_i] - const input = { - label: label.slice(0, label.length - 1), - bitWidth: bitwidths[label], - values: [], - } - group_table.find('tr').each(function () { - input.values.push($(this).find('td').slice(1).eq(inp_i).html()) - }) - - group.inputs.push(input) - } - - // Push all the outputs in the group - for (let out_i = 0; out_i < outputCount; out_i++) { - const label = Object.keys(bitwidths)[inputCount + out_i] - const output = { - label: label.slice(0, label.length - 1), - bitWidth: bitwidths[label], - values: [], - } - group_table.find('tr').each(function () { - output.values.push( - $(this) - .find('td') - .slice(1) - .eq(inputCount + out_i) - .html() - ) - }) - - group.outputs.push(output) - } - - groups.push(group) - } - - return groups -} - -function getTestTitle() { - return $('#test-title-label').text() -} - -function getGroupTitle(group_i) { - return $(`#data-group-title-${group_i + 1}`).text() -} - -/* Parse UI table into Javascript Object */ -function parse() { - const data = {} - const tableData = getData() - data.type = testMode - data.title = getTestTitle() - data.groups = tableData - return data -} - -/* Export test data as a CSV file */ -function exportAsCSV() { - let csvData = '' - csvData += 'Title,Test Type,Input Count,Output Count\n' - csvData += `${getTestTitle()},${testMode},${inputCount},${outputCount}\n\n\n` - csvData += $('table').eq(0).table2CSV() - csvData += '\n\n' - $('table') - .slice(1) - .each(function (group_i) { - csvData += getGroupTitle(group_i) - csvData += '\n' - csvData += $(this).table2CSV() - csvData += '\n\n' - }) - - download(`${getTestTitle()}.csv`, csvData) - return csvData -} - -/* - Imports data from CSV and loads into the table - To achieve this, first converts to JSON then uses request param to load json to table -*/ -function importFromCSV() { - const file = $('#csvFileInput').prop('files')[0] - const reader = new FileReader() - - // If circuitScopeID exists, ie. if popup opened from testbench, then use that to redirect - const query = new URLSearchParams(window.location.search) - // Preserve popup status while redirecting - const isPopup = query.get('popUp') || false - - // When the file is read, redirect to the data location - reader.onload = () => { - const csvContent = reader.result - const jsonData = csv2json(csvContent, 1, 1) - - window.location = `/testbench?scopeID=${ - circuitScopeID || '' - }&data=${jsonData}&popUp=${isPopup}` - } - - reader.readAsText(file) -} - -// Clicks the hidden upload file button, entrypoint into importFromCSV() -// The hidden button in-turn calls importFromCSV() -function clickUpload() { - $('#csvFileInput').click() -} - -/* Converts CSV to JSON to be loaded into the table */ -function csv2json(csvFileData) { - const stripQuotes = (str) => str.replaceAll('"', '') - - /* Extracts bitwidths from the csv data */ - const getBitWidthsCSV = (csvDataBW) => { - const testMetadata = csvDataBW.split('\n\n')[0].split('\n') - const labels = testMetadata[1] - .split(',') - .slice(1) - .map((label) => stripQuotes(label)) - const bitWidths = testMetadata[2] - .split(',') - .slice(1) - .map((bw) => Number(stripQuotes(bw))) - - return { labels, bitWidths } - } - - const csvMetadata = csvFileData.split('\n\n\n')[0].split('\n')[1].split(',') - const csvData = csvFileData.split('\n\n\n')[1] - const jsonData = {} - - jsonData.title = csvMetadata[0] - jsonData.type = csvMetadata[1] - const inputCountCSV = Number(csvMetadata[2]) - const outputCountCSV = Number(csvMetadata[3]) - - jsonData.groups = [] - const { labels, bitWidths } = getBitWidthsCSV(csvData) - - const groups = csvData.split('\n\n').slice(1) - for (let group_i = 0; group_i < groups.length - 1; group_i++) { - const rows = groups[group_i].split('\n') - jsonData.groups[group_i] = { - label: rows[0], - n: rows.length - 1, - inputs: [], - outputs: [], - } - - // Parse Inputs - for (let input_i = 0; input_i < inputCountCSV; input_i++) { - const thisInput = { - label: labels[input_i], - bitWidth: bitWidths[input_i], - values: [], - } - for (let case_i = 1; case_i < rows.length; case_i++) - thisInput.values.push( - stripQuotes(rows[case_i].split(',')[input_i + 1]) - ) - - jsonData.groups[group_i].inputs.push(thisInput) - } - - // Parse Outputs - for ( - let output_i = inputCountCSV; - output_i < inputCountCSV + outputCountCSV; - output_i++ - ) { - const thisOutput = { - label: labels[output_i], - bitWidth: bitWidths[output_i], - values: [], - } - for (let case_i = 1; case_i < rows.length; case_i++) { - thisOutput.values.push( - stripQuotes(rows[case_i].split(',')[output_i + 1]) - ) - } - - jsonData.groups[group_i].outputs.push(thisOutput) - } - } - - return JSON.stringify(jsonData) -} - -/* Helper function to download generated file */ -function download(filename, text) { - var element = document.createElement('a') - element.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent(text)}` - ) - element.setAttribute('download', filename) - - element.style.display = 'none' - document.body.appendChild(element) - - element.click() - - document.body.removeChild(element) -} - -/** - * Called when Save is clicked. If opened in popup, sends message to parent window - * to attach test to the testbench. - */ -function saveData() { - const testData = parse() - - if (creatorMode === CREATORMODE.SIMULATOR_POPUP) { - const postData = { scopeID: circuitScopeID, testData } - window.opener.postMessage( - { type: 'testData', data: JSON.stringify(postData) }, - '*' - ) - window.close() - } -} - -/* Loads data from JSON string into the table */ -function loadData(dataJSON) { - const data = JSON.parse(dataJSON) - if (data.title) $('#test-title-label').text(data.title) - changeTestMode() - changeTestMode(data.type) - for (let group_i = 0; group_i < data.groups.length; group_i++) { - const group = data.groups[group_i] - addGroup(group.label) - for (let case_i = 0; case_i < group.inputs[0].values.length; case_i++) { - addCase(group_i) - } - } - - // Add input values - for (let input_i = 0; input_i < data.groups[0].inputs.length; input_i++) { - const input = data.groups[0].inputs[input_i] - const values = data.groups.map((group) => group.inputs[input_i].values) - - addInput(input.label, input.bitWidth, values) - } - - // Add output values - for ( - let output_i = 0; - output_i < data.groups[0].outputs.length; - output_i++ - ) { - const output = data.groups[0].outputs[output_i] - const values = data.groups.map( - (group) => group.outputs[output_i].values - ) - - addOutput(output.label, output.bitWidth, values) - } -} - -/** - * Loads result from JSON string into the testbench creator UI - */ -function loadResult(dataJSON) { - const data = JSON.parse(dataJSON) - if (data.title) $('#test-title-label').text(data.title) - changeTestMode() - changeTestMode(data.type) - for (let group_i = 0; group_i < data.groups.length; group_i++) { - const group = data.groups[group_i] - addGroup(group.label) - for (let case_i = 0; case_i < group.inputs[0].values.length; case_i++) { - addCase(group_i) - } - } - - // Add input values - for (let input_i = 0; input_i < data.groups[0].inputs.length; input_i++) { - const input = data.groups[0].inputs[input_i] - const values = data.groups.map((group) => group.inputs[input_i].values) - - addInput(input.label, input.bitWidth, values) - } - - // Add output values - for ( - let output_i = 0; - output_i < data.groups[0].outputs.length; - output_i++ - ) { - const output = data.groups[0].outputs[output_i] - const values = data.groups.map( - (group) => group.outputs[output_i].values - ) - const results = data.groups.map( - (group) => group.outputs[output_i].results - ) - const expectedOutputs = [] - const actualOutputs = [] - - for (let group_i = 0; group_i < values.length; group_i++) { - const groupExpectedOuts = [] - const groupActualOuts = [] - for (let val_i = 0; val_i < values[group_i].length; val_i++) { - groupExpectedOuts.push(values[group_i][val_i]) - groupActualOuts.push(results[group_i][val_i]) - } - - expectedOutputs.push(groupExpectedOuts) - actualOutputs.push(groupActualOuts) - } - addOutput( - `${output.label}`, - output.bitWidth, - expectedOutputs, - true, - actualOutputs - ) - } -} - -/** - * Makes the UI read only for displaying results - */ -function readOnlyUI() { - makeContentUneditable() - makeUnsortable() - $('.lower-button, .table-button, .tb-minus').hide() - $('.tablink').attr('disabled', 'disabled') - $('.tablink').removeClass('tablink-no-override') - $('.data-group-info').text('') -} - -function makeContentUneditable() { - $('body') - .find('td, th, span, h3, div') - .each(function () { - $(this).attr('contenteditable', 'false') - }) -} - -function makeSortable() { - const helper = function (e, ui) { - const helperE = ui.clone() - helperE.children().each(function (child_i) { - $(this).width(ui.children().eq(child_i).width()) - }) - - return helperE - } - - function makePlaceholder(e, ui) { - ui.placeholder.children().each(function () { - $(this).css('border', '0px') - }) - } - - /* - Sortable hack: To allow sorting inside empty tables, the tables should have some height. - But it is not possible to give tables height without having rows, so we add a tbody. - tbody gives the table height but messes up all the other things. So we only keep tbody - if the table has no rows, and once table gets rows, we remove that tbody - */ - function removeTbody(e, ui) { - $(e.target).find('tbody').remove() - } - - function createTbody(e, ui) { - if ($(e.target).find('tr, tbody').length === 0) { - $(e.target).append('') - } - } - - $('.data-group table').sortable({ - handle: '.tb-handle', - helper, - start: makePlaceholder, - placeholder: 'clone', - connectWith: 'table', - receive: removeTbody, // For sortable hack - remove: createTbody, // For sortable hack - items: 'tr', - revert: 50, - scroll: false, - }) -} - -function makeUnsortable() { - $('.data-group table').sortable({ disabled: true }) -} - -function escapeHtml(unsafe) { - return unsafe - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') -} - -// Making HTML called functions global - -window.addGroup = addGroup -window.deleteGroup = deleteGroup -window.addCase = addCase -window.deleteCase = deleteCase -window.addInput = addInput -window.deleteInput = deleteInput -window.addOutput = addOutput -window.deleteOutput = deleteOutput -window.parse = parse -window.saveData = saveData -window.changeTestMode = changeTestMode -window.exportAsCSV = exportAsCSV -window.importFromCSV = importFromCSV -window.csv2json = csv2json -window.clickUpload = clickUpload diff --git a/v0/src/simulator/src/testbench.js b/v0/src/simulator/src/testbench.js deleted file mode 100644 index d6f8a070..00000000 --- a/v0/src/simulator/src/testbench.js +++ /dev/null @@ -1,1140 +0,0 @@ -/** - * This file contains all functions related the the testbench - * Contains the the testbench engine and UI modules - */ - -import { scheduleBackup } from './data/backupCircuit' -import { changeClockEnable } from './sequential' -import { play } from './engine' -import Scope from './circuit' -import { showMessage, escapeHtml } from './utils' -import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' - -/** - * @typedef {number} RunContext - */ -const CONTEXT = { - CONTEXT_SIMULATOR: 0, - CONTEXT_ASSIGNMENTS: 1, -} - -const VALIDATION_ERRORS = { - NOTPRESENT: 0, // Element is not present in the circuit - WRONGBITWIDTH: 1, // Element is present but has incorrect bitwidth - DUPLICATE_ID_DATA: 2, // Duplicate identifiers in test data - DUPLICATE_ID_SCOPE: 3, // Duplicate identifiers in scope - NO_RST: 4, // Sequential circuit but no reset(RST) in scope -} - -const TESTBENCH_CREATOR_PATH = '/testbench' - -// Do we have any other function to do this? -// Utility function. Converts decimal number to binary string -function dec2bin(dec, bitWidth = undefined) { - if (dec === undefined) return 'X' - const bin = (dec >>> 0).toString(2) - if (!bitWidth) return bin - - return '0'.repeat(bitWidth - bin.length) + bin -} - -/** - * Class to store all data related to the testbench and functions to use it - * @param {Object} data - Javascript object of the test data - * @param {number=} currentGroup - Current group index in the test - * @param {number=} currentCase - Current case index in the group - */ -export class TestbenchData { - constructor(data, currentGroup = 0, currentCase = 0) { - this.currentCase = currentCase - this.currentGroup = currentGroup - this.testData = data - } - - /** - * Checks whether given case-group pair exists in the test - */ - isCaseValid() { - if ( - this.currentGroup >= this.data.groups.length || - this.currentGroup < 0 - ) - return false - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - if (this.currentCase >= caseCount || this.currentCase < 0) return false - - return true - } - - /** - * Validate and set case and group in the test - * @param {number} groupIndex - Group index to set - * @param {number} caseIndex - Case index to set - */ - setCase(groupIndex, caseIndex) { - const newCase = new TestbenchData(this.testData, groupIndex, caseIndex) - if (newCase.isCaseValid()) { - this.currentGroup = groupIndex - this.currentCase = caseIndex - return true - } - - return false - } - - /** - * Validate and go to the next group. - * Skips over empty groups - */ - groupNext() { - const newCase = new TestbenchData(this.testData, this.currentGroup, 0) - const groupCount = newCase.testData.groups.length - let caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - - while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { - newCase.currentGroup++ - if (newCase.currentGroup >= groupCount) return false - caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - } - - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } - - /** - * Validate and go to the previous group. - * Skips over empty groups - */ - groupPrev() { - const newCase = new TestbenchData(this.testData, this.currentGroup, 0) - const groupCount = newCase.testData.groups.length - let caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - - while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { - newCase.currentGroup-- - if (newCase.currentGroup < 0) return false - caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - } - - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } - - /** - * Validate and go to the next case - */ - caseNext() { - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - if (this.currentCase >= caseCount - 1) return this.groupNext() - this.currentCase++ - return true - } - - /** - * Validate and go to the previous case - */ - casePrev() { - if (this.currentCase <= 0) { - if (!this.groupPrev()) return false - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - this.currentCase = caseCount - 1 - return true - } - - this.currentCase-- - return true - } - - /** - * Finds and switches to the first non empty group to start the test from - */ - goToFirstValidGroup() { - const newCase = new TestbenchData(this.testData, 0, 0) - const caseCount = - newCase.testData.groups[this.currentGroup].inputs[0].values.length - - // If the first group is not empty, do nothing - if (caseCount > 0) return true - - // Otherwise go next until non empty group - const validExists = newCase.groupNext() - - // If all groups empty return false - if (!validExists) return false - - // else set case to the non empty group - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } -} - -/** - * UI Function - * Create prompt for the testbench UI when creator is opened - */ -function creatorOpenPrompt(creatorWindow) { - scheduleBackup() - const windowSVG = ` - - - - - ` - - const s = ` -
-
- ${windowSVG} -
-

A browser pop-up is opened to create the test

-

Please save the test to open it here

-
- ` - - $('#setTestbenchData').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - text: 'Close Pop-Up', - click() { - $(this).dialog('close') - creatorWindow.close() - }, - }, - ], - }) - - $('#setTestbenchData').empty() - $('#setTestbenchData').append(s) -} - -/** - * Interface function to run testbench. Called by testbench prompt on simulator or assignments - * @param {Object} data - Object containing Test Data - * @param {RunContext=} runContext - Whether simulator or Assignment called this function - * @param {Scope=} scope - the circuit - */ -export function runTestBench( - data, - scope = globalScope, - runContext = CONTEXT.CONTEXT_SIMULATOR -) { - const isValid = validate(data, scope) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - } - - if (runContext === CONTEXT.CONTEXT_SIMULATOR) { - const tempTestbenchData = new TestbenchData(data) - if (!tempTestbenchData.goToFirstValidGroup()) { - showMessage('Testbench: The test is empty') - return - } - - globalScope.testbenchData = tempTestbenchData - - updateTestbenchUI() - return - } - - if (runContext === CONTEXT.CONTEXT_ASSIGNMENTS) { - // Not implemented - } -} - -/** - * Updates the TestBench UI on the simulator with the current test attached - * If no test is attached then shows the 'No test attached' screen - * Called by runTestBench() when test is set, also called by UX/setupPanelListeners() - * whenever ux change requires this UI to update(such as clicking on a different circuit or - * loading a saved circuit) - */ -export function updateTestbenchUI() { - // Remove all listeners from buttons - $('.tb-dialog-button').off('click') - $('.tb-case-button').off('click') - - setupTestbenchUI() - if (globalScope.testbenchData != undefined) { - const { testbenchData } = globalScope - - // Initialize the UI - setUITableHeaders(testbenchData) - - // Add listeners to buttons - $('.tb-case-button#prev-case-btn').on( - 'click', - buttonListenerFunctions.previousCaseButton - ) - $('.tb-case-button#next-case-btn').on( - 'click', - buttonListenerFunctions.nextCaseButton - ) - $('.tb-case-button#prev-group-btn').on( - 'click', - buttonListenerFunctions.previousGroupButton - ) - $('.tb-case-button#next-group-btn').on( - 'click', - buttonListenerFunctions.nextGroupButton - ) - $('.tb-dialog-button#change-test-btn').on( - 'click', - buttonListenerFunctions.changeTestButton - ) - $('.tb-dialog-button#runall-btn').on( - 'click', - buttonListenerFunctions.runAllButton - ) - $('.tb-dialog-button#edit-test-btn').on( - 'click', - buttonListenerFunctions.editTestButton - ) - $('.tb-dialog-button#validate-btn').on( - 'click', - buttonListenerFunctions.validateButton - ) - $('.tb-dialog-button#remove-test-btn').on( - 'click', - buttonListenerFunctions.removeTestButton - ) - } - - // Add listener to attach test button - $('.tb-dialog-button#attach-test-btn').on( - 'click', - buttonListenerFunctions.attachTestButton - ) -} - -/** - * Defines all the functions called as event listeners for buttons on the UI - */ -const buttonListenerFunctions = { - previousCaseButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.casePrev() - buttonListenerFunctions.computeCase() - }, - - nextCaseButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.caseNext() - buttonListenerFunctions.computeCase() - }, - - previousGroupButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.groupPrev() - buttonListenerFunctions.computeCase() - }, - - nextGroupButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.groupNext() - buttonListenerFunctions.computeCase() - }, - - changeTestButton: () => { - openCreator('create') - }, - - runAllButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - const results = runAll(globalScope.testbenchData.testData, globalScope) - const { passed } = results.summary - const { total } = results.summary - const resultString = JSON.stringify(results.detailed) - $('#runall-summary').text(`${passed} out of ${total}`) - $('#runall-detailed-link').on('click', () => { - openCreator('result', resultString) - }) - $('.testbench-runall-label').css('display', 'table-cell') - $('.testbench-runall-label').delay(5000).fadeOut('slow') - }, - - editTestButton: () => { - const editDataString = JSON.stringify( - globalScope.testbenchData.testData - ) - openCreator('edit', editDataString) - }, - - validateButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - showValidationUI(isValid) - }, - - removeTestButton: async () => { - if ( - await confirmOption( - 'Are you sure you want to remove the test from the circuit?' - ) - ) { - globalScope.testbenchData = undefined - setupTestbenchUI() - } - }, - - attachTestButton: () => { - openCreator('create') - }, - - rerunTestButton: () => { - buttonListenerFunctions.computeCase() - }, - - computeCase: () => { - setUICurrentCase(globalScope.testbenchData) - const result = runSingleTest(globalScope.testbenchData, globalScope) - setUIResult(globalScope.testbenchData, result) - }, -} - -/** - * UI Function - * Checks whether test is attached to the scope and switches UI accordingly - */ -export function setupTestbenchUI() { - // Don't change UI if UI is minimized (because hide() and show() are recursive) - if ($('.testbench-manual-panel .minimize').css('display') === 'none') return - - if (globalScope.testbenchData === undefined) { - $('.tb-test-not-null').hide() - $('.tb-test-null').show() - return - } - - $('.tb-test-null').hide() - $('.tb-test-not-null').show() -} - -/** - * Run all the tests automatically. Called by runTestBench() - * @param {Object} data - Object containing Test Data - * @param {Scope=} scope - the circuit - */ -export function runAll(data, scope = globalScope) { - // Stop the clocks - // TestBench will now take over clock toggling - changeClockEnable(false) - - const { inputs, outputs, reset } = bindIO(data, scope) - let totalCases = 0 - let passedCases = 0 - - data.groups.forEach((group) => { - // for (const output of group.outputs) output.results = []; - group.outputs.forEach((output) => (output.results = [])) - for (let case_i = 0; case_i < group.n; case_i++) { - totalCases++ - // Set and propagate the inputs - setInputValues(inputs, group, case_i, scope) - // If sequential, trigger clock now - if (data.type === 'seq') tickClock(scope) - // Get output values - const caseResult = getOutputValues(data, outputs) - // Put the results in the data - - let casePassed = true // Tracks if current case passed or failed - - caseResult.forEach((_, outName) => { - // TODO: find() is not the best idea because of O(n) - const output = group.outputs.find( - (dataOutput) => dataOutput.label === outName - ) - output.results.push(caseResult.get(outName)) - - if (output.values[case_i] !== caseResult.get(outName)) - casePassed = false - }) - - // If current case passed, then increment passedCases - if (casePassed) passedCases++ - } - - // If sequential, trigger reset at the end of group (set) - if (data.type === 'seq') triggerReset(reset) - }) - - // Tests done, restart the clocks - changeClockEnable(true) - - // Return results - const results = {} - results.detailed = data - results.summary = { passed: passedCases, total: totalCases } - return results -} - -/** - * Runs single test - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleTest(testbenchData, scope) { - const data = testbenchData.testData - - let result - if (data.type === 'comb') { - result = runSingleCombinational(testbenchData, scope) - } else if (data.type === 'seq') { - result = runSingleSequential(testbenchData, scope) - } - - return result -} - -/** - * Runs single combinational test - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleCombinational(testbenchData, scope) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const { inputs, outputs } = bindIO(data, scope) - const group = data.groups[groupIndex] - - // Stop the clocks - changeClockEnable(false) - - // Set input values according to the test - setInputValues(inputs, group, caseIndex, scope) - // Check output values - const result = getOutputValues(data, outputs) - // Restart the clocks - changeClockEnable(true) - return result -} - -/** - * Runs single sequential test and all tests above it in the group - * Used in MANUAL mode - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleSequential(testbenchData, scope) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const { inputs, outputs, reset } = bindIO(data, scope) - const group = data.groups[groupIndex] - - // Stop the clocks - changeClockEnable(false) - - // Trigger reset - triggerReset(reset, scope) - - // Run the test and tests above in the same group - for (let case_i = 0; case_i <= caseIndex; case_i++) { - setInputValues(inputs, group, case_i, scope) - tickClock(scope) - } - - const result = getOutputValues(data, outputs) - - // Restart the clocks - changeClockEnable(true) - - return result -} - -/** - * Set and propogate the input values according to the testcase. - * Called by runSingle() and runAll() - * @param {Object} inputs - Object with keys as input names and values as inputs - * @param {Object} group - Test group - * @param {number} caseIndex - Index of the case in the group - * @param {Scope} scope - the circuit - */ -function setInputValues(inputs, group, caseIndex, scope) { - group.inputs.forEach((input) => { - inputs[input.label].state = parseInt(input.values[caseIndex], 2) - }) - - // Propagate inputs - play(scope) -} - -/** - * Gets Output values as a Map with keys as output name and value as output state - * @param {Object} outputs - Object with keys as output names and values as outputs - */ -function getOutputValues(data, outputs) { - const values = new Map() - - data.groups[0].outputs.forEach((dataOutput) => { - // Using node value because output state only changes on rendering - const resultValue = outputs[dataOutput.label].nodeList[0].value - const resultBW = outputs[dataOutput.label].nodeList[0].bitWidth - values.set(dataOutput.label, dec2bin(resultValue, resultBW)) - }) - - return values -} - -/** - * UI Function - * Shows validation UI - * @param {Object} validationErrors - Object with errors returned by validate() - */ -function showValidationUI(validationErrors) { - const checkSVG = ` - - - - ` - - let s = ` -
-
- ${checkSVG} -
- All good. No validation errors -
- ` - - if (!validationErrors.ok) { - s = ` -
-

Please fix these errors to run tests

- - - - - - ` - - validationErrors.invalids.forEach((vError) => { - s += ` - - - - - ` - }) - - s += '
IdentifierError
${vError.identifier}${vError.message}
' - } - - $('#testbenchValidate').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - text: 'Ok', - click() { - $(this).dialog('close') - }, - }, - { - text: 'Auto Fix', - click() { - const fixes = validationAutoFix(validationErrors) - showMessage(`Testbench: Auto fixed ${fixes} errors`) - $(this).dialog('close') - }, - }, - ], - }) - - $('#testbenchValidate').empty() - $('#testbenchValidate').append(s) -} - -/** - * Validate if all inputs and output elements are present with correct bitwidths - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validate(data, scope) { - let invalids = [] - - // Check for duplicate identifiers - if (!checkDistinctIdentifiersData(data)) { - invalids.push({ - type: VALIDATION_ERRORS.DUPLICATE_ID_DATA, - identifier: '-', - message: 'Duplicate identifiers in test data', - }) - } - - if (!checkDistinctIdentifiersScope(scope)) { - invalids.push({ - type: VALIDATION_ERRORS.DUPLICATE_ID_SCOPE, - identifier: '-', - message: 'Duplicate identifiers in circuit', - }) - } - - // Don't do further checks if duplicates - if (invalids.length > 0) return { ok: false, invalids } - - // Validate inputs and outputs - const inputsValid = validateInputs(data, scope) - const outputsValid = validateOutputs(data, scope) - - invalids = inputsValid.ok ? invalids : invalids.concat(inputsValid.invalids) - invalids = outputsValid.ok - ? invalids - : invalids.concat(outputsValid.invalids) - - // Validate presence of reset if test is sequential - if (data.type === 'seq') { - const resetPresent = scope.Input.some( - (simulatorReset) => - simulatorReset.label === 'RST' && - simulatorReset.bitWidth === 1 && - simulatorReset.objectType === 'Input' - ) - - if (!resetPresent) { - invalids.push({ - type: VALIDATION_ERRORS.NO_RST, - identifier: 'RST', - message: 'Reset(RST) not present in circuit', - }) - } - } - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Autofix whatever is possible in validation errors. - * returns number of autofixed errors - * @param {Object} validationErrors - Object with errors returned by validate() - */ -function validationAutoFix(validationErrors) { - // Currently only autofixes bitwidths - let fixedErrors = 0 - // Return if no errors - if (validationErrors.ok) return fixedErrors - - const bitwidthErrors = validationErrors.invalids.filter( - (vError) => vError.type === VALIDATION_ERRORS.WRONGBITWIDTH - ) - - bitwidthErrors.forEach((bwError) => { - const { element, expectedBitWidth } = bwError.extraInfo - element.newBitWidth(expectedBitWidth) - fixedErrors++ - }) - - return fixedErrors -} - -/** - * Checks if all the labels in the test data are unique. Called by validate() - * @param {Object} data - Object containing Test Data - */ -function checkDistinctIdentifiersData(data) { - const inputIdentifiersData = data.groups[0].inputs.map( - (input) => input.label - ) - const outputIdentifiersData = data.groups[0].outputs.map( - (output) => output.label - ) - const identifiersData = inputIdentifiersData.concat(outputIdentifiersData) - - return new Set(identifiersData).size === identifiersData.length -} - -/** - * Checks if all the input/output labels in the scope are unique. Called by validate() - * TODO: Replace with identifiers - * @param {Scope} scope - the circuit - */ -function checkDistinctIdentifiersScope(scope) { - const inputIdentifiersScope = scope.Input.map((input) => input.label) - const outputIdentifiersScope = scope.Output.map((output) => output.label) - let identifiersScope = inputIdentifiersScope.concat(outputIdentifiersScope) - - // Remove identifiers which have not been set yet (ie. empty strings) - identifiersScope = identifiersScope.filter((identifer) => identifer != '') - - return new Set(identifiersScope).size === identifiersScope.length -} - -/** - * Validates presence and bitwidths of test inputs in the circuit. - * Called by validate() - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validateInputs(data, scope) { - const invalids = [] - - data.groups[0].inputs.forEach((dataInput) => { - const matchInput = scope.Input.find( - (simulatorInput) => simulatorInput.label === dataInput.label - ) - - if (matchInput === undefined) { - invalids.push({ - type: VALIDATION_ERRORS.NOTPRESENT, - identifier: dataInput.label, - message: 'Input is not present in the circuit', - }) - } else if (matchInput.bitWidth !== dataInput.bitWidth) { - invalids.push({ - type: VALIDATION_ERRORS.WRONGBITWIDTH, - identifier: dataInput.label, - extraInfo: { - element: matchInput, - expectedBitWidth: dataInput.bitWidth, - }, - message: `Input bitwidths don't match in circuit and test (${matchInput.bitWidth} vs ${dataInput.bitWidth})`, - }) - } - }) - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Validates presence and bitwidths of test outputs in the circuit. - * Called by validate() - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validateOutputs(data, scope) { - const invalids = [] - - data.groups[0].outputs.forEach((dataOutput) => { - const matchOutput = scope.Output.find( - (simulatorOutput) => simulatorOutput.label === dataOutput.label - ) - - if (matchOutput === undefined) { - invalids.push({ - type: VALIDATION_ERRORS.NOTPRESENT, - identifier: dataOutput.label, - message: 'Output is not present in the circuit', - }) - } else if (matchOutput.bitWidth !== dataOutput.bitWidth) { - invalids.push({ - type: VALIDATION_ERRORS.WRONGBITWIDTH, - identifier: dataOutput.label, - extraInfo: { - element: matchOutput, - expectedBitWidth: dataOutput.bitWidth, - }, - message: `Output bitwidths don't match in circuit and test (${matchOutput.bitWidth} vs ${dataOutput.bitWidth})`, - }) - } - }) - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Returns object of scope inputs and outputs keyed by their labels - * @param {Object} data - Object containing Test Data - * @param {Scope=} scope - the circuit - */ -function bindIO(data, scope) { - const inputs = {} - const outputs = {} - let reset - - data.groups[0].inputs.forEach((dataInput) => { - inputs[dataInput.label] = scope.Input.find( - (simulatorInput) => simulatorInput.label === dataInput.label - ) - }) - - data.groups[0].outputs.forEach((dataOutput) => { - outputs[dataOutput.label] = scope.Output.find( - (simulatorOutput) => simulatorOutput.label === dataOutput.label - ) - }) - - if (data.type === 'seq') { - reset = scope.Input.find( - (simulatorOutput) => simulatorOutput.label === 'RST' - ) - } - - return { inputs, outputs, reset } -} - -/** - * Ticks clock recursively one full cycle (Only used in testbench context) - * @param {Scope} scope - the circuit whose clock to be ticked - */ -function tickClock(scope) { - scope.clockTick() - play(scope) - scope.clockTick() - play(scope) -} - -/** - * Triggers reset (Only used in testbench context) - * @param {Input} reset - reset pin to be triggered - * @param {Scope} scope - the circuit - */ -function triggerReset(reset, scope) { - reset.state = 1 - play(scope) - reset.state = 0 - play(scope) -} - -/** - * UI Function - * Sets IO labels and bitwidths on UI table - * Called by simulatorRunTestbench() - * @param {Object} data - Object containing the test data - */ -function setUITableHeaders(testbenchData) { - const data = testbenchData.testData - const inputCount = data.groups[0].inputs.length - const outputCount = data.groups[0].outputs.length - - $('#tb-manual-table-inputs-head').attr('colspan', inputCount) - $('#tb-manual-table-outputs-head').attr('colspan', outputCount) - - $('.testbench-runall-label').css('display', 'none') - - $('.tb-data#data-title') - .children() - .eq(1) - .text(data.title || 'Untitled') - $('.tb-data#data-type') - .children() - .eq(1) - .text(data.type === 'comb' ? 'Combinational' : 'Sequential') - - $('#tb-manual-table-labels').html('LABELS') - $('#tb-manual-table-bitwidths').html('Bitwidth') - - data.groups[0].inputs.concat(data.groups[0].outputs).forEach((io) => { - const label = `${escapeHtml(io.label)}` - const bw = `${escapeHtml(io.bitWidth.toString())}` - $('#tb-manual-table-labels').append(label) - $('#tb-manual-table-bitwidths').append(bw) - }) - - setUICurrentCase(testbenchData) -} - -/** - * UI Function - * Set current test case data on the UI - * @param {Object} data - Object containing the test data - * @param {number} groupIndex - Index of the group of current case - * @param {number} caseIndex - Index of the case within the group - */ -function setUICurrentCase(testbenchData) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const currCaseElement = $('#tb-manual-table-current-case') - currCaseElement.empty() - currCaseElement.append('Current Case') - $('#tb-manual-table-test-result').empty() - $('#tb-manual-table-test-result').append('Result') - - data.groups[groupIndex].inputs.forEach((input) => { - currCaseElement.append( - `${escapeHtml(input.values[caseIndex])}` - ) - }) - - data.groups[groupIndex].outputs.forEach((output) => { - currCaseElement.append( - `${escapeHtml(output.values[caseIndex])}` - ) - }) - - $('.testbench-manual-panel .group-label').text( - data.groups[groupIndex].label - ) - $('.testbench-manual-panel .case-label').text(caseIndex + 1) -} - -/** - * UI Function - * Set the current test case result on the UI - * @param {Object} data - Object containing the test data - * @param {Map} result - Map containing the output values (returned by getOutputValues()) - */ -function setUIResult(testbenchData, result) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - const resultElement = $('#tb-manual-table-test-result') - let inputCount = data.groups[0].inputs.length - resultElement.empty() - resultElement.append('Result') - while (inputCount--) { - resultElement.append(' - ') - } - - for (const output of result.keys()) { - const resultValue = result.get(output) - const expectedValue = data.groups[groupIndex].outputs.find( - (dataOutput) => dataOutput.label === output - ).values[caseIndex] - const color = resultValue === expectedValue ? '#17FC12' : '#FF1616' - resultElement.append( - `${escapeHtml(resultValue)}` - ) - } -} - -/** - * Use this function to navigate to test creator. This function starts the storage listener - * so the test is loaded directly into the simulator - * @param {string} type - 'create', 'edit' or 'result' - * @param {String} dataString - data in JSON string to load in case of 'edit' and 'result' - */ -function openCreator(type, dataString) { - const popupHeight = 800 - const popupWidth = 1200 - const popupTop = (window.height - popupHeight) / 2 - const popupLeft = (window.width - popupWidth) / 2 - const POPUP_STYLE_STRING = `height=${popupHeight},width=${popupWidth},top=${popupTop},left=${popupLeft}` - let popUp - - /* Listener to catch testData from pop up and load it onto the testbench */ - const dataListener = (message) => { - if ( - message.origin !== window.origin || - message.data.type !== 'testData' - ) - return - - // Check if the current scope requested the creator pop up - const data = JSON.parse(message.data.data) - - // Unbind event listener - window.removeEventListener('message', dataListener) - - // If scopeID does not match, do nothing and return - if (data.scopeID != globalScope.id) return - - // Load test data onto the scope - runTestBench(data.testData, globalScope, CONTEXT.CONTEXT_SIMULATOR) - - // Close the 'Pop up is open' dialog - $('#setTestbenchData').dialog('close') - } - - if (type === 'create') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - creatorOpenPrompt(popUp) - window.addEventListener('message', dataListener) - } - - if (type === 'edit') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&data=${dataString}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - creatorOpenPrompt(popUp) - window.addEventListener('message', dataListener) - } - - if (type === 'result') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&result=${dataString}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - } - - // Check if popup was closed (in case it was closed by window's X button), - // then close 'popup open' dialog - if (popUp && type !== 'result') { - const checkPopUp = setInterval(() => { - if (popUp.closed) { - // Close the dialog if it's open - if ($('#setTestbenchData').dialog('isOpen')) - $('#setTestbenchData').dialog('close') - - // Remove the event listener that listens for data from popup - window.removeEventListener('message', dataListener) - clearInterval(checkPopUp) - } - }, 1000) - } -} diff --git a/v0/src/simulator/src/testbench.ts b/v0/src/simulator/src/testbench.ts new file mode 100644 index 00000000..70676e09 --- /dev/null +++ b/v0/src/simulator/src/testbench.ts @@ -0,0 +1,761 @@ +import { TestData } from "#/store/testBenchStore"; +import { showMessage } from '#/simulator/src/utils' +import { useTestBenchStore, TestBenchData } from "#/store/testBenchStore"; +import { changeClockEnable } from '#/simulator/src/sequential' +import { play } from '#/simulator/src/engine' +import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' +import { escapeHtml } from '#/simulator/src/utils' + +const CONTEXT = { + CONTEXT_SIMULATOR: 0, + CONTEXT_ASSIGNMENTS: 1, +} + +export const VALIDATION_ERRORS = { + NOTPRESENT: 0, // Element is not present in the circuit + WRONGBITWIDTH: 1, // Element is present but has incorrect bitwidth + DUPLICATE_ID_DATA: 2, // Duplicate identifiers in test data + DUPLICATE_ID_SCOPE: 3, // Duplicate identifiers in scope + NO_RST: 4, // Sequential circuit but no reset(RST) in scope +} + +export class TestbenchData { + currentCase: number; + currentGroup: number; + testData: TestData; + + constructor(data: TestData, currentGroup = 0, currentCase = 0) { + this.currentCase = currentCase; + this.currentGroup = currentGroup; + this.testData = data; + } + + isCaseValid() { + if (this.currentGroup >= this.testData.groups.length || this.currentGroup < 0) return false; + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + if (this.currentCase >= caseCount || this.currentCase < 0) return false; + + return true; + } + + setCase(groupIndex: number, caseIndex: number) { + const newCase = new TestbenchData(this.testData, groupIndex, caseIndex); + if (newCase.isCaseValid()) { + this.currentGroup = groupIndex; + this.currentCase = caseIndex; + return true; + } + return false; + } + + groupNext() { + const newCase = new TestbenchData(this.testData, this.currentGroup, 0); + const groupCount = newCase.testData.groups.length; + let caseCount = 0; + if (newCase.testData.groups[this.currentGroup].inputs[0]) { + caseCount = newCase.testData.groups[this.currentGroup].inputs[0].values.length; + } + + while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { + newCase.currentGroup++; + if (newCase.currentGroup >= groupCount) return false; + caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + } + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } + + groupPrev() { + const newCase = new TestbenchData(this.testData, this.currentGroup, 0); + const groupCount = newCase.testData.groups.length; + let caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + + while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { + newCase.currentGroup--; + if (newCase.currentGroup < 0) return false; + caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + } + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } + + caseNext() { + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + if (this.currentCase >= caseCount - 1) return this.groupNext(); + this.currentCase++; + return true; + } + + casePrev() { + if (this.currentCase <= 0) { + if (!this.groupPrev()) return false; + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + this.currentCase = caseCount - 1; + return true; + } + + this.currentCase--; + return true; + } + + goToFirstValidGroup() { + const newCase = new TestbenchData(this.testData, 0, 0); + let caseCount = 0; + if (newCase.testData.groups[this.currentGroup].inputs[0]) { + caseCount = newCase.testData.groups[this.currentGroup].inputs[0].values.length; + } + + if (caseCount > 0) return true; + + const validExists = newCase.groupNext(); + + if (!validExists) return false; + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } +} + +/** + * Checks if all the labels in the test data are unique. Called by validate() + */ +function checkDistinctIdentifiersData(data: TestData) { + const inputIdentifiersData = data.groups[0].inputs.map( + (input) => input.label + ) + const outputIdentifiersData = data.groups[0].outputs.map( + (output) => output.label + ) + const identifiersData = inputIdentifiersData.concat(outputIdentifiersData) + + return new Set(identifiersData).size === identifiersData.length +} + +/** + * Checks if all the input/output labels in the scope are unique. Called by validate() + * TODO: Replace with identifiers + */ +function checkDistinctIdentifiersScope(scope) { + const inputIdentifiersScope = scope.Input.map((input) => input.label) + const outputIdentifiersScope = scope.Output.map((output) => output.label) + let identifiersScope = inputIdentifiersScope.concat(outputIdentifiersScope) + + // Remove identifiers which have not been set yet (ie. empty strings) + identifiersScope = identifiersScope.filter((identifer) => identifer != '') + + return new Set(identifiersScope).size === identifiersScope.length +} + +/** + * Validates presence and bitwidths of test inputs in the circuit. + * Called by validate() + */ +function validateInputs(data: TestData, scope) { + const invalids: Invalids[] = [] + + data.groups[0].inputs.forEach((dataInput) => { + const matchInput = scope.Input.find( + (simulatorInput) => simulatorInput.label === dataInput.label + ) + + if (matchInput === undefined) { + invalids.push({ + type: VALIDATION_ERRORS.NOTPRESENT, + identifier: dataInput.label, + message: 'Input is not present in the circuit', + }) + } else if (matchInput.bitWidth !== dataInput.bitWidth) { + invalids.push({ + type: VALIDATION_ERRORS.WRONGBITWIDTH, + identifier: dataInput.label, + extraInfo: { + element: matchInput, + expectedBitWidth: dataInput.bitWidth, + }, + message: `Input bitwidths don't match in circuit and test (${matchInput.bitWidth} vs ${dataInput.bitWidth})`, + }) + } + }) + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +interface Invalids { + type: number + identifier: string + message: string + extraInfo?: any +} + +/** + * Validates presence and bitwidths of test outputs in the circuit. + * Called by validate() + */ +function validateOutputs(data: TestData, scope) { + const invalids: Invalids[] = [] + + data.groups[0].outputs.forEach((dataOutput) => { + const matchOutput = scope.Output.find( + (simulatorOutput) => simulatorOutput.label === dataOutput.label + ) + + if (matchOutput === undefined) { + invalids.push({ + type: VALIDATION_ERRORS.NOTPRESENT, + identifier: dataOutput.label, + message: 'Output is not present in the circuit', + }) + } else if (matchOutput.bitWidth !== dataOutput.bitWidth) { + invalids.push({ + type: VALIDATION_ERRORS.WRONGBITWIDTH, + identifier: dataOutput.label, + extraInfo: { + element: matchOutput, + expectedBitWidth: dataOutput.bitWidth, + }, + message: `Output bitwidths don't match in circuit and test (${matchOutput.bitWidth} vs ${dataOutput.bitWidth})`, + }) + } + }) + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +/** + * Validate if all inputs and output elements are present with correct bitwidths + */ +function validate(data: TestData, scope) { + let invalids = [] + + // Check for duplicate identifiers + if (!checkDistinctIdentifiersData(data)) { + invalids.push({ + type: VALIDATION_ERRORS.DUPLICATE_ID_DATA, + identifier: '-', + message: 'Duplicate identifiers in test data', + }) + } + + if (!checkDistinctIdentifiersScope(scope)) { + invalids.push({ + type: VALIDATION_ERRORS.DUPLICATE_ID_SCOPE, + identifier: '-', + message: 'Duplicate identifiers in circuit', + }) + } + + // Don't do further checks if duplicates + if (invalids.length > 0) return { ok: false, invalids } + + // Validate inputs and outputs + const inputsValid = validateInputs(data, scope) + const outputsValid = validateOutputs(data, scope) + + invalids = inputsValid.ok ? invalids : invalids.concat(inputsValid.invalids) + invalids = outputsValid.ok + ? invalids + : invalids.concat(outputsValid.invalids) + + // Validate presence of reset if test is sequential + if (data.type === 'seq') { + const resetPresent = scope.Input.some( + (simulatorReset) => + simulatorReset.label === 'RST' && + simulatorReset.bitWidth === 1 && + simulatorReset.objectType === 'Input' + ) + + if (!resetPresent) { + invalids.push({ + type: VALIDATION_ERRORS.NO_RST, + identifier: 'RST', + message: 'Reset(RST) not present in circuit', + }) + } + } + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +/** + * Returns object of scope inputs and outputs keyed by their labels + */ +function bindIO(data: TestData, scope) { + const inputs: { [key: string]: any } = {} + const outputs: { [key: string]: any } = {} + let reset + + data.groups[0].inputs.forEach((dataInput) => { + inputs[dataInput.label] = scope.Input.find( + (simulatorInput) => simulatorInput.label === dataInput.label + ) + }) + + data.groups[0].outputs.forEach((dataOutput) => { + outputs[dataOutput.label] = scope.Output.find( + (simulatorOutput) => simulatorOutput.label === dataOutput.label + ) + }) + + if (data.type === 'seq') { + reset = scope.Input.find( + (simulatorOutput) => simulatorOutput.label === 'RST' + ) + } + + return { inputs, outputs, reset } +} + +/** + * Set and propogate the input values according to the testcase. + * Called by runSingle() and runAll() + */ +function setInputValues(inputs, group, caseIndex: number, scope) { + group.inputs.forEach((input) => { + inputs[input.label].state = parseInt(input.values[caseIndex], 2) + }) + + // Propagate inputs + play(scope) +} + +/** + * Ticks clock recursively one full cycle (Only used in testbench context) + */ +function tickClock(scope: any) { + scope.clockTick() + play(scope) + scope.clockTick() + play(scope) +} + +// Do we have any other function to do this? +// Utility function. Converts decimal number to binary string +function dec2bin(dec: number | undefined, bitWidth = undefined) { + if (dec === undefined) return 'X' + const bin = (dec >>> 0).toString(2) + if (!bitWidth) return bin + + return '0'.repeat(bitWidth - bin.length) + bin +} + +/** + * Gets Output values as a Map with keys as output name and value as output state + */ +function getOutputValues(data: TestData, outputs) { + const values = new Map() + + data.groups[0].outputs.forEach((dataOutput) => { + // Using node value because output state only changes on rendering + const resultValue = outputs[dataOutput.label].nodeList[0].value + const resultBW = outputs[dataOutput.label].nodeList[0].bitWidth + values.set(dataOutput.label, dec2bin(resultValue, resultBW)) + }) + + return values +} + +/** + * Triggers reset (Only used in testbench context) + */ +function triggerReset(reset: any, scope: any) { + reset.state = 1 + play(scope) + reset.state = 0 + play(scope) +} + +/** + * Interface function to run testbench. Called by testbench prompt on simulator or assignments + */ +export function runTestBench( + data: TestData, + scope = globalScope, + runContext = CONTEXT.CONTEXT_SIMULATOR +) { + const testBenchStore = useTestBenchStore() + // const { testbenchData } = toRefs(testBenchStore) + const isValid = validate(data, scope) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + } + + if (runContext === CONTEXT.CONTEXT_SIMULATOR) { + const tempTestbenchData = new TestbenchData(data) + if (!tempTestbenchData.goToFirstValidGroup()) { + showMessage('Testbench: The test is empty') + testBenchStore.showTestbenchUI = false + return + } + + testBenchStore.testbenchData = tempTestbenchData + + return + } + + if (runContext === CONTEXT.CONTEXT_ASSIGNMENTS) { + // Not implemented + } +} + +interface Results { + detailed: TestData + summary: { + passed: number + total: number + } +} + +/** + * Run all the tests automatically. Called by runTestBench() + */ +export function runAll(data: TestData, scope = globalScope) { + // Stop the clocks + // TestBench will now take over clock toggling + changeClockEnable(false) + + const { inputs, outputs, reset } = bindIO(data, scope) + let totalCases = 0 + let passedCases = 0 + + data.groups.forEach((group) => { + // for (const output of group.outputs) output.results = []; + group.outputs.forEach((output) => (output.results = [])) + for (let case_i = 0; case_i < group.n; case_i++) { + totalCases++ + // Set and propagate the inputs + setInputValues(inputs, group, case_i, scope) + // If sequential, trigger clock now + if (data.type === 'seq') tickClock(scope) + // Get output values + const caseResult = getOutputValues(data, outputs) + // Put the results in the data + + let casePassed = true // Tracks if current case passed or failed + + caseResult.forEach((_, outName) => { + // TODO: find() is not the best idea because of O(n) + const output = group.outputs.find( + (dataOutput) => dataOutput.label === outName + ) + output?.results?.push(caseResult.get(outName)) + + if (output?.values[case_i] !== caseResult.get(outName)) + casePassed = false + }) + + // If current case passed, then increment passedCases + if (casePassed) passedCases++ + } + + // If sequential, trigger reset at the end of group (set) + if (data.type === 'seq') triggerReset(reset, scope) // qs. why scope is not passed? + }) + + // Tests done, restart the clocks + changeClockEnable(true) + + // Return results + const results: Results = { + detailed: data, + summary: { passed: passedCases, total: totalCases } + }; + return results +} + +/** + * Runs single combinational test + */ +function runSingleCombinational(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + const groupIndex = testbenchData.currentGroup + const caseIndex = testbenchData.currentCase + + const { inputs, outputs } = bindIO(data, scope) + const group = data.groups[groupIndex] + + // Stop the clocks + changeClockEnable(false) + + // Set input values according to the test + setInputValues(inputs, group, caseIndex, scope) + // Check output values + const result = getOutputValues(data, outputs) + // Restart the clocks + changeClockEnable(true) + return result +} + +/** + * Runs single sequential test and all tests above it in the group + * Used in MANUAL mode + */ +function runSingleSequential(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + const groupIndex = testbenchData.currentGroup + const caseIndex = testbenchData.currentCase + + const { inputs, outputs, reset } = bindIO(data, scope) + const group = data.groups[groupIndex] + + // Stop the clocks + changeClockEnable(false) + + // Trigger reset + triggerReset(reset, scope) + + // Run the test and tests above in the same group + for (let case_i = 0; case_i <= caseIndex; case_i++) { + setInputValues(inputs, group, case_i, scope) + tickClock(scope) + } + + const result = getOutputValues(data, outputs) + + // Restart the clocks + changeClockEnable(true) + + return result +} + +type openCreatorType = 'create' | 'edit' | 'result' + +export function openCreator(type: openCreatorType) { + const testBenchStore = useTestBenchStore(); + if (type === 'create') { + testBenchStore.showResults = false; + testBenchStore.readOnly = false; + testBenchStore.showTestBenchCreator = true; + } + + if (type === 'edit') { + testBenchStore.showResults = false; + testBenchStore.readOnly = false; + testBenchStore.showTestBenchCreator = true; + } + + if (type === 'result') { + testBenchStore.showResults = true; + testBenchStore.readOnly = true; + testBenchStore.showTestBenchCreator = true; + } +} + +/** +* UI Function +* Set the current test case result on the UI +*/ + +function setUIResult(testbenchData: TestBenchData, result) { + const testBenchStore = useTestBenchStore(); + const data = testbenchData.testData; + const groupIndex = testbenchData.currentGroup; + const caseIndex = testbenchData.currentCase; + + const inputCount = data.groups[0].inputs.length; + const newResultValues = []; + + for (let i = 0; i < inputCount; i++) { + newResultValues.push({ value: ' - ', color: '#000' }); + } + + for (const output of result.keys()) { + const resultValue = result.get(output); + const outputData = data.groups[groupIndex].outputs.find( + (dataOutput) => dataOutput.label === output + ); + + const expectedValue = outputData ? outputData.values[caseIndex] : undefined; + const color = resultValue === expectedValue ? '#17FC12' : '#FF1616'; + newResultValues.push({ value: escapeHtml(resultValue), color }); + } + + testBenchStore.resultValues = newResultValues; +} + +/** + * Defines all the functions called as event listeners for buttons on the UI + */ +export const buttonListenerFunctions = { + previousCaseButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.casePrev) { + testbenchData.casePrev(); + } + buttonListenerFunctions.computeCase() + }, + + nextCaseButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.caseNext) { + testbenchData.caseNext(); + } + buttonListenerFunctions.computeCase() + }, + + previousGroupButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.groupPrev) { + testbenchData.groupPrev(); + } + buttonListenerFunctions.computeCase() + }, + + nextGroupButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.groupNext) { + testbenchData.groupNext(); + } + buttonListenerFunctions.computeCase() + }, + + changeTestButton: () => { + openCreator('create') + }, + + runAllButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const results = runAll(useTestBenchStore().testbenchData.testData, globalScope) + const { passed } = results.summary + const { total } = results.summary + + useTestBenchStore().passed = passed + useTestBenchStore().total = total + useTestBenchStore().showPassed = true + + setTimeout(() => { + useTestBenchStore().showPassed = false + }, 3000) + }, + + editTestButton: () => { + const editDataString = JSON.stringify( + useTestBenchStore().testbenchData.testData + ) + openCreator('edit') + }, + + validateButton: () => { + const testBenchStore = useTestBenchStore() + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + testBenchStore.validationErrors = isValid + testBenchStore.showTestBenchValidator = true + }, + + removeTestButton: async () => { + if ( + await confirmOption( + 'Are you sure you want to remove the test from the circuit?' + ) + ) { + useTestBenchStore().testbenchData = { + testData: { + type: "", + title: "", + groups: [ + { + label: "Group 1", + inputs: [], + outputs: [], + n: 0 + } + ], + }, + currentGroup: 0, + currentCase: 0, + } + useTestBenchStore().showTestbenchUI = false + } + }, + + attachTestButton: () => { + openCreator('create') + }, + + rerunTestButton: () => { + buttonListenerFunctions.computeCase() + }, + + computeCase: () => { + const result = runSingleTest(useTestBenchStore().testbenchData, globalScope) + setUIResult(useTestBenchStore().testbenchData, result) + }, +} + +/** +* Runs single test +*/ +function runSingleTest(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + + let result + if (data.type === 'comb') { + result = runSingleCombinational(testbenchData, scope) + } else if (data.type === 'seq') { + result = runSingleSequential(testbenchData, scope) + } + + return result +} diff --git a/v0/src/simulator/src/testbench/ForceGate.js b/v0/src/simulator/src/testbench/ForceGate.js index 5da82c6f..332af06c 100644 --- a/v0/src/simulator/src/testbench/ForceGate.js +++ b/v0/src/simulator/src/testbench/ForceGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText4 } from '../canvasApi' /** * @class diff --git a/v0/src/simulator/src/testbench/testbenchInput.js b/v0/src/simulator/src/testbench/testbenchInput.js index bdf7452b..f877aca8 100644 --- a/v0/src/simulator/src/testbench/testbenchInput.js +++ b/v0/src/simulator/src/testbench/testbenchInput.js @@ -1,5 +1,5 @@ import CircuitElement from '../circuitElement' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import Node, { findNode } from '../node' import plotArea from '../plotArea' @@ -63,12 +63,11 @@ export default class TB_Input extends CircuitElement { setup() { this.iteration = 0 this.running = false - this.nodeList.clean(this.clockInp) + this.nodeList = this.nodeList.filter(x=> x !== this.clockInp); this.deleteNodes() this.nodeList = [] this.nodeList.push(this.clockInp) this.testData = this.testData || { inputs: [], outputs: [], n: 0 } - // this.clockInp = new Node(0,20, 0,this,1); this.setDimensions() diff --git a/v0/src/simulator/src/testbench/testbenchOutput.js b/v0/src/simulator/src/testbench/testbenchOutput.js index 865ec258..49117626 100644 --- a/v0/src/simulator/src/testbench/testbenchOutput.js +++ b/v0/src/simulator/src/testbench/testbenchOutput.js @@ -1,5 +1,5 @@ import CircuitElement from '../circuitElement' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText } from '../canvasApi' import Node, { findNode } from '../node' @@ -29,15 +29,8 @@ function dec2bin(dec, bitWidth = undefined) { export default class TB_Output extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', identifier) { super(x, y, scope, dir, 1) - // this.setDimensions(60,20); this.objectType = 'TB_Output' this.scope.TB_Output.push(this) - - // this.xSize=10; - - // this.plotValues = []; - // this.inp1 = new Node(0, 0, 0, this); - // this.inp1 = new Node(100, 100, 0, this); this.setIdentifier(identifier || 'Test1') this.inputs = [] this.testBenchInput = undefined @@ -45,10 +38,6 @@ export default class TB_Output extends CircuitElement { this.setup() } - // TB_Output.prototype.dblclick=function(){ - // this.testData=JSON.parse(prompt("Enter TestBench Json")); - // this.setup(); - // } setDimensions() { this.leftDimensionX = 0 this.rightDimensionX = 160 @@ -61,9 +50,6 @@ export default class TB_Output extends CircuitElement { } setup() { - // this.iteration = 0; - // this.running = false; - // this.nodeList.clean(this.clockInp); this.deleteNodes() // deletes all nodes whenever setup is called. this.nodeList = [] @@ -161,22 +147,6 @@ export default class TB_Output extends CircuitElement { yRotate = 20 } - // rect2(ctx, -120+xRotate+this.xSize, -20+yRotate, 120-this.xSize, 40, xx, yy, "RIGHT"); - // if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) - // ctx.fillStyle = "rgba(255, 255, 32,0.8)"; - // ctx.fill(); - // ctx.stroke(); - // - // ctx.font = "14px Raleway"; - // this.xOff = ctx.measureText(this.identifier).width; - // ctx.beginPath(); - // rect2(ctx, -105+xRotate+this.xSize, -11+yRotate,this.xOff + 10, 23, xx, yy, "RIGHT"); - // ctx.fillStyle = "#eee" - // ctx.strokeStyle = "#ccc"; - // ctx.fill(); - // ctx.stroke(); - // - ctx.beginPath() ctx.textAlign = 'center' ctx.fillStyle = 'black' @@ -187,9 +157,6 @@ export default class TB_Output extends CircuitElement { yy + 14, 10 ) - - // fillText(ctx, ["Not Running","Running"][+this.running], xx + this.rightDimensionX/ 2 , yy + 14 + 10 + 20*this.testData.inputs.length, 10); - // fillText(ctx, "Case: "+(this.iteration), xx + this.rightDimensionX/ 2 , yy + 14 + 20 + 20*this.testData.inputs.length, 10); fillText( ctx, ['Unpaired', 'Paired'][+(this.testBenchInput != undefined)], @@ -209,7 +176,6 @@ export default class TB_Output extends CircuitElement { i < this.testBenchInput.testData.outputs.length; i++ ) { - // ctx.beginPath(); fillText( ctx, this.testBenchInput.testData.outputs[i].label, diff --git a/v0/src/simulator/src/themer/customThemeAbstraction.js b/v0/src/simulator/src/themer/customThemeAbstraction.ts similarity index 74% rename from v0/src/simulator/src/themer/customThemeAbstraction.js rename to v0/src/simulator/src/themer/customThemeAbstraction.ts index 399134ea..341226d0 100644 --- a/v0/src/simulator/src/themer/customThemeAbstraction.js +++ b/v0/src/simulator/src/themer/customThemeAbstraction.ts @@ -3,7 +3,24 @@ * @param {*} themeOptions * @returns an Object */ -export const CreateAbstraction = (themeOptions) => { + +interface ThemeProperties { + color: string; + description: string; + ref: string[]; +} + +export interface Themes { + Navbar?: ThemeProperties; + Primary?: ThemeProperties; + Secondary?: ThemeProperties; + Canvas?: ThemeProperties; + Stroke?: ThemeProperties; + Text?: ThemeProperties; + Borders?: ThemeProperties; +} + +export const CreateAbstraction = (themeOptions: { [key: string]: string }): Themes => { return { Navbar: { color: themeOptions['--bg-navbar'], diff --git a/v0/src/simulator/src/themer/customThemer.js b/v0/src/simulator/src/themer/customThemer.js deleted file mode 100644 index 51a7e0b2..00000000 --- a/v0/src/simulator/src/themer/customThemer.js +++ /dev/null @@ -1,154 +0,0 @@ -// /* eslint-disable import/prefer-default-export */ -// /* eslint-disable import/no-cycle */ -// import { dots } from '../canvasApi' -// import themeOptions from './themes' -// import { updateThemeForStyle } from './themer' -// import { CreateAbstraction } from './customThemeAbstraction' - -// /** -// * -// */ -// var customTheme = CreateAbstraction(themeOptions['Custom Theme']) - -// const updateBG = () => dots(true, false, true) - -// /** -// * Generates Custom theme card HTML -// * return Html Element Theme card html (properties_container) -// */ -// // const getCustomThemeCard = () => { -// // var propertiesContainer = document.createElement('form') -// // const keys = Object.keys(customTheme) -// // keys.forEach((key) => { -// // const property = document.createElement('div') -// // const newPropertyLabel = document.createElement('label') -// // newPropertyLabel.textContent = `${key} (${customTheme[key].description})` -// // newPropertyLabel.setAttribute('for', key) -// // const newPropertyInput = document.createElement('input') -// // newPropertyInput.setAttribute('type', 'color') -// // newPropertyInput.setAttribute('name', key) -// // newPropertyInput.setAttribute('value', customTheme[key].color) -// // newPropertyInput.classList.add('customColorInput') -// // property.append(newPropertyLabel) -// // property.append(newPropertyInput) -// // propertiesContainer.append(property) -// // }) -// // const downloadAnchor = document.createElement('a') -// // downloadAnchor.setAttribute('id', 'downloadThemeFile') -// // downloadAnchor.setAttribute('style', 'display:none') -// // propertiesContainer.appendChild(downloadAnchor) -// // return propertiesContainer -// // } - -// /** -// * Create Custom Color Themes Dialog -// */ -// // export const CustomColorThemes = () => { -// // $('#CustomColorThemesDialog').empty() -// // $('#CustomColorThemesDialog').append(getCustomThemeCard()) -// // $('#CustomColorThemesDialog').dialog({ -// // resizable: false, -// // close() { -// // themeOptions['Custom Theme'] = -// // JSON.parse(localStorage.getItem('Custom Theme')) || -// // themeOptions['Default Theme'] // hack for closing dialog box without saving -// // // Rollback to previous theme -// // updateThemeForStyle(localStorage.getItem('theme')) -// // updateBG() -// // }, -// // buttons: [ -// // { -// // text: 'Apply Theme', -// // click() { -// // // update theme to Custom Theme -// // localStorage.setItem('theme', 'Custom Theme') -// // // add Custom theme to custom theme object -// // localStorage.setItem( -// // 'Custom Theme', -// // JSON.stringify(themeOptions['Custom Theme']) -// // ) -// // $('.set').removeClass('set') -// // $('.selected').addClass('set') -// // $(this).dialog('close') -// // }, -// // }, -// // { -// // text: 'Import Theme', -// // click() { -// // $('#importThemeFile').click() -// // }, -// // }, -// // { -// // text: 'Export Theme', -// // click() { -// // const dlAnchorElem = -// // document.getElementById('downloadThemeFile') -// // dlAnchorElem.setAttribute( -// // 'href', -// // `data:text/json;charset=utf-8,${encodeURIComponent( -// // JSON.stringify(themeOptions['Custom Theme']) -// // )}` -// // ) -// // dlAnchorElem.setAttribute('download', 'CV_CustomTheme.json') -// // dlAnchorElem.click() -// // }, -// // }, -// // ], -// // }) - -// // $('#CustomColorThemesDialog').focus() - -// // /** -// // * To preview the changes -// // */ -// // // function setColorEvent() { -// // // $('.customColorInput').on('input', (e) => { -// // // customTheme[e.target.name].color = e.target.value -// // // customTheme[e.target.name].ref.forEach((property) => { -// // // themeOptions['Custom Theme'][property] = e.target.value -// // // }) -// // // updateThemeForStyle('Custom Theme') -// // // updateBG() -// // // }) -// // // } -// // // setColorEvent() - -// // // hack for updating current theme to the saved custom theme -// // setTimeout(() => { -// // updateThemeForStyle('Custom Theme') -// // updateBG() -// // }, 50) - -// // /** -// // * Read JSON file and -// // * set Custom theme to the Content of the JSON file -// // * */ -// // // function receivedText(e) { -// // // const lines = JSON.parse(e.target.result) -// // // customTheme = CreateAbstraction(lines) -// // // themeOptions['Custom Theme'] = lines -// // // // preview theme -// // // updateThemeForStyle('Custom Theme') -// // // updateBG() -// // // // update colors in dialog box -// // // $('#CustomColorThemesDialog').empty() -// // // $('#CustomColorThemesDialog').append(getCustomThemeCard()) -// // // setColorEvent() -// // // } - -// // /** -// // * Add listener for file input -// // * Read imported JSON file -// // */ -// // // $('#importThemeFile').on('change', (event) => { -// // // var File = event.target.files[0] -// // // if (File !== null && File.name.split('.')[1] === 'json') { -// // // var fr = new FileReader() -// // // fr.onload = receivedText -// // // fr.readAsText(File) -// // // $('#importThemeFile').val('') -// // // } else { -// // // alert('File Not Supported !') -// // // } -// // // }) -// // } diff --git a/v0/src/simulator/src/themer/customThemer.vue b/v0/src/simulator/src/themer/customThemer.vue new file mode 100644 index 00000000..17f64f6e --- /dev/null +++ b/v0/src/simulator/src/themer/customThemer.vue @@ -0,0 +1,174 @@ + + + + + \ No newline at end of file diff --git a/v0/src/simulator/src/themer/themeCardSvg.js b/v0/src/simulator/src/themer/themeCardSvg.ts similarity index 98% rename from v0/src/simulator/src/themer/themeCardSvg.js rename to v0/src/simulator/src/themer/themeCardSvg.ts index 5e1776cb..de3c9f78 100644 --- a/v0/src/simulator/src/themer/themeCardSvg.js +++ b/v0/src/simulator/src/themer/themeCardSvg.ts @@ -1,4 +1,4 @@ -export default ` +const svgString: string = ` @@ -98,5 +98,6 @@ export default ` - -` +`; + +export default svgString; \ No newline at end of file diff --git a/v0/src/simulator/src/themer/themer.js b/v0/src/simulator/src/themer/themer.js deleted file mode 100644 index 2c61865e..00000000 --- a/v0/src/simulator/src/themer/themer.js +++ /dev/null @@ -1,223 +0,0 @@ -import { dots } from '../canvasApi' -import themeOptions from './themes' -import themeCardSvg from './themeCardSvg' -import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' - -/** - * Extracts canvas theme colors from CSS-Variables and returns a JSON Object - * @returns {object} - */ -const getCanvasColors = () => { - let colors = {} - colors['hover_select'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--hover-and-sel') - colors['fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--fill') - colors['mini_fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--mini-map') - colors['mini_stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--mini-map-stroke') - colors['stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--stroke') - colors['stroke_alt'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--secondary-stroke') - colors['input_text'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--input-text') - colors['color_wire_draw'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-draw') - colors['color_wire_con'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-cnt') - colors['color_wire_pow'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-pow') - colors['color_wire_sel'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-sel') - colors['color_wire_lose'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-lose') - colors['color_wire'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-norm') - colors['text'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--text') - colors['node'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--node') - colors['node_norm'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--node-norm') - colors['splitter'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--splitter') - colors['out_rect'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--output-rect') - colors['canvas_stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--canvas-stroke') - colors['canvas_fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--canvas-fill') - return colors -} - -/** - * Common canvas theme color object, used for rendering canvas elements - */ -export let colors = getCanvasColors() - -/** - * Updates theme - * 1) Sets CSS Variables for UI elements - * 2) Sets color variable for Canvas elements - */ -export function updateThemeForStyle(themeName) { - const selectedTheme = themeOptions[themeName] - if (selectedTheme === undefined) return - const html = document.getElementsByTagName('html')[0] - Object.keys(selectedTheme).forEach((property, i) => { - html.style.setProperty(property, selectedTheme[property]) - }) - colors = getCanvasColors() -} - -/** - * Theme Preview Card SVG - * Sets the SVG colors according to theme - * @param {string} themeName Name of theme - * @returns {SVG} - */ -export const getThemeCardSvg = (themeName) => { - const colors = themeOptions[themeName] - let svgIcon = $(themeCardSvg) - - // Dynamically set the colors according to the theme - $('.svgText', svgIcon).attr('fill', colors['--text-panel']) - - $('.svgNav', svgIcon).attr('fill', colors['--bg-tab']) - $('.svgNav', svgIcon).attr('stroke', colors['--br-primary']) - - $('.svgGridBG', svgIcon).attr('fill', colors['--canvas-fill']) - $('.svgGrid', svgIcon).attr('fill', colors['--canvas-stroke']) - - $('.svgPanel', svgIcon).attr('fill', colors['--primary']) - $('.svgPanel', svgIcon).attr('stroke', colors['--br-primary']) - - $('.svgChev', svgIcon).attr('stroke', colors['--br-secondary']) - - $('.svgHeader', svgIcon).attr('fill', colors['--primary']) - let temp = svgIcon.prop('outerHTML') - return svgIcon.prop('outerHTML') -} - -/** - * Generates theme card HTML - * @param {string} themeName Name of theme - * @param {boolean} selected Flag variable for currently selected theme - * @return {string} Theme card html - */ -export const getThemeCard = (themeName, selected) => { - if (themeName === 'Custom Theme') return '
' - let themeId = themeName.replace(' ', '') - let selectedClass = selected ? 'selected set' : '' - // themeSel is the hit area - return ` -
-
- ${getThemeCardSvg(themeName)} - - - - -
- ` -} - -/** - * Create Color Themes Dialog - */ -export const colorThemes = () => { - const simulatorStore = SimulatorStore() - simulatorStore.dialogBox.theme_dialog = true - - // const selectedTheme = localStorage.getItem('theme') - // $('#colorThemesDialog').empty() - // const themes = Object.keys(themeOptions) - // themes.forEach((theme) => { - // if (theme === selectedTheme) { - // $('#colorThemesDialog').append(getThemeCard(theme, true)) - // } else { - // $('#colorThemesDialog').append(getThemeCard(theme, false)) - // } - // }) - - // $('.selected label').trigger('click') - // $('#colorThemesDialog').dialog({ - // resizable: false, - // close() { - // // Rollback to previous theme - // updateThemeForStyle(localStorage.getItem('theme')) - // updateBG() - // }, - // buttons: [ - // { - // text: 'Apply Theme', - // click() { - // // check if any theme is selected or not - // if ($('.selected label').text()) { - // localStorage.removeItem('Custom Theme') - // localStorage.setItem( - // 'theme', - // $('.selected label').text() - // ) - // } - // $('.set').removeClass('set') - // $('.selected').addClass('set') - // $(this).dialog('close') - // }, - // }, - // { - // text: 'Custom Theme', - // click() { - // CustomColorThemes() - // $(this).dialog('close') - // }, - // }, - // ], - // }) - - $('#colorThemesDialog').focus() - $('.ui-dialog[aria-describedby="colorThemesDialog"]').on('click', () => - $('#colorThemesDialog').focus() - ) //hack for losing focus - - $('.themeSel').on('mousedown', (e) => { - e.preventDefault() - $('.selected').removeClass('selected') - let themeCard = $(e.target.parentElement) - themeCard.addClass('selected') - // Extract radio button - var radioButton = themeCard.find('input[type=radio]') - radioButton.trigger('click') // Mark as selected - updateThemeForStyle(themeCard.find('label').text()) // Extract theme name and set - updateBG() - }) -} - -export const updateBG = () => dots(true, false, true) -;(() => { - if (!localStorage.getItem('theme')) - localStorage.setItem('theme', 'Default Theme') - updateThemeForStyle(localStorage.getItem('theme')) -})() diff --git a/v0/src/simulator/src/themer/themer.ts b/v0/src/simulator/src/themer/themer.ts new file mode 100644 index 00000000..d8597939 --- /dev/null +++ b/v0/src/simulator/src/themer/themer.ts @@ -0,0 +1,218 @@ +import { dots } from '../canvasApi'; +import importedThemeOptions from './themes'; +import { ThemeOptions } from './themer.types'; +import themeCardSvg from './themeCardSvg'; +import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore'; + +const themeOptions: ThemeOptions = importedThemeOptions; + +/** + * Helper function to set CSS variable values into a colors object. + */ +const setColor = (colors: Record, key: string, cssVar: string): void => { + colors[key] = getComputedStyle(document.documentElement).getPropertyValue(cssVar); +}; + +/** + * Extracts canvas theme colors from CSS variables and returns a JSON object. + */ +const getCanvasColors = (): Record => { + const colors: Record = {}; + setColor(colors, 'hover_select', '--hover-and-sel'); + setColor(colors, 'fill', '--fill'); + setColor(colors, 'mini_fill', '--mini-map'); + setColor(colors, 'mini_stroke', '--mini-map-stroke'); + setColor(colors, 'stroke', '--stroke'); + setColor(colors, 'stroke_alt', '--secondary-stroke'); + setColor(colors, 'input_text', '--input-text'); + setColor(colors, 'color_wire_draw', '--wire-draw'); + setColor(colors, 'color_wire_con', '--wire-cnt'); + setColor(colors, 'color_wire_pow', '--wire-pow'); + setColor(colors, 'color_wire_sel', '--wire-sel'); + setColor(colors, 'color_wire_lose', '--wire-lose'); + setColor(colors, 'color_wire', '--wire-norm'); + setColor(colors, 'text', '--text'); + setColor(colors, 'node', '--node'); + setColor(colors, 'node_norm', '--node-norm'); + setColor(colors, 'splitter', '--splitter'); + setColor(colors, 'out_rect', '--output-rect'); + setColor(colors, 'canvas_stroke', '--canvas-stroke'); + setColor(colors, 'canvas_fill', '--canvas-fill'); + return colors; +}; + +/** + * Common canvas theme color object, used for rendering canvas elements. + */ +export let colors: Record = getCanvasColors(); + +/** + * Updates theme by setting CSS variables and updating the colors object. + */ +export function updateThemeForStyle(themeName: string): void { + const selectedTheme = themeOptions[themeName]; + if (selectedTheme === undefined) return; + + const html = document.documentElement; + Object.keys(selectedTheme).forEach((property) => { + html.style.setProperty(property, selectedTheme[property]); + }); + + colors = getCanvasColors(); +} + +/** + * Helper function to set attributes for SVG elements. + */ +const setAttributes = (element: Element, attributes: Record): void => { + Object.entries(attributes).forEach(([attr, value]) => { + element.setAttribute(attr, value); + }); +}; + +/** + * Generates a theme preview card SVG with colors based on the selected theme. + */ +export const getThemeCardSvg = (themeName: string): string => { + if (!themeOptions[themeName]) { + console.error(`Theme "${themeName}" not found`); + return ''; + } + + const colors = themeOptions[themeName]; + const parser = new DOMParser(); + const svgDoc = parser.parseFromString(themeCardSvg, 'image/svg+xml'); + + // Check for parsing errors + const parserError = svgDoc.querySelector('parsererror'); + if (parserError) { + console.error('Failed to parse SVG:', parserError); + return ''; + } + + const svgElement = svgDoc.documentElement; + + const applyStyles = (selector: string, attributes: Record): void => { + svgElement.querySelectorAll(selector).forEach((el) => setAttributes(el, attributes)); + }; + + applyStyles('.svgText', { fill: colors['--text-panel'] || '#000000' }); + applyStyles('.svgNav', { fill: colors['--bg-tab'], stroke: colors['--br-primary'] }); + applyStyles('.svgGridBG', { fill: colors['--canvas-fill'] }); + applyStyles('.svgGrid', { fill: colors['--canvas-stroke'] }); + applyStyles('.svgPanel', { fill: colors['--primary'], stroke: colors['--br-primary'] }); + applyStyles('.svgChev', { stroke: colors['--br-secondary'] }); + applyStyles('.svgHeader', { fill: colors['--primary'] }); + + return svgElement.outerHTML; +}; + +/** + * Generates theme card HTML. + */ +export const getThemeCard = (themeName: string, selected: boolean): string => { + if (themeName === 'Custom Theme') return '
'; + + const themeId = themeName.replace(' ', ''); + const selectedClass = selected ? 'selected set' : ''; + + return ` +
+
+ ${getThemeCardSvg(themeName)} + + + + +
+ `; +}; + +/** + * Handles theme selection logic. + */ +const handleThemeSelection = (e: MouseEvent): void => { + e.preventDefault(); + + // Remove 'selected' class from all theme cards + document.querySelectorAll('.selected').forEach((el) => el.classList.remove('selected')); + + const themeCard = (e.target as HTMLElement).parentElement; + if (!themeCard) return; + + // Add 'selected' class to the clicked theme card + themeCard.classList.add('selected'); + + // Find the radio button and label within the theme card + const radioButton = themeCard.querySelector('input[type=radio]') as HTMLInputElement; + const label = themeCard.querySelector('label'); + + if (radioButton) { + radioButton.click(); // Mark the radio button as selected + } + + if (label) { + updateThemeForStyle(label.textContent || ''); // Update the theme based on the label text + } + + updateBG(); // Update the background +}; + +/** + * Sets up event listeners for theme selection. + */ +const setupThemeSelectionHandlers = (cleanupListeners: (() => void)[]): void => { + document.querySelectorAll('.themeSel').forEach((element) => { + const mousedownHandler = (e: MouseEvent) => handleThemeSelection(e); + + element.addEventListener('mousedown', mousedownHandler as EventListener); + cleanupListeners.push(() => element.removeEventListener('mousedown', mousedownHandler as EventListener)); + }); +}; + +/** + * Initializes the color themes dialog. + */ +export const colorThemes = (): void => { + const simulatorStore = SimulatorStore(); + const cleanupListeners: (() => void)[] = []; + + simulatorStore.dialogBox.theme_dialog = true; + + const dialog = document.querySelector('.ui-dialog[aria-describedby="colorThemesDialog"]'); + if (dialog) { + const dialogClickHandler = () => { + const colorThemesDialog = document.getElementById('colorThemesDialog'); + if (colorThemesDialog) colorThemesDialog.focus(); + }; + + dialog.addEventListener('click', dialogClickHandler); + cleanupListeners.push(() => dialog.removeEventListener('click', dialogClickHandler)); + } + + setupThemeSelectionHandlers(cleanupListeners); + + // Add cleanup method to store + (simulatorStore as any).cleanupThemeDialog = () => { + cleanupListeners.forEach(cleanup => cleanup()); + }; +}; + +/** + * Updates the background of the canvas. + */ +export const updateBG = (): void => dots(true, false, true); + +/** + * Initializes the theme on load. + */ +const initializeTheme = (): void => { + const theme = localStorage.getItem('theme') || 'Default Theme'; + if (!localStorage.getItem('theme')) { + localStorage.setItem('theme', theme); + } + updateThemeForStyle(theme); +}; + +// Initialize theme on load +initializeTheme(); \ No newline at end of file diff --git a/v0/src/simulator/src/themer/themer.types.ts b/v0/src/simulator/src/themer/themer.types.ts new file mode 100644 index 00000000..639e5052 --- /dev/null +++ b/v0/src/simulator/src/themer/themer.types.ts @@ -0,0 +1,13 @@ +export interface ThemeOptions { + [key: string]: { + [property: string]: string; + }; +} + +interface Theme { + [key: string]: string; +} + +export interface Themes { + [themeName: string]: Theme; +} \ No newline at end of file diff --git a/v1/src/simulator/src/themer/themes.js b/v0/src/simulator/src/themer/themes.ts similarity index 99% rename from v1/src/simulator/src/themer/themes.js rename to v0/src/simulator/src/themer/themes.ts index d4f8caa1..b0dbe421 100644 --- a/v1/src/simulator/src/themer/themes.js +++ b/v0/src/simulator/src/themer/themes.ts @@ -1,4 +1,6 @@ -export default { +import { Themes } from './themer.types' + +const themes: Themes = { 'Default Theme': { '--text-navbar--alt': '#000', '--br-secondary': '#7d7d7d', @@ -326,7 +328,7 @@ export default { '--disable': '#956c6a', '--table-head-dark': '#2e2b21', }, - 'Custom Theme': JSON.parse(localStorage.getItem('Custom Theme')) || { + 'Custom Theme': JSON.parse(localStorage.getItem('Custom Theme') || '{}') || { '--text-navbar--alt': '#000', '--br-secondary': '#7d7d7d', '--br-circuit-cur': '#ffffff', @@ -380,3 +382,5 @@ export default { '--output-rect': '#0000ff', }, } + +export default themes; diff --git a/v0/src/simulator/src/tutorials.js b/v0/src/simulator/src/tutorials.js index a1f10d67..dde6f52c 100644 --- a/v0/src/simulator/src/tutorials.js +++ b/v0/src/simulator/src/tutorials.js @@ -33,16 +33,6 @@ export const tour = [ // offset: 750, }, }, - // { - // element: '.forum-tab', - // popover: { - // className: "", - // title: 'Forum Tab', - // description: "The forums can help you report issues & bugs, feature requests, and discussing about circuits with the community!", - // position: 'right', - // // offset: -25, - // }, - // }, { element: '#tabsBar', popover: { @@ -63,16 +53,6 @@ export const tour = [ offset: 0, }, }, - - // { - // element: '#delCirGuide', - // popover: { - // title: 'Delete sub-circuit button', - // description: "You can make delete sub-circuits by pressing the cross *Note that main circuit cannot be deleted.", - // position: 'right', - // // offset: 250, - // }, - // }, { element: '.report-sidebar a', popover: { @@ -95,6 +75,15 @@ export const tour = [ offset: 0, }, }, + { + element: '.testbench-manual-panel', + popover: { + title: 'Test Bench Panel', + description: 'This panel helps you test your circuit correctness by observing how your circuit responds under different test cases, ensuring a thorough and effective validation process.', + position: 'right', + offset: 0, + }, + }, ] // Not used currently diff --git a/v0/src/simulator/src/types/app.types.ts b/v0/src/simulator/src/types/app.types.ts new file mode 100644 index 00000000..e126fcd6 --- /dev/null +++ b/v0/src/simulator/src/types/app.types.ts @@ -0,0 +1,33 @@ +interface Device { + type: string; + net?: string; + order?: number; + bits: number; + label?: string; + abits?: number; + words?: number; + offset?: number; + rdports?: Array<{ clock_polarity?: boolean }>; + wrports?: Array<{ clock_polarity?: boolean }>; + memdata?: Array; +} + +interface Connector { + to: { + id: string; + port: string; + }; + from: { + id: string; + port: string; + }; + name: string; +} + +export interface JsConfig { + devices: { + [key: string]: Device; + }; + connectors: Connector[]; + subcircuits: Record; +} \ No newline at end of file diff --git a/v0/src/simulator/src/utils.js b/v0/src/simulator/src/utils.ts similarity index 50% rename from v0/src/simulator/src/utils.js rename to v0/src/simulator/src/utils.ts index 9d6a32b9..a85b186e 100644 --- a/v0/src/simulator/src/utils.js +++ b/v0/src/simulator/src/utils.ts @@ -1,4 +1,4 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, play, @@ -9,6 +9,10 @@ import { import { layoutModeGet } from './layoutMode' import plotArea from './plotArea' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { useActions } from '#/store/SimulatorStore/actions' +import { writeTextFile } from '@tauri-apps/plugin-fs'; +import { join, downloadDir } from '@tauri-apps/api/path'; +import { isTauri } from '@tauri-apps/api/core' window.globalScope = undefined window.lightMode = false // To be deprecated @@ -16,14 +20,14 @@ window.projectId = undefined window.id = undefined window.loading = false // Flag - all assets are loaded -var prevErrorMessage // Global variable for error messages -var prevShowMessage // Global variable for error messages +let prevErrorMessage: string | undefined // Global variable for error messages +let prevShowMessage: string | undefined // Global variable for error messages export function generateId() { - var id = '' - var possible = + let id = '' + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' - for (var i = 0; i < 20; i++) { + for (let i = 0; i < 20; i++) { id += possible.charAt(Math.floor(Math.random() * possible.length)) } @@ -48,39 +52,25 @@ export function clockTick() { /** * Helper function to show error - * @param {string} error -The error to be shown - * @category utils */ -export function showError(error) { +export function showError(error: string) { errorDetectedSet(true) // if error ha been shown return if (error === prevErrorMessage) return prevErrorMessage = error - var id = Math.floor(Math.random() * 10000) - $('#MessageDiv').append( - `` - ) - setTimeout(() => { - prevErrorMessage = undefined - $(`#${id}`).fadeOut() - }, 1500) + + useActions().showMessage(error, 'error') } // Helper function to show message -export function showMessage(mes) { +export function showMessage(mes: string) { if (mes === prevShowMessage) return prevShowMessage = mes - var id = Math.floor(Math.random() * 10000) - $('#MessageDiv').append( - `` - ) - setTimeout(() => { - prevShowMessage = undefined - $(`#${id}`).fadeOut() - }, 2500) + + useActions().showMessage(mes, 'success') } -export function distance(x1, y1, x2, y2) { +export function distance(x1: number, y1: number, x2: number, y2: number) { return Math.sqrt((x2 - x1) ** 2) + (y2 - y1) ** 2 } @@ -89,22 +79,22 @@ export function distance(x1, y1, x2, y2) { * @param {Array} a - any array * @category utils */ -export function uniq(a) { - var seen = {} +export function uniq(a: any[]) { + const seen: { [key: string]: boolean } = {}; const tmp = a.filter((item) => seen.hasOwnProperty(item) ? false : (seen[item] = true) - ) - return tmp + ); + return tmp; } // Generates final verilog code for each element // Gate = &/|/^ // Invert is true for xNor, Nor, Nand export function gateGenerateVerilog(gate, invert = false) { - var inputs = [] - var outputs = [] + let inputs = [] + let outputs = [] - for (var i = 0; i < this.nodeList.length; i++) { + for (let i = 0; i < this.nodeList.length; i++) { if (this.nodeList[i].type == NODE_INPUT) { inputs.push(this.nodeList[i]) } else { @@ -114,13 +104,13 @@ export function gateGenerateVerilog(gate, invert = false) { } } - var res = 'assign ' + let res = 'assign ' if (outputs.length == 1) res += outputs[0].verilogLabel else res += `{${outputs.map((x) => x.verilogLabel).join(', ')}}` res += ' = ' - var inputParams = inputs.map((x) => x.verilogLabel).join(` ${gate} `) + const inputParams = inputs.map((x) => x.verilogLabel).join(` ${gate} `) if (invert) { res += `~(${inputParams});` } else { @@ -130,8 +120,17 @@ export function gateGenerateVerilog(gate, invert = false) { } // Helper function to download text -export function download(filename, text) { - var pom = document.createElement('a') +export function downloadFile(filename: string, text: string | number | boolean | JSON) { + if (isTauri()) { + return downloadFileDesktop(filename, text); + } else { + return downloadFileWeb(filename, text); + } +} + +// For Web Application +export function downloadFileWeb(filename: string, text: string | number | boolean) { + const pom = document.createElement('a') pom.setAttribute( 'href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text) @@ -139,7 +138,7 @@ export function download(filename, text) { pom.setAttribute('download', filename) if (document.createEvent) { - var event = document.createEvent('MouseEvents') + const event = document.createEvent('MouseEvents') event.initEvent('click', true, true) pom.dispatchEvent(event) } else { @@ -147,13 +146,25 @@ export function download(filename, text) { } } +// For Desktop Application +export async function downloadFileDesktop(filename: string, text: string | number | boolean | JSON) { + const downloadsDirectory = await downloadDir(); + let path = filename; + + if (!filename.startsWith('/')) { + path = await join(downloadsDirectory, filename); + } + + await writeTextFile(path, text.toString()); +} + // Helper function to open a new tab -export function openInNewTab(url) { - var win = window.open(url, '_blank') - win.focus() +export function openInNewTab(url: string | URL | undefined) { + const win = window.open(url, '_blank') + win?.focus() } -export function copyToClipboard(text) { +export function copyToClipboard(text: string) { const textarea = document.createElement('textarea') // Move it off-screen. @@ -161,27 +172,27 @@ export function copyToClipboard(text) { // Set to readonly to prevent mobile devices opening a keyboard when // text is .select()'ed. - textarea.setAttribute('readonly', true) + textarea.setAttribute('readonly', 'true') document.body.appendChild(textarea) textarea.value = text // Check if there is any content selected previously. const selected = - document.getSelection().rangeCount > 0 - ? document.getSelection().getRangeAt(0) + document.getSelection()?.rangeCount ?? 0 > 0 + ? document.getSelection()?.getRangeAt(0) : false // iOS Safari blocks programmatic execCommand copying normally, without this hack. // https://stackoverflow.com/questions/34045777/copy-to-clipboard-using-javascript-in-ios if (navigator.userAgent.match(/ipad|ipod|iphone/i)) { const editable = textarea.contentEditable - textarea.contentEditable = true + textarea.contentEditable = 'true' const range = document.createRange() range.selectNodeContents(textarea) const sel = window.getSelection() - sel.removeAllRanges() - sel.addRange(range) + sel?.removeAllRanges() + sel?.addRange(range) textarea.setSelectionRange(0, 999999) textarea.contentEditable = editable } else { @@ -193,8 +204,8 @@ export function copyToClipboard(text) { // Restore previous selection. if (selected) { - document.getSelection().removeAllRanges() - document.getSelection().addRange(selected) + document.getSelection()?.removeAllRanges() + document.getSelection()?.addRange(selected) } textarea.remove() return result @@ -205,7 +216,7 @@ export function copyToClipboard(text) { } } -export function truncateString(str, num) { +export function truncateString(str: string, num: number) { // If the length of str is less than or equal to num // just return str--don't truncate it. if (str.length <= num) { @@ -216,13 +227,13 @@ export function truncateString(str, num) { } export function bitConverterDialog() { - const simulatorStore = SimulatorStore(); - simulatorStore.dialogBox.hex_bin_dec_converter_dialog = true; + const simulatorStore = SimulatorStore() + simulatorStore.dialogBox.hex_bin_dec_converter_dialog = true } -export function getImageDimensions(file) { +export function getImageDimensions(file: string) { return new Promise(function (resolved, rejected) { - var i = new Image() + const i = new Image() i.onload = function () { resolved({ w: i.width, h: i.height }) } @@ -231,15 +242,24 @@ export function getImageDimensions(file) { } // convertors -export var convertors = { - dec2bin: (x) => '0b' + x.toString(2), - dec2hex: (x) => '0x' + x.toString(16), - dec2octal: (x) => '0' + x.toString(8), - dec2bcd: (x) => parseInt(x.toString(10), 16).toString(2), +export const convertors = { + dec2bin: (x: number) => '0b' + x.toString(2), + dec2hex: (x: number) => '0x' + x.toString(16), + dec2octal: (x: number) => '0' + x.toString(8), + dec2bcd: (x: number) => parseInt(x.toString(10), 16).toString(2), } -export function parseNumber(num) { - if (num instanceof Number) return num +export function setBaseValues(x) { + if (isNaN(x)) return; + $("#binaryInput").val(convertors.dec2bin(x)); + $("#bcdInput").val(convertors.dec2bcd(x)); + $("#octalInput").val(convertors.dec2octal(x)); + $("#hexInput").val(convertors.dec2hex(x)); + $("#decimalInput").val(x); +} + +export function parseNumber(num: string | number) { + if(typeof num === 'number') return num; if (num.slice(0, 2).toLocaleLowerCase() == '0b') return parseInt(num.slice(2), 2) if (num.slice(0, 2).toLocaleLowerCase() == '0x') @@ -248,26 +268,75 @@ export function parseNumber(num) { return parseInt(num) } -export function promptFile(contentType, multiple) { - var input = document.createElement('input') +export function setupBitConvertor() { + $("#decimalInput").on('keyup', function () { + var x = parseInt($("#decimalInput").val(), 10); + setBaseValues(x); + }) + + $("#binaryInput").on('keyup', function () { + var inp = $("#binaryInput").val(); + var x; + if (inp.slice(0, 2) == '0b') + x = parseInt(inp.slice(2), 2); + else + x = parseInt(inp, 2); + setBaseValues(x); + }) + $("#bcdInput").on('keyup', function () { + var input = $("#bcdInput").val(); + var num = 0; + while (input.length % 4 !== 0){ + input = "0" + input; + } + if(input !== 0){ + var i = 0; + while (i < input.length / 4){ + if(parseInt(input.slice((4 * i), 4 * (i + 1)), 2) < 10) + num = num * 10 + parseInt(input.slice((4 * i), 4 * (i + 1)), 2); + else + return setBaseValues(NaN); + i++; + } + } + return setBaseValues(x); + }) + + $("#hexInput").on('keyup', function () { + var x = parseInt($("#hexInput").val(), 16); + setBaseValues(x); + }) + + $("#octalInput").on('keyup', function () { + var x = parseInt($("#octalInput").val(), 8); + setBaseValues(x); + }) +} + +export function promptFile(contentType: string, multiple: boolean) { + const input = document.createElement('input') input.type = 'file' input.multiple = multiple input.accept = contentType return new Promise(function (resolve) { - document.activeElement.onfocus = function () { - document.activeElement.onfocus = null - setTimeout(resolve, 500) + if (document.activeElement instanceof HTMLInputElement) { + (document.activeElement as HTMLInputElement).onfocus = function () { + (document.activeElement as HTMLInputElement).onfocus = null; + setTimeout(resolve, 500); + }; } input.onchange = function () { - var files = Array.from(input.files) - if (multiple) return resolve(files) - resolve(files[0]) + const files = input.files + if (files === null) return resolve([]) + const fileArray = Array.from(files) + if (multiple) return resolve(fileArray) + resolve(fileArray[0]) } input.click() }) } -export function escapeHtml(unsafe) { +export function escapeHtml(unsafe: string) { return unsafe .replace(/&/g, '&') .replace(/" + obj.objectType + '
' - ) - - if (obj.subcircuitMutableProperties && obj.canShowInSubcircuit) { - for (let attr in obj.subcircuitMutableProperties) { - var prop = obj.subcircuitMutableProperties[attr] - if (obj.subcircuitMutableProperties[attr].type == 'number') { - var s = - '

' + - prop.name + - "

" - $('#moduleProperty-inner').append(s) - } - } - if (!obj.labelDirectionFixed) { - if (!obj.subcircuitMetadata.labelDirection) - obj.subcircuitMetadata.labelDirection = obj.labelDirection - var s = $( - "' - ) - s.val(obj.subcircuitMetadata.labelDirection) - $('#moduleProperty-inner').append( - '

Label Direction: ' + $(s).prop('outerHTML') + '

' - ) - } - } - } else if ( - simulationArea.lastSelected === undefined || - ['Wire', 'CircuitElement', 'Node'].indexOf( - simulationArea.lastSelected.objectType - ) !== -1 - ) { - $('#moduleProperty').show() - - $('#moduleProperty-inner').append( - `

Project:

` - ) - $('#moduleProperty-inner').append( - `

Circuit:

` - ) - $('#moduleProperty-inner').append( - `

Clock Time (ms):

` - ) - $('#moduleProperty-inner').append( - `

Clock Enabled:

` - ) - $('#moduleProperty-inner').append( - `

Lite Mode:

` - ) - $('#moduleProperty-inner').append( - "

" - ) - // $('#moduleProperty-inner').append("

"); - } else { - $('#moduleProperty').show() - - $('#moduleProperty-inner').append( - `

${obj.objectType}
` - ) - // $('#moduleProperty').append(""); - if (!obj.fixedBitWidth) { - $('#moduleProperty-inner').append( - `

BitWidth:

` - ) - } - - if (obj.changeInputSize) { - $('#moduleProperty-inner').append( - `

Input Size:

` - ) - } - - if (!obj.propagationDelayFixed) { - $('#moduleProperty-inner').append( - `

Delay:

` - ) - } - - if (!obj.disableLabel) - $('#moduleProperty-inner').append( - `

Label:

` - ) - - var s - if (!obj.labelDirectionFixed) { - s = $( - `${ - "' - ) - s.val(obj.labelDirection) - $('#moduleProperty-inner').append( - `

Label Direction: ${$(s).prop('outerHTML')}

` - ) - } - - if (!obj.directionFixed) { - s = $( - `${ - "' - ) - $('#moduleProperty-inner').append( - `

Direction: ${$(s).prop('outerHTML')}

` - ) - } else if (!obj.orientationFixed) { - s = $( - `${ - "' - ) - $('#moduleProperty-inner').append( - `

Orientation: ${$(s).prop('outerHTML')}

` - ) - } - - if (obj.mutableProperties) { - for (const attr in obj.mutableProperties) { - var prop = obj.mutableProperties[attr] - if (obj.mutableProperties[attr].type === 'number') { - s = `

${ - prop.name - }

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'text') { - s = `

${ - prop.name - }

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'button') { - s = `

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'textarea') { - s = `

${prop.name}

` - $('#moduleProperty-inner').append(s) - } - } - } - } - - var helplink = obj && obj.helplink - if (helplink) { - $('#moduleProperty-inner').append( - '

' - ) - $('#HelpButton').on('click', () => { - window.open(helplink) - }) - } -*/ checkPropertiesUpdate(this) - - // $(".moduleProperty input[type='number']").inputSpinner(); } /** @@ -613,28 +294,63 @@ export function deleteSelected() { updateRestrictedElementsInScope() } -export function setupPanels() { - // $('#dragQPanel') - // .on('mousedown', () => - // $('.quick-btn').draggable({ - // disabled: false, - // containment: 'window', - // }) - // ) - // .on('mouseup', () => $('.quick-btn').draggable({ disabled: true })) - - // let position = { x: 0, y: 0 } - // interact('.quick-btn').draggable({ - // allowFrom: '#dragQPanel', - // listeners: { - // move(event) { - // position.x = position.x + event.dx - // position.y = position.y + event.dy - // event.target.style.transform = `translate(${position.x}px, ${position.y}px)` - // }, - // }, - // }) +/** + * listener for opening the prompt for bin conversion + * @category ux + */ +$('#bitconverter').on('click', () => { + $('#bitconverterprompt').dialog({ + resizable: false, + buttons: [ + { + text: 'Reset', + click() { + $('#decimalInput').val('0') + $('#binaryInput').val('0') + $('#octalInput').val('0') + $('#hexInput').val('0') + }, + }, + ], + }) +}) + +// convertors +const convertors = { + dec2bin: (x) => `0b${x.toString(2)}`, + dec2hex: (x) => `0x${x.toString(16)}`, + dec2octal: (x) => `0${x.toString(8)}`, +} + +function setBaseValues(x) { + if (isNaN(x)) return + $('#binaryInput').val(convertors.dec2bin(x)) + $('#octalInput').val(convertors.dec2octal(x)) + $('#hexInput').val(convertors.dec2hex(x)) + $('#decimalInput').val(x) +} + +$('#decimalInput').on('keyup', () => { + var x = parseInt($('#decimalInput').val(), 10) + setBaseValues(x) +}) + +$('#binaryInput').on('keyup', () => { + var x = parseInt($('#binaryInput').val(), 2) + setBaseValues(x) +}) + +$('#hexInput').on('keyup', () => { + var x = parseInt($('#hexInput').val(), 16) + setBaseValues(x) +}) + +$('#octalInput').on('keyup', () => { + var x = parseInt($('#octalInput').val(), 8) + setBaseValues(x) +}) +export function setupPanels() { dragging('#dragQPanel', '.quick-btn') setupPanelListeners('.elementPanel') @@ -648,16 +364,9 @@ export function setupPanels() { // Minimize Timing Diagram (takes too much space) $('.timing-diagram-panel .minimize').trigger('click') - // Update the Testbench Panel UI - updateTestbenchUI() // Minimize Testbench UI $('.testbench-manual-panel .minimize').trigger('click') - // Hack because minimizing panel then maximizing sets visibility recursively - // updateTestbenchUI calls some hide()s which are undone by maximization - // TODO: Remove hack - $('.testbench-manual-panel .maximize').on('click', setupTestbenchUI) - $('#projectName').on('click', () => { $("input[name='setProjectName']").focus().select() }) @@ -670,26 +379,6 @@ function setupPanelListeners(panelSelector) { var bodySelector = `${panelSelector} > .panel-body` dragging(headerSelector, panelSelector) - // let position = { x: 0, y: 0 } - // Drag Start - // $(headerSelector).on('mousedown', () => - // $(panelSelector).draggable({ disabled: false, containment: 'window' }) - // interact(panelSelector).draggable({ - // allowFrom: headerSelector, - // listeners: { - // move(event) { - // position.x += event.dx - // position.y += event.dy - - // event.target.style.transform = `translate(${position.x}px, ${position.y}px)` - // }, - // }, - // }) - // ) - // // Drag End - // $(headerSelector).on('mouseup', () => - // $(panelSelector).draggable({ disabled: true }) - // ) // Current Panel on Top var minimized = false $(headerSelector).on('dblclick', () => @@ -725,6 +414,13 @@ export function exitFullView() { element.style.display = '' } }) + + // Mobile Components + + const simulatorMobileStore = toRefs(useSimulatorMobileStore()); + + simulatorMobileStore.showQuickButtons.value = true + simulatorMobileStore.showMobileButtons.value = true } export function fullView() { @@ -743,61 +439,58 @@ export function fullView() { } }) + // Mobile Components + + const simulatorMobileStore = toRefs(useSimulatorMobileStore()); + + simulatorMobileStore.showElementsPanel.value = false + simulatorMobileStore.showPropertiesPanel.value = false + simulatorMobileStore.showTimingDiagram.value = false + simulatorMobileStore.showQuickButtons.value = false + simulatorMobileStore.showMobileButtons.value = false + app.appendChild(exitViewEl) exitViewEl.addEventListener('click', exitFullView) } -/** +/** Fills the elements that can be displayed in the subcircuit, in the subcircuit menu **/ export function fillSubcircuitElements() { - $('#subcircuitMenu').empty() - var subCircuitElementExists = false + const simulatorStore = SimulatorStore() + const { subCircuitElementList, isEmptySubCircuitElementList } = toRefs(simulatorStore) + subCircuitElementList.value = [] + isEmptySubCircuitElementList.value = true + + const subcircuitElements = [] + + let subCircuitElementExists = false + for (let el of circuitElementList) { if (globalScope[el].length === 0) continue if (!globalScope[el][0].canShowInSubcircuit) continue - let tempHTML = '' - - // add a panel for each existing group - tempHTML += `
${el}s
` - tempHTML += `
` let available = false + const elementGroup = { + type: el, + elements: [], + } + // add an SVG for each element for (let i = 0; i < globalScope[el].length; i++) { if (!globalScope[el][i].subcircuitMetadata.showInSubcircuit) { - tempHTML += `
` - tempHTML += `` - tempHTML += `

${ - globalScope[el][i].label !== '' - ? globalScope[el][i].label - : 'unlabeled' - }

` - tempHTML += '
' available = true + const element = globalScope[el][i]; + elementGroup.elements.push(element); } } - tempHTML += '
' subCircuitElementExists = subCircuitElementExists || available - if (available) $('#subcircuitMenu').append(tempHTML) - } + if (available) { + subcircuitElements.push(elementGroup); + } - if (subCircuitElementExists) { - // $('#subcircuitMenu').accordion('refresh') - } else { - $('#subcircuitMenu').append('

No layout elements available

') + subCircuitElementList.value = subcircuitElements + isEmptySubCircuitElementList.value = !subCircuitElementExists } - - $('.subcircuitModule').mousedown(function () { - let elementName = this.dataset.elementName - let elementIndex = this.dataset.elementId - - let element = globalScope[elementName][elementIndex] - - element.subcircuitMetadata.showInSubcircuit = true - element.newElement = true - simulationArea.lastSelected = element - this.parentElement.removeChild(this) - }) } diff --git a/v0/src/simulator/src/verilog.js b/v0/src/simulator/src/verilog.js index d0811b2c..5e0fcc26 100644 --- a/v0/src/simulator/src/verilog.js +++ b/v0/src/simulator/src/verilog.js @@ -7,8 +7,6 @@ */ import { scopeList } from './circuit' import { errorDetectedGet } from './engine' -import { download } from './utils' -import { getProjectName } from './data/save' import modules from './modules' import { sanitizeLabel } from './verilogHelpers' import CodeMirror from 'codemirror/lib/codemirror.js' @@ -19,49 +17,14 @@ import 'codemirror/addon/edit/closebrackets.js' import 'codemirror/addon/hint/anyword-hint.js' import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/display/autorefresh.js' -import { openInNewTab, copyToClipboard, showMessage } from './utils' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { inputList, moduleList } from './metadata' + var editor export function generateVerilog() { const simulatorStore = SimulatorStore() simulatorStore.dialogBox.exportverilog_dialog = true - // var dialog = $('#verilog-export-code-window-div') - // var data = verilog.exportVerilog() - // editor.setValue(data) - // $('#verilog-export-code-window-div .CodeMirror').css( - // 'height', - // $(window).height() - 200 - // ) - // dialog.dialog({ - // resizable: false, - // width: '90%', - // height: 'auto', - // position: { my: 'center', at: 'center', of: window }, - // buttons: [ - // { - // text: 'Download Verilog File', - // click() { - // var fileName = getProjectName() || 'Untitled' - // download(fileName + '.v', editor.getValue()) - // }, - // }, - // { - // text: 'Copy to Clipboard', - // click() { - // copyToClipboard(editor.getValue()) - // showMessage('Code has been copied') - // }, - // }, - // { - // text: 'Try in EDA Playground', - // click() { - // copyToClipboard(editor.getValue()) - // openInNewTab('https://www.edaplayground.com/x/XZpY') - // }, - // }, - // ], - // }) } export function setupVerilogExportCodeWindow() { @@ -529,45 +492,14 @@ export var verilog = { return res }, - /* - sanitizeLabel: function(name){ - // Replace spaces by "_" - name = name.replace(/ /g , "_"); - // Replace Hyphens by "_" - name = name.replace(/-/g , "_"); - // Replace Colons by "_" - name = name.replace(/:/g , "_"); - // replace ~ with inv_ - name = name.replace(/~/g , "inv_"); - // Shorten Inverse to inv - name = name.replace(/Inverse/g , "inv"); - - // If first character is a number - if(name.substring(0, 1).search(/[0-9]/g) > -1) { - name = "w_" + name; - } - - // if first character is not \ already - if (name[0] != '\\') { - //if there are non-alphanum_ character, add \ - if (name.search(/[\W]/g) > -1) - name = "\\" + name; - } - return name; - }, - */ } -/* - Helper function to generate spaces for indentation -*/ +/* Helper function to generate spaces for indentation */ function sp(indentation) { return ' '.repeat(indentation * 2) } -/* - Helper function to indent paragraph -*/ +/* Helper function to indent paragraph */ function indent(indentation, string) { var result = string.split('\n') if (result[result.length - 1] == '') { diff --git a/v0/src/simulator/src/verilogHelpers.js b/v0/src/simulator/src/verilogHelpers.js index 3f9a4123..e2b4cb4a 100644 --- a/v0/src/simulator/src/verilogHelpers.js +++ b/v0/src/simulator/src/verilogHelpers.js @@ -1,5 +1,4 @@ export function sanitizeLabel(name) { - // return name.replace(/ Inverse/g, "_inv").replace(/ /g , "_"); var temp = name // if there is a space anywhere but the last place // replace spaces by "_" diff --git a/v0/src/simulator/src/wire.js b/v0/src/simulator/src/wire.js deleted file mode 100644 index 7e06e7d2..00000000 --- a/v0/src/simulator/src/wire.js +++ /dev/null @@ -1,240 +0,0 @@ -/* eslint-disable no-multi-assign */ -// wire object -import { drawLine } from './canvasApi' -import simulationArea from './simulationArea' -import Node from './node' -import { updateSimulationSet, forceResetNodesSet } from './engine' -import { colors } from './themer/themer' - -/** - * Wire - To connect two nodes. - * @class - * @memberof module:wire - * @param {Node} node1 - * @param {Node} node2 - * @param {Scope} scope - The circuit in which wire has to be drawn - * @category wire - */ -export default class Wire { - constructor(node1, node2, scope) { - this.objectType = 'Wire' - this.node1 = node1 - this.scope = scope - this.node2 = node2 - this.type = 'horizontal' - - this.updateData() - this.scope.wires.push(this) - forceResetNodesSet(true) - } - - // if data changes - updateData() { - this.x1 = this.node1.absX() - this.y1 = this.node1.absY() - this.x2 = this.node2.absX() - this.y2 = this.node2.absY() - if (this.x1 === this.x2) this.type = 'vertical' - } - - updateScope(scope) { - this.scope = scope - this.checkConnections() - } - - // to check if nodes are disconnected - checkConnections() { - var check = - this.node1.deleted || - this.node2.deleted || - !this.node1.connections.contains(this.node2) || - !this.node2.connections.contains(this.node1) - if (check) this.delete() - return check - } - - dblclick() { - if ( - this.node1.parent == globalScope.root && - this.node2.parent == globalScope.root - ) { - simulationArea.multipleObjectSelections = [this.node1, this.node2] - simulationArea.lastSelected = undefined - } - } - - update() { - var updated = false - if (embed) return updated - - if (this.node1.absX() === this.node2.absX()) { - this.x1 = this.x2 = this.node1.absX() - this.type = 'vertical' - } else if (this.node1.absY() === this.node2.absY()) { - this.y1 = this.y2 = this.node1.absY() - this.type = 'horizontal' - } - - // if (wireToBeChecked && this.checkConnections()) { - // this.delete(); - // return updated; - // } // SLOW , REMOVE - if ( - simulationArea.shiftDown === false && - simulationArea.mouseDown === true && - simulationArea.selected === false && - this.checkWithin( - simulationArea.mouseDownX, - simulationArea.mouseDownY - ) - ) { - simulationArea.selected = true - simulationArea.lastSelected = this - updated = true - } else if ( - simulationArea.mouseDown && - simulationArea.lastSelected === this && - !this.checkWithin(simulationArea.mouseX, simulationArea.mouseY) - ) { - var n = new Node( - simulationArea.mouseDownX, - simulationArea.mouseDownY, - 2, - this.scope.root - ) - n.clicked = true - n.wasClicked = true - simulationArea.lastSelected = n - this.converge(n) - } - // eslint-disable-next-line no-empty - if (simulationArea.lastSelected === this) { - } - - if (this.node1.deleted || this.node2.deleted) { - this.delete() - return updated - } // if either of the nodes are deleted - - if (simulationArea.mouseDown === false) { - if (this.type === 'horizontal') { - if (this.node1.absY() !== this.y1) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.node1.absX(), this.y1, 2, this.scope.root) - this.converge(n) - updated = true - } else if (this.node2.absY() !== this.y2) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.node2.absX(), this.y2, 2, this.scope.root) - this.converge(n) - updated = true - } - } else if (this.type === 'vertical') { - if (this.node1.absX() !== this.x1) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.x1, this.node1.absY(), 2, this.scope.root) - this.converge(n) - updated = true - } else if (this.node2.absX() !== this.x2) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.x2, this.node2.absY(), 2, this.scope.root) - this.converge(n) - updated = true - } - } - } - return updated - } - - draw() { - // for calculating min-max Width,min-max Height - // - const ctx = simulationArea.context - - var color - if (simulationArea.lastSelected == this) { - color = colors['color_wire_sel'] - } else if ( - this.node1.value == undefined || - this.node2.value == undefined - ) { - color = colors['color_wire_lose'] - } else if (this.node1.bitWidth == 1) { - color = [ - colors['color_wire_lose'], - colors['color_wire_con'], - colors['color_wire_pow'], - ][this.node1.value + 1] - } else { - color = colors['color_wire'] - } - drawLine( - ctx, - this.node1.absX(), - this.node1.absY(), - this.node2.absX(), - this.node2.absY(), - color, - 3 - ) - } - - // checks if node lies on wire - checkConvergence(n) { - return this.checkWithin(n.absX(), n.absY()) - } - - // fn checks if coordinate lies on wire - checkWithin(x, y) { - if ( - this.type === 'horizontal' && - this.node1.absX() < this.node2.absX() && - x > this.node1.absX() && - x < this.node2.absX() && - y === this.node2.absY() - ) - return true - if ( - this.type === 'horizontal' && - this.node1.absX() > this.node2.absX() && - x < this.node1.absX() && - x > this.node2.absX() && - y === this.node2.absY() - ) - return true - if ( - this.type === 'vertical' && - this.node1.absY() < this.node2.absY() && - y > this.node1.absY() && - y < this.node2.absY() && - x === this.node2.absX() - ) - return true - if ( - this.type === 'vertical' && - this.node1.absY() > this.node2.absY() && - y < this.node1.absY() && - y > this.node2.absY() && - x === this.node2.absX() - ) - return true - return false - } - - // add intermediate node between these 2 nodes - converge(n) { - this.node1.connect(n) - this.node2.connect(n) - this.delete() - } - - delete() { - forceResetNodesSet(true) - updateSimulationSet(true) - this.node1.connections.clean(this.node2) - this.node2.connections.clean(this.node1) - this.scope.wires.clean(this) - this.node1.checkDeleted() - this.node2.checkDeleted() - } -} diff --git a/v0/src/simulator/src/wire.ts b/v0/src/simulator/src/wire.ts new file mode 100644 index 00000000..885701c1 --- /dev/null +++ b/v0/src/simulator/src/wire.ts @@ -0,0 +1,265 @@ +/* eslint-disable no-multi-assign */ +import { drawLine } from './canvasApi'; +import { simulationArea } from './simulationArea'; +import Node from './node'; +import { updateSimulationSet, forceResetNodesSet } from './engine'; +import { colors } from './themer/themer'; +import CircuitElement from './circuitElement'; + +interface Scope { + wires: Wire[]; + root: CircuitElement; + timeStamp: number; +} + +enum WireValue { + LOOSE = -1, + LOW = 0, + HIGH = 1 +} + +export default class Wire { + objectType = 'Wire'; + type = 'horizontal'; + x1: number; + y1: number; + x2: number; + y2: number; + + constructor(public node1: Node, public node2: Node, public scope: Scope) { + this.x1 = this.node1.absX(); + this.y1 = this.node1.absY(); + this.x2 = this.node2.absX(); + this.y2 = this.node2.absY(); + this.updateData(); + this.scope.wires.push(this); + forceResetNodesSet(true); + } + + updateData(): void { + [this.x1, this.y1, this.x2, this.y2] = [ + this.node1.absX(), this.node1.absY(), + this.node2.absX(), this.node2.absY() + ]; + if (this.x1 === this.x2) this.type = 'vertical'; + } + + updateScope(scope: Scope): void { + this.scope = scope; + this.checkConnections(); + } + + checkConnections(): boolean { + const disconnected = this.node1.deleted || this.node2.deleted || + !this.node1.connections?.includes(this.node2) || + !this.node2.connections?.includes(this.node1); + if (disconnected) this.delete(); + return disconnected; + } + + dblclick(): void { + if (this.node1.parent === globalScope.root && this.node2.parent === globalScope.root) { + simulationArea.multipleObjectSelections = [this.node1, this.node2]; + simulationArea.lastSelected = undefined; + } + } + + update(): boolean { + let updated = false; + if (embed) return updated; + + this.updateWireType(); + updated = this.handleMouseInteraction() || updated; + + if (this.node1.deleted || this.node2.deleted) { + this.delete(); + return updated; + } + + if (!simulationArea.mouseDown) { + updated = this.handleNodeAlignment() || updated; + } + + return updated; + } + + draw(): void { + drawLine( + simulationArea.context, + this.node1.absX(), this.node1.absY(), + this.node2.absX(), this.node2.absY(), + this.getWireColor(), 3 + ); + } + + checkConvergence(n: Node): boolean { + return this.checkWithin(n.absX(), n.absY()); + } + + checkWithin(x: number, y: number): boolean { + if (this.type === 'horizontal') { + return y === this.node1.absY() && this.isBetween(x, this.node1.absX(), this.node2.absX()); + } + + if (this.type === 'vertical') { + return x === this.node1.absX() && this.isBetween(y, this.node1.absY(), this.node2.absY()); + } + + return false; + } + + private isBetween(value: number, a: number, b: number): boolean { + return value >= Math.min(a, b) && value <= Math.max(a, b); + } + + converge(n: Node): void { + this.node1.connect(n); + this.node2.connect(n); + this.delete(); + } + + delete(): void { + forceResetNodesSet(true); + updateSimulationSet(true); + this.removeMutualConnections(); + this.scope.wires = this.scope.wires.filter(x => x !== this); + this.node1.checkDeleted(); + this.node2.checkDeleted(); + this.scope.timeStamp = Date.now(); + } + + private removeMutualConnections(): void { + this.removeConnection(this.node1, this.node2); + this.removeConnection(this.node2, this.node1); + } + + private removeConnection(node: Node, otherNode: Node): void { + if (node.connections) { + node.connections = node.connections.filter(x => x !== otherNode); + } + } + + private updateWireType(): void { + const x1 = this.node1.absX(); + const x2 = this.node2.absX(); + const y1 = this.node1.absY(); + const y2 = this.node2.absY(); + + if (x1 === x2) { + this.x1 = this.x2 = x1; + this.type = 'vertical'; + } else if (y1 === y2) { + this.y1 = this.y2 = y1; + this.type = 'horizontal'; + } + } + + private handleMouseInteraction(): boolean { + if (this.checkWireSelection()) { + simulationArea.selected = true; + simulationArea.lastSelected = this; + return true; + } + + if (this.checkWireDrag()) { + this.createIntermediateNode(); + return true; + } + + return false; + } + + private checkWireSelection(): boolean { + return !simulationArea.shiftDown && + simulationArea.mouseDown && + !simulationArea.selected && + this.checkWithin(simulationArea.mouseDownX, simulationArea.mouseDownY); + } + + private checkWireDrag(): boolean { + return simulationArea.mouseDown && + simulationArea.lastSelected === this && + !this.checkWithin(simulationArea.mouseX, simulationArea.mouseY); + } + + private createIntermediateNode(): void { + const n = new Node( + simulationArea.mouseDownX, + simulationArea.mouseDownY, + 2, + this.scope.root + ); + n.clicked = true; + n.wasClicked = true; + simulationArea.lastSelected = n; + this.converge(n); + } + + private handleNodeAlignment(): boolean { + if (this.type === 'horizontal') { + return this.alignNodesAlongYAxis(); + } + if (this.type === 'vertical') { + return this.alignNodesAlongXAxis(); + } + return false; + } + + private alignNodesAlongYAxis(): boolean { + return this.checkAndCreateNode( + this.node1.absY(), + this.y1, + () => new Node(this.node1.absX(), this.y1, 2, this.scope.root), + this.node2.absY(), + this.y2, + () => new Node(this.node2.absX(), this.y2, 2, this.scope.root) + ); + } + + private alignNodesAlongXAxis(): boolean { + return this.checkAndCreateNode( + this.node1.absX(), + this.x1, + () => new Node(this.x1, this.node1.absY(), 2, this.scope.root), + this.node2.absX(), + this.x2, + () => new Node(this.x2, this.node2.absY(), 2, this.scope.root) + ); + } + + private checkAndCreateNode( + current1: number, + expected1: number, + createNode1: () => Node, + current2: number, + expected2: number, + createNode2: () => Node + ): boolean { + if (current1 !== expected1) { + this.converge(createNode1()); + return true; + } + if (current2 !== expected2) { + this.converge(createNode2()); + return true; + } + return false; + } + + private getWireColor(): string { + if (simulationArea.lastSelected === this) { + return colors['color_wire_sel']; + } + if (this.node1.value === undefined || this.node2.value === undefined) { + return colors['color_wire_lose']; + } + if (this.node1.bitWidth === 1) { + return [ + colors['color_wire_lose'], + colors['color_wire_con'], + colors['color_wire_pow'], + ][this.node1.value - WireValue.LOOSE]; + } + return colors['color_wire']; + } +} \ No newline at end of file diff --git a/v0/src/simulator/vendor/canvas2svg.js b/v0/src/simulator/vendor/canvas2svg.js deleted file mode 100644 index 73dae81d..00000000 --- a/v0/src/simulator/vendor/canvas2svg.js +++ /dev/null @@ -1,1469 +0,0 @@ -/*!! - * Canvas 2 Svg v1.0.19 - * A low level canvas to SVG converter. Uses a mock canvas context to build an SVG document. - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Author: - * Kerry Liu - * - * Copyright (c) 2014 Gliffy Inc. - */ - -;(function () { - 'use strict' - - var STYLES, ctx, CanvasGradient, CanvasPattern, namedEntities - - //helper function to format a string - function format(str, args) { - var keys = Object.keys(args), - i - for (i = 0; i < keys.length; i++) { - str = str.replace( - new RegExp('\\{' + keys[i] + '\\}', 'gi'), - args[keys[i]] - ) - } - return str - } - - //helper function that generates a random string - function randomString(holder) { - var chars, randomstring, i - if (!holder) { - throw new Error( - 'cannot create a random attribute name for an undefined object' - ) - } - chars = 'ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz' - randomstring = '' - do { - randomstring = '' - for (i = 0; i < 12; i++) { - randomstring += chars[Math.floor(Math.random() * chars.length)] - } - } while (holder[randomstring]) - return randomstring - } - - //helper function to map named to numbered entities - function createNamedToNumberedLookup(items, radix) { - var i, - entity, - lookup = {}, - base10, - base16 - items = items.split(',') - radix = radix || 10 - // Map from named to numbered entities. - for (i = 0; i < items.length; i += 2) { - entity = '&' + items[i + 1] + ';' - base10 = parseInt(items[i], radix) - lookup[entity] = '&#' + base10 + ';' - } - //FF and IE need to create a regex from hex values ie   == \xa0 - lookup['\\xa0'] = ' ' - return lookup - } - - //helper function to map canvas-textAlign to svg-textAnchor - function getTextAnchor(textAlign) { - //TODO: support rtl languages - var mapping = { - left: 'start', - right: 'end', - center: 'middle', - start: 'start', - end: 'end', - } - return mapping[textAlign] || mapping.start - } - - //helper function to map canvas-textBaseline to svg-dominantBaseline - function getDominantBaseline(textBaseline) { - //INFO: not supported in all browsers - var mapping = { - alphabetic: 'alphabetic', - hanging: 'hanging', - top: 'text-before-edge', - bottom: 'text-after-edge', - middle: 'central', - } - return mapping[textBaseline] || mapping.alphabetic - } - - // Unpack entities lookup where the numbers are in radix 32 to reduce the size - // entity mapping courtesy of tinymce - namedEntities = createNamedToNumberedLookup( - '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + - '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + - '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + - '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + - '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + - '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + - '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + - '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + - '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + - '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + - 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + - 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + - 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + - 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + - 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + - '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + - '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + - '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + - '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + - '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + - 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + - 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + - 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + - '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + - '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', - 32 - ) - - //Some basic mappings for attributes and default values. - STYLES = { - strokeStyle: { - svgAttr: 'stroke', //corresponding svg attribute - canvas: '#000000', //canvas default - svg: 'none', //svg default - apply: 'stroke', //apply on stroke() or fill() - }, - fillStyle: { - svgAttr: 'fill', - canvas: '#000000', - svg: null, //svg default is black, but we need to special case this to handle canvas stroke without fill - apply: 'fill', - }, - lineCap: { - svgAttr: 'stroke-linecap', - canvas: 'butt', - svg: 'butt', - apply: 'stroke', - }, - lineJoin: { - svgAttr: 'stroke-linejoin', - canvas: 'miter', - svg: 'miter', - apply: 'stroke', - }, - miterLimit: { - svgAttr: 'stroke-miterlimit', - canvas: 10, - svg: 4, - apply: 'stroke', - }, - lineWidth: { - svgAttr: 'stroke-width', - canvas: 1, - svg: 1, - apply: 'stroke', - }, - globalAlpha: { - svgAttr: 'opacity', - canvas: 1, - svg: 1, - apply: 'fill stroke', - }, - font: { - //font converts to multiple svg attributes, there is custom logic for this - canvas: '10px sans-serif', - }, - shadowColor: { - canvas: '#000000', - }, - shadowOffsetX: { - canvas: 0, - }, - shadowOffsetY: { - canvas: 0, - }, - shadowBlur: { - canvas: 0, - }, - textAlign: { - canvas: 'start', - }, - textBaseline: { - canvas: 'alphabetic', - }, - lineDash: { - svgAttr: 'stroke-dasharray', - canvas: [], - svg: null, - apply: 'stroke', - }, - } - - /** - * - * @param gradientNode - reference to the gradient - * @constructor - */ - CanvasGradient = function (gradientNode, ctx) { - this.__root = gradientNode - this.__ctx = ctx - } - - /** - * Adds a color stop to the gradient root - */ - CanvasGradient.prototype.addColorStop = function (offset, color) { - var stop = this.__ctx.__createElement('stop'), - regex, - matches - stop.setAttribute('offset', offset) - if (color.indexOf('rgba') !== -1) { - //separate alpha value, since webkit can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(color) - stop.setAttribute( - 'stop-color', - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - stop.setAttribute('stop-opacity', matches[4]) - } else { - stop.setAttribute('stop-color', color) - } - this.__root.appendChild(stop) - } - - CanvasPattern = function (pattern, ctx) { - this.__root = pattern - this.__ctx = ctx - } - - /** - * The mock canvas context - * @param o - options include: - * ctx - existing Context2D to wrap around - * width - width of your canvas (defaults to 500) - * height - height of your canvas (defaults to 500) - * enableMirroring - enables canvas mirroring (get image data) (defaults to false) - * document - the document object (defaults to the current document) - */ - ctx = function (o) { - var defaultOptions = { - width: 500, - height: 500, - enableMirroring: false, - }, - options - - //keep support for this way of calling C2S: new C2S(width,height) - if (arguments.length > 1) { - options = defaultOptions - options.width = arguments[0] - options.height = arguments[1] - } else if (!o) { - options = defaultOptions - } else { - options = o - } - - if (!(this instanceof ctx)) { - //did someone call this without new? - return new ctx(options) - } - - //setup options - this.width = options.width || defaultOptions.width - this.height = options.height || defaultOptions.height - this.enableMirroring = - options.enableMirroring !== undefined - ? options.enableMirroring - : defaultOptions.enableMirroring - - this.canvas = this ///point back to this instance! - this.__document = options.document || document - - // allow passing in an existing context to wrap around - // if a context is passed in, we know a canvas already exist - if (options.ctx) { - this.__ctx = options.ctx - } else { - this.__canvas = this.__document.createElement('canvas') - this.__ctx = this.__canvas.getContext('2d') - } - - this.__setDefaultStyles() - this.__stack = [this.__getStyleState()] - this.__groupStack = [] - - //the root svg element - this.__root = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg' - ) - this.__root.setAttribute('version', 1.1) - this.__root.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - this.__root.setAttributeNS( - 'http://www.w3.org/2000/xmlns/', - 'xmlns:xlink', - 'http://www.w3.org/1999/xlink' - ) - this.__root.setAttribute('width', this.width) - this.__root.setAttribute('height', this.height) - - //make sure we don't generate the same ids in defs - this.__ids = {} - - //defs tag - this.__defs = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'defs' - ) - this.__root.appendChild(this.__defs) - - //also add a group child. the svg element can't use the transform attribute - this.__currentElement = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'g' - ) - this.__root.appendChild(this.__currentElement) - } - - /** - * Creates the specified svg element - * @private - */ - ctx.prototype.__createElement = function ( - elementName, - properties, - resetFill - ) { - if (typeof properties === 'undefined') { - properties = {} - } - - var element = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - elementName - ), - keys = Object.keys(properties), - i, - key - if (resetFill) { - //if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black. - element.setAttribute('fill', 'none') - element.setAttribute('stroke', 'none') - } - for (i = 0; i < keys.length; i++) { - key = keys[i] - element.setAttribute(key, properties[key]) - } - return element - } - - /** - * Applies default canvas styles to the context - * @private - */ - ctx.prototype.__setDefaultStyles = function () { - //default 2d canvas context properties see:http://www.w3.org/TR/2dcontext/ - var keys = Object.keys(STYLES), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = STYLES[key].canvas - } - } - - /** - * Applies styles on restore - * @param styleState - * @private - */ - ctx.prototype.__applyStyleState = function (styleState) { - var keys = Object.keys(styleState), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = styleState[key] - } - } - - /** - * Gets the current style state - * @return {Object} - * @private - */ - ctx.prototype.__getStyleState = function () { - var i, - styleState = {}, - keys = Object.keys(STYLES), - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - styleState[key] = this[key] - } - return styleState - } - - /** - * Apples the current styles to the current SVG element. On "ctx.fill" or "ctx.stroke" - * @param type - * @private - */ - ctx.prototype.__applyStyleToCurrentElement = function (type) { - var currentElement = this.__currentElement - var currentStyleGroup = this.__currentElementsToStyle - if (currentStyleGroup) { - currentElement.setAttribute(type, '') - currentElement = currentStyleGroup.element - currentStyleGroup.children.forEach(function (node) { - node.setAttribute(type, '') - }) - } - - var keys = Object.keys(STYLES), - i, - style, - value, - id, - regex, - matches - for (i = 0; i < keys.length; i++) { - style = STYLES[keys[i]] - value = this[keys[i]] - if (style.apply) { - //is this a gradient or pattern? - if (value instanceof CanvasPattern) { - //pattern - if (value.__ctx) { - //copy over defs - while (value.__ctx.__defs.childNodes.length) { - id = - value.__ctx.__defs.childNodes[0].getAttribute( - 'id' - ) - this.__ids[id] = id - this.__defs.appendChild( - value.__ctx.__defs.childNodes[0] - ) - } - } - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if (value instanceof CanvasGradient) { - //gradient - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if ( - style.apply.indexOf(type) !== -1 && - style.svg !== value - ) { - if ( - (style.svgAttr === 'stroke' || - style.svgAttr === 'fill') && - value.indexOf('rgba') !== -1 - ) { - //separate alpha value, since illustrator can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(value) - currentElement.setAttribute( - style.svgAttr, - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - //should take globalAlpha here - var opacity = matches[4] - var globalAlpha = this.globalAlpha - if (globalAlpha != null) { - opacity *= globalAlpha - } - currentElement.setAttribute( - style.svgAttr + '-opacity', - opacity - ) - } else { - var attr = style.svgAttr - if (keys[i] === 'globalAlpha') { - attr = type + '-' + style.svgAttr - if (currentElement.getAttribute(attr)) { - //fill-opacity or stroke-opacity has already been set by stroke or fill. - continue - } - } - //otherwise only update attribute if right type, and not svg default - currentElement.setAttribute(attr, value) - } - } - } - } - } - - /** - * Will return the closest group or svg node. May return the current element. - * @private - */ - ctx.prototype.__closestGroupOrSvg = function (node) { - node = node || this.__currentElement - if (node.nodeName === 'g' || node.nodeName === 'svg') { - return node - } else { - return this.__closestGroupOrSvg(node.parentNode) - } - } - - /** - * Returns the serialized value of the svg so far - * @param fixNamedEntities - Standalone SVG doesn't support named entities, which document.createTextNode encodes. - * If true, we attempt to find all named entities and encode it as a numeric entity. - * @return serialized svg - */ - ctx.prototype.getSerializedSvg = function (fixNamedEntities) { - var serialized = new XMLSerializer().serializeToString(this.__root), - keys, - i, - key, - value, - regexp, - xmlns - - //IE search for a duplicate xmnls because they didn't implement setAttributeNS correctly - xmlns = - /xmlns="http:\/\/www\.w3\.org\/2000\/svg".+xmlns="http:\/\/www\.w3\.org\/2000\/svg/gi - if (xmlns.test(serialized)) { - serialized = serialized.replace( - 'xmlns="http://www.w3.org/2000/svg', - 'xmlns:xlink="http://www.w3.org/1999/xlink' - ) - } - - if (fixNamedEntities) { - keys = Object.keys(namedEntities) - //loop over each named entity and replace with the proper equivalent. - for (i = 0; i < keys.length; i++) { - key = keys[i] - value = namedEntities[key] - regexp = new RegExp(key, 'gi') - if (regexp.test(serialized)) { - serialized = serialized.replace(regexp, value) - } - } - } - - return serialized - } - - /** - * Returns the root svg - * @return - */ - ctx.prototype.getSvg = function () { - return this.__root - } - /** - * Will generate a group tag. - */ - ctx.prototype.save = function () { - var group = this.__createElement('g') - var parent = this.__closestGroupOrSvg() - this.__groupStack.push(parent) - parent.appendChild(group) - this.__currentElement = group - this.__stack.push(this.__getStyleState()) - } - /** - * Sets current element to parent, or just root if already root - */ - ctx.prototype.restore = function () { - this.__currentElement = this.__groupStack.pop() - this.__currentElementsToStyle = null - //Clearing canvas will make the poped group invalid, currentElement is set to the root group node. - if (!this.__currentElement) { - this.__currentElement = this.__root.childNodes[1] - } - var state = this.__stack.pop() - this.__applyStyleState(state) - } - - /** - * Helper method to add transform - * @private - */ - ctx.prototype.__addTransform = function (t) { - //if the current element has siblings, add another group - var parent = this.__closestGroupOrSvg() - if (parent.childNodes.length > 0) { - if (this.__currentElement.nodeName === 'path') { - if (!this.__currentElementsToStyle) - this.__currentElementsToStyle = { - element: parent, - children: [], - } - this.__currentElementsToStyle.children.push( - this.__currentElement - ) - this.__applyCurrentDefaultPath() - } - - var group = this.__createElement('g') - parent.appendChild(group) - this.__currentElement = group - } - - var transform = this.__currentElement.getAttribute('transform') - if (transform) { - transform += ' ' - } else { - transform = '' - } - transform += t - this.__currentElement.setAttribute('transform', transform) - } - - /** - * scales the current element - */ - ctx.prototype.scale = function (x, y) { - if (y === undefined) { - y = x - } - this.__addTransform(format('scale({x},{y})', { x: x, y: y })) - } - - /** - * rotates the current element - */ - ctx.prototype.rotate = function (angle) { - var degrees = (angle * 180) / Math.PI - this.__addTransform( - format('rotate({angle},{cx},{cy})', { - angle: degrees, - cx: 0, - cy: 0, - }) - ) - } - - /** - * translates the current element - */ - ctx.prototype.translate = function (x, y) { - this.__addTransform(format('translate({x},{y})', { x: x, y: y })) - } - - /** - * applies a transform to the current element - */ - ctx.prototype.transform = function (a, b, c, d, e, f) { - this.__addTransform( - format('matrix({a},{b},{c},{d},{e},{f})', { - a: a, - b: b, - c: c, - d: d, - e: e, - f: f, - }) - ) - } - - /** - * Create a new Path Element - */ - ctx.prototype.beginPath = function () { - var path, parent - - // Note that there is only one current default path, it is not part of the drawing state. - // See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path - this.__currentDefaultPath = '' - this.__currentPosition = {} - - path = this.__createElement('path', {}, true) - parent = this.__closestGroupOrSvg() - parent.appendChild(path) - this.__currentElement = path - } - - /** - * Helper function to apply currentDefaultPath to current path element - * @private - */ - ctx.prototype.__applyCurrentDefaultPath = function () { - var currentElement = this.__currentElement - if (currentElement.nodeName === 'path') { - currentElement.setAttribute('d', this.__currentDefaultPath) - } else { - console.error( - 'Attempted to apply path command to node', - currentElement.nodeName - ) - } - } - - /** - * Helper function to add path command - * @private - */ - ctx.prototype.__addPathCommand = function (command) { - this.__currentDefaultPath += ' ' - this.__currentDefaultPath += command - } - - /** - * Adds the move command to the current path element, - * if the currentPathElement is not empty create a new path element - */ - ctx.prototype.moveTo = function (x, y) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - - // creates a new subpath with the given point - this.__currentPosition = { x: x, y: y } - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } - - /** - * Closes the current path - */ - ctx.prototype.closePath = function () { - if (this.__currentDefaultPath) { - this.__addPathCommand('Z') - } - } - - /** - * Adds a line to command - */ - ctx.prototype.lineTo = function (x, y) { - this.__currentPosition = { x: x, y: y } - if (this.__currentDefaultPath.indexOf('M') > -1) { - this.__addPathCommand(format('L {x} {y}', { x: x, y: y })) - } else { - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } - } - - /** - * Add a bezier command - */ - ctx.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}', { - cp1x: cp1x, - cp1y: cp1y, - cp2x: cp2x, - cp2y: cp2y, - x: x, - y: y, - }) - ) - } - - /** - * Adds a quadratic curve to command - */ - ctx.prototype.quadraticCurveTo = function (cpx, cpy, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('Q {cpx} {cpy} {x} {y}', { cpx: cpx, cpy: cpy, x: x, y: y }) - ) - } - - /** - * Return a new normalized vector of given vector - */ - var normalize = function (vector) { - var len = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]) - return [vector[0] / len, vector[1] / len] - } - - /** - * Adds the arcTo to the current path - * - * @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto - */ - ctx.prototype.arcTo = function (x1, y1, x2, y2, radius) { - // Let the point (x0, y0) be the last point in the subpath. - var x0 = this.__currentPosition && this.__currentPosition.x - var y0 = this.__currentPosition && this.__currentPosition.y - - // First ensure there is a subpath for (x1, y1). - if (typeof x0 == 'undefined' || typeof y0 == 'undefined') { - return - } - - // Negative values for radius must cause the implementation to throw an IndexSizeError exception. - if (radius < 0) { - throw new Error( - 'IndexSizeError: The radius provided (' + - radius + - ') is negative.' - ) - } - - // If the point (x0, y0) is equal to the point (x1, y1), - // or if the point (x1, y1) is equal to the point (x2, y2), - // or if the radius radius is zero, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - if ( - (x0 === x1 && y0 === y1) || - (x1 === x2 && y1 === y2) || - radius === 0 - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - var unit_vec_p1_p0 = normalize([x0 - x1, y0 - y1]) - var unit_vec_p1_p2 = normalize([x2 - x1, y2 - y1]) - if ( - unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === - unit_vec_p1_p0[1] * unit_vec_p1_p2[0] - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius, - // and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1), - // and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2). - // The points at which this circle touches these two lines are called the start and end tangent points respectively. - - // note that both vectors are unit vectors, so the length is 1 - var cos = - unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + - unit_vec_p1_p0[1] * unit_vec_p1_p2[1] - var theta = Math.acos(Math.abs(cos)) - - // Calculate origin - var unit_vec_p1_origin = normalize([ - unit_vec_p1_p0[0] + unit_vec_p1_p2[0], - unit_vec_p1_p0[1] + unit_vec_p1_p2[1], - ]) - var len_p1_origin = radius / Math.sin(theta / 2) - var x = x1 + len_p1_origin * unit_vec_p1_origin[0] - var y = y1 + len_p1_origin * unit_vec_p1_origin[1] - - // Calculate start angle and end angle - // rotate 90deg clockwise (note that y axis points to its down) - var unit_vec_origin_start_tangent = [ - -unit_vec_p1_p0[1], - unit_vec_p1_p0[0], - ] - // rotate 90deg counter clockwise (note that y axis points to its down) - var unit_vec_origin_end_tangent = [ - unit_vec_p1_p2[1], - -unit_vec_p1_p2[0], - ] - var getAngle = function (vector) { - // get angle (clockwise) between vector and (1, 0) - var x = vector[0] - var y = vector[1] - if (y >= 0) { - // note that y axis points to its down - return Math.acos(x) - } else { - return -Math.acos(x) - } - } - var startAngle = getAngle(unit_vec_origin_start_tangent) - var endAngle = getAngle(unit_vec_origin_end_tangent) - - // Connect the point (x0, y0) to the start tangent point by a straight line - this.lineTo( - x + unit_vec_origin_start_tangent[0] * radius, - y + unit_vec_origin_start_tangent[1] * radius - ) - - // Connect the start tangent point to the end tangent point by arc - // and adding the end tangent point to the subpath. - this.arc(x, y, radius, startAngle, endAngle) - } - - /** - * Sets the stroke property on the current element - */ - ctx.prototype.stroke = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute( - 'paint-order', - 'fill stroke markers' - ) - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('stroke') - } - - /** - * Sets fill properties on the current element - */ - ctx.prototype.fill = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute( - 'paint-order', - 'stroke fill markers' - ) - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('fill') - } - - /** - * Adds a rectangle to the path. - */ - ctx.prototype.rect = function (x, y, width, height) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - this.moveTo(x, y) - this.lineTo(x + width, y) - this.lineTo(x + width, y + height) - this.lineTo(x, y + height) - this.lineTo(x, y) - this.closePath() - } - - /** - * adds a rectangle element - */ - ctx.prototype.fillRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('fill') - } - - /** - * Draws a rectangle with no fill - * @param x - * @param y - * @param width - * @param height - */ - ctx.prototype.strokeRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('stroke') - } - - /** - * Clear entire canvas: - * 1. save current transforms - * 2. remove all the childNodes of the root g element - */ - ctx.prototype.__clearCanvas = function () { - var current = this.__closestGroupOrSvg(), - transform = current.getAttribute('transform') - var rootGroup = this.__root.childNodes[1] - var childNodes = rootGroup.childNodes - for (var i = childNodes.length - 1; i >= 0; i--) { - if (childNodes[i]) { - rootGroup.removeChild(childNodes[i]) - } - } - this.__currentElement = rootGroup - //reset __groupStack as all the child group nodes are all removed. - this.__groupStack = [] - if (transform) { - this.__addTransform(transform) - } - } - - /** - * "Clears" a canvas by just drawing a white rectangle in the current group. - */ - ctx.prototype.clearRect = function (x, y, width, height) { - //clear entire canvas - if ( - x === 0 && - y === 0 && - width === this.width && - height === this.height - ) { - this.__clearCanvas() - return - } - var rect, - parent = this.__closestGroupOrSvg() - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - fill: '#FFFFFF', - }, - true - ) - parent.appendChild(rect) - } - - /** - * Adds a linear gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ - ctx.prototype.createLinearGradient = function (x1, y1, x2, y2) { - var grad = this.__createElement( - 'linearGradient', - { - id: randomString(this.__ids), - x1: x1 + 'px', - x2: x2 + 'px', - y1: y1 + 'px', - y2: y2 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) - } - - /** - * Adds a radial gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ - ctx.prototype.createRadialGradient = function (x0, y0, r0, x1, y1, r1) { - var grad = this.__createElement( - 'radialGradient', - { - id: randomString(this.__ids), - cx: x1 + 'px', - cy: y1 + 'px', - r: r1 + 'px', - fx: x0 + 'px', - fy: y0 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) - } - - /** - * Parses the font string and returns svg mapping - * @private - */ - ctx.prototype.__parseFont = function () { - var regex = - /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\'\"\sa-z0-9]+?)\s*$/i - var fontPart = regex.exec(this.font) - var data = { - style: fontPart[1] || 'normal', - size: fontPart[4] || '10px', - family: fontPart[6] || 'sans-serif', - weight: fontPart[3] || 'normal', - decoration: fontPart[2] || 'normal', - href: null, - } - - //canvas doesn't support underline natively, but we can pass this attribute - if (this.__fontUnderline === 'underline') { - data.decoration = 'underline' - } - - //canvas also doesn't support linking, but we can pass this as well - if (this.__fontHref) { - data.href = this.__fontHref - } - - return data - } - - /** - * Helper to link text fragments - * @param font - * @param element - * @return {*} - * @private - */ - ctx.prototype.__wrapTextLink = function (font, element) { - if (font.href) { - var a = this.__createElement('a') - a.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - font.href - ) - a.appendChild(element) - return a - } - return element - } - - /** - * Fills or strokes text - * @param text - * @param x - * @param y - * @param action - stroke or fill - * @private - */ - ctx.prototype.__applyText = function (text, x, y, action) { - var font = this.__parseFont(), - parent = this.__closestGroupOrSvg(), - textElement = this.__createElement( - 'text', - { - 'font-family': font.family, - 'font-size': font.size, - 'font-style': font.style, - 'font-weight': font.weight, - 'text-decoration': font.decoration, - x: x, - y: y, - 'text-anchor': getTextAnchor(this.textAlign), - 'dominant-baseline': getDominantBaseline(this.textBaseline), - }, - true - ) - - textElement.appendChild(this.__document.createTextNode(text)) - this.__currentElement = textElement - this.__applyStyleToCurrentElement(action) - parent.appendChild(this.__wrapTextLink(font, textElement)) - } - - /** - * Creates a text element - * @param text - * @param x - * @param y - */ - ctx.prototype.fillText = function (text, x, y) { - this.__applyText(text, x, y, 'fill') - } - - /** - * Strokes text - * @param text - * @param x - * @param y - */ - ctx.prototype.strokeText = function (text, x, y) { - this.__applyText(text, x, y, 'stroke') - } - - /** - * No need to implement this for svg. - * @param text - * @return {TextMetrics} - */ - ctx.prototype.measureText = function (text) { - this.__ctx.font = this.font - return this.__ctx.measureText(text) - } - - /** - * Arc command! - */ - ctx.prototype.arc = function ( - x, - y, - radius, - startAngle, - endAngle, - counterClockwise - ) { - // in canvas no circle is drawn if no angle is provided. - if (startAngle === endAngle) { - return - } - startAngle = startAngle % (2 * Math.PI) - endAngle = endAngle % (2 * Math.PI) - if (startAngle === endAngle) { - //circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle) - endAngle = - (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % - (2 * Math.PI) - } - var endX = x + radius * Math.cos(endAngle), - endY = y + radius * Math.sin(endAngle), - startX = x + radius * Math.cos(startAngle), - startY = y + radius * Math.sin(startAngle), - sweepFlag = counterClockwise ? 0 : 1, - largeArcFlag = 0, - diff = endAngle - startAngle - - // https://github.com/gliffy/canvas2svg/issues/4 - if (diff < 0) { - diff += 2 * Math.PI - } - - if (counterClockwise) { - largeArcFlag = diff > Math.PI ? 0 : 1 - } else { - largeArcFlag = diff > Math.PI ? 1 : 0 - } - - this.lineTo(startX, startY) - this.__addPathCommand( - format( - 'A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}', - { - rx: radius, - ry: radius, - xAxisRotation: 0, - largeArcFlag: largeArcFlag, - sweepFlag: sweepFlag, - endX: endX, - endY: endY, - } - ) - ) - - this.__currentPosition = { x: endX, y: endY } - } - - /** - * Generates a ClipPath from the clip command. - */ - ctx.prototype.clip = function () { - var group = this.__closestGroupOrSvg(), - clipPath = this.__createElement('clipPath'), - id = randomString(this.__ids), - newGroup = this.__createElement('g') - - this.__applyCurrentDefaultPath() - group.removeChild(this.__currentElement) - clipPath.setAttribute('id', id) - clipPath.appendChild(this.__currentElement) - - this.__defs.appendChild(clipPath) - - //set the clip path to this group - group.setAttribute('clip-path', format('url(#{id})', { id: id })) - - //clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations - // to this path - group.appendChild(newGroup) - - this.__currentElement = newGroup - } - - /** - * Draws a canvas, image or mock context to this canvas. - * Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support. - * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage - */ - ctx.prototype.drawImage = function () { - //convert arguments to a real array - var args = Array.prototype.slice.call(arguments), - image = args[0], - dx, - dy, - dw, - dh, - sx = 0, - sy = 0, - sw, - sh, - parent, - svg, - defs, - group, - currentElement, - svgImage, - canvas, - context, - id - - if (args.length === 3) { - dx = args[1] - dy = args[2] - sw = image.width - sh = image.height - dw = sw - dh = sh - } else if (args.length === 5) { - dx = args[1] - dy = args[2] - dw = args[3] - dh = args[4] - sw = image.width - sh = image.height - } else if (args.length === 9) { - sx = args[1] - sy = args[2] - sw = args[3] - sh = args[4] - dx = args[5] - dy = args[6] - dw = args[7] - dh = args[8] - } else { - throw new Error( - 'Invalid number of arguments passed to drawImage: ' + - arguments.length - ) - } - - parent = this.__closestGroupOrSvg() - currentElement = this.__currentElement - var translateDirective = 'translate(' + dx + ', ' + dy + ')' - if (image instanceof ctx) { - //canvas2svg mock canvas context. In the future we may want to clone nodes instead. - //also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context. - svg = image.getSvg().cloneNode(true) - if (svg.childNodes && svg.childNodes.length > 1) { - defs = svg.childNodes[0] - while (defs.childNodes.length) { - id = defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild(defs.childNodes[0]) - } - group = svg.childNodes[1] - if (group) { - //save original transform - var originTransform = group.getAttribute('transform') - var transformDirective - if (originTransform) { - transformDirective = - originTransform + ' ' + translateDirective - } else { - transformDirective = translateDirective - } - group.setAttribute('transform', transformDirective) - parent.appendChild(group) - } - } - } else if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - //canvas or image - svgImage = this.__createElement('image') - svgImage.setAttribute('width', dw) - svgImage.setAttribute('height', dh) - svgImage.setAttribute('preserveAspectRatio', 'none') - - if (sx || sy || sw !== image.width || sh !== image.height) { - //crop the image using a temporary canvas - canvas = this.__document.createElement('canvas') - canvas.width = dw - canvas.height = dh - context = canvas.getContext('2d') - context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh) - image = canvas - } - svgImage.setAttribute('transform', translateDirective) - svgImage.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - parent.appendChild(svgImage) - } - } - - /** - * Generates a pattern tag - */ - ctx.prototype.createPattern = function (image, repetition) { - var pattern = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'pattern' - ), - id = randomString(this.__ids), - img - pattern.setAttribute('id', id) - pattern.setAttribute('width', image.width) - pattern.setAttribute('height', image.height) - if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - img = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'image' - ) - img.setAttribute('width', image.width) - img.setAttribute('height', image.height) - img.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - pattern.appendChild(img) - this.__defs.appendChild(pattern) - } else if (image instanceof ctx) { - pattern.appendChild(image.__root.childNodes[1]) - this.__defs.appendChild(pattern) - } - return new CanvasPattern(pattern, this) - } - - ctx.prototype.setLineDash = function (dashArray) { - if (dashArray && dashArray.length > 0) { - this.lineDash = dashArray.join(',') - } else { - this.lineDash = null - } - } - - /** - * Not yet implemented - */ - ctx.prototype.drawFocusRing = function () {} - ctx.prototype.createImageData = function () {} - ctx.prototype.getImageData = function () {} - ctx.prototype.putImageData = function () {} - ctx.prototype.globalCompositeOperation = function () {} - ctx.prototype.setTransform = function () {} - - //add options for alternative namespace - if (typeof window === 'object') { - window.C2S = ctx - } - - // CommonJS/Browserify - if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = ctx - } -})() diff --git a/v0/src/store/SimulatorStore/actions.ts b/v0/src/store/SimulatorStore/actions.ts index e127bc5f..f5dee32b 100644 --- a/v0/src/store/SimulatorStore/actions.ts +++ b/v0/src/store/SimulatorStore/actions.ts @@ -5,12 +5,28 @@ export const useActions = defineStore('simulatorStore.actions', () => { const state = useState() function showTitle(): void { - console.log(state.title) + } + + function showMessage(message: string, type: 'error' | 'success') { + if (type === 'error') { + state.errorMessages.push(message) + } else { + state.successMessages.push(message) + } + + setTimeout(() => { + if (type === 'error') { + state.errorMessages.shift() + } else { + state.successMessages.shift() + } + }, type === 'error' ? 1500 : 2500) } // Note you are free to define as many internal functions as you want. // You only expose the functions that are returned. return { showTitle, + showMessage, } }) diff --git a/v0/src/store/SimulatorStore/state.ts b/v0/src/store/SimulatorStore/state.ts index 1bad89ad..cc57592f 100644 --- a/v0/src/store/SimulatorStore/state.ts +++ b/v0/src/store/SimulatorStore/state.ts @@ -3,16 +3,20 @@ import { defineStore } from 'pinia' // use camel case variable names export interface State { title: string - activeCircuit: - | Object - | { - id: number | string - name: string - } - circuit_list: Array + activeCircuit: { + id: number | string + name: string + } | undefined; + circuit_list: { + id: number | string + name: string + isVerilog?: boolean + focussed?: boolean + }[]; + errorMessages: string[] + successMessages: string[] + circuit_name_clickable: boolean; dialogBox: { - // create_circuit: boolean - // delete_circuit: boolean combinationalanalysis_dialog: boolean hex_bin_dec_converter_dialog: boolean saveimage_dialog: boolean @@ -25,8 +29,14 @@ export interface State { export_project_dialog: boolean import_project_dialog: boolean } - // createCircuit: Object | { circuitName: string } combinationalAnalysis: Object + subCircuitElementList: Array + isEmptySubCircuitElementList: boolean +} + +interface LayoutElementGroup { + type: string + elements: any[] } export const useState = defineStore({ @@ -35,11 +45,12 @@ export const useState = defineStore({ state: (): State => { return { title: 'Welcome to CircuitVerse Simulator', - activeCircuit: {}, + activeCircuit: undefined, circuit_list: [], + errorMessages: [], + successMessages: [], + circuit_name_clickable: false, dialogBox: { - // create_circuit: false, - // delete_circuit: false, combinationalanalysis_dialog: false, hex_bin_dec_converter_dialog: false, saveimage_dialog: false, @@ -52,15 +63,14 @@ export const useState = defineStore({ export_project_dialog: false, import_project_dialog: false, }, - // createCircuit: { - // circuitName: 'Untitled Circuit', - // }, combinationalAnalysis: { inputNameList: 'eg. In A, In B', outputNameList: 'eg. Out X, Out Y', booleanExpression: 'Example: (AB)', decimalColumnBox: false, }, + subCircuitElementList: [], + isEmptySubCircuitElementList: true, } }, -}) +}) \ No newline at end of file diff --git a/v0/src/store/authStore.ts b/v0/src/store/authStore.ts index 12dd433c..57c23043 100644 --- a/v0/src/store/authStore.ts +++ b/v0/src/store/authStore.ts @@ -4,6 +4,7 @@ interface AuthStoreType { isLoggedIn: boolean userId: string | number username: string + userAvatar: string locale: string isAdmin: boolean } @@ -13,6 +14,7 @@ interface UserInfo { id: string attributes: { name: string + profile_picture: string locale: string admin: boolean } @@ -22,7 +24,8 @@ export const useAuthStore = defineStore({ state: (): AuthStoreType => ({ isLoggedIn: false, userId: '', - username: '', + username: 'Guest', + userAvatar: 'default', locale: 'en', isAdmin: false, }), @@ -30,7 +33,11 @@ export const useAuthStore = defineStore({ setUserInfo(userInfo: UserInfo): void { this.isLoggedIn = true this.userId = userInfo.id ?? '' - this.username = userInfo.attributes.name ?? '' + this.username = userInfo.attributes.name ?? 'Guest' + if (userInfo.attributes.profile_picture != 'original/Default.jpg') { + this.userAvatar = + userInfo.attributes.profile_picture ?? 'default' + } this.locale = userInfo.attributes.locale ?? 'en' this.isAdmin = userInfo.attributes.admin }, @@ -45,6 +52,9 @@ export const useAuthStore = defineStore({ getUsername(): string { return this.username }, + getUserAvatar(): string { + return this.userAvatar + }, getLocale(): string { return this.locale }, diff --git a/v0/src/store/layoutStore.ts b/v0/src/store/layoutStore.ts new file mode 100644 index 00000000..6a6131b6 --- /dev/null +++ b/v0/src/store/layoutStore.ts @@ -0,0 +1,84 @@ +import { defineStore } from "pinia"; +import { ref, Ref, watch } from "vue"; + +export const useLayoutStore = defineStore("layoutStore", () => { + const layoutMode = ref(false); + const layoutDialogRef: Ref = ref(null); + const layoutElementPanelRef: Ref = ref(null); + const elementsPanelRef: Ref = ref(null); + const timingDiagramPanelRef: Ref = ref(null); + const testbenchPanelRef: Ref = ref(null); + + watch(layoutMode, (val) => { + if (val) { + fadeIn(layoutDialogRef.value); + fadeIn(layoutElementPanelRef.value); + fadeOut(elementsPanelRef.value); + fadeOut(timingDiagramPanelRef.value); + fadeOut(testbenchPanelRef.value); + } else { + fadeOut(layoutDialogRef.value); + fadeOut(layoutElementPanelRef.value); + fadeIn(elementsPanelRef.value); + fadeIn(timingDiagramPanelRef.value); + fadeIn(testbenchPanelRef.value); + } + }); + + function fadeIn(element: HTMLElement | null, duration = 200) { + if (!element) return; + element.style.display = "block"; + element.style.opacity = "0"; + let startTime: number | null = null; + + function animate(currentTime: number | null) { + if (!startTime) { + startTime = currentTime; + } + + const elapsedTime = (currentTime ?? 0) - (startTime ?? 0); + const newOpacity = elapsedTime / duration; + + element!.style.opacity = newOpacity > 1 ? "1" : newOpacity.toString(); + + if (elapsedTime < duration) { + requestAnimationFrame(animate); + } + } + + requestAnimationFrame(animate); + } + + function fadeOut(element: HTMLElement | null, duration = 200) { + if (!element) return; + let startTime: number | null = null; + + function animate(currentTime: number | null) { + if (!startTime) { + startTime = currentTime; + } + + const elapsedTime = (currentTime ?? 0) - (startTime ?? 0); + const newOpacity = 1 - elapsedTime / duration; + + element!.style.opacity = newOpacity < 0 ? "0" : newOpacity.toString(); + + if (elapsedTime < duration) { + requestAnimationFrame(animate); + } else { + element!.style.display = "none"; + } + } + + requestAnimationFrame(animate); + } + + return { + layoutMode, + layoutDialogRef, + layoutElementPanelRef, + elementsPanelRef, + timingDiagramPanelRef, + testbenchPanelRef, + }; +}); \ No newline at end of file diff --git a/v0/src/store/propertiesPanelStore.ts b/v0/src/store/propertiesPanelStore.ts new file mode 100644 index 00000000..07f4c462 --- /dev/null +++ b/v0/src/store/propertiesPanelStore.ts @@ -0,0 +1,24 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { tempBuffer } from "#/simulator/src/layoutMode"; + +export const usePropertiesPanelStore = defineStore("propertiesPanelStore", () => { + const inLayoutMode = ref(false) + const panelBodyHeader = ref('PROJECT PROPERTIES') + const propertiesPanelObj = ref(undefined) + const panelType = ref(1) // default is panel type 2 (project properties) + + // Layout + + const titleEnable = ref(tempBuffer?.layout?.titleEnabled) + const layoutDialogRef = ref(null); + + return { + inLayoutMode, + panelBodyHeader, + propertiesPanelObj, + panelType, + titleEnable, + layoutDialogRef, + }; +}); diff --git a/v0/src/store/simulatorMobileStore.ts b/v0/src/store/simulatorMobileStore.ts new file mode 100644 index 00000000..fcdb0e7c --- /dev/null +++ b/v0/src/store/simulatorMobileStore.ts @@ -0,0 +1,36 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; + +export type ElementsType = 'elements' | 'layout-elements' + +export const useSimulatorMobileStore = defineStore("simulatorMobileStore", () => { + const minWidthToShowMobile = ref(991); + const showMobileView = ref(false); + const showCanvas = ref(false); + const showTimingDiagram = ref(false); + const showElementsPanel = ref(false); + const showPropertiesPanel = ref(false); + const showQuickButtons = ref(true); + const showMobileButtons = ref(true); + const showVerilogPanel = ref(false); + const isCopy = ref(false); + const isVerilog = ref(false); + const showCircuits = ref('elements') + + showMobileView.value = window.innerWidth <= minWidthToShowMobile.value + + return { + minWidthToShowMobile, + showMobileView, + showCanvas, + showTimingDiagram, + showElementsPanel, + showPropertiesPanel, + showQuickButtons, + showMobileButtons, + showVerilogPanel, + isCopy, + isVerilog, + showCircuits, + }; +}); diff --git a/v0/src/store/testBenchStore.ts b/v0/src/store/testBenchStore.ts new file mode 100644 index 00000000..68f952a2 --- /dev/null +++ b/v0/src/store/testBenchStore.ts @@ -0,0 +1,105 @@ +import { defineStore } from "pinia"; +import { reactive, ref } from "vue"; +import { runTestBench } from "#/simulator/src/testbench"; + +export interface TestData { + type: string; + title: string; + groups: { + label: string; + inputs: { + label: string; + bitWidth: number; + values: string[]; + }[]; + outputs: { + label: string; + bitWidth: number; + values: string[]; + results?: string[]; + }[]; + n: number; + }[]; +} + +export interface TestBenchData { + testData: TestData; + currentGroup: number; + currentCase: number; + + isCaseValid?(): boolean; + setCase?(groupIndex: number, caseIndex: number): boolean; + groupNext?(): boolean; + groupPrev?(): boolean; + caseNext?(): boolean; + casePrev?(): boolean; + goToFirstValidGroup?(): boolean; +}; + +export interface ValidationErrors { + ok: boolean + invalids?: { + type: number + identifier: string + message: string + extraInfo?: any + }[] +} + +export interface Result { + value: string; + color: string; +} + +export const useTestBenchStore = defineStore("testBenchStore", () => { + const showTestBenchCreator = ref(false); + const showTestbenchUI = ref(false); + const showTestBenchValidator = ref(false); + const resultValues = ref([]); + const passed = ref(0); + const total = ref(0); + const showPassed = ref(false); + const showResults = ref(false); + const readOnly = ref(false); + + const testData = reactive({ + type: "", + title: "", + groups: [], + }); + + const testbenchData = reactive({ + testData: testData, + currentGroup: 0, + currentCase: 0, + }); + + const validationErrors: ValidationErrors = reactive({ + ok: true, + invalids: [] + }); + + const sendData = (dataValues: TestData) => { + showTestbenchUI.value = true; + testData.type = dataValues.type; + testData.title = dataValues.title; + testData.groups = dataValues.groups; + runTestBench(dataValues, globalScope, 0); + showTestBenchCreator.value = false; + } + + return { + showTestBenchCreator, + sendData, + testbenchData, + showTestbenchUI, + validationErrors, + showTestBenchValidator, + resultValues, + passed, + total, + showResults, + readOnly, + showPassed, + } +}) diff --git a/v0/src/store/timingDiagramPanelStore.ts b/v0/src/store/timingDiagramPanelStore.ts new file mode 100644 index 00000000..fbab4ace --- /dev/null +++ b/v0/src/store/timingDiagramPanelStore.ts @@ -0,0 +1,25 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import buttonsJSON from '#/assets/constants/Panels/TimingDiagramPanel/buttons.json' + +export interface TimingDiagramButton { + title: string + icon: string + class: string + type: string + click: string +} + +export const useTimingDiagramPanelStore = defineStore("timingDiagramPanelStore", () => { + const buttons = ref(buttonsJSON) + const plotRef = ref(null) + const cycleUnits = ref(1000) + const timingDiagramPanelRef = ref(null); + + return { + buttons, + plotRef, + cycleUnits, + timingDiagramPanelRef + }; +}); diff --git a/v0/src/styles/color_theme.scss b/v0/src/styles/color_theme.scss index 5bdc9fff..8b467c52 100644 --- a/v0/src/styles/color_theme.scss +++ b/v0/src/styles/color_theme.scss @@ -138,6 +138,11 @@ box-shadow: 0px 0px 10px #4545457f; } +.draggable-panel-mobile { + background: white; + box-shadow: 0px 0px 10px #4545457f; +} + .panel-header { color: var(--text-panel); background: var(--primary); @@ -223,7 +228,6 @@ #tabsBar { background-color: var(--bg-tabs); - border-top: 1px solid var(--br-primary); border-bottom: 1px solid var(--br-primary); } diff --git a/v0/src/styles/css/UX.css b/v0/src/styles/css/UX.css index e5011d8a..890d4cfa 100644 --- a/v0/src/styles/css/UX.css +++ b/v0/src/styles/css/UX.css @@ -642,31 +642,6 @@ div.icon img { display: inline-block; } -.img__description { - position: absolute; - /*top: 0;*/ - bottom: -16; - text-align: center; - left: 0; - right: 0; - background-color: #0099ff; - color: white; - font-size: 8px; - /*background: rgba(29, 106, 154, 0.72); - color: #fff;*/ - visibility: hidden; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - opacity: 0; - /* transition effect. not necessary */ - transition: opacity 0.2s, visibility 0.2s; -} - -.icon:hover .img__description { - visibility: visible; - opacity: 1; -} - .icon:hover { /*background-color: #cce5ff;*/ /*border-color: blue;*/ diff --git a/v0/src/styles/css/embed.css b/v0/src/styles/css/embed.css index ed09eb73..34517a8f 100644 --- a/v0/src/styles/css/embed.css +++ b/v0/src/styles/css/embed.css @@ -46,7 +46,8 @@ border-radius: 6px; opacity: 0.1; transition: 0.4s; - height: 109px; + height: auto; + gap: 1rem; display: flex; flex-direction: column; justify-content: space-between; @@ -259,3 +260,15 @@ button:focus { .embed-fullscreen-btn { border-radius: 20px; } + +#bottom_right_circuit_heading { + text-decoration: none; + position: fixed; + bottom: 1.5rem; + right: 2rem; + padding: 8px; + font-family: Verdana; + font-size: 12px; + color: var(--text-panel); + z-index: 2; +} diff --git a/v0/src/styles/css/main.stylesheet.css b/v0/src/styles/css/main.stylesheet.css index b487179b..b4dfabef 100644 --- a/v0/src/styles/css/main.stylesheet.css +++ b/v0/src/styles/css/main.stylesheet.css @@ -661,14 +661,6 @@ div.icon img { right: 10px; } -.layoutElementPanel { - width: 220px; - font: inherit; - display: none; - top: 90px; - left: 10px; -} - .timing-diagram-panel { border-radius: 5px; z-index: 70; @@ -801,10 +793,6 @@ div.icon img { width: 200px; } -.testbench-runall-label { - display: none; -} - .tb-dialog-button { display: inline; margin: 8px; @@ -1390,6 +1378,10 @@ input:checked + .slider:before { text-align: center; padding-top: 20px; } + + #moduleProperty-inner { + padding: 1rem; + } } /*! download dialog styling end here */ @@ -1517,12 +1509,14 @@ input:checked + .slider:before { #miniMap { position: fixed; z-index: 3; - bottom: 20px; - right: 40px; + bottom: -6rem; + right: 0.5rem; overflow-y: scroll; opacity: 0.5; overflow: hidden; border: none; + height: 15rem; + width: 18rem; } .disable::after { @@ -1764,9 +1758,17 @@ canvas { width: 800px; } +@media (max-width: 991px) { + #plot { + width: 100%; + } +} + .timing-diagram-toolbar { + display: flex; + align-items: center; + flex-wrap: wrap; padding-left: 4px; - padding: 2px; cursor: default; } @@ -1856,7 +1858,7 @@ canvas { margin-bottom: 0.5rem; } -/* +/* .ProseMirror ul { list-style-type: disc; } diff --git a/v0/src/styles/css/testCreator.css b/v0/src/styles/css/testCreator.css index 47877b3c..63bdd2f1 100644 --- a/v0/src/styles/css/testCreator.css +++ b/v0/src/styles/css/testCreator.css @@ -10,7 +10,7 @@ background-color: #ffffff; border: 2px solid black; color: black; - /*padding: 20px;*/ + padding: 6px; text-align: center; text-decoration: none; display: inline-block; diff --git a/v0/src/styles/simulator.scss b/v0/src/styles/simulator.scss index f6460422..a9940c15 100644 --- a/v0/src/styles/simulator.scss +++ b/v0/src/styles/simulator.scss @@ -23,10 +23,9 @@ $fa-font-path: '../../../node_modules/@fortawesome/fontawesome-free/webfonts'; position: fixed; right: -119px; text-decoration: none; - bottom: 30px; transition: 0.3s; width: 160px; - z-index: 999; + z-index: 99; } .report-sidebar span { diff --git a/v1/src/assets/constants/theme.ts b/v1/src/assets/constants/theme.ts new file mode 100644 index 00000000..d3dddd85 --- /dev/null +++ b/v1/src/assets/constants/theme.ts @@ -0,0 +1,17 @@ +export type ThemeType = { + 'default': string; + 'night-sky': string; + 'lite-born-spring': string; + 'g-and-w': string; + 'high-contrast': string; + 'color-blind': string; +}; + +export const THEME: ThemeType = { + 'default': 'Default Theme', + 'night-sky': 'Night Sky', + 'lite-born-spring': 'Lite-born Spring', + 'g-and-w': 'G&W', + 'high-contrast': 'High Contrast', + 'color-blind': 'Color Blind', +}; \ No newline at end of file diff --git a/v1/src/components/DialogBox/CombinationalAnalysis.vue b/v1/src/components/DialogBox/CombinationalAnalysis.vue index 3b4092a8..b4826594 100644 --- a/v1/src/components/DialogBox/CombinationalAnalysis.vue +++ b/v1/src/components/DialogBox/CombinationalAnalysis.vue @@ -23,21 +23,11 @@ import { stripTags } from '#/simulator/src/utils' import { useState } from '#/store/SimulatorStore/state' import messageBox from '@/MessageBox/messageBox.vue' -import { ref } from '@vue/reactivity' -import { onMounted, onUpdated } from '@vue/runtime-core' +import { ref } from 'vue' +import { onMounted } from 'vue' /* imports from combinationalAnalysis.js */ -import Node from '#/simulator/src/node' -import BooleanMinimize from '#/simulator/src/quinMcCluskey' -import Input from '#/simulator/src/modules/Input' -import ConstantVal from '#/simulator/src/modules/ConstantVal' -import Output from '#/simulator/src/modules/Output' -import AndGate from '#/simulator/src/modules/AndGate' -import OrGate from '#/simulator/src/modules/OrGate' -import NotGate from '#/simulator/src/modules/NotGate' -import simulationArea from '#/simulator/src/simulationArea' -import { findDimensions } from '#/simulator/src/canvasApi' -import { confirmSingleOption } from '../helpers/confirmComponent/ConfirmComponent.vue' +import { GenerateCircuit, solveBooleanFunction } from '#/simulator/src/combinationalAnalysis' const SimulatorState = useState() onMounted(() => { @@ -148,7 +138,7 @@ function dialogBoxConformation(selectedOption, circuitItem) { } if (selectedOption == 'generateCircuit') { SimulatorState.dialogBox.combinationalanalysis_dialog = false - generateCircuit() + GenerateCircuit() clearData() SimulatorState.dialogBox.combinationalanalysis_dialog = false } @@ -199,7 +189,7 @@ function createLogicTable() { SimulatorState.dialogBox.combinationalanalysis_dialog = false output.value = [] solveBooleanFunction(booleanInputVariables, booleanExpression) - if (output != null) { + if (output.value != null) { createBooleanPrompt(booleanInputVariables, booleanExpression) } } else if ( @@ -295,377 +285,6 @@ function createBooleanPrompt(inputList, outputList, scope = globalScope) { ] } -function generateBooleanTableData(outputListNames) { - var data = {} - for (var i = 0; i < outputListNames.length; i++) { - data[outputListNames[i]] = { - x: [], - 1: [], - 0: [], - } - var rows = $(`.${outputListNames[i]}`) - for (let j = 0; j < rows.length; j++) { - data[outputListNames[i]][rows[j].innerHTML].push(rows[j].id) - } - } - return data -} - -function drawCombinationalAnalysis( - combinationalData, - inputList, - outputList, - scope = globalScope -) { - findDimensions(scope) - var inputCount = inputList.length - var maxTerms = 0 - for (var i = 0; i < combinationalData.length; i++) { - maxTerms = Math.max(maxTerms, combinationalData[i].length) - } - - var startPosX = 200 - var startPosY = 200 - - var currentPosY = 300 - - if (simulationArea.maxWidth && simulationArea.maxHeight) { - if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { - startPosX += simulationArea.maxWidth - } else { - startPosY += simulationArea.maxHeight - currentPosY += simulationArea.maxHeight - } - } - var andPosX = startPosX + inputCount * 40 + 40 + 40 - var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80 - var outputPosX = orPosX + 60 - var inputObjects = [] - - var logixNodes = [] - - // Appending constant input to the end of inputObjects - for (var i = 0; i <= inputCount; i++) { - if (i < inputCount) { - // Regular Input - inputObjects.push( - new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1) - ) - inputObjects[i].setLabel(inputList[i]) - } else { - // Constant Input - inputObjects.push( - new ConstantVal( - startPosX + i * 40, - startPosY, - scope, - 'DOWN', - 1, - '1' - ) - ) - inputObjects[i].setLabel('_C_') - } - - inputObjects[i].newLabelDirection('UP') - var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root) - inputObjects[i].output1.connect(v1) - var v2 = new Node( - startPosX + i * 40 + 20, - startPosY + 20, - 2, - scope.root - ) - v1.connect(v2) - var notG = new NotGate( - startPosX + i * 40 + 20, - startPosY + 40, - scope, - 'DOWN', - 1 - ) - notG.inp1.connect(v2) - logixNodes.push(v1) - logixNodes.push(notG.output1) - } - - function countTerm(s) { - var c = 0 - for (var i = 0; i < s.length; i++) { - if (s[i] !== '-') c++ - } - return c - } - - for (var i = 0; i < combinationalData.length; i++) { - var andGateNodes = [] - for (var j = 0; j < combinationalData[i].length; j++) { - var c = countTerm(combinationalData[i][j]) - if (c > 1) { - var andGate = new AndGate( - andPosX, - currentPosY, - scope, - 'RIGHT', - c, - 1 - ) - andGateNodes.push(andGate.output1) - var misses = 0 - for (var k = 0; k < combinationalData[i][j].length; k++) { - if (combinationalData[i][j][k] == '-') { - misses++ - continue - } - var index = 2 * k + (combinationalData[i][j][k] == 0) - var v = new Node( - logixNodes[index].absX(), - andGate.inp[k - misses].absY(), - 2, - scope.root - ) - logixNodes[index].connect(v) - logixNodes[index] = v - v.connect(andGate.inp[k - misses]) - } - } else { - for (var k = 0; k < combinationalData[i][j].length; k++) { - if (combinationalData[i][j][k] == '-') continue - var index = 2 * k + (combinationalData[i][j][k] == 0) - var andGateSubstituteNode = new Node( - andPosX, - currentPosY, - 2, - scope.root - ) - var v = new Node( - logixNodes[index].absX(), - andGateSubstituteNode.absY(), - 2, - scope.root - ) - logixNodes[index].connect(v) - logixNodes[index] = v - v.connect(andGateSubstituteNode) - andGateNodes.push(andGateSubstituteNode) - } - } - currentPosY += c * 10 + 30 - } - - var andGateCount = andGateNodes.length - var midWay = Math.floor(andGateCount / 2) - var orGatePosY = - (andGateNodes[midWay].absY() + - andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / - 2 - if (orGatePosY % 10 == 5) { - orGatePosY += 5 - } // To make or gate fall in grid - if (andGateCount > 1) { - var o = new OrGate( - orPosX, - orGatePosY, - scope, - 'RIGHT', - andGateCount, - 1 - ) - if (andGateCount % 2 == 1) - andGateNodes[midWay].connect(o.inp[midWay]) - for (var j = 0; j < midWay; j++) { - var v = new Node( - andPosX + 30 + (midWay - j) * 10, - andGateNodes[j].absY(), - 2, - scope.root - ) - v.connect(andGateNodes[j]) - var v2 = new Node( - andPosX + 30 + (midWay - j) * 10, - o.inp[j].absY(), - 2, - scope.root - ) - v2.connect(v) - o.inp[j].connect(v2) - - var v = new Node( - andPosX + 30 + (midWay - j) * 10, - andGateNodes[andGateCount - j - 1].absY(), - 2, - scope.root - ) - v.connect(andGateNodes[andGateCount - j - 1]) - var v2 = new Node( - andPosX + 30 + (midWay - j) * 10, - o.inp[andGateCount - j - 1].absY(), - 2, - scope.root - ) - v2.connect(v) - o.inp[andGateCount - j - 1].connect(v2) - } - var out = new Output(outputPosX, o.y, scope, 'LEFT', 1) - out.inp1.connect(o.output1) - } else { - var out = new Output( - outputPosX, - andGateNodes[0].absY(), - scope, - 'LEFT', - 1 - ) - out.inp1.connect(andGateNodes[0]) - } - out.setLabel(outputList[i]) - out.newLabelDirection('RIGHT') - } - for (var i = 0; i < logixNodes.length; i++) { - if (logixNodes[i].absY() != currentPosY) { - var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root) - logixNodes[i].connect(v) - } - } - globalScope.centerFocus() -} - -/** - * This function solves passed boolean expression and returns - * output array which contains solution of the truth table - * of given boolean expression - * @param {Array} inputListNames - labels for input nodes - * @param {String} booleanExpression - boolean expression which is to be solved - */ -function solveBooleanFunction(inputListNames, booleanExpression) { - let i - let j - output.value = [] - - if ( - booleanExpression.match( - /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g - ) != null - ) { - // alert('One of the characters is not allowed.') - confirmSingleOption('One of the characters is not allowed.') - return - } - - if (inputListNames.length > 8) { - // alert('You can only have 8 variables at a time.') - confirmSingleOption('You can only have 8 variables at a time.') - return - } - var matrix = [] - for (i = 0; i < inputListNames.length; i++) { - matrix[i] = new Array(inputListNames.length) - } - - for (i = 0; i < inputListNames.length; i++) { - for (j = 0; j < 1 << inputListNames.length; j++) { - matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) - } - } - // generate equivalent expression by replacing input vars with possible combinations of o and 1 - for (i = 0; i < 2 ** inputListNames.length; i++) { - const data = [] - for (j = 0; j < inputListNames.length; j++) { - data[j] = - Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 - } - let equation = booleanExpression - for (j = 0; j < inputListNames.length; j++) { - equation = equation.replace( - new RegExp(inputListNames[j], 'g'), - data[j] - ) - } - - output.value[i] = solve(equation) - } - // generates solution for the truth table of booleanexpression - function solve(equation) { - while (equation.indexOf('(') != -1) { - const start = equation.lastIndexOf('(') - const end = equation.indexOf(')', start) - if (start != -1) { - equation = - equation.substring(0, start) + - solve(equation.substring(start + 1, end)) + - equation.substring(end + 1) - } - } - equation = equation.replace(/''/g, '') - equation = equation.replace(/0'/g, '1') - equation = equation.replace(/1'/g, '0') - for (let i = 0; i < equation.length - 1; i++) { - if ( - (equation[i] == '0' || equation[i] == '1') && - (equation[i + 1] == '0' || equation[i + 1] == '1') - ) { - equation = - equation.substring(0, i + 1) + - '*' + - equation.substring(i + 1, equation.length) - } - } - try { - const safeEval = eval - const answer = safeEval(equation) - if (answer == 0) { - return 0 - } - if (answer > 0) { - return 1 - } - return '' - } catch (e) { - return '' - } - } -} - -function generateCircuit() { - var data = generateBooleanTableData(outputListNamesInteger.value) - var minimizedCircuit = [] - let inputCount = inputListNames.value.length - for (const output in data) { - let oneCount = data[output][1].length // Number of ones - let zeroCount = data[output][0].length // Number of zeroes - if (oneCount == 0) { - // Hardcode to 0 as output - minimizedCircuit.push(['-'.repeat(inputCount) + '0']) - } else if (zeroCount == 0) { - // Hardcode to 1 as output - minimizedCircuit.push(['-'.repeat(inputCount) + '1']) - } else { - // Perform KMap like minimzation - const temp = new BooleanMinimize( - inputListNames.value.length, - data[output][1].map(Number), - data[output].x.map(Number) - ) - minimizedCircuit.push(temp.result) - } - } - if (output.value == null) { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames.value, - outputListNames.value, - globalScope - ) - } else { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames.value, - [`${outputListNames.value}`], - globalScope - ) - } -} - function printBooleanTable() { var sTable = $('.messageBox .v-card-text')[0].innerHTML @@ -673,7 +292,7 @@ function printBooleanTable() { ``.replace(/\n/g, "") var win = window.open('', '', 'height=700,width=700') var htmlBody = ` @@ -702,7 +321,7 @@ function printBooleanTable() { } - diff --git a/v1/src/components/DialogBox/ExportProject.vue b/v1/src/components/DialogBox/ExportProject.vue index 0da58f88..77645495 100644 --- a/v1/src/components/DialogBox/ExportProject.vue +++ b/v1/src/components/DialogBox/ExportProject.vue @@ -41,7 +41,7 @@ import { ref } from 'vue' import { useState } from '#/store/SimulatorStore/state' import { useProjectStore } from '#/store/projectStore' import { generateSaveData } from '#/simulator/src/data/save' -import { download } from '#/simulator/src/utils' +import { downloadFile } from '#/simulator/src/utils' import { escapeHtml } from '#/simulator/src/utils' export function ExportProject() { @@ -73,7 +73,7 @@ const exportAsFile = async () => { false ) fileName = `${fileName.replace(/[^a-z0-9]/gi, '_')}.cv` - download(fileName, circuitData) + downloadFile(fileName, circuitData) SimulatorState.dialogBox.export_project_dialog = false } diff --git a/v1/src/components/DialogBox/ExportVerilog.vue b/v1/src/components/DialogBox/ExportVerilog.vue index d826ad35..8bcaae12 100644 --- a/v1/src/components/DialogBox/ExportVerilog.vue +++ b/v1/src/components/DialogBox/ExportVerilog.vue @@ -43,7 +43,7 @@ \ No newline at end of file +import LayoutElementsPanel from './Panels/LayoutElementsPanel/LayoutElementsPanel.vue' +import TestBenchPanel from './Panels/TestBenchPanel/TestBenchPanel.vue' +import TestBenchCreator from './Panels/TestBenchPanel/TestBenchCreator.vue' +import TestBenchValidator from './Panels/TestBenchPanel/TestBenchValidator.vue' +import QuickButtonMobile from './Navbar/QuickButton/QuickButtonMobile.vue' +import TimingDiagramMobile from './Panels/TimingDiagramPanel/TimingDiagramMobile.vue' +import ElementsPanelMobile from './Panels/ElementsPanel/ElementsPanelMobile.vue' +import PropertiesPanelMobile from './Panels/PropertiesPanel/PropertiesPanelMobile.vue' +import { simulationArea } from '#/simulator/src/simulationArea' +import { paste } from '#/simulator/src/events' +import { panStart, panMove, panStop } from '#/simulator/src/listeners' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { useState } from '#/store/SimulatorStore/state' +import { reactive, ref, watch } from 'vue' + +const simulatorMobileStore = useSimulatorMobileStore() +const selectMultiple = ref(false) +const propertiesPanelPos = reactive({ + up: 22, + down: 14 +}); + +watch(() => simulatorMobileStore.isVerilog, (val) => { + if (val) { + propertiesPanelPos.up = 10 + propertiesPanelPos.down = 2 + } else { + propertiesPanelPos.up = 22 + propertiesPanelPos.down = 14 + } +}) + +const copyBtnClick = () => { + window.document.execCommand('copy') + simulationArea.shiftDown = false + simulatorMobileStore.isCopy = true +} + +const pasteBtnClick = () => { + paste(localStorage.getItem('clipboardData')); + simulatorMobileStore.isCopy = false +} + +const propertiesBtnClick = () => { + simulatorMobileStore.showPropertiesPanel = !simulatorMobileStore.showPropertiesPanel +} + + + diff --git a/v1/src/components/Logo/Logo.vue b/v1/src/components/Logo/Logo.vue index 56130b8c..48ef6c97 100644 --- a/v1/src/components/Logo/Logo.vue +++ b/v1/src/components/Logo/Logo.vue @@ -1,7 +1,7 @@ + + \ No newline at end of file diff --git a/v1/src/components/Navbar/Navbar.css b/v1/src/components/Navbar/Navbar.css index 0e5eb828..acdaef1a 100644 --- a/v1/src/components/Navbar/Navbar.css +++ b/v1/src/components/Navbar/Navbar.css @@ -1,4 +1,4 @@ -@import url('/v1/src/styles/color_theme.scss'); +@import url('/src/styles/color_theme.scss'); .navbar { background-color: var(--white); diff --git a/v1/src/components/Navbar/Navbar.vue b/v1/src/components/Navbar/Navbar.vue index caeec961..a1a4bcb5 100644 --- a/v1/src/components/Navbar/Navbar.vue +++ b/v1/src/components/Navbar/Navbar.vue @@ -1,9 +1,12 @@ diff --git a/v1/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue b/v1/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue new file mode 100644 index 00000000..19455127 --- /dev/null +++ b/v1/src/components/Navbar/NavbarLinks/NavbarLink/NavbarLink2.vue @@ -0,0 +1,121 @@ + + + + + + + \ No newline at end of file diff --git a/v1/src/components/Navbar/NavbarLinks/NavbarLinks.vue b/v1/src/components/Navbar/NavbarLinks/NavbarLinks.vue index 3c01a4dc..72241d76 100644 --- a/v1/src/components/Navbar/NavbarLinks/NavbarLinks.vue +++ b/v1/src/components/Navbar/NavbarLinks/NavbarLinks.vue @@ -5,12 +5,12 @@ :key="navbarItem.id" class="navbar-nav navbar-menu noSelect pointerCursor" > - + - diff --git a/v1/src/components/Navbar/QuickButton/QuickButtonMobile.vue b/v1/src/components/Navbar/QuickButton/QuickButtonMobile.vue new file mode 100644 index 00000000..6d9791b1 --- /dev/null +++ b/v1/src/components/Navbar/QuickButton/QuickButtonMobile.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/v1/src/components/Navbar/User/UserMenu.vue b/v1/src/components/Navbar/User/UserMenu.vue new file mode 100644 index 00000000..4d5c825f --- /dev/null +++ b/v1/src/components/Navbar/User/UserMenu.vue @@ -0,0 +1,190 @@ + + + + \ No newline at end of file diff --git a/v1/src/components/Panels/ElementsPanel/ElementsPanel.ts b/v1/src/components/Panels/ElementsPanel/ElementsPanel.ts new file mode 100644 index 00000000..66a6462e --- /dev/null +++ b/v1/src/components/Panels/ElementsPanel/ElementsPanel.ts @@ -0,0 +1,25 @@ +import { simulationArea } from "#/simulator/src/simulationArea" +import modules from "#/simulator/src/modules" +import { uxvar } from "#/simulator/src/ux" + +export function createElement(elementName: string) { + if (simulationArea.lastSelected?.newElement) + simulationArea.lastSelected.delete() + var obj = new modules[elementName]() + simulationArea.lastSelected = obj + uxvar.smartDropXX += 70 + if (uxvar.smartDropXX / globalScope.scale > width) { + uxvar.smartDropXX = 50 + uxvar.smartDropYY += 80 + } +} + +export function getImgUrl(elementName: string) { + try { + const elementImg = new URL(`../../../assets/img/${elementName}.svg`, import.meta.url).href; + return elementImg; + } catch (e) { + console.error("Error loading image:", e); + return ''; + } +} diff --git a/v1/src/components/Panels/ElementsPanel/ElementsPanel.vue b/v1/src/components/Panels/ElementsPanel/ElementsPanel.vue index e5c52896..8aac793c 100644 --- a/v1/src/components/Panels/ElementsPanel/ElementsPanel.vue +++ b/v1/src/components/Panels/ElementsPanel/ElementsPanel.vue @@ -1,6 +1,6 @@ diff --git a/v1/src/router/index.ts b/v1/src/router/index.ts index 730aea09..0a604dab 100644 --- a/v1/src/router/index.ts +++ b/v1/src/router/index.ts @@ -2,7 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router' import simulatorHandler from '../pages/simulatorHandler.vue' import Embed from '../pages/embed.vue' -const routes = [ +export const routes = [ { path: '/', redirect: '/simulatorvue', // @TODO: update later back to /simulator diff --git a/v1/src/simulator/spec/bitConvertor.spec.js b/v1/src/simulator/spec/bitConvertor.spec.js new file mode 100644 index 00000000..157db0c5 --- /dev/null +++ b/v1/src/simulator/spec/bitConvertor.spec.js @@ -0,0 +1,88 @@ +import { setup } from '../src/setup'; +import { bitConverterDialog, setBaseValues, setupBitConvertor } from '../src/utils'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('data dir working', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + // Open BitConvertor Dialog + test('bitConvertor Dialog working', () => { + expect(() => bitConverterDialog()).not.toThrow(); + }); + + test('function setupBitConvertor working', () => { + expect(() => setupBitConvertor()).not.toThrow(); + }); + + test('function setBaseValues working', () => { + const randomBaseValue = Math.floor(Math.random() * 100); + console.log('Testing for Base Value --> ', randomBaseValue); + expect(() => setBaseValues(randomBaseValue)).not.toThrow(); + }); +}); diff --git a/v1/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json b/v1/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json index bf601345..90b10612 100644 --- a/v1/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json +++ b/v1/src/simulator/spec/circuits/Decoders-plexers-circuitdata.json @@ -1,1109 +1,1337 @@ { - "name": "Decoders and Plexers", - "timePeriod": 500, - "clockEnabled": true, - "projectId": "RVvp1Qq4hf3eVcfUO7sE", - "focussedCircuit": 11597572508, - "orderedTabs": ["11597572508"], - "scopes": [ - { - "layout": { - "width": 100, - "height": 280, - "title_x": 50, - "title_y": 13, - "titleEnabled": true + "name": "Decoder&Plexers", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "hWmIAEfeaUjXbtHfKS15", + "focussedCircuit": 11597572508, + "orderedTabs": [ + "11597572508" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 540, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Control Signal", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 970, + "y": -60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 9 + ] + }, + { + "x": 560, + "y": -60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 17, + 29 + ] + }, + { + "x": 560, + "y": 590, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": -10, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": -10, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Control Signal", + "connections": [ + 17 + ] + }, + { + "x": 860, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 16, + 20 + ] + }, + { + "x": 860, + "y": 30, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 15 + ] + }, + { + "x": 560, + "y": 50, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 10, + 14 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 820, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 15, + 37 + ] + }, + { + "x": 780, + "y": -130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 6, + 25 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": -10, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": -10, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 780, + "y": 410, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 31 + ] + }, + { + "x": 820, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 37 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 560, + "y": -190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 9 + ] + }, + { + "x": -10, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 30, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 30, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 10, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 820, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 26, + 30 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "Input", + "connections": [ + 60 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Output", + "connections": [ + 47 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "2", + "label": "Bit Selector", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "2", + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 20, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 250, + "y": 290, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 48, + 57, + 60 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 49 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 20, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 250, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 51, + 54 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 56 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 43, + 51 + ] + } + ], + "id": 11597572508, + "name": "Main", + "Input": [ + { + "x": 480, + "y": -190, + "objectType": "Input", + "label": "s", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 4 }, - "verilogMetadata": { - "isVerilogCircuit": false, - "isMainCircuit": false, - "code": "// Write Some Verilog Code Here!", - "subCircuitScopeIds": [] + "values": { + "state": 1 }, - "allNodes": [ - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [14] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [5] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [6] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Control Signal", - "connections": [24] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [14] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [1] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [2] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [15] - }, - { - "x": -10, - "y": -10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [12] - }, - { - "x": -10, - "y": 10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [13] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Control Signal", - "connections": [11] - }, - { - "x": 80, - "y": 510, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [10, 25] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [8] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [9] - }, - { - "x": -30, - "y": 130, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [0, 4, 15] - }, - { - "x": -30, - "y": 340, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [7, 14] - }, - { - "x": -20, - "y": 0, - "type": 0, - "bitWidth": 2, - "label": "Input", - "connections": [20] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "Output", - "connections": [19] - }, - { - "x": 0, - "y": 20, - "type": 0, - "bitWidth": 1, - "label": "Bit Selector", - "connections": [26] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [17] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 2, - "label": "", - "connections": [16] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [22] - }, - { - "x": -180, - "y": 160, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [21, 23] - }, - { - "x": -180, - "y": 220, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [22, 24, 25] - }, - { - "x": 90, - "y": 220, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [3, 23] - }, - { - "x": -180, - "y": 510, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [11, 23, 27] - }, - { - "x": 70, - "y": 700, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [18, 27] - }, - { - "x": -180, - "y": 700, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [25, 26] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [33] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [32] - }, - { - "x": 20, - "y": 20, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [30] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [28] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [39] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [37] - }, - { - "x": 20, - "y": 20, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [38] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [35] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [36] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [34] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [46] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [47] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [45] - }, - { - "x": 10, - "y": 30, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [44] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [43] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [42] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [40] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [41] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [53] - }, - { - "x": -10, - "y": -10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [51] - }, - { - "x": -10, - "y": 10, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [52] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [49] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [50] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [48] - } - ], - "id": 11597572508, - "name": "Main", - "Input": [ - { - "x": -70, - "y": 130, - "objectType": "Input", - "label": "inp1", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 4 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 60, - "id": "cZW4OLLsTA1aBoRSmHxv" - } - ] - } - }, - { - "x": -70, - "y": 150, - "objectType": "Input", - "label": "inp2", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 5 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 20, - "id": "OhBFKFzir02JVzBVOV44" - } - ] - } - }, - { - "x": -30, - "y": 630, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 20 - }, - "values": { - "state": 3 - }, - "constructorParamaters": [ - "RIGHT", - 2, - { - "x": 0, - "y": 120, - "id": "Tci49l79hiLHSfxqSPhk" - } - ] - } - }, - { - "x": -360, - "y": 160, - "objectType": "Input", - "label": "s", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 21 - }, - "values": { - "state": 0 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 40, - "id": "2jYcmNNFpmoq6jcELh8X" - } - ] - } - }, - { - "x": -10, - "y": 840, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 33 - }, - "values": { - "state": 0 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 80, - "id": "wUbTZgbmrEStf17qxgOw" - } - ] - } - }, - { - "x": 0, - "y": 1030, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 39 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 100, - "id": "hiFGtGajuArxucFOfydA" - } - ] - } - }, - { - "x": -550, - "y": 310, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 46 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 140, - "id": "6br60gi40FN03qZRFG9W" - } - ] - } - }, - { - "x": -550, - "y": 330, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 47 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 160, - "id": "EcNRmJVcoyFZdMUmGwQw" - } - ] - } - }, - { - "x": -600, - "y": 680, - "objectType": "Input", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 53 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 180, - "id": "eAluIwGbrt2vmFD37xUb" - } - ] - } - } - ], - "Output": [ - { - "x": 250, - "y": 140, - "objectType": "Output", - "label": "out1", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 6 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 40, - "id": "PQtMRkU1V36zoiUZaKnC" - } - ] - } - }, - { - "x": 340, - "y": 330, - "objectType": "Output", - "label": "out3", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 12 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 20, - "id": "rl7YenrdGRoBr9BXA2Ee" - } - ] - } - }, - { - "x": 340, - "y": 350, - "objectType": "Output", - "label": "out4", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 13 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 60, - "id": "gPrg5glyUDxsQmGldTow" - } - ] - } - }, - { - "x": 260, - "y": 630, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 19 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 80, - "id": "qqnDrlsm0T8y1dyyiGlL" - } - ] - } - }, - { - "x": 270, - "y": 860, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 31 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 120, - "id": "2smYfkmptbhEZ2gFBMmf" - } - ] - } - }, - { - "x": 270, - "y": 840, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 32 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 100, - "id": "45NWNA9b3l54VZE5cFYS" - } - ] - } - }, - { - "x": 220, - "y": 1030, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 37 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 140, - "id": "COIaU2CIfnmcZ8h0Nxpq" - } - ] - } - }, - { - "x": 220, - "y": 1050, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 38 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 160, - "id": "bJ7CLsYt9Johbanua2d4" - } - ] - } - }, - { - "x": -460, - "y": 400, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 44 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 180, - "id": "Of7qPmfBvyW9mhiLkfpN" - } - ] - } - }, - { - "x": -290, - "y": 320, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 45 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 200, - "id": "LLwXovDSOe6rplHPIDhv" - } - ] - } - }, - { - "x": -310, - "y": 670, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 51 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 220, - "id": "Yo4Zo5P6gClWQJZWt5DF" - } - ] - } - }, - { - "x": -310, - "y": 690, - "objectType": "Output", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 52 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 240, - "id": "T86CxN5DtKbZtDaZXSMx" - } - ] - } - } - ], - "Multiplexer": [ - { - "x": 90, - "y": 140, - "objectType": "Multiplexer", - "label": "multiplexer", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 1, 1], - "nodes": { - "inp": [0, 1], - "output1": 2, - "controlSignalInput": 3 - } - } - } - ], - "BitSelector": [ - { - "x": 70, - "y": 630, - "objectType": "BitSelector", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 16, - "output1": 17, - "bitSelectorInp": 18 - }, - "constructorParamaters": ["RIGHT", 2, 1] - } - } - ], - "Demultiplexer": [ - { - "x": 80, - "y": 340, - "objectType": "Demultiplexer", - "label": "demultiplexer", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["LEFT", 1, 1], - "nodes": { - "output1": [8, 9], - "input": 7, - "controlSignalInput": 10 - } - } - } - ], - "MSB": [ - { - "x": 70, - "y": 840, - "objectType": "MSB", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 28, - "output1": 29, - "enable": 30 - }, - "constructorParamaters": ["RIGHT", 1] - } - } - ], - "LSB": [ - { - "x": 70, - "y": 1030, - "objectType": "LSB", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": 34, - "output1": 35, - "enable": 36 - }, - "constructorParamaters": ["RIGHT", 1] - } - } + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "af8X6iUZ1TNVcEuYsobR" + } + ] + } + }, + { + "x": 730, + "y": -150, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 80, + "id": "AHg5Ngs8KrHtKKUUBv5o" + } + ] + } + }, + { + "x": 730, + "y": -130, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "0uCn6zjaOWINyTt3INWL" + } + ] + } + }, + { + "x": 750, + "y": 430, + "objectType": "Input", + "label": "inp3", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 38 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "OjD26bycgCZOCebnr0Ta" + } + ] + } + }, + { + "x": 750, + "y": 450, + "objectType": "Input", + "label": "inp4", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 39 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 100, + "id": "YdXUBNPghcKOcTzkSNxJ" + } + ] + } + }, + { + "x": 300, + "y": 110, + "objectType": "Input", + "label": "CS", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 46 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "UP", + "2", + { + "x": 0, + "y": 120, + "id": "W3XYx9tc8fIFjVMFNfU4" + } + ] + } + }, + { + "x": 210, + "y": 20, + "objectType": "Input", + "label": "inp5", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 60 + }, + "values": { + "state": 8 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 140, + "id": "fKHb7DuWJcS9KM2fSxKT" + } + ] + } + } + ], + "Output": [ + { + "x": 1130, + "y": -140, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 7 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 280, + "id": "qkQ6ZVtFDuQN5LjoFSAx" + } + ] + } + }, + { + "x": 1130, + "y": 20, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 18 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "vRfw4YkouGy4laNyoTHO" + } + ] + } + }, + { + "x": 1130, + "y": 40, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 19 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "m1fSssWAIUVKndqPS8U1" + } + ] + } + }, + { + "x": 1040, + "y": 610, + "objectType": "Output", + "label": "out11", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 27 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 260, + "id": "uN0pAvVNRJQlNB4Vc9o0" + } + ] + } + }, + { + "x": 1040, + "y": 630, + "objectType": "Output", + "label": "out12", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 28 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "5UVbtIsq3uzOx0b1RtVW" + } + ] + } + }, + { + "x": 940, + "y": 540, + "objectType": "Output", + "label": "en", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 40 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 220, + "id": "2xTmvrisBijPkcsbt8lX" + } + ] + } + }, + { + "x": 1090, + "y": 410, + "objectType": "Output", + "label": "out9", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 41 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "Jh30ULWWwan7JgfJXssO" + } + ] + } + }, + { + "x": 1090, + "y": 430, + "objectType": "Output", + "label": "out10", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 42 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "3RzXrQjoiihgZROY8zOw" + } + ] + } + }, + { + "x": 440, + "y": 20, + "objectType": "Output", + "label": "out13", + "direction": "LEFT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 47 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 240, + "id": "i9MpQKKTbqxk9t7uOyol" + } + ] + } + }, + { + "x": 430, + "y": 290, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 52 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 60, + "id": "Nl8jdW1Ovj3hvi0lyLd6" + } + ] + } + }, + { + "x": 400, + "y": 310, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 53 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "lSTBjSRHvf3uvq8AI5FR" + } + ] + } + }, + { + "x": 380, + "y": 410, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 58 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 100, + "id": "xfXE7U7J0IRm1FVEzw3I" + } + ] + } + }, + { + "x": 350, + "y": 430, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "0tRtiePfdUKapjpaz8uy" + } + ] + } + } + ], + "Multiplexer": [ + { + "x": 970, + "y": -140, + "objectType": "Multiplexer", + "label": "Multiplexer", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1, + 1 ], - "PriorityEncoder": [ - { - "x": -480, - "y": 320, - "objectType": "PriorityEncoder", - "label": "", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "nodes": { - "inp1": [40, 41], - "output1": [42], - "enable": 43 - }, - "constructorParamaters": ["RIGHT", 1] - } - } + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2, + "controlSignalInput": 3 + } + } + } + ], + "BitSelector": [ + { + "x": 300, + "y": 20, + "objectType": "BitSelector", + "label": "bit-selector", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 43, + "output1": 44, + "bitSelectorInp": 45 + }, + "constructorParamaters": [ + "RIGHT", + "4", + "2" + ] + } + } + ], + "Demultiplexer": [ + { + "x": 980, + "y": 30, + "objectType": "Demultiplexer", + "label": "Demultiplexer", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1, + 1 ], - "Decoder": [ - { - "x": -480, - "y": 680, - "objectType": "Decoder", - "label": "", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["LEFT", 1], - "nodes": { - "output1": [49, 50], - "input": 48 - } - } - } + "nodes": { + "output1": [ + 12, + 13 + ], + "input": 11, + "controlSignalInput": 14 + } + } + } + ], + "MSB": [ + { + "x": 320, + "y": 290, + "objectType": "MSB", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 48, + "output1": 49, + "enable": 50 + }, + "constructorParamaters": [ + "RIGHT", + 4 + ] + } + } + ], + "LSB": [ + { + "x": 320, + "y": 410, + "objectType": "LSB", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": 54, + "output1": 55, + "enable": 56 + }, + "constructorParamaters": [ + "RIGHT", + 4 + ] + } + } + ], + "PriorityEncoder": [ + { + "x": 920, + "y": 420, + "objectType": "PriorityEncoder", + "label": "priority encoder", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "nodes": { + "inp1": [ + 30, + 31, + 32, + 33 + ], + "output1": [ + 34, + 35 + ], + "enable": 36 + }, + "constructorParamaters": [ + "RIGHT", + 2 + ] + } + } + ], + "Decoder": [ + { + "x": 950, + "y": 620, + "objectType": "Decoder", + "label": "Decoder", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1 ], - "restrictedCircuitElementsUsed": [], - "nodes": [11, 14, 15, 22, 23, 24, 25, 26, 27] + "nodes": { + "output1": [ + 23, + 24 + ], + "input": 22 + } + } } - ] + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 8, + 9, + 10, + 15, + 16, + 17, + 20, + 21, + 25, + 26, + 29, + 37, + 51, + 57 + ] + } + ] } diff --git a/v1/src/simulator/spec/circuits/alu-circuitdata.json b/v1/src/simulator/spec/circuits/alu-circuitdata.json new file mode 100644 index 00000000..cd350e17 --- /dev/null +++ b/v1/src/simulator/spec/circuits/alu-circuitdata.json @@ -0,0 +1,8377 @@ +{ + "name": "ALU-74LS181", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "eWFjA0GCvFw4aqbmWcc4", + "focussedCircuit": 33755305138, + "orderedTabs": [ + "33755305138", + "35784513673" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 300, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 750, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 6, + 73 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 740, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 22, + 24 + ] + }, + { + "x": 650, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 25, + 39 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 650, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 28, + 29 + ] + }, + { + "x": 620, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 27 + ] + }, + { + "x": 690, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 27 + ] + }, + { + "x": 700, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 9, + 82 + ] + }, + { + "x": 540, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 33 + ] + }, + { + "x": 520, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 33 + ] + }, + { + "x": 530, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 32, + 34 + ] + }, + { + "x": 530, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 35, + 37 + ] + }, + { + "x": 710, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 10, + 34, + 36 + ] + }, + { + "x": 730, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 35 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 580, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 16, + 90 + ] + }, + { + "x": 560, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 24 + ] + }, + { + "x": 600, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 12, + 92 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 366 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 49 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 364 + ] + }, + { + "x": 530, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 49 + ] + }, + { + "x": 560, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 48 + ] + }, + { + "x": 580, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 46, + 51 + ] + }, + { + "x": 610, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 50 + ] + }, + { + "x": 700, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 53 + ] + }, + { + "x": 710, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 52 + ] + }, + { + "x": 740, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 55 + ] + }, + { + "x": 730, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 54 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 88 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 73 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 106 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 81 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 82 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 87 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 104 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 92 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 80 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 103 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 91 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 90 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 97 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 84 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 83 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 100 + ] + }, + { + "x": 450, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 58, + 125 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 440, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 57, + 74, + 76 + ] + }, + { + "x": 350, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 75, + 77, + 91 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 79 + ] + }, + { + "x": 350, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 78, + 80, + 81 + ] + }, + { + "x": 320, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 65, + 79 + ] + }, + { + "x": 390, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 60, + 79 + ] + }, + { + "x": 400, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 61, + 134 + ] + }, + { + "x": 240, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 71, + 85 + ] + }, + { + "x": 220, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 70, + 85 + ] + }, + { + "x": 230, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 83, + 84, + 86 + ] + }, + { + "x": 230, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 85, + 87, + 89 + ] + }, + { + "x": 410, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 62, + 86, + 88 + ] + }, + { + "x": 430, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 87 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 86 + ] + }, + { + "x": 280, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 68, + 142 + ] + }, + { + "x": 260, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 67, + 76 + ] + }, + { + "x": 300, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 40, + 64, + 144 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 105 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 107 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 352 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 101 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 69 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 102 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 353 + ] + }, + { + "x": 230, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 72, + 101 + ] + }, + { + "x": 260, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 96, + 100 + ] + }, + { + "x": 280, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 98, + 103 + ] + }, + { + "x": 310, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 66, + 102 + ] + }, + { + "x": 400, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 63, + 105 + ] + }, + { + "x": 410, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 93, + 104 + ] + }, + { + "x": 440, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 59, + 107 + ] + }, + { + "x": 430, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 94, + 106 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 140 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 127 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 125 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 158 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 133 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 134 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 139 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 156 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 144 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 132 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 155 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 143 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 142 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 149 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 136 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 135 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 152 + ] + }, + { + "x": 150, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 73, + 110, + 177 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 127 + ] + }, + { + "x": 140, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 109, + 126, + 128 + ] + }, + { + "x": 50, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 127, + 129, + 143 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 128 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 131 + ] + }, + { + "x": 50, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 130, + 132, + 133 + ] + }, + { + "x": 20, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 117, + 131 + ] + }, + { + "x": 90, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 112, + 131 + ] + }, + { + "x": 100, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 82, + 113, + 186 + ] + }, + { + "x": -60, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 123, + 137 + ] + }, + { + "x": -80, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 122, + 137 + ] + }, + { + "x": -70, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 135, + 136, + 138 + ] + }, + { + "x": -70, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 137, + 139, + 141 + ] + }, + { + "x": 110, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 114, + 138, + 140 + ] + }, + { + "x": 130, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 108, + 139 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 138 + ] + }, + { + "x": -20, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 90, + 120, + 194 + ] + }, + { + "x": -40, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 119, + 128 + ] + }, + { + "x": 0, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 92, + 116, + 196 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 157 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 159 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 347 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 153 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 121 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 154 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 348 + ] + }, + { + "x": -70, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 124, + 153 + ] + }, + { + "x": -40, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 148, + 152 + ] + }, + { + "x": -20, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 150, + 155 + ] + }, + { + "x": 10, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 118, + 154 + ] + }, + { + "x": 100, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 115, + 157 + ] + }, + { + "x": 110, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 145, + 156 + ] + }, + { + "x": 140, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 111, + 159 + ] + }, + { + "x": 130, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 146, + 158 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 192 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 179 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 177 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 210 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 185 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 186 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 191 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 208 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 196 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 184 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 207 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 195 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 194 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 201 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 188 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 187 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 204 + ] + }, + { + "x": -140, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 125, + 162 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 179 + ] + }, + { + "x": -150, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 161, + 178, + 180 + ] + }, + { + "x": -240, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 179, + 181, + 195 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 180 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 183 + ] + }, + { + "x": -240, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 182, + 184, + 185 + ] + }, + { + "x": -270, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 169, + 183 + ] + }, + { + "x": -200, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 164, + 183 + ] + }, + { + "x": -190, + "y": 160, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 134, + 165 + ] + }, + { + "x": -350, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 175, + 189 + ] + }, + { + "x": -370, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 174, + 189 + ] + }, + { + "x": -360, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 187, + 188, + 190 + ] + }, + { + "x": -360, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 189, + 191, + 193 + ] + }, + { + "x": -180, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 166, + 190, + 192 + ] + }, + { + "x": -160, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 160, + 191 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 190 + ] + }, + { + "x": -310, + "y": 120, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 142, + 172 + ] + }, + { + "x": -330, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 171, + 180 + ] + }, + { + "x": -290, + "y": 140, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 144, + 168 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 209 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 211 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 246 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 205 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 173 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 206 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 253 + ] + }, + { + "x": -360, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 176, + 205 + ] + }, + { + "x": -330, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 200, + 204 + ] + }, + { + "x": -310, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 202, + 207 + ] + }, + { + "x": -280, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 170, + 206 + ] + }, + { + "x": -190, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 167, + 209 + ] + }, + { + "x": -180, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 197, + 208 + ] + }, + { + "x": -150, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 163, + 211 + ] + }, + { + "x": -160, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 198, + 210 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 214 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 235 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 212 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 238 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 238 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 235 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 219 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 218 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 232 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 290 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 236 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 237 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 228 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 229 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 230 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 248 + ] + }, + { + "x": -310, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 224, + 229 + ] + }, + { + "x": -300, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 225, + 228 + ] + }, + { + "x": -280, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 226, + 231 + ] + }, + { + "x": -270, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 230, + 244 + ] + }, + { + "x": -440, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 220, + 233 + ] + }, + { + "x": -370, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 232, + 439 + ] + }, + { + "x": -380, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 253, + 437 + ] + }, + { + "x": -450, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 213, + 217, + 236 + ] + }, + { + "x": -320, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 222, + 235, + 240 + ] + }, + { + "x": -300, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 223, + 253, + 283 + ] + }, + { + "x": -470, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 215, + 216, + 239 + ] + }, + { + "x": -280, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 238, + 241, + 456 + ] + }, + { + "x": -270, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 236, + 242, + 268 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 239 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 240 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 245 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 231 + ] + }, + { + "x": -260, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 243, + 247, + 246 + ] + }, + { + "x": -170, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 199, + 245, + 271 + ] + }, + { + "x": -360, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 245, + 438 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 227 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 257 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 294 + ] + }, + { + "x": -140, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 348, + 440 + ] + }, + { + "x": -120, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 284, + 441 + ] + }, + { + "x": -320, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 203, + 234, + 237 + ] + }, + { + "x": 830, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "3", + "connections": [ + 361, + 397 + ] + }, + { + "x": 880, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "4", + "connections": [ + 387, + 401 + ] + }, + { + "x": 870, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "1", + "connections": [ + 357, + 402 + ] + }, + { + "x": -270, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 249, + 258 + ] + }, + { + "x": -130, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 257, + 442 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 290 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 294 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 269 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 283 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 284 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 276 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 268 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 282 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 279 + ] + }, + { + "x": -40, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 240, + 265, + 269 + ] + }, + { + "x": 0, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 261, + 268, + 270 + ] + }, + { + "x": 30, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 269, + 342, + 452 + ] + }, + { + "x": 60, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 246, + 349, + 453 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 278 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 305 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 298 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 280 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 264 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 281 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 272 + ] + }, + { + "x": -30, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 267, + 280 + ] + }, + { + "x": 0, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 275, + 279 + ] + }, + { + "x": 20, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 277, + 458 + ] + }, + { + "x": -20, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 266, + 348, + 361 + ] + }, + { + "x": 10, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 237, + 262, + 357 + ] + }, + { + "x": 20, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 252, + 263, + 457 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 297 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 293 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 301 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 302 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 307 + ] + }, + { + "x": -450, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 221, + 259, + 291 + ] + }, + { + "x": -180, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 290, + 292 + ] + }, + { + "x": -180, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 291, + 293 + ] + }, + { + "x": -150, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 286, + 292 + ] + }, + { + "x": -280, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 250, + 260, + 295 + ] + }, + { + "x": -190, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 294, + 296 + ] + }, + { + "x": -190, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 295, + 297 + ] + }, + { + "x": -140, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 285, + 296 + ] + }, + { + "x": 20, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 274, + 299, + 427 + ] + }, + { + "x": -90, + "y": 810, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 298, + 300 + ] + }, + { + "x": -90, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 299, + 301 + ] + }, + { + "x": -120, + "y": 770, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 287, + 300 + ] + }, + { + "x": -110, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 288, + 303 + ] + }, + { + "x": -80, + "y": 780, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 302, + 304 + ] + }, + { + "x": -80, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 303, + 358 + ] + }, + { + "x": 30, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 273, + 306 + ] + }, + { + "x": 170, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 305, + 445 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 289 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 342 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 362 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 335 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 346 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 345 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 349 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 350 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 351 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 338 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 357 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 344 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 356 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 355 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 337 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 343 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 361 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 360 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 336 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 332 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 331 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 333 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 334 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 339 + ] + }, + { + "x": 280, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 327, + 335 + ] + }, + { + "x": 290, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 326, + 336 + ] + }, + { + "x": 310, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 328, + 337 + ] + }, + { + "x": 320, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 329, + 338 + ] + }, + { + "x": 230, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 310, + 331 + ] + }, + { + "x": 280, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 325, + 332 + ] + }, + { + "x": 330, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 321, + 333 + ] + }, + { + "x": 380, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 316, + 334 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 330 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 368 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 358 + ] + }, + { + "x": 220, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 270, + 308, + 343 + ] + }, + { + "x": 270, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 322, + 342, + 344 + ] + }, + { + "x": 310, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 318, + 343, + 345 + ] + }, + { + "x": 360, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 312, + 344 + ] + }, + { + "x": 370, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 311, + 385, + 456 + ] + }, + { + "x": 120, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 147, + 356, + 457 + ] + }, + { + "x": -30, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 151, + 251, + 282 + ] + }, + { + "x": 380, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 271, + 313, + 384 + ] + }, + { + "x": 390, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 314, + 356, + 383 + ] + }, + { + "x": 400, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 315, + 352, + 355 + ] + }, + { + "x": 420, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 95, + 351, + 382 + ] + }, + { + "x": 270, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 99, + 354, + 362 + ] + }, + { + "x": 780, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "5", + "connections": [ + 353, + 394 + ] + }, + { + "x": 350, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 320, + 351, + 360 + ] + }, + { + "x": 340, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 319, + 347, + 350 + ] + }, + { + "x": 320, + "y": 510, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 256, + 283, + 317 + ] + }, + { + "x": 310, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 304, + 341, + 359 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 358 + ] + }, + { + "x": 290, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 324, + 355, + 447 + ] + }, + { + "x": 280, + "y": 490, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 254, + 282, + 323 + ] + }, + { + "x": 240, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 309, + 353, + 446 + ] + }, + { + "x": 470, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 364, + 448 + ] + }, + { + "x": 570, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 363, + 410 + ] + }, + { + "x": 490, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 381, + 449 + ] + }, + { + "x": 720, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 389, + 411 + ] + }, + { + "x": 910, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "8", + "connections": [ + 404, + 412 + ] + }, + { + "x": 320, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 340, + 369 + ] + }, + { + "x": 480, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 368, + 450 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 383 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 384 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 382 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 381 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 390 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 386 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 385 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 387 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 388 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 389 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 428 + ] + }, + { + "x": 610, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 365, + 373, + 389 + ] + }, + { + "x": 600, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 352, + 372, + 388 + ] + }, + { + "x": 580, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 350, + 370, + 387 + ] + }, + { + "x": 570, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 349, + 371, + 386 + ] + }, + { + "x": 620, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 346, + 376 + ] + }, + { + "x": 630, + "y": 500, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 375, + 384 + ] + }, + { + "x": 640, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 255, + 377, + 383 + ] + }, + { + "x": 650, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 378, + 382, + 413 + ] + }, + { + "x": 660, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 366, + 379, + 381 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 374 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 407 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 408 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 419 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 354 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 411 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 421 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 254 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 413 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 412 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 423 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 255 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 256 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 406 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 367 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 426 + ] + }, + { + "x": 900, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 403, + 413 + ] + }, + { + "x": 730, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 391, + 409 + ] + }, + { + "x": 750, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 392, + 409 + ] + }, + { + "x": 740, + "y": 550, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 407, + 408, + 410 + ] + }, + { + "x": 740, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 364, + 409 + ] + }, + { + "x": 800, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 366, + 395, + 412 + ] + }, + { + "x": 850, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 367, + 399, + 411 + ] + }, + { + "x": 840, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 388, + 398, + 406 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 422 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 420 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 424 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 425 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 431 + ] + }, + { + "x": 740, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 393, + 420 + ] + }, + { + "x": 800, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 415, + 419 + ] + }, + { + "x": 790, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 396, + 422 + ] + }, + { + "x": 810, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 414, + 421 + ] + }, + { + "x": 840, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 400, + 424 + ] + }, + { + "x": 830, + "y": 630, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 416, + 423 + ] + }, + { + "x": 840, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 417, + 426 + ] + }, + { + "x": 890, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 405, + 425 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 298 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 380 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 432 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 435 + ] + }, + { + "x": 820, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 418, + 432, + 433 + ] + }, + { + "x": 660, + "y": 720, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 429, + 431 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 431 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 436 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 430 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 434 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 234 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 247 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 233 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 251 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 252 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 258 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 446 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 447 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 306 + ] + }, + { + "x": 160, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 362, + 443 + ] + }, + { + "x": 180, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 360, + 444 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 363 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 365 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 369 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 456 + ] + }, + { + "x": -10, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 270 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 271 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 457 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 458 + ] + }, + { + "x": 40, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 239, + 346, + 451 + ] + }, + { + "x": 70, + "y": 480, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 284, + 347, + 454 + ] + }, + { + "x": 50, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 281, + 455 + ] + } + ], + "id": 35784513673, + "name": "ALU", + "Input": [ + { + "x": 870, + "y": 120, + "objectType": "Input", + "label": "S0", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 20, + "id": "bgyS7iMmTulYzuhvuJAw" + } + ] + } + }, + { + "x": 870, + "y": 140, + "objectType": "Input", + "label": "S1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 1 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 40, + "id": "WLqXqxdEhvoLWHtBXHjI" + } + ] + } + }, + { + "x": 870, + "y": 160, + "objectType": "Input", + "label": "S2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 2 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 60, + "id": "a8z7DkCwKWXkSw3WfkAz" + } + ] + } + }, + { + "x": 870, + "y": 180, + "objectType": "Input", + "label": "S3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 3 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 0, + "y": 80, + "id": "oU212lSCqnaiI2XB6l6k" + } + ] + } + }, + { + "x": 740, + "y": 30, + "objectType": "Input", + "label": "~B3", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 22 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 100, + "id": "1ukWtQYmxOZZ1aandrYs" + } + ] + } + }, + { + "x": 530, + "y": 30, + "objectType": "Input", + "label": "~A3", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 37 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 120, + "id": "dtsyFvTYyoF8pFrQ4gZv" + } + ] + } + }, + { + "x": 440, + "y": 30, + "objectType": "Input", + "label": "~B2", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 74 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 140, + "id": "rMYJA0Nz0IHW6cXFoIMh" + } + ] + } + }, + { + "x": 230, + "y": 30, + "objectType": "Input", + "label": "~A2", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 89 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 160, + "id": "k4Q6Y6aWUXjA9uMOFLA9" + } + ] + } + }, + { + "x": 140, + "y": 30, + "objectType": "Input", + "label": "~B1", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 126 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 180, + "id": "omeNlryzvz7Pz0lFjW6r" + } + ] + } + }, + { + "x": -70, + "y": 30, + "objectType": "Input", + "label": "~A1", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 141 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 200, + "id": "n8heKwweZojnOjBCw7yI" + } + ] + } + }, + { + "x": -150, + "y": 30, + "objectType": "Input", + "label": "~B0", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 178 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 220, + "id": "EZQWSGwtHHM3LMJAiLUX" + } + ] + } + }, + { + "x": -360, + "y": 30, + "objectType": "Input", + "label": "~A0", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 193 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 240, + "id": "DnHv05kyFumssr1vnxvh" + } + ] + } + }, + { + "x": -450, + "y": 30, + "objectType": "Input", + "label": "M", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 214 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 260, + "id": "UrilH2CzjLyUst4aRdT7" + } + ] + } + }, + { + "x": -470, + "y": 30, + "objectType": "Input", + "label": "~Cn", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 215 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + 1, + { + "x": 0, + "y": 280, + "id": "OCylfDQemyKD1ghkGw99" + } + ] + } + } + ], + "Output": [ + { + "x": -450, + "y": 890, + "objectType": "Output", + "label": "~F0", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 259 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 80, + "id": "O88tnQx6pYWyz8DgCW2w" + } + ] + } + }, + { + "x": -280, + "y": 890, + "objectType": "Output", + "label": "~F1", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 260 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 100, + "id": "Q7u02WLnBPTPrO8hOd0v" + } + ] + } + }, + { + "x": -130, + "y": 890, + "objectType": "Output", + "label": "A=B", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 307 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 120, + "id": "9FyiglYgXYTjs8PjQO9z" + } + ] + } + }, + { + "x": 310, + "y": 890, + "objectType": "Output", + "label": "~F3", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 359 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 140, + "id": "pGwpiM47ZeuqcCx5ecc5" + } + ] + } + }, + { + "x": 590, + "y": 890, + "objectType": "Output", + "label": "~P", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 390 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 160, + "id": "lLu0TkM1mm3IY2JQMoOO" + } + ] + } + }, + { + "x": 20, + "y": 890, + "objectType": "Output", + "label": "~F2", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 427 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 180, + "id": "iPKabWfwVrry6UrorWWC" + } + ] + } + }, + { + "x": 650, + "y": 890, + "objectType": "Output", + "label": "~Cn+4", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 435 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 200, + "id": "wyQYiBXlg5PGYSQBqecL" + } + ] + } + }, + { + "x": 820, + "y": 890, + "objectType": "Output", + "label": "~G", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 436 + }, + "constructorParamaters": [ + "UP", + 1, + { + "x": 100, + "y": 220, + "id": "5UE1sKl4PlJGJHUtfQdh" + } + ] + } + } + ], + "NotGate": [ + { + "x": 650, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 26, + "inp1": 25 + } + } + }, + { + "x": 350, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 78, + "inp1": 77 + } + } + }, + { + "x": 50, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 130, + "inp1": 129 + } + } + }, + { + "x": -240, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 182, + "inp1": 181 + } + } + }, + { + "x": -450, + "y": 80, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 213, + "inp1": 212 + } + } + }, + { + "x": 820, + "y": 830, + "objectType": "NotGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 1 + ], + "nodes": { + "output1": 434, + "inp1": 433 + } + } + } + ], + "AndGate": [ + { + "x": 740, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 4, + 5, + 6 + ], + "output1": 7 + } + } + }, + { + "x": 700, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 8, + 9, + 10 + ], + "output1": 11 + } + } + }, + { + "x": 610, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 12, + 13 + ], + "output1": 14 + } + } + }, + { + "x": 570, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 15, + 16 + ], + "output1": 17 + } + } + }, + { + "x": 530, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 18, + 19 + ], + "output1": 20 + } + } + }, + { + "x": 440, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 56, + 57, + 58 + ], + "output1": 59 + } + } + }, + { + "x": 400, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 60, + 61, + 62 + ], + "output1": 63 + } + } + }, + { + "x": 310, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 64, + 65 + ], + "output1": 66 + } + } + }, + { + "x": 270, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 67, + 68 + ], + "output1": 69 + } + } + }, + { + "x": 230, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 70, + 71 + ], + "output1": 72 + } + } + }, + { + "x": 140, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 108, + 109, + 110 + ], + "output1": 111 + } + } + }, + { + "x": 100, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 112, + 113, + 114 + ], + "output1": 115 + } + } + }, + { + "x": 10, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 116, + 117 + ], + "output1": 118 + } + } + }, + { + "x": -30, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 119, + 120 + ], + "output1": 121 + } + } + }, + { + "x": -70, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 122, + 123 + ], + "output1": 124 + } + } + }, + { + "x": -150, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 160, + 161, + 162 + ], + "output1": 163 + } + } + }, + { + "x": -190, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 164, + 165, + 166 + ], + "output1": 167 + } + } + }, + { + "x": -280, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 168, + 169 + ], + "output1": 170 + } + } + }, + { + "x": -320, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 171, + 172 + ], + "output1": 173 + } + } + }, + { + "x": -360, + "y": 250, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 174, + 175 + ], + "output1": 176 + } + } + }, + { + "x": -310, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 222, + 223 + ], + "output1": 224 + } + } + }, + { + "x": -270, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 241, + 242, + 243 + ], + "output1": 244 + } + } + }, + { + "x": 10, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 261, + 262, + 263 + ], + "output1": 264 + } + } + }, + { + "x": -30, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 265, + 266 + ], + "output1": 267 + } + } + }, + { + "x": -130, + "y": 800, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 285, + 286, + 287, + 288 + ], + "output1": 289 + } + } + }, + { + "x": 230, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 308, + 309 + ], + "output1": 310 + } + } + }, + { + "x": 380, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "5", + 1 + ], + "nodes": { + "inp": [ + 311, + 312, + 313, + 314, + 315 + ], + "output1": 316 + } + } + }, + { + "x": 330, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 317, + 318, + 319, + 320 + ], + "output1": 321 + } + } + }, + { + "x": 280, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 322, + 323, + 324 + ], + "output1": 325 + } + } + }, + { + "x": 740, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 391, + 392 + ], + "output1": 393 + } + } + }, + { + "x": 790, + "y": 590, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 394, + 395 + ], + "output1": 396 + } + } + }, + { + "x": 840, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 397, + 398, + 399 + ], + "output1": 400 + } + } + }, + { + "x": 890, + "y": 590, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 401, + 402, + 403, + 404 + ], + "output1": 405 + } + } + }, + { + "x": 50, + "y": 580, + "objectType": "AndGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 451, + 452, + 453, + 454 + ], + "output1": 455 + } + } + } + ], + "NorGate": [ + { + "x": 720, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 41, + 42 + ], + "output1": 43 + } + } + }, + { + "x": 570, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 44, + 45, + 46 + ], + "output1": 47 + } + } + }, + { + "x": 420, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 93, + 94 + ], + "output1": 95 + } + } + }, + { + "x": 270, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 96, + 97, + 98 + ], + "output1": 99 + } + } + }, + { + "x": 120, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 145, + 146 + ], + "output1": 147 + } + } + }, + { + "x": -30, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 148, + 149, + 150 + ], + "output1": 151 + } + } + }, + { + "x": -170, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 197, + 198 + ], + "output1": 199 + } + } + }, + { + "x": -320, + "y": 340, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 200, + 201, + 202 + ], + "output1": 203 + } + } + }, + { + "x": -290, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 225, + 226 + ], + "output1": 227 + } + } + }, + { + "x": 10, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "3", + 1 + ], + "nodes": { + "inp": [ + 275, + 276, + 277 + ], + "output1": 278 + } + } + }, + { + "x": 300, + "y": 660, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 326, + 327, + 328, + 329 + ], + "output1": 330 + } + } + }, + { + "x": 820, + "y": 670, + "objectType": "NorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 414, + 415, + 416, + 417 + ], + "output1": 418 + } + } + } + ], + "NandGate": [ + { + "x": -460, + "y": 580, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "RIGHT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 216, + 217 + ], + "output1": 218 + } + } + }, + { + "x": 590, + "y": 580, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "4", + 1 + ], + "nodes": { + "inp": [ + 370, + 371, + 372, + 373 + ], + "output1": 374 + } + } + }, + { + "x": 640, + "y": 590, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "5", + 1 + ], + "nodes": { + "inp": [ + 375, + 376, + 377, + 378, + 379 + ], + "output1": 380 + } + } + }, + { + "x": 650, + "y": 770, + "objectType": "NandGate", + "label": "", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + "2", + 1 + ], + "nodes": { + "inp": [ + 428, + 429 + ], + "output1": 430 + } + } + } + ], + "XorGate": [ + { + "x": -450, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 219, + 220 + ], + "output1": 221 + } + } + }, + { + "x": -280, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 248, + 249 + ], + "output1": 250 + } + } + }, + { + "x": 20, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 272, + 273 + ], + "output1": 274 + } + } + }, + { + "x": 310, + "y": 760, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 339, + 340 + ], + "output1": 341 + } + } + }, + { + "x": -370, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 437, + 438 + ], + "output1": 439 + } + } + }, + { + "x": -130, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 440, + 441 + ], + "output1": 442 + } + } + }, + { + "x": 170, + "y": 680, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 443, + 444 + ], + "output1": 445 + } + } + }, + { + "x": 480, + "y": 670, + "objectType": "XorGate", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "DOWN", + 2, + 1 + ], + "nodes": { + "inp": [ + 448, + 449 + ], + "output1": 450 + } + } + } + ], + "nodes": [ + 21, + 23, + 24, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 38, + 39, + 40, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 73, + 75, + 76, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 90, + 91, + 92, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 125, + 127, + 128, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 142, + 143, + 144, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 177, + 179, + 180, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 194, + 195, + 196, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 245, + 246, + 247, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 268, + 269, + 270, + 271, + 279, + 280, + 281, + 282, + 283, + 284, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 381, + 382, + 383, + 384, + 385, + 386, + 387, + 388, + 389, + 406, + 407, + 408, + 409, + 410, + 411, + 412, + 413, + 419, + 420, + 421, + 422, + 423, + 424, + 425, + 426, + 431, + 432, + 446, + 447, + 456, + 457, + 458 + ] + }, + { + "layout": { + "width": 100, + "height": 140, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 1 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 9 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 11 + ] + }, + { + "x": 870, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 61 + ] + }, + { + "x": 870, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 6 + ] + }, + { + "x": 890, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 57 + ] + }, + { + "x": 890, + "y": 360, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 8 + ] + }, + { + "x": 840, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 55 + ] + }, + { + "x": 840, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 10 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 910, + "y": 410, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 19 + ] + }, + { + "x": 910, + "y": 360, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 60 + ] + }, + { + "x": 900, + "y": 430, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 21 + ] + }, + { + "x": 900, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 58 + ] + }, + { + "x": 860, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 16, + 23 + ] + }, + { + "x": 860, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 56 + ] + }, + { + "x": 810, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 25 + ] + }, + { + "x": 810, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 24, + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 920, + "y": 560, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 28 + ] + }, + { + "x": 920, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 62 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 940, + "y": 600, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 31 + ] + }, + { + "x": 940, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 63 + ] + }, + { + "x": 40, + "y": 0, + "type": 1, + "bitWidth": 4, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 65 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 43 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 67 + ] + }, + { + "x": 1120, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 44 + ] + }, + { + "x": 1120, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 69 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 66 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 68 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 71 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 80, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": 0, + "y": 100, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 0, + "y": 120, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": 0, + "y": 140, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": 0, + "y": 160, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 0, + "y": 180, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 200, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 3 + ] + }, + { + "x": 0, + "y": 220, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 0, + "y": 240, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 0, + "y": 260, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 0, + "y": 280, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 100, + "y": 80, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 100, + "y": 100, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 100, + "y": 120, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 46 + ] + }, + { + "x": 100, + "y": 140, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 100, + "y": 160, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 100, + "y": 180, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 100, + "y": 200, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 100, + "y": 220, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 49 + ] + } + ], + "id": 33755305138, + "name": "Main", + "Input": [ + { + "x": 710, + "y": 390, + "objectType": "Input", + "label": "~A", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 15 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 100, + "id": "KkUsNwfO4X0x4c04hwMv" + } + ] + } + }, + { + "x": 710, + "y": 480, + "objectType": "Input", + "label": "~B", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 12 + }, + "values": { + "state": 12 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 20, + "id": "P6IeBwGNUu70jnDV7AEM" + } + ] + } + }, + { + "x": 740, + "y": 560, + "objectType": "Input", + "label": "Mode", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 26 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "v6fmRUb6A8NpuXLnnBr2" + } + ] + } + }, + { + "x": 740, + "y": 600, + "objectType": "Input", + "label": "~Cn", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 29 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "xxDizRwLr4gvjxzTAF9Q" + } + ] + } + }, + { + "x": 700, + "y": 230, + "objectType": "Input", + "label": "S", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 32 + }, + "values": { + "state": 4 + }, + "constructorParamaters": [ + "RIGHT", + 4, + { + "x": 0, + "y": 80, + "id": "wjiTCwACtzuNTQPiA7Qd" + } + ] + } + } + ], + "Output": [ + { + "x": 1260, + "y": 290, + "objectType": "Output", + "label": "~F", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 4, + { + "x": 100, + "y": 40, + "id": "8EmhK1WYRAieQ1CdZaw8" + } + ] + } + }, + { + "x": 1090, + "y": 260, + "objectType": "Output", + "label": "A=B", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 46 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "HBawk8lC7uuFfL6yoUs4" + } + ] + } + }, + { + "x": 1090, + "y": 300, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 47 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "j9nnntr30X9Y0XSOHFG9" + } + ] + } + }, + { + "x": 1090, + "y": 340, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 48 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "82KrKflpCRdOtyEkALcm" + } + ] + } + }, + { + "x": 1090, + "y": 360, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 49 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "dqfl9XSBF9zphXeBra5W" + } + ] + } + } + ], + "Splitter": [ + { + "x": 770, + "y": 360, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 2, + 3, + 4, + 5 + ], + "inp1": 1 + } + } + }, + { + "x": 770, + "y": 450, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 14, + 15, + 16, + 17 + ], + "inp1": 13 + } + } + }, + { + "x": 780, + "y": 200, + "objectType": "Splitter", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 34, + 35, + 36, + 37 + ], + "inp1": 33 + } + } + }, + { + "x": 1200, + "y": 260, + "objectType": "Splitter", + "label": "", + "direction": "LEFT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 39, + 40, + 41, + 42 + ], + "inp1": 38 + } + } + } + ], + "SubCircuit": [ + { + "x": 960, + "y": 140, + "id": "35784513673", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63 + ], + "outputNodes": [ + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 6, + 7, + 8, + 9, + 10, + 11, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 27, + 28, + 30, + 31, + 43, + 44 + ] + } + ] +} diff --git a/v1/src/simulator/spec/circuits/gates-circuitdata.json b/v1/src/simulator/spec/circuits/gates-circuitdata.json index a5c96609..7361a1d5 100644 --- a/v1/src/simulator/spec/circuits/gates-circuitdata.json +++ b/v1/src/simulator/spec/circuits/gates-circuitdata.json @@ -1,710 +1,879 @@ { - "name": "gates-circuitdata", - "timePeriod": 500, - "clockEnabled": true, - "projectId": "hCqg1Ns4JVckHsnyKQDi", - "focussedCircuit": 11597572508, - "orderedTabs": ["11597572508"], - "scopes": [ - { - "layout": { - "width": 100, - "height": 280, - "title_x": 50, - "title_y": 13, - "titleEnabled": true + "name": "gates-circuitdata", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "hCqg1Ns4JVckHsnyKQDi", + "focussedCircuit": 11597572508, + "orderedTabs": [ + "11597572508" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 280, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 23 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 28 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 260, + "y": -10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 20, + 30 + ] + }, + { + "x": 260, + "y": 130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 3, + 33 + ] + }, + { + "x": 210, + "y": 10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 21, + 32 + ] + }, + { + "x": 210, + "y": 150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 4, + 34 + ] + }, + { + "x": 260, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 11, + 35 + ] + }, + { + "x": 210, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 32, + 12, + 41 + ] + }, + { + "x": 260, + "y": 460, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 6, + 36 + ] + }, + { + "x": 260, + "y": 600, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 17, + 38 + ] + }, + { + "x": 260, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 14 + ] + }, + { + "x": 260, + "y": 740, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 36, + 37, + 8 + ] + }, + { + "x": 210, + "y": 840, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 40 + ] + }, + { + "x": 210, + "y": 760, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 39, + 9, + 41 + ] + }, + { + "x": 210, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 40, + 18 + ] + } + ], + "id": 11597572508, + "name": "Main", + "Input": [ + { + "x": -30, + "y": -10, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 20 }, - "verilogMetadata": { - "isVerilogCircuit": false, - "isMainCircuit": false, - "code": "// Write Some Verilog Code Here!", - "subCircuitScopeIds": [] + "values": { + "state": 1 }, - "allNodes": [ - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [22] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [30] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [32] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [23] - }, - { - "x": -10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [35] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [25] - }, - { - "x": -20, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [38] - }, - { - "x": -20, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [40] - }, - { - "x": 20, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [27] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [33] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [34] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [24] - }, - { - "x": -10, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [37] - }, - { - "x": -10, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [39] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [28] - }, - { - "x": -20, - "y": -10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [36] - }, - { - "x": -20, - "y": 10, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [41] - }, - { - "x": 30, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [26] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [29] - }, - { - "x": 10, - "y": 0, - "type": 1, - "bitWidth": 1, - "label": "", - "connections": [31] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [2] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [5] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [13] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [7] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [19] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [10] - }, - { - "x": 10, - "y": 0, - "type": 0, - "bitWidth": 1, - "label": "", - "connections": [16] - }, - { - "x": 260, - "y": -10, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [0, 20, 30] - }, - { - "x": 260, - "y": 130, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [29, 3, 33] - }, - { - "x": 210, - "y": 10, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [1, 21, 32] - }, - { - "x": 210, - "y": 150, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [31, 4, 34] - }, - { - "x": 260, - "y": 300, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [30, 11, 35] - }, - { - "x": 210, - "y": 320, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [32, 12, 41] - }, - { - "x": 260, - "y": 460, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [33, 6, 36] - }, - { - "x": 260, - "y": 600, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [35, 17, 38] - }, - { - "x": 260, - "y": 820, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [38, 14] - }, - { - "x": 260, - "y": 740, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [36, 37, 8] - }, - { - "x": 210, - "y": 840, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [15, 40] - }, - { - "x": 210, - "y": 760, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [39, 9, 41] - }, - { - "x": 210, - "y": 620, - "type": 2, - "bitWidth": 1, - "label": "", - "connections": [34, 40, 18] - } - ], - "id": 11597572508, - "name": "Main", - "Input": [ - { - "x": -30, - "y": -10, - "objectType": "Input", - "label": "inp1", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 20 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 20, - "id": "55mKFwVFnZeU6ucfO8am" - } - ] - } - }, - { - "x": -30, - "y": 10, - "objectType": "Input", - "label": "inp2", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 0, - "customData": { - "nodes": { - "output1": 21 - }, - "values": { - "state": 1 - }, - "constructorParamaters": [ - "RIGHT", - 1, - { - "x": 0, - "y": 40, - "id": "2O2YfZk7yuqLrtiRb429" - } - ] - } - } - ], - "Output": [ - { - "x": 500, - "y": 0, - "objectType": "Output", - "label": "out1", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 22 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 20, - "id": "RarwxCcQgRygZftUFlMr" - } - ] - } - }, - { - "x": 510, - "y": 140, - "objectType": "Output", - "label": "out2", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 23 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 40, - "id": "N0agpzN04aqy9nLexP98" - } - ] - } - }, - { - "x": 520, - "y": 310, - "objectType": "Output", - "label": "out3", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 24 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 60, - "id": "2yO9fxrqrjPk1urH47Fc" - } - ] - } - }, - { - "x": 520, - "y": 460, - "objectType": "Output", - "label": "out4", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 25 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 80, - "id": "IN7sNsKhkByzBHRShVdu" - } - ] - } - }, - { - "x": 520, - "y": 610, - "objectType": "Output", - "label": "out5", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 26 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 100, - "id": "Dfr4VEfv27q3AOwkLqpx" - } - ] - } - }, - { - "x": 520, - "y": 750, - "objectType": "Output", - "label": "out6", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 27 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 120, - "id": "FGeZ7ip5nJo9MUlEyJ35" - } - ] - } - }, - { - "x": 530, - "y": 830, - "objectType": "Output", - "label": "out7", - "direction": "LEFT", - "labelDirection": "RIGHT", - "propagationDelay": 0, - "customData": { - "nodes": { - "inp1": 28 - }, - "constructorParamaters": [ - "LEFT", - 1, - { - "x": 100, - "y": 140, - "id": "oYVAxzNmrQgKjC7I3xOg" - } - ] - } - } - ], - "NotGate": [ - { - "x": 340, - "y": 460, - "objectType": "NotGate", - "label": "NOT GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 1], - "nodes": { - "output1": 7, - "inp1": 6 - } - } - } + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "55mKFwVFnZeU6ucfO8am" + } + ] + } + }, + { + "x": -30, + "y": 10, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 21 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "2O2YfZk7yuqLrtiRb429" + } + ] + } + } + ], + "Output": [ + { + "x": 500, + "y": 0, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 22 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "RarwxCcQgRygZftUFlMr" + } + ] + } + }, + { + "x": 510, + "y": 140, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 23 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "N0agpzN04aqy9nLexP98" + } + ] + } + }, + { + "x": 520, + "y": 310, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 24 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "2yO9fxrqrjPk1urH47Fc" + } + ] + } + }, + { + "x": 520, + "y": 460, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 25 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "IN7sNsKhkByzBHRShVdu" + } + ] + } + }, + { + "x": 520, + "y": 610, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 26 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 100, + "id": "Dfr4VEfv27q3AOwkLqpx" + } + ] + } + }, + { + "x": 520, + "y": 750, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 27 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "FGeZ7ip5nJo9MUlEyJ35" + } + ] + } + }, + { + "x": 530, + "y": 830, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 28 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "oYVAxzNmrQgKjC7I3xOg" + } + ] + } + } + ], + "NotGate": [ + { + "x": 340, + "y": 460, + "objectType": "NotGate", + "label": "NOT GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 ], - "OrGate": [ - { - "x": 330, - "y": 140, - "objectType": "OrGate", - "label": "OR GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [3, 4], - "output1": 5 - } - } - } + "nodes": { + "output1": 7, + "inp1": 6 + } + } + } + ], + "OrGate": [ + { + "x": 330, + "y": 140, + "objectType": "OrGate", + "label": "OR GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "AndGate": [ - { - "x": 320, - "y": 0, - "objectType": "AndGate", - "label": "AND GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [0, 1], - "output1": 2 - } - } - } + "nodes": { + "inp": [ + 3, + 4 + ], + "output1": 5 + } + } + } + ], + "AndGate": [ + { + "x": 320, + "y": 0, + "objectType": "AndGate", + "label": "AND GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "NorGate": [ - { - "x": 330, - "y": 830, - "objectType": "NorGate", - "label": "NOR", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [14, 15], - "output1": 16 - } - } - } + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2 + } + } + } + ], + "NorGate": [ + { + "x": 330, + "y": 830, + "objectType": "NorGate", + "label": "NOR", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "NandGate": [ - { - "x": 340, - "y": 310, - "objectType": "NandGate", - "label": "NAND GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [11, 12], - "output1": 13 - } - } - } + "nodes": { + "inp": [ + 14, + 15 + ], + "output1": 16 + } + } + } + ], + "NandGate": [ + { + "x": 340, + "y": 310, + "objectType": "NandGate", + "label": "NAND GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "XorGate": [ - { - "x": 330, - "y": 750, - "objectType": "XorGate", - "label": "XOR", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [8, 9], - "output1": 10 - } - } - } + "nodes": { + "inp": [ + 11, + 12 + ], + "output1": 13 + } + } + } + ], + "XorGate": [ + { + "x": 330, + "y": 750, + "objectType": "XorGate", + "label": "XOR", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "XnorGate": [ - { - "x": 330, - "y": 610, - "objectType": "XnorGate", - "label": "XNOR GATE", - "direction": "RIGHT", - "labelDirection": "LEFT", - "propagationDelay": 10, - "customData": { - "constructorParamaters": ["RIGHT", 2, 1], - "nodes": { - "inp": [17, 18], - "output1": 19 - } - } - } + "nodes": { + "inp": [ + 8, + 9 + ], + "output1": 10 + } + } + } + ], + "XnorGate": [ + { + "x": 330, + "y": 610, + "objectType": "XnorGate", + "label": "XNOR GATE", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 ], - "restrictedCircuitElementsUsed": [], - "nodes": [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41] + "nodes": { + "inp": [ + 17, + 18 + ], + "output1": 19 + } + } } - ] + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41 + ] + } + ] } diff --git a/v1/src/simulator/spec/circuits/misc-circuitdata.json b/v1/src/simulator/spec/circuits/misc-circuitdata.json new file mode 100644 index 00000000..9da89ca2 --- /dev/null +++ b/v1/src/simulator/spec/circuits/misc-circuitdata.json @@ -0,0 +1,1572 @@ +{ + "name": "misc", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "Z66aSelqsnFvwJteATxg", + "focussedCircuit": 60033074305, + "orderedTabs": [ + "60033074305" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 320, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -30, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "A", + "connections": [ + 12 + ] + }, + { + "x": -30, + "y": 30, + "type": 0, + "bitWidth": 1, + "label": "B", + "connections": [ + 22 + ] + }, + { + "x": -10, + "y": -40, + "type": 0, + "bitWidth": 3, + "label": "Ctrl", + "connections": [ + 5 + ] + }, + { + "x": -10, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "Cout", + "connections": [ + 10 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Out", + "connections": [ + 8 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 3, + "label": "", + "connections": [ + 2, + 56 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": -20, + "y": -240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 9 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -110, + "y": -400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 6, + 13 + ] + }, + { + "x": -110, + "y": -150, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 12, + 21 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "A", + "connections": [ + 21 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "B", + "connections": [ + 23 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Cin", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "Sum", + "connections": [ + 25 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Cout", + "connections": [ + 27 + ] + }, + { + "x": -110, + "y": -20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 16, + 31 + ] + }, + { + "x": -170, + "y": -340, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 7, + 23 + ] + }, + { + "x": -170, + "y": -10, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 22, + 72 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 70, + "y": 60, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 26 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 3, + "label": "input stream", + "connections": [ + 56 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 3, + "label": "2's complement", + "connections": [ + 30 + ] + }, + { + "x": 30, + "y": 0, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 29 + ] + }, + { + "x": -110, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 32, + 39 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "reset", + "connections": [] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": -110, + "y": 340, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 36, + 44 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": -10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 30, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [ + 50 + ] + }, + { + "x": -110, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 39, + 41, + 69 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 50, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 48 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": -160, + "y": 260, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 46, + 47, + 49 + ] + }, + { + "x": -160, + "y": 570, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 48, + 50 + ] + }, + { + "x": 60, + "y": 570, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 49 + ] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 20, + "y": -30, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 59 + ] + }, + { + "x": 40, + "y": -660, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 51, + 56, + 63 + ] + }, + { + "x": 40, + "y": -530, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 5, + 28, + 55 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 3, + "label": "", + "connections": [ + 63 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 2, + "label": "", + "connections": [ + 65 + ] + }, + { + "x": 40, + "y": -850, + "type": 2, + "bitWidth": 3, + "label": "", + "connections": [ + 55, + 60 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 61 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 2, + "label": "", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 0, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 71 + ] + }, + { + "x": -110, + "y": 700, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 70 + ] + }, + { + "x": 60, + "y": 700, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 69, + 67 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 68 + ] + }, + { + "x": -170, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 66 + ] + } + ], + "id": 60033074305, + "name": "Main", + "Input": [ + { + "x": -50, + "y": -530, + "objectType": "Input", + "label": "mode", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 7 + }, + "constructorParamaters": [ + "RIGHT", + 3, + { + "x": 0, + "y": 100, + "id": "XLIG7xxHzqiqXN4niWjc" + } + ] + } + }, + { + "x": -260, + "y": -400, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "xnFLotUtTF8dDqzdt63A" + } + ] + } + }, + { + "x": -260, + "y": -340, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 7 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "20RIzYI8HAyZyA6HZkie" + } + ] + } + }, + { + "x": -240, + "y": 0, + "objectType": "Input", + "label": "inp3", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 24 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "4Pt2rPBEr90DVh789QpH" + } + ] + } + }, + { + "x": -230, + "y": 260, + "objectType": "Input", + "label": "enable", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 47 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 80, + "id": "Bvzy3iTJUD5HiGnxpab6" + } + ] + } + } + ], + "Output": [ + { + "x": 250, + "y": -370, + "objectType": "Output", + "label": "ALU-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 8 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "AKbMNYWkZvw4oWCYQ12W" + } + ] + } + }, + { + "x": 260, + "y": -240, + "objectType": "Output", + "label": "ALU-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 9 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "K7hEEwIPmQ17joAgCPXg" + } + ] + } + }, + { + "x": 250, + "y": -150, + "objectType": "Output", + "label": "Tunnel-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 15 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "jgCz5e7jPDpPEbwEaQgh" + } + ] + } + }, + { + "x": 150, + "y": -10, + "objectType": "Output", + "label": "Adder-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 25 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "IaKcxWxYEyFXwog5mmN9" + } + ] + } + }, + { + "x": 200, + "y": 60, + "objectType": "Output", + "label": "Adder-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 26 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "zuWpzdjxikK9URyRNLmT" + } + ] + } + }, + { + "x": 270, + "y": -530, + "objectType": "Output", + "label": "2s-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 30 + }, + "constructorParamaters": [ + "LEFT", + 3, + { + "x": 100, + "y": 100, + "id": "4uEXpHNgO8CNC3NeKPhs" + } + ] + } + }, + { + "x": 160, + "y": 190, + "objectType": "Output", + "label": "T-state-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 35 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "MwFKnzZlWzyDBVGrzz5e" + } + ] + } + }, + { + "x": 160, + "y": 340, + "objectType": "Output", + "label": "buffer-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 40 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "kCRFdkujlb6UZZaBH2Wi" + } + ] + } + }, + { + "x": 180, + "y": 450, + "objectType": "Output", + "label": "CI-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "vh7IJznYSr54Ohz8GC2R" + } + ] + } + }, + { + "x": 240, + "y": -710, + "objectType": "Output", + "label": "s-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 57 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "c4XKu6fhOdVbCK6wqiht" + } + ] + } + }, + { + "x": 240, + "y": -690, + "objectType": "Output", + "label": "s-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 58 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 220, + "id": "IcyojhGiGRYqMM9B87k5" + } + ] + } + }, + { + "x": 240, + "y": -670, + "objectType": "Output", + "label": "s-out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 240, + "id": "ccIvryJkgZqu7qvSQg4l" + } + ] + } + }, + { + "x": 220, + "y": -880, + "objectType": "Output", + "label": "s-un-out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 64 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 260, + "id": "9CB5RKzglQEWYo6MvnDa" + } + ] + } + }, + { + "x": 230, + "y": -860, + "objectType": "Output", + "label": "s-un-out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 65 + }, + "constructorParamaters": [ + "LEFT", + 2, + { + "x": 100, + "y": 280, + "id": "dujdaDsq5xV6Z9bOchmB" + } + ] + } + }, + { + "x": 170, + "y": 640, + "objectType": "Output", + "label": "Force-out", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 71 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 300, + "id": "iHSRiMZgMM6EXgN1xPfJ" + } + ] + } + } + ], + "Splitter": [ + { + "x": 120, + "y": -680, + "objectType": "Splitter", + "label": "splitter-equal", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3, + [ + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 52, + 53, + 54 + ], + "inp1": 51 + } + } + }, + { + "x": 130, + "y": -860, + "objectType": "Splitter", + "label": "splitter-unequal", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3, + [ + 1, + 2 + ] + ], + "nodes": { + "outputs": [ + 61, + 62 + ], + "inp1": 60 + } + } + } + ], + "ControlledInverter": [ + { + "x": 60, + "y": 450, + "objectType": "ControlledInverter", + "label": "controlled Inverter", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 42, + "inp1": 41, + "state": 43 + } + } + } + ], + "TriState": [ + { + "x": 50, + "y": 190, + "objectType": "TriState", + "label": "T-state buffer", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 33, + "inp1": 32, + "state": 34 + } + } + } + ], + "Adder": [ + { + "x": 50, + "y": -10, + "objectType": "Adder", + "label": "Adder", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "inpA": 16, + "inpB": 17, + "carryIn": 18, + "carryOut": 20, + "sum": 19 + } + } + } + ], + "TwoComplement": [ + { + "x": 120, + "y": -530, + "objectType": "TwoComplement", + "label": "2's compliment", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 3 + ], + "nodes": { + "output1": 29, + "inp1": 28 + } + } + } + ], + "Buffer": [ + { + "x": 50, + "y": 340, + "objectType": "Buffer", + "label": "buffer", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 38, + "inp1": 36, + "reset": 37 + } + } + } + ], + "Tunnel": [ + { + "x": -50, + "y": -150, + "objectType": "Tunnel", + "label": "Tunnel-IN", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1, + "T" + ], + "nodes": { + "inp1": 11 + }, + "values": { + "identifier": "T" + } + } + }, + { + "x": 140, + "y": -150, + "objectType": "Tunnel", + "label": "Tunnel-Out", + "direction": "LEFT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "LEFT", + 1, + "T" + ], + "nodes": { + "inp1": 14 + }, + "values": { + "identifier": "T" + } + } + } + ], + "ALU": [ + { + "x": -10, + "y": -370, + "objectType": "ALU", + "label": "ALU", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "inp1": 0, + "inp2": 1, + "output": 4, + "carryOut": 3, + "controlSignalInput": 2 + } + } + } + ], + "ForceGate": [ + { + "x": 60, + "y": 640, + "objectType": "ForceGate", + "label": "force gate", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 68, + "inp1": 66, + "inp2": 67 + } + } + }, + { + "x": 60, + "y": 640, + "objectType": "ForceGate", + "label": "force gate", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 1 + ], + "nodes": { + "output1": 68, + "inp1": 66, + "inp2": 67 + } + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 10, + 12, + 13, + 21, + 22, + 23, + 27, + 31, + 39, + 44, + 46, + 48, + 49, + 50, + 55, + 56, + 63, + 69, + 70, + 72 + ] + } + ] +} diff --git a/v1/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json b/v1/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json new file mode 100644 index 00000000..3b684246 --- /dev/null +++ b/v1/src/simulator/spec/circuits/rippleCarryAdder-circuitdata.json @@ -0,0 +1,3109 @@ +{ + "name": "Ripple-carry-adder", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "4XoG4GWmQZ9NS4om0iHI", + "focussedCircuit": 93663071628, + "orderedTabs": [ + "93663071628", + "71620967501", + "51553545569" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "1", + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "1", + "label": "", + "connections": [ + 28 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 200, + "y": 90, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 13, + 27 + ] + }, + { + "x": 200, + "y": 130, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 14, + 28 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 300, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 13 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 200, + "y": 100, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 3, + 10 + ] + }, + { + "x": 200, + "y": 120, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 4, + 11 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 300, + "y": 130, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 6, + 16 + ] + }, + { + "x": 310, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 12, + 15, + 20 + ] + }, + { + "x": 310, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 19 + ] + }, + { + "x": 260, + "y": 170, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 6, + 22 + ] + }, + { + "x": 260, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 21 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 26 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 160, + "y": 200, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 23, + 27 + ] + }, + { + "x": 160, + "y": 90, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 0, + 3, + 26 + ] + }, + { + "x": 150, + "y": 130, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 1, + 4, + 29 + ] + }, + { + "x": 150, + "y": 220, + "type": 2, + "bitWidth": "1", + "label": "", + "connections": [ + 24, + 28 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 370, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 34 + ] + }, + { + "x": 370, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 32 + ] + } + ], + "id": 71620967501, + "name": "1 Bit Full adder", + "Input": [ + { + "x": 120, + "y": 90, + "objectType": "Input", + "label": "A", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + "1", + { + "x": 0, + "y": 20, + "id": "E2sClOSN6pWrS98RgOYs" + } + ] + } + }, + { + "x": 120, + "y": 130, + "objectType": "Input", + "label": "B", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 1 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + "1", + { + "x": 0, + "y": 40, + "id": "HTbtSbs9eS4J1TQuPXGO" + } + ] + } + }, + { + "x": 120, + "y": 170, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 2 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "VEynnegCN4NTDTf8CiFi" + } + ] + } + } + ], + "Output": [ + { + "x": 470, + "y": 120, + "objectType": "Output", + "label": "Sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 5 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "iaTzfFCd96wCDEqETEJQ" + } + ] + } + }, + { + "x": 470, + "y": 200, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 35 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "dW2kDiC82HpklbBdEwV7" + } + ] + } + } + ], + "OrGate": [ + { + "x": 420, + "y": 200, + "objectType": "OrGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 30, + 31 + ], + "output1": 32 + } + } + } + ], + "AndGate": [ + { + "x": 340, + "y": 180, + "objectType": "AndGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 7, + 8 + ], + "output1": 9 + } + } + }, + { + "x": 180, + "y": 210, + "objectType": "AndGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 23, + 24 + ], + "output1": 25 + } + } + } + ], + "XorGate": [ + { + "x": 260, + "y": 110, + "objectType": "XorGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 10, + 11 + ], + "output1": 12 + } + } + }, + { + "x": 350, + "y": 120, + "objectType": "XorGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 15, + 16 + ], + "output1": 17 + } + } + } + ], + "nodes": [ + 3, + 4, + 6, + 13, + 14, + 18, + 19, + 20, + 21, + 22, + 26, + 27, + 28, + 29, + 33, + 34 + ] + }, + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 1 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 22 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 7 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 27 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 30 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 620, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 61 + ] + }, + { + "x": 620, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 12, + 64 + ] + }, + { + "x": 830, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 15, + 66 + ] + }, + { + "x": 830, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 69 + ] + }, + { + "x": 260, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 52 + ] + }, + { + "x": 280, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 18 + ] + }, + { + "x": 440, + "y": 240, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 17, + 73 + ] + }, + { + "x": 300, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 20 + ] + }, + { + "x": 630, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 21 + ] + }, + { + "x": 630, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 62 + ] + }, + { + "x": 320, + "y": 220, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 23 + ] + }, + { + "x": 840, + "y": 220, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 24 + ] + }, + { + "x": 840, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 23, + 67 + ] + }, + { + "x": 650, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 33 + ] + }, + { + "x": 650, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 25, + 63 + ] + }, + { + "x": 430, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 8, + 28 + ] + }, + { + "x": 270, + "y": 210, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 29 + ] + }, + { + "x": 270, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 28, + 53 + ] + }, + { + "x": 450, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 31 + ] + }, + { + "x": 460, + "y": 190, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 30, + 32 + ] + }, + { + "x": 460, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 31, + 57 + ] + }, + { + "x": 470, + "y": 200, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 10, + 25 + ] + }, + { + "x": 490, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 35 + ] + }, + { + "x": 850, + "y": 180, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 36 + ] + }, + { + "x": 850, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 68 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 46 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 600, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 45, + 60 + ] + }, + { + "x": 600, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 44, + 46 + ] + }, + { + "x": 470, + "y": 380, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 41, + 45 + ] + }, + { + "x": 490, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 48 + ] + }, + { + "x": 790, + "y": 400, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 76 + ] + }, + { + "x": 1000, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 50, + 77 + ] + }, + { + "x": 510, + "y": 420, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 43, + 49 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 79 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 29 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 37 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 74 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 73 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": "1", + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 77 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 450, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 40, + 55 + ] + }, + { + "x": 440, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 58 + ] + }, + { + "x": 430, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 75 + ] + }, + { + "x": 430, + "y": 320, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 59, + 74 + ] + }, + { + "x": 790, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 48, + 65 + ] + }, + { + "x": 1000, + "y": 280, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 49, + 70 + ] + }, + { + "x": 1020, + "y": 300, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 71, + 79 + ] + }, + { + "x": 1020, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 51, + 78 + ] + } + ], + "id": 51553545569, + "name": "4 bit Full adder", + "Input": [ + { + "x": 330, + "y": 90, + "objectType": "Input", + "label": "A", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 0 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "DOWN", + "4", + { + "x": 0, + "y": 20, + "id": "2bB0Ry57AnIPDOzWSzda" + } + ] + } + }, + { + "x": 500, + "y": 90, + "objectType": "Input", + "label": "B", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 8 + }, + "constructorParamaters": [ + "DOWN", + "4", + { + "x": 0, + "y": 40, + "id": "Iw9xWH2HyRpquRWUnMOe" + } + ] + } + }, + { + "x": 240, + "y": 320, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 37 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "A9dm3htBUx0UtdfjbjKF" + } + ] + } + } + ], + "Output": [ + { + "x": 520, + "y": 500, + "objectType": "Output", + "label": "Sum", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 38 + }, + "constructorParamaters": [ + "UP", + "4", + { + "x": 100, + "y": 30, + "id": "Yawujtkc6mntSdTwrzFi" + } + ] + } + }, + { + "x": 1050, + "y": 310, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 51 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 50, + "id": "NkU1KLcqXFqu75u3vyJJ" + } + ] + } + } + ], + "Splitter": [ + { + "x": 300, + "y": 130, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 2, + 3, + 4, + 5 + ], + "inp1": 1 + } + } + }, + { + "x": 470, + "y": 130, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 8, + 9, + 10, + 11 + ], + "inp1": 7 + } + } + }, + { + "x": 490, + "y": 450, + "objectType": "Splitter", + "label": "", + "direction": "UP", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "UP", + 4, + [ + 1, + 1, + 1, + 1 + ] + ], + "nodes": { + "outputs": [ + 40, + 41, + 42, + 43 + ], + "inp1": 39 + } + } + } + ], + "SubCircuit": [ + { + "x": 310, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 52, + 53, + 54 + ], + "outputNodes": [ + 55, + 56 + ], + "version": "2.0" + }, + { + "x": 480, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 57, + 58, + 59 + ], + "outputNodes": [ + 60, + 61 + ], + "version": "2.0" + }, + { + "x": 670, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 62, + 63, + 64 + ], + "outputNodes": [ + 65, + 66 + ], + "version": "2.0" + }, + { + "x": 870, + "y": 260, + "id": "71620967501", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 67, + 68, + 69 + ], + "outputNodes": [ + 70, + 71 + ], + "version": "2.0" + } + ], + "nodes": [ + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79 + ] + }, + { + "layout": { + "width": 100, + "height": 110, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 44 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 76 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 66 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 53 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 16, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 16, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 16, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 33 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 36 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 39 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": 16, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 42 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 47 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 48 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 51 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 35 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 45 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 69 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 38 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 50 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 56 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 71 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 57 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 4, + "label": "", + "connections": [ + 52 + ] + }, + { + "x": 0, + "y": 60, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 58 + ] + }, + { + "x": 100, + "y": 30, + "type": 1, + "bitWidth": "4", + "label": "", + "connections": [ + 72 + ] + }, + { + "x": 100, + "y": 50, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 75 + ] + }, + { + "x": 720, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 0, + 8 + ] + }, + { + "x": 740, + "y": 370, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 9, + 34 + ] + }, + { + "x": 890, + "y": 370, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 33, + 35 + ] + }, + { + "x": 890, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 17, + 34 + ] + }, + { + "x": 760, + "y": 360, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 10, + 37 + ] + }, + { + "x": 1040, + "y": 360, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 36, + 38 + ] + }, + { + "x": 1040, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 22, + 37 + ] + }, + { + "x": 780, + "y": 340, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 11, + 40 + ] + }, + { + "x": 1180, + "y": 340, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 39, + 41 + ] + }, + { + "x": 1180, + "y": 410, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 27, + 40 + ] + }, + { + "x": 1090, + "y": 320, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 13, + 43 + ] + }, + { + "x": 690, + "y": 320, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 42, + 44 + ] + }, + { + "x": 690, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 1, + 43 + ] + }, + { + "x": 900, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 18, + 46 + ] + }, + { + "x": 900, + "y": 300, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 45, + 47 + ] + }, + { + "x": 1110, + "y": 300, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 14, + 46 + ] + }, + { + "x": 1130, + "y": 330, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 15, + 49 + ] + }, + { + "x": 1060, + "y": 330, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 48, + 50 + ] + }, + { + "x": 1060, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 23, + 49 + ] + }, + { + "x": 1210, + "y": 290, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 16, + 52 + ] + }, + { + "x": 1210, + "y": 430, + "type": 2, + "bitWidth": 4, + "label": "", + "connections": [ + 28, + 51 + ] + }, + { + "x": 890, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 54 + ] + }, + { + "x": 890, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 19, + 53 + ] + }, + { + "x": 1050, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 56 + ] + }, + { + "x": 1050, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 24, + 55 + ] + }, + { + "x": 1200, + "y": 440, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 26, + 58 + ] + }, + { + "x": 1200, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 29, + 57 + ] + }, + { + "x": -10, + "y": 30, + "type": 0, + "bitWidth": "16", + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 20, + "y": -40, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 64 + ] + }, + { + "x": 20, + "y": -20, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 67 + ] + }, + { + "x": 20, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 70 + ] + }, + { + "x": 20, + "y": 20, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 74 + ] + }, + { + "x": 900, + "y": 530, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 60, + 65 + ] + }, + { + "x": 870, + "y": 530, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 64, + 66 + ] + }, + { + "x": 870, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 3, + 65 + ] + }, + { + "x": 920, + "y": 520, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 61, + 68 + ] + }, + { + "x": 1030, + "y": 520, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 67, + 69 + ] + }, + { + "x": 1030, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 20, + 68 + ] + }, + { + "x": 940, + "y": 560, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 62, + 80 + ] + }, + { + "x": 1180, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 25, + 81 + ] + }, + { + "x": 1350, + "y": 420, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 30, + 73 + ] + }, + { + "x": 1350, + "y": 600, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 72, + 74 + ] + }, + { + "x": 960, + "y": 600, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 63, + 73 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": "16", + "label": "", + "connections": [ + 78 + ] + }, + { + "x": 1020, + "y": 660, + "type": 2, + "bitWidth": "16", + "label": "", + "connections": [ + 59, + 77 + ] + }, + { + "x": 40, + "y": 0, + "type": 0, + "bitWidth": "4", + "label": "", + "connections": [ + 81 + ] + }, + { + "x": 1180, + "y": 560, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 70, + 81 + ] + }, + { + "x": 1180, + "y": 540, + "type": 2, + "bitWidth": "4", + "label": "", + "connections": [ + 71, + 79, + 80 + ] + } + ], + "id": 93663071628, + "name": "Main", + "Input": [ + { + "x": 790, + "y": 230, + "objectType": "Input", + "label": "A", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 5 + }, + "values": { + "state": 14332 + }, + "constructorParamaters": [ + "DOWN", + 16, + { + "x": 0, + "y": 60, + "id": "RSEDtPWAqfBaZZokKbtT" + } + ] + } + }, + { + "x": 1160, + "y": 230, + "objectType": "Input", + "label": "B", + "direction": "DOWN", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 6 + }, + "values": { + "state": 24572 + }, + "constructorParamaters": [ + "DOWN", + 16, + { + "x": 0, + "y": 20, + "id": "Txd27FkQfb3c95FRrcnk" + } + ] + } + }, + { + "x": 700, + "y": 450, + "objectType": "Input", + "label": "Cin", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 76 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "DemZmzyVBGIMNFmj70kj" + } + ] + } + } + ], + "Output": [ + { + "x": 1380, + "y": 440, + "objectType": "Output", + "label": "Cout", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 75 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 90, + "id": "tLrcFmdJBCxYVIMskoQb" + } + ] + } + }, + { + "x": 1020, + "y": 740, + "objectType": "Output", + "label": "Sum", + "direction": "UP", + "labelDirection": "DOWN", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 77 + }, + "constructorParamaters": [ + "UP", + 16, + { + "x": 100, + "y": 20, + "id": "o31VsUe37gDTsycMMgVW" + } + ] + } + }, + { + "x": 1250, + "y": 540, + "objectType": "Output", + "label": "", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 79 + }, + "constructorParamaters": [ + "LEFT", + "4", + { + "x": 100, + "y": 40, + "id": "XOjb1SYysdaUdivdnR9O" + } + ] + } + } + ], + "Splitter": [ + { + "x": 760, + "y": 270, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 8, + 9, + 10, + 11 + ], + "inp1": 7 + } + } + }, + { + "x": 1130, + "y": 270, + "objectType": "Splitter", + "label": "", + "direction": "DOWN", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "DOWN", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 13, + 14, + 15, + 16 + ], + "inp1": 12 + } + } + }, + { + "x": 940, + "y": 650, + "objectType": "Splitter", + "label": "", + "direction": "UP", + "labelDirection": "LEFT", + "propagationDelay": 100, + "customData": { + "constructorParamaters": [ + "UP", + 16, + [ + 4, + 4, + 4, + 4 + ] + ], + "nodes": { + "outputs": [ + 60, + 61, + 62, + 63 + ], + "inp1": 59 + } + } + } + ], + "SubCircuit": [ + { + "x": 760, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 0, + 1, + 2 + ], + "outputNodes": [ + 3, + 4 + ], + "version": "2.0" + }, + { + "x": 920, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 17, + 18, + 19 + ], + "outputNodes": [ + 20, + 21 + ], + "version": "2.0" + }, + { + "x": 1070, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 22, + 23, + 24 + ], + "outputNodes": [ + 25, + 26 + ], + "version": "2.0" + }, + { + "x": 1230, + "y": 390, + "id": "51553545569", + "label": "", + "labelDirection": "RIGHT", + "inputNodes": [ + 27, + 28, + 29 + ], + "outputNodes": [ + 30, + 31 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 78, + 80, + 81 + ] + } + ] +} diff --git a/v1/src/simulator/spec/circuits/sequential-circuitdata.json b/v1/src/simulator/spec/circuits/sequential-circuitdata.json new file mode 100644 index 00000000..b97d60ce --- /dev/null +++ b/v1/src/simulator/spec/circuits/sequential-circuitdata.json @@ -0,0 +1,1184 @@ +{ + "name": "sample", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "yDvzoCP6Qa2VDwWDoj5Q", + "focussedCircuit": 81140742990, + "orderedTabs": [ + "81140742990" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 220, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 3 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 19 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "D", + "connections": [ + 17 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 0 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 12 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 19 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 34 + ] + }, + { + "x": 790, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 5, + 34 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 20 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "D", + "connections": [ + 18 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 21 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 22 + ] + }, + { + "x": 600, + "y": 310, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 9, + 18 + ] + }, + { + "x": 600, + "y": 450, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 14, + 17, + 32 + ] + }, + { + "x": 480, + "y": 330, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 10, + 20 + ] + }, + { + "x": 480, + "y": 470, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 19, + 33 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 33 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "T", + "connections": [ + 32 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 30 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 31 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 36 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 25 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 26 + ] + }, + { + "x": 600, + "y": 620, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 24, + 49 + ] + }, + { + "x": 480, + "y": 640, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 20, + 23, + 50 + ] + }, + { + "x": 400, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 11, + 12, + 35 + ] + }, + { + "x": 400, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 34, + 36, + 47 + ] + }, + { + "x": 800, + "y": 710, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 27, + 35 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "J", + "connections": [ + 49 + ] + }, + { + "x": -20, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "K", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "Clock", + "connections": [ + 50 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 45 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 46 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 48 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 40 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 41 + ] + }, + { + "x": 400, + "y": 890, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 35, + 48, + 64 + ] + }, + { + "x": 790, + "y": 890, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 42, + 47 + ] + }, + { + "x": 600, + "y": 820, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 32, + 37, + 61 + ] + }, + { + "x": 480, + "y": 840, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 33, + 39 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 62 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "R", + "connections": [ + 63 + ] + }, + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "S", + "connections": [ + 61 + ] + }, + { + "x": 20, + "y": -10, + "type": 1, + "bitWidth": 1, + "label": "Q", + "connections": [ + 59 + ] + }, + { + "x": 20, + "y": 10, + "type": 1, + "bitWidth": 1, + "label": "Q Inverse", + "connections": [ + 60 + ] + }, + { + "x": 10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Asynchronous Reset", + "connections": [ + 65 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Preset", + "connections": [] + }, + { + "x": -10, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "Enable", + "connections": [] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 54 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 55 + ] + }, + { + "x": 600, + "y": 990, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 49, + 53 + ] + }, + { + "x": 570, + "y": 830, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 38, + 51, + 63 + ] + }, + { + "x": 570, + "y": 1010, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 52, + 62 + ] + }, + { + "x": 400, + "y": 1060, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 47, + 65 + ] + }, + { + "x": 790, + "y": 1060, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 56, + 64 + ] + } + ], + "id": 81140742990, + "name": "Main", + "Input": [ + { + "x": 270, + "y": 310, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 9 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "ADKJudOKQoIs54SteC0v" + } + ] + } + }, + { + "x": 270, + "y": 390, + "objectType": "Input", + "label": "RST", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "auACgXFHbJMmKSylcRIS" + } + ] + } + }, + { + "x": 540, + "y": 830, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 51 + }, + "values": { + "state": 0 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "gxYJoZ7q7csS6z5HFjAu" + } + ] + } + } + ], + "Output": [ + { + "x": 920, + "y": 310, + "objectType": "Output", + "label": "out1", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 0 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "p812Pea4ZmGV5PkGdpPe" + } + ] + } + }, + { + "x": 920, + "y": 330, + "objectType": "Output", + "label": "out2", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 8 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "bQnnZVmd5kDPIeO22TfP" + } + ] + } + }, + { + "x": 920, + "y": 450, + "objectType": "Output", + "label": "out3", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 21 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "7kEPCd8x0CsWmJDHGtz7" + } + ] + } + }, + { + "x": 920, + "y": 470, + "objectType": "Output", + "label": "out4", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 22 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 80, + "id": "umwIPzgaQxhyw3KXeoIe" + } + ] + } + }, + { + "x": 900, + "y": 620, + "objectType": "Output", + "label": "out5", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 30 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 100, + "id": "ACFEeZBErU96lY78ng2n" + } + ] + } + }, + { + "x": 900, + "y": 640, + "objectType": "Output", + "label": "out6", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 31 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 120, + "id": "3TD9jZdXa1AX43jOeh4V" + } + ] + } + }, + { + "x": 900, + "y": 820, + "objectType": "Output", + "label": "out7", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 45 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 140, + "id": "hCbf5heEes1MWbjfBxag" + } + ] + } + }, + { + "x": 900, + "y": 840, + "objectType": "Output", + "label": "out8", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 46 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 160, + "id": "U33L7gSGF200Koy8RUpn" + } + ] + } + }, + { + "x": 900, + "y": 990, + "objectType": "Output", + "label": "out9", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 59 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 180, + "id": "4rIpXftfQyQsEnQT7uXl" + } + ] + } + }, + { + "x": 900, + "y": 1010, + "objectType": "Output", + "label": "out10", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 60 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 200, + "id": "CYefIzHlGgRM7OF8Ctdw" + } + ] + } + } + ], + "TflipFlop": [ + { + "x": 790, + "y": 630, + "objectType": "TflipFlop", + "label": "T Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 23, + "dInp": 24, + "qOutput": 25, + "qInvOutput": 26, + "reset": 27, + "preset": 28, + "en": 29 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "JKflipFlop": [ + { + "x": 780, + "y": 830, + "objectType": "JKflipFlop", + "label": "Jk Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "J": 37, + "K": 38, + "clockInp": 39, + "qOutput": 40, + "qInvOutput": 41, + "reset": 42, + "preset": 43, + "en": 44 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "SRflipFlop": [ + { + "x": 780, + "y": 1000, + "objectType": "SRflipFlop", + "label": "SR Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "S": 53, + "R": 52, + "qOutput": 54, + "qInvOutput": 55, + "reset": 56, + "preset": 57, + "en": 58 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "DflipFlop": [ + { + "x": 780, + "y": 320, + "objectType": "DflipFlop", + "label": "D Flip Flop", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 1, + "dInp": 2, + "qOutput": 3, + "qInvOutput": 4, + "reset": 5, + "preset": 6, + "en": 7 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "Clock": [ + { + "x": 270, + "y": 330, + "objectType": "Clock", + "label": "CLOCK", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 10 + }, + "constructorParamaters": [ + "RIGHT" + ] + } + } + ], + "Dlatch": [ + { + "x": 790, + "y": 460, + "objectType": "Dlatch", + "label": "D latch", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 10, + "customData": { + "nodes": { + "clockInp": 13, + "dInp": 14, + "qOutput": 15, + "qInvOutput": 16 + }, + "constructorParamaters": [ + "RIGHT", + 1 + ] + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 12, + 17, + 18, + 19, + 20, + 32, + 33, + 34, + 35, + 36, + 47, + 48, + 49, + 50, + 61, + 62, + 63, + 64, + 65 + ] + } + ] +} diff --git a/v1/src/simulator/spec/circuits/subCircuit-circuitdata.json b/v1/src/simulator/spec/circuits/subCircuit-circuitdata.json new file mode 100644 index 00000000..e1703e76 --- /dev/null +++ b/v1/src/simulator/spec/circuits/subCircuit-circuitdata.json @@ -0,0 +1,814 @@ +{ + "name": "SubCircuit", + "timePeriod": 500, + "clockEnabled": true, + "projectId": "KXmhGDZlwFlzVjPmxY8g", + "focussedCircuit": 69980799589, + "orderedTabs": [ + "69980799589", + "98622262167" + ], + "scopes": [ + { + "layout": { + "width": 100, + "height": 60, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": -20, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": -20, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 12 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 7 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 9 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 13 + ] + }, + { + "x": 660, + "y": 250, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 7, + 11 + ] + }, + { + "x": 660, + "y": 370, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 6 + ] + }, + { + "x": 620, + "y": 230, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 0, + 9, + 10 + ] + }, + { + "x": 620, + "y": 390, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 4, + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 2 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + } + ], + "id": 98622262167, + "name": "Half-adder", + "Input": [ + { + "x": 580, + "y": 230, + "objectType": "Input", + "label": "inp1", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 10 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "yDbVL6dY6nnuOp5jcZ95" + } + ] + } + }, + { + "x": 580, + "y": 250, + "objectType": "Input", + "label": "inp2", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "xQoyxdS12E5xJ9dmz35B" + } + ] + } + } + ], + "Output": [ + { + "x": 990, + "y": 240, + "objectType": "Output", + "label": "sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 12 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 20, + "id": "dzWcRuJoJdE8Bg2MY1KI" + } + ] + } + }, + { + "x": 1010, + "y": 380, + "objectType": "Output", + "label": "carry", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 13 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "MxBKygipJq4eP2ofPb14" + } + ] + } + } + ], + "AndGate": [ + { + "x": 740, + "y": 380, + "objectType": "AndGate", + "label": "AND", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 3, + 4 + ], + "output1": 5 + } + } + } + ], + "XorGate": [ + { + "x": 750, + "y": 240, + "objectType": "XorGate", + "label": "Xor", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 0, + 1 + ], + "output1": 2 + } + } + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 6, + 7, + 8, + 9 + ] + }, + { + "layout": { + "width": 100, + "height": 80, + "title_x": 50, + "title_y": 13, + "titleEnabled": true + }, + "verilogMetadata": { + "isVerilogCircuit": false, + "isMainCircuit": false, + "code": "// Write Some Verilog Code Here!", + "subCircuitScopeIds": [] + }, + "allNodes": [ + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 6 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 21 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 100, + "y": 20, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 14 + ] + }, + { + "x": 100, + "y": 40, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 8 + ] + }, + { + "x": 0, + "y": 20, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 0 + ] + }, + { + "x": 0, + "y": 40, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 20 + ] + }, + { + "x": -10, + "y": -10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 5 + ] + }, + { + "x": -10, + "y": 10, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 24 + ] + }, + { + "x": 20, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 15 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 17 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 16 + ] + }, + { + "x": 10, + "y": 0, + "type": 1, + "bitWidth": 1, + "label": "", + "connections": [ + 18 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 4 + ] + }, + { + "x": 10, + "y": 0, + "type": 0, + "bitWidth": 1, + "label": "", + "connections": [ + 10 + ] + }, + { + "x": -270, + "y": 0, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 2, + 12 + ] + }, + { + "x": -310, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 3, + 11 + ] + }, + { + "x": -240, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 13, + 19 + ] + }, + { + "x": 40, + "y": 110, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 18, + 20 + ] + }, + { + "x": 40, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 7, + 19 + ] + }, + { + "x": -20, + "y": 20, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 1, + 22 + ] + }, + { + "x": -20, + "y": 70, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 21, + 23 + ] + }, + { + "x": 270, + "y": 70, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 22, + 24 + ] + }, + { + "x": 270, + "y": 40, + "type": 2, + "bitWidth": 1, + "label": "", + "connections": [ + 9, + 23 + ] + } + ], + "id": 69980799589, + "name": "Main", + "Input": [ + { + "x": -320, + "y": -140, + "objectType": "Input", + "label": "x", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 11 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 40, + "id": "TzPoFqkKRnczSlQMidjq" + } + ] + } + }, + { + "x": -280, + "y": -140, + "objectType": "Input", + "label": "y", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 12 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 60, + "id": "XBpwBuRDlldQywdEHsgz" + } + ] + } + }, + { + "x": -250, + "y": -140, + "objectType": "Input", + "label": "cin", + "direction": "RIGHT", + "labelDirection": "UP", + "propagationDelay": 0, + "customData": { + "nodes": { + "output1": 13 + }, + "values": { + "state": 1 + }, + "constructorParamaters": [ + "RIGHT", + 1, + { + "x": 0, + "y": 20, + "id": "HQYLk2tHMKI6uYYikApo" + } + ] + } + } + ], + "Output": [ + { + "x": 420, + "y": 0, + "objectType": "Output", + "label": "sum", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 14 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 40, + "id": "GOiOE9VzXMlMW1txqFEb" + } + ] + } + }, + { + "x": 420, + "y": 30, + "objectType": "Output", + "label": "carry", + "direction": "LEFT", + "labelDirection": "RIGHT", + "propagationDelay": 0, + "customData": { + "nodes": { + "inp1": 15 + }, + "constructorParamaters": [ + "LEFT", + 1, + { + "x": 100, + "y": 60, + "id": "ASuCOL13vtFBub8uPD7N" + } + ] + } + } + ], + "OrGate": [ + { + "x": 320, + "y": 30, + "objectType": "OrGate", + "label": "", + "direction": "RIGHT", + "labelDirection": "LEFT", + "propagationDelay": 10, + "customData": { + "constructorParamaters": [ + "RIGHT", + 2, + 1 + ], + "nodes": { + "inp": [ + 8, + 9 + ], + "output1": 10 + } + } + } + ], + "SubCircuit": [ + { + "x": -180, + "y": -20, + "id": "98622262167", + "label": "half-adder", + "labelDirection": "UP", + "inputNodes": [ + 2, + 3 + ], + "outputNodes": [ + 0, + 1 + ], + "version": "2.0" + }, + { + "x": 110, + "y": -20, + "id": "98622262167", + "label": "half-adder", + "labelDirection": "UP", + "inputNodes": [ + 6, + 7 + ], + "outputNodes": [ + 4, + 5 + ], + "version": "2.0" + } + ], + "restrictedCircuitElementsUsed": [], + "nodes": [ + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24 + ] + } + ] +} diff --git a/v1/src/simulator/spec/combinationalAnalysis.spec.js b/v1/src/simulator/spec/combinationalAnalysis.spec.js new file mode 100644 index 00000000..646187cd --- /dev/null +++ b/v1/src/simulator/spec/combinationalAnalysis.spec.js @@ -0,0 +1,92 @@ +import { setup } from '../src/setup'; +import { runAll } from '../src/testbench'; +import testData from './testData/gates-testdata.json'; +import { GenerateCircuit, performCombinationalAnalysis } from '../src/combinationalAnalysis'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Combinational Analysis Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('performCombinationalAnalysis function working', () => { + expect(() => performCombinationalAnalysis('', '', 'AB')).not.toThrow(); + }); + + test('Generating Circuit', () => { + expect(() => GenerateCircuit([13], ['A', 'B'], [0, 0, 0, 1], 'AB')).not.toThrow(); + }); + + test('testing Combinational circuit', () => { + testData.AndGate.groups[0].inputs[0].label = 'A'; + testData.AndGate.groups[0].inputs[1].label = 'B'; + testData.AndGate.groups[0].outputs[0].label = 'AB'; + + const result = runAll(testData.AndGate); + expect(result.summary.passed).toBe(3); + }); +}); diff --git a/v1/src/simulator/spec/complexCircuit.spec.js b/v1/src/simulator/spec/complexCircuit.spec.js new file mode 100644 index 00000000..32b33083 --- /dev/null +++ b/v1/src/simulator/spec/complexCircuit.spec.js @@ -0,0 +1,96 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import { runAll } from '../src/testbench'; +import aluCircuitData from './circuits/alu-circuitdata.json'; +import rippleCircuitData from './circuits/rippleCarryAdder-circuitdata.json'; +import rippleTestData from './testData/ripple-carry-adder.json'; +import aluTestData from './testData/alu-testdata.json'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('data dir working', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load ripple carry adder circuit-data', () => { + expect(() => load(rippleCircuitData)).not.toThrow(); + }); + + test('ripple carry adder circuit testing', () => { + const result = runAll(rippleTestData.testData); + expect(result.summary.passed).toBe(10); + }); + + test('load ALU circuit-data', () => { + expect(() => load(aluCircuitData)).not.toThrow(); + }); + + test('ALU circuit testing', () => { + const result = runAll(aluTestData.testData); + expect(result.summary.passed).toBe(5); + }); +}); diff --git a/v1/src/simulator/spec/data.spec.js b/v1/src/simulator/spec/data.spec.js index f91a08c8..f1626d66 100644 --- a/v1/src/simulator/spec/data.spec.js +++ b/v1/src/simulator/spec/data.spec.js @@ -1,121 +1,170 @@ -/** - * @jest-environment jsdom - */ - -import CodeMirror from 'codemirror' -import { setup } from '../src/setup' -import load from '../src/data/load' -import gatesCircuitData from './circuits/gates-circuitdata.json' -import decoderCircuitData from './circuits/Decoders-plexers-circuitdata.json' -import { checkIfBackup, scheduleBackup } from '../src/data/backupCircuit' -import undo from '../src/data/undo' -import redo from '../src/data/redo' -import save from '../src/data/save' +import { describe, test, expect, vi, beforeAll } from 'vitest'; +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import gatesCircuitData from './circuits/gates-circuitdata.json'; +import decoderCircuitData from './circuits/Decoders-plexers-circuitdata.json'; +import { checkIfBackup, scheduleBackup } from '../src/data/backupCircuit'; +import undo from '../src/data/undo'; +import redo from '../src/data/redo'; +import save from '../src/data/save'; import { clearProject, newProject, recoverProject, saveOffline, openOffline, -} from '../src/data/project' -import createSaveAsImgPrompt from '../src/data/saveImage' - -jest.mock('codemirror') +} from '../src/data/project'; +import createSaveAsImgPrompt from '../src/data/saveImage'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import simulator from '#/pages/simulatorHandler.vue'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import vuetify from '#/plugins/vuetify'; +import { routes } from '#/router'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => {} })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); describe('data dir working', () => { - CodeMirror.fromTextArea.mockReturnValueOnce({ setValue: () => {} }) - window.confirm = jest.fn(() => true) - setup() + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); test('load gates_circuitData without throwing error', () => { - expect(() => load(gatesCircuitData)).not.toThrow() - }) + expect(() => load(gatesCircuitData)).not.toThrow(); + }); test('should load another circuit data decoder_circuitData', () => { - expect(() => load(decoderCircuitData)).not.toThrow() - }) + expect(() => load(decoderCircuitData)).not.toThrow(); + }); test('schedule backup working', () => { - // toggle states of inputs a dn then run schedule backup globalScope.Input.forEach((input) => { - input.state = input.state === 1 ? 0 : 1 - expect(() => scheduleBackup()).not.toThrow() - }) - }) + input.state = input.state === 1 ? 0 : 1; + expect(() => scheduleBackup()).not.toThrow(); + }); + }); test('check if backup performed', () => { - expect(() => checkIfBackup(globalScope)).toBeTruthy() - }) + expect(checkIfBackup(globalScope)).toBeTruthy(); + }); test('undo working', () => { const beforeUndo = { backups: globalScope.backups.length, history: globalScope.history.length, - } + }; for (let i = 1; i < beforeUndo.backups; i++) { - undo() + undo(); const afterUndo = { backups: globalScope.backups.length + i, history: globalScope.history.length - i, - } - expect(afterUndo).toEqual(beforeUndo) + }; + expect(afterUndo).toEqual(beforeUndo); } - }) + }); test('redo working', () => { const beforeRedo = { backups: globalScope.backups.length, history: globalScope.history.length, - } + }; for (let i = 1; i < beforeRedo.history; i++) { - redo() + redo(); const afterRedo = { backups: globalScope.backups.length - i, history: globalScope.history.length + i, - } - expect(afterRedo).toEqual(beforeRedo) + }; + expect(afterRedo).toEqual(beforeRedo); } - }) + }); test('save updated circuit_data', () => { - // save project - window.logixProjectId = decoderCircuitData.projectId - expect(() => save()).not.toThrow() - }) + window.logixProjectId = decoderCircuitData.projectId; + expect(() => save()).not.toThrow(); + }); test('project working', () => { - // create new project - expect(() => newProject(true)).not.toThrow() - }) + expect(() => newProject(true)).not.toThrow(); + }); test('clear Project working', () => { - // clear project - expect(() => clearProject()).not.toThrow() - }) + expect(() => clearProject()).not.toThrow(); + }); test('recover Project working', () => { - // recover project from localstorage - localStorage.setItem('recover', JSON.stringify(gatesCircuitData)) - expect(() => recoverProject()).not.toThrow() - }) + localStorage.setItem('recover', JSON.stringify(gatesCircuitData)); + expect(() => recoverProject()).not.toThrow(); + }); test('SaveOffline working', () => { - // save offline gate project - expect(() => saveOffline()).not.toThrow() - }) + expect(() => saveOffline()).not.toThrow(); + }); test('OpenOffline working', () => { - // open dialog - openOffline() - // click on first input - $('#openProjectDialog input')[0].click() - // click on open button - $('#Open_offline_btn')[0].click() - // it should load the offline saved project - expect(globalScope.id).toBe(11597572508) - }) + openOffline(); + document.querySelector('#openProjectDialog input')?.click(); + document.querySelector('#Open_offline_btn')?.click(); + expect(globalScope.id).toBe(11597572508); + }); test('saveImage working', () => { - expect(() => createSaveAsImgPrompt()).not.toThrow() - }) -}) + expect(() => createSaveAsImgPrompt()).not.toThrow(); + }); +}); diff --git a/v1/src/simulator/spec/decoders-plexers.spec.js b/v1/src/simulator/spec/decoders-plexers.spec.js new file mode 100644 index 00000000..2c4151b1 --- /dev/null +++ b/v1/src/simulator/spec/decoders-plexers.spec.js @@ -0,0 +1,115 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/Decoders-plexers-circuitdata.json'; +import testData from './testData/decoders-plexers.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Decoders and Plexers Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load decoders-plexers circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('Multiplexer working', () => { + const result = runAll(testData.Multiplexers); + expect(result.summary.passed).toBe(8); + }); + + test('Demultiplexer working', () => { + const result = runAll(testData.Demultiplexer); + expect(result.summary.passed).toBe(4); + }); + + test('BitSelector working', () => { + const result = runAll(testData['bit-selector']); + expect(result.summary.passed).toBe(4); + }); + + test('MSB working', () => { + const result = runAll(testData.msb); + expect(result.summary.passed).toBe(5); + }); + + test('LSB working', () => { + const result = runAll(testData.lsb); + expect(result.summary.passed).toBe(10); + }); + + test('Priority Encoder working', () => { + const result = runAll(testData['priority-encoder']); + expect(result.summary.passed).toBe(4); + }); + + test('Decoder working', () => { + const result = runAll(testData.Decoder); + expect(result.summary.passed).toBe(2); + }); +}); diff --git a/v1/src/simulator/spec/gates.spec.js b/v1/src/simulator/spec/gates.spec.js index 90c7b1bd..1af5a4a7 100644 --- a/v1/src/simulator/spec/gates.spec.js +++ b/v1/src/simulator/spec/gates.spec.js @@ -1,57 +1,115 @@ -/** - * @jest-environment jsdom - */ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/gates-circuitdata.json'; +import testData from './testData/gates-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; -import CodeMirror from 'codemirror' -import { setup } from '../src/setup' +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); -import load from '../src/data/load' -import circuitData from './circuits/gates-circuitdata.json' -import testData from './testData/gates-testdata.json' -import { runAll } from '../src/testbench' +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); -jest.mock('codemirror') +describe('Simulator Gates Working', () => { + let pinia; + let router; -describe('Simulator Gates Testing', () => { - CodeMirror.fromTextArea.mockReturnValueOnce({ setValue: (text) => {} }) - setup() + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); test('load circuitData', () => { - expect(() => load(circuitData)).not.toThrow() - }) - - test('AND gate testing', () => { - const result = runAll(testData.AndGate) - expect(result.summary.passed).toBe(4) - }) - - test('NAND gate testing', () => { - const result = runAll(testData.nandGate) - expect(result.summary.passed).toBe(4) - }) - - test('NOR gate testing', () => { - const result = runAll(testData.norGate) - expect(result.summary.passed).toBe(4) - }) - - test('NOT gate testing', () => { - const result = runAll(testData.notGate) - expect(result.summary.passed).toBe(2) - }) - - test('OR gate testing', () => { - const result = runAll(testData.OrGate) - expect(result.summary.passed).toBe(4) - }) - - test('XNOR gate testing', () => { - const result = runAll(testData.xnorGate) - expect(result.summary.passed).toBe(4) - }) - - test('XOR gate testing', () => { - const result = runAll(testData.xorGate) - expect(result.summary.passed).toBe(4) - }) -}) + expect(() => load(circuitData)).not.toThrow(); + }); + + test('AND gate working', () => { + const result = runAll(testData.AndGate); + expect(result.summary.passed).toBe(4); + }); + + test('NAND gate working', () => { + const result = runAll(testData.nandGate); + expect(result.summary.passed).toBe(4); + }); + + test('NOR gate working', () => { + const result = runAll(testData.norGate); + expect(result.summary.passed).toBe(4); + }); + + test('NOT gate working', () => { + const result = runAll(testData.notGate); + expect(result.summary.passed).toBe(2); + }); + + test('OR gate working', () => { + const result = runAll(testData.OrGate); + expect(result.summary.passed).toBe(4); + }); + + test('XNOR gate working', () => { + const result = runAll(testData.xnorGate); + expect(result.summary.passed).toBe(4); + }); + + test('XOR gate working', () => { + const result = runAll(testData.xorGate); + expect(result.summary.passed).toBe(4); + }); +}); diff --git a/v1/src/simulator/spec/misc.spec.js b/v1/src/simulator/spec/misc.spec.js new file mode 100644 index 00000000..57a217e2 --- /dev/null +++ b/v1/src/simulator/spec/misc.spec.js @@ -0,0 +1,130 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/misc-circuitdata.json'; +import testData from './testData/misc-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Misc-Elements Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('ALU working', () => { + const result = runAll(testData.ALU); + expect(result.summary.passed).toBe(28); + }); + + test('Adder working', () => { + const result = runAll(testData.Adder); + expect(result.summary.passed).toBe(8); + }); + + test('Buffer working', () => { + const result = runAll(testData.buffer); + expect(result.summary.passed).toBe(2); + }); + + test('TriState Buffer working', () => { + const result = runAll(testData.Tristate); + expect(result.summary.passed).toBe(4); + }); + + test('Tunnel working', () => { + const result = runAll(testData.Tunnel); + expect(result.summary.passed).toBe(2); + }); + + test("2's Compliment working", () => { + const result = runAll(testData.comp); + expect(result.summary.passed).toBe(8); + }); + + test('Controlled Inverter working', () => { + const result = runAll(testData.ControlledInverter); + expect(result.summary.passed).toBe(3); + }); + + test('Equal Splitter working', () => { + const result = runAll(testData.SplitterEqual); + expect(result.summary.passed).toBe(8); + }); + + test('UnEqual Splitter working', () => { + const result = runAll(testData.SplitterUnEqual); + expect(result.summary.passed).toBe(8); + }); + + test('Force Gate working', () => { + const result = runAll(testData.ForceGate); + expect(result.summary.passed).toBe(2); + }); +}); diff --git a/v1/src/simulator/spec/sequential.spec.js b/v1/src/simulator/spec/sequential.spec.js new file mode 100644 index 00000000..74cdb75f --- /dev/null +++ b/v1/src/simulator/spec/sequential.spec.js @@ -0,0 +1,105 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/sequential-circuitdata.json'; +import testData from './testData/sequential-testdata.json'; +import { runAll } from '../src/testbench'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('Simulator Sequential Element Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load circuitData', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('D Flip Flop working', () => { + const result = runAll(testData.DFlipFlop); + expect(result.summary.passed).toBe(2); + }); + + test('D latch working', () => { + const result = runAll(testData.DLatch); + expect(result.summary.passed).toBe(2); + }); + + test('JK Flip Flop working', () => { + const result = runAll(testData.JkFlipFlop); + expect(result.summary.passed).toBe(4); + }); + + test('SR Flip Flop working', () => { + const result = runAll(testData.SRFlipFlop); + expect(result.summary.passed).toBe(4); + }); + + test('T Flip Flop working', () => { + const result = runAll(testData.TFlipFlop); + expect(result.summary.passed).toBe(4); + }); +}); diff --git a/v1/src/simulator/spec/subCircuit.spec.js b/v1/src/simulator/spec/subCircuit.spec.js new file mode 100644 index 00000000..f8bae60b --- /dev/null +++ b/v1/src/simulator/spec/subCircuit.spec.js @@ -0,0 +1,85 @@ +import { setup } from '../src/setup'; +import load from '../src/data/load'; +import circuitData from './circuits/subCircuit-circuitdata.json'; +import { runAll } from '../src/testbench'; +import testData from './testData/subCircuit-testdata.json'; +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { createRouter, createWebHistory } from 'vue-router'; +import i18n from '#/locales/i18n'; +import { routes } from '#/router'; +import vuetify from '#/plugins/vuetify'; +import simulator from '#/pages/simulator.vue'; + +vi.mock('codemirror', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + fromTextArea: vi.fn(() => ({ setValue: () => { } })), + }; +}); + +vi.mock('codemirror-editor-vue3', () => ({ + defineSimpleMode: vi.fn(), +})); + +describe('SubCircuit Testing', () => { + let pinia; + let router; + + beforeAll(async () => { + pinia = createPinia(); + setActivePinia(pinia); + + router = createRouter({ + history: createWebHistory(), + routes, + }); + + const elem = document.createElement('div') + + if (document.body) { + document.body.appendChild(elem) + } + + global.document.createRange = vi.fn(() => ({ + setEnd: vi.fn(), + setStart: vi.fn(), + getBoundingClientRect: vi.fn(() => ({ + x: 0, + y: 0, + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + })), + getClientRects: vi.fn(() => ({ + item: vi.fn(() => null), + length: 0, + [Symbol.iterator]: vi.fn(() => []), + })), + })); + + global.globalScope = global.globalScope || {}; + + mount(simulator, { + global: { + plugins: [pinia, router, i18n, vuetify], + }, + attachTo: elem, + }); + + setup(); + }); + + test('load subCircuit data without throwing error', () => { + expect(() => load(circuitData)).not.toThrow(); + }); + + test('subCircuit working', () => { + const result = runAll(testData.subCircuit); + expect(result.summary.passed).toBe(8); + }); +}); diff --git a/v1/src/simulator/spec/testData/alu-testdata.json b/v1/src/simulator/spec/testData/alu-testdata.json new file mode 100644 index 00000000..ada54b17 --- /dev/null +++ b/v1/src/simulator/spec/testData/alu-testdata.json @@ -0,0 +1,108 @@ +{ + "testData": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "S", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0010", + "1111", + "0100" + ] + }, + { + "label": "~A", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "1100", + "1100", + "1111" + ] + }, + { + "label": "~B", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "1100", + "1100", + "1100" + ] + }, + { + "label": "Mode", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1" + ] + }, + { + "label": "~Cn", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "~F", + "bitWidth": 4, + "values": [ + "0001", + "0000", + "1111", + "1011", + "0011" + ], + "results": [ + "0001", + "0000", + "1111", + "1011", + "0011" + ] + }, + { + "label": "A=B", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0", + "0" + ], + "results": [ + "0", + "0", + "1", + "0", + "0" + ] + } + ], + "n": 5 + } + ] + } +} + diff --git a/v1/src/simulator/spec/testData/decoders-plexers.json b/v1/src/simulator/spec/testData/decoders-plexers.json new file mode 100644 index 00000000..504919c3 --- /dev/null +++ b/v1/src/simulator/spec/testData/decoders-plexers.json @@ -0,0 +1,401 @@ +{ + "Multiplexers": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Multiplexers", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "Demultiplexer":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Demultiplexer", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "out2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "0" + ] + }, + { + "label": "out3", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "Decoder":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "Decoder", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out11", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + }, + { + "label": "out12", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "priority-encoder":{ + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "priority-encoder", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp4", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out9", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "out10", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "en", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "bit-selector": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "bit-selector", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0001", + "0010", + "0100", + "1000" + ] + }, + { + "label": "CS", + "bitWidth": 2, + "values": [ + "00", + "01", + "10", + "11" + ] + } + ], + "outputs": [ + { + "label": "out13", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "msb": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "msb", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0000", + "0001", + "0010", + "0100", + "1000" + ] + } + ], + "outputs": [ + { + "label": "out4", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0001", + "0010", + "0011" + ] + }, + { + "label": "out5", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1" + ] + } + ], + "n": 5 + } + ] + }, + "lsb": { + "type": "comb", + "title": "Decoders And Plexers", + "groups": [ + { + "label": "lsb", + "inputs": [ + { + "label": "inp5", + "bitWidth": 4, + "values": [ + "0000", + "0001", + "0011", + "0111", + "1111", + "1000", + "1100", + "1110", + "0100", + "0010" + ] + } + ], + "outputs": [ + { + "label": "out6", + "bitWidth": 4, + "values": [ + "0000", + "0000", + "0000", + "0000", + "0000", + "0011", + "0010", + "0001", + "0010", + "0001" + ] + }, + { + "label": "out7", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "1", + "1" + ] + } + ], + "n": 10 + } + ] + } + } diff --git a/v1/src/simulator/spec/testData/gates-testdata.json b/v1/src/simulator/spec/testData/gates-testdata.json index 3152253b..18cdf8fc 100644 --- a/v1/src/simulator/spec/testData/gates-testdata.json +++ b/v1/src/simulator/spec/testData/gates-testdata.json @@ -1,200 +1,296 @@ { - "AndGate": { - "type": "comb", - "title": "AND Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out1", - "bitWidth": 1, - "values": ["0", "0", "0", "1"] - } - ], - "n": 4 - } - ] - }, - "OrGate": { - "type": "comb", - "title": "OR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out2", - "bitWidth": 1, - "values": ["0", "1", "1", "1"] - } - ], - "n": 4 - } - ] - }, - "nandGate": { - "type": "comb", - "title": "NAND Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out3", - "bitWidth": 1, - "values": ["1", "1", "1", "0"] - } - ], - "n": 4 - } - ] - }, - "xorGate": { - "type": "comb", - "title": "XOR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out6", - "bitWidth": 1, - "values": ["0", "1", "1", "0"] - } - ], - "n": 4 - } - ] - }, - "norGate": { - "type": "comb", - "title": "NOR Gate", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out7", - "bitWidth": 1, - "values": ["1", "0", "0", "0"] - } - ], - "n": 4 - } - ] - }, - "notGate": { - "type": "comb", - "title": "NOT GAte", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "1"] - } - ], - "outputs": [ - { - "label": "out4", - "bitWidth": 1, - "values": ["1", "0"] - } - ], - "n": 2 - } - ] - }, - "xnorGate": { - "type": "comb", - "title": "XNOR GAte", - "groups": [ - { - "label": "Group 1", - "inputs": [ - { - "label": "inp1", - "bitWidth": 1, - "values": ["0", "0", "1", "1"] - }, - { - "label": "inp2", - "bitWidth": 1, - "values": ["0", "1", "0", "1"] - } - ], - "outputs": [ - { - "label": "out5", - "bitWidth": 1, - "values": ["1", "0", "0", "1"] - } - ], - "n": 4 - } - ] - } + "AndGate": { + "type": "comb", + "title": "AND Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "OrGate": { + "type": "comb", + "title": "OR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "nandGate": { + "type": "comb", + "title": "NAND Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out3", + "bitWidth": 1, + "values": [ + "1", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "xorGate": { + "type": "comb", + "title": "XOR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out6", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "norGate": { + "type": "comb", + "title": "NOR Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out7", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "notGate": { + "type": "comb", + "title": "NOT GAte", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out4", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "xnorGate": { + "type": "comb", + "title": "XNOR GAte", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out5", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + } } diff --git a/v1/src/simulator/spec/testData/misc-testdata.json b/v1/src/simulator/spec/testData/misc-testdata.json new file mode 100644 index 00000000..df7e6509 --- /dev/null +++ b/v1/src/simulator/spec/testData/misc-testdata.json @@ -0,0 +1,959 @@ +{ + "ALU": { + "type": "comb", + "title": "ALU", + "groups": [ + { + "label": "000", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "000", + "000", + "000" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0" + ], + "results": [ + "0", + "0", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "001", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "001", + "001", + "001", + "001" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ], + "results": [ + "0", + "1", + "1", + "1" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "010", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "010", + "010", + "010", + "010" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1" + ], + "results": [ + "0", + "0", + "0", + "1" + ] + } + ], + "n": 4 + }, + { + "label": "100", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "100", + "100", + "100", + "100" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0" + ], + "results": [ + "0", + "0", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "101", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "101", + "101", + "101", + "101" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1", + "1" + ], + "results": [ + "1", + "0", + "1", + "1" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "110", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "110", + "110", + "110", + "110" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + }, + { + "label": "111", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "mode", + "bitWidth": 3, + "values": [ + "111", + "111", + "111", + "111" + ] + } + ], + "outputs": [ + { + "label": "ALU-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "0" + ], + "results": [ + "0", + "1", + "0", + "0" + ] + }, + { + "label": "ALU-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0" + ], + "results": [ + "0", + "0", + "0", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "Adder": { + "type": "comb", + "title": "Adder", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Adder-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "Adder-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "buffer": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "buffer-out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "Tristate": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + }, + { + "label": "enable", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "T-state-out1", + "bitWidth": 1, + "values": [ + "X", + "X", + "0", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "Tunnel": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Tunnel-out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 2 + } + ] + }, + "comp": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "001", + "010", + "011", + "100", + "101", + "110", + "111" + ] + } + ], + "outputs": [ + { + "label": "2s-out1", + "bitWidth": 3, + "values": [ + "000", + "111", + "110", + "101", + "100", + "011", + "010", + "001" + ] + } + ], + "n": 8 + } + ] + }, + "ControlledInverter": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1" + ] + }, + { + "label": "enable", + "bitWidth": 1, + "values": [ + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "CI-out1", + "bitWidth": 1, + "values": [ + "X", + "1", + "0" + ] + } + ], + "n": 3 + } + ] + }, + "SplitterEqual": { + "type": "comb", + "title": "Splitter", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "inp3", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Adder-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ], + "results": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "Adder-out2", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ], + "results": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + }, + "SplitterUnEqual": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "mode", + "bitWidth": 3, + "values": [ + "000", + "001", + "010", + "011", + "100", + "101", + "110", + "111" + ] + } + ], + "outputs": [ + { + "label": "s-un-out1", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + }, + { + "label": "s-un-out2", + "bitWidth": 2, + "values": [ + "00", + "00", + "01", + "01", + "10", + "10", + "11", + "11" + ] + } + ], + "n": 8 + } + ] + }, + "ForceGate": { + "type": "comb", + "title": "Force Gate", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "Force-out", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "n": 8 + } + ] + } +} diff --git a/v1/src/simulator/spec/testData/ripple-carry-adder.json b/v1/src/simulator/spec/testData/ripple-carry-adder.json new file mode 100644 index 00000000..1a76b9ce --- /dev/null +++ b/v1/src/simulator/spec/testData/ripple-carry-adder.json @@ -0,0 +1,92 @@ +{ + "testData": { + "type": "comb", + "title": "Untitled", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "A", + "bitWidth": 16, + "values": [ + "0", + "1111111111111111", + "1111111111111111", + "1111111111111110", + "1111111111111110", + "1111111111111100", + "1111111111111100", + "0011111111111100", + "0011111111111100", + "0011011111111100" + ] + }, + { + "label": "B", + "bitWidth": 16, + "values": [ + "0", + "1111111111111111", + "1111111111111111", + "1111111111111110", + "1111111111111110", + "1111111111111100", + "1111111111111100", + "1101111111111100", + "1101111111111100", + "0101111111111100" + ] + }, + { + "label": "Cin", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1", + "1" + ] + } + ], + "outputs": [ + { + "label": "Sum", + "bitWidth": 16, + "values": [ + "0000000000000000", + "1111111111111110", + "1111111111111111", + "1111111111111100", + "1111111111111101", + "1111111111111000", + "1111111111111001", + "0001111111111000", + "0001111111111001", + "1001011111111001" + ], + "results": [ + "0000000000000000", + "1111111111111110", + "1111111111111111", + "1111111111111100", + "1111111111111101", + "1111111111111000", + "1111111111111001", + "0001111111111000", + "0001111111111001", + "1001011111111001" + ] + } + ], + "n": 10 + } + ] + } +} diff --git a/v1/src/simulator/spec/testData/sequential-testdata.json b/v1/src/simulator/spec/testData/sequential-testdata.json new file mode 100644 index 00000000..545ed223 --- /dev/null +++ b/v1/src/simulator/spec/testData/sequential-testdata.json @@ -0,0 +1,250 @@ +{ + "DFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out1", + "bitWidth": 1, + "values": [ + "0", + "1" + ], + "results": [ + "0", + "1" + ] + }, + { + "label": "out2", + "bitWidth": 1, + "values": [ + "1", + "0" + ], + "results": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "DLatch": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out3", + "bitWidth": 1, + "values": [ + "0", + "1" + ] + }, + { + "label": "out4", + "bitWidth": 1, + "values": [ + "1", + "0" + ] + } + ], + "n": 2 + } + ] + }, + "JkFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out7", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ], + "results": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "out8", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0" + ], + "results": [ + "0", + "1", + "1", + "0" + ] + } + ], + "n": 4 + } + ] + }, + "SRFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "1" + ] + }, + { + "label": "inp2", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "out9", + "bitWidth": 1, + "values": [ + "1", + "0", + "0", + "0" + ] + }, + { + "label": "out10", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + }, + "TFlipFlop": { + "type": "seq", + "title": "Untitled", + "groups": [ + { + "label": "Set 1", + "inputs": [ + { + "label": "inp1", + "bitWidth": 1, + "values": [ + "1", + "0", + "1", + "0" + ] + } + ], + "outputs": [ + { + "label": "out5", + "bitWidth": 1, + "values": [ + "1", + "1", + "0", + "0" + ] + }, + { + "label": "out6", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1" + ] + } + ], + "n": 4 + } + ] + } +} diff --git a/v1/src/simulator/spec/testData/subCircuit-testdata.json b/v1/src/simulator/spec/testData/subCircuit-testdata.json new file mode 100644 index 00000000..2bd50617 --- /dev/null +++ b/v1/src/simulator/spec/testData/subCircuit-testdata.json @@ -0,0 +1,86 @@ +{ + "subCircuit": { + "type": "comb", + "title": "fullAdder", + "groups": [ + { + "label": "Group 1", + "inputs": [ + { + "label": "x", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "0", + "1", + "1", + "1", + "1" + ] + }, + { + "label": "y", + "bitWidth": 1, + "values": [ + "0", + "0", + "1", + "1", + "0", + "0", + "1", + "1" + ] + }, + { + "label": "cin", + "bitWidth": 1, + "values": [ + "0", + "1", + "0", + "1", + "0", + "1", + "0", + "1" + ] + } + ], + "outputs": [ + { + "label": "sum", + "bitWidth": 1, + "values": [ + "0", + "1", + "1", + "0", + "1", + "0", + "0", + "1" + ] + }, + { + "label": "carry", + "bitWidth": 1, + "values": [ + "0", + "0", + "0", + "1", + "0", + "1", + "1", + "1" + ] + } + ], + "n": 8 + } + ] + } + } diff --git a/v1/src/simulator/spec/vitestSetup.ts b/v1/src/simulator/spec/vitestSetup.ts new file mode 100644 index 00000000..1f2780a0 --- /dev/null +++ b/v1/src/simulator/spec/vitestSetup.ts @@ -0,0 +1,11 @@ +global.window = window; +global.jQuery = require('jquery'); +global.DPR = true; +global.width = true; +global.height = true; + +window.Jquery = require('jquery'); +window.$ = require('jquery'); +window.restrictedElements = []; +window.userSignedIn = true; +window.embed = false; diff --git a/v1/src/simulator/src/Verilog2CV.js b/v1/src/simulator/src/Verilog2CV.js index 83e7641e..bc1a755d 100644 --- a/v1/src/simulator/src/Verilog2CV.js +++ b/v1/src/simulator/src/Verilog2CV.js @@ -4,7 +4,7 @@ import { changeCircuitName, } from './circuit' import SubCircuit from './subcircuit' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import CodeMirror from 'codemirror/lib/codemirror.js' import 'codemirror/lib/codemirror.css' @@ -31,6 +31,8 @@ import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/display/autorefresh.js' import { showError, showMessage } from './utils' import { showProperties } from './ux' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' var editor var verilogMode = false @@ -42,7 +44,17 @@ export async function createVerilogCircuit() { true, true ) - if (returned) verilogModeSet(true) + + if (returned) { + verilogModeSet(true) + + try { + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) + simulatorMobileStore.isVerilog.value = true + } catch (error) { + console.error('Failed to update simulatorMobileStore:', error) + } + } } export function saveVerilogCode() { @@ -72,11 +84,26 @@ export function verilogModeSet(mode) { if (mode == verilogMode) return verilogMode = mode if (mode) { + const code_window = document.getElementById('code-window') + if(code_window) document.getElementById('code-window').style.display = 'block' + + const elementPanel = document.querySelector('.elementPanel') + if(elementPanel) document.querySelector('.elementPanel').style.display = 'none' + + const timingDiagramPanel = document.querySelector('.timing-diagram-panel') + if(timingDiagramPanel) document.querySelector('.timing-diagram-panel').style.display = 'none' + + const quickBtn = document.querySelector('.quick-btn') + if(quickBtn) document.querySelector('.quick-btn').style.display = 'none' + + const verilogEditorPanel = document.getElementById('verilogEditorPanel') + if(verilogEditorPanel) document.getElementById('verilogEditorPanel').style.display = 'block' + if (!embed) { simulationArea.lastSelected = globalScope.root showProperties(undefined) @@ -84,10 +111,24 @@ export function verilogModeSet(mode) { } resetVerilogCode() } else { + const code_window = document.getElementById('code-window') + if(code_window) document.getElementById('code-window').style.display = 'none' + + const elementPanel = document.querySelector('.elementPanel') + if(elementPanel) document.querySelector('.elementPanel').style.display = '' + + const timingDiagramPanel = document.querySelector('.timing-diagram-panel') + if(timingDiagramPanel) document.querySelector('.timing-diagram-panel').style.display = '' + + const quickBtn = document.querySelector('.quick-btn') + if(quickBtn) document.querySelector('.quick-btn').style.display = '' + + const verilogEditorPanel = document.getElementById('verilogEditorPanel') + if(verilogEditorPanel) document.getElementById('verilogEditorPanel').style.display = 'none' } } diff --git a/v1/src/simulator/src/VerilogClasses.js b/v1/src/simulator/src/VerilogClasses.js index 253748af..3dfe92ca 100644 --- a/v1/src/simulator/src/VerilogClasses.js +++ b/v1/src/simulator/src/VerilogClasses.js @@ -3,67 +3,27 @@ import NandGate from './modules/NandGate' import Multiplexer from './modules/Multiplexer' import XorGate from './modules/XorGate' import XnorGate from './modules/XnorGate' -import SevenSegDisplay from './modules/SevenSegDisplay' -import SixteenSegDisplay from './modules/SixteenSegDisplay' -import HexDisplay from './modules/HexDisplay' import OrGate from './modules/OrGate' -import Stepper from './modules/Stepper' import NotGate from './modules/NotGate' -import Text from './modules/Text' -import TriState from './modules/TriState' import Buffer from './modules/Buffer' -import ControlledInverter from './modules/ControlledInverter' import Adder from './modules/Adder' import verilogMultiplier from './modules/verilogMultiplier' import verilogDivider from './modules/verilogDivider' import verilogPower from './modules/verilogPower' import verilogShiftLeft from './modules/verilogShiftLeft' import verilogShiftRight from './modules/verilogShiftRight' -import TwoComplement from './modules/TwoComplement' import Splitter from './modules/Splitter' -import Ground from './modules/Ground' -import Power from './modules/Power' import Input from './modules/Input' import Output from './modules/Output' -import BitSelector from './modules/BitSelector' import ConstantVal from './modules/ConstantVal' import NorGate from './modules/NorGate' import DigitalLed from './modules/DigitalLed' -import VariableLed from './modules/VariableLed' import Button from './modules/Button' -import RGBLed from './modules/RGBLed' -import SquareRGBLed from './modules/SquareRGBLed' -import Demultiplexer from './modules/Demultiplexer' -import Decoder from './modules/Decoder' -import Flag from './modules/Flag' -import MSB from './modules/MSB' import LSB from './modules/LSB' -import PriorityEncoder from './modules/PriorityEncoder' -import Tunnel from './modules/Tunnel' import ALU from './modules/ALU' -import Rectangle from './modules/Rectangle' -import Arrow from './modules/Arrow' -import Counter from './modules/Counter' -import Random from './modules/Random' -import RGBLedMatrix from './modules/RGBLedMatrix' -import simulationArea from './simulationArea' -import TflipFlop from './sequential/TflipFlop' import DflipFlop from './sequential/DflipFlop' -import Dlatch from './sequential/Dlatch' -import SRflipFlop from './sequential/SRflipFlop' -import JKflipFlop from './sequential/JKflipFlop' -import TTY from './sequential/TTY' -import Keyboard from './sequential/Keyboard' import Clock from './sequential/Clock' -import RAM from './sequential/RAM' import verilogRAM from './sequential/verilogRAM' -import EEPROM from './sequential/EEPROM' -import Rom from './sequential/Rom' -import TB_Input from './testbench/testbenchInput' -import TB_Output from './testbench/testbenchOutput' -import ForceGate from './testbench/ForceGate' -import { newCircuit, switchCircuit, changeCircuitName } from './circuit' -import SubCircuit from './subcircuit' function getBitWidth(bitsJSON) { if (Number.isInteger(bitsJSON)) { diff --git a/v1/src/simulator/src/app.js b/v1/src/simulator/src/app.ts similarity index 97% rename from v1/src/simulator/src/app.js rename to v1/src/simulator/src/app.ts index 00b64e60..0f4c7940 100644 --- a/v1/src/simulator/src/app.js +++ b/v1/src/simulator/src/app.ts @@ -1,9 +1,9 @@ -import { setup } from './setup' -import Array from './arrayHelpers' +import { setup } from './setup'; +import { JsConfig } from './types/app.types' document.addEventListener('DOMContentLoaded', () => { - setup() - var js = { + setup(); + const js: JsConfig = { devices: { dev0: { type: 'Input', @@ -207,7 +207,5 @@ document.addEventListener('DOMContentLoaded', () => { }, ], subcircuits: {}, - } -}) - -window.Array = Array + }; +}); \ No newline at end of file diff --git a/v1/src/simulator/src/arrayHelpers.js b/v1/src/simulator/src/arrayHelpers.js deleted file mode 100644 index 8d10917e..00000000 --- a/v1/src/simulator/src/arrayHelpers.js +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable func-names */ -/* eslint-disable no-global-assign */ -/* eslint-disable no-extend-native */ -export default Array = window.Array - -Object.defineProperty(Array.prototype, 'clean', { - value: function (deleteValue) { - for (var i = 0; i < this.length; i++) { - if (this[i] === deleteValue) { - this.splice(i, 1) - i-- - } - } - return this - }, - enumerable: false, -}) - -Object.defineProperty(Array.prototype, 'extend', { - value: function (otherArray) { - /* you should include a test to check whether other_array really is an array */ - otherArray.forEach(function (v) { - this.push(v) - }, this) - }, - enumerable: false, -}) - -Object.defineProperty(Array.prototype, 'contains', { - value: function (value) { - return this.indexOf(value) > -1 - }, - enumerable: false, -}) diff --git a/v1/src/simulator/src/backgroundArea.js b/v1/src/simulator/src/backgroundArea.js deleted file mode 100644 index 49da21aa..00000000 --- a/v1/src/simulator/src/backgroundArea.js +++ /dev/null @@ -1,17 +0,0 @@ -import { dots } from './canvasApi' - -var backgroundArea -export default backgroundArea = { - canvas: document.getElementById('backgroundArea'), - setup() { - this.canvas = document.getElementById('backgroundArea') - this.canvas.width = width - this.canvas.height = height - this.context = this.canvas.getContext('2d') - dots(true, false) - }, - clear() { - if (!this.context) return - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) - }, -} diff --git a/v1/src/simulator/src/backgroundArea.ts b/v1/src/simulator/src/backgroundArea.ts new file mode 100644 index 00000000..7556b0f8 --- /dev/null +++ b/v1/src/simulator/src/backgroundArea.ts @@ -0,0 +1,20 @@ +import { BackgroundArea } from './interface/backgroundArea' +import { dots } from './canvasApi'; + +export const backgroundArea: BackgroundArea = { + canvas: null, + context: null, + setup() { + this.canvas = document.getElementById('backgroundArea') as HTMLCanvasElement; + this.canvas.width = width; + this.canvas.height = height; + this.context = this.canvas.getContext('2d'); + dots(true, false); + }, + clear() { + if (!this.context || !this.canvas) { + return; + } + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + }, +}; diff --git a/v1/src/simulator/src/canvas2svg.js b/v1/src/simulator/src/canvas2svg.js deleted file mode 100644 index d6f5dc64..00000000 --- a/v1/src/simulator/src/canvas2svg.js +++ /dev/null @@ -1,1433 +0,0 @@ -/*!! - * Canvas 2 Svg v1.0.19 - * A low level canvas to SVG converter. Uses a mock canvas context to build an SVG document. - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Author: - * Kerry Liu - * - * Copyright (c) 2014 Gliffy Inc. - */ - -/** - * CircuitVerse - Edited - * Latest npm package is 1.0.16 but we need 1.0.19 - */ - -'use strict' - -var STYLES, ctx, CanvasGradient, CanvasPattern, namedEntities - -//helper function to format a string -function format(str, args) { - var keys = Object.keys(args), - i - for (i = 0; i < keys.length; i++) { - str = str.replace( - new RegExp('\\{' + keys[i] + '\\}', 'gi'), - args[keys[i]] - ) - } - return str -} - -//helper function that generates a random string -function randomString(holder) { - var chars, randomstring, i - if (!holder) { - throw new Error( - 'cannot create a random attribute name for an undefined object' - ) - } - chars = 'ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz' - randomstring = '' - do { - randomstring = '' - for (i = 0; i < 12; i++) { - randomstring += chars[Math.floor(Math.random() * chars.length)] - } - } while (holder[randomstring]) - return randomstring -} - -//helper function to map named to numbered entities -function createNamedToNumberedLookup(items, radix) { - var i, - entity, - lookup = {}, - base10, - base16 - items = items.split(',') - radix = radix || 10 - // Map from named to numbered entities. - for (i = 0; i < items.length; i += 2) { - entity = '&' + items[i + 1] + ';' - base10 = parseInt(items[i], radix) - lookup[entity] = '&#' + base10 + ';' - } - //FF and IE need to create a regex from hex values ie   == \xa0 - lookup['\\xa0'] = ' ' - return lookup -} - -//helper function to map canvas-textAlign to svg-textAnchor -function getTextAnchor(textAlign) { - //TODO: support rtl languages - var mapping = { - left: 'start', - right: 'end', - center: 'middle', - start: 'start', - end: 'end', - } - return mapping[textAlign] || mapping.start -} - -//helper function to map canvas-textBaseline to svg-dominantBaseline -function getDominantBaseline(textBaseline) { - //INFO: not supported in all browsers - var mapping = { - alphabetic: 'alphabetic', - hanging: 'hanging', - top: 'text-before-edge', - bottom: 'text-after-edge', - middle: 'central', - } - return mapping[textBaseline] || mapping.alphabetic -} - -// Unpack entities lookup where the numbers are in radix 32 to reduce the size -// entity mapping courtesy of tinymce -namedEntities = createNamedToNumberedLookup( - '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + - '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + - '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + - '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + - '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + - '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + - '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + - '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + - '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + - '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + - 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + - 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + - 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + - 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + - 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + - '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + - '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + - '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + - '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + - '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + - 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + - 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + - 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + - '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + - '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', - 32 -) - -//Some basic mappings for attributes and default values. -STYLES = { - strokeStyle: { - svgAttr: 'stroke', //corresponding svg attribute - canvas: '#000000', //canvas default - svg: 'none', //svg default - apply: 'stroke', //apply on stroke() or fill() - }, - fillStyle: { - svgAttr: 'fill', - canvas: '#000000', - svg: null, //svg default is black, but we need to special case this to handle canvas stroke without fill - apply: 'fill', - }, - lineCap: { - svgAttr: 'stroke-linecap', - canvas: 'butt', - svg: 'butt', - apply: 'stroke', - }, - lineJoin: { - svgAttr: 'stroke-linejoin', - canvas: 'miter', - svg: 'miter', - apply: 'stroke', - }, - miterLimit: { - svgAttr: 'stroke-miterlimit', - canvas: 10, - svg: 4, - apply: 'stroke', - }, - lineWidth: { - svgAttr: 'stroke-width', - canvas: 1, - svg: 1, - apply: 'stroke', - }, - globalAlpha: { - svgAttr: 'opacity', - canvas: 1, - svg: 1, - apply: 'fill stroke', - }, - font: { - //font converts to multiple svg attributes, there is custom logic for this - canvas: '10px sans-serif', - }, - shadowColor: { - canvas: '#000000', - }, - shadowOffsetX: { - canvas: 0, - }, - shadowOffsetY: { - canvas: 0, - }, - shadowBlur: { - canvas: 0, - }, - textAlign: { - canvas: 'start', - }, - textBaseline: { - canvas: 'alphabetic', - }, - lineDash: { - svgAttr: 'stroke-dasharray', - canvas: [], - svg: null, - apply: 'stroke', - }, -} - -/** - * - * @param gradientNode - reference to the gradient - * @constructor - */ -CanvasGradient = function (gradientNode, ctx) { - this.__root = gradientNode - this.__ctx = ctx -} - -/** - * Adds a color stop to the gradient root - */ -CanvasGradient.prototype.addColorStop = function (offset, color) { - var stop = this.__ctx.__createElement('stop'), - regex, - matches - stop.setAttribute('offset', offset) - if (color.indexOf('rgba') !== -1) { - //separate alpha value, since webkit can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(color) - stop.setAttribute( - 'stop-color', - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - stop.setAttribute('stop-opacity', matches[4]) - } else { - stop.setAttribute('stop-color', color) - } - this.__root.appendChild(stop) -} - -CanvasPattern = function (pattern, ctx) { - this.__root = pattern - this.__ctx = ctx -} - -/** - * The mock canvas context - * @param o - options include: - * ctx - existing Context2D to wrap around - * width - width of your canvas (defaults to 500) - * height - height of your canvas (defaults to 500) - * enableMirroring - enables canvas mirroring (get image data) (defaults to false) - * document - the document object (defaults to the current document) - */ -ctx = function (o) { - var defaultOptions = { width: 500, height: 500, enableMirroring: false }, - options - - //keep support for this way of calling C2S: new C2S(width,height) - if (arguments.length > 1) { - options = defaultOptions - options.width = arguments[0] - options.height = arguments[1] - } else if (!o) { - options = defaultOptions - } else { - options = o - } - - if (!(this instanceof ctx)) { - //did someone call this without new? - return new ctx(options) - } - - //setup options - this.width = options.width || defaultOptions.width - this.height = options.height || defaultOptions.height - this.enableMirroring = - options.enableMirroring !== undefined - ? options.enableMirroring - : defaultOptions.enableMirroring - - this.canvas = this ///point back to this instance! - this.__document = options.document || document - - // allow passing in an existing context to wrap around - // if a context is passed in, we know a canvas already exist - if (options.ctx) { - this.__ctx = options.ctx - } else { - this.__canvas = this.__document.createElement('canvas') - this.__ctx = this.__canvas.getContext('2d') - } - - this.__setDefaultStyles() - this.__stack = [this.__getStyleState()] - this.__groupStack = [] - - //the root svg element - this.__root = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg' - ) - this.__root.setAttribute('version', 1.1) - this.__root.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - this.__root.setAttributeNS( - 'http://www.w3.org/2000/xmlns/', - 'xmlns:xlink', - 'http://www.w3.org/1999/xlink' - ) - this.__root.setAttribute('width', this.width) - this.__root.setAttribute('height', this.height) - - //make sure we don't generate the same ids in defs - this.__ids = {} - - //defs tag - this.__defs = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'defs' - ) - this.__root.appendChild(this.__defs) - - //also add a group child. the svg element can't use the transform attribute - this.__currentElement = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'g' - ) - this.__root.appendChild(this.__currentElement) -} - -/** - * Creates the specified svg element - * @private - */ -ctx.prototype.__createElement = function (elementName, properties, resetFill) { - if (typeof properties === 'undefined') { - properties = {} - } - - var element = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - elementName - ), - keys = Object.keys(properties), - i, - key - if (resetFill) { - //if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black. - element.setAttribute('fill', 'none') - element.setAttribute('stroke', 'none') - } - for (i = 0; i < keys.length; i++) { - key = keys[i] - element.setAttribute(key, properties[key]) - } - return element -} - -/** - * Applies default canvas styles to the context - * @private - */ -ctx.prototype.__setDefaultStyles = function () { - //default 2d canvas context properties see:http://www.w3.org/TR/2dcontext/ - var keys = Object.keys(STYLES), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = STYLES[key].canvas - } -} - -/** - * Applies styles on restore - * @param styleState - * @private - */ -ctx.prototype.__applyStyleState = function (styleState) { - var keys = Object.keys(styleState), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = styleState[key] - } -} - -/** - * Gets the current style state - * @return {Object} - * @private - */ -ctx.prototype.__getStyleState = function () { - var i, - styleState = {}, - keys = Object.keys(STYLES), - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - styleState[key] = this[key] - } - return styleState -} - -/** - * Apples the current styles to the current SVG element. On "ctx.fill" or "ctx.stroke" - * @param type - * @private - */ -ctx.prototype.__applyStyleToCurrentElement = function (type) { - var currentElement = this.__currentElement - var currentStyleGroup = this.__currentElementsToStyle - if (currentStyleGroup) { - currentElement.setAttribute(type, '') - currentElement = currentStyleGroup.element - currentStyleGroup.children.forEach(function (node) { - node.setAttribute(type, '') - }) - } - - var keys = Object.keys(STYLES), - i, - style, - value, - id, - regex, - matches - for (i = 0; i < keys.length; i++) { - style = STYLES[keys[i]] - value = this[keys[i]] - if (style.apply) { - //is this a gradient or pattern? - if (value instanceof CanvasPattern) { - //pattern - if (value.__ctx) { - //copy over defs - while (value.__ctx.__defs.childNodes.length) { - id = value.__ctx.__defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild( - value.__ctx.__defs.childNodes[0] - ) - } - } - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if (value instanceof CanvasGradient) { - //gradient - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if ( - style.apply.indexOf(type) !== -1 && - style.svg !== value - ) { - if ( - (style.svgAttr === 'stroke' || style.svgAttr === 'fill') && - value.indexOf('rgba') !== -1 - ) { - //separate alpha value, since illustrator can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(value) - currentElement.setAttribute( - style.svgAttr, - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - //should take globalAlpha here - var opacity = matches[4] - var globalAlpha = this.globalAlpha - if (globalAlpha != null) { - opacity *= globalAlpha - } - currentElement.setAttribute( - style.svgAttr + '-opacity', - opacity - ) - } else { - var attr = style.svgAttr - if (keys[i] === 'globalAlpha') { - attr = type + '-' + style.svgAttr - if (currentElement.getAttribute(attr)) { - //fill-opacity or stroke-opacity has already been set by stroke or fill. - continue - } - } - //otherwise only update attribute if right type, and not svg default - currentElement.setAttribute(attr, value) - } - } - } - } -} - -/** - * Will return the closest group or svg node. May return the current element. - * @private - */ -ctx.prototype.__closestGroupOrSvg = function (node) { - node = node || this.__currentElement - if (node.nodeName === 'g' || node.nodeName === 'svg') { - return node - } else { - return this.__closestGroupOrSvg(node.parentNode) - } -} - -/** - * Returns the serialized value of the svg so far - * @param fixNamedEntities - Standalone SVG doesn't support named entities, which document.createTextNode encodes. - * If true, we attempt to find all named entities and encode it as a numeric entity. - * @return serialized svg - */ -ctx.prototype.getSerializedSvg = function (fixNamedEntities) { - var serialized = new XMLSerializer().serializeToString(this.__root), - keys, - i, - key, - value, - regexp, - xmlns - - //IE search for a duplicate xmnls because they didn't implement setAttributeNS correctly - xmlns = - /xmlns="http:\/\/www\.w3\.org\/2000\/svg".+xmlns="http:\/\/www\.w3\.org\/2000\/svg/gi - if (xmlns.test(serialized)) { - serialized = serialized.replace( - 'xmlns="http://www.w3.org/2000/svg', - 'xmlns:xlink="http://www.w3.org/1999/xlink' - ) - } - - if (fixNamedEntities) { - keys = Object.keys(namedEntities) - //loop over each named entity and replace with the proper equivalent. - for (i = 0; i < keys.length; i++) { - key = keys[i] - value = namedEntities[key] - regexp = new RegExp(key, 'gi') - if (regexp.test(serialized)) { - serialized = serialized.replace(regexp, value) - } - } - } - - return serialized -} - -/** - * Returns the root svg - * @return svg - */ -ctx.prototype.getSvg = function () { - return this.__root -} -/** - * Will generate a group tag. - */ -ctx.prototype.save = function () { - var group = this.__createElement('g') - var parent = this.__closestGroupOrSvg() - this.__groupStack.push(parent) - parent.appendChild(group) - this.__currentElement = group - this.__stack.push(this.__getStyleState()) -} -/** - * Sets current element to parent, or just root if already root - */ -ctx.prototype.restore = function () { - this.__currentElement = this.__groupStack.pop() - this.__currentElementsToStyle = null - //Clearing canvas will make the poped group invalid, currentElement is set to the root group node. - if (!this.__currentElement) { - this.__currentElement = this.__root.childNodes[1] - } - var state = this.__stack.pop() - this.__applyStyleState(state) -} - -/** - * Helper method to add transform - * @private - */ -ctx.prototype.__addTransform = function (t) { - //if the current element has siblings, add another group - var parent = this.__closestGroupOrSvg() - if (parent.childNodes.length > 0) { - if (this.__currentElement.nodeName === 'path') { - if (!this.__currentElementsToStyle) - this.__currentElementsToStyle = { - element: parent, - children: [], - } - this.__currentElementsToStyle.children.push(this.__currentElement) - this.__applyCurrentDefaultPath() - } - - var group = this.__createElement('g') - parent.appendChild(group) - this.__currentElement = group - } - - var transform = this.__currentElement.getAttribute('transform') - if (transform) { - transform += ' ' - } else { - transform = '' - } - transform += t - this.__currentElement.setAttribute('transform', transform) -} - -/** - * scales the current element - */ -ctx.prototype.scale = function (x, y) { - if (y === undefined) { - y = x - } - this.__addTransform(format('scale({x},{y})', { x: x, y: y })) -} - -/** - * rotates the current element - */ -ctx.prototype.rotate = function (angle) { - var degrees = (angle * 180) / Math.PI - this.__addTransform( - format('rotate({angle},{cx},{cy})', { angle: degrees, cx: 0, cy: 0 }) - ) -} - -/** - * translates the current element - */ -ctx.prototype.translate = function (x, y) { - this.__addTransform(format('translate({x},{y})', { x: x, y: y })) -} - -/** - * applies a transform to the current element - */ -ctx.prototype.transform = function (a, b, c, d, e, f) { - this.__addTransform( - format('matrix({a},{b},{c},{d},{e},{f})', { - a: a, - b: b, - c: c, - d: d, - e: e, - f: f, - }) - ) -} - -/** - * Create a new Path Element - */ -ctx.prototype.beginPath = function () { - var path, parent - - // Note that there is only one current default path, it is not part of the drawing state. - // See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path - this.__currentDefaultPath = '' - this.__currentPosition = {} - - path = this.__createElement('path', {}, true) - parent = this.__closestGroupOrSvg() - parent.appendChild(path) - this.__currentElement = path -} - -/** - * Helper function to apply currentDefaultPath to current path element - * @private - */ -ctx.prototype.__applyCurrentDefaultPath = function () { - var currentElement = this.__currentElement - if (currentElement.nodeName === 'path') { - currentElement.setAttribute('d', this.__currentDefaultPath) - } else { - console.error( - 'Attempted to apply path command to node', - currentElement.nodeName - ) - } -} - -/** - * Helper function to add path command - * @private - */ -ctx.prototype.__addPathCommand = function (command) { - this.__currentDefaultPath += ' ' - this.__currentDefaultPath += command -} - -/** - * Adds the move command to the current path element, - * if the currentPathElement is not empty create a new path element - */ -ctx.prototype.moveTo = function (x, y) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - - // creates a new subpath with the given point - this.__currentPosition = { x: x, y: y } - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) -} - -/** - * Closes the current path - */ -ctx.prototype.closePath = function () { - if (this.__currentDefaultPath) { - this.__addPathCommand('Z') - } -} - -/** - * Adds a line to command - */ -ctx.prototype.lineTo = function (x, y) { - this.__currentPosition = { x: x, y: y } - if (this.__currentDefaultPath.indexOf('M') > -1) { - this.__addPathCommand(format('L {x} {y}', { x: x, y: y })) - } else { - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } -} - -/** - * Add a bezier command - */ -ctx.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}', { - cp1x: cp1x, - cp1y: cp1y, - cp2x: cp2x, - cp2y: cp2y, - x: x, - y: y, - }) - ) -} - -/** - * Adds a quadratic curve to command - */ -ctx.prototype.quadraticCurveTo = function (cpx, cpy, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('Q {cpx} {cpy} {x} {y}', { cpx: cpx, cpy: cpy, x: x, y: y }) - ) -} - -/** - * Return a new normalized vector of given vector - */ -var normalize = function (vector) { - var len = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]) - return [vector[0] / len, vector[1] / len] -} - -/** - * Adds the arcTo to the current path - * - * @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto - */ -ctx.prototype.arcTo = function (x1, y1, x2, y2, radius) { - // Let the point (x0, y0) be the last point in the subpath. - var x0 = this.__currentPosition && this.__currentPosition.x - var y0 = this.__currentPosition && this.__currentPosition.y - - // First ensure there is a subpath for (x1, y1). - if (typeof x0 == 'undefined' || typeof y0 == 'undefined') { - return - } - - // Negative values for radius must cause the implementation to throw an IndexSizeError exception. - if (radius < 0) { - throw new Error( - 'IndexSizeError: The radius provided (' + radius + ') is negative.' - ) - } - - // If the point (x0, y0) is equal to the point (x1, y1), - // or if the point (x1, y1) is equal to the point (x2, y2), - // or if the radius radius is zero, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - if ((x0 === x1 && y0 === y1) || (x1 === x2 && y1 === y2) || radius === 0) { - this.lineTo(x1, y1) - return - } - - // Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - var unit_vec_p1_p0 = normalize([x0 - x1, y0 - y1]) - var unit_vec_p1_p2 = normalize([x2 - x1, y2 - y1]) - if ( - unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === - unit_vec_p1_p0[1] * unit_vec_p1_p2[0] - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius, - // and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1), - // and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2). - // The points at which this circle touches these two lines are called the start and end tangent points respectively. - - // note that both vectors are unit vectors, so the length is 1 - var cos = - unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + - unit_vec_p1_p0[1] * unit_vec_p1_p2[1] - var theta = Math.acos(Math.abs(cos)) - - // Calculate origin - var unit_vec_p1_origin = normalize([ - unit_vec_p1_p0[0] + unit_vec_p1_p2[0], - unit_vec_p1_p0[1] + unit_vec_p1_p2[1], - ]) - var len_p1_origin = radius / Math.sin(theta / 2) - var x = x1 + len_p1_origin * unit_vec_p1_origin[0] - var y = y1 + len_p1_origin * unit_vec_p1_origin[1] - - // Calculate start angle and end angle - // rotate 90deg clockwise (note that y axis points to its down) - var unit_vec_origin_start_tangent = [-unit_vec_p1_p0[1], unit_vec_p1_p0[0]] - // rotate 90deg counter clockwise (note that y axis points to its down) - var unit_vec_origin_end_tangent = [unit_vec_p1_p2[1], -unit_vec_p1_p2[0]] - var getAngle = function (vector) { - // get angle (clockwise) between vector and (1, 0) - var x = vector[0] - var y = vector[1] - if (y >= 0) { - // note that y axis points to its down - return Math.acos(x) - } else { - return -Math.acos(x) - } - } - var startAngle = getAngle(unit_vec_origin_start_tangent) - var endAngle = getAngle(unit_vec_origin_end_tangent) - - // Connect the point (x0, y0) to the start tangent point by a straight line - this.lineTo( - x + unit_vec_origin_start_tangent[0] * radius, - y + unit_vec_origin_start_tangent[1] * radius - ) - - // Connect the start tangent point to the end tangent point by arc - // and adding the end tangent point to the subpath. - this.arc(x, y, radius, startAngle, endAngle) -} - -/** - * Sets the stroke property on the current element - */ -ctx.prototype.stroke = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute('paint-order', 'fill stroke markers') - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('stroke') -} - -/** - * Sets fill properties on the current element - */ -ctx.prototype.fill = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute('paint-order', 'stroke fill markers') - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('fill') -} - -/** - * Adds a rectangle to the path. - */ -ctx.prototype.rect = function (x, y, width, height) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - this.moveTo(x, y) - this.lineTo(x + width, y) - this.lineTo(x + width, y + height) - this.lineTo(x, y + height) - this.lineTo(x, y) - this.closePath() -} - -/** - * adds a rectangle element - */ -ctx.prototype.fillRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('fill') -} - -/** - * Draws a rectangle with no fill - * @param x - * @param y - * @param width - * @param height - */ -ctx.prototype.strokeRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('stroke') -} - -/** - * Clear entire canvas: - * 1. save current transforms - * 2. remove all the childNodes of the root g element - */ -ctx.prototype.__clearCanvas = function () { - var current = this.__closestGroupOrSvg(), - transform = current.getAttribute('transform') - var rootGroup = this.__root.childNodes[1] - var childNodes = rootGroup.childNodes - for (var i = childNodes.length - 1; i >= 0; i--) { - if (childNodes[i]) { - rootGroup.removeChild(childNodes[i]) - } - } - this.__currentElement = rootGroup - //reset __groupStack as all the child group nodes are all removed. - this.__groupStack = [] - if (transform) { - this.__addTransform(transform) - } -} - -/** - * "Clears" a canvas by just drawing a white rectangle in the current group. - */ -ctx.prototype.clearRect = function (x, y, width, height) { - //clear entire canvas - if (x === 0 && y === 0 && width === this.width && height === this.height) { - this.__clearCanvas() - return - } - var rect, - parent = this.__closestGroupOrSvg() - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - fill: '#FFFFFF', - }, - true - ) - parent.appendChild(rect) -} - -/** - * Adds a linear gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ -ctx.prototype.createLinearGradient = function (x1, y1, x2, y2) { - var grad = this.__createElement( - 'linearGradient', - { - id: randomString(this.__ids), - x1: x1 + 'px', - x2: x2 + 'px', - y1: y1 + 'px', - y2: y2 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) -} - -/** - * Adds a radial gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ -ctx.prototype.createRadialGradient = function (x0, y0, r0, x1, y1, r1) { - var grad = this.__createElement( - 'radialGradient', - { - id: randomString(this.__ids), - cx: x1 + 'px', - cy: y1 + 'px', - r: r1 + 'px', - fx: x0 + 'px', - fy: y0 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) -} - -/** - * Parses the font string and returns svg mapping - * @private - */ -ctx.prototype.__parseFont = function () { - var regex = - /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\'\"\sa-z0-9]+?)\s*$/i - var fontPart = regex.exec(this.font) - var data = { - style: fontPart[1] || 'normal', - size: fontPart[4] || '10px', - family: fontPart[6] || 'sans-serif', - weight: fontPart[3] || 'normal', - decoration: fontPart[2] || 'normal', - href: null, - } - - //canvas doesn't support underline natively, but we can pass this attribute - if (this.__fontUnderline === 'underline') { - data.decoration = 'underline' - } - - //canvas also doesn't support linking, but we can pass this as well - if (this.__fontHref) { - data.href = this.__fontHref - } - - return data -} - -/** - * Helper to link text fragments - * @param font - * @param element - * @return {*} - * @private - */ -ctx.prototype.__wrapTextLink = function (font, element) { - if (font.href) { - var a = this.__createElement('a') - a.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - font.href - ) - a.appendChild(element) - return a - } - return element -} - -/** - * Fills or strokes text - * @param text - * @param x - * @param y - * @param action - stroke or fill - * @private - */ -ctx.prototype.__applyText = function (text, x, y, action) { - var font = this.__parseFont(), - parent = this.__closestGroupOrSvg(), - textElement = this.__createElement( - 'text', - { - 'font-family': font.family, - 'font-size': font.size, - 'font-style': font.style, - 'font-weight': font.weight, - 'text-decoration': font.decoration, - x: x, - y: y, - 'text-anchor': getTextAnchor(this.textAlign), - 'dominant-baseline': getDominantBaseline(this.textBaseline), - }, - true - ) - - textElement.appendChild(this.__document.createTextNode(text)) - this.__currentElement = textElement - this.__applyStyleToCurrentElement(action) - parent.appendChild(this.__wrapTextLink(font, textElement)) -} - -/** - * Creates a text element - * @param text - * @param x - * @param y - */ -ctx.prototype.fillText = function (text, x, y) { - this.__applyText(text, x, y, 'fill') -} - -/** - * Strokes text - * @param text - * @param x - * @param y - */ -ctx.prototype.strokeText = function (text, x, y) { - this.__applyText(text, x, y, 'stroke') -} - -/** - * No need to implement this for svg. - * @param text - * @return {TextMetrics} - */ -ctx.prototype.measureText = function (text) { - this.__ctx.font = this.font - return this.__ctx.measureText(text) -} - -/** - * Arc command! - */ -ctx.prototype.arc = function ( - x, - y, - radius, - startAngle, - endAngle, - counterClockwise -) { - // in canvas no circle is drawn if no angle is provided. - if (startAngle === endAngle) { - return - } - startAngle = startAngle % (2 * Math.PI) - endAngle = endAngle % (2 * Math.PI) - if (startAngle === endAngle) { - //circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle) - endAngle = - (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % - (2 * Math.PI) - } - var endX = x + radius * Math.cos(endAngle), - endY = y + radius * Math.sin(endAngle), - startX = x + radius * Math.cos(startAngle), - startY = y + radius * Math.sin(startAngle), - sweepFlag = counterClockwise ? 0 : 1, - largeArcFlag = 0, - diff = endAngle - startAngle - - // https://github.com/gliffy/canvas2svg/issues/4 - if (diff < 0) { - diff += 2 * Math.PI - } - - if (counterClockwise) { - largeArcFlag = diff > Math.PI ? 0 : 1 - } else { - largeArcFlag = diff > Math.PI ? 1 : 0 - } - - this.lineTo(startX, startY) - this.__addPathCommand( - format( - 'A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}', - { - rx: radius, - ry: radius, - xAxisRotation: 0, - largeArcFlag: largeArcFlag, - sweepFlag: sweepFlag, - endX: endX, - endY: endY, - } - ) - ) - - this.__currentPosition = { x: endX, y: endY } -} - -/** - * Generates a ClipPath from the clip command. - */ -ctx.prototype.clip = function () { - var group = this.__closestGroupOrSvg(), - clipPath = this.__createElement('clipPath'), - id = randomString(this.__ids), - newGroup = this.__createElement('g') - - this.__applyCurrentDefaultPath() - group.removeChild(this.__currentElement) - clipPath.setAttribute('id', id) - clipPath.appendChild(this.__currentElement) - - this.__defs.appendChild(clipPath) - - //set the clip path to this group - group.setAttribute('clip-path', format('url(#{id})', { id: id })) - - //clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations - // to this path - group.appendChild(newGroup) - - this.__currentElement = newGroup -} - -/** - * Draws a canvas, image or mock context to this canvas. - * Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support. - * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage - */ -ctx.prototype.drawImage = function () { - //convert arguments to a real array - var args = Array.prototype.slice.call(arguments), - image = args[0], - dx, - dy, - dw, - dh, - sx = 0, - sy = 0, - sw, - sh, - parent, - svg, - defs, - group, - currentElement, - svgImage, - canvas, - context, - id - - if (args.length === 3) { - dx = args[1] - dy = args[2] - sw = image.width - sh = image.height - dw = sw - dh = sh - } else if (args.length === 5) { - dx = args[1] - dy = args[2] - dw = args[3] - dh = args[4] - sw = image.width - sh = image.height - } else if (args.length === 9) { - sx = args[1] - sy = args[2] - sw = args[3] - sh = args[4] - dx = args[5] - dy = args[6] - dw = args[7] - dh = args[8] - } else { - throw new Error( - 'Inavlid number of arguments passed to drawImage: ' + - arguments.length - ) - } - - parent = this.__closestGroupOrSvg() - currentElement = this.__currentElement - var translateDirective = 'translate(' + dx + ', ' + dy + ')' - if (image instanceof ctx) { - //canvas2svg mock canvas context. In the future we may want to clone nodes instead. - //also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context. - svg = image.getSvg().cloneNode(true) - if (svg.childNodes && svg.childNodes.length > 1) { - defs = svg.childNodes[0] - while (defs.childNodes.length) { - id = defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild(defs.childNodes[0]) - } - group = svg.childNodes[1] - if (group) { - //save original transform - var originTransform = group.getAttribute('transform') - var transformDirective - if (originTransform) { - transformDirective = - originTransform + ' ' + translateDirective - } else { - transformDirective = translateDirective - } - group.setAttribute('transform', transformDirective) - parent.appendChild(group) - } - } - } else if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - //canvas or image - svgImage = this.__createElement('image') - svgImage.setAttribute('width', dw) - svgImage.setAttribute('height', dh) - svgImage.setAttribute('preserveAspectRatio', 'none') - - if (sx || sy || sw !== image.width || sh !== image.height) { - //crop the image using a temporary canvas - canvas = this.__document.createElement('canvas') - canvas.width = dw - canvas.height = dh - context = canvas.getContext('2d') - context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh) - image = canvas - } - svgImage.setAttribute('transform', translateDirective) - svgImage.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - parent.appendChild(svgImage) - } -} - -/** - * Generates a pattern tag - */ -ctx.prototype.createPattern = function (image, repetition) { - var pattern = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'pattern' - ), - id = randomString(this.__ids), - img - pattern.setAttribute('id', id) - pattern.setAttribute('width', image.width) - pattern.setAttribute('height', image.height) - if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - img = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'image' - ) - img.setAttribute('width', image.width) - img.setAttribute('height', image.height) - img.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - pattern.appendChild(img) - this.__defs.appendChild(pattern) - } else if (image instanceof ctx) { - pattern.appendChild(image.__root.childNodes[1]) - this.__defs.appendChild(pattern) - } - return new CanvasPattern(pattern, this) -} - -ctx.prototype.setLineDash = function (dashArray) { - if (dashArray && dashArray.length > 0) { - this.lineDash = dashArray.join(',') - } else { - this.lineDash = null - } -} - -/** - * Not yet implemented - */ -ctx.prototype.drawFocusRing = function () {} -ctx.prototype.createImageData = function () {} -ctx.prototype.getImageData = function () {} -ctx.prototype.putImageData = function () {} -ctx.prototype.globalCompositeOperation = function () {} -ctx.prototype.setTransform = function () {} - -//add options for alternative namespace -// if (typeof window === "object") { -// window.C2S = ctx; -// } - -// CommonJS/Browserify -// if (typeof module === "object" && typeof module.exports === "object") { -// module.exports = ctx; -// } - -export default ctx diff --git a/v1/src/simulator/src/canvasApi.js b/v1/src/simulator/src/canvasApi.js index 08ee65d3..950bb2b8 100644 --- a/v1/src/simulator/src/canvasApi.js +++ b/v1/src/simulator/src/canvasApi.js @@ -1,8 +1,9 @@ /* eslint-disable no-param-reassign */ -import backgroundArea from './backgroundArea' -import simulationArea from './simulationArea' +import { backgroundArea } from './backgroundArea' +import { simulationArea } from './simulationArea' import miniMapArea, { removeMiniMap, updatelastMinimapShown } from './minimap' import { colors } from './themer/themer' +import { updateOrder } from './metadata' var unit = 10 @@ -107,9 +108,10 @@ export function changeScale(delta, xx, yy, method = 1) { if (!embed && !lightMode) { findDimensions(globalScope) miniMapArea.setup() - $('#miniMap').show() + let miniMap = document.querySelector('#miniMap'); + miniMap.style.display = 'block'; updatelastMinimapShown() - $('#miniMap').show() + miniMap.style.display = 'block'; setTimeout(removeMiniMap, 2000) } } @@ -240,7 +242,10 @@ export function moveTo(ctx, x1, y1, xx, yy, dir, bypass = false) { xx *= globalScope.scale yy *= globalScope.scale if (bypass) { - ctx.moveTo(xx + globalScope.ox + newX, yy + globalScope.oy + newY) + ctx.moveTo( + Math.round(xx + globalScope.ox + newX), + Math.round(yy + globalScope.oy + newY) + ) } else { ctx.moveTo( Math.round(xx + globalScope.ox + newX - correction) + correction, @@ -437,9 +442,9 @@ export function drawLine(ctx, x1, y1, x2, y2, color, width) { // Checks if string color is a valid color using a hack export function validColor(color) { - var $div = $('
') - $div.css('border', `1px solid ${color}`) - return $div.css('border-color') !== '' + let newDiv = document.createElement('div') + newDiv.style.border = `1px solid ${color}` + return newDiv.style.borderColor !== '' } // Helper function to color "RED" to RGBA diff --git a/v1/src/simulator/src/circuit.js b/v1/src/simulator/src/circuit.ts similarity index 69% rename from v1/src/simulator/src/circuit.js rename to v1/src/simulator/src/circuit.ts index f86429e3..cf04fc9e 100644 --- a/v1/src/simulator/src/circuit.js +++ b/v1/src/simulator/src/circuit.ts @@ -11,13 +11,10 @@ /* eslint-disable no-alert */ import CircuitElement from './circuitElement' import plotArea from './plotArea' -import simulationArea, { changeClockTime } from './simulationArea' +import { simulationArea } from './simulationArea' import { stripTags, uniq, - showMessage, - showError, - truncateString, } from './utils' import { findDimensions, dots } from './canvasApi' import { updateRestrictedElementsList } from './restrictedElementDiv' @@ -32,28 +29,33 @@ import { changeLightMode, } from './engine' import { toggleLayoutMode, layoutModeGet } from './layoutMode' -import { setProjectName, getProjectName } from './data/save' +import { setProjectName } from './data/save' import { changeClockEnable } from './sequential' import { changeInputSize } from './modules' import { verilogModeGet, verilogModeSet } from './Verilog2CV' -import { updateTestbenchUI } from './testbench' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' -import { toRef, toRefs } from 'vue' +import { toRefs } from 'vue' import { provideCircuitName } from '#/components/helpers/promptComponent/PromptComponent.vue' import { deleteCurrentCircuit } from '#/components/helpers/deleteCircuit/DeleteCircuit.vue' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { inputList, moduleList } from './metadata' export const circuitProperty = { toggleLayoutMode, setProjectName, changeCircuitName, - // changeClockTime, deleteCurrentCircuit, changeClockEnable, changeInputSize, changeLightMode, + changeClockTime } -export var scopeList = {} +function changeClockTime(t: number) { + simulationArea.changeClockTime(t) +} + +export let scopeList: { [key: string]: Scope } = {} export function resetScopeList() { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) @@ -65,20 +67,20 @@ export function resetScopeList() { * Disables layoutMode if enabled * Changes UI tab etc * Sets flags to make updates, resets most of the things - * @param {string} id - identifier for circuit - * @category circuit */ -export function switchCircuit(id) { +export function switchCircuit(id: string) { // TODO: fix tomorrow const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) const { activeCircuit } = toRefs(simulatorStore) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) if (layoutModeGet()) { toggleLayoutMode() } if (!scopeList[id].verilogMetadata.isVerilogCircuit) { verilogModeSet(false) + simulatorMobileStore.isVerilog.value = false } // globalScope.fixLayout(); @@ -94,6 +96,7 @@ export function switchCircuit(id) { globalScope = scopeList[id] if (globalScope.verilogMetadata.isVerilogCircuit) { verilogModeSet(true) + simulatorMobileStore.isVerilog.value = true } if (globalScope.isVisible()) { // $(`#${id}`).addClass('current') @@ -101,8 +104,10 @@ export function switchCircuit(id) { (circuit) => circuit.id == id ) // TODO: add strict equality after typescript circuit_list.value[index].focussed = true - activeCircuit.value.id = globalScope.id - activeCircuit.value.name = globalScope.name + if (activeCircuit.value) { + activeCircuit.value.id = globalScope.id + activeCircuit.value.name = globalScope.name + } } updateSimulationSet(true) updateSubcircuitSet(true) @@ -111,7 +116,6 @@ export function switchCircuit(id) { simulationArea.lastSelected = globalScope.root if (!embed) { showProperties(simulationArea.lastSelected) - updateTestbenchUI() plotArea.reset() } updateCanvasSet(true) @@ -121,13 +125,18 @@ export function switchCircuit(id) { updateRestrictedElementsList() } -export function getDependenciesList(scopeId) { +export function getDependenciesList(scopeId: string | number) { let scope = scopeList[scopeId] if (scope == undefined) scope = scopeList[globalScope.id] let dependencies = '' - for (id in scopeList) { - if (id != scope.id && scopeList[id].checkDependency(scope.id)) { + for (let id in scopeList) { + let formattedId; + if (typeof scopeId === 'number') + formattedId = scopeId; + else + formattedId = parseInt(scopeId); + if (id != scope.id && scopeList[id].checkDependency(formattedId)) { if (dependencies === '') { dependencies = scopeList[id].name } else { @@ -171,8 +180,8 @@ export function getDependenciesList(scopeId) { * Wrapper function around newCircuit to be called from + button on UI */ export async function createNewCircuitScope( - name, - id = undefined, + name: string | Error | undefined = undefined, + id: string | undefined = undefined, isVerilog = false, isVerilogMain = false ) { @@ -185,28 +194,31 @@ export async function createNewCircuitScope( newCircuit(name, id, isVerilog, isVerilogMain) if (!embed) { showProperties(simulationArea.lastSelected) - updateTestbenchUI() plotArea.reset() } return true } +export function circuitNameClicked() { + simulationArea.lastSelected = globalScope.root +} + /** * Function to create new circuit * Function creates button in tab, creates scope and switches to this circuit - * @param {string} name - name of the new circuit - * @param {string} id - identifier for circuit - * @category circuit */ -export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { +export function newCircuit(name: string | undefined, id: string | undefined, isVerilog = false, isVerilogMain = false) { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) const { activeCircuit } = toRefs(simulatorStore) + const { circuit_name_clickable } = toRefs(simulatorStore) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) if (layoutModeGet()) { toggleLayoutMode() } if (verilogModeGet()) { verilogModeSet(false) + simulatorMobileStore.isVerilog.value = false } name = name || 'Untitled-Circuit' name = stripTags(name) @@ -231,46 +243,26 @@ export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { // $('.circuits').removeClass('current') circuit_list.value.forEach((circuit) => (circuit.focussed = false)) circuit_list.value[circuit_list.value.length - 1].focussed = true - activeCircuit.value.id = scope.id - activeCircuit.value.name = scope.name + if (activeCircuit.value) { + activeCircuit.value.id = scope.id + activeCircuit.value.name = scope.name + } if (!isVerilog || isVerilogMain) { - if (embed) { - // added calss - embed-tab using vue logic - // var html = `
${truncateString( - // name, - // 18 - // )}
` - // $('#tabsBar').append(html) - // $('#tabsBar').addClass('embed-tabs') - } else { - // logic implemented in vue - } - + circuit_name_clickable.value = false; // Remove listeners - //$('.circuits').off('click') - $('.circuitName').off('click') - //$('.tabsCloseButton').off('click') - + // $('.circuitName').off('click') // switch circuit function moved inside vue component - if (!embed) { - $('.circuitName').on('click', () => { - simulationArea.lastSelected = globalScope.root - setTimeout(() => { - // here link with the properties panel - document.getElementById('circname').select() - }, 100) - }) + // $('.circuitName').on('click', () => { + // simulationArea.lastSelected = globalScope.root + // setTimeout(() => { + // // here link with the properties panel + // document.getElementById('circname').select() + // }, 100) + // }) + circuit_name_clickable.value = true; } - // moved inside vue - component - // $('.tabsCloseButton').on('click', function (e) { - // e.stopPropagation() - // deleteCurrentCircuit(this.id) - // }) - if (!embed) { showProperties(scope.root) } @@ -281,20 +273,15 @@ export function newCircuit(name, id, isVerilog = false, isVerilogMain = false) { /** * Used to change name of a circuit - * @param {string} name - new name - * @param {string} id - id of the circuit - * @category circuit */ -export function changeCircuitName(name, id = globalScope.id) { +export function changeCircuitName(name: string, id = globalScope.id) { const simulatorStore = SimulatorStore() const { circuit_list } = toRefs(simulatorStore) - // const { activeCircuit } = toRefs(simulatorStore) name = name || 'Untitled' name = stripTags(name) scopeList[id].name = name const index = circuit_list.value.findIndex((circuit) => circuit.id === id) circuit_list.value[index].name = name - // activeCircuit.value.name = name // add later if necessary at current stage not important handled by projectProperty on switching circuit } /** @@ -305,6 +292,30 @@ export function changeCircuitName(name, id = globalScope.id) { * @category circuit */ export default class Scope { + restrictedCircuitElementsUsed: any[]; + id: number | string; + CircuitElement: any[]; + name: string; + root: CircuitElement; + backups: string[]; + history: string[]; + timeStamp: number; + verilogMetadata: { isVerilogCircuit: boolean; isMainCircuit: boolean; code: string; subCircuitScopeIds: string[]; }; + ox: number; + oy: number; + scale: number; + stack: any[]; + layout: { width: number; height: number; title_x: number; title_y: number; titleEnabled: boolean; }; + tunnelList?: {}; + pending?: any[]; + nodes?: any[]; + allNodes?: any[]; + wires?: any[]; + Input?: any[]; + Output?: any[]; + Splitter?: any[]; + SubCircuit?: any[]; + Clock?: any[]; constructor(name = 'localScope', id = undefined) { this.restrictedCircuitElementsUsed = [] this.id = id || Math.floor(Math.random() * 100000000000 + 1) @@ -364,14 +375,20 @@ export default class Scope { * Resets all nodes recursively */ reset() { - for (let i = 0; i < this.allNodes.length; i++) { - this.allNodes[i].reset() + if (this.allNodes) { + for (let i = 0; i < this.allNodes.length; i++) { + this.allNodes[i].reset() + } } - for (let i = 0; i < this.Splitter.length; i++) { - this.Splitter[i].reset() + if (this.Splitter) { + for (let i = 0; i < this.Splitter.length; i++) { + this.Splitter[i].reset() + } } - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].reset() + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].reset() + } } } @@ -381,12 +398,14 @@ export default class Scope { addInputs() { for (let i = 0; i < inputList.length; i++) { for (var j = 0; j < this[inputList[i]].length; j++) { - simulationArea.simulationQueue.add(this[inputList[i]][j], 0) + simulationArea.simulationQueue?.add(this[inputList[i]][j], 0) } } - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].addInputs() + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].addInputs() + } } } @@ -394,27 +413,34 @@ export default class Scope { * Ticks clocks recursively -- needs to be deprecated and synchronize all clocks with a global clock */ clockTick() { - for (let i = 0; i < this.Clock.length; i++) { - this.Clock[i].toggleState() - } // tick clock! - for (let i = 0; i < this.SubCircuit.length; i++) { - this.SubCircuit[i].localScope.clockTick() - } // tick clock! + if (this.Clock) { + for (let i = 0; i < this.Clock.length; i++) { + this.Clock[i].toggleState() + } // tick clock! + } + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + this.SubCircuit[i].localScope.clockTick() + } // tick clock! + } } /** * Checks if this circuit contains directly or indirectly scope with id * Recursive nature */ - checkDependency(id) { + checkDependency(id: number) { if (id === this.id) return true - for (let i = 0; i < this.SubCircuit.length; i++) { - if (this.SubCircuit[i].id === id) return true + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + if (this.SubCircuit[i].id === id) return true + } } - - for (let i = 0; i < this.SubCircuit.length; i++) { - if (scopeList[this.SubCircuit[i].id].checkDependency(id)) - return true + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + if (scopeList[this.SubCircuit[i].id].checkDependency(id)) + return true + } } return false @@ -425,9 +451,11 @@ export default class Scope { */ getDependencies() { var list = [] - for (let i = 0; i < this.SubCircuit.length; i++) { - list.push(this.SubCircuit[i].id) - list.extend(scopeList[this.SubCircuit[i].id].getDependencies()) + if (this.SubCircuit) { + for (let i = 0; i < this.SubCircuit.length; i++) { + list.push(this.SubCircuit[i].id) + list.push(...scopeList[this.SubCircuit[i].id].getDependencies()) + } } return uniq(list) } @@ -437,11 +465,15 @@ export default class Scope { */ fixLayout() { var maxY = 20 - for (let i = 0; i < this.Input.length; i++) { - maxY = Math.max(this.Input[i].layoutProperties.y, maxY) + if (this.Input) { + for (let i = 0; i < this.Input.length; i++) { + maxY = Math.max(this.Input[i].layoutProperties.y, maxY) + } } - for (let i = 0; i < this.Output.length; i++) { - maxY = Math.max(this.Output[i].layoutProperties.y, maxY) + if (this.Output) { + for (let i = 0; i < this.Output.length; i++) { + maxY = Math.max(this.Output[i].layoutProperties.y, maxY) + } } if (maxY !== this.layout.height) { this.layout.height = maxY + 10 diff --git a/v1/src/simulator/src/circuitElement.js b/v1/src/simulator/src/circuitElement.js index cd368c4d..a7d5565e 100644 --- a/v1/src/simulator/src/circuitElement.js +++ b/v1/src/simulator/src/circuitElement.js @@ -1,7 +1,8 @@ /* eslint-disable no-multi-assign */ /* eslint-disable no-bitwise */ +/* eslint-disable */ import { scheduleUpdate } from './engine' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { fixDirection, fillText, @@ -154,7 +155,7 @@ export default class CircuitElement { /** * To generate JSON-safe data that can be loaded * @memberof CircuitElement - * @return {JSON} - the data to be saved + * @return {object} - the data to be saved */ saveObject() { var data = { @@ -176,7 +177,7 @@ export default class CircuitElement { /** * Always overriden * @memberof CircuitElement - * @return {JSON} - the data to be saved + * @return {object} - the data to be saved */ // eslint-disable-next-line class-methods-use-this customSave() { @@ -332,7 +333,7 @@ export default class CircuitElement { this.drag() if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( let i = 0; @@ -348,7 +349,7 @@ export default class CircuitElement { this.startDragging() if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( let i = 0; @@ -376,9 +377,9 @@ export default class CircuitElement { if (simulationArea.shiftDown) { simulationArea.lastSelected = undefined if ( - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { - simulationArea.multipleObjectSelections.clean(this) + simulationArea.multipleObjectSelections = simulationArea.multipleObjectSelections.filter(x => x !== this); } else { simulationArea.multipleObjectSelections.push(this) } @@ -479,8 +480,8 @@ export default class CircuitElement { * NOT OVERRIDABLE */ isHover() { - var mX = simulationArea.mouseXf - this.x - var mY = this.y - simulationArea.mouseYf + var mX = simulationArea.touch ? simulationArea.mouseDownX - this.x : simulationArea.mouseXf - this.x; + var mY = simulationArea.touch ? this.y - simulationArea.mouseDownY : this.y - simulationArea.mouseYf; var rX = this.rightDimensionX var lX = this.leftDimensionX @@ -578,7 +579,7 @@ export default class CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -646,7 +647,7 @@ export default class CircuitElement { /** Draws element in layout mode (inside the subcircuit) @param {number} xOffset - x position of the subcircuit - @param {number} yOffset - y position of the subcircuit + @param {number} yOffset - y position of the subcircuit Called by subcirucit.js/customDraw() - for drawing as a part of another circuit and layoutMode.js/renderLayout() - for drawing in layoutMode @@ -734,7 +735,7 @@ export default class CircuitElement { // OVERRIDE WITH CAUTION delete() { simulationArea.lastSelected = undefined - this.scope[this.objectType].clean(this) // CHECK IF THIS IS VALID + this.scope[this.objectType] = this.scope[this.objectType].filter(x => x !== this) if (this.deleteNodesWhenDeleted) { this.deleteNodes() } else { @@ -852,7 +853,8 @@ export default class CircuitElement { resolve() {} /** - * Helper Function to process verilog + * Helper Function to process Verilog + * @return {string} */ processVerilog() { // Output count used to sanitize output @@ -882,7 +884,7 @@ export default class CircuitElement { if ( !this.scope.verilogWireList[ this.nodeList[i].bitWidth - ].contains(this.nodeList[i].verilogLabel) + ].includes(this.nodeList[i].verilogLabel) ) this.scope.verilogWireList[ this.nodeList[i].bitWidth @@ -956,8 +958,8 @@ export default class CircuitElement { } /** - * Helper Function to generate verilog - * @return {JSON} + * Helper Function to generate Verilog. + * @return {string} */ generateVerilog() { // Example: and and_1(_out, _out, _Q[0]); diff --git a/v1/src/simulator/src/combinationalAnalysis.js b/v1/src/simulator/src/combinationalAnalysis.js index e45cb1b8..7577dcc0 100644 --- a/v1/src/simulator/src/combinationalAnalysis.js +++ b/v1/src/simulator/src/combinationalAnalysis.js @@ -1,667 +1,333 @@ /* eslint-disable import/no-cycle */ /* eslint-disable guard-for-in */ /* eslint-disable no-restricted-syntax */ -import Node from './node' -import { scheduleBackup } from './data/backupCircuit' -import BooleanMinimize from './quinMcCluskey' -import Input from './modules/Input' -import ConstantVal from './modules/ConstantVal' -import Output from './modules/Output' -import AndGate from './modules/AndGate' -import OrGate from './modules/OrGate' -import NotGate from './modules/NotGate' -import { stripTags } from './utils' -import simulationArea from './simulationArea' -import { findDimensions } from './canvasApi' +import Node from './node'; +import { scheduleBackup } from './data/backupCircuit'; +import BooleanMinimize from './quinMcCluskey'; +import Input from './modules/Input'; +import ConstantVal from './modules/ConstantVal'; +import Output from './modules/Output'; +import AndGate from './modules/AndGate'; +import OrGate from './modules/OrGate'; +import NotGate from './modules/NotGate'; +import { stripTags } from './utils'; +import { simulationArea } from './simulationArea'; +import { findDimensions } from './canvasApi'; import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' -// var inputSample = 5 -// var dataSample = [ -// ['01---', '11110', '01---', '00000'], -// ['01110', '1-1-1', '----0'], -// ['01---', '11110', '01110', '1-1-1', '0---0'], -// ['----1'], -// ] +export const performCombinationalAnalysis = (inputNameList, outputNameList, booleanNameExpression, scope = globalScope) => { + if(!inputNameList || !outputNameList || !booleanNameExpression) { + return; + } + var flag = 0; + var inputList = stripTags(inputNameList).split(','); + var outputList = stripTags(outputNameList).split(','); + var booleanExpression = booleanNameExpression; + inputList = inputList.map((x) => x.trim()); + inputList = inputList.filter((e) => e); + outputList = outputList.map((x) => x.trim()); + outputList = outputList.filter((e) => e); + booleanExpression = booleanExpression.replace(/ /g, ''); + booleanExpression = booleanExpression.toUpperCase(); -// var sampleInputListNames = ['A', 'B'] -// var sampleOutputListNames = ['X'] + var booleanInputVariables = []; + for (var i = 0; i < booleanExpression.length; i++) { + if ((booleanExpression[i] >= 'A' && booleanExpression[i] <= 'Z')) { + if (booleanExpression.indexOf(booleanExpression[i]) == i) { + booleanInputVariables.push(booleanExpression[i]); + } + } + } + booleanInputVariables.sort(); + if (inputList.length > 0 && outputList.length > 0 && booleanInputVariables.length == 0) { + createBooleanPrompt(inputList, outputList, null, scope); + } + else if (booleanInputVariables.length > 0 && inputList.length == 0 && outputList.length == 0) { + var output = solveBooleanFunction(booleanInputVariables, booleanExpression); + if(output != null) { + createBooleanPrompt(booleanInputVariables, booleanExpression, output, scope); + } + } + else if ((inputList.length == 0 || outputList.length == 0) && booleanInputVariables == 0) { + alert('Enter Input / Output Variable(s) OR Boolean Function!'); + } + else { + alert('Use Either Combinational Analysis Or Boolean Function To Generate Circuit!'); + } +}; -/** - * The prompt for combinational analysis - * @param {Scope=} - the circuit in which we want combinational analysis - * @category combinationalAnalysis - */ -export function createCombinationalAnalysisPrompt(scope = globalScope) { - scheduleBackup() - SimulatorStore().dialogBox.combinationalanalysis_dialog = true - /* - $('#combinationalAnalysis').empty() - $('#combinationalAnalysis').append( - "

Enter Input names separated by commas:

" - ) - $('#combinationalAnalysis').append( - "

Enter Output names separated by commas:

" - ) - $('#combinationalAnalysis').append("

OR

") - $('#combinationalAnalysis').append( - "

Enter Boolean Function:

" - ) - $('#combinationalAnalysis').append( - "" - ) - $('#combinationalAnalysis').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - style: 'padding: 5px', - text: 'Next', - click() { - var inputList = stripTags($('#inputNameList').val()).split( - ',' - ) - var outputList = stripTags( - $('#outputNameList').val() - ).split(',') - var booleanExpression = $('#booleanExpression').val() - inputList = inputList.map((x) => x.trim()) - inputList = inputList.filter((e) => e) - outputList = outputList.map((x) => x.trim()) - outputList = outputList.filter((e) => e) - booleanExpression = booleanExpression.replace(/ /g, '') - booleanExpression = booleanExpression.toUpperCase() - var booleanInputVariables = [] - for (var i = 0; i < booleanExpression.length; i++) { - if ( - booleanExpression[i] >= 'A' && - booleanExpression[i] <= 'Z' - ) { - if ( - booleanExpression.indexOf( - booleanExpression[i] - ) == i - ) { - booleanInputVariables.push(booleanExpression[i]) - } - } - } - booleanInputVariables.sort() - if ( - inputList.length > 0 && - outputList.length > 0 && - booleanInputVariables.length == 0 - ) { - $(this).dialog('close') - createBooleanPrompt(inputList, outputList, null, scope) - } else if ( - booleanInputVariables.length > 0 && - inputList.length == 0 && - outputList.length == 0 - ) { - $(this).dialog('close') - var output = solveBooleanFunction( - booleanInputVariables, - booleanExpression - ) - if (output != null) { - createBooleanPrompt( - booleanInputVariables, - booleanExpression, - output, - scope - ) - } - } else if ( - (inputList.length == 0 || outputList.length == 0) && - booleanInputVariables == 0 - ) { - alert( - 'Enter Input / Output Variable(s) OR Boolean Function!' - ) - } else { - alert( - 'Use Either Combinational Analysis Or Boolean Function To Generate Circuit!' - ) - } - }, - }, - ], - }) - - $('#combinationalAnalysis').checkBo() - */ -} -// /** -// * This funciton hashes the output array and makes required JSON using -// * a BooleanMinimize class defined in Quin_Mcluskey.js var s which will -// * be output table is also initialied here -// * @param {Array} inputListNames - labels of input nodes -// * @param {Array} outputListNames - labels of output nodes -// * @param {Scope=} scope - h circuit -// * @category combinationalAnalysis -// */ -/* - function createBooleanPrompt( - inputListNames, - outputListNames, - output, - scope = globalScope - ) { - var inputListNames = - inputListNames || prompt('Enter inputs separated by commas').split(',') - var outputListNames = - outputListNames || - prompt('Enter outputs separated by commas').split(',') - var outputListNamesInteger = [] - if (output == null) { - for (var i = 0; i < outputListNames.length; i++) { - outputListNamesInteger[i] = 7 * i + 13 - } // assigning an integer to the value, 7*i + 13 is random - } else { - outputListNamesInteger = [13] - } - var s = '' - s += '' - s += '' - if ($('#decimalColumnBox').is(':checked')) { - s += '' - } - for (var i = 0; i < inputListNames.length; i++) { - s += `` - } - if (output == null) { - for (var i = 0; i < outputListNames.length; i++) { - s += `` - } - } else { - s += `` - } - s += '' - - var matrix = [] - for (var i = 0; i < inputListNames.length; i++) { - matrix[i] = new Array(1 << inputListNames.length) - } - - for (var i = 0; i < inputListNames.length; i++) { - for (var j = 0; j < 1 << inputListNames.length; j++) { - matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) - } - } - - for (var j = 0; j < 1 << inputListNames.length; j++) { - s += '' - if ($('#decimalColumnBox').is(':checked')) { - s += `` - } - for (var i = 0; i < inputListNames.length; i++) { - s += `` - } - for (var i = 0; i < outputListNamesInteger.length; i++) { - if (output == null) { - s += - `' - // using hash values as they'll be used in the generateBooleanTableData function - } - } - if (output != null) { - s += - `' - } - s += '' - } - s += '' - s += '
' + 'dec' + '${inputListNames[i]}${outputListNames[i]}${outputListNames}
${j}${matrix[i][j]}` + - 'x' + - '` + - `${output[j]}` + - '
' - $('#combinationalAnalysis').empty() - $('#combinationalAnalysis').append(s) - $('#combinationalAnalysis').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - style: 'padding: 6px', - text: 'Generate Circuit', - click() { - $(this).dialog('close') - var data = generateBooleanTableData(outputListNamesInteger) - // passing the hash values to avoid spaces being passed which is causing a problem - var minimizedCircuit = [] - let inputCount = inputListNames.length - for (const output in data) { - let oneCount = data[output][1].length // Number of ones - let zeroCount = data[output][0].length // Number of zeroes - if (oneCount == 0) { - // Hardcode to 0 as output - minimizedCircuit.push([ - '-'.repeat(inputCount) + '0', - ]) - } else if (zeroCount == 0) { - // Hardcode to 1 as output - minimizedCircuit.push([ - '-'.repeat(inputCount) + '1', - ]) - } else { - // Perform KMap like minimzation - const temp = new BooleanMinimize( - inputListNames.length, - data[output][1].map(Number), - data[output].x.map(Number) - ) - minimizedCircuit.push(temp.result) - } - } - if (output == null) { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames, - outputListNames, - scope - ) - } else { - drawCombinationalAnalysis( - minimizedCircuit, - inputListNames, - [`${outputListNames}`], - scope - ) - } - }, - }, - { - style: 'padding: 6px', - text: 'Print Truth Table', - click() { - var sTable = document.getElementById( - 'combinationalAnalysis' - ).innerHTML - var style = - '' - var win = window.open('', '', 'height=700,width=700') - var htmlBody = ` - \ - Boolean Logic Table\ - ${style}\ - \ - \ -
${sTable}
\ - - ` - win.document.write(htmlBody) - win.document.close() - win.print() - }, - }, - ], - }) - - $('.output').on('click', function () { - var v = $(this).html() - if (v == 0) v = $(this).html(1) - else if (v == 1) v = $(this).html('x') - else if (v == 'x') v = $(this).html(0) - }) - } -*/ - -// function generateBooleanTableData(outputListNames) { -// var data = {} -// for (var i = 0; i < outputListNames.length; i++) { -// data[outputListNames[i]] = { -// x: [], -// 1: [], -// 0: [], -// } -// var rows = $(`.${outputListNames[i]}`) -// for (let j = 0; j < rows.length; j++) { -// data[outputListNames[i]][rows[j].innerHTML].push(rows[j].id) -// } -// } -// return data -// } - -// function drawCombinationalAnalysis( -// combinationalData, -// inputList, -// outputListNames, -// scope = globalScope -// ) { -// findDimensions(scope) -// var inputCount = inputList.length -// var maxTerms = 0 -// for (var i = 0; i < combinationalData.length; i++) { -// maxTerms = Math.max(maxTerms, combinationalData[i].length) -// } +export const GenerateCircuit = (outputListNamesInteger, inputListNames, output, outputListNames, scope = globalScope) => { + var data = generateBooleanTableData(outputListNamesInteger); + // passing the hash values to avoid spaces being passed which is causing a problem + var minimizedCircuit = []; + let inputCount = inputListNames.length; + for (const output in data) { + let oneCount = data[output][1].length; // Number of ones + let zeroCount = data[output][0].length; // Number of zeroes + if(oneCount == 0) { + // Hardcode to 0 as output + minimizedCircuit.push(['-'.repeat(inputCount) + '0']); + } + else if(zeroCount == 0) { + // Hardcode to 1 as output + minimizedCircuit.push(['-'.repeat(inputCount) + '1']); + } + else { + // Perform KMap like minimzation + const temp = new BooleanMinimize( + inputListNames.length, + data[output][1].map(Number), + data[output].x.map(Number), + ); + minimizedCircuit.push(temp.result); + } + } + if (output == null) { + drawCombinationalAnalysis(minimizedCircuit, inputListNames, outputListNames, scope); + } + else { + drawCombinationalAnalysis(minimizedCircuit, inputListNames, [`${outputListNames}`], scope); + } +}; -// var startPosX = 200 -// var startPosY = 200 - -// var currentPosY = 300 - -// if (simulationArea.maxWidth && simulationArea.maxHeight) { -// if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { -// startPosX += simulationArea.maxWidth -// } else { -// startPosY += simulationArea.maxHeight -// currentPosY += simulationArea.maxHeight -// } -// } -// var andPosX = startPosX + inputCount * 40 + 40 + 40 -// var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80 -// var outputPosX = orPosX + 60 -// var inputObjects = [] +function generateBooleanTableData(outputListNames) { + var data = {}; + for (var i = 0; i < outputListNames.length; i++) { + data[outputListNames[i]] = { + x: [], + 1: [], + 0: [], + }; + var rows = $(`.${outputListNames[i]}`); + for (let j = 0; j < rows.length; j++) { + data[outputListNames[i]][rows[j].innerHTML].push(rows[j].id); + } + } + return data; +} -// var logixNodes = [] +function drawCombinationalAnalysis(combinationalData, inputList, outputListNames, scope = globalScope) { + findDimensions(scope); + var inputCount = inputList.length; + var maxTerms = 0; + for (var i = 0; i < combinationalData.length; i++) { maxTerms = Math.max(maxTerms, combinationalData[i].length); } -// // Appending constant input to the end of inputObjects -// for (var i = 0; i <= inputCount; i++) { -// if (i < inputCount) { -// // Regular Input -// inputObjects.push( -// new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1) -// ) -// inputObjects[i].setLabel(inputList[i]) -// } else { -// // Constant Input -// inputObjects.push( -// new ConstantVal( -// startPosX + i * 40, -// startPosY, -// scope, -// 'DOWN', -// 1, -// '1' -// ) -// ) -// inputObjects[i].setLabel('_C_') -// } + var startPosX = 200; + var startPosY = 200; -// inputObjects[i].newLabelDirection('UP') -// var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root) -// inputObjects[i].output1.connect(v1) -// var v2 = new Node( -// startPosX + i * 40 + 20, -// startPosY + 20, -// 2, -// scope.root -// ) -// v1.connect(v2) -// var notG = new NotGate( -// startPosX + i * 40 + 20, -// startPosY + 40, -// scope, -// 'DOWN', -// 1 -// ) -// notG.inp1.connect(v2) -// logixNodes.push(v1) -// logixNodes.push(notG.output1) -// } + var currentPosY = 300; -// function countTerm(s) { -// var c = 0 -// for (var i = 0; i < s.length; i++) { -// if (s[i] !== '-') c++ -// } -// return c -// } + if (simulationArea.maxWidth && simulationArea.maxHeight) { + if (simulationArea.maxHeight + currentPosY > simulationArea.maxWidth) { + startPosX += simulationArea.maxWidth; + } else { + startPosY += simulationArea.maxHeight; + currentPosY += simulationArea.maxHeight; + } + } + var andPosX = startPosX + inputCount * 40 + 40 + 40; + var orPosX = andPosX + Math.floor(maxTerms / 2) * 10 + 80; + var outputPosX = orPosX + 60; + var inputObjects = []; -// for (var i = 0; i < combinationalData.length; i++) { -// var andGateNodes = [] -// for (var j = 0; j < combinationalData[i].length; j++) { -// var c = countTerm(combinationalData[i][j]) -// if (c > 1) { -// var andGate = new AndGate( -// andPosX, -// currentPosY, -// scope, -// 'RIGHT', -// c, -// 1 -// ) -// andGateNodes.push(andGate.output1) -// var misses = 0 -// for (var k = 0; k < combinationalData[i][j].length; k++) { -// if (combinationalData[i][j][k] == '-') { -// misses++ -// continue -// } -// var index = 2 * k + (combinationalData[i][j][k] == 0) -// var v = new Node( -// logixNodes[index].absX(), -// andGate.inp[k - misses].absY(), -// 2, -// scope.root -// ) -// logixNodes[index].connect(v) -// logixNodes[index] = v -// v.connect(andGate.inp[k - misses]) -// } -// } else { -// for (var k = 0; k < combinationalData[i][j].length; k++) { -// if (combinationalData[i][j][k] == '-') continue -// var index = 2 * k + (combinationalData[i][j][k] == 0) -// var andGateSubstituteNode = new Node( -// andPosX, -// currentPosY, -// 2, -// scope.root -// ) -// var v = new Node( -// logixNodes[index].absX(), -// andGateSubstituteNode.absY(), -// 2, -// scope.root -// ) -// logixNodes[index].connect(v) -// logixNodes[index] = v -// v.connect(andGateSubstituteNode) -// andGateNodes.push(andGateSubstituteNode) -// } -// } -// currentPosY += c * 10 + 30 -// } + var logixNodes = []; -// var andGateCount = andGateNodes.length -// var midWay = Math.floor(andGateCount / 2) -// var orGatePosY = -// (andGateNodes[midWay].absY() + -// andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / -// 2 -// if (orGatePosY % 10 == 5) { -// orGatePosY += 5 -// } // To make or gate fall in grid -// if (andGateCount > 1) { -// var o = new OrGate( -// orPosX, -// orGatePosY, -// scope, -// 'RIGHT', -// andGateCount, -// 1 -// ) -// if (andGateCount % 2 == 1) -// andGateNodes[midWay].connect(o.inp[midWay]) -// for (var j = 0; j < midWay; j++) { -// var v = new Node( -// andPosX + 30 + (midWay - j) * 10, -// andGateNodes[j].absY(), -// 2, -// scope.root -// ) -// v.connect(andGateNodes[j]) -// var v2 = new Node( -// andPosX + 30 + (midWay - j) * 10, -// o.inp[j].absY(), -// 2, -// scope.root -// ) -// v2.connect(v) -// o.inp[j].connect(v2) + // Appending constant input to the end of inputObjects + for (var i = 0; i <= inputCount; i++) { + if(i < inputCount) { + // Regular Input + inputObjects.push(new Input(startPosX + i * 40, startPosY, scope, 'DOWN', 1)); + inputObjects[i].setLabel(inputList[i]); + } + else { + // Constant Input + inputObjects.push(new ConstantVal(startPosX + i * 40, startPosY, scope, 'DOWN', 1, '1')); + inputObjects[i].setLabel('_C_'); + } -// var v = new Node( -// andPosX + 30 + (midWay - j) * 10, -// andGateNodes[andGateCount - j - 1].absY(), -// 2, -// scope.root -// ) -// v.connect(andGateNodes[andGateCount - j - 1]) -// var v2 = new Node( -// andPosX + 30 + (midWay - j) * 10, -// o.inp[andGateCount - j - 1].absY(), -// 2, -// scope.root -// ) -// v2.connect(v) -// o.inp[andGateCount - j - 1].connect(v2) -// } -// var out = new Output(outputPosX, o.y, scope, 'LEFT', 1) -// out.inp1.connect(o.output1) -// } else { -// var out = new Output( -// outputPosX, -// andGateNodes[0].absY(), -// scope, -// 'LEFT', -// 1 -// ) -// out.inp1.connect(andGateNodes[0]) -// } -// out.setLabel(outputListNames[i]) -// out.newLabelDirection('RIGHT') -// } -// for (var i = 0; i < logixNodes.length; i++) { -// if (logixNodes[i].absY() != currentPosY) { -// var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root) -// logixNodes[i].connect(v) -// } -// } -// globalScope.centerFocus() -// } + inputObjects[i].newLabelDirection('UP'); + var v1 = new Node(startPosX + i * 40, startPosY + 20, 2, scope.root); + inputObjects[i].output1.connect(v1); + var v2 = new Node(startPosX + i * 40 + 20, startPosY + 20, 2, scope.root); + v1.connect(v2); + var notG = new NotGate(startPosX + i * 40 + 20, startPosY + 40, scope, 'DOWN', 1); + notG.inp1.connect(v2); + logixNodes.push(v1); + logixNodes.push(notG.output1); + } -// /** -// * This function solves passed boolean expression and returns -// * output array which contains solution of the truth table -// * of given boolean expression -// * @param {Array} inputListNames - labels for input nodes -// * @param {String} booleanExpression - boolean expression which is to be solved -// */ -// function solveBooleanFunction(inputListNames, booleanExpression) { -// let i -// let j -// let output = [] + function countTerm(s) { + var c = 0; + for (var i = 0; i < s.length; i++) { if (s[i] !== '-')c++; } + return c; + } -// if ( -// booleanExpression.match( -// /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g -// ) != null -// ) { -// alert('One of the characters is not allowed.') -// return -// } + for (var i = 0; i < combinationalData.length; i++) { + var andGateNodes = []; + for (var j = 0; j < combinationalData[i].length; j++) { + var c = countTerm(combinationalData[i][j]); + if (c > 1) { + var andGate = new AndGate(andPosX, currentPosY, scope, 'RIGHT', c, 1); + andGateNodes.push(andGate.output1); + var misses = 0; + for (var k = 0; k < combinationalData[i][j].length; k++) { + if (combinationalData[i][j][k] == '-') { misses++; continue; } + var index = 2 * k + (combinationalData[i][j][k] == 0); + var v = new Node(logixNodes[index].absX(), andGate.inp[k - misses].absY(), 2, scope.root); + logixNodes[index].connect(v); + logixNodes[index] = v; + v.connect(andGate.inp[k - misses]); + } + } else { + for (var k = 0; k < combinationalData[i][j].length; k++) { + if (combinationalData[i][j][k] == '-') continue; + var index = 2 * k + (combinationalData[i][j][k] == 0); + var andGateSubstituteNode = new Node(andPosX, currentPosY, 2, scope.root); + var v = new Node(logixNodes[index].absX(), andGateSubstituteNode.absY(), 2, scope.root); + logixNodes[index].connect(v); + logixNodes[index] = v; + v.connect(andGateSubstituteNode); + andGateNodes.push(andGateSubstituteNode); + } + } + currentPosY += c * 10 + 30; + } -// if (inputListNames.length > 8) { -// alert('You can only have 8 variables at a time.') -// return -// } + var andGateCount = andGateNodes.length; + var midWay = Math.floor(andGateCount / 2); + var orGatePosY = (andGateNodes[midWay].absY() + andGateNodes[Math.floor((andGateCount - 1) / 2)].absY()) / 2; + if (orGatePosY % 10 == 5) { orGatePosY += 5; } // To make or gate fall in grid + if (andGateCount > 1) { + var o = new OrGate(orPosX, orGatePosY, scope, 'RIGHT', andGateCount, 1); + if (andGateCount % 2 == 1)andGateNodes[midWay].connect(o.inp[midWay]); + for (var j = 0; j < midWay; j++) { + var v = new Node(andPosX + 30 + (midWay - j) * 10, andGateNodes[j].absY(), 2, scope.root); + v.connect(andGateNodes[j]); + var v2 = new Node(andPosX + 30 + (midWay - j) * 10, o.inp[j].absY(), 2, scope.root); + v2.connect(v); + o.inp[j].connect(v2); -// var s = '' -// s += '' -// s += '' -// if ($('#decimalColumnBox').is(':checked')) { -// s += '' -// } -// for (i = 0; i < inputListNames.length; i++) { -// s += `` -// } -// s += `` -// s += '' -// var matrix = [] -// for (i = 0; i < inputListNames.length; i++) { -// matrix[i] = new Array(inputListNames.length) -// } + var v = new Node(andPosX + 30 + (midWay - j) * 10, andGateNodes[andGateCount - j - 1].absY(), 2, scope.root); + v.connect(andGateNodes[andGateCount - j - 1]); + var v2 = new Node(andPosX + 30 + (midWay - j) * 10, o.inp[andGateCount - j - 1].absY(), 2, scope.root); + v2.connect(v); + o.inp[andGateCount - j - 1].connect(v2); + } + var out = new Output(outputPosX, o.y, scope, 'LEFT', 1); + out.inp1.connect(o.output1); + } else { + var out = new Output(outputPosX, andGateNodes[0].absY(), scope, 'LEFT', 1); + out.inp1.connect(andGateNodes[0]); + } + out.setLabel(outputListNames[i]); + out.newLabelDirection('RIGHT'); + } + for (var i = 0; i < logixNodes.length; i++) { + if (logixNodes[i].absY() != currentPosY) { + var v = new Node(logixNodes[i].absX(), currentPosY, 2, scope.root); + logixNodes[i].connect(v); + } + } + globalScope.centerFocus(); +} -// for (i = 0; i < inputListNames.length; i++) { -// for (j = 0; j < 1 << inputListNames.length; j++) { -// matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) -// } -// } -// // generate equivalent expression by replacing input vars with possible combinations of o and 1 -// for (i = 0; i < 2 ** inputListNames.length; i++) { -// const data = [] -// for (j = 0; j < inputListNames.length; j++) { -// data[j] = -// Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 -// } -// let equation = booleanExpression -// for (j = 0; j < inputListNames.length; j++) { -// equation = equation.replace( -// new RegExp(inputListNames[j], 'g'), -// data[j] -// ) -// } +/** + * This function solves passed boolean expression and returns + * output array which contains solution of the truth table + * of given boolean expression + * @param {Array} inputListNames - labels for input nodes + * @param {String} booleanExpression - boolean expression which is to be solved + */ +export function solveBooleanFunction(inputListNames, booleanExpression) { + let i + let j + output.value = [] -// output[i] = solve(equation) -// } + if ( + booleanExpression.match( + /[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01+'() ]/g + ) != null + ) { + // alert('One of the characters is not allowed.') + confirmSingleOption('One of the characters is not allowed.') + return + } -// for (j = 0; j < 1 << inputListNames.length; j++) { -// s += '' -// if ($('#decimalColumnBox').is(':checked')) { -// s += `` -// } -// for (i = 0; i < inputListNames.length; i++) { -// s += `` -// } + if (inputListNames.length > 8) { + // alert('You can only have 8 variables at a time.') + confirmSingleOption('You can only have 8 variables at a time.') + return + } + var matrix = [] + for (i = 0; i < inputListNames.length; i++) { + matrix[i] = new Array(inputListNames.length) + } -// s += `' -// s += '' -// } + for (i = 0; i < inputListNames.length; i++) { + for (j = 0; j < 1 << inputListNames.length; j++) { + matrix[i][j] = +((j & (1 << (inputListNames.length - i - 1))) != 0) + } + } + // generate equivalent expression by replacing input vars with possible combinations of o and 1 + for (i = 0; i < 2 ** inputListNames.length; i++) { + const data = [] + for (j = 0; j < inputListNames.length; j++) { + data[j] = + Math.floor(i / Math.pow(2, inputListNames.length - j - 1)) % 2 + } + let equation = booleanExpression + for (j = 0; j < inputListNames.length; j++) { + equation = equation.replace( + new RegExp(inputListNames[j], 'g'), + data[j] + ) + } -// s += '' -// s += '
' + 'dec' + '${inputListNames[i]}${booleanExpression}
${j}${matrix[i][j]}` + `${output[j]}` + '
' -// // generates solution for the truth table of booleanexpression -// function solve(equation) { -// while (equation.indexOf('(') != -1) { -// const start = equation.lastIndexOf('(') -// const end = equation.indexOf(')', start) -// if (start != -1) { -// equation = -// equation.substring(0, start) + -// solve(equation.substring(start + 1, end)) + -// equation.substring(end + 1) -// } -// } -// equation = equation.replace(/''/g, '') -// equation = equation.replace(/0'/g, '1') -// equation = equation.replace(/1'/g, '0') -// for (let i = 0; i < equation.length - 1; i++) { -// if ( -// (equation[i] == '0' || equation[i] == '1') && -// (equation[i + 1] == '0' || equation[i + 1] == '1') -// ) { -// equation = -// equation.substring(0, i + 1) + -// '*' + -// equation.substring(i + 1, equation.length) -// } -// } -// try { -// const safeEval = eval -// const answer = safeEval(equation) -// if (answer == 0) { -// return 0 -// } -// if (answer > 0) { -// return 1 -// } -// return '' -// } catch (e) { -// return '' -// } -// } + output.value[i] = solve(equation) + } + // generates solution for the truth table of booleanexpression + function solve(equation) { + while (equation.indexOf('(') != -1) { + const start = equation.lastIndexOf('(') + const end = equation.indexOf(')', start) + if (start != -1) { + equation = + equation.substring(0, start) + + solve(equation.substring(start + 1, end)) + + equation.substring(end + 1) + } + } + equation = equation.replace(/''/g, '') + equation = equation.replace(/0'/g, '1') + equation = equation.replace(/1'/g, '0') + for (let i = 0; i < equation.length - 1; i++) { + if ( + (equation[i] == '0' || equation[i] == '1') && + (equation[i + 1] == '0' || equation[i + 1] == '1') + ) { + equation = + equation.substring(0, i + 1) + + '*' + + equation.substring(i + 1, equation.length) + } + } + try { + const safeEval = eval + const answer = safeEval(equation) + if (answer == 0) { + return 0 + } + if (answer > 0) { + return 1 + } + return '' + } catch (e) { + return '' + } + } +} -// return output -// } +export function createCombinationalAnalysisPrompt(scope = globalScope) { + scheduleBackup() + SimulatorStore().dialogBox.combinationalanalysis_dialog = true +} diff --git a/v1/src/simulator/src/contention.ts b/v1/src/simulator/src/contention.ts new file mode 100644 index 00000000..23c5ee24 --- /dev/null +++ b/v1/src/simulator/src/contention.ts @@ -0,0 +1,123 @@ +/** + * Represents a node with bitWidth and value properties + */ +interface Node { + bitWidth: number; + value: number | undefined; + } + + /** + * @class ContentionPendingData + * + * Data structure to store pending contentions in the circuit. + */ + export default class ContentionPendingData { + private contentionPendingMap: Map>; + private totalContentions: number; + + constructor() { + this.contentionPendingMap = new Map>(); + this.totalContentions = 0; + } + + /** + * Adds a contention between two nodes + * @param ourNode The source node + * @param theirNode The target node + */ + add(ourNode: Node, theirNode: Node): void { + if (this.contentionPendingMap.has(ourNode)) { + const existingSet = this.contentionPendingMap.get(ourNode)!; + if (!existingSet.has(theirNode)) this.totalContentions++; + existingSet.add(theirNode); + return; + } + + this.totalContentions++; + this.contentionPendingMap.set(ourNode, new Set([theirNode])); + } + + /** + * Checks if a node has any pending contentions + * @param ourNode The node to check + * @returns Whether the node has contentions + */ + has(ourNode: Node): boolean { + return this.contentionPendingMap.has(ourNode); + } + + /** + * Removes a specific contention entry + * @param ourNode The source node + * @param theirNode The target node + */ + remove(ourNode: Node, theirNode: Node): void { + if (!this.contentionPendingMap.has(ourNode) || + !this.contentionPendingMap.get(ourNode)!.has(theirNode)) return; + + this.contentionPendingMap.get(ourNode)!.delete(theirNode); + if (this.contentionPendingMap.get(ourNode)!.size === 0) { + this.contentionPendingMap.delete(ourNode); + } + this.totalContentions--; + } + + /** + * Removes all contentions for a specific node + * @param ourNode The node to remove contentions for + */ + removeAllContentionsForNode(ourNode: Node): void { + if (!this.contentionPendingMap.has(ourNode)) return; + + const contentionsForOurNode = this.contentionPendingMap.get(ourNode)!; + for (const theirNode of contentionsForOurNode) { + this.remove(ourNode, theirNode); + } + } + + /** + * Removes a contention if the nodes are resolved + * @param ourNode The source node + * @param theirNode The target node + */ + removeIfResolved(ourNode: Node, theirNode: Node): void { + if (ourNode.bitWidth === theirNode.bitWidth && + (ourNode.value === theirNode.value || ourNode.value === undefined)) { + this.remove(ourNode, theirNode); + } + } + + /** + * Removes resolved contentions for a specific node + * @param ourNode The node to check for resolved contentions + */ + removeIfResolvedAllContentionsForNode(ourNode: Node): void { + if (!this.contentionPendingMap.has(ourNode)) return; + + const contentionsForOurNode = this.contentionPendingMap.get(ourNode)!; + for (const theirNode of contentionsForOurNode) { + this.removeIfResolved(ourNode, theirNode); + } + } + + /** + * @returns Total number of contentions + */ + size(): number { + return this.totalContentions; + } + + /** + * @returns List of all contention pairs + */ + nodes(): [Node, Node][] { + const items: [Node, Node][] = []; + for (const [ourNode, contentionSet] of this.contentionPendingMap) { + for (const theirNode of contentionSet) { + items.push([ourNode, theirNode]); + } + } + + return items; + } + } \ No newline at end of file diff --git a/v1/src/simulator/src/data.js b/v1/src/simulator/src/data.js index 4e573c21..bb9df0e7 100644 --- a/v1/src/simulator/src/data.js +++ b/v1/src/simulator/src/data.js @@ -10,16 +10,11 @@ import { openOffline, recoverProject, } from './data/project' -import { newCircuit, createNewCircuitScope } from './circuit' +import { createNewCircuitScope } from './circuit' import { createCombinationalAnalysisPrompt } from './combinationalAnalysis' import { colorThemes } from './themer/themer' import { showTourGuide } from './tutorials' -import { - createVerilogCircuit, - // saveVerilogCode, - // resetVerilogCode, - // applyVerilogTheme, -} from './Verilog2CV' +import { createVerilogCircuit } from './Verilog2CV' import { generateVerilog } from './verilog' import { bitConverterDialog } from './utils' import { keyBinder } from '#/components/DialogBox/CustomShortcut.vue' @@ -33,7 +28,6 @@ logixFunction.createSaveAsImgPrompt = createSaveAsImgPrompt logixFunction.clearProject = clearProject logixFunction.newProject = newProject logixFunction.saveOffline = saveOffline -// logixFunction.newCircuit = newCircuit logixFunction.createOpenLocalPrompt = openOffline logixFunction.recoverProject = recoverProject logixFunction.createSubCircuitPrompt = createSubCircuitPrompt @@ -43,12 +37,9 @@ logixFunction.fullViewOption = fullView logixFunction.colorThemes = colorThemes logixFunction.showTourGuide = showTourGuideHelper logixFunction.newVerilogModule = createVerilogCircuit -// logixFunction.saveVerilogCode = saveVerilogCode -// logixFunction.resetVerilogCode = resetVerilogCode logixFunction.generateVerilog = generateVerilog -// logixFunction.applyVerilogTheme = applyVerilogTheme logixFunction.bitconverter = bitConverterDialog -logixFunction.createNewCircuitScope = createNewCircuitScope +logixFunction.createNewCircuitScope = createNewCircuit logixFunction.customShortcut = keyBinder logixFunction.ExportProject = ExportProject logixFunction.ImportProject = ImportProject @@ -60,3 +51,8 @@ function showTourGuideHelper() { showTourGuide() }, 100) } + +// Hack to call createNewCircuitScope with keyboard shortcut +function createNewCircuit() { + createNewCircuitScope() +} diff --git a/v1/src/simulator/src/data/backupCircuit.js b/v1/src/simulator/src/data/backupCircuit.js index c17a93c3..e15f5e44 100644 --- a/v1/src/simulator/src/data/backupCircuit.js +++ b/v1/src/simulator/src/data/backupCircuit.js @@ -1,4 +1,6 @@ import { projectSavedSet } from './project' +import { moduleList, updateOrder } from '../metadata' + /* eslint-disable no-param-reassign */ function extract(obj) { return obj.saveObject() diff --git a/v1/src/simulator/src/data/load.js b/v1/src/simulator/src/data/load.js index f9d7b89b..1bc51e65 100644 --- a/v1/src/simulator/src/data/load.js +++ b/v1/src/simulator/src/data/load.js @@ -8,7 +8,7 @@ import { gridUpdateSet, } from '../engine' import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { loadSubCircuit } from '../subcircuit' import { scheduleBackup } from './backupCircuit' @@ -18,9 +18,11 @@ import { generateId } from '../utils' import modules from '../modules' import { oppositeDirection } from '../canvasApi' import plotArea from '../plotArea' -import { updateTestbenchUI, TestbenchData } from '../testbench' +import { TestbenchData } from '#/simulator/src/testbench' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' import { toRefs } from 'vue' +import { moduleList } from '../metadata' + /** * Backward compatibility - needs to be deprecated * @param {CircuitElement} obj - the object to be rectified @@ -282,9 +284,6 @@ export default function load(data) { // Switch to last focussedCircuit if (data.focussedCircuit) switchCircuit(String(data.focussedCircuit)) - // Update the testbench UI - updateTestbenchUI() - updateSimulationSet(true) updateCanvasSet(true) gridUpdateSet(true) diff --git a/v1/src/simulator/src/data/project.js b/v1/src/simulator/src/data/project.ts similarity index 86% rename from v1/src/simulator/src/data/project.js rename to v1/src/simulator/src/data/project.ts index 5a88fdd5..71d244b7 100644 --- a/v1/src/simulator/src/data/project.js +++ b/v1/src/simulator/src/data/project.ts @@ -17,7 +17,8 @@ import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComp */ export async function recoverProject() { if (localStorage.getItem('recover')) { - var data = JSON.parse(localStorage.getItem('recover')) + const recover = localStorage.getItem('recover') + const data = recover ? JSON.parse(recover) : {} if (await confirmOption(`Would you like to recover: ${data.name}`)) { load(data) } @@ -78,11 +79,10 @@ export function openOffline() { } /** * Flag for project saved or not - * @type {boolean} * @category data */ -var projectSaved = true -export function projectSavedSet(param) { +let projectSaved = true +export function projectSavedSet(param: boolean) { projectSaved = param } @@ -91,10 +91,11 @@ export function projectSavedSet(param) { * @category data */ export async function saveOffline() { - const data = await generateSaveData() + const data = await generateSaveData('') if (data instanceof Error) return localStorage.setItem(projectId, data) - const temp = JSON.parse(localStorage.getItem('projectList')) || {} + const projectList = localStorage.getItem('projectList') + const temp = projectList ? JSON.parse(projectList) : {} temp[projectId] = getProjectName() localStorage.setItem('projectList', JSON.stringify(temp)) showMessage( @@ -109,8 +110,8 @@ export async function saveOffline() { function checkToSave() { let saveFlag = false // eslint-disable-next-line no-restricted-syntax - for (id in scopeList) { - saveFlag |= checkIfBackup(scopeList[id]) + for (const id in scopeList) { + saveFlag = saveFlag || checkIfBackup(scopeList[id]) } return saveFlag } @@ -131,14 +132,14 @@ window.onbeforeunload = async function () { // 'You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?' // ) const data = await generateSaveData('Untitled') - localStorage.setItem('recover', await data) + const stringData = JSON.stringify(data) + localStorage.setItem('recover', stringData) // eslint-disable-next-line consistent-return return 'Are u sure u want to leave? Any unsaved changes may not be recoverable' } /** * Function to clear project - * @category data */ export async function clearProject() { if (await confirmOption('Would you like to clear the project?')) { @@ -152,10 +153,8 @@ export async function clearProject() { /** Function used to start a new project while prompting confirmation from the user - * @param {boolean} verify - flag to verify a new project - * @category data */ -export async function newProject(verify) { +export async function newProject(verify: boolean) { if ( verify || projectSaved || @@ -166,7 +165,8 @@ export async function newProject(verify) { ) { clearProject() localStorage.removeItem('recover') - window.location = '/simulator' + const baseUrl = window.location.origin !== 'null' ? window.location.origin : 'http://localhost:4000'; + window.location.assign(`${baseUrl}/simulatorvue/`); setProjectName(undefined) projectId = generateId() diff --git a/v1/src/simulator/src/data/redo.js b/v1/src/simulator/src/data/redo.js deleted file mode 100644 index bc252a98..00000000 --- a/v1/src/simulator/src/data/redo.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable import/no-cycle */ -/** - * Function to restore copy from backup - * @param {Scope=} scope - The circuit on which redo is called - * @category data - */ -import { layoutModeGet } from '../layoutMode' -import Scope, { scopeList } from '../circuit' -import { loadScope } from './load' -import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import { forceResetNodesSet } from '../engine' -/** - * Function called to generate a prompt to save an image - * @param {Scope=} - the circuit in which we want to call redo - * @category data - * @exports redo - */ -export default function redo(scope = globalScope) { - if (layoutModeGet()) return - if (scope.history.length === 0) return - const backupOx = globalScope.ox - const backupOy = globalScope.oy - const backupScale = globalScope.scale - globalScope.ox = 0 - globalScope.oy = 0 - const tempScope = new Scope(scope.name) - loading = true - const redoData = scope.history.pop() - scope.backups.push(redoData) - loadScope(tempScope, JSON.parse(redoData)) - tempScope.backups = scope.backups - tempScope.history = scope.history - tempScope.id = scope.id - tempScope.name = scope.name - tempScope.testbenchData = scope.testbenchData - scopeList[scope.id] = tempScope - globalScope = tempScope - globalScope.ox = backupOx - globalScope.oy = backupOy - globalScope.scale = backupScale - loading = false - forceResetNodesSet(true) - - // Updated restricted elements - updateRestrictedElementsInScope() -} -// for html file diff --git a/v1/src/simulator/src/data/redo.ts b/v1/src/simulator/src/data/redo.ts new file mode 100644 index 00000000..67753db0 --- /dev/null +++ b/v1/src/simulator/src/data/redo.ts @@ -0,0 +1,76 @@ +/* eslint-disable import/no-cycle */ +import { layoutModeGet } from '../layoutMode'; +import Scope, { scopeList } from '../circuit'; +import { loadScope } from './load'; +import { updateRestrictedElementsInScope } from '../restrictedElementDiv'; +import { forceResetNodesSet } from '../engine'; + +// Extend the Scope type to include missing properties +interface ExtendedScope extends Scope { + testbenchData: any; + ox: number; + oy: number; + scale: number; + history: string[]; + backups: string[]; + name: string; + id: string | number; +} + +// Type declarations for global variables +declare var globalScope: ExtendedScope; +declare var loading: boolean; + +/** + * Function to restore copy from backup + * @param {ExtendedScope=} scope - The circuit on which redo is called + * @category data + */ +export default function redo(scope: ExtendedScope = globalScope): void { + if (layoutModeGet()) return; + if (scope.history.length === 0) return; + + // Store the current view state + const backupOx: number = globalScope.ox; + const backupOy: number = globalScope.oy; + const backupScale: number = globalScope.scale; + + // Reset the view position + globalScope.ox = 0; + globalScope.oy = 0; + + // Create a temporary scope + const tempScope: ExtendedScope = new Scope(scope.name) as ExtendedScope; + loading = true; + + // Get the redo data and update history + const redoData: string = scope.history.pop()!; + scope.backups.push(redoData); + + // Load the scope data + loadScope(tempScope, JSON.parse(redoData)); + + // Transfer persistent properties + tempScope.backups = scope.backups; + tempScope.history = scope.history; + tempScope.id = scope.id; + tempScope.name = scope.name; + tempScope.testbenchData = scope.testbenchData; + + // Update the scope list + scopeList[scope.id] = tempScope; + + // Update global scope + globalScope = tempScope; + + // Restore view state + globalScope.ox = backupOx; + globalScope.oy = backupOy; + globalScope.scale = backupScale; + + loading = false; + forceResetNodesSet(true); + + // Update restricted elements + updateRestrictedElementsInScope(); +} \ No newline at end of file diff --git a/v1/src/simulator/src/data/save.js b/v1/src/simulator/src/data/save.js index 4695b312..ecc38eb4 100644 --- a/v1/src/simulator/src/data/save.js +++ b/v1/src/simulator/src/data/save.js @@ -1,22 +1,23 @@ import { scopeList } from '../circuit' import { resetup } from '../setup' -import { update } from '../engine' +import { update, updateSubcircuitSet } from '../engine' import { stripTags, showMessage } from '../utils' import { backUp } from './backupCircuit' -import simulationArea from '../simulationArea' -import backgroundArea from '../backgroundArea' +import { simulationArea } from '../simulationArea' +import { backgroundArea } from '../backgroundArea' import { findDimensions } from '../canvasApi' import { projectSavedSet } from './project' import { colors } from '../themer/themer' import { layoutModeGet, toggleLayoutMode } from '../layoutMode' import { verilogModeGet } from '../Verilog2CV' import domtoimage from 'dom-to-image' -import '../../vendor/canvas2svg' +import canvasToSvg from "canvas-to-svg" import { useProjectStore } from '#/store/projectStore' import { provideProjectName } from '#/components/helpers/promptComponent/PromptComponent.vue' import { UpdateProjectDetail } from '#/components/helpers/createNewProject/UpdateProjectDetail.vue' import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' import { getToken } from '#/pages/simulatorHandler.vue' +import { renderOrder } from '../metadata' // var projectName = undefined @@ -68,7 +69,7 @@ function downloadAsImg(name, imgType) { export function getTabsOrder() { var tabs = document.getElementById('tabsBar').firstChild.children var order = [] - for (let i = 0; i < tabs.length; i++) { + for (let i = 0; i < tabs?.length; i++) { order.push(tabs[i].id) } return order @@ -98,7 +99,6 @@ export async function generateSaveData(name, setName = true) { data.timePeriod = simulationArea.timePeriod data.clockEnabled = simulationArea.clockEnabled data.projectId = projectId - data.simulatorVersion = "v1" data.focussedCircuit = globalScope.id data.orderedTabs = getTabsOrder() @@ -122,6 +122,13 @@ export async function generateSaveData(name, setName = true) { } completed[id] = true + + // This update is very important. + // if a scope's input/output changes and the user saves without going + // to circuits where this circuit is used as a subcircuit. It will + // break the code since the Subcircuit will have different number of + // in/out nodes compared to the localscope input/output objects. + updateSubcircuitSet(true); update(scopeList[id], true) // For any pending integrity checks on subcircuits data.scopes.push(backUp(scopeList[id])) } @@ -186,7 +193,7 @@ export function generateImage( // If SVG, create SVG context - using canvas2svg here if (imgType === 'svg') { - simulationArea.context = new C2S(width, height) + simulationArea.context = new canvasToSvg(width, height) resolution = 1 } else if (imgType !== 'png') { transparent = false @@ -237,7 +244,7 @@ export function generateImage( simulationArea.context.fill() } - // Draw circuits, why is it updateOrder and not renderOrder? + // Draw circuits for (let i = 0; i < renderOrder.length; i++) { for (let j = 0; j < scope[renderOrder[i]].length; j++) { scope[renderOrder[i]][j].draw() @@ -309,16 +316,16 @@ async function generateImageForOnline() { if (verilogModeGet()) { var node = document.getElementsByClassName('CodeMirror')[0] // var node = document.getElementsByClassName('CodeMirror')[0]; - var prevHeight = $(node).css('height') - var prevWidth = $(node).css('width') + var prevHeight = window.getComputedStyle(node).height + var prevWidth = window.getComputedStyle(node).width var baseWidth = 500 var baseHeight = Math.round(baseWidth / ratio) - $(node).css('height', baseHeight) - $(node).css('width', baseWidth) + node.style.height = baseHeight + 'px' + node.style.width = baseWidth + 'px' var data = await domtoimage.toJpeg(node) - $(node).css('width', prevWidth) - $(node).css('height', prevHeight) + node.style.width = prevWidth + node.style.height = prevHeight data = await crop(data, baseWidth, baseHeight) return data } @@ -359,14 +366,16 @@ export default async function save() { const data = await generateSaveData() if (data instanceof Error) return - $('.loadingIcon').fadeIn() + let loadingIcon = document.querySelector('.loadingIcon'); + loadingIcon.style.transition = 'opacity 0.5s linear'; + loadingIcon.style.opacity = '1'; const projectName = getProjectName() var imageData = await generateImageForOnline() const headers = { 'Content-Type': 'application/json', - 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'), + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'), Authorization: `Token ${getToken('cvt')}`, } @@ -380,7 +389,11 @@ export default async function save() { ) ) window.location.href = '/users/sign_in' - else $('.loadingIcon').fadeOut() + else { + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; + } // eslint-disable-next-line camelcase } else if ([0, undefined, null, '', '0'].includes(window.logixProjectId)) { // Create new project - this part needs to be improved and optimised @@ -433,7 +446,11 @@ export default async function save() { showMessage( `We have Created a new project: ${projectName} in our servers.` ) - $('.loadingIcon').fadeOut() + + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; + localStorage.removeItem('recover') const responseJson = response.json() responseJson.then((data) => { @@ -503,7 +520,9 @@ export default async function save() { "There was an error, we couldn't save to our servers" ) } - $('.loadingIcon').fadeOut() + let loadingIcon = document.querySelector('.loadingIcon') + loadingIcon.style.transition = 'opacity 0.2s'; + loadingIcon.style.opacity = '0'; }) .catch((error) => { console.error('Error:', error) diff --git a/v1/src/simulator/src/data/saveImage.js b/v1/src/simulator/src/data/saveImage.js deleted file mode 100644 index 8e2b813d..00000000 --- a/v1/src/simulator/src/data/saveImage.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Helper function to show prompt to save image - * Options - resolution, image type, view - * @param {Scope=} scope - useless though - * @category data - */ -import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' - -/** - * Function called to generate a prompt to save an image - * @category data - * @param {Scope=} - circuit whose image we want - * @exports createSaveAsImgPrompt - */ -export default function createSaveAsImgPrompt(scope = globalScope) { - const simulatorStore = SimulatorStore() - simulatorStore.dialogBox.saveimage_dialog = true -} diff --git a/v1/src/simulator/src/data/saveImage.ts b/v1/src/simulator/src/data/saveImage.ts new file mode 100644 index 00000000..cce91367 --- /dev/null +++ b/v1/src/simulator/src/data/saveImage.ts @@ -0,0 +1,16 @@ +import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore'; +import Scope from '../circuit'; + +// Type declaration for global variable +declare var globalScope: Scope; + +/** + * Function called to generate a prompt to save an image + * @category data + * @param {Scope=} scope - circuit whose image we want + * @exports createSaveAsImgPrompt + */ +export default function createSaveAsImgPrompt(scope: Scope = globalScope): void { + const simulatorStore = SimulatorStore(); + simulatorStore.dialogBox.saveimage_dialog = true; +} \ No newline at end of file diff --git a/v1/src/simulator/src/data/undo.js b/v1/src/simulator/src/data/undo.js deleted file mode 100644 index 67f22005..00000000 --- a/v1/src/simulator/src/data/undo.js +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable import/no-cycle */ -/** - * Function to restore copy from backup - * @param {Scope=} scope - The circuit on which undo is called - * @category data - */ -import { layoutModeGet } from '../layoutMode' -import Scope, { scopeList } from '../circuit' -import { loadScope } from './load' -import { updateRestrictedElementsInScope } from '../restrictedElementDiv' -import { forceResetNodesSet } from '../engine' -/** - * Function called to generate a prompt to save an image - * @param {Scope=} - the circuit in which we want to call undo - * @category data - * @exports undo - */ -export default function undo(scope = globalScope) { - if (layoutModeGet()) return - if (scope.backups.length < 2) return - const backupOx = globalScope.ox - const backupOy = globalScope.oy - const backupScale = globalScope.scale - globalScope.ox = 0 - globalScope.oy = 0 - const tempScope = new Scope(scope.name) - loading = true - const undoData = scope.backups.pop() - scope.history.push(undoData) - scope.backups.length !== 0 && - loadScope( - tempScope, - JSON.parse(scope.backups[scope.backups.length - 1]) - ) - tempScope.backups = scope.backups - tempScope.history = scope.history - tempScope.id = scope.id - tempScope.name = scope.name - tempScope.testbenchData = scope.testbenchData - scopeList[scope.id] = tempScope - globalScope = tempScope - globalScope.ox = backupOx - globalScope.oy = backupOy - globalScope.scale = backupScale - loading = false - forceResetNodesSet(true) - - // Updated restricted elements - updateRestrictedElementsInScope() -} -// for html file diff --git a/v1/src/simulator/src/data/undo.ts b/v1/src/simulator/src/data/undo.ts new file mode 100644 index 00000000..c2bf64b2 --- /dev/null +++ b/v1/src/simulator/src/data/undo.ts @@ -0,0 +1,82 @@ +/* eslint-disable import/no-cycle */ +import { layoutModeGet } from '../layoutMode' +import Scope, { scopeList } from '../circuit' +import { loadScope } from './load' +import { updateRestrictedElementsInScope } from '../restrictedElementDiv' +import { forceResetNodesSet } from '../engine' + +// Declare global variables +declare let globalScope: Scope +declare let loading: boolean + +/** + * Function to restore copy from backup + * @param scope - The circuit on which undo is called + * @category data + */ +export default function undo(scope: Scope = globalScope): void { + if (layoutModeGet() || scope.backups.length < 2) return + + const { ox, oy, scale } = saveGlobalScopePosition() + resetGlobalScopePosition() + + loading = true + const undoData = popLastBackup(scope) + if (!undoData) return + + scope.history.push(undoData) + + const tempScope = createTempScope(scope) + if (!tempScope) return + + updateGlobalScope(tempScope, ox, oy, scale) + forceResetNodesSet(true) + updateRestrictedElementsInScope() +} + +function saveGlobalScopePosition() { + return { + ox: globalScope.ox, + oy: globalScope.oy, + scale: globalScope.scale, + } +} + +function resetGlobalScopePosition() { + globalScope.ox = 0 + globalScope.oy = 0 +} + +function popLastBackup(scope: Scope): string | undefined { + return scope.backups.pop() +} + +function createTempScope(scope: Scope): Scope | undefined { + const tempScope = new Scope(scope.name) + if (scope.backups.length === 0) return tempScope + + try { + loadScope(tempScope, JSON.parse(scope.backups[scope.backups.length - 1])) + } catch (error) { + console.error('Failed to parse backup data:', error) + loading = false + return undefined + } + + tempScope.backups = scope.backups + tempScope.history = scope.history + tempScope.id = scope.id + tempScope.name = scope.name + tempScope.testbenchData = scope.testbenchData + + return tempScope +} + +function updateGlobalScope(tempScope: Scope, ox: number, oy: number, scale: number) { + scopeList[tempScope.id] = tempScope + globalScope = tempScope + globalScope.ox = ox + globalScope.oy = oy + globalScope.scale = scale + loading = false +} \ No newline at end of file diff --git a/v1/src/simulator/src/embed.js b/v1/src/simulator/src/embed.js index b17e82ba..f1a103ec 100644 --- a/v1/src/simulator/src/embed.js +++ b/v1/src/simulator/src/embed.js @@ -1,7 +1,7 @@ // /* eslint-disable import/no-cycle */ // // Helper functions for when circuit is embedded // import { scopeList, circuitProperty } from './circuit' -// import simulationArea from './simulationArea' +// import { simulationArea } from './simulationArea' // import { // scheduleUpdate, // wireToBeCheckedSet, diff --git a/v1/src/simulator/src/embedListeners.js b/v1/src/simulator/src/embedListeners.js index e7cb2d0a..6f7acece 100644 --- a/v1/src/simulator/src/embedListeners.js +++ b/v1/src/simulator/src/embedListeners.js @@ -1,7 +1,11 @@ /* eslint-disable import/no-cycle */ // Listeners when circuit is embedded +/* eslint-disable no-plusplus */ +/* eslint-disable func-names */ +/* eslint-disable prefer-const */ +/* eslint-disable max-len */ // Refer listeners.js -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, update, @@ -14,167 +18,191 @@ import { errorDetectedSet, } from './engine' import { changeScale } from './canvasApi' -import { copy, paste } from './events' -import { ZoomIn, ZoomOut } from './listeners' +import { ZoomIn, ZoomOut, pinchZoom, getCoordinate, } from './listeners'; -var unit = 10 +const unit = 10 +let embedCoordinate; +/** *Function embedPanStart + *This function hepls to initialize mouse and touch + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanStart(e) { + embedCoordinate = getCoordinate(e); + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); -export default function startListeners() { - window.addEventListener('keyup', (e) => { - scheduleUpdate(1) - if (e.keyCode == 16) { - simulationArea.shiftDown = false - } - if (e.key == 'Meta' || e.key == 'Control') { - simulationArea.controlDown = false + simulationArea.lastSelected = undefined; + simulationArea.selected = false; + simulationArea.hover = undefined; + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseDownRawX = (embedCoordinate.x - rect.left) * DPR; + simulationArea.mouseDownRawY = (embedCoordinate.y - rect.top) * DPR; + simulationArea.mouseDownX = Math.round(((simulationArea.mouseDownRawX - globalScope.ox) / globalScope.scale) / unit) * unit; + simulationArea.mouseDownY = Math.round(((simulationArea.mouseDownRawY - globalScope.oy) / globalScope.scale) / unit) * unit; + simulationArea.mouseDown = true; + simulationArea.oldx = globalScope.ox; + simulationArea.oldy = globalScope.oy; + e.preventDefault(); + scheduleUpdate(1); +} +/** *Function embedPanMove + *This function hepls to move simulator and its elements using touch and mouse + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanMove(e) { + embedCoordinate = getCoordinate(e); + if (!simulationArea.touch || e.touches.length === 1) { + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseRawX = (embedCoordinate.x - rect.left) * DPR; + simulationArea.mouseRawY = (embedCoordinate.y - rect.top) * DPR; + simulationArea.mouseXf = (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale; + simulationArea.mouseYf = (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale; + simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit; + simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit; + updateCanvasSet(true); + if (simulationArea.lastSelected == globalScope.root) { + updateCanvasSet(true); + let fn; + fn = function () { + updateSelectionsAndPane(); + }; + scheduleUpdate(0, 20, fn); + } else { + scheduleUpdate(0, 200); } - }) - - document - .getElementById('simulationArea') - .addEventListener('mousedown', (e) => { - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - - simulationArea.lastSelected = undefined - simulationArea.selected = false - simulationArea.hover = undefined - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseDownRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseDownRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseDownX = - Math.round( - (simulationArea.mouseDownRawX - globalScope.ox) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDownY = - Math.round( - (simulationArea.mouseDownRawY - globalScope.oy) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDown = true - simulationArea.oldx = globalScope.ox - simulationArea.oldy = globalScope.oy - - e.preventDefault() - scheduleUpdate(1) - }) - - document - .getElementById('simulationArea') - .addEventListener('mousemove', () => { - var ele = document.getElementById('elementName') - if (globalScope && simulationArea && simulationArea.objectList) { - var { objectList } = simulationArea - objectList = objectList.filter((val) => val !== 'wires') + } + if (simulationArea.touch && e.touches.length === 2) { + pinchZoom(e); + } +} +/** *Function embedPanEnd + *This function update simulator after mouse and touch end + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +function embedPanEnd() { + simulationArea.mouseDown = false; + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + scheduleUpdate(1); +} +/** *Function BlockElementPan + *This function block the pan of elements since in embed simulator you can only view simulator NOT update +*/ - for (var i = 0; i < objectList.length; i++) { - for ( - var j = 0; - j < globalScope[objectList[i]].length; - j++ - ) { - if (globalScope[objectList[i]][j].isHover()) { - ele.style.display = 'block' - if (objectList[i] === 'SubCircuit') { - ele.innerHTML = `Subcircuit: ${globalScope.SubCircuit[j].data.name}` - } else { - ele.innerHTML = `CircuitElement: ${objectList[i]}` - } - return - } +function BlockElementPan() { + const ele = document.getElementById('elementName'); + if (globalScope && simulationArea && simulationArea.objectList) { + let { objectList } = simulationArea; + objectList = objectList.filter((val) => val !== 'wires'); + for (let i = 0; i < objectList.length; i++) { + for (let j = 0; j < globalScope[objectList[i]].length; j++) { + if (globalScope[objectList[i]][j].isHover()) { + ele.style.display = 'block'; + if (objectList[i] === 'SubCircuit') { + ele.innerHTML = `Subcircuit: ${globalScope.SubCircuit[j].data.name}`; + } else { + ele.innerHTML = `CircuitElement: ${objectList[i]}`; } + return; } } + } + } + ele.style.display = 'none'; + document.getElementById('elementName').innerHTML = ''; +} - ele.style.display = 'none' - document.getElementById('elementName').innerHTML = '' - }) - +export default function startListeners() { + window.addEventListener('keyup', (e) => { + scheduleUpdate(1); + if (e.keyCode == 16) { + simulationArea.shiftDown = false; + } + if (e.key == 'Meta' || e.key == 'Control') { + simulationArea.controlDown = false; + } + }); + // All event listeners starts from here + document.getElementById('simulationArea').addEventListener('mousedown', (e) => { + simulationArea.touch = false; + embedPanStart(e); + }); + document.getElementById('simulationArea').addEventListener('mousemove', () => { + simulationArea.touch = false; + BlockElementPan(); + }); + document.getElementById('simulationArea').addEventListener('touchstart', (e) => { + simulationArea.touch = true; + embedPanStart(e); + }); + document.getElementById('simulationArea').addEventListener('touchmove', () => { + simulationArea.touch = true; + BlockElementPan(); + }); window.addEventListener('mousemove', (e) => { - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseXf = - (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale - simulationArea.mouseYf = - (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale - simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit - simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit + embedPanMove(e); + }); + window.addEventListener('touchmove', (e) => { + embedPanMove(e); + }); + window.addEventListener('mouseup', () => { + embedPanEnd(); + }); + window.addEventListener('mousedown', function () { + this.focus(); + }); + window.addEventListener('touchend', () => { + embedPanEnd(); + }); + window.addEventListener('touchstart', function () { + this.focus(); + }); + document.getElementById('simulationArea').addEventListener('mousewheel', MouseScroll); + document.getElementById('simulationArea').addEventListener('DOMMouseScroll', MouseScroll); - updateCanvasSet(true) - if (simulationArea.lastSelected == globalScope.root) { - updateCanvasSet(true) - var fn - fn = function () { - updateSelectionsAndPane() - } - scheduleUpdate(0, 20, fn) - } else { - scheduleUpdate(0, 200) - } - }) window.addEventListener('keydown', (e) => { - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); // zoom in (+) if (e.key == 'Meta' || e.key == 'Control') { - simulationArea.controlDown = true + simulationArea.controlDown = true; } - - if ( - simulationArea.controlDown && - (e.keyCode == 187 || e.KeyCode == 171) - ) { - e.preventDefault() - ZoomIn() + if (simulationArea.controlDown && (e.keyCode == 187 || e.KeyCode == 171)) { + e.preventDefault(); + ZoomIn(); } - // zoom out (-) - if ( - simulationArea.controlDown && - (e.keyCode == 189 || e.Keycode == 173) - ) { - e.preventDefault() - ZoomOut() + if (simulationArea.controlDown && (e.keyCode == 189 || e.Keycode == 173)) { + e.preventDefault(); + ZoomOut(); } - if ( - simulationArea.mouseRawX < 0 || - simulationArea.mouseRawY < 0 || - simulationArea.mouseRawX > width || - simulationArea.mouseRawY > height - ) - return + if (simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height) return; - scheduleUpdate(1) - updateCanvasSet(true) + scheduleUpdate(1); + updateCanvasSet(true); - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.keyDown - ) { - if ( - e.key.toString().length == 1 || - e.key.toString() == 'Backspace' - ) { - simulationArea.lastSelected.keyDown(e.key.toString()) - return + if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown) { + if (e.key.toString().length == 1 || e.key.toString() == 'Backspace') { + simulationArea.lastSelected.keyDown(e.key.toString()); + return; } } - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.keyDown2 - ) { + if (simulationArea.lastSelected && simulationArea.lastSelected.keyDown2) { if (e.key.toString().length == 1) { - simulationArea.lastSelected.keyDown2(e.key.toString()) - return + simulationArea.lastSelected.keyDown2(e.key.toString()); + return; } } @@ -187,73 +215,46 @@ export default function startListeners() { // } if (e.key == 'T' || e.key == 't') { - simulationArea.changeClockTime(prompt('Enter Time:')) + simulationArea.changeClockTime(prompt('Enter Time:')); } - }) - document - .getElementById('simulationArea') - .addEventListener('dblclick', (e) => { - scheduleUpdate(2) - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.dblclick !== undefined - ) { - simulationArea.lastSelected.dblclick() - } - }) - - window.addEventListener('mouseup', (e) => { - simulationArea.mouseDown = false - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - }) - window.addEventListener('mousedown', function (e) { - this.focus() - }) - - document - .getElementById('simulationArea') - .addEventListener('mousewheel', MouseScroll) - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', MouseScroll) - + }); + document.getElementById('simulationArea').addEventListener('dblclick', () => { + scheduleUpdate(2); + if (simulationArea.lastSelected && simulationArea.lastSelected.dblclick !== undefined) { + simulationArea.lastSelected.dblclick(); + } + }); function MouseScroll(event) { - updateCanvasSet(true) + updateCanvasSet(true); - event.preventDefault() - var deltaY = event.wheelDelta ? event.wheelDelta : -event.detail - var scrolledUp = deltaY < 0 - var scrolledDown = deltaY > 0 + event.preventDefault(); + const deltaY = event.wheelDelta ? event.wheelDelta : -event.detail; + const scrolledUp = deltaY < 0; + const scrolledDown = deltaY > 0; if (event.ctrlKey) { if (scrolledUp && globalScope.scale > 0.5 * DPR) { - changeScale(-0.1 * DPR) + changeScale(-0.1 * DPR); } if (scrolledDown && globalScope.scale < 4 * DPR) { - changeScale(0.1 * DPR) + changeScale(0.1 * DPR); } } else { if (scrolledUp && globalScope.scale < 4 * DPR) { - changeScale(0.1 * DPR) + changeScale(0.1 * DPR); } if (scrolledDown && globalScope.scale > 0.5 * DPR) { - changeScale(-0.1 * DPR) + changeScale(-0.1 * DPR); } } - updateCanvasSet(true) - gridUpdateSet(true) - update() // Schedule update not working, this is INEFFICENT + updateCanvasSet(true); + gridUpdateSet(true); + update(); // Schedule update not working, this is INEFFICENT } } +// eslint-disable-next-line no-unused-vars var isIe = navigator.userAgent.toLowerCase().indexOf('msie') != -1 || navigator.userAgent.toLowerCase().indexOf('trident') != -1 diff --git a/v1/src/simulator/src/engine.js b/v1/src/simulator/src/engine.js index 2f74df6e..5227eb76 100644 --- a/v1/src/simulator/src/engine.js +++ b/v1/src/simulator/src/engine.js @@ -5,13 +5,15 @@ /* eslint-disable no-bitwise */ import { layoutModeGet, layoutUpdate } from './layoutMode' import plotArea from './plotArea' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { dots, canvasMessage, findDimensions, rect2 } from './canvasApi' import { showProperties, prevPropertyObjGet } from './ux' import { showError } from './utils' import miniMapArea from './minimap' import { resetup } from './setup' import { verilogModeGet } from './Verilog2CV' +import { renderOrder, updateOrder } from './metadata' +import ContentionPendingData from './contention'; /** * Core of the simulation and rendering algorithm. @@ -368,7 +370,7 @@ export function updateSelectionsAndPane(scope = globalScope) { for (let i = 0; i < updateOrder.length; i++) { for (var j = 0; j < scope[updateOrder[i]].length; j++) { var obj = scope[updateOrder[i]][j] - if (simulationArea.multipleObjectSelections.contains(obj)) + if (simulationArea.multipleObjectSelections.includes(obj)) continue var x var y @@ -404,6 +406,7 @@ export function play(scope = globalScope, resetNodes = false) { simulationArea.simulationQueue.reset() plotArea.setExecutionTime() // Waveform thing + resetNodeHighlights(scope); // Reset Nodes if required if (resetNodes || forceResetNodes) { scope.reset() @@ -411,9 +414,8 @@ export function play(scope = globalScope, resetNodes = false) { forceResetNodesSet(false) } - // To store list of circuitselements that have shown contention but kept temporarily - // Mainly to resolve tristate bus issues - simulationArea.contentionPending = [] + // To store set of Nodes that have shown contention but kept temporarily + simulationArea.contentionPending = new ContentionPendingData(); // add inputs to the simulation queue scope.addInputs() // to check if we have infinite loop in circuit @@ -425,25 +427,34 @@ export function play(scope = globalScope, resetNodes = false) { return } elem = simulationArea.simulationQueue.pop() + elem.resolve() + stepCount++ if (stepCount > 1000000) { // Cyclic or infinite Circuit Detection showError( 'Simulation Stack limit exceeded: maybe due to cyclic paths or contention' ) - errorDetectedSet(true) forceResetNodesSet(true) } } - // Check for TriState Contentions - if (simulationArea.contentionPending.length) { - showError('Contention at TriState') - forceResetNodesSet(true) - errorDetectedSet(true) + // Check for Contentions + if (simulationArea.contentionPending.size() > 0) { + for (const [ourNode, theirNode] of simulationArea.contentionPending.nodes()) { + ourNode.highlighted = true; + theirNode.highlighted = true; + } + + forceResetNodesSet(true); + showError('Contention Error: One or more bus contentions in the circuit (check highlighted nodes)'); } } +export function resetNodeHighlights(scope) { + for (const node of scope.allNodes) node.highlighted = false; +} + /** * Function to check for any UI update, it is throttled by time * @param {number=} count - this is used to force update @@ -451,7 +462,7 @@ export function play(scope = globalScope, resetNodes = false) { * @param {function} fn - function to run before updating UI * @category engine */ -export function scheduleUpdate(count = 0, time = 100, fn) { +export function scheduleUpdate(count = 0, time = 100, fn = undefined) { if (lightMode) time *= 5 var updateFn = layoutModeGet() ? layoutUpdate : update if (count) { diff --git a/v0/src/simulator/src/eventQueue.js b/v1/src/simulator/src/eventQueue.ts similarity index 87% rename from v0/src/simulator/src/eventQueue.js rename to v1/src/simulator/src/eventQueue.ts index f40110e1..349f137c 100644 --- a/v0/src/simulator/src/eventQueue.js +++ b/v1/src/simulator/src/eventQueue.ts @@ -2,19 +2,29 @@ * Event Queue is simply a priority Queue, basic implementation O(n^2). * @category eventQueue */ -export default class EventQueue { - constructor(size) { + +interface QueueObject { + queueProperties: { + inQueue: boolean + time: number + index: number + } + propagationDelay: number +} + +export class EventQueue { + size: number + queue: Array + frontIndex: number + time: number + constructor(size: number) { this.size = size this.queue = new Array(size) this.frontIndex = 0 this.time = 0 } - /** - * @param {CircuitElement} obj - the elemnt to be added - * @param {number} delay - the delay in adding an object to queue - */ - add(obj, delay) { + add(obj: QueueObject, delay: number) { if (obj.queueProperties.inQueue) { obj.queueProperties.time = this.time + (delay || obj.propagationDelay) @@ -41,7 +51,6 @@ export default class EventQueue { if (this.frontIndex == this.size) throw 'EventQueue size exceeded' this.queue[this.frontIndex] = obj - // obj.queueProperties.time=obj.propagationDelay; obj.queueProperties.time = this.time + (delay || obj.propagationDelay) obj.queueProperties.index = this.frontIndex this.frontIndex++ @@ -60,7 +69,7 @@ export default class EventQueue { * To add without any delay. * @param {CircuitElement} obj - the object to be added */ - addImmediate(obj) { + addImmediate(obj: QueueObject) { this.queue[this.frontIndex] = obj obj.queueProperties.time = this.time obj.queueProperties.index = this.frontIndex @@ -70,10 +79,8 @@ export default class EventQueue { /** * Function to swap two objects in queue. - * @param {number} v1 - * @param {number} v2 */ - swap(v1, v2) { + swap(v1: number, v2: number) { const obj1 = this.queue[v1] obj1.queueProperties.index = v2 diff --git a/v1/src/simulator/src/events.js b/v1/src/simulator/src/events.js index c3c0edca..07de4275 100644 --- a/v1/src/simulator/src/events.js +++ b/v1/src/simulator/src/events.js @@ -11,16 +11,16 @@ import { import { backUp } from './data/backupCircuit' import { getNextPosition } from './modules' import { generateId } from './utils' -import simulationArea from './simulationArea' -import { TestbenchData } from './testbench' +import { simulationArea } from './simulationArea' +import { TestbenchData } from '#/simulator/src/testbench' +import { moduleList, updateOrder } from './metadata' /** * Helper function to paste - * @param {JSON} copyData - the data to be pasted * @category events */ export function paste(copyData) { - if (copyData === undefined) return + if (copyData === 'undefined') return var data = JSON.parse(copyData) if (!data.logixClipBoardData) return @@ -104,7 +104,7 @@ export function paste(copyData) { l !== 'objects' && l !== 'CircuitElement' ) { - globalScope[l].extend(tempScope[l]) + globalScope[l].push(...tempScope[l]) } }) for (let i = 0; i < tempScope.Input.length; i++) { @@ -119,7 +119,6 @@ export function paste(copyData) { globalScope ) } - var canvasUpdate = true updateSimulationSet(true) updateSubcircuitSet(true) scheduleUpdate() @@ -165,7 +164,7 @@ export function cut(copyList) { const obj = globalScope[updateOrder[i]][j] if (obj.objectType != 'Wire') { // }&&obj.objectType!='CircuitElement'){//}&&(obj.objectType!='Node'||obj.type==2)){ - if (!copyList.contains(globalScope[updateOrder[i]][j])) { + if (!copyList.includes(globalScope[updateOrder[i]][j])) { globalScope[updateOrder[i]][j].cleanDelete() } } @@ -198,9 +197,8 @@ export function cut(copyList) { data.logixClipBoardData = true data = JSON.stringify(data) - simulationArea.multipleObjectSelections = [] // copyList.slice(); - simulationArea.copyList = [] // copyList.slice(); - var canvasUpdate = true + simulationArea.multipleObjectSelections = [] + simulationArea.copyList = [] updateSimulationSet(true) globalScope = tempScope scheduleUpdate() @@ -252,7 +250,7 @@ export function copy(copyList, cutflag = false) { const obj = globalScope[updateOrder[i]][j] if (obj.objectType != 'Wire') { // }&&obj.objectType!='CircuitElement'){//}&&(obj.objectType!='Node'||obj.type==2)){ - if (!copyList.contains(globalScope[updateOrder[i]][j])) { + if (!copyList.includes(globalScope[updateOrder[i]][j])) { globalScope[updateOrder[i]][j].cleanDelete() } } @@ -297,9 +295,8 @@ export function copy(copyList, cutflag = false) { data.logixClipBoardData = true data.testbenchData = undefined // Don't copy testbench data data = JSON.stringify(data) - simulationArea.multipleObjectSelections = [] // copyList.slice(); - simulationArea.copyList = [] // copyList.slice(); - var canvasUpdate = true + simulationArea.multipleObjectSelections = [] + simulationArea.copyList = [] updateSimulationSet(true) globalScope = tempScope scheduleUpdate() diff --git a/v0/src/simulator/src/hotkey_binder/defaultKeys.js b/v1/src/simulator/src/hotkey_binder/defaultKeys.ts similarity index 89% rename from v0/src/simulator/src/hotkey_binder/defaultKeys.js rename to v1/src/simulator/src/hotkey_binder/defaultKeys.ts index 0529ce5f..42afbbf6 100644 --- a/v0/src/simulator/src/hotkey_binder/defaultKeys.js +++ b/v1/src/simulator/src/hotkey_binder/defaultKeys.ts @@ -1,8 +1,11 @@ /**Add more elements here, along with a valid value for key * Elements keys must have the same name as their ID **/ +export interface DefaultKeysType { + [key: string]: string; +} -export const defaultKeys = { +export const defaultKeys: DefaultKeysType = { 'New Circuit': 'Shift + N', 'Save Online': 'Ctrl + S', 'Save Offline': 'Ctrl + Alt + S', diff --git a/v1/src/simulator/src/hotkey_binder/model/actions.js b/v1/src/simulator/src/hotkey_binder/model/actions.js deleted file mode 100644 index 102209ee..00000000 --- a/v1/src/simulator/src/hotkey_binder/model/actions.js +++ /dev/null @@ -1,205 +0,0 @@ -import { defaultKeys } from '../defaultKeys' -import { addShortcut } from './addShortcut' -import { updateHTML } from '../view/panel.ui' -import simulationArea from '../../simulationArea' -import { - scheduleUpdate, - update, - updateSelectionsAndPane, - wireToBeCheckedSet, - updatePositionSet, - updateSimulationSet, - updateCanvasSet, - gridUpdateSet, - errorDetectedSet, -} from '../../engine' - -import { getOS } from './utils.js' -import { shortcut } from './shortcuts.plugin.js' -/** - * Function used to add or change keys user or default - * grabs the keycombo from localstorage & - * calls the addShortcut function in a loop to bind them - * @param {string} mode - user custom keys or default keys - */ -export const addKeys = (mode) => { - shortcut.removeAll() - if (mode === 'user') { - localStorage.removeItem('defaultKeys') - let userKeys = localStorage.get('userKeys') - for (let pref in userKeys) { - let key = userKeys[pref] - key = key.split(' ').join('') - addShortcut(key, pref) - } - updateHTML('user') - } else if (mode == 'default') { - if (localStorage.userKeys) localStorage.removeItem('userKeys') - let defaultKeys = localStorage.get('defaultKeys') - for (let pref in defaultKeys) { - let key = defaultKeys[pref] - key = key.split(' ').join('') - addShortcut(key, pref) - } - updateHTML('default') - } -} -/** - * Function used to check if new keys are added, adds missing keys if added - */ -export const checkUpdate = () => { - const userK = localStorage.get('userKeys') - if (Object.size(userK) !== Object.size(defaultKeys)) { - for (const [key, value] of Object.entries(defaultKeys)) { - if (!Object.keys(userK).includes(key)) { - userK[key] = value - } - } - localStorage.set('userKeys', userK) - } else { - return - } -} -/** - * Function used to set userKeys, grabs the keycombo from the panel UI - * sets it to the localStorage & cals addKeys - * removes the defaultkeys from localStorage - */ -export const setUserKeys = () => { - if (localStorage.defaultKeys) localStorage.removeItem('defaultKeys') - let userKeys = {} - let x = 0 - while ($('#preference').children()[x]) { - userKeys[ - $('#preference').children()[x].children[1].children[0].innerText - ] = $('#preference').children()[x].children[1].children[1].innerText - x++ - } - localStorage.set('userKeys', userKeys) - addKeys('user') -} -/** - * Function used to set defaultKeys, grabs the keycombo from the defaultkeys metadata - * sets it to the localStorage & cals addKeys - * removes the userkeys from localStorage if present - * also checks for OS type - */ -export const setDefault = () => { - if (localStorage.userKeys) localStorage.removeItem('userKeys') - if (getOS() === 'MacOS') { - const macDefaultKeys = {} - for (let [key, value] of Object.entries(defaultKeys)) { - if (value.split(' + ')[0] == 'Ctrl'); - macDefaultKeys[key] = - value.split(' + ')[0] == 'Ctrl' - ? value.replace('Ctrl', 'Meta') - : value - localStorage.set('defaultKeys', macDefaultKeys) - } - } else { - localStorage.set('defaultKeys', defaultKeys) //TODO add a confirmation alert - } - addKeys('default') -} -/** - * function to check if user entered keys are already assigned to other key - * gives a warning message if keys already assigned - * @param {string} combo the key combo - * @param {string} target the target option of the panel - */ -export const warnOverride = (combo, target, warning) => { - let x = 0 - while ($('#preference').children()[x]) { - if ( - $('#preference').children()[x].children[1].children[1].innerText === - combo && - $('#preference').children()[x].children[1].children[0].innerText !== - target.previousElementSibling.innerText - ) { - const assignee = - $('#preference').children()[x].children[1].children[0].innerText - // $('#warning').text( - // `This key(s) is already assigned to: ${assignee}, press Enter to override.` - // ) - warning.value = `This key(s) is already assigned to: ${assignee}, press Enter to override.` - $('#edit').css('border', '1.5px solid #dc5656') - return - } else { - $('#edit').css('border', 'none') - } - x++ - } -} - -export const elementDirection = (direct) => () => { - if (simulationArea.lastSelected) { - simulationArea.lastSelected.newDirection(direct.toUpperCase()) - $("select[name |= 'newDirection']").val(direct.toUpperCase()) - updateSystem() - } -} - -export const labelDirection = (direct) => () => { - if ( - simulationArea.lastSelected && - !simulationArea.lastSelected.labelDirectionFixed - ) { - simulationArea.lastSelected.labelDirection = direct.toUpperCase() - $("select[name |= 'newLabelDirection']").val(direct.toUpperCase()) - updateSystem() - } -} - -export const insertLabel = () => { - if (simulationArea.lastSelected) { - $("input[name |= 'setLabel']").focus() - $("input[name |= 'setLabel']").val().length - ? null - : $("input[name |= 'setLabel']").val('Untitled') - $("input[name |= 'setLabel']").select() - updateSystem() - } -} - -export const moveElement = (direct) => () => { - if (simulationArea.lastSelected) { - switch (direct) { - case 'up': - simulationArea.lastSelected.y -= 10 - break - case 'down': - simulationArea.lastSelected.y += 10 - break - case 'left': - simulationArea.lastSelected.x -= 10 - break - case 'right': - simulationArea.lastSelected.x += 10 - break - } - updateSystem() - } -} - -export const openHotkey = () => $('#customShortcut').trigger('click') - -export const createNewCircuitScopeCall = () => - $('#createNewCircuitScope').trigger('click') // TODO: remove later - -export const openDocumentation = () => { - if ( - simulationArea.lastSelected == undefined || - simulationArea.lastSelected.helplink == undefined - ) { - // didn't select any element or documentation not found - window.open('https://docs.circuitverse.org/', '_blank') - } else { - window.open(simulationArea.lastSelected.helplink, '_blank') - } -} - -function updateSystem() { - updateCanvasSet(true) - wireToBeCheckedSet(1) - scheduleUpdate(1) -} diff --git a/v1/src/simulator/src/hotkey_binder/model/actions.ts b/v1/src/simulator/src/hotkey_binder/model/actions.ts new file mode 100644 index 00000000..33452764 --- /dev/null +++ b/v1/src/simulator/src/hotkey_binder/model/actions.ts @@ -0,0 +1,340 @@ +/* eslint-disable import/no-cycle */ +import { defaultKeys } from '../defaultKeys' +import { addShortcut } from './addShortcut' +import { updateHTML } from '../view/panel.ui' +import { simulationArea } from '../../simulationArea' +import { + scheduleUpdate, + wireToBeCheckedSet, + updateCanvasSet, +} from '../../engine' + +import { getOS } from './utils' +import { shortcut } from './shortcuts.plugin' + +import { KeyMap } from './model.types' + +type DirectionType = 'up' | 'down' | 'left' | 'right' + +/** + * Function used to add or change keys user or default + * grabs the keycombo from localstorage & + * calls the addShortcut function in a loop to bind them + * @param {string} mode - user custom keys or default keys + */ +export const addKeys = (mode: 'user' | 'default'): void => { + shortcut.removeAll() + const keys = mode === 'user' ? getUserKeys() : getDefaultKeys() + bindKeys(keys, mode) +} + +/** + * Get user keys from localStorage + */ +const getUserKeys = (): KeyMap => { + localStorage.removeItem('defaultKeys') + return JSON.parse(localStorage.getItem('userKeys') || '{}') +} + +/** + * Get default keys from localStorage + */ +const getDefaultKeys = (): KeyMap => { + if (localStorage.userKeys) localStorage.removeItem('userKeys') + return JSON.parse(localStorage.getItem('defaultKeys') || '{}') +} + +/** + * Bind keys to shortcuts + */ +const bindKeys = (keys: KeyMap, mode: 'user' | 'default'): void => { + Object.entries(keys).forEach(([pref, key]) => { + const normalizedKey = key.split(' ').join('') + addShortcut(normalizedKey, pref) + }) + updateHTML(mode) +} + +/** + * Function used to check if new keys are added, adds missing keys if added + */ +export const checkUpdate = (): void => { + const userK: KeyMap = JSON.parse(localStorage.getItem('userKeys') || '{}'); + const defaultK: KeyMap = defaultKeys; + + const hasChanges = syncKeys(userK, defaultK); + + if (hasChanges) { + localStorage.setItem('userKeys', JSON.stringify(userK)); + } +}; + +const syncKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + const hasAddedOrUpdated = addOrUpdateKeys(userK, defaultK); + const hasRemoved = removeObsoleteKeys(userK, defaultK); + + return hasAddedOrUpdated || hasRemoved; +}; + +const addOrUpdateKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + let hasChanges = false; + + for (const key of Object.keys(defaultK)) { + if (!Object.hasOwn(userK, key) || userK[key] !== defaultK[key]) { + userK[key] = defaultK[key]; + hasChanges = true; + } + } + + return hasChanges; +}; + +const removeObsoleteKeys = (userK: KeyMap, defaultK: KeyMap): boolean => { + let hasChanges = false; + + for (const key of Object.keys(userK)) { + if (!Object.hasOwn(defaultK, key)) { + delete userK[key]; + hasChanges = true; + } + } + + return hasChanges; +}; + +/** + * Add missing keys to user keys + */ +const addMissingKeys = (userK: KeyMap): void => { + Object.entries(defaultKeys).forEach(([key, value]) => { + if (!userK[key]) { + userK[key] = value + } + }) +} + +/** + * Function used to set userKeys, grabs the keycombo from the panel UI + * sets it to the localStorage & calls addKeys + * removes the defaultkeys from localStorage + */ +export const setUserKeys = (): void => { + if (localStorage.defaultKeys) localStorage.removeItem('defaultKeys') + const userKeys = getUserKeysFromUI() + localStorage.setItem('userKeys', JSON.stringify(userKeys)) + addKeys('user') +} + +/** + * Get user keys from the UI + */ +const getUserKeysFromUI = (): KeyMap => { + const userKeys: KeyMap = {} + const preferenceChildren = document.getElementById('preference')?.children + if (!preferenceChildren) return userKeys + + Array.from(preferenceChildren).forEach((child) => { + const keyChild = child?.children[1]?.children[0] + const valueChild = child?.children[1]?.children[1] + + if (keyChild instanceof HTMLElement && valueChild instanceof HTMLElement) { + userKeys[keyChild.innerText] = valueChild.innerText + } + }) + return userKeys +} + +/** + * Function used to set defaultKeys, grabs the keycombo from the defaultkeys metadata + * sets it to the localStorage & calls addKeys + * removes the userkeys from localStorage if present + * also checks for OS type + */ +export const setDefault = (): void => { + if (localStorage.getItem('userKeys')) localStorage.removeItem('userKeys') + const keys = getOS() === 'MacOS' ? getMacDefaultKeys() : defaultKeys + localStorage.setItem('defaultKeys', JSON.stringify(keys)) + addKeys('default') +} + +/** + * Get default keys for MacOS + */ +const getMacDefaultKeys = (): KeyMap => { + const macDefaultKeys: KeyMap = {} + Object.entries(defaultKeys).forEach(([key, value]) => { + macDefaultKeys[key] = value.split(' + ')[0] === 'Ctrl' ? value.replace('Ctrl', 'Meta') : value + }) + return macDefaultKeys +} + +/** + * Function to check if user entered keys are already assigned to other key + * gives a warning message if keys already assigned + */ +export const warnOverride = ( + combo: string, + target: HTMLElement, + warning: HTMLInputElement +): void => { + const preferenceChildren = document.getElementById('preference')?.children + if (!preferenceChildren) return + + const isComboAssigned = checkIfComboIsAssigned(combo, target, preferenceChildren) + if (isComboAssigned) { + warning.value = `This key(s) is already assigned to: ${isComboAssigned}, press Enter to override.` + setEditElementBorder('#dc5656') + } else { + setEditElementBorder('none') + } +} + +/** + * Check if the key combo is already assigned to another key + */ +const checkIfComboIsAssigned = ( + combo: string, + target: HTMLElement, + preferenceChildren: HTMLCollection +): string | undefined => { + return Array.from(preferenceChildren).reduce((acc, child) => { + if (acc) return acc + return getAssigneeFromPreference(child, combo, target) + }, undefined) +} + +/** + * Get the assignee from a preference element if the combo matches + */ +const getAssigneeFromPreference = ( + preferenceElement: Element | null, + combo: string, + target: HTMLElement +): string | undefined => { + const keyChild = preferenceElement?.children[1]?.children[0] + const valueChild = preferenceElement?.children[1]?.children[1] + + if (keyChild instanceof HTMLElement && valueChild instanceof HTMLElement) { + const assignee = keyChild.innerText + if (valueChild.innerText === combo && + assignee !== (target.previousElementSibling as HTMLElement)?.innerText) { + return assignee + } + } + return undefined +} + +/** + * Set border style for edit element + */ +const setEditElementBorder = (color: string): void => { + const editElement = document.getElementById('edit') + if (editElement) { + editElement.style.border = color === 'none' ? 'none' : `1.5px solid ${color}` + } +} + +/** + * Update element direction + */ +export const elementDirection = (direct: string) => (): void => { + if (simulationArea.lastSelected) { + simulationArea.lastSelected.newDirection(direct.toUpperCase()) + updateSelectElement("select[name^='newDirection']", direct.toUpperCase()) + updateSystem() + } +} + +/** + * Update label direction + */ +export const labelDirection = (direct: string) => (): void => { + if (simulationArea.lastSelected && !simulationArea.lastSelected.labelDirectionFixed) { + simulationArea.lastSelected.labelDirection = direct.toUpperCase() + updateSelectElement("select[name^='newLabelDirection']", direct.toUpperCase()) + updateSystem() + } +} + +/** + * Update select element value + */ +const updateSelectElement = (selector: string, value: string): void => { + const selectElement = document.querySelector(selector) + if (selectElement) { + selectElement.value = value + } +} + +/** + * Insert label into input field + */ +export const insertLabel = (): void => { + if (!simulationArea.lastSelected) return + + const labelInput = document.querySelector("input[name^='setLabel']") + if (!labelInput) return + + focusAndSetLabel(labelInput) + updateSystem() +} + +/** + * Focus on the label input and set a default value if empty + */ +const focusAndSetLabel = (labelInput: HTMLInputElement): void => { + labelInput.focus() + if (!labelInput.value) { + labelInput.value = 'Untitled' + } + labelInput.select() +} + +/** + * Move element in a specific direction + */ +export const moveElement = (direct: DirectionType) => (): void => { + if (simulationArea.lastSelected) { + const { x, y } = simulationArea.lastSelected + const newPosition = calculateNewPosition(direct, x, y) + simulationArea.lastSelected.x = newPosition.x + simulationArea.lastSelected.y = newPosition.y + updateSystem() + } +} + +/** + * Calculate new position based on direction + */ +const calculateNewPosition = (direct: DirectionType, x: number, y: number): { x: number; y: number } => { + switch (direct) { + case 'up': return { x, y: y - 10 } + case 'down': return { x, y: y + 10 } + case 'left': return { x: x - 10, y } + case 'right': return { x: x + 10, y } + } +} + +/** + * Open hotkey settings + */ +export const openHotkey = (): void => { + document.getElementById('customShortcut')?.click() +} + +/** + * Open documentation + */ +export const openDocumentation = (): void => { + const url = simulationArea.lastSelected?.helplink || 'https://docs.circuitverse.org/' + window.open(url, '_blank') +} + +/** + * Update system state + */ +function updateSystem(): void { + updateCanvasSet(true) + wireToBeCheckedSet(1) + scheduleUpdate(1) +} \ No newline at end of file diff --git a/v1/src/simulator/src/hotkey_binder/model/addShortcut.js b/v1/src/simulator/src/hotkey_binder/model/addShortcut.ts similarity index 69% rename from v1/src/simulator/src/hotkey_binder/model/addShortcut.js rename to v1/src/simulator/src/hotkey_binder/model/addShortcut.ts index 27834ab1..c5e0b4dd 100644 --- a/v1/src/simulator/src/hotkey_binder/model/addShortcut.js +++ b/v1/src/simulator/src/hotkey_binder/model/addShortcut.ts @@ -1,8 +1,4 @@ -// import { shortcut } from './Shortcuts.plugin'; -// import createSaveAsImgPrompt from '../../data/saveImage'; -//Assign the callback func for the keymap here import { - createNewCircuitScopeCall, elementDirection, insertLabel, labelDirection, @@ -15,13 +11,44 @@ import { saveOffline, openOffline } from '../../data/project' import createSaveAsImgPrompt from '../../data/saveImage' import { createSubCircuitPrompt } from '../../subcircuit' import { createCombinationalAnalysisPrompt } from '../../combinationalAnalysis' -import { shortcut } from './shortcuts.plugin.js' +import { shortcut } from './shortcuts.plugin' +import logixFunction from '../../data' +import { ShortcutOptions } from './model.types' + +export type ActionType = + | 'New Circuit' + | 'Save Online' + | 'Save Offline' + | 'Download as Image' + | 'Open Offline' + | 'Insert Sub-circuit' + | 'Combinational Analysis' + | 'Direction Up' + | 'Direction Down' + | 'Direction Left' + | 'Direction Right' + | 'Insert Label' + | 'Label Direction Up' + | 'Label Direction Down' + | 'Label Direction Left' + | 'Label Direction Right' + | 'Move Element Up' + | 'Move Element Down' + | 'Move Element Left' + | 'Move Element Right' + | 'Hotkey Preference' + | 'Open Documentation' + +export const addShortcut = ( + keys: string, + action: ActionType, + customOptions?: Partial +): void => { + let callback: (() => void) | (() => Promise) -export const addShortcut = (keys, action) => { - let callback switch (action) { case 'New Circuit': - callback = createNewCircuitScopeCall // TODO: directly call rather than using dom click + callback = logixFunction.createNewCircuitScope break case 'Save Online': callback = save @@ -40,10 +67,7 @@ export const addShortcut = (keys, action) => { break case 'Combinational Analysis': callback = createCombinationalAnalysisPrompt - break //bug - // case "Start Plot": - // callback = startPlot; - // break; + break case 'Direction Up': callback = elementDirection('up') break @@ -90,13 +114,16 @@ export const addShortcut = (keys, action) => { callback = openDocumentation break default: - callback = () => console.log('No shortcut found..') - break + callback = () => console.error('No shortcut found..') } - shortcut.add(keys, callback, { + + const options: ShortcutOptions = { type: 'keydown', propagate: false, target: document, disable_in_input: true, - }) -} + ...customOptions + } + + shortcut.add(keys, callback, options) +} \ No newline at end of file diff --git a/v1/src/simulator/src/hotkey_binder/model/model.types.ts b/v1/src/simulator/src/hotkey_binder/model/model.types.ts new file mode 100644 index 00000000..271cbf01 --- /dev/null +++ b/v1/src/simulator/src/hotkey_binder/model/model.types.ts @@ -0,0 +1,25 @@ +//This file holds the interfaces required for src/simulator/src/hotkey_binder/model +//to be continued for storing interfaces of the parent folder + +export interface ShortcutOptions { + type?: string + propagate?: boolean + disable_in_input?: boolean + target?: Document | string + keycode?: number | false +} + +export interface ShortcutBinding { + callback: EventListener + target: Document | HTMLElement + event: string +} + +export interface ModifierState { + wanted: boolean + pressed: boolean +} + +export interface KeyMap { + [key: string]: string +} diff --git a/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js b/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js deleted file mode 100644 index f80d37bd..00000000 --- a/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * http://www.openjs.com/scripts/events/keyboard_shortcuts/ - * Version : 2.01.B - * By Binny V A - * License : BSD - */ - -/** - * Restrictions: - * The shortcut key combination should be specified in this format ... Modifier[+Modifier..]+Key. - * Can have a single key without Modifier .. Key, not Key + Key - * These restrictions must be be hardcoded to not let users input invalid key combo - * There is no way to override Ctrl+N, Ctrl+T, or Ctrl+W in Google Chrome since version 4 of Chrome (shipped in 2010). - * - **/ - -//*! This plugin has been modified - -export const shortcut = { - all_shortcuts: {}, //All the shortcuts are stored in this array ex. download : keycombo; - add: function (shortcut_combination, callback, opt) { - //Provide a set of default options - var default_options = { - type: 'keydown', - propagate: false, - disable_in_input: true, - target: document, - keycode: false, - } - - if (!opt) opt = default_options - else { - for (var dfo in default_options) { - if (typeof opt[dfo] == 'undefined') - opt[dfo] = default_options[dfo] - } - } - - var ele = opt.target - if (typeof opt.target == 'string') - ele = document.getElementById(opt.target) - var ths = this - shortcut_combination = shortcut_combination.toLowerCase() - - //The function to be called at keypress - var func = function (e) { - e = e || window.event - if (opt['disable_in_input']) { - //Don't enable shortcut keys in Input, Textarea fields - var element - if (e.target) element = e.target - else if (e.srcElement) element = e.srcElement - if (element.nodeType == 3) element = element.parentNode - - if (element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') - return - } - - let code = '' - //Find Which key is pressed - if (e.keyCode) code = e.keyCode - else if (e.which) code = e.which - var character = String.fromCharCode(code).toLowerCase() - // e.preventDefault(); - - if (code == 188) character = ',' //If the user presses , when the type is onkeydown - if (code == 190) character = '.' //If the user presses , when the type is onkeydown - - var keys = shortcut_combination.split('+') - //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked - var kp = 0 - - //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken - var shift_nums = { - '`': '~', - 1: '!', - 2: '@', - 3: '#', - 4: '$', - 5: '%', - 6: '^', - 7: '&', - 8: '*', - 9: '(', - 0: ')', - '-': '_', - '=': '+', - ';': ':', - "'": '"', - ',': '<', - '.': '>', - '/': '?', - '\\': '|', - } - //Special Keys - and their codes - var special_keys = { - esc: 27, - escape: 27, - tab: 9, - space: 32, - return: 13, - enter: 13, - backspace: 8, - - scrolllock: 145, - scroll_lock: 145, - scroll: 145, - capslock: 20, - caps_lock: 20, - caps: 20, - numlock: 144, - num_lock: 144, - num: 144, - - pause: 19, - break: 19, - - insert: 45, - home: 36, - delete: 46, - end: 35, - - pageup: 33, - page_up: 33, - pu: 33, - - pagedown: 34, - page_down: 34, - pd: 34, - - left: 37, - up: 38, - right: 39, - down: 40, - - f1: 112, - f2: 113, - f3: 114, - f4: 115, - f5: 116, - f6: 117, - f7: 118, - f8: 119, - f9: 120, - f10: 121, - f11: 122, - f12: 123, - } - - var modifiers = { - shift: { wanted: false, pressed: false }, - ctrl: { wanted: false, pressed: false }, - alt: { wanted: false, pressed: false }, - meta: { wanted: false, pressed: false }, //Meta is Mac specific - } - - if (e.ctrlKey) modifiers.ctrl.pressed = true - if (e.shiftKey) modifiers.shift.pressed = true - if (e.altKey) modifiers.alt.pressed = true - if (e.metaKey) modifiers.meta.pressed = true - - let k - for (var i = 0; (k = keys[i]), i < keys.length; i++) { - //Modifiers - if (k == 'ctrl' || k == 'control') { - kp++ - modifiers.ctrl.wanted = true - } else if (k == 'shift') { - kp++ - modifiers.shift.wanted = true - } else if (k == 'alt') { - kp++ - modifiers.alt.wanted = true - } else if (k == 'meta') { - kp++ - modifiers.meta.wanted = true - } else if (k.length > 1) { - //If it is a special key - if (special_keys[k] == code) kp++ - } else if (opt['keycode']) { - if (opt['keycode'] == code) kp++ - } else { - //The special keys did not match - if (character == k) kp++ - else { - if (shift_nums[character] && e.shiftKey) { - //Stupid Shift key bug created by using lowercase - character = shift_nums[character] - if (character == k) kp++ - } - } - } - } - - if ( - kp == keys.length && - modifiers.ctrl.pressed == modifiers.ctrl.wanted && - modifiers.shift.pressed == modifiers.shift.wanted && - modifiers.alt.pressed == modifiers.alt.wanted && - modifiers.meta.pressed == modifiers.meta.wanted - ) { - callback(e) - - if (!opt['propagate']) { - //Stop the event - //e.cancelBubble is supported by IE - this will kill the bubbling process. - e.cancelBubble = true - e.returnValue = false - - //e.stopPropagation works in Firefox. - if (e.stopPropagation) { - e.stopPropagation() - e.preventDefault() - } - return false - } - } - } - this.all_shortcuts[shortcut_combination] = { - callback: func, - target: ele, - event: opt['type'], - } - //Attach the function with the event - if (ele.addEventListener) ele.addEventListener(opt['type'], func, false) - else if (ele.attachEvent) ele.attachEvent('on' + opt['type'], func) - else ele['on' + opt['type']] = func - }, - - //Remove the shortcut - just specify the shortcut and I will remove the binding - remove: function (shortcut_combination) { - shortcut_combination = shortcut_combination.toLowerCase() - var binding = this.all_shortcuts[shortcut_combination] - delete this.all_shortcuts[shortcut_combination] - if (!binding) return - var type = binding['event'] - var ele = binding['target'] - var callback = binding['callback'] - - if (ele.detachEvent) ele.detachEvent('on' + type, callback) - else if (ele.removeEventListener) - ele.removeEventListener(type, callback, false) - else ele['on' + type] = false - }, - removeAll: function () { - for (let x in this.all_shortcuts) { - this.remove(x) - } - }, -} diff --git a/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts b/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts new file mode 100644 index 00000000..f34d25b3 --- /dev/null +++ b/v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts @@ -0,0 +1,232 @@ +import { ShortcutOptions,ShortcutBinding,ModifierState } from './model.types' + +export const shortcut = { + all_shortcuts: {} as Record, + + add: function (shortcut_combination: string, callback: (e: KeyboardEvent) => void, opt?: ShortcutOptions): void { + if (!shortcut_combination || typeof shortcut_combination !== 'string') { + throw new Error('Shortcut combination must be a non-empty string'); + } + if (!callback || typeof callback !== 'function') { + throw new Error('Callback must be a function'); + } + + const options = this.getOptions(opt); + const ele = this.getTargetElement(options.target); + shortcut_combination = shortcut_combination.toLowerCase(); + + const func = this.createEventListener(shortcut_combination, callback, options); + this.registerShortcut(shortcut_combination, func, ele, options.type || 'keydown'); + }, + + remove: function (shortcut_combination: string): void { + shortcut_combination = shortcut_combination.toLowerCase(); + const binding = this.all_shortcuts[shortcut_combination]; + + if (binding) { + this.unregisterShortcut(binding); + delete this.all_shortcuts[shortcut_combination]; + } else { + console.warn(`No binding found for shortcut: ${shortcut_combination}`); + } + }, + + removeAll: function (): void { + const failures: string[] = []; + Object.keys(this.all_shortcuts).forEach(shortcut => { + try { + this.remove(shortcut); + } catch (error) { + failures.push(shortcut); + console.error(`Failed to remove shortcut ${shortcut}: ${error}`); + } + }); + if (failures.length > 0) { + console.warn(`Failed to remove ${failures.length} shortcuts: ${failures.join(', ')}`); + } + }, + + getOptions: function (opt?: ShortcutOptions): ShortcutOptions { + const default_options: ShortcutOptions = { + type: 'keydown', + propagate: false, + disable_in_input: true, + target: document, + keycode: false, + }; + return opt ? { ...default_options, ...opt } : default_options; + }, + + getTargetElement: function (target: Document | string | undefined): Document | HTMLElement { + if (typeof target === 'string') { + return document.getElementById(target) || document; + } + return target || document; + }, + + createEventListener: function (shortcut_combination: string, callback: (e: KeyboardEvent) => void, options: ShortcutOptions): EventListener { + return (evt: Event): void => { + const e = evt as KeyboardEvent; + + if (this.shouldIgnoreEvent(e, options)) { + return; + } + + if (this.isShortcutMatch(shortcut_combination, e, options)) { + this.handleShortcutMatch(e, callback, options); + } + }; + }, + + shouldIgnoreEvent: function (e: KeyboardEvent, options: ShortcutOptions): boolean { + return (options.disable_in_input ?? true) && this.isInputElement(e.target as HTMLElement); + }, + + handleShortcutMatch: function (e: KeyboardEvent, callback: (e: KeyboardEvent) => void, options: ShortcutOptions): void { + callback(e); + + if (!options.propagate) { + e.stopPropagation(); + e.preventDefault(); + } + }, + + isInputElement: function (element: HTMLElement): boolean { + if (element.nodeType === 3 && element.parentNode) { + element = element.parentNode as HTMLElement; + } else if (element.nodeType === 3) { + return true; + } + return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA'; + }, + + isShortcutMatch: function (shortcut_combination: string, e: KeyboardEvent, options: ShortcutOptions): boolean { + const keys = shortcut_combination.split('+'); + const modifiers = this.getModifiersState(keys, e); + const character = this.getCharacterFromKeyCode(e); + + return this.checkKeysMatch(keys, character, e, options) && + this.checkModifiersMatch(modifiers); + }, + + getModifiersState: function (keys: string[], e: KeyboardEvent): Record { + const modifiers: Record = { + shift: { wanted: false, pressed: e.shiftKey }, + ctrl: { wanted: false, pressed: e.ctrlKey }, + alt: { wanted: false, pressed: e.altKey }, + meta: { wanted: false, pressed: e.metaKey } + }; + + keys.forEach(k => { + if (k === 'ctrl' || k === 'control') modifiers.ctrl.wanted = true; + else if (k === 'shift') modifiers.shift.wanted = true; + else if (k === 'alt') modifiers.alt.wanted = true; + else if (k === 'meta') modifiers.meta.wanted = true; + }); + + return modifiers; + }, + + getCharacterFromKeyCode: function (e: KeyboardEvent): string { + const code = e.keyCode || e.which; + let character = String.fromCharCode(code).toLowerCase(); + + if (code === 188) character = ','; + if (code === 190) character = '.'; + + return character; + }, + + checkKeysMatch: function (keys: string[], character: string, e: KeyboardEvent, options: ShortcutOptions): boolean { + let kp = 0; + + keys.forEach(k => { + if (this.isModifierKey(k)) { + kp++; + } else if (this.isSpecialKeyMatch(k, e)) { + kp++; + } else if (options.keycode && this.isKeyCodeMatch(options.keycode, e)) { + kp++; + } else if (this.isCharacterMatch(k, character, e)) { + kp++; + } + }); + + return kp === keys.length; + }, + + isModifierKey: function (key: string): boolean { + return key === 'ctrl' || key === 'control' || key === 'shift' || key === 'alt' || key === 'meta'; + }, + + isSpecialKeyMatch: function (key: string, e: KeyboardEvent): boolean { + const special_keys: Record = { + esc: 27, escape: 27, tab: 9, space: 32, return: 13, enter: 13, backspace: 8, + scrolllock: 145, scroll_lock: 145, scroll: 145, capslock: 20, caps_lock: 20, caps: 20, + numlock: 144, num_lock: 144, num: 144, pause: 19, break: 19, insert: 45, home: 36, + delete: 46, end: 35, pageup: 33, page_up: 33, pu: 33, pagedown: 34, page_down: 34, pd: 34, + left: 37, up: 38, right: 39, down: 40, f1: 112, f2: 113, f3: 114, f4: 115, f5: 116, + f6: 117, f7: 118, f8: 119, f9: 120, f10: 121, f11: 122, f12: 123 + }; + + return special_keys[key] === (e.keyCode || e.which); + }, + + isKeyCodeMatch: function (keycode: number | false, e: KeyboardEvent): boolean { + return keycode === (e.keyCode || e.which); + }, + + isCharacterMatch: function (key: string, character: string, e: KeyboardEvent): boolean { + const shift_nums: Record = { + '`': '~', 1: '!', 2: '@', 3: '#', 4: '$', 5: '%', 6: '^', 7: '&', 8: '*', 9: '(', 0: ')', + '-': '_', '=': '+', ';': ':', "'": '"', ',': '<', '.': '>', '/': '?', '\\': '|' + }; + + if (character === key) { + return true; + } else if (shift_nums[character] && e.shiftKey) { + return shift_nums[character] === key; + } + + return false; + }, + + checkModifiersMatch: function (modifiers: Record): boolean { + return modifiers.ctrl.pressed === modifiers.ctrl.wanted && + modifiers.shift.pressed === modifiers.shift.wanted && + modifiers.alt.pressed === modifiers.alt.wanted && + modifiers.meta.pressed === modifiers.meta.wanted; + }, + + registerShortcut: function (shortcut_combination: string, func: EventListener, ele: Document | HTMLElement, event: string): void { + this.all_shortcuts[shortcut_combination] = { + callback: func, + target: ele, + event: event + }; + + if (ele.addEventListener) { + ele.addEventListener(event, func, false); + } else if ((ele as any).attachEvent) { + (ele as any).attachEvent('on' + event, func); + } else { + (ele as any)['on' + event] = func; + } + }, + + unregisterShortcut: function (binding: ShortcutBinding): void { + const { target, callback, event } = binding; + + try { + if (target.removeEventListener) { + target.removeEventListener(event, callback); + } else if ((target as any).detachEvent) { + (target as any).detachEvent('on' + event, callback); + } else { + (target as any)['on' + event] = null; + } + } catch (error) { + console.warn(`Failed to remove event Listener: ${error}`); + } + } +}; \ No newline at end of file diff --git a/v1/src/simulator/src/hotkey_binder/model/utils.js b/v1/src/simulator/src/hotkey_binder/model/utils.js deleted file mode 100644 index 8a2a8a8b..00000000 --- a/v1/src/simulator/src/hotkey_binder/model/utils.js +++ /dev/null @@ -1,67 +0,0 @@ -Storage.prototype.set = function (key, obj) { - return this.setItem(key, JSON.stringify(obj)) -} - -Storage.prototype.get = function (key) { - return JSON.parse(this.getItem(key)) -} - -Object.size = function (obj) { - var size = 0, - key - for (key in obj) { - if (obj.hasOwnProperty(key)) size++ - } - return size -} - -export const getKey = (obj, val) => - Object.keys(obj).find((key) => obj[key] === val) - -export const getOS = () => { - let OSName = '' - if (navigator.appVersion.indexOf('Win') != -1) OSName = 'Windows' - if (navigator.appVersion.indexOf('Mac') != -1) OSName = 'MacOS' - if (navigator.appVersion.indexOf('X11') != -1) OSName = 'UNIX' - if (navigator.appVersion.indexOf('Linux') != -1) OSName = 'Linux' - return OSName -} - -export const checkRestricted = (key) => { - const restrictedKeys = [ - 'Ctrl + N', - 'Ctrl + W', - 'Ctrl + T', - 'Ctrl + C', - 'Ctrl + V', - 'Ctrl + Delete', - 'Ctrl + Backspace', - 'Ctrl + /', - 'Ctrl + \\', - 'Ctrl + ]', - "Ctrl + '", - 'Ctrl + `', - 'Ctrl + [', - 'Ctrl + ~', - 'Ctrl + Num1', - 'Ctrl + Num2', - 'Ctrl + Num3', - 'Ctrl + Num4', - 'Ctrl + Num5', - 'Ctrl + Num6', - 'Ctrl + Num*', - 'Ctrl + Num/', - 'Ctrl + Num.', - 'Ctrl + Num0', - ] - if (getOS == 'macOS') { - restrictedKeys.forEach((value, i) => { - if (value.split(' + ')[0] == 'Ctrl'); - restrictedKeys[i] = - value.split(' + ')[0] == 'Ctrl' - ? value.replace('Ctrl', 'Meta') - : value - }) - } - return restrictedKeys.includes(key) -} diff --git a/v1/src/simulator/src/hotkey_binder/model/utils.ts b/v1/src/simulator/src/hotkey_binder/model/utils.ts new file mode 100644 index 00000000..8e51b981 --- /dev/null +++ b/v1/src/simulator/src/hotkey_binder/model/utils.ts @@ -0,0 +1,74 @@ +// Add type-safe set method to Storage Prototype +Storage.prototype.set = function(key: string, obj: T): void { + this.setItem(key, JSON.stringify(obj)); +} + +// Add type-safe get method to Storage prototype +Storage.prototype.get = function(key: string): T | null { + const item = this.getItem(key); + if (!item) return null; + try { + return JSON.parse(item) as T; + } catch (e) { + console.error(`Failed to parse stored item ${key}:`, e); + return null; + } + +} + +// Type-safe object size function +export function objectSize(obj: Record): number { + return Object.keys(obj).length; +} + +// Find key by value in an object +export function getKey>(obj: T, val: any): string | undefined { + return Object.keys(obj).find(key => { + const value = obj[key]; + if (typeof value === 'object' && value !== null) { + return JSON.stringify(value) === JSON.stringify(val); + } + return value === val; + }); +} + +// OS detection patterns +const OS_PATTERNS: Record = { + 'Windows': /windows/i, + 'MacOS': /mac/i, + 'Linux': /linux/i, + 'UNIX': /x11/i +}; +export function getOS(): string { + const userInput = `${navigator.platform} ${navigator.userAgent}`.toLowerCase(); + + for (const [os, pattern] of Object.entries(OS_PATTERNS)) { + if (pattern.test(userInput)) { + return os; + } + } + + return ''; +} +// Check for restricted key combinations +export function checkRestricted(key: string): boolean { + const restrictedKeys: string[] = [ + 'Ctrl + N', 'Ctrl + W', 'Ctrl + T', 'Ctrl + C', 'Ctrl + V', + 'Ctrl + Delete', 'Ctrl + Backspace', 'Ctrl + /', 'Ctrl + \\', + 'Ctrl + ]', "Ctrl + '", 'Ctrl + `', 'Ctrl + [', 'Ctrl + ~', + 'Ctrl + Num1', 'Ctrl + Num2', 'Ctrl + Num3', 'Ctrl + Num4', + 'Ctrl + Num5', 'Ctrl + Num6', 'Ctrl + Num*', 'Ctrl + Num/', + 'Ctrl + Num.', 'Ctrl + Num0' + ]; + + // Adjust for MacOS if needed + const modifiedKeys = getOS() === 'MacOS' + ? restrictedKeys.map(value => + value.startsWith('Ctrl') + ? value.replace('Ctrl', 'Meta') + : value + ) + : restrictedKeys; + + return modifiedKeys.includes(key); +} \ No newline at end of file diff --git a/v1/src/simulator/src/interface/backgroundArea.ts b/v1/src/simulator/src/interface/backgroundArea.ts new file mode 100644 index 00000000..e4d08e13 --- /dev/null +++ b/v1/src/simulator/src/interface/backgroundArea.ts @@ -0,0 +1,6 @@ +export interface BackgroundArea { + canvas: HTMLCanvasElement | null; + context: CanvasRenderingContext2D | null; + setup(): void; + clear(): void; +} \ No newline at end of file diff --git a/v1/src/simulator/src/interface/simulationArea.ts b/v1/src/simulator/src/interface/simulationArea.ts new file mode 100644 index 00000000..de181800 --- /dev/null +++ b/v1/src/simulator/src/interface/simulationArea.ts @@ -0,0 +1,39 @@ +import { EventQueue } from '../eventQueue' +export interface SimulationArea { + canvas: HTMLCanvasElement; + context: CanvasRenderingContext2D|null; + selected: boolean; + hover: boolean; + clockState: number; + clockEnabled: boolean; + // TODO: make this CircuitElement|null once converted to typescript + lastSelected: any|null; + stack: any[]; + prevScale: number; + oldx: number; + oldy: number; + objectList: any[]; + maxHeight: number; + maxWidth: number; + minHeight: number; + minWidth: number; + multipleObjectSelections: any[]; + copyList: any[]; + shiftDown: boolean; + controlDown: boolean; + timePeriod: number; + mouseX: number; + mouseY: number; + mouseDownX: number; + mouseDownY: number; + simulationQueue: EventQueue; + clickCount: number; + lock: string; + mouseDown: boolean; + ClockInterval: NodeJS.Timeout|null; + touch: boolean; + timer: () => void; + setup: () => void; + changeClockTime: (t: number) => void; + clear: () => void; +} \ No newline at end of file diff --git a/v0/src/simulator/src/layout/layoutBuffer.js b/v1/src/simulator/src/layout/layoutBuffer.ts similarity index 87% rename from v0/src/simulator/src/layout/layoutBuffer.js rename to v1/src/simulator/src/layout/layoutBuffer.ts index 1c339d28..c5705b77 100644 --- a/v0/src/simulator/src/layout/layoutBuffer.js +++ b/v1/src/simulator/src/layout/layoutBuffer.ts @@ -1,3 +1,4 @@ +import CircuitElement from '../circuitElement' import LayoutNode from './layoutNode' /** * Buffer object to store changes so that you can reset changes @@ -6,6 +7,18 @@ import LayoutNode from './layoutNode' * @category layout */ export default class LayoutBuffer { + layout: { + width: number + height: number + x: number + y: number + title_x: number + title_y: number + titleEnabled: boolean + } + Input: LayoutNode[] + Output: LayoutNode[] + subElements: CircuitElement[] constructor(scope = globalScope) { var w = 300 * DPR var h = 50 * DPR @@ -53,7 +66,7 @@ export default class LayoutBuffer { * Check if position is on the boundaries of subcircuit * if the desired width and heiht is allowed */ - isAllowed(x, y) { + isAllowed(x: number, y: number) { if (x < 0 || x > this.layout.width || y < 0 || y > this.layout.height) return false if (x > 0 && x < this.layout.width && y > 0 && y < this.layout.height) @@ -76,7 +89,7 @@ export default class LayoutBuffer { * Function is called while decreasing height to * check if it is possible without moving other node */ - isNodeAt(x, y) { + isNodeAt(x: number, y: number) { for (let i = 0; i < this.Input.length; i++) { if (this.Input[i].x === x && this.Input[i].y === y) return true } diff --git a/v0/src/simulator/src/layout/layoutNode.js b/v1/src/simulator/src/layout/layoutNode.ts similarity index 85% rename from v0/src/simulator/src/layout/layoutNode.js rename to v1/src/simulator/src/layout/layoutNode.ts index ddf199b3..33d55d4f 100644 --- a/v0/src/simulator/src/layout/layoutNode.js +++ b/v1/src/simulator/src/layout/layoutNode.ts @@ -1,21 +1,28 @@ import { drawCircle } from '../canvasApi' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { tempBuffer } from '../layoutMode' +import CircuitElement from '../circuitElement' /** - * @class - * @param {number} x - x coord of node - * @param {number} y - y coord of node - * @param {strng} id - id for node - * @param {string=} label - label for the node - * @param {number} xx - parent x - * @param {number} yy - parent y - * @param {number} type - input or output node - * @param {CircuitElement} parent parent of the node * @category layout */ export default class LayoutNode { - constructor(x, y, id, label = '', type, parent) { + x: number + y: number + prevx: number | undefined + prevy: number | undefined + radius: number + clicked: boolean + hover: boolean + wasClicked: boolean + prev: string + count: number + objectType: string + type: number + id: string + label: string + parent: CircuitElement + constructor(x: number, y: number, id: string, label = '', type: number, parent: CircuitElement) { this.type = type this.id = id diff --git a/v1/src/simulator/src/layoutMode.js b/v1/src/simulator/src/layoutMode.ts similarity index 83% rename from v1/src/simulator/src/layoutMode.js rename to v1/src/simulator/src/layoutMode.ts index c400cb71..5c548db6 100644 --- a/v1/src/simulator/src/layoutMode.js +++ b/v1/src/simulator/src/layoutMode.ts @@ -2,9 +2,8 @@ /* eslint-disable no-continue */ import { dots, correctWidth, fillText, rect2 } from './canvasApi' import LayoutBuffer from './layout/layoutBuffer' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { - hideProperties, fillSubcircuitElements, prevPropertyObjGet, prevPropertyObjSet, @@ -19,8 +18,11 @@ import { } from './engine' import miniMapArea from './minimap' import { showMessage } from './utils' -import * as metadata from './metadata.json' -import { verilogModeGet, verilogModeSet } from './Verilog2CV' +import { verilogModeSet } from './Verilog2CV' +import { useLayoutStore } from '#/store/layoutStore' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' +import { circuitElementList } from './metadata' /** * Layout.js - all subcircuit layout related code is here @@ -31,11 +33,11 @@ import { verilogModeGet, verilogModeSet } from './Verilog2CV' var layoutMode = false -export function layoutModeSet(param) { +export function layoutModeSet(param: boolean) { layoutMode = param } -export function layoutModeGet(param) { +export function layoutModeGet() { return layoutMode } @@ -43,15 +45,13 @@ export function layoutModeGet(param) { * @type {LayoutBuffer} - used to temporartily store all changes. * @category layoutMode */ -export var tempBuffer +export var tempBuffer: LayoutBuffer /** * Helper function to determine alignment and position of nodes for rendering - * @param {number} x - width of label - * @param {number} y - height of label * @category layoutMode */ -export function determineLabel(x, y) { +export function determineLabel(x: number, y: number) { if (x === 0) return ['left', 5, 5] if (x === tempBuffer.layout.width) return ['right', -5, 5] if (y === 0) return ['center', 0, 13] @@ -148,8 +148,8 @@ export function renderLayout(scope = globalScope) { fillText( ctx, tempBuffer.Input[i].label, - tempBuffer.Input[i].x + info[1], - tempBuffer.Input[i].y + info[2], + tempBuffer.Input[i].x + typeof info[1] === 'number' ? info[1] : parseInt(info[1] as string), + tempBuffer.Input[i].y + typeof info[2] === 'number' ? info[2] : parseInt(info[2] as string), 12 ) } @@ -164,8 +164,8 @@ export function renderLayout(scope = globalScope) { fillText( ctx, tempBuffer.Output[i].label, - tempBuffer.Output[i].x + info[1], - tempBuffer.Output[i].y + info[2], + tempBuffer.Output[i].x + typeof info[1] === 'number' ? info[1] : parseInt(info[1] as string), + tempBuffer.Output[i].y + typeof info[2] === 'number' ? info[2] : parseInt(info[2] as string), 12 ) } @@ -446,29 +446,25 @@ export function saveLayout() { * @category layoutMode */ export function toggleLayoutMode() { - // hideProperties() - // lines from hideProperty function() <--- + const layoutStore = toRefs(useLayoutStore()) + const simulatorMobileStore = toRefs(useSimulatorMobileStore()) prevPropertyObjSet(undefined) $('.objectPropertyAttribute').unbind('change keyup paste click') if (layoutModeGet()) { layoutModeSet(false) - $('#layoutDialog').fadeOut() - $('.layoutElementPanel').fadeOut() - $('.elementPanel').fadeIn() - $('.timing-diagram-panel').fadeIn() - $('.testbench-manual-panel').fadeIn() + layoutStore.layoutMode.value = false globalScope.centerFocus(false) - if (globalScope.verilogMetadata.isVerilogCircuit) verilogModeSet(true) + if (globalScope.verilogMetadata.isVerilogCircuit) { + verilogModeSet(true) + simulatorMobileStore.isVerilog.value = true + } dots() } else { layoutModeSet(true) verilogModeSet(false) - $('#layoutDialog').fadeIn() - $('.layoutElementPanel').fadeIn() - $('.elementPanel').fadeOut() - $('.timing-diagram-panel').fadeOut() - $('.testbench-manual-panel').fadeOut() + layoutStore.layoutMode.value = true + simulatorMobileStore.isVerilog.value = false fillSubcircuitElements() globalScope.ox = 0 @@ -476,7 +472,6 @@ export function toggleLayoutMode() { globalScope.scale = DPR * 1.3 dots() tempBuffer = new LayoutBuffer() - // $('#toggleLayoutTitle')[0].checked = tempBuffer.layout.titleEnabled } update(globalScope, true) scheduleUpdate() @@ -497,48 +492,3 @@ export const layoutFunctions = { saveLayout, toggleLayoutMode, } - -// export function setupLayoutModePanelListeners() { -// $('#decreaseLayoutWidth').on('click', () => { -// decreaseLayoutWidth() -// }) -// $('#increaseLayoutWidth').on('click', () => { -// increaseLayoutWidth() -// }) -// $('#decreaseLayoutHeight').on('click', () => { -// decreaseLayoutHeight() -// }) -// $('#increaseLayoutHeight').on('click', () => { -// increaseLayoutHeight() -// }) -// $('#layoutResetNodes').on('click', () => { -// layoutResetNodes() -// }) -// $('#layoutTitleUp').on('click', () => { -// layoutTitleUp() -// }) -// $('#layoutTitleDown').on('click', () => { -// layoutTitleDown() -// }) -// $('#layoutTitleLeft').on('click', () => { -// layoutTitleLeft() -// }) -// $('#layoutTitleRight').on('click', () => { -// layoutTitleRight() -// }) -// $('#toggleLayoutTitle').on('click', () => { -// toggleLayoutTitle() -// }) -// $('#saveLayout').on('click', () => { -// saveLayout() -// }) -// $('#cancelLayout').on('click', () => { -// cancelLayout() -// }) -// $('#layoutDialog button').on('click', () => { -// scheduleUpdate() -// }) -// $('#layoutDialog input').on('click', () => { -// scheduleUpdate() -// }) -// } diff --git a/v1/src/simulator/src/listeners.js b/v1/src/simulator/src/listeners.js index 460be076..6db5661a 100644 --- a/v1/src/simulator/src/listeners.js +++ b/v1/src/simulator/src/listeners.js @@ -1,11 +1,18 @@ +/* eslint-disable no-shadow */ +/* eslint-disable no-negated-condition */ +/* eslint-disable no-alert */ +/* eslint-disable new-cap */ +/* eslint-disable no-undef */ +/* eslint-disable eqeqeq */ +/* eslint-disable prefer-template */ +/* eslint-disable no-param-reassign */ // Most Listeners are stored here import { layoutModeGet, tempBuffer, layoutUpdate, - // setupLayoutModePanelListeners, } from './layoutMode' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, update, @@ -17,127 +24,298 @@ import { gridUpdateSet, errorDetectedSet, } from './engine' -import { changeScale } from './canvasApi' +import { changeScale, findDimensions } from './canvasApi' import { scheduleBackup } from './data/backupCircuit' -import { - hideProperties, - deleteSelected, - uxvar, - fullView, - exitFullView, -} from './ux' -import { - updateRestrictedElementsList, - updateRestrictedElementsInScope, - hideRestricted, - showRestricted, -} from './restrictedElementDiv' +import { hideProperties, deleteSelected, uxvar, exitFullView } from './ux'; +import { updateRestrictedElementsList, updateRestrictedElementsInScope, hideRestricted, showRestricted } from './restrictedElementDiv'; import { removeMiniMap, updatelastMinimapShown } from './minimap' import undo from './data/undo' import redo from './data/redo' import { copy, paste, selectAll } from './events' -import save from './data/save' import { verilogModeGet } from './Verilog2CV' import { setupTimingListeners } from './plotArea' +import logixFunction from './data' +import { listen } from '@tauri-apps/api/event' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' + +const unit = 10 +let listenToSimulator = true +let coordinate; +const returnCoordinate = { + x: 0, + y: 0 +} -var unit = 10 -var listenToSimulator = true +let currDistance = 0; +let distance = 0; +let pinchZ = 0; +let centreX; +let centreY; +let timeout; +let lastTap = 0; + +/** + * + * @param {event} e + * function for double click or double tap + */ +function onDoubleClickorTap(e) { + updateCanvasSet(true); + if (simulationArea.lastSelected && simulationArea.lastSelected.dblclick !== undefined) { + simulationArea.lastSelected.dblclick(); + } else if (!simulationArea.shiftDown) { + simulationArea.multipleObjectSelections = []; + } + scheduleUpdate(2); + e.preventDefault(); +} -export default function startListeners() { - // added the below functionalities in QuickButton.vue component local script tag part - - // $('#deleteSelected').on('click', () => { - // deleteSelected() - // }) - - // $('#zoomIn').on('click', () => { - // changeScale(0.2, 'zoomButton', 'zoomButton', 2) - // }) - - // $('#zoomOut').on('click', () => { - // changeScale(-0.2, 'zoomButton', 'zoomButton', 2) - // }) - - // $('#undoButton').on('click', () => { - // undo() - // }) - // $('#redoButton').on('click', () => { - // redo() - // }) - // $('#viewButton').on('click', () => { - // fullView() - // }) +/** + * + * @param {event} e + * function to detect tap and double tap + */ +function getTap(e) { + const currentTime = new Date().getTime(); + const tapLength = currentTime - lastTap; + clearTimeout(timeout); + if (tapLength < 500 && tapLength > 0) { + onDoubleClickorTap(e); + } else { + // Single tap + } + lastTap = currentTime; + e.preventDefault(); +} + +const isIe = (navigator.userAgent.toLowerCase().indexOf('msie') != -1 || navigator.userAgent.toLowerCase().indexOf('trident') != -1); + +// Function to getCoordinate +// *If touch is enable then it will return touch coordinate +// *else it will return mouse coordinate +// +export function getCoordinate(e) { + if (simulationArea.touch) { + returnCoordinate.x = e.touches[0].clientX; + returnCoordinate.y = e.touches[0].clientY; + return returnCoordinate; + } + + if (!simulationArea.touch) { + returnCoordinate.x = e.clientX; + returnCoordinate.y = e.clientY; + return returnCoordinate; + } + + return returnCoordinate; +} + +/* Function for Panstop on simulator + *For now variable name starts with mouse like mouseDown are used both + touch and mouse will change in future +*/ +export function pinchZoom(e, globalScope) { + e.preventDefault(); + gridUpdateSet(true); + scheduleUpdate(); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + // Calculating distance between touch to see if its pinchIN or pinchOut + distance = Math.sqrt((e.touches[1].clientX - e.touches[0].clientX) ** 2, (e.touches[1].clientY - e.touches[0].clientY) ** 2); + if (distance >= currDistance) { + pinchZ += 0.02; + currDistance = distance; + } else if (currDistance >= distance) { + pinchZ -= 0.02; + currDistance = distance; + } + if (pinchZ >= 2) { + pinchZ = 2; + } + else if (pinchZ <= 0.5) { + pinchZ = 0.5; + } + const oldScale = globalScope.scale; + globalScope.scale = Math.max(0.5, Math.min(4 * DPR, pinchZ * 3)); + globalScope.scale = Math.round(globalScope.scale * 10) / 10; + // This is not working as expected + centreX = (e.touches[0].clientX + e.touches[1].clientX) / 2; + centreY = (e.touches[0].clientY + e.touches[1].clientY) / 2; + const rect = simulationArea.canvas.getBoundingClientRect(); + const RawX = (centreX - rect.left) * DPR; + const RawY = (centreY - rect.top) * DPR; + const Xf = Math.round(((RawX - globalScope.ox) / globalScope.scale) / unit); + const Yf = Math.round(((RawY - globalScope.ox) / globalScope.scale) / unit); + const currCentreX = Math.round(Xf / unit) * unit; + const currCentreY = Math.round(Yf / unit) * unit; + globalScope.ox = Math.round(currCentreX * (globalScope.scale - oldScale)); + globalScope.oy = Math.round(currCentreY * (globalScope.scale - oldScale)); + gridUpdateSet(true); + scheduleUpdate(1); +} + +/* + *Function to start the pan in simulator + *Works for both touch and Mouse + *For now variable name starts from mouse like mouseDown are used both + touch and mouse will change in future + */ +export function panStart(e) { + coordinate = getCoordinate(e); + simulationArea.mouseDown = true; + // Deselect Input + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + simulationArea.lastSelected = undefined; + simulationArea.selected = false; + simulationArea.hover = undefined; + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseDownRawX = (coordinate.x - rect.left) * DPR; + simulationArea.mouseDownRawY = (coordinate.y - rect.top) * DPR; + simulationArea.mouseDownX = Math.round(((simulationArea.mouseDownRawX - globalScope.ox) / globalScope.scale) / unit) * unit; + simulationArea.mouseDownY = Math.round(((simulationArea.mouseDownRawY - globalScope.oy) / globalScope.scale) / unit) * unit; + if (simulationArea.touch) { + simulationArea.mouseX = simulationArea.mouseDownX; + simulationArea.mouseY = simulationArea.mouseDownY; + } + + simulationArea.oldx = globalScope.ox; + simulationArea.oldy = globalScope.oy; + e.preventDefault(); + scheduleBackup(); + scheduleUpdate(1); + $('.dropdown.open').removeClass('open'); +} + +/* + * Function to pan in simulator + * Works for both touch and Mouse + * Pinch to zoom also implemented in the same + * For now variable name starts from mouse like mouseDown are used both + touch and mouse will change in future + */ + +export function panMove(e) { + // If only one it touched + // pan left or right + if (!simulationArea.touch || e.touches.length === 1) { + coordinate = getCoordinate(e); + const rect = simulationArea.canvas.getBoundingClientRect(); + simulationArea.mouseRawX = (coordinate.x - rect.left) * DPR; + simulationArea.mouseRawY = (coordinate.y - rect.top) * DPR; + simulationArea.mouseXf = (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale; + simulationArea.mouseYf = (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale; + simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit; + simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit; + updateCanvasSet(true); + if (simulationArea.lastSelected && (simulationArea.mouseDown || simulationArea.lastSelected.newElement)) { + updateCanvasSet(true); + let fn; + + if (simulationArea.lastSelected == globalScope.root) { + fn = function () { + updateSelectionsAndPane(); + }; + } else { + fn = function () { + if (simulationArea.lastSelected) { + simulationArea.lastSelected.update(); + } + }; + } + + scheduleUpdate(0, 20, fn); + } else { + scheduleUpdate(0, 200); + } + } + // If two fingures are touched + // pinchZoom + if (simulationArea.touch && e.touches.length === 2) { + pinchZoom(e, globalScope); + } +} + +export function panStop(e) { + const simulatorMobileStore = useSimulatorMobileStore() + simulationArea.mouseDown = false; + if (!lightMode) { + updatelastMinimapShown(); + setTimeout(removeMiniMap, 2000); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + + scheduleUpdate(1); + simulationArea.mouseDown = false; + + // eslint-disable-next-line no-plusplus + for (let i = 0; i < 2; i++) { + updatePositionSet(true); + wireToBeCheckedSet(1); + update(); + } + + errorDetectedSet(false); + updateSimulationSet(true); + updatePositionSet(true); + updateCanvasSet(true); + gridUpdateSet(true); + wireToBeCheckedSet(1); + + scheduleUpdate(1); + // Var rect = simulationArea.canvas.getBoundingClientRect(); + + if (!(simulationArea.mouseRawX < 0 || simulationArea.mouseRawY < 0 || simulationArea.mouseRawX > width || simulationArea.mouseRawY > height)) { + uxvar.smartDropXX = simulationArea.mouseX + 100; // Math.round(((simulationArea.mouseRawX - globalScope.ox+100) / globalScope.scale) / unit) * unit; + uxvar.smartDropYY = simulationArea.mouseY - 50; // Math.round(((simulationArea.mouseRawY - globalScope.oy+100) / globalScope.scale) / unit) * unit; + } + + if (simulationArea.touch) { + const { isCopy } = toRefs(simulatorMobileStore) + // small hack so Current circuit element should not spwan above last circuit element + if (!isCopy.value) { + findDimensions(globalScope); + simulationArea.mouseX = 100 + simulationArea.maxWidth || 0; + simulationArea.mouseY = simulationArea.minHeight || 0; + getTap(e); + } + } +} + +export default function startListeners() { $(document).on('keyup', (e) => { if (e.key === 'Escape') exitFullView() }) $('#projectName').on('click', () => { - simulationArea.lastSelected = globalScope.root - setTimeout(() => { - document.getElementById('projname').select() - }, 100) - }) - /* Makes tabs reordering possible by making them sortable */ - // $("#tabsBar").sortable({ - // containment: 'parent', - // items: '> div', - // revert: false, - // opacity: 0.5, - // tolerance: 'pointer', - // placeholder: 'placeholder', - // forcePlaceholderSize: true, - // }); + simulationArea.lastSelected = globalScope.root; + setTimeout(() => { + document.getElementById("projname").select(); + }, 100); + }); - document - .getElementById('simulationArea') - .addEventListener('mousedown', (e) => { - simulationArea.mouseDown = true - - // Deselect Input - if (document.activeElement instanceof HTMLElement) - document.activeElement.blur() - - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - - simulationArea.lastSelected = undefined - simulationArea.selected = false - simulationArea.hover = undefined - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseDownRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseDownRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseDownX = - Math.round( - (simulationArea.mouseDownRawX - globalScope.ox) / - globalScope.scale / - unit - ) * unit - simulationArea.mouseDownY = - Math.round( - (simulationArea.mouseDownRawY - globalScope.oy) / - globalScope.scale / - unit - ) * unit - simulationArea.oldx = globalScope.ox - simulationArea.oldy = globalScope.oy - - e.preventDefault() - scheduleBackup() - scheduleUpdate(1) - $('.dropdown.open').removeClass('open') - }) document .getElementById('simulationArea') .addEventListener('mouseup', (e) => { - if (simulationArea.lastSelected) + if (simulationArea.lastSelected) { simulationArea.lastSelected.newElement = false - /* - handling restricted circuit elements - */ - + } + // handling restricted circuit elements if ( simulationArea.lastSelected && restrictedElements.includes( @@ -153,7 +331,7 @@ export default function startListeners() { updateRestrictedElementsList() } - // deselect multible elements with click + // deselect multible elements with click if ( !simulationArea.shiftDown && simulationArea.multipleObjectSelections.length > 0 @@ -167,9 +345,6 @@ export default function startListeners() { } } }) - document - .getElementById('simulationArea') - .addEventListener('mousemove', onMouseMove) window.addEventListener('keyup', (e) => { scheduleUpdate(1) @@ -220,10 +395,6 @@ export default function startListeners() { if (listenToSimulator) { // If mouse is focusing on input element, then override any action - // if($(':focus').length){ - // return; - // } - if ( document.activeElement.tagName == 'INPUT' || simulationArea.mouseRawX < 0 || @@ -279,18 +450,6 @@ export default function startListeners() { updateCanvasSet(true) wireToBeCheckedSet(1) - // Needs to be deprecated, moved to more recent listeners - if ( - simulationArea.controlDown && - (e.key == 'C' || e.key == 'c') - ) { - // simulationArea.copyList=simulationArea.multipleObjectSelections.slice(); - // if(simulationArea.lastSelected&&simulationArea.lastSelected!==simulationArea.root&&!simulationArea.copyList.contains(simulationArea.lastSelected)){ - // simulationArea.copyList.push(simulationArea.lastSelected); - // } - // copy(simulationArea.copyList); - } - if ( simulationArea.lastSelected && simulationArea.lastSelected.keyDown @@ -344,7 +503,7 @@ export default function startListeners() { simulationArea.lastSelected.objectType != 'Wire' && simulationArea.lastSelected.objectType != 'CircuitElement' && - !simulationArea.multipleObjectSelections.contains( + !simulationArea.multipleObjectSelections.includes( simulationArea.lastSelected ) ) { @@ -407,31 +566,9 @@ export default function startListeners() { true ) - document - .getElementById('simulationArea') - .addEventListener('dblclick', (e) => { - updateCanvasSet(true) - if ( - simulationArea.lastSelected && - simulationArea.lastSelected.dblclick !== undefined - ) { - simulationArea.lastSelected.dblclick() - } else if (!simulationArea.shiftDown) { - simulationArea.multipleObjectSelections = [] - } - scheduleUpdate(2) - }) - - document - .getElementById('simulationArea') - .addEventListener('mouseup', onMouseUp) - - document - .getElementById('simulationArea') - .addEventListener('mousewheel', MouseScroll) - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', MouseScroll) + document.getElementById('simulationArea').addEventListener('dblclick', e => { + onDoubleClickorTap(e); + }); function MouseScroll(event) { updateCanvasSet(true) @@ -448,6 +585,13 @@ export default function startListeners() { else update() // Schedule update not working, this is INEFFICIENT } + document + .getElementById('simulationArea') + .addEventListener('mousewheel', MouseScroll) + document + .getElementById('simulationArea') + .addEventListener('DOMMouseScroll', MouseScroll) + document.addEventListener('cut', (e) => { if (verilogModeGet()) return if (document.activeElement.tagName == 'INPUT') return @@ -459,12 +603,12 @@ export default function startListeners() { if ( simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && - !simulationArea.copyList.contains(simulationArea.lastSelected) + !simulationArea.copyList.includes(simulationArea.lastSelected) ) { simulationArea.copyList.push(simulationArea.lastSelected) } - var textToPutOnClipboard = copy(simulationArea.copyList, true) + const textToPutOnClipboard = copy(simulationArea.copyList, true) // Updated restricted elements updateRestrictedElementsInScope() @@ -490,12 +634,12 @@ export default function startListeners() { if ( simulationArea.lastSelected && simulationArea.lastSelected !== simulationArea.root && - !simulationArea.copyList.contains(simulationArea.lastSelected) + !simulationArea.copyList.includes(simulationArea.lastSelected) ) { simulationArea.copyList.push(simulationArea.lastSelected) } - var textToPutOnClipboard = copy(simulationArea.copyList) + const textToPutOnClipboard = copy(simulationArea.copyList) // Updated restricted elements updateRestrictedElementsInScope() @@ -532,33 +676,25 @@ export default function startListeners() { }) // 'drag and drop' event listener for subcircuit elements in layout mode - $('#subcircuitMenu').on( - 'dragstop', - '.draggableSubcircuitElement', - function (event, ui) { - const sideBarWidth = $('#guide_1')[0].clientWidth - let tempElement - - if (ui.position.top > 10 && ui.position.left > sideBarWidth) { - // make a shallow copy of the element with the new coordinates - tempElement = - globalScope[this.dataset.elementName][ - this.dataset.elementId - ] - - // Changing the coordinate doesn't work yet, nodes get far from element - tempElement.x = ui.position.left - sideBarWidth - tempElement.y = ui.position.top - for (let node of tempElement.nodeList) { - node.x = ui.position.left - sideBarWidth - node.y = ui.position.top - } - - tempBuffer.subElements.push(tempElement) - this.parentElement.removeChild(this) + $('#subcircuitMenu').on('dragstop', '.draggableSubcircuitElement', function (event, ui) { + const sideBarWidth = $('#guide_1')[0].clientWidth; + let tempElement; + + if (ui.position.top > 10 && ui.position.left > sideBarWidth) { + // Make a shallow copy of the element with the new coordinates + tempElement = globalScope[this.dataset.elementName][this.dataset.elementId]; + // Changing the coordinate doesn't work yet, nodes get far from element + tempElement.x = ui.position.left - sideBarWidth; + tempElement.y = ui.position.top; + for (const node of tempElement.nodeList) { + node.x = ui.position.left - sideBarWidth; + node.y = ui.position.top; } + + tempBuffer.subElements.push(tempElement); + this.parentElement.removeChild(this); } - ) + }); restrictedElements.forEach((element) => { $(`#${element}`).mouseover(() => { @@ -571,102 +707,15 @@ export default function startListeners() { }) zoomSliderListeners() - // setupLayoutModePanelListeners() if (!embed) { setupTimingListeners() } } -var isIe = - navigator.userAgent.toLowerCase().indexOf('msie') != -1 || - navigator.userAgent.toLowerCase().indexOf('trident') != -1 - -function onMouseMove(e) { - var rect = simulationArea.canvas.getBoundingClientRect() - simulationArea.mouseRawX = (e.clientX - rect.left) * DPR - simulationArea.mouseRawY = (e.clientY - rect.top) * DPR - simulationArea.mouseXf = - (simulationArea.mouseRawX - globalScope.ox) / globalScope.scale - simulationArea.mouseYf = - (simulationArea.mouseRawY - globalScope.oy) / globalScope.scale - simulationArea.mouseX = Math.round(simulationArea.mouseXf / unit) * unit - simulationArea.mouseY = Math.round(simulationArea.mouseYf / unit) * unit - - updateCanvasSet(true) - - if ( - simulationArea.lastSelected && - (simulationArea.mouseDown || simulationArea.lastSelected.newElement) - ) { - updateCanvasSet(true) - var fn - - if (simulationArea.lastSelected == globalScope.root) { - fn = function () { - updateSelectionsAndPane() - } - } else { - fn = function () { - if (simulationArea.lastSelected) { - simulationArea.lastSelected.update() - } - } - } - scheduleUpdate(0, 20, fn) - } else { - scheduleUpdate(0, 200) - } -} - -function onMouseUp(e) { - simulationArea.mouseDown = false - if (!lightMode) { - updatelastMinimapShown() - setTimeout(removeMiniMap, 2000) - } - - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - simulationArea.mouseDown = false - - for (var i = 0; i < 2; i++) { - updatePositionSet(true) - wireToBeCheckedSet(1) - update() - } - errorDetectedSet(false) - updateSimulationSet(true) - updatePositionSet(true) - updateCanvasSet(true) - gridUpdateSet(true) - wireToBeCheckedSet(1) - - scheduleUpdate(1) - var rect = simulationArea.canvas.getBoundingClientRect() - - if ( - !( - simulationArea.mouseRawX < 0 || - simulationArea.mouseRawY < 0 || - simulationArea.mouseRawX > width || - simulationArea.mouseRawY > height - ) - ) { - uxvar.smartDropXX = simulationArea.mouseX + 100 // Math.round(((simulationArea.mouseRawX - globalScope.ox+100) / globalScope.scale) / unit) * unit; - uxvar.smartDropYY = simulationArea.mouseY - 50 // Math.round(((simulationArea.mouseRawY - globalScope.oy+100) / globalScope.scale) / unit) * unit; - } -} - function resizeTabs() { - var $windowsize = $('body').width() - var $sideBarsize = $('.side').width() - var $maxwidth = $windowsize - $sideBarsize + const $windowsize = $('body').width() + const $sideBarsize = $('.side').width() + const $maxwidth = $windowsize - $sideBarsize $('#tabsBar div').each(function (e) { $(this).css({ 'max-width': $maxwidth - 30 }) }) @@ -675,87 +724,156 @@ function resizeTabs() { window.addEventListener('resize', resizeTabs) resizeTabs() -// $(() => { -// $('[data-toggle="tooltip"]').tooltip() -// }) - // direction is only 1 or -1 -function handleZoom(direction) { - var zoomSlider = $('#customRange1') - var currentSliderValue = parseInt(zoomSlider.val(), 10) - currentSliderValue += direction - +function handleZoom (direction) { if (globalScope.scale > 0.5 * DPR) { - zoomSlider.val(currentSliderValue).change() + changeScale(direction * 0.1 * DPR); } else if (globalScope.scale < 4 * DPR) { - zoomSlider.val(currentSliderValue).change() + changeScale(direction * 0.1 * DPR); } - - gridUpdateSet(true) - scheduleUpdate() -} - -export function ZoomIn() { - handleZoom(1) -} - -export function ZoomOut() { - handleZoom(-1) -} - -function zoomSliderListeners() { - document.getElementById('customRange1').value = 5 - document - .getElementById('simulationArea') - .addEventListener('DOMMouseScroll', zoomSliderScroll) - document - .getElementById('simulationArea') - .addEventListener('mousewheel', zoomSliderScroll) - let curLevel = document.getElementById('customRange1').value + gridUpdateSet(true); + scheduleUpdate(); + } + export function ZoomIn () { + handleZoom(1); + } + export function ZoomOut () { + handleZoom(-1); + } + function zoomSliderListeners () { + document.getElementById("customRange1").value = 5; + document.getElementById('simulationArea').addEventListener('DOMMouseScroll', zoomSliderScroll); + document.getElementById('simulationArea').addEventListener('mousewheel', zoomSliderScroll); + let curLevel = document.getElementById("customRange1").value; $(document).on('input change', '#customRange1', function (e) { - let newValue = $(this).val() - let changeInScale = newValue - curLevel - updateCanvasSet(true) - changeScale(changeInScale * 0.1, 'zoomButton', 'zoomButton', 3) - gridUpdateSet(true) - curLevel = newValue - }) - function zoomSliderScroll(e) { - let zoomLevel = document.getElementById('customRange1').value - let deltaY = e.wheelDelta ? e.wheelDelta : -e.detail - const directionY = deltaY > 0 ? 1 : -1 - if (directionY > 0) zoomLevel++ - else zoomLevel-- - if (zoomLevel >= 45) { - zoomLevel = 45 - document.getElementById('customRange1').value = 45 - } else if (zoomLevel <= 0) { - zoomLevel = 0 - document.getElementById('customRange1').value = 0 - } else { - document.getElementById('customRange1').value = zoomLevel - curLevel = zoomLevel - } + const newValue = $(this).val(); + const changeInScale = newValue - curLevel; + updateCanvasSet(true); + changeScale(changeInScale * 0.1, 'zoomButton', 'zoomButton', 3) + gridUpdateSet(true); + curLevel = newValue; + }); + function zoomSliderScroll (e) { + let zoomLevel = document.getElementById("customRange1").value; + const deltaY = e.wheelDelta ? e.wheelDelta : -e.detail; + const directionY = deltaY > 0 ? 1 : -1; + if (directionY > 0) zoomLevel++ + else zoomLevel-- + if (zoomLevel >= 45) { + zoomLevel = 45; + document.getElementById("customRange1").value = 45; + } else if (zoomLevel <= 0) { + zoomLevel = 0; + document.getElementById("customRange1").value = 0; + } else { + document.getElementById("customRange1").value = zoomLevel; + curLevel = zoomLevel; + } } - - // previously used for the + and - zoom buttons in quickButtons - - // function sliderZoomButton(direction) { - // var zoomSlider = $('#customRange1') - // var currentSliderValue = parseInt(zoomSlider.val(), 10) - // if (direction === -1) { - // currentSliderValue-- - // } else { - // currentSliderValue++ - // } - // zoomSlider.val(currentSliderValue).change() - // } - - // $('#decrement').click(() => { - // sliderZoomButton(-1) - // }) - - // $('#increment').click(() => { - // sliderZoomButton(1) - // }) -} + function sliderZoomButton (direction) { + const zoomSlider = $('#customRange1'); + let currentSliderValue = parseInt(zoomSlider.val(), 10); + if (direction === -1) { + currentSliderValue--; + } else { + currentSliderValue++; + } + zoomSlider.val(currentSliderValue).change(); + } + $('#decrement').click(() => { + sliderZoomButton(-1); + }); + $('#increment').click(() => { + sliderZoomButton(1); + }); + } + +// Desktop App Listeners + +listen('new-project', () => { + logixFunction.newProject(); +}); + +listen('save-online', () => { + logixFunction.save(); +}); + +listen('save-offline', () => { + logixFunction.saveOffline(); +}); + +listen('open-offline', () => { + logixFunction.createOpenLocalPrompt(); +}); + +listen('export', () => { + logixFunction.ExportProject(); +}); + +listen('import', () => { + logixFunction.ImportProject(); +}); + +listen('recover', () => { + logixFunction.recoverProject(); +}); + +listen('clear', () => { + logixFunction.clearProject(); +}); + +listen('preview-circuit', () => { + logixFunction.fullViewOption(); +}); + +listen('new-circuit', () => { + logixFunction.createNewCircuitScope(); +}); + +listen('new-verilog-module', () => { + logixFunction.newVerilogModule(); +}); + +listen('insert-sub-circuit', () => { + logixFunction.createSubCircuitPrompt(); +}); + +listen('combinational-analysis', () => { + logixFunction.createCombinationalAnalysisPrompt(); +}); + +listen('hex-bin-dec', () => { + logixFunction.bitconverter(); +}); + +listen('download-image', () => { + logixFunction.createSaveAsImgPrompt(); +}); + +listen('themes', () => { + logixFunction.colorThemes(); +}); + +listen('custom-shortcut', () => { + logixFunction.customShortcut(); +}); + +listen('export-verilog', () => { + logixFunction.generateVerilog(); +}); + +listen('tutorial', () => { + logixFunction.showTourGuide(); +}); + +listen('user-manual', () => { + logixFunction.showUserManual(); +}); + +listen('learn-digital-circuit', () => { + logixFunction.showDigitalCircuit(); +}); + +listen('discussion-forum', () => { + logixFunction.showDiscussionForum(); +}); diff --git a/v1/src/simulator/src/metadata.json b/v1/src/simulator/src/metadata.json deleted file mode 100644 index 8ed4f225..00000000 --- a/v1/src/simulator/src/metadata.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "circuitElementList": [ - "Input", - "Output", - "NotGate", - "OrGate", - "AndGate", - "NorGate", - "NandGate", - "XorGate", - "XnorGate", - "SevenSegDisplay", - "SixteenSegDisplay", - "HexDisplay", - "Multiplexer", - "BitSelector", - "Splitter", - "Power", - "Ground", - "ConstantVal", - "ControlledInverter", - "TriState", - "Adder", - "verilogMultiplier", - "verilogDivider", - "verilogPower", - "verilogShiftLeft", - "TwoComplement", - "verilogShiftRight", - "Rom", - "RAM", - "verilogRAM", - "EEPROM", - "TflipFlop", - "JKflipFlop", - "SRflipFlop", - "DflipFlop", - "TTY", - "Keyboard", - "Clock", - "DigitalLed", - "Stepper", - "VariableLed", - "RGBLed", - "SquareRGBLed", - "RGBLedMatrix", - "Button", - "Demultiplexer", - "Buffer", - "SubCircuit", - "Flag", - "MSB", - "LSB", - "PriorityEncoder", - "Tunnel", - "ALU", - "Decoder", - "Random", - "Counter", - "Dlatch", - "TB_Input", - "TB_Output", - "ForceGate" - ], - "annotationList": ["Text", "Rectangle", "Arrow", "ImageAnnotation"], - "inputList": [ - "Random", - "Dlatch", - "JKflipFlop", - "TflipFlop", - "SRflipFlop", - "DflipFlop", - "Buffer", - "Stepper", - "Ground", - "Power", - "ConstantVal", - "Input", - "Clock", - "Button", - "Counter" - ], - "subCircuitInputList": [ - "Random", - "Dlatch", - "JKflipFlop", - "TflipFlop", - "SRflipFlop", - "DflipFlop", - "Buffer", - "Stepper", - "Ground", - "Power", - "ConstantVal", - "Clock", - "Button", - "Counter" - ], - "elementHierarchy": { - "Input": [ - { "name": "Input", "label": "Input" }, - { "name": "Button", "label": "Button" }, - { "name": "Power", "label": "Power" }, - { "name": "Ground", "label": "Ground" }, - { "name": "ConstantVal", "label": "Constant Value" }, - { "name": "Stepper", "label": "Stepper" }, - { "name": "Random", "label": "Random" }, - { "name": "Counter", "label": "Counter" } - ], - "Output": [ - { "name": "Output", "label": "Output" }, - { "name": "RGBLed", "label": "RGB Led" }, - { "name": "DigitalLed", "label": "Digital Led" }, - { "name": "VariableLed", "label": "Variable Led" }, - { "name": "HexDisplay", "label": "Hex Display" }, - { "name": "SevenSegDisplay", "label": "Seven Segment Display" }, - { "name": "SixteenSegDisplay", "label": "Sixteen Segment Display" }, - { "name": "SquareRGBLed", "label": "Square RGB Led" }, - { "name": "RGBLedMatrix", "label": "RGB Led Matrix" } - ], - "Gates": [ - { "name": "AndGate", "label": "And Gate" }, - { "name": "OrGate", "label": "Or Gate" }, - { "name": "NotGate", "label": "Not Gate" }, - { "name": "XorGate", "label": "Xor Gate" }, - { "name": "NandGate", "label": "Nand Gate" }, - { "name": "NorGate", "label": "Nor Gate" }, - { "name": "XnorGate", "label": "Xnor Gate" } - ], - "Decoders & Plexers": [ - { "name": "Multiplexer", "label": "Multiplexer" }, - { "name": "Demultiplexer", "label": "Demultiplexer" }, - { "name": "BitSelector", "label": "Bit Selector" }, - { "name": "MSB", "label": "MSB(Most Significant Bit)" }, - { "name": "LSB", "label": "LSB(Least Significant Bit)" }, - { "name": "PriorityEncoder", "label": "Priority Encoder" }, - { "name": "Decoder", "label": "Decoder" } - ], - "Sequential Elements": [ - { "name": "DflipFlop", "label": "D flip Flop" }, - { "name": "Dlatch", "label": "D latch" }, - { "name": "TflipFlop", "label": "T flip Flop" }, - { "name": "JKflipFlop", "label": "JK flip Flop" }, - { "name": "SRflipFlop", "label": "SR flip Flop" }, - { "name": "TTY", "label": "TTY" }, - { "name": "Keyboard", "label": "Keyboard" }, - { "name": "Clock", "label": "Clock" }, - { "name": "Rom", "label": "ROM" }, - { "name": "RAM", "label": "RAM" }, - { "name": "verilogRAM", "label": "Verilog RAM" }, - { "name": "EEPROM", "label": "EEPROM" } - ], - "Annotation": [ - { "name": "Rectangle", "label": "Rectangle" }, - { "name": "Arrow", "label": "Arrow" }, - { "name": "ImageAnnotation", "label": "Image Annotation" }, - { "name": "Text", "label": "Text" } - ], - "Misc": [ - { "name": "TwoComplement", "label": "Two Complement" }, - { "name": "Flag", "label": "Flag" }, - { "name": "Splitter", "label": "Splitter" }, - { "name": "Adder", "label": "Adder" }, - { "name": "ALU", "label": "ALU(Arithmetic and Logical Unit)" }, - { "name": "TriState", "label": "TriState Flip Flop" }, - { "name": "Tunnel", "label": "Tunnel" }, - { "name": "verilogMultiplier", "label": "Verilog Multiplier" }, - { "name": "verilogDivider", "label": "Verilog Divider" }, - { "name": "verilogPower", "label": "Verilog Power" }, - { "name": "verilogShiftLeft", "label": "Verilog Shift Left" }, - { "name": "verilogShiftRight", "label": "Verilog Shift Right" }, - { "name": "Buffer", "label": "Buffer" }, - { "name": "ControlledInverter", "label": "Controlled Inverter" }, - { "name": "TB_Input", "label": "TB Input" }, - { "name": "TB_Output", "label": "TB Output" }, - { "name": "ForceGate", "label": "Force Gate" } - ] - } -} diff --git a/v1/src/simulator/src/metadata.ts b/v1/src/simulator/src/metadata.ts new file mode 100644 index 00000000..5d99084c --- /dev/null +++ b/v1/src/simulator/src/metadata.ts @@ -0,0 +1,191 @@ + +export const circuitElementList = [ + "Input", + "Output", + "NotGate", + "OrGate", + "AndGate", + "NorGate", + "NandGate", + "XorGate", + "XnorGate", + "SevenSegDisplay", + "SixteenSegDisplay", + "HexDisplay", + "Multiplexer", + "BitSelector", + "Splitter", + "Power", + "Ground", + "ConstantVal", + "ControlledInverter", + "TriState", + "Adder", + "verilogMultiplier", + "verilogDivider", + "verilogPower", + "verilogShiftLeft", + "TwoComplement", + "verilogShiftRight", + "Rom", + "RAM", + "verilogRAM", + "EEPROM", + "TflipFlop", + "JKflipFlop", + "SRflipFlop", + "DflipFlop", + "TTY", + "Keyboard", + "Clock", + "DigitalLed", + "Stepper", + "VariableLed", + "RGBLed", + "SquareRGBLed", + "RGBLedMatrix", + "Button", + "Demultiplexer", + "Buffer", + "SubCircuit", + "Flag", + "MSB", + "LSB", + "PriorityEncoder", + "Tunnel", + "ALU", + "Decoder", + "Random", + "Counter", + "Dlatch", + "TB_Input", + "TB_Output", + "ForceGate" +] +const annotationList = ["Text", "Rectangle", "Arrow", "ImageAnnotation"] +export const moduleList = [...circuitElementList, ...annotationList] +export const updateOrder = [ + 'wires', + ...circuitElementList, + 'nodes', + ...annotationList, +] // Order of update +export const renderOrder = [...moduleList.slice().reverse(), 'wires', 'allNodes'] // Order of render +export const inputList = [ + "Random", + "Dlatch", + "JKflipFlop", + "TflipFlop", + "SRflipFlop", + "DflipFlop", + "Buffer", + "Stepper", + "Ground", + "Power", + "ConstantVal", + "Input", + "Clock", + "Button", + "Counter" +] +export const subCircuitInputList = [ + "Random", + "Dlatch", + "JKflipFlop", + "TflipFlop", + "SRflipFlop", + "DflipFlop", + "Buffer", + "Stepper", + "Ground", + "Power", + "ConstantVal", + "Clock", + "Button", + "Counter" +] +interface NameLabel { + name: string; + label: string; +} + +export const elementHierarchy: Record = { + "Input": [ + { name: "Input", label: "Input" }, + { name: "Button", label: "Button" }, + { name: "Power", label: "Power" }, + { name: "Ground", label: "Ground" }, + { name: "ConstantVal", label: "Constant Value" }, + { name: "Stepper", label: "Stepper" }, + { name: "Random", label: "Random" }, + { name: "Counter", label: "Counter" } + ], + "Output": [ + { name: "Output", label: "Output" }, + { name: "RGBLed", label: "RGB Led" }, + { name: "DigitalLed", label: "Digital Led" }, + { name: "VariableLed", label: "Variable Led" }, + { name: "HexDisplay", label: "Hex Display" }, + { name: "SevenSegDisplay", label: "Seven Segment Display" }, + { name: "SixteenSegDisplay", label: "Sixteen Segment Display" }, + { name: "SquareRGBLed", label: "Square RGB Led" }, + { name: "RGBLedMatrix", label: "RGB Led Matrix" } + ], + "Gates": [ + { name: "AndGate", label: "And Gate" }, + { name: "OrGate", label: "Or Gate" }, + { name: "NotGate", label: "Not Gate" }, + { name: "XorGate", label: "Xor Gate" }, + { name: "NandGate", label: "Nand Gate" }, + { name: "NorGate", label: "Nor Gate" }, + { name: "XnorGate", label: "Xnor Gate" } + ], + "Decoders & Plexers": [ + { name: "Multiplexer", label: "Multiplexer" }, + { name: "Demultiplexer", label: "Demultiplexer" }, + { name: "BitSelector", label: "Bit Selector" }, + { name: "MSB", label: "MSB(Most Significant Bit)" }, + { name: "LSB", label: "LSB(Least Significant Bit)" }, + { name: "PriorityEncoder", label: "Priority Encoder" }, + { name: "Decoder", label: "Decoder" } + ], + "Sequential Elements": [ + { name: "DflipFlop", label: "D flip Flop" }, + { name: "Dlatch", label: "D latch" }, + { name: "TflipFlop", label: "T flip Flop" }, + { name: "JKflipFlop", label: "JK flip Flop" }, + { name: "SRflipFlop", label: "SR flip Flop" }, + { name: "TTY", label: "TTY" }, + { name: "Keyboard", label: "Keyboard" }, + { name: "Clock", label: "Clock" }, + { name: "Rom", label: "ROM" }, + { name: "RAM", label: "RAM" }, + { name: "verilogRAM", label: "Verilog RAM" }, + { name: "EEPROM", label: "EEPROM" } + ], + "Annotation": [ + { name: "Rectangle", label: "Rectangle" }, + { name: "Arrow", label: "Arrow" }, + { name: "ImageAnnotation", label: "Image Annotation" }, + { name: "Text", label: "Text" } + ], + "Misc": [ + { name: "TwoComplement", label: "Two Complement" }, + { name: "Flag", label: "Flag" }, + { name: "Splitter", label: "Splitter" }, + { name: "Adder", label: "Adder" }, + { name: "ALU", label: "ALU(Arithmetic and Logical Unit)" }, + { name: "TriState", label: "TriState Flip Flop" }, + { name: "Tunnel", label: "Tunnel" }, + { name: "verilogMultiplier", label: "Verilog Multiplier" }, + { name: "verilogDivider", label: "Verilog Divider" }, + { name: "verilogPower", label: "Verilog Power" }, + { name: "verilogShiftLeft", label: "Verilog Shift Left" }, + { name: "verilogShiftRight", label: "Verilog Shift Right" }, + { name: "Buffer", label: "Buffer" }, + { name: "ControlledInverter", label: "Controlled Inverter" }, + { name: "TB_Input", label: "TB Input" }, + { name: "TB_Output", label: "TB Output" }, + { name: "ForceGate", label: "Force Gate" } + ] +} \ No newline at end of file diff --git a/v1/src/simulator/src/minimap.js b/v1/src/simulator/src/minimap.js index 6cfcf49d..84286984 100644 --- a/v1/src/simulator/src/minimap.js +++ b/v1/src/simulator/src/minimap.js @@ -1,6 +1,7 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { colors } from './themer/themer' import { layoutModeGet } from './layoutMode' +import { updateOrder } from './metadata' /** * @type {Object} miniMapArea diff --git a/v1/src/simulator/src/moduleSetup.js b/v1/src/simulator/src/moduleSetup.js index 5002bc69..fb75f6a8 100644 --- a/v1/src/simulator/src/moduleSetup.js +++ b/v1/src/simulator/src/moduleSetup.js @@ -54,7 +54,7 @@ import Rom from './sequential/Rom' import SRflipFlop from './sequential/SRflipFlop' import TflipFlop from './sequential/TflipFlop' import TTY from './sequential/TTY' -import ForceGate from './testbench/ForceGate' +import ForceGate from './sequential/ForceGate' import TB_Input from './testbench/testbenchInput' import TB_Output from './testbench/testbenchOutput' import verilogMultiplier from './modules/verilogMultiplier' diff --git a/v1/src/simulator/src/modules.js b/v1/src/simulator/src/modules.js index 41bacb6f..f52adb3b 100644 --- a/v1/src/simulator/src/modules.js +++ b/v1/src/simulator/src/modules.js @@ -1,5 +1,5 @@ /* eslint-disable import/no-cycle */ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' export function getNextPosition(x = 0, scope = globalScope) { let possibleY = 20 diff --git a/v1/src/simulator/src/modules/ALU.js b/v1/src/simulator/src/modules/ALU.js index 19cda667..bd10474e 100644 --- a/v1/src/simulator/src/modules/ALU.js +++ b/v1/src/simulator/src/modules/ALU.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText4 } from '../canvasApi' import { colors } from '../themer/themer' @@ -95,7 +95,7 @@ export default class ALU extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v1/src/simulator/src/modules/Adder.js b/v1/src/simulator/src/modules/Adder.js index 8f369a9f..205455b1 100644 --- a/v1/src/simulator/src/modules/Adder.js +++ b/v1/src/simulator/src/modules/Adder.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class diff --git a/v1/src/simulator/src/modules/AndGate.js b/v1/src/simulator/src/modules/AndGate.js index 43c3fced..4885d8ab 100644 --- a/v1/src/simulator/src/modules/AndGate.js +++ b/v1/src/simulator/src/modules/AndGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' import { changeInputSize } from '../modules' import { colors } from '../themer/themer' @@ -123,7 +123,7 @@ export default class AndGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -142,7 +142,7 @@ export default class AndGate extends CircuitElement { * @category modules */ AndGate.prototype.tooltipText = - 'And Gate Tooltip : Implements logical conjunction' + 'And Gate ToolTip : Implements logical conjunction' /** * @memberof AndGate diff --git a/v1/src/simulator/src/modules/Arrow.js b/v1/src/simulator/src/modules/Arrow.js index 24eeddfd..1956bb70 100644 --- a/v1/src/simulator/src/modules/Arrow.js +++ b/v1/src/simulator/src/modules/Arrow.js @@ -1,8 +1,6 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Arrow @@ -64,7 +62,7 @@ export default class Arrow extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/BitSelector.js b/v1/src/simulator/src/modules/BitSelector.js index 8c91cee4..d730a8d5 100644 --- a/v1/src/simulator/src/modules/BitSelector.js +++ b/v1/src/simulator/src/modules/BitSelector.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, extractBits } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -118,7 +118,7 @@ export default class BitSelector extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/Buffer.js b/v1/src/simulator/src/modules/Buffer.js index f3e9cd69..e1237b83 100644 --- a/v1/src/simulator/src/modules/Buffer.js +++ b/v1/src/simulator/src/modules/Buffer.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Buffer @@ -103,7 +102,7 @@ export default class Buffer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/Button.js b/v1/src/simulator/src/modules/Button.js index b108afaa..e4099ffa 100644 --- a/v1/src/simulator/src/modules/Button.js +++ b/v1/src/simulator/src/modules/Button.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' /** @@ -86,7 +86,7 @@ export default class Button extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(232, 13, 13,0.6)' } @@ -111,7 +111,7 @@ export default class Button extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(232, 13, 13,0.6)' if (this.wasClicked) ctx.fillStyle = 'rgba(232, 13, 13,0.8)' diff --git a/v1/src/simulator/src/modules/ConstantVal.js b/v1/src/simulator/src/modules/ConstantVal.js index d5f9028a..3e58dc64 100644 --- a/v1/src/simulator/src/modules/ConstantVal.js +++ b/v1/src/simulator/src/modules/ConstantVal.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText, oppositeDirection } from '../canvasApi' import { colors } from '../themer/themer' @@ -140,7 +140,7 @@ export default class ConstantVal extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/ControlledInverter.js b/v1/src/simulator/src/modules/ControlledInverter.js index c846abec..4f74d147 100644 --- a/v1/src/simulator/src/modules/ControlledInverter.js +++ b/v1/src/simulator/src/modules/ControlledInverter.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * ControlledInverter @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class ControlledInverter extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['ControlledInverter'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) @@ -72,9 +68,14 @@ export default class ControlledInverter extends CircuitElement { (32 - this.bitWidth) simulationArea.simulationQueue.add(this.output1) } - if (this.state.value === 0) { - this.output1.value = undefined + else if ( + this.output1.value !== undefined && + !simulationArea.contentionPending.has(this.output1) + ) { + this.output1.value = undefined; + simulationArea.simulationQueue.add(this.output1); } + simulationArea.contentionPending.removeAllContentionsForNode(this.output1); } /** @@ -96,7 +97,7 @@ export default class ControlledInverter extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/Counter.js b/v1/src/simulator/src/modules/Counter.js index 7ffb23fc..633baaec 100644 --- a/v1/src/simulator/src/modules/Counter.js +++ b/v1/src/simulator/src/modules/Counter.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { lineTo, moveTo, fillText, correctWidth, rect2 } from '../canvasApi' import { colors } from '../themer/themer' @@ -142,7 +142,7 @@ export default class Counter extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v1/src/simulator/src/modules/Decoder.js b/v1/src/simulator/src/modules/Decoder.js index 6b6d9278..3d4a6955 100644 --- a/v1/src/simulator/src/modules/Decoder.js +++ b/v1/src/simulator/src/modules/Decoder.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, rect, fillText } from '../canvasApi' /** * @class @@ -18,10 +18,6 @@ import { colors } from '../themer/themer' export default class Decoder extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'LEFT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Decoder'].push(this); - */ - // this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10); this.outputsize = 1 << this.bitWidth this.xOff = 0 this.yOff = 1 @@ -31,31 +27,8 @@ export default class Decoder extends CircuitElement { if (this.bitWidth <= 3) { this.yOff = 2 } - - // this.changeControlSignalSize = function(size) { - // if (size === undefined || size < 1 || size > 32) return; - // if (this.controlSignalSize === size) return; - // let obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size); - // this.cleanDelete(); - // simulationArea.lastSelected = obj; - // return obj; - // } - // this.mutableProperties = { - // "controlSignalSize": { - // name: "Control Signal Size", - // type: "number", - // max: "32", - // min: "1", - // func: "changeControlSignalSize", - // }, - // } // eslint-disable-next-line no-shadow this.newBitWidth = function (bitWidth) { - // this.bitWidth = bitWidth; - // for (let i = 0; i < this.inputSize; i++) { - // this.outputs1[i].bitWidth = bitWidth - // } - // this.input.bitWidth = bitWidth; if (bitWidth === undefined || bitWidth < 1 || bitWidth > 32) return if (this.bitWidth === bitWidth) return const obj = new Decoder( @@ -85,8 +58,6 @@ export default class Decoder extends CircuitElement { ) this.output1.push(a) } - - // this.controlSignalInput = new Node(0,this.yOff * 10 * (this.outputsize / 2 - 1) +this.xOff + 10, 0, this, this.controlSignalSize,"Control Signal"); } /** @@ -129,12 +100,6 @@ export default class Decoder extends CircuitElement { const xx = this.x const yy = this.y - - // ctx.beginPath(); - // moveTo(ctx, 0,this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 *this.xOff, xx, yy, this.direction); - // lineTo(ctx, 0,this.yOff * 5 * (this.outputsize - 1) +this.xOff, xx, yy, this.direction); - // ctx.stroke(); - ctx.beginPath() ctx.strokeStyle = colors['stroke'] ctx.lineWidth = correctWidth(4) @@ -176,7 +141,7 @@ export default class Decoder extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } @@ -186,7 +151,6 @@ export default class Decoder extends CircuitElement { ctx.beginPath() ctx.fillStyle = 'black' ctx.textAlign = 'center' - // [xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2); for (let i = 0; i < this.outputsize; i++) { if (this.direction === 'LEFT') fillText( diff --git a/v1/src/simulator/src/modules/Demultiplexer.js b/v1/src/simulator/src/modules/Demultiplexer.js index feb21cfa..1a679539 100644 --- a/v1/src/simulator/src/modules/Demultiplexer.js +++ b/v1/src/simulator/src/modules/Demultiplexer.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -206,7 +206,7 @@ export default class Demultiplexer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v1/src/simulator/src/modules/DigitalLed.js b/v1/src/simulator/src/modules/DigitalLed.js index df17fbfa..da280340 100644 --- a/v1/src/simulator/src/modules/DigitalLed.js +++ b/v1/src/simulator/src/modules/DigitalLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, @@ -10,7 +10,6 @@ import { drawCircle2, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * DigitalLed @@ -26,13 +25,11 @@ import { colors } from '../themer/themer' export default class DigitalLed extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { // Calling base class constructor - super(x, y, scope, 'UP', 1) - /* this is done in this.baseSetup() now - this.scope['DigitalLed'].push(this); - */ this.rectangleObject = false - this.setDimensions(10, 20) + this.setWidth(10); + this.upDimensionY = 20; + this.downDimensionY = 40; this.inp1 = new Node(-40, 0, 0, this, 1) this.directionFixed = true this.fixedBitWidth = true @@ -114,7 +111,7 @@ export default class DigitalLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -140,7 +137,7 @@ export default class DigitalLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v1/src/simulator/src/modules/Flag.js b/v1/src/simulator/src/modules/Flag.js index f332622b..b0cd9bf2 100644 --- a/v1/src/simulator/src/modules/Flag.js +++ b/v1/src/simulator/src/modules/Flag.js @@ -1,9 +1,8 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText } from '../canvasApi' import plotArea from '../plotArea' -import EventQueue from '../eventQueue' /** * @class * Flag @@ -28,9 +27,6 @@ export default class Flag extends CircuitElement { identifier ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Flag'].push(this); - */ this.setWidth(60) this.setHeight(20) this.rectangleObject = false @@ -127,7 +123,7 @@ export default class Flag extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -189,9 +185,6 @@ export default class Flag extends CircuitElement { } else { this.inp1.leftx = 20 } - // if(this.direction=="LEFT" || this.direction=="RIGHT") this.inp1.leftx=50-this.xSize; - // this.inp1.refresh(); - this.inp1.refresh() } } diff --git a/v1/src/simulator/src/modules/Ground.js b/v1/src/simulator/src/modules/Ground.js index f1c88932..e9e801b9 100644 --- a/v1/src/simulator/src/modules/Ground.js +++ b/v1/src/simulator/src/modules/Ground.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Ground @@ -18,33 +17,12 @@ import { colors } from '../themer/themer' export default class Ground extends CircuitElement { constructor(x, y, scope = globalScope, bitWidth = 1) { super(x, y, scope, 'RIGHT', bitWidth) - /* this is done in this.baseSetup() now - this.scope['Ground'].push(this); - */ this.rectangleObject = false this.setDimensions(10, 10) this.directionFixed = true this.output1 = new Node(0, -10, 1, this) } - /** - * @memberof Ground - * fn to create save Json Data of object - * @return {JSON} - */ - customSave() { - const data = { - nodes: { - output1: findNode(this.output1), - }, - values: { - state: this.state, - }, - constructorParamaters: [this.direction, this.bitWidth], - } - return data - } - /** * @memberof Ground * resolve output values based on inputData @@ -80,7 +58,7 @@ export default class Ground extends CircuitElement { ctx.strokeStyle = [colors['stroke'], 'brown'][ ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + 0 + simulationArea.multipleObjectSelections.includes(this)) + 0 ] ctx.lineWidth = correctWidth(3) diff --git a/v1/src/simulator/src/modules/HexDisplay.js b/v1/src/simulator/src/modules/HexDisplay.js index b96cd096..1c58b1b1 100644 --- a/v1/src/simulator/src/modules/HexDisplay.js +++ b/v1/src/simulator/src/modules/HexDisplay.js @@ -1,16 +1,14 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, - arc, rect2, validColor, colorToRGBA, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * HexDisplay @@ -25,9 +23,6 @@ import { colors } from '../themer/themer' export default class HexDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 4) - /* this is done in this.baseSetup() now - this.scope['HexDisplay'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(30, 50) @@ -96,9 +91,6 @@ export default class HexDisplay extends CircuitElement { customDraw() { var ctx = simulationArea.context - const xx = this.x - const yy = this.y - ctx.strokeStyle = colors['stroke'] ctx.lineWidth = correctWidth(3) @@ -366,7 +358,7 @@ export default class HexDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v1/src/simulator/src/modules/ImageAnnotation.js b/v1/src/simulator/src/modules/ImageAnnotation.js index 67ac4d8b..d46eba66 100644 --- a/v1/src/simulator/src/modules/ImageAnnotation.js +++ b/v1/src/simulator/src/modules/ImageAnnotation.js @@ -1,9 +1,8 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText, drawImage } from '../canvasApi' import { colors } from '../themer/themer' -import { promptFile, showMessage, getImageDimensions } from '../utils' +import { promptFile, showMessage } from '../utils' /** * @class * Image @@ -113,7 +112,7 @@ export default class ImageAnnotation extends CircuitElement { if ( simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.1)' ctx.fill() diff --git a/v1/src/simulator/src/modules/Input.js b/v1/src/simulator/src/modules/Input.js index d33c8627..d6ac8dd2 100644 --- a/v1/src/simulator/src/modules/Input.js +++ b/v1/src/simulator/src/modules/Input.js @@ -1,7 +1,7 @@ /* eslint-disable no-unused-expressions */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, oppositeDirection, fillText } from '../canvasApi' import { getNextPosition } from '../modules' import { generateId } from '../utils' @@ -40,9 +40,6 @@ export default class Input extends CircuitElement { layoutProperties ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Input'].push(this); - */ if (layoutProperties) { this.layoutProperties = layoutProperties } else { diff --git a/v1/src/simulator/src/modules/LSB.js b/v1/src/simulator/src/modules/LSB.js index 0f7e4e61..c4b9e487 100644 --- a/v1/src/simulator/src/modules/LSB.js +++ b/v1/src/simulator/src/modules/LSB.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,16 +18,12 @@ import { colors } from '../themer/themer' export default class LSB extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['LSB'].push(this); - */ this.leftDimensionX = 10 this.rightDimensionX = 20 this.setHeight(30) this.directionFixed = true this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.rectangleObject = false - // this.inputSize = 1 << this.bitWidth; this.intputSize = this.bitWidth this.inp1 = new Node(-10, 0, 0, this, this.inputSize) @@ -58,7 +54,6 @@ export default class LSB extends CircuitElement { * @param {number} bitWidth - new bitwidth */ newBitWidth(bitWidth) { - // this.inputSize = 1 << bitWidth this.inputSize = bitWidth this.inp1.bitWidth = this.inputSize this.bitWidth = bitWidth @@ -104,9 +99,9 @@ export default class LSB extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() diff --git a/v1/src/simulator/src/modules/MSB.js b/v1/src/simulator/src/modules/MSB.js index fbe14b2c..dfb587b4 100644 --- a/v1/src/simulator/src/modules/MSB.js +++ b/v1/src/simulator/src/modules/MSB.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,17 +18,12 @@ import { colors } from '../themer/themer' export default class MSB extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['MSB'].push(this); - */ - // this.setDimensions(20, 20); this.leftDimensionX = 10 this.rightDimensionX = 20 this.setHeight(30) this.directionFixed = true this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.rectangleObject = false - // this.inputSize = 1 << this.bitWidth; this.intputSize = this.bitWidth this.inp1 = new Node(-10, 0, 0, this, this.inputSize) @@ -98,9 +93,9 @@ export default class MSB extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() diff --git a/v1/src/simulator/src/modules/Multiplexer.js b/v1/src/simulator/src/modules/Multiplexer.js index 638b9d01..59c92387 100644 --- a/v1/src/simulator/src/modules/Multiplexer.js +++ b/v1/src/simulator/src/modules/Multiplexer.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * Multiplexer @@ -27,9 +26,6 @@ export default class Multiplexer extends CircuitElement { controlSignalSize = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Multiplexer'].push(this); - */ this.controlSignalSize = controlSignalSize || parseInt(prompt('Enter control signal bitWidth'), 10) @@ -215,7 +211,7 @@ export default class Multiplexer extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v1/src/simulator/src/modules/NandGate.js b/v1/src/simulator/src/modules/NandGate.js index 1cf25e82..2a57fe14 100644 --- a/v1/src/simulator/src/modules/NandGate.js +++ b/v1/src/simulator/src/modules/NandGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2, arc } from '../canvasApi' import { changeInputSize } from '../modules' import { gateGenerateVerilog } from '../utils' @@ -29,9 +29,6 @@ export default class NandGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NandGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) this.inp = [] @@ -120,7 +117,7 @@ export default class NandGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/NorGate.js b/v1/src/simulator/src/modules/NorGate.js index 38572dd5..e7e370c0 100644 --- a/v1/src/simulator/src/modules/NorGate.js +++ b/v1/src/simulator/src/modules/NorGate.js @@ -1,13 +1,12 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { gateGenerateVerilog } from '../utils' import { correctWidth, bezierCurveTo, moveTo, - arc2, drawCircle2, } from '../canvasApi' import { changeInputSize } from '../modules' @@ -35,9 +34,6 @@ export default class NorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -134,9 +130,9 @@ export default class NorGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) - ctx.fillStyle = colors['hover_select'] + ctx.fillStyle = colors['hover_select'] ctx.fill() ctx.stroke() ctx.beginPath() diff --git a/v1/src/simulator/src/modules/NotGate.js b/v1/src/simulator/src/modules/NotGate.js index 38ec3a05..6c1ca9a5 100644 --- a/v1/src/simulator/src/modules/NotGate.js +++ b/v1/src/simulator/src/modules/NotGate.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * NotGate @@ -19,12 +18,8 @@ import { colors } from '../themer/themer' export default class NotGate extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['NotGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) - this.inp1 = new Node(-10, 0, 0, this) this.output1 = new Node(20, 0, 1, this) } @@ -79,7 +74,7 @@ export default class NotGate extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -107,7 +102,7 @@ export default class NotGate extends CircuitElement { * @category modules */ NotGate.prototype.tooltipText = - 'Not Gate Tooltip : Inverts the input digital signal.' + 'Not Gate ToolTip : Inverts the input digital signal.' NotGate.prototype.helplink = 'https://docs.circuitverse.org/#/chapter4/4gates?id=not-gate' NotGate.prototype.objectType = 'NotGate' NotGate.prototype.verilogType = 'not' diff --git a/v1/src/simulator/src/modules/OrGate.js b/v1/src/simulator/src/modules/OrGate.js deleted file mode 100644 index 31b557cd..00000000 --- a/v1/src/simulator/src/modules/OrGate.js +++ /dev/null @@ -1,175 +0,0 @@ -import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, bezierCurveTo, moveTo, arc2 } from '../canvasApi' -import { changeInputSize } from '../modules' -import { gateGenerateVerilog } from '../utils' - -/** - * @class - * OrGate - * @extends CircuitElement - * @param {number} x - x coordinate of element. - * @param {number} y - y coordinate of element. - * @param {Scope=} scope - Cirucit on which element is drawn - * @param {string=} dir - direction of element - * @param {number=} inputs - number of input nodes - * @param {number=} bitWidth - bit width per node. - * @category modules - */ -import { colors } from '../themer/themer' - -export default class OrGate extends CircuitElement { - constructor( - x, - y, - scope = globalScope, - dir = 'RIGHT', - inputs = 2, - bitWidth = 1 - ) { - // Calling base class constructor - super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['OrGate'].push(this); - */ - this.rectangleObject = false - this.setDimensions(15, 20) - // Inherit base class prototype - this.inp = [] - this.inputSize = inputs - if (inputs % 2 === 1) { - for (let i = Math.floor(inputs / 2) - 1; i >= 0; i--) { - const a = new Node(-10, -10 * (i + 1), 0, this) - this.inp.push(a) - } - let a = new Node(-10, 0, 0, this) - this.inp.push(a) - for (let i = 0; i < Math.floor(inputs / 2); i++) { - a = new Node(-10, 10 * (i + 1), 0, this) - this.inp.push(a) - } - } else { - for (let i = inputs / 2 - 1; i >= 0; i--) { - const a = new Node(-10, -10 * (i + 1), 0, this) - this.inp.push(a) - } - for (let i = 0; i < inputs / 2; i++) { - const a = new Node(-10, 10 * (i + 1), 0, this) - this.inp.push(a) - } - } - this.output1 = new Node(20, 0, 1, this) - } - - /** - * @memberof OrGate - * fn to create save Json Data of object - * @return {JSON} - */ - customSave() { - const data = { - constructorParamaters: [ - this.direction, - this.inputSize, - this.bitWidth, - ], - - nodes: { - inp: this.inp.map(findNode), - output1: findNode(this.output1), - }, - } - return data - } - - /** - * @memberof OrGate - * resolve output values based on inputData - */ - resolve() { - let result = this.inp[0].value || 0 - if (this.isResolvable() === false) { - return - } - for (let i = 1; i < this.inputSize; i++) - result |= this.inp[i].value || 0 - this.output1.value = result >>> 0 - simulationArea.simulationQueue.add(this.output1) - } - - /** - * @memberof OrGate - * function to draw element - */ - customDraw() { - var ctx = simulationArea.context - ctx.strokeStyle = colors['stroke'] - ctx.lineWidth = correctWidth(3) - - const xx = this.x - const yy = this.y - ctx.beginPath() - ctx.fillStyle = colors['fill'] - - moveTo(ctx, -10, -20, xx, yy, this.direction, true) - bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction) - bezierCurveTo( - 0 + 15, - 0 + 10, - 0, - 0 + 20, - -10, - +20, - xx, - yy, - this.direction - ) - bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - ctx.closePath() - if ( - (this.hover && !simulationArea.shiftDown) || - simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) - ) - ctx.fillStyle = colors['hover_select'] - ctx.fill() - ctx.stroke() - } - - generateVerilog() { - return gateGenerateVerilog.call(this, '|') - } -} - -/** - * @memberof OrGate - * Help Tip - * @type {string} - * @category modules - */ -OrGate.prototype.tooltipText = - 'Or Gate Tooltip : Implements logical disjunction' - -/** - * @memberof OrGate - * function to change input nodes of the element - * @category modules - */ -OrGate.prototype.changeInputSize = changeInputSize - -/** - * @memberof SevenSegDisplay - * @type {boolean} - * @category modules - */ -OrGate.prototype.alwaysResolve = true - -/** - * @memberof SevenSegDisplay - * @type {string} - * @category modules - */ -OrGate.prototype.verilogType = 'or' -OrGate.prototype.helplink = 'https://docs.circuitverse.org/#/chapter4/4gates?id=or-gate' -OrGate.prototype.objectType = 'OrGate' diff --git a/v1/src/simulator/src/modules/OrGate.ts b/v1/src/simulator/src/modules/OrGate.ts new file mode 100644 index 00000000..897cc229 --- /dev/null +++ b/v1/src/simulator/src/modules/OrGate.ts @@ -0,0 +1,133 @@ +import CircuitElement from '../circuitElement'; +import Node, { findNode } from '../node'; +import { simulationArea } from '../simulationArea'; +import { correctWidth, bezierCurveTo, moveTo } from '../canvasApi'; +import { changeInputSize } from '../modules'; +import { gateGenerateVerilog } from '../utils'; + +import { colors } from '../themer/themer'; + +export default class OrGate extends CircuitElement { + private inp: Node[]; + private inputSize: number; + private output1: Node; + + constructor( + x: number, + y: number, + scope: any = globalScope, + dir: string = 'RIGHT', + inputs: number = 2, + bitWidth: number = 1 + ) { + super(x, y, scope, dir, bitWidth); + this.rectangleObject = false; + this.setDimensions(15, 20); + this.inp = []; + this.inputSize = inputs; + if (inputs % 2 === 1) { + for (let i = Math.floor(inputs / 2) - 1; i >= 0; i--) { + const a = new Node(-10, -10 * (i + 1), 0, this); + this.inp.push(a); + } + let a = new Node(-10, 0, 0, this); + this.inp.push(a); + for (let i = 0; i < Math.floor(inputs / 2); i++) { + a = new Node(-10, 10 * (i + 1), 0, this); + this.inp.push(a); + } + } else { + for (let i = inputs / 2 - 1; i >= 0; i--) { + const a = new Node(-10, -10 * (i + 1), 0, this); + this.inp.push(a); + } + for (let i = 0; i < inputs / 2; i++) { + const a = new Node(-10, 10 * (i + 1), 0, this); + this.inp.push(a); + } + } + this.output1 = new Node(20, 0, 1, this); + } + + // Resolve output values based on inp + resolve() { + let result = this.inp[0].value || 0; + if (this.isResolvable() === false) { + return; + } + for (let i = 1; i < this.inputSize; i++) { + result |= this.inp[i].value || 0; + } + this.output1.value = result >>> 0; + simulationArea.simulationQueue.add(this.output1); + } + + customDraw() { + var ctx = simulationArea.context; + if (ctx) { + ctx.strokeStyle = colors['stroke']; + ctx.lineWidth = correctWidth(3); + + const xx = this.x; + const yy = this.y; + ctx.beginPath(); + ctx.fillStyle = colors['fill']; + + moveTo(ctx, -10, -20, xx, yy, this.direction, true); + bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction); + bezierCurveTo( + 0 + 15, + 0 + 10, + 0, + 0 + 20, + -10, + +20, + xx, + yy, + this.direction + ); + bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction); + ctx.closePath(); + if ( + (this.hover && !simulationArea.shiftDown) || + simulationArea.lastSelected === this || + simulationArea.multipleObjectSelections.includes(this) + ) { + ctx.fillStyle = colors['hover_select']; + } + ctx.fill(); + ctx.stroke(); + } + } + + customSave(): object { + const data = { + constructorParamaters: [ + this.direction, + this.inputSize, + this.bitWidth, + ], + nodes: { + inp: this.inp.map(findNode), + output1: findNode(this.output1), + }, + }; + return data; + } + + generateVerilog(): string { + return gateGenerateVerilog.call(this, '|'); + } +} + +OrGate.prototype.tooltipText = + 'Or Gate ToolTip : Implements logical disjunction'; + +OrGate.prototype.changeInputSize = changeInputSize; + +OrGate.prototype.alwaysResolve = true; + +OrGate.prototype.verilogType = 'or'; +OrGate.prototype.helplink = + 'https://docs.circuitverse.org/#/chapter4/4gates?id=or-gate'; +OrGate.prototype.objectType = 'OrGate'; \ No newline at end of file diff --git a/v1/src/simulator/src/modules/Output.js b/v1/src/simulator/src/modules/Output.js index 23ef3975..b4442664 100644 --- a/v1/src/simulator/src/modules/Output.js +++ b/v1/src/simulator/src/modules/Output.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText, rect2, oppositeDirection } from '../canvasApi' import { getNextPosition } from '../modules' import { generateId } from '../utils' @@ -40,9 +40,6 @@ export default class Output extends CircuitElement { ) { // Calling base class constructor super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Output'].push(this); - */ if (layoutProperties) { this.layoutProperties = layoutProperties } else { @@ -59,15 +56,6 @@ export default class Output extends CircuitElement { this.inp1 = new Node(this.bitWidth * 10, 0, 0, this) } - /** - * @memberof Output - * function to generate verilog for output - * @return {string} - */ - generateVerilog() { - return `assign ${this.label} = ${this.inp1.verilogLabel};` - } - /** * @memberof Output * fn to create save Json Data of object @@ -140,7 +128,7 @@ export default class Output extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } @@ -186,6 +174,11 @@ export default class Output extends CircuitElement { this.labelDirection = oppositeDirection[this.direction] } + /** + * @memberof Output + * function to generate verilog for output + * @return {string} + */ generateVerilog() { return ( 'assign ' + this.verilogLabel + ' = ' + this.inp1.verilogLabel + ';' diff --git a/v1/src/simulator/src/modules/Power.js b/v1/src/simulator/src/modules/Power.js index 87c419a5..f1efe4a0 100644 --- a/v1/src/simulator/src/modules/Power.js +++ b/v1/src/simulator/src/modules/Power.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * Power @@ -18,9 +17,6 @@ import { colors } from '../themer/themer' export default class Power extends CircuitElement { constructor(x, y, scope = globalScope, bitWidth = 1) { super(x, y, scope, 'RIGHT', bitWidth) - /* this is done in this.baseSetup() now - this.scope['Power'].push(this); - */ this.directionFixed = true this.rectangleObject = false this.setDimensions(10, 10) @@ -72,7 +68,7 @@ export default class Power extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/PriorityEncoder.js b/v1/src/simulator/src/modules/PriorityEncoder.js index b74d7f90..0eea9e7e 100644 --- a/v1/src/simulator/src/modules/PriorityEncoder.js +++ b/v1/src/simulator/src/modules/PriorityEncoder.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode, dec2bin } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class PriorityEncoder extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['PriorityEncoder'].push(this); - */ this.bitWidth = bitWidth || parseInt(prompt('Enter bitWidth'), 10) this.inputSize = 1 << this.bitWidth @@ -29,7 +26,8 @@ export default class PriorityEncoder extends CircuitElement { this.yOff = 2 } - this.setDimensions(20, this.yOff * 5 * this.inputSize) + this.setDimensions(20, this.yOff * 5 * this.inputSize + 10); + this.rightDimensionX += 10; this.directionFixed = true this.rectangleObject = false @@ -182,7 +180,7 @@ export default class PriorityEncoder extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/RGBLed.js b/v1/src/simulator/src/modules/RGBLed.js index a1bcc659..799979f2 100644 --- a/v1/src/simulator/src/modules/RGBLed.js +++ b/v1/src/simulator/src/modules/RGBLed.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, arc, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * RGBLed @@ -18,12 +17,10 @@ export default class RGBLed extends CircuitElement { constructor(x, y, scope = globalScope) { // Calling base class constructor super(x, y, scope, 'UP', 8) - /* this is done in this.baseSetup() now - this.scope['RGBLed'].push(this); - */ this.rectangleObject = false this.inp = [] this.setDimensions(10, 10) + this.downDimensionY = 40; this.inp1 = new Node(-40, -10, 0, this, 8) this.inp2 = new Node(-40, 0, 0, this, 8) this.inp3 = new Node(-40, 10, 0, this, 8) @@ -89,7 +86,6 @@ export default class RGBLed extends CircuitElement { `rgba(${a}, ${b}, ${c}, 0.8)`, 'rgba(227, 228, 229, 0.8)', ][(a === undefined || b === undefined || c === undefined) + 0] - // ctx.fillStyle = ["rgba(200, 200, 200, 0.3)","rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined) || (a === 0 && b === 0 && c === 0)) + 0]; ctx.lineWidth = correctWidth(1) ctx.beginPath() @@ -115,7 +111,7 @@ export default class RGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -145,7 +141,7 @@ export default class RGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v1/src/simulator/src/modules/RGBLedMatrix.js b/v1/src/simulator/src/modules/RGBLedMatrix.js index 00fe1757..4825b0f6 100644 --- a/v1/src/simulator/src/modules/RGBLedMatrix.js +++ b/v1/src/simulator/src/modules/RGBLedMatrix.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, rotate, lineTo, moveTo } from '../canvasApi' /** @@ -28,9 +28,6 @@ export default class RGBLedMatrix extends CircuitElement { } = {} ) { super(x, y, scope, 'RIGHT', 8) - /* this is done in this.baseSetup() now - this.scope['RGBLedMatrix'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.rectangleObject = true diff --git a/v1/src/simulator/src/modules/Random.js b/v1/src/simulator/src/modules/Random.js index 01c9427b..fbfa2084 100644 --- a/v1/src/simulator/src/modules/Random.js +++ b/v1/src/simulator/src/modules/Random.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText, lineTo, moveTo, correctWidth, rect2 } from '../canvasApi' /** * @class @@ -131,7 +131,7 @@ export default class Random extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v1/src/simulator/src/modules/Rectangle.js b/v1/src/simulator/src/modules/Rectangle.js index 09bf240f..4fa2c461 100644 --- a/v1/src/simulator/src/modules/Rectangle.js +++ b/v1/src/simulator/src/modules/Rectangle.js @@ -1,6 +1,5 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect } from '../canvasApi' /** * @class @@ -16,9 +15,6 @@ import { correctWidth, rect } from '../canvasApi' export default class Rectangle extends CircuitElement { constructor(x, y, scope = globalScope, rows = 15, cols = 20) { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['Rectangle'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.rectangleObject = false @@ -100,7 +96,7 @@ export default class Rectangle extends CircuitElement { if ( simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.1)' ctx.fill() diff --git a/v1/src/simulator/src/modules/SevenSegDisplay.js b/v1/src/simulator/src/modules/SevenSegDisplay.js index eedd26f0..9c79ace5 100644 --- a/v1/src/simulator/src/modules/SevenSegDisplay.js +++ b/v1/src/simulator/src/modules/SevenSegDisplay.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { colorToRGBA, correctWidth, @@ -23,9 +23,6 @@ import { export default class SevenSegDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['SevenSegDisplay'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.setDimensions(30, 50) @@ -266,7 +263,7 @@ export default class SevenSegDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v1/src/simulator/src/modules/SixteenSegDisplay.js b/v1/src/simulator/src/modules/SixteenSegDisplay.js index 944ba443..9a15575a 100644 --- a/v1/src/simulator/src/modules/SixteenSegDisplay.js +++ b/v1/src/simulator/src/modules/SixteenSegDisplay.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { colorToRGBA, correctWidth, @@ -10,7 +10,6 @@ import { rect2, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * SixteenSegDisplay @@ -23,9 +22,6 @@ import { changeInputSize } from '../modules' export default class SixteenSegDisplay extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { super(x, y, scope, 'RIGHT', 16) - /* this is done in this.baseSetup() now - this.scope['SixteenSegDisplay'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.setDimensions(30, 50) @@ -435,7 +431,7 @@ export default class SixteenSegDisplay extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32,0.6)' ctx.fill() diff --git a/v1/src/simulator/src/modules/Splitter.js b/v1/src/simulator/src/modules/Splitter.js index ffcb296c..1cf3f006 100644 --- a/v1/src/simulator/src/modules/Splitter.js +++ b/v1/src/simulator/src/modules/Splitter.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText2 } from '../canvasApi' import { colors } from '../themer/themer' @@ -30,9 +30,6 @@ export default class Splitter extends CircuitElement { bitWidthSplit = undefined ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Splitter'].push(this); - */ this.rectangleObject = false this.bitWidthSplit = @@ -169,8 +166,6 @@ export default class Splitter extends CircuitElement { this.inp1.value = n >>> 0 simulationArea.simulationQueue.add(this.inp1) } - // else if (this.inp1.value !== n) { - // } } this.prevInpValue = this.inp1.value } @@ -183,57 +178,16 @@ export default class Splitter extends CircuitElement { this.prevInpValue = undefined } - /** - * @memberof Splitter - * fn to process verilog of the element - * @return {JSON} - */ - processVerilog() { - if ( - this.inp1.verilogLabel !== '' && - this.outputs[0].verilogLabel === '' - ) { - let bitCount = 0 - for (let i = 0; i < this.splitCount; i++) { - // let bitSplitValue = extractBits(this.inp1.value, bitCount, bitCount + this.bitWidthSplit[i] - 1); - if (this.bitWidthSplit[i] > 1) { - const label = `${this.inp1.verilogLabel}[ ${ - bitCount + this.bitWidthSplit[i] - 1 - }:${bitCount}]` - } else { - const label = `${this.inp1.verilogLabel}[${bitCount}]` - } - if (this.outputs[i].verilogLabel !== label) { - this.outputs[i].verilogLabel = label - this.scope.stack.push(this.outputs[i]) - } - bitCount += this.bitWidthSplit[i] - } - } else if ( - this.inp1.verilogLabel === '' && - this.outputs[0].verilogLabel !== '' - ) { - const label = `{${this.outputs - .map((x) => x.verilogLabel) - .join(',')}}` - if (this.inp1.verilogLabel !== label) { - this.inp1.verilogLabel = label - this.scope.stack.push(this.inp1) - } - } - } - /** * @memberof Splitter * function to draw element */ customDraw() { var ctx = simulationArea.context - // ctx.strokeStyle = [colors['splitter'], 'brown'][ ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + 0 + simulationArea.multipleObjectSelections.includes(this)) + 0 ] ctx.lineWidth = correctWidth(3) const xx = this.x @@ -280,13 +234,18 @@ export default class Splitter extends CircuitElement { ctx.fill() } + /** + * @memberof Splitter + * fn to process verilog of the element + * @return {JSON} + */ processVerilog() { // Combiner if (this.inp1.verilogLabel == '') { this.isSplitter = false this.inp1.verilogLabel = this.verilogLabel + '_cmb' if ( - !this.scope.verilogWireList[this.bitWidth].contains( + !this.scope.verilogWireList[this.bitWidth].includes( this.inp1.verilogLabel ) ) diff --git a/v1/src/simulator/src/modules/SquareRGBLed.js b/v1/src/simulator/src/modules/SquareRGBLed.js index b93e0bb6..c9bb5295 100644 --- a/v1/src/simulator/src/modules/SquareRGBLed.js +++ b/v1/src/simulator/src/modules/SquareRGBLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, rect2 } from '../canvasApi' /** @@ -17,9 +17,6 @@ import { correctWidth, lineTo, moveTo, rect2 } from '../canvasApi' export default class SquareRGBLed extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'UP', pinLength = 1) { super(x, y, scope, dir, 8) - /* this is done in this.baseSetup() now - this.scope['SquareRGBLed'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) this.pinLength = pinLength === undefined ? 1 : pinLength @@ -146,7 +143,7 @@ export default class SquareRGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32)' } @@ -175,7 +172,7 @@ export default class SquareRGBLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = 'rgba(255, 255, 32)' } diff --git a/v1/src/simulator/src/modules/Stepper.js b/v1/src/simulator/src/modules/Stepper.js index c6cfbd3f..7b0b0cb1 100644 --- a/v1/src/simulator/src/modules/Stepper.js +++ b/v1/src/simulator/src/modules/Stepper.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * Stepper @@ -19,11 +18,7 @@ import { colors } from '../themer/themer' export default class Stepper extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 8) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Stepper'].push(this); - */ this.setDimensions(20, 20) - this.output1 = new Node(20, 0, 1, this, bitWidth) this.state = 0 } diff --git a/v1/src/simulator/src/modules/Text.js b/v1/src/simulator/src/modules/Text.js index 7248c575..3713edbc 100644 --- a/v1/src/simulator/src/modules/Text.js +++ b/v1/src/simulator/src/modules/Text.js @@ -1,6 +1,5 @@ import CircuitElement from '../circuitElement' -import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { rect2, fillText } from '../canvasApi' /** * @class @@ -19,10 +18,6 @@ import { copy, paste } from '../events' export default class Text extends CircuitElement { constructor(x, y, scope = globalScope, label = '', fontSize = 14) { super(x, y, scope, 'RIGHT', 1) - /* this is done in this.baseSetup() now - this.scope['Text'].push(this); - */ - // this.setDimensions(15, 15); this.fixedBitWidth = true this.directionFixed = true this.labelDirectionFixed = true @@ -130,7 +125,7 @@ export default class Text extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.beginPath() ctx.fillStyle = colors['fill'] diff --git a/v1/src/simulator/src/modules/TriState.js b/v1/src/simulator/src/modules/TriState.js index e4048fc9..b408a0d9 100644 --- a/v1/src/simulator/src/modules/TriState.js +++ b/v1/src/simulator/src/modules/TriState.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, lineTo, moveTo, arc } from '../canvasApi' -import { changeInputSize } from '../modules' +import { simulationArea } from '../simulationArea' +import { correctWidth, lineTo, moveTo } from '../canvasApi' /** * @class * TriState @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class TriState extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['TriState'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) @@ -29,9 +25,6 @@ export default class TriState extends CircuitElement { this.output1 = new Node(20, 0, 1, this) this.state = new Node(0, 0, 0, this, 1, 'Enable') } - - // TriState.prototype.propagationDelay=10000; - /** * @memberof TriState * fn to create save Json Data of object @@ -74,15 +67,14 @@ export default class TriState extends CircuitElement { this.output1.value = this.inp1.value // >>>0)<<(32-this.bitWidth))>>>(32-this.bitWidth); simulationArea.simulationQueue.add(this.output1) } - simulationArea.contentionPending.clean(this) } else if ( this.output1.value !== undefined && - !simulationArea.contentionPending.contains(this) + !simulationArea.contentionPending.has(this.output1) ) { this.output1.value = undefined simulationArea.simulationQueue.add(this.output1) } - simulationArea.contentionPending.clean(this) + simulationArea.contentionPending.removeAllContentionsForNode(this.output1); } /** @@ -104,7 +96,7 @@ export default class TriState extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/Tunnel.js b/v1/src/simulator/src/modules/Tunnel.js index 7e3f96c5..d8acab0a 100644 --- a/v1/src/simulator/src/modules/Tunnel.js +++ b/v1/src/simulator/src/modules/Tunnel.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText } from '../canvasApi' import plotArea from '../plotArea' import { showError } from '../utils' @@ -28,9 +28,6 @@ export default class Tunnel extends CircuitElement { identifier ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['Tunnel'].push(this); - */ this.rectangleObject = false this.centerElement = true this.xSize = 10 @@ -77,8 +74,6 @@ export default class Tunnel extends CircuitElement { this.upDimensionY = Math.abs(-20 + yRotate) this.rightDimensionX = Math.abs(xRotate) this.downDimensionY = Math.abs(20 + yRotate) - - // rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT"); } /** @@ -174,13 +169,18 @@ export default class Tunnel extends CircuitElement { * @param {string=} id - id so that every link is unique */ setIdentifier(id = '') { - if (id.length === 0) return - if (this.scope.tunnelList[this.identifier]) - this.scope.tunnelList[this.identifier].clean(this) + if (id.length === 0) { + return + } + if (this.scope.tunnelList[this.identifier]) { + this.scope.tunnelList[this.identifier] = this.scope.tunnelList[this.identifier].filter(x=> x !== this); + } this.identifier = id - if (this.scope.tunnelList[this.identifier]) + if (this.scope.tunnelList[this.identifier]) { this.scope.tunnelList[this.identifier].push(this) - else this.scope.tunnelList[this.identifier] = [this] + } else { + this.scope.tunnelList[this.identifier] = [this] + } // Change the bitwidth to be same as the other elements with this.identifier if ( @@ -203,8 +203,8 @@ export default class Tunnel extends CircuitElement { * delete the tunnel element */ delete() { - this.scope.Tunnel.clean(this) - this.scope.tunnelList[this.identifier].clean(this) + this.scope.Tunnel = this.scope.Tunnel.filter(x => x !== this); + this.scope.tunnelList[this.identifier] = this.scope.tunnelList[this.identifier].filter(x=> x !== this); super.delete() } @@ -250,7 +250,7 @@ export default class Tunnel extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.fillStyle = colors['hover_select'] } diff --git a/v1/src/simulator/src/modules/TwoComplement.js b/v1/src/simulator/src/modules/TwoComplement.js index ace62ec7..88b35979 100644 --- a/v1/src/simulator/src/modules/TwoComplement.js +++ b/v1/src/simulator/src/modules/TwoComplement.js @@ -1,8 +1,7 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText, drawCircle2 } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * TwoComplement @@ -19,9 +18,6 @@ import { colors } from '../themer/themer' export default class TwoComplement extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['TwoComplement'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 15) this.inp1 = new Node(-10, 0, 0, this, this.bitWidth, 'input stream') @@ -77,7 +73,7 @@ export default class TwoComplement extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -98,5 +94,5 @@ export default class TwoComplement extends CircuitElement { * @category modules */ TwoComplement.prototype.tooltipText = - "Two's Complement Tooltip : Calculates the two's complement" + "Two's Complement ToolTip : Calculates the two's complement" TwoComplement.prototype.objectType = 'TwoComplement' diff --git a/v1/src/simulator/src/modules/VariableLed.js b/v1/src/simulator/src/modules/VariableLed.js index a32cb5aa..bd9c5bef 100644 --- a/v1/src/simulator/src/modules/VariableLed.js +++ b/v1/src/simulator/src/modules/VariableLed.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, @@ -10,7 +10,6 @@ import { colorToRGBA, validColor, } from '../canvasApi' -import { changeInputSize } from '../modules' /** * @class * VariableLed @@ -24,14 +23,10 @@ import { colors } from '../themer/themer' export default class VariableLed extends CircuitElement { constructor(x, y, scope = globalScope, color = 'Red') { - // Calling base class constructor - super(x, y, scope, 'UP', 8) - /* this is done in this.baseSetup() now - this.scope['VariableLed'].push(this); - */ this.rectangleObject = false this.setDimensions(10, 20) + this.downDimensionY = 40; this.inp1 = new Node(-40, 0, 0, this, 8) this.directionFixed = true this.fixedBitWidth = true @@ -120,16 +115,12 @@ export default class VariableLed extends CircuitElement { lineTo(ctx, 0, -9, xx, yy, this.direction) arc(ctx, 0, 0, 9, -Math.PI / 2, Math.PI / 2, xx, yy, this.direction) lineTo(ctx, -20, 9, xx, yy, this.direction) - /* lineTo(ctx,-18,12,xx,yy,this.direction); - arc(ctx,0,0,Math.sqrt(468),((Math.PI/2) + Math.acos(12/Math.sqrt(468))),((-Math.PI/2) - Math.asin(18/Math.sqrt(468))),xx,yy,this.direction); - - */ lineTo(ctx, -20, -9, xx, yy, this.direction) ctx.stroke() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -157,7 +148,7 @@ export default class VariableLed extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = 'rgba(255, 255, 32,0.8)' ctx.fill() diff --git a/v1/src/simulator/src/modules/XnorGate.js b/v1/src/simulator/src/modules/XnorGate.js index dd93e734..0a95867e 100644 --- a/v1/src/simulator/src/modules/XnorGate.js +++ b/v1/src/simulator/src/modules/XnorGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, bezierCurveTo, @@ -35,9 +35,6 @@ export default class XnorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['XnorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -132,12 +129,11 @@ export default class XnorGate extends CircuitElement { this.direction ) bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction); ctx.closePath() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/modules/XorGate.js b/v1/src/simulator/src/modules/XorGate.js index 74c5b0d8..067afd05 100644 --- a/v1/src/simulator/src/modules/XorGate.js +++ b/v1/src/simulator/src/modules/XorGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, bezierCurveTo, moveTo, arc2 } from '../canvasApi' import { changeInputSize } from '../modules' import { gateGenerateVerilog } from '../utils' @@ -29,9 +29,6 @@ export default class XorGate extends CircuitElement { bitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['XorGate'].push(this); - */ this.rectangleObject = false this.setDimensions(15, 20) @@ -125,12 +122,11 @@ export default class XorGate extends CircuitElement { this.direction ) bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction) - // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction); ctx.closePath() if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] ctx.fill() @@ -161,7 +157,7 @@ export default class XorGate extends CircuitElement { * @type {string} * @category modules */ -XorGate.prototype.tooltipText = 'Xor Gate Tooltip : Implements an exclusive OR.' +XorGate.prototype.tooltipText = 'Xor Gate ToolTip : Implements an exclusive OR.' /** * @memberof XorGate diff --git a/v1/src/simulator/src/modules/verilogDivider.js b/v1/src/simulator/src/modules/verilogDivider.js index cd6acaf5..c3421cc8 100644 --- a/v1/src/simulator/src/modules/verilogDivider.js +++ b/v1/src/simulator/src/modules/verilogDivider.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogDivider extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogDivider'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v1/src/simulator/src/modules/verilogMultiplier.js b/v1/src/simulator/src/modules/verilogMultiplier.js index d428c036..2e3a41db 100644 --- a/v1/src/simulator/src/modules/verilogMultiplier.js +++ b/v1/src/simulator/src/modules/verilogMultiplier.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogMultiplier extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogMultiplier'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v1/src/simulator/src/modules/verilogPower.js b/v1/src/simulator/src/modules/verilogPower.js index ded6fdc1..10f764fa 100644 --- a/v1/src/simulator/src/modules/verilogPower.js +++ b/v1/src/simulator/src/modules/verilogPower.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogPower extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogPower'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inpA = new Node(-20, -10, 0, this, this.bitWidth, 'A') diff --git a/v1/src/simulator/src/modules/verilogShiftLeft.js b/v1/src/simulator/src/modules/verilogShiftLeft.js index 65a61a4c..012fa63f 100644 --- a/v1/src/simulator/src/modules/verilogShiftLeft.js +++ b/v1/src/simulator/src/modules/verilogShiftLeft.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogShiftLeft extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogShiftLeft'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input') diff --git a/v1/src/simulator/src/modules/verilogShiftRight.js b/v1/src/simulator/src/modules/verilogShiftRight.js index a37332fb..5aad5c23 100644 --- a/v1/src/simulator/src/modules/verilogShiftRight.js +++ b/v1/src/simulator/src/modules/verilogShiftRight.js @@ -1,7 +1,7 @@ /* eslint-disable no-bitwise */ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' /** * @class @@ -24,9 +24,6 @@ export default class verilogShiftRight extends CircuitElement { outputBitWidth = 1 ) { super(x, y, scope, dir, bitWidth) - /* this is done in this.baseSetup() now - this.scope['verilogShiftRight'].push(this); - */ this.setDimensions(20, 20) this.outputBitWidth = outputBitWidth this.inp1 = new Node(-20, -10, 0, this, this.bitWidth, 'Input') diff --git a/v1/src/simulator/src/node.js b/v1/src/simulator/src/node.js index 696a664b..c81f781a 100644 --- a/v1/src/simulator/src/node.js +++ b/v1/src/simulator/src/node.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-cycle */ import { drawCircle, drawLine, arc } from './canvasApi' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { distance, showError } from './utils' import { renderCanvas, @@ -12,8 +12,8 @@ import { canvasMessageData, } from './engine' import Wire from './wire' -// import { colors } from './themer/themer'; import { colors } from './themer/themer' +import ContentionMeta from './contention' /** * Constructs all the connections of Node node @@ -24,7 +24,7 @@ import { colors } from './themer/themer' export function constructNodeConnections(node, data) { for (var i = 0; i < data.connections.length; i++) { if ( - !node.connections.contains(node.scope.allNodes[data.connections[i]]) + !node.connections.includes(node.scope.allNodes[data.connections[i]]) ) node.connect(node.scope.allNodes[data.connections[i]]) } @@ -42,12 +42,13 @@ export function replace(node, index) { } var { scope } = node var { parent } = node - parent.nodeList.clean(node) + parent.nodeList = parent.nodeList.filter(x=> x !== node); node.delete() node = scope.allNodes[index] node.parent = parent parent.nodeList.push(node) node.updateRotation() + node.scope.timeStamp = new Date().getTime() return node } function rotate(x1, y1, dir) { @@ -162,7 +163,7 @@ export default class Node { this.id = `node${uniqueIdCounter}` uniqueIdCounter++ this.parent = parent - if (type != 2 && this.parent.nodeList !== undefined) { + if (type != NODE_INTERMEDIATE && this.parent.nodeList !== undefined) { this.parent.nodeList.push(this) } @@ -187,6 +188,7 @@ export default class Node { this.hover = false this.wasClicked = false this.scope = this.parent.scope + this.scope.timeStamp = new Date().getTime() /** * @type {string} * value of this.prev is @@ -201,7 +203,7 @@ export default class Node { // This fn is called during rotations and setup this.refresh() - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { this.parent.scope.nodes.push(this) } @@ -226,7 +228,7 @@ export default class Node { * function to convert a node to intermediate node */ converToIntermediate() { - this.type = 2 + this.type = NODE_INTERMEDIATE this.x = this.absX() this.y = this.absY() this.parent = this.scope.root @@ -250,10 +252,10 @@ export default class Node { } /** - * Funciton for saving a node + * function for saving a node */ saveObject() { - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { this.leftx = this.x this.lefty = this.y } @@ -288,8 +290,9 @@ export default class Node { refresh() { this.updateRotation() for (var i = 0; i < this.connections.length; i++) { - this.connections[i].connections.clean(this) + this.connections[i].connections = this.connections[i].connections.filter(x => x !== this) } + this.scope.timeStamp = new Date().getTime() this.connections = [] } @@ -312,7 +315,7 @@ export default class Node { */ updateScope(scope) { this.scope = scope - if (this.type == 2) this.parent = scope.root + if (this.type == NODE_INTERMEDIATE) this.parent = scope.root } /** @@ -335,11 +338,15 @@ export default class Node { */ connect(n) { if (n == this) return - if (n.connections.contains(this)) return - var w = new Wire(this, n, this.parent.scope) + if (n.connections.includes(this)) { + return + } + new Wire(this, n, this.parent.scope) this.connections.push(n) n.connections.push(this) + this.scope.timeStamp = new Date().getTime() + updateCanvasSet(true) updateSimulationSet(true) scheduleUpdate() @@ -350,11 +357,13 @@ export default class Node { */ connectWireLess(n) { if (n == this) return - if (n.connections.contains(this)) return + if (n.connections.includes(this)) return this.connections.push(n) n.connections.push(this) - updateCanvasSet(true) + this.scope.timeStamp = new Date().getTime() + + // updateCanvasSet(true) updateSimulationSet(true) scheduleUpdate() } @@ -363,14 +372,22 @@ export default class Node { * disconnecting two nodes connected wirelessly */ disconnectWireLess(n) { - this.connections.clean(n) - n.connections.clean(this) + this.connections = this.connections.filter(x => x !== n) + n.connections = n.connections.filter(x => x !== this) + + this.scope.timeStamp = new Date().getTime() } /** * function to resolve a node */ resolve() { + if (this.type == NODE_OUTPUT) { + // Since output node forces its value on its neighbours, remove its contentions. + // An existing contention will now trickle to the other output node that was causing + // the contention. + simulationArea.contentionPending.removeAllContentionsForNode(this); + } // Remove Propogation of values (TriState) if (this.value == undefined) { for (var i = 0; i < this.connections.length; i++) { @@ -395,7 +412,7 @@ export default class Node { this.parent.isResolvable() && !this.parent.queueProperties.inQueue ) { - if (this.parent.objectType == 'TriState') { + if (this.parent.objectType == 'TriState' || this.parent.objectType == 'ControlledInverter') { if (this.parent.state.value) { simulationArea.simulationQueue.add(this.parent) } @@ -408,52 +425,69 @@ export default class Node { return } - if (this.type == 0) { + // For input nodes, resolve its parents if they are resolvable at this point. + if (this.type == NODE_INPUT) { if (this.parent.isResolvable()) { simulationArea.simulationQueue.add(this.parent) } } + else if (this.type == NODE_OUTPUT) { + // Since output node forces its value on its neighbours, remove its contentions. + // An existing contention will now trickle to the other output node that was causing + // the contention. + simulationArea.contentionPending.removeAllContentionsForNode(this); + } for (var i = 0; i < this.connections.length; i++) { - const node = this.connections[i] - - if (node.value != this.value || node.bitWidth != this.bitWidth) { - if ( - node.type == 1 && - node.value != undefined && - node.parent.objectType != 'TriState' && - !(node.subcircuitOverride && node.scope != this.scope) && // Subcircuit Input Node Output Override - node.parent.objectType != 'SubCircuit' - ) { - // Subcircuit Output Node Override - this.highlighted = true - node.highlighted = true - var circuitName = node.scope.name - var circuitElementName = node.parent.objectType - showError( - `Contention Error: ${this.value} and ${node.value} at ${circuitElementName} in ${circuitName}` - ) - } else if (node.bitWidth == this.bitWidth || node.type == 2) { - if ( - node.parent.objectType == 'TriState' && - node.value != undefined && - node.type == 1 - ) { - if (node.parent.state.value) { - simulationArea.contentionPending.push(node.parent) + const node = this.connections[i]; + + switch (node.type) { + // TODO: For an output node, a downstream value (value given by elements other than the parent) + // should be overwritten in contention check and should not cause contention. + case NODE_OUTPUT: + if (node.value != this.value || node.bitWidth != this.bitWidth) { + // Check contentions + if (node.value != undefined && node.parent.objectType != 'SubCircuit' + && !(node.subcircuitOverride && node.scope != this.scope)) { + // Tristate has always been a pain in the ass. + if ((node.parent.objectType == 'TriState' || node.parent.objectType == 'ControlledInverter') && node.value != undefined) { + if (node.parent.state.value) { + simulationArea.contentionPending.add(node, this); + break; + } + } + else { + simulationArea.contentionPending.add(node, this); + break; } } - - node.bitWidth = this.bitWidth - node.value = this.value - simulationArea.simulationQueue.add(node) } else { - this.highlighted = true - node.highlighted = true - showError( - `BitWidth Error: ${this.bitWidth} and ${node.bitWidth}` - ) + // Output node was given an agreeing value, so remove any contention + // entry between these two nodes if it exists. + simulationArea.contentionPending.remove(node, this); + } + + // Fallthrough. NODE_OUTPUT propagates like a contention checked NODE_INPUT + case NODE_INPUT: + // Check bitwidths + if (this.bitWidth != node.bitWidth) { + this.highlighted = true; + node.highlighted = true; + showError(`BitWidth Error: ${this.bitWidth} and ${node.bitWidth}`); + break; } + + // Fallthrough. NODE_INPUT propagates like a bitwidth checked NODE_INTERMEDIATE + case NODE_INTERMEDIATE: + + if (node.value != this.value || node.bitWidth != this.bitWidth) { + // Propagate + node.bitWidth = this.bitWidth; + node.value = this.value; + simulationArea.simulationQueue.add(node); + } + default: + break; } } } @@ -563,8 +597,8 @@ export default class Node { if (this.bitWidth == 1) colorNode = [colorNodeConnect, colorNodePow][this.value] if (this.value == undefined) colorNode = colorNodeLose - if (this.type == 2) this.checkHover() - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) this.checkHover() + if (this.type == NODE_INTERMEDIATE) { drawCircle(ctx, this.absX(), this.absY(), 3, colorNode) } else { drawCircle(ctx, this.absX(), this.absY(), 3, colorNodeSelected) @@ -576,7 +610,7 @@ export default class Node { (this.isHover() && !simulationArea.selected && !simulationArea.shiftDown) || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { ctx.strokeStyle = colorNodeSelected ctx.beginPath() @@ -600,7 +634,7 @@ export default class Node { if (this.showHover || simulationArea.lastSelected == this) { canvasMessageData.x = this.absX() canvasMessageData.y = this.absY() - 15 - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { var v = 'X' if (this.value !== undefined) { v = this.value.toString(16) @@ -629,7 +663,7 @@ export default class Node { */ checkDeleted() { if (this.deleted) this.delete() - if (this.connections.length == 0 && this.type == 2) this.delete() + if (this.connections.length == 0 && this.type == NODE_INTERMEDIATE) this.delete() } /** @@ -670,10 +704,10 @@ export default class Node { if (!this.wasClicked && this.clicked) { this.wasClicked = true this.prev = 'a' - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( var i = 0; @@ -689,9 +723,9 @@ export default class Node { if (simulationArea.shiftDown) { simulationArea.lastSelected = undefined if ( - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { - simulationArea.multipleObjectSelections.clean(this) + simulationArea.multipleObjectSelections = simulationArea.multipleObjectSelections.filter(x=> x !== this); } else { simulationArea.multipleObjectSelections.push(this) } @@ -702,7 +736,7 @@ export default class Node { } else if (this.wasClicked && this.clicked) { if ( !simulationArea.shiftDown && - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) { for ( var i = 0; @@ -712,7 +746,7 @@ export default class Node { simulationArea.multipleObjectSelections[i].drag() } } - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { if ( this.connections.length == 1 && this.connections[0].absX() == simulationArea.mouseX && @@ -881,7 +915,7 @@ export default class Node { simulationArea.lastSelected = n2 } - if (this.type == 2 && simulationArea.mouseDown == false) { + if (this.type == NODE_INTERMEDIATE && simulationArea.mouseDown == false) { if (this.connections.length == 2) { if ( this.connections[0].absX() == this.connections[1].absX() || @@ -900,17 +934,20 @@ export default class Node { delete() { updateSimulationSet(true) this.deleted = true - this.parent.scope.allNodes.clean(this) - this.parent.scope.nodes.clean(this) + this.parent.scope.allNodes = this.parent.scope.allNodes.filter(x => x !== this) + this.parent.scope.nodes = this.parent.scope.nodes.filter(x => x !== this) - this.parent.scope.root.nodeList.clean(this) // Hope this works! - Can cause bugs + this.parent.scope.root.nodeList = this.parent.scope.root.nodeList.filter(x => x !== this) // Hope this works! - Can cause bugs if (simulationArea.lastSelected == this) simulationArea.lastSelected = undefined for (var i = 0; i < this.connections.length; i++) { - this.connections[i].connections.clean(this) + this.connections[i].connections = this.connections[i].connections.filter(x => x !== this) this.connections[i].checkDeleted() } + + this.scope.timeStamp = new Date().getTime() + wireToBeCheckedSet(1) forceResetNodesSet(true) scheduleUpdate() @@ -947,7 +984,7 @@ export default class Node { y == this.parent.scope.allNodes[i].absY() ) { n = this.parent.scope.allNodes[i] - if (this.type == 2) { + if (this.type == NODE_INTERMEDIATE) { for (var j = 0; j < this.connections.length; j++) { n.connect(this.connections[j]) } @@ -964,7 +1001,7 @@ export default class Node { for (var i = 0; i < this.parent.scope.wires.length; i++) { if (this.parent.scope.wires[i].checkConvergence(this)) { var n = this - if (this.type != 2) { + if (this.type != NODE_INTERMEDIATE) { n = new Node( this.absX(), this.absY(), diff --git a/v1/src/simulator/src/plotArea.js b/v1/src/simulator/src/plotArea.js index 79bf2582..869d27ac 100644 --- a/v1/src/simulator/src/plotArea.js +++ b/v1/src/simulator/src/plotArea.js @@ -1,5 +1,10 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { convertors } from './utils' +import { join, downloadDir } from '@tauri-apps/api/path'; +import { writeFile } from '@tauri-apps/plugin-fs'; +import { isTauri } from '@tauri-apps/api/core' +import { useSimulatorMobileStore } from '#/store/simulatorMobileStore' +import { toRefs } from 'vue' var DPR = window.devicePixelRatio || 1 @@ -106,12 +111,43 @@ const plotArea = { }, // download as image download() { + if(isTauri()){ + this.downloadImageDesktop() + return + } + var img = this.canvas.toDataURL(`image/png`) const anchor = document.createElement('a') anchor.href = img anchor.download = `waveform.png` anchor.click() }, + // download as image for desktop + async downloadImageDesktop() { + try { + const img = this.canvas.toDataURL('image/png'); + + const response = await fetch(img); + const blob = await response.blob(); + + const arrayBuffer = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsArrayBuffer(blob); + }); + + const downloadsDirectory = await downloadDir(); + + const random = Math.random().toString(36).substring(7); + + const path = await join(downloadsDirectory, `waveform-${random}.png`); + + await writeFile({ path, contents: new Uint8Array(arrayBuffer) }); + } catch (error) { + console.error('Error during download:', error); + } + }, // update canvas size to use full screen resize() { var oldHeight = this.height @@ -403,12 +439,16 @@ const plotArea = { }, // Driver function to render and update plot() { + const simulatorMobileStore = useSimulatorMobileStore() + const { showCanvas } = toRefs(simulatorMobileStore) if (embed) return if (globalScope.Flag.length === 0) { this.canvas.width = 0 this.canvas.height = 0 + showCanvas.value = false return } + showCanvas.value = true this.update() this.render() @@ -445,52 +485,6 @@ const timingDiagramButtonActions = { export { timingDiagramButtonActions } export function setupTimingListeners() { - // $('.timing-diagram-smaller').on('click', () => { - // $('#plot').width(Math.max($('#plot').width() - 20, 560)) - // plotArea.resize() - // }) - // $('.timing-diagram-larger').on('click', () => { - // $('#plot').width($('#plot').width() + 20) - // plotArea.resize() - // }) - // $('.timing-diagram-small-height').on('click', () => { - // if (plotHeight >= sh(20)) { - // plotHeight -= sh(5) - // waveFormHeight = plotHeight - 2 * waveFormPadding - // } - // }) - // $('.timing-diagram-large-height').on('click', () => { - // if (plotHeight < sh(50)) { - // plotHeight += sh(5) - // waveFormHeight = plotHeight - 2 * waveFormPadding - // } - // }) - // $('.timing-diagram-reset').on('click', () => { - // plotArea.reset() - // }) - // $('.timing-diagram-calibrate').on('click', () => { - // plotArea.calibrate() - // }) - // $('.timing-diagram-resume').on('click', () => { - // plotArea.resume() - // }) - // $('.timing-diagram-pause').on('click', () => { - // plotArea.pause() - // }) - // $('.timing-diagram-download').on('click', () => { - // plotArea.download() - // }) - // $('.timing-diagram-zoom-in').on('click', () => { - // plotArea.zoomIn() - // }) - // $('.timing-diagram-zoom-out').on('click', () => { - // plotArea.zoomOut() - // }) - // $('#timing-diagram-units').on('change paste keyup', function () { - // var timeUnits = parseInt($(this).val(), 10) - // if (isNaN(timeUnits) || timeUnits < 1) return - // plotArea.cycleUnit = timeUnits - // }) document.getElementById('plotArea').addEventListener('mousedown', (e) => { var rect = plotArea.canvas.getBoundingClientRect() var x = sh(e.clientX - rect.left) diff --git a/v0/src/simulator/src/quinMcCluskey.js b/v1/src/simulator/src/quinMcCluskey.ts similarity index 84% rename from v0/src/simulator/src/quinMcCluskey.js rename to v1/src/simulator/src/quinMcCluskey.ts index f15041db..5983fb47 100644 --- a/v0/src/simulator/src/quinMcCluskey.js +++ b/v1/src/simulator/src/quinMcCluskey.ts @@ -1,11 +1,18 @@ // Algorithm used for Combinational Analysis +type BooleanMinimizeType = { + minTerms: number[] + dontCares: number[] + numVars: number + result: string[] +} + export default function BooleanMinimize( - numVarsArg, - minTermsArg, - dontCaresArg = [] + numVarsArg: number, + minTermsArg: number[], + dontCaresArg: number[] = [] ) { - var __result + var __result: string[] Object.defineProperties(this, { minTerms: { @@ -47,7 +54,7 @@ export default function BooleanMinimize( } BooleanMinimize.prototype.solve = function () { - function dec_to_binary_string(n) { + const dec_to_binary_string = (n: number) => { var str = n.toString(2) while (str.length != this.numVars) { @@ -57,14 +64,14 @@ BooleanMinimize.prototype.solve = function () { return str } - function num_set_bits(s) { + const num_set_bits = (s: string) => { var ans = 0 for (let i = 0; i < s.length; ++i) if (s[i] === '1') ans++ return ans } - function get_prime_implicants(allTerms) { - var table = [] + const get_prime_implicants = (allTerms: string[]) => { + var table: Set[] = [] var primeImplicants = new Set() var reduced @@ -115,11 +122,11 @@ BooleanMinimize.prototype.solve = function () { return primeImplicants } - function get_essential_prime_implicants(primeImplicants, minTerms) { + const get_essential_prime_implicants = (primeImplicants: string[], minTerms: string[]) => { var table = [], column - function check_if_similar(minTerm, primeImplicant) { + const check_if_similar = (minTerm: string, primeImplicant: string) => { for (let i = 0; i < primeImplicant.length; ++i) { if ( primeImplicant[i] !== '-' && @@ -131,7 +138,7 @@ BooleanMinimize.prototype.solve = function () { return true } - function get_complexity(terms) { + const get_complexity = (terms: string[]) => { var complexity = terms.length for (let t of terms) { @@ -146,7 +153,7 @@ BooleanMinimize.prototype.solve = function () { return complexity } - function isSubset(sub, sup) { + const isSubset = (sub: Set, sup: Set) => { for (let i of sub) { if (!sup.has(i)) return false } @@ -166,8 +173,8 @@ BooleanMinimize.prototype.solve = function () { table.push(column) } - var possibleSets = [], - tempSets + let possibleSets: Set[] = [], + tempSets: Set[] for (let i of table[0]) { possibleSets.push(new Set([i])) @@ -216,12 +223,12 @@ BooleanMinimize.prototype.solve = function () { return essentialImplicants } - var minTerms = this.minTerms.map(dec_to_binary_string.bind(this)) - var dontCares = this.dontCares.map(dec_to_binary_string.bind(this)) + var minTerms: string[] = this.minTerms.map(dec_to_binary_string.bind(this)) + var dontCares: string[] = this.dontCares.map(dec_to_binary_string.bind(this)) return get_essential_prime_implicants.call( this, - Array.from(get_prime_implicants.call(this, minTerms.concat(dontCares))), + Array.from(get_prime_implicants.call(this, minTerms.concat(dontCares))) as string[], minTerms ) } diff --git a/v1/src/simulator/src/sequential.js b/v1/src/simulator/src/sequential.js index bd1740de..46dcd693 100644 --- a/v1/src/simulator/src/sequential.js +++ b/v1/src/simulator/src/sequential.js @@ -1,5 +1,5 @@ import { scheduleUpdate, play, updateCanvasSet } from './engine' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' /** * a global function as a helper for simulationArea.changeClockEnable @@ -8,18 +8,3 @@ import simulationArea from './simulationArea' export function changeClockEnable(val) { simulationArea.clockEnabled = val } - -/** - * WIP function defined and used - * @param {number} n - * @category sequential - */ -export function runTest(n = 10) { - var t = new Date().getTime() - for (var i = 0; i < n; i++) { - clockTick() - } - updateCanvasSet(true) - play() - scheduleUpdate() -} diff --git a/v1/src/simulator/src/sequential/Clock.js b/v1/src/simulator/src/sequential/Clock.js index 86e24955..fcfac673 100644 --- a/v1/src/simulator/src/sequential/Clock.js +++ b/v1/src/simulator/src/sequential/Clock.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo } from '../canvasApi' import { colors } from '../themer/themer' /** @@ -17,9 +17,6 @@ import { colors } from '../themer/themer' export default class Clock extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['Clock'].push(this); - */ this.fixedBitWidth = true this.output1 = new Node(10, 0, 1, this, 1) this.state = 0 diff --git a/v1/src/simulator/src/sequential/DflipFlop.js b/v1/src/simulator/src/sequential/DflipFlop.js index 4543ba61..f21fe2a1 100644 --- a/v1/src/simulator/src/sequential/DflipFlop.js +++ b/v1/src/simulator/src/sequential/DflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import { colors } from '../themer/themer' /** @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class DflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* - this.scope['DflipFlop'].push(this); - */ this.directionFixed = true this.setDimensions(20, 20) this.rectangleObject = true @@ -43,9 +40,6 @@ export default class DflipFlop extends CircuitElement { */ isResolvable() { return true - // if (this.reset.value == 1) return true; - // if (this.clockInp.value != undefined && this.dInp.value != undefined) return true; - // return false; } newBitWidth(bitWidth) { @@ -116,7 +110,6 @@ export default class DflipFlop extends CircuitElement { customDraw() { var ctx = simulationArea.context - // ctx.strokeStyle = colors['stroke'] ctx.fillStyle = colors['fill'] ctx.beginPath() @@ -127,7 +120,6 @@ export default class DflipFlop extends CircuitElement { moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() diff --git a/v1/src/simulator/src/sequential/Dlatch.js b/v1/src/simulator/src/sequential/Dlatch.js index 7532d3db..cc3b7097 100644 --- a/v1/src/simulator/src/sequential/Dlatch.js +++ b/v1/src/simulator/src/sequential/Dlatch.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -20,9 +20,6 @@ import { colors } from '../themer/themer' export default class Dlatch extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { super(x, y, scope, dir, bitWidth) - /* - this.scope['Dlatch'].push(this); - */ this.directionFixed = true this.setDimensions(20, 20) this.rectangleObject = true @@ -30,16 +27,13 @@ export default class Dlatch extends CircuitElement { this.dInp = new Node(-20, -10, 0, this, this.bitWidth, 'D') this.qOutput = new Node(20, -10, 1, this, this.bitWidth, 'Q') this.qInvOutput = new Node(20, 10, 1, this, this.bitWidth, 'Q Inverse') - // this.reset = new Node(10, 20, 0, this, 1, "Asynchronous Reset"); - // this.preset = new Node(0, 20, 0, this, this.bitWidth, "Preset"); - // this.en = new Node(-10, 20, 0, this, 1, "Enable"); this.state = 0 this.prevClockState = 0 this.wasClicked = false } /** - * Idea: shoould be D FF? + * Idea: should be D FF? */ isResolvable() { if (this.clockInp.value != undefined && this.dInp.value != undefined) @@ -52,7 +46,6 @@ export default class Dlatch extends CircuitElement { this.dInp.bitWidth = bitWidth this.qOutput.bitWidth = bitWidth this.qInvOutput.bitWidth = bitWidth - // this.preset.bitWidth = bitWidth; } /** @@ -80,9 +73,6 @@ export default class Dlatch extends CircuitElement { dInp: findNode(this.dInp), qOutput: findNode(this.qOutput), qInvOutput: findNode(this.qInvOutput), - // reset: findNode(this.reset), - // preset: findNode(this.preset), - // en: findNode(this.en), }, constructorParamaters: [this.direction, this.bitWidth], } @@ -97,11 +87,9 @@ export default class Dlatch extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' diff --git a/v1/src/simulator/src/sequential/EEPROM.js b/v1/src/simulator/src/sequential/EEPROM.js index 3a3427b8..f2e13636 100644 --- a/v1/src/simulator/src/sequential/EEPROM.js +++ b/v1/src/simulator/src/sequential/EEPROM.js @@ -31,9 +31,6 @@ export default class EEPROM extends RAM { data = null ) { super(x, y, scope, dir, bitWidth, addressWidth) - /* - this.scope['EEPROM'].push(this); - */ this.data = data || this.data } diff --git a/v1/src/simulator/src/sequential/ForceGate.js b/v1/src/simulator/src/sequential/ForceGate.js new file mode 100644 index 00000000..332af06c --- /dev/null +++ b/v1/src/simulator/src/sequential/ForceGate.js @@ -0,0 +1,92 @@ +import CircuitElement from '../circuitElement' +import Node, { findNode } from '../node' +import { simulationArea } from '../simulationArea' +import { fillText4 } from '../canvasApi' +/** + * @class + * ForceGate + * @extends CircuitElement + * @param {number} x - x coordinate of element. + * @param {number} y - y coordinate of element. + * @param {Scope=} scope - Cirucit on which element is drawn + * @param {string=} dir - direction of element + * @param {number=} bitWidth - bit width per node. + * @category testbench + */ +export default class ForceGate extends CircuitElement { + constructor(x, y, scope = globalScope, dir = 'RIGHT', bitWidth = 1) { + super(x, y, scope, dir, bitWidth) + this.setDimensions(20, 10) + this.objectType = 'ForceGate' + this.scope.ForceGate.push(this) + this.inp1 = new Node(-20, 0, 0, this) + this.inp2 = new Node(0, 0, 0, this) + this.output1 = new Node(20, 0, 1, this) + } + + /** + * @memberof ForceGate + * Checks if the element is resolvable + * @return {boolean} + */ + isResolvable() { + return this.inp1.value !== undefined || this.inp2.value !== undefined + } + + /** + * @memberof ForceGate + * fn to create save Json Data of object + * @return {JSON} + */ + customSave() { + const data = { + constructorParamaters: [this.direction, this.bitWidth], + nodes: { + output1: findNode(this.output1), + inp1: findNode(this.inp1), + inp2: findNode(this.inp2), + }, + } + return data + } + + /** + * @memberof ForceGate + * resolve output values based on inputData + */ + resolve() { + if (this.inp2.value !== undefined) { + this.output1.value = this.inp2.value + } else { + this.output1.value = this.inp1.value + } + simulationArea.simulationQueue.add(this.output1) + } + + /** + * @memberof ForceGate + * function to draw element + */ + customDraw() { + var ctx = simulationArea.context + const xx = this.x + const yy = this.y + + ctx.beginPath() + ctx.fillStyle = 'Black' + ctx.textAlign = 'center' + + fillText4(ctx, 'I', -10, 0, xx, yy, this.direction, 10) + fillText4(ctx, 'O', 10, 0, xx, yy, this.direction, 10) + ctx.fill() + } +} + +/** + * @memberof ForceGate + * Help Tip + * @type {string} + * @category testbench + */ +ForceGate.prototype.tooltipText = 'Force Gate ToolTip : ForceGate Selected.' +ForceGate.prototype.objectType = 'ForceGate' diff --git a/v1/src/simulator/src/sequential/JKflipFlop.js b/v1/src/simulator/src/sequential/JKflipFlop.js index c02eae3f..4f975c79 100644 --- a/v1/src/simulator/src/sequential/JKflipFlop.js +++ b/v1/src/simulator/src/sequential/JKflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class JKflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['JKflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -37,8 +34,6 @@ export default class JKflipFlop extends CircuitElement { this.slaveState = 0 this.masterState = 0 this.prevClockState = 0 - - // this.wasClicked = false; } /** @@ -139,13 +134,9 @@ export default class JKflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() diff --git a/v1/src/simulator/src/sequential/Keyboard.js b/v1/src/simulator/src/sequential/Keyboard.js index ffeb7a9c..a86a1d04 100644 --- a/v1/src/simulator/src/sequential/Keyboard.js +++ b/v1/src/simulator/src/sequential/Keyboard.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText3 } from '../canvasApi' /** * @class @@ -18,15 +18,12 @@ import { colors } from '../themer/themer' export default class Keyboard extends CircuitElement { constructor(x, y, scope = globalScope, bufferSize = 32) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['Keyboard'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.bufferSize = bufferSize || parseInt(prompt('Enter buffer size:')) this.elementWidth = Math.max(80, Math.ceil(this.bufferSize / 2) * 20) - this.elementHeight = 40 // Math.max(40,Math.ceil(this.rows*15/20)*20); + this.elementHeight = 40 this.setWidth(this.elementWidth / 2) this.setHeight(this.elementHeight / 2) diff --git a/v1/src/simulator/src/sequential/RAM.js b/v1/src/simulator/src/sequential/RAM.js index b406f921..cdaab091 100644 --- a/v1/src/simulator/src/sequential/RAM.js +++ b/v1/src/simulator/src/sequential/RAM.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' import { parseNumber, showMessage } from '../utils' /** @@ -43,7 +43,6 @@ import { parseNumber, showMessage } from '../utils' * by keeping the max addressWidth small. If needed, we can increase the max. * @category sequential */ -import { colors } from '../themer/themer' import { showError } from '../utils' export default class RAM extends CircuitElement { constructor( @@ -55,9 +54,6 @@ export default class RAM extends CircuitElement { addressWidth = 10 ) { super(x, y, scope, dir, Math.min(Math.max(1, bitWidth), 32)) - /* - this.scope['RAM'].push(this); - */ this.setDimensions(60, 40) this.directionFixed = true @@ -270,9 +266,6 @@ export default class RAM extends CircuitElement { } showMessage('Data dumped to developer Console') - - console.log(JSON.stringify(this.data)) - if (logLabel) { console.groupEnd() } diff --git a/v1/src/simulator/src/sequential/Rom.js b/v1/src/simulator/src/sequential/Rom.js index 69bb544b..823208ab 100644 --- a/v1/src/simulator/src/sequential/Rom.js +++ b/v1/src/simulator/src/sequential/Rom.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, rect2, fillText3 } from '../canvasApi' /** * @class @@ -21,9 +21,6 @@ export default class Rom extends CircuitElement { data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['Rom'].push(this); - */ this.fixedBitWidth = true this.directionFixed = true this.rectangleObject = false @@ -133,7 +130,7 @@ export default class Rom extends CircuitElement { hoverIndex === undefined && ((!simulationArea.shiftDown && this.hover) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this)) + simulationArea.multipleObjectSelections.includes(this)) ) ctx.fillStyle = colors['hover_select'] ctx.fill() diff --git a/v1/src/simulator/src/sequential/SRflipFlop.js b/v1/src/simulator/src/sequential/SRflipFlop.js index af1a16ce..f3010fbe 100644 --- a/v1/src/simulator/src/sequential/SRflipFlop.js +++ b/v1/src/simulator/src/sequential/SRflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText } from '../canvasApi' /** * @class @@ -18,9 +18,6 @@ import { colors } from '../themer/themer' export default class SRflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['SRflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -33,9 +30,6 @@ export default class SRflipFlop extends CircuitElement { this.preset = new Node(0, 20, 0, this, 1, 'Preset') this.en = new Node(-10, 20, 0, this, 1, 'Enable') this.state = 0 - // this.slaveState = 0; - // this.prevClockState = 0; - // this.wasClicked = false; } newBitWidth(bitWidth) { @@ -52,9 +46,6 @@ export default class SRflipFlop extends CircuitElement { */ isResolvable() { return true - if (this.reset.value == 1) return true - if (this.S.value != undefined && this.R.value != undefined) return true - return false } /** @@ -105,20 +96,13 @@ export default class SRflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - - // rect(ctx, xx - 20, yy - 20, 40, 40); - // moveTo(ctx, -20, 5, xx, yy, this.direction); - // lineTo(ctx, -15, 10, xx, yy, this.direction); - // lineTo(ctx, -20, 15, xx, yy, this.direction); - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' ctx.fillStyle = colors['input_text'] ctx.textAlign = 'center' - fillText(ctx, this.state.toString(16), xx, yy + 5) + this.state ? fillText(ctx, this.state.toString(16), xx, yy + 5) : fillText(ctx, '0', xx, yy + 5); ctx.fill() } } diff --git a/v1/src/simulator/src/sequential/TTY.js b/v1/src/simulator/src/sequential/TTY.js index d0c89461..e533b99c 100644 --- a/v1/src/simulator/src/sequential/TTY.js +++ b/v1/src/simulator/src/sequential/TTY.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText3 } from '../canvasApi' import { colors } from '../themer/themer' @@ -21,9 +21,6 @@ import { colors } from '../themer/themer' export default class TTY extends CircuitElement { constructor(x, y, scope = globalScope, rows = 3, cols = 32) { super(x, y, scope, 'RIGHT', 1) - /* - this.scope['TTY'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.cols = cols || parseInt(prompt('Enter cols:')) @@ -33,7 +30,6 @@ export default class TTY extends CircuitElement { this.elementHeight = Math.max(40, Math.ceil((this.rows * 15) / 20) * 20) this.setWidth(this.elementWidth / 2) this.setHeight(this.elementHeight / 2) - // this.element = new Element(x, y, "TTY",this.elementWidth/2, this,this.elementHeight/2); this.clockInp = new Node( -this.elementWidth / 2, @@ -51,7 +47,6 @@ export default class TTY extends CircuitElement { 7, 'Ascii Input' ) - // this.qOutput = new Node(20, -10, 1, this); this.reset = new Node( 30 - this.elementWidth / 2, this.elementHeight / 2, @@ -68,8 +63,6 @@ export default class TTY extends CircuitElement { 1, 'Enable' ) - // this.masterState = 0; - // this.slaveState = 0; this.prevClockState = 0 this.data = '' @@ -78,7 +71,7 @@ export default class TTY extends CircuitElement { /** * @memberof TTY - * this funciton is used to change the size of the screen + * this function is used to change the size of the screen */ changeRowSize(size) { if (size == undefined || size < 1 || size > 10) return @@ -91,7 +84,7 @@ export default class TTY extends CircuitElement { /** * @memberof TTY - * this funciton is used to change the size of the screen + * this function is used to change the size of the screen */ changeColSize(size) { if (size == undefined || size < 20 || size > 100) return @@ -173,7 +166,6 @@ export default class TTY extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - this.elementWidth/2, yy - this.elementHeight/2, this.elementWidth, this.elementHeight); moveTo( ctx, @@ -199,9 +191,6 @@ export default class TTY extends CircuitElement { yy, this.direction ) - - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) - // ctx.fillStyle = "rgba(255, 255, 32,0.8)"; ctx.stroke() ctx.beginPath() diff --git a/v1/src/simulator/src/sequential/TflipFlop.js b/v1/src/simulator/src/sequential/TflipFlop.js index cedb9f6b..ce1f7be9 100644 --- a/v1/src/simulator/src/sequential/TflipFlop.js +++ b/v1/src/simulator/src/sequential/TflipFlop.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import { colors } from '../themer/themer' @@ -19,9 +19,6 @@ import { colors } from '../themer/themer' export default class TflipFlop extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT') { super(x, y, scope, dir, 1) - /* - this.scope['TflipFlop'].push(this); - */ this.directionFixed = true this.fixedBitWidth = true this.setDimensions(20, 20) @@ -36,8 +33,6 @@ export default class TflipFlop extends CircuitElement { this.masterState = 0 this.slaveState = 0 this.prevClockState = 0 - - // this.wasClicked = false; } /** @@ -133,12 +128,10 @@ export default class TflipFlop extends CircuitElement { ctx.lineWidth = correctWidth(3) var xx = this.x var yy = this.y - // rect(ctx, xx - 20, yy - 20, 40, 40); moveTo(ctx, -20, 5, xx, yy, this.direction) lineTo(ctx, -15, 10, xx, yy, this.direction) lineTo(ctx, -20, 15, xx, yy, this.direction) - // if ((this.b.hover&&!simulationArea.shiftDown)|| simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";ctx.fill(); ctx.stroke() ctx.beginPath() ctx.font = '20px Raleway' diff --git a/v1/src/simulator/src/sequential/verilogRAM.js b/v1/src/simulator/src/sequential/verilogRAM.js index d1e9c71d..c3915d47 100644 --- a/v1/src/simulator/src/sequential/verilogRAM.js +++ b/v1/src/simulator/src/sequential/verilogRAM.js @@ -1,7 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' -import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' +import { simulationArea } from '../simulationArea' /** * @class * verilogRAM Component. @@ -42,7 +41,6 @@ import { correctWidth, fillText2, fillText4, drawCircle2 } from '../canvasApi' * by keeping the max addressWidth small. If needed, we can increase the max. * @category sequential */ -import { colors } from '../themer/themer' function customResolve( clockInp, @@ -110,7 +108,6 @@ function customResolve( if (en[i].value == 0) { prevClockState[i] = clockInp[i].value } else if (en[i].value == 1 || en[i].connections.length == 0) { - // if(en.value==1) // Creating Infinite Loop, WHY ?? if (clockInp[i].value == prevClockState[i]) { if (clockInp[i].value == 0 && dInp[i].value != undefined) { masterState[i] = dInp[i].value @@ -152,9 +149,6 @@ export default class verilogRAM extends CircuitElement { wrports ) { super(x, y, scope, dir, Math.min(Math.max(1, bitWidth), 32)) - /* - this.scope['verilogRAM'].push(this); - */ this.setDimensions(60, 40) this.directionFixed = true @@ -413,22 +407,9 @@ export default class verilogRAM extends CircuitElement { } newBitWidth(value) { - // value = parseInt(value); - // if (!isNaN(value) && this.bitWidth != value && value >= 1 && value <= 32) { - // this.bitWidth = value; - // this.dataIn.bitWidth = value; - // this.dataOut.bitWidth = value; - // this.clearData(); - // } } changeAddressWidth(value) { - // value = parseInt(value); - // if (!isNaN(value) && this.addressWidth != value && value >= 1 && value <= this.maxAddressWidth) { - // this.addressWidth = value; - // this.address.bitWidth = value; - // this.clearData(); - // } } clearData() { @@ -498,27 +479,6 @@ export default class verilogRAM extends CircuitElement { } customDraw() { - // var ctx = simulationArea.context; - // // - // var xx = this.x; - // var yy = this.y; - // ctx.beginPath(); - // ctx.strokeStyle = 'gray'; - // ctx.fillStyle = this.write.value ? 'red' : 'lightgreen'; - // ctx.lineWidth = correctWidth(1); - // drawCircle2(ctx, 50, -30, 3, xx, yy, this.direction); - // ctx.fill(); - // ctx.stroke(); - // ctx.beginPath(); - // ctx.textAlign = 'center'; - // ctx.fillStyle = 'black'; - // fillText4(ctx, this.memSizeString(), 0, -10, xx, yy, this.direction, 12); - // fillText4(ctx, this.shortName, 0, 10, xx, yy, this.direction, 12); - // fillText2(ctx, 'A', this.address.x + 12, this.address.y, xx, yy, this.direction); - // fillText2(ctx, 'DI', this.dataIn.x + 12, this.dataIn.y, xx, yy, this.direction); - // fillText2(ctx, 'W', this.write.x + 12, this.write.y, xx, yy, this.direction); - // fillText2(ctx, 'DO', this.dataOut.x - 15, this.dataOut.y, xx, yy, this.direction); - // ctx.fill(); } memSizeString() { @@ -543,9 +503,6 @@ export default class verilogRAM extends CircuitElement { if (logLabel) { console.group(this.label) } - - console.log(this.data) - if (logLabel) { console.groupEnd() } diff --git a/v1/src/simulator/src/setup.js b/v1/src/simulator/src/setup.js index 3be06161..1f04977e 100644 --- a/v1/src/simulator/src/setup.js +++ b/v1/src/simulator/src/setup.js @@ -1,20 +1,15 @@ /* eslint-disable import/no-cycle */ /* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */ - -import { Tooltip } from 'bootstrap' -import metadata from './metadata.json' import { generateId, showMessage } from './utils' -import backgroundArea from './backgroundArea' +import { backgroundArea } from './backgroundArea' import plotArea from './plotArea' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { dots } from './canvasApi' import { update, updateSimulationSet, updateCanvasSet } from './engine' import { setupUI } from './ux' import startMainListeners from './listeners' -// import startEmbedListeners from './embedListeners' -import './embed' -import { newCircuit, scopeList } from './circuit' +import { newCircuit } from './circuit' import load from './data/load' import save from './data/save' import { showTourGuide } from './tutorials' @@ -26,7 +21,6 @@ import 'codemirror/addon/edit/closebrackets' import 'codemirror/addon/hint/anyword-hint' import 'codemirror/addon/hint/show-hint' import { setupCodeMirrorEnvironment } from './Verilog2CV' -// import { keyBinder } from '#/components/DialogBox/CustomShortcut.vue' import '../vendor/jquery-ui.min.css' import '../vendor/jquery-ui.min' import { confirmSingleOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' @@ -47,7 +41,7 @@ export function resetup() { if (!embed) { height = (document.body.clientHeight - - document.getElementById('toolbar').clientHeight) * + document.getElementById('toolbar')?.clientHeight) * DPR } else { height = document.getElementById('simulation').clientHeight * DPR @@ -97,29 +91,6 @@ function setupEnvironment() { setupCodeMirrorEnvironment() } -/** - * It initializes some useful array which are helpful - * while simulating, saving and loading project. - * It also draws icons in the sidebar - * @category setup - */ -function setupElementLists() { - // $('#menu').empty() - - window.circuitElementList = metadata.circuitElementList - window.annotationList = metadata.annotationList - window.inputList = metadata.inputList - window.subCircuitInputList = metadata.subCircuitInputList - window.moduleList = [...circuitElementList, ...annotationList] - window.updateOrder = [ - 'wires', - ...circuitElementList, - 'nodes', - ...annotationList, - ] // Order of update - window.renderOrder = [...moduleList.slice().reverse(), 'wires', 'allNodes'] // Order of render -} - /** * Fetches project data from API and loads it into the simulator. * @param {number} projectId The ID of the project to fetch data for @@ -139,14 +110,6 @@ async function fetchProjectData(projectId) { ) if (response.ok) { const data = await response.json() - const simulatorVersion = data.simulatorVersion - const projectName = data.name - if(!simulatorVersion){ - window.location.href = `/simulator/edit/${projectId}` - } - if(simulatorVersion && simulatorVersion != "v1"){ - window.location.href = `/simulatorvue/edit/${projectName}?simver=${simulatorVersion}` - } await load(data) await simulationArea.changeClockTime(data.timePeriod || 500) $('.loadingIcon').fadeOut() @@ -205,9 +168,6 @@ function showTour() { * @category setup */ export function setup() { - // let embed = false - // const startListeners = embed ? startEmbedListeners : startMainListeners - setupElementLists() setupEnvironment() if (!embed) { setupUI() diff --git a/v1/src/simulator/src/simulationArea.js b/v1/src/simulator/src/simulationArea.js deleted file mode 100644 index 3784988a..00000000 --- a/v1/src/simulator/src/simulationArea.js +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable import/no-cycle */ -import EventQueue from './eventQueue' -import { clockTick } from './utils' - -/** - * simulation environment object - holds simulation canvas - * @type {Object} simulationArea - * @property {HTMLCanvasElement} canvas - * @property {boolean} selected - * @property {boolean} hover - * @property {number} clockState - * @property {boolean} clockEnabled - * @property {undefined} lastSelected - * @property {Array} stack - * @property {number} prevScale - * @property {number} oldx - * @property {number} oldy - * @property {Array} objectList - * @property {number} maxHeight - * @property {number} maxWidth - * @property {number} minHeight - * @property {number} minWidth - * @property {Array} multipleObjectSelections - * @property {Array} copyList - List of selected elements - * @property {boolean} shiftDown - shift down or not - * @property {boolean} controlDown - contol down or not - * @property {number} timePeriod - time period - * @property {number} mouseX - mouse x - * @property {number} mouseY - mouse y - * @property {number} mouseDownX - mouse click x - * @property {number} mouseDownY - mouse click y - * @property {Array} simulationQueue - simulation queue - * @property {number} clickCount - number of clicks - * @property {string} lock - locked or unlocked - * @property {function} timer - timer - * @property {function} setup - to setup the simulaton area - * @property {function} changeClockTime - change clock time - * @property {function} clear - clear the simulation area - * @category simulationArea - */ -const simulationArea = { - canvas: document.getElementById('simulationArea'), - selected: false, - hover: false, - clockState: 0, - clockEnabled: true, - lastSelected: undefined, - stack: [], - prevScale: 0, - oldx: 0, - oldy: 0, - objectList: [], - maxHeight: 0, - maxWidth: 0, - minHeight: 0, - minWidth: 0, - multipleObjectSelections: [], - copyList: [], - shiftDown: false, - controlDown: false, - timePeriod: 500, - mouseX: 0, - mouseY: 0, - mouseDownX: 0, - mouseDownY: 0, - simulationQueue: undefined, - multiAddElement: false, - - clickCount: 0, // double click - lock: 'unlocked', - timer() { - ckickTimer = setTimeout(() => { - simulationArea.clickCount = 0 - }, 600) - }, - - setup() { - this.canvas = document.getElementById('simulationArea') - this.canvas.width = width - this.canvas.height = height - this.simulationQueue = new EventQueue(10000) - this.context = this.canvas.getContext('2d') - simulationArea.changeClockTime(simulationArea.timePeriod) - this.mouseDown = false - }, - changeClockTime(t) { - if (t < 50) return - clearInterval(simulationArea.ClockInterval) - t = t || prompt('Enter Time Period:') - simulationArea.timePeriod = t - simulationArea.ClockInterval = setInterval(clockTick, t) - }, - clear() { - if (!this.context) return - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height) - }, -} -export const { changeClockTime } = simulationArea -export default simulationArea diff --git a/v1/src/simulator/src/simulationArea.ts b/v1/src/simulator/src/simulationArea.ts new file mode 100644 index 00000000..bd2f3f9a --- /dev/null +++ b/v1/src/simulator/src/simulationArea.ts @@ -0,0 +1,70 @@ +import { EventQueue } from './eventQueue' +import { SimulationArea } from './interface/simulationArea' +import { clockTick } from './utils' + +const simulationArea: SimulationArea = { + canvas: document.getElementById('simulationArea') as HTMLCanvasElement, + context: null, + selected: false, + hover: false, + clockState: 0, + clockEnabled: true, + lastSelected: null, + stack: [], + prevScale: 0, + oldx: 0, + oldy: 0, + objectList: [], + maxHeight: 0, + maxWidth: 0, + minHeight: 0, + minWidth: 0, + multipleObjectSelections: [], + copyList: [], + shiftDown: false, + controlDown: false, + timePeriod: 500, + mouseX: 0, + mouseY: 0, + mouseDownX: 0, + mouseDownY: 0, + simulationQueue: new EventQueue(10000), + clickCount: 0, + lock: 'unlocked', + mouseDown: false, + ClockInterval: null, + touch: false, + + timer() { + const clickTimer = setTimeout(() => { + simulationArea.clickCount = 0 + }, 600) + }, + setup() { + this.canvas = document.getElementById('simulationArea') as HTMLCanvasElement; + this.canvas.width = width; + this.canvas.height = height; + this.simulationQueue = new EventQueue(10000); + this.context = this.canvas.getContext('2d')!; + simulationArea.changeClockTime(simulationArea.timePeriod); + this.mouseDown = false; + }, + changeClockTime(t: number) { + if (t < 50) { + return; + } + if (simulationArea.ClockInterval != null) { + clearInterval(simulationArea.ClockInterval); + } + simulationArea.timePeriod = t; + simulationArea.ClockInterval = setInterval(clockTick, t); + }, + clear() { + if (!this.context) { + return; + } + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + }, +}; +export { simulationArea } +export const { changeClockTime } = simulationArea \ No newline at end of file diff --git a/v1/src/simulator/src/subcircuit.js b/v1/src/simulator/src/subcircuit.js index 85fdc53e..377ea3b5 100644 --- a/v1/src/simulator/src/subcircuit.js +++ b/v1/src/simulator/src/subcircuit.js @@ -1,7 +1,7 @@ /* eslint-disable import/no-cycle */ import Scope, { scopeList, switchCircuit } from './circuit' import CircuitElement from './circuitElement' -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleBackup, checkIfBackup } from './data/backupCircuit' import { scheduleUpdate, @@ -20,6 +20,8 @@ import { layoutModeGet } from './layoutMode' import { verilogModeGet } from './Verilog2CV' import { sanitizeLabel } from './verilogHelpers' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { circuitElementList, subCircuitInputList } from './metadata' + /** * Function to load a subcicuit * @category subcircuit @@ -40,50 +42,6 @@ export function createSubCircuitPrompt(scope = globalScope) { } const simulatorStore = SimulatorStore() simulatorStore.dialogBox.insertsubcircuit_dialog = true - /* - $('#insertSubcircuitDialog').empty() - let flag = true - for (id in scopeList) { - if ( - !scopeList[id].checkDependency(scope.id) && - scopeList[id].isVisible() - ) { - flag = false - $('#insertSubcircuitDialog').append( - `` - ) - } - } - if (flag) - $('#insertSubcircuitDialog').append( - "

Looks like there are no other circuits which doesn't have this circuit as a dependency. Create a new one!

" - ) - $('#insertSubcircuitDialog').dialog({ - resizable: false, - maxHeight: 800, - width: 450, - maxWidth: 800, - minWidth: 250, - buttons: !flag - ? [ - { - text: 'Insert SubCircuit', - click() { - if (!$('input[name=subCircuitId]:checked').val()) - return - simulationArea.lastSelected = new SubCircuit( - undefined, - undefined, - globalScope, - $('input[name=subCircuitId]:checked').val() - ) - $(this).dialog('close') - }, - }, - ] - : [], - }) - */ } /** @@ -207,8 +165,8 @@ export default class SubCircuit extends CircuitElement { this.downDimensionY = subcircuitScope.layout.height } - this.nodeList.extend(this.inputNodes) - this.nodeList.extend(this.outputNodes) + this.nodeList.push(...this.inputNodes) + this.nodeList.push(...this.outputNodes) } else { this.version = '2.0' } @@ -297,14 +255,11 @@ export default class SubCircuit extends CircuitElement { // Needs to be deprecated, removed reBuild() { - // new SubCircuit(x = this.x, y = this.y, scope = this.scope, this.id); - // this.scope.backups = []; // Because all previous states are invalid now - // this.delete(); - // showMessage('Subcircuit: ' + subcircuitScope.name + ' has been reloaded.'); } /** - * rebuilds the subcircuit if any change to localscope is made + * If the circuit referenced by localscope is changed, then the localscope + * needs to be updated. This function does that. */ reBuildCircuit() { this.data = JSON.parse(scheduleBackup(scopeList[this.id])) @@ -365,7 +320,7 @@ export default class SubCircuit extends CircuitElement { } else { this.scope.backups = [] this.inputNodes[i].delete() - this.nodeList.clean(this.inputNodes[i]) + this.nodeList = this.nodeList.filter(x => x !== this.inputNodes[i]) } } @@ -381,7 +336,7 @@ export default class SubCircuit extends CircuitElement { } else { this.scope.backups = [] temp_map_inp[id][1].delete() - this.nodeList.clean(temp_map_inp[id][1]) + this.nodeList = this.nodeList.filter(x => x !== temp_map_inp[id][1]) temp_map_inp[id][1] = new Node( temp_map_inp[id][0].layoutProperties.x, temp_map_inp[id][0].layoutProperties.y, @@ -426,7 +381,7 @@ export default class SubCircuit extends CircuitElement { this.outputNodes[i] } else { this.outputNodes[i].delete() - this.nodeList.clean(this.outputNodes[i]) + this.nodeList = this.nodeList.filter(x => x !== this.outputNodes[i]) } } @@ -441,7 +396,7 @@ export default class SubCircuit extends CircuitElement { temp_map_out[id][1].bitWidth = temp_map_out[id][0].bitWidth } else { temp_map_out[id][1].delete() - this.nodeList.clean(temp_map_out[id][1]) + this.nodeList = this.nodeList.filter(x => x !== temp_map_out[id][1]) temp_map_out[id][1] = new Node( temp_map_out[id][0].layoutProperties.x, temp_map_out[id][0].layoutProperties.y, @@ -479,12 +434,9 @@ export default class SubCircuit extends CircuitElement { this.reBuildCircuit() } - // Should this be done here or only when this.reBuildCircuit() is called? - { - this.localScope.reset() - updateSimulationSet(true) - forceResetNodesSet(true) - } + this.localScope.reset() + updateSimulationSet(true) + forceResetNodesSet(true) this.makeConnections() } @@ -658,7 +610,7 @@ export default class SubCircuit extends CircuitElement { if ( (this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected === this || - simulationArea.multipleObjectSelections.contains(this) + simulationArea.multipleObjectSelections.includes(this) ) ctx.fillStyle = colors['hover_select'] } @@ -688,6 +640,7 @@ export default class SubCircuit extends CircuitElement { ) } } else { + console.error('Unknown Version: ', this.version) } for (var i = 0; i < subcircuitScope.Input.length; i++) { diff --git a/v1/src/simulator/src/testCreator.js b/v1/src/simulator/src/testCreator.js deleted file mode 100644 index 4a1708c2..00000000 --- a/v1/src/simulator/src/testCreator.js +++ /dev/null @@ -1,780 +0,0 @@ -/* - This file contains all javascript related to the test creator UI - at /testbench -*/ - -import _ from '../vendor/table2csv' - -const CREATORMODE = { - NORMAL: 0, - SIMULATOR_POPUP: 1, -} - -var testMode = 'comb' -var groupIndex = 0 -var inputCount = 0 -var nextInputIndex = 0 -var outputCount = 0 -var nextOutputIndex = 0 -var cases = [0] -var creatorMode = CREATORMODE.NORMAL -var circuitScopeID - -function dataReset() { - groupIndex = -1 - cases = [0] -} - -/** - * Onload, check if it is opened in a popup. - * Check if test is being edited, or created - */ -window.onload = () => { - const query = new URLSearchParams(window.location.search) - if (query.has('popUp')) { - if (query.get('popUp') == 'true') { - creatorMode = CREATORMODE.SIMULATOR_POPUP - $('.right-button-group').append( - '' - ) - } - } - if (query.has('data')) { - $('#tb-creator-head').html('Edit Test') - circuitScopeID = query.get('scopeID') - loadData(query.get('data')) - return - } - - if (query.has('result')) { - $('#tb-creator-head').html('Test Result') - loadResult(query.get('result')) - readOnlyUI() - return - } - - circuitScopeID = query.get('scopeID') - addInput() - addOutput() - makeSortable() -} - -/* Change UI testMode between Combinational(comb) and Sequential(seq) */ -function changeTestMode(m) { - if (testMode === m) return false - dataReset() - testMode = m - $('#combSelect').removeClass('tab-selected') - $('#seqSelect').removeClass('tab-selected') - $('#tb-new-group').css('visibility', m === 'seq' ? 'visible' : 'hidden') - $(`#${m}Select`).addClass('tab-selected') - $('#dataGroup').empty() - - return true -} - -/* Adds case to a group */ -function addCase(grp) { - const currentGroupTable = $(`#data-table-${grp + 1}`) - - let s = - '
\n' - for (let i = 0; i < inputCount + outputCount; i++) - s += '0' - s += '' - - // Sortable hack - currentGroupTable.find('tbody').remove() - currentGroupTable.append(s) -} - -/* Deletes case from a group */ -function deleteCase(element) { - const row = element.parent().parent() - const grp = Number(row.parent().attr('id').split('-').pop()) - - row.remove() -} - -/* Adds group with default name 'Group N' or name supplied in @param groupName */ -/* Used without params by UI, used with params by loadData() */ -function addGroup( - groupName = `${testMode === 'comb' ? 'Group' : 'Set'} ${groupIndex + 2}` -) { - $('.plus-button').removeClass('latest-button') - groupIndex++ - - const s = ` -
-

${escapeHtml(groupName)}

-
Click + to add tests to the ${ - testMode === 'comb' ? 'group' : 'set' - }
- - -
- -
- ` - cases[groupIndex] = 0 - $('#dataGroup').append(s) - - makeSortable() -} - -/* Deletes a group */ -function deleteGroup(element) { - const groupDiv = element.parent() - const grp = Number(groupDiv.attr('id').split('-').pop()) - groupDiv.remove() -} - -/* Adds input with default value 0 or values supplied in @param inputData */ -/* Used without params for UI, used with params by loadData() */ -function addInput( - label = `inp${nextInputIndex + 1}`, - bitwidth = 1, - inputData = [] -) { - nextInputIndex++ - inputCount++ - // Change head table contents - const sHead = `${escapeHtml( - label - )} ` - const sData = `${escapeHtml( - bitwidth.toString() - )}` - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .eq(inputCount - 1) - .after(sHead) - $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .eq(inputCount - 1) - .after(sData) - $('#tb-inputs-head').attr('colspan', inputCount) - - // Change data tables' contents - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - const s = `${ - inputData.length - ? escapeHtml(inputData[group_i][case_i]) - : 0 - }` - $(this) - .find('td') - .eq(inputCount - 1) - .after(s) - }) - }) -} - -/* Adds output with default value 0 or values supplied in @param outputData */ -/* Used without params for UI, used with params by loadData() */ -/* Used with resultData and result=true for setting result */ -function addOutput( - label = `out${nextOutputIndex + 1}`, - bitwidth = 1, - outputData = [], - result = false, - resultData = [] -) { - nextOutputIndex++ - outputCount++ - // Change head table contents - let sHead = `${escapeHtml( - label - )} ` - let sData = `${escapeHtml( - bitwidth.toString() - )}` - - // If result then set colspan to 2 - if (result) { - sHead = `${escapeHtml( - label - )} ` - sData = `${escapeHtml( - bitwidth.toString() - )}` - } - - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .eq(inputCount + outputCount - 1) - .after(sHead) - $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .eq(inputCount + outputCount - 1) - .after(sData) - // If not result then colspan is outputCount - $('#tb-outputs-head').attr('colspan', outputCount) - // else it's 2*outputCount - if (result) { - $('#tb-outputs-head').attr('colspan', 2 * outputCount) - } - - // Change data tables' contents - - // If not result just add the outputs - if (!result) { - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - const s = `${ - outputData.length - ? escapeHtml(outputData[group_i][case_i]) - : 0 - }` - $(this) - .find('td') - .eq(inputCount + outputCount - 1) - .after(s) - }) - }) - - // If result then add results besides the outputs - // Hacky - } else { - $('#dataGroup') - .find('table') - .each(function (group_i) { - $(this) - .find('tr') - .each(function (case_i) { - // Add the outputs (expected values) - const outputCellData = `${escapeHtml( - outputData[group_i][case_i] - )}` - $(this) - .find('td') - .eq(inputCount + 2 * (outputCount - 1)) - .after(outputCellData) - - // Add the actual values - const resultColor = - resultData[group_i][case_i] === - outputData[group_i][case_i] - ? 'green' - : 'red' - const resultCellData = `${escapeHtml( - resultData[group_i][case_i] - )}` - $(this) - .find('td') - .eq(inputCount + 2 * outputCount - 1) - .after(resultCellData) - }) - }) - } -} - -/* Deletes input unless there's only one input */ -function deleteInput(element) { - if (inputCount === 1) return - const columnIndex = element.parent().eq(0).index() - - $('#testBenchTable tr, .data-group tr') - .slice(1) - .each(function () { - $(this).find('td, th').eq(columnIndex).remove() - }) - - inputCount-- - $('#tb-inputs-head').attr('colspan', inputCount) -} - -/* Deletes output unless there's only one output */ -function deleteOutput(element) { - if (outputCount === 1) return - const columnIndex = element.parent().eq(0).index() - - $('#testBenchTable tr, .data-group tr') - .slice(1) - .each(function () { - $(this).find('td, th').eq(columnIndex).remove() - }) - - outputCount-- - $('#tb-outputs-head').attr('colspan', outputCount) -} - -/* Returns input/output(keys) and their bitwidths(values) */ -/* Called by getData() */ -function getBitWidths() { - const bitwidths = {} - $('#testBenchTable') - .find('tr') - .eq(1) - .find('th') - .slice(1) - .each(function (index) { - const inp = $(this).text() - const bw = $('#testBenchTable') - .find('tr') - .eq(2) - .find('td') - .slice(1) - .eq(index) - .html() - bitwidths[inp] = Number(bw) - }) - return bitwidths -} - -/* Returns data for all the groups for all inputs and outputs */ -/* Called by parse() */ -function getData() { - const bitwidths = getBitWidths() - const groups = [] - const groupCount = $('#dataGroup').children().length - for (let group_i = 0; group_i < groupCount; group_i++) { - const group = {} - group.label = getGroupTitle(group_i) - group.inputs = [] - group.outputs = [] - - const group_table = $(`#data-table-${group_i + 1}`) - group.n = group_table.find('tr').length - - // Push all the inputs in the group - for (let inp_i = 0; inp_i < inputCount; inp_i++) { - const label = Object.keys(bitwidths)[inp_i] - const input = { - label: label.slice(0, label.length - 1), - bitWidth: bitwidths[label], - values: [], - } - group_table.find('tr').each(function () { - input.values.push($(this).find('td').slice(1).eq(inp_i).html()) - }) - - group.inputs.push(input) - } - - // Push all the outputs in the group - for (let out_i = 0; out_i < outputCount; out_i++) { - const label = Object.keys(bitwidths)[inputCount + out_i] - const output = { - label: label.slice(0, label.length - 1), - bitWidth: bitwidths[label], - values: [], - } - group_table.find('tr').each(function () { - output.values.push( - $(this) - .find('td') - .slice(1) - .eq(inputCount + out_i) - .html() - ) - }) - - group.outputs.push(output) - } - - groups.push(group) - } - - return groups -} - -function getTestTitle() { - return $('#test-title-label').text() -} - -function getGroupTitle(group_i) { - return $(`#data-group-title-${group_i + 1}`).text() -} - -/* Parse UI table into Javascript Object */ -function parse() { - const data = {} - const tableData = getData() - data.type = testMode - data.title = getTestTitle() - data.groups = tableData - return data -} - -/* Export test data as a CSV file */ -function exportAsCSV() { - let csvData = '' - csvData += 'Title,Test Type,Input Count,Output Count\n' - csvData += `${getTestTitle()},${testMode},${inputCount},${outputCount}\n\n\n` - csvData += $('table').eq(0).table2CSV() - csvData += '\n\n' - $('table') - .slice(1) - .each(function (group_i) { - csvData += getGroupTitle(group_i) - csvData += '\n' - csvData += $(this).table2CSV() - csvData += '\n\n' - }) - - download(`${getTestTitle()}.csv`, csvData) - return csvData -} - -/* - Imports data from CSV and loads into the table - To achieve this, first converts to JSON then uses request param to load json to table -*/ -function importFromCSV() { - const file = $('#csvFileInput').prop('files')[0] - const reader = new FileReader() - - // If circuitScopeID exists, ie. if popup opened from testbench, then use that to redirect - const query = new URLSearchParams(window.location.search) - // Preserve popup status while redirecting - const isPopup = query.get('popUp') || false - - // When the file is read, redirect to the data location - reader.onload = () => { - const csvContent = reader.result - const jsonData = csv2json(csvContent, 1, 1) - - window.location = `/testbench?scopeID=${ - circuitScopeID || '' - }&data=${jsonData}&popUp=${isPopup}` - } - - reader.readAsText(file) -} - -// Clicks the hidden upload file button, entrypoint into importFromCSV() -// The hidden button in-turn calls importFromCSV() -function clickUpload() { - $('#csvFileInput').click() -} - -/* Converts CSV to JSON to be loaded into the table */ -function csv2json(csvFileData) { - const stripQuotes = (str) => str.replaceAll('"', '') - - /* Extracts bitwidths from the csv data */ - const getBitWidthsCSV = (csvDataBW) => { - const testMetadata = csvDataBW.split('\n\n')[0].split('\n') - const labels = testMetadata[1] - .split(',') - .slice(1) - .map((label) => stripQuotes(label)) - const bitWidths = testMetadata[2] - .split(',') - .slice(1) - .map((bw) => Number(stripQuotes(bw))) - - return { labels, bitWidths } - } - - const csvMetadata = csvFileData.split('\n\n\n')[0].split('\n')[1].split(',') - const csvData = csvFileData.split('\n\n\n')[1] - const jsonData = {} - - jsonData.title = csvMetadata[0] - jsonData.type = csvMetadata[1] - const inputCountCSV = Number(csvMetadata[2]) - const outputCountCSV = Number(csvMetadata[3]) - - jsonData.groups = [] - const { labels, bitWidths } = getBitWidthsCSV(csvData) - - const groups = csvData.split('\n\n').slice(1) - for (let group_i = 0; group_i < groups.length - 1; group_i++) { - const rows = groups[group_i].split('\n') - jsonData.groups[group_i] = { - label: rows[0], - n: rows.length - 1, - inputs: [], - outputs: [], - } - - // Parse Inputs - for (let input_i = 0; input_i < inputCountCSV; input_i++) { - const thisInput = { - label: labels[input_i], - bitWidth: bitWidths[input_i], - values: [], - } - for (let case_i = 1; case_i < rows.length; case_i++) - thisInput.values.push( - stripQuotes(rows[case_i].split(',')[input_i + 1]) - ) - - jsonData.groups[group_i].inputs.push(thisInput) - } - - // Parse Outputs - for ( - let output_i = inputCountCSV; - output_i < inputCountCSV + outputCountCSV; - output_i++ - ) { - const thisOutput = { - label: labels[output_i], - bitWidth: bitWidths[output_i], - values: [], - } - for (let case_i = 1; case_i < rows.length; case_i++) { - thisOutput.values.push( - stripQuotes(rows[case_i].split(',')[output_i + 1]) - ) - } - - jsonData.groups[group_i].outputs.push(thisOutput) - } - } - - return JSON.stringify(jsonData) -} - -/* Helper function to download generated file */ -function download(filename, text) { - var element = document.createElement('a') - element.setAttribute( - 'href', - `data:text/plain;charset=utf-8,${encodeURIComponent(text)}` - ) - element.setAttribute('download', filename) - - element.style.display = 'none' - document.body.appendChild(element) - - element.click() - - document.body.removeChild(element) -} - -/** - * Called when Save is clicked. If opened in popup, sends message to parent window - * to attach test to the testbench. - */ -function saveData() { - const testData = parse() - - if (creatorMode === CREATORMODE.SIMULATOR_POPUP) { - const postData = { scopeID: circuitScopeID, testData } - window.opener.postMessage( - { type: 'testData', data: JSON.stringify(postData) }, - '*' - ) - window.close() - } -} - -/* Loads data from JSON string into the table */ -function loadData(dataJSON) { - const data = JSON.parse(dataJSON) - if (data.title) $('#test-title-label').text(data.title) - changeTestMode() - changeTestMode(data.type) - for (let group_i = 0; group_i < data.groups.length; group_i++) { - const group = data.groups[group_i] - addGroup(group.label) - for (let case_i = 0; case_i < group.inputs[0].values.length; case_i++) { - addCase(group_i) - } - } - - // Add input values - for (let input_i = 0; input_i < data.groups[0].inputs.length; input_i++) { - const input = data.groups[0].inputs[input_i] - const values = data.groups.map((group) => group.inputs[input_i].values) - - addInput(input.label, input.bitWidth, values) - } - - // Add output values - for ( - let output_i = 0; - output_i < data.groups[0].outputs.length; - output_i++ - ) { - const output = data.groups[0].outputs[output_i] - const values = data.groups.map( - (group) => group.outputs[output_i].values - ) - - addOutput(output.label, output.bitWidth, values) - } -} - -/** - * Loads result from JSON string into the testbench creator UI - */ -function loadResult(dataJSON) { - const data = JSON.parse(dataJSON) - if (data.title) $('#test-title-label').text(data.title) - changeTestMode() - changeTestMode(data.type) - for (let group_i = 0; group_i < data.groups.length; group_i++) { - const group = data.groups[group_i] - addGroup(group.label) - for (let case_i = 0; case_i < group.inputs[0].values.length; case_i++) { - addCase(group_i) - } - } - - // Add input values - for (let input_i = 0; input_i < data.groups[0].inputs.length; input_i++) { - const input = data.groups[0].inputs[input_i] - const values = data.groups.map((group) => group.inputs[input_i].values) - - addInput(input.label, input.bitWidth, values) - } - - // Add output values - for ( - let output_i = 0; - output_i < data.groups[0].outputs.length; - output_i++ - ) { - const output = data.groups[0].outputs[output_i] - const values = data.groups.map( - (group) => group.outputs[output_i].values - ) - const results = data.groups.map( - (group) => group.outputs[output_i].results - ) - const expectedOutputs = [] - const actualOutputs = [] - - for (let group_i = 0; group_i < values.length; group_i++) { - const groupExpectedOuts = [] - const groupActualOuts = [] - for (let val_i = 0; val_i < values[group_i].length; val_i++) { - groupExpectedOuts.push(values[group_i][val_i]) - groupActualOuts.push(results[group_i][val_i]) - } - - expectedOutputs.push(groupExpectedOuts) - actualOutputs.push(groupActualOuts) - } - addOutput( - `${output.label}`, - output.bitWidth, - expectedOutputs, - true, - actualOutputs - ) - } -} - -/** - * Makes the UI read only for displaying results - */ -function readOnlyUI() { - makeContentUneditable() - makeUnsortable() - $('.lower-button, .table-button, .tb-minus').hide() - $('.tablink').attr('disabled', 'disabled') - $('.tablink').removeClass('tablink-no-override') - $('.data-group-info').text('') -} - -function makeContentUneditable() { - $('body') - .find('td, th, span, h3, div') - .each(function () { - $(this).attr('contenteditable', 'false') - }) -} - -function makeSortable() { - const helper = function (e, ui) { - const helperE = ui.clone() - helperE.children().each(function (child_i) { - $(this).width(ui.children().eq(child_i).width()) - }) - - return helperE - } - - function makePlaceholder(e, ui) { - ui.placeholder.children().each(function () { - $(this).css('border', '0px') - }) - } - - /* - Sortable hack: To allow sorting inside empty tables, the tables should have some height. - But it is not possible to give tables height without having rows, so we add a tbody. - tbody gives the table height but messes up all the other things. So we only keep tbody - if the table has no rows, and once table gets rows, we remove that tbody - */ - function removeTbody(e, ui) { - $(e.target).find('tbody').remove() - } - - function createTbody(e, ui) { - if ($(e.target).find('tr, tbody').length === 0) { - $(e.target).append('') - } - } - - $('.data-group table').sortable({ - handle: '.tb-handle', - helper, - start: makePlaceholder, - placeholder: 'clone', - connectWith: 'table', - receive: removeTbody, // For sortable hack - remove: createTbody, // For sortable hack - items: 'tr', - revert: 50, - scroll: false, - }) -} - -function makeUnsortable() { - $('.data-group table').sortable({ disabled: true }) -} - -function escapeHtml(unsafe) { - return unsafe - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') -} - -// Making HTML called functions global - -window.addGroup = addGroup -window.deleteGroup = deleteGroup -window.addCase = addCase -window.deleteCase = deleteCase -window.addInput = addInput -window.deleteInput = deleteInput -window.addOutput = addOutput -window.deleteOutput = deleteOutput -window.parse = parse -window.saveData = saveData -window.changeTestMode = changeTestMode -window.exportAsCSV = exportAsCSV -window.importFromCSV = importFromCSV -window.csv2json = csv2json -window.clickUpload = clickUpload diff --git a/v1/src/simulator/src/testbench.js b/v1/src/simulator/src/testbench.js deleted file mode 100644 index d6f8a070..00000000 --- a/v1/src/simulator/src/testbench.js +++ /dev/null @@ -1,1140 +0,0 @@ -/** - * This file contains all functions related the the testbench - * Contains the the testbench engine and UI modules - */ - -import { scheduleBackup } from './data/backupCircuit' -import { changeClockEnable } from './sequential' -import { play } from './engine' -import Scope from './circuit' -import { showMessage, escapeHtml } from './utils' -import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' - -/** - * @typedef {number} RunContext - */ -const CONTEXT = { - CONTEXT_SIMULATOR: 0, - CONTEXT_ASSIGNMENTS: 1, -} - -const VALIDATION_ERRORS = { - NOTPRESENT: 0, // Element is not present in the circuit - WRONGBITWIDTH: 1, // Element is present but has incorrect bitwidth - DUPLICATE_ID_DATA: 2, // Duplicate identifiers in test data - DUPLICATE_ID_SCOPE: 3, // Duplicate identifiers in scope - NO_RST: 4, // Sequential circuit but no reset(RST) in scope -} - -const TESTBENCH_CREATOR_PATH = '/testbench' - -// Do we have any other function to do this? -// Utility function. Converts decimal number to binary string -function dec2bin(dec, bitWidth = undefined) { - if (dec === undefined) return 'X' - const bin = (dec >>> 0).toString(2) - if (!bitWidth) return bin - - return '0'.repeat(bitWidth - bin.length) + bin -} - -/** - * Class to store all data related to the testbench and functions to use it - * @param {Object} data - Javascript object of the test data - * @param {number=} currentGroup - Current group index in the test - * @param {number=} currentCase - Current case index in the group - */ -export class TestbenchData { - constructor(data, currentGroup = 0, currentCase = 0) { - this.currentCase = currentCase - this.currentGroup = currentGroup - this.testData = data - } - - /** - * Checks whether given case-group pair exists in the test - */ - isCaseValid() { - if ( - this.currentGroup >= this.data.groups.length || - this.currentGroup < 0 - ) - return false - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - if (this.currentCase >= caseCount || this.currentCase < 0) return false - - return true - } - - /** - * Validate and set case and group in the test - * @param {number} groupIndex - Group index to set - * @param {number} caseIndex - Case index to set - */ - setCase(groupIndex, caseIndex) { - const newCase = new TestbenchData(this.testData, groupIndex, caseIndex) - if (newCase.isCaseValid()) { - this.currentGroup = groupIndex - this.currentCase = caseIndex - return true - } - - return false - } - - /** - * Validate and go to the next group. - * Skips over empty groups - */ - groupNext() { - const newCase = new TestbenchData(this.testData, this.currentGroup, 0) - const groupCount = newCase.testData.groups.length - let caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - - while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { - newCase.currentGroup++ - if (newCase.currentGroup >= groupCount) return false - caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - } - - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } - - /** - * Validate and go to the previous group. - * Skips over empty groups - */ - groupPrev() { - const newCase = new TestbenchData(this.testData, this.currentGroup, 0) - const groupCount = newCase.testData.groups.length - let caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - - while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { - newCase.currentGroup-- - if (newCase.currentGroup < 0) return false - caseCount = - newCase.testData.groups[newCase.currentGroup].inputs[0].values - .length - } - - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } - - /** - * Validate and go to the next case - */ - caseNext() { - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - if (this.currentCase >= caseCount - 1) return this.groupNext() - this.currentCase++ - return true - } - - /** - * Validate and go to the previous case - */ - casePrev() { - if (this.currentCase <= 0) { - if (!this.groupPrev()) return false - const caseCount = - this.testData.groups[this.currentGroup].inputs[0].values.length - this.currentCase = caseCount - 1 - return true - } - - this.currentCase-- - return true - } - - /** - * Finds and switches to the first non empty group to start the test from - */ - goToFirstValidGroup() { - const newCase = new TestbenchData(this.testData, 0, 0) - const caseCount = - newCase.testData.groups[this.currentGroup].inputs[0].values.length - - // If the first group is not empty, do nothing - if (caseCount > 0) return true - - // Otherwise go next until non empty group - const validExists = newCase.groupNext() - - // If all groups empty return false - if (!validExists) return false - - // else set case to the non empty group - this.currentGroup = newCase.currentGroup - this.currentCase = newCase.currentCase - return true - } -} - -/** - * UI Function - * Create prompt for the testbench UI when creator is opened - */ -function creatorOpenPrompt(creatorWindow) { - scheduleBackup() - const windowSVG = ` - - - - - ` - - const s = ` -
-
- ${windowSVG} -
-

A browser pop-up is opened to create the test

-

Please save the test to open it here

-
- ` - - $('#setTestbenchData').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - text: 'Close Pop-Up', - click() { - $(this).dialog('close') - creatorWindow.close() - }, - }, - ], - }) - - $('#setTestbenchData').empty() - $('#setTestbenchData').append(s) -} - -/** - * Interface function to run testbench. Called by testbench prompt on simulator or assignments - * @param {Object} data - Object containing Test Data - * @param {RunContext=} runContext - Whether simulator or Assignment called this function - * @param {Scope=} scope - the circuit - */ -export function runTestBench( - data, - scope = globalScope, - runContext = CONTEXT.CONTEXT_SIMULATOR -) { - const isValid = validate(data, scope) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - } - - if (runContext === CONTEXT.CONTEXT_SIMULATOR) { - const tempTestbenchData = new TestbenchData(data) - if (!tempTestbenchData.goToFirstValidGroup()) { - showMessage('Testbench: The test is empty') - return - } - - globalScope.testbenchData = tempTestbenchData - - updateTestbenchUI() - return - } - - if (runContext === CONTEXT.CONTEXT_ASSIGNMENTS) { - // Not implemented - } -} - -/** - * Updates the TestBench UI on the simulator with the current test attached - * If no test is attached then shows the 'No test attached' screen - * Called by runTestBench() when test is set, also called by UX/setupPanelListeners() - * whenever ux change requires this UI to update(such as clicking on a different circuit or - * loading a saved circuit) - */ -export function updateTestbenchUI() { - // Remove all listeners from buttons - $('.tb-dialog-button').off('click') - $('.tb-case-button').off('click') - - setupTestbenchUI() - if (globalScope.testbenchData != undefined) { - const { testbenchData } = globalScope - - // Initialize the UI - setUITableHeaders(testbenchData) - - // Add listeners to buttons - $('.tb-case-button#prev-case-btn').on( - 'click', - buttonListenerFunctions.previousCaseButton - ) - $('.tb-case-button#next-case-btn').on( - 'click', - buttonListenerFunctions.nextCaseButton - ) - $('.tb-case-button#prev-group-btn').on( - 'click', - buttonListenerFunctions.previousGroupButton - ) - $('.tb-case-button#next-group-btn').on( - 'click', - buttonListenerFunctions.nextGroupButton - ) - $('.tb-dialog-button#change-test-btn').on( - 'click', - buttonListenerFunctions.changeTestButton - ) - $('.tb-dialog-button#runall-btn').on( - 'click', - buttonListenerFunctions.runAllButton - ) - $('.tb-dialog-button#edit-test-btn').on( - 'click', - buttonListenerFunctions.editTestButton - ) - $('.tb-dialog-button#validate-btn').on( - 'click', - buttonListenerFunctions.validateButton - ) - $('.tb-dialog-button#remove-test-btn').on( - 'click', - buttonListenerFunctions.removeTestButton - ) - } - - // Add listener to attach test button - $('.tb-dialog-button#attach-test-btn').on( - 'click', - buttonListenerFunctions.attachTestButton - ) -} - -/** - * Defines all the functions called as event listeners for buttons on the UI - */ -const buttonListenerFunctions = { - previousCaseButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.casePrev() - buttonListenerFunctions.computeCase() - }, - - nextCaseButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.caseNext() - buttonListenerFunctions.computeCase() - }, - - previousGroupButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.groupPrev() - buttonListenerFunctions.computeCase() - }, - - nextGroupButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - globalScope.testbenchData.groupNext() - buttonListenerFunctions.computeCase() - }, - - changeTestButton: () => { - openCreator('create') - }, - - runAllButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - if (!isValid.ok) { - showMessage( - 'Testbench: Some elements missing from circuit. Click Validate to know more' - ) - return - } - const results = runAll(globalScope.testbenchData.testData, globalScope) - const { passed } = results.summary - const { total } = results.summary - const resultString = JSON.stringify(results.detailed) - $('#runall-summary').text(`${passed} out of ${total}`) - $('#runall-detailed-link').on('click', () => { - openCreator('result', resultString) - }) - $('.testbench-runall-label').css('display', 'table-cell') - $('.testbench-runall-label').delay(5000).fadeOut('slow') - }, - - editTestButton: () => { - const editDataString = JSON.stringify( - globalScope.testbenchData.testData - ) - openCreator('edit', editDataString) - }, - - validateButton: () => { - const isValid = validate( - globalScope.testbenchData.testData, - globalScope - ) - showValidationUI(isValid) - }, - - removeTestButton: async () => { - if ( - await confirmOption( - 'Are you sure you want to remove the test from the circuit?' - ) - ) { - globalScope.testbenchData = undefined - setupTestbenchUI() - } - }, - - attachTestButton: () => { - openCreator('create') - }, - - rerunTestButton: () => { - buttonListenerFunctions.computeCase() - }, - - computeCase: () => { - setUICurrentCase(globalScope.testbenchData) - const result = runSingleTest(globalScope.testbenchData, globalScope) - setUIResult(globalScope.testbenchData, result) - }, -} - -/** - * UI Function - * Checks whether test is attached to the scope and switches UI accordingly - */ -export function setupTestbenchUI() { - // Don't change UI if UI is minimized (because hide() and show() are recursive) - if ($('.testbench-manual-panel .minimize').css('display') === 'none') return - - if (globalScope.testbenchData === undefined) { - $('.tb-test-not-null').hide() - $('.tb-test-null').show() - return - } - - $('.tb-test-null').hide() - $('.tb-test-not-null').show() -} - -/** - * Run all the tests automatically. Called by runTestBench() - * @param {Object} data - Object containing Test Data - * @param {Scope=} scope - the circuit - */ -export function runAll(data, scope = globalScope) { - // Stop the clocks - // TestBench will now take over clock toggling - changeClockEnable(false) - - const { inputs, outputs, reset } = bindIO(data, scope) - let totalCases = 0 - let passedCases = 0 - - data.groups.forEach((group) => { - // for (const output of group.outputs) output.results = []; - group.outputs.forEach((output) => (output.results = [])) - for (let case_i = 0; case_i < group.n; case_i++) { - totalCases++ - // Set and propagate the inputs - setInputValues(inputs, group, case_i, scope) - // If sequential, trigger clock now - if (data.type === 'seq') tickClock(scope) - // Get output values - const caseResult = getOutputValues(data, outputs) - // Put the results in the data - - let casePassed = true // Tracks if current case passed or failed - - caseResult.forEach((_, outName) => { - // TODO: find() is not the best idea because of O(n) - const output = group.outputs.find( - (dataOutput) => dataOutput.label === outName - ) - output.results.push(caseResult.get(outName)) - - if (output.values[case_i] !== caseResult.get(outName)) - casePassed = false - }) - - // If current case passed, then increment passedCases - if (casePassed) passedCases++ - } - - // If sequential, trigger reset at the end of group (set) - if (data.type === 'seq') triggerReset(reset) - }) - - // Tests done, restart the clocks - changeClockEnable(true) - - // Return results - const results = {} - results.detailed = data - results.summary = { passed: passedCases, total: totalCases } - return results -} - -/** - * Runs single test - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleTest(testbenchData, scope) { - const data = testbenchData.testData - - let result - if (data.type === 'comb') { - result = runSingleCombinational(testbenchData, scope) - } else if (data.type === 'seq') { - result = runSingleSequential(testbenchData, scope) - } - - return result -} - -/** - * Runs single combinational test - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleCombinational(testbenchData, scope) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const { inputs, outputs } = bindIO(data, scope) - const group = data.groups[groupIndex] - - // Stop the clocks - changeClockEnable(false) - - // Set input values according to the test - setInputValues(inputs, group, caseIndex, scope) - // Check output values - const result = getOutputValues(data, outputs) - // Restart the clocks - changeClockEnable(true) - return result -} - -/** - * Runs single sequential test and all tests above it in the group - * Used in MANUAL mode - * @param {Object} data - Object containing Test Data - * @param {number} groupIndex - Index of the group to be tested - * @param {number} caseIndex - Index of the case inside the group - * @param {Scope} scope - The circuit - */ -function runSingleSequential(testbenchData, scope) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const { inputs, outputs, reset } = bindIO(data, scope) - const group = data.groups[groupIndex] - - // Stop the clocks - changeClockEnable(false) - - // Trigger reset - triggerReset(reset, scope) - - // Run the test and tests above in the same group - for (let case_i = 0; case_i <= caseIndex; case_i++) { - setInputValues(inputs, group, case_i, scope) - tickClock(scope) - } - - const result = getOutputValues(data, outputs) - - // Restart the clocks - changeClockEnable(true) - - return result -} - -/** - * Set and propogate the input values according to the testcase. - * Called by runSingle() and runAll() - * @param {Object} inputs - Object with keys as input names and values as inputs - * @param {Object} group - Test group - * @param {number} caseIndex - Index of the case in the group - * @param {Scope} scope - the circuit - */ -function setInputValues(inputs, group, caseIndex, scope) { - group.inputs.forEach((input) => { - inputs[input.label].state = parseInt(input.values[caseIndex], 2) - }) - - // Propagate inputs - play(scope) -} - -/** - * Gets Output values as a Map with keys as output name and value as output state - * @param {Object} outputs - Object with keys as output names and values as outputs - */ -function getOutputValues(data, outputs) { - const values = new Map() - - data.groups[0].outputs.forEach((dataOutput) => { - // Using node value because output state only changes on rendering - const resultValue = outputs[dataOutput.label].nodeList[0].value - const resultBW = outputs[dataOutput.label].nodeList[0].bitWidth - values.set(dataOutput.label, dec2bin(resultValue, resultBW)) - }) - - return values -} - -/** - * UI Function - * Shows validation UI - * @param {Object} validationErrors - Object with errors returned by validate() - */ -function showValidationUI(validationErrors) { - const checkSVG = ` - - - - ` - - let s = ` -
-
- ${checkSVG} -
- All good. No validation errors -
- ` - - if (!validationErrors.ok) { - s = ` -
-

Please fix these errors to run tests

- - - - - - ` - - validationErrors.invalids.forEach((vError) => { - s += ` - - - - - ` - }) - - s += '
IdentifierError
${vError.identifier}${vError.message}
' - } - - $('#testbenchValidate').dialog({ - resizable: false, - width: 'auto', - buttons: [ - { - text: 'Ok', - click() { - $(this).dialog('close') - }, - }, - { - text: 'Auto Fix', - click() { - const fixes = validationAutoFix(validationErrors) - showMessage(`Testbench: Auto fixed ${fixes} errors`) - $(this).dialog('close') - }, - }, - ], - }) - - $('#testbenchValidate').empty() - $('#testbenchValidate').append(s) -} - -/** - * Validate if all inputs and output elements are present with correct bitwidths - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validate(data, scope) { - let invalids = [] - - // Check for duplicate identifiers - if (!checkDistinctIdentifiersData(data)) { - invalids.push({ - type: VALIDATION_ERRORS.DUPLICATE_ID_DATA, - identifier: '-', - message: 'Duplicate identifiers in test data', - }) - } - - if (!checkDistinctIdentifiersScope(scope)) { - invalids.push({ - type: VALIDATION_ERRORS.DUPLICATE_ID_SCOPE, - identifier: '-', - message: 'Duplicate identifiers in circuit', - }) - } - - // Don't do further checks if duplicates - if (invalids.length > 0) return { ok: false, invalids } - - // Validate inputs and outputs - const inputsValid = validateInputs(data, scope) - const outputsValid = validateOutputs(data, scope) - - invalids = inputsValid.ok ? invalids : invalids.concat(inputsValid.invalids) - invalids = outputsValid.ok - ? invalids - : invalids.concat(outputsValid.invalids) - - // Validate presence of reset if test is sequential - if (data.type === 'seq') { - const resetPresent = scope.Input.some( - (simulatorReset) => - simulatorReset.label === 'RST' && - simulatorReset.bitWidth === 1 && - simulatorReset.objectType === 'Input' - ) - - if (!resetPresent) { - invalids.push({ - type: VALIDATION_ERRORS.NO_RST, - identifier: 'RST', - message: 'Reset(RST) not present in circuit', - }) - } - } - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Autofix whatever is possible in validation errors. - * returns number of autofixed errors - * @param {Object} validationErrors - Object with errors returned by validate() - */ -function validationAutoFix(validationErrors) { - // Currently only autofixes bitwidths - let fixedErrors = 0 - // Return if no errors - if (validationErrors.ok) return fixedErrors - - const bitwidthErrors = validationErrors.invalids.filter( - (vError) => vError.type === VALIDATION_ERRORS.WRONGBITWIDTH - ) - - bitwidthErrors.forEach((bwError) => { - const { element, expectedBitWidth } = bwError.extraInfo - element.newBitWidth(expectedBitWidth) - fixedErrors++ - }) - - return fixedErrors -} - -/** - * Checks if all the labels in the test data are unique. Called by validate() - * @param {Object} data - Object containing Test Data - */ -function checkDistinctIdentifiersData(data) { - const inputIdentifiersData = data.groups[0].inputs.map( - (input) => input.label - ) - const outputIdentifiersData = data.groups[0].outputs.map( - (output) => output.label - ) - const identifiersData = inputIdentifiersData.concat(outputIdentifiersData) - - return new Set(identifiersData).size === identifiersData.length -} - -/** - * Checks if all the input/output labels in the scope are unique. Called by validate() - * TODO: Replace with identifiers - * @param {Scope} scope - the circuit - */ -function checkDistinctIdentifiersScope(scope) { - const inputIdentifiersScope = scope.Input.map((input) => input.label) - const outputIdentifiersScope = scope.Output.map((output) => output.label) - let identifiersScope = inputIdentifiersScope.concat(outputIdentifiersScope) - - // Remove identifiers which have not been set yet (ie. empty strings) - identifiersScope = identifiersScope.filter((identifer) => identifer != '') - - return new Set(identifiersScope).size === identifiersScope.length -} - -/** - * Validates presence and bitwidths of test inputs in the circuit. - * Called by validate() - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validateInputs(data, scope) { - const invalids = [] - - data.groups[0].inputs.forEach((dataInput) => { - const matchInput = scope.Input.find( - (simulatorInput) => simulatorInput.label === dataInput.label - ) - - if (matchInput === undefined) { - invalids.push({ - type: VALIDATION_ERRORS.NOTPRESENT, - identifier: dataInput.label, - message: 'Input is not present in the circuit', - }) - } else if (matchInput.bitWidth !== dataInput.bitWidth) { - invalids.push({ - type: VALIDATION_ERRORS.WRONGBITWIDTH, - identifier: dataInput.label, - extraInfo: { - element: matchInput, - expectedBitWidth: dataInput.bitWidth, - }, - message: `Input bitwidths don't match in circuit and test (${matchInput.bitWidth} vs ${dataInput.bitWidth})`, - }) - } - }) - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Validates presence and bitwidths of test outputs in the circuit. - * Called by validate() - * @param {Object} data - Object containing Test Data - * @param {Scope} scope - the circuit - */ -function validateOutputs(data, scope) { - const invalids = [] - - data.groups[0].outputs.forEach((dataOutput) => { - const matchOutput = scope.Output.find( - (simulatorOutput) => simulatorOutput.label === dataOutput.label - ) - - if (matchOutput === undefined) { - invalids.push({ - type: VALIDATION_ERRORS.NOTPRESENT, - identifier: dataOutput.label, - message: 'Output is not present in the circuit', - }) - } else if (matchOutput.bitWidth !== dataOutput.bitWidth) { - invalids.push({ - type: VALIDATION_ERRORS.WRONGBITWIDTH, - identifier: dataOutput.label, - extraInfo: { - element: matchOutput, - expectedBitWidth: dataOutput.bitWidth, - }, - message: `Output bitwidths don't match in circuit and test (${matchOutput.bitWidth} vs ${dataOutput.bitWidth})`, - }) - } - }) - - if (invalids.length > 0) return { ok: false, invalids } - return { ok: true } -} - -/** - * Returns object of scope inputs and outputs keyed by their labels - * @param {Object} data - Object containing Test Data - * @param {Scope=} scope - the circuit - */ -function bindIO(data, scope) { - const inputs = {} - const outputs = {} - let reset - - data.groups[0].inputs.forEach((dataInput) => { - inputs[dataInput.label] = scope.Input.find( - (simulatorInput) => simulatorInput.label === dataInput.label - ) - }) - - data.groups[0].outputs.forEach((dataOutput) => { - outputs[dataOutput.label] = scope.Output.find( - (simulatorOutput) => simulatorOutput.label === dataOutput.label - ) - }) - - if (data.type === 'seq') { - reset = scope.Input.find( - (simulatorOutput) => simulatorOutput.label === 'RST' - ) - } - - return { inputs, outputs, reset } -} - -/** - * Ticks clock recursively one full cycle (Only used in testbench context) - * @param {Scope} scope - the circuit whose clock to be ticked - */ -function tickClock(scope) { - scope.clockTick() - play(scope) - scope.clockTick() - play(scope) -} - -/** - * Triggers reset (Only used in testbench context) - * @param {Input} reset - reset pin to be triggered - * @param {Scope} scope - the circuit - */ -function triggerReset(reset, scope) { - reset.state = 1 - play(scope) - reset.state = 0 - play(scope) -} - -/** - * UI Function - * Sets IO labels and bitwidths on UI table - * Called by simulatorRunTestbench() - * @param {Object} data - Object containing the test data - */ -function setUITableHeaders(testbenchData) { - const data = testbenchData.testData - const inputCount = data.groups[0].inputs.length - const outputCount = data.groups[0].outputs.length - - $('#tb-manual-table-inputs-head').attr('colspan', inputCount) - $('#tb-manual-table-outputs-head').attr('colspan', outputCount) - - $('.testbench-runall-label').css('display', 'none') - - $('.tb-data#data-title') - .children() - .eq(1) - .text(data.title || 'Untitled') - $('.tb-data#data-type') - .children() - .eq(1) - .text(data.type === 'comb' ? 'Combinational' : 'Sequential') - - $('#tb-manual-table-labels').html('LABELS') - $('#tb-manual-table-bitwidths').html('Bitwidth') - - data.groups[0].inputs.concat(data.groups[0].outputs).forEach((io) => { - const label = `${escapeHtml(io.label)}` - const bw = `${escapeHtml(io.bitWidth.toString())}` - $('#tb-manual-table-labels').append(label) - $('#tb-manual-table-bitwidths').append(bw) - }) - - setUICurrentCase(testbenchData) -} - -/** - * UI Function - * Set current test case data on the UI - * @param {Object} data - Object containing the test data - * @param {number} groupIndex - Index of the group of current case - * @param {number} caseIndex - Index of the case within the group - */ -function setUICurrentCase(testbenchData) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - - const currCaseElement = $('#tb-manual-table-current-case') - currCaseElement.empty() - currCaseElement.append('Current Case') - $('#tb-manual-table-test-result').empty() - $('#tb-manual-table-test-result').append('Result') - - data.groups[groupIndex].inputs.forEach((input) => { - currCaseElement.append( - `${escapeHtml(input.values[caseIndex])}` - ) - }) - - data.groups[groupIndex].outputs.forEach((output) => { - currCaseElement.append( - `${escapeHtml(output.values[caseIndex])}` - ) - }) - - $('.testbench-manual-panel .group-label').text( - data.groups[groupIndex].label - ) - $('.testbench-manual-panel .case-label').text(caseIndex + 1) -} - -/** - * UI Function - * Set the current test case result on the UI - * @param {Object} data - Object containing the test data - * @param {Map} result - Map containing the output values (returned by getOutputValues()) - */ -function setUIResult(testbenchData, result) { - const data = testbenchData.testData - const groupIndex = testbenchData.currentGroup - const caseIndex = testbenchData.currentCase - const resultElement = $('#tb-manual-table-test-result') - let inputCount = data.groups[0].inputs.length - resultElement.empty() - resultElement.append('Result') - while (inputCount--) { - resultElement.append(' - ') - } - - for (const output of result.keys()) { - const resultValue = result.get(output) - const expectedValue = data.groups[groupIndex].outputs.find( - (dataOutput) => dataOutput.label === output - ).values[caseIndex] - const color = resultValue === expectedValue ? '#17FC12' : '#FF1616' - resultElement.append( - `${escapeHtml(resultValue)}` - ) - } -} - -/** - * Use this function to navigate to test creator. This function starts the storage listener - * so the test is loaded directly into the simulator - * @param {string} type - 'create', 'edit' or 'result' - * @param {String} dataString - data in JSON string to load in case of 'edit' and 'result' - */ -function openCreator(type, dataString) { - const popupHeight = 800 - const popupWidth = 1200 - const popupTop = (window.height - popupHeight) / 2 - const popupLeft = (window.width - popupWidth) / 2 - const POPUP_STYLE_STRING = `height=${popupHeight},width=${popupWidth},top=${popupTop},left=${popupLeft}` - let popUp - - /* Listener to catch testData from pop up and load it onto the testbench */ - const dataListener = (message) => { - if ( - message.origin !== window.origin || - message.data.type !== 'testData' - ) - return - - // Check if the current scope requested the creator pop up - const data = JSON.parse(message.data.data) - - // Unbind event listener - window.removeEventListener('message', dataListener) - - // If scopeID does not match, do nothing and return - if (data.scopeID != globalScope.id) return - - // Load test data onto the scope - runTestBench(data.testData, globalScope, CONTEXT.CONTEXT_SIMULATOR) - - // Close the 'Pop up is open' dialog - $('#setTestbenchData').dialog('close') - } - - if (type === 'create') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - creatorOpenPrompt(popUp) - window.addEventListener('message', dataListener) - } - - if (type === 'edit') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&data=${dataString}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - creatorOpenPrompt(popUp) - window.addEventListener('message', dataListener) - } - - if (type === 'result') { - const url = `${TESTBENCH_CREATOR_PATH}?scopeID=${globalScope.id}&result=${dataString}&popUp=true` - popUp = window.open(url, 'popupWindow', POPUP_STYLE_STRING) - } - - // Check if popup was closed (in case it was closed by window's X button), - // then close 'popup open' dialog - if (popUp && type !== 'result') { - const checkPopUp = setInterval(() => { - if (popUp.closed) { - // Close the dialog if it's open - if ($('#setTestbenchData').dialog('isOpen')) - $('#setTestbenchData').dialog('close') - - // Remove the event listener that listens for data from popup - window.removeEventListener('message', dataListener) - clearInterval(checkPopUp) - } - }, 1000) - } -} diff --git a/v1/src/simulator/src/testbench.ts b/v1/src/simulator/src/testbench.ts new file mode 100644 index 00000000..70676e09 --- /dev/null +++ b/v1/src/simulator/src/testbench.ts @@ -0,0 +1,761 @@ +import { TestData } from "#/store/testBenchStore"; +import { showMessage } from '#/simulator/src/utils' +import { useTestBenchStore, TestBenchData } from "#/store/testBenchStore"; +import { changeClockEnable } from '#/simulator/src/sequential' +import { play } from '#/simulator/src/engine' +import { confirmOption } from '#/components/helpers/confirmComponent/ConfirmComponent.vue' +import { escapeHtml } from '#/simulator/src/utils' + +const CONTEXT = { + CONTEXT_SIMULATOR: 0, + CONTEXT_ASSIGNMENTS: 1, +} + +export const VALIDATION_ERRORS = { + NOTPRESENT: 0, // Element is not present in the circuit + WRONGBITWIDTH: 1, // Element is present but has incorrect bitwidth + DUPLICATE_ID_DATA: 2, // Duplicate identifiers in test data + DUPLICATE_ID_SCOPE: 3, // Duplicate identifiers in scope + NO_RST: 4, // Sequential circuit but no reset(RST) in scope +} + +export class TestbenchData { + currentCase: number; + currentGroup: number; + testData: TestData; + + constructor(data: TestData, currentGroup = 0, currentCase = 0) { + this.currentCase = currentCase; + this.currentGroup = currentGroup; + this.testData = data; + } + + isCaseValid() { + if (this.currentGroup >= this.testData.groups.length || this.currentGroup < 0) return false; + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + if (this.currentCase >= caseCount || this.currentCase < 0) return false; + + return true; + } + + setCase(groupIndex: number, caseIndex: number) { + const newCase = new TestbenchData(this.testData, groupIndex, caseIndex); + if (newCase.isCaseValid()) { + this.currentGroup = groupIndex; + this.currentCase = caseIndex; + return true; + } + return false; + } + + groupNext() { + const newCase = new TestbenchData(this.testData, this.currentGroup, 0); + const groupCount = newCase.testData.groups.length; + let caseCount = 0; + if (newCase.testData.groups[this.currentGroup].inputs[0]) { + caseCount = newCase.testData.groups[this.currentGroup].inputs[0].values.length; + } + + while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { + newCase.currentGroup++; + if (newCase.currentGroup >= groupCount) return false; + caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + } + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } + + groupPrev() { + const newCase = new TestbenchData(this.testData, this.currentGroup, 0); + const groupCount = newCase.testData.groups.length; + let caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + + while (caseCount === 0 || this.currentGroup === newCase.currentGroup) { + newCase.currentGroup--; + if (newCase.currentGroup < 0) return false; + caseCount = newCase.testData.groups[newCase.currentGroup].inputs[0].values.length; + } + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } + + caseNext() { + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + if (this.currentCase >= caseCount - 1) return this.groupNext(); + this.currentCase++; + return true; + } + + casePrev() { + if (this.currentCase <= 0) { + if (!this.groupPrev()) return false; + const caseCount = this.testData.groups[this.currentGroup].inputs[0].values.length; + this.currentCase = caseCount - 1; + return true; + } + + this.currentCase--; + return true; + } + + goToFirstValidGroup() { + const newCase = new TestbenchData(this.testData, 0, 0); + let caseCount = 0; + if (newCase.testData.groups[this.currentGroup].inputs[0]) { + caseCount = newCase.testData.groups[this.currentGroup].inputs[0].values.length; + } + + if (caseCount > 0) return true; + + const validExists = newCase.groupNext(); + + if (!validExists) return false; + + this.currentGroup = newCase.currentGroup; + this.currentCase = newCase.currentCase; + return true; + } +} + +/** + * Checks if all the labels in the test data are unique. Called by validate() + */ +function checkDistinctIdentifiersData(data: TestData) { + const inputIdentifiersData = data.groups[0].inputs.map( + (input) => input.label + ) + const outputIdentifiersData = data.groups[0].outputs.map( + (output) => output.label + ) + const identifiersData = inputIdentifiersData.concat(outputIdentifiersData) + + return new Set(identifiersData).size === identifiersData.length +} + +/** + * Checks if all the input/output labels in the scope are unique. Called by validate() + * TODO: Replace with identifiers + */ +function checkDistinctIdentifiersScope(scope) { + const inputIdentifiersScope = scope.Input.map((input) => input.label) + const outputIdentifiersScope = scope.Output.map((output) => output.label) + let identifiersScope = inputIdentifiersScope.concat(outputIdentifiersScope) + + // Remove identifiers which have not been set yet (ie. empty strings) + identifiersScope = identifiersScope.filter((identifer) => identifer != '') + + return new Set(identifiersScope).size === identifiersScope.length +} + +/** + * Validates presence and bitwidths of test inputs in the circuit. + * Called by validate() + */ +function validateInputs(data: TestData, scope) { + const invalids: Invalids[] = [] + + data.groups[0].inputs.forEach((dataInput) => { + const matchInput = scope.Input.find( + (simulatorInput) => simulatorInput.label === dataInput.label + ) + + if (matchInput === undefined) { + invalids.push({ + type: VALIDATION_ERRORS.NOTPRESENT, + identifier: dataInput.label, + message: 'Input is not present in the circuit', + }) + } else if (matchInput.bitWidth !== dataInput.bitWidth) { + invalids.push({ + type: VALIDATION_ERRORS.WRONGBITWIDTH, + identifier: dataInput.label, + extraInfo: { + element: matchInput, + expectedBitWidth: dataInput.bitWidth, + }, + message: `Input bitwidths don't match in circuit and test (${matchInput.bitWidth} vs ${dataInput.bitWidth})`, + }) + } + }) + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +interface Invalids { + type: number + identifier: string + message: string + extraInfo?: any +} + +/** + * Validates presence and bitwidths of test outputs in the circuit. + * Called by validate() + */ +function validateOutputs(data: TestData, scope) { + const invalids: Invalids[] = [] + + data.groups[0].outputs.forEach((dataOutput) => { + const matchOutput = scope.Output.find( + (simulatorOutput) => simulatorOutput.label === dataOutput.label + ) + + if (matchOutput === undefined) { + invalids.push({ + type: VALIDATION_ERRORS.NOTPRESENT, + identifier: dataOutput.label, + message: 'Output is not present in the circuit', + }) + } else if (matchOutput.bitWidth !== dataOutput.bitWidth) { + invalids.push({ + type: VALIDATION_ERRORS.WRONGBITWIDTH, + identifier: dataOutput.label, + extraInfo: { + element: matchOutput, + expectedBitWidth: dataOutput.bitWidth, + }, + message: `Output bitwidths don't match in circuit and test (${matchOutput.bitWidth} vs ${dataOutput.bitWidth})`, + }) + } + }) + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +/** + * Validate if all inputs and output elements are present with correct bitwidths + */ +function validate(data: TestData, scope) { + let invalids = [] + + // Check for duplicate identifiers + if (!checkDistinctIdentifiersData(data)) { + invalids.push({ + type: VALIDATION_ERRORS.DUPLICATE_ID_DATA, + identifier: '-', + message: 'Duplicate identifiers in test data', + }) + } + + if (!checkDistinctIdentifiersScope(scope)) { + invalids.push({ + type: VALIDATION_ERRORS.DUPLICATE_ID_SCOPE, + identifier: '-', + message: 'Duplicate identifiers in circuit', + }) + } + + // Don't do further checks if duplicates + if (invalids.length > 0) return { ok: false, invalids } + + // Validate inputs and outputs + const inputsValid = validateInputs(data, scope) + const outputsValid = validateOutputs(data, scope) + + invalids = inputsValid.ok ? invalids : invalids.concat(inputsValid.invalids) + invalids = outputsValid.ok + ? invalids + : invalids.concat(outputsValid.invalids) + + // Validate presence of reset if test is sequential + if (data.type === 'seq') { + const resetPresent = scope.Input.some( + (simulatorReset) => + simulatorReset.label === 'RST' && + simulatorReset.bitWidth === 1 && + simulatorReset.objectType === 'Input' + ) + + if (!resetPresent) { + invalids.push({ + type: VALIDATION_ERRORS.NO_RST, + identifier: 'RST', + message: 'Reset(RST) not present in circuit', + }) + } + } + + if (invalids.length > 0) return { ok: false, invalids } + return { ok: true } +} + +/** + * Returns object of scope inputs and outputs keyed by their labels + */ +function bindIO(data: TestData, scope) { + const inputs: { [key: string]: any } = {} + const outputs: { [key: string]: any } = {} + let reset + + data.groups[0].inputs.forEach((dataInput) => { + inputs[dataInput.label] = scope.Input.find( + (simulatorInput) => simulatorInput.label === dataInput.label + ) + }) + + data.groups[0].outputs.forEach((dataOutput) => { + outputs[dataOutput.label] = scope.Output.find( + (simulatorOutput) => simulatorOutput.label === dataOutput.label + ) + }) + + if (data.type === 'seq') { + reset = scope.Input.find( + (simulatorOutput) => simulatorOutput.label === 'RST' + ) + } + + return { inputs, outputs, reset } +} + +/** + * Set and propogate the input values according to the testcase. + * Called by runSingle() and runAll() + */ +function setInputValues(inputs, group, caseIndex: number, scope) { + group.inputs.forEach((input) => { + inputs[input.label].state = parseInt(input.values[caseIndex], 2) + }) + + // Propagate inputs + play(scope) +} + +/** + * Ticks clock recursively one full cycle (Only used in testbench context) + */ +function tickClock(scope: any) { + scope.clockTick() + play(scope) + scope.clockTick() + play(scope) +} + +// Do we have any other function to do this? +// Utility function. Converts decimal number to binary string +function dec2bin(dec: number | undefined, bitWidth = undefined) { + if (dec === undefined) return 'X' + const bin = (dec >>> 0).toString(2) + if (!bitWidth) return bin + + return '0'.repeat(bitWidth - bin.length) + bin +} + +/** + * Gets Output values as a Map with keys as output name and value as output state + */ +function getOutputValues(data: TestData, outputs) { + const values = new Map() + + data.groups[0].outputs.forEach((dataOutput) => { + // Using node value because output state only changes on rendering + const resultValue = outputs[dataOutput.label].nodeList[0].value + const resultBW = outputs[dataOutput.label].nodeList[0].bitWidth + values.set(dataOutput.label, dec2bin(resultValue, resultBW)) + }) + + return values +} + +/** + * Triggers reset (Only used in testbench context) + */ +function triggerReset(reset: any, scope: any) { + reset.state = 1 + play(scope) + reset.state = 0 + play(scope) +} + +/** + * Interface function to run testbench. Called by testbench prompt on simulator or assignments + */ +export function runTestBench( + data: TestData, + scope = globalScope, + runContext = CONTEXT.CONTEXT_SIMULATOR +) { + const testBenchStore = useTestBenchStore() + // const { testbenchData } = toRefs(testBenchStore) + const isValid = validate(data, scope) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + } + + if (runContext === CONTEXT.CONTEXT_SIMULATOR) { + const tempTestbenchData = new TestbenchData(data) + if (!tempTestbenchData.goToFirstValidGroup()) { + showMessage('Testbench: The test is empty') + testBenchStore.showTestbenchUI = false + return + } + + testBenchStore.testbenchData = tempTestbenchData + + return + } + + if (runContext === CONTEXT.CONTEXT_ASSIGNMENTS) { + // Not implemented + } +} + +interface Results { + detailed: TestData + summary: { + passed: number + total: number + } +} + +/** + * Run all the tests automatically. Called by runTestBench() + */ +export function runAll(data: TestData, scope = globalScope) { + // Stop the clocks + // TestBench will now take over clock toggling + changeClockEnable(false) + + const { inputs, outputs, reset } = bindIO(data, scope) + let totalCases = 0 + let passedCases = 0 + + data.groups.forEach((group) => { + // for (const output of group.outputs) output.results = []; + group.outputs.forEach((output) => (output.results = [])) + for (let case_i = 0; case_i < group.n; case_i++) { + totalCases++ + // Set and propagate the inputs + setInputValues(inputs, group, case_i, scope) + // If sequential, trigger clock now + if (data.type === 'seq') tickClock(scope) + // Get output values + const caseResult = getOutputValues(data, outputs) + // Put the results in the data + + let casePassed = true // Tracks if current case passed or failed + + caseResult.forEach((_, outName) => { + // TODO: find() is not the best idea because of O(n) + const output = group.outputs.find( + (dataOutput) => dataOutput.label === outName + ) + output?.results?.push(caseResult.get(outName)) + + if (output?.values[case_i] !== caseResult.get(outName)) + casePassed = false + }) + + // If current case passed, then increment passedCases + if (casePassed) passedCases++ + } + + // If sequential, trigger reset at the end of group (set) + if (data.type === 'seq') triggerReset(reset, scope) // qs. why scope is not passed? + }) + + // Tests done, restart the clocks + changeClockEnable(true) + + // Return results + const results: Results = { + detailed: data, + summary: { passed: passedCases, total: totalCases } + }; + return results +} + +/** + * Runs single combinational test + */ +function runSingleCombinational(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + const groupIndex = testbenchData.currentGroup + const caseIndex = testbenchData.currentCase + + const { inputs, outputs } = bindIO(data, scope) + const group = data.groups[groupIndex] + + // Stop the clocks + changeClockEnable(false) + + // Set input values according to the test + setInputValues(inputs, group, caseIndex, scope) + // Check output values + const result = getOutputValues(data, outputs) + // Restart the clocks + changeClockEnable(true) + return result +} + +/** + * Runs single sequential test and all tests above it in the group + * Used in MANUAL mode + */ +function runSingleSequential(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + const groupIndex = testbenchData.currentGroup + const caseIndex = testbenchData.currentCase + + const { inputs, outputs, reset } = bindIO(data, scope) + const group = data.groups[groupIndex] + + // Stop the clocks + changeClockEnable(false) + + // Trigger reset + triggerReset(reset, scope) + + // Run the test and tests above in the same group + for (let case_i = 0; case_i <= caseIndex; case_i++) { + setInputValues(inputs, group, case_i, scope) + tickClock(scope) + } + + const result = getOutputValues(data, outputs) + + // Restart the clocks + changeClockEnable(true) + + return result +} + +type openCreatorType = 'create' | 'edit' | 'result' + +export function openCreator(type: openCreatorType) { + const testBenchStore = useTestBenchStore(); + if (type === 'create') { + testBenchStore.showResults = false; + testBenchStore.readOnly = false; + testBenchStore.showTestBenchCreator = true; + } + + if (type === 'edit') { + testBenchStore.showResults = false; + testBenchStore.readOnly = false; + testBenchStore.showTestBenchCreator = true; + } + + if (type === 'result') { + testBenchStore.showResults = true; + testBenchStore.readOnly = true; + testBenchStore.showTestBenchCreator = true; + } +} + +/** +* UI Function +* Set the current test case result on the UI +*/ + +function setUIResult(testbenchData: TestBenchData, result) { + const testBenchStore = useTestBenchStore(); + const data = testbenchData.testData; + const groupIndex = testbenchData.currentGroup; + const caseIndex = testbenchData.currentCase; + + const inputCount = data.groups[0].inputs.length; + const newResultValues = []; + + for (let i = 0; i < inputCount; i++) { + newResultValues.push({ value: ' - ', color: '#000' }); + } + + for (const output of result.keys()) { + const resultValue = result.get(output); + const outputData = data.groups[groupIndex].outputs.find( + (dataOutput) => dataOutput.label === output + ); + + const expectedValue = outputData ? outputData.values[caseIndex] : undefined; + const color = resultValue === expectedValue ? '#17FC12' : '#FF1616'; + newResultValues.push({ value: escapeHtml(resultValue), color }); + } + + testBenchStore.resultValues = newResultValues; +} + +/** + * Defines all the functions called as event listeners for buttons on the UI + */ +export const buttonListenerFunctions = { + previousCaseButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.casePrev) { + testbenchData.casePrev(); + } + buttonListenerFunctions.computeCase() + }, + + nextCaseButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.caseNext) { + testbenchData.caseNext(); + } + buttonListenerFunctions.computeCase() + }, + + previousGroupButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.groupPrev) { + testbenchData.groupPrev(); + } + buttonListenerFunctions.computeCase() + }, + + nextGroupButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const testbenchData = useTestBenchStore().testbenchData; + if (testbenchData && testbenchData.groupNext) { + testbenchData.groupNext(); + } + buttonListenerFunctions.computeCase() + }, + + changeTestButton: () => { + openCreator('create') + }, + + runAllButton: () => { + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + if (!isValid.ok) { + showMessage( + 'Testbench: Some elements missing from circuit. Click Validate to know more' + ) + return + } + const results = runAll(useTestBenchStore().testbenchData.testData, globalScope) + const { passed } = results.summary + const { total } = results.summary + + useTestBenchStore().passed = passed + useTestBenchStore().total = total + useTestBenchStore().showPassed = true + + setTimeout(() => { + useTestBenchStore().showPassed = false + }, 3000) + }, + + editTestButton: () => { + const editDataString = JSON.stringify( + useTestBenchStore().testbenchData.testData + ) + openCreator('edit') + }, + + validateButton: () => { + const testBenchStore = useTestBenchStore() + const isValid = validate( + useTestBenchStore().testbenchData.testData, + globalScope + ) + testBenchStore.validationErrors = isValid + testBenchStore.showTestBenchValidator = true + }, + + removeTestButton: async () => { + if ( + await confirmOption( + 'Are you sure you want to remove the test from the circuit?' + ) + ) { + useTestBenchStore().testbenchData = { + testData: { + type: "", + title: "", + groups: [ + { + label: "Group 1", + inputs: [], + outputs: [], + n: 0 + } + ], + }, + currentGroup: 0, + currentCase: 0, + } + useTestBenchStore().showTestbenchUI = false + } + }, + + attachTestButton: () => { + openCreator('create') + }, + + rerunTestButton: () => { + buttonListenerFunctions.computeCase() + }, + + computeCase: () => { + const result = runSingleTest(useTestBenchStore().testbenchData, globalScope) + setUIResult(useTestBenchStore().testbenchData, result) + }, +} + +/** +* Runs single test +*/ +function runSingleTest(testbenchData: TestBenchData, scope) { + const data = testbenchData.testData + + let result + if (data.type === 'comb') { + result = runSingleCombinational(testbenchData, scope) + } else if (data.type === 'seq') { + result = runSingleSequential(testbenchData, scope) + } + + return result +} diff --git a/v1/src/simulator/src/testbench/ForceGate.js b/v1/src/simulator/src/testbench/ForceGate.js index 5da82c6f..332af06c 100644 --- a/v1/src/simulator/src/testbench/ForceGate.js +++ b/v1/src/simulator/src/testbench/ForceGate.js @@ -1,6 +1,6 @@ import CircuitElement from '../circuitElement' import Node, { findNode } from '../node' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { fillText4 } from '../canvasApi' /** * @class diff --git a/v1/src/simulator/src/testbench/testbenchInput.js b/v1/src/simulator/src/testbench/testbenchInput.js index bdf7452b..f877aca8 100644 --- a/v1/src/simulator/src/testbench/testbenchInput.js +++ b/v1/src/simulator/src/testbench/testbenchInput.js @@ -1,5 +1,5 @@ import CircuitElement from '../circuitElement' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, lineTo, moveTo, fillText } from '../canvasApi' import Node, { findNode } from '../node' import plotArea from '../plotArea' @@ -63,12 +63,11 @@ export default class TB_Input extends CircuitElement { setup() { this.iteration = 0 this.running = false - this.nodeList.clean(this.clockInp) + this.nodeList = this.nodeList.filter(x=> x !== this.clockInp); this.deleteNodes() this.nodeList = [] this.nodeList.push(this.clockInp) this.testData = this.testData || { inputs: [], outputs: [], n: 0 } - // this.clockInp = new Node(0,20, 0,this,1); this.setDimensions() diff --git a/v1/src/simulator/src/testbench/testbenchOutput.js b/v1/src/simulator/src/testbench/testbenchOutput.js index 865ec258..49117626 100644 --- a/v1/src/simulator/src/testbench/testbenchOutput.js +++ b/v1/src/simulator/src/testbench/testbenchOutput.js @@ -1,5 +1,5 @@ import CircuitElement from '../circuitElement' -import simulationArea from '../simulationArea' +import { simulationArea } from '../simulationArea' import { correctWidth, fillText } from '../canvasApi' import Node, { findNode } from '../node' @@ -29,15 +29,8 @@ function dec2bin(dec, bitWidth = undefined) { export default class TB_Output extends CircuitElement { constructor(x, y, scope = globalScope, dir = 'RIGHT', identifier) { super(x, y, scope, dir, 1) - // this.setDimensions(60,20); this.objectType = 'TB_Output' this.scope.TB_Output.push(this) - - // this.xSize=10; - - // this.plotValues = []; - // this.inp1 = new Node(0, 0, 0, this); - // this.inp1 = new Node(100, 100, 0, this); this.setIdentifier(identifier || 'Test1') this.inputs = [] this.testBenchInput = undefined @@ -45,10 +38,6 @@ export default class TB_Output extends CircuitElement { this.setup() } - // TB_Output.prototype.dblclick=function(){ - // this.testData=JSON.parse(prompt("Enter TestBench Json")); - // this.setup(); - // } setDimensions() { this.leftDimensionX = 0 this.rightDimensionX = 160 @@ -61,9 +50,6 @@ export default class TB_Output extends CircuitElement { } setup() { - // this.iteration = 0; - // this.running = false; - // this.nodeList.clean(this.clockInp); this.deleteNodes() // deletes all nodes whenever setup is called. this.nodeList = [] @@ -161,22 +147,6 @@ export default class TB_Output extends CircuitElement { yRotate = 20 } - // rect2(ctx, -120+xRotate+this.xSize, -20+yRotate, 120-this.xSize, 40, xx, yy, "RIGHT"); - // if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) - // ctx.fillStyle = "rgba(255, 255, 32,0.8)"; - // ctx.fill(); - // ctx.stroke(); - // - // ctx.font = "14px Raleway"; - // this.xOff = ctx.measureText(this.identifier).width; - // ctx.beginPath(); - // rect2(ctx, -105+xRotate+this.xSize, -11+yRotate,this.xOff + 10, 23, xx, yy, "RIGHT"); - // ctx.fillStyle = "#eee" - // ctx.strokeStyle = "#ccc"; - // ctx.fill(); - // ctx.stroke(); - // - ctx.beginPath() ctx.textAlign = 'center' ctx.fillStyle = 'black' @@ -187,9 +157,6 @@ export default class TB_Output extends CircuitElement { yy + 14, 10 ) - - // fillText(ctx, ["Not Running","Running"][+this.running], xx + this.rightDimensionX/ 2 , yy + 14 + 10 + 20*this.testData.inputs.length, 10); - // fillText(ctx, "Case: "+(this.iteration), xx + this.rightDimensionX/ 2 , yy + 14 + 20 + 20*this.testData.inputs.length, 10); fillText( ctx, ['Unpaired', 'Paired'][+(this.testBenchInput != undefined)], @@ -209,7 +176,6 @@ export default class TB_Output extends CircuitElement { i < this.testBenchInput.testData.outputs.length; i++ ) { - // ctx.beginPath(); fillText( ctx, this.testBenchInput.testData.outputs[i].label, diff --git a/v1/src/simulator/src/themer/customThemeAbstraction.js b/v1/src/simulator/src/themer/customThemeAbstraction.ts similarity index 74% rename from v1/src/simulator/src/themer/customThemeAbstraction.js rename to v1/src/simulator/src/themer/customThemeAbstraction.ts index 399134ea..341226d0 100644 --- a/v1/src/simulator/src/themer/customThemeAbstraction.js +++ b/v1/src/simulator/src/themer/customThemeAbstraction.ts @@ -3,7 +3,24 @@ * @param {*} themeOptions * @returns an Object */ -export const CreateAbstraction = (themeOptions) => { + +interface ThemeProperties { + color: string; + description: string; + ref: string[]; +} + +export interface Themes { + Navbar?: ThemeProperties; + Primary?: ThemeProperties; + Secondary?: ThemeProperties; + Canvas?: ThemeProperties; + Stroke?: ThemeProperties; + Text?: ThemeProperties; + Borders?: ThemeProperties; +} + +export const CreateAbstraction = (themeOptions: { [key: string]: string }): Themes => { return { Navbar: { color: themeOptions['--bg-navbar'], diff --git a/v1/src/simulator/src/themer/customThemer.js b/v1/src/simulator/src/themer/customThemer.js deleted file mode 100644 index 51a7e0b2..00000000 --- a/v1/src/simulator/src/themer/customThemer.js +++ /dev/null @@ -1,154 +0,0 @@ -// /* eslint-disable import/prefer-default-export */ -// /* eslint-disable import/no-cycle */ -// import { dots } from '../canvasApi' -// import themeOptions from './themes' -// import { updateThemeForStyle } from './themer' -// import { CreateAbstraction } from './customThemeAbstraction' - -// /** -// * -// */ -// var customTheme = CreateAbstraction(themeOptions['Custom Theme']) - -// const updateBG = () => dots(true, false, true) - -// /** -// * Generates Custom theme card HTML -// * return Html Element Theme card html (properties_container) -// */ -// // const getCustomThemeCard = () => { -// // var propertiesContainer = document.createElement('form') -// // const keys = Object.keys(customTheme) -// // keys.forEach((key) => { -// // const property = document.createElement('div') -// // const newPropertyLabel = document.createElement('label') -// // newPropertyLabel.textContent = `${key} (${customTheme[key].description})` -// // newPropertyLabel.setAttribute('for', key) -// // const newPropertyInput = document.createElement('input') -// // newPropertyInput.setAttribute('type', 'color') -// // newPropertyInput.setAttribute('name', key) -// // newPropertyInput.setAttribute('value', customTheme[key].color) -// // newPropertyInput.classList.add('customColorInput') -// // property.append(newPropertyLabel) -// // property.append(newPropertyInput) -// // propertiesContainer.append(property) -// // }) -// // const downloadAnchor = document.createElement('a') -// // downloadAnchor.setAttribute('id', 'downloadThemeFile') -// // downloadAnchor.setAttribute('style', 'display:none') -// // propertiesContainer.appendChild(downloadAnchor) -// // return propertiesContainer -// // } - -// /** -// * Create Custom Color Themes Dialog -// */ -// // export const CustomColorThemes = () => { -// // $('#CustomColorThemesDialog').empty() -// // $('#CustomColorThemesDialog').append(getCustomThemeCard()) -// // $('#CustomColorThemesDialog').dialog({ -// // resizable: false, -// // close() { -// // themeOptions['Custom Theme'] = -// // JSON.parse(localStorage.getItem('Custom Theme')) || -// // themeOptions['Default Theme'] // hack for closing dialog box without saving -// // // Rollback to previous theme -// // updateThemeForStyle(localStorage.getItem('theme')) -// // updateBG() -// // }, -// // buttons: [ -// // { -// // text: 'Apply Theme', -// // click() { -// // // update theme to Custom Theme -// // localStorage.setItem('theme', 'Custom Theme') -// // // add Custom theme to custom theme object -// // localStorage.setItem( -// // 'Custom Theme', -// // JSON.stringify(themeOptions['Custom Theme']) -// // ) -// // $('.set').removeClass('set') -// // $('.selected').addClass('set') -// // $(this).dialog('close') -// // }, -// // }, -// // { -// // text: 'Import Theme', -// // click() { -// // $('#importThemeFile').click() -// // }, -// // }, -// // { -// // text: 'Export Theme', -// // click() { -// // const dlAnchorElem = -// // document.getElementById('downloadThemeFile') -// // dlAnchorElem.setAttribute( -// // 'href', -// // `data:text/json;charset=utf-8,${encodeURIComponent( -// // JSON.stringify(themeOptions['Custom Theme']) -// // )}` -// // ) -// // dlAnchorElem.setAttribute('download', 'CV_CustomTheme.json') -// // dlAnchorElem.click() -// // }, -// // }, -// // ], -// // }) - -// // $('#CustomColorThemesDialog').focus() - -// // /** -// // * To preview the changes -// // */ -// // // function setColorEvent() { -// // // $('.customColorInput').on('input', (e) => { -// // // customTheme[e.target.name].color = e.target.value -// // // customTheme[e.target.name].ref.forEach((property) => { -// // // themeOptions['Custom Theme'][property] = e.target.value -// // // }) -// // // updateThemeForStyle('Custom Theme') -// // // updateBG() -// // // }) -// // // } -// // // setColorEvent() - -// // // hack for updating current theme to the saved custom theme -// // setTimeout(() => { -// // updateThemeForStyle('Custom Theme') -// // updateBG() -// // }, 50) - -// // /** -// // * Read JSON file and -// // * set Custom theme to the Content of the JSON file -// // * */ -// // // function receivedText(e) { -// // // const lines = JSON.parse(e.target.result) -// // // customTheme = CreateAbstraction(lines) -// // // themeOptions['Custom Theme'] = lines -// // // // preview theme -// // // updateThemeForStyle('Custom Theme') -// // // updateBG() -// // // // update colors in dialog box -// // // $('#CustomColorThemesDialog').empty() -// // // $('#CustomColorThemesDialog').append(getCustomThemeCard()) -// // // setColorEvent() -// // // } - -// // /** -// // * Add listener for file input -// // * Read imported JSON file -// // */ -// // // $('#importThemeFile').on('change', (event) => { -// // // var File = event.target.files[0] -// // // if (File !== null && File.name.split('.')[1] === 'json') { -// // // var fr = new FileReader() -// // // fr.onload = receivedText -// // // fr.readAsText(File) -// // // $('#importThemeFile').val('') -// // // } else { -// // // alert('File Not Supported !') -// // // } -// // // }) -// // } diff --git a/v1/src/simulator/src/themer/customThemer.vue b/v1/src/simulator/src/themer/customThemer.vue new file mode 100644 index 00000000..17f64f6e --- /dev/null +++ b/v1/src/simulator/src/themer/customThemer.vue @@ -0,0 +1,174 @@ + + + + + \ No newline at end of file diff --git a/v1/src/simulator/src/themer/themeCardSvg.js b/v1/src/simulator/src/themer/themeCardSvg.ts similarity index 98% rename from v1/src/simulator/src/themer/themeCardSvg.js rename to v1/src/simulator/src/themer/themeCardSvg.ts index 5e1776cb..de3c9f78 100644 --- a/v1/src/simulator/src/themer/themeCardSvg.js +++ b/v1/src/simulator/src/themer/themeCardSvg.ts @@ -1,4 +1,4 @@ -export default ` +const svgString: string = ` @@ -98,5 +98,6 @@ export default ` - -` +`; + +export default svgString; \ No newline at end of file diff --git a/v1/src/simulator/src/themer/themer.js b/v1/src/simulator/src/themer/themer.js deleted file mode 100644 index 2c61865e..00000000 --- a/v1/src/simulator/src/themer/themer.js +++ /dev/null @@ -1,223 +0,0 @@ -import { dots } from '../canvasApi' -import themeOptions from './themes' -import themeCardSvg from './themeCardSvg' -import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' - -/** - * Extracts canvas theme colors from CSS-Variables and returns a JSON Object - * @returns {object} - */ -const getCanvasColors = () => { - let colors = {} - colors['hover_select'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--hover-and-sel') - colors['fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--fill') - colors['mini_fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--mini-map') - colors['mini_stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--mini-map-stroke') - colors['stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--stroke') - colors['stroke_alt'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--secondary-stroke') - colors['input_text'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--input-text') - colors['color_wire_draw'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-draw') - colors['color_wire_con'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-cnt') - colors['color_wire_pow'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-pow') - colors['color_wire_sel'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-sel') - colors['color_wire_lose'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-lose') - colors['color_wire'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--wire-norm') - colors['text'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--text') - colors['node'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--node') - colors['node_norm'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--node-norm') - colors['splitter'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--splitter') - colors['out_rect'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--output-rect') - colors['canvas_stroke'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--canvas-stroke') - colors['canvas_fill'] = getComputedStyle( - document.documentElement - ).getPropertyValue('--canvas-fill') - return colors -} - -/** - * Common canvas theme color object, used for rendering canvas elements - */ -export let colors = getCanvasColors() - -/** - * Updates theme - * 1) Sets CSS Variables for UI elements - * 2) Sets color variable for Canvas elements - */ -export function updateThemeForStyle(themeName) { - const selectedTheme = themeOptions[themeName] - if (selectedTheme === undefined) return - const html = document.getElementsByTagName('html')[0] - Object.keys(selectedTheme).forEach((property, i) => { - html.style.setProperty(property, selectedTheme[property]) - }) - colors = getCanvasColors() -} - -/** - * Theme Preview Card SVG - * Sets the SVG colors according to theme - * @param {string} themeName Name of theme - * @returns {SVG} - */ -export const getThemeCardSvg = (themeName) => { - const colors = themeOptions[themeName] - let svgIcon = $(themeCardSvg) - - // Dynamically set the colors according to the theme - $('.svgText', svgIcon).attr('fill', colors['--text-panel']) - - $('.svgNav', svgIcon).attr('fill', colors['--bg-tab']) - $('.svgNav', svgIcon).attr('stroke', colors['--br-primary']) - - $('.svgGridBG', svgIcon).attr('fill', colors['--canvas-fill']) - $('.svgGrid', svgIcon).attr('fill', colors['--canvas-stroke']) - - $('.svgPanel', svgIcon).attr('fill', colors['--primary']) - $('.svgPanel', svgIcon).attr('stroke', colors['--br-primary']) - - $('.svgChev', svgIcon).attr('stroke', colors['--br-secondary']) - - $('.svgHeader', svgIcon).attr('fill', colors['--primary']) - let temp = svgIcon.prop('outerHTML') - return svgIcon.prop('outerHTML') -} - -/** - * Generates theme card HTML - * @param {string} themeName Name of theme - * @param {boolean} selected Flag variable for currently selected theme - * @return {string} Theme card html - */ -export const getThemeCard = (themeName, selected) => { - if (themeName === 'Custom Theme') return '
' - let themeId = themeName.replace(' ', '') - let selectedClass = selected ? 'selected set' : '' - // themeSel is the hit area - return ` -
-
- ${getThemeCardSvg(themeName)} - - - - -
- ` -} - -/** - * Create Color Themes Dialog - */ -export const colorThemes = () => { - const simulatorStore = SimulatorStore() - simulatorStore.dialogBox.theme_dialog = true - - // const selectedTheme = localStorage.getItem('theme') - // $('#colorThemesDialog').empty() - // const themes = Object.keys(themeOptions) - // themes.forEach((theme) => { - // if (theme === selectedTheme) { - // $('#colorThemesDialog').append(getThemeCard(theme, true)) - // } else { - // $('#colorThemesDialog').append(getThemeCard(theme, false)) - // } - // }) - - // $('.selected label').trigger('click') - // $('#colorThemesDialog').dialog({ - // resizable: false, - // close() { - // // Rollback to previous theme - // updateThemeForStyle(localStorage.getItem('theme')) - // updateBG() - // }, - // buttons: [ - // { - // text: 'Apply Theme', - // click() { - // // check if any theme is selected or not - // if ($('.selected label').text()) { - // localStorage.removeItem('Custom Theme') - // localStorage.setItem( - // 'theme', - // $('.selected label').text() - // ) - // } - // $('.set').removeClass('set') - // $('.selected').addClass('set') - // $(this).dialog('close') - // }, - // }, - // { - // text: 'Custom Theme', - // click() { - // CustomColorThemes() - // $(this).dialog('close') - // }, - // }, - // ], - // }) - - $('#colorThemesDialog').focus() - $('.ui-dialog[aria-describedby="colorThemesDialog"]').on('click', () => - $('#colorThemesDialog').focus() - ) //hack for losing focus - - $('.themeSel').on('mousedown', (e) => { - e.preventDefault() - $('.selected').removeClass('selected') - let themeCard = $(e.target.parentElement) - themeCard.addClass('selected') - // Extract radio button - var radioButton = themeCard.find('input[type=radio]') - radioButton.trigger('click') // Mark as selected - updateThemeForStyle(themeCard.find('label').text()) // Extract theme name and set - updateBG() - }) -} - -export const updateBG = () => dots(true, false, true) -;(() => { - if (!localStorage.getItem('theme')) - localStorage.setItem('theme', 'Default Theme') - updateThemeForStyle(localStorage.getItem('theme')) -})() diff --git a/v1/src/simulator/src/themer/themer.ts b/v1/src/simulator/src/themer/themer.ts new file mode 100644 index 00000000..d8597939 --- /dev/null +++ b/v1/src/simulator/src/themer/themer.ts @@ -0,0 +1,218 @@ +import { dots } from '../canvasApi'; +import importedThemeOptions from './themes'; +import { ThemeOptions } from './themer.types'; +import themeCardSvg from './themeCardSvg'; +import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore'; + +const themeOptions: ThemeOptions = importedThemeOptions; + +/** + * Helper function to set CSS variable values into a colors object. + */ +const setColor = (colors: Record, key: string, cssVar: string): void => { + colors[key] = getComputedStyle(document.documentElement).getPropertyValue(cssVar); +}; + +/** + * Extracts canvas theme colors from CSS variables and returns a JSON object. + */ +const getCanvasColors = (): Record => { + const colors: Record = {}; + setColor(colors, 'hover_select', '--hover-and-sel'); + setColor(colors, 'fill', '--fill'); + setColor(colors, 'mini_fill', '--mini-map'); + setColor(colors, 'mini_stroke', '--mini-map-stroke'); + setColor(colors, 'stroke', '--stroke'); + setColor(colors, 'stroke_alt', '--secondary-stroke'); + setColor(colors, 'input_text', '--input-text'); + setColor(colors, 'color_wire_draw', '--wire-draw'); + setColor(colors, 'color_wire_con', '--wire-cnt'); + setColor(colors, 'color_wire_pow', '--wire-pow'); + setColor(colors, 'color_wire_sel', '--wire-sel'); + setColor(colors, 'color_wire_lose', '--wire-lose'); + setColor(colors, 'color_wire', '--wire-norm'); + setColor(colors, 'text', '--text'); + setColor(colors, 'node', '--node'); + setColor(colors, 'node_norm', '--node-norm'); + setColor(colors, 'splitter', '--splitter'); + setColor(colors, 'out_rect', '--output-rect'); + setColor(colors, 'canvas_stroke', '--canvas-stroke'); + setColor(colors, 'canvas_fill', '--canvas-fill'); + return colors; +}; + +/** + * Common canvas theme color object, used for rendering canvas elements. + */ +export let colors: Record = getCanvasColors(); + +/** + * Updates theme by setting CSS variables and updating the colors object. + */ +export function updateThemeForStyle(themeName: string): void { + const selectedTheme = themeOptions[themeName]; + if (selectedTheme === undefined) return; + + const html = document.documentElement; + Object.keys(selectedTheme).forEach((property) => { + html.style.setProperty(property, selectedTheme[property]); + }); + + colors = getCanvasColors(); +} + +/** + * Helper function to set attributes for SVG elements. + */ +const setAttributes = (element: Element, attributes: Record): void => { + Object.entries(attributes).forEach(([attr, value]) => { + element.setAttribute(attr, value); + }); +}; + +/** + * Generates a theme preview card SVG with colors based on the selected theme. + */ +export const getThemeCardSvg = (themeName: string): string => { + if (!themeOptions[themeName]) { + console.error(`Theme "${themeName}" not found`); + return ''; + } + + const colors = themeOptions[themeName]; + const parser = new DOMParser(); + const svgDoc = parser.parseFromString(themeCardSvg, 'image/svg+xml'); + + // Check for parsing errors + const parserError = svgDoc.querySelector('parsererror'); + if (parserError) { + console.error('Failed to parse SVG:', parserError); + return ''; + } + + const svgElement = svgDoc.documentElement; + + const applyStyles = (selector: string, attributes: Record): void => { + svgElement.querySelectorAll(selector).forEach((el) => setAttributes(el, attributes)); + }; + + applyStyles('.svgText', { fill: colors['--text-panel'] || '#000000' }); + applyStyles('.svgNav', { fill: colors['--bg-tab'], stroke: colors['--br-primary'] }); + applyStyles('.svgGridBG', { fill: colors['--canvas-fill'] }); + applyStyles('.svgGrid', { fill: colors['--canvas-stroke'] }); + applyStyles('.svgPanel', { fill: colors['--primary'], stroke: colors['--br-primary'] }); + applyStyles('.svgChev', { stroke: colors['--br-secondary'] }); + applyStyles('.svgHeader', { fill: colors['--primary'] }); + + return svgElement.outerHTML; +}; + +/** + * Generates theme card HTML. + */ +export const getThemeCard = (themeName: string, selected: boolean): string => { + if (themeName === 'Custom Theme') return '
'; + + const themeId = themeName.replace(' ', ''); + const selectedClass = selected ? 'selected set' : ''; + + return ` +
+
+ ${getThemeCardSvg(themeName)} + + + + +
+ `; +}; + +/** + * Handles theme selection logic. + */ +const handleThemeSelection = (e: MouseEvent): void => { + e.preventDefault(); + + // Remove 'selected' class from all theme cards + document.querySelectorAll('.selected').forEach((el) => el.classList.remove('selected')); + + const themeCard = (e.target as HTMLElement).parentElement; + if (!themeCard) return; + + // Add 'selected' class to the clicked theme card + themeCard.classList.add('selected'); + + // Find the radio button and label within the theme card + const radioButton = themeCard.querySelector('input[type=radio]') as HTMLInputElement; + const label = themeCard.querySelector('label'); + + if (radioButton) { + radioButton.click(); // Mark the radio button as selected + } + + if (label) { + updateThemeForStyle(label.textContent || ''); // Update the theme based on the label text + } + + updateBG(); // Update the background +}; + +/** + * Sets up event listeners for theme selection. + */ +const setupThemeSelectionHandlers = (cleanupListeners: (() => void)[]): void => { + document.querySelectorAll('.themeSel').forEach((element) => { + const mousedownHandler = (e: MouseEvent) => handleThemeSelection(e); + + element.addEventListener('mousedown', mousedownHandler as EventListener); + cleanupListeners.push(() => element.removeEventListener('mousedown', mousedownHandler as EventListener)); + }); +}; + +/** + * Initializes the color themes dialog. + */ +export const colorThemes = (): void => { + const simulatorStore = SimulatorStore(); + const cleanupListeners: (() => void)[] = []; + + simulatorStore.dialogBox.theme_dialog = true; + + const dialog = document.querySelector('.ui-dialog[aria-describedby="colorThemesDialog"]'); + if (dialog) { + const dialogClickHandler = () => { + const colorThemesDialog = document.getElementById('colorThemesDialog'); + if (colorThemesDialog) colorThemesDialog.focus(); + }; + + dialog.addEventListener('click', dialogClickHandler); + cleanupListeners.push(() => dialog.removeEventListener('click', dialogClickHandler)); + } + + setupThemeSelectionHandlers(cleanupListeners); + + // Add cleanup method to store + (simulatorStore as any).cleanupThemeDialog = () => { + cleanupListeners.forEach(cleanup => cleanup()); + }; +}; + +/** + * Updates the background of the canvas. + */ +export const updateBG = (): void => dots(true, false, true); + +/** + * Initializes the theme on load. + */ +const initializeTheme = (): void => { + const theme = localStorage.getItem('theme') || 'Default Theme'; + if (!localStorage.getItem('theme')) { + localStorage.setItem('theme', theme); + } + updateThemeForStyle(theme); +}; + +// Initialize theme on load +initializeTheme(); \ No newline at end of file diff --git a/v1/src/simulator/src/themer/themer.types.ts b/v1/src/simulator/src/themer/themer.types.ts new file mode 100644 index 00000000..639e5052 --- /dev/null +++ b/v1/src/simulator/src/themer/themer.types.ts @@ -0,0 +1,13 @@ +export interface ThemeOptions { + [key: string]: { + [property: string]: string; + }; +} + +interface Theme { + [key: string]: string; +} + +export interface Themes { + [themeName: string]: Theme; +} \ No newline at end of file diff --git a/v0/src/simulator/src/themer/themes.js b/v1/src/simulator/src/themer/themes.ts similarity index 99% rename from v0/src/simulator/src/themer/themes.js rename to v1/src/simulator/src/themer/themes.ts index d4f8caa1..b0dbe421 100644 --- a/v0/src/simulator/src/themer/themes.js +++ b/v1/src/simulator/src/themer/themes.ts @@ -1,4 +1,6 @@ -export default { +import { Themes } from './themer.types' + +const themes: Themes = { 'Default Theme': { '--text-navbar--alt': '#000', '--br-secondary': '#7d7d7d', @@ -326,7 +328,7 @@ export default { '--disable': '#956c6a', '--table-head-dark': '#2e2b21', }, - 'Custom Theme': JSON.parse(localStorage.getItem('Custom Theme')) || { + 'Custom Theme': JSON.parse(localStorage.getItem('Custom Theme') || '{}') || { '--text-navbar--alt': '#000', '--br-secondary': '#7d7d7d', '--br-circuit-cur': '#ffffff', @@ -380,3 +382,5 @@ export default { '--output-rect': '#0000ff', }, } + +export default themes; diff --git a/v1/src/simulator/src/tutorials.js b/v1/src/simulator/src/tutorials.js index a1f10d67..dde6f52c 100644 --- a/v1/src/simulator/src/tutorials.js +++ b/v1/src/simulator/src/tutorials.js @@ -33,16 +33,6 @@ export const tour = [ // offset: 750, }, }, - // { - // element: '.forum-tab', - // popover: { - // className: "", - // title: 'Forum Tab', - // description: "The forums can help you report issues & bugs, feature requests, and discussing about circuits with the community!", - // position: 'right', - // // offset: -25, - // }, - // }, { element: '#tabsBar', popover: { @@ -63,16 +53,6 @@ export const tour = [ offset: 0, }, }, - - // { - // element: '#delCirGuide', - // popover: { - // title: 'Delete sub-circuit button', - // description: "You can make delete sub-circuits by pressing the cross *Note that main circuit cannot be deleted.", - // position: 'right', - // // offset: 250, - // }, - // }, { element: '.report-sidebar a', popover: { @@ -95,6 +75,15 @@ export const tour = [ offset: 0, }, }, + { + element: '.testbench-manual-panel', + popover: { + title: 'Test Bench Panel', + description: 'This panel helps you test your circuit correctness by observing how your circuit responds under different test cases, ensuring a thorough and effective validation process.', + position: 'right', + offset: 0, + }, + }, ] // Not used currently diff --git a/v1/src/simulator/src/types/app.types.ts b/v1/src/simulator/src/types/app.types.ts new file mode 100644 index 00000000..e126fcd6 --- /dev/null +++ b/v1/src/simulator/src/types/app.types.ts @@ -0,0 +1,33 @@ +interface Device { + type: string; + net?: string; + order?: number; + bits: number; + label?: string; + abits?: number; + words?: number; + offset?: number; + rdports?: Array<{ clock_polarity?: boolean }>; + wrports?: Array<{ clock_polarity?: boolean }>; + memdata?: Array; +} + +interface Connector { + to: { + id: string; + port: string; + }; + from: { + id: string; + port: string; + }; + name: string; +} + +export interface JsConfig { + devices: { + [key: string]: Device; + }; + connectors: Connector[]; + subcircuits: Record; +} \ No newline at end of file diff --git a/v1/src/simulator/src/utils.js b/v1/src/simulator/src/utils.ts similarity index 50% rename from v1/src/simulator/src/utils.js rename to v1/src/simulator/src/utils.ts index 9d6a32b9..a85b186e 100644 --- a/v1/src/simulator/src/utils.js +++ b/v1/src/simulator/src/utils.ts @@ -1,4 +1,4 @@ -import simulationArea from './simulationArea' +import { simulationArea } from './simulationArea' import { scheduleUpdate, play, @@ -9,6 +9,10 @@ import { import { layoutModeGet } from './layoutMode' import plotArea from './plotArea' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { useActions } from '#/store/SimulatorStore/actions' +import { writeTextFile } from '@tauri-apps/plugin-fs'; +import { join, downloadDir } from '@tauri-apps/api/path'; +import { isTauri } from '@tauri-apps/api/core' window.globalScope = undefined window.lightMode = false // To be deprecated @@ -16,14 +20,14 @@ window.projectId = undefined window.id = undefined window.loading = false // Flag - all assets are loaded -var prevErrorMessage // Global variable for error messages -var prevShowMessage // Global variable for error messages +let prevErrorMessage: string | undefined // Global variable for error messages +let prevShowMessage: string | undefined // Global variable for error messages export function generateId() { - var id = '' - var possible = + let id = '' + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' - for (var i = 0; i < 20; i++) { + for (let i = 0; i < 20; i++) { id += possible.charAt(Math.floor(Math.random() * possible.length)) } @@ -48,39 +52,25 @@ export function clockTick() { /** * Helper function to show error - * @param {string} error -The error to be shown - * @category utils */ -export function showError(error) { +export function showError(error: string) { errorDetectedSet(true) // if error ha been shown return if (error === prevErrorMessage) return prevErrorMessage = error - var id = Math.floor(Math.random() * 10000) - $('#MessageDiv').append( - `` - ) - setTimeout(() => { - prevErrorMessage = undefined - $(`#${id}`).fadeOut() - }, 1500) + + useActions().showMessage(error, 'error') } // Helper function to show message -export function showMessage(mes) { +export function showMessage(mes: string) { if (mes === prevShowMessage) return prevShowMessage = mes - var id = Math.floor(Math.random() * 10000) - $('#MessageDiv').append( - `` - ) - setTimeout(() => { - prevShowMessage = undefined - $(`#${id}`).fadeOut() - }, 2500) + + useActions().showMessage(mes, 'success') } -export function distance(x1, y1, x2, y2) { +export function distance(x1: number, y1: number, x2: number, y2: number) { return Math.sqrt((x2 - x1) ** 2) + (y2 - y1) ** 2 } @@ -89,22 +79,22 @@ export function distance(x1, y1, x2, y2) { * @param {Array} a - any array * @category utils */ -export function uniq(a) { - var seen = {} +export function uniq(a: any[]) { + const seen: { [key: string]: boolean } = {}; const tmp = a.filter((item) => seen.hasOwnProperty(item) ? false : (seen[item] = true) - ) - return tmp + ); + return tmp; } // Generates final verilog code for each element // Gate = &/|/^ // Invert is true for xNor, Nor, Nand export function gateGenerateVerilog(gate, invert = false) { - var inputs = [] - var outputs = [] + let inputs = [] + let outputs = [] - for (var i = 0; i < this.nodeList.length; i++) { + for (let i = 0; i < this.nodeList.length; i++) { if (this.nodeList[i].type == NODE_INPUT) { inputs.push(this.nodeList[i]) } else { @@ -114,13 +104,13 @@ export function gateGenerateVerilog(gate, invert = false) { } } - var res = 'assign ' + let res = 'assign ' if (outputs.length == 1) res += outputs[0].verilogLabel else res += `{${outputs.map((x) => x.verilogLabel).join(', ')}}` res += ' = ' - var inputParams = inputs.map((x) => x.verilogLabel).join(` ${gate} `) + const inputParams = inputs.map((x) => x.verilogLabel).join(` ${gate} `) if (invert) { res += `~(${inputParams});` } else { @@ -130,8 +120,17 @@ export function gateGenerateVerilog(gate, invert = false) { } // Helper function to download text -export function download(filename, text) { - var pom = document.createElement('a') +export function downloadFile(filename: string, text: string | number | boolean | JSON) { + if (isTauri()) { + return downloadFileDesktop(filename, text); + } else { + return downloadFileWeb(filename, text); + } +} + +// For Web Application +export function downloadFileWeb(filename: string, text: string | number | boolean) { + const pom = document.createElement('a') pom.setAttribute( 'href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text) @@ -139,7 +138,7 @@ export function download(filename, text) { pom.setAttribute('download', filename) if (document.createEvent) { - var event = document.createEvent('MouseEvents') + const event = document.createEvent('MouseEvents') event.initEvent('click', true, true) pom.dispatchEvent(event) } else { @@ -147,13 +146,25 @@ export function download(filename, text) { } } +// For Desktop Application +export async function downloadFileDesktop(filename: string, text: string | number | boolean | JSON) { + const downloadsDirectory = await downloadDir(); + let path = filename; + + if (!filename.startsWith('/')) { + path = await join(downloadsDirectory, filename); + } + + await writeTextFile(path, text.toString()); +} + // Helper function to open a new tab -export function openInNewTab(url) { - var win = window.open(url, '_blank') - win.focus() +export function openInNewTab(url: string | URL | undefined) { + const win = window.open(url, '_blank') + win?.focus() } -export function copyToClipboard(text) { +export function copyToClipboard(text: string) { const textarea = document.createElement('textarea') // Move it off-screen. @@ -161,27 +172,27 @@ export function copyToClipboard(text) { // Set to readonly to prevent mobile devices opening a keyboard when // text is .select()'ed. - textarea.setAttribute('readonly', true) + textarea.setAttribute('readonly', 'true') document.body.appendChild(textarea) textarea.value = text // Check if there is any content selected previously. const selected = - document.getSelection().rangeCount > 0 - ? document.getSelection().getRangeAt(0) + document.getSelection()?.rangeCount ?? 0 > 0 + ? document.getSelection()?.getRangeAt(0) : false // iOS Safari blocks programmatic execCommand copying normally, without this hack. // https://stackoverflow.com/questions/34045777/copy-to-clipboard-using-javascript-in-ios if (navigator.userAgent.match(/ipad|ipod|iphone/i)) { const editable = textarea.contentEditable - textarea.contentEditable = true + textarea.contentEditable = 'true' const range = document.createRange() range.selectNodeContents(textarea) const sel = window.getSelection() - sel.removeAllRanges() - sel.addRange(range) + sel?.removeAllRanges() + sel?.addRange(range) textarea.setSelectionRange(0, 999999) textarea.contentEditable = editable } else { @@ -193,8 +204,8 @@ export function copyToClipboard(text) { // Restore previous selection. if (selected) { - document.getSelection().removeAllRanges() - document.getSelection().addRange(selected) + document.getSelection()?.removeAllRanges() + document.getSelection()?.addRange(selected) } textarea.remove() return result @@ -205,7 +216,7 @@ export function copyToClipboard(text) { } } -export function truncateString(str, num) { +export function truncateString(str: string, num: number) { // If the length of str is less than or equal to num // just return str--don't truncate it. if (str.length <= num) { @@ -216,13 +227,13 @@ export function truncateString(str, num) { } export function bitConverterDialog() { - const simulatorStore = SimulatorStore(); - simulatorStore.dialogBox.hex_bin_dec_converter_dialog = true; + const simulatorStore = SimulatorStore() + simulatorStore.dialogBox.hex_bin_dec_converter_dialog = true } -export function getImageDimensions(file) { +export function getImageDimensions(file: string) { return new Promise(function (resolved, rejected) { - var i = new Image() + const i = new Image() i.onload = function () { resolved({ w: i.width, h: i.height }) } @@ -231,15 +242,24 @@ export function getImageDimensions(file) { } // convertors -export var convertors = { - dec2bin: (x) => '0b' + x.toString(2), - dec2hex: (x) => '0x' + x.toString(16), - dec2octal: (x) => '0' + x.toString(8), - dec2bcd: (x) => parseInt(x.toString(10), 16).toString(2), +export const convertors = { + dec2bin: (x: number) => '0b' + x.toString(2), + dec2hex: (x: number) => '0x' + x.toString(16), + dec2octal: (x: number) => '0' + x.toString(8), + dec2bcd: (x: number) => parseInt(x.toString(10), 16).toString(2), } -export function parseNumber(num) { - if (num instanceof Number) return num +export function setBaseValues(x) { + if (isNaN(x)) return; + $("#binaryInput").val(convertors.dec2bin(x)); + $("#bcdInput").val(convertors.dec2bcd(x)); + $("#octalInput").val(convertors.dec2octal(x)); + $("#hexInput").val(convertors.dec2hex(x)); + $("#decimalInput").val(x); +} + +export function parseNumber(num: string | number) { + if(typeof num === 'number') return num; if (num.slice(0, 2).toLocaleLowerCase() == '0b') return parseInt(num.slice(2), 2) if (num.slice(0, 2).toLocaleLowerCase() == '0x') @@ -248,26 +268,75 @@ export function parseNumber(num) { return parseInt(num) } -export function promptFile(contentType, multiple) { - var input = document.createElement('input') +export function setupBitConvertor() { + $("#decimalInput").on('keyup', function () { + var x = parseInt($("#decimalInput").val(), 10); + setBaseValues(x); + }) + + $("#binaryInput").on('keyup', function () { + var inp = $("#binaryInput").val(); + var x; + if (inp.slice(0, 2) == '0b') + x = parseInt(inp.slice(2), 2); + else + x = parseInt(inp, 2); + setBaseValues(x); + }) + $("#bcdInput").on('keyup', function () { + var input = $("#bcdInput").val(); + var num = 0; + while (input.length % 4 !== 0){ + input = "0" + input; + } + if(input !== 0){ + var i = 0; + while (i < input.length / 4){ + if(parseInt(input.slice((4 * i), 4 * (i + 1)), 2) < 10) + num = num * 10 + parseInt(input.slice((4 * i), 4 * (i + 1)), 2); + else + return setBaseValues(NaN); + i++; + } + } + return setBaseValues(x); + }) + + $("#hexInput").on('keyup', function () { + var x = parseInt($("#hexInput").val(), 16); + setBaseValues(x); + }) + + $("#octalInput").on('keyup', function () { + var x = parseInt($("#octalInput").val(), 8); + setBaseValues(x); + }) +} + +export function promptFile(contentType: string, multiple: boolean) { + const input = document.createElement('input') input.type = 'file' input.multiple = multiple input.accept = contentType return new Promise(function (resolve) { - document.activeElement.onfocus = function () { - document.activeElement.onfocus = null - setTimeout(resolve, 500) + if (document.activeElement instanceof HTMLInputElement) { + (document.activeElement as HTMLInputElement).onfocus = function () { + (document.activeElement as HTMLInputElement).onfocus = null; + setTimeout(resolve, 500); + }; } input.onchange = function () { - var files = Array.from(input.files) - if (multiple) return resolve(files) - resolve(files[0]) + const files = input.files + if (files === null) return resolve([]) + const fileArray = Array.from(files) + if (multiple) return resolve(fileArray) + resolve(fileArray[0]) } input.click() }) } -export function escapeHtml(unsafe) { +export function escapeHtml(unsafe: string) { return unsafe .replace(/&/g, '&') .replace(/" + obj.objectType + '
' - ) - - if (obj.subcircuitMutableProperties && obj.canShowInSubcircuit) { - for (let attr in obj.subcircuitMutableProperties) { - var prop = obj.subcircuitMutableProperties[attr] - if (obj.subcircuitMutableProperties[attr].type == 'number') { - var s = - '

' + - prop.name + - "

" - $('#moduleProperty-inner').append(s) - } - } - if (!obj.labelDirectionFixed) { - if (!obj.subcircuitMetadata.labelDirection) - obj.subcircuitMetadata.labelDirection = obj.labelDirection - var s = $( - "' - ) - s.val(obj.subcircuitMetadata.labelDirection) - $('#moduleProperty-inner').append( - '

Label Direction: ' + $(s).prop('outerHTML') + '

' - ) - } - } - } else if ( - simulationArea.lastSelected === undefined || - ['Wire', 'CircuitElement', 'Node'].indexOf( - simulationArea.lastSelected.objectType - ) !== -1 - ) { - $('#moduleProperty').show() - - $('#moduleProperty-inner').append( - `

Project:

` - ) - $('#moduleProperty-inner').append( - `

Circuit:

` - ) - $('#moduleProperty-inner').append( - `

Clock Time (ms):

` - ) - $('#moduleProperty-inner').append( - `

Clock Enabled:

` - ) - $('#moduleProperty-inner').append( - `

Lite Mode:

` - ) - $('#moduleProperty-inner').append( - "

" - ) - // $('#moduleProperty-inner').append("

"); - } else { - $('#moduleProperty').show() - - $('#moduleProperty-inner').append( - `

${obj.objectType}
` - ) - // $('#moduleProperty').append(""); - if (!obj.fixedBitWidth) { - $('#moduleProperty-inner').append( - `

BitWidth:

` - ) - } - - if (obj.changeInputSize) { - $('#moduleProperty-inner').append( - `

Input Size:

` - ) - } - - if (!obj.propagationDelayFixed) { - $('#moduleProperty-inner').append( - `

Delay:

` - ) - } - - if (!obj.disableLabel) - $('#moduleProperty-inner').append( - `

Label:

` - ) - - var s - if (!obj.labelDirectionFixed) { - s = $( - `${ - "' - ) - s.val(obj.labelDirection) - $('#moduleProperty-inner').append( - `

Label Direction: ${$(s).prop('outerHTML')}

` - ) - } - - if (!obj.directionFixed) { - s = $( - `${ - "' - ) - $('#moduleProperty-inner').append( - `

Direction: ${$(s).prop('outerHTML')}

` - ) - } else if (!obj.orientationFixed) { - s = $( - `${ - "' - ) - $('#moduleProperty-inner').append( - `

Orientation: ${$(s).prop('outerHTML')}

` - ) - } - - if (obj.mutableProperties) { - for (const attr in obj.mutableProperties) { - var prop = obj.mutableProperties[attr] - if (obj.mutableProperties[attr].type === 'number') { - s = `

${ - prop.name - }

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'text') { - s = `

${ - prop.name - }

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'button') { - s = `

` - $('#moduleProperty-inner').append(s) - } else if (obj.mutableProperties[attr].type === 'textarea') { - s = `

${prop.name}

` - $('#moduleProperty-inner').append(s) - } - } - } - } - - var helplink = obj && obj.helplink - if (helplink) { - $('#moduleProperty-inner').append( - '

' - ) - $('#HelpButton').on('click', () => { - window.open(helplink) - }) - } -*/ checkPropertiesUpdate(this) - - // $(".moduleProperty input[type='number']").inputSpinner(); } /** @@ -613,28 +294,63 @@ export function deleteSelected() { updateRestrictedElementsInScope() } -export function setupPanels() { - // $('#dragQPanel') - // .on('mousedown', () => - // $('.quick-btn').draggable({ - // disabled: false, - // containment: 'window', - // }) - // ) - // .on('mouseup', () => $('.quick-btn').draggable({ disabled: true })) - - // let position = { x: 0, y: 0 } - // interact('.quick-btn').draggable({ - // allowFrom: '#dragQPanel', - // listeners: { - // move(event) { - // position.x = position.x + event.dx - // position.y = position.y + event.dy - // event.target.style.transform = `translate(${position.x}px, ${position.y}px)` - // }, - // }, - // }) +/** + * listener for opening the prompt for bin conversion + * @category ux + */ +$('#bitconverter').on('click', () => { + $('#bitconverterprompt').dialog({ + resizable: false, + buttons: [ + { + text: 'Reset', + click() { + $('#decimalInput').val('0') + $('#binaryInput').val('0') + $('#octalInput').val('0') + $('#hexInput').val('0') + }, + }, + ], + }) +}) + +// convertors +const convertors = { + dec2bin: (x) => `0b${x.toString(2)}`, + dec2hex: (x) => `0x${x.toString(16)}`, + dec2octal: (x) => `0${x.toString(8)}`, +} + +function setBaseValues(x) { + if (isNaN(x)) return + $('#binaryInput').val(convertors.dec2bin(x)) + $('#octalInput').val(convertors.dec2octal(x)) + $('#hexInput').val(convertors.dec2hex(x)) + $('#decimalInput').val(x) +} + +$('#decimalInput').on('keyup', () => { + var x = parseInt($('#decimalInput').val(), 10) + setBaseValues(x) +}) + +$('#binaryInput').on('keyup', () => { + var x = parseInt($('#binaryInput').val(), 2) + setBaseValues(x) +}) + +$('#hexInput').on('keyup', () => { + var x = parseInt($('#hexInput').val(), 16) + setBaseValues(x) +}) + +$('#octalInput').on('keyup', () => { + var x = parseInt($('#octalInput').val(), 8) + setBaseValues(x) +}) +export function setupPanels() { dragging('#dragQPanel', '.quick-btn') setupPanelListeners('.elementPanel') @@ -648,16 +364,9 @@ export function setupPanels() { // Minimize Timing Diagram (takes too much space) $('.timing-diagram-panel .minimize').trigger('click') - // Update the Testbench Panel UI - updateTestbenchUI() // Minimize Testbench UI $('.testbench-manual-panel .minimize').trigger('click') - // Hack because minimizing panel then maximizing sets visibility recursively - // updateTestbenchUI calls some hide()s which are undone by maximization - // TODO: Remove hack - $('.testbench-manual-panel .maximize').on('click', setupTestbenchUI) - $('#projectName').on('click', () => { $("input[name='setProjectName']").focus().select() }) @@ -670,26 +379,6 @@ function setupPanelListeners(panelSelector) { var bodySelector = `${panelSelector} > .panel-body` dragging(headerSelector, panelSelector) - // let position = { x: 0, y: 0 } - // Drag Start - // $(headerSelector).on('mousedown', () => - // $(panelSelector).draggable({ disabled: false, containment: 'window' }) - // interact(panelSelector).draggable({ - // allowFrom: headerSelector, - // listeners: { - // move(event) { - // position.x += event.dx - // position.y += event.dy - - // event.target.style.transform = `translate(${position.x}px, ${position.y}px)` - // }, - // }, - // }) - // ) - // // Drag End - // $(headerSelector).on('mouseup', () => - // $(panelSelector).draggable({ disabled: true }) - // ) // Current Panel on Top var minimized = false $(headerSelector).on('dblclick', () => @@ -725,6 +414,13 @@ export function exitFullView() { element.style.display = '' } }) + + // Mobile Components + + const simulatorMobileStore = toRefs(useSimulatorMobileStore()); + + simulatorMobileStore.showQuickButtons.value = true + simulatorMobileStore.showMobileButtons.value = true } export function fullView() { @@ -743,61 +439,58 @@ export function fullView() { } }) + // Mobile Components + + const simulatorMobileStore = toRefs(useSimulatorMobileStore()); + + simulatorMobileStore.showElementsPanel.value = false + simulatorMobileStore.showPropertiesPanel.value = false + simulatorMobileStore.showTimingDiagram.value = false + simulatorMobileStore.showQuickButtons.value = false + simulatorMobileStore.showMobileButtons.value = false + app.appendChild(exitViewEl) exitViewEl.addEventListener('click', exitFullView) } -/** +/** Fills the elements that can be displayed in the subcircuit, in the subcircuit menu **/ export function fillSubcircuitElements() { - $('#subcircuitMenu').empty() - var subCircuitElementExists = false + const simulatorStore = SimulatorStore() + const { subCircuitElementList, isEmptySubCircuitElementList } = toRefs(simulatorStore) + subCircuitElementList.value = [] + isEmptySubCircuitElementList.value = true + + const subcircuitElements = [] + + let subCircuitElementExists = false + for (let el of circuitElementList) { if (globalScope[el].length === 0) continue if (!globalScope[el][0].canShowInSubcircuit) continue - let tempHTML = '' - - // add a panel for each existing group - tempHTML += `
${el}s
` - tempHTML += `
` let available = false + const elementGroup = { + type: el, + elements: [], + } + // add an SVG for each element for (let i = 0; i < globalScope[el].length; i++) { if (!globalScope[el][i].subcircuitMetadata.showInSubcircuit) { - tempHTML += `
` - tempHTML += `` - tempHTML += `

${ - globalScope[el][i].label !== '' - ? globalScope[el][i].label - : 'unlabeled' - }

` - tempHTML += '
' available = true + const element = globalScope[el][i]; + elementGroup.elements.push(element); } } - tempHTML += '
' subCircuitElementExists = subCircuitElementExists || available - if (available) $('#subcircuitMenu').append(tempHTML) - } + if (available) { + subcircuitElements.push(elementGroup); + } - if (subCircuitElementExists) { - // $('#subcircuitMenu').accordion('refresh') - } else { - $('#subcircuitMenu').append('

No layout elements available

') + subCircuitElementList.value = subcircuitElements + isEmptySubCircuitElementList.value = !subCircuitElementExists } - - $('.subcircuitModule').mousedown(function () { - let elementName = this.dataset.elementName - let elementIndex = this.dataset.elementId - - let element = globalScope[elementName][elementIndex] - - element.subcircuitMetadata.showInSubcircuit = true - element.newElement = true - simulationArea.lastSelected = element - this.parentElement.removeChild(this) - }) } diff --git a/v1/src/simulator/src/verilog.js b/v1/src/simulator/src/verilog.js index d0811b2c..5e0fcc26 100644 --- a/v1/src/simulator/src/verilog.js +++ b/v1/src/simulator/src/verilog.js @@ -7,8 +7,6 @@ */ import { scopeList } from './circuit' import { errorDetectedGet } from './engine' -import { download } from './utils' -import { getProjectName } from './data/save' import modules from './modules' import { sanitizeLabel } from './verilogHelpers' import CodeMirror from 'codemirror/lib/codemirror.js' @@ -19,49 +17,14 @@ import 'codemirror/addon/edit/closebrackets.js' import 'codemirror/addon/hint/anyword-hint.js' import 'codemirror/addon/hint/show-hint.js' import 'codemirror/addon/display/autorefresh.js' -import { openInNewTab, copyToClipboard, showMessage } from './utils' import { SimulatorStore } from '#/store/SimulatorStore/SimulatorStore' +import { inputList, moduleList } from './metadata' + var editor export function generateVerilog() { const simulatorStore = SimulatorStore() simulatorStore.dialogBox.exportverilog_dialog = true - // var dialog = $('#verilog-export-code-window-div') - // var data = verilog.exportVerilog() - // editor.setValue(data) - // $('#verilog-export-code-window-div .CodeMirror').css( - // 'height', - // $(window).height() - 200 - // ) - // dialog.dialog({ - // resizable: false, - // width: '90%', - // height: 'auto', - // position: { my: 'center', at: 'center', of: window }, - // buttons: [ - // { - // text: 'Download Verilog File', - // click() { - // var fileName = getProjectName() || 'Untitled' - // download(fileName + '.v', editor.getValue()) - // }, - // }, - // { - // text: 'Copy to Clipboard', - // click() { - // copyToClipboard(editor.getValue()) - // showMessage('Code has been copied') - // }, - // }, - // { - // text: 'Try in EDA Playground', - // click() { - // copyToClipboard(editor.getValue()) - // openInNewTab('https://www.edaplayground.com/x/XZpY') - // }, - // }, - // ], - // }) } export function setupVerilogExportCodeWindow() { @@ -529,45 +492,14 @@ export var verilog = { return res }, - /* - sanitizeLabel: function(name){ - // Replace spaces by "_" - name = name.replace(/ /g , "_"); - // Replace Hyphens by "_" - name = name.replace(/-/g , "_"); - // Replace Colons by "_" - name = name.replace(/:/g , "_"); - // replace ~ with inv_ - name = name.replace(/~/g , "inv_"); - // Shorten Inverse to inv - name = name.replace(/Inverse/g , "inv"); - - // If first character is a number - if(name.substring(0, 1).search(/[0-9]/g) > -1) { - name = "w_" + name; - } - - // if first character is not \ already - if (name[0] != '\\') { - //if there are non-alphanum_ character, add \ - if (name.search(/[\W]/g) > -1) - name = "\\" + name; - } - return name; - }, - */ } -/* - Helper function to generate spaces for indentation -*/ +/* Helper function to generate spaces for indentation */ function sp(indentation) { return ' '.repeat(indentation * 2) } -/* - Helper function to indent paragraph -*/ +/* Helper function to indent paragraph */ function indent(indentation, string) { var result = string.split('\n') if (result[result.length - 1] == '') { diff --git a/v1/src/simulator/src/verilogHelpers.js b/v1/src/simulator/src/verilogHelpers.js index 3f9a4123..e2b4cb4a 100644 --- a/v1/src/simulator/src/verilogHelpers.js +++ b/v1/src/simulator/src/verilogHelpers.js @@ -1,5 +1,4 @@ export function sanitizeLabel(name) { - // return name.replace(/ Inverse/g, "_inv").replace(/ /g , "_"); var temp = name // if there is a space anywhere but the last place // replace spaces by "_" diff --git a/v1/src/simulator/src/wire.js b/v1/src/simulator/src/wire.js deleted file mode 100644 index 7e06e7d2..00000000 --- a/v1/src/simulator/src/wire.js +++ /dev/null @@ -1,240 +0,0 @@ -/* eslint-disable no-multi-assign */ -// wire object -import { drawLine } from './canvasApi' -import simulationArea from './simulationArea' -import Node from './node' -import { updateSimulationSet, forceResetNodesSet } from './engine' -import { colors } from './themer/themer' - -/** - * Wire - To connect two nodes. - * @class - * @memberof module:wire - * @param {Node} node1 - * @param {Node} node2 - * @param {Scope} scope - The circuit in which wire has to be drawn - * @category wire - */ -export default class Wire { - constructor(node1, node2, scope) { - this.objectType = 'Wire' - this.node1 = node1 - this.scope = scope - this.node2 = node2 - this.type = 'horizontal' - - this.updateData() - this.scope.wires.push(this) - forceResetNodesSet(true) - } - - // if data changes - updateData() { - this.x1 = this.node1.absX() - this.y1 = this.node1.absY() - this.x2 = this.node2.absX() - this.y2 = this.node2.absY() - if (this.x1 === this.x2) this.type = 'vertical' - } - - updateScope(scope) { - this.scope = scope - this.checkConnections() - } - - // to check if nodes are disconnected - checkConnections() { - var check = - this.node1.deleted || - this.node2.deleted || - !this.node1.connections.contains(this.node2) || - !this.node2.connections.contains(this.node1) - if (check) this.delete() - return check - } - - dblclick() { - if ( - this.node1.parent == globalScope.root && - this.node2.parent == globalScope.root - ) { - simulationArea.multipleObjectSelections = [this.node1, this.node2] - simulationArea.lastSelected = undefined - } - } - - update() { - var updated = false - if (embed) return updated - - if (this.node1.absX() === this.node2.absX()) { - this.x1 = this.x2 = this.node1.absX() - this.type = 'vertical' - } else if (this.node1.absY() === this.node2.absY()) { - this.y1 = this.y2 = this.node1.absY() - this.type = 'horizontal' - } - - // if (wireToBeChecked && this.checkConnections()) { - // this.delete(); - // return updated; - // } // SLOW , REMOVE - if ( - simulationArea.shiftDown === false && - simulationArea.mouseDown === true && - simulationArea.selected === false && - this.checkWithin( - simulationArea.mouseDownX, - simulationArea.mouseDownY - ) - ) { - simulationArea.selected = true - simulationArea.lastSelected = this - updated = true - } else if ( - simulationArea.mouseDown && - simulationArea.lastSelected === this && - !this.checkWithin(simulationArea.mouseX, simulationArea.mouseY) - ) { - var n = new Node( - simulationArea.mouseDownX, - simulationArea.mouseDownY, - 2, - this.scope.root - ) - n.clicked = true - n.wasClicked = true - simulationArea.lastSelected = n - this.converge(n) - } - // eslint-disable-next-line no-empty - if (simulationArea.lastSelected === this) { - } - - if (this.node1.deleted || this.node2.deleted) { - this.delete() - return updated - } // if either of the nodes are deleted - - if (simulationArea.mouseDown === false) { - if (this.type === 'horizontal') { - if (this.node1.absY() !== this.y1) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.node1.absX(), this.y1, 2, this.scope.root) - this.converge(n) - updated = true - } else if (this.node2.absY() !== this.y2) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.node2.absX(), this.y2, 2, this.scope.root) - this.converge(n) - updated = true - } - } else if (this.type === 'vertical') { - if (this.node1.absX() !== this.x1) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.x1, this.node1.absY(), 2, this.scope.root) - this.converge(n) - updated = true - } else if (this.node2.absX() !== this.x2) { - // if(this.checkConnections()){this.delete();return;} - n = new Node(this.x2, this.node2.absY(), 2, this.scope.root) - this.converge(n) - updated = true - } - } - } - return updated - } - - draw() { - // for calculating min-max Width,min-max Height - // - const ctx = simulationArea.context - - var color - if (simulationArea.lastSelected == this) { - color = colors['color_wire_sel'] - } else if ( - this.node1.value == undefined || - this.node2.value == undefined - ) { - color = colors['color_wire_lose'] - } else if (this.node1.bitWidth == 1) { - color = [ - colors['color_wire_lose'], - colors['color_wire_con'], - colors['color_wire_pow'], - ][this.node1.value + 1] - } else { - color = colors['color_wire'] - } - drawLine( - ctx, - this.node1.absX(), - this.node1.absY(), - this.node2.absX(), - this.node2.absY(), - color, - 3 - ) - } - - // checks if node lies on wire - checkConvergence(n) { - return this.checkWithin(n.absX(), n.absY()) - } - - // fn checks if coordinate lies on wire - checkWithin(x, y) { - if ( - this.type === 'horizontal' && - this.node1.absX() < this.node2.absX() && - x > this.node1.absX() && - x < this.node2.absX() && - y === this.node2.absY() - ) - return true - if ( - this.type === 'horizontal' && - this.node1.absX() > this.node2.absX() && - x < this.node1.absX() && - x > this.node2.absX() && - y === this.node2.absY() - ) - return true - if ( - this.type === 'vertical' && - this.node1.absY() < this.node2.absY() && - y > this.node1.absY() && - y < this.node2.absY() && - x === this.node2.absX() - ) - return true - if ( - this.type === 'vertical' && - this.node1.absY() > this.node2.absY() && - y < this.node1.absY() && - y > this.node2.absY() && - x === this.node2.absX() - ) - return true - return false - } - - // add intermediate node between these 2 nodes - converge(n) { - this.node1.connect(n) - this.node2.connect(n) - this.delete() - } - - delete() { - forceResetNodesSet(true) - updateSimulationSet(true) - this.node1.connections.clean(this.node2) - this.node2.connections.clean(this.node1) - this.scope.wires.clean(this) - this.node1.checkDeleted() - this.node2.checkDeleted() - } -} diff --git a/v1/src/simulator/src/wire.ts b/v1/src/simulator/src/wire.ts new file mode 100644 index 00000000..885701c1 --- /dev/null +++ b/v1/src/simulator/src/wire.ts @@ -0,0 +1,265 @@ +/* eslint-disable no-multi-assign */ +import { drawLine } from './canvasApi'; +import { simulationArea } from './simulationArea'; +import Node from './node'; +import { updateSimulationSet, forceResetNodesSet } from './engine'; +import { colors } from './themer/themer'; +import CircuitElement from './circuitElement'; + +interface Scope { + wires: Wire[]; + root: CircuitElement; + timeStamp: number; +} + +enum WireValue { + LOOSE = -1, + LOW = 0, + HIGH = 1 +} + +export default class Wire { + objectType = 'Wire'; + type = 'horizontal'; + x1: number; + y1: number; + x2: number; + y2: number; + + constructor(public node1: Node, public node2: Node, public scope: Scope) { + this.x1 = this.node1.absX(); + this.y1 = this.node1.absY(); + this.x2 = this.node2.absX(); + this.y2 = this.node2.absY(); + this.updateData(); + this.scope.wires.push(this); + forceResetNodesSet(true); + } + + updateData(): void { + [this.x1, this.y1, this.x2, this.y2] = [ + this.node1.absX(), this.node1.absY(), + this.node2.absX(), this.node2.absY() + ]; + if (this.x1 === this.x2) this.type = 'vertical'; + } + + updateScope(scope: Scope): void { + this.scope = scope; + this.checkConnections(); + } + + checkConnections(): boolean { + const disconnected = this.node1.deleted || this.node2.deleted || + !this.node1.connections?.includes(this.node2) || + !this.node2.connections?.includes(this.node1); + if (disconnected) this.delete(); + return disconnected; + } + + dblclick(): void { + if (this.node1.parent === globalScope.root && this.node2.parent === globalScope.root) { + simulationArea.multipleObjectSelections = [this.node1, this.node2]; + simulationArea.lastSelected = undefined; + } + } + + update(): boolean { + let updated = false; + if (embed) return updated; + + this.updateWireType(); + updated = this.handleMouseInteraction() || updated; + + if (this.node1.deleted || this.node2.deleted) { + this.delete(); + return updated; + } + + if (!simulationArea.mouseDown) { + updated = this.handleNodeAlignment() || updated; + } + + return updated; + } + + draw(): void { + drawLine( + simulationArea.context, + this.node1.absX(), this.node1.absY(), + this.node2.absX(), this.node2.absY(), + this.getWireColor(), 3 + ); + } + + checkConvergence(n: Node): boolean { + return this.checkWithin(n.absX(), n.absY()); + } + + checkWithin(x: number, y: number): boolean { + if (this.type === 'horizontal') { + return y === this.node1.absY() && this.isBetween(x, this.node1.absX(), this.node2.absX()); + } + + if (this.type === 'vertical') { + return x === this.node1.absX() && this.isBetween(y, this.node1.absY(), this.node2.absY()); + } + + return false; + } + + private isBetween(value: number, a: number, b: number): boolean { + return value >= Math.min(a, b) && value <= Math.max(a, b); + } + + converge(n: Node): void { + this.node1.connect(n); + this.node2.connect(n); + this.delete(); + } + + delete(): void { + forceResetNodesSet(true); + updateSimulationSet(true); + this.removeMutualConnections(); + this.scope.wires = this.scope.wires.filter(x => x !== this); + this.node1.checkDeleted(); + this.node2.checkDeleted(); + this.scope.timeStamp = Date.now(); + } + + private removeMutualConnections(): void { + this.removeConnection(this.node1, this.node2); + this.removeConnection(this.node2, this.node1); + } + + private removeConnection(node: Node, otherNode: Node): void { + if (node.connections) { + node.connections = node.connections.filter(x => x !== otherNode); + } + } + + private updateWireType(): void { + const x1 = this.node1.absX(); + const x2 = this.node2.absX(); + const y1 = this.node1.absY(); + const y2 = this.node2.absY(); + + if (x1 === x2) { + this.x1 = this.x2 = x1; + this.type = 'vertical'; + } else if (y1 === y2) { + this.y1 = this.y2 = y1; + this.type = 'horizontal'; + } + } + + private handleMouseInteraction(): boolean { + if (this.checkWireSelection()) { + simulationArea.selected = true; + simulationArea.lastSelected = this; + return true; + } + + if (this.checkWireDrag()) { + this.createIntermediateNode(); + return true; + } + + return false; + } + + private checkWireSelection(): boolean { + return !simulationArea.shiftDown && + simulationArea.mouseDown && + !simulationArea.selected && + this.checkWithin(simulationArea.mouseDownX, simulationArea.mouseDownY); + } + + private checkWireDrag(): boolean { + return simulationArea.mouseDown && + simulationArea.lastSelected === this && + !this.checkWithin(simulationArea.mouseX, simulationArea.mouseY); + } + + private createIntermediateNode(): void { + const n = new Node( + simulationArea.mouseDownX, + simulationArea.mouseDownY, + 2, + this.scope.root + ); + n.clicked = true; + n.wasClicked = true; + simulationArea.lastSelected = n; + this.converge(n); + } + + private handleNodeAlignment(): boolean { + if (this.type === 'horizontal') { + return this.alignNodesAlongYAxis(); + } + if (this.type === 'vertical') { + return this.alignNodesAlongXAxis(); + } + return false; + } + + private alignNodesAlongYAxis(): boolean { + return this.checkAndCreateNode( + this.node1.absY(), + this.y1, + () => new Node(this.node1.absX(), this.y1, 2, this.scope.root), + this.node2.absY(), + this.y2, + () => new Node(this.node2.absX(), this.y2, 2, this.scope.root) + ); + } + + private alignNodesAlongXAxis(): boolean { + return this.checkAndCreateNode( + this.node1.absX(), + this.x1, + () => new Node(this.x1, this.node1.absY(), 2, this.scope.root), + this.node2.absX(), + this.x2, + () => new Node(this.x2, this.node2.absY(), 2, this.scope.root) + ); + } + + private checkAndCreateNode( + current1: number, + expected1: number, + createNode1: () => Node, + current2: number, + expected2: number, + createNode2: () => Node + ): boolean { + if (current1 !== expected1) { + this.converge(createNode1()); + return true; + } + if (current2 !== expected2) { + this.converge(createNode2()); + return true; + } + return false; + } + + private getWireColor(): string { + if (simulationArea.lastSelected === this) { + return colors['color_wire_sel']; + } + if (this.node1.value === undefined || this.node2.value === undefined) { + return colors['color_wire_lose']; + } + if (this.node1.bitWidth === 1) { + return [ + colors['color_wire_lose'], + colors['color_wire_con'], + colors['color_wire_pow'], + ][this.node1.value - WireValue.LOOSE]; + } + return colors['color_wire']; + } +} \ No newline at end of file diff --git a/v1/src/simulator/vendor/canvas2svg.js b/v1/src/simulator/vendor/canvas2svg.js deleted file mode 100644 index 73dae81d..00000000 --- a/v1/src/simulator/vendor/canvas2svg.js +++ /dev/null @@ -1,1469 +0,0 @@ -/*!! - * Canvas 2 Svg v1.0.19 - * A low level canvas to SVG converter. Uses a mock canvas context to build an SVG document. - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Author: - * Kerry Liu - * - * Copyright (c) 2014 Gliffy Inc. - */ - -;(function () { - 'use strict' - - var STYLES, ctx, CanvasGradient, CanvasPattern, namedEntities - - //helper function to format a string - function format(str, args) { - var keys = Object.keys(args), - i - for (i = 0; i < keys.length; i++) { - str = str.replace( - new RegExp('\\{' + keys[i] + '\\}', 'gi'), - args[keys[i]] - ) - } - return str - } - - //helper function that generates a random string - function randomString(holder) { - var chars, randomstring, i - if (!holder) { - throw new Error( - 'cannot create a random attribute name for an undefined object' - ) - } - chars = 'ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz' - randomstring = '' - do { - randomstring = '' - for (i = 0; i < 12; i++) { - randomstring += chars[Math.floor(Math.random() * chars.length)] - } - } while (holder[randomstring]) - return randomstring - } - - //helper function to map named to numbered entities - function createNamedToNumberedLookup(items, radix) { - var i, - entity, - lookup = {}, - base10, - base16 - items = items.split(',') - radix = radix || 10 - // Map from named to numbered entities. - for (i = 0; i < items.length; i += 2) { - entity = '&' + items[i + 1] + ';' - base10 = parseInt(items[i], radix) - lookup[entity] = '&#' + base10 + ';' - } - //FF and IE need to create a regex from hex values ie   == \xa0 - lookup['\\xa0'] = ' ' - return lookup - } - - //helper function to map canvas-textAlign to svg-textAnchor - function getTextAnchor(textAlign) { - //TODO: support rtl languages - var mapping = { - left: 'start', - right: 'end', - center: 'middle', - start: 'start', - end: 'end', - } - return mapping[textAlign] || mapping.start - } - - //helper function to map canvas-textBaseline to svg-dominantBaseline - function getDominantBaseline(textBaseline) { - //INFO: not supported in all browsers - var mapping = { - alphabetic: 'alphabetic', - hanging: 'hanging', - top: 'text-before-edge', - bottom: 'text-after-edge', - middle: 'central', - } - return mapping[textBaseline] || mapping.alphabetic - } - - // Unpack entities lookup where the numbers are in radix 32 to reduce the size - // entity mapping courtesy of tinymce - namedEntities = createNamedToNumberedLookup( - '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + - '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + - '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + - '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + - '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + - '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + - '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + - '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + - '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + - '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + - 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + - 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + - 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + - 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + - 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + - '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + - '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + - '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + - '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + - '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + - 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + - 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + - 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + - '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + - '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', - 32 - ) - - //Some basic mappings for attributes and default values. - STYLES = { - strokeStyle: { - svgAttr: 'stroke', //corresponding svg attribute - canvas: '#000000', //canvas default - svg: 'none', //svg default - apply: 'stroke', //apply on stroke() or fill() - }, - fillStyle: { - svgAttr: 'fill', - canvas: '#000000', - svg: null, //svg default is black, but we need to special case this to handle canvas stroke without fill - apply: 'fill', - }, - lineCap: { - svgAttr: 'stroke-linecap', - canvas: 'butt', - svg: 'butt', - apply: 'stroke', - }, - lineJoin: { - svgAttr: 'stroke-linejoin', - canvas: 'miter', - svg: 'miter', - apply: 'stroke', - }, - miterLimit: { - svgAttr: 'stroke-miterlimit', - canvas: 10, - svg: 4, - apply: 'stroke', - }, - lineWidth: { - svgAttr: 'stroke-width', - canvas: 1, - svg: 1, - apply: 'stroke', - }, - globalAlpha: { - svgAttr: 'opacity', - canvas: 1, - svg: 1, - apply: 'fill stroke', - }, - font: { - //font converts to multiple svg attributes, there is custom logic for this - canvas: '10px sans-serif', - }, - shadowColor: { - canvas: '#000000', - }, - shadowOffsetX: { - canvas: 0, - }, - shadowOffsetY: { - canvas: 0, - }, - shadowBlur: { - canvas: 0, - }, - textAlign: { - canvas: 'start', - }, - textBaseline: { - canvas: 'alphabetic', - }, - lineDash: { - svgAttr: 'stroke-dasharray', - canvas: [], - svg: null, - apply: 'stroke', - }, - } - - /** - * - * @param gradientNode - reference to the gradient - * @constructor - */ - CanvasGradient = function (gradientNode, ctx) { - this.__root = gradientNode - this.__ctx = ctx - } - - /** - * Adds a color stop to the gradient root - */ - CanvasGradient.prototype.addColorStop = function (offset, color) { - var stop = this.__ctx.__createElement('stop'), - regex, - matches - stop.setAttribute('offset', offset) - if (color.indexOf('rgba') !== -1) { - //separate alpha value, since webkit can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(color) - stop.setAttribute( - 'stop-color', - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - stop.setAttribute('stop-opacity', matches[4]) - } else { - stop.setAttribute('stop-color', color) - } - this.__root.appendChild(stop) - } - - CanvasPattern = function (pattern, ctx) { - this.__root = pattern - this.__ctx = ctx - } - - /** - * The mock canvas context - * @param o - options include: - * ctx - existing Context2D to wrap around - * width - width of your canvas (defaults to 500) - * height - height of your canvas (defaults to 500) - * enableMirroring - enables canvas mirroring (get image data) (defaults to false) - * document - the document object (defaults to the current document) - */ - ctx = function (o) { - var defaultOptions = { - width: 500, - height: 500, - enableMirroring: false, - }, - options - - //keep support for this way of calling C2S: new C2S(width,height) - if (arguments.length > 1) { - options = defaultOptions - options.width = arguments[0] - options.height = arguments[1] - } else if (!o) { - options = defaultOptions - } else { - options = o - } - - if (!(this instanceof ctx)) { - //did someone call this without new? - return new ctx(options) - } - - //setup options - this.width = options.width || defaultOptions.width - this.height = options.height || defaultOptions.height - this.enableMirroring = - options.enableMirroring !== undefined - ? options.enableMirroring - : defaultOptions.enableMirroring - - this.canvas = this ///point back to this instance! - this.__document = options.document || document - - // allow passing in an existing context to wrap around - // if a context is passed in, we know a canvas already exist - if (options.ctx) { - this.__ctx = options.ctx - } else { - this.__canvas = this.__document.createElement('canvas') - this.__ctx = this.__canvas.getContext('2d') - } - - this.__setDefaultStyles() - this.__stack = [this.__getStyleState()] - this.__groupStack = [] - - //the root svg element - this.__root = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'svg' - ) - this.__root.setAttribute('version', 1.1) - this.__root.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - this.__root.setAttributeNS( - 'http://www.w3.org/2000/xmlns/', - 'xmlns:xlink', - 'http://www.w3.org/1999/xlink' - ) - this.__root.setAttribute('width', this.width) - this.__root.setAttribute('height', this.height) - - //make sure we don't generate the same ids in defs - this.__ids = {} - - //defs tag - this.__defs = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'defs' - ) - this.__root.appendChild(this.__defs) - - //also add a group child. the svg element can't use the transform attribute - this.__currentElement = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'g' - ) - this.__root.appendChild(this.__currentElement) - } - - /** - * Creates the specified svg element - * @private - */ - ctx.prototype.__createElement = function ( - elementName, - properties, - resetFill - ) { - if (typeof properties === 'undefined') { - properties = {} - } - - var element = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - elementName - ), - keys = Object.keys(properties), - i, - key - if (resetFill) { - //if fill or stroke is not specified, the svg element should not display. By default SVG's fill is black. - element.setAttribute('fill', 'none') - element.setAttribute('stroke', 'none') - } - for (i = 0; i < keys.length; i++) { - key = keys[i] - element.setAttribute(key, properties[key]) - } - return element - } - - /** - * Applies default canvas styles to the context - * @private - */ - ctx.prototype.__setDefaultStyles = function () { - //default 2d canvas context properties see:http://www.w3.org/TR/2dcontext/ - var keys = Object.keys(STYLES), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = STYLES[key].canvas - } - } - - /** - * Applies styles on restore - * @param styleState - * @private - */ - ctx.prototype.__applyStyleState = function (styleState) { - var keys = Object.keys(styleState), - i, - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - this[key] = styleState[key] - } - } - - /** - * Gets the current style state - * @return {Object} - * @private - */ - ctx.prototype.__getStyleState = function () { - var i, - styleState = {}, - keys = Object.keys(STYLES), - key - for (i = 0; i < keys.length; i++) { - key = keys[i] - styleState[key] = this[key] - } - return styleState - } - - /** - * Apples the current styles to the current SVG element. On "ctx.fill" or "ctx.stroke" - * @param type - * @private - */ - ctx.prototype.__applyStyleToCurrentElement = function (type) { - var currentElement = this.__currentElement - var currentStyleGroup = this.__currentElementsToStyle - if (currentStyleGroup) { - currentElement.setAttribute(type, '') - currentElement = currentStyleGroup.element - currentStyleGroup.children.forEach(function (node) { - node.setAttribute(type, '') - }) - } - - var keys = Object.keys(STYLES), - i, - style, - value, - id, - regex, - matches - for (i = 0; i < keys.length; i++) { - style = STYLES[keys[i]] - value = this[keys[i]] - if (style.apply) { - //is this a gradient or pattern? - if (value instanceof CanvasPattern) { - //pattern - if (value.__ctx) { - //copy over defs - while (value.__ctx.__defs.childNodes.length) { - id = - value.__ctx.__defs.childNodes[0].getAttribute( - 'id' - ) - this.__ids[id] = id - this.__defs.appendChild( - value.__ctx.__defs.childNodes[0] - ) - } - } - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if (value instanceof CanvasGradient) { - //gradient - currentElement.setAttribute( - style.apply, - format('url(#{id})', { - id: value.__root.getAttribute('id'), - }) - ) - } else if ( - style.apply.indexOf(type) !== -1 && - style.svg !== value - ) { - if ( - (style.svgAttr === 'stroke' || - style.svgAttr === 'fill') && - value.indexOf('rgba') !== -1 - ) { - //separate alpha value, since illustrator can't handle it - regex = - /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi - matches = regex.exec(value) - currentElement.setAttribute( - style.svgAttr, - format('rgb({r},{g},{b})', { - r: matches[1], - g: matches[2], - b: matches[3], - }) - ) - //should take globalAlpha here - var opacity = matches[4] - var globalAlpha = this.globalAlpha - if (globalAlpha != null) { - opacity *= globalAlpha - } - currentElement.setAttribute( - style.svgAttr + '-opacity', - opacity - ) - } else { - var attr = style.svgAttr - if (keys[i] === 'globalAlpha') { - attr = type + '-' + style.svgAttr - if (currentElement.getAttribute(attr)) { - //fill-opacity or stroke-opacity has already been set by stroke or fill. - continue - } - } - //otherwise only update attribute if right type, and not svg default - currentElement.setAttribute(attr, value) - } - } - } - } - } - - /** - * Will return the closest group or svg node. May return the current element. - * @private - */ - ctx.prototype.__closestGroupOrSvg = function (node) { - node = node || this.__currentElement - if (node.nodeName === 'g' || node.nodeName === 'svg') { - return node - } else { - return this.__closestGroupOrSvg(node.parentNode) - } - } - - /** - * Returns the serialized value of the svg so far - * @param fixNamedEntities - Standalone SVG doesn't support named entities, which document.createTextNode encodes. - * If true, we attempt to find all named entities and encode it as a numeric entity. - * @return serialized svg - */ - ctx.prototype.getSerializedSvg = function (fixNamedEntities) { - var serialized = new XMLSerializer().serializeToString(this.__root), - keys, - i, - key, - value, - regexp, - xmlns - - //IE search for a duplicate xmnls because they didn't implement setAttributeNS correctly - xmlns = - /xmlns="http:\/\/www\.w3\.org\/2000\/svg".+xmlns="http:\/\/www\.w3\.org\/2000\/svg/gi - if (xmlns.test(serialized)) { - serialized = serialized.replace( - 'xmlns="http://www.w3.org/2000/svg', - 'xmlns:xlink="http://www.w3.org/1999/xlink' - ) - } - - if (fixNamedEntities) { - keys = Object.keys(namedEntities) - //loop over each named entity and replace with the proper equivalent. - for (i = 0; i < keys.length; i++) { - key = keys[i] - value = namedEntities[key] - regexp = new RegExp(key, 'gi') - if (regexp.test(serialized)) { - serialized = serialized.replace(regexp, value) - } - } - } - - return serialized - } - - /** - * Returns the root svg - * @return - */ - ctx.prototype.getSvg = function () { - return this.__root - } - /** - * Will generate a group tag. - */ - ctx.prototype.save = function () { - var group = this.__createElement('g') - var parent = this.__closestGroupOrSvg() - this.__groupStack.push(parent) - parent.appendChild(group) - this.__currentElement = group - this.__stack.push(this.__getStyleState()) - } - /** - * Sets current element to parent, or just root if already root - */ - ctx.prototype.restore = function () { - this.__currentElement = this.__groupStack.pop() - this.__currentElementsToStyle = null - //Clearing canvas will make the poped group invalid, currentElement is set to the root group node. - if (!this.__currentElement) { - this.__currentElement = this.__root.childNodes[1] - } - var state = this.__stack.pop() - this.__applyStyleState(state) - } - - /** - * Helper method to add transform - * @private - */ - ctx.prototype.__addTransform = function (t) { - //if the current element has siblings, add another group - var parent = this.__closestGroupOrSvg() - if (parent.childNodes.length > 0) { - if (this.__currentElement.nodeName === 'path') { - if (!this.__currentElementsToStyle) - this.__currentElementsToStyle = { - element: parent, - children: [], - } - this.__currentElementsToStyle.children.push( - this.__currentElement - ) - this.__applyCurrentDefaultPath() - } - - var group = this.__createElement('g') - parent.appendChild(group) - this.__currentElement = group - } - - var transform = this.__currentElement.getAttribute('transform') - if (transform) { - transform += ' ' - } else { - transform = '' - } - transform += t - this.__currentElement.setAttribute('transform', transform) - } - - /** - * scales the current element - */ - ctx.prototype.scale = function (x, y) { - if (y === undefined) { - y = x - } - this.__addTransform(format('scale({x},{y})', { x: x, y: y })) - } - - /** - * rotates the current element - */ - ctx.prototype.rotate = function (angle) { - var degrees = (angle * 180) / Math.PI - this.__addTransform( - format('rotate({angle},{cx},{cy})', { - angle: degrees, - cx: 0, - cy: 0, - }) - ) - } - - /** - * translates the current element - */ - ctx.prototype.translate = function (x, y) { - this.__addTransform(format('translate({x},{y})', { x: x, y: y })) - } - - /** - * applies a transform to the current element - */ - ctx.prototype.transform = function (a, b, c, d, e, f) { - this.__addTransform( - format('matrix({a},{b},{c},{d},{e},{f})', { - a: a, - b: b, - c: c, - d: d, - e: e, - f: f, - }) - ) - } - - /** - * Create a new Path Element - */ - ctx.prototype.beginPath = function () { - var path, parent - - // Note that there is only one current default path, it is not part of the drawing state. - // See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path - this.__currentDefaultPath = '' - this.__currentPosition = {} - - path = this.__createElement('path', {}, true) - parent = this.__closestGroupOrSvg() - parent.appendChild(path) - this.__currentElement = path - } - - /** - * Helper function to apply currentDefaultPath to current path element - * @private - */ - ctx.prototype.__applyCurrentDefaultPath = function () { - var currentElement = this.__currentElement - if (currentElement.nodeName === 'path') { - currentElement.setAttribute('d', this.__currentDefaultPath) - } else { - console.error( - 'Attempted to apply path command to node', - currentElement.nodeName - ) - } - } - - /** - * Helper function to add path command - * @private - */ - ctx.prototype.__addPathCommand = function (command) { - this.__currentDefaultPath += ' ' - this.__currentDefaultPath += command - } - - /** - * Adds the move command to the current path element, - * if the currentPathElement is not empty create a new path element - */ - ctx.prototype.moveTo = function (x, y) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - - // creates a new subpath with the given point - this.__currentPosition = { x: x, y: y } - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } - - /** - * Closes the current path - */ - ctx.prototype.closePath = function () { - if (this.__currentDefaultPath) { - this.__addPathCommand('Z') - } - } - - /** - * Adds a line to command - */ - ctx.prototype.lineTo = function (x, y) { - this.__currentPosition = { x: x, y: y } - if (this.__currentDefaultPath.indexOf('M') > -1) { - this.__addPathCommand(format('L {x} {y}', { x: x, y: y })) - } else { - this.__addPathCommand(format('M {x} {y}', { x: x, y: y })) - } - } - - /** - * Add a bezier command - */ - ctx.prototype.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}', { - cp1x: cp1x, - cp1y: cp1y, - cp2x: cp2x, - cp2y: cp2y, - x: x, - y: y, - }) - ) - } - - /** - * Adds a quadratic curve to command - */ - ctx.prototype.quadraticCurveTo = function (cpx, cpy, x, y) { - this.__currentPosition = { x: x, y: y } - this.__addPathCommand( - format('Q {cpx} {cpy} {x} {y}', { cpx: cpx, cpy: cpy, x: x, y: y }) - ) - } - - /** - * Return a new normalized vector of given vector - */ - var normalize = function (vector) { - var len = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]) - return [vector[0] / len, vector[1] / len] - } - - /** - * Adds the arcTo to the current path - * - * @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto - */ - ctx.prototype.arcTo = function (x1, y1, x2, y2, radius) { - // Let the point (x0, y0) be the last point in the subpath. - var x0 = this.__currentPosition && this.__currentPosition.x - var y0 = this.__currentPosition && this.__currentPosition.y - - // First ensure there is a subpath for (x1, y1). - if (typeof x0 == 'undefined' || typeof y0 == 'undefined') { - return - } - - // Negative values for radius must cause the implementation to throw an IndexSizeError exception. - if (radius < 0) { - throw new Error( - 'IndexSizeError: The radius provided (' + - radius + - ') is negative.' - ) - } - - // If the point (x0, y0) is equal to the point (x1, y1), - // or if the point (x1, y1) is equal to the point (x2, y2), - // or if the radius radius is zero, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - if ( - (x0 === x1 && y0 === y1) || - (x1 === x2 && y1 === y2) || - radius === 0 - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line, - // then the method must add the point (x1, y1) to the subpath, - // and connect that point to the previous point (x0, y0) by a straight line. - var unit_vec_p1_p0 = normalize([x0 - x1, y0 - y1]) - var unit_vec_p1_p2 = normalize([x2 - x1, y2 - y1]) - if ( - unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === - unit_vec_p1_p0[1] * unit_vec_p1_p2[0] - ) { - this.lineTo(x1, y1) - return - } - - // Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius, - // and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1), - // and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2). - // The points at which this circle touches these two lines are called the start and end tangent points respectively. - - // note that both vectors are unit vectors, so the length is 1 - var cos = - unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + - unit_vec_p1_p0[1] * unit_vec_p1_p2[1] - var theta = Math.acos(Math.abs(cos)) - - // Calculate origin - var unit_vec_p1_origin = normalize([ - unit_vec_p1_p0[0] + unit_vec_p1_p2[0], - unit_vec_p1_p0[1] + unit_vec_p1_p2[1], - ]) - var len_p1_origin = radius / Math.sin(theta / 2) - var x = x1 + len_p1_origin * unit_vec_p1_origin[0] - var y = y1 + len_p1_origin * unit_vec_p1_origin[1] - - // Calculate start angle and end angle - // rotate 90deg clockwise (note that y axis points to its down) - var unit_vec_origin_start_tangent = [ - -unit_vec_p1_p0[1], - unit_vec_p1_p0[0], - ] - // rotate 90deg counter clockwise (note that y axis points to its down) - var unit_vec_origin_end_tangent = [ - unit_vec_p1_p2[1], - -unit_vec_p1_p2[0], - ] - var getAngle = function (vector) { - // get angle (clockwise) between vector and (1, 0) - var x = vector[0] - var y = vector[1] - if (y >= 0) { - // note that y axis points to its down - return Math.acos(x) - } else { - return -Math.acos(x) - } - } - var startAngle = getAngle(unit_vec_origin_start_tangent) - var endAngle = getAngle(unit_vec_origin_end_tangent) - - // Connect the point (x0, y0) to the start tangent point by a straight line - this.lineTo( - x + unit_vec_origin_start_tangent[0] * radius, - y + unit_vec_origin_start_tangent[1] * radius - ) - - // Connect the start tangent point to the end tangent point by arc - // and adding the end tangent point to the subpath. - this.arc(x, y, radius, startAngle, endAngle) - } - - /** - * Sets the stroke property on the current element - */ - ctx.prototype.stroke = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute( - 'paint-order', - 'fill stroke markers' - ) - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('stroke') - } - - /** - * Sets fill properties on the current element - */ - ctx.prototype.fill = function () { - if (this.__currentElement.nodeName === 'path') { - this.__currentElement.setAttribute( - 'paint-order', - 'stroke fill markers' - ) - } - this.__applyCurrentDefaultPath() - this.__applyStyleToCurrentElement('fill') - } - - /** - * Adds a rectangle to the path. - */ - ctx.prototype.rect = function (x, y, width, height) { - if (this.__currentElement.nodeName !== 'path') { - this.beginPath() - } - this.moveTo(x, y) - this.lineTo(x + width, y) - this.lineTo(x + width, y + height) - this.lineTo(x, y + height) - this.lineTo(x, y) - this.closePath() - } - - /** - * adds a rectangle element - */ - ctx.prototype.fillRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('fill') - } - - /** - * Draws a rectangle with no fill - * @param x - * @param y - * @param width - * @param height - */ - ctx.prototype.strokeRect = function (x, y, width, height) { - var rect, parent - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - }, - true - ) - parent = this.__closestGroupOrSvg() - parent.appendChild(rect) - this.__currentElement = rect - this.__applyStyleToCurrentElement('stroke') - } - - /** - * Clear entire canvas: - * 1. save current transforms - * 2. remove all the childNodes of the root g element - */ - ctx.prototype.__clearCanvas = function () { - var current = this.__closestGroupOrSvg(), - transform = current.getAttribute('transform') - var rootGroup = this.__root.childNodes[1] - var childNodes = rootGroup.childNodes - for (var i = childNodes.length - 1; i >= 0; i--) { - if (childNodes[i]) { - rootGroup.removeChild(childNodes[i]) - } - } - this.__currentElement = rootGroup - //reset __groupStack as all the child group nodes are all removed. - this.__groupStack = [] - if (transform) { - this.__addTransform(transform) - } - } - - /** - * "Clears" a canvas by just drawing a white rectangle in the current group. - */ - ctx.prototype.clearRect = function (x, y, width, height) { - //clear entire canvas - if ( - x === 0 && - y === 0 && - width === this.width && - height === this.height - ) { - this.__clearCanvas() - return - } - var rect, - parent = this.__closestGroupOrSvg() - rect = this.__createElement( - 'rect', - { - x: x, - y: y, - width: width, - height: height, - fill: '#FFFFFF', - }, - true - ) - parent.appendChild(rect) - } - - /** - * Adds a linear gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ - ctx.prototype.createLinearGradient = function (x1, y1, x2, y2) { - var grad = this.__createElement( - 'linearGradient', - { - id: randomString(this.__ids), - x1: x1 + 'px', - x2: x2 + 'px', - y1: y1 + 'px', - y2: y2 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) - } - - /** - * Adds a radial gradient to a defs tag. - * Returns a canvas gradient object that has a reference to it's parent def - */ - ctx.prototype.createRadialGradient = function (x0, y0, r0, x1, y1, r1) { - var grad = this.__createElement( - 'radialGradient', - { - id: randomString(this.__ids), - cx: x1 + 'px', - cy: y1 + 'px', - r: r1 + 'px', - fx: x0 + 'px', - fy: y0 + 'px', - gradientUnits: 'userSpaceOnUse', - }, - false - ) - this.__defs.appendChild(grad) - return new CanvasGradient(grad, this) - } - - /** - * Parses the font string and returns svg mapping - * @private - */ - ctx.prototype.__parseFont = function () { - var regex = - /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\'\"\sa-z0-9]+?)\s*$/i - var fontPart = regex.exec(this.font) - var data = { - style: fontPart[1] || 'normal', - size: fontPart[4] || '10px', - family: fontPart[6] || 'sans-serif', - weight: fontPart[3] || 'normal', - decoration: fontPart[2] || 'normal', - href: null, - } - - //canvas doesn't support underline natively, but we can pass this attribute - if (this.__fontUnderline === 'underline') { - data.decoration = 'underline' - } - - //canvas also doesn't support linking, but we can pass this as well - if (this.__fontHref) { - data.href = this.__fontHref - } - - return data - } - - /** - * Helper to link text fragments - * @param font - * @param element - * @return {*} - * @private - */ - ctx.prototype.__wrapTextLink = function (font, element) { - if (font.href) { - var a = this.__createElement('a') - a.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - font.href - ) - a.appendChild(element) - return a - } - return element - } - - /** - * Fills or strokes text - * @param text - * @param x - * @param y - * @param action - stroke or fill - * @private - */ - ctx.prototype.__applyText = function (text, x, y, action) { - var font = this.__parseFont(), - parent = this.__closestGroupOrSvg(), - textElement = this.__createElement( - 'text', - { - 'font-family': font.family, - 'font-size': font.size, - 'font-style': font.style, - 'font-weight': font.weight, - 'text-decoration': font.decoration, - x: x, - y: y, - 'text-anchor': getTextAnchor(this.textAlign), - 'dominant-baseline': getDominantBaseline(this.textBaseline), - }, - true - ) - - textElement.appendChild(this.__document.createTextNode(text)) - this.__currentElement = textElement - this.__applyStyleToCurrentElement(action) - parent.appendChild(this.__wrapTextLink(font, textElement)) - } - - /** - * Creates a text element - * @param text - * @param x - * @param y - */ - ctx.prototype.fillText = function (text, x, y) { - this.__applyText(text, x, y, 'fill') - } - - /** - * Strokes text - * @param text - * @param x - * @param y - */ - ctx.prototype.strokeText = function (text, x, y) { - this.__applyText(text, x, y, 'stroke') - } - - /** - * No need to implement this for svg. - * @param text - * @return {TextMetrics} - */ - ctx.prototype.measureText = function (text) { - this.__ctx.font = this.font - return this.__ctx.measureText(text) - } - - /** - * Arc command! - */ - ctx.prototype.arc = function ( - x, - y, - radius, - startAngle, - endAngle, - counterClockwise - ) { - // in canvas no circle is drawn if no angle is provided. - if (startAngle === endAngle) { - return - } - startAngle = startAngle % (2 * Math.PI) - endAngle = endAngle % (2 * Math.PI) - if (startAngle === endAngle) { - //circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle) - endAngle = - (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % - (2 * Math.PI) - } - var endX = x + radius * Math.cos(endAngle), - endY = y + radius * Math.sin(endAngle), - startX = x + radius * Math.cos(startAngle), - startY = y + radius * Math.sin(startAngle), - sweepFlag = counterClockwise ? 0 : 1, - largeArcFlag = 0, - diff = endAngle - startAngle - - // https://github.com/gliffy/canvas2svg/issues/4 - if (diff < 0) { - diff += 2 * Math.PI - } - - if (counterClockwise) { - largeArcFlag = diff > Math.PI ? 0 : 1 - } else { - largeArcFlag = diff > Math.PI ? 1 : 0 - } - - this.lineTo(startX, startY) - this.__addPathCommand( - format( - 'A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}', - { - rx: radius, - ry: radius, - xAxisRotation: 0, - largeArcFlag: largeArcFlag, - sweepFlag: sweepFlag, - endX: endX, - endY: endY, - } - ) - ) - - this.__currentPosition = { x: endX, y: endY } - } - - /** - * Generates a ClipPath from the clip command. - */ - ctx.prototype.clip = function () { - var group = this.__closestGroupOrSvg(), - clipPath = this.__createElement('clipPath'), - id = randomString(this.__ids), - newGroup = this.__createElement('g') - - this.__applyCurrentDefaultPath() - group.removeChild(this.__currentElement) - clipPath.setAttribute('id', id) - clipPath.appendChild(this.__currentElement) - - this.__defs.appendChild(clipPath) - - //set the clip path to this group - group.setAttribute('clip-path', format('url(#{id})', { id: id })) - - //clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations - // to this path - group.appendChild(newGroup) - - this.__currentElement = newGroup - } - - /** - * Draws a canvas, image or mock context to this canvas. - * Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support. - * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage - */ - ctx.prototype.drawImage = function () { - //convert arguments to a real array - var args = Array.prototype.slice.call(arguments), - image = args[0], - dx, - dy, - dw, - dh, - sx = 0, - sy = 0, - sw, - sh, - parent, - svg, - defs, - group, - currentElement, - svgImage, - canvas, - context, - id - - if (args.length === 3) { - dx = args[1] - dy = args[2] - sw = image.width - sh = image.height - dw = sw - dh = sh - } else if (args.length === 5) { - dx = args[1] - dy = args[2] - dw = args[3] - dh = args[4] - sw = image.width - sh = image.height - } else if (args.length === 9) { - sx = args[1] - sy = args[2] - sw = args[3] - sh = args[4] - dx = args[5] - dy = args[6] - dw = args[7] - dh = args[8] - } else { - throw new Error( - 'Invalid number of arguments passed to drawImage: ' + - arguments.length - ) - } - - parent = this.__closestGroupOrSvg() - currentElement = this.__currentElement - var translateDirective = 'translate(' + dx + ', ' + dy + ')' - if (image instanceof ctx) { - //canvas2svg mock canvas context. In the future we may want to clone nodes instead. - //also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context. - svg = image.getSvg().cloneNode(true) - if (svg.childNodes && svg.childNodes.length > 1) { - defs = svg.childNodes[0] - while (defs.childNodes.length) { - id = defs.childNodes[0].getAttribute('id') - this.__ids[id] = id - this.__defs.appendChild(defs.childNodes[0]) - } - group = svg.childNodes[1] - if (group) { - //save original transform - var originTransform = group.getAttribute('transform') - var transformDirective - if (originTransform) { - transformDirective = - originTransform + ' ' + translateDirective - } else { - transformDirective = translateDirective - } - group.setAttribute('transform', transformDirective) - parent.appendChild(group) - } - } - } else if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - //canvas or image - svgImage = this.__createElement('image') - svgImage.setAttribute('width', dw) - svgImage.setAttribute('height', dh) - svgImage.setAttribute('preserveAspectRatio', 'none') - - if (sx || sy || sw !== image.width || sh !== image.height) { - //crop the image using a temporary canvas - canvas = this.__document.createElement('canvas') - canvas.width = dw - canvas.height = dh - context = canvas.getContext('2d') - context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh) - image = canvas - } - svgImage.setAttribute('transform', translateDirective) - svgImage.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - parent.appendChild(svgImage) - } - } - - /** - * Generates a pattern tag - */ - ctx.prototype.createPattern = function (image, repetition) { - var pattern = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'pattern' - ), - id = randomString(this.__ids), - img - pattern.setAttribute('id', id) - pattern.setAttribute('width', image.width) - pattern.setAttribute('height', image.height) - if (image.nodeName === 'CANVAS' || image.nodeName === 'IMG') { - img = this.__document.createElementNS( - 'http://www.w3.org/2000/svg', - 'image' - ) - img.setAttribute('width', image.width) - img.setAttribute('height', image.height) - img.setAttributeNS( - 'http://www.w3.org/1999/xlink', - 'xlink:href', - image.nodeName === 'CANVAS' - ? image.toDataURL() - : image.getAttribute('src') - ) - pattern.appendChild(img) - this.__defs.appendChild(pattern) - } else if (image instanceof ctx) { - pattern.appendChild(image.__root.childNodes[1]) - this.__defs.appendChild(pattern) - } - return new CanvasPattern(pattern, this) - } - - ctx.prototype.setLineDash = function (dashArray) { - if (dashArray && dashArray.length > 0) { - this.lineDash = dashArray.join(',') - } else { - this.lineDash = null - } - } - - /** - * Not yet implemented - */ - ctx.prototype.drawFocusRing = function () {} - ctx.prototype.createImageData = function () {} - ctx.prototype.getImageData = function () {} - ctx.prototype.putImageData = function () {} - ctx.prototype.globalCompositeOperation = function () {} - ctx.prototype.setTransform = function () {} - - //add options for alternative namespace - if (typeof window === 'object') { - window.C2S = ctx - } - - // CommonJS/Browserify - if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = ctx - } -})() diff --git a/v1/src/store/SimulatorStore/actions.ts b/v1/src/store/SimulatorStore/actions.ts index e127bc5f..f5dee32b 100644 --- a/v1/src/store/SimulatorStore/actions.ts +++ b/v1/src/store/SimulatorStore/actions.ts @@ -5,12 +5,28 @@ export const useActions = defineStore('simulatorStore.actions', () => { const state = useState() function showTitle(): void { - console.log(state.title) + } + + function showMessage(message: string, type: 'error' | 'success') { + if (type === 'error') { + state.errorMessages.push(message) + } else { + state.successMessages.push(message) + } + + setTimeout(() => { + if (type === 'error') { + state.errorMessages.shift() + } else { + state.successMessages.shift() + } + }, type === 'error' ? 1500 : 2500) } // Note you are free to define as many internal functions as you want. // You only expose the functions that are returned. return { showTitle, + showMessage, } }) diff --git a/v1/src/store/SimulatorStore/state.ts b/v1/src/store/SimulatorStore/state.ts index 1bad89ad..cc57592f 100644 --- a/v1/src/store/SimulatorStore/state.ts +++ b/v1/src/store/SimulatorStore/state.ts @@ -3,16 +3,20 @@ import { defineStore } from 'pinia' // use camel case variable names export interface State { title: string - activeCircuit: - | Object - | { - id: number | string - name: string - } - circuit_list: Array + activeCircuit: { + id: number | string + name: string + } | undefined; + circuit_list: { + id: number | string + name: string + isVerilog?: boolean + focussed?: boolean + }[]; + errorMessages: string[] + successMessages: string[] + circuit_name_clickable: boolean; dialogBox: { - // create_circuit: boolean - // delete_circuit: boolean combinationalanalysis_dialog: boolean hex_bin_dec_converter_dialog: boolean saveimage_dialog: boolean @@ -25,8 +29,14 @@ export interface State { export_project_dialog: boolean import_project_dialog: boolean } - // createCircuit: Object | { circuitName: string } combinationalAnalysis: Object + subCircuitElementList: Array + isEmptySubCircuitElementList: boolean +} + +interface LayoutElementGroup { + type: string + elements: any[] } export const useState = defineStore({ @@ -35,11 +45,12 @@ export const useState = defineStore({ state: (): State => { return { title: 'Welcome to CircuitVerse Simulator', - activeCircuit: {}, + activeCircuit: undefined, circuit_list: [], + errorMessages: [], + successMessages: [], + circuit_name_clickable: false, dialogBox: { - // create_circuit: false, - // delete_circuit: false, combinationalanalysis_dialog: false, hex_bin_dec_converter_dialog: false, saveimage_dialog: false, @@ -52,15 +63,14 @@ export const useState = defineStore({ export_project_dialog: false, import_project_dialog: false, }, - // createCircuit: { - // circuitName: 'Untitled Circuit', - // }, combinationalAnalysis: { inputNameList: 'eg. In A, In B', outputNameList: 'eg. Out X, Out Y', booleanExpression: 'Example: (AB)', decimalColumnBox: false, }, + subCircuitElementList: [], + isEmptySubCircuitElementList: true, } }, -}) +}) \ No newline at end of file diff --git a/v1/src/store/authStore.ts b/v1/src/store/authStore.ts index 12dd433c..57c23043 100644 --- a/v1/src/store/authStore.ts +++ b/v1/src/store/authStore.ts @@ -4,6 +4,7 @@ interface AuthStoreType { isLoggedIn: boolean userId: string | number username: string + userAvatar: string locale: string isAdmin: boolean } @@ -13,6 +14,7 @@ interface UserInfo { id: string attributes: { name: string + profile_picture: string locale: string admin: boolean } @@ -22,7 +24,8 @@ export const useAuthStore = defineStore({ state: (): AuthStoreType => ({ isLoggedIn: false, userId: '', - username: '', + username: 'Guest', + userAvatar: 'default', locale: 'en', isAdmin: false, }), @@ -30,7 +33,11 @@ export const useAuthStore = defineStore({ setUserInfo(userInfo: UserInfo): void { this.isLoggedIn = true this.userId = userInfo.id ?? '' - this.username = userInfo.attributes.name ?? '' + this.username = userInfo.attributes.name ?? 'Guest' + if (userInfo.attributes.profile_picture != 'original/Default.jpg') { + this.userAvatar = + userInfo.attributes.profile_picture ?? 'default' + } this.locale = userInfo.attributes.locale ?? 'en' this.isAdmin = userInfo.attributes.admin }, @@ -45,6 +52,9 @@ export const useAuthStore = defineStore({ getUsername(): string { return this.username }, + getUserAvatar(): string { + return this.userAvatar + }, getLocale(): string { return this.locale }, diff --git a/v1/src/store/layoutStore.ts b/v1/src/store/layoutStore.ts new file mode 100644 index 00000000..6a6131b6 --- /dev/null +++ b/v1/src/store/layoutStore.ts @@ -0,0 +1,84 @@ +import { defineStore } from "pinia"; +import { ref, Ref, watch } from "vue"; + +export const useLayoutStore = defineStore("layoutStore", () => { + const layoutMode = ref(false); + const layoutDialogRef: Ref = ref(null); + const layoutElementPanelRef: Ref = ref(null); + const elementsPanelRef: Ref = ref(null); + const timingDiagramPanelRef: Ref = ref(null); + const testbenchPanelRef: Ref = ref(null); + + watch(layoutMode, (val) => { + if (val) { + fadeIn(layoutDialogRef.value); + fadeIn(layoutElementPanelRef.value); + fadeOut(elementsPanelRef.value); + fadeOut(timingDiagramPanelRef.value); + fadeOut(testbenchPanelRef.value); + } else { + fadeOut(layoutDialogRef.value); + fadeOut(layoutElementPanelRef.value); + fadeIn(elementsPanelRef.value); + fadeIn(timingDiagramPanelRef.value); + fadeIn(testbenchPanelRef.value); + } + }); + + function fadeIn(element: HTMLElement | null, duration = 200) { + if (!element) return; + element.style.display = "block"; + element.style.opacity = "0"; + let startTime: number | null = null; + + function animate(currentTime: number | null) { + if (!startTime) { + startTime = currentTime; + } + + const elapsedTime = (currentTime ?? 0) - (startTime ?? 0); + const newOpacity = elapsedTime / duration; + + element!.style.opacity = newOpacity > 1 ? "1" : newOpacity.toString(); + + if (elapsedTime < duration) { + requestAnimationFrame(animate); + } + } + + requestAnimationFrame(animate); + } + + function fadeOut(element: HTMLElement | null, duration = 200) { + if (!element) return; + let startTime: number | null = null; + + function animate(currentTime: number | null) { + if (!startTime) { + startTime = currentTime; + } + + const elapsedTime = (currentTime ?? 0) - (startTime ?? 0); + const newOpacity = 1 - elapsedTime / duration; + + element!.style.opacity = newOpacity < 0 ? "0" : newOpacity.toString(); + + if (elapsedTime < duration) { + requestAnimationFrame(animate); + } else { + element!.style.display = "none"; + } + } + + requestAnimationFrame(animate); + } + + return { + layoutMode, + layoutDialogRef, + layoutElementPanelRef, + elementsPanelRef, + timingDiagramPanelRef, + testbenchPanelRef, + }; +}); \ No newline at end of file diff --git a/v1/src/store/propertiesPanelStore.ts b/v1/src/store/propertiesPanelStore.ts new file mode 100644 index 00000000..07f4c462 --- /dev/null +++ b/v1/src/store/propertiesPanelStore.ts @@ -0,0 +1,24 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { tempBuffer } from "#/simulator/src/layoutMode"; + +export const usePropertiesPanelStore = defineStore("propertiesPanelStore", () => { + const inLayoutMode = ref(false) + const panelBodyHeader = ref('PROJECT PROPERTIES') + const propertiesPanelObj = ref(undefined) + const panelType = ref(1) // default is panel type 2 (project properties) + + // Layout + + const titleEnable = ref(tempBuffer?.layout?.titleEnabled) + const layoutDialogRef = ref(null); + + return { + inLayoutMode, + panelBodyHeader, + propertiesPanelObj, + panelType, + titleEnable, + layoutDialogRef, + }; +}); diff --git a/v1/src/store/simulatorMobileStore.ts b/v1/src/store/simulatorMobileStore.ts new file mode 100644 index 00000000..fcdb0e7c --- /dev/null +++ b/v1/src/store/simulatorMobileStore.ts @@ -0,0 +1,36 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; + +export type ElementsType = 'elements' | 'layout-elements' + +export const useSimulatorMobileStore = defineStore("simulatorMobileStore", () => { + const minWidthToShowMobile = ref(991); + const showMobileView = ref(false); + const showCanvas = ref(false); + const showTimingDiagram = ref(false); + const showElementsPanel = ref(false); + const showPropertiesPanel = ref(false); + const showQuickButtons = ref(true); + const showMobileButtons = ref(true); + const showVerilogPanel = ref(false); + const isCopy = ref(false); + const isVerilog = ref(false); + const showCircuits = ref('elements') + + showMobileView.value = window.innerWidth <= minWidthToShowMobile.value + + return { + minWidthToShowMobile, + showMobileView, + showCanvas, + showTimingDiagram, + showElementsPanel, + showPropertiesPanel, + showQuickButtons, + showMobileButtons, + showVerilogPanel, + isCopy, + isVerilog, + showCircuits, + }; +}); diff --git a/v1/src/store/testBenchStore.ts b/v1/src/store/testBenchStore.ts new file mode 100644 index 00000000..68f952a2 --- /dev/null +++ b/v1/src/store/testBenchStore.ts @@ -0,0 +1,105 @@ +import { defineStore } from "pinia"; +import { reactive, ref } from "vue"; +import { runTestBench } from "#/simulator/src/testbench"; + +export interface TestData { + type: string; + title: string; + groups: { + label: string; + inputs: { + label: string; + bitWidth: number; + values: string[]; + }[]; + outputs: { + label: string; + bitWidth: number; + values: string[]; + results?: string[]; + }[]; + n: number; + }[]; +} + +export interface TestBenchData { + testData: TestData; + currentGroup: number; + currentCase: number; + + isCaseValid?(): boolean; + setCase?(groupIndex: number, caseIndex: number): boolean; + groupNext?(): boolean; + groupPrev?(): boolean; + caseNext?(): boolean; + casePrev?(): boolean; + goToFirstValidGroup?(): boolean; +}; + +export interface ValidationErrors { + ok: boolean + invalids?: { + type: number + identifier: string + message: string + extraInfo?: any + }[] +} + +export interface Result { + value: string; + color: string; +} + +export const useTestBenchStore = defineStore("testBenchStore", () => { + const showTestBenchCreator = ref(false); + const showTestbenchUI = ref(false); + const showTestBenchValidator = ref(false); + const resultValues = ref([]); + const passed = ref(0); + const total = ref(0); + const showPassed = ref(false); + const showResults = ref(false); + const readOnly = ref(false); + + const testData = reactive({ + type: "", + title: "", + groups: [], + }); + + const testbenchData = reactive({ + testData: testData, + currentGroup: 0, + currentCase: 0, + }); + + const validationErrors: ValidationErrors = reactive({ + ok: true, + invalids: [] + }); + + const sendData = (dataValues: TestData) => { + showTestbenchUI.value = true; + testData.type = dataValues.type; + testData.title = dataValues.title; + testData.groups = dataValues.groups; + runTestBench(dataValues, globalScope, 0); + showTestBenchCreator.value = false; + } + + return { + showTestBenchCreator, + sendData, + testbenchData, + showTestbenchUI, + validationErrors, + showTestBenchValidator, + resultValues, + passed, + total, + showResults, + readOnly, + showPassed, + } +}) diff --git a/v1/src/store/timingDiagramPanelStore.ts b/v1/src/store/timingDiagramPanelStore.ts new file mode 100644 index 00000000..fbab4ace --- /dev/null +++ b/v1/src/store/timingDiagramPanelStore.ts @@ -0,0 +1,25 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import buttonsJSON from '#/assets/constants/Panels/TimingDiagramPanel/buttons.json' + +export interface TimingDiagramButton { + title: string + icon: string + class: string + type: string + click: string +} + +export const useTimingDiagramPanelStore = defineStore("timingDiagramPanelStore", () => { + const buttons = ref(buttonsJSON) + const plotRef = ref(null) + const cycleUnits = ref(1000) + const timingDiagramPanelRef = ref(null); + + return { + buttons, + plotRef, + cycleUnits, + timingDiagramPanelRef + }; +}); diff --git a/v1/src/styles/color_theme.scss b/v1/src/styles/color_theme.scss index 5bdc9fff..8b467c52 100644 --- a/v1/src/styles/color_theme.scss +++ b/v1/src/styles/color_theme.scss @@ -138,6 +138,11 @@ box-shadow: 0px 0px 10px #4545457f; } +.draggable-panel-mobile { + background: white; + box-shadow: 0px 0px 10px #4545457f; +} + .panel-header { color: var(--text-panel); background: var(--primary); @@ -223,7 +228,6 @@ #tabsBar { background-color: var(--bg-tabs); - border-top: 1px solid var(--br-primary); border-bottom: 1px solid var(--br-primary); } diff --git a/v1/src/styles/css/UX.css b/v1/src/styles/css/UX.css index e5011d8a..890d4cfa 100644 --- a/v1/src/styles/css/UX.css +++ b/v1/src/styles/css/UX.css @@ -642,31 +642,6 @@ div.icon img { display: inline-block; } -.img__description { - position: absolute; - /*top: 0;*/ - bottom: -16; - text-align: center; - left: 0; - right: 0; - background-color: #0099ff; - color: white; - font-size: 8px; - /*background: rgba(29, 106, 154, 0.72); - color: #fff;*/ - visibility: hidden; - border-bottom-left-radius: 2px; - border-bottom-right-radius: 2px; - opacity: 0; - /* transition effect. not necessary */ - transition: opacity 0.2s, visibility 0.2s; -} - -.icon:hover .img__description { - visibility: visible; - opacity: 1; -} - .icon:hover { /*background-color: #cce5ff;*/ /*border-color: blue;*/ diff --git a/v1/src/styles/css/embed.css b/v1/src/styles/css/embed.css index ed09eb73..34517a8f 100644 --- a/v1/src/styles/css/embed.css +++ b/v1/src/styles/css/embed.css @@ -46,7 +46,8 @@ border-radius: 6px; opacity: 0.1; transition: 0.4s; - height: 109px; + height: auto; + gap: 1rem; display: flex; flex-direction: column; justify-content: space-between; @@ -259,3 +260,15 @@ button:focus { .embed-fullscreen-btn { border-radius: 20px; } + +#bottom_right_circuit_heading { + text-decoration: none; + position: fixed; + bottom: 1.5rem; + right: 2rem; + padding: 8px; + font-family: Verdana; + font-size: 12px; + color: var(--text-panel); + z-index: 2; +} diff --git a/v1/src/styles/css/main.stylesheet.css b/v1/src/styles/css/main.stylesheet.css index b487179b..b4dfabef 100644 --- a/v1/src/styles/css/main.stylesheet.css +++ b/v1/src/styles/css/main.stylesheet.css @@ -661,14 +661,6 @@ div.icon img { right: 10px; } -.layoutElementPanel { - width: 220px; - font: inherit; - display: none; - top: 90px; - left: 10px; -} - .timing-diagram-panel { border-radius: 5px; z-index: 70; @@ -801,10 +793,6 @@ div.icon img { width: 200px; } -.testbench-runall-label { - display: none; -} - .tb-dialog-button { display: inline; margin: 8px; @@ -1390,6 +1378,10 @@ input:checked + .slider:before { text-align: center; padding-top: 20px; } + + #moduleProperty-inner { + padding: 1rem; + } } /*! download dialog styling end here */ @@ -1517,12 +1509,14 @@ input:checked + .slider:before { #miniMap { position: fixed; z-index: 3; - bottom: 20px; - right: 40px; + bottom: -6rem; + right: 0.5rem; overflow-y: scroll; opacity: 0.5; overflow: hidden; border: none; + height: 15rem; + width: 18rem; } .disable::after { @@ -1764,9 +1758,17 @@ canvas { width: 800px; } +@media (max-width: 991px) { + #plot { + width: 100%; + } +} + .timing-diagram-toolbar { + display: flex; + align-items: center; + flex-wrap: wrap; padding-left: 4px; - padding: 2px; cursor: default; } @@ -1856,7 +1858,7 @@ canvas { margin-bottom: 0.5rem; } -/* +/* .ProseMirror ul { list-style-type: disc; } diff --git a/v1/src/styles/css/testCreator.css b/v1/src/styles/css/testCreator.css index 47877b3c..63bdd2f1 100644 --- a/v1/src/styles/css/testCreator.css +++ b/v1/src/styles/css/testCreator.css @@ -10,7 +10,7 @@ background-color: #ffffff; border: 2px solid black; color: black; - /*padding: 20px;*/ + padding: 6px; text-align: center; text-decoration: none; display: inline-block; diff --git a/v1/src/styles/simulator.scss b/v1/src/styles/simulator.scss index f6460422..a9940c15 100644 --- a/v1/src/styles/simulator.scss +++ b/v1/src/styles/simulator.scss @@ -23,10 +23,9 @@ $fa-font-path: '../../../node_modules/@fortawesome/fontawesome-free/webfonts'; position: fixed; right: -119px; text-decoration: none; - bottom: 30px; transition: 0.3s; width: 160px; - z-index: 999; + z-index: 99; } .report-sidebar span { From 460f985f55146b7ed356397a9835bb5d31c0740f Mon Sep 17 00:00:00 2001 From: ThatDeparted2061 Date: Fri, 27 Jun 2025 01:09:45 +0530 Subject: [PATCH 2/3] chore: Add logic for correct version loading to setup.js --- v0/src/simulator/src/setup.js | 8 ++++++++ v1/src/simulator/src/setup.js | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/v0/src/simulator/src/setup.js b/v0/src/simulator/src/setup.js index 1f04977e..b23a8417 100644 --- a/v0/src/simulator/src/setup.js +++ b/v0/src/simulator/src/setup.js @@ -110,6 +110,14 @@ async function fetchProjectData(projectId) { ) if (response.ok) { const data = await response.json() + const simulatorVersion = data.simulatorVersion + const projectName = data.name + if(!simulatorVersion){ + window.location.href = `/simulator/edit/${projectName}` + } + if(simulatorVersion && simulatorVersion != "v0"){ + window.location.href = `/simulatorvue/edit/${projectName}?simver=${simulatorVersion}` + } await load(data) await simulationArea.changeClockTime(data.timePeriod || 500) $('.loadingIcon').fadeOut() diff --git a/v1/src/simulator/src/setup.js b/v1/src/simulator/src/setup.js index 1f04977e..b23a8417 100644 --- a/v1/src/simulator/src/setup.js +++ b/v1/src/simulator/src/setup.js @@ -110,6 +110,14 @@ async function fetchProjectData(projectId) { ) if (response.ok) { const data = await response.json() + const simulatorVersion = data.simulatorVersion + const projectName = data.name + if(!simulatorVersion){ + window.location.href = `/simulator/edit/${projectName}` + } + if(simulatorVersion && simulatorVersion != "v0"){ + window.location.href = `/simulatorvue/edit/${projectName}?simver=${simulatorVersion}` + } await load(data) await simulationArea.changeClockTime(data.timePeriod || 500) $('.loadingIcon').fadeOut() From 329004730e331db4dbd02288f0fa43c7b843eda3 Mon Sep 17 00:00:00 2001 From: ThatDeparted2061 Date: Fri, 27 Jun 2025 01:12:18 +0530 Subject: [PATCH 3/3] chore: add version of simulato to save.js --- v0/src/simulator/src/data/save.js | 1 + v1/src/simulator/src/data/save.js | 1 + 2 files changed, 2 insertions(+) diff --git a/v0/src/simulator/src/data/save.js b/v0/src/simulator/src/data/save.js index ecc38eb4..cf14c375 100644 --- a/v0/src/simulator/src/data/save.js +++ b/v0/src/simulator/src/data/save.js @@ -101,6 +101,7 @@ export async function generateSaveData(name, setName = true) { data.projectId = projectId data.focussedCircuit = globalScope.id data.orderedTabs = getTabsOrder() + data.simulatorVersion = "v0" // Version of the simulator, used to identify the version of the simulator that created this project // Project Circuits, each scope is one circuit data.scopes = [] diff --git a/v1/src/simulator/src/data/save.js b/v1/src/simulator/src/data/save.js index ecc38eb4..3ca13ca0 100644 --- a/v1/src/simulator/src/data/save.js +++ b/v1/src/simulator/src/data/save.js @@ -101,6 +101,7 @@ export async function generateSaveData(name, setName = true) { data.projectId = projectId data.focussedCircuit = globalScope.id data.orderedTabs = getTabsOrder() + data.simulatorVersion = "v1" // Version of the simulator, used to identify the version of the simulator that created this project // Project Circuits, each scope is one circuit data.scopes = []