+[submodule "SampleERCP"]
+ path = SampleERCP
+ url = <address of this repo>
+ branch = SampleERCP
[submodule "SWTHelper"]
path = SWTHelper
url = https://github.com/Haspamelodica/SWTHelper
--- /dev/null
+# Rechnerarchitektur GP 2019
+#### Modularer Grafischer Schaltkreis Simulator (für die MI-Maschine)
+
+*Ihr könnt hier gerne nach belieben Dinge ändern, haltet euch nicht zurück^^*
+
+## Anforderungen
+
+### Pflichtfeatures
+1. Emulation der MI-Maschine (siehe Am2900ME)
+2. Visualisierung der MI-Maschine sehr ähnlich dem Bild der VL
+3. sehr gute Website, Dokumentation, Hilfe aus dem Kontextmenü heraus
+4. Hilfreiche Fehlermeldungen, Warnungen bei gefährlichen Operationen
+ für uns/Entwickler: gutes Loggen, Absturzberichte
+5. Immer hilfreiche Tooltips zu fast allem.
+
+
+### Sollte möglich sein
+1. Export der Ansicht
+2. Sicht des Assemblerprogrammierers, spezifizieren einer ISA und Nutzung
+3. Farben, Schriftgröße & Co. einstellbar (für Präsentation, Hell/Dunkel, Farbenblind/…)
+4. Entwurf eines Schaltkreises mit einem Editor
+5. Sprache ändern (für nicht Muttersprachler, internat. Potenzial, Erweiterungsmögl.)
+6. Sehr einfache Installation (Eclipse Marketplace)
+7. Editor sollte tooltip Einstellung erlauben
+8. Rückgängig
+
+
+### Wunschfeatures
+1. Debuggen im Sinne von Breakpoints & Co.
+2. interaktives Tutorial in der GUI
+3. Zurückspulen der Simulation / Zeitleiste
+4. Wiederherstellungspunkt (Status)
+
+### Weiterführende Ideen
+1. x86 Modell
+2. ARM Modell
+3. Signalgraphen
+
+### Use Cases
+<details><summary><strong>Alle Use Cases anzeigen</strong></summary><p>
+
+#### 01. Installation
+Das Programm lässt sich entweder über den Eclipse Marketplace einfach installieren (oder als Eclipse Projekt) oder als eigenes Eclipse RPC Projekt direkt herunterladen (ggf. entpacken) und starten.<sup>[A]</sup> Das Programm / Plugin lässt sich auf Windows (7+), MacOS und Linux ausführen; alle verbreitete Hardware nach 2010 mit 64 Bit OS sollte funktionieren.<sup>[B]</sup> Es muss auf den Rechnern in den TUM Rechnerhallen funktionieren.<sup>[C]</sup>
+
+#### 02. Deinstallation
+Das Programm muss sich ohne nennenswerten Aufwand oder Kentnisse vom Benutzer rückstandslos entfernen lassen.<sup>[A]</sup>
+
+#### 03. Programmstart
+Das Programm bzw. Plugin startet schnell (unter 10 sec.; besser unter 5 sec).<sup>[A]</sup> Bei dem ersten Programmstart ist ein Willkommensfenster zu sehen, das auf erklärende Resourcen verweist, den Nutzer grüßt und ggf. auf die (Sprach-)Einstellungen hinweist.<sup>[B]</sup> Es wird bestenfalls auf ein Beispielprojekt verwiesen (kann erstellt werden?) um dem Nutzer zu ermöglichen, sich damit vertraut zu machen.<sup>[C]</sup> Ein schnell Link zum Erstellen eines neuen Projekts/Simulation/... wird angezeigt.<sup>[D]</sup>
+
+#### 04. Programmende
+Sollten bei Beenden des Programms oder Programmabsturz nicht persistierte Daten vorliegen, muss dafür gesorgt werden, dass diese nicht verloren gehen.<sup>[A]</sup> Enweder durch einen Dialog<sup>[B]</sup>, oder durch erzeugte Recovery-Dateien<sup>[C]</sup>. Bei Absturz des Programms wird eine passende und aufschlussreiche Fehlermeldung angezeigt, bestenfalls mit Link zu einer Report-Möglichkeit.<sup>[D]</sup>
+
+#### 05. Einstellungen
+Die Hauptextfarbe und Schriftgröße muss einstellbar sein<sup>[A]</sup>, besser noch Hintergrund- und Markierungsfarben und Schriftstil.<sup>[B]</sup> Die Einstellung der Sprache muss möglich sein.<sup>[C]</sup>
+
+#### 06. Einstieg
+Das Einstiegsprojekt zeigt zu Beginn die passende Ansicht an, die Mikroprogrammierung ist wie bei dem Am2900ME ungehindert möglich.<sup>[A]</sup> Bestenfalls ist dieses beim (erstmaligen) Start direkt geöffnet.<sup>[B]</sup> Wichtige Fenster (v.a. die grafische Darstellung) sind direkt sichtbar, oder zumindest in einem Tab geöffnet (müssen nicht gesucht werden).<sup>[C]</sup>
+
+#### 07. Nutzung der Visualisierung
+Die Visualisierung soll möglichst der Vorlesung entsprechen.<sup>[A]</sup> Sie lässt sich transformieren (z.B. Zoom mit dem Mausrad, Verschieben mit Mausklick oder Mausklick und Alt) und wieder zurücksetzen.<sup>[B]</sup>
+
+#### 08. Hilfestellung
+Mit dem Produkt wird eine offline-Dokumentation mitgeliefert. (bestenfalls DE und EN)<sup>[A]</sup> Mit Rechtsklick lässt sich über ein Kontextmenü der Teil der Dokumentation öffnen, der das angeklickte und seine Funktion beschreibt (Vorbild Cinema4D). Dies sollte mit fast allem möglich sein.<sup>[B]</sup> Bleibt man mit der Maus länger über einem GUI-Bestandteil, wird eine kurze Beschreibung/Hilfe dazu angezeigt (Tooltip).<sup>[C]</sup>
+
+#### 09. Dateihandhabung
+Die Dateien sollten möglichst menschenlesbar sein, z.B. in CSV-Format, um Kommunikation mit anderer Software und Änderungen durch den Nutzer zu ermöglichen.<sup>[A]</sup> Die Dateien enthalten eine Versionsnummer, um Abwärtskompatibilität und hilfreiche Fehlermeldungen zu ermöglichen.<sup>[B]</sup>
+
+#### 10. Entwicklerunterstützung
+Das Projekt soll sich einfach bauen/kompilieren/exportieren lassen, es muss beschrieben werden wie das möglich ist.<sup>[A]</sup> Die Verbreitung zur Anwendung soll ebenfalls unproblematisch sein.<sup>[B]</sup>
+
+#### Fügt hier eure eigenen dazu, fortlaufend nummeriert und ggf. mit <sup>[A,B,C,..]</sup> genauer spezifiziert.
+
+</p></details>
+
+### UML und Ähnliches
+#### Grobe Struktur
+![image](https://user-images.githubusercontent.com/11130248/57186855-aae24600-6ee6-11e9-88b4-371622d43adc.png)
+
+## Technologie-Stack
+* Git (anscheinend über Gitlab)
+* Eclipse RCP
+ - (noch zu testen)
+* Java
+ - Version 8?
+ - Version 10?
+ - Version 12?
+* Bibliotheken
+ - JUnit 5.4.x ? AssertJ? [http://joel-costigliola.github.io/assertj/index.html](http://joel-costigliola.github.io/assertj/index.html)
+ - (Apache Commons?)
+ Sehr weit verbreitete und gut designte & getestete Lib;
+ aber zusätzliche Dep.
+ - Sonstiges? Logging? Log4j
+- Automatischer Build mit Maven? Wohl eher nicht, wegen ERPC Build
+
+## Meilensteine
+
+## Außenwirkung
+### Name, Abkürzung
+### Signet, Logo
+### Beschreibung
+
+## Sonstiges
+### Nützliche Links
+- [https://wiki.eclipse.org/Rich_Client_Platform](https://wiki.eclipse.org/Rich_Client_Platform) -Links
+- [https://wiki.eclipse.org/User_Interface_Guidelines](https://wiki.eclipse.org/User_Interface_Guidelines) - etwas alt, aber nützlich
+- [https://download.eclipse.org/eclipse/downloads/](https://download.eclipse.org/eclipse/downloads/) - Eclipse Project
+- [https://www.vogella.com/tutorials/EclipseRCP/article.html](https://www.vogella.com/tutorials/EclipseRCP/article.html) - **Eclipse RPC Tutorial**
+- [https://github.com/eclipse/gef/wiki](https://github.com/eclipse/gef/wiki) - **Wiki für das Grafikframework**
+- [https://github.com/eclipse/MaisiKoleni/Am2900ME](https://github.com/eclipse/MaisiKoleni/Am2900ME) - der geistige Vorgänger
+- [https://github.com/Haspamelodica/Am2900ME_swt](https://github.com/Haspamelodica/Am2900ME_swt) - ... auch mit SWT
+
+### Rechtliches
+<details><summary>
+MIT Lizenz? - https://choosealicense.com/licenses/mit/
+
+</summary><p>
+
+>MIT License
+>
+>Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
+>
+>
+>
+>Permission is hereby granted, free of charge, to any person obtaining a copy
+>of this software and associated documentation files (the "Software"), to deal
+>in the Software without restriction, including without limitation the rights
+>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+>copies of the Software, and to permit persons to whom the Software is
+>furnished to do so, subject to the following conditions:
+>
+>The above copyright notice and this permission notice shall be included in all
+>copies or substantial portions of the Software.
+>
+>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+>IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+>FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+>AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+>LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+>OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+>SOFTWARE.
+
+</p></details>
+
+Muss ggf. Eclipse Public License verwendet werden wegen Copyleft?
+<details><summary>
+Eclipse Public License 2.0? - https://www.eclipse.org/legal/epl-2.0/
+
+</summary><p>
+
+>Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
+>
+>This program and the accompanying materials are made
+>available under the terms of the Eclipse Public License 2.0
+>which is available at https://www.eclipse.org/legal/epl-2.0/
+>
+>This Source Code may also be made available under the following Secondary
+>Licenses when the conditions for such availability set forth in the Eclipse
+>Public License, v. 2.0 are satisfied: GNU General Public License, version 2
+>with the GNU Classpath Exception which is
+>available at https://www.gnu.org/software/classpath/license.html.
+>
+>SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+</p></details>
--- /dev/null
+Subproject commit 10e87495184e49c5cab906921f0afaf2473d9aed
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5" />
+ <classpathentry kind="con"
+ path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-10">
+ <attributes>
+ <attribute name="module" value="true" />
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="bin" />
+</classpath>
--- /dev/null
+/bin/
+*.class
+*.log
+
+# package files
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# vm crash logs
+hs_err_pid*
\ No newline at end of file
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=10
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=10
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=140
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=140
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
--- /dev/null
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_ERA-MI
+formatter_settings_version=16
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=false
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=true
+sp_cleanup.convert_to_enhanced_for_loop=true
+sp_cleanup.correct_indentation=true
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=true
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=false
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=true
+sp_cleanup.remove_redundant_semicolons=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
--- /dev/null
+package era.mi.logic;
+
+import era.mi.logic.timeline.Timeline;
+
+public class Simulation
+{
+ public final static Timeline TIMELINE = new Timeline(11);
+
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic;
+
+import java.util.Arrays;
+
+import era.mi.logic.types.Bit;
+
+public final class Util
+{
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] concat(T[]... arrays)
+ {
+ if (arrays.length == 0)
+ throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
+
+ int length = 0;
+ for (T[] array : arrays)
+ length += array.length;
+
+ T[] newArray = Arrays.copyOf(arrays[0], length);
+ int appendIndex = arrays[0].length;
+ for (int i = 1; i < arrays.length; i++)
+ {
+ System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
+ appendIndex += arrays[i].length;
+ }
+
+ return newArray;
+ }
+
+// @SuppressWarnings("unchecked")
+// public static <T> T[][] split(T[] array, int... lengths)
+// {
+// //TODO: implement array split again; This version contains an illegal cast
+// int totalLength = 0;
+// for(int length : lengths)
+// totalLength += length;
+//
+// if(totalLength != array.length)
+// throw new IllegalArgumentException(); //TODO: add proper error message
+//
+// Object[][] newArray = new Object[lengths.length][];
+// int splitIndex = 0;
+// for(int i = 0; i < lengths.length; i++)
+// {
+// System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
+// splitIndex += lengths[i];
+// }
+//
+// return (T[][]) newArray;
+// }
+
+ public static Bit[] and(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::and);
+ }
+
+ public static Bit[] or(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::or);
+ }
+
+ public static Bit[] xor(Bit[] a, Bit[] b)
+ {
+ return binBitOp(a, b, Bit::xor);
+ }
+
+ private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
+ {
+ if (a.length != b.length)
+ throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+ Bit[] out = new Bit[a.length];
+ for (int i = 0; i < a.length; i++)
+ {
+ out[i] = op.execute(a[i], b[i]);
+ }
+ return out;
+ }
+
+ public static Bit[] not(Bit[] a)
+ {
+ Bit[] out = new Bit[a.length];
+ for (int i = 0; i < a.length; i++)
+ {
+ out[i] = a[i].not();
+ }
+ return out;
+ }
+
+ /**
+ * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, the result is stored in the first array.
+ *
+ * @author Christian Femers
+ */
+ public static Bit[] combineInto(Bit[] dest, Bit[] addition)
+ {
+ if (dest.length != addition.length)
+ throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+ for (int i = 0; i < addition.length; i++)
+ {
+ dest[i] = dest[i].join(addition[i]);
+ }
+ return dest;
+ }
+
+ interface BitOp
+ {
+ Bit execute(Bit a, Bit b);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.WireObserver;
+
+/**
+ * A basic component that recomputes all outputs (with a delay), when it is updated.
+ *
+ * @author Fabian Stemmler
+ */
+public abstract class BasicComponent implements WireObserver, Component
+{
+ private int processTime;
+
+ /**
+ *
+ * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.
+ *
+ * @author Fabian Stemmler
+ */
+ public BasicComponent(int processTime)
+ {
+ this.processTime = processTime > 0 ? processTime : 1;
+ }
+
+ @Override
+ public void update(Wire initiator, BitVector oldValues)
+ {
+ Simulation.TIMELINE.addEvent(e -> compute(), processTime);
+ }
+
+ protected abstract void compute();
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.types.Bit;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class BitDisplay extends BasicComponent
+{
+ private final WireEnd in;
+ private BitVector displayedValue;
+
+ public BitDisplay(WireEnd in)
+ {
+ super(1);
+ this.in = in;
+ in.addObserver(this);
+ compute();
+ }
+
+ @Override
+ protected void compute()
+ {
+ displayedValue = in.getValues();
+ }
+
+ public BitVector getDisplayedValue()
+ {
+ return displayedValue;
+ }
+
+ public boolean isDisplaying(Bit... values)
+ {
+ return displayedValue.equals(BitVector.of(values));
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(in);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of();
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.timeline.TimelineEvent;
+import era.mi.logic.timeline.TimelineEventHandler;
+import era.mi.logic.types.Bit;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class Clock implements TimelineEventHandler, Component
+{
+ private boolean toggle = false;
+ private WireEnd out;
+ private int delta;
+
+ /**
+ *
+ * @param out {@link Wire} the clock's impulses are fed into
+ * @param delta ticks between rising and falling edge
+ */
+ public Clock(WireEnd out, int delta)
+ {
+ this.delta = delta;
+ this.out = out;
+ addToTimeline();
+ }
+
+ @Override
+ public void handle(TimelineEvent e)
+ {
+ addToTimeline();
+ out.feedSignals(toggle ? Bit.ONE : Bit.ZERO);
+ toggle = !toggle;
+ }
+
+ public WireEnd getOut()
+ {
+ return out;
+ }
+
+ private void addToTimeline()
+ {
+ Simulation.TIMELINE.addEvent(this, delta);
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of();
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.wires.Wire.WireEnd;
+
+public interface Component
+{
+
+ /**
+ * Returns immutable list of all inputs to the {@link Component} (including e.g. the select bits to a MUX). Intended for visualization
+ * in the UI.
+ */
+ public List<WireEnd> getAllInputs();
+
+ /**
+ * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI.
+ */
+ public List<WireEnd> getAllOutputs();
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+import era.mi.logic.wires.WireObserver;
+
+public class Connector implements WireObserver, Component
+{
+ private boolean connected;
+ private final WireEnd a;
+ private final WireEnd b;
+
+ public Connector(WireEnd a, WireEnd b)
+ {
+ if (a.length() != b.length())
+ throw new IllegalArgumentException(String.format("WireArray width does not match: %d, %d", a.length(), b.length()));
+ this.a = a;
+ this.b = b;
+ a.addObserver(this);
+ b.addObserver(this);
+ }
+
+ public void connect()
+ {
+ connected = true;
+ update(a.getWire());
+ update(b.getWire());
+ }
+
+ public void disconnect()
+ {
+ connected = false;
+ a.clearSignals();
+ b.clearSignals();
+ }
+
+ public void setConnection(boolean connected)
+ {
+ if (connected)
+ connect();
+ else
+ disconnect();
+ }
+
+ @Override
+ public void update(Wire initiator, BitVector oldValues)
+ {
+ if (connected)
+ Simulation.TIMELINE.addEvent(e -> update(initiator), 1);
+ }
+
+ private void update(Wire initiator)
+ {
+ if (initiator == a.getWire())
+ b.feedSignals(a.wireValuesExcludingMe());
+ else
+ a.feedSignals(b.wireValuesExcludingMe());
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(a, b);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(a, b);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+
+/**
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
+ * output.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class Demux extends BasicComponent
+{
+ private final WireEnd select, in;
+ private final WireEnd[] outputs;
+ private final int outputSize;
+ private int selected = -1;
+
+ /**
+ * Output {@link Wire}s and in must be of uniform length
+ *
+ * @param in Must be of uniform length with all outputs.
+ * @param select Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.
+ * @param outputs One of these outputs receives the input signal, depending on the select bits
+ */
+ public Demux(int processTime, WireEnd in, WireEnd select, WireEnd... outputs)
+ {
+ super(processTime);
+ outputSize = in.length();
+
+ this.in = in;
+ this.outputs = outputs;
+ for (int i = 0; i < this.outputs.length; i++)
+ {
+ if (outputs[i].length() != outputSize)
+ throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform length!");
+ this.outputs[i] = outputs[i];
+ }
+
+ this.select = select;
+ select.addObserver(this);
+
+ int maxInputs = 1 << select.length();
+ if (this.outputs.length > maxInputs)
+ throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "
+ + select.length() + " select bits (" + maxInputs + ").");
+ in.addObserver(this);
+ }
+
+ @Override
+ public void compute()
+ {
+ int selectValue = select.hasNumericValue() ? (int) select.getUnsignedValue() : -1;
+ if (selectValue >= outputs.length)
+ selectValue = -1;
+
+ if (selected != selectValue && selected != -1)
+ outputs[selected].clearSignals();
+
+ selected = selectValue;
+
+ if (selectValue != -1)
+ outputs[selectValue].feedSignals(in.getValues());
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(in, select);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(outputs);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.types.Bit;
+import era.mi.logic.wires.Wire.WireEnd;
+
+/**
+ * This class models a simple on/off (ONE/ZERO) switch for user interaction.
+ *
+ * @author Christian Femers
+ *
+ */
+public class ManualSwitch implements Component
+{
+ private WireEnd output;
+ private boolean isOn;
+
+ public ManualSwitch(WireEnd output)
+ {
+ if (output.length() != 1)
+ throw new IllegalArgumentException("Switch output can be only a single wire");
+ this.output = output;
+ }
+
+ public void switchOn()
+ {
+ setState(true);
+ }
+
+ public void switchOff()
+ {
+ setState(false);
+ }
+
+ public void toggle()
+ {
+ setState(!isOn);
+ }
+
+ public void setState(boolean isOn)
+ {
+ if (this.isOn == isOn)
+ return;
+ this.isOn = isOn;
+ output.feedSignals(getValue());
+ }
+
+ public boolean isOn()
+ {
+ return isOn;
+ }
+
+ public Bit getValue()
+ {
+ return isOn ? Bit.ONE : Bit.ZERO;
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of();
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(output);
+ }
+
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+import era.mi.logic.wires.WireObserver;
+
+public class Merger implements WireObserver, Component
+{
+ private WireEnd out;
+ private WireEnd[] inputs;
+ private int[] beginningIndex;
+
+ /**
+ *
+ * @param union The output of merging n {@link Wire}s into one. Must have length = a1.length() + a2.length() + ... + an.length().
+ * @param inputs The inputs to be merged into the union
+ */
+ public Merger(WireEnd union, WireEnd... inputs)
+ {
+ this.inputs = inputs;
+ this.out = union;
+ this.beginningIndex = new int[inputs.length];
+
+ int length = 0;
+ for (int i = 0; i < inputs.length; i++)
+ {
+ beginningIndex[i] = length;
+ length += inputs[i].length();
+ inputs[i].addObserver(this);
+ }
+
+ if (length != union.length())
+ throw new IllegalArgumentException(
+ "The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");
+ }
+
+ public WireEnd getInput(int index)
+ {
+ return inputs[index];
+ }
+
+ public WireEnd getUnion()
+ {
+ return out;
+ }
+
+ @Override
+ public void update(Wire initiator, BitVector oldValues)
+ {
+ int index = find(initiator);
+ int beginning = beginningIndex[index];
+ out.feedSignals(beginning, inputs[index].getValues());
+ }
+
+ private int find(Wire w)
+ {
+ for (int i = 0; i < inputs.length; i++)
+ if (inputs[i].getWire() == w)
+ return i;
+ return -1;
+ }
+
+ public WireEnd[] getInputs()
+ {
+ return inputs.clone();
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(inputs);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+
+/**
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
+ * output.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class Mux extends BasicComponent
+{
+ private WireEnd select;
+ private WireEnd out;
+ private WireEnd[] inputs;
+ private final int outputSize;
+
+ /**
+ * Input {@link Wire}s and out must be of uniform length
+ *
+ * @param out Must be of uniform length with all inputs.
+ * @param select Indexes the input array which is to be mapped to the output. Must have enough bits to index all inputs.
+ * @param inputs One of these inputs is mapped to the output, depending on the select bits
+ */
+ public Mux(int processTime, WireEnd out, WireEnd select, WireEnd... inputs)
+ {
+ super(processTime);
+ outputSize = out.length();
+
+ this.inputs = inputs.clone();
+ for (int i = 0; i < this.inputs.length; i++)
+ {
+ if (inputs[i].length() != outputSize)
+ throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");
+ inputs[i].addObserver(this);
+ }
+
+ this.select = select;
+ select.addObserver(this);
+
+ int maxInputs = 1 << select.length();
+ if (this.inputs.length > maxInputs)
+ throw new IllegalArgumentException("There are more inputs (" + this.inputs.length + ") to the MUX than supported by "
+ + select.length() + " select bits (" + maxInputs + ").");
+
+ this.out = out;
+ }
+
+ public WireEnd getOut()
+ {
+ return out;
+ }
+
+ public WireEnd getSelect()
+ {
+ return select;
+ }
+
+ @Override
+ public void compute()
+ {
+ int selectValue;
+ if (!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) >= inputs.length)
+ {
+ out.clearSignals();
+ return;
+ }
+
+ WireEnd active = inputs[selectValue];
+ out.feedSignals(active.getValues());
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ ArrayList<WireEnd> wires = new ArrayList<WireEnd>(Arrays.asList(inputs));
+ wires.add(select);
+ return Collections.unmodifiableList(wires);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+import era.mi.logic.wires.WireObserver;
+
+public class Splitter implements WireObserver
+{
+ private WireEnd input;
+ private WireEnd[] outputs;
+
+ public Splitter(WireEnd input, WireEnd... outputs)
+ {
+ this.input = input;
+ this.outputs = outputs;
+ input.addObserver(this);
+ int length = 0;
+ for (WireEnd out : outputs)
+ length += out.length();
+
+ if (input.length() != length)
+ throw new IllegalArgumentException(
+ "The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length().");
+ }
+
+ protected void compute()
+ {
+ BitVector inputBits = input.getValues();
+ int startIndex = 0;
+ for (int i = 0; i < outputs.length; i++)
+ {
+ outputs[i].feedSignals(inputBits.subVector(startIndex, startIndex + outputs[i].length()));
+ startIndex += outputs[i].length();
+ }
+ }
+
+ @Override
+ public void update(Wire initiator, BitVector oldValues)
+ {
+ compute();
+ }
+}
--- /dev/null
+package era.mi.logic.components;
+
+import java.util.List;
+
+import era.mi.logic.types.Bit;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class TriStateBuffer extends BasicComponent
+{
+ WireEnd in, enable;
+ WireEnd out;
+
+ public TriStateBuffer(int processTime, WireEnd in, WireEnd out, WireEnd enable)
+ {
+ super(processTime);
+ if (in.length() != out.length())
+ throw new IllegalArgumentException(
+ "Tri-state output must have the same amount of bits as the input. Input: " + in.length() + " Output: " + out.length());
+ if (enable.length() != 1)
+ throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length() + ".");
+ this.in = in;
+ in.addObserver(this);
+ this.enable = enable;
+ enable.addObserver(this);
+ this.out = out;
+ }
+
+ @Override
+ protected void compute()
+ {
+ if (enable.getValue() == Bit.ONE)
+ out.feedSignals(in.getValues());
+ else
+ out.clearSignals();
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(in, enable);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+
+}
--- /dev/null
+package era.mi.logic.components.gates;
+
+import era.mi.logic.types.BitVector.BitVectorMutator;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class AndGate extends MultiInputGate
+{
+ public AndGate(int processTime, WireEnd out, WireEnd... in)
+ {
+ super(processTime, BitVectorMutator::and, out, in);
+ }
+}
--- /dev/null
+package era.mi.logic.components.gates;
+
+import java.util.List;
+
+import era.mi.logic.components.BasicComponent;
+import era.mi.logic.types.BitVector.BitVectorMutator;
+import era.mi.logic.types.MutationOperation;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public abstract class MultiInputGate extends BasicComponent
+{
+ protected WireEnd[] in;
+ protected WireEnd out;
+ protected final int length;
+ protected MutationOperation op;
+
+ protected MultiInputGate(int processTime, MutationOperation op, WireEnd out, WireEnd... in)
+ {
+ super(processTime);
+ this.op = op;
+ length = out.length();
+ this.in = in.clone();
+ if (in.length < 1)
+ throw new IllegalArgumentException(String.format("Cannot create gate with %d wires.", in.length));
+ for (WireEnd w : in)
+ {
+ if (w.length() != length)
+ throw new IllegalArgumentException("All wires connected to the gate must be of uniform length.");
+ w.addObserver(this);
+ }
+ this.out = out;
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(in);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+
+ @Override
+ protected void compute()
+ {
+ BitVectorMutator mutator = BitVectorMutator.empty();
+ for (WireEnd w : in)
+ op.apply(mutator, w.getValues());
+ out.feedSignals(mutator.get());
+ }
+}
--- /dev/null
+package era.mi.logic.components.gates;
+
+import java.util.List;
+
+import era.mi.logic.components.BasicComponent;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class NotGate extends BasicComponent
+{
+ private WireEnd in;
+ private WireEnd out;
+
+ public NotGate(int processTime, WireEnd in, WireEnd out)
+ {
+ super(processTime);
+ this.in = in;
+ in.addObserver(this);
+ this.out = out;
+ }
+
+ @Override
+ protected void compute()
+ {
+ out.feedSignals(in.getValues().not());
+ }
+
+ public WireEnd getIn()
+ {
+ return in;
+ }
+
+ public WireEnd getOut()
+ {
+ return out;
+ }
+
+ @Override
+ public List<WireEnd> getAllInputs()
+ {
+ return List.of(in);
+ }
+
+ @Override
+ public List<WireEnd> getAllOutputs()
+ {
+ return List.of(out);
+ }
+}
--- /dev/null
+package era.mi.logic.components.gates;
+
+import era.mi.logic.types.BitVector.BitVectorMutator;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public class OrGate extends MultiInputGate
+{
+ public OrGate(int processTime, WireEnd out, WireEnd... in)
+ {
+ super(processTime, BitVectorMutator::or, out, in);
+ }
+}
--- /dev/null
+package era.mi.logic.components.gates;
+
+import era.mi.logic.types.BitVector.BitVectorMutator;
+import era.mi.logic.wires.Wire.WireEnd;
+
+/**
+ * Outputs 1 when the number of 1 inputs is odd.
+ *
+ * @author Fabian Stemmler
+ */
+public class XorGate extends MultiInputGate
+{
+ public XorGate(int processTime, WireEnd out, WireEnd... in)
+ {
+ super(processTime, BitVectorMutator::xor, out, in);
+ }
+
+}
--- /dev/null
+package era.mi.logic.tests;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.function.LongConsumer;
+
+import org.junit.jupiter.api.Test;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.components.Connector;
+import era.mi.logic.components.Demux;
+import era.mi.logic.components.Merger;
+import era.mi.logic.components.Mux;
+import era.mi.logic.components.Splitter;
+import era.mi.logic.components.TriStateBuffer;
+import era.mi.logic.components.gates.AndGate;
+import era.mi.logic.components.gates.NotGate;
+import era.mi.logic.components.gates.OrGate;
+import era.mi.logic.components.gates.XorGate;
+import era.mi.logic.types.Bit;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.WireEnd;
+
+@SuppressWarnings("unused")
+class ComponentTest
+{
+
+ @Test
+ void circuitExampleTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(1, 1), b = new Wire(1, 1), c = new Wire(1, 10), d = new Wire(2, 1), e = new Wire(1, 1), f = new Wire(1, 1),
+ g = new Wire(1, 1), h = new Wire(2, 1), i = new Wire(2, 1), j = new Wire(1, 1), k = new Wire(1, 1);
+ new AndGate(1, f.createEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+ new NotGate(1, f.createReadOnlyEnd(), g.createEnd());
+ new Merger(h.createEnd(), c.createReadOnlyEnd(), g.createReadOnlyEnd());
+ new Mux(1, i.createEnd(), e.createReadOnlyEnd(), h.createReadOnlyEnd(), d.createReadOnlyEnd());
+ new Splitter(i.createReadOnlyEnd(), k.createEnd(), j.createEnd());
+
+ a.createEnd().feedSignals(Bit.ZERO);
+ b.createEnd().feedSignals(Bit.ONE);
+ c.createEnd().feedSignals(Bit.ZERO);
+ d.createEnd().feedSignals(Bit.ONE, Bit.ONE);
+ e.createEnd().feedSignals(Bit.ZERO);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.ONE, j.getValue());
+ assertEquals(Bit.ZERO, k.getValue());
+ }
+
+ @Test
+ void splitterTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(3, 1), b = new Wire(2, 1), c = new Wire(3, 1), in = new Wire(8, 1);
+ in.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+ new Splitter(in.createReadOnlyEnd(), a.createEnd(), b.createEnd(), c.createEnd());
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO);
+ assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO);
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE);
+ }
+
+ @Test
+ void mergerTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(3, 1), b = new Wire(2, 1), c = new Wire(3, 1), out = new Wire(8, 1);
+ a.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);
+ b.createEnd().feedSignals(Bit.ONE, Bit.ZERO);
+ c.createEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ new Merger(out.createEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+ }
+
+ @Test
+ void triStateBufferTest()
+ {
+ Wire a = new Wire(1, 1), b = new Wire(1, 1), en = new Wire(1, 1), notEn = new Wire(1, 1);
+ new NotGate(1, en.createReadOnlyEnd(), notEn.createEnd());
+ new TriStateBuffer(1, a.createReadOnlyEnd(), b.createEnd(), en.createReadOnlyEnd());
+ new TriStateBuffer(1, b.createReadOnlyEnd(), a.createEnd(), notEn.createReadOnlyEnd());
+
+ WireEnd enI = en.createEnd(), aI = a.createEnd(), bI = b.createEnd();
+ enI.feedSignals(Bit.ONE);
+ aI.feedSignals(Bit.ONE);
+ bI.feedSignals(Bit.Z);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.ONE, b.getValue());
+
+ bI.feedSignals(Bit.ZERO);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.X, b.getValue());
+ assertEquals(Bit.ONE, a.getValue());
+
+ aI.clearSignals();
+ enI.feedSignals(Bit.ZERO);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.ZERO, a.getValue());
+
+ }
+
+ @Test
+ void muxTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(4, 3), b = new Wire(4, 6), c = new Wire(4, 4), select = new Wire(2, 5), out = new Wire(4, 1);
+ WireEnd selectIn = select.createEnd();
+
+ selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
+ a.createEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+ c.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ new Mux(1, out.createEnd(), select.createReadOnlyEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+ selectIn.feedSignals(Bit.ZERO, Bit.ONE);
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ selectIn.feedSignals(Bit.ONE, Bit.ONE);
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+
+ }
+
+ @Test
+ void demuxTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(4, 3), b = new Wire(4, 6), c = new Wire(4, 4), select = new Wire(2, 5), in = new Wire(4, 1);
+ WireEnd selectIn = select.createEnd();
+
+ selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
+ in.createEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+
+ new Demux(1, in.createReadOnlyEnd(), select.createReadOnlyEnd(), a.createEnd(), b.createEnd(), c.createEnd());
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(a.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+ assertBitArrayEquals(c.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+ selectIn.feedSignals(Bit.ZERO, Bit.ONE);
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+
+ selectIn.feedSignals(Bit.ONE, Bit.ONE);
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+ assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+ assertBitArrayEquals(c.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+
+ }
+
+ @Test
+ void andTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(4, 1), b = new Wire(4, 3), c = new Wire(4, 1);
+ new AndGate(1, c.createEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+ a.createEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
+ b.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(c.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO);
+ }
+
+ @Test
+ void orTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(4, 1), b = new Wire(4, 3), c = new Wire(4, 1);
+ new OrGate(1, c.createEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+ a.createEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
+ b.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE);
+ }
+
+ @Test
+ void xorTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(3, 1), b = new Wire(3, 2), c = new Wire(3, 1), d = new Wire(3, 1);
+ new XorGate(1, d.createEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
+ a.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
+ b.createEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+ c.createEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(d.getValues(), Bit.ZERO, Bit.ONE, Bit.ONE);
+ }
+
+ @Test
+ void notTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire a = new Wire(3, 1), b = new Wire(3, 2);
+ new NotGate(1, a.createReadOnlyEnd(), b.createEnd());
+ a.createEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO, Bit.ZERO);
+ }
+
+ @Test
+ void rsLatchCircuitTest()
+ {
+ Simulation.TIMELINE.reset();
+ Wire r = new Wire(1, 1), s = new Wire(1, 1), t1 = new Wire(1, 15), t2 = new Wire(1, 1), q = new Wire(1, 1), nq = new Wire(1, 1);
+
+ new OrGate(1, t2.createEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());
+ new OrGate(1, t1.createEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());
+ new NotGate(1, t2.createReadOnlyEnd(), q.createEnd());
+ new NotGate(1, t1.createReadOnlyEnd(), nq.createEnd());
+
+ WireEnd sIn = s.createEnd(), rIn = r.createEnd();
+
+ sIn.feedSignals(Bit.ONE);
+ rIn.feedSignals(Bit.ZERO);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.ONE, q.getValue());
+ assertEquals(Bit.ZERO, nq.getValue());
+
+ sIn.feedSignals(Bit.ZERO);
+
+ Simulation.TIMELINE.executeAll();
+ assertEquals(Bit.ONE, q.getValue());
+ assertEquals(Bit.ZERO, nq.getValue());
+
+ rIn.feedSignals(Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(Bit.ZERO, q.getValue());
+ assertEquals(Bit.ONE, nq.getValue());
+ }
+
+ @Test
+ void numericValueTest()
+ {
+ Simulation.TIMELINE.reset();
+
+ Wire a = new Wire(4, 1);
+ a.createEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);
+
+ Simulation.TIMELINE.executeAll();
+
+ assertEquals(15, a.getUnsignedValue());
+ assertEquals(-1, a.getSignedValue());
+ }
+
+ @Test
+ void multipleInputs()
+ {
+ Simulation.TIMELINE.reset();
+ Wire w = new Wire(2, 1);
+ WireEnd wI1 = w.createEnd(), wI2 = w.createEnd();
+ wI1.feedSignals(Bit.ONE, Bit.Z);
+ wI2.feedSignals(Bit.Z, Bit.X);
+ Simulation.TIMELINE.executeAll();
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X);
+
+ wI2.feedSignals(Bit.ZERO, Bit.Z);
+ Simulation.TIMELINE.executeAll();
+ assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z);
+
+ wI2.feedSignals(Bit.Z, Bit.Z);
+ Simulation.TIMELINE.executeAll();
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
+
+ wI2.feedSignals(Bit.ONE, Bit.Z);
+ w.addObserver((i, oldValues) -> fail("WireArray notified observer, although value did not change."));
+ Simulation.TIMELINE.executeAll();
+ assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
+ }
+
+ @Test
+ void wireConnections()
+ {
+ // Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde
+
+ Simulation.TIMELINE.reset();
+
+ Wire a = new Wire(1, 2);
+ Wire b = new Wire(1, 2);
+ Wire c = new Wire(1, 2);
+ WireEnd aI = a.createEnd();
+ WireEnd bI = b.createEnd();
+ WireEnd cI = c.createEnd();
+
+ TestBitDisplay test = new TestBitDisplay(c.createReadOnlyEnd());
+ TestBitDisplay test2 = new TestBitDisplay(a.createReadOnlyEnd());
+ LongConsumer print = time -> System.out.format("Time %2d\n a: %s\n b: %s\n c: %s\n", time, a, b, c);
+
+ cI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+
+ cI.feedSignals(Bit.X);
+ test.assertAfterSimulationIs(print, Bit.X);
+
+ cI.feedSignals(Bit.X);
+ cI.feedSignals(Bit.Z);
+ test.assertAfterSimulationIs(print, Bit.Z);
+
+ new Connector(b.createEnd(), c.createEnd()).connect();
+ test.assertAfterSimulationIs(print, Bit.Z);
+ System.err.println("ONE");
+ bI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+ System.err.println("ZERO");
+ bI.feedSignals(Bit.ZERO);
+ test.assertAfterSimulationIs(print, Bit.ZERO);
+ System.err.println("Z");
+ bI.feedSignals(Bit.Z);
+ test.assertAfterSimulationIs(print, Bit.Z);
+
+ new Connector(a.createEnd(), b.createEnd()).connect();
+ System.err.println("Z 2");
+ aI.feedSignals(Bit.Z);
+ test.assertAfterSimulationIs(print, Bit.Z);
+ test2.assertAfterSimulationIs(Bit.Z);
+ System.err.println("ONE 2");
+ aI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+ test2.assertAfterSimulationIs(Bit.ONE);
+ System.err.println("ZERO 2");
+ aI.feedSignals(Bit.ZERO);
+ test.assertAfterSimulationIs(print, Bit.ZERO);
+ test2.assertAfterSimulationIs(Bit.ZERO);
+ System.err.println("Z 2 II");
+ aI.feedSignals(Bit.Z);
+ test.assertAfterSimulationIs(print, Bit.Z);
+ test2.assertAfterSimulationIs(Bit.Z);
+
+ System.err.println("No Conflict yet");
+ bI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+ test2.assertAfterSimulationIs(Bit.ONE);
+ aI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+ test2.assertAfterSimulationIs(Bit.ONE);
+ System.err.println("Conflict");
+ aI.feedSignals(Bit.ZERO);
+ test.assertAfterSimulationIs(print, Bit.X);
+ test2.assertAfterSimulationIs(Bit.X);
+ aI.feedSignals(Bit.ONE);
+ test.assertAfterSimulationIs(print, Bit.ONE);
+ test2.assertAfterSimulationIs(Bit.ONE);
+ }
+
+ private static void assertBitArrayEquals(BitVector actual, Bit... expected)
+ {
+ assertArrayEquals(expected, actual.getBits());
+ }
+}
--- /dev/null
+package era.mi.logic.tests;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.components.ManualSwitch;
+import era.mi.logic.components.gates.NotGate;
+import era.mi.logic.components.gates.OrGate;
+import era.mi.logic.timeline.Timeline.ExecutionResult;
+import era.mi.logic.wires.Wire;
+
+public class GUITest extends JPanel
+{
+
+ private static final long serialVersionUID = 1L;
+
+ private static final int WIRE_DELAY = 40;
+ private static final int OR_DELAY = 100;
+ private static final int NOT_DELAY = 100;
+
+ Wire r = new Wire(1, WIRE_DELAY);
+ Wire s = new Wire(1, WIRE_DELAY);
+ Wire t1 = new Wire(1, WIRE_DELAY);
+ Wire t2 = new Wire(1, WIRE_DELAY);
+ Wire q = new Wire(1, WIRE_DELAY);
+ Wire nq = new Wire(1, WIRE_DELAY);
+
+ ManualSwitch rIn = new ManualSwitch(r.createEnd());
+ ManualSwitch sIn = new ManualSwitch(s.createEnd());
+
+ OrGate or1 = new OrGate(OR_DELAY, t2.createEnd(), r.createEnd(), nq.createEnd());
+ OrGate or2 = new OrGate(OR_DELAY, t1.createEnd(), s.createEnd(), q.createEnd());
+ NotGate not1 = new NotGate(NOT_DELAY, t2.createEnd(), q.createEnd());
+ NotGate not2 = new NotGate(NOT_DELAY, t1.createEnd(), nq.createEnd());
+
+ Map<ManualSwitch, Rectangle> switchMap = new HashMap<>();
+
+ int height;
+ int width;
+ boolean sizeChanged;
+
+ public GUITest()
+ {
+ addMouseListener(new MouseListener()
+ {
+
+ @Override
+ public void mouseReleased(MouseEvent e)
+ {
+ for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
+ {
+ if (dim.getValue().contains(e.getPoint()))
+ {
+ dim.getKey().switchOff();
+ repaint();
+ }
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e)
+ {
+ for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
+ {
+ if (dim.getValue().contains(e.getPoint()))
+ {
+ dim.getKey().switchOn();
+ repaint();
+ }
+ }
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e)
+ {
+ // none
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e)
+ {
+ // none
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ // If you want toggle buttons, use this code instead
+// for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet()) {
+// if (dim.getValue().contains(e.getPoint())) {
+// dim.getKey().toggle();
+// repaint();
+// }
+// }
+ }
+ });
+ }
+
+ @Override
+ public void paint(Graphics some_g)
+ {
+ super.paint(some_g);
+ Graphics2D g = ((Graphics2D) some_g);
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+
+ checkSizeChange();
+ adaptFont(g);
+
+ drawWire(g, r, "r", 2, 9, 4, 9);
+
+ drawWire(g, s, "s", 2, 3, 4, 3);
+
+ drawWire(g, t2, "t2", 5, 8.5, 6, 8.5);
+
+ drawWire(g, t1, "t1", 5, 3.5, 6, 3.5);
+
+ drawWire(g, q, "q", 7, 8.5, 9, 8.5);
+
+ drawWire(g, nq, "nq", 7, 3.5, 9, 3.5);
+
+ drawWire(g, q, "", 7.5, 8.5, 7.5, 7.5);
+ drawWire(g, q, "", 7.5, 7.5, 3, 4.5);
+ drawWire(g, q, "", 3, 4.5, 3, 4);
+ drawWire(g, q, "q", 3, 4, 4, 4);
+
+ drawWire(g, nq, "", 7.5, 3.5, 7.5, 4.5);
+ drawWire(g, nq, "", 7.5, 4.5, 3, 7.5);
+ drawWire(g, nq, "", 3, 7.5, 3, 8);
+ drawWire(g, nq, "nq", 3, 8, 4, 8);
+
+ drawSquare(g, 4, 8, "OR");
+ drawSquare(g, 4, 3, "OR");
+
+ drawSquare(g, 6, 8, "NOT");
+ drawSquare(g, 6, 3, "NOT");
+
+ drawSwitch(g, rIn, "Switch R", 0.5, 8.25, 2, 9.75);
+ drawSwitch(g, sIn, "Switch S", 0.5, 2.25, 2, 3.75);
+
+ drawString(g, "Hint: drag the cursor out of the pressed switch to keep it's state", 5, 0, 0.0, 1.0);
+ }
+
+ private void checkSizeChange()
+ {
+ sizeChanged = height != getHeight() || width != getWidth();
+ if (sizeChanged)
+ {
+ height = getHeight();
+ width = getWidth();
+ }
+ }
+
+ private void adaptFont(Graphics g)
+ {
+ g.setFont(g.getFont().deriveFont(Math.min(height, width) / 40f));
+ }
+
+ private void drawString(Graphics g, String s, int x, int y, double anchorX, double anchorY)
+ {
+ int h = g.getFontMetrics().getAscent();
+ int w = g.getFontMetrics().stringWidth(s);
+ g.drawString(s, x - (int) (w * anchorX), y + (int) (h * anchorY));
+ }
+
+ private void drawWire(Graphics g, Wire wa, String name, double x1, double y1, double x2, double y2)
+ {
+ setTo(g, wa);
+ g.drawLine(gX(x1), gY(y1), gX(x2), gY(y2));
+ drawString(g, name, (gX(x1) + gX(x2)) / 2, (gY(y1) + gY(y2)) / 2 - 5, 0, 0);
+ }
+
+ private void drawSquare(Graphics g, int posX, int posY, String text)
+ {
+ int x1 = gX(posX) - 5;
+ int x2 = gX(posX + 1) + 5;
+ int y1 = gY(posY) - 5;
+ int y2 = gY(posY + 1) + 5;
+
+ g.setColor(Color.WHITE);
+ g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ setBlack(g);
+ g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
+
+ }
+
+ private void drawSwitch(Graphics g, ManualSwitch ms, String text, double posX1, double posY1, double posX2, double posY2)
+ {
+ int x1 = gX(posX1) - 5;
+ int x2 = gX(posX2) + 5;
+ int y1 = gY(posY1) - 5;
+ int y2 = gY(posY2) + 5;
+
+ if (sizeChanged)
+ {
+ Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ switchMap.put(ms, r);
+ }
+
+ g.setColor(ms.isOn() ? Color.getHSBColor(.3f, .5f, 1f) : Color.WHITE);
+ g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ setBlack(g);
+ g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+ drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
+ }
+
+ private static void setBlack(Graphics g)
+ {
+ g.setColor(Color.BLACK);
+ }
+
+ private static void setTo(Graphics g, Wire wa)
+ {
+ switch (wa.getValue())
+ {
+ case ONE:
+ g.setColor(Color.GREEN);
+ break;
+ case X:
+ g.setColor(Color.RED);
+ break;
+ case Z:
+ g.setColor(Color.DARK_GRAY);
+ break;
+ case ZERO:
+ g.setColor(Color.BLACK);
+ break;
+ case U:
+ g.setColor(Color.MAGENTA);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private int gY(double pos)
+ {
+ return (int) (pos * height / 11);
+ }
+
+ private int gX(double pos)
+ {
+ return (int) (pos * width / 11) + 50;
+ }
+
+ public static void main(String[] args)
+ {
+ JFrame f = new JFrame("Test circuit 1.0.0");
+ GUITest gt = new GUITest();
+ f.add(gt);
+ f.setSize(800, 600);
+ f.setLocation(500, 400);
+ f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ f.setVisible(true);
+
+ long begin = System.currentTimeMillis();
+
+ long lastFrame = begin;
+ long updateT = 16;
+
+ while (f.isVisible())
+ {
+ ExecutionResult er = Simulation.TIMELINE.executeUpTo((lastFrame - begin) * 3, lastFrame + 14);
+// if (Simulation.TIMELINE.hasNext())
+// Simulation.TIMELINE.executeNext();
+ if (er != ExecutionResult.NOTHING_DONE)
+ gt.repaint(12);
+ try
+ {
+ Thread.sleep(Math.max(updateT - System.currentTimeMillis() + lastFrame, 0));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ lastFrame = System.currentTimeMillis();
+ }
+ }
+}
--- /dev/null
+package era.mi.logic.tests;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.function.LongConsumer;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.components.BitDisplay;
+import era.mi.logic.types.Bit;
+import era.mi.logic.wires.Wire.WireEnd;
+
+public final class TestBitDisplay extends BitDisplay
+{
+
+ public TestBitDisplay(WireEnd in)
+ {
+ super(in);
+ }
+
+ public void assertDisplays(Bit... expected)
+ {
+ assertArrayEquals(expected, getDisplayedValue().getBits());
+ }
+
+ public void assertAfterSimulationIs(Bit... expected)
+ {
+ Simulation.TIMELINE.executeAll();
+ assertDisplays(expected);
+ }
+
+ public void assertAfterSimulationIs(LongConsumer r, Bit... expected)
+ {
+ while (Simulation.TIMELINE.hasNext())
+ {
+ Simulation.TIMELINE.executeNext();
+ r.accept(Simulation.TIMELINE.getSimulationTime());
+ }
+ assertDisplays(expected);
+ }
+
+ @Override
+ protected void compute()
+ {
+ super.compute();
+ System.out.println("update: value is " + getDisplayedValue());
+ }
+}
--- /dev/null
+package era.mi.logic.timeline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.function.Consumer;
+
+/**
+ * Orders Events by the time they are due to be executed. Can execute Events individually.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class Timeline
+{
+ private PriorityQueue<InnerEvent> events;
+ private long currentTime = 0;
+
+ private final List<Consumer<TimelineEvent>> eventAddedListener;
+
+ public Timeline(int initCapacity)
+ {
+ events = new PriorityQueue<InnerEvent>(initCapacity, (a, b) ->
+ {
+ long difference = a.getTiming() - b.getTiming();
+ if (difference == 0)
+ return 0;
+ return difference < 0 ? -1 : 1;
+ });
+
+ eventAddedListener = new ArrayList<>();
+ }
+
+ public boolean hasNext()
+ {
+ return !events.isEmpty();
+ }
+
+ public void executeNext()
+ {
+ InnerEvent first = events.poll();
+ currentTime = first.getTiming();
+ first.run();
+ }
+
+ public void executeAll()
+ {
+ while (hasNext())
+ executeNext();
+ }
+
+ /**
+ * Executes all events up to a given simulation timestamp. The simulation process can be constrained by a real world timestamp.
+ *
+ * @param timestamp the simulation timestamp up to which the events will be processed
+ * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop.
+ * @return if it was possible to fulfil the goal in the given real world time.
+ * @author Christian Femers
+ */
+ public ExecutionResult executeUpTo(long timestamp, long stopMillis)
+ {
+ if (events.isEmpty())
+ {
+ currentTime = timestamp;
+ return ExecutionResult.NOTHING_DONE;
+ }
+ int checkStop = 0;
+ InnerEvent first = events.peek();
+ while (first != null && first.getTiming() <= timestamp)
+ {
+ events.remove();
+ currentTime = first.getTiming();
+ first.run();
+ // Don't check after every run
+ checkStop = (checkStop + 1) % 10;
+ if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)
+ return ExecutionResult.RAN_OUT_OF_TIME;
+ first = events.peek();
+ }
+ currentTime = timestamp;
+ return ExecutionResult.DONE_IN_TIME;
+ }
+
+ public long getSimulationTime()
+ {
+ return currentTime;
+ }
+
+ public long nextEventTime()
+ {
+ if (!hasNext())
+ return -1;
+ return events.peek().timing;
+ }
+
+ public void reset()
+ {
+ events.clear();
+ currentTime = 0;
+ }
+
+ public void addEventAddedListener(Consumer<TimelineEvent> listener)
+ {
+ eventAddedListener.add(listener);
+ }
+
+ public void removeEventAddedListener(Consumer<TimelineEvent> listener)
+ {
+ eventAddedListener.remove(listener);
+ }
+
+ /**
+ * Adds an Event to the {@link Timeline}
+ *
+ * @param function The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.
+ * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.
+ */
+ public void addEvent(TimelineEventHandler function, int relativeTiming)
+ {
+ long timing = currentTime + relativeTiming;
+ TimelineEvent event = new TimelineEvent(timing);
+ events.add(new InnerEvent(function, event, timing));
+ eventAddedListener.forEach(l -> l.accept(event));
+ }
+
+ private class InnerEvent
+ {
+
+ final long timing;
+ private final TimelineEventHandler function;
+ private final TimelineEvent event;
+
+ /**
+ * Creates an {@link InnerEvent}
+ *
+ * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs
+ * @param timing Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;
+ */
+ InnerEvent(TimelineEventHandler function, TimelineEvent event, long timing)
+ {
+ this.function = function;
+ this.event = event;
+ this.timing = timing;
+ }
+
+ public long getTiming()
+ {
+ return timing;
+ }
+
+ public void run()
+ {
+ function.handle(event);
+ }
+
+ @Override
+ public String toString()
+ {
+ return event.toString();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return "simulation time: " + currentTime + ", " + events.toString();
+ }
+
+ public static long toNanoseconds(long ticks)
+ {
+ return ticks; // TODO: Alter this when it has been determined how ticks should relate to real time.
+ }
+
+ public enum ExecutionResult
+ {
+ NOTHING_DONE, DONE_IN_TIME, RAN_OUT_OF_TIME
+ }
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic.timeline;
+
+/**
+ * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to
+ * store.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class TimelineEvent
+{
+ private final long timing;
+
+ TimelineEvent(long timing)
+ {
+ super();
+ this.timing = timing;
+ }
+
+ public long getTiming()
+ {
+ return timing;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "timestamp: " + timing;
+ }
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic.timeline;
+
+public interface TimelineEventHandler
+{
+ public void handle(TimelineEvent e);
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic.types;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * stdlogic according to IEEE 1164
+ */
+public enum Bit implements StrictLogicType<Bit>
+{
+ U("U"), X("X"), ZERO("0"), ONE("1"), Z("Z");
+
+ private final String symbol;
+
+ private Bit(String symbol)
+ {
+ this.symbol = symbol;
+ }
+
+ @Override
+ public Bit and(Bit other)
+ {
+ return fromTable(AND_TABLE, this, other);
+ }
+
+ @Override
+ public Bit or(Bit other)
+ {
+ return fromTable(OR_TABLE, this, other);
+ }
+
+ @Override
+ public Bit xor(Bit other)
+ {
+ return fromTable(XOR_TABLE, this, other);
+ }
+
+ @Override
+ public Bit not()
+ {
+ switch (this)
+ {
+ case U:
+ return U;
+ case ONE:
+ return ZERO;
+ case ZERO:
+ return ONE;
+ default:
+ return X;
+ }
+ }
+
+ public Bit[] makeArray(int length)
+ {
+ Bit[] bits = new Bit[length];
+ Arrays.fill(bits, this);
+ return bits;
+ }
+
+ public BitVector toVector(int length)
+ {
+ return BitVector.of(this, length);
+ }
+
+ @Override
+ public Bit join(Bit other)
+ {
+ return fromTable(JOIN_TABLE, this, other);
+ }
+
+ @Override
+ public String toString()
+ {
+ return getSymbol();
+ }
+
+ public String getSymbol()
+ {
+ return symbol;
+ }
+
+ public static Bit parse(String s)
+ {
+ Bit bit = SYMBOL_MAP.get(s);
+ Objects.requireNonNull(bit, "No Bit found for symbol " + s);
+ return bit;
+ }
+
+ public static Bit parse(String s, int symbolPosition)
+ {
+ return parse(s.substring(symbolPosition, symbolPosition + 1));
+ }
+
+ private static Bit fromTable(Bit[][] table, Bit a, Bit b)
+ {
+ return table[a.ordinal()][b.ordinal()];
+ }
+
+ static final Map<String, Bit> SYMBOL_MAP = Map.of(U.symbol, U, X.symbol, X, ZERO.symbol, ZERO, ONE.symbol, ONE, Z.symbol, Z);
+
+ // @formatter:off
+ private static final Bit[][] JOIN_TABLE =
+ { { U, U, U, U, U },
+ { U, X, X, X, X },
+ { U, X, ZERO, X, ZERO },
+ { U, X, X, ONE, ONE },
+ { U, X, ZERO, ONE, Z } };
+
+ private static final Bit[][] AND_TABLE =
+ { { U, U, ZERO, U, U },
+ { U, X, ZERO, X, X },
+ { ZERO, ZERO, ZERO, ZERO, ZERO },
+ { U, X, ZERO, ONE, X },
+ { U, X, ZERO, X, X } };
+
+ private static final Bit[][] OR_TABLE =
+ { { U, U, U, ONE, U },
+ { U, X, X, ONE, X },
+ { U, X, ZERO, ONE, X },
+ { ONE, ONE, ONE, ONE, ONE },
+ { U, X, X, ONE, X } };
+
+ private static final Bit[][] XOR_TABLE =
+ { { U, U, U, U, U },
+ { U, X, X, X, X },
+ { U, X, ZERO, ONE, X },
+ { U, X, ONE, ZERO, X },
+ { U, X, X, X, X } };
+ // @formatter:on
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic.types;
+
+import static java.lang.String.format;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * Immutable class representing a {@link Bit}Vector
+ *
+ *
+ * @author Christian Femers
+ *
+ */
+public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
+{
+ private final Bit[] bits;
+
+ private BitVector(Bit[] bits)
+ {
+ this.bits = Objects.requireNonNull(bits);
+ }
+
+ public static BitVector of(Bit... bits)
+ {
+ return new BitVector(bits.clone());
+ }
+
+ public static BitVector of(Bit bit, int length)
+ {
+ return new BitVector(bit.makeArray(length));
+ }
+
+ public BitVectorMutator mutator()
+ {
+ return BitVectorMutator.of(this);
+ }
+
+ public Bit getBit(int bitIndex)
+ {
+ return bits[bitIndex];
+ }
+
+ public Bit[] getBits()
+ {
+ return bits.clone();
+ }
+
+ @Override
+ public BitVector join(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
+ }
+
+ @Override
+ public BitVector and(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
+ }
+
+ @Override
+ public BitVector or(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
+ }
+
+ @Override
+ public BitVector xor(BitVector t)
+ {
+ checkCompatibility(t);
+ return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
+ }
+
+ @Override
+ public BitVector not()
+ {
+ return new BitVector(unOp(bits.clone(), Bit::not));
+ }
+
+ public int length()
+ {
+ return bits.length;
+ }
+
+ public BitVector concat(BitVector other)
+ {
+ Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
+ System.arraycopy(other.bits, 0, newBits, length(), other.length());
+ return new BitVector(newBits);
+ }
+
+ public BitVector subVector(int start)
+ {
+ return new BitVector(Arrays.copyOfRange(bits, start, length()));
+ }
+
+ public BitVector subVector(int start, int end)
+ {
+ return new BitVector(Arrays.copyOfRange(bits, start, end));
+ }
+
+ private void checkCompatibility(BitVector bv)
+ {
+ if (length() != bv.length())
+ throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
+ }
+
+ static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
+ {
+ if (dest == null)
+ return second.clone();
+ for (int i = 0; i < dest.length; i++)
+ {
+ dest[i] = op.apply(dest[i], second[i]);
+ }
+ return dest;
+ }
+
+ static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
+ {
+ if (dest == null)
+ return null;
+ for (int i = 0; i < dest.length; i++)
+ {
+ dest[i] = op.apply(dest[i]);
+ }
+ return dest;
+ }
+
+ /**
+ * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
+ *
+ * @author Christian Femers
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
+ {
+ private Bit[] bits;
+
+ private BitVectorMutator(Bit[] bits)
+ {
+ this.bits = bits;
+ }
+
+ static BitVectorMutator of(BitVector bv)
+ {
+ return new BitVectorMutator(bv.getBits());
+ }
+
+ /**
+ * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
+ *
+ */
+ public static BitVectorMutator empty()
+ {
+ return new BitVectorMutator(null);
+ }
+
+ /**
+ * Produces the resulting, immutable {@link BitVector}<br>
+ *
+ * @throws IllegalStateException if the mutator is (still) empty
+ */
+ public BitVector get()
+ {
+ if (bits == null)
+ throw new IllegalStateException("cannot create a BitVector from an empty mutator");
+ return new BitVector(bits);
+ }
+
+ @Override
+ public BitVectorMutator join(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::join);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator and(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::and);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator or(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::or);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator xor(BitVector t)
+ {
+ checkCompatibility(t);
+ bits = binOp(bits, t.bits, Bit::xor);
+ return this;
+ }
+
+ @Override
+ public BitVectorMutator not()
+ {
+ unOp(bits, Bit::not);
+ return this;
+ }
+
+ private void checkCompatibility(BitVector bv)
+ {
+ if (bits != null && bits.length != bv.length())
+ throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
+ }
+ }
+
+ /**
+ * @see Arrays#hashCode(Object[])
+ */
+ @Override
+ public int hashCode()
+ {
+ return Arrays.hashCode(bits);
+ }
+
+ /**
+ * Does test for equality of values/content
+ *
+ * @see Object#equals(Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof BitVector))
+ return false;
+ BitVector other = (BitVector) obj;
+ return Arrays.equals(bits, other.bits);
+ }
+
+ /**
+ * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
+ * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
+ *
+ * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
+ *
+ * @see Object#equals(Object)
+ */
+ public boolean equalsWithOffset(BitVector other, int offset)
+ {
+ if (other == null)
+ return false;
+ return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
+ }
+
+ /**
+ * All {@link Bit}s symbols concatenated together
+ *
+ * @see #parse(String)
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder(bits.length);
+ for (Bit bit : bits)
+ sb.append(bit);
+ return sb.toString();
+ }
+
+ /**
+ * Parses a String containing solely {@link Bit} symbols
+ *
+ * @see #toString()
+ */
+ public static BitVector parse(String s)
+ {
+ Bit[] values = new Bit[s.length()];
+ for (int i = 0; i < s.length(); i++)
+ {
+ values[i] = Bit.parse(s, i);
+ }
+ return new BitVector(values);
+ }
+
+ @Override
+ public Iterator<Bit> iterator()
+ {
+ return new Iterator<>()
+ {
+ private int pos = 0;
+
+ @Override
+ public Bit next()
+ {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ return getBit(pos++);
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return pos != length();
+ }
+ };
+ }
+}
--- /dev/null
+package era.mi.logic.types;
+
+/**
+ * Interface for types that support the basic logic operations
+ *
+ * @author Christian Femers
+ *
+ * @param <T> the logic type itself, to make the operations closed in T
+ * @param <S> the operand type, may be the same as T, see {@link StrictLogicType}
+ */
+public interface LogicType<T extends LogicType<T, S>, S>
+{
+ /**
+ * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164)
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 joined 0 == 0
+ * 1 joined 0 == X
+ * 0 joined 1 == X
+ * 1 joined 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T join(S t);
+
+ /**
+ * Classical logic AND
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 AND 0 == 0
+ * 1 AND 0 == 0
+ * 0 AND 1 == 0
+ * 1 AND 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T and(S t);
+
+ /**
+ * Classical logic OR
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 OR 0 == 0
+ * 1 OR 0 == 1
+ * 0 OR 1 == 1
+ * 1 OR 1 == 1
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T or(S t);
+
+ /**
+ * Classical logic XOR (exclusive OR)
+ *
+ * For example:
+ *
+ * <pre>
+ * 0 XOR 0 == 0
+ * 1 XOR 0 == 1
+ * 0 XOR 1 == 1
+ * 1 XOR 1 == 0
+ * </pre>
+ *
+ * @param t the second logic signal
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T xor(S t);
+
+ /**
+ * Classical logic NOT (logical negation)
+ *
+ * For example:
+ *
+ * <pre>
+ * NOT 0 == 1
+ * NOT 1 == 0
+ * </pre>
+ *
+ * @return the resulting value
+ * @author Christian Femers
+ */
+ T not();
+
+ /**
+ * {@link #and(Object) AND} and then {@link #not() NOT}
+ *
+ * @author Christian Femers
+ */
+ default T nand(S t)
+ {
+ return and(t).not();
+ }
+
+ /**
+ * {@link #or(Object) OR} and then {@link #not() NOT}
+ *
+ * @author Christian Femers
+ */
+ default T nor(S t)
+ {
+ return or(t).not();
+ }
+
+ /**
+ * {@link #xor(Object) XOR} and then {@link #not() NOT}<br>
+ * Used to determine equality (alias parity, consistency)
+ *
+ * @author Christian Femers
+ */
+ default T xnor(S t)
+ {
+ return xor(t).not();
+ }
+}
--- /dev/null
+package era.mi.logic.types;
+
+import java.util.function.BiFunction;
+
+import era.mi.logic.types.BitVector.BitVectorMutator;
+
+@FunctionalInterface
+public interface MutationOperation extends BiFunction<BitVectorMutator, BitVector, BitVectorMutator>
+{
+
+}
--- /dev/null
+package era.mi.logic.types;
+
+/**
+ * Interface for types that support the basic logic operations only among themselves, making it mathematically closed
+ *
+ * @author Christian Femers
+ * @see LogicType
+ *
+ * @param <T> the logic type itself to make the operations closed
+ */
+public interface StrictLogicType<T extends StrictLogicType<T>> extends LogicType<T, T>
+{
+ // this is just a matter of type parameters
+}
--- /dev/null
+package era.mi.logic.wires;
+
+import static era.mi.logic.types.Bit.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.types.Bit;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.types.BitVector.BitVectorMutator;
+
+/**
+ * Represents an array of wires that can store n bits of information.
+ *
+ * @author Fabian Stemmler
+ *
+ */
+public class Wire
+{
+ private BitVector values;
+ public final int travelTime;
+ private List<WireObserver> observers = new ArrayList<WireObserver>();
+ public final int length;
+ private List<WireEnd> inputs = new ArrayList<WireEnd>();
+
+ public Wire(int length, int travelTime)
+ {
+ if (length < 1)
+ throw new IllegalArgumentException(
+ String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
+ this.length = length;
+ this.travelTime = travelTime;
+ initValues();
+ }
+
+ private void initValues()
+ {
+ values = U.toVector(length);
+ }
+
+ private void recalculateSingleInput()
+ {
+ setNewValues(inputs.get(0).getInputValues());
+ }
+
+ private void recalculateMultipleInputs()
+ {
+ BitVectorMutator mutator = BitVectorMutator.empty();
+ for (WireEnd wireArrayEnd : inputs)
+ mutator.join(wireArrayEnd.getInputValues());
+ setNewValues(mutator.get());
+ }
+
+ private void setNewValues(BitVector newValues)
+ {
+ if (values.equals(newValues))
+ return;
+ BitVector oldValues = values;
+ values = newValues;
+ notifyObservers(oldValues);
+ }
+
+ private void recalculate()
+ {
+ switch (inputs.size())
+ {
+ case 0:
+ return;
+ case 1:
+ recalculateSingleInput();
+ break;
+ default:
+ recalculateMultipleInputs();
+ }
+ }
+
+ /**
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.
+ *
+ * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same
+ * value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
+ *
+ * @author Fabian Stemmler
+ */
+ public boolean hasNumericValue()
+ {
+ for (Bit b : values)
+ {
+ if (b != Bit.ZERO && b != Bit.ONE)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.
+ *
+ * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+ *
+ * @author Fabian Stemmler
+ */
+ public long getUnsignedValue()
+ {
+ long val = 0;
+ long mask = 1;
+ for (Bit bit : values)
+ {
+ switch (bit)
+ {
+ default:
+ case Z:
+ case X:
+ return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
+ // Random number?
+ case ONE:
+ val |= mask;
+ break;
+ case ZERO:
+ }
+ mask = mask << 1;
+ }
+ return val;
+ }
+
+ /**
+ * The {@link Wire} is interpreted as a signed integer with n bits.
+ *
+ * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+ *
+ * @author Fabian Stemmler
+ */
+ public long getSignedValue()
+ {
+ long val = getUnsignedValue();
+ long mask = 1 << (length - 1);
+ if ((mask & val) != 0)
+ {
+ int shifts = 64 - length;
+ return (val << shifts) >> shifts;
+ }
+ return val;
+ }
+
+ public Bit getValue()
+ {
+ return getValue(0);
+ }
+
+ public Bit getValue(int index)
+ {
+ return values.getBit(index);
+ }
+
+ public BitVector getValues(int start, int end)
+ {
+ return values.subVector(start, end);
+ }
+
+ public BitVector getValues()
+ {
+ return values;
+ }
+
+ /**
+ * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.
+ *
+ * @param ob The {@link WireObserver} to be notified of changes.
+ * @return true if the given {@link WireObserver} was not already registered, false otherwise
+ *
+ * @author Fabian Stemmler
+ */
+ public boolean addObserver(WireObserver ob)
+ {
+ return observers.add(ob);
+ }
+
+ private void notifyObservers(BitVector oldValues)
+ {
+ for (WireObserver o : observers)
+ o.update(this, oldValues);
+ }
+
+ /**
+ * Create and register a {@link WireEnd} object, which is tied to this {@link Wire}.
+ */
+ public WireEnd createEnd()
+ {
+ return new WireEnd(false);
+ }
+
+ /**
+ * Create a {@link WireEnd} object, which is tied to this {@link Wire}. This {@link WireEnd} cannot written to.
+ */
+ public WireEnd createReadOnlyEnd()
+ {
+ return new WireEnd(true);
+ }
+
+ private void registerInput(WireEnd toRegister)
+ {
+ inputs.add(toRegister);
+ }
+
+ /**
+ * A {@link WireEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
+ * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0
+ * and 1 turn into X when they are mixed
+ *
+ * @author Fabian Stemmler
+ */
+ public class WireEnd
+ {
+ private boolean open;
+ private BitVector inputValues;
+
+ private WireEnd(boolean readOnly)
+ {
+ super();
+ open = !readOnly; // TODO: that makes sense, doesn't it?
+ initValues();
+ if (!readOnly)
+ registerInput(this);
+ }
+
+ private void initValues()
+ {
+ inputValues = U.toVector(length);
+ }
+
+ /**
+ * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
+ *
+ * @param newValues The new values the wires should take on.
+ *
+ * @author Fabian Stemmler
+ */
+ public void feedSignals(Bit... newValues)
+ {
+ feedSignals(BitVector.of(newValues));
+ }
+
+ public void feedSignals(BitVector newValues)
+ {
+ if (newValues.length() != length)
+ throw new IllegalArgumentException(
+ String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
+ if (!open)
+ throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
+ Simulation.TIMELINE.addEvent(e -> setValues(newValues), travelTime);
+ }
+
+ /**
+ * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
+ *
+ * @param bitVector The new values the wires should take on.
+ * @param startingBit The first index of the subarray of wires.
+ *
+ * @author Fabian Stemmler
+ */
+ public void feedSignals(int startingBit, BitVector bitVector)
+ {
+ if (!open)
+ throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
+ Simulation.TIMELINE.addEvent(e -> setValues(startingBit, bitVector), travelTime);
+ }
+
+ private void setValues(int startingBit, BitVector newValues)
+ {
+ // index check covered in equals
+ if (!inputValues.equalsWithOffset(newValues, startingBit))
+ {
+ Bit[] vals = inputValues.getBits();
+ System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
+ inputValues = BitVector.of(vals);
+ Wire.this.recalculate();
+ }
+ }
+
+ private void setValues(BitVector newValues)
+ {
+ if (inputValues.equals(newValues))
+ return;
+ inputValues = newValues;
+ Wire.this.recalculate();
+ }
+
+ /**
+ * @return The value (of bit 0) the {@link WireEnd} is currently feeding into the associated {@link Wire}.
+ */
+ public Bit getInputValue()
+ {
+ return getInputValue(0);
+ }
+
+ /**
+ * @return The value which the {@link WireEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
+ */
+ public Bit getInputValue(int index)
+ {
+ return inputValues.getBit(index);
+ }
+
+ /**
+ * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated {@link Wire}.
+ */
+ public BitVector getInputValues()
+ {
+ return getInputValues(0, length);
+ }
+
+ public BitVector getInputValues(int start, int end)
+ {
+ return inputValues.subVector(start, end);
+ }
+
+ /**
+ * {@link WireEnd} now feeds Z into the associated {@link Wire}.
+ */
+ public void clearSignals()
+ {
+ feedSignals(Z.toVector(length));
+ }
+
+ public BitVector wireValuesExcludingMe()
+ {
+ BitVectorMutator mutator = BitVectorMutator.empty();
+ for (WireEnd wireEnd : inputs)
+ {
+ if (wireEnd == this)
+ continue;
+ mutator.join(wireEnd.inputValues);
+ }
+ return mutator.get();
+ }
+
+ /**
+ * Included for convenient use on {@link Wire}s of length 1.
+ *
+ * @return The value of bit 0.
+ *
+ * @author Fabian Stemmler
+ */
+ public Bit getValue()
+ {
+ return Wire.this.getValue();
+ }
+
+ /**
+ * @param index Index of the requested bit.
+ * @return The value of the indexed bit.
+ *
+ * @author Fabian Stemmler
+ */
+ public Bit getValue(int index)
+ {
+ return Wire.this.getValue(index);
+ }
+
+ /**
+ * @param index Index of the requested bit.
+ * @return The value of the indexed bit.
+ *
+ * @author Fabian Stemmler
+ */
+ public BitVector getValues()
+ {
+ return Wire.this.getValues();
+ }
+
+ /**
+ * @param start Start of the wanted segment. (inclusive)
+ * @param end End of the wanted segment. (exclusive)
+ * @return The values of the segment of {@link Bit}s indexed.
+ *
+ * @author Fabian Stemmler
+ */
+ public BitVector getValues(int start, int end)
+ {
+ return Wire.this.getValues(start, end);
+ }
+
+ /**
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.
+ *
+ * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the
+ * same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
+ *
+ * @author Fabian Stemmler
+ */
+ public boolean hasNumericValue()
+ {
+ return Wire.this.hasNumericValue();
+ }
+
+ /**
+ * The {@link Wire} is interpreted as an unsigned integer with n bits.
+ *
+ * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+ *
+ * @author Fabian Stemmler
+ */
+ public long getUnsignedValue()
+ {
+ return Wire.this.getUnsignedValue();
+ }
+
+ /**
+ * The {@link Wire} is interpreted as a signed integer with n bits.
+ *
+ * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+ *
+ * @author Fabian Stemmler
+ */
+ public long getSignedValue()
+ {
+ return Wire.this.getSignedValue();
+ }
+
+ @Override
+ public String toString()
+ {
+ return inputValues.toString();
+ // return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
+ }
+
+ public void close()
+ {
+ inputs.remove(this);
+ open = false;
+ }
+
+ public int length()
+ {
+ return length;
+ }
+
+ public boolean addObserver(WireObserver ob)
+ {
+ return Wire.this.addObserver(ob);
+ }
+
+ public Wire getWire()
+ {
+ return Wire.this;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);
+ // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
+ }
+
+ public static WireEnd[] extractEnds(Wire[] w)
+ {
+ WireEnd[] inputs = new WireEnd[w.length];
+ for (int i = 0; i < w.length; i++)
+ inputs[i] = w[i].createEnd();
+ return inputs;
+ }
+}
\ No newline at end of file
--- /dev/null
+package era.mi.logic.wires;
+
+import era.mi.logic.types.BitVector;
+
+public interface WireObserver
+{
+ public void update(Wire initiator, BitVector oldValues);
+}