From: Daniel Kirschten Date: Mon, 20 May 2019 17:31:07 +0000 (+0200) Subject: Merged logicui into master X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=fb3edf0f514d574d60cc5874b4d53ebaaa34b7e1;hp=32a3d41c11b96c2530c25b6059b4341a8b34a2e2;p=Mograsim.git Merged logicui into master --- diff --git a/.gitmodules b/.gitmodules index 74725734..c6d72056 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ +[submodule "SampleERCP"] + path = SampleERCP + url =
+ branch = SampleERCP [submodule "SWTHelper"] path = SWTHelper url = https://github.com/Haspamelodica/SWTHelper diff --git a/LogicUI/.classpath b/LogicUI/.classpath index effa05bc..56baf239 100644 --- a/LogicUI/.classpath +++ b/LogicUI/.classpath @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/LogicUI/.project b/LogicUI/.project index b5e0280d..8b40ae19 100644 --- a/LogicUI/.project +++ b/LogicUI/.project @@ -1,17 +1,17 @@ - - - LogicUI - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - + + + LogicUI + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/README.md b/README.md new file mode 100644 index 00000000..e69de29b diff --git a/REQUIREMENTS.MD b/REQUIREMENTS.MD new file mode 100644 index 00000000..3a7a8d77 --- /dev/null +++ b/REQUIREMENTS.MD @@ -0,0 +1,165 @@ +# 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 +
Alle Use Cases anzeigen

+ +#### 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.[A] 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.[B] Es muss auf den Rechnern in den TUM Rechnerhallen funktionieren.[C] + +#### 02. Deinstallation +Das Programm muss sich ohne nennenswerten Aufwand oder Kentnisse vom Benutzer rückstandslos entfernen lassen.[A] + +#### 03. Programmstart +Das Programm bzw. Plugin startet schnell (unter 10 sec.; besser unter 5 sec).[A] 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.[B] Es wird bestenfalls auf ein Beispielprojekt verwiesen (kann erstellt werden?) um dem Nutzer zu ermöglichen, sich damit vertraut zu machen.[C] Ein schnell Link zum Erstellen eines neuen Projekts/Simulation/... wird angezeigt.[D] + +#### 04. Programmende +Sollten bei Beenden des Programms oder Programmabsturz nicht persistierte Daten vorliegen, muss dafür gesorgt werden, dass diese nicht verloren gehen.[A] Enweder durch einen Dialog[B], oder durch erzeugte Recovery-Dateien[C]. Bei Absturz des Programms wird eine passende und aufschlussreiche Fehlermeldung angezeigt, bestenfalls mit Link zu einer Report-Möglichkeit.[D] + +#### 05. Einstellungen +Die Hauptextfarbe und Schriftgröße muss einstellbar sein[A], besser noch Hintergrund- und Markierungsfarben und Schriftstil.[B] Die Einstellung der Sprache muss möglich sein.[C] + +#### 06. Einstieg +Das Einstiegsprojekt zeigt zu Beginn die passende Ansicht an, die Mikroprogrammierung ist wie bei dem Am2900ME ungehindert möglich.[A] Bestenfalls ist dieses beim (erstmaligen) Start direkt geöffnet.[B] Wichtige Fenster (v.a. die grafische Darstellung) sind direkt sichtbar, oder zumindest in einem Tab geöffnet (müssen nicht gesucht werden).[C] + +#### 07. Nutzung der Visualisierung +Die Visualisierung soll möglichst der Vorlesung entsprechen.[A] Sie lässt sich transformieren (z.B. Zoom mit dem Mausrad, Verschieben mit Mausklick oder Mausklick und Alt) und wieder zurücksetzen.[B] + +#### 08. Hilfestellung +Mit dem Produkt wird eine offline-Dokumentation mitgeliefert. (bestenfalls DE und EN)[A] 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.[B] Bleibt man mit der Maus länger über einem GUI-Bestandteil, wird eine kurze Beschreibung/Hilfe dazu angezeigt (Tooltip).[C] + +#### 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.[A] Die Dateien enthalten eine Versionsnummer, um Abwärtskompatibilität und hilfreiche Fehlermeldungen zu ermöglichen.[B] + +#### 10. Entwicklerunterstützung +Das Projekt soll sich einfach bauen/kompilieren/exportieren lassen, es muss beschrieben werden wie das möglich ist.[A] Die Verbreitung zur Anwendung soll ebenfalls unproblematisch sein.[B] + +#### Fügt hier eure eigenen dazu, fortlaufend nummeriert und ggf. mit [A,B,C,..] genauer spezifiziert. + +

+ +### 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 +
+MIT Lizenz? - https://choosealicense.com/licenses/mit/ + +

+ +>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. + +

+ +Muss ggf. Eclipse Public License verwendet werden wegen Copyleft? +
+Eclipse Public License 2.0? - https://www.eclipse.org/legal/epl-2.0/ + +

+ +>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 + +

diff --git a/SampleERCP b/SampleERCP new file mode 160000 index 00000000..10e87495 --- /dev/null +++ b/SampleERCP @@ -0,0 +1 @@ +Subproject commit 10e87495184e49c5cab906921f0afaf2473d9aed diff --git a/era.mi/.classpath b/era.mi/.classpath new file mode 100644 index 00000000..be855233 --- /dev/null +++ b/era.mi/.classpath @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/era.mi/.gitignore b/era.mi/.gitignore new file mode 100644 index 00000000..f59a3a78 --- /dev/null +++ b/era.mi/.gitignore @@ -0,0 +1,15 @@ +/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 diff --git a/era.mi/.settings/org.eclipse.jdt.core.prefs b/era.mi/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..82c6671b --- /dev/null +++ b/era.mi/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,367 @@ +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 diff --git a/era.mi/.settings/org.eclipse.jdt.ui.prefs b/era.mi/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000..07b37c11 --- /dev/null +++ b/era.mi/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,63 @@ +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 diff --git a/era.mi/src/era/mi/logic/Simulation.java b/era.mi/src/era/mi/logic/Simulation.java new file mode 100644 index 00000000..0468ec1e --- /dev/null +++ b/era.mi/src/era/mi/logic/Simulation.java @@ -0,0 +1,9 @@ +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 diff --git a/era.mi/src/era/mi/logic/Util.java b/era.mi/src/era/mi/logic/Util.java new file mode 100644 index 00000000..d621a44c --- /dev/null +++ b/era.mi/src/era/mi/logic/Util.java @@ -0,0 +1,110 @@ +package era.mi.logic; + +import java.util.Arrays; + +import era.mi.logic.types.Bit; + +public final class Util +{ + + @SuppressWarnings("unchecked") + public static 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[][] 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); + } +} diff --git a/era.mi/src/era/mi/logic/components/BasicComponent.java b/era.mi/src/era/mi/logic/components/BasicComponent.java new file mode 100644 index 00000000..e6952838 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/BasicComponent.java @@ -0,0 +1,35 @@ +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(); +} diff --git a/era.mi/src/era/mi/logic/components/BitDisplay.java b/era.mi/src/era/mi/logic/components/BitDisplay.java new file mode 100644 index 00000000..971eb7a7 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/BitDisplay.java @@ -0,0 +1,49 @@ +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 getAllInputs() + { + return List.of(in); + } + + @Override + public List getAllOutputs() + { + return List.of(); + } +} diff --git a/era.mi/src/era/mi/logic/components/Clock.java b/era.mi/src/era/mi/logic/components/Clock.java new file mode 100644 index 00000000..07419b46 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Clock.java @@ -0,0 +1,59 @@ +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 getAllInputs() + { + return List.of(); + } + + @Override + public List getAllOutputs() + { + return List.of(out); + } +} diff --git a/era.mi/src/era/mi/logic/components/Component.java b/era.mi/src/era/mi/logic/components/Component.java new file mode 100644 index 00000000..5e994e3e --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Component.java @@ -0,0 +1,20 @@ +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 getAllInputs(); + + /** + * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI. + */ + public List getAllOutputs(); +} diff --git a/era.mi/src/era/mi/logic/components/Connector.java b/era.mi/src/era/mi/logic/components/Connector.java new file mode 100644 index 00000000..89fb96eb --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Connector.java @@ -0,0 +1,75 @@ +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 getAllInputs() + { + return List.of(a, b); + } + + @Override + public List getAllOutputs() + { + return List.of(a, b); + } +} diff --git a/era.mi/src/era/mi/logic/components/Demux.java b/era.mi/src/era/mi/logic/components/Demux.java new file mode 100644 index 00000000..ffc1bbad --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Demux.java @@ -0,0 +1,80 @@ +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 getAllInputs() + { + return List.of(in, select); + } + + @Override + public List getAllOutputs() + { + return List.of(outputs); + } +} diff --git a/era.mi/src/era/mi/logic/components/ManualSwitch.java b/era.mi/src/era/mi/logic/components/ManualSwitch.java new file mode 100644 index 00000000..0ad4a76c --- /dev/null +++ b/era.mi/src/era/mi/logic/components/ManualSwitch.java @@ -0,0 +1,71 @@ +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 getAllInputs() + { + return List.of(); + } + + @Override + public List getAllOutputs() + { + return List.of(output); + } + +} diff --git a/era.mi/src/era/mi/logic/components/Merger.java b/era.mi/src/era/mi/logic/components/Merger.java new file mode 100644 index 00000000..34ba217c --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Merger.java @@ -0,0 +1,82 @@ +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 getAllInputs() + { + return List.of(inputs); + } + + @Override + public List getAllOutputs() + { + return List.of(out); + } +} diff --git a/era.mi/src/era/mi/logic/components/Mux.java b/era.mi/src/era/mi/logic/components/Mux.java new file mode 100644 index 00000000..aea71166 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Mux.java @@ -0,0 +1,93 @@ +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 getAllInputs() + { + ArrayList wires = new ArrayList(Arrays.asList(inputs)); + wires.add(select); + return Collections.unmodifiableList(wires); + } + + @Override + public List getAllOutputs() + { + return List.of(out); + } +} diff --git a/era.mi/src/era/mi/logic/components/Splitter.java b/era.mi/src/era/mi/logic/components/Splitter.java new file mode 100644 index 00000000..4764c27a --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Splitter.java @@ -0,0 +1,43 @@ +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(); + } +} diff --git a/era.mi/src/era/mi/logic/components/TriStateBuffer.java b/era.mi/src/era/mi/logic/components/TriStateBuffer.java new file mode 100644 index 00000000..0ab162f1 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/TriStateBuffer.java @@ -0,0 +1,49 @@ +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 getAllInputs() + { + return List.of(in, enable); + } + + @Override + public List getAllOutputs() + { + return List.of(out); + } + +} diff --git a/era.mi/src/era/mi/logic/components/gates/AndGate.java b/era.mi/src/era/mi/logic/components/gates/AndGate.java new file mode 100644 index 00000000..5da680e4 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/gates/AndGate.java @@ -0,0 +1,12 @@ +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); + } +} diff --git a/era.mi/src/era/mi/logic/components/gates/MultiInputGate.java b/era.mi/src/era/mi/logic/components/gates/MultiInputGate.java new file mode 100644 index 00000000..e76661d9 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/gates/MultiInputGate.java @@ -0,0 +1,54 @@ +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 getAllInputs() + { + return List.of(in); + } + + @Override + public List 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()); + } +} diff --git a/era.mi/src/era/mi/logic/components/gates/NotGate.java b/era.mi/src/era/mi/logic/components/gates/NotGate.java new file mode 100644 index 00000000..1c0d8330 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/gates/NotGate.java @@ -0,0 +1,48 @@ +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 getAllInputs() + { + return List.of(in); + } + + @Override + public List getAllOutputs() + { + return List.of(out); + } +} diff --git a/era.mi/src/era/mi/logic/components/gates/OrGate.java b/era.mi/src/era/mi/logic/components/gates/OrGate.java new file mode 100644 index 00000000..8c1775fd --- /dev/null +++ b/era.mi/src/era/mi/logic/components/gates/OrGate.java @@ -0,0 +1,12 @@ +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); + } +} diff --git a/era.mi/src/era/mi/logic/components/gates/XorGate.java b/era.mi/src/era/mi/logic/components/gates/XorGate.java new file mode 100644 index 00000000..73a25568 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/gates/XorGate.java @@ -0,0 +1,18 @@ +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); + } + +} diff --git a/era.mi/src/era/mi/logic/tests/ComponentTest.java b/era.mi/src/era/mi/logic/tests/ComponentTest.java new file mode 100644 index 00000000..8a9bc5a4 --- /dev/null +++ b/era.mi/src/era/mi/logic/tests/ComponentTest.java @@ -0,0 +1,384 @@ +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()); + } +} diff --git a/era.mi/src/era/mi/logic/tests/GUITest.java b/era.mi/src/era/mi/logic/tests/GUITest.java new file mode 100644 index 00000000..b93d4b6b --- /dev/null +++ b/era.mi/src/era/mi/logic/tests/GUITest.java @@ -0,0 +1,294 @@ +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 switchMap = new HashMap<>(); + + int height; + int width; + boolean sizeChanged; + + public GUITest() + { + addMouseListener(new MouseListener() + { + + @Override + public void mouseReleased(MouseEvent e) + { + for (Entry dim : switchMap.entrySet()) + { + if (dim.getValue().contains(e.getPoint())) + { + dim.getKey().switchOff(); + repaint(); + } + } + } + + @Override + public void mousePressed(MouseEvent e) + { + for (Entry 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 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(); + } + } +} diff --git a/era.mi/src/era/mi/logic/tests/TestBitDisplay.java b/era.mi/src/era/mi/logic/tests/TestBitDisplay.java new file mode 100644 index 00000000..cb0494e1 --- /dev/null +++ b/era.mi/src/era/mi/logic/tests/TestBitDisplay.java @@ -0,0 +1,47 @@ +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()); + } +} diff --git a/era.mi/src/era/mi/logic/timeline/Timeline.java b/era.mi/src/era/mi/logic/timeline/Timeline.java new file mode 100644 index 00000000..8107db96 --- /dev/null +++ b/era.mi/src/era/mi/logic/timeline/Timeline.java @@ -0,0 +1,178 @@ +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 events; + private long currentTime = 0; + + private final List> eventAddedListener; + + public Timeline(int initCapacity) + { + events = new PriorityQueue(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 listener) + { + eventAddedListener.add(listener); + } + + public void removeEventAddedListener(Consumer 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 diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEvent.java b/era.mi/src/era/mi/logic/timeline/TimelineEvent.java new file mode 100644 index 00000000..46decf5f --- /dev/null +++ b/era.mi/src/era/mi/logic/timeline/TimelineEvent.java @@ -0,0 +1,30 @@ +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 diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java b/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java new file mode 100644 index 00000000..59a91c95 --- /dev/null +++ b/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java @@ -0,0 +1,6 @@ +package era.mi.logic.timeline; + +public interface TimelineEventHandler +{ + public void handle(TimelineEvent e); +} \ No newline at end of file diff --git a/era.mi/src/era/mi/logic/types/Bit.java b/era.mi/src/era/mi/logic/types/Bit.java new file mode 100644 index 00000000..6674f9a7 --- /dev/null +++ b/era.mi/src/era/mi/logic/types/Bit.java @@ -0,0 +1,132 @@ +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 +{ + 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 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 diff --git a/era.mi/src/era/mi/logic/types/BitVector.java b/era.mi/src/era/mi/logic/types/BitVector.java new file mode 100644 index 00000000..38d7d263 --- /dev/null +++ b/era.mi/src/era/mi/logic/types/BitVector.java @@ -0,0 +1,316 @@ +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, Iterable, 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 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 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 + { + 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}
+ * + * @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 offset to the right.
+ * Therefore offset + other.length() <= this.length() needs to be true. + * + * @throws ArrayIndexOutOfBoundsException if offset + other.length() > this.length() + * + * @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 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(); + } + }; + } +} diff --git a/era.mi/src/era/mi/logic/types/LogicType.java b/era.mi/src/era/mi/logic/types/LogicType.java new file mode 100644 index 00000000..9a3180e7 --- /dev/null +++ b/era.mi/src/era/mi/logic/types/LogicType.java @@ -0,0 +1,130 @@ +package era.mi.logic.types; + +/** + * Interface for types that support the basic logic operations + * + * @author Christian Femers + * + * @param the logic type itself, to make the operations closed in T + * @param the operand type, may be the same as T, see {@link StrictLogicType} + */ +public interface LogicType, S> +{ + /** + * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164) + * + * For example: + * + *
+	 * 0 joined 0 == 0
+	 * 1 joined 0 == X
+	 * 0 joined 1 == X
+	 * 1 joined 1 == 1
+	 * 
+ * + * @param t the second logic signal + * @return the resulting value + * @author Christian Femers + */ + T join(S t); + + /** + * Classical logic AND + * + * For example: + * + *
+	 * 0 AND 0 == 0
+	 * 1 AND 0 == 0
+	 * 0 AND 1 == 0
+	 * 1 AND 1 == 1
+	 * 
+ * + * @param t the second logic signal + * @return the resulting value + * @author Christian Femers + */ + T and(S t); + + /** + * Classical logic OR + * + * For example: + * + *
+	 * 0 OR 0 == 0
+	 * 1 OR 0 == 1
+	 * 0 OR 1 == 1
+	 * 1 OR 1 == 1
+	 * 
+ * + * @param t the second logic signal + * @return the resulting value + * @author Christian Femers + */ + T or(S t); + + /** + * Classical logic XOR (exclusive OR) + * + * For example: + * + *
+	 * 0 XOR 0 == 0
+	 * 1 XOR 0 == 1
+	 * 0 XOR 1 == 1
+	 * 1 XOR 1 == 0
+	 * 
+ * + * @param t the second logic signal + * @return the resulting value + * @author Christian Femers + */ + T xor(S t); + + /** + * Classical logic NOT (logical negation) + * + * For example: + * + *
+	 * NOT 0 == 1
+	 * NOT 1 == 0
+	 * 
+ * + * @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}
+ * Used to determine equality (alias parity, consistency) + * + * @author Christian Femers + */ + default T xnor(S t) + { + return xor(t).not(); + } +} diff --git a/era.mi/src/era/mi/logic/types/MutationOperation.java b/era.mi/src/era/mi/logic/types/MutationOperation.java new file mode 100644 index 00000000..d7a16fce --- /dev/null +++ b/era.mi/src/era/mi/logic/types/MutationOperation.java @@ -0,0 +1,11 @@ +package era.mi.logic.types; + +import java.util.function.BiFunction; + +import era.mi.logic.types.BitVector.BitVectorMutator; + +@FunctionalInterface +public interface MutationOperation extends BiFunction +{ + +} diff --git a/era.mi/src/era/mi/logic/types/StrictLogicType.java b/era.mi/src/era/mi/logic/types/StrictLogicType.java new file mode 100644 index 00000000..560bb96f --- /dev/null +++ b/era.mi/src/era/mi/logic/types/StrictLogicType.java @@ -0,0 +1,14 @@ +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 the logic type itself to make the operations closed + */ +public interface StrictLogicType> extends LogicType +{ + // this is just a matter of type parameters +} diff --git a/era.mi/src/era/mi/logic/wires/Wire.java b/era.mi/src/era/mi/logic/wires/Wire.java new file mode 100644 index 00000000..a7b96eee --- /dev/null +++ b/era.mi/src/era/mi/logic/wires/Wire.java @@ -0,0 +1,463 @@ +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 observers = new ArrayList(); + public final int length; + private List inputs = new ArrayList(); + + 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 true if all bits are either Bit.ONE or Bit.ZERO (they do not all have to have the same + * value), not Bit.X or Bit.Z. false 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 true if all bits are either Bit.ONE or Bit.ZERO (they do not all have to have the + * same value), not Bit.X or Bit.Z. false 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 diff --git a/era.mi/src/era/mi/logic/wires/WireObserver.java b/era.mi/src/era/mi/logic/wires/WireObserver.java new file mode 100644 index 00000000..9258e0a0 --- /dev/null +++ b/era.mi/src/era/mi/logic/wires/WireObserver.java @@ -0,0 +1,8 @@ +package era.mi.logic.wires; + +import era.mi.logic.types.BitVector; + +public interface WireObserver +{ + public void update(Wire initiator, BitVector oldValues); +}